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