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