net/softnic: use separate session mempools
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_common.h>
11 #include <rte_cycles.h>
12 #include <rte_string_fns.h>
13 #include <rte_cryptodev.h>
14
15 #include "rte_eth_softnic_internals.h"
16 #include "parser.h"
17
18 #ifndef CMD_MAX_TOKENS
19 #define CMD_MAX_TOKENS     256
20 #endif
21
22 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
23 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
24 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
25 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
26 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
27 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
28 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
29 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
30 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
31 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
32 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
33
34 static int
35 is_comment(char *in)
36 {
37         if ((strlen(in) && index("!#%;", in[0])) ||
38                 (strncmp(in, "//", 2) == 0) ||
39                 (strncmp(in, "--", 2) == 0))
40                 return 1;
41
42         return 0;
43 }
44
45 /**
46  * mempool <mempool_name>
47  *  buffer <buffer_size>
48  *  pool <pool_size>
49  *  cache <cache_size>
50  */
51 static void
52 cmd_mempool(struct pmd_internals *softnic,
53         char **tokens,
54         uint32_t n_tokens,
55         char *out,
56         size_t out_size)
57 {
58         struct softnic_mempool_params p;
59         char *name;
60         struct softnic_mempool *mempool;
61
62         if (n_tokens != 8) {
63                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
64                 return;
65         }
66
67         name = tokens[1];
68
69         if (strcmp(tokens[2], "buffer") != 0) {
70                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
71                 return;
72         }
73
74         if (softnic_parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
75                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
76                 return;
77         }
78
79         if (strcmp(tokens[4], "pool") != 0) {
80                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
81                 return;
82         }
83
84         if (softnic_parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
85                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
86                 return;
87         }
88
89         if (strcmp(tokens[6], "cache") != 0) {
90                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
91                 return;
92         }
93
94         if (softnic_parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
95                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
96                 return;
97         }
98
99         mempool = softnic_mempool_create(softnic, name, &p);
100         if (mempool == NULL) {
101                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
102                 return;
103         }
104 }
105
106 /**
107  * link <link_name>
108  *    dev <device_name> | port <port_id>
109  */
110 static void
111 cmd_link(struct pmd_internals *softnic,
112         char **tokens,
113         uint32_t n_tokens,
114         char *out,
115         size_t out_size)
116 {
117         struct softnic_link_params p;
118         struct softnic_link *link;
119         char *name;
120
121         memset(&p, 0, sizeof(p));
122
123         if (n_tokens != 4) {
124                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
125                 return;
126         }
127         name = tokens[1];
128
129         if (strcmp(tokens[2], "dev") == 0) {
130                 p.dev_name = tokens[3];
131         } else if (strcmp(tokens[2], "port") == 0) {
132                 p.dev_name = NULL;
133
134                 if (softnic_parser_read_uint16(&p.port_id, tokens[3]) != 0) {
135                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
136                         return;
137                 }
138         } else {
139                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
140                 return;
141         }
142
143         link = softnic_link_create(softnic, name, &p);
144         if (link == NULL) {
145                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
146                 return;
147         }
148 }
149
150 /**
151  * swq <swq_name>
152  *  size <size>
153  */
154 static void
155 cmd_swq(struct pmd_internals *softnic,
156         char **tokens,
157         uint32_t n_tokens,
158         char *out,
159         size_t out_size)
160 {
161         struct softnic_swq_params p;
162         char *name;
163         struct softnic_swq *swq;
164
165         if (n_tokens != 4) {
166                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
167                 return;
168         }
169
170         name = tokens[1];
171
172         if (strcmp(tokens[2], "size") != 0) {
173                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
174                 return;
175         }
176
177         if (softnic_parser_read_uint32(&p.size, tokens[3]) != 0) {
178                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
179                 return;
180         }
181
182         swq = softnic_swq_create(softnic, name, &p);
183         if (swq == NULL) {
184                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
185                 return;
186         }
187 }
188
189 /**
190  * tmgr shaper profile
191  *  id <profile_id>
192  *  rate <tb_rate> size <tb_size>
193  *  adj <packet_length_adjust>
194  */
195 static void
196 cmd_tmgr_shaper_profile(struct pmd_internals *softnic,
197         char **tokens,
198         uint32_t n_tokens,
199         char *out,
200         size_t out_size)
201 {
202         struct rte_tm_shaper_params sp;
203         struct rte_tm_error error;
204         uint32_t shaper_profile_id;
205         uint16_t port_id;
206         int status;
207
208         memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
209
210         if (n_tokens != 11) {
211                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
212                 return;
213         }
214
215         if (strcmp(tokens[1], "shaper") != 0) {
216                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper");
217                 return;
218         }
219
220         if (strcmp(tokens[2], "profile") != 0) {
221                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
222                 return;
223         }
224
225         if (strcmp(tokens[3], "id") != 0) {
226                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id");
227                 return;
228         }
229
230         if (softnic_parser_read_uint32(&shaper_profile_id, tokens[4]) != 0) {
231                 snprintf(out, out_size, MSG_ARG_INVALID, "profile_id");
232                 return;
233         }
234
235         if (strcmp(tokens[5], "rate") != 0) {
236                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
237                 return;
238         }
239
240         if (softnic_parser_read_uint64(&sp.peak.rate, tokens[6]) != 0) {
241                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
242                 return;
243         }
244
245         if (strcmp(tokens[7], "size") != 0) {
246                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
247                 return;
248         }
249
250         if (softnic_parser_read_uint64(&sp.peak.size, tokens[8]) != 0) {
251                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
252                 return;
253         }
254
255         if (strcmp(tokens[9], "adj") != 0) {
256                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "adj");
257                 return;
258         }
259
260         if (softnic_parser_read_int32(&sp.pkt_length_adjust, tokens[10]) != 0) {
261                 snprintf(out, out_size, MSG_ARG_INVALID, "packet_length_adjust");
262                 return;
263         }
264
265         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
266         if (status)
267                 return;
268
269         status = rte_tm_shaper_profile_add(port_id, shaper_profile_id, &sp, &error);
270         if (status != 0) {
271                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
272                 return;
273         }
274 }
275
276 /**
277  * tmgr shared shaper
278  *  id <shared_shaper_id>
279  *  profile <shaper_profile_id>
280  */
281 static void
282 cmd_tmgr_shared_shaper(struct pmd_internals *softnic,
283         char **tokens,
284         uint32_t n_tokens,
285         char *out,
286         size_t out_size)
287 {
288         struct rte_tm_error error;
289         uint32_t shared_shaper_id, shaper_profile_id;
290         uint16_t port_id;
291         int status;
292
293         if (n_tokens != 7) {
294                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
295                 return;
296         }
297
298         if (strcmp(tokens[1], "shared") != 0) {
299                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared");
300                 return;
301         }
302
303         if (strcmp(tokens[2], "shaper") != 0) {
304                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper");
305                 return;
306         }
307
308         if (strcmp(tokens[3], "id") != 0) {
309                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id");
310                 return;
311         }
312
313         if (softnic_parser_read_uint32(&shared_shaper_id, tokens[4]) != 0) {
314                 snprintf(out, out_size, MSG_ARG_INVALID, "shared_shaper_id");
315                 return;
316         }
317
318         if (strcmp(tokens[5], "profile") != 0) {
319                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
320                 return;
321         }
322
323         if (softnic_parser_read_uint32(&shaper_profile_id, tokens[6]) != 0) {
324                 snprintf(out, out_size, MSG_ARG_INVALID, "shaper_profile_id");
325                 return;
326         }
327
328         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
329         if (status)
330                 return;
331
332         status = rte_tm_shared_shaper_add_update(port_id,
333                 shared_shaper_id,
334                 shaper_profile_id,
335                 &error);
336         if (status != 0) {
337                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
338                 return;
339         }
340 }
341
342 /**
343  * tmgr node
344  *   id <node_id>
345  *   parent <parent_node_id | none>
346  *   priority <priority>
347  *   weight <weight>
348  *   [shaper profile <shaper_profile_id>]
349  *   [shared shaper <shared_shaper_id>]
350  *   [nonleaf sp <n_sp_priorities>]
351  */
352 static void
353 cmd_tmgr_node(struct pmd_internals *softnic,
354         char **tokens,
355         uint32_t n_tokens,
356         char *out,
357         size_t out_size)
358 {
359         struct rte_tm_error error;
360         struct rte_tm_node_params np;
361         uint32_t node_id, parent_node_id, priority, weight, shared_shaper_id;
362         uint16_t port_id;
363         int status;
364
365         memset(&np, 0, sizeof(struct rte_tm_node_params));
366         np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
367         np.nonleaf.n_sp_priorities = 1;
368
369         if (n_tokens < 10) {
370                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
371                 return;
372         }
373
374         if (strcmp(tokens[1], "node") != 0) {
375                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "node");
376                 return;
377         }
378
379         if (strcmp(tokens[2], "id") != 0) {
380                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id");
381                 return;
382         }
383
384         if (softnic_parser_read_uint32(&node_id, tokens[3]) != 0) {
385                 snprintf(out, out_size, MSG_ARG_INVALID, "node_id");
386                 return;
387         }
388
389         if (strcmp(tokens[4], "parent") != 0) {
390                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "parent");
391                 return;
392         }
393
394         if (strcmp(tokens[5], "none") == 0)
395                 parent_node_id = RTE_TM_NODE_ID_NULL;
396         else {
397                 if (softnic_parser_read_uint32(&parent_node_id, tokens[5]) != 0) {
398                         snprintf(out, out_size, MSG_ARG_INVALID, "parent_node_id");
399                         return;
400                 }
401         }
402
403         if (strcmp(tokens[6], "priority") != 0) {
404                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
405                 return;
406         }
407
408         if (softnic_parser_read_uint32(&priority, tokens[7]) != 0) {
409                 snprintf(out, out_size, MSG_ARG_INVALID, "priority");
410                 return;
411         }
412
413         if (strcmp(tokens[8], "weight") != 0) {
414                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight");
415                 return;
416         }
417
418         if (softnic_parser_read_uint32(&weight, tokens[9]) != 0) {
419                 snprintf(out, out_size, MSG_ARG_INVALID, "weight");
420                 return;
421         }
422
423         tokens += 10;
424         n_tokens -= 10;
425
426         if (n_tokens >= 2 &&
427                 (strcmp(tokens[0], "shaper") == 0) &&
428                 (strcmp(tokens[1], "profile") == 0)) {
429                 if (n_tokens < 3) {
430                         snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node");
431                         return;
432                 }
433
434                 if (strcmp(tokens[2], "none") == 0) {
435                         np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
436                 } else {
437                         if (softnic_parser_read_uint32(&np.shaper_profile_id, tokens[2]) != 0) {
438                                 snprintf(out, out_size, MSG_ARG_INVALID, "shaper_profile_id");
439                                 return;
440                         }
441                 }
442
443                 tokens += 3;
444                 n_tokens -= 3;
445         } /* shaper profile */
446
447         if (n_tokens >= 2 &&
448                 (strcmp(tokens[0], "shared") == 0) &&
449                 (strcmp(tokens[1], "shaper") == 0)) {
450                 if (n_tokens < 3) {
451                         snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node");
452                         return;
453                 }
454
455                 if (softnic_parser_read_uint32(&shared_shaper_id, tokens[2]) != 0) {
456                         snprintf(out, out_size, MSG_ARG_INVALID, "shared_shaper_id");
457                         return;
458                 }
459
460                 np.shared_shaper_id = &shared_shaper_id;
461                 np.n_shared_shapers = 1;
462
463                 tokens += 3;
464                 n_tokens -= 3;
465         } /* shared shaper */
466
467         if (n_tokens >= 2 &&
468                 (strcmp(tokens[0], "nonleaf") == 0) &&
469                 (strcmp(tokens[1], "sp") == 0)) {
470                 if (n_tokens < 3) {
471                         snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node");
472                         return;
473                 }
474
475                 if (softnic_parser_read_uint32(&np.nonleaf.n_sp_priorities, tokens[2]) != 0) {
476                         snprintf(out, out_size, MSG_ARG_INVALID, "n_sp_priorities");
477                         return;
478                 }
479
480                 tokens += 3;
481                 n_tokens -= 3;
482         } /* nonleaf sp <n_sp_priorities> */
483
484         if (n_tokens) {
485                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
486                 return;
487         }
488
489         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
490         if (status != 0)
491                 return;
492
493         status = rte_tm_node_add(port_id,
494                 node_id,
495                 parent_node_id,
496                 priority,
497                 weight,
498                 RTE_TM_NODE_LEVEL_ID_ANY,
499                 &np,
500                 &error);
501         if (status != 0) {
502                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
503                 return;
504         }
505 }
506
507 static uint32_t
508 root_node_id(uint32_t n_spp,
509         uint32_t n_pps)
510 {
511         uint32_t n_queues = n_spp * n_pps * RTE_SCHED_QUEUES_PER_PIPE;
512         uint32_t n_tc = n_spp * n_pps * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
513         uint32_t n_pipes = n_spp * n_pps;
514
515         return n_queues + n_tc + n_pipes + n_spp;
516 }
517
518 static uint32_t
519 subport_node_id(uint32_t n_spp,
520         uint32_t n_pps,
521         uint32_t subport_id)
522 {
523         uint32_t n_pipes = n_spp * n_pps;
524         uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
525         uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE;
526
527         return n_queues + n_tc + n_pipes + subport_id;
528 }
529
530 static uint32_t
531 pipe_node_id(uint32_t n_spp,
532         uint32_t n_pps,
533         uint32_t subport_id,
534         uint32_t pipe_id)
535 {
536         uint32_t n_pipes = n_spp * n_pps;
537         uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
538         uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE;
539
540         return n_queues +
541                 n_tc +
542                 pipe_id +
543                 subport_id * n_pps;
544 }
545
546 static uint32_t
547 tc_node_id(uint32_t n_spp,
548         uint32_t n_pps,
549         uint32_t subport_id,
550         uint32_t pipe_id,
551         uint32_t tc_id)
552 {
553         uint32_t n_pipes = n_spp * n_pps;
554         uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE;
555
556         return n_queues +
557                 tc_id +
558                 (pipe_id + subport_id * n_pps) * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
559 }
560
561 static uint32_t
562 queue_node_id(uint32_t n_spp __rte_unused,
563         uint32_t n_pps,
564         uint32_t subport_id,
565         uint32_t pipe_id,
566         uint32_t tc_id,
567         uint32_t queue_id)
568 {
569         return queue_id +
570                 tc_id * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE +
571                 (pipe_id + subport_id * n_pps) * RTE_SCHED_QUEUES_PER_PIPE;
572 }
573
574 struct tmgr_hierarchy_default_params {
575         uint32_t n_spp; /**< Number of subports per port. */
576         uint32_t n_pps; /**< Number of pipes per subport. */
577
578         struct {
579                 uint32_t port;
580                 uint32_t subport;
581                 uint32_t pipe;
582                 uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
583         } shaper_profile_id;
584
585         struct {
586                 uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
587                 uint32_t tc_valid[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
588         } shared_shaper_id;
589
590         struct {
591                 uint32_t queue[RTE_SCHED_QUEUES_PER_PIPE];
592         } weight;
593 };
594
595 static int
596 tmgr_hierarchy_default(struct pmd_internals *softnic,
597         struct tmgr_hierarchy_default_params *params)
598 {
599         struct rte_tm_node_params root_node_params = {
600                 .shaper_profile_id = params->shaper_profile_id.port,
601                 .nonleaf = {
602                         .n_sp_priorities = 1,
603                 },
604         };
605
606         struct rte_tm_node_params subport_node_params = {
607                 .shaper_profile_id = params->shaper_profile_id.subport,
608                 .nonleaf = {
609                         .n_sp_priorities = 1,
610                 },
611         };
612
613         struct rte_tm_node_params pipe_node_params = {
614                 .shaper_profile_id = params->shaper_profile_id.pipe,
615                 .nonleaf = {
616                         .n_sp_priorities = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE,
617                 },
618         };
619
620         struct rte_tm_node_params tc_node_params[] = {
621                 [0] = {
622                         .shaper_profile_id = params->shaper_profile_id.tc[0],
623                         .shared_shaper_id = &params->shared_shaper_id.tc[0],
624                         .n_shared_shapers =
625                                 (&params->shared_shaper_id.tc_valid[0]) ? 1 : 0,
626                         .nonleaf = {
627                                 .n_sp_priorities = 1,
628                         },
629                 },
630
631                 [1] = {
632                         .shaper_profile_id = params->shaper_profile_id.tc[1],
633                         .shared_shaper_id = &params->shared_shaper_id.tc[1],
634                         .n_shared_shapers =
635                                 (&params->shared_shaper_id.tc_valid[1]) ? 1 : 0,
636                         .nonleaf = {
637                                 .n_sp_priorities = 1,
638                         },
639                 },
640
641                 [2] = {
642                         .shaper_profile_id = params->shaper_profile_id.tc[2],
643                         .shared_shaper_id = &params->shared_shaper_id.tc[2],
644                         .n_shared_shapers =
645                                 (&params->shared_shaper_id.tc_valid[2]) ? 1 : 0,
646                         .nonleaf = {
647                                 .n_sp_priorities = 1,
648                         },
649                 },
650
651                 [3] = {
652                         .shaper_profile_id = params->shaper_profile_id.tc[3],
653                         .shared_shaper_id = &params->shared_shaper_id.tc[3],
654                         .n_shared_shapers =
655                                 (&params->shared_shaper_id.tc_valid[3]) ? 1 : 0,
656                         .nonleaf = {
657                                 .n_sp_priorities = 1,
658                         },
659                 },
660         };
661
662         struct rte_tm_node_params queue_node_params = {
663                 .shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE,
664         };
665
666         struct rte_tm_error error;
667         uint32_t n_spp = params->n_spp, n_pps = params->n_pps, s;
668         int status;
669         uint16_t port_id;
670
671         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
672         if (status)
673                 return -1;
674
675         /* Hierarchy level 0: Root node */
676         status = rte_tm_node_add(port_id,
677                 root_node_id(n_spp, n_pps),
678                 RTE_TM_NODE_ID_NULL,
679                 0,
680                 1,
681                 RTE_TM_NODE_LEVEL_ID_ANY,
682                 &root_node_params,
683                 &error);
684         if (status)
685                 return -1;
686
687         /* Hierarchy level 1: Subport nodes */
688         for (s = 0; s < params->n_spp; s++) {
689                 uint32_t p;
690
691                 status = rte_tm_node_add(port_id,
692                         subport_node_id(n_spp, n_pps, s),
693                         root_node_id(n_spp, n_pps),
694                         0,
695                         1,
696                         RTE_TM_NODE_LEVEL_ID_ANY,
697                         &subport_node_params,
698                         &error);
699                 if (status)
700                         return -1;
701
702                 /* Hierarchy level 2: Pipe nodes */
703                 for (p = 0; p < params->n_pps; p++) {
704                         uint32_t t;
705
706                         status = rte_tm_node_add(port_id,
707                                 pipe_node_id(n_spp, n_pps, s, p),
708                                 subport_node_id(n_spp, n_pps, s),
709                                 0,
710                                 1,
711                                 RTE_TM_NODE_LEVEL_ID_ANY,
712                                 &pipe_node_params,
713                                 &error);
714                         if (status)
715                                 return -1;
716
717                         /* Hierarchy level 3: Traffic class nodes */
718                         for (t = 0; t < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; t++) {
719                                 uint32_t q;
720
721                                 status = rte_tm_node_add(port_id,
722                                         tc_node_id(n_spp, n_pps, s, p, t),
723                                         pipe_node_id(n_spp, n_pps, s, p),
724                                         t,
725                                         1,
726                                         RTE_TM_NODE_LEVEL_ID_ANY,
727                                         &tc_node_params[t],
728                                         &error);
729                                 if (status)
730                                         return -1;
731
732                                 /* Hierarchy level 4: Queue nodes */
733                                 for (q = 0; q < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; q++) {
734                                         status = rte_tm_node_add(port_id,
735                                                 queue_node_id(n_spp, n_pps, s, p, t, q),
736                                                 tc_node_id(n_spp, n_pps, s, p, t),
737                                                 0,
738                                                 params->weight.queue[q],
739                                                 RTE_TM_NODE_LEVEL_ID_ANY,
740                                                 &queue_node_params,
741                                                 &error);
742                                         if (status)
743                                                 return -1;
744                                 } /* Queue */
745                         } /* TC */
746                 } /* Pipe */
747         } /* Subport */
748
749         return 0;
750 }
751
752
753 /**
754  * tmgr hierarchy-default
755  *  spp <n_subports_per_port>
756  *  pps <n_pipes_per_subport>
757  *  shaper profile
758  *   port <profile_id>
759  *   subport <profile_id>
760  *   pipe <profile_id>
761  *   tc0 <profile_id>
762  *   tc1 <profile_id>
763  *   tc2 <profile_id>
764  *   tc3 <profile_id>
765  *  shared shaper
766  *   tc0 <id | none>
767  *   tc1 <id | none>
768  *   tc2 <id | none>
769  *   tc3 <id | none>
770  *  weight
771  *   queue  <q0> ... <q15>
772  */
773 static void
774 cmd_tmgr_hierarchy_default(struct pmd_internals *softnic,
775         char **tokens,
776         uint32_t n_tokens,
777         char *out,
778         size_t out_size)
779 {
780         struct tmgr_hierarchy_default_params p;
781         int i, status;
782
783         memset(&p, 0, sizeof(p));
784
785         if (n_tokens != 50) {
786                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
787                 return;
788         }
789
790         if (strcmp(tokens[1], "hierarchy-default") != 0) {
791                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy-default");
792                 return;
793         }
794
795         if (strcmp(tokens[2], "spp") != 0) {
796                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
797                 return;
798         }
799
800         if (softnic_parser_read_uint32(&p.n_spp, tokens[3]) != 0) {
801                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
802                 return;
803         }
804
805         if (strcmp(tokens[4], "pps") != 0) {
806                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
807                 return;
808         }
809
810         if (softnic_parser_read_uint32(&p.n_pps, tokens[5]) != 0) {
811                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
812                 return;
813         }
814
815         /* Shaper profile */
816
817         if (strcmp(tokens[6], "shaper") != 0) {
818                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper");
819                 return;
820         }
821
822         if (strcmp(tokens[7], "profile") != 0) {
823                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
824                 return;
825         }
826
827         if (strcmp(tokens[8], "port") != 0) {
828                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
829                 return;
830         }
831
832         if (softnic_parser_read_uint32(&p.shaper_profile_id.port, tokens[9]) != 0) {
833                 snprintf(out, out_size, MSG_ARG_INVALID, "port profile id");
834                 return;
835         }
836
837         if (strcmp(tokens[10], "subport") != 0) {
838                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "subport");
839                 return;
840         }
841
842         if (softnic_parser_read_uint32(&p.shaper_profile_id.subport, tokens[11]) != 0) {
843                 snprintf(out, out_size, MSG_ARG_INVALID, "subport profile id");
844                 return;
845         }
846
847         if (strcmp(tokens[12], "pipe") != 0) {
848                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
849                 return;
850         }
851
852         if (softnic_parser_read_uint32(&p.shaper_profile_id.pipe, tokens[13]) != 0) {
853                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
854                 return;
855         }
856
857         if (strcmp(tokens[14], "tc0") != 0) {
858                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0");
859                 return;
860         }
861
862         if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[0], tokens[15]) != 0) {
863                 snprintf(out, out_size, MSG_ARG_INVALID, "tc0 profile id");
864                 return;
865         }
866
867         if (strcmp(tokens[16], "tc1") != 0) {
868                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1");
869                 return;
870         }
871
872         if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[1], tokens[17]) != 0) {
873                 snprintf(out, out_size, MSG_ARG_INVALID, "tc1 profile id");
874                 return;
875         }
876
877         if (strcmp(tokens[18], "tc2") != 0) {
878                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2");
879                 return;
880         }
881
882         if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[2], tokens[19]) != 0) {
883                 snprintf(out, out_size, MSG_ARG_INVALID, "tc2 profile id");
884                 return;
885         }
886
887         if (strcmp(tokens[20], "tc3") != 0) {
888                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3");
889                 return;
890         }
891
892         if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[3], tokens[21]) != 0) {
893                 snprintf(out, out_size, MSG_ARG_INVALID, "tc3 profile id");
894                 return;
895         }
896
897         /* Shared shaper */
898
899         if (strcmp(tokens[22], "shared") != 0) {
900                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared");
901                 return;
902         }
903
904         if (strcmp(tokens[23], "shaper") != 0) {
905                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper");
906                 return;
907         }
908
909         if (strcmp(tokens[24], "tc0") != 0) {
910                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0");
911                 return;
912         }
913
914         if (strcmp(tokens[25], "none") == 0)
915                 p.shared_shaper_id.tc_valid[0] = 0;
916         else {
917                 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[0], tokens[25]) != 0) {
918                         snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc0");
919                         return;
920                 }
921
922                 p.shared_shaper_id.tc_valid[0] = 1;
923         }
924
925         if (strcmp(tokens[26], "tc1") != 0) {
926                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1");
927                 return;
928         }
929
930         if (strcmp(tokens[27], "none") == 0)
931                 p.shared_shaper_id.tc_valid[1] = 0;
932         else {
933                 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[1], tokens[27]) != 0) {
934                         snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc1");
935                         return;
936                 }
937
938                 p.shared_shaper_id.tc_valid[1] = 1;
939         }
940
941         if (strcmp(tokens[28], "tc2") != 0) {
942                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2");
943                 return;
944         }
945
946         if (strcmp(tokens[29], "none") == 0)
947                 p.shared_shaper_id.tc_valid[2] = 0;
948         else {
949                 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[2], tokens[29]) != 0) {
950                         snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc2");
951                         return;
952                 }
953
954                 p.shared_shaper_id.tc_valid[2] = 1;
955         }
956
957         if (strcmp(tokens[30], "tc3") != 0) {
958                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3");
959                 return;
960         }
961
962         if (strcmp(tokens[31], "none") == 0)
963                 p.shared_shaper_id.tc_valid[3] = 0;
964         else {
965                 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[3], tokens[31]) != 0) {
966                         snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc3");
967                         return;
968                 }
969
970                 p.shared_shaper_id.tc_valid[3] = 1;
971         }
972
973         /* Weight */
974
975         if (strcmp(tokens[32], "weight") != 0) {
976                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight");
977                 return;
978         }
979
980         if (strcmp(tokens[33], "queue") != 0) {
981                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queue");
982                 return;
983         }
984
985         for (i = 0; i < 16; i++) {
986                 if (softnic_parser_read_uint32(&p.weight.queue[i], tokens[34 + i]) != 0) {
987                         snprintf(out, out_size, MSG_ARG_INVALID, "weight queue");
988                         return;
989                 }
990         }
991
992         status = tmgr_hierarchy_default(softnic, &p);
993         if (status != 0) {
994                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
995                 return;
996         }
997 }
998
999 /**
1000  * tmgr hierarchy commit
1001  */
1002 static void
1003 cmd_tmgr_hierarchy_commit(struct pmd_internals *softnic,
1004         char **tokens,
1005         uint32_t n_tokens,
1006         char *out,
1007         size_t out_size)
1008 {
1009         struct rte_tm_error error;
1010         uint16_t port_id;
1011         int status;
1012
1013         if (n_tokens != 3) {
1014                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1015                 return;
1016         }
1017
1018         if (strcmp(tokens[1], "hierarchy") != 0) {
1019                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy");
1020                 return;
1021         }
1022
1023         if (strcmp(tokens[2], "commit") != 0) {
1024                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "commit");
1025                 return;
1026         }
1027
1028         status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
1029         if (status != 0)
1030                 return;
1031
1032         status = rte_tm_hierarchy_commit(port_id, 1, &error);
1033         if (status) {
1034                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1035                 return;
1036         }
1037 }
1038
1039 /**
1040  * tmgr <tmgr_name>
1041  */
1042 static void
1043 cmd_tmgr(struct pmd_internals *softnic,
1044         char **tokens,
1045         uint32_t n_tokens,
1046         char *out,
1047         size_t out_size)
1048 {
1049         char *name;
1050         struct softnic_tmgr_port *tmgr_port;
1051
1052         if (n_tokens != 2) {
1053                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1054                 return;
1055         }
1056
1057         name = tokens[1];
1058
1059         tmgr_port = softnic_tmgr_port_create(softnic, name);
1060         if (tmgr_port == NULL) {
1061                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1062                 return;
1063         }
1064 }
1065
1066 /**
1067  * tap <tap_name>
1068  */
1069 static void
1070 cmd_tap(struct pmd_internals *softnic,
1071         char **tokens,
1072         uint32_t n_tokens,
1073         char *out,
1074         size_t out_size)
1075 {
1076         char *name;
1077         struct softnic_tap *tap;
1078
1079         if (n_tokens != 2) {
1080                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1081                 return;
1082         }
1083
1084         name = tokens[1];
1085
1086         tap = softnic_tap_create(softnic, name);
1087         if (tap == NULL) {
1088                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1089                 return;
1090         }
1091 }
1092
1093 /**
1094  * cryptodev <tap_name> dev <device_name> | dev_id <device_id>
1095  * queue <n_queues> <queue_size> max_sessions <n_sessions>
1096  **/
1097
1098 static void
1099 cmd_cryptodev(struct pmd_internals *softnic,
1100                 char **tokens,
1101                 uint32_t n_tokens,
1102                 char *out,
1103                 size_t out_size)
1104 {
1105         struct softnic_cryptodev_params params;
1106         char *name;
1107
1108         memset(&params, 0, sizeof(params));
1109         if (n_tokens != 9) {
1110                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1111                 return;
1112         }
1113
1114         name = tokens[1];
1115
1116         if (strcmp(tokens[2], "dev") == 0)
1117                 params.dev_name = tokens[3];
1118         else if (strcmp(tokens[2], "dev_id") == 0) {
1119                 if (softnic_parser_read_uint32(&params.dev_id, tokens[3]) < 0) {
1120                         snprintf(out, out_size, MSG_ARG_INVALID,
1121                                 "dev_id");
1122                         return;
1123                 }
1124         } else {
1125                 snprintf(out, out_size, MSG_ARG_INVALID,
1126                         "cryptodev");
1127                 return;
1128         }
1129
1130         if (strcmp(tokens[4], "queue")) {
1131                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1132                         "4");
1133                 return;
1134         }
1135
1136         if (softnic_parser_read_uint32(&params.n_queues, tokens[5]) < 0) {
1137                 snprintf(out, out_size, MSG_ARG_INVALID,
1138                         "q");
1139                 return;
1140         }
1141
1142         if (softnic_parser_read_uint32(&params.queue_size, tokens[6]) < 0) {
1143                 snprintf(out, out_size, MSG_ARG_INVALID,
1144                         "queue_size");
1145                 return;
1146         }
1147
1148         if (strcmp(tokens[7], "max_sessions")) {
1149                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1150                         "4");
1151                 return;
1152         }
1153
1154         if (softnic_parser_read_uint32(&params.session_pool_size, tokens[8])
1155                         < 0) {
1156                 snprintf(out, out_size, MSG_ARG_INVALID,
1157                         "q");
1158                 return;
1159         }
1160
1161         if (softnic_cryptodev_create(softnic, name, &params) == NULL) {
1162                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1163                 return;
1164         }
1165 }
1166
1167 /**
1168  * port in action profile <profile_name>
1169  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
1170  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
1171  */
1172 static void
1173 cmd_port_in_action_profile(struct pmd_internals *softnic,
1174         char **tokens,
1175         uint32_t n_tokens,
1176         char *out,
1177         size_t out_size)
1178 {
1179         struct softnic_port_in_action_profile_params p;
1180         struct softnic_port_in_action_profile *ap;
1181         char *name;
1182         uint32_t t0;
1183
1184         memset(&p, 0, sizeof(p));
1185
1186         if (n_tokens < 5) {
1187                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1188                 return;
1189         }
1190
1191         if (strcmp(tokens[1], "in") != 0) {
1192                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1193                 return;
1194         }
1195
1196         if (strcmp(tokens[2], "action") != 0) {
1197                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
1198                 return;
1199         }
1200
1201         if (strcmp(tokens[3], "profile") != 0) {
1202                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1203                 return;
1204         }
1205
1206         name = tokens[4];
1207
1208         t0 = 5;
1209
1210         if (t0 < n_tokens &&
1211                 (strcmp(tokens[t0], "filter") == 0)) {
1212                 uint32_t size;
1213
1214                 if (n_tokens < t0 + 10) {
1215                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
1216                         return;
1217                 }
1218
1219                 if (strcmp(tokens[t0 + 1], "match") == 0) {
1220                         p.fltr.filter_on_match = 1;
1221                 } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) {
1222                         p.fltr.filter_on_match = 0;
1223                 } else {
1224                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
1225                         return;
1226                 }
1227
1228                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1229                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1230                         return;
1231                 }
1232
1233                 if (softnic_parser_read_uint32(&p.fltr.key_offset,
1234                         tokens[t0 + 3]) != 0) {
1235                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1236                         return;
1237                 }
1238
1239                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1240                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1241                         return;
1242                 }
1243
1244                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
1245                 if ((softnic_parse_hex_string(tokens[t0 + 5],
1246                         p.fltr.key_mask, &size) != 0) ||
1247                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
1248                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1249                         return;
1250                 }
1251
1252                 if (strcmp(tokens[t0 + 6], "key") != 0) {
1253                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1254                         return;
1255                 }
1256
1257                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
1258                 if ((softnic_parse_hex_string(tokens[t0 + 7],
1259                         p.fltr.key, &size) != 0) ||
1260                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
1261                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
1262                         return;
1263                 }
1264
1265                 if (strcmp(tokens[t0 + 8], "port") != 0) {
1266                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1267                         return;
1268                 }
1269
1270                 if (softnic_parser_read_uint32(&p.fltr.port_id,
1271                         tokens[t0 + 9]) != 0) {
1272                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1273                         return;
1274                 }
1275
1276                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
1277                 t0 += 10;
1278         } /* filter */
1279
1280         if (t0 < n_tokens &&
1281                 (strcmp(tokens[t0], "balance") == 0)) {
1282                 uint32_t i;
1283
1284                 if (n_tokens < t0 + 22) {
1285                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1286                                 "port in action profile balance");
1287                         return;
1288                 }
1289
1290                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1291                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1292                         return;
1293                 }
1294
1295                 if (softnic_parser_read_uint32(&p.lb.key_offset,
1296                         tokens[t0 + 2]) != 0) {
1297                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1298                         return;
1299                 }
1300
1301                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1302                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1303                         return;
1304                 }
1305
1306                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1307                 if (softnic_parse_hex_string(tokens[t0 + 4],
1308                         p.lb.key_mask, &p.lb.key_size) != 0) {
1309                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1310                         return;
1311                 }
1312
1313                 if (strcmp(tokens[t0 + 5], "port") != 0) {
1314                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1315                         return;
1316                 }
1317
1318                 for (i = 0; i < 16; i++)
1319                         if (softnic_parser_read_uint32(&p.lb.port_id[i],
1320                         tokens[t0 + 6 + i]) != 0) {
1321                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1322                                 return;
1323                         }
1324
1325                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
1326                 t0 += 22;
1327         } /* balance */
1328
1329         if (t0 < n_tokens) {
1330                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1331                 return;
1332         }
1333
1334         ap = softnic_port_in_action_profile_create(softnic, name, &p);
1335         if (ap == NULL) {
1336                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1337                 return;
1338         }
1339 }
1340
1341 /**
1342  * table action profile <profile_name>
1343  *  ipv4 | ipv6
1344  *  offset <ip_offset>
1345  *  fwd
1346  *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
1347  *  [meter srtcm | trtcm
1348  *      tc <n_tc>
1349  *      stats none | pkts | bytes | both]
1350  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
1351  *  [encap ether | vlan | qinq | mpls | pppoe |
1352  *      vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]
1353  *  [nat src | dst
1354  *      proto udp | tcp]
1355  *  [ttl drop | fwd
1356  *      stats none | pkts]
1357  *  [stats pkts | bytes | both]
1358  *  [time]
1359  *  [tag]
1360  *  [decap]
1361  *
1362  */
1363 static void
1364 cmd_table_action_profile(struct pmd_internals *softnic,
1365         char **tokens,
1366         uint32_t n_tokens,
1367         char *out,
1368         size_t out_size)
1369 {
1370         struct softnic_table_action_profile_params p;
1371         struct softnic_table_action_profile *ap;
1372         char *name;
1373         uint32_t t0;
1374
1375         memset(&p, 0, sizeof(p));
1376
1377         if (n_tokens < 8) {
1378                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1379                 return;
1380         }
1381
1382         if (strcmp(tokens[1], "action") != 0) {
1383                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
1384                 return;
1385         }
1386
1387         if (strcmp(tokens[2], "profile") != 0) {
1388                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1389                 return;
1390         }
1391
1392         name = tokens[3];
1393
1394         if (strcmp(tokens[4], "ipv4") == 0) {
1395                 p.common.ip_version = 1;
1396         } else if (strcmp(tokens[4], "ipv6") == 0) {
1397                 p.common.ip_version = 0;
1398         } else {
1399                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1400                 return;
1401         }
1402
1403         if (strcmp(tokens[5], "offset") != 0) {
1404                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1405                 return;
1406         }
1407
1408         if (softnic_parser_read_uint32(&p.common.ip_offset,
1409                 tokens[6]) != 0) {
1410                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1411                 return;
1412         }
1413
1414         if (strcmp(tokens[7], "fwd") != 0) {
1415                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1416                 return;
1417         }
1418
1419         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1420
1421         t0 = 8;
1422         if (t0 < n_tokens &&
1423                 (strcmp(tokens[t0], "balance") == 0)) {
1424                 if (n_tokens < t0 + 7) {
1425                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1426                         return;
1427                 }
1428
1429                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1430                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1431                         return;
1432                 }
1433
1434                 if (softnic_parser_read_uint32(&p.lb.key_offset,
1435                         tokens[t0 + 2]) != 0) {
1436                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1437                         return;
1438                 }
1439
1440                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1441                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1442                         return;
1443                 }
1444
1445                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1446                 if (softnic_parse_hex_string(tokens[t0 + 4],
1447                         p.lb.key_mask, &p.lb.key_size) != 0) {
1448                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1449                         return;
1450                 }
1451
1452                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1453                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1454                         return;
1455                 }
1456
1457                 if (softnic_parser_read_uint32(&p.lb.out_offset,
1458                         tokens[t0 + 6]) != 0) {
1459                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1460                         return;
1461                 }
1462
1463                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1464                 t0 += 7;
1465         } /* balance */
1466
1467         if (t0 < n_tokens &&
1468                 (strcmp(tokens[t0], "meter") == 0)) {
1469                 if (n_tokens < t0 + 6) {
1470                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1471                                 "table action profile meter");
1472                         return;
1473                 }
1474
1475                 if (strcmp(tokens[t0 + 1], "srtcm") == 0) {
1476                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1477                 } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) {
1478                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1479                 } else {
1480                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1481                                 "srtcm or trtcm");
1482                         return;
1483                 }
1484
1485                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
1486                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1487                         return;
1488                 }
1489
1490                 if (softnic_parser_read_uint32(&p.mtr.n_tc,
1491                         tokens[t0 + 3]) != 0) {
1492                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1493                         return;
1494                 }
1495
1496                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1497                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1498                         return;
1499                 }
1500
1501                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1502                         p.mtr.n_packets_enabled = 0;
1503                         p.mtr.n_bytes_enabled = 0;
1504                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1505                         p.mtr.n_packets_enabled = 1;
1506                         p.mtr.n_bytes_enabled = 0;
1507                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1508                         p.mtr.n_packets_enabled = 0;
1509                         p.mtr.n_bytes_enabled = 1;
1510                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1511                         p.mtr.n_packets_enabled = 1;
1512                         p.mtr.n_bytes_enabled = 1;
1513                 } else {
1514                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1515                                 "none or pkts or bytes or both");
1516                         return;
1517                 }
1518
1519                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1520                 t0 += 6;
1521         } /* meter */
1522
1523         if (t0 < n_tokens &&
1524                 (strcmp(tokens[t0], "tm") == 0)) {
1525                 if (n_tokens < t0 + 5) {
1526                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1527                                 "table action profile tm");
1528                         return;
1529                 }
1530
1531                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1532                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1533                         return;
1534                 }
1535
1536                 if (softnic_parser_read_uint32(&p.tm.n_subports_per_port,
1537                         tokens[t0 + 2]) != 0) {
1538                         snprintf(out, out_size, MSG_ARG_INVALID,
1539                                 "n_subports_per_port");
1540                         return;
1541                 }
1542
1543                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1544                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1545                         return;
1546                 }
1547
1548                 if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport,
1549                         tokens[t0 + 4]) != 0) {
1550                         snprintf(out, out_size, MSG_ARG_INVALID,
1551                                 "n_pipes_per_subport");
1552                         return;
1553                 }
1554
1555                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1556                 t0 += 5;
1557         } /* tm */
1558
1559         if (t0 < n_tokens &&
1560                 (strcmp(tokens[t0], "encap") == 0)) {
1561                 uint32_t n_extra_tokens = 0;
1562
1563                 if (n_tokens < t0 + 2) {
1564                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1565                                 "action profile encap");
1566                         return;
1567                 }
1568
1569                 if (strcmp(tokens[t0 + 1], "ether") == 0) {
1570                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1571                 } else if (strcmp(tokens[t0 + 1], "vlan") == 0) {
1572                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1573                 } else if (strcmp(tokens[t0 + 1], "qinq") == 0) {
1574                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1575                 } else if (strcmp(tokens[t0 + 1], "mpls") == 0) {
1576                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1577                 } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) {
1578                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1579                 } else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
1580                         if (n_tokens < t0 + 2 + 5) {
1581                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1582                                         "action profile encap vxlan");
1583                                 return;
1584                         }
1585
1586                         if (strcmp(tokens[t0 + 2], "offset") != 0) {
1587                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1588                                         "vxlan: offset");
1589                                 return;
1590                         }
1591
1592                         if (softnic_parser_read_uint32(&p.encap.vxlan.data_offset,
1593                                 tokens[t0 + 2 + 1]) != 0) {
1594                                 snprintf(out, out_size, MSG_ARG_INVALID,
1595                                         "vxlan: ether_offset");
1596                                 return;
1597                         }
1598
1599                         if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
1600                                 p.encap.vxlan.ip_version = 1;
1601                         else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
1602                                 p.encap.vxlan.ip_version = 0;
1603                         else {
1604                                 snprintf(out, out_size, MSG_ARG_INVALID,
1605                                         "vxlan: ipv4 or ipv6");
1606                                 return;
1607                         }
1608
1609                         if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
1610                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1611                                         "vxlan: vlan");
1612                                 return;
1613                         }
1614
1615                         if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
1616                                 p.encap.vxlan.vlan = 1;
1617                         else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
1618                                 p.encap.vxlan.vlan = 0;
1619                         else {
1620                                 snprintf(out, out_size, MSG_ARG_INVALID,
1621                                         "vxlan: on or off");
1622                                 return;
1623                         }
1624
1625                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
1626                         n_extra_tokens = 5;
1627
1628                 } else {
1629                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1630                         return;
1631                 }
1632                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1633                 t0 += 2 + n_extra_tokens;
1634         } /* encap */
1635
1636         if (t0 < n_tokens &&
1637                 (strcmp(tokens[t0], "nat") == 0)) {
1638                 if (n_tokens < t0 + 4) {
1639                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1640                                 "table action profile nat");
1641                         return;
1642                 }
1643
1644                 if (strcmp(tokens[t0 + 1], "src") == 0) {
1645                         p.nat.source_nat = 1;
1646                 } else if (strcmp(tokens[t0 + 1], "dst") == 0) {
1647                         p.nat.source_nat = 0;
1648                 } else {
1649                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1650                                 "src or dst");
1651                         return;
1652                 }
1653
1654                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1655                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1656                         return;
1657                 }
1658
1659                 if (strcmp(tokens[t0 + 3], "tcp") == 0) {
1660                         p.nat.proto = 0x06;
1661                 } else if (strcmp(tokens[t0 + 3], "udp") == 0) {
1662                         p.nat.proto = 0x11;
1663                 } else {
1664                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1665                                 "tcp or udp");
1666                         return;
1667                 }
1668
1669                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1670                 t0 += 4;
1671         } /* nat */
1672
1673         if (t0 < n_tokens &&
1674                 (strcmp(tokens[t0], "ttl") == 0)) {
1675                 if (n_tokens < t0 + 4) {
1676                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1677                                 "table action profile ttl");
1678                         return;
1679                 }
1680
1681                 if (strcmp(tokens[t0 + 1], "drop") == 0) {
1682                         p.ttl.drop = 1;
1683                 } else if (strcmp(tokens[t0 + 1], "fwd") == 0) {
1684                         p.ttl.drop = 0;
1685                 } else {
1686                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1687                                 "drop or fwd");
1688                         return;
1689                 }
1690
1691                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1692                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1693                         return;
1694                 }
1695
1696                 if (strcmp(tokens[t0 + 3], "none") == 0) {
1697                         p.ttl.n_packets_enabled = 0;
1698                 } else if (strcmp(tokens[t0 + 3], "pkts") == 0) {
1699                         p.ttl.n_packets_enabled = 1;
1700                 } else {
1701                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1702                                 "none or pkts");
1703                         return;
1704                 }
1705
1706                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1707                 t0 += 4;
1708         } /* ttl */
1709
1710         if (t0 < n_tokens &&
1711                 (strcmp(tokens[t0], "stats") == 0)) {
1712                 if (n_tokens < t0 + 2) {
1713                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1714                                 "table action profile stats");
1715                         return;
1716                 }
1717
1718                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1719                         p.stats.n_packets_enabled = 1;
1720                         p.stats.n_bytes_enabled = 0;
1721                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1722                         p.stats.n_packets_enabled = 0;
1723                         p.stats.n_bytes_enabled = 1;
1724                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1725                         p.stats.n_packets_enabled = 1;
1726                         p.stats.n_bytes_enabled = 1;
1727                 } else {
1728                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1729                                 "pkts or bytes or both");
1730                         return;
1731                 }
1732
1733                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1734                 t0 += 2;
1735         } /* stats */
1736
1737         if (t0 < n_tokens &&
1738                 (strcmp(tokens[t0], "time") == 0)) {
1739                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1740                 t0 += 1;
1741         } /* time */
1742
1743         if (t0 < n_tokens &&
1744                 (strcmp(tokens[t0], "tag") == 0)) {
1745                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG;
1746                 t0 += 1;
1747         } /* tag */
1748
1749         if (t0 < n_tokens &&
1750                 (strcmp(tokens[t0], "decap") == 0)) {
1751                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP;
1752                 t0 += 1;
1753         } /* decap */
1754
1755         if (t0 < n_tokens && (strcmp(tokens[t0], "sym_crypto") == 0)) {
1756                 struct softnic_cryptodev *cryptodev;
1757
1758                 if (n_tokens < t0 + 5 ||
1759                                 strcmp(tokens[t0 + 1], "dev") ||
1760                                 strcmp(tokens[t0 + 3], "offset")) {
1761                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1762                                 "table action profile sym_crypto");
1763                         return;
1764                 }
1765
1766                 cryptodev = softnic_cryptodev_find(softnic, tokens[t0 + 2]);
1767                 if (cryptodev == NULL) {
1768                         snprintf(out, out_size, MSG_ARG_INVALID,
1769                                 "table action profile sym_crypto");
1770                         return;
1771                 }
1772
1773                 p.sym_crypto.cryptodev_id = cryptodev->dev_id;
1774
1775                 if (softnic_parser_read_uint32(&p.sym_crypto.op_offset,
1776                                 tokens[t0 + 4]) != 0) {
1777                         snprintf(out, out_size, MSG_ARG_INVALID,
1778                                         "table action profile sym_crypto");
1779                         return;
1780                 }
1781
1782                 p.sym_crypto.mp_create = cryptodev->mp_create;
1783                 p.sym_crypto.mp_init = cryptodev->mp_init;
1784
1785                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO;
1786
1787                 t0 += 5;
1788         } /* sym_crypto */
1789
1790         if (t0 < n_tokens) {
1791                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1792                 return;
1793         }
1794
1795         ap = softnic_table_action_profile_create(softnic, name, &p);
1796         if (ap == NULL) {
1797                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1798                 return;
1799         }
1800 }
1801
1802 /**
1803  * pipeline <pipeline_name>
1804  *  period <timer_period_ms>
1805  *  offset_port_id <offset_port_id>
1806  */
1807 static void
1808 cmd_pipeline(struct pmd_internals *softnic,
1809         char **tokens,
1810         uint32_t n_tokens,
1811         char *out,
1812         size_t out_size)
1813 {
1814         struct pipeline_params p;
1815         char *name;
1816         struct pipeline *pipeline;
1817
1818         if (n_tokens != 6) {
1819                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1820                 return;
1821         }
1822
1823         name = tokens[1];
1824
1825         if (strcmp(tokens[2], "period") != 0) {
1826                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1827                 return;
1828         }
1829
1830         if (softnic_parser_read_uint32(&p.timer_period_ms,
1831                 tokens[3]) != 0) {
1832                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1833                 return;
1834         }
1835
1836         if (strcmp(tokens[4], "offset_port_id") != 0) {
1837                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1838                 return;
1839         }
1840
1841         if (softnic_parser_read_uint32(&p.offset_port_id,
1842                 tokens[5]) != 0) {
1843                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1844                 return;
1845         }
1846
1847         pipeline = softnic_pipeline_create(softnic, name, &p);
1848         if (pipeline == NULL) {
1849                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1850                 return;
1851         }
1852 }
1853
1854 /**
1855  * pipeline <pipeline_name> port in
1856  *  bsz <burst_size>
1857  *  link <link_name> rxq <queue_id>
1858  *  | swq <swq_name>
1859  *  | tmgr <tmgr_name>
1860  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
1861  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
1862  *  | cryptodev <cryptodev_name> rxq <queue_id>
1863  *  [action <port_in_action_profile_name>]
1864  *  [disabled]
1865  */
1866 static void
1867 cmd_pipeline_port_in(struct pmd_internals *softnic,
1868         char **tokens,
1869         uint32_t n_tokens,
1870         char *out,
1871         size_t out_size)
1872 {
1873         struct softnic_port_in_params p;
1874         char *pipeline_name;
1875         uint32_t t0;
1876         int enabled, status;
1877
1878         memset(&p, 0, sizeof(p));
1879
1880         if (n_tokens < 7) {
1881                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1882                 return;
1883         }
1884
1885         pipeline_name = tokens[1];
1886
1887         if (strcmp(tokens[2], "port") != 0) {
1888                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1889                 return;
1890         }
1891
1892         if (strcmp(tokens[3], "in") != 0) {
1893                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1894                 return;
1895         }
1896
1897         if (strcmp(tokens[4], "bsz") != 0) {
1898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1899                 return;
1900         }
1901
1902         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1903                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1904                 return;
1905         }
1906
1907         t0 = 6;
1908
1909         if (strcmp(tokens[t0], "link") == 0) {
1910                 if (n_tokens < t0 + 4) {
1911                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1912                                 "pipeline port in link");
1913                         return;
1914                 }
1915
1916                 p.type = PORT_IN_RXQ;
1917
1918                 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name));
1919
1920                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1921                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1922                         return;
1923                 }
1924
1925                 if (softnic_parser_read_uint16(&p.rxq.queue_id,
1926                         tokens[t0 + 3]) != 0) {
1927                         snprintf(out, out_size, MSG_ARG_INVALID,
1928                                 "queue_id");
1929                         return;
1930                 }
1931                 t0 += 4;
1932         } else if (strcmp(tokens[t0], "swq") == 0) {
1933                 if (n_tokens < t0 + 2) {
1934                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1935                                 "pipeline port in swq");
1936                         return;
1937                 }
1938
1939                 p.type = PORT_IN_SWQ;
1940
1941                 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name));
1942
1943                 t0 += 2;
1944         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1945                 if (n_tokens < t0 + 2) {
1946                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1947                                 "pipeline port in tmgr");
1948                         return;
1949                 }
1950
1951                 p.type = PORT_IN_TMGR;
1952
1953                 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name));
1954
1955                 t0 += 2;
1956         } else if (strcmp(tokens[t0], "tap") == 0) {
1957                 if (n_tokens < t0 + 6) {
1958                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1959                                 "pipeline port in tap");
1960                         return;
1961                 }
1962
1963                 p.type = PORT_IN_TAP;
1964
1965                 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name));
1966
1967                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1968                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1969                                 "mempool");
1970                         return;
1971                 }
1972
1973                 p.tap.mempool_name = tokens[t0 + 3];
1974
1975                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1976                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1977                                 "mtu");
1978                         return;
1979                 }
1980
1981                 if (softnic_parser_read_uint32(&p.tap.mtu,
1982                         tokens[t0 + 5]) != 0) {
1983                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1984                         return;
1985                 }
1986
1987                 t0 += 6;
1988         } else if (strcmp(tokens[t0], "source") == 0) {
1989                 if (n_tokens < t0 + 6) {
1990                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1991                                 "pipeline port in source");
1992                         return;
1993                 }
1994
1995                 p.type = PORT_IN_SOURCE;
1996
1997                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1998                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1999                                 "mempool");
2000                         return;
2001                 }
2002
2003                 p.source.mempool_name = tokens[t0 + 2];
2004
2005                 if (strcmp(tokens[t0 + 3], "file") != 0) {
2006                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2007                                 "file");
2008                         return;
2009                 }
2010
2011                 p.source.file_name = tokens[t0 + 4];
2012
2013                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
2014                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2015                                 "bpp");
2016                         return;
2017                 }
2018
2019                 if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt,
2020                         tokens[t0 + 6]) != 0) {
2021                         snprintf(out, out_size, MSG_ARG_INVALID,
2022                                 "n_bytes_per_pkt");
2023                         return;
2024                 }
2025
2026                 t0 += 7;
2027         } else if (strcmp(tokens[t0], "cryptodev") == 0) {
2028                 if (n_tokens < t0 + 3) {
2029                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2030                                 "pipeline port in cryptodev");
2031                         return;
2032                 }
2033
2034                 p.type = PORT_IN_CRYPTODEV;
2035
2036                 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name));
2037                 if (softnic_parser_read_uint16(&p.rxq.queue_id,
2038                                 tokens[t0 + 3]) != 0) {
2039                         snprintf(out, out_size, MSG_ARG_INVALID,
2040                                 "rxq");
2041                         return;
2042                 }
2043
2044                 p.cryptodev.arg_callback = NULL;
2045                 p.cryptodev.f_callback = NULL;
2046
2047                 t0 += 4;
2048         } else {
2049                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2050                 return;
2051         }
2052
2053         if (n_tokens > t0 &&
2054                 (strcmp(tokens[t0], "action") == 0)) {
2055                 if (n_tokens < t0 + 2) {
2056                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2057                         return;
2058                 }
2059
2060                 strlcpy(p.action_profile_name, tokens[t0 + 1],
2061                         sizeof(p.action_profile_name));
2062
2063                 t0 += 2;
2064         }
2065
2066         enabled = 1;
2067         if (n_tokens > t0 &&
2068                 (strcmp(tokens[t0], "disabled") == 0)) {
2069                 enabled = 0;
2070
2071                 t0 += 1;
2072         }
2073
2074         if (n_tokens != t0) {
2075                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2076                 return;
2077         }
2078
2079         status = softnic_pipeline_port_in_create(softnic,
2080                 pipeline_name,
2081                 &p,
2082                 enabled);
2083         if (status) {
2084                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2085                 return;
2086         }
2087 }
2088
2089 /**
2090  * pipeline <pipeline_name> port out
2091  *  bsz <burst_size>
2092  *  link <link_name> txq <txq_id>
2093  *  | swq <swq_name>
2094  *  | tmgr <tmgr_name>
2095  *  | tap <tap_name>
2096  *  | sink [file <file_name> pkts <max_n_pkts>]
2097  *  | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset>
2098  */
2099 static void
2100 cmd_pipeline_port_out(struct pmd_internals *softnic,
2101         char **tokens,
2102         uint32_t n_tokens,
2103         char *out,
2104         size_t out_size)
2105 {
2106         struct softnic_port_out_params p;
2107         char *pipeline_name;
2108         int status;
2109
2110         memset(&p, 0, sizeof(p));
2111
2112         if (n_tokens < 7) {
2113                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2114                 return;
2115         }
2116
2117         pipeline_name = tokens[1];
2118
2119         if (strcmp(tokens[2], "port") != 0) {
2120                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2121                 return;
2122         }
2123
2124         if (strcmp(tokens[3], "out") != 0) {
2125                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2126                 return;
2127         }
2128
2129         if (strcmp(tokens[4], "bsz") != 0) {
2130                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
2131                 return;
2132         }
2133
2134         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
2135                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
2136                 return;
2137         }
2138
2139         if (strcmp(tokens[6], "link") == 0) {
2140                 if (n_tokens != 10) {
2141                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2142                                 "pipeline port out link");
2143                         return;
2144                 }
2145
2146                 p.type = PORT_OUT_TXQ;
2147
2148                 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name));
2149
2150                 if (strcmp(tokens[8], "txq") != 0) {
2151                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
2152                         return;
2153                 }
2154
2155                 if (softnic_parser_read_uint16(&p.txq.queue_id,
2156                         tokens[9]) != 0) {
2157                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
2158                         return;
2159                 }
2160         } else if (strcmp(tokens[6], "swq") == 0) {
2161                 if (n_tokens != 8) {
2162                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2163                                 "pipeline port out swq");
2164                         return;
2165                 }
2166
2167                 p.type = PORT_OUT_SWQ;
2168
2169                 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name));
2170         } else if (strcmp(tokens[6], "tmgr") == 0) {
2171                 if (n_tokens != 8) {
2172                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2173                                 "pipeline port out tmgr");
2174                         return;
2175                 }
2176
2177                 p.type = PORT_OUT_TMGR;
2178
2179                 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name));
2180         } else if (strcmp(tokens[6], "tap") == 0) {
2181                 if (n_tokens != 8) {
2182                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2183                                 "pipeline port out tap");
2184                         return;
2185                 }
2186
2187                 p.type = PORT_OUT_TAP;
2188
2189                 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name));
2190         } else if (strcmp(tokens[6], "sink") == 0) {
2191                 if ((n_tokens != 7) && (n_tokens != 11)) {
2192                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2193                                 "pipeline port out sink");
2194                         return;
2195                 }
2196
2197                 p.type = PORT_OUT_SINK;
2198
2199                 if (n_tokens == 7) {
2200                         p.sink.file_name = NULL;
2201                         p.sink.max_n_pkts = 0;
2202                 } else {
2203                         if (strcmp(tokens[7], "file") != 0) {
2204                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2205                                         "file");
2206                                 return;
2207                         }
2208
2209                         p.sink.file_name = tokens[8];
2210
2211                         if (strcmp(tokens[9], "pkts") != 0) {
2212                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
2213                                 return;
2214                         }
2215
2216                         if (softnic_parser_read_uint32(&p.sink.max_n_pkts,
2217                                 tokens[10]) != 0) {
2218                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
2219                                 return;
2220                         }
2221                 }
2222         } else if (strcmp(tokens[6], "cryptodev") == 0) {
2223                 if (n_tokens != 12) {
2224                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2225                                 "pipeline port out cryptodev");
2226                         return;
2227                 }
2228
2229                 p.type = PORT_OUT_CRYPTODEV;
2230
2231                 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name));
2232
2233                 if (strcmp(tokens[8], "txq")) {
2234                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2235                                 "pipeline port out cryptodev");
2236                         return;
2237                 }
2238
2239                 if (softnic_parser_read_uint16(&p.cryptodev.queue_id, tokens[9])
2240                                 != 0) {
2241                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
2242                         return;
2243                 }
2244
2245                 if (strcmp(tokens[10], "offset")) {
2246                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2247                                 "pipeline port out cryptodev");
2248                         return;
2249                 }
2250
2251                 if (softnic_parser_read_uint32(&p.cryptodev.op_offset,
2252                                 tokens[11]) != 0) {
2253                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
2254                         return;
2255                 }
2256         } else {
2257                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2258                 return;
2259         }
2260
2261         status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p);
2262         if (status) {
2263                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2264                 return;
2265         }
2266 }
2267
2268 /**
2269  * pipeline <pipeline_name> table
2270  *      match
2271  *      acl
2272  *          ipv4 | ipv6
2273  *          offset <ip_header_offset>
2274  *          size <n_rules>
2275  *      | array
2276  *          offset <key_offset>
2277  *          size <n_keys>
2278  *      | hash
2279  *          ext | lru
2280  *          key <key_size>
2281  *          mask <key_mask>
2282  *          offset <key_offset>
2283  *          buckets <n_buckets>
2284  *          size <n_keys>
2285  *      | lpm
2286  *          ipv4 | ipv6
2287  *          offset <ip_header_offset>
2288  *          size <n_rules>
2289  *      | stub
2290  *  [action <table_action_profile_name>]
2291  */
2292 static void
2293 cmd_pipeline_table(struct pmd_internals *softnic,
2294         char **tokens,
2295         uint32_t n_tokens,
2296         char *out,
2297         size_t out_size)
2298 {
2299         struct softnic_table_params p;
2300         char *pipeline_name;
2301         uint32_t t0;
2302         int status;
2303
2304         memset(&p, 0, sizeof(p));
2305
2306         if (n_tokens < 5) {
2307                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2308                 return;
2309         }
2310
2311         pipeline_name = tokens[1];
2312
2313         if (strcmp(tokens[2], "table") != 0) {
2314                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2315                 return;
2316         }
2317
2318         if (strcmp(tokens[3], "match") != 0) {
2319                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2320                 return;
2321         }
2322
2323         t0 = 4;
2324         if (strcmp(tokens[t0], "acl") == 0) {
2325                 if (n_tokens < t0 + 6) {
2326                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2327                                 "pipeline table acl");
2328                         return;
2329                 }
2330
2331                 p.match_type = TABLE_ACL;
2332
2333                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
2334                         p.match.acl.ip_version = 1;
2335                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
2336                         p.match.acl.ip_version = 0;
2337                 } else {
2338                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2339                                 "ipv4 or ipv6");
2340                         return;
2341                 }
2342
2343                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2344                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2345                         return;
2346                 }
2347
2348                 if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset,
2349                         tokens[t0 + 3]) != 0) {
2350                         snprintf(out, out_size, MSG_ARG_INVALID,
2351                                 "ip_header_offset");
2352                         return;
2353                 }
2354
2355                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2356                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2357                         return;
2358                 }
2359
2360                 if (softnic_parser_read_uint32(&p.match.acl.n_rules,
2361                         tokens[t0 + 5]) != 0) {
2362                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2363                         return;
2364                 }
2365
2366                 t0 += 6;
2367         } else if (strcmp(tokens[t0], "array") == 0) {
2368                 if (n_tokens < t0 + 5) {
2369                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2370                                 "pipeline table array");
2371                         return;
2372                 }
2373
2374                 p.match_type = TABLE_ARRAY;
2375
2376                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
2377                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2378                         return;
2379                 }
2380
2381                 if (softnic_parser_read_uint32(&p.match.array.key_offset,
2382                         tokens[t0 + 2]) != 0) {
2383                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2384                         return;
2385                 }
2386
2387                 if (strcmp(tokens[t0 + 3], "size") != 0) {
2388                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2389                         return;
2390                 }
2391
2392                 if (softnic_parser_read_uint32(&p.match.array.n_keys,
2393                         tokens[t0 + 4]) != 0) {
2394                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2395                         return;
2396                 }
2397
2398                 t0 += 5;
2399         } else if (strcmp(tokens[t0], "hash") == 0) {
2400                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
2401
2402                 if (n_tokens < t0 + 12) {
2403                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2404                                 "pipeline table hash");
2405                         return;
2406                 }
2407
2408                 p.match_type = TABLE_HASH;
2409
2410                 if (strcmp(tokens[t0 + 1], "ext") == 0) {
2411                         p.match.hash.extendable_bucket = 1;
2412                 } else if (strcmp(tokens[t0 + 1], "lru") == 0) {
2413                         p.match.hash.extendable_bucket = 0;
2414                 } else {
2415                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2416                                 "ext or lru");
2417                         return;
2418                 }
2419
2420                 if (strcmp(tokens[t0 + 2], "key") != 0) {
2421                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
2422                         return;
2423                 }
2424
2425                 if ((softnic_parser_read_uint32(&p.match.hash.key_size,
2426                         tokens[t0 + 3]) != 0) ||
2427                         p.match.hash.key_size == 0 ||
2428                         p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) {
2429                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
2430                         return;
2431                 }
2432
2433                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
2434                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
2435                         return;
2436                 }
2437
2438                 if ((softnic_parse_hex_string(tokens[t0 + 5],
2439                         p.match.hash.key_mask, &key_mask_size) != 0) ||
2440                         key_mask_size != p.match.hash.key_size) {
2441                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
2442                         return;
2443                 }
2444
2445                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
2446                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2447                         return;
2448                 }
2449
2450                 if (softnic_parser_read_uint32(&p.match.hash.key_offset,
2451                         tokens[t0 + 7]) != 0) {
2452                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2453                         return;
2454                 }
2455
2456                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
2457                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
2458                         return;
2459                 }
2460
2461                 if (softnic_parser_read_uint32(&p.match.hash.n_buckets,
2462                         tokens[t0 + 9]) != 0) {
2463                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
2464                         return;
2465                 }
2466
2467                 if (strcmp(tokens[t0 + 10], "size") != 0) {
2468                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2469                         return;
2470                 }
2471
2472                 if (softnic_parser_read_uint32(&p.match.hash.n_keys,
2473                         tokens[t0 + 11]) != 0) {
2474                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2475                         return;
2476                 }
2477
2478                 t0 += 12;
2479         } else if (strcmp(tokens[t0], "lpm") == 0) {
2480                 if (n_tokens < t0 + 6) {
2481                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2482                                 "pipeline table lpm");
2483                         return;
2484                 }
2485
2486                 p.match_type = TABLE_LPM;
2487
2488                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
2489                         p.match.lpm.key_size = 4;
2490                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
2491                         p.match.lpm.key_size = 16;
2492                 } else {
2493                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2494                                 "ipv4 or ipv6");
2495                         return;
2496                 }
2497
2498                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2499                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2500                         return;
2501                 }
2502
2503                 if (softnic_parser_read_uint32(&p.match.lpm.key_offset,
2504                         tokens[t0 + 3]) != 0) {
2505                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2506                         return;
2507                 }
2508
2509                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2510                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2511                         return;
2512                 }
2513
2514                 if (softnic_parser_read_uint32(&p.match.lpm.n_rules,
2515                         tokens[t0 + 5]) != 0) {
2516                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2517                         return;
2518                 }
2519
2520                 t0 += 6;
2521         } else if (strcmp(tokens[t0], "stub") == 0) {
2522                 p.match_type = TABLE_STUB;
2523
2524                 t0 += 1;
2525         } else {
2526                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2527                 return;
2528         }
2529
2530         if (n_tokens > t0 &&
2531                 (strcmp(tokens[t0], "action") == 0)) {
2532                 if (n_tokens < t0 + 2) {
2533                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2534                         return;
2535                 }
2536
2537                 strlcpy(p.action_profile_name, tokens[t0 + 1],
2538                         sizeof(p.action_profile_name));
2539
2540                 t0 += 2;
2541         }
2542
2543         if (n_tokens > t0) {
2544                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2545                 return;
2546         }
2547
2548         status = softnic_pipeline_table_create(softnic, pipeline_name, &p);
2549         if (status) {
2550                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2551                 return;
2552         }
2553 }
2554
2555 /**
2556  * pipeline <pipeline_name> port in <port_id> table <table_id>
2557  */
2558 static void
2559 cmd_pipeline_port_in_table(struct pmd_internals *softnic,
2560         char **tokens,
2561         uint32_t n_tokens,
2562         char *out,
2563         size_t out_size)
2564 {
2565         char *pipeline_name;
2566         uint32_t port_id, table_id;
2567         int status;
2568
2569         if (n_tokens != 7) {
2570                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2571                 return;
2572         }
2573
2574         pipeline_name = tokens[1];
2575
2576         if (strcmp(tokens[2], "port") != 0) {
2577                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2578                 return;
2579         }
2580
2581         if (strcmp(tokens[3], "in") != 0) {
2582                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2583                 return;
2584         }
2585
2586         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
2587                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2588                 return;
2589         }
2590
2591         if (strcmp(tokens[5], "table") != 0) {
2592                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2593                 return;
2594         }
2595
2596         if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) {
2597                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2598                 return;
2599         }
2600
2601         status = softnic_pipeline_port_in_connect_to_table(softnic,
2602                 pipeline_name,
2603                 port_id,
2604                 table_id);
2605         if (status) {
2606                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2607                 return;
2608         }
2609 }
2610
2611 /**
2612  * pipeline <pipeline_name> port in <port_id> stats read [clear]
2613  */
2614
2615 #define MSG_PIPELINE_PORT_IN_STATS                         \
2616         "Pkts in: %" PRIu64 "\n"                           \
2617         "Pkts dropped by AH: %" PRIu64 "\n"                \
2618         "Pkts dropped by other: %" PRIu64 "\n"
2619
2620 static void
2621 cmd_pipeline_port_in_stats(struct pmd_internals *softnic,
2622         char **tokens,
2623         uint32_t n_tokens,
2624         char *out,
2625         size_t out_size)
2626 {
2627         struct rte_pipeline_port_in_stats stats;
2628         char *pipeline_name;
2629         uint32_t port_id;
2630         int clear, status;
2631
2632         if (n_tokens != 7 &&
2633                 n_tokens != 8) {
2634                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2635                 return;
2636         }
2637
2638         pipeline_name = tokens[1];
2639
2640         if (strcmp(tokens[2], "port") != 0) {
2641                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2642                 return;
2643         }
2644
2645         if (strcmp(tokens[3], "in") != 0) {
2646                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2647                 return;
2648         }
2649
2650         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
2651                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2652                 return;
2653         }
2654
2655         if (strcmp(tokens[5], "stats") != 0) {
2656                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2657                 return;
2658         }
2659
2660         if (strcmp(tokens[6], "read") != 0) {
2661                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2662                 return;
2663         }
2664
2665         clear = 0;
2666         if (n_tokens == 8) {
2667                 if (strcmp(tokens[7], "clear") != 0) {
2668                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2669                         return;
2670                 }
2671
2672                 clear = 1;
2673         }
2674
2675         status = softnic_pipeline_port_in_stats_read(softnic,
2676                 pipeline_name,
2677                 port_id,
2678                 &stats,
2679                 clear);
2680         if (status) {
2681                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2682                 return;
2683         }
2684
2685         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2686                 stats.stats.n_pkts_in,
2687                 stats.n_pkts_dropped_by_ah,
2688                 stats.stats.n_pkts_drop);
2689 }
2690
2691 /**
2692  * pipeline <pipeline_name> port in <port_id> enable
2693  */
2694 static void
2695 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
2696         char **tokens,
2697         uint32_t n_tokens,
2698         char *out,
2699         size_t out_size)
2700 {
2701         char *pipeline_name;
2702         uint32_t port_id;
2703         int status;
2704
2705         if (n_tokens != 6) {
2706                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2707                 return;
2708         }
2709
2710         pipeline_name = tokens[1];
2711
2712         if (strcmp(tokens[2], "port") != 0) {
2713                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2714                 return;
2715         }
2716
2717         if (strcmp(tokens[3], "in") != 0) {
2718                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2719                 return;
2720         }
2721
2722         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
2723                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2724                 return;
2725         }
2726
2727         if (strcmp(tokens[5], "enable") != 0) {
2728                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2729                 return;
2730         }
2731
2732         status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id);
2733         if (status) {
2734                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2735                 return;
2736         }
2737 }
2738
2739 /**
2740  * pipeline <pipeline_name> port in <port_id> disable
2741  */
2742 static void
2743 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
2744         char **tokens,
2745         uint32_t n_tokens,
2746         char *out,
2747         size_t out_size)
2748 {
2749         char *pipeline_name;
2750         uint32_t port_id;
2751         int status;
2752
2753         if (n_tokens != 6) {
2754                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2755                 return;
2756         }
2757
2758         pipeline_name = tokens[1];
2759
2760         if (strcmp(tokens[2], "port") != 0) {
2761                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2762                 return;
2763         }
2764
2765         if (strcmp(tokens[3], "in") != 0) {
2766                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2767                 return;
2768         }
2769
2770         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
2771                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2772                 return;
2773         }
2774
2775         if (strcmp(tokens[5], "disable") != 0) {
2776                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2777                 return;
2778         }
2779
2780         status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id);
2781         if (status) {
2782                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2783                 return;
2784         }
2785 }
2786
2787 /**
2788  * pipeline <pipeline_name> port out <port_id> stats read [clear]
2789  */
2790 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2791         "Pkts in: %" PRIu64 "\n"                           \
2792         "Pkts dropped by AH: %" PRIu64 "\n"                \
2793         "Pkts dropped by other: %" PRIu64 "\n"
2794
2795 static void
2796 cmd_pipeline_port_out_stats(struct pmd_internals *softnic,
2797         char **tokens,
2798         uint32_t n_tokens,
2799         char *out,
2800         size_t out_size)
2801 {
2802         struct rte_pipeline_port_out_stats stats;
2803         char *pipeline_name;
2804         uint32_t port_id;
2805         int clear, status;
2806
2807         if (n_tokens != 7 &&
2808                 n_tokens != 8) {
2809                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2810                 return;
2811         }
2812
2813         pipeline_name = tokens[1];
2814
2815         if (strcmp(tokens[2], "port") != 0) {
2816                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2817                 return;
2818         }
2819
2820         if (strcmp(tokens[3], "out") != 0) {
2821                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2822                 return;
2823         }
2824
2825         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
2826                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2827                 return;
2828         }
2829
2830         if (strcmp(tokens[5], "stats") != 0) {
2831                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2832                 return;
2833         }
2834
2835         if (strcmp(tokens[6], "read") != 0) {
2836                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2837                 return;
2838         }
2839
2840         clear = 0;
2841         if (n_tokens == 8) {
2842                 if (strcmp(tokens[7], "clear") != 0) {
2843                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2844                         return;
2845                 }
2846
2847                 clear = 1;
2848         }
2849
2850         status = softnic_pipeline_port_out_stats_read(softnic,
2851                 pipeline_name,
2852                 port_id,
2853                 &stats,
2854                 clear);
2855         if (status) {
2856                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2857                 return;
2858         }
2859
2860         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2861                 stats.stats.n_pkts_in,
2862                 stats.n_pkts_dropped_by_ah,
2863                 stats.stats.n_pkts_drop);
2864 }
2865
2866 /**
2867  * pipeline <pipeline_name> table <table_id> stats read [clear]
2868  */
2869 #define MSG_PIPELINE_TABLE_STATS                                     \
2870         "Pkts in: %" PRIu64 "\n"                                     \
2871         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2872         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2873         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2874         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2875         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2876
2877 static void
2878 cmd_pipeline_table_stats(struct pmd_internals *softnic,
2879         char **tokens,
2880         uint32_t n_tokens,
2881         char *out,
2882         size_t out_size)
2883 {
2884         struct rte_pipeline_table_stats stats;
2885         char *pipeline_name;
2886         uint32_t table_id;
2887         int clear, status;
2888
2889         if (n_tokens != 6 &&
2890                 n_tokens != 7) {
2891                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2892                 return;
2893         }
2894
2895         pipeline_name = tokens[1];
2896
2897         if (strcmp(tokens[2], "table") != 0) {
2898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2899                 return;
2900         }
2901
2902         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
2903                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2904                 return;
2905         }
2906
2907         if (strcmp(tokens[4], "stats") != 0) {
2908                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2909                 return;
2910         }
2911
2912         if (strcmp(tokens[5], "read") != 0) {
2913                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2914                 return;
2915         }
2916
2917         clear = 0;
2918         if (n_tokens == 7) {
2919                 if (strcmp(tokens[6], "clear") != 0) {
2920                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2921                         return;
2922                 }
2923
2924                 clear = 1;
2925         }
2926
2927         status = softnic_pipeline_table_stats_read(softnic,
2928                 pipeline_name,
2929                 table_id,
2930                 &stats,
2931                 clear);
2932         if (status) {
2933                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2934                 return;
2935         }
2936
2937         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2938                 stats.stats.n_pkts_in,
2939                 stats.stats.n_pkts_lookup_miss,
2940                 stats.n_pkts_dropped_by_lkp_hit_ah,
2941                 stats.n_pkts_dropped_lkp_hit,
2942                 stats.n_pkts_dropped_by_lkp_miss_ah,
2943                 stats.n_pkts_dropped_lkp_miss);
2944 }
2945
2946 /**
2947  * <match> ::=
2948  *
2949  * match
2950  *    acl
2951  *       priority <priority>
2952  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2953  *       <sp0> <sp1> <dp0> <dp1> <proto>
2954  *    | array <pos>
2955  *    | hash
2956  *       raw <key>
2957  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2958  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2959  *       | ipv4_addr <addr>
2960  *       | ipv6_addr <addr>
2961  *       | qinq <svlan> <cvlan>
2962  *    | lpm
2963  *       ipv4 | ipv6 <addr> <depth>
2964  */
2965 struct pkt_key_qinq {
2966         uint16_t ethertype_svlan;
2967         uint16_t svlan;
2968         uint16_t ethertype_cvlan;
2969         uint16_t cvlan;
2970 } __attribute__((__packed__));
2971
2972 struct pkt_key_ipv4_5tuple {
2973         uint8_t time_to_live;
2974         uint8_t proto;
2975         uint16_t hdr_checksum;
2976         uint32_t sa;
2977         uint32_t da;
2978         uint16_t sp;
2979         uint16_t dp;
2980 } __attribute__((__packed__));
2981
2982 struct pkt_key_ipv6_5tuple {
2983         uint16_t payload_length;
2984         uint8_t proto;
2985         uint8_t hop_limit;
2986         uint8_t sa[16];
2987         uint8_t da[16];
2988         uint16_t sp;
2989         uint16_t dp;
2990 } __attribute__((__packed__));
2991
2992 struct pkt_key_ipv4_addr {
2993         uint32_t addr;
2994 } __attribute__((__packed__));
2995
2996 struct pkt_key_ipv6_addr {
2997         uint8_t addr[16];
2998 } __attribute__((__packed__));
2999
3000 static uint32_t
3001 parse_match(char **tokens,
3002         uint32_t n_tokens,
3003         char *out,
3004         size_t out_size,
3005         struct softnic_table_rule_match *m)
3006 {
3007         memset(m, 0, sizeof(*m));
3008
3009         if (n_tokens < 2)
3010                 return 0;
3011
3012         if (strcmp(tokens[0], "match") != 0) {
3013                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
3014                 return 0;
3015         }
3016
3017         if (strcmp(tokens[1], "acl") == 0) {
3018                 if (n_tokens < 14) {
3019                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3020                         return 0;
3021                 }
3022
3023                 m->match_type = TABLE_ACL;
3024
3025                 if (strcmp(tokens[2], "priority") != 0) {
3026                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
3027                         return 0;
3028                 }
3029
3030                 if (softnic_parser_read_uint32(&m->match.acl.priority,
3031                         tokens[3]) != 0) {
3032                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
3033                         return 0;
3034                 }
3035
3036                 if (strcmp(tokens[4], "ipv4") == 0) {
3037                         struct in_addr saddr, daddr;
3038
3039                         m->match.acl.ip_version = 1;
3040
3041                         if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) {
3042                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
3043                                 return 0;
3044                         }
3045                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
3046
3047                         if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) {
3048                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
3049                                 return 0;
3050                         }
3051                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
3052                 } else if (strcmp(tokens[4], "ipv6") == 0) {
3053                         struct in6_addr saddr, daddr;
3054
3055                         m->match.acl.ip_version = 0;
3056
3057                         if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) {
3058                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
3059                                 return 0;
3060                         }
3061                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
3062
3063                         if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) {
3064                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
3065                                 return 0;
3066                         }
3067                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
3068                 } else {
3069                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
3070                                 "ipv4 or ipv6");
3071                         return 0;
3072                 }
3073
3074                 if (softnic_parser_read_uint32(&m->match.acl.sa_depth,
3075                         tokens[6]) != 0) {
3076                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
3077                         return 0;
3078                 }
3079
3080                 if (softnic_parser_read_uint32(&m->match.acl.da_depth,
3081                         tokens[8]) != 0) {
3082                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
3083                         return 0;
3084                 }
3085
3086                 if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
3087                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
3088                         return 0;
3089                 }
3090
3091                 if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
3092                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
3093                         return 0;
3094                 }
3095
3096                 if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
3097                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
3098                         return 0;
3099                 }
3100
3101                 if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
3102                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
3103                         return 0;
3104                 }
3105
3106                 if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
3107                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
3108                         return 0;
3109                 }
3110
3111                 m->match.acl.proto_mask = 0xff;
3112
3113                 return 14;
3114         } /* acl */
3115
3116         if (strcmp(tokens[1], "array") == 0) {
3117                 if (n_tokens < 3) {
3118                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3119                         return 0;
3120                 }
3121
3122                 m->match_type = TABLE_ARRAY;
3123
3124                 if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
3125                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
3126                         return 0;
3127                 }
3128
3129                 return 3;
3130         } /* array */
3131
3132         if (strcmp(tokens[1], "hash") == 0) {
3133                 if (n_tokens < 3) {
3134                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3135                         return 0;
3136                 }
3137
3138                 m->match_type = TABLE_HASH;
3139
3140                 if (strcmp(tokens[2], "raw") == 0) {
3141                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
3142
3143                         if (n_tokens < 4) {
3144                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3145                                         tokens[0]);
3146                                 return 0;
3147                         }
3148
3149                         if (softnic_parse_hex_string(tokens[3],
3150                                 m->match.hash.key, &key_size) != 0) {
3151                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
3152                                 return 0;
3153                         }
3154
3155                         return 4;
3156                 } /* hash raw */
3157
3158                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
3159                         struct pkt_key_ipv4_5tuple *ipv4 =
3160                                 (struct pkt_key_ipv4_5tuple *)m->match.hash.key;
3161                         struct in_addr saddr, daddr;
3162                         uint16_t sp, dp;
3163                         uint8_t proto;
3164
3165                         if (n_tokens < 8) {
3166                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3167                                         tokens[0]);
3168                                 return 0;
3169                         }
3170
3171                         if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) {
3172                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
3173                                 return 0;
3174                         }
3175
3176                         if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) {
3177                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
3178                                 return 0;
3179                         }
3180
3181                         if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) {
3182                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
3183                                 return 0;
3184                         }
3185
3186                         if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) {
3187                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
3188                                 return 0;
3189                         }
3190
3191                         if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) {
3192                                 snprintf(out, out_size, MSG_ARG_INVALID,
3193                                         "proto");
3194                                 return 0;
3195                         }
3196
3197                         ipv4->sa = saddr.s_addr;
3198                         ipv4->da = daddr.s_addr;
3199                         ipv4->sp = rte_cpu_to_be_16(sp);
3200                         ipv4->dp = rte_cpu_to_be_16(dp);
3201                         ipv4->proto = proto;
3202
3203                         return 8;
3204                 } /* hash ipv4_5tuple */
3205
3206                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
3207                         struct pkt_key_ipv6_5tuple *ipv6 =
3208                                 (struct pkt_key_ipv6_5tuple *)m->match.hash.key;
3209                         struct in6_addr saddr, daddr;
3210                         uint16_t sp, dp;
3211                         uint8_t proto;
3212
3213                         if (n_tokens < 8) {
3214                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3215                                         tokens[0]);
3216                                 return 0;
3217                         }
3218
3219                         if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) {
3220                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
3221                                 return 0;
3222                         }
3223
3224                         if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) {
3225                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
3226                                 return 0;
3227                         }
3228
3229                         if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) {
3230                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
3231                                 return 0;
3232                         }
3233
3234                         if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) {
3235                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
3236                                 return 0;
3237                         }
3238
3239                         if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) {
3240                                 snprintf(out, out_size, MSG_ARG_INVALID,
3241                                         "proto");
3242                                 return 0;
3243                         }
3244
3245                         memcpy(ipv6->sa, saddr.s6_addr, 16);
3246                         memcpy(ipv6->da, daddr.s6_addr, 16);
3247                         ipv6->sp = rte_cpu_to_be_16(sp);
3248                         ipv6->dp = rte_cpu_to_be_16(dp);
3249                         ipv6->proto = proto;
3250
3251                         return 8;
3252                 } /* hash ipv6_5tuple */
3253
3254                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
3255                         struct pkt_key_ipv4_addr *ipv4_addr =
3256                                 (struct pkt_key_ipv4_addr *)m->match.hash.key;
3257                         struct in_addr addr;
3258
3259                         if (n_tokens < 4) {
3260                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3261                                         tokens[0]);
3262                                 return 0;
3263                         }
3264
3265                         if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) {
3266                                 snprintf(out, out_size, MSG_ARG_INVALID,
3267                                         "addr");
3268                                 return 0;
3269                         }
3270
3271                         ipv4_addr->addr = addr.s_addr;
3272
3273                         return 4;
3274                 } /* hash ipv4_addr */
3275
3276                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
3277                         struct pkt_key_ipv6_addr *ipv6_addr =
3278                                 (struct pkt_key_ipv6_addr *)m->match.hash.key;
3279                         struct in6_addr addr;
3280
3281                         if (n_tokens < 4) {
3282                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3283                                         tokens[0]);
3284                                 return 0;
3285                         }
3286
3287                         if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) {
3288                                 snprintf(out, out_size, MSG_ARG_INVALID,
3289                                         "addr");
3290                                 return 0;
3291                         }
3292
3293                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
3294
3295                         return 4;
3296                 } /* hash ipv6_5tuple */
3297
3298                 if (strcmp(tokens[2], "qinq") == 0) {
3299                         struct pkt_key_qinq *qinq =
3300                                 (struct pkt_key_qinq *)m->match.hash.key;
3301                         uint16_t svlan, cvlan;
3302
3303                         if (n_tokens < 5) {
3304                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
3305                                         tokens[0]);
3306                                 return 0;
3307                         }
3308
3309                         if ((softnic_parser_read_uint16(&svlan, tokens[3]) != 0) ||
3310                                 svlan > 0xFFF) {
3311                                 snprintf(out, out_size, MSG_ARG_INVALID,
3312                                         "svlan");
3313                                 return 0;
3314                         }
3315
3316                         if ((softnic_parser_read_uint16(&cvlan, tokens[4]) != 0) ||
3317                                 cvlan > 0xFFF) {
3318                                 snprintf(out, out_size, MSG_ARG_INVALID,
3319                                         "cvlan");
3320                                 return 0;
3321                         }
3322
3323                         qinq->svlan = rte_cpu_to_be_16(svlan);
3324                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
3325
3326                         return 5;
3327                 } /* hash qinq */
3328
3329                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3330                 return 0;
3331         } /* hash */
3332
3333         if (strcmp(tokens[1], "lpm") == 0) {
3334                 if (n_tokens < 5) {
3335                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3336                         return 0;
3337                 }
3338
3339                 m->match_type = TABLE_LPM;
3340
3341                 if (strcmp(tokens[2], "ipv4") == 0) {
3342                         struct in_addr addr;
3343
3344                         m->match.lpm.ip_version = 1;
3345
3346                         if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) {
3347                                 snprintf(out, out_size, MSG_ARG_INVALID,
3348                                         "addr");
3349                                 return 0;
3350                         }
3351
3352                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3353                 } else if (strcmp(tokens[2], "ipv6") == 0) {
3354                         struct in6_addr addr;
3355
3356                         m->match.lpm.ip_version = 0;
3357
3358                         if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) {
3359                                 snprintf(out, out_size, MSG_ARG_INVALID,
3360                                         "addr");
3361                                 return 0;
3362                         }
3363
3364                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
3365                 } else {
3366                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3367                                 "ipv4 or ipv6");
3368                         return 0;
3369                 }
3370
3371                 if (softnic_parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
3372                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
3373                         return 0;
3374                 }
3375
3376                 return 5;
3377         } /* lpm */
3378
3379         snprintf(out, out_size, MSG_ARG_MISMATCH,
3380                 "acl or array or hash or lpm");
3381         return 0;
3382 }
3383
3384 /**
3385  * table_action ::=
3386  *
3387  * action
3388  *    fwd
3389  *       drop
3390  *       | port <port_id>
3391  *       | meta
3392  *       | table <table_id>
3393  *    [balance <out0> ... <out7>]
3394  *    [meter
3395  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3396  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3397  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3398  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
3399  *    [tm subport <subport_id> pipe <pipe_id>]
3400  *    [encap
3401  *       ether <da> <sa>
3402  *       | vlan <da> <sa> <pcp> <dei> <vid>
3403  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
3404  *       | mpls unicast | multicast
3405  *          <da> <sa>
3406  *          label0 <label> <tc> <ttl>
3407  *          [label1 <label> <tc> <ttl>
3408  *          [label2 <label> <tc> <ttl>
3409  *          [label3 <label> <tc> <ttl>]]]
3410  *       | pppoe <da> <sa> <session_id>]
3411  *       | vxlan ether <da> <sa>
3412  *          [vlan <pcp> <dei> <vid>]
3413  *          ipv4 <sa> <da> <dscp> <ttl>
3414  *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
3415  *          udp <sp> <dp>
3416  *          vxlan <vni>]
3417  *    [nat ipv4 | ipv6 <addr> <port>]
3418  *    [ttl dec | keep]
3419  *    [stats]
3420  *    [time]
3421  *    [tag <tag>]
3422  *    [decap <n>]
3423  *    [sym_crypto
3424  *       encrypt | decrypt
3425  *       type
3426  *       | cipher
3427  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3428  *       | cipher_auth
3429  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3430  *          auth_algo <algo> auth_key <key> digest_size <size>
3431  *       | aead
3432  *          aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad>
3433  *          digest_size <size>
3434  *       data_offset <data_offset>]
3435  *
3436  * where:
3437  *    <pa> ::= g | y | r | drop
3438  */
3439 static uint32_t
3440 parse_table_action_fwd(char **tokens,
3441         uint32_t n_tokens,
3442         struct softnic_table_rule_action *a)
3443 {
3444         if (n_tokens == 0 ||
3445                 (strcmp(tokens[0], "fwd") != 0))
3446                 return 0;
3447
3448         tokens++;
3449         n_tokens--;
3450
3451         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
3452                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
3453                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3454                 return 1 + 1;
3455         }
3456
3457         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
3458                 uint32_t id;
3459
3460                 if (n_tokens < 2 ||
3461                         softnic_parser_read_uint32(&id, tokens[1]))
3462                         return 0;
3463
3464                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
3465                 a->fwd.id = id;
3466                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3467                 return 1 + 2;
3468         }
3469
3470         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
3471                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3472                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3473                 return 1 + 1;
3474         }
3475
3476         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
3477                 uint32_t id;
3478
3479                 if (n_tokens < 2 ||
3480                         softnic_parser_read_uint32(&id, tokens[1]))
3481                         return 0;
3482
3483                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
3484                 a->fwd.id = id;
3485                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3486                 return 1 + 2;
3487         }
3488
3489         return 0;
3490 }
3491
3492 static uint32_t
3493 parse_table_action_balance(char **tokens,
3494         uint32_t n_tokens,
3495         struct softnic_table_rule_action *a)
3496 {
3497         uint32_t i;
3498
3499         if (n_tokens == 0 ||
3500                 (strcmp(tokens[0], "balance") != 0))
3501                 return 0;
3502
3503         tokens++;
3504         n_tokens--;
3505
3506         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
3507                 return 0;
3508
3509         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
3510                 if (softnic_parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
3511                         return 0;
3512
3513         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
3514         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
3515 }
3516
3517 static int
3518 parse_policer_action(char *token, enum rte_table_action_policer *a)
3519 {
3520         if (strcmp(token, "g") == 0) {
3521                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
3522                 return 0;
3523         }
3524
3525         if (strcmp(token, "y") == 0) {
3526                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
3527                 return 0;
3528         }
3529
3530         if (strcmp(token, "r") == 0) {
3531                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
3532                 return 0;
3533         }
3534
3535         if (strcmp(token, "drop") == 0) {
3536                 *a = RTE_TABLE_ACTION_POLICER_DROP;
3537                 return 0;
3538         }
3539
3540         return -1;
3541 }
3542
3543 static uint32_t
3544 parse_table_action_meter_tc(char **tokens,
3545         uint32_t n_tokens,
3546         struct rte_table_action_mtr_tc_params *mtr)
3547 {
3548         if (n_tokens < 9 ||
3549                 strcmp(tokens[0], "meter") ||
3550                 softnic_parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
3551                 strcmp(tokens[2], "policer") ||
3552                 strcmp(tokens[3], "g") ||
3553                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
3554                 strcmp(tokens[5], "y") ||
3555                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
3556                 strcmp(tokens[7], "r") ||
3557                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
3558                 return 0;
3559
3560         return 9;
3561 }
3562
3563 static uint32_t
3564 parse_table_action_meter(char **tokens,
3565         uint32_t n_tokens,
3566         struct softnic_table_rule_action *a)
3567 {
3568         if (n_tokens == 0 ||
3569                 strcmp(tokens[0], "meter"))
3570                 return 0;
3571
3572         tokens++;
3573         n_tokens--;
3574
3575         if (n_tokens < 10 ||
3576                 strcmp(tokens[0], "tc0") ||
3577                 (parse_table_action_meter_tc(tokens + 1,
3578                         n_tokens - 1,
3579                         &a->mtr.mtr[0]) == 0))
3580                 return 0;
3581
3582         tokens += 10;
3583         n_tokens -= 10;
3584
3585         if (n_tokens == 0 ||
3586                 strcmp(tokens[0], "tc1")) {
3587                 a->mtr.tc_mask = 1;
3588                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3589                 return 1 + 10;
3590         }
3591
3592         if (n_tokens < 30 ||
3593                 (parse_table_action_meter_tc(tokens + 1,
3594                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3595                 strcmp(tokens[10], "tc2") ||
3596                 (parse_table_action_meter_tc(tokens + 11,
3597                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3598                 strcmp(tokens[20], "tc3") ||
3599                 (parse_table_action_meter_tc(tokens + 21,
3600                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
3601                 return 0;
3602
3603         a->mtr.tc_mask = 0xF;
3604         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3605         return 1 + 10 + 3 * 10;
3606 }
3607
3608 static uint32_t
3609 parse_table_action_tm(char **tokens,
3610         uint32_t n_tokens,
3611         struct softnic_table_rule_action *a)
3612 {
3613         uint32_t subport_id, pipe_id;
3614
3615         if (n_tokens < 5 ||
3616                 strcmp(tokens[0], "tm") ||
3617                 strcmp(tokens[1], "subport") ||
3618                 softnic_parser_read_uint32(&subport_id, tokens[2]) ||
3619                 strcmp(tokens[3], "pipe") ||
3620                 softnic_parser_read_uint32(&pipe_id, tokens[4]))
3621                 return 0;
3622
3623         a->tm.subport_id = subport_id;
3624         a->tm.pipe_id = pipe_id;
3625         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3626         return 5;
3627 }
3628
3629 static uint32_t
3630 parse_table_action_encap(char **tokens,
3631         uint32_t n_tokens,
3632         struct softnic_table_rule_action *a)
3633 {
3634         if (n_tokens == 0 ||
3635                 strcmp(tokens[0], "encap"))
3636                 return 0;
3637
3638         tokens++;
3639         n_tokens--;
3640
3641         /* ether */
3642         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3643                 if (n_tokens < 3 ||
3644                         softnic_parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3645                         softnic_parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3646                         return 0;
3647
3648                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3649                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3650                 return 1 + 3;
3651         }
3652
3653         /* vlan */
3654         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3655                 uint32_t pcp, dei, vid;
3656
3657                 if (n_tokens < 6 ||
3658                         softnic_parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3659                         softnic_parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3660                         softnic_parser_read_uint32(&pcp, tokens[3]) ||
3661                         pcp > 0x7 ||
3662                         softnic_parser_read_uint32(&dei, tokens[4]) ||
3663                         dei > 0x1 ||
3664                         softnic_parser_read_uint32(&vid, tokens[5]) ||
3665                         vid > 0xFFF)
3666                         return 0;
3667
3668                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3669                 a->encap.vlan.vlan.dei = dei & 0x1;
3670                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3671                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3672                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3673                 return 1 + 6;
3674         }
3675
3676         /* qinq */
3677         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3678                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3679                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3680
3681                 if (n_tokens < 9 ||
3682                         softnic_parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3683                         softnic_parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3684                         softnic_parser_read_uint32(&svlan_pcp, tokens[3]) ||
3685                         svlan_pcp > 0x7 ||
3686                         softnic_parser_read_uint32(&svlan_dei, tokens[4]) ||
3687                         svlan_dei > 0x1 ||
3688                         softnic_parser_read_uint32(&svlan_vid, tokens[5]) ||
3689                         svlan_vid > 0xFFF ||
3690                         softnic_parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3691                         cvlan_pcp > 0x7 ||
3692                         softnic_parser_read_uint32(&cvlan_dei, tokens[7]) ||
3693                         cvlan_dei > 0x1 ||
3694                         softnic_parser_read_uint32(&cvlan_vid, tokens[8]) ||
3695                         cvlan_vid > 0xFFF)
3696                         return 0;
3697
3698                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3699                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3700                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3701                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3702                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3703                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3704                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3705                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3706                 return 1 + 9;
3707         }
3708
3709         /* mpls */
3710         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3711                 uint32_t label, tc, ttl;
3712
3713                 if (n_tokens < 8)
3714                         return 0;
3715
3716                 if (strcmp(tokens[1], "unicast") == 0)
3717                         a->encap.mpls.unicast = 1;
3718                 else if (strcmp(tokens[1], "multicast") == 0)
3719                         a->encap.mpls.unicast = 0;
3720                 else
3721                         return 0;
3722
3723                 if (softnic_parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3724                         softnic_parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3725                         strcmp(tokens[4], "label0") ||
3726                         softnic_parser_read_uint32(&label, tokens[5]) ||
3727                         label > 0xFFFFF ||
3728                         softnic_parser_read_uint32(&tc, tokens[6]) ||
3729                         tc > 0x7 ||
3730                         softnic_parser_read_uint32(&ttl, tokens[7]) ||
3731                         ttl > 0x3F)
3732                         return 0;
3733
3734                 a->encap.mpls.mpls[0].label = label;
3735                 a->encap.mpls.mpls[0].tc = tc;
3736                 a->encap.mpls.mpls[0].ttl = ttl;
3737
3738                 tokens += 8;
3739                 n_tokens -= 8;
3740
3741                 if (n_tokens == 0 ||
3742                         strcmp(tokens[0], "label1")) {
3743                         a->encap.mpls.mpls_count = 1;
3744                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3745                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3746                         return 1 + 8;
3747                 }
3748
3749                 if (n_tokens < 4 ||
3750                         softnic_parser_read_uint32(&label, tokens[1]) ||
3751                         label > 0xFFFFF ||
3752                         softnic_parser_read_uint32(&tc, tokens[2]) ||
3753                         tc > 0x7 ||
3754                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
3755                         ttl > 0x3F)
3756                         return 0;
3757
3758                 a->encap.mpls.mpls[1].label = label;
3759                 a->encap.mpls.mpls[1].tc = tc;
3760                 a->encap.mpls.mpls[1].ttl = ttl;
3761
3762                 tokens += 4;
3763                 n_tokens -= 4;
3764
3765                 if (n_tokens == 0 ||
3766                         strcmp(tokens[0], "label2")) {
3767                         a->encap.mpls.mpls_count = 2;
3768                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3769                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3770                         return 1 + 8 + 4;
3771                 }
3772
3773                 if (n_tokens < 4 ||
3774                         softnic_parser_read_uint32(&label, tokens[1]) ||
3775                         label > 0xFFFFF ||
3776                         softnic_parser_read_uint32(&tc, tokens[2]) ||
3777                         tc > 0x7 ||
3778                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
3779                         ttl > 0x3F)
3780                         return 0;
3781
3782                 a->encap.mpls.mpls[2].label = label;
3783                 a->encap.mpls.mpls[2].tc = tc;
3784                 a->encap.mpls.mpls[2].ttl = ttl;
3785
3786                 tokens += 4;
3787                 n_tokens -= 4;
3788
3789                 if (n_tokens == 0 ||
3790                         strcmp(tokens[0], "label3")) {
3791                         a->encap.mpls.mpls_count = 3;
3792                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3793                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3794                         return 1 + 8 + 4 + 4;
3795                 }
3796
3797                 if (n_tokens < 4 ||
3798                         softnic_parser_read_uint32(&label, tokens[1]) ||
3799                         label > 0xFFFFF ||
3800                         softnic_parser_read_uint32(&tc, tokens[2]) ||
3801                         tc > 0x7 ||
3802                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
3803                         ttl > 0x3F)
3804                         return 0;
3805
3806                 a->encap.mpls.mpls[3].label = label;
3807                 a->encap.mpls.mpls[3].tc = tc;
3808                 a->encap.mpls.mpls[3].ttl = ttl;
3809
3810                 a->encap.mpls.mpls_count = 4;
3811                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3812                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3813                 return 1 + 8 + 4 + 4 + 4;
3814         }
3815
3816         /* pppoe */
3817         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3818                 if (n_tokens < 4 ||
3819                         softnic_parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3820                         softnic_parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3821                         softnic_parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3822                                 tokens[3]))
3823                         return 0;
3824
3825                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3826                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3827                 return 1 + 4;
3828         }
3829
3830         /* vxlan */
3831         if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
3832                 uint32_t n = 0;
3833
3834                 n_tokens--;
3835                 tokens++;
3836                 n++;
3837
3838                 /* ether <da> <sa> */
3839                 if ((n_tokens < 3) ||
3840                         strcmp(tokens[0], "ether") ||
3841                         softnic_parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
3842                         softnic_parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
3843                         return 0;
3844
3845                 n_tokens -= 3;
3846                 tokens += 3;
3847                 n += 3;
3848
3849                 /* [vlan <pcp> <dei> <vid>] */
3850                 if (strcmp(tokens[0], "vlan") == 0) {
3851                         uint32_t pcp, dei, vid;
3852
3853                         if ((n_tokens < 4) ||
3854                                 softnic_parser_read_uint32(&pcp, tokens[1]) ||
3855                                 (pcp > 7) ||
3856                                 softnic_parser_read_uint32(&dei, tokens[2]) ||
3857                                 (dei > 1) ||
3858                                 softnic_parser_read_uint32(&vid, tokens[3]) ||
3859                                 (vid > 0xFFF))
3860                                 return 0;
3861
3862                         a->encap.vxlan.vlan.pcp = pcp;
3863                         a->encap.vxlan.vlan.dei = dei;
3864                         a->encap.vxlan.vlan.vid = vid;
3865
3866                         n_tokens -= 4;
3867                         tokens += 4;
3868                         n += 4;
3869                 }
3870
3871                 /* ipv4 <sa> <da> <dscp> <ttl>
3872                    | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
3873                 if (strcmp(tokens[0], "ipv4") == 0) {
3874                         struct in_addr sa, da;
3875                         uint8_t dscp, ttl;
3876
3877                         if ((n_tokens < 5) ||
3878                                 softnic_parse_ipv4_addr(tokens[1], &sa) ||
3879                                 softnic_parse_ipv4_addr(tokens[2], &da) ||
3880                                 softnic_parser_read_uint8(&dscp, tokens[3]) ||
3881                                 (dscp > 64) ||
3882                                 softnic_parser_read_uint8(&ttl, tokens[4]))
3883                                 return 0;
3884
3885                         a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
3886                         a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
3887                         a->encap.vxlan.ipv4.dscp = dscp;
3888                         a->encap.vxlan.ipv4.ttl = ttl;
3889
3890                         n_tokens -= 5;
3891                         tokens += 5;
3892                         n += 5;
3893                 } else if (strcmp(tokens[0], "ipv6") == 0) {
3894                         struct in6_addr sa, da;
3895                         uint32_t flow_label;
3896                         uint8_t dscp, hop_limit;
3897
3898                         if ((n_tokens < 6) ||
3899                                 softnic_parse_ipv6_addr(tokens[1], &sa) ||
3900                                 softnic_parse_ipv6_addr(tokens[2], &da) ||
3901                                 softnic_parser_read_uint32(&flow_label, tokens[3]) ||
3902                                 softnic_parser_read_uint8(&dscp, tokens[4]) ||
3903                                 (dscp > 64) ||
3904                                 softnic_parser_read_uint8(&hop_limit, tokens[5]))
3905                                 return 0;
3906
3907                         memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3908                         memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
3909                         a->encap.vxlan.ipv6.flow_label = flow_label;
3910                         a->encap.vxlan.ipv6.dscp = dscp;
3911                         a->encap.vxlan.ipv6.hop_limit = hop_limit;
3912
3913                         n_tokens -= 6;
3914                         tokens += 6;
3915                         n += 6;
3916                 } else
3917                         return 0;
3918
3919                 /* udp <sp> <dp> */
3920                 if ((n_tokens < 3) ||
3921                         strcmp(tokens[0], "udp") ||
3922                         softnic_parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
3923                         softnic_parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
3924                         return 0;
3925
3926                 n_tokens -= 3;
3927                 tokens += 3;
3928                 n += 3;
3929
3930                 /* vxlan <vni> */
3931                 if ((n_tokens < 2) ||
3932                         strcmp(tokens[0], "vxlan") ||
3933                         softnic_parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
3934                         (a->encap.vxlan.vxlan.vni > 0xFFFFFF))
3935                         return 0;
3936
3937                 n_tokens -= 2;
3938                 tokens += 2;
3939                 n += 2;
3940
3941                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
3942                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3943                 return 1 + n;
3944         }
3945
3946         return 0;
3947 }
3948
3949 static uint32_t
3950 parse_table_action_nat(char **tokens,
3951         uint32_t n_tokens,
3952         struct softnic_table_rule_action *a)
3953 {
3954         if (n_tokens < 4 ||
3955                 strcmp(tokens[0], "nat"))
3956                 return 0;
3957
3958         if (strcmp(tokens[1], "ipv4") == 0) {
3959                 struct in_addr addr;
3960                 uint16_t port;
3961
3962                 if (softnic_parse_ipv4_addr(tokens[2], &addr) ||
3963                         softnic_parser_read_uint16(&port, tokens[3]))
3964                         return 0;
3965
3966                 a->nat.ip_version = 1;
3967                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3968                 a->nat.port = port;
3969                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3970                 return 4;
3971         }
3972
3973         if (strcmp(tokens[1], "ipv6") == 0) {
3974                 struct in6_addr addr;
3975                 uint16_t port;
3976
3977                 if (softnic_parse_ipv6_addr(tokens[2], &addr) ||
3978                         softnic_parser_read_uint16(&port, tokens[3]))
3979                         return 0;
3980
3981                 a->nat.ip_version = 0;
3982                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3983                 a->nat.port = port;
3984                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3985                 return 4;
3986         }
3987
3988         return 0;
3989 }
3990
3991 static uint32_t
3992 parse_table_action_ttl(char **tokens,
3993         uint32_t n_tokens,
3994         struct softnic_table_rule_action *a)
3995 {
3996         if (n_tokens < 2 ||
3997                 strcmp(tokens[0], "ttl"))
3998                 return 0;
3999
4000         if (strcmp(tokens[1], "dec") == 0)
4001                 a->ttl.decrement = 1;
4002         else if (strcmp(tokens[1], "keep") == 0)
4003                 a->ttl.decrement = 0;
4004         else
4005                 return 0;
4006
4007         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
4008         return 2;
4009 }
4010
4011 static uint32_t
4012 parse_table_action_stats(char **tokens,
4013         uint32_t n_tokens,
4014         struct softnic_table_rule_action *a)
4015 {
4016         if (n_tokens < 1 ||
4017                 strcmp(tokens[0], "stats"))
4018                 return 0;
4019
4020         a->stats.n_packets = 0;
4021         a->stats.n_bytes = 0;
4022         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
4023         return 1;
4024 }
4025
4026 static uint32_t
4027 parse_table_action_time(char **tokens,
4028         uint32_t n_tokens,
4029         struct softnic_table_rule_action *a)
4030 {
4031         if (n_tokens < 1 ||
4032                 strcmp(tokens[0], "time"))
4033                 return 0;
4034
4035         a->time.time = rte_rdtsc();
4036         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
4037         return 1;
4038 }
4039
4040 static void
4041 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p)
4042 {
4043         struct rte_crypto_sym_xform *xform[2] = {NULL};
4044         uint32_t i;
4045
4046         xform[0] = p->xform;
4047         if (xform[0])
4048                 xform[1] = xform[0]->next;
4049
4050         for (i = 0; i < 2; i++) {
4051                 if (xform[i] == NULL)
4052                         continue;
4053
4054                 switch (xform[i]->type) {
4055                 case RTE_CRYPTO_SYM_XFORM_CIPHER:
4056                         if (xform[i]->cipher.key.data)
4057                                 free(xform[i]->cipher.key.data);
4058                         if (p->cipher_auth.cipher_iv.val)
4059                                 free(p->cipher_auth.cipher_iv.val);
4060                         if (p->cipher_auth.cipher_iv_update.val)
4061                                 free(p->cipher_auth.cipher_iv_update.val);
4062                         break;
4063                 case RTE_CRYPTO_SYM_XFORM_AUTH:
4064                         if (xform[i]->auth.key.data)
4065                                 free(xform[i]->cipher.key.data);
4066                         if (p->cipher_auth.auth_iv.val)
4067                                 free(p->cipher_auth.cipher_iv.val);
4068                         if (p->cipher_auth.auth_iv_update.val)
4069                                 free(p->cipher_auth.cipher_iv_update.val);
4070                         break;
4071                 case RTE_CRYPTO_SYM_XFORM_AEAD:
4072                         if (xform[i]->aead.key.data)
4073                                 free(xform[i]->cipher.key.data);
4074                         if (p->aead.iv.val)
4075                                 free(p->aead.iv.val);
4076                         if (p->aead.aad.val)
4077                                 free(p->aead.aad.val);
4078                         break;
4079                 default:
4080                         continue;
4081                 }
4082         }
4083
4084 }
4085
4086 static struct rte_crypto_sym_xform *
4087 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p,
4088                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
4089                 uint32_t *used_n_tokens)
4090 {
4091         struct rte_crypto_sym_xform *xform_cipher;
4092         int status;
4093         size_t len;
4094
4095         if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") ||
4096                         strcmp(tokens[3], "cipher_key") ||
4097                         strcmp(tokens[5], "cipher_iv"))
4098                 return NULL;
4099
4100         xform_cipher = calloc(1, sizeof(*xform_cipher));
4101         if (xform_cipher == NULL)
4102                 return NULL;
4103
4104         xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
4105         xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT :
4106                         RTE_CRYPTO_CIPHER_OP_DECRYPT;
4107
4108         /* cipher_algo */
4109         status = rte_cryptodev_get_cipher_algo_enum(
4110                         &xform_cipher->cipher.algo, tokens[2]);
4111         if (status < 0)
4112                 goto error_exit;
4113
4114         /* cipher_key */
4115         len = strlen(tokens[4]);
4116         xform_cipher->cipher.key.data = calloc(1, len / 2 + 1);
4117         if (xform_cipher->cipher.key.data == NULL)
4118                 goto error_exit;
4119
4120         status = softnic_parse_hex_string(tokens[4],
4121                         xform_cipher->cipher.key.data,
4122                         (uint32_t *)&len);
4123         if (status < 0)
4124                 goto error_exit;
4125
4126         xform_cipher->cipher.key.length = (uint16_t)len;
4127
4128         /* cipher_iv */
4129         len = strlen(tokens[6]);
4130
4131         p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1);
4132         if (p->cipher_auth.cipher_iv.val == NULL)
4133                 goto error_exit;
4134
4135         status = softnic_parse_hex_string(tokens[6],
4136                         p->cipher_auth.cipher_iv.val,
4137                         (uint32_t *)&len);
4138         if (status < 0)
4139                 goto error_exit;
4140
4141         xform_cipher->cipher.iv.length = (uint16_t)len;
4142         xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
4143         p->cipher_auth.cipher_iv.length = (uint32_t)len;
4144         *used_n_tokens = 7;
4145
4146         return xform_cipher;
4147
4148 error_exit:
4149         if (xform_cipher->cipher.key.data)
4150                 free(xform_cipher->cipher.key.data);
4151
4152         if (p->cipher_auth.cipher_iv.val) {
4153                 free(p->cipher_auth.cipher_iv.val);
4154                 p->cipher_auth.cipher_iv.val = NULL;
4155         }
4156
4157         free(xform_cipher);
4158
4159         return NULL;
4160 }
4161
4162 static struct rte_crypto_sym_xform *
4163 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p,
4164                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
4165                 uint32_t *used_n_tokens)
4166 {
4167         struct rte_crypto_sym_xform *xform_cipher;
4168         struct rte_crypto_sym_xform *xform_auth;
4169         int status;
4170         size_t len;
4171
4172         if (n_tokens < 13 ||
4173                         strcmp(tokens[7], "auth_algo") ||
4174                         strcmp(tokens[9], "auth_key") ||
4175                         strcmp(tokens[11], "digest_size"))
4176                 return NULL;
4177
4178         xform_auth = calloc(1, sizeof(*xform_auth));
4179         if (xform_auth == NULL)
4180                 return NULL;
4181
4182         xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH;
4183         xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE :
4184                         RTE_CRYPTO_AUTH_OP_VERIFY;
4185
4186         /* auth_algo */
4187         status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo,
4188                         tokens[8]);
4189         if (status < 0)
4190                 goto error_exit;
4191
4192         /* auth_key */
4193         len = strlen(tokens[10]);
4194         xform_auth->auth.key.data = calloc(1, len / 2 + 1);
4195         if (xform_auth->auth.key.data == NULL)
4196                 goto error_exit;
4197
4198         status = softnic_parse_hex_string(tokens[10],
4199                         xform_auth->auth.key.data, (uint32_t *)&len);
4200         if (status < 0)
4201                 goto error_exit;
4202
4203         xform_auth->auth.key.length = (uint16_t)len;
4204
4205         if (strcmp(tokens[11], "digest_size"))
4206                 goto error_exit;
4207
4208         status = softnic_parser_read_uint16(&xform_auth->auth.digest_length,
4209                         tokens[12]);
4210         if (status < 0)
4211                 goto error_exit;
4212
4213         xform_cipher = parse_table_action_cipher(p, tokens, 7, encrypt,
4214                         used_n_tokens);
4215         if (xform_cipher == NULL)
4216                 goto error_exit;
4217
4218         *used_n_tokens += 6;
4219
4220         if (encrypt) {
4221                 xform_cipher->next = xform_auth;
4222                 return xform_cipher;
4223         } else {
4224                 xform_auth->next = xform_cipher;
4225                 return xform_auth;
4226         }
4227
4228 error_exit:
4229         if (xform_auth->auth.key.data)
4230                 free(xform_auth->auth.key.data);
4231         if (p->cipher_auth.auth_iv.val) {
4232                 free(p->cipher_auth.auth_iv.val);
4233                 p->cipher_auth.auth_iv.val = 0;
4234         }
4235
4236         free(xform_auth);
4237
4238         return NULL;
4239 }
4240
4241 static struct rte_crypto_sym_xform *
4242 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p,
4243                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
4244                 uint32_t *used_n_tokens)
4245 {
4246         struct rte_crypto_sym_xform *xform_aead;
4247         int status;
4248         size_t len;
4249
4250         if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") ||
4251                         strcmp(tokens[3], "aead_key") ||
4252                         strcmp(tokens[5], "aead_iv") ||
4253                         strcmp(tokens[7], "aead_aad") ||
4254                         strcmp(tokens[9], "digest_size"))
4255                 return NULL;
4256
4257         xform_aead = calloc(1, sizeof(*xform_aead));
4258         if (xform_aead == NULL)
4259                 return NULL;
4260
4261         xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD;
4262         xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT :
4263                         RTE_CRYPTO_AEAD_OP_DECRYPT;
4264
4265         /* aead_algo */
4266         status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo,
4267                         tokens[2]);
4268         if (status < 0)
4269                 goto error_exit;
4270
4271         /* aead_key */
4272         len = strlen(tokens[4]);
4273         xform_aead->aead.key.data = calloc(1, len / 2 + 1);
4274         if (xform_aead->aead.key.data == NULL)
4275                 goto error_exit;
4276
4277         status = softnic_parse_hex_string(tokens[4], xform_aead->aead.key.data,
4278                         (uint32_t *)&len);
4279         if (status < 0)
4280                 goto error_exit;
4281
4282         xform_aead->aead.key.length = (uint16_t)len;
4283
4284         /* aead_iv */
4285         len = strlen(tokens[6]);
4286         p->aead.iv.val = calloc(1, len / 2 + 1);
4287         if (p->aead.iv.val == NULL)
4288                 goto error_exit;
4289
4290         status = softnic_parse_hex_string(tokens[6], p->aead.iv.val,
4291                         (uint32_t *)&len);
4292         if (status < 0)
4293                 goto error_exit;
4294
4295         xform_aead->aead.iv.length = (uint16_t)len;
4296         xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
4297         p->aead.iv.length = (uint32_t)len;
4298
4299         /* aead_aad */
4300         len = strlen(tokens[8]);
4301         p->aead.aad.val = calloc(1, len / 2 + 1);
4302         if (p->aead.aad.val == NULL)
4303                 goto error_exit;
4304
4305         status = softnic_parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len);
4306         if (status < 0)
4307                 goto error_exit;
4308
4309         xform_aead->aead.aad_length = (uint16_t)len;
4310         p->aead.aad.length = (uint32_t)len;
4311
4312         /* digest_size */
4313         status = softnic_parser_read_uint16(&xform_aead->aead.digest_length,
4314                         tokens[10]);
4315         if (status < 0)
4316                 goto error_exit;
4317
4318         *used_n_tokens = 11;
4319
4320         return xform_aead;
4321
4322 error_exit:
4323         if (xform_aead->aead.key.data)
4324                 free(xform_aead->aead.key.data);
4325         if (p->aead.iv.val) {
4326                 free(p->aead.iv.val);
4327                 p->aead.iv.val = NULL;
4328         }
4329         if (p->aead.aad.val) {
4330                 free(p->aead.aad.val);
4331                 p->aead.aad.val = NULL;
4332         }
4333
4334         free(xform_aead);
4335
4336         return NULL;
4337 }
4338
4339
4340 static uint32_t
4341 parse_table_action_sym_crypto(char **tokens,
4342         uint32_t n_tokens,
4343         struct softnic_table_rule_action *a)
4344 {
4345         struct rte_table_action_sym_crypto_params *p = &a->sym_crypto;
4346         struct rte_crypto_sym_xform *xform = NULL;
4347         uint32_t used_n_tokens;
4348         uint32_t encrypt;
4349         int status;
4350
4351         if ((n_tokens < 12) ||
4352                 strcmp(tokens[0], "sym_crypto") ||
4353                 strcmp(tokens[2], "type"))
4354                 return 0;
4355
4356         memset(p, 0, sizeof(*p));
4357
4358         if (strcmp(tokens[1], "encrypt") == 0)
4359                 encrypt = 1;
4360         else
4361                 encrypt = 0;
4362
4363         status = softnic_parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]);
4364         if (status < 0)
4365                 return 0;
4366
4367         if (strcmp(tokens[3], "cipher") == 0) {
4368                 tokens += 3;
4369                 n_tokens -= 3;
4370
4371                 xform = parse_table_action_cipher(p, tokens, n_tokens, encrypt,
4372                                 &used_n_tokens);
4373         } else if (strcmp(tokens[3], "cipher_auth") == 0) {
4374                 tokens += 3;
4375                 n_tokens -= 3;
4376
4377                 xform = parse_table_action_cipher_auth(p, tokens, n_tokens,
4378                                 encrypt, &used_n_tokens);
4379         } else if (strcmp(tokens[3], "aead") == 0) {
4380                 tokens += 3;
4381                 n_tokens -= 3;
4382
4383                 xform = parse_table_action_aead(p, tokens, n_tokens, encrypt,
4384                                 &used_n_tokens);
4385         }
4386
4387         if (xform == NULL)
4388                 return 0;
4389
4390         p->xform = xform;
4391
4392         if (strcmp(tokens[used_n_tokens], "data_offset")) {
4393                 parse_free_sym_crypto_param_data(p);
4394                 return 0;
4395         }
4396
4397         a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO;
4398
4399         return used_n_tokens + 5;
4400 }
4401
4402 static uint32_t
4403 parse_table_action_tag(char **tokens,
4404         uint32_t n_tokens,
4405         struct softnic_table_rule_action *a)
4406 {
4407         if (n_tokens < 2 ||
4408                 strcmp(tokens[0], "tag"))
4409                 return 0;
4410
4411         if (softnic_parser_read_uint32(&a->tag.tag, tokens[1]))
4412                 return 0;
4413
4414         a->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
4415         return 2;
4416 }
4417
4418 static uint32_t
4419 parse_table_action_decap(char **tokens,
4420         uint32_t n_tokens,
4421         struct softnic_table_rule_action *a)
4422 {
4423         if (n_tokens < 2 ||
4424                 strcmp(tokens[0], "decap"))
4425                 return 0;
4426
4427         if (softnic_parser_read_uint16(&a->decap.n, tokens[1]))
4428                 return 0;
4429
4430         a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
4431         return 2;
4432 }
4433
4434 static uint32_t
4435 parse_table_action(char **tokens,
4436         uint32_t n_tokens,
4437         char *out,
4438         size_t out_size,
4439         struct softnic_table_rule_action *a)
4440 {
4441         uint32_t n_tokens0 = n_tokens;
4442
4443         memset(a, 0, sizeof(*a));
4444
4445         if (n_tokens < 2 ||
4446                 strcmp(tokens[0], "action"))
4447                 return 0;
4448
4449         tokens++;
4450         n_tokens--;
4451
4452         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
4453                 uint32_t n;
4454
4455                 n = parse_table_action_fwd(tokens, n_tokens, a);
4456                 if (n == 0) {
4457                         snprintf(out, out_size, MSG_ARG_INVALID,
4458                                 "action fwd");
4459                         return 0;
4460                 }
4461
4462                 tokens += n;
4463                 n_tokens -= n;
4464         }
4465
4466         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
4467                 uint32_t n;
4468
4469                 n = parse_table_action_balance(tokens, n_tokens, a);
4470                 if (n == 0) {
4471                         snprintf(out, out_size, MSG_ARG_INVALID,
4472                                 "action balance");
4473                         return 0;
4474                 }
4475
4476                 tokens += n;
4477                 n_tokens -= n;
4478         }
4479
4480         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
4481                 uint32_t n;
4482
4483                 n = parse_table_action_meter(tokens, n_tokens, a);
4484                 if (n == 0) {
4485                         snprintf(out, out_size, MSG_ARG_INVALID,
4486                                 "action meter");
4487                         return 0;
4488                 }
4489
4490                 tokens += n;
4491                 n_tokens -= n;
4492         }
4493
4494         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
4495                 uint32_t n;
4496
4497                 n = parse_table_action_tm(tokens, n_tokens, a);
4498                 if (n == 0) {
4499                         snprintf(out, out_size, MSG_ARG_INVALID,
4500                                 "action tm");
4501                         return 0;
4502                 }
4503
4504                 tokens += n;
4505                 n_tokens -= n;
4506         }
4507
4508         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
4509                 uint32_t n;
4510
4511                 n = parse_table_action_encap(tokens, n_tokens, a);
4512                 if (n == 0) {
4513                         snprintf(out, out_size, MSG_ARG_INVALID,
4514                                 "action encap");
4515                         return 0;
4516                 }
4517
4518                 tokens += n;
4519                 n_tokens -= n;
4520         }
4521
4522         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
4523                 uint32_t n;
4524
4525                 n = parse_table_action_nat(tokens, n_tokens, a);
4526                 if (n == 0) {
4527                         snprintf(out, out_size, MSG_ARG_INVALID,
4528                                 "action nat");
4529                         return 0;
4530                 }
4531
4532                 tokens += n;
4533                 n_tokens -= n;
4534         }
4535
4536         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
4537                 uint32_t n;
4538
4539                 n = parse_table_action_ttl(tokens, n_tokens, a);
4540                 if (n == 0) {
4541                         snprintf(out, out_size, MSG_ARG_INVALID,
4542                                 "action ttl");
4543                         return 0;
4544                 }
4545
4546                 tokens += n;
4547                 n_tokens -= n;
4548         }
4549
4550         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
4551                 uint32_t n;
4552
4553                 n = parse_table_action_stats(tokens, n_tokens, a);
4554                 if (n == 0) {
4555                         snprintf(out, out_size, MSG_ARG_INVALID,
4556                                 "action stats");
4557                         return 0;
4558                 }
4559
4560                 tokens += n;
4561                 n_tokens -= n;
4562         }
4563
4564         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
4565                 uint32_t n;
4566
4567                 n = parse_table_action_time(tokens, n_tokens, a);
4568                 if (n == 0) {
4569                         snprintf(out, out_size, MSG_ARG_INVALID,
4570                                 "action time");
4571                         return 0;
4572                 }
4573
4574                 tokens += n;
4575                 n_tokens -= n;
4576         }
4577
4578         if (n_tokens && (strcmp(tokens[0], "tag") == 0)) {
4579                 uint32_t n;
4580
4581                 n = parse_table_action_tag(tokens, n_tokens, a);
4582                 if (n == 0) {
4583                         snprintf(out, out_size, MSG_ARG_INVALID,
4584                                 "action tag");
4585                         return 0;
4586                 }
4587
4588                 tokens += n;
4589                 n_tokens -= n;
4590         }
4591
4592         if (n_tokens && (strcmp(tokens[0], "decap") == 0)) {
4593                 uint32_t n;
4594
4595                 n = parse_table_action_decap(tokens, n_tokens, a);
4596                 if (n == 0) {
4597                         snprintf(out, out_size, MSG_ARG_INVALID,
4598                                 "action decap");
4599                         return 0;
4600                 }
4601
4602                 tokens += n;
4603                 n_tokens -= n;
4604         }
4605
4606         if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) {
4607                 uint32_t n;
4608
4609                 n = parse_table_action_sym_crypto(tokens, n_tokens, a);
4610                 if (n == 0) {
4611                         snprintf(out, out_size, MSG_ARG_INVALID,
4612                                 "action sym_crypto");
4613                 }
4614
4615                 tokens += n;
4616                 n_tokens -= n;
4617         }
4618
4619         if (n_tokens0 - n_tokens == 1) {
4620                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4621                 return 0;
4622         }
4623
4624         return n_tokens0 - n_tokens;
4625 }
4626
4627 /**
4628  * pipeline <pipeline_name> table <table_id> rule add
4629  *    match <match>
4630  *    action <table_action>
4631  */
4632 static void
4633 cmd_softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
4634         char **tokens,
4635         uint32_t n_tokens,
4636         char *out,
4637         size_t out_size)
4638 {
4639         struct softnic_table_rule_match m;
4640         struct softnic_table_rule_action a;
4641         char *pipeline_name;
4642         void *data;
4643         uint32_t table_id, t0, n_tokens_parsed;
4644         int status;
4645
4646         if (n_tokens < 8) {
4647                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4648                 return;
4649         }
4650
4651         pipeline_name = tokens[1];
4652
4653         if (strcmp(tokens[2], "table") != 0) {
4654                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4655                 return;
4656         }
4657
4658         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
4659                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4660                 return;
4661         }
4662
4663         if (strcmp(tokens[4], "rule") != 0) {
4664                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4665                 return;
4666         }
4667
4668         if (strcmp(tokens[5], "add") != 0) {
4669                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4670                 return;
4671         }
4672
4673         t0 = 6;
4674
4675         /* match */
4676         n_tokens_parsed = parse_match(tokens + t0,
4677                 n_tokens - t0,
4678                 out,
4679                 out_size,
4680                 &m);
4681         if (n_tokens_parsed == 0)
4682                 return;
4683         t0 += n_tokens_parsed;
4684
4685         /* action */
4686         n_tokens_parsed = parse_table_action(tokens + t0,
4687                 n_tokens - t0,
4688                 out,
4689                 out_size,
4690                 &a);
4691         if (n_tokens_parsed == 0)
4692                 return;
4693         t0 += n_tokens_parsed;
4694
4695         if (t0 != n_tokens) {
4696                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4697                 return;
4698         }
4699
4700         status = softnic_pipeline_table_rule_add(softnic,
4701                 pipeline_name,
4702                 table_id,
4703                 &m,
4704                 &a,
4705                 &data);
4706         if (status) {
4707                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4708                 return;
4709         }
4710 }
4711
4712 /**
4713  * pipeline <pipeline_name> table <table_id> rule add
4714  *    match
4715  *       default
4716  *    action
4717  *       fwd
4718  *          drop
4719  *          | port <port_id>
4720  *          | meta
4721  *          | table <table_id>
4722  */
4723 static void
4724 cmd_softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
4725         char **tokens,
4726         uint32_t n_tokens,
4727         char *out,
4728         size_t out_size)
4729 {
4730         struct softnic_table_rule_action action;
4731         void *data;
4732         char *pipeline_name;
4733         uint32_t table_id;
4734         int status;
4735
4736         if (n_tokens != 11 &&
4737                 n_tokens != 12) {
4738                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4739                 return;
4740         }
4741
4742         pipeline_name = tokens[1];
4743
4744         if (strcmp(tokens[2], "table") != 0) {
4745                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4746                 return;
4747         }
4748
4749         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
4750                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4751                 return;
4752         }
4753
4754         if (strcmp(tokens[4], "rule") != 0) {
4755                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4756                 return;
4757         }
4758
4759         if (strcmp(tokens[5], "add") != 0) {
4760                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4761                 return;
4762         }
4763
4764         if (strcmp(tokens[6], "match") != 0) {
4765                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4766                 return;
4767         }
4768
4769         if (strcmp(tokens[7], "default") != 0) {
4770                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4771                 return;
4772         }
4773
4774         if (strcmp(tokens[8], "action") != 0) {
4775                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4776                 return;
4777         }
4778
4779         if (strcmp(tokens[9], "fwd") != 0) {
4780                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
4781                 return;
4782         }
4783
4784         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
4785
4786         if (strcmp(tokens[10], "drop") == 0) {
4787                 if (n_tokens != 11) {
4788                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4789                         return;
4790                 }
4791
4792                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
4793         } else if (strcmp(tokens[10], "port") == 0) {
4794                 uint32_t id;
4795
4796                 if (n_tokens != 12) {
4797                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4798                         return;
4799                 }
4800
4801                 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
4802                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
4803                         return;
4804                 }
4805
4806                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
4807                 action.fwd.id = id;
4808         } else if (strcmp(tokens[10], "meta") == 0) {
4809                 if (n_tokens != 11) {
4810                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4811                         return;
4812                 }
4813
4814                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
4815         } else if (strcmp(tokens[10], "table") == 0) {
4816                 uint32_t id;
4817
4818                 if (n_tokens != 12) {
4819                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4820                         return;
4821                 }
4822
4823                 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
4824                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4825                         return;
4826                 }
4827
4828                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
4829                 action.fwd.id = id;
4830         } else {
4831                 snprintf(out, out_size, MSG_ARG_INVALID,
4832                         "drop or port or meta or table");
4833                 return;
4834         }
4835
4836         status = softnic_pipeline_table_rule_add_default(softnic,
4837                 pipeline_name,
4838                 table_id,
4839                 &action,
4840                 &data);
4841         if (status) {
4842                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4843                 return;
4844         }
4845 }
4846
4847 /**
4848  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
4849  *
4850  * File <file_name>:
4851  * - line format: match <match> action <action>
4852  */
4853 static int
4854 cli_rule_file_process(const char *file_name,
4855         size_t line_len_max,
4856         struct softnic_table_rule_match *m,
4857         struct softnic_table_rule_action *a,
4858         uint32_t *n_rules,
4859         uint32_t *line_number,
4860         char *out,
4861         size_t out_size);
4862
4863 static void
4864 cmd_softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
4865         char **tokens,
4866         uint32_t n_tokens,
4867         char *out,
4868         size_t out_size)
4869 {
4870         struct softnic_table_rule_match *match;
4871         struct softnic_table_rule_action *action;
4872         void **data;
4873         char *pipeline_name, *file_name;
4874         uint32_t table_id, n_rules, n_rules_parsed, line_number;
4875         int status;
4876
4877         if (n_tokens != 9) {
4878                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4879                 return;
4880         }
4881
4882         pipeline_name = tokens[1];
4883
4884         if (strcmp(tokens[2], "table") != 0) {
4885                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4886                 return;
4887         }
4888
4889         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
4890                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4891                 return;
4892         }
4893
4894         if (strcmp(tokens[4], "rule") != 0) {
4895                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4896                 return;
4897         }
4898
4899         if (strcmp(tokens[5], "add") != 0) {
4900                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4901                 return;
4902         }
4903
4904         if (strcmp(tokens[6], "bulk") != 0) {
4905                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
4906                 return;
4907         }
4908
4909         file_name = tokens[7];
4910
4911         if ((softnic_parser_read_uint32(&n_rules, tokens[8]) != 0) ||
4912                 n_rules == 0) {
4913                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
4914                 return;
4915         }
4916
4917         /* Memory allocation. */
4918         match = calloc(n_rules, sizeof(struct softnic_table_rule_match));
4919         action = calloc(n_rules, sizeof(struct softnic_table_rule_action));
4920         data = calloc(n_rules, sizeof(void *));
4921         if (match == NULL ||
4922                 action == NULL ||
4923                 data == NULL) {
4924                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
4925                 free(data);
4926                 free(action);
4927                 free(match);
4928                 return;
4929         }
4930
4931         /* Load rule file */
4932         n_rules_parsed = n_rules;
4933         status = cli_rule_file_process(file_name,
4934                 1024,
4935                 match,
4936                 action,
4937                 &n_rules_parsed,
4938                 &line_number,
4939                 out,
4940                 out_size);
4941         if (status) {
4942                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4943                 free(data);
4944                 free(action);
4945                 free(match);
4946                 return;
4947         }
4948         if (n_rules_parsed != n_rules) {
4949                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
4950                 free(data);
4951                 free(action);
4952                 free(match);
4953                 return;
4954         }
4955
4956         /* Rule bulk add */
4957         status = softnic_pipeline_table_rule_add_bulk(softnic,
4958                 pipeline_name,
4959                 table_id,
4960                 match,
4961                 action,
4962                 data,
4963                 &n_rules);
4964         if (status) {
4965                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4966                 free(data);
4967                 free(action);
4968                 free(match);
4969                 return;
4970         }
4971
4972         /* Memory free */
4973         free(data);
4974         free(action);
4975         free(match);
4976 }
4977
4978 /**
4979  * pipeline <pipeline_name> table <table_id> rule delete
4980  *    match <match>
4981  */
4982 static void
4983 cmd_softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
4984         char **tokens,
4985         uint32_t n_tokens,
4986         char *out,
4987         size_t out_size)
4988 {
4989         struct softnic_table_rule_match m;
4990         char *pipeline_name;
4991         uint32_t table_id, n_tokens_parsed, t0;
4992         int status;
4993
4994         if (n_tokens < 8) {
4995                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4996                 return;
4997         }
4998
4999         pipeline_name = tokens[1];
5000
5001         if (strcmp(tokens[2], "table") != 0) {
5002                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5003                 return;
5004         }
5005
5006         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5007                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5008                 return;
5009         }
5010
5011         if (strcmp(tokens[4], "rule") != 0) {
5012                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5013                 return;
5014         }
5015
5016         if (strcmp(tokens[5], "delete") != 0) {
5017                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5018                 return;
5019         }
5020
5021         t0 = 6;
5022
5023         /* match */
5024         n_tokens_parsed = parse_match(tokens + t0,
5025                 n_tokens - t0,
5026                 out,
5027                 out_size,
5028                 &m);
5029         if (n_tokens_parsed == 0)
5030                 return;
5031         t0 += n_tokens_parsed;
5032
5033         if (n_tokens != t0) {
5034                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5035                 return;
5036         }
5037
5038         status = softnic_pipeline_table_rule_delete(softnic,
5039                 pipeline_name,
5040                 table_id,
5041                 &m);
5042         if (status) {
5043                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5044                 return;
5045         }
5046 }
5047
5048 /**
5049  * pipeline <pipeline_name> table <table_id> rule delete
5050  *    match
5051  *       default
5052  */
5053 static void
5054 cmd_softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
5055         char **tokens,
5056         uint32_t n_tokens,
5057         char *out,
5058         size_t out_size)
5059 {
5060         char *pipeline_name;
5061         uint32_t table_id;
5062         int status;
5063
5064         if (n_tokens != 8) {
5065                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5066                 return;
5067         }
5068
5069         pipeline_name = tokens[1];
5070
5071         if (strcmp(tokens[2], "table") != 0) {
5072                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5073                 return;
5074         }
5075
5076         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5077                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5078                 return;
5079         }
5080
5081         if (strcmp(tokens[4], "rule") != 0) {
5082                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5083                 return;
5084         }
5085
5086         if (strcmp(tokens[5], "delete") != 0) {
5087                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5088                 return;
5089         }
5090
5091         if (strcmp(tokens[6], "match") != 0) {
5092                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
5093                 return;
5094         }
5095
5096         if (strcmp(tokens[7], "default") != 0) {
5097                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
5098                 return;
5099         }
5100
5101         status = softnic_pipeline_table_rule_delete_default(softnic,
5102                 pipeline_name,
5103                 table_id);
5104         if (status) {
5105                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5106                 return;
5107         }
5108 }
5109
5110 /**
5111  * pipeline <pipeline_name> table <table_id> rule read stats [clear]
5112  */
5113 static void
5114 cmd_softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic __rte_unused,
5115         char **tokens,
5116         uint32_t n_tokens __rte_unused,
5117         char *out,
5118         size_t out_size)
5119 {
5120         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5121 }
5122
5123 /**
5124  * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
5125  *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
5126  *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
5127  */
5128 static void
5129 cmd_pipeline_table_meter_profile_add(struct pmd_internals *softnic,
5130         char **tokens,
5131         uint32_t n_tokens,
5132         char *out,
5133         size_t out_size)
5134 {
5135         struct rte_table_action_meter_profile p;
5136         char *pipeline_name;
5137         uint32_t table_id, meter_profile_id;
5138         int status;
5139
5140         if (n_tokens < 9) {
5141                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5142                 return;
5143         }
5144
5145         pipeline_name = tokens[1];
5146
5147         if (strcmp(tokens[2], "table") != 0) {
5148                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5149                 return;
5150         }
5151
5152         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5153                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5154                 return;
5155         }
5156
5157         if (strcmp(tokens[4], "meter") != 0) {
5158                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5159                 return;
5160         }
5161
5162         if (strcmp(tokens[5], "profile") != 0) {
5163                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5164                 return;
5165         }
5166
5167         if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5168                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5169                 return;
5170         }
5171
5172         if (strcmp(tokens[7], "add") != 0) {
5173                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5174                 return;
5175         }
5176
5177         if (strcmp(tokens[8], "srtcm") == 0) {
5178                 if (n_tokens != 15) {
5179                         snprintf(out, out_size, MSG_ARG_MISMATCH,
5180                                 tokens[0]);
5181                         return;
5182                 }
5183
5184                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
5185
5186                 if (strcmp(tokens[9], "cir") != 0) {
5187                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5188                         return;
5189                 }
5190
5191                 if (softnic_parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
5192                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5193                         return;
5194                 }
5195
5196                 if (strcmp(tokens[11], "cbs") != 0) {
5197                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5198                         return;
5199                 }
5200
5201                 if (softnic_parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
5202                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5203                         return;
5204                 }
5205
5206                 if (strcmp(tokens[13], "ebs") != 0) {
5207                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
5208                         return;
5209                 }
5210
5211                 if (softnic_parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
5212                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
5213                         return;
5214                 }
5215         } else if (strcmp(tokens[8], "trtcm") == 0) {
5216                 if (n_tokens != 17) {
5217                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5218                         return;
5219                 }
5220
5221                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
5222
5223                 if (strcmp(tokens[9], "cir") != 0) {
5224                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5225                         return;
5226                 }
5227
5228                 if (softnic_parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
5229                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5230                         return;
5231                 }
5232
5233                 if (strcmp(tokens[11], "pir") != 0) {
5234                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
5235                         return;
5236                 }
5237
5238                 if (softnic_parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
5239                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
5240                         return;
5241                 }
5242                 if (strcmp(tokens[13], "cbs") != 0) {
5243                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5244                         return;
5245                 }
5246
5247                 if (softnic_parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
5248                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5249                         return;
5250                 }
5251
5252                 if (strcmp(tokens[15], "pbs") != 0) {
5253                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
5254                         return;
5255                 }
5256
5257                 if (softnic_parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
5258                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
5259                         return;
5260                 }
5261         } else {
5262                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5263                 return;
5264         }
5265
5266         status = softnic_pipeline_table_mtr_profile_add(softnic,
5267                 pipeline_name,
5268                 table_id,
5269                 meter_profile_id,
5270                 &p);
5271         if (status) {
5272                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5273                 return;
5274         }
5275 }
5276
5277 /**
5278  * pipeline <pipeline_name> table <table_id>
5279  *  meter profile <meter_profile_id> delete
5280  */
5281 static void
5282 cmd_pipeline_table_meter_profile_delete(struct pmd_internals *softnic,
5283         char **tokens,
5284         uint32_t n_tokens,
5285         char *out,
5286         size_t out_size)
5287 {
5288         char *pipeline_name;
5289         uint32_t table_id, meter_profile_id;
5290         int status;
5291
5292         if (n_tokens != 8) {
5293                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5294                 return;
5295         }
5296
5297         pipeline_name = tokens[1];
5298
5299         if (strcmp(tokens[2], "table") != 0) {
5300                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5301                 return;
5302         }
5303
5304         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5305                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5306                 return;
5307         }
5308
5309         if (strcmp(tokens[4], "meter") != 0) {
5310                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5311                 return;
5312         }
5313
5314         if (strcmp(tokens[5], "profile") != 0) {
5315                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5316                 return;
5317         }
5318
5319         if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5320                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5321                 return;
5322         }
5323
5324         if (strcmp(tokens[7], "delete") != 0) {
5325                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5326                 return;
5327         }
5328
5329         status = softnic_pipeline_table_mtr_profile_delete(softnic,
5330                 pipeline_name,
5331                 table_id,
5332                 meter_profile_id);
5333         if (status) {
5334                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5335                 return;
5336         }
5337 }
5338
5339 /**
5340  * pipeline <pipeline_name> table <table_id> rule read meter [clear]
5341  */
5342 static void
5343 cmd_pipeline_table_rule_meter_read(struct pmd_internals *softnic __rte_unused,
5344         char **tokens,
5345         uint32_t n_tokens __rte_unused,
5346         char *out,
5347         size_t out_size)
5348 {
5349         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5350 }
5351
5352 /**
5353  * pipeline <pipeline_name> table <table_id> dscp <file_name>
5354  *
5355  * File <file_name>:
5356  *  - exactly 64 lines
5357  *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
5358  */
5359 static int
5360 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5361         const char *file_name,
5362         uint32_t *line_number)
5363 {
5364         FILE *f = NULL;
5365         uint32_t dscp, l;
5366
5367         /* Check input arguments */
5368         if (dscp_table == NULL ||
5369                 file_name == NULL ||
5370                 line_number == NULL) {
5371                 if (line_number)
5372                         *line_number = 0;
5373                 return -EINVAL;
5374         }
5375
5376         /* Open input file */
5377         f = fopen(file_name, "r");
5378         if (f == NULL) {
5379                 *line_number = 0;
5380                 return -EINVAL;
5381         }
5382
5383         /* Read file */
5384         for (dscp = 0, l = 1; ; l++) {
5385                 char line[64];
5386                 char *tokens[3];
5387                 enum rte_meter_color color;
5388                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5389
5390                 if (fgets(line, sizeof(line), f) == NULL)
5391                         break;
5392
5393                 if (is_comment(line))
5394                         continue;
5395
5396                 if (softnic_parse_tokenize_string(line, tokens, &n_tokens)) {
5397                         *line_number = l;
5398                         fclose(f);
5399                         return -EINVAL;
5400                 }
5401
5402                 if (n_tokens == 0)
5403                         continue;
5404
5405                 if (dscp >= RTE_DIM(dscp_table->entry) ||
5406                         n_tokens != RTE_DIM(tokens) ||
5407                         softnic_parser_read_uint32(&tc_id, tokens[0]) ||
5408                         tc_id >= RTE_TABLE_ACTION_TC_MAX ||
5409                         softnic_parser_read_uint32(&tc_queue_id, tokens[1]) ||
5410                         tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX ||
5411                         (strlen(tokens[2]) != 1)) {
5412                         *line_number = l;
5413                         fclose(f);
5414                         return -EINVAL;
5415                 }
5416
5417                 switch (tokens[2][0]) {
5418                 case 'g':
5419                 case 'G':
5420                         color = e_RTE_METER_GREEN;
5421                         break;
5422
5423                 case 'y':
5424                 case 'Y':
5425                         color = e_RTE_METER_YELLOW;
5426                         break;
5427
5428                 case 'r':
5429                 case 'R':
5430                         color = e_RTE_METER_RED;
5431                         break;
5432
5433                 default:
5434                         *line_number = l;
5435                         fclose(f);
5436                         return -EINVAL;
5437                 }
5438
5439                 dscp_table->entry[dscp].tc_id = tc_id;
5440                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5441                 dscp_table->entry[dscp].color = color;
5442                 dscp++;
5443         }
5444
5445         /* Close file */
5446         fclose(f);
5447         return 0;
5448 }
5449
5450 static void
5451 cmd_pipeline_table_dscp(struct pmd_internals *softnic,
5452         char **tokens,
5453         uint32_t n_tokens,
5454         char *out,
5455         size_t out_size)
5456 {
5457         struct rte_table_action_dscp_table dscp_table;
5458         char *pipeline_name, *file_name;
5459         uint32_t table_id, line_number;
5460         int status;
5461
5462         if (n_tokens != 6) {
5463                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5464                 return;
5465         }
5466
5467         pipeline_name = tokens[1];
5468
5469         if (strcmp(tokens[2], "table") != 0) {
5470                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5471                 return;
5472         }
5473
5474         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5475                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5476                 return;
5477         }
5478
5479         if (strcmp(tokens[4], "dscp") != 0) {
5480                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5481                 return;
5482         }
5483
5484         file_name = tokens[5];
5485
5486         status = load_dscp_table(&dscp_table, file_name, &line_number);
5487         if (status) {
5488                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5489                 return;
5490         }
5491
5492         status = softnic_pipeline_table_dscp_table_update(softnic,
5493                 pipeline_name,
5494                 table_id,
5495                 UINT64_MAX,
5496                 &dscp_table);
5497         if (status) {
5498                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5499                 return;
5500         }
5501 }
5502
5503 /**
5504  * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
5505  */
5506 static void
5507 cmd_softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic __rte_unused,
5508         char **tokens,
5509         uint32_t n_tokens __rte_unused,
5510         char *out,
5511         size_t out_size)
5512 {
5513         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5514 }
5515
5516 /**
5517  * thread <thread_id> pipeline <pipeline_name> enable
5518  */
5519 static void
5520 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
5521         char **tokens,
5522         uint32_t n_tokens,
5523         char *out,
5524         size_t out_size)
5525 {
5526         char *pipeline_name;
5527         uint32_t thread_id;
5528         int status;
5529
5530         if (n_tokens != 5) {
5531                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5532                 return;
5533         }
5534
5535         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
5536                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5537                 return;
5538         }
5539
5540         if (strcmp(tokens[2], "pipeline") != 0) {
5541                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5542                 return;
5543         }
5544
5545         pipeline_name = tokens[3];
5546
5547         if (strcmp(tokens[4], "enable") != 0) {
5548                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5549                 return;
5550         }
5551
5552         status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name);
5553         if (status) {
5554                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5555                 return;
5556         }
5557 }
5558
5559 /**
5560  * thread <thread_id> pipeline <pipeline_name> disable
5561  */
5562 static void
5563 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
5564         char **tokens,
5565         uint32_t n_tokens,
5566         char *out,
5567         size_t out_size)
5568 {
5569         char *pipeline_name;
5570         uint32_t thread_id;
5571         int status;
5572
5573         if (n_tokens != 5) {
5574                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5575                 return;
5576         }
5577
5578         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
5579                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5580                 return;
5581         }
5582
5583         if (strcmp(tokens[2], "pipeline") != 0) {
5584                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5585                 return;
5586         }
5587
5588         pipeline_name = tokens[3];
5589
5590         if (strcmp(tokens[4], "disable") != 0) {
5591                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5592                 return;
5593         }
5594
5595         status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name);
5596         if (status) {
5597                 snprintf(out, out_size, MSG_CMD_FAIL,
5598                         "thread pipeline disable");
5599                 return;
5600         }
5601 }
5602
5603 /**
5604  * flowapi map
5605  *  group <group_id>
5606  *  ingress | egress
5607  *  pipeline <pipeline_name>
5608  *  table <table_id>
5609  */
5610 static void
5611 cmd_softnic_flowapi_map(struct pmd_internals *softnic,
5612                 char **tokens,
5613                 uint32_t n_tokens,
5614                 char *out,
5615                 size_t out_size)
5616 {
5617         char *pipeline_name;
5618         uint32_t group_id, table_id;
5619         int ingress, status;
5620
5621         if (n_tokens != 9) {
5622                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5623                 return;
5624         }
5625
5626         if (strcmp(tokens[1], "map") != 0) {
5627                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "map");
5628                 return;
5629         }
5630
5631         if (strcmp(tokens[2], "group") != 0) {
5632                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group");
5633                 return;
5634         }
5635
5636         if (softnic_parser_read_uint32(&group_id, tokens[3]) != 0) {
5637                 snprintf(out, out_size, MSG_ARG_INVALID, "group_id");
5638                 return;
5639         }
5640
5641         if (strcmp(tokens[4], "ingress") == 0) {
5642                 ingress = 1;
5643         } else if (strcmp(tokens[4], "egress") == 0) {
5644                 ingress = 0;
5645         } else {
5646                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ingress | egress");
5647                 return;
5648         }
5649
5650         if (strcmp(tokens[5], "pipeline") != 0) {
5651                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5652                 return;
5653         }
5654
5655         pipeline_name = tokens[6];
5656
5657         if (strcmp(tokens[7], "table") != 0) {
5658                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5659                 return;
5660         }
5661
5662         if (softnic_parser_read_uint32(&table_id, tokens[8]) != 0) {
5663                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5664                 return;
5665         }
5666
5667         status = flow_attr_map_set(softnic,
5668                         group_id,
5669                         ingress,
5670                         pipeline_name,
5671                         table_id);
5672         if (status) {
5673                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5674                 return;
5675         }
5676 }
5677
5678 void
5679 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
5680 {
5681         char *tokens[CMD_MAX_TOKENS];
5682         uint32_t n_tokens = RTE_DIM(tokens);
5683         struct pmd_internals *softnic = arg;
5684         int status;
5685
5686         if (is_comment(in))
5687                 return;
5688
5689         status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
5690         if (status) {
5691                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
5692                 return;
5693         }
5694
5695         if (n_tokens == 0)
5696                 return;
5697
5698         if (strcmp(tokens[0], "mempool") == 0) {
5699                 cmd_mempool(softnic, tokens, n_tokens, out, out_size);
5700                 return;
5701         }
5702
5703         if (strcmp(tokens[0], "link") == 0) {
5704                 cmd_link(softnic, tokens, n_tokens, out, out_size);
5705                 return;
5706         }
5707
5708         if (strcmp(tokens[0], "swq") == 0) {
5709                 cmd_swq(softnic, tokens, n_tokens, out, out_size);
5710                 return;
5711         }
5712
5713         if (strcmp(tokens[0], "tmgr") == 0) {
5714                 if (n_tokens == 2) {
5715                         cmd_tmgr(softnic, tokens, n_tokens, out, out_size);
5716                         return;
5717                 }
5718
5719                 if (n_tokens >= 3 &&
5720                         (strcmp(tokens[1], "shaper") == 0) &&
5721                         (strcmp(tokens[2], "profile") == 0)) {
5722                         cmd_tmgr_shaper_profile(softnic, tokens, n_tokens, out, out_size);
5723                         return;
5724                 }
5725
5726                 if (n_tokens >= 3 &&
5727                         (strcmp(tokens[1], "shared") == 0) &&
5728                         (strcmp(tokens[2], "shaper") == 0)) {
5729                         cmd_tmgr_shared_shaper(softnic, tokens, n_tokens, out, out_size);
5730                         return;
5731                 }
5732
5733                 if (n_tokens >= 2 &&
5734                         (strcmp(tokens[1], "node") == 0)) {
5735                         cmd_tmgr_node(softnic, tokens, n_tokens, out, out_size);
5736                         return;
5737                 }
5738
5739                 if (n_tokens >= 2 &&
5740                         (strcmp(tokens[1], "hierarchy-default") == 0)) {
5741                         cmd_tmgr_hierarchy_default(softnic, tokens, n_tokens, out, out_size);
5742                         return;
5743                 }
5744
5745                 if (n_tokens >= 3 &&
5746                         (strcmp(tokens[1], "hierarchy") == 0) &&
5747                         (strcmp(tokens[2], "commit") == 0)) {
5748                         cmd_tmgr_hierarchy_commit(softnic, tokens, n_tokens, out, out_size);
5749                         return;
5750                 }
5751         }
5752
5753         if (strcmp(tokens[0], "tap") == 0) {
5754                 cmd_tap(softnic, tokens, n_tokens, out, out_size);
5755                 return;
5756         }
5757
5758         if (strcmp(tokens[0], "cryptodev") == 0) {
5759                 cmd_cryptodev(softnic, tokens, n_tokens, out, out_size);
5760                 return;
5761         }
5762
5763         if (strcmp(tokens[0], "port") == 0) {
5764                 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size);
5765                 return;
5766         }
5767
5768         if (strcmp(tokens[0], "table") == 0) {
5769                 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size);
5770                 return;
5771         }
5772
5773         if (strcmp(tokens[0], "pipeline") == 0) {
5774                 if (n_tokens >= 3 &&
5775                         (strcmp(tokens[2], "period") == 0)) {
5776                         cmd_pipeline(softnic, tokens, n_tokens, out, out_size);
5777                         return;
5778                 }
5779
5780                 if (n_tokens >= 5 &&
5781                         (strcmp(tokens[2], "port") == 0) &&
5782                         (strcmp(tokens[3], "in") == 0) &&
5783                         (strcmp(tokens[4], "bsz") == 0)) {
5784                         cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size);
5785                         return;
5786                 }
5787
5788                 if (n_tokens >= 5 &&
5789                         (strcmp(tokens[2], "port") == 0) &&
5790                         (strcmp(tokens[3], "out") == 0) &&
5791                         (strcmp(tokens[4], "bsz") == 0)) {
5792                         cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size);
5793                         return;
5794                 }
5795
5796                 if (n_tokens >= 4 &&
5797                         (strcmp(tokens[2], "table") == 0) &&
5798                         (strcmp(tokens[3], "match") == 0)) {
5799                         cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size);
5800                         return;
5801                 }
5802
5803                 if (n_tokens >= 6 &&
5804                         (strcmp(tokens[2], "port") == 0) &&
5805                         (strcmp(tokens[3], "in") == 0) &&
5806                         (strcmp(tokens[5], "table") == 0)) {
5807                         cmd_pipeline_port_in_table(softnic, tokens, n_tokens,
5808                                 out, out_size);
5809                         return;
5810                 }
5811
5812                 if (n_tokens >= 6 &&
5813                         (strcmp(tokens[2], "port") == 0) &&
5814                         (strcmp(tokens[3], "in") == 0) &&
5815                         (strcmp(tokens[5], "stats") == 0)) {
5816                         cmd_pipeline_port_in_stats(softnic, tokens, n_tokens,
5817                                 out, out_size);
5818                         return;
5819                 }
5820
5821                 if (n_tokens >= 6 &&
5822                         (strcmp(tokens[2], "port") == 0) &&
5823                         (strcmp(tokens[3], "in") == 0) &&
5824                         (strcmp(tokens[5], "enable") == 0)) {
5825                         cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens,
5826                                 out, out_size);
5827                         return;
5828                 }
5829
5830                 if (n_tokens >= 6 &&
5831                         (strcmp(tokens[2], "port") == 0) &&
5832                         (strcmp(tokens[3], "in") == 0) &&
5833                         (strcmp(tokens[5], "disable") == 0)) {
5834                         cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens,
5835                                 out, out_size);
5836                         return;
5837                 }
5838
5839                 if (n_tokens >= 6 &&
5840                         (strcmp(tokens[2], "port") == 0) &&
5841                         (strcmp(tokens[3], "out") == 0) &&
5842                         (strcmp(tokens[5], "stats") == 0)) {
5843                         cmd_pipeline_port_out_stats(softnic, tokens, n_tokens,
5844                                 out, out_size);
5845                         return;
5846                 }
5847
5848                 if (n_tokens >= 5 &&
5849                         (strcmp(tokens[2], "table") == 0) &&
5850                         (strcmp(tokens[4], "stats") == 0)) {
5851                         cmd_pipeline_table_stats(softnic, tokens, n_tokens,
5852                                 out, out_size);
5853                         return;
5854                 }
5855
5856                 if (n_tokens >= 7 &&
5857                         (strcmp(tokens[2], "table") == 0) &&
5858                         (strcmp(tokens[4], "rule") == 0) &&
5859                         (strcmp(tokens[5], "add") == 0) &&
5860                         (strcmp(tokens[6], "match") == 0)) {
5861                         if (n_tokens >= 8 &&
5862                                 (strcmp(tokens[7], "default") == 0)) {
5863                                 cmd_softnic_pipeline_table_rule_add_default(softnic, tokens,
5864                                         n_tokens, out, out_size);
5865                                 return;
5866                         }
5867
5868                         cmd_softnic_pipeline_table_rule_add(softnic, tokens, n_tokens,
5869                                 out, out_size);
5870                         return;
5871                 }
5872
5873                 if (n_tokens >= 7 &&
5874                         (strcmp(tokens[2], "table") == 0) &&
5875                         (strcmp(tokens[4], "rule") == 0) &&
5876                         (strcmp(tokens[5], "add") == 0) &&
5877                         (strcmp(tokens[6], "bulk") == 0)) {
5878                         cmd_softnic_pipeline_table_rule_add_bulk(softnic, tokens,
5879                                 n_tokens, out, out_size);
5880                         return;
5881                 }
5882
5883                 if (n_tokens >= 7 &&
5884                         (strcmp(tokens[2], "table") == 0) &&
5885                         (strcmp(tokens[4], "rule") == 0) &&
5886                         (strcmp(tokens[5], "delete") == 0) &&
5887                         (strcmp(tokens[6], "match") == 0)) {
5888                         if (n_tokens >= 8 &&
5889                                 (strcmp(tokens[7], "default") == 0)) {
5890                                 cmd_softnic_pipeline_table_rule_delete_default(softnic, tokens,
5891                                         n_tokens, out, out_size);
5892                                 return;
5893                                 }
5894
5895                         cmd_softnic_pipeline_table_rule_delete(softnic, tokens, n_tokens,
5896                                 out, out_size);
5897                         return;
5898                 }
5899
5900                 if (n_tokens >= 7 &&
5901                         (strcmp(tokens[2], "table") == 0) &&
5902                         (strcmp(tokens[4], "rule") == 0) &&
5903                         (strcmp(tokens[5], "read") == 0) &&
5904                         (strcmp(tokens[6], "stats") == 0)) {
5905                         cmd_softnic_pipeline_table_rule_stats_read(softnic, tokens, n_tokens,
5906                                 out, out_size);
5907                         return;
5908                 }
5909
5910                 if (n_tokens >= 8 &&
5911                         (strcmp(tokens[2], "table") == 0) &&
5912                         (strcmp(tokens[4], "meter") == 0) &&
5913                         (strcmp(tokens[5], "profile") == 0) &&
5914                         (strcmp(tokens[7], "add") == 0)) {
5915                         cmd_pipeline_table_meter_profile_add(softnic, tokens, n_tokens,
5916                                 out, out_size);
5917                         return;
5918                 }
5919
5920                 if (n_tokens >= 8 &&
5921                         (strcmp(tokens[2], "table") == 0) &&
5922                         (strcmp(tokens[4], "meter") == 0) &&
5923                         (strcmp(tokens[5], "profile") == 0) &&
5924                         (strcmp(tokens[7], "delete") == 0)) {
5925                         cmd_pipeline_table_meter_profile_delete(softnic, tokens,
5926                                 n_tokens, out, out_size);
5927                         return;
5928                 }
5929
5930                 if (n_tokens >= 7 &&
5931                         (strcmp(tokens[2], "table") == 0) &&
5932                         (strcmp(tokens[4], "rule") == 0) &&
5933                         (strcmp(tokens[5], "read") == 0) &&
5934                         (strcmp(tokens[6], "meter") == 0)) {
5935                         cmd_pipeline_table_rule_meter_read(softnic, tokens, n_tokens,
5936                                 out, out_size);
5937                         return;
5938                 }
5939
5940                 if (n_tokens >= 5 &&
5941                         (strcmp(tokens[2], "table") == 0) &&
5942                         (strcmp(tokens[4], "dscp") == 0)) {
5943                         cmd_pipeline_table_dscp(softnic, tokens, n_tokens,
5944                                 out, out_size);
5945                         return;
5946                 }
5947
5948                 if (n_tokens >= 7 &&
5949                         (strcmp(tokens[2], "table") == 0) &&
5950                         (strcmp(tokens[4], "rule") == 0) &&
5951                         (strcmp(tokens[5], "read") == 0) &&
5952                         (strcmp(tokens[6], "ttl") == 0)) {
5953                         cmd_softnic_pipeline_table_rule_ttl_read(softnic, tokens, n_tokens,
5954                                 out, out_size);
5955                         return;
5956                 }
5957         }
5958
5959         if (strcmp(tokens[0], "thread") == 0) {
5960                 if (n_tokens >= 5 &&
5961                         (strcmp(tokens[4], "enable") == 0)) {
5962                         cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens,
5963                                 out, out_size);
5964                         return;
5965                 }
5966
5967                 if (n_tokens >= 5 &&
5968                         (strcmp(tokens[4], "disable") == 0)) {
5969                         cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens,
5970                                 out, out_size);
5971                         return;
5972                 }
5973         }
5974
5975         if (strcmp(tokens[0], "flowapi") == 0) {
5976                 cmd_softnic_flowapi_map(softnic, tokens, n_tokens, out,
5977                                         out_size);
5978                 return;
5979         }
5980
5981         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
5982 }
5983
5984 int
5985 softnic_cli_script_process(struct pmd_internals *softnic,
5986         const char *file_name,
5987         size_t msg_in_len_max,
5988         size_t msg_out_len_max)
5989 {
5990         char *msg_in = NULL, *msg_out = NULL;
5991         FILE *f = NULL;
5992
5993         /* Check input arguments */
5994         if (file_name == NULL ||
5995                 (strlen(file_name) == 0) ||
5996                 msg_in_len_max == 0 ||
5997                 msg_out_len_max == 0)
5998                 return -EINVAL;
5999
6000         msg_in = malloc(msg_in_len_max + 1);
6001         msg_out = malloc(msg_out_len_max + 1);
6002         if (msg_in == NULL ||
6003                 msg_out == NULL) {
6004                 free(msg_out);
6005                 free(msg_in);
6006                 return -ENOMEM;
6007         }
6008
6009         /* Open input file */
6010         f = fopen(file_name, "r");
6011         if (f == NULL) {
6012                 free(msg_out);
6013                 free(msg_in);
6014                 return -EIO;
6015         }
6016
6017         /* Read file */
6018         for ( ; ; ) {
6019                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6020                         break;
6021
6022                 printf("%s", msg_in);
6023                 msg_out[0] = 0;
6024
6025                 softnic_cli_process(msg_in,
6026                         msg_out,
6027                         msg_out_len_max,
6028                         softnic);
6029
6030                 if (strlen(msg_out))
6031                         printf("%s", msg_out);
6032         }
6033
6034         /* Close file */
6035         fclose(f);
6036         free(msg_out);
6037         free(msg_in);
6038         return 0;
6039 }
6040
6041 static int
6042 cli_rule_file_process(const char *file_name,
6043         size_t line_len_max,
6044         struct softnic_table_rule_match *m,
6045         struct softnic_table_rule_action *a,
6046         uint32_t *n_rules,
6047         uint32_t *line_number,
6048         char *out,
6049         size_t out_size)
6050 {
6051         FILE *f = NULL;
6052         char *line = NULL;
6053         uint32_t rule_id, line_id;
6054         int status = 0;
6055
6056         /* Check input arguments */
6057         if (file_name == NULL ||
6058                 (strlen(file_name) == 0) ||
6059                 line_len_max == 0) {
6060                 *line_number = 0;
6061                 return -EINVAL;
6062         }
6063
6064         /* Memory allocation */
6065         line = malloc(line_len_max + 1);
6066         if (line == NULL) {
6067                 *line_number = 0;
6068                 return -ENOMEM;
6069         }
6070
6071         /* Open file */
6072         f = fopen(file_name, "r");
6073         if (f == NULL) {
6074                 *line_number = 0;
6075                 free(line);
6076                 return -EIO;
6077         }
6078
6079         /* Read file */
6080         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
6081                 char *tokens[CMD_MAX_TOKENS];
6082                 uint32_t n_tokens, n_tokens_parsed, t0;
6083
6084                 /* Read next line from file. */
6085                 if (fgets(line, line_len_max + 1, f) == NULL)
6086                         break;
6087
6088                 /* Comment. */
6089                 if (is_comment(line))
6090                         continue;
6091
6092                 /* Parse line. */
6093                 n_tokens = RTE_DIM(tokens);
6094                 status = softnic_parse_tokenize_string(line, tokens, &n_tokens);
6095                 if (status) {
6096                         status = -EINVAL;
6097                         break;
6098                 }
6099
6100                 /* Empty line. */
6101                 if (n_tokens == 0)
6102                         continue;
6103                 t0 = 0;
6104
6105                 /* Rule match. */
6106                 n_tokens_parsed = parse_match(tokens + t0,
6107                         n_tokens - t0,
6108                         out,
6109                         out_size,
6110                         &m[rule_id]);
6111                 if (n_tokens_parsed == 0) {
6112                         status = -EINVAL;
6113                         break;
6114                 }
6115                 t0 += n_tokens_parsed;
6116
6117                 /* Rule action. */
6118                 n_tokens_parsed = parse_table_action(tokens + t0,
6119                         n_tokens - t0,
6120                         out,
6121                         out_size,
6122                         &a[rule_id]);
6123                 if (n_tokens_parsed == 0) {
6124                         status = -EINVAL;
6125                         break;
6126                 }
6127                 t0 += n_tokens_parsed;
6128
6129                 /* Line completed. */
6130                 if (t0 < n_tokens) {
6131                         status = -EINVAL;
6132                         break;
6133                 }
6134
6135                 /* Increment rule count */
6136                 rule_id++;
6137         }
6138
6139         /* Close file */
6140         fclose(f);
6141
6142         /* Memory free */
6143         free(line);
6144
6145         *n_rules = rule_id;
6146         *line_number = line_id;
6147         return status;
6148 }