examples/ip_pipeline: add KNI 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 "swq.h"
18 #include "tap.h"
19 #include "tmgr.h"
20
21 #ifndef CMD_MAX_TOKENS
22 #define CMD_MAX_TOKENS     256
23 #endif
24
25 #define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
26 #define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
27 #define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
28 #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
29 #define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
30 #define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
31 #define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
32 #define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
33 #define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
34 #define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
35
36 static int
37 is_comment(char *in)
38 {
39         if ((strlen(in) && index("!#%;", in[0])) ||
40                 (strncmp(in, "//", 2) == 0) ||
41                 (strncmp(in, "--", 2) == 0))
42                 return 1;
43
44         return 0;
45 }
46
47 /**
48  * mempool <mempool_name>
49  *  buffer <buffer_size>
50  *  pool <pool_size>
51  *  cache <cache_size>
52  *  cpu <cpu_id>
53  */
54 static void
55 cmd_mempool(char **tokens,
56         uint32_t n_tokens,
57         char *out,
58         size_t out_size)
59 {
60         struct mempool_params p;
61         char *name;
62         struct mempool *mempool;
63
64         if (n_tokens != 10) {
65                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
66                 return;
67         }
68
69         name = tokens[1];
70
71         if (strcmp(tokens[2], "buffer") != 0) {
72                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
73                 return;
74         }
75
76         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
77                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
78                 return;
79         }
80
81         if (strcmp(tokens[4], "pool") != 0) {
82                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
83                 return;
84         }
85
86         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
87                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
88                 return;
89         }
90
91         if (strcmp(tokens[6], "cache") != 0) {
92                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
93                 return;
94         }
95
96         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
97                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
98                 return;
99         }
100
101         if (strcmp(tokens[8], "cpu") != 0) {
102                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
103                 return;
104         }
105
106         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
107                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
108                 return;
109         }
110
111         mempool = mempool_create(name, &p);
112         if (mempool == NULL) {
113                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
114                 return;
115         }
116 }
117
118 /**
119  * link <link_name>
120  *  dev <device_name> | port <port_id>
121  *  rxq <n_queues> <queue_size> <mempool_name>
122  *  txq <n_queues> <queue_size>
123  *  promiscuous on | off
124  *  [rss <qid_0> ... <qid_n>]
125  */
126 static void
127 cmd_link(char **tokens,
128         uint32_t n_tokens,
129         char *out,
130         size_t out_size)
131 {
132         struct link_params p;
133         struct link_params_rss rss;
134         struct link *link;
135         char *name;
136
137         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
138                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
139                 return;
140         }
141         name = tokens[1];
142
143         if (strcmp(tokens[2], "dev") == 0)
144                 p.dev_name = tokens[3];
145         else if (strcmp(tokens[2], "port") == 0) {
146                 p.dev_name = NULL;
147
148                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
149                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
150                         return;
151                 }
152         } else {
153                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
154                 return;
155         }
156
157         if (strcmp(tokens[4], "rxq") != 0) {
158                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
159                 return;
160         }
161
162         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
163                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
164                 return;
165         }
166         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
167                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
168                 return;
169         }
170
171         p.rx.mempool_name = tokens[7];
172
173         if (strcmp(tokens[8], "txq") != 0) {
174                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
175                 return;
176         }
177
178         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
179                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
180                 return;
181         }
182
183         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
184                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
185                 return;
186         }
187
188         if (strcmp(tokens[11], "promiscuous") != 0) {
189                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
190                 return;
191         }
192
193         if (strcmp(tokens[12], "on") == 0)
194                 p.promiscuous = 1;
195         else if (strcmp(tokens[12], "off") == 0)
196                 p.promiscuous = 0;
197         else {
198                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
199                 return;
200         }
201
202         /* RSS */
203         p.rx.rss = NULL;
204         if (n_tokens > 13) {
205                 uint32_t queue_id, i;
206
207                 if (strcmp(tokens[13], "rss") != 0) {
208                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
209                         return;
210                 }
211
212                 p.rx.rss = &rss;
213
214                 rss.n_queues = 0;
215                 for (i = 14; i < n_tokens; i++) {
216                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
217                                 snprintf(out, out_size, MSG_ARG_INVALID,
218                                         "queue_id");
219                                 return;
220                         }
221
222                         rss.queue_id[rss.n_queues] = queue_id;
223                         rss.n_queues++;
224                 }
225         }
226
227         link = link_create(name, &p);
228         if (link == NULL) {
229                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
230                 return;
231         }
232 }
233
234 /**
235  * swq <swq_name>
236  *  size <size>
237  *  cpu <cpu_id>
238  */
239 static void
240 cmd_swq(char **tokens,
241         uint32_t n_tokens,
242         char *out,
243         size_t out_size)
244 {
245         struct swq_params p;
246         char *name;
247         struct swq *swq;
248
249         if (n_tokens != 6) {
250                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
251                 return;
252         }
253
254         name = tokens[1];
255
256         if (strcmp(tokens[2], "size") != 0) {
257                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
258                 return;
259         }
260
261         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
262                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
263                 return;
264         }
265
266         if (strcmp(tokens[4], "cpu") != 0) {
267                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
268                 return;
269         }
270
271         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
272                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
273                 return;
274         }
275
276         swq = swq_create(name, &p);
277         if (swq == NULL) {
278                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
279                 return;
280         }
281 }
282
283 /**
284  * tmgr subport profile
285  *  <tb_rate> <tb_size>
286  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
287  *  <tc_period>
288  */
289 static void
290 cmd_tmgr_subport_profile(char **tokens,
291         uint32_t n_tokens,
292         char *out,
293         size_t out_size)
294 {
295         struct rte_sched_subport_params p;
296         int status, i;
297
298         if (n_tokens != 10) {
299                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
300                 return;
301         }
302
303         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
304                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
305                 return;
306         }
307
308         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
309                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
310                 return;
311         }
312
313         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
314                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
315                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
316                         return;
317                 }
318
319         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
320                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
321                 return;
322         }
323
324         status = tmgr_subport_profile_add(&p);
325         if (status != 0) {
326                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
327                 return;
328         }
329 }
330
331 /**
332  * tmgr pipe profile
333  *  <tb_rate> <tb_size>
334  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
335  *  <tc_period>
336  *  <tc_ov_weight>
337  *  <wrr_weight0..15>
338  */
339 static void
340 cmd_tmgr_pipe_profile(char **tokens,
341         uint32_t n_tokens,
342         char *out,
343         size_t out_size)
344 {
345         struct rte_sched_pipe_params p;
346         int status, i;
347
348         if (n_tokens != 27) {
349                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
350                 return;
351         }
352
353         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
354                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
355                 return;
356         }
357
358         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
359                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
360                 return;
361         }
362
363         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
364                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
365                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
366                         return;
367                 }
368
369         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
370                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
371                 return;
372         }
373
374 #ifdef RTE_SCHED_SUBPORT_TC_OV
375         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
376                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
377                 return;
378         }
379 #endif
380
381         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
382                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
383                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
384                         return;
385                 }
386
387         status = tmgr_pipe_profile_add(&p);
388         if (status != 0) {
389                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
390                 return;
391         }
392 }
393
394 /**
395  * tmgr <tmgr_name>
396  *  rate <rate>
397  *  spp <n_subports_per_port>
398  *  pps <n_pipes_per_subport>
399  *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
400  *  fo <frame_overhead>
401  *  mtu <mtu>
402  *  cpu <cpu_id>
403  */
404 static void
405 cmd_tmgr(char **tokens,
406         uint32_t n_tokens,
407         char *out,
408         size_t out_size)
409 {
410         struct tmgr_port_params p;
411         char *name;
412         struct tmgr_port *tmgr_port;
413         int i;
414
415         if (n_tokens != 19) {
416                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
417                 return;
418         }
419
420         name = tokens[1];
421
422         if (strcmp(tokens[2], "rate") != 0) {
423                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
424                 return;
425         }
426
427         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
428                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
429                 return;
430         }
431
432         if (strcmp(tokens[4], "spp") != 0) {
433                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
434                 return;
435         }
436
437         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
438                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
439                 return;
440         }
441
442         if (strcmp(tokens[6], "pps") != 0) {
443                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
444                 return;
445         }
446
447         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
448                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
449                 return;
450         }
451
452         if (strcmp(tokens[8], "qsize") != 0) {
453                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
454                 return;
455         }
456
457         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
458                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
459                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
460                         return;
461                 }
462
463         if (strcmp(tokens[13], "fo") != 0) {
464                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
465                 return;
466         }
467
468         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
469                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
470                 return;
471         }
472
473         if (strcmp(tokens[15], "mtu") != 0) {
474                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
475                 return;
476         }
477
478         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
479                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
480                 return;
481         }
482
483         if (strcmp(tokens[17], "cpu") != 0) {
484                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
485                 return;
486         }
487
488         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
489                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
490                 return;
491         }
492
493         tmgr_port = tmgr_port_create(name, &p);
494         if (tmgr_port == NULL) {
495                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
496                 return;
497         }
498 }
499
500 /**
501  * tmgr <tmgr_name> subport <subport_id>
502  *  profile <subport_profile_id>
503  */
504 static void
505 cmd_tmgr_subport(char **tokens,
506         uint32_t n_tokens,
507         char *out,
508         size_t out_size)
509 {
510         uint32_t subport_id, subport_profile_id;
511         int status;
512         char *name;
513
514         if (n_tokens != 6) {
515                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
516                 return;
517         }
518
519         name = tokens[1];
520
521         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
522                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
523                 return;
524         }
525
526         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
527                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
528                 return;
529         }
530
531         status = tmgr_subport_config(name, subport_id, subport_profile_id);
532         if (status) {
533                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
534                 return;
535         }
536 }
537
538 /**
539  * tmgr <tmgr_name> subport <subport_id> pipe
540  *  from <pipe_id_first> to <pipe_id_last>
541  *  profile <pipe_profile_id>
542  */
543 static void
544 cmd_tmgr_subport_pipe(char **tokens,
545         uint32_t n_tokens,
546         char *out,
547         size_t out_size)
548 {
549         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
550         int status;
551         char *name;
552
553         if (n_tokens != 11) {
554                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
555                 return;
556         }
557
558         name = tokens[1];
559
560         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
561                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
562                 return;
563         }
564
565         if (strcmp(tokens[4], "pipe") != 0) {
566                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
567                 return;
568         }
569
570         if (strcmp(tokens[5], "from") != 0) {
571                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
572                 return;
573         }
574
575         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
576                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
577                 return;
578         }
579
580         if (strcmp(tokens[7], "to") != 0) {
581                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
582                 return;
583         }
584
585         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
586                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
587                 return;
588         }
589
590         if (strcmp(tokens[9], "profile") != 0) {
591                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
592                 return;
593         }
594
595         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
596                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
597                 return;
598         }
599
600         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
601                         pipe_id_last, pipe_profile_id);
602         if (status) {
603                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
604                 return;
605         }
606 }
607
608 /**
609  * tap <tap_name>
610  */
611 static void
612 cmd_tap(char **tokens,
613         uint32_t n_tokens,
614         char *out,
615         size_t out_size)
616 {
617         char *name;
618         struct tap *tap;
619
620         if (n_tokens != 2) {
621                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
622                 return;
623         }
624
625         name = tokens[1];
626
627         tap = tap_create(name);
628         if (tap == NULL) {
629                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
630                 return;
631         }
632 }
633
634 /**
635  * kni <kni_name>
636  *  link <link_name>
637  *  mempool <mempool_name>
638  *  [thread <thread_id>]
639  */
640 static void
641 cmd_kni(char **tokens,
642         uint32_t n_tokens,
643         char *out,
644         size_t out_size)
645 {
646         struct kni_params p;
647         char *name;
648         struct kni *kni;
649
650         if ((n_tokens != 6) && (n_tokens != 8)) {
651                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
652                 return;
653         }
654
655         name = tokens[1];
656
657         if (strcmp(tokens[2], "link") != 0) {
658                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
659                 return;
660         }
661
662         p.link_name = tokens[3];
663
664         if (strcmp(tokens[4], "mempool") != 0) {
665                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
666                 return;
667         }
668
669         p.mempool_name = tokens[5];
670
671         if (n_tokens == 8) {
672                 if (strcmp(tokens[6], "thread") != 0) {
673                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
674                         return;
675                 }
676
677                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
678                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
679                         return;
680                 }
681
682                 p.force_bind = 1;
683         } else
684                 p.force_bind = 0;
685
686         kni = kni_create(name, &p);
687         if (kni == NULL) {
688                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
689                 return;
690         }
691 }
692
693 void
694 cli_process(char *in, char *out, size_t out_size)
695 {
696         char *tokens[CMD_MAX_TOKENS];
697         uint32_t n_tokens = RTE_DIM(tokens);
698         int status;
699
700         if (is_comment(in))
701                 return;
702
703         status = parse_tokenize_string(in, tokens, &n_tokens);
704         if (status) {
705                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
706                 return;
707         }
708
709         if (n_tokens == 0)
710                 return;
711
712         if (strcmp(tokens[0], "mempool") == 0) {
713                 cmd_mempool(tokens, n_tokens, out, out_size);
714                 return;
715         }
716
717         if (strcmp(tokens[0], "link") == 0) {
718                 cmd_link(tokens, n_tokens, out, out_size);
719                 return;
720         }
721
722         if (strcmp(tokens[0], "swq") == 0) {
723                 cmd_swq(tokens, n_tokens, out, out_size);
724                 return;
725         }
726
727         if (strcmp(tokens[0], "tmgr") == 0) {
728                 if ((n_tokens >= 3) &&
729                         (strcmp(tokens[1], "subport") == 0) &&
730                         (strcmp(tokens[2], "profile") == 0)) {
731                         cmd_tmgr_subport_profile(tokens, n_tokens,
732                                 out, out_size);
733                         return;
734                 }
735
736                 if ((n_tokens >= 3) &&
737                         (strcmp(tokens[1], "pipe") == 0) &&
738                         (strcmp(tokens[2], "profile") == 0)) {
739                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
740                         return;
741                 }
742
743                 if ((n_tokens >= 5) &&
744                         (strcmp(tokens[2], "subport") == 0) &&
745                         (strcmp(tokens[4], "profile") == 0)) {
746                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
747                         return;
748                 }
749
750                 if ((n_tokens >= 5) &&
751                         (strcmp(tokens[2], "subport") == 0) &&
752                         (strcmp(tokens[4], "pipe") == 0)) {
753                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
754                         return;
755                 }
756
757                 cmd_tmgr(tokens, n_tokens, out, out_size);
758                 return;
759         }
760
761         if (strcmp(tokens[0], "tap") == 0) {
762                 cmd_tap(tokens, n_tokens, out, out_size);
763                 return;
764         }
765
766         if (strcmp(tokens[0], "kni") == 0) {
767                 cmd_kni(tokens, n_tokens, out, out_size);
768                 return;
769         }
770
771         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
772 }
773
774 int
775 cli_script_process(const char *file_name,
776         size_t msg_in_len_max,
777         size_t msg_out_len_max)
778 {
779         char *msg_in = NULL, *msg_out = NULL;
780         FILE *f = NULL;
781
782         /* Check input arguments */
783         if ((file_name == NULL) ||
784                 (strlen(file_name) == 0) ||
785                 (msg_in_len_max == 0) ||
786                 (msg_out_len_max == 0))
787                 return -EINVAL;
788
789         msg_in = malloc(msg_in_len_max + 1);
790         msg_out = malloc(msg_out_len_max + 1);
791         if ((msg_in == NULL) ||
792                 (msg_out == NULL)) {
793                 free(msg_out);
794                 free(msg_in);
795                 return -ENOMEM;
796         }
797
798         /* Open input file */
799         f = fopen(file_name, "r");
800         if (f == NULL) {
801                 free(msg_out);
802                 free(msg_in);
803                 return -EIO;
804         }
805
806         /* Read file */
807         for ( ; ; ) {
808                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
809                         break;
810
811                 printf("%s", msg_in);
812                 msg_out[0] = 0;
813
814                 cli_process(msg_in,
815                         msg_out,
816                         msg_out_len_max);
817
818                 if (strlen(msg_out))
819                         printf("%s", msg_out);
820         }
821
822         /* Close file */
823         fclose(f);
824         free(msg_out);
825         free(msg_in);
826         return 0;
827 }