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