xref: /dpdk/app/test/test_graph.c (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
700 test_graph_model_mcore_dispatch_node_lcore_affinity_set(void)
701 {
702 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
703 	unsigned int worker_lcore = RTE_MAX_LCORE;
704 	struct rte_graph_param graph_conf = {0};
705 	rte_node_t nid = RTE_NODE_ID_INVALID;
706 	char node_name[64] = "test_node00";
707 	struct rte_node *node;
708 	int ret = 0;
709 
710 	worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
711 	ret = rte_graph_model_mcore_dispatch_node_lcore_affinity_set(node_name, worker_lcore);
712 	if (ret == 0)
713 		printf("Set node %s affinity to lcore %u\n", node_name, worker_lcore);
714 
715 	nid = rte_node_from_name(node_name);
716 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test1", &graph_conf);
717 	node = rte_graph_node_get(cloned_graph_id, nid);
718 
719 	if (node->dispatch.lcore_id != worker_lcore) {
720 		printf("set node affinity failed\n");
721 		ret = -1;
722 	}
723 
724 	rte_graph_destroy(cloned_graph_id);
725 
726 	return ret;
727 }
728 
729 static int
730 test_graph_model_mcore_dispatch_core_bind_unbind(void)
731 {
732 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
733 	unsigned int worker_lcore = RTE_MAX_LCORE;
734 	struct rte_graph_param graph_conf = {0};
735 	struct rte_graph *graph;
736 	int ret = 0;
737 
738 	worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
739 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test2", &graph_conf);
740 
741 	ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
742 	if (ret != 0) {
743 		printf("Set graph mcore dispatch model failed\n");
744 		goto fail;
745 	}
746 
747 	ret = rte_graph_model_mcore_dispatch_core_bind(cloned_graph_id, worker_lcore);
748 	if (ret != 0) {
749 		printf("bind graph %d to lcore %u failed\n", graph_id, worker_lcore);
750 		goto fail;
751 	}
752 
753 	graph = rte_graph_lookup("worker0-cloned-test2");
754 
755 	if (graph->dispatch.lcore_id != worker_lcore) {
756 		printf("bind graph %s(id:%d) with lcore %u failed\n",
757 		       graph->name, graph->id, worker_lcore);
758 		ret = -1;
759 		goto fail;
760 	}
761 
762 	rte_graph_model_mcore_dispatch_core_unbind(cloned_graph_id);
763 	if (graph->dispatch.lcore_id != RTE_MAX_LCORE) {
764 		printf("unbind graph %s(id:%d) failed %d\n",
765 		       graph->name, graph->id, graph->dispatch.lcore_id);
766 		ret = -1;
767 	}
768 
769 fail:
770 	rte_graph_destroy(cloned_graph_id);
771 
772 	return ret;
773 }
774 
775 static int
776 test_graph_worker_model_set_get(void)
777 {
778 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
779 	struct rte_graph_param graph_conf = {0};
780 	struct rte_graph *graph;
781 	int ret = 0;
782 
783 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test3", &graph_conf);
784 	ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
785 	if (ret != 0) {
786 		printf("Set graph mcore dispatch model failed\n");
787 		goto fail;
788 	}
789 
790 	graph = rte_graph_lookup("worker0-cloned-test3");
791 	if (rte_graph_worker_model_get(graph) != RTE_GRAPH_MODEL_MCORE_DISPATCH) {
792 		printf("Get graph worker model failed\n");
793 		ret = -1;
794 	}
795 
796 fail:
797 	rte_graph_destroy(cloned_graph_id);
798 
799 	return ret;
800 }
801 
802 static int
803 test_graph_walk(void)
804 {
805 	struct rte_graph *graph = rte_graph_lookup("worker0");
806 	int i;
807 
808 	if (!graph) {
809 		printf("Graph lookup failed\n");
810 		return -1;
811 	}
812 
813 	for (i = 0; i < 5; i++)
814 		rte_graph_walk(graph);
815 	return 0;
816 }
817 
818 static int
819 test_graph_lookup_functions(void)
820 {
821 	test_main_t *tm = &test_main;
822 	struct rte_node *node;
823 	int i;
824 
825 	for (i = 0; i < MAX_NODES; i++) {
826 		node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
827 		if (!node) {
828 			printf("rte_graph_node_get, failed for node = %d\n",
829 			       tm->test_node[i].idx);
830 			return -1;
831 		}
832 
833 		if (tm->test_node[i].idx != node->id) {
834 			printf("Node id didn't match, expected = %d got = %d\n",
835 			       tm->test_node[i].idx, node->id);
836 			return 0;
837 		}
838 
839 		if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
840 			printf("Node name didn't match, expected = %s got %s\n",
841 			       node_names[i], node->name);
842 			return -1;
843 		}
844 	}
845 
846 	for (i = 0; i < MAX_NODES; i++) {
847 		node = rte_graph_node_get_by_name("worker0", node_names[i]);
848 		if (!node) {
849 			printf("rte_graph_node_get, failed for node = %d\n",
850 			       tm->test_node[i].idx);
851 			return -1;
852 		}
853 
854 		if (tm->test_node[i].idx != node->id) {
855 			printf("Node id didn't match, expected = %d got = %d\n",
856 			       tm->test_node[i].idx, node->id);
857 			return 0;
858 		}
859 
860 		if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
861 			printf("Node name didn't match, expected = %s got %s\n",
862 			       node_names[i], node->name);
863 			return -1;
864 		}
865 	}
866 
867 	return 0;
868 }
869 
870 static int
871 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
872 			 const struct rte_graph_cluster_node_stats *st)
873 {
874 	int i;
875 
876 	RTE_SET_USED(is_first);
877 	RTE_SET_USED(is_last);
878 	RTE_SET_USED(cookie);
879 
880 	for (i = 0; i < MAX_NODES + 1; i++) {
881 		rte_node_t id = rte_node_from_name(node_patterns[i]);
882 		if (id == st->id) {
883 			if (obj_stats[i] != st->objs) {
884 				printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
885 				       node_patterns[i], obj_stats[i],
886 				       st->objs);
887 				return -1;
888 			}
889 
890 			if (fn_calls[i] != st->calls) {
891 				printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
892 				       node_patterns[i], fn_calls[i],
893 				       st->calls);
894 				return -1;
895 			}
896 		}
897 	}
898 	return 0;
899 }
900 
901 static int
902 test_print_stats(void)
903 {
904 	struct rte_graph_cluster_stats_param s_param;
905 	struct rte_graph_cluster_stats *stats;
906 	const char *pattern = "worker0";
907 
908 	if (!rte_graph_has_stats_feature())
909 		return 0;
910 
911 	/* Prepare stats object */
912 	memset(&s_param, 0, sizeof(s_param));
913 	s_param.f = stdout;
914 	s_param.socket_id = SOCKET_ID_ANY;
915 	s_param.graph_patterns = &pattern;
916 	s_param.nb_graph_patterns = 1;
917 	s_param.fn = graph_cluster_stats_cb_t;
918 
919 	stats = rte_graph_cluster_stats_create(&s_param);
920 	if (stats == NULL) {
921 		printf("Unable to get stats\n");
922 		return -1;
923 	}
924 	/* Clear screen and move to top left */
925 	rte_graph_cluster_stats_get(stats, 0);
926 	rte_graph_cluster_stats_destroy(stats);
927 
928 	return 0;
929 }
930 
931 static int
932 graph_setup(void)
933 {
934 	int i, j;
935 
936 	static const struct rte_mbuf_dynfield graph_dynfield_desc = {
937 		.name = "test_graph_dynfield",
938 		.size = sizeof(graph_dynfield_t),
939 		.align = alignof(graph_dynfield_t),
940 	};
941 	graph_dynfield_offset =
942 		rte_mbuf_dynfield_register(&graph_dynfield_desc);
943 	if (graph_dynfield_offset < 0) {
944 		printf("Cannot register mbuf field\n");
945 		return TEST_FAILED;
946 	}
947 
948 	for (i = 0; i <= MAX_NODES; i++) {
949 		for (j = 0; j < MBUFF_SIZE; j++)
950 			mbuf_p[i][j] = &mbuf[i][j];
951 	}
952 	if (test_node_clone()) {
953 		printf("test_node_clone: fail\n");
954 		return -1;
955 	}
956 	printf("test_node_clone: pass\n");
957 
958 	return 0;
959 }
960 
961 static void
962 graph_teardown(void)
963 {
964 	int id;
965 
966 	id = rte_graph_destroy(rte_graph_from_name("worker0"));
967 	if (id)
968 		printf("Graph Destroy failed\n");
969 }
970 
971 static struct unit_test_suite graph_testsuite = {
972 	.suite_name = "Graph library test suite",
973 	.setup = graph_setup,
974 	.teardown = graph_teardown,
975 	.unit_test_cases = {
976 		TEST_CASE(test_update_edges),
977 		TEST_CASE(test_lookup_functions),
978 		TEST_CASE(test_create_graph),
979 		TEST_CASE(test_graph_clone),
980 		TEST_CASE(test_graph_model_mcore_dispatch_node_lcore_affinity_set),
981 		TEST_CASE(test_graph_model_mcore_dispatch_core_bind_unbind),
982 		TEST_CASE(test_graph_worker_model_set_get),
983 		TEST_CASE(test_graph_lookup_functions),
984 		TEST_CASE(test_graph_walk),
985 		TEST_CASE(test_print_stats),
986 		TEST_CASES_END(), /**< NULL terminate unit test array */
987 	},
988 };
989 
990 static int
991 graph_autotest_fn(void)
992 {
993 	return unit_test_suite_runner(&graph_testsuite);
994 }
995 
996 REGISTER_FAST_TEST(graph_autotest, true, true, graph_autotest_fn);
997 
998 static int
999 test_node_list_dump(void)
1000 {
1001 	rte_node_list_dump(stdout);
1002 
1003 	return TEST_SUCCESS;
1004 }
1005 
1006 #endif /* !RTE_EXEC_ENV_WINDOWS */
1007 
1008 REGISTER_FAST_TEST(node_list_dump, true, true, test_node_list_dump);
1009