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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 (params->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 free(p->cipher_auth.cipher_iv.val);
4486 free(p->cipher_auth.cipher_iv_update.val);
4487 break;
4488 case RTE_CRYPTO_SYM_XFORM_AUTH:
4489 if (p->cipher_auth.auth_iv.val)
4490 free(p->cipher_auth.cipher_iv.val);
4491 if (p->cipher_auth.auth_iv_update.val)
4492 free(p->cipher_auth.cipher_iv_update.val);
4493 break;
4494 case RTE_CRYPTO_SYM_XFORM_AEAD:
4495 free(p->aead.iv.val);
4496 free(p->aead.aad.val);
4497 break;
4498 default:
4499 continue;
4500 }
4501 }
4502
4503 }
4504
4505 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)4506 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p,
4507 uint8_t *key, uint32_t max_key_len, char **tokens,
4508 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
4509 {
4510 struct rte_crypto_sym_xform *xform_cipher;
4511 int status;
4512 size_t len;
4513
4514 if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") ||
4515 strcmp(tokens[3], "cipher_key") ||
4516 strcmp(tokens[5], "cipher_iv"))
4517 return NULL;
4518
4519 xform_cipher = calloc(1, sizeof(*xform_cipher));
4520 if (xform_cipher == NULL)
4521 return NULL;
4522
4523 xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
4524 xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT :
4525 RTE_CRYPTO_CIPHER_OP_DECRYPT;
4526
4527 /* cipher_algo */
4528 status = rte_cryptodev_get_cipher_algo_enum(
4529 &xform_cipher->cipher.algo, tokens[2]);
4530 if (status < 0)
4531 goto error_exit;
4532
4533 /* cipher_key */
4534 len = strlen(tokens[4]);
4535 if (len / 2 > max_key_len) {
4536 status = -ENOMEM;
4537 goto error_exit;
4538 }
4539
4540 status = softnic_parse_hex_string(tokens[4], key, (uint32_t *)&len);
4541 if (status < 0)
4542 goto error_exit;
4543
4544 xform_cipher->cipher.key.data = key;
4545 xform_cipher->cipher.key.length = (uint16_t)len;
4546
4547 /* cipher_iv */
4548 len = strlen(tokens[6]);
4549
4550 p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1);
4551 if (p->cipher_auth.cipher_iv.val == NULL)
4552 goto error_exit;
4553
4554 status = softnic_parse_hex_string(tokens[6],
4555 p->cipher_auth.cipher_iv.val,
4556 (uint32_t *)&len);
4557 if (status < 0)
4558 goto error_exit;
4559
4560 xform_cipher->cipher.iv.length = (uint16_t)len;
4561 xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
4562 p->cipher_auth.cipher_iv.length = (uint32_t)len;
4563 *used_n_tokens = 7;
4564
4565 return xform_cipher;
4566
4567 error_exit:
4568 if (p->cipher_auth.cipher_iv.val) {
4569 free(p->cipher_auth.cipher_iv.val);
4570 p->cipher_auth.cipher_iv.val = NULL;
4571 }
4572
4573 free(xform_cipher);
4574
4575 return NULL;
4576 }
4577
4578 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)4579 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p,
4580 uint8_t *key, uint32_t max_key_len, char **tokens,
4581 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
4582 {
4583 struct rte_crypto_sym_xform *xform_cipher;
4584 struct rte_crypto_sym_xform *xform_auth;
4585 int status;
4586 size_t len;
4587
4588 if (n_tokens < 13 ||
4589 strcmp(tokens[7], "auth_algo") ||
4590 strcmp(tokens[9], "auth_key") ||
4591 strcmp(tokens[11], "digest_size"))
4592 return NULL;
4593
4594 xform_auth = calloc(1, sizeof(*xform_auth));
4595 if (xform_auth == NULL)
4596 return NULL;
4597
4598 xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH;
4599 xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE :
4600 RTE_CRYPTO_AUTH_OP_VERIFY;
4601
4602 /* auth_algo */
4603 status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo,
4604 tokens[8]);
4605 if (status < 0)
4606 goto error_exit;
4607
4608 /* auth_key */
4609 len = strlen(tokens[10]);
4610 if (len / 2 > max_key_len) {
4611 status = -ENOMEM;
4612 goto error_exit;
4613 }
4614
4615 status = softnic_parse_hex_string(tokens[10], key, (uint32_t *)&len);
4616 if (status < 0)
4617 goto error_exit;
4618
4619 xform_auth->auth.key.data = key;
4620 xform_auth->auth.key.length = (uint16_t)len;
4621
4622 key += xform_auth->auth.key.length;
4623 max_key_len -= xform_auth->auth.key.length;
4624
4625 if (strcmp(tokens[11], "digest_size"))
4626 goto error_exit;
4627
4628 status = softnic_parser_read_uint16(&xform_auth->auth.digest_length,
4629 tokens[12]);
4630 if (status < 0)
4631 goto error_exit;
4632
4633 xform_cipher = parse_table_action_cipher(p, key, max_key_len, tokens, 7,
4634 encrypt, used_n_tokens);
4635 if (xform_cipher == NULL)
4636 goto error_exit;
4637
4638 *used_n_tokens += 6;
4639
4640 if (encrypt) {
4641 xform_cipher->next = xform_auth;
4642 return xform_cipher;
4643 } else {
4644 xform_auth->next = xform_cipher;
4645 return xform_auth;
4646 }
4647
4648 error_exit:
4649 if (p->cipher_auth.auth_iv.val) {
4650 free(p->cipher_auth.auth_iv.val);
4651 p->cipher_auth.auth_iv.val = 0;
4652 }
4653
4654 free(xform_auth);
4655
4656 return NULL;
4657 }
4658
4659 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)4660 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p,
4661 uint8_t *key, uint32_t max_key_len, char **tokens,
4662 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
4663 {
4664 struct rte_crypto_sym_xform *xform_aead;
4665 int status;
4666 size_t len;
4667
4668 if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") ||
4669 strcmp(tokens[3], "aead_key") ||
4670 strcmp(tokens[5], "aead_iv") ||
4671 strcmp(tokens[7], "aead_aad") ||
4672 strcmp(tokens[9], "digest_size"))
4673 return NULL;
4674
4675 xform_aead = calloc(1, sizeof(*xform_aead));
4676 if (xform_aead == NULL)
4677 return NULL;
4678
4679 xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD;
4680 xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT :
4681 RTE_CRYPTO_AEAD_OP_DECRYPT;
4682
4683 /* aead_algo */
4684 status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo,
4685 tokens[2]);
4686 if (status < 0)
4687 goto error_exit;
4688
4689 /* aead_key */
4690 len = strlen(tokens[4]);
4691 if (len / 2 > max_key_len) {
4692 status = -ENOMEM;
4693 goto error_exit;
4694 }
4695
4696 status = softnic_parse_hex_string(tokens[4], key, (uint32_t *)&len);
4697 if (status < 0)
4698 goto error_exit;
4699
4700 xform_aead->aead.key.data = key;
4701 xform_aead->aead.key.length = (uint16_t)len;
4702
4703 /* aead_iv */
4704 len = strlen(tokens[6]);
4705 p->aead.iv.val = calloc(1, len / 2 + 1);
4706 if (p->aead.iv.val == NULL)
4707 goto error_exit;
4708
4709 status = softnic_parse_hex_string(tokens[6], p->aead.iv.val,
4710 (uint32_t *)&len);
4711 if (status < 0)
4712 goto error_exit;
4713
4714 xform_aead->aead.iv.length = (uint16_t)len;
4715 xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
4716 p->aead.iv.length = (uint32_t)len;
4717
4718 /* aead_aad */
4719 len = strlen(tokens[8]);
4720 p->aead.aad.val = calloc(1, len / 2 + 1);
4721 if (p->aead.aad.val == NULL)
4722 goto error_exit;
4723
4724 status = softnic_parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len);
4725 if (status < 0)
4726 goto error_exit;
4727
4728 xform_aead->aead.aad_length = (uint16_t)len;
4729 p->aead.aad.length = (uint32_t)len;
4730
4731 /* digest_size */
4732 status = softnic_parser_read_uint16(&xform_aead->aead.digest_length,
4733 tokens[10]);
4734 if (status < 0)
4735 goto error_exit;
4736
4737 *used_n_tokens = 11;
4738
4739 return xform_aead;
4740
4741 error_exit:
4742 if (p->aead.iv.val) {
4743 free(p->aead.iv.val);
4744 p->aead.iv.val = NULL;
4745 }
4746 if (p->aead.aad.val) {
4747 free(p->aead.aad.val);
4748 p->aead.aad.val = NULL;
4749 }
4750
4751 free(xform_aead);
4752
4753 return NULL;
4754 }
4755
4756
4757 static uint32_t
parse_table_action_sym_crypto(char ** tokens,uint32_t n_tokens,struct softnic_table_rule_action * a)4758 parse_table_action_sym_crypto(char **tokens,
4759 uint32_t n_tokens,
4760 struct softnic_table_rule_action *a)
4761 {
4762 struct rte_table_action_sym_crypto_params *p = &a->sym_crypto;
4763 struct rte_crypto_sym_xform *xform = NULL;
4764 uint8_t *key = a->sym_crypto_key;
4765 uint32_t max_key_len = SYM_CRYPTO_MAX_KEY_SIZE;
4766 uint32_t used_n_tokens;
4767 uint32_t encrypt;
4768 int status;
4769
4770 if ((n_tokens < 12) ||
4771 strcmp(tokens[0], "sym_crypto") ||
4772 strcmp(tokens[2], "type"))
4773 return 0;
4774
4775 memset(p, 0, sizeof(*p));
4776
4777 if (strcmp(tokens[1], "encrypt") == 0)
4778 encrypt = 1;
4779 else
4780 encrypt = 0;
4781
4782 status = softnic_parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]);
4783 if (status < 0)
4784 return 0;
4785
4786 if (strcmp(tokens[3], "cipher") == 0) {
4787 tokens += 3;
4788 n_tokens -= 3;
4789
4790 xform = parse_table_action_cipher(p, key, max_key_len, tokens,
4791 n_tokens, encrypt, &used_n_tokens);
4792 } else if (strcmp(tokens[3], "cipher_auth") == 0) {
4793 tokens += 3;
4794 n_tokens -= 3;
4795
4796 xform = parse_table_action_cipher_auth(p, key, max_key_len,
4797 tokens, n_tokens, encrypt, &used_n_tokens);
4798 } else if (strcmp(tokens[3], "aead") == 0) {
4799 tokens += 3;
4800 n_tokens -= 3;
4801
4802 xform = parse_table_action_aead(p, key, max_key_len, tokens,
4803 n_tokens, encrypt, &used_n_tokens);
4804 }
4805
4806 if (xform == NULL)
4807 return 0;
4808
4809 p->xform = xform;
4810
4811 if (strcmp(tokens[used_n_tokens], "data_offset")) {
4812 parse_free_sym_crypto_param_data(p);
4813 return 0;
4814 }
4815
4816 a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO;
4817
4818 return used_n_tokens + 5;
4819 }
4820
4821 static uint32_t
parse_table_action_tag(char ** tokens,uint32_t n_tokens,struct softnic_table_rule_action * a)4822 parse_table_action_tag(char **tokens,
4823 uint32_t n_tokens,
4824 struct softnic_table_rule_action *a)
4825 {
4826 if (n_tokens < 2 ||
4827 strcmp(tokens[0], "tag"))
4828 return 0;
4829
4830 if (softnic_parser_read_uint32(&a->tag.tag, tokens[1]))
4831 return 0;
4832
4833 a->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
4834 return 2;
4835 }
4836
4837 static uint32_t
parse_table_action_decap(char ** tokens,uint32_t n_tokens,struct softnic_table_rule_action * a)4838 parse_table_action_decap(char **tokens,
4839 uint32_t n_tokens,
4840 struct softnic_table_rule_action *a)
4841 {
4842 if (n_tokens < 2 ||
4843 strcmp(tokens[0], "decap"))
4844 return 0;
4845
4846 if (softnic_parser_read_uint16(&a->decap.n, tokens[1]))
4847 return 0;
4848
4849 a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
4850 return 2;
4851 }
4852
4853 static uint32_t
parse_table_action(char ** tokens,uint32_t n_tokens,char * out,size_t out_size,struct softnic_table_rule_action * a)4854 parse_table_action(char **tokens,
4855 uint32_t n_tokens,
4856 char *out,
4857 size_t out_size,
4858 struct softnic_table_rule_action *a)
4859 {
4860 uint32_t n_tokens0 = n_tokens;
4861
4862 memset(a, 0, sizeof(*a));
4863
4864 if (n_tokens < 2 ||
4865 strcmp(tokens[0], "action"))
4866 return 0;
4867
4868 tokens++;
4869 n_tokens--;
4870
4871 if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
4872 uint32_t n;
4873
4874 n = parse_table_action_fwd(tokens, n_tokens, a);
4875 if (n == 0) {
4876 snprintf(out, out_size, MSG_ARG_INVALID,
4877 "action fwd");
4878 return 0;
4879 }
4880
4881 tokens += n;
4882 n_tokens -= n;
4883 }
4884
4885 if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
4886 uint32_t n;
4887
4888 n = parse_table_action_balance(tokens, n_tokens, a);
4889 if (n == 0) {
4890 snprintf(out, out_size, MSG_ARG_INVALID,
4891 "action balance");
4892 return 0;
4893 }
4894
4895 tokens += n;
4896 n_tokens -= n;
4897 }
4898
4899 if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
4900 uint32_t n;
4901
4902 n = parse_table_action_meter(tokens, n_tokens, a);
4903 if (n == 0) {
4904 snprintf(out, out_size, MSG_ARG_INVALID,
4905 "action meter");
4906 return 0;
4907 }
4908
4909 tokens += n;
4910 n_tokens -= n;
4911 }
4912
4913 if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
4914 uint32_t n;
4915
4916 n = parse_table_action_tm(tokens, n_tokens, a);
4917 if (n == 0) {
4918 snprintf(out, out_size, MSG_ARG_INVALID,
4919 "action tm");
4920 return 0;
4921 }
4922
4923 tokens += n;
4924 n_tokens -= n;
4925 }
4926
4927 if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
4928 uint32_t n;
4929
4930 n = parse_table_action_encap(tokens, n_tokens, a);
4931 if (n == 0) {
4932 snprintf(out, out_size, MSG_ARG_INVALID,
4933 "action encap");
4934 return 0;
4935 }
4936
4937 tokens += n;
4938 n_tokens -= n;
4939 }
4940
4941 if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
4942 uint32_t n;
4943
4944 n = parse_table_action_nat(tokens, n_tokens, a);
4945 if (n == 0) {
4946 snprintf(out, out_size, MSG_ARG_INVALID,
4947 "action nat");
4948 return 0;
4949 }
4950
4951 tokens += n;
4952 n_tokens -= n;
4953 }
4954
4955 if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
4956 uint32_t n;
4957
4958 n = parse_table_action_ttl(tokens, n_tokens, a);
4959 if (n == 0) {
4960 snprintf(out, out_size, MSG_ARG_INVALID,
4961 "action ttl");
4962 return 0;
4963 }
4964
4965 tokens += n;
4966 n_tokens -= n;
4967 }
4968
4969 if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
4970 uint32_t n;
4971
4972 n = parse_table_action_stats(tokens, n_tokens, a);
4973 if (n == 0) {
4974 snprintf(out, out_size, MSG_ARG_INVALID,
4975 "action stats");
4976 return 0;
4977 }
4978
4979 tokens += n;
4980 n_tokens -= n;
4981 }
4982
4983 if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
4984 uint32_t n;
4985
4986 n = parse_table_action_time(tokens, n_tokens, a);
4987 if (n == 0) {
4988 snprintf(out, out_size, MSG_ARG_INVALID,
4989 "action time");
4990 return 0;
4991 }
4992
4993 tokens += n;
4994 n_tokens -= n;
4995 }
4996
4997 if (n_tokens && (strcmp(tokens[0], "tag") == 0)) {
4998 uint32_t n;
4999
5000 n = parse_table_action_tag(tokens, n_tokens, a);
5001 if (n == 0) {
5002 snprintf(out, out_size, MSG_ARG_INVALID,
5003 "action tag");
5004 return 0;
5005 }
5006
5007 tokens += n;
5008 n_tokens -= n;
5009 }
5010
5011 if (n_tokens && (strcmp(tokens[0], "decap") == 0)) {
5012 uint32_t n;
5013
5014 n = parse_table_action_decap(tokens, n_tokens, a);
5015 if (n == 0) {
5016 snprintf(out, out_size, MSG_ARG_INVALID,
5017 "action decap");
5018 return 0;
5019 }
5020
5021 tokens += n;
5022 n_tokens -= n;
5023 }
5024
5025 if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) {
5026 uint32_t n;
5027
5028 n = parse_table_action_sym_crypto(tokens, n_tokens, a);
5029 if (n == 0) {
5030 snprintf(out, out_size, MSG_ARG_INVALID,
5031 "action sym_crypto");
5032 }
5033
5034 tokens += n;
5035 n_tokens -= n;
5036 }
5037
5038 if (n_tokens0 - n_tokens == 1) {
5039 snprintf(out, out_size, MSG_ARG_INVALID, "action");
5040 return 0;
5041 }
5042
5043 return n_tokens0 - n_tokens;
5044 }
5045
5046 /**
5047 * pipeline <pipeline_name> table <table_id> rule add
5048 * match <match>
5049 * action <table_action>
5050 */
5051 static void
cmd_softnic_pipeline_table_rule_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5052 cmd_softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
5053 char **tokens,
5054 uint32_t n_tokens,
5055 char *out,
5056 size_t out_size)
5057 {
5058 struct softnic_table_rule_match m;
5059 struct softnic_table_rule_action a;
5060 char *pipeline_name;
5061 void *data;
5062 uint32_t table_id, t0, n_tokens_parsed;
5063 int status;
5064
5065 if (n_tokens < 8) {
5066 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5067 return;
5068 }
5069
5070 pipeline_name = tokens[1];
5071
5072 if (strcmp(tokens[2], "table") != 0) {
5073 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5074 return;
5075 }
5076
5077 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5078 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5079 return;
5080 }
5081
5082 if (strcmp(tokens[4], "rule") != 0) {
5083 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5084 return;
5085 }
5086
5087 if (strcmp(tokens[5], "add") != 0) {
5088 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5089 return;
5090 }
5091
5092 t0 = 6;
5093
5094 /* match */
5095 n_tokens_parsed = parse_match(tokens + t0,
5096 n_tokens - t0,
5097 out,
5098 out_size,
5099 &m);
5100 if (n_tokens_parsed == 0)
5101 return;
5102 t0 += n_tokens_parsed;
5103
5104 /* action */
5105 n_tokens_parsed = parse_table_action(tokens + t0,
5106 n_tokens - t0,
5107 out,
5108 out_size,
5109 &a);
5110 if (n_tokens_parsed == 0)
5111 return;
5112 t0 += n_tokens_parsed;
5113
5114 if (t0 != n_tokens) {
5115 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5116 return;
5117 }
5118
5119 status = softnic_pipeline_table_rule_add(softnic,
5120 pipeline_name,
5121 table_id,
5122 &m,
5123 &a,
5124 &data);
5125 if (status) {
5126 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5127 return;
5128 }
5129 }
5130
5131 /**
5132 * pipeline <pipeline_name> table <table_id> rule add
5133 * match
5134 * default
5135 * action
5136 * fwd
5137 * drop
5138 * | port <port_id>
5139 * | meta
5140 * | table <table_id>
5141 */
5142 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)5143 cmd_softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
5144 char **tokens,
5145 uint32_t n_tokens,
5146 char *out,
5147 size_t out_size)
5148 {
5149 struct softnic_table_rule_action action;
5150 void *data;
5151 char *pipeline_name;
5152 uint32_t table_id;
5153 int status;
5154
5155 if (n_tokens != 11 &&
5156 n_tokens != 12) {
5157 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5158 return;
5159 }
5160
5161 pipeline_name = tokens[1];
5162
5163 if (strcmp(tokens[2], "table") != 0) {
5164 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5165 return;
5166 }
5167
5168 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5169 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5170 return;
5171 }
5172
5173 if (strcmp(tokens[4], "rule") != 0) {
5174 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5175 return;
5176 }
5177
5178 if (strcmp(tokens[5], "add") != 0) {
5179 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5180 return;
5181 }
5182
5183 if (strcmp(tokens[6], "match") != 0) {
5184 snprintf(out, out_size, MSG_ARG_INVALID, "match");
5185 return;
5186 }
5187
5188 if (strcmp(tokens[7], "default") != 0) {
5189 snprintf(out, out_size, MSG_ARG_INVALID, "default");
5190 return;
5191 }
5192
5193 if (strcmp(tokens[8], "action") != 0) {
5194 snprintf(out, out_size, MSG_ARG_INVALID, "action");
5195 return;
5196 }
5197
5198 if (strcmp(tokens[9], "fwd") != 0) {
5199 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
5200 return;
5201 }
5202
5203 action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
5204
5205 if (strcmp(tokens[10], "drop") == 0) {
5206 if (n_tokens != 11) {
5207 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5208 return;
5209 }
5210
5211 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
5212 } else if (strcmp(tokens[10], "port") == 0) {
5213 uint32_t id;
5214
5215 if (n_tokens != 12) {
5216 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5217 return;
5218 }
5219
5220 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
5221 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
5222 return;
5223 }
5224
5225 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
5226 action.fwd.id = id;
5227 } else if (strcmp(tokens[10], "meta") == 0) {
5228 if (n_tokens != 11) {
5229 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5230 return;
5231 }
5232
5233 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
5234 } else if (strcmp(tokens[10], "table") == 0) {
5235 uint32_t id;
5236
5237 if (n_tokens != 12) {
5238 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5239 return;
5240 }
5241
5242 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
5243 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5244 return;
5245 }
5246
5247 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
5248 action.fwd.id = id;
5249 } else {
5250 snprintf(out, out_size, MSG_ARG_INVALID,
5251 "drop or port or meta or table");
5252 return;
5253 }
5254
5255 status = softnic_pipeline_table_rule_add_default(softnic,
5256 pipeline_name,
5257 table_id,
5258 &action,
5259 &data);
5260 if (status) {
5261 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5262 return;
5263 }
5264 }
5265
5266 /**
5267 * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
5268 *
5269 * File <file_name>:
5270 * - line format: match <match> action <action>
5271 */
5272 static int
5273 cli_rule_file_process(const char *file_name,
5274 size_t line_len_max,
5275 struct softnic_table_rule_match *m,
5276 struct softnic_table_rule_action *a,
5277 uint32_t *n_rules,
5278 uint32_t *line_number,
5279 char *out,
5280 size_t out_size);
5281
5282 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)5283 cmd_softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
5284 char **tokens,
5285 uint32_t n_tokens,
5286 char *out,
5287 size_t out_size)
5288 {
5289 struct softnic_table_rule_match *match;
5290 struct softnic_table_rule_action *action;
5291 void **data;
5292 char *pipeline_name, *file_name;
5293 uint32_t table_id, n_rules, n_rules_parsed, line_number;
5294 int status;
5295
5296 if (n_tokens != 9) {
5297 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5298 return;
5299 }
5300
5301 pipeline_name = tokens[1];
5302
5303 if (strcmp(tokens[2], "table") != 0) {
5304 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5305 return;
5306 }
5307
5308 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5309 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5310 return;
5311 }
5312
5313 if (strcmp(tokens[4], "rule") != 0) {
5314 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5315 return;
5316 }
5317
5318 if (strcmp(tokens[5], "add") != 0) {
5319 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5320 return;
5321 }
5322
5323 if (strcmp(tokens[6], "bulk") != 0) {
5324 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
5325 return;
5326 }
5327
5328 file_name = tokens[7];
5329
5330 if ((softnic_parser_read_uint32(&n_rules, tokens[8]) != 0) ||
5331 n_rules == 0) {
5332 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
5333 return;
5334 }
5335
5336 /* Memory allocation. */
5337 match = calloc(n_rules, sizeof(struct softnic_table_rule_match));
5338 action = calloc(n_rules, sizeof(struct softnic_table_rule_action));
5339 data = calloc(n_rules, sizeof(void *));
5340 if (match == NULL ||
5341 action == NULL ||
5342 data == NULL) {
5343 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
5344 free(data);
5345 free(action);
5346 free(match);
5347 return;
5348 }
5349
5350 /* Load rule file */
5351 n_rules_parsed = n_rules;
5352 status = cli_rule_file_process(file_name,
5353 1024,
5354 match,
5355 action,
5356 &n_rules_parsed,
5357 &line_number,
5358 out,
5359 out_size);
5360 if (status) {
5361 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5362 free(data);
5363 free(action);
5364 free(match);
5365 return;
5366 }
5367 if (n_rules_parsed != n_rules) {
5368 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
5369 free(data);
5370 free(action);
5371 free(match);
5372 return;
5373 }
5374
5375 /* Rule bulk add */
5376 status = softnic_pipeline_table_rule_add_bulk(softnic,
5377 pipeline_name,
5378 table_id,
5379 match,
5380 action,
5381 data,
5382 &n_rules);
5383 if (status) {
5384 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5385 free(data);
5386 free(action);
5387 free(match);
5388 return;
5389 }
5390
5391 /* Memory free */
5392 free(data);
5393 free(action);
5394 free(match);
5395 }
5396
5397 /**
5398 * pipeline <pipeline_name> table <table_id> rule delete
5399 * match <match>
5400 */
5401 static void
cmd_softnic_pipeline_table_rule_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5402 cmd_softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
5403 char **tokens,
5404 uint32_t n_tokens,
5405 char *out,
5406 size_t out_size)
5407 {
5408 struct softnic_table_rule_match m;
5409 char *pipeline_name;
5410 uint32_t table_id, n_tokens_parsed, t0;
5411 int status;
5412
5413 if (n_tokens < 8) {
5414 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5415 return;
5416 }
5417
5418 pipeline_name = tokens[1];
5419
5420 if (strcmp(tokens[2], "table") != 0) {
5421 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5422 return;
5423 }
5424
5425 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5426 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5427 return;
5428 }
5429
5430 if (strcmp(tokens[4], "rule") != 0) {
5431 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5432 return;
5433 }
5434
5435 if (strcmp(tokens[5], "delete") != 0) {
5436 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5437 return;
5438 }
5439
5440 t0 = 6;
5441
5442 /* match */
5443 n_tokens_parsed = parse_match(tokens + t0,
5444 n_tokens - t0,
5445 out,
5446 out_size,
5447 &m);
5448 if (n_tokens_parsed == 0)
5449 return;
5450 t0 += n_tokens_parsed;
5451
5452 if (n_tokens != t0) {
5453 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5454 return;
5455 }
5456
5457 status = softnic_pipeline_table_rule_delete(softnic,
5458 pipeline_name,
5459 table_id,
5460 &m);
5461 if (status) {
5462 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5463 return;
5464 }
5465 }
5466
5467 /**
5468 * pipeline <pipeline_name> table <table_id> rule delete
5469 * match
5470 * default
5471 */
5472 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)5473 cmd_softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
5474 char **tokens,
5475 uint32_t n_tokens,
5476 char *out,
5477 size_t out_size)
5478 {
5479 char *pipeline_name;
5480 uint32_t table_id;
5481 int status;
5482
5483 if (n_tokens != 8) {
5484 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5485 return;
5486 }
5487
5488 pipeline_name = tokens[1];
5489
5490 if (strcmp(tokens[2], "table") != 0) {
5491 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5492 return;
5493 }
5494
5495 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5496 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5497 return;
5498 }
5499
5500 if (strcmp(tokens[4], "rule") != 0) {
5501 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5502 return;
5503 }
5504
5505 if (strcmp(tokens[5], "delete") != 0) {
5506 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5507 return;
5508 }
5509
5510 if (strcmp(tokens[6], "match") != 0) {
5511 snprintf(out, out_size, MSG_ARG_INVALID, "match");
5512 return;
5513 }
5514
5515 if (strcmp(tokens[7], "default") != 0) {
5516 snprintf(out, out_size, MSG_ARG_INVALID, "default");
5517 return;
5518 }
5519
5520 status = softnic_pipeline_table_rule_delete_default(softnic,
5521 pipeline_name,
5522 table_id);
5523 if (status) {
5524 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5525 return;
5526 }
5527 }
5528
5529 /**
5530 * pipeline <pipeline_name> table <table_id> rule read stats [clear]
5531 */
5532 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)5533 cmd_softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic __rte_unused,
5534 char **tokens,
5535 uint32_t n_tokens __rte_unused,
5536 char *out,
5537 size_t out_size)
5538 {
5539 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5540 }
5541
5542 /**
5543 * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
5544 * add srtcm cir <cir> cbs <cbs> ebs <ebs>
5545 * | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
5546 */
5547 static void
cmd_pipeline_table_meter_profile_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5548 cmd_pipeline_table_meter_profile_add(struct pmd_internals *softnic,
5549 char **tokens,
5550 uint32_t n_tokens,
5551 char *out,
5552 size_t out_size)
5553 {
5554 struct rte_table_action_meter_profile p;
5555 char *pipeline_name;
5556 uint32_t table_id, meter_profile_id;
5557 int status;
5558
5559 if (n_tokens < 9) {
5560 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5561 return;
5562 }
5563
5564 pipeline_name = tokens[1];
5565
5566 if (strcmp(tokens[2], "table") != 0) {
5567 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5568 return;
5569 }
5570
5571 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5572 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5573 return;
5574 }
5575
5576 if (strcmp(tokens[4], "meter") != 0) {
5577 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5578 return;
5579 }
5580
5581 if (strcmp(tokens[5], "profile") != 0) {
5582 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5583 return;
5584 }
5585
5586 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5587 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5588 return;
5589 }
5590
5591 if (strcmp(tokens[7], "add") != 0) {
5592 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5593 return;
5594 }
5595
5596 if (strcmp(tokens[8], "srtcm") == 0) {
5597 if (n_tokens != 15) {
5598 snprintf(out, out_size, MSG_ARG_MISMATCH,
5599 tokens[0]);
5600 return;
5601 }
5602
5603 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
5604
5605 if (strcmp(tokens[9], "cir") != 0) {
5606 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5607 return;
5608 }
5609
5610 if (softnic_parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
5611 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5612 return;
5613 }
5614
5615 if (strcmp(tokens[11], "cbs") != 0) {
5616 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5617 return;
5618 }
5619
5620 if (softnic_parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
5621 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5622 return;
5623 }
5624
5625 if (strcmp(tokens[13], "ebs") != 0) {
5626 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
5627 return;
5628 }
5629
5630 if (softnic_parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
5631 snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
5632 return;
5633 }
5634 } else if (strcmp(tokens[8], "trtcm") == 0) {
5635 if (n_tokens != 17) {
5636 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5637 return;
5638 }
5639
5640 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
5641
5642 if (strcmp(tokens[9], "cir") != 0) {
5643 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5644 return;
5645 }
5646
5647 if (softnic_parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
5648 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5649 return;
5650 }
5651
5652 if (strcmp(tokens[11], "pir") != 0) {
5653 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
5654 return;
5655 }
5656
5657 if (softnic_parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
5658 snprintf(out, out_size, MSG_ARG_INVALID, "pir");
5659 return;
5660 }
5661 if (strcmp(tokens[13], "cbs") != 0) {
5662 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5663 return;
5664 }
5665
5666 if (softnic_parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
5667 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5668 return;
5669 }
5670
5671 if (strcmp(tokens[15], "pbs") != 0) {
5672 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
5673 return;
5674 }
5675
5676 if (softnic_parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
5677 snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
5678 return;
5679 }
5680 } else {
5681 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5682 return;
5683 }
5684
5685 status = softnic_pipeline_table_mtr_profile_add(softnic,
5686 pipeline_name,
5687 table_id,
5688 meter_profile_id,
5689 &p);
5690 if (status) {
5691 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5692 return;
5693 }
5694 }
5695
5696 /**
5697 * pipeline <pipeline_name> table <table_id>
5698 * meter profile <meter_profile_id> delete
5699 */
5700 static void
cmd_pipeline_table_meter_profile_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5701 cmd_pipeline_table_meter_profile_delete(struct pmd_internals *softnic,
5702 char **tokens,
5703 uint32_t n_tokens,
5704 char *out,
5705 size_t out_size)
5706 {
5707 char *pipeline_name;
5708 uint32_t table_id, meter_profile_id;
5709 int status;
5710
5711 if (n_tokens != 8) {
5712 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5713 return;
5714 }
5715
5716 pipeline_name = tokens[1];
5717
5718 if (strcmp(tokens[2], "table") != 0) {
5719 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5720 return;
5721 }
5722
5723 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5724 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5725 return;
5726 }
5727
5728 if (strcmp(tokens[4], "meter") != 0) {
5729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5730 return;
5731 }
5732
5733 if (strcmp(tokens[5], "profile") != 0) {
5734 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5735 return;
5736 }
5737
5738 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5739 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5740 return;
5741 }
5742
5743 if (strcmp(tokens[7], "delete") != 0) {
5744 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5745 return;
5746 }
5747
5748 status = softnic_pipeline_table_mtr_profile_delete(softnic,
5749 pipeline_name,
5750 table_id,
5751 meter_profile_id);
5752 if (status) {
5753 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5754 return;
5755 }
5756 }
5757
5758 /**
5759 * pipeline <pipeline_name> table <table_id> rule read meter [clear]
5760 */
5761 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)5762 cmd_pipeline_table_rule_meter_read(struct pmd_internals *softnic __rte_unused,
5763 char **tokens,
5764 uint32_t n_tokens __rte_unused,
5765 char *out,
5766 size_t out_size)
5767 {
5768 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5769 }
5770
5771 /**
5772 * pipeline <pipeline_name> table <table_id> dscp <file_name>
5773 *
5774 * File <file_name>:
5775 * - exactly 64 lines
5776 * - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
5777 */
5778 static int
load_dscp_table(struct rte_table_action_dscp_table * dscp_table,const char * file_name,uint32_t * line_number)5779 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5780 const char *file_name,
5781 uint32_t *line_number)
5782 {
5783 FILE *f = NULL;
5784 uint32_t dscp, l;
5785
5786 /* Check input arguments */
5787 if (dscp_table == NULL ||
5788 file_name == NULL ||
5789 line_number == NULL) {
5790 if (line_number)
5791 *line_number = 0;
5792 return -EINVAL;
5793 }
5794
5795 /* Open input file */
5796 f = fopen(file_name, "r");
5797 if (f == NULL) {
5798 *line_number = 0;
5799 return -EINVAL;
5800 }
5801
5802 /* Read file */
5803 for (dscp = 0, l = 1; ; l++) {
5804 char line[64];
5805 char *tokens[3];
5806 enum rte_color color;
5807 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5808
5809 if (fgets(line, sizeof(line), f) == NULL)
5810 break;
5811
5812 if (is_comment(line))
5813 continue;
5814
5815 if (softnic_parse_tokenize_string(line, tokens, &n_tokens)) {
5816 *line_number = l;
5817 fclose(f);
5818 return -EINVAL;
5819 }
5820
5821 if (n_tokens == 0)
5822 continue;
5823
5824 if (dscp >= RTE_DIM(dscp_table->entry) ||
5825 n_tokens != RTE_DIM(tokens) ||
5826 softnic_parser_read_uint32(&tc_id, tokens[0]) ||
5827 tc_id >= RTE_TABLE_ACTION_TC_MAX ||
5828 softnic_parser_read_uint32(&tc_queue_id, tokens[1]) ||
5829 tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX ||
5830 (strlen(tokens[2]) != 1)) {
5831 *line_number = l;
5832 fclose(f);
5833 return -EINVAL;
5834 }
5835
5836 switch (tokens[2][0]) {
5837 case 'g':
5838 case 'G':
5839 color = RTE_COLOR_GREEN;
5840 break;
5841
5842 case 'y':
5843 case 'Y':
5844 color = RTE_COLOR_YELLOW;
5845 break;
5846
5847 case 'r':
5848 case 'R':
5849 color = RTE_COLOR_RED;
5850 break;
5851
5852 default:
5853 *line_number = l;
5854 fclose(f);
5855 return -EINVAL;
5856 }
5857
5858 dscp_table->entry[dscp].tc_id = tc_id;
5859 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5860 dscp_table->entry[dscp].color = color;
5861 dscp++;
5862 }
5863
5864 /* Close file */
5865 fclose(f);
5866 return 0;
5867 }
5868
5869 static void
cmd_pipeline_table_dscp(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5870 cmd_pipeline_table_dscp(struct pmd_internals *softnic,
5871 char **tokens,
5872 uint32_t n_tokens,
5873 char *out,
5874 size_t out_size)
5875 {
5876 struct rte_table_action_dscp_table dscp_table;
5877 char *pipeline_name, *file_name;
5878 uint32_t table_id, line_number;
5879 int status;
5880
5881 if (n_tokens != 6) {
5882 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5883 return;
5884 }
5885
5886 pipeline_name = tokens[1];
5887
5888 if (strcmp(tokens[2], "table") != 0) {
5889 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5890 return;
5891 }
5892
5893 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
5894 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5895 return;
5896 }
5897
5898 if (strcmp(tokens[4], "dscp") != 0) {
5899 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5900 return;
5901 }
5902
5903 file_name = tokens[5];
5904
5905 status = load_dscp_table(&dscp_table, file_name, &line_number);
5906 if (status) {
5907 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5908 return;
5909 }
5910
5911 status = softnic_pipeline_table_dscp_table_update(softnic,
5912 pipeline_name,
5913 table_id,
5914 UINT64_MAX,
5915 &dscp_table);
5916 if (status) {
5917 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5918 return;
5919 }
5920 }
5921
5922 /**
5923 * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
5924 */
5925 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)5926 cmd_softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic __rte_unused,
5927 char **tokens,
5928 uint32_t n_tokens __rte_unused,
5929 char *out,
5930 size_t out_size)
5931 {
5932 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5933 }
5934
5935 /**
5936 * thread <thread_id> pipeline <pipeline_name> enable
5937 */
5938 static void
cmd_softnic_thread_pipeline_enable(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5939 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
5940 char **tokens,
5941 uint32_t n_tokens,
5942 char *out,
5943 size_t out_size)
5944 {
5945 char *pipeline_name;
5946 uint32_t thread_id;
5947 int status;
5948
5949 if (n_tokens != 5) {
5950 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5951 return;
5952 }
5953
5954 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
5955 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5956 return;
5957 }
5958
5959 if (strcmp(tokens[2], "pipeline") != 0) {
5960 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5961 return;
5962 }
5963
5964 pipeline_name = tokens[3];
5965
5966 if (strcmp(tokens[4], "enable") != 0) {
5967 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5968 return;
5969 }
5970
5971 status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name);
5972 if (status) {
5973 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5974 return;
5975 }
5976 }
5977
5978 /**
5979 * thread <thread_id> pipeline <pipeline_name> disable
5980 */
5981 static void
cmd_softnic_thread_pipeline_disable(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)5982 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
5983 char **tokens,
5984 uint32_t n_tokens,
5985 char *out,
5986 size_t out_size)
5987 {
5988 char *pipeline_name;
5989 uint32_t thread_id;
5990 int status;
5991
5992 if (n_tokens != 5) {
5993 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5994 return;
5995 }
5996
5997 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
5998 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5999 return;
6000 }
6001
6002 if (strcmp(tokens[2], "pipeline") != 0) {
6003 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
6004 return;
6005 }
6006
6007 pipeline_name = tokens[3];
6008
6009 if (strcmp(tokens[4], "disable") != 0) {
6010 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
6011 return;
6012 }
6013
6014 status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name);
6015 if (status) {
6016 snprintf(out, out_size, MSG_CMD_FAIL,
6017 "thread pipeline disable");
6018 return;
6019 }
6020 }
6021
6022 /**
6023 * flowapi map
6024 * group <group_id>
6025 * ingress | egress
6026 * pipeline <pipeline_name>
6027 * table <table_id>
6028 */
6029 static void
cmd_softnic_flowapi_map(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)6030 cmd_softnic_flowapi_map(struct pmd_internals *softnic,
6031 char **tokens,
6032 uint32_t n_tokens,
6033 char *out,
6034 size_t out_size)
6035 {
6036 char *pipeline_name;
6037 uint32_t group_id, table_id;
6038 int ingress, status;
6039
6040 if (n_tokens != 9) {
6041 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
6042 return;
6043 }
6044
6045 if (strcmp(tokens[1], "map") != 0) {
6046 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "map");
6047 return;
6048 }
6049
6050 if (strcmp(tokens[2], "group") != 0) {
6051 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group");
6052 return;
6053 }
6054
6055 if (softnic_parser_read_uint32(&group_id, tokens[3]) != 0) {
6056 snprintf(out, out_size, MSG_ARG_INVALID, "group_id");
6057 return;
6058 }
6059
6060 if (strcmp(tokens[4], "ingress") == 0) {
6061 ingress = 1;
6062 } else if (strcmp(tokens[4], "egress") == 0) {
6063 ingress = 0;
6064 } else {
6065 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ingress | egress");
6066 return;
6067 }
6068
6069 if (strcmp(tokens[5], "pipeline") != 0) {
6070 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
6071 return;
6072 }
6073
6074 pipeline_name = tokens[6];
6075
6076 if (strcmp(tokens[7], "table") != 0) {
6077 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
6078 return;
6079 }
6080
6081 if (softnic_parser_read_uint32(&table_id, tokens[8]) != 0) {
6082 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
6083 return;
6084 }
6085
6086 status = flow_attr_map_set(softnic,
6087 group_id,
6088 ingress,
6089 pipeline_name,
6090 table_id);
6091 if (status) {
6092 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
6093 return;
6094 }
6095 }
6096
6097 void
softnic_cli_process(char * in,char * out,size_t out_size,void * arg)6098 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
6099 {
6100 char *tokens[CMD_MAX_TOKENS];
6101 uint32_t n_tokens = RTE_DIM(tokens);
6102 struct pmd_internals *softnic = arg;
6103 int status;
6104
6105 if (is_comment(in))
6106 return;
6107
6108 status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
6109 if (status) {
6110 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
6111 return;
6112 }
6113
6114 if (n_tokens == 0)
6115 return;
6116
6117 if (strcmp(tokens[0], "mempool") == 0) {
6118 cmd_mempool(softnic, tokens, n_tokens, out, out_size);
6119 return;
6120 }
6121
6122 if (strcmp(tokens[0], "link") == 0) {
6123 cmd_link(softnic, tokens, n_tokens, out, out_size);
6124 return;
6125 }
6126
6127 if (strcmp(tokens[0], "swq") == 0) {
6128 cmd_swq(softnic, tokens, n_tokens, out, out_size);
6129 return;
6130 }
6131
6132 if (strcmp(tokens[0], "tmgr") == 0) {
6133 if (n_tokens == 2) {
6134 cmd_tmgr(softnic, tokens, n_tokens, out, out_size);
6135 return;
6136 }
6137
6138 if (n_tokens >= 3 &&
6139 (strcmp(tokens[1], "shaper") == 0) &&
6140 (strcmp(tokens[2], "profile") == 0)) {
6141 cmd_tmgr_shaper_profile(softnic, tokens, n_tokens, out, out_size);
6142 return;
6143 }
6144
6145 if (n_tokens >= 3 &&
6146 (strcmp(tokens[1], "shared") == 0) &&
6147 (strcmp(tokens[2], "shaper") == 0)) {
6148 cmd_tmgr_shared_shaper(softnic, tokens, n_tokens, out, out_size);
6149 return;
6150 }
6151
6152 if (n_tokens >= 2 &&
6153 (strcmp(tokens[1], "node") == 0)) {
6154 cmd_tmgr_node(softnic, tokens, n_tokens, out, out_size);
6155 return;
6156 }
6157
6158 if (n_tokens >= 2 &&
6159 (strcmp(tokens[1], "hierarchy-default") == 0)) {
6160 cmd_tmgr_hierarchy_default(softnic, tokens, n_tokens, out, out_size);
6161 return;
6162 }
6163
6164 if (n_tokens >= 3 &&
6165 (strcmp(tokens[1], "hierarchy") == 0) &&
6166 (strcmp(tokens[2], "commit") == 0)) {
6167 cmd_tmgr_hierarchy_commit(softnic, tokens, n_tokens, out, out_size);
6168 return;
6169 }
6170 }
6171
6172 if (strcmp(tokens[0], "tap") == 0) {
6173 cmd_tap(softnic, tokens, n_tokens, out, out_size);
6174 return;
6175 }
6176
6177 if (strcmp(tokens[0], "cryptodev") == 0) {
6178 cmd_cryptodev(softnic, tokens, n_tokens, out, out_size);
6179 return;
6180 }
6181
6182 if (strcmp(tokens[0], "port") == 0) {
6183 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size);
6184 return;
6185 }
6186
6187 if (strcmp(tokens[0], "table") == 0) {
6188 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size);
6189 return;
6190 }
6191
6192 if (strcmp(tokens[0], "pipeline") == 0) {
6193 if (n_tokens >= 3 &&
6194 (strcmp(tokens[2], "period") == 0)) {
6195 cmd_pipeline(softnic, tokens, n_tokens, out, out_size);
6196 return;
6197 }
6198
6199 if (n_tokens >= 5 &&
6200 (strcmp(tokens[2], "port") == 0) &&
6201 (strcmp(tokens[3], "in") == 0) &&
6202 (strcmp(tokens[4], "bsz") == 0)) {
6203 cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size);
6204 return;
6205 }
6206
6207 if (n_tokens >= 5 &&
6208 (strcmp(tokens[2], "port") == 0) &&
6209 (strcmp(tokens[3], "out") == 0) &&
6210 (strcmp(tokens[4], "bsz") == 0)) {
6211 cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size);
6212 return;
6213 }
6214
6215 if (n_tokens >= 4 &&
6216 (strcmp(tokens[2], "table") == 0) &&
6217 (strcmp(tokens[3], "match") == 0)) {
6218 cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size);
6219 return;
6220 }
6221
6222 if (n_tokens >= 6 &&
6223 (strcmp(tokens[2], "port") == 0) &&
6224 (strcmp(tokens[3], "in") == 0) &&
6225 (strcmp(tokens[5], "table") == 0)) {
6226 cmd_pipeline_port_in_table(softnic, tokens, n_tokens,
6227 out, out_size);
6228 return;
6229 }
6230
6231 if (n_tokens >= 6 &&
6232 (strcmp(tokens[2], "port") == 0) &&
6233 (strcmp(tokens[3], "in") == 0) &&
6234 (strcmp(tokens[5], "stats") == 0)) {
6235 cmd_pipeline_port_in_stats(softnic, tokens, n_tokens,
6236 out, out_size);
6237 return;
6238 }
6239
6240 if (n_tokens >= 6 &&
6241 (strcmp(tokens[2], "port") == 0) &&
6242 (strcmp(tokens[3], "in") == 0) &&
6243 (strcmp(tokens[5], "enable") == 0)) {
6244 cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens,
6245 out, out_size);
6246 return;
6247 }
6248
6249 if (n_tokens >= 6 &&
6250 (strcmp(tokens[2], "port") == 0) &&
6251 (strcmp(tokens[3], "in") == 0) &&
6252 (strcmp(tokens[5], "disable") == 0)) {
6253 cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens,
6254 out, out_size);
6255 return;
6256 }
6257
6258 if (n_tokens >= 6 &&
6259 (strcmp(tokens[2], "port") == 0) &&
6260 (strcmp(tokens[3], "out") == 0) &&
6261 (strcmp(tokens[5], "stats") == 0)) {
6262 cmd_pipeline_port_out_stats(softnic, tokens, n_tokens,
6263 out, out_size);
6264 return;
6265 }
6266
6267 if (n_tokens >= 5 &&
6268 (strcmp(tokens[2], "table") == 0) &&
6269 (strcmp(tokens[4], "stats") == 0)) {
6270 cmd_pipeline_table_stats(softnic, tokens, n_tokens,
6271 out, out_size);
6272 return;
6273 }
6274
6275 if (n_tokens >= 7 &&
6276 (strcmp(tokens[2], "table") == 0) &&
6277 (strcmp(tokens[4], "rule") == 0) &&
6278 (strcmp(tokens[5], "add") == 0) &&
6279 (strcmp(tokens[6], "match") == 0)) {
6280 if (n_tokens >= 8 &&
6281 (strcmp(tokens[7], "default") == 0)) {
6282 cmd_softnic_pipeline_table_rule_add_default(softnic, tokens,
6283 n_tokens, out, out_size);
6284 return;
6285 }
6286
6287 cmd_softnic_pipeline_table_rule_add(softnic, tokens, n_tokens,
6288 out, out_size);
6289 return;
6290 }
6291
6292 if (n_tokens >= 7 &&
6293 (strcmp(tokens[2], "table") == 0) &&
6294 (strcmp(tokens[4], "rule") == 0) &&
6295 (strcmp(tokens[5], "add") == 0) &&
6296 (strcmp(tokens[6], "bulk") == 0)) {
6297 cmd_softnic_pipeline_table_rule_add_bulk(softnic, tokens,
6298 n_tokens, out, out_size);
6299 return;
6300 }
6301
6302 if (n_tokens >= 7 &&
6303 (strcmp(tokens[2], "table") == 0) &&
6304 (strcmp(tokens[4], "rule") == 0) &&
6305 (strcmp(tokens[5], "delete") == 0) &&
6306 (strcmp(tokens[6], "match") == 0)) {
6307 if (n_tokens >= 8 &&
6308 (strcmp(tokens[7], "default") == 0)) {
6309 cmd_softnic_pipeline_table_rule_delete_default(softnic, tokens,
6310 n_tokens, out, out_size);
6311 return;
6312 }
6313
6314 cmd_softnic_pipeline_table_rule_delete(softnic, tokens, n_tokens,
6315 out, out_size);
6316 return;
6317 }
6318
6319 if (n_tokens >= 7 &&
6320 (strcmp(tokens[2], "table") == 0) &&
6321 (strcmp(tokens[4], "rule") == 0) &&
6322 (strcmp(tokens[5], "read") == 0) &&
6323 (strcmp(tokens[6], "stats") == 0)) {
6324 cmd_softnic_pipeline_table_rule_stats_read(softnic, tokens, n_tokens,
6325 out, out_size);
6326 return;
6327 }
6328
6329 if (n_tokens >= 8 &&
6330 (strcmp(tokens[2], "table") == 0) &&
6331 (strcmp(tokens[4], "meter") == 0) &&
6332 (strcmp(tokens[5], "profile") == 0) &&
6333 (strcmp(tokens[7], "add") == 0)) {
6334 cmd_pipeline_table_meter_profile_add(softnic, tokens, n_tokens,
6335 out, out_size);
6336 return;
6337 }
6338
6339 if (n_tokens >= 8 &&
6340 (strcmp(tokens[2], "table") == 0) &&
6341 (strcmp(tokens[4], "meter") == 0) &&
6342 (strcmp(tokens[5], "profile") == 0) &&
6343 (strcmp(tokens[7], "delete") == 0)) {
6344 cmd_pipeline_table_meter_profile_delete(softnic, tokens,
6345 n_tokens, out, out_size);
6346 return;
6347 }
6348
6349 if (n_tokens >= 7 &&
6350 (strcmp(tokens[2], "table") == 0) &&
6351 (strcmp(tokens[4], "rule") == 0) &&
6352 (strcmp(tokens[5], "read") == 0) &&
6353 (strcmp(tokens[6], "meter") == 0)) {
6354 cmd_pipeline_table_rule_meter_read(softnic, tokens, n_tokens,
6355 out, out_size);
6356 return;
6357 }
6358
6359 if (n_tokens >= 5 &&
6360 (strcmp(tokens[2], "table") == 0) &&
6361 (strcmp(tokens[4], "dscp") == 0)) {
6362 cmd_pipeline_table_dscp(softnic, tokens, n_tokens,
6363 out, out_size);
6364 return;
6365 }
6366
6367 if (n_tokens >= 7 &&
6368 (strcmp(tokens[2], "table") == 0) &&
6369 (strcmp(tokens[4], "rule") == 0) &&
6370 (strcmp(tokens[5], "read") == 0) &&
6371 (strcmp(tokens[6], "ttl") == 0)) {
6372 cmd_softnic_pipeline_table_rule_ttl_read(softnic, tokens, n_tokens,
6373 out, out_size);
6374 return;
6375 }
6376 }
6377
6378 if (strcmp(tokens[0], "thread") == 0) {
6379 if (n_tokens >= 5 &&
6380 (strcmp(tokens[4], "enable") == 0)) {
6381 cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens,
6382 out, out_size);
6383 return;
6384 }
6385
6386 if (n_tokens >= 5 &&
6387 (strcmp(tokens[4], "disable") == 0)) {
6388 cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens,
6389 out, out_size);
6390 return;
6391 }
6392 }
6393
6394 if (strcmp(tokens[0], "flowapi") == 0) {
6395 cmd_softnic_flowapi_map(softnic, tokens, n_tokens, out,
6396 out_size);
6397 return;
6398 }
6399
6400 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
6401 }
6402
6403 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)6404 softnic_cli_script_process(struct pmd_internals *softnic,
6405 const char *file_name,
6406 size_t msg_in_len_max,
6407 size_t msg_out_len_max)
6408 {
6409 char *msg_in = NULL, *msg_out = NULL;
6410 FILE *f = NULL;
6411
6412 /* Check input arguments */
6413 if (file_name == NULL ||
6414 (strlen(file_name) == 0) ||
6415 msg_in_len_max == 0 ||
6416 msg_out_len_max == 0)
6417 return -EINVAL;
6418
6419 msg_in = malloc(msg_in_len_max + 1);
6420 msg_out = malloc(msg_out_len_max + 1);
6421 if (msg_in == NULL ||
6422 msg_out == NULL) {
6423 free(msg_out);
6424 free(msg_in);
6425 return -ENOMEM;
6426 }
6427
6428 /* Open input file */
6429 f = fopen(file_name, "r");
6430 if (f == NULL) {
6431 free(msg_out);
6432 free(msg_in);
6433 return -EIO;
6434 }
6435
6436 /* Read file */
6437 for ( ; ; ) {
6438 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6439 break;
6440
6441 printf("%s", msg_in);
6442 msg_out[0] = 0;
6443
6444 softnic_cli_process(msg_in,
6445 msg_out,
6446 msg_out_len_max,
6447 softnic);
6448
6449 if (strlen(msg_out))
6450 printf("%s", msg_out);
6451 }
6452
6453 /* Close file */
6454 fclose(f);
6455 free(msg_out);
6456 free(msg_in);
6457 return 0;
6458 }
6459
6460 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)6461 cli_rule_file_process(const char *file_name,
6462 size_t line_len_max,
6463 struct softnic_table_rule_match *m,
6464 struct softnic_table_rule_action *a,
6465 uint32_t *n_rules,
6466 uint32_t *line_number,
6467 char *out,
6468 size_t out_size)
6469 {
6470 FILE *f = NULL;
6471 char *line = NULL;
6472 uint32_t rule_id, line_id;
6473 int status = 0;
6474
6475 /* Check input arguments */
6476 if (file_name == NULL ||
6477 (strlen(file_name) == 0) ||
6478 line_len_max == 0) {
6479 *line_number = 0;
6480 return -EINVAL;
6481 }
6482
6483 /* Memory allocation */
6484 line = malloc(line_len_max + 1);
6485 if (line == NULL) {
6486 *line_number = 0;
6487 return -ENOMEM;
6488 }
6489
6490 /* Open file */
6491 f = fopen(file_name, "r");
6492 if (f == NULL) {
6493 *line_number = 0;
6494 free(line);
6495 return -EIO;
6496 }
6497
6498 /* Read file */
6499 for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
6500 char *tokens[CMD_MAX_TOKENS];
6501 uint32_t n_tokens, n_tokens_parsed, t0;
6502
6503 /* Read next line from file. */
6504 if (fgets(line, line_len_max + 1, f) == NULL)
6505 break;
6506
6507 /* Comment. */
6508 if (is_comment(line))
6509 continue;
6510
6511 /* Parse line. */
6512 n_tokens = RTE_DIM(tokens);
6513 status = softnic_parse_tokenize_string(line, tokens, &n_tokens);
6514 if (status) {
6515 status = -EINVAL;
6516 break;
6517 }
6518
6519 /* Empty line. */
6520 if (n_tokens == 0)
6521 continue;
6522 t0 = 0;
6523
6524 /* Rule match. */
6525 n_tokens_parsed = parse_match(tokens + t0,
6526 n_tokens - t0,
6527 out,
6528 out_size,
6529 &m[rule_id]);
6530 if (n_tokens_parsed == 0) {
6531 status = -EINVAL;
6532 break;
6533 }
6534 t0 += n_tokens_parsed;
6535
6536 /* Rule action. */
6537 n_tokens_parsed = parse_table_action(tokens + t0,
6538 n_tokens - t0,
6539 out,
6540 out_size,
6541 &a[rule_id]);
6542 if (n_tokens_parsed == 0) {
6543 status = -EINVAL;
6544 break;
6545 }
6546 t0 += n_tokens_parsed;
6547
6548 /* Line completed. */
6549 if (t0 < n_tokens) {
6550 status = -EINVAL;
6551 break;
6552 }
6553
6554 /* Increment rule count */
6555 rule_id++;
6556 }
6557
6558 /* Close file */
6559 fclose(f);
6560
6561 /* Memory free */
6562 free(line);
6563
6564 *n_rules = rule_id;
6565 *line_number = line_id;
6566 return status;
6567 }
6568