examples/ip_pipeline: add pipeline object
[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
12 #include "cli.h"
13 #include "kni.h"
14 #include "link.h"
15 #include "mempool.h"
16 #include "parser.h"
17 #include "pipeline.h"
18 #include "swq.h"
19 #include "tap.h"
20 #include "tmgr.h"
21
22 #ifndef CMD_MAX_TOKENS
23 #define CMD_MAX_TOKENS     256
24 #endif
25
26 #define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
27 #define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
28 #define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
29 #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
30 #define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
31 #define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
32 #define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
33 #define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
34 #define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
35 #define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
36
37 static int
38 is_comment(char *in)
39 {
40         if ((strlen(in) && index("!#%;", in[0])) ||
41                 (strncmp(in, "//", 2) == 0) ||
42                 (strncmp(in, "--", 2) == 0))
43                 return 1;
44
45         return 0;
46 }
47
48 /**
49  * mempool <mempool_name>
50  *  buffer <buffer_size>
51  *  pool <pool_size>
52  *  cache <cache_size>
53  *  cpu <cpu_id>
54  */
55 static void
56 cmd_mempool(char **tokens,
57         uint32_t n_tokens,
58         char *out,
59         size_t out_size)
60 {
61         struct mempool_params p;
62         char *name;
63         struct mempool *mempool;
64
65         if (n_tokens != 10) {
66                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
67                 return;
68         }
69
70         name = tokens[1];
71
72         if (strcmp(tokens[2], "buffer") != 0) {
73                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
74                 return;
75         }
76
77         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
78                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
79                 return;
80         }
81
82         if (strcmp(tokens[4], "pool") != 0) {
83                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
84                 return;
85         }
86
87         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
88                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
89                 return;
90         }
91
92         if (strcmp(tokens[6], "cache") != 0) {
93                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
94                 return;
95         }
96
97         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
98                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
99                 return;
100         }
101
102         if (strcmp(tokens[8], "cpu") != 0) {
103                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
104                 return;
105         }
106
107         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
108                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
109                 return;
110         }
111
112         mempool = mempool_create(name, &p);
113         if (mempool == NULL) {
114                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
115                 return;
116         }
117 }
118
119 /**
120  * link <link_name>
121  *  dev <device_name> | port <port_id>
122  *  rxq <n_queues> <queue_size> <mempool_name>
123  *  txq <n_queues> <queue_size>
124  *  promiscuous on | off
125  *  [rss <qid_0> ... <qid_n>]
126  */
127 static void
128 cmd_link(char **tokens,
129         uint32_t n_tokens,
130         char *out,
131         size_t out_size)
132 {
133         struct link_params p;
134         struct link_params_rss rss;
135         struct link *link;
136         char *name;
137
138         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
139                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
140                 return;
141         }
142         name = tokens[1];
143
144         if (strcmp(tokens[2], "dev") == 0)
145                 p.dev_name = tokens[3];
146         else if (strcmp(tokens[2], "port") == 0) {
147                 p.dev_name = NULL;
148
149                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
150                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
151                         return;
152                 }
153         } else {
154                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
155                 return;
156         }
157
158         if (strcmp(tokens[4], "rxq") != 0) {
159                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
160                 return;
161         }
162
163         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
164                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
165                 return;
166         }
167         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
168                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
169                 return;
170         }
171
172         p.rx.mempool_name = tokens[7];
173
174         if (strcmp(tokens[8], "txq") != 0) {
175                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
176                 return;
177         }
178
179         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
180                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
181                 return;
182         }
183
184         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
185                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
186                 return;
187         }
188
189         if (strcmp(tokens[11], "promiscuous") != 0) {
190                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
191                 return;
192         }
193
194         if (strcmp(tokens[12], "on") == 0)
195                 p.promiscuous = 1;
196         else if (strcmp(tokens[12], "off") == 0)
197                 p.promiscuous = 0;
198         else {
199                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
200                 return;
201         }
202
203         /* RSS */
204         p.rx.rss = NULL;
205         if (n_tokens > 13) {
206                 uint32_t queue_id, i;
207
208                 if (strcmp(tokens[13], "rss") != 0) {
209                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
210                         return;
211                 }
212
213                 p.rx.rss = &rss;
214
215                 rss.n_queues = 0;
216                 for (i = 14; i < n_tokens; i++) {
217                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
218                                 snprintf(out, out_size, MSG_ARG_INVALID,
219                                         "queue_id");
220                                 return;
221                         }
222
223                         rss.queue_id[rss.n_queues] = queue_id;
224                         rss.n_queues++;
225                 }
226         }
227
228         link = link_create(name, &p);
229         if (link == NULL) {
230                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
231                 return;
232         }
233 }
234
235 /**
236  * swq <swq_name>
237  *  size <size>
238  *  cpu <cpu_id>
239  */
240 static void
241 cmd_swq(char **tokens,
242         uint32_t n_tokens,
243         char *out,
244         size_t out_size)
245 {
246         struct swq_params p;
247         char *name;
248         struct swq *swq;
249
250         if (n_tokens != 6) {
251                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
252                 return;
253         }
254
255         name = tokens[1];
256
257         if (strcmp(tokens[2], "size") != 0) {
258                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
259                 return;
260         }
261
262         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
263                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
264                 return;
265         }
266
267         if (strcmp(tokens[4], "cpu") != 0) {
268                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
269                 return;
270         }
271
272         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
273                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
274                 return;
275         }
276
277         swq = swq_create(name, &p);
278         if (swq == NULL) {
279                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
280                 return;
281         }
282 }
283
284 /**
285  * tmgr subport profile
286  *  <tb_rate> <tb_size>
287  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
288  *  <tc_period>
289  */
290 static void
291 cmd_tmgr_subport_profile(char **tokens,
292         uint32_t n_tokens,
293         char *out,
294         size_t out_size)
295 {
296         struct rte_sched_subport_params p;
297         int status, i;
298
299         if (n_tokens != 10) {
300                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
301                 return;
302         }
303
304         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
305                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
306                 return;
307         }
308
309         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
310                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
311                 return;
312         }
313
314         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
315                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
316                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
317                         return;
318                 }
319
320         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
321                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
322                 return;
323         }
324
325         status = tmgr_subport_profile_add(&p);
326         if (status != 0) {
327                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
328                 return;
329         }
330 }
331
332 /**
333  * tmgr pipe profile
334  *  <tb_rate> <tb_size>
335  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
336  *  <tc_period>
337  *  <tc_ov_weight>
338  *  <wrr_weight0..15>
339  */
340 static void
341 cmd_tmgr_pipe_profile(char **tokens,
342         uint32_t n_tokens,
343         char *out,
344         size_t out_size)
345 {
346         struct rte_sched_pipe_params p;
347         int status, i;
348
349         if (n_tokens != 27) {
350                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
351                 return;
352         }
353
354         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
355                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
356                 return;
357         }
358
359         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
360                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
361                 return;
362         }
363
364         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
365                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
366                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
367                         return;
368                 }
369
370         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
371                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
372                 return;
373         }
374
375 #ifdef RTE_SCHED_SUBPORT_TC_OV
376         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
377                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
378                 return;
379         }
380 #endif
381
382         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
383                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
384                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
385                         return;
386                 }
387
388         status = tmgr_pipe_profile_add(&p);
389         if (status != 0) {
390                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
391                 return;
392         }
393 }
394
395 /**
396  * tmgr <tmgr_name>
397  *  rate <rate>
398  *  spp <n_subports_per_port>
399  *  pps <n_pipes_per_subport>
400  *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
401  *  fo <frame_overhead>
402  *  mtu <mtu>
403  *  cpu <cpu_id>
404  */
405 static void
406 cmd_tmgr(char **tokens,
407         uint32_t n_tokens,
408         char *out,
409         size_t out_size)
410 {
411         struct tmgr_port_params p;
412         char *name;
413         struct tmgr_port *tmgr_port;
414         int i;
415
416         if (n_tokens != 19) {
417                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
418                 return;
419         }
420
421         name = tokens[1];
422
423         if (strcmp(tokens[2], "rate") != 0) {
424                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
425                 return;
426         }
427
428         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
429                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
430                 return;
431         }
432
433         if (strcmp(tokens[4], "spp") != 0) {
434                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
435                 return;
436         }
437
438         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
439                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
440                 return;
441         }
442
443         if (strcmp(tokens[6], "pps") != 0) {
444                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
445                 return;
446         }
447
448         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
449                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
450                 return;
451         }
452
453         if (strcmp(tokens[8], "qsize") != 0) {
454                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
455                 return;
456         }
457
458         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
459                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
460                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
461                         return;
462                 }
463
464         if (strcmp(tokens[13], "fo") != 0) {
465                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
466                 return;
467         }
468
469         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
470                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
471                 return;
472         }
473
474         if (strcmp(tokens[15], "mtu") != 0) {
475                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
476                 return;
477         }
478
479         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
480                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
481                 return;
482         }
483
484         if (strcmp(tokens[17], "cpu") != 0) {
485                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
486                 return;
487         }
488
489         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
490                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
491                 return;
492         }
493
494         tmgr_port = tmgr_port_create(name, &p);
495         if (tmgr_port == NULL) {
496                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
497                 return;
498         }
499 }
500
501 /**
502  * tmgr <tmgr_name> subport <subport_id>
503  *  profile <subport_profile_id>
504  */
505 static void
506 cmd_tmgr_subport(char **tokens,
507         uint32_t n_tokens,
508         char *out,
509         size_t out_size)
510 {
511         uint32_t subport_id, subport_profile_id;
512         int status;
513         char *name;
514
515         if (n_tokens != 6) {
516                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
517                 return;
518         }
519
520         name = tokens[1];
521
522         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
523                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
524                 return;
525         }
526
527         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
528                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
529                 return;
530         }
531
532         status = tmgr_subport_config(name, subport_id, subport_profile_id);
533         if (status) {
534                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
535                 return;
536         }
537 }
538
539 /**
540  * tmgr <tmgr_name> subport <subport_id> pipe
541  *  from <pipe_id_first> to <pipe_id_last>
542  *  profile <pipe_profile_id>
543  */
544 static void
545 cmd_tmgr_subport_pipe(char **tokens,
546         uint32_t n_tokens,
547         char *out,
548         size_t out_size)
549 {
550         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
551         int status;
552         char *name;
553
554         if (n_tokens != 11) {
555                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
556                 return;
557         }
558
559         name = tokens[1];
560
561         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
562                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
563                 return;
564         }
565
566         if (strcmp(tokens[4], "pipe") != 0) {
567                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
568                 return;
569         }
570
571         if (strcmp(tokens[5], "from") != 0) {
572                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
573                 return;
574         }
575
576         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
577                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
578                 return;
579         }
580
581         if (strcmp(tokens[7], "to") != 0) {
582                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
583                 return;
584         }
585
586         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
587                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
588                 return;
589         }
590
591         if (strcmp(tokens[9], "profile") != 0) {
592                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
593                 return;
594         }
595
596         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
597                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
598                 return;
599         }
600
601         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
602                         pipe_id_last, pipe_profile_id);
603         if (status) {
604                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
605                 return;
606         }
607 }
608
609 /**
610  * tap <tap_name>
611  */
612 static void
613 cmd_tap(char **tokens,
614         uint32_t n_tokens,
615         char *out,
616         size_t out_size)
617 {
618         char *name;
619         struct tap *tap;
620
621         if (n_tokens != 2) {
622                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
623                 return;
624         }
625
626         name = tokens[1];
627
628         tap = tap_create(name);
629         if (tap == NULL) {
630                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
631                 return;
632         }
633 }
634
635 /**
636  * kni <kni_name>
637  *  link <link_name>
638  *  mempool <mempool_name>
639  *  [thread <thread_id>]
640  */
641 static void
642 cmd_kni(char **tokens,
643         uint32_t n_tokens,
644         char *out,
645         size_t out_size)
646 {
647         struct kni_params p;
648         char *name;
649         struct kni *kni;
650
651         if ((n_tokens != 6) && (n_tokens != 8)) {
652                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
653                 return;
654         }
655
656         name = tokens[1];
657
658         if (strcmp(tokens[2], "link") != 0) {
659                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
660                 return;
661         }
662
663         p.link_name = tokens[3];
664
665         if (strcmp(tokens[4], "mempool") != 0) {
666                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
667                 return;
668         }
669
670         p.mempool_name = tokens[5];
671
672         if (n_tokens == 8) {
673                 if (strcmp(tokens[6], "thread") != 0) {
674                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
675                         return;
676                 }
677
678                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
679                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
680                         return;
681                 }
682
683                 p.force_bind = 1;
684         } else
685                 p.force_bind = 0;
686
687         kni = kni_create(name, &p);
688         if (kni == NULL) {
689                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
690                 return;
691         }
692 }
693
694 /**
695  * port in action profile <profile_name>
696  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
697  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
698  */
699 static void
700 cmd_port_in_action_profile(char **tokens,
701         uint32_t n_tokens,
702         char *out,
703         size_t out_size)
704 {
705         struct port_in_action_profile_params p;
706         struct port_in_action_profile *ap;
707         char *name;
708         uint32_t t0;
709
710         memset(&p, 0, sizeof(p));
711
712         if (n_tokens < 5) {
713                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
714                 return;
715         }
716
717         if (strcmp(tokens[1], "in") != 0) {
718                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
719                 return;
720         }
721
722         if (strcmp(tokens[2], "action") != 0) {
723                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
724                 return;
725         }
726
727         if (strcmp(tokens[3], "profile") != 0) {
728                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
729                 return;
730         }
731
732         name = tokens[4];
733
734         t0 = 5;
735
736         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
737                 uint32_t size;
738
739                 if (n_tokens < t0 + 10) {
740                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
741                         return;
742                 }
743
744                 if (strcmp(tokens[t0 + 1], "match") == 0)
745                         p.fltr.filter_on_match = 1;
746                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
747                         p.fltr.filter_on_match = 0;
748                 else {
749                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
750                         return;
751                 }
752
753                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
754                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
755                         return;
756                 }
757
758                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
759                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
760                         return;
761                 }
762
763                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
764                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
765                         return;
766                 }
767
768                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
769                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
770                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
771                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
772                         return;
773                 }
774
775                 if (strcmp(tokens[t0 + 6], "key") != 0) {
776                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
777                         return;
778                 }
779
780                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
781                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
782                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
783                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
784                         return;
785                 }
786
787                 if (strcmp(tokens[t0 + 8], "port") != 0) {
788                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
789                         return;
790                 }
791
792                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
793                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
794                         return;
795                 }
796
797                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
798                 t0 += 10;
799         } /* filter */
800
801         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
802                 uint32_t i;
803
804                 if (n_tokens < t0 + 22) {
805                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance");
806                         return;
807                 }
808
809                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
810                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
811                         return;
812                 }
813
814                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
815                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
816                         return;
817                 }
818
819                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
820                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
821                         return;
822                 }
823
824                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
825                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
826                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
827                         return;
828                 }
829
830                 if (strcmp(tokens[t0 + 5], "port") != 0) {
831                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
832                         return;
833                 }
834
835                 for (i = 0; i < 16; i++)
836                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
837                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
838                                 return;
839                         }
840
841                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
842                 t0 += 22;
843         } /* balance */
844
845         if (t0 < n_tokens) {
846                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
847                 return;
848         }
849
850         ap = port_in_action_profile_create(name, &p);
851         if (ap == NULL) {
852                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
853                 return;
854         }
855 }
856
857 /**
858  * table action profile <profile_name>
859  *  ipv4 | ipv6
860  *  offset <ip_offset>
861  *  fwd
862  *  [meter srtcm | trtcm
863  *      tc <n_tc>
864  *      stats none | pkts | bytes | both]
865  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
866  *  [encap ether | vlan | qinq | mpls | pppoe]
867  *  [nat src | dst
868  *      proto udp | tcp]
869  *  [ttl drop | fwd
870  *      stats none | pkts]
871  *  [stats pkts | bytes | both]
872  *  [time]
873  */
874 static void
875 cmd_table_action_profile(char **tokens,
876         uint32_t n_tokens,
877         char *out,
878         size_t out_size)
879 {
880         struct table_action_profile_params p;
881         struct table_action_profile *ap;
882         char *name;
883         uint32_t t0;
884
885         memset(&p, 0, sizeof(p));
886
887         if (n_tokens < 8) {
888                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
889                 return;
890         }
891
892         if (strcmp(tokens[1], "action") != 0) {
893                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
894                 return;
895         }
896
897         if (strcmp(tokens[2], "profile") != 0) {
898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
899                 return;
900         }
901
902         name = tokens[3];
903
904         if (strcmp(tokens[4], "ipv4") == 0)
905                 p.common.ip_version = 1;
906         else if (strcmp(tokens[4], "ipv6") == 0)
907                 p.common.ip_version = 0;
908         else {
909                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
910                 return;
911         }
912
913         if (strcmp(tokens[5], "offset") != 0) {
914                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
915                 return;
916         }
917
918         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
919                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
920                 return;
921         }
922
923         if (strcmp(tokens[7], "fwd") != 0) {
924                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
925                 return;
926         }
927
928         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
929
930         t0 = 8;
931         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
932                 if (n_tokens < t0 + 6) {
933                         snprintf(out, out_size, MSG_ARG_MISMATCH,
934                                 "table action profile meter");
935                         return;
936                 }
937
938                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
939                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
940                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
941                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
942                 else {
943                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
944                                 "srtcm or trtcm");
945                         return;
946                 }
947
948                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
949                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
950                         return;
951                 }
952
953                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
954                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
955                         return;
956                 }
957
958                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
959                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
960                         return;
961                 }
962
963                 if (strcmp(tokens[t0 + 5], "none") == 0) {
964                         p.mtr.n_packets_enabled = 0;
965                         p.mtr.n_bytes_enabled = 0;
966                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
967                         p.mtr.n_packets_enabled = 1;
968                         p.mtr.n_bytes_enabled = 0;
969                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
970                         p.mtr.n_packets_enabled = 0;
971                         p.mtr.n_bytes_enabled = 1;
972                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
973                         p.mtr.n_packets_enabled = 1;
974                         p.mtr.n_bytes_enabled = 1;
975                 } else {
976                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
977                                 "none or pkts or bytes or both");
978                         return;
979                 }
980
981                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
982                 t0 += 6;
983         } /* meter */
984
985         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
986                 if (n_tokens < t0 + 5) {
987                         snprintf(out, out_size, MSG_ARG_MISMATCH,
988                                 "table action profile tm");
989                         return;
990                 }
991
992                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
993                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
994                         return;
995                 }
996
997                 if (parser_read_uint32(&p.tm.n_subports_per_port,
998                         tokens[t0 + 2]) != 0) {
999                         snprintf(out, out_size, MSG_ARG_INVALID,
1000                                 "n_subports_per_port");
1001                         return;
1002                 }
1003
1004                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1005                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1006                         return;
1007                 }
1008
1009                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1010                         tokens[t0 + 4]) != 0) {
1011                         snprintf(out, out_size, MSG_ARG_INVALID,
1012                                 "n_pipes_per_subport");
1013                         return;
1014                 }
1015
1016                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1017                 t0 += 5;
1018         } /* tm */
1019
1020         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1021                 if (n_tokens < t0 + 2) {
1022                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1023                                 "action profile encap");
1024                         return;
1025                 }
1026
1027                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1028                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1029                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1030                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1031                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1032                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1033                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1034                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1035                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1036                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1037                 else {
1038                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1039                         return;
1040                 }
1041
1042                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1043                 t0 += 2;
1044         } /* encap */
1045
1046         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1047                 if (n_tokens < t0 + 4) {
1048                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1049                                 "table action profile nat");
1050                         return;
1051                 }
1052
1053                 if (strcmp(tokens[t0 + 1], "src") == 0)
1054                         p.nat.source_nat = 1;
1055                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1056                         p.nat.source_nat = 0;
1057                 else {
1058                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1059                                 "src or dst");
1060                         return;
1061                 }
1062
1063                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1064                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1065                         return;
1066                 }
1067
1068                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1069                         p.nat.proto = 0x06;
1070                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1071                         p.nat.proto = 0x11;
1072                 else {
1073                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1074                                 "tcp or udp");
1075                         return;
1076                 }
1077
1078                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1079                 t0 += 4;
1080         } /* nat */
1081
1082         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1083                 if (n_tokens < t0 + 4) {
1084                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1085                                 "table action profile ttl");
1086                         return;
1087                 }
1088
1089                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1090                         p.ttl.drop = 1;
1091                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1092                         p.ttl.drop = 0;
1093                 else {
1094                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1095                                 "drop or fwd");
1096                         return;
1097                 }
1098
1099                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1100                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1101                         return;
1102                 }
1103
1104                 if (strcmp(tokens[t0 + 3], "none") == 0)
1105                         p.ttl.n_packets_enabled = 0;
1106                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1107                         p.ttl.n_packets_enabled = 1;
1108                 else {
1109                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1110                                 "none or pkts");
1111                         return;
1112                 }
1113
1114                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1115                 t0 += 4;
1116         } /* ttl */
1117
1118         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1119                 if (n_tokens < t0 + 2) {
1120                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1121                                 "table action profile stats");
1122                         return;
1123                 }
1124
1125                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1126                         p.stats.n_packets_enabled = 1;
1127                         p.stats.n_bytes_enabled = 0;
1128                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1129                         p.stats.n_packets_enabled = 0;
1130                         p.stats.n_bytes_enabled = 1;
1131                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1132                         p.stats.n_packets_enabled = 1;
1133                         p.stats.n_bytes_enabled = 1;
1134                 } else {
1135                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1136                                 "pkts or bytes or both");
1137                         return;
1138                 }
1139
1140                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1141                 t0 += 2;
1142         } /* stats */
1143
1144         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1145                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1146                 t0 += 1;
1147         } /* time */
1148
1149         if (t0 < n_tokens) {
1150                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1151                 return;
1152         }
1153
1154         ap = table_action_profile_create(name, &p);
1155         if (ap == NULL) {
1156                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1157                 return;
1158         }
1159 }
1160
1161 /**
1162  * pipeline <pipeline_name>
1163  *  period <timer_period_ms>
1164  *  offset_port_id <offset_port_id>
1165  *  cpu <cpu_id>
1166  */
1167 static void
1168 cmd_pipeline(char **tokens,
1169         uint32_t n_tokens,
1170         char *out,
1171         size_t out_size)
1172 {
1173         struct pipeline_params p;
1174         char *name;
1175         struct pipeline *pipeline;
1176
1177         if (n_tokens != 8) {
1178                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1179                 return;
1180         }
1181
1182         name = tokens[1];
1183
1184         if (strcmp(tokens[2], "period") != 0) {
1185                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1186                 return;
1187         }
1188
1189         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1190                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1191                 return;
1192         }
1193
1194         if (strcmp(tokens[4], "offset_port_id") != 0) {
1195                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1196                 return;
1197         }
1198
1199         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1200                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1201                 return;
1202         }
1203
1204         if (strcmp(tokens[6], "cpu") != 0) {
1205                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1206                 return;
1207         }
1208
1209         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1210                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1211                 return;
1212         }
1213
1214         pipeline = pipeline_create(name, &p);
1215         if (pipeline == NULL) {
1216                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1217                 return;
1218         }
1219 }
1220
1221 /**
1222  * pipeline <pipeline_name> port in
1223  *  bsz <burst_size>
1224  *  link <link_name> rxq <queue_id>
1225  *  | swq <swq_name>
1226  *  | tmgr <tmgr_name>
1227  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
1228  *  | kni <kni_name>
1229  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
1230  *  [action <port_in_action_profile_name>]
1231  *  [disabled]
1232  */
1233 static void
1234 cmd_pipeline_port_in(char **tokens,
1235         uint32_t n_tokens,
1236         char *out,
1237         size_t out_size)
1238 {
1239         struct port_in_params p;
1240         char *pipeline_name;
1241         uint32_t t0;
1242         int enabled, status;
1243
1244         if (n_tokens < 7) {
1245                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1246                 return;
1247         }
1248
1249         pipeline_name = tokens[1];
1250
1251         if (strcmp(tokens[2], "port") != 0) {
1252                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1253                 return;
1254         }
1255
1256         if (strcmp(tokens[3], "in") != 0) {
1257                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1258                 return;
1259         }
1260
1261         if (strcmp(tokens[4], "bsz") != 0) {
1262                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1263                 return;
1264         }
1265
1266         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1267                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1268                 return;
1269         }
1270
1271         t0 = 6;
1272
1273         if (strcmp(tokens[t0], "link") == 0) {
1274                 if (n_tokens < t0 + 4) {
1275                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1276                                 "pipeline port in link");
1277                         return;
1278                 }
1279
1280                 p.type = PORT_IN_RXQ;
1281
1282                 p.dev_name = tokens[t0 + 1];
1283
1284                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1285                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1286                         return;
1287                 }
1288
1289                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1290                         snprintf(out, out_size, MSG_ARG_INVALID,
1291                                 "queue_id");
1292                         return;
1293                 }
1294                 t0 += 4;
1295         } else if (strcmp(tokens[t0], "swq") == 0) {
1296                 if (n_tokens < t0 + 2) {
1297                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1298                                 "pipeline port in swq");
1299                         return;
1300                 }
1301
1302                 p.type = PORT_IN_SWQ;
1303
1304                 p.dev_name = tokens[t0 + 1];
1305
1306                 t0 += 2;
1307         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1308                 if (n_tokens < t0 + 2) {
1309                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1310                                 "pipeline port in tmgr");
1311                         return;
1312                 }
1313
1314                 p.type = PORT_IN_TMGR;
1315
1316                 p.dev_name = tokens[t0 + 1];
1317
1318                 t0 += 2;
1319         } else if (strcmp(tokens[t0], "tap") == 0) {
1320                 if (n_tokens < t0 + 6) {
1321                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1322                                 "pipeline port in tap");
1323                         return;
1324                 }
1325
1326                 p.type = PORT_IN_TAP;
1327
1328                 p.dev_name = tokens[t0 + 1];
1329
1330                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1331                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1332                                 "mempool");
1333                         return;
1334                 }
1335
1336                 p.tap.mempool_name = tokens[t0 + 3];
1337
1338                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1339                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1340                                 "mtu");
1341                         return;
1342                 }
1343
1344                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1345                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1346                         return;
1347                 }
1348
1349                 t0 += 6;
1350         } else if (strcmp(tokens[t0], "kni") == 0) {
1351                 if (n_tokens < t0 + 2) {
1352                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1353                                 "pipeline port in kni");
1354                         return;
1355                 }
1356
1357                 p.type = PORT_IN_KNI;
1358
1359                 p.dev_name = tokens[t0 + 1];
1360
1361                 t0 += 2;
1362         } else if (strcmp(tokens[t0], "source") == 0) {
1363                 if (n_tokens < t0 + 6) {
1364                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1365                                 "pipeline port in source");
1366                         return;
1367                 }
1368
1369                 p.type = PORT_IN_SOURCE;
1370
1371                 p.dev_name = NULL;
1372
1373                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1374                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1375                                 "mempool");
1376                         return;
1377                 }
1378
1379                 p.source.mempool_name = tokens[t0 + 2];
1380
1381                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1382                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1383                                 "file");
1384                         return;
1385                 }
1386
1387                 p.source.file_name = tokens[t0 + 4];
1388
1389                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1390                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1391                                 "bpp");
1392                         return;
1393                 }
1394
1395                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1396                         snprintf(out, out_size, MSG_ARG_INVALID,
1397                                 "n_bytes_per_pkt");
1398                         return;
1399                 }
1400
1401                 t0 += 7;
1402         } else {
1403                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1404                 return;
1405         }
1406
1407         p.action_profile_name = NULL;
1408         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1409                 if (n_tokens < t0 + 2) {
1410                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1411                         return;
1412                 }
1413
1414                 p.action_profile_name = tokens[t0 + 1];
1415
1416                 t0 += 2;
1417         }
1418
1419         enabled = 1;
1420         if ((n_tokens > t0) &&
1421                 (strcmp(tokens[t0], "disabled") == 0)) {
1422                 enabled = 0;
1423
1424                 t0 += 1;
1425         }
1426
1427         if (n_tokens != t0) {
1428                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1429                 return;
1430         }
1431
1432         status = pipeline_port_in_create(pipeline_name,
1433                 &p, enabled);
1434         if (status) {
1435                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1436                 return;
1437         }
1438 }
1439
1440 /**
1441  * pipeline <pipeline_name> port out
1442  *  bsz <burst_size>
1443  *  link <link_name> txq <txq_id>
1444  *  | swq <swq_name>
1445  *  | tmgr <tmgr_name>
1446  *  | tap <tap_name>
1447  *  | kni <kni_name>
1448  *  | sink [file <file_name> pkts <max_n_pkts>]
1449  */
1450 static void
1451 cmd_pipeline_port_out(char **tokens,
1452         uint32_t n_tokens,
1453         char *out,
1454         size_t out_size)
1455 {
1456         struct port_out_params p;
1457         char *pipeline_name;
1458         int status;
1459
1460         memset(&p, 0, sizeof(p));
1461
1462         if (n_tokens < 7) {
1463                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1464                 return;
1465         }
1466
1467         pipeline_name = tokens[1];
1468
1469         if (strcmp(tokens[2], "port") != 0) {
1470                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1471                 return;
1472         }
1473
1474         if (strcmp(tokens[3], "out") != 0) {
1475                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1476                 return;
1477         }
1478
1479         if (strcmp(tokens[4], "bsz") != 0) {
1480                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1481                 return;
1482         }
1483
1484         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1485                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1486                 return;
1487         }
1488
1489         if (strcmp(tokens[6], "link") == 0) {
1490                 if (n_tokens != 10) {
1491                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1492                                 "pipeline port out link");
1493                         return;
1494                 }
1495
1496                 p.type = PORT_OUT_TXQ;
1497
1498                 p.dev_name = tokens[7];
1499
1500                 if (strcmp(tokens[8], "txq") != 0) {
1501                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1502                         return;
1503                 }
1504
1505                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1506                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1507                         return;
1508                 }
1509         } else if (strcmp(tokens[6], "swq") == 0) {
1510                 if (n_tokens != 8) {
1511                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1512                                 "pipeline port out swq");
1513                         return;
1514                 }
1515
1516                 p.type = PORT_OUT_SWQ;
1517
1518                 p.dev_name = tokens[7];
1519         } else if (strcmp(tokens[6], "tmgr") == 0) {
1520                 if (n_tokens != 8) {
1521                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1522                                 "pipeline port out tmgr");
1523                         return;
1524                 }
1525
1526                 p.type = PORT_OUT_TMGR;
1527
1528                 p.dev_name = tokens[7];
1529         } else if (strcmp(tokens[6], "tap") == 0) {
1530                 if (n_tokens != 8) {
1531                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1532                                 "pipeline port out tap");
1533                         return;
1534                 }
1535
1536                 p.type = PORT_OUT_TAP;
1537
1538                 p.dev_name = tokens[7];
1539         } else if (strcmp(tokens[6], "kni") == 0) {
1540                 if (n_tokens != 8) {
1541                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1542                                 "pipeline port out kni");
1543                         return;
1544                 }
1545
1546                 p.type = PORT_OUT_KNI;
1547
1548                 p.dev_name = tokens[7];
1549         } else if (strcmp(tokens[6], "sink") == 0) {
1550                 if ((n_tokens != 7) && (n_tokens != 11)) {
1551                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1552                                 "pipeline port out sink");
1553                         return;
1554                 }
1555
1556                 p.type = PORT_OUT_SINK;
1557
1558                 p.dev_name = NULL;
1559
1560                 if (n_tokens == 7) {
1561                         p.sink.file_name = NULL;
1562                         p.sink.max_n_pkts = 0;
1563                 } else {
1564                         if (strcmp(tokens[7], "file") != 0) {
1565                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1566                                         "file");
1567                                 return;
1568                         }
1569
1570                         p.sink.file_name = tokens[8];
1571
1572                         if (strcmp(tokens[9], "pkts") != 0) {
1573                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1574                                 return;
1575                         }
1576
1577                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1578                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1579                                 return;
1580                         }
1581                 }
1582         } else {
1583                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1584                 return;
1585         }
1586
1587         status = pipeline_port_out_create(pipeline_name, &p);
1588         if (status) {
1589                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1590                 return;
1591         }
1592 }
1593
1594 /**
1595  * pipeline <pipeline_name> table
1596  *      match
1597  *      acl
1598  *          ipv4 | ipv6
1599  *          offset <ip_header_offset>
1600  *          size <n_rules>
1601  *      | array
1602  *          offset <key_offset>
1603  *          size <n_keys>
1604  *      | hash
1605  *          ext | lru
1606  *          key <key_size>
1607  *          mask <key_mask>
1608  *          offset <key_offset>
1609  *          buckets <n_buckets>
1610  *          size <n_keys>
1611  *      | lpm
1612  *          ipv4 | ipv6
1613  *          offset <ip_header_offset>
1614  *          size <n_rules>
1615  *      | stub
1616  *  [action <table_action_profile_name>]
1617  */
1618 static void
1619 cmd_pipeline_table(char **tokens,
1620         uint32_t n_tokens,
1621         char *out,
1622         size_t out_size)
1623 {
1624         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1625         struct table_params p;
1626         char *pipeline_name;
1627         uint32_t t0;
1628         int status;
1629
1630         if (n_tokens < 5) {
1631                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1632                 return;
1633         }
1634
1635         pipeline_name = tokens[1];
1636
1637         if (strcmp(tokens[2], "table") != 0) {
1638                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1639                 return;
1640         }
1641
1642         if (strcmp(tokens[3], "match") != 0) {
1643                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1644                 return;
1645         }
1646
1647         t0 = 4;
1648         if (strcmp(tokens[t0], "acl") == 0) {
1649                 if (n_tokens < t0 + 6) {
1650                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1651                                 "pipeline table acl");
1652                         return;
1653                 }
1654
1655                 p.match_type = TABLE_ACL;
1656
1657                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1658                         p.match.acl.ip_version = 1;
1659                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1660                         p.match.acl.ip_version = 0;
1661                 else {
1662                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1663                                 "ipv4 or ipv6");
1664                         return;
1665                 }
1666
1667                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1668                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1669                         return;
1670                 }
1671
1672                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
1673                         tokens[t0 + 3]) != 0) {
1674                         snprintf(out, out_size, MSG_ARG_INVALID,
1675                                 "ip_header_offset");
1676                         return;
1677                 }
1678
1679                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1680                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1681                         return;
1682                 }
1683
1684                 if (parser_read_uint32(&p.match.acl.n_rules,
1685                         tokens[t0 + 5]) != 0) {
1686                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1687                         return;
1688                 }
1689
1690                 t0 += 6;
1691         } else if (strcmp(tokens[t0], "array") == 0) {
1692                 if (n_tokens < t0 + 5) {
1693                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1694                                 "pipeline table array");
1695                         return;
1696                 }
1697
1698                 p.match_type = TABLE_ARRAY;
1699
1700                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1701                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1702                         return;
1703                 }
1704
1705                 if (parser_read_uint32(&p.match.array.key_offset,
1706                         tokens[t0 + 2]) != 0) {
1707                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1708                         return;
1709                 }
1710
1711                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1712                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1713                         return;
1714                 }
1715
1716                 if (parser_read_uint32(&p.match.array.n_keys,
1717                         tokens[t0 + 4]) != 0) {
1718                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1719                         return;
1720                 }
1721
1722                 t0 += 5;
1723         } else if (strcmp(tokens[t0], "hash") == 0) {
1724                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1725
1726                 if (n_tokens < t0 + 12) {
1727                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1728                                 "pipeline table hash");
1729                         return;
1730                 }
1731
1732                 p.match_type = TABLE_HASH;
1733
1734                 if (strcmp(tokens[t0 + 1], "ext") == 0)
1735                         p.match.hash.extendable_bucket = 1;
1736                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
1737                         p.match.hash.extendable_bucket = 0;
1738                 else {
1739                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1740                                 "ext or lru");
1741                         return;
1742                 }
1743
1744                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1745                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1746                         return;
1747                 }
1748
1749                 if ((parser_read_uint32(&p.match.hash.key_size,
1750                         tokens[t0 + 3]) != 0) ||
1751                         (p.match.hash.key_size == 0) ||
1752                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
1753                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1754                         return;
1755                 }
1756
1757                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1758                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1759                         return;
1760                 }
1761
1762                 if ((parse_hex_string(tokens[t0 + 5],
1763                         key_mask, &key_mask_size) != 0) ||
1764                         (key_mask_size != p.match.hash.key_size)) {
1765                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1766                         return;
1767                 }
1768                 p.match.hash.key_mask = key_mask;
1769
1770                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1771                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1772                         return;
1773                 }
1774
1775                 if (parser_read_uint32(&p.match.hash.key_offset,
1776                         tokens[t0 + 7]) != 0) {
1777                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1778                         return;
1779                 }
1780
1781                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1782                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1783                         return;
1784                 }
1785
1786                 if (parser_read_uint32(&p.match.hash.n_buckets,
1787                         tokens[t0 + 9]) != 0) {
1788                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1789                         return;
1790                 }
1791
1792                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1793                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1794                         return;
1795                 }
1796
1797                 if (parser_read_uint32(&p.match.hash.n_keys,
1798                         tokens[t0 + 11]) != 0) {
1799                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1800                         return;
1801                 }
1802
1803                 t0 += 12;
1804         } else if (strcmp(tokens[t0], "lpm") == 0) {
1805                 if (n_tokens < t0 + 6) {
1806                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1807                                 "pipeline table lpm");
1808                         return;
1809                 }
1810
1811                 p.match_type = TABLE_LPM;
1812
1813                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1814                         p.match.lpm.key_size = 4;
1815                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1816                         p.match.lpm.key_size = 16;
1817                 else {
1818                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1819                                 "ipv4 or ipv6");
1820                         return;
1821                 }
1822
1823                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1824                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1825                         return;
1826                 }
1827
1828                 if (parser_read_uint32(&p.match.lpm.key_offset,
1829                         tokens[t0 + 3]) != 0) {
1830                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1831                         return;
1832                 }
1833
1834                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1835                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1836                         return;
1837                 }
1838
1839                 if (parser_read_uint32(&p.match.lpm.n_rules,
1840                         tokens[t0 + 5]) != 0) {
1841                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1842                         return;
1843                 }
1844
1845                 t0 += 6;
1846         } else if (strcmp(tokens[t0], "stub") == 0) {
1847                 if (n_tokens < t0 + 1) {
1848                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1849                                 "pipeline table stub");
1850                         return;
1851                 }
1852
1853                 p.match_type = TABLE_STUB;
1854
1855                 t0 += 1;
1856         } else {
1857                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1858                 return;
1859         }
1860
1861         p.action_profile_name = NULL;
1862         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1863                 if (n_tokens < t0 + 2) {
1864                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1865                         return;
1866                 }
1867
1868                 p.action_profile_name = tokens[t0 + 1];
1869
1870                 t0 += 2;
1871         }
1872
1873         if (n_tokens > t0) {
1874                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1875                 return;
1876         }
1877
1878         status = pipeline_table_create(pipeline_name, &p);
1879         if (status) {
1880                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1881                 return;
1882         }
1883 }
1884
1885 /**
1886  * pipeline <pipeline_name> port in <port_id> table <table_id>
1887  */
1888 static void
1889 cmd_pipeline_port_in_table(char **tokens,
1890         uint32_t n_tokens,
1891         char *out,
1892         size_t out_size)
1893 {
1894         char *pipeline_name;
1895         uint32_t port_id, table_id;
1896         int status;
1897
1898         if (n_tokens != 7) {
1899                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1900                 return;
1901         }
1902
1903         pipeline_name = tokens[1];
1904
1905         if (strcmp(tokens[2], "port") != 0) {
1906                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1907                 return;
1908         }
1909
1910         if (strcmp(tokens[3], "in") != 0) {
1911                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1912                 return;
1913         }
1914
1915         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
1916                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1917                 return;
1918         }
1919
1920         if (strcmp(tokens[5], "table") != 0) {
1921                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1922                 return;
1923         }
1924
1925         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
1926                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1927                 return;
1928         }
1929
1930         status = pipeline_port_in_connect_to_table(pipeline_name,
1931                 port_id,
1932                 table_id);
1933         if (status) {
1934                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1935                 return;
1936         }
1937 }
1938
1939 void
1940 cli_process(char *in, char *out, size_t out_size)
1941 {
1942         char *tokens[CMD_MAX_TOKENS];
1943         uint32_t n_tokens = RTE_DIM(tokens);
1944         int status;
1945
1946         if (is_comment(in))
1947                 return;
1948
1949         status = parse_tokenize_string(in, tokens, &n_tokens);
1950         if (status) {
1951                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1952                 return;
1953         }
1954
1955         if (n_tokens == 0)
1956                 return;
1957
1958         if (strcmp(tokens[0], "mempool") == 0) {
1959                 cmd_mempool(tokens, n_tokens, out, out_size);
1960                 return;
1961         }
1962
1963         if (strcmp(tokens[0], "link") == 0) {
1964                 cmd_link(tokens, n_tokens, out, out_size);
1965                 return;
1966         }
1967
1968         if (strcmp(tokens[0], "swq") == 0) {
1969                 cmd_swq(tokens, n_tokens, out, out_size);
1970                 return;
1971         }
1972
1973         if (strcmp(tokens[0], "tmgr") == 0) {
1974                 if ((n_tokens >= 3) &&
1975                         (strcmp(tokens[1], "subport") == 0) &&
1976                         (strcmp(tokens[2], "profile") == 0)) {
1977                         cmd_tmgr_subport_profile(tokens, n_tokens,
1978                                 out, out_size);
1979                         return;
1980                 }
1981
1982                 if ((n_tokens >= 3) &&
1983                         (strcmp(tokens[1], "pipe") == 0) &&
1984                         (strcmp(tokens[2], "profile") == 0)) {
1985                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
1986                         return;
1987                 }
1988
1989                 if ((n_tokens >= 5) &&
1990                         (strcmp(tokens[2], "subport") == 0) &&
1991                         (strcmp(tokens[4], "profile") == 0)) {
1992                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
1993                         return;
1994                 }
1995
1996                 if ((n_tokens >= 5) &&
1997                         (strcmp(tokens[2], "subport") == 0) &&
1998                         (strcmp(tokens[4], "pipe") == 0)) {
1999                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
2000                         return;
2001                 }
2002
2003                 cmd_tmgr(tokens, n_tokens, out, out_size);
2004                 return;
2005         }
2006
2007         if (strcmp(tokens[0], "tap") == 0) {
2008                 cmd_tap(tokens, n_tokens, out, out_size);
2009                 return;
2010         }
2011
2012         if (strcmp(tokens[0], "kni") == 0) {
2013                 cmd_kni(tokens, n_tokens, out, out_size);
2014                 return;
2015         }
2016
2017         if (strcmp(tokens[0], "port") == 0) {
2018                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
2019                 return;
2020         }
2021
2022         if (strcmp(tokens[0], "table") == 0) {
2023                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
2024                 return;
2025         }
2026
2027         if (strcmp(tokens[0], "pipeline") == 0) {
2028                 if ((n_tokens >= 3) &&
2029                         (strcmp(tokens[2], "period") == 0)) {
2030                         cmd_pipeline(tokens, n_tokens, out, out_size);
2031                         return;
2032                 }
2033
2034                 if ((n_tokens >= 5) &&
2035                         (strcmp(tokens[2], "port") == 0) &&
2036                         (strcmp(tokens[3], "in") == 0) &&
2037                         (strcmp(tokens[4], "bsz") == 0)) {
2038                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
2039                         return;
2040                 }
2041
2042                 if ((n_tokens >= 5) &&
2043                         (strcmp(tokens[2], "port") == 0) &&
2044                         (strcmp(tokens[3], "out") == 0) &&
2045                         (strcmp(tokens[4], "bsz") == 0)) {
2046                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
2047                         return;
2048                 }
2049
2050                 if ((n_tokens >= 4) &&
2051                         (strcmp(tokens[2], "table") == 0) &&
2052                         (strcmp(tokens[3], "match") == 0)) {
2053                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
2054                         return;
2055                 }
2056
2057                 if ((n_tokens >= 6) &&
2058                         (strcmp(tokens[2], "port") == 0) &&
2059                         (strcmp(tokens[3], "in") == 0) &&
2060                         (strcmp(tokens[5], "table") == 0)) {
2061                         cmd_pipeline_port_in_table(tokens, n_tokens,
2062                                 out, out_size);
2063                         return;
2064                 }
2065         }
2066
2067         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
2068 }
2069
2070 int
2071 cli_script_process(const char *file_name,
2072         size_t msg_in_len_max,
2073         size_t msg_out_len_max)
2074 {
2075         char *msg_in = NULL, *msg_out = NULL;
2076         FILE *f = NULL;
2077
2078         /* Check input arguments */
2079         if ((file_name == NULL) ||
2080                 (strlen(file_name) == 0) ||
2081                 (msg_in_len_max == 0) ||
2082                 (msg_out_len_max == 0))
2083                 return -EINVAL;
2084
2085         msg_in = malloc(msg_in_len_max + 1);
2086         msg_out = malloc(msg_out_len_max + 1);
2087         if ((msg_in == NULL) ||
2088                 (msg_out == NULL)) {
2089                 free(msg_out);
2090                 free(msg_in);
2091                 return -ENOMEM;
2092         }
2093
2094         /* Open input file */
2095         f = fopen(file_name, "r");
2096         if (f == NULL) {
2097                 free(msg_out);
2098                 free(msg_in);
2099                 return -EIO;
2100         }
2101
2102         /* Read file */
2103         for ( ; ; ) {
2104                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
2105                         break;
2106
2107                 printf("%s", msg_in);
2108                 msg_out[0] = 0;
2109
2110                 cli_process(msg_in,
2111                         msg_out,
2112                         msg_out_len_max);
2113
2114                 if (strlen(msg_out))
2115                         printf("%s", msg_out);
2116         }
2117
2118         /* Close file */
2119         fclose(f);
2120         free(msg_out);
2121         free(msg_in);
2122         return 0;
2123 }