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