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