examples/ip_pipeline: add action profile objects
[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 /**
694  * port in action profile <profile_name>
695  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
696  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
697  */
698 static void
699 cmd_port_in_action_profile(char **tokens,
700         uint32_t n_tokens,
701         char *out,
702         size_t out_size)
703 {
704         struct port_in_action_profile_params p;
705         struct port_in_action_profile *ap;
706         char *name;
707         uint32_t t0;
708
709         memset(&p, 0, sizeof(p));
710
711         if (n_tokens < 5) {
712                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
713                 return;
714         }
715
716         if (strcmp(tokens[1], "in") != 0) {
717                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
718                 return;
719         }
720
721         if (strcmp(tokens[2], "action") != 0) {
722                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
723                 return;
724         }
725
726         if (strcmp(tokens[3], "profile") != 0) {
727                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
728                 return;
729         }
730
731         name = tokens[4];
732
733         t0 = 5;
734
735         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
736                 uint32_t size;
737
738                 if (n_tokens < t0 + 10) {
739                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
740                         return;
741                 }
742
743                 if (strcmp(tokens[t0 + 1], "match") == 0)
744                         p.fltr.filter_on_match = 1;
745                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
746                         p.fltr.filter_on_match = 0;
747                 else {
748                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
749                         return;
750                 }
751
752                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
753                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
754                         return;
755                 }
756
757                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
758                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
759                         return;
760                 }
761
762                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
763                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
764                         return;
765                 }
766
767                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
768                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
769                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
770                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
771                         return;
772                 }
773
774                 if (strcmp(tokens[t0 + 6], "key") != 0) {
775                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
776                         return;
777                 }
778
779                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
780                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
781                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
782                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
783                         return;
784                 }
785
786                 if (strcmp(tokens[t0 + 8], "port") != 0) {
787                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
788                         return;
789                 }
790
791                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
792                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
793                         return;
794                 }
795
796                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
797                 t0 += 10;
798         } /* filter */
799
800         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
801                 uint32_t i;
802
803                 if (n_tokens < t0 + 22) {
804                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance");
805                         return;
806                 }
807
808                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
809                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
810                         return;
811                 }
812
813                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
814                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
815                         return;
816                 }
817
818                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
819                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
820                         return;
821                 }
822
823                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
824                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
825                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
826                         return;
827                 }
828
829                 if (strcmp(tokens[t0 + 5], "port") != 0) {
830                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
831                         return;
832                 }
833
834                 for (i = 0; i < 16; i++)
835                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
836                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
837                                 return;
838                         }
839
840                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
841                 t0 += 22;
842         } /* balance */
843
844         if (t0 < n_tokens) {
845                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
846                 return;
847         }
848
849         ap = port_in_action_profile_create(name, &p);
850         if (ap == NULL) {
851                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
852                 return;
853         }
854 }
855
856 /**
857  * table action profile <profile_name>
858  *  ipv4 | ipv6
859  *  offset <ip_offset>
860  *  fwd
861  *  [meter srtcm | trtcm
862  *      tc <n_tc>
863  *      stats none | pkts | bytes | both]
864  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
865  *  [encap ether | vlan | qinq | mpls | pppoe]
866  *  [nat src | dst
867  *      proto udp | tcp]
868  *  [ttl drop | fwd
869  *      stats none | pkts]
870  *  [stats pkts | bytes | both]
871  *  [time]
872  */
873 static void
874 cmd_table_action_profile(char **tokens,
875         uint32_t n_tokens,
876         char *out,
877         size_t out_size)
878 {
879         struct table_action_profile_params p;
880         struct table_action_profile *ap;
881         char *name;
882         uint32_t t0;
883
884         memset(&p, 0, sizeof(p));
885
886         if (n_tokens < 8) {
887                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
888                 return;
889         }
890
891         if (strcmp(tokens[1], "action") != 0) {
892                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
893                 return;
894         }
895
896         if (strcmp(tokens[2], "profile") != 0) {
897                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
898                 return;
899         }
900
901         name = tokens[3];
902
903         if (strcmp(tokens[4], "ipv4") == 0)
904                 p.common.ip_version = 1;
905         else if (strcmp(tokens[4], "ipv6") == 0)
906                 p.common.ip_version = 0;
907         else {
908                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
909                 return;
910         }
911
912         if (strcmp(tokens[5], "offset") != 0) {
913                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
914                 return;
915         }
916
917         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
918                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
919                 return;
920         }
921
922         if (strcmp(tokens[7], "fwd") != 0) {
923                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
924                 return;
925         }
926
927         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
928
929         t0 = 8;
930         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
931                 if (n_tokens < t0 + 6) {
932                         snprintf(out, out_size, MSG_ARG_MISMATCH,
933                                 "table action profile meter");
934                         return;
935                 }
936
937                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
938                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
939                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
940                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
941                 else {
942                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
943                                 "srtcm or trtcm");
944                         return;
945                 }
946
947                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
948                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
949                         return;
950                 }
951
952                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
953                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
954                         return;
955                 }
956
957                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
958                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
959                         return;
960                 }
961
962                 if (strcmp(tokens[t0 + 5], "none") == 0) {
963                         p.mtr.n_packets_enabled = 0;
964                         p.mtr.n_bytes_enabled = 0;
965                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
966                         p.mtr.n_packets_enabled = 1;
967                         p.mtr.n_bytes_enabled = 0;
968                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
969                         p.mtr.n_packets_enabled = 0;
970                         p.mtr.n_bytes_enabled = 1;
971                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
972                         p.mtr.n_packets_enabled = 1;
973                         p.mtr.n_bytes_enabled = 1;
974                 } else {
975                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
976                                 "none or pkts or bytes or both");
977                         return;
978                 }
979
980                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
981                 t0 += 6;
982         } /* meter */
983
984         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
985                 if (n_tokens < t0 + 5) {
986                         snprintf(out, out_size, MSG_ARG_MISMATCH,
987                                 "table action profile tm");
988                         return;
989                 }
990
991                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
992                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
993                         return;
994                 }
995
996                 if (parser_read_uint32(&p.tm.n_subports_per_port,
997                         tokens[t0 + 2]) != 0) {
998                         snprintf(out, out_size, MSG_ARG_INVALID,
999                                 "n_subports_per_port");
1000                         return;
1001                 }
1002
1003                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1004                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1005                         return;
1006                 }
1007
1008                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1009                         tokens[t0 + 4]) != 0) {
1010                         snprintf(out, out_size, MSG_ARG_INVALID,
1011                                 "n_pipes_per_subport");
1012                         return;
1013                 }
1014
1015                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1016                 t0 += 5;
1017         } /* tm */
1018
1019         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1020                 if (n_tokens < t0 + 2) {
1021                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1022                                 "action profile encap");
1023                         return;
1024                 }
1025
1026                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1027                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1028                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1029                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1030                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1031                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1032                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1033                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1034                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1035                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1036                 else {
1037                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1038                         return;
1039                 }
1040
1041                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1042                 t0 += 2;
1043         } /* encap */
1044
1045         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1046                 if (n_tokens < t0 + 4) {
1047                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1048                                 "table action profile nat");
1049                         return;
1050                 }
1051
1052                 if (strcmp(tokens[t0 + 1], "src") == 0)
1053                         p.nat.source_nat = 1;
1054                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1055                         p.nat.source_nat = 0;
1056                 else {
1057                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1058                                 "src or dst");
1059                         return;
1060                 }
1061
1062                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1063                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1064                         return;
1065                 }
1066
1067                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1068                         p.nat.proto = 0x06;
1069                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1070                         p.nat.proto = 0x11;
1071                 else {
1072                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1073                                 "tcp or udp");
1074                         return;
1075                 }
1076
1077                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1078                 t0 += 4;
1079         } /* nat */
1080
1081         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1082                 if (n_tokens < t0 + 4) {
1083                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1084                                 "table action profile ttl");
1085                         return;
1086                 }
1087
1088                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1089                         p.ttl.drop = 1;
1090                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1091                         p.ttl.drop = 0;
1092                 else {
1093                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1094                                 "drop or fwd");
1095                         return;
1096                 }
1097
1098                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1099                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1100                         return;
1101                 }
1102
1103                 if (strcmp(tokens[t0 + 3], "none") == 0)
1104                         p.ttl.n_packets_enabled = 0;
1105                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1106                         p.ttl.n_packets_enabled = 1;
1107                 else {
1108                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1109                                 "none or pkts");
1110                         return;
1111                 }
1112
1113                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1114                 t0 += 4;
1115         } /* ttl */
1116
1117         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1118                 if (n_tokens < t0 + 2) {
1119                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1120                                 "table action profile stats");
1121                         return;
1122                 }
1123
1124                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1125                         p.stats.n_packets_enabled = 1;
1126                         p.stats.n_bytes_enabled = 0;
1127                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1128                         p.stats.n_packets_enabled = 0;
1129                         p.stats.n_bytes_enabled = 1;
1130                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1131                         p.stats.n_packets_enabled = 1;
1132                         p.stats.n_bytes_enabled = 1;
1133                 } else {
1134                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1135                                 "pkts or bytes or both");
1136                         return;
1137                 }
1138
1139                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1140                 t0 += 2;
1141         } /* stats */
1142
1143         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1144                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1145                 t0 += 1;
1146         } /* time */
1147
1148         if (t0 < n_tokens) {
1149                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1150                 return;
1151         }
1152
1153         ap = table_action_profile_create(name, &p);
1154         if (ap == NULL) {
1155                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1156                 return;
1157         }
1158 }
1159
1160 void
1161 cli_process(char *in, char *out, size_t out_size)
1162 {
1163         char *tokens[CMD_MAX_TOKENS];
1164         uint32_t n_tokens = RTE_DIM(tokens);
1165         int status;
1166
1167         if (is_comment(in))
1168                 return;
1169
1170         status = parse_tokenize_string(in, tokens, &n_tokens);
1171         if (status) {
1172                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1173                 return;
1174         }
1175
1176         if (n_tokens == 0)
1177                 return;
1178
1179         if (strcmp(tokens[0], "mempool") == 0) {
1180                 cmd_mempool(tokens, n_tokens, out, out_size);
1181                 return;
1182         }
1183
1184         if (strcmp(tokens[0], "link") == 0) {
1185                 cmd_link(tokens, n_tokens, out, out_size);
1186                 return;
1187         }
1188
1189         if (strcmp(tokens[0], "swq") == 0) {
1190                 cmd_swq(tokens, n_tokens, out, out_size);
1191                 return;
1192         }
1193
1194         if (strcmp(tokens[0], "tmgr") == 0) {
1195                 if ((n_tokens >= 3) &&
1196                         (strcmp(tokens[1], "subport") == 0) &&
1197                         (strcmp(tokens[2], "profile") == 0)) {
1198                         cmd_tmgr_subport_profile(tokens, n_tokens,
1199                                 out, out_size);
1200                         return;
1201                 }
1202
1203                 if ((n_tokens >= 3) &&
1204                         (strcmp(tokens[1], "pipe") == 0) &&
1205                         (strcmp(tokens[2], "profile") == 0)) {
1206                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
1207                         return;
1208                 }
1209
1210                 if ((n_tokens >= 5) &&
1211                         (strcmp(tokens[2], "subport") == 0) &&
1212                         (strcmp(tokens[4], "profile") == 0)) {
1213                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
1214                         return;
1215                 }
1216
1217                 if ((n_tokens >= 5) &&
1218                         (strcmp(tokens[2], "subport") == 0) &&
1219                         (strcmp(tokens[4], "pipe") == 0)) {
1220                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
1221                         return;
1222                 }
1223
1224                 cmd_tmgr(tokens, n_tokens, out, out_size);
1225                 return;
1226         }
1227
1228         if (strcmp(tokens[0], "tap") == 0) {
1229                 cmd_tap(tokens, n_tokens, out, out_size);
1230                 return;
1231         }
1232
1233         if (strcmp(tokens[0], "kni") == 0) {
1234                 cmd_kni(tokens, n_tokens, out, out_size);
1235                 return;
1236         }
1237
1238         if (strcmp(tokens[0], "port") == 0) {
1239                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
1240                 return;
1241         }
1242
1243         if (strcmp(tokens[0], "table") == 0) {
1244                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
1245                 return;
1246         }
1247
1248         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
1249 }
1250
1251 int
1252 cli_script_process(const char *file_name,
1253         size_t msg_in_len_max,
1254         size_t msg_out_len_max)
1255 {
1256         char *msg_in = NULL, *msg_out = NULL;
1257         FILE *f = NULL;
1258
1259         /* Check input arguments */
1260         if ((file_name == NULL) ||
1261                 (strlen(file_name) == 0) ||
1262                 (msg_in_len_max == 0) ||
1263                 (msg_out_len_max == 0))
1264                 return -EINVAL;
1265
1266         msg_in = malloc(msg_in_len_max + 1);
1267         msg_out = malloc(msg_out_len_max + 1);
1268         if ((msg_in == NULL) ||
1269                 (msg_out == NULL)) {
1270                 free(msg_out);
1271                 free(msg_in);
1272                 return -ENOMEM;
1273         }
1274
1275         /* Open input file */
1276         f = fopen(file_name, "r");
1277         if (f == NULL) {
1278                 free(msg_out);
1279                 free(msg_in);
1280                 return -EIO;
1281         }
1282
1283         /* Read file */
1284         for ( ; ; ) {
1285                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
1286                         break;
1287
1288                 printf("%s", msg_in);
1289                 msg_out[0] = 0;
1290
1291                 cli_process(msg_in,
1292                         msg_out,
1293                         msg_out_len_max);
1294
1295                 if (strlen(msg_out))
1296                         printf("%s", msg_out);
1297         }
1298
1299         /* Close file */
1300         fclose(f);
1301         free(msg_out);
1302         free(msg_in);
1303         return 0;
1304 }