1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2020 Marvell International Ltd.
3 */
4
5 #include "test.h"
6
7 #include <assert.h>
8 #include <inttypes.h>
9 #include <signal.h>
10 #include <stdalign.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <rte_errno.h>
16
17 #ifdef RTE_EXEC_ENV_WINDOWS
18 static int
test_node_list_dump(void)19 test_node_list_dump(void)
20 {
21 printf("node_list_dump not supported on Windows, skipping test\n");
22 return TEST_SKIPPED;
23 }
24
25 #else
26
27 #include <rte_graph.h>
28 #include <rte_graph_worker.h>
29 #include <rte_mbuf.h>
30 #include <rte_mbuf_dyn.h>
31 #include <rte_random.h>
32
33 static uint16_t test_node_worker_source(struct rte_graph *graph,
34 struct rte_node *node, void **objs,
35 uint16_t nb_objs);
36
37 static uint16_t test_node0_worker(struct rte_graph *graph,
38 struct rte_node *node, void **objs,
39 uint16_t nb_objs);
40
41 static uint16_t test_node1_worker(struct rte_graph *graph,
42 struct rte_node *node, void **objs,
43 uint16_t nb_objs);
44
45 static uint16_t test_node2_worker(struct rte_graph *graph,
46 struct rte_node *node, void **objs,
47 uint16_t nb_objs);
48
49 static uint16_t test_node3_worker(struct rte_graph *graph,
50 struct rte_node *node, void **objs,
51 uint16_t nb_objs);
52
53 #define MBUFF_SIZE 512
54 #define MAX_NODES 4
55
56 typedef uint64_t graph_dynfield_t;
57 static int graph_dynfield_offset = -1;
58
59 static inline graph_dynfield_t *
graph_field(struct rte_mbuf * mbuf)60 graph_field(struct rte_mbuf *mbuf)
61 {
62 return RTE_MBUF_DYNFIELD(mbuf, \
63 graph_dynfield_offset, graph_dynfield_t *);
64 }
65
66 static struct rte_mbuf mbuf[MAX_NODES + 1][MBUFF_SIZE];
67 static void *mbuf_p[MAX_NODES + 1][MBUFF_SIZE];
68 static rte_graph_t graph_id;
69 static uint64_t obj_stats[MAX_NODES + 1];
70 static uint64_t fn_calls[MAX_NODES + 1];
71
72 const char *node_patterns[] = {
73 "test_node_source1", "test_node00",
74 "test_node00-test_node11", "test_node00-test_node22",
75 "test_node00-test_node33",
76 };
77
78 const char *node_names[] = {
79 "test_node00",
80 "test_node00-test_node11",
81 "test_node00-test_node22",
82 "test_node00-test_node33",
83 };
84
85 struct test_node_register {
86 char name[RTE_NODE_NAMESIZE];
87 rte_node_process_t process;
88 uint16_t nb_edges;
89 const char *next_nodes[MAX_NODES];
90 };
91
92 typedef struct {
93 uint32_t idx;
94 struct test_node_register node;
95 } test_node_t;
96
97 typedef struct {
98 test_node_t test_node[MAX_NODES];
99 } test_main_t;
100
101 static test_main_t test_main = {
102 .test_node = {
103 {
104 .node = {
105 .name = "test_node00",
106 .process = test_node0_worker,
107 .nb_edges = 2,
108 .next_nodes = {"test_node00-"
109 "test_node11",
110 "test_node00-"
111 "test_node22"},
112 },
113 },
114 {
115 .node = {
116 .name = "test_node11",
117 .process = test_node1_worker,
118 .nb_edges = 1,
119 .next_nodes = {"test_node00-"
120 "test_node22"},
121 },
122 },
123 {
124 .node = {
125 .name = "test_node22",
126 .process = test_node2_worker,
127 .nb_edges = 1,
128 .next_nodes = {"test_node00-"
129 "test_node33"},
130 },
131 },
132 {
133 .node = {
134 .name = "test_node33",
135 .process = test_node3_worker,
136 .nb_edges = 1,
137 .next_nodes = {"test_node00"},
138 },
139 },
140 },
141 };
142
143 static int
node_init(const struct rte_graph * graph,struct rte_node * node)144 node_init(const struct rte_graph *graph, struct rte_node *node)
145 {
146 RTE_SET_USED(graph);
147 *(uint32_t *)node->ctx = node->id;
148
149 return 0;
150 }
151
152 static struct rte_node_register test_node_source = {
153 .name = "test_node_source1",
154 .process = test_node_worker_source,
155 .flags = RTE_NODE_SOURCE_F,
156 .nb_edges = 2,
157 .init = node_init,
158 .next_nodes = {"test_node00", "test_node00-test_node11"},
159 };
160 RTE_NODE_REGISTER(test_node_source);
161
162 static struct rte_node_register test_node0 = {
163 .name = "test_node00",
164 .process = test_node0_worker,
165 .init = node_init,
166 };
167 RTE_NODE_REGISTER(test_node0);
168
169 uint16_t
test_node_worker_source(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)170 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
171 void **objs, uint16_t nb_objs)
172 {
173 uint32_t obj_node0 = rte_rand() % 100, obj_node1;
174 test_main_t *tm = &test_main;
175 struct rte_mbuf *data;
176 void **next_stream;
177 rte_node_t next;
178 uint32_t i;
179
180 RTE_SET_USED(objs);
181 nb_objs = RTE_GRAPH_BURST_SIZE;
182
183 /* Prepare stream for next node 0 */
184 obj_node0 = nb_objs * obj_node0 * 0.01;
185 next = 0;
186 next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
187 for (i = 0; i < obj_node0; i++) {
188 data = &mbuf[0][i];
189 *graph_field(data) = ((uint64_t)tm->test_node[0].idx << 32) | i;
190 if ((i + 1) == obj_node0)
191 *graph_field(data) |= (1 << 16);
192 next_stream[i] = &mbuf[0][i];
193 }
194 rte_node_next_stream_put(graph, node, next, obj_node0);
195
196 /* Prepare stream for next node 1 */
197 obj_node1 = nb_objs - obj_node0;
198 next = 1;
199 next_stream = rte_node_next_stream_get(graph, node, next, obj_node1);
200 for (i = 0; i < obj_node1; i++) {
201 data = &mbuf[0][obj_node0 + i];
202 *graph_field(data) = ((uint64_t)tm->test_node[1].idx << 32) | i;
203 if ((i + 1) == obj_node1)
204 *graph_field(data) |= (1 << 16);
205 next_stream[i] = &mbuf[0][obj_node0 + i];
206 }
207
208 rte_node_next_stream_put(graph, node, next, obj_node1);
209 obj_stats[0] += nb_objs;
210 fn_calls[0] += 1;
211 return nb_objs;
212 }
213
214 uint16_t
test_node0_worker(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)215 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
216 uint16_t nb_objs)
217 {
218 test_main_t *tm = &test_main;
219
220 if (*(uint32_t *)node->ctx == test_node0.id) {
221 uint32_t obj_node0 = rte_rand() % 100, obj_node1;
222 struct rte_mbuf *data;
223 uint8_t second_pass = 0;
224 uint32_t count = 0;
225 uint32_t i;
226
227 obj_stats[1] += nb_objs;
228 fn_calls[1] += 1;
229
230 for (i = 0; i < nb_objs; i++) {
231 data = (struct rte_mbuf *)objs[i];
232 if ((*graph_field(data) >> 32) != tm->test_node[0].idx) {
233 printf("Data idx miss match at node 0, expected"
234 " = %u got = %u\n",
235 tm->test_node[0].idx,
236 (uint32_t)(*graph_field(data) >> 32));
237 goto end;
238 }
239
240 if ((*graph_field(data) & 0xffff) != (i - count)) {
241 printf("Expected buff count miss match at "
242 "node 0\n");
243 goto end;
244 }
245
246 if (*graph_field(data) & (0x1 << 16))
247 count = i + 1;
248 if (*graph_field(data) & (0x1 << 17))
249 second_pass = 1;
250 }
251
252 if (count != i) {
253 printf("Count mismatch at node 0\n");
254 goto end;
255 }
256
257 obj_node0 = nb_objs * obj_node0 * 0.01;
258 for (i = 0; i < obj_node0; i++) {
259 data = &mbuf[1][i];
260 *graph_field(data) =
261 ((uint64_t)tm->test_node[1].idx << 32) | i;
262 if ((i + 1) == obj_node0)
263 *graph_field(data) |= (1 << 16);
264 if (second_pass)
265 *graph_field(data) |= (1 << 17);
266 }
267 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
268 obj_node0);
269
270 obj_node1 = nb_objs - obj_node0;
271 for (i = 0; i < obj_node1; i++) {
272 data = &mbuf[1][obj_node0 + i];
273 *graph_field(data) =
274 ((uint64_t)tm->test_node[2].idx << 32) | i;
275 if ((i + 1) == obj_node1)
276 *graph_field(data) |= (1 << 16);
277 if (second_pass)
278 *graph_field(data) |= (1 << 17);
279 }
280 rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
281 obj_node1);
282
283 } else if (*(uint32_t *)node->ctx == tm->test_node[1].idx) {
284 test_node1_worker(graph, node, objs, nb_objs);
285 } else if (*(uint32_t *)node->ctx == tm->test_node[2].idx) {
286 test_node2_worker(graph, node, objs, nb_objs);
287 } else if (*(uint32_t *)node->ctx == tm->test_node[3].idx) {
288 test_node3_worker(graph, node, objs, nb_objs);
289 } else {
290 printf("Unexpected node context\n");
291 }
292
293 end:
294 return nb_objs;
295 }
296
297 uint16_t
test_node1_worker(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)298 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
299 uint16_t nb_objs)
300 {
301 test_main_t *tm = &test_main;
302 uint8_t second_pass = 0;
303 uint32_t obj_node0 = 0;
304 struct rte_mbuf *data;
305 uint32_t count = 0;
306 uint32_t i;
307
308 obj_stats[2] += nb_objs;
309 fn_calls[2] += 1;
310 for (i = 0; i < nb_objs; i++) {
311 data = (struct rte_mbuf *)objs[i];
312 if ((*graph_field(data) >> 32) != tm->test_node[1].idx) {
313 printf("Data idx miss match at node 1, expected = %u"
314 " got = %u\n",
315 tm->test_node[1].idx,
316 (uint32_t)(*graph_field(data) >> 32));
317 goto end;
318 }
319
320 if ((*graph_field(data) & 0xffff) != (i - count)) {
321 printf("Expected buff count miss match at node 1\n");
322 goto end;
323 }
324
325 if (*graph_field(data) & (0x1 << 16))
326 count = i + 1;
327 if (*graph_field(data) & (0x1 << 17))
328 second_pass = 1;
329 }
330
331 if (count != i) {
332 printf("Count mismatch at node 1\n");
333 goto end;
334 }
335
336 obj_node0 = nb_objs;
337 for (i = 0; i < obj_node0; i++) {
338 data = &mbuf[2][i];
339 *graph_field(data) = ((uint64_t)tm->test_node[2].idx << 32) | i;
340 if ((i + 1) == obj_node0)
341 *graph_field(data) |= (1 << 16);
342 if (second_pass)
343 *graph_field(data) |= (1 << 17);
344 }
345 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
346
347 end:
348 return nb_objs;
349 }
350
351 uint16_t
test_node2_worker(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)352 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
353 uint16_t nb_objs)
354 {
355 test_main_t *tm = &test_main;
356 uint8_t second_pass = 0;
357 struct rte_mbuf *data;
358 uint32_t count = 0;
359 uint32_t obj_node0;
360 uint32_t i;
361
362 obj_stats[3] += nb_objs;
363 fn_calls[3] += 1;
364 for (i = 0; i < nb_objs; i++) {
365 data = (struct rte_mbuf *)objs[i];
366 if ((*graph_field(data) >> 32) != tm->test_node[2].idx) {
367 printf("Data idx miss match at node 2, expected = %u"
368 " got = %u\n",
369 tm->test_node[2].idx,
370 (uint32_t)(*graph_field(data) >> 32));
371 goto end;
372 }
373
374 if ((*graph_field(data) & 0xffff) != (i - count)) {
375 printf("Expected buff count miss match at node 2\n");
376 goto end;
377 }
378
379 if (*graph_field(data) & (0x1 << 16))
380 count = i + 1;
381 if (*graph_field(data) & (0x1 << 17))
382 second_pass = 1;
383 }
384
385 if (count != i) {
386 printf("Count mismatch at node 2\n");
387 goto end;
388 }
389
390 if (!second_pass) {
391 obj_node0 = nb_objs;
392 for (i = 0; i < obj_node0; i++) {
393 data = &mbuf[3][i];
394 *graph_field(data) =
395 ((uint64_t)tm->test_node[3].idx << 32) | i;
396 if ((i + 1) == obj_node0)
397 *graph_field(data) |= (1 << 16);
398 }
399 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
400 obj_node0);
401 }
402
403 end:
404 return nb_objs;
405 }
406
407 uint16_t
test_node3_worker(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)408 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
409 uint16_t nb_objs)
410 {
411 test_main_t *tm = &test_main;
412 uint8_t second_pass = 0;
413 struct rte_mbuf *data;
414 uint32_t count = 0;
415 uint32_t obj_node0;
416 uint32_t i;
417
418 obj_stats[4] += nb_objs;
419 fn_calls[4] += 1;
420 for (i = 0; i < nb_objs; i++) {
421 data = (struct rte_mbuf *)objs[i];
422 if ((*graph_field(data) >> 32) != tm->test_node[3].idx) {
423 printf("Data idx miss match at node 3, expected = %u"
424 " got = %u\n",
425 tm->test_node[3].idx,
426 (uint32_t)(*graph_field(data) >> 32));
427 goto end;
428 }
429
430 if ((*graph_field(data) & 0xffff) != (i - count)) {
431 printf("Expected buff count miss match at node 3\n");
432 goto end;
433 }
434
435 if (*graph_field(data) & (0x1 << 16))
436 count = i + 1;
437 if (*graph_field(data) & (0x1 << 17))
438 second_pass = 1;
439 }
440
441 if (count != i) {
442 printf("Count mismatch at node 3\n");
443 goto end;
444 }
445
446 if (second_pass) {
447 printf("Unexpected buffers are at node 3\n");
448 goto end;
449 } else {
450 obj_node0 = nb_objs * 2;
451 for (i = 0; i < obj_node0; i++) {
452 data = &mbuf[4][i];
453 *graph_field(data) =
454 ((uint64_t)tm->test_node[0].idx << 32) | i;
455 *graph_field(data) |= (1 << 17);
456 if ((i + 1) == obj_node0)
457 *graph_field(data) |= (1 << 16);
458 }
459 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
460 obj_node0);
461 }
462
463 end:
464 return nb_objs;
465 }
466
467 static int
test_lookup_functions(void)468 test_lookup_functions(void)
469 {
470 test_main_t *tm = &test_main;
471 int i;
472
473 /* Verify the name with ID */
474 for (i = 1; i < MAX_NODES; i++) {
475 char *name = rte_node_id_to_name(tm->test_node[i].idx);
476 if (strcmp(name, node_names[i]) != 0) {
477 printf("Test node name verify by ID = %d failed "
478 "Expected = %s, got %s\n",
479 i, node_names[i], name);
480 return -1;
481 }
482 }
483
484 /* Verify by name */
485 for (i = 1; i < MAX_NODES; i++) {
486 uint32_t idx = rte_node_from_name(node_names[i]);
487 if (idx != tm->test_node[i].idx) {
488 printf("Test node ID verify by name = %s failed "
489 "Expected = %d, got %d\n",
490 node_names[i], tm->test_node[i].idx, idx);
491 return -1;
492 }
493 }
494
495 /* Verify edge count */
496 for (i = 1; i < MAX_NODES; i++) {
497 uint32_t count = rte_node_edge_count(tm->test_node[i].idx);
498 if (count != tm->test_node[i].node.nb_edges) {
499 printf("Test number of edges for node = %s failed Expected = %d, got = %d\n",
500 tm->test_node[i].node.name,
501 tm->test_node[i].node.nb_edges, count);
502 return -1;
503 }
504 }
505
506 /* Verify edge names */
507 for (i = 1; i < MAX_NODES; i++) {
508 uint32_t j, count;
509 char **next_edges;
510
511 count = rte_node_edge_get(tm->test_node[i].idx, NULL);
512 if (count != tm->test_node[i].node.nb_edges * sizeof(char *)) {
513 printf("Test number of edge count for node = %s failed Expected = %d, got = %d\n",
514 tm->test_node[i].node.name,
515 tm->test_node[i].node.nb_edges, count);
516 return -1;
517 }
518 next_edges = malloc(count);
519 count = rte_node_edge_get(tm->test_node[i].idx, next_edges);
520 if (count != tm->test_node[i].node.nb_edges) {
521 printf("Test number of edges for node = %s failed Expected = %d, got %d\n",
522 tm->test_node[i].node.name,
523 tm->test_node[i].node.nb_edges, count);
524 free(next_edges);
525 return -1;
526 }
527
528 for (j = 0; j < count; j++) {
529 if (strcmp(next_edges[j],
530 tm->test_node[i].node.next_nodes[j]) != 0) {
531 printf("Edge name miss match, expected = %s got = %s\n",
532 tm->test_node[i].node.next_nodes[j],
533 next_edges[j]);
534 free(next_edges);
535 return -1;
536 }
537 }
538 free(next_edges);
539 }
540
541 return 0;
542 }
543
544 static int
test_node_clone(void)545 test_node_clone(void)
546 {
547 test_main_t *tm = &test_main;
548 uint32_t node_id, dummy_id;
549 int i;
550
551 node_id = rte_node_from_name("test_node00");
552 tm->test_node[0].idx = node_id;
553
554 dummy_id = rte_node_clone(node_id, "test_node00");
555 if (rte_node_is_invalid(dummy_id)) {
556 printf("Got invalid id when clone, Expecting fail\n");
557 return -1;
558 }
559
560 /* Clone with same name, should fail */
561 dummy_id = rte_node_clone(node_id, "test_node00");
562 if (!rte_node_is_invalid(dummy_id)) {
563 printf("Got valid id when clone with same name, Expecting fail\n");
564 return -1;
565 }
566
567 for (i = 1; i < MAX_NODES; i++) {
568 tm->test_node[i].idx =
569 rte_node_clone(node_id, tm->test_node[i].node.name);
570 if (rte_node_is_invalid(tm->test_node[i].idx)) {
571 printf("Got invalid node id\n");
572 return -1;
573 }
574 }
575
576 /* Clone from cloned node should fail */
577 dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node");
578 if (!rte_node_is_invalid(dummy_id)) {
579 printf("Got valid node id when cloning from cloned node, expected fail\n");
580 return -1;
581 }
582
583 return 0;
584 }
585
586 static int
test_update_edges(void)587 test_update_edges(void)
588 {
589 test_main_t *tm = &test_main;
590 uint32_t node_id;
591 uint16_t count;
592 int i;
593
594 node_id = rte_node_from_name("test_node00");
595 count = rte_node_edge_update(node_id, 0,
596 tm->test_node[0].node.next_nodes,
597 tm->test_node[0].node.nb_edges);
598 if (count != tm->test_node[0].node.nb_edges) {
599 printf("Update edges failed expected: %d got = %d\n",
600 tm->test_node[0].node.nb_edges, count);
601 return -1;
602 }
603
604 for (i = 1; i < MAX_NODES; i++) {
605 count = rte_node_edge_update(tm->test_node[i].idx, 0,
606 tm->test_node[i].node.next_nodes,
607 tm->test_node[i].node.nb_edges);
608 if (count != tm->test_node[i].node.nb_edges) {
609 printf("Update edges failed expected: %d got = %d\n",
610 tm->test_node[i].node.nb_edges, count);
611 return -1;
612 }
613
614 count = rte_node_edge_shrink(tm->test_node[i].idx,
615 tm->test_node[i].node.nb_edges);
616 if (count != tm->test_node[i].node.nb_edges) {
617 printf("Shrink edges failed\n");
618 return -1;
619 }
620 }
621
622 return 0;
623 }
624
625 static int
test_create_graph(void)626 test_create_graph(void)
627 {
628 static const char *node_patterns_dummy[] = {
629 "test_node_source1", "test_node00",
630 "test_node00-test_node11", "test_node00-test_node22",
631 "test_node00-test_node33", "test_node00-dummy_node",
632 };
633 struct rte_graph_param gconf = {
634 .socket_id = SOCKET_ID_ANY,
635 .nb_node_patterns = 6,
636 .node_patterns = node_patterns_dummy,
637 };
638 uint32_t dummy_node_id;
639 uint32_t node_id;
640
641 node_id = rte_node_from_name("test_node00");
642 dummy_node_id = rte_node_clone(node_id, "dummy_node");
643 if (rte_node_is_invalid(dummy_node_id)) {
644 printf("Got invalid node id\n");
645 return -1;
646 }
647
648 graph_id = rte_graph_create("worker0", &gconf);
649 if (graph_id != RTE_GRAPH_ID_INVALID) {
650 printf("Graph creation success with isolated node, expected graph creation fail\n");
651 return -1;
652 }
653
654 gconf.nb_node_patterns = 5;
655 gconf.node_patterns = node_patterns;
656 graph_id = rte_graph_create("worker0", &gconf);
657 if (graph_id == RTE_GRAPH_ID_INVALID) {
658 printf("Graph creation failed with error = %d\n", rte_errno);
659 return -1;
660 }
661 return 0;
662 }
663
664 static int
test_graph_clone(void)665 test_graph_clone(void)
666 {
667 rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
668 rte_graph_t main_graph_id = RTE_GRAPH_ID_INVALID;
669 struct rte_graph_param graph_conf = {0};
670 int ret = 0;
671
672 main_graph_id = rte_graph_from_name("worker0");
673 if (main_graph_id == RTE_GRAPH_ID_INVALID) {
674 printf("Must create main graph first\n");
675 ret = -1;
676 }
677
678 graph_conf.dispatch.mp_capacity = 1024;
679 graph_conf.dispatch.wq_size_max = 32;
680
681 cloned_graph_id = rte_graph_clone(main_graph_id, "cloned-test0", &graph_conf);
682
683 if (cloned_graph_id == RTE_GRAPH_ID_INVALID) {
684 printf("Graph creation failed with error = %d\n", rte_errno);
685 ret = -1;
686 }
687
688 if (strcmp(rte_graph_id_to_name(cloned_graph_id), "worker0-cloned-test0")) {
689 printf("Cloned graph should name as %s but get %s\n", "worker0-cloned-test",
690 rte_graph_id_to_name(cloned_graph_id));
691 ret = -1;
692 }
693
694 rte_graph_destroy(cloned_graph_id);
695
696 return ret;
697 }
698
699 static int
test_graph_id_collisions(void)700 test_graph_id_collisions(void)
701 {
702 static const char *node_patterns[] = {"test_node_source1", "test_node00"};
703 struct rte_graph_param gconf = {
704 .socket_id = SOCKET_ID_ANY,
705 .nb_node_patterns = 2,
706 .node_patterns = node_patterns,
707 };
708 rte_graph_t g1, g2, g3, g4;
709
710 g1 = rte_graph_create("worker1", &gconf);
711 if (g1 == RTE_GRAPH_ID_INVALID) {
712 printf("Graph 1 creation failed with error = %d\n", rte_errno);
713 return -1;
714 }
715 g2 = rte_graph_create("worker2", &gconf);
716 if (g2 == RTE_GRAPH_ID_INVALID) {
717 printf("Graph 2 creation failed with error = %d\n", rte_errno);
718 return -1;
719 }
720 g3 = rte_graph_create("worker3", &gconf);
721 if (g3 == RTE_GRAPH_ID_INVALID) {
722 printf("Graph 3 creation failed with error = %d\n", rte_errno);
723 return -1;
724 }
725 if (g1 == g2 || g2 == g3 || g1 == g3) {
726 printf("Graph ids should be different\n");
727 return -1;
728 }
729 if (rte_graph_destroy(g2) < 0) {
730 printf("Graph 2 suppression failed\n");
731 return -1;
732 }
733 g4 = rte_graph_create("worker4", &gconf);
734 if (g4 == RTE_GRAPH_ID_INVALID) {
735 printf("Graph 4 creation failed with error = %d\n", rte_errno);
736 return -1;
737 }
738 if (g1 == g3 || g1 == g4 || g3 == g4) {
739 printf("Graph ids should be different\n");
740 return -1;
741 }
742 g2 = rte_graph_clone(g1, "worker2", &gconf);
743 if (g2 == RTE_GRAPH_ID_INVALID) {
744 printf("Graph 4 creation failed with error = %d\n", rte_errno);
745 return -1;
746 }
747 if (g1 == g2 || g1 == g3 || g1 == g4 || g2 == g3 || g2 == g4 || g3 == g4) {
748 printf("Graph ids should be different\n");
749 return -1;
750 }
751 if (rte_graph_destroy(g1) < 0) {
752 printf("Graph 1 suppression failed\n");
753 return -1;
754 }
755 if (rte_graph_destroy(g2) < 0) {
756 printf("Graph 2 suppression failed\n");
757 return -1;
758 }
759 if (rte_graph_destroy(g3) < 0) {
760 printf("Graph 3 suppression failed\n");
761 return -1;
762 }
763 if (rte_graph_destroy(g4) < 0) {
764 printf("Graph 4 suppression failed\n");
765 return -1;
766 }
767 return 0;
768 }
769
770 static int
test_graph_model_mcore_dispatch_node_lcore_affinity_set(void)771 test_graph_model_mcore_dispatch_node_lcore_affinity_set(void)
772 {
773 rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
774 unsigned int worker_lcore = RTE_MAX_LCORE;
775 struct rte_graph_param graph_conf = {0};
776 rte_node_t nid = RTE_NODE_ID_INVALID;
777 char node_name[64] = "test_node00";
778 struct rte_node *node;
779 int ret = 0;
780
781 worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
782 ret = rte_graph_model_mcore_dispatch_node_lcore_affinity_set(node_name, worker_lcore);
783 if (ret == 0)
784 printf("Set node %s affinity to lcore %u\n", node_name, worker_lcore);
785
786 nid = rte_node_from_name(node_name);
787 cloned_graph_id = rte_graph_clone(graph_id, "cloned-test1", &graph_conf);
788 node = rte_graph_node_get(cloned_graph_id, nid);
789
790 if (node->dispatch.lcore_id != worker_lcore) {
791 printf("set node affinity failed\n");
792 ret = -1;
793 }
794
795 rte_graph_destroy(cloned_graph_id);
796
797 return ret;
798 }
799
800 static int
test_graph_model_mcore_dispatch_core_bind_unbind(void)801 test_graph_model_mcore_dispatch_core_bind_unbind(void)
802 {
803 rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
804 unsigned int worker_lcore = RTE_MAX_LCORE;
805 struct rte_graph_param graph_conf = {0};
806 struct rte_graph *graph;
807 int ret = 0;
808
809 worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
810 cloned_graph_id = rte_graph_clone(graph_id, "cloned-test2", &graph_conf);
811
812 ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
813 if (ret != 0) {
814 printf("Set graph mcore dispatch model failed\n");
815 goto fail;
816 }
817
818 ret = rte_graph_model_mcore_dispatch_core_bind(cloned_graph_id, worker_lcore);
819 if (ret != 0) {
820 printf("bind graph %d to lcore %u failed\n", graph_id, worker_lcore);
821 goto fail;
822 }
823
824 graph = rte_graph_lookup("worker0-cloned-test2");
825
826 if (graph->dispatch.lcore_id != worker_lcore) {
827 printf("bind graph %s(id:%d) with lcore %u failed\n",
828 graph->name, graph->id, worker_lcore);
829 ret = -1;
830 goto fail;
831 }
832
833 rte_graph_model_mcore_dispatch_core_unbind(cloned_graph_id);
834 if (graph->dispatch.lcore_id != RTE_MAX_LCORE) {
835 printf("unbind graph %s(id:%d) failed %d\n",
836 graph->name, graph->id, graph->dispatch.lcore_id);
837 ret = -1;
838 }
839
840 fail:
841 rte_graph_destroy(cloned_graph_id);
842
843 return ret;
844 }
845
846 static int
test_graph_worker_model_set_get(void)847 test_graph_worker_model_set_get(void)
848 {
849 rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
850 struct rte_graph_param graph_conf = {0};
851 struct rte_graph *graph;
852 int ret = 0;
853
854 cloned_graph_id = rte_graph_clone(graph_id, "cloned-test3", &graph_conf);
855 ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
856 if (ret != 0) {
857 printf("Set graph mcore dispatch model failed\n");
858 goto fail;
859 }
860
861 graph = rte_graph_lookup("worker0-cloned-test3");
862 if (rte_graph_worker_model_get(graph) != RTE_GRAPH_MODEL_MCORE_DISPATCH) {
863 printf("Get graph worker model failed\n");
864 ret = -1;
865 }
866
867 fail:
868 rte_graph_destroy(cloned_graph_id);
869
870 return ret;
871 }
872
873 static int
test_graph_walk(void)874 test_graph_walk(void)
875 {
876 struct rte_graph *graph = rte_graph_lookup("worker0");
877 int i;
878
879 if (!graph) {
880 printf("Graph lookup failed\n");
881 return -1;
882 }
883
884 for (i = 0; i < 5; i++)
885 rte_graph_walk(graph);
886 return 0;
887 }
888
889 static int
test_graph_lookup_functions(void)890 test_graph_lookup_functions(void)
891 {
892 test_main_t *tm = &test_main;
893 struct rte_node *node;
894 int i;
895
896 for (i = 0; i < MAX_NODES; i++) {
897 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
898 if (!node) {
899 printf("rte_graph_node_get, failed for node = %d\n",
900 tm->test_node[i].idx);
901 return -1;
902 }
903
904 if (tm->test_node[i].idx != node->id) {
905 printf("Node id didn't match, expected = %d got = %d\n",
906 tm->test_node[i].idx, node->id);
907 return 0;
908 }
909
910 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
911 printf("Node name didn't match, expected = %s got %s\n",
912 node_names[i], node->name);
913 return -1;
914 }
915 }
916
917 for (i = 0; i < MAX_NODES; i++) {
918 node = rte_graph_node_get_by_name("worker0", node_names[i]);
919 if (!node) {
920 printf("rte_graph_node_get, failed for node = %d\n",
921 tm->test_node[i].idx);
922 return -1;
923 }
924
925 if (tm->test_node[i].idx != node->id) {
926 printf("Node id didn't match, expected = %d got = %d\n",
927 tm->test_node[i].idx, node->id);
928 return 0;
929 }
930
931 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
932 printf("Node name didn't match, expected = %s got %s\n",
933 node_names[i], node->name);
934 return -1;
935 }
936 }
937
938 return 0;
939 }
940
941 static int
graph_cluster_stats_cb_t(bool is_first,bool is_last,void * cookie,const struct rte_graph_cluster_node_stats * st)942 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
943 const struct rte_graph_cluster_node_stats *st)
944 {
945 int i;
946
947 RTE_SET_USED(is_first);
948 RTE_SET_USED(is_last);
949 RTE_SET_USED(cookie);
950
951 for (i = 0; i < MAX_NODES + 1; i++) {
952 rte_node_t id = rte_node_from_name(node_patterns[i]);
953 if (id == st->id) {
954 if (obj_stats[i] != st->objs) {
955 printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
956 node_patterns[i], obj_stats[i],
957 st->objs);
958 return -1;
959 }
960
961 if (fn_calls[i] != st->calls) {
962 printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
963 node_patterns[i], fn_calls[i],
964 st->calls);
965 return -1;
966 }
967 }
968 }
969 return 0;
970 }
971
972 static int
test_print_stats(void)973 test_print_stats(void)
974 {
975 struct rte_graph_cluster_stats_param s_param;
976 struct rte_graph_cluster_stats *stats;
977 const char *pattern = "worker0";
978
979 if (!rte_graph_has_stats_feature())
980 return 0;
981
982 /* Prepare stats object */
983 memset(&s_param, 0, sizeof(s_param));
984 s_param.f = stdout;
985 s_param.socket_id = SOCKET_ID_ANY;
986 s_param.graph_patterns = &pattern;
987 s_param.nb_graph_patterns = 1;
988 s_param.fn = graph_cluster_stats_cb_t;
989
990 stats = rte_graph_cluster_stats_create(&s_param);
991 if (stats == NULL) {
992 printf("Unable to get stats\n");
993 return -1;
994 }
995 /* Clear screen and move to top left */
996 rte_graph_cluster_stats_get(stats, 0);
997 rte_graph_cluster_stats_destroy(stats);
998
999 return 0;
1000 }
1001
1002 static int
graph_setup(void)1003 graph_setup(void)
1004 {
1005 int i, j;
1006
1007 static const struct rte_mbuf_dynfield graph_dynfield_desc = {
1008 .name = "test_graph_dynfield",
1009 .size = sizeof(graph_dynfield_t),
1010 .align = alignof(graph_dynfield_t),
1011 };
1012 graph_dynfield_offset =
1013 rte_mbuf_dynfield_register(&graph_dynfield_desc);
1014 if (graph_dynfield_offset < 0) {
1015 printf("Cannot register mbuf field\n");
1016 return TEST_FAILED;
1017 }
1018
1019 for (i = 0; i <= MAX_NODES; i++) {
1020 for (j = 0; j < MBUFF_SIZE; j++)
1021 mbuf_p[i][j] = &mbuf[i][j];
1022 }
1023 if (test_node_clone()) {
1024 printf("test_node_clone: fail\n");
1025 return -1;
1026 }
1027 printf("test_node_clone: pass\n");
1028
1029 return 0;
1030 }
1031
1032 static void
graph_teardown(void)1033 graph_teardown(void)
1034 {
1035 int id;
1036
1037 id = rte_graph_destroy(rte_graph_from_name("worker0"));
1038 if (id)
1039 printf("Graph Destroy failed\n");
1040 }
1041
1042 static struct unit_test_suite graph_testsuite = {
1043 .suite_name = "Graph library test suite",
1044 .setup = graph_setup,
1045 .teardown = graph_teardown,
1046 .unit_test_cases = {
1047 TEST_CASE(test_update_edges),
1048 TEST_CASE(test_lookup_functions),
1049 TEST_CASE(test_create_graph),
1050 TEST_CASE(test_graph_clone),
1051 TEST_CASE(test_graph_id_collisions),
1052 TEST_CASE(test_graph_model_mcore_dispatch_node_lcore_affinity_set),
1053 TEST_CASE(test_graph_model_mcore_dispatch_core_bind_unbind),
1054 TEST_CASE(test_graph_worker_model_set_get),
1055 TEST_CASE(test_graph_lookup_functions),
1056 TEST_CASE(test_graph_walk),
1057 TEST_CASE(test_print_stats),
1058 TEST_CASES_END(), /**< NULL terminate unit test array */
1059 },
1060 };
1061
1062 static int
graph_autotest_fn(void)1063 graph_autotest_fn(void)
1064 {
1065 return unit_test_suite_runner(&graph_testsuite);
1066 }
1067
1068 REGISTER_FAST_TEST(graph_autotest, true, true, graph_autotest_fn);
1069
1070 static int
test_node_list_dump(void)1071 test_node_list_dump(void)
1072 {
1073 rte_node_list_dump(stdout);
1074
1075 return TEST_SUCCESS;
1076 }
1077
1078 #endif /* !RTE_EXEC_ENV_WINDOWS */
1079
1080 REGISTER_FAST_TEST(node_list_dump, true, true, test_node_list_dump);
1081