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