app/testpmd: fix metering and policing command for RFC4115
[dpdk.git] / app / test / test_graph.c
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 <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <rte_errno.h>
15
16 #ifdef RTE_EXEC_ENV_WINDOWS
17 static int
18 test_node_list_dump(void)
19 {
20         printf("node_list_dump not supported on Windows, skipping test\n");
21         return TEST_SKIPPED;
22 }
23
24 #else
25
26 #include <rte_graph.h>
27 #include <rte_graph_worker.h>
28 #include <rte_mbuf.h>
29 #include <rte_mbuf_dyn.h>
30 #include <rte_random.h>
31
32 static uint16_t test_node_worker_source(struct rte_graph *graph,
33                                         struct rte_node *node, void **objs,
34                                         uint16_t nb_objs);
35
36 static uint16_t test_node0_worker(struct rte_graph *graph,
37                                   struct rte_node *node, void **objs,
38                                   uint16_t nb_objs);
39
40 static uint16_t test_node1_worker(struct rte_graph *graph,
41                                   struct rte_node *node, void **objs,
42                                   uint16_t nb_objs);
43
44 static uint16_t test_node2_worker(struct rte_graph *graph,
45                                   struct rte_node *node, void **objs,
46                                   uint16_t nb_objs);
47
48 static uint16_t test_node3_worker(struct rte_graph *graph,
49                                   struct rte_node *node, void **objs,
50                                   uint16_t nb_objs);
51
52 #define MBUFF_SIZE 512
53 #define MAX_NODES  4
54
55 typedef uint64_t graph_dynfield_t;
56 static int graph_dynfield_offset = -1;
57
58 static inline graph_dynfield_t *
59 graph_field(struct rte_mbuf *mbuf)
60 {
61         return RTE_MBUF_DYNFIELD(mbuf, \
62                         graph_dynfield_offset, graph_dynfield_t *);
63 }
64
65 static struct rte_mbuf mbuf[MAX_NODES + 1][MBUFF_SIZE];
66 static void *mbuf_p[MAX_NODES + 1][MBUFF_SIZE];
67 static rte_graph_t graph_id;
68 static uint64_t obj_stats[MAX_NODES + 1];
69 static uint64_t fn_calls[MAX_NODES + 1];
70
71 const char *node_patterns[] = {
72         "test_node_source1",       "test_node00",
73         "test_node00-test_node11", "test_node00-test_node22",
74         "test_node00-test_node33",
75 };
76
77 const char *node_names[] = {
78         "test_node00",
79         "test_node00-test_node11",
80         "test_node00-test_node22",
81         "test_node00-test_node33",
82 };
83
84 struct test_node_register {
85         char name[RTE_NODE_NAMESIZE];
86         rte_node_process_t process;
87         uint16_t nb_edges;
88         const char *next_nodes[MAX_NODES];
89 };
90
91 typedef struct {
92         uint32_t idx;
93         struct test_node_register node;
94 } test_node_t;
95
96 typedef struct {
97         test_node_t test_node[MAX_NODES];
98 } test_main_t;
99
100 static test_main_t test_main = {
101         .test_node = {
102                 {
103                         .node = {
104                                         .name = "test_node00",
105                                         .process = test_node0_worker,
106                                         .nb_edges = 2,
107                                         .next_nodes = {"test_node00-"
108                                                        "test_node11",
109                                                        "test_node00-"
110                                                        "test_node22"},
111                                 },
112                 },
113                 {
114                         .node = {
115                                         .name = "test_node11",
116                                         .process = test_node1_worker,
117                                         .nb_edges = 1,
118                                         .next_nodes = {"test_node00-"
119                                                        "test_node22"},
120                                 },
121                 },
122                 {
123                         .node = {
124                                         .name = "test_node22",
125                                         .process = test_node2_worker,
126                                         .nb_edges = 1,
127                                         .next_nodes = {"test_node00-"
128                                                        "test_node33"},
129                                 },
130                 },
131                 {
132                         .node = {
133                                         .name = "test_node33",
134                                         .process = test_node3_worker,
135                                         .nb_edges = 1,
136                                         .next_nodes = {"test_node00"},
137                                 },
138                 },
139         },
140 };
141
142 static int
143 node_init(const struct rte_graph *graph, struct rte_node *node)
144 {
145         RTE_SET_USED(graph);
146         *(uint32_t *)node->ctx = node->id;
147
148         return 0;
149 }
150
151 static struct rte_node_register test_node_source = {
152         .name = "test_node_source1",
153         .process = test_node_worker_source,
154         .flags = RTE_NODE_SOURCE_F,
155         .nb_edges = 2,
156         .init = node_init,
157         .next_nodes = {"test_node00", "test_node00-test_node11"},
158 };
159 RTE_NODE_REGISTER(test_node_source);
160
161 static struct rte_node_register test_node0 = {
162         .name = "test_node00",
163         .process = test_node0_worker,
164         .init = node_init,
165 };
166 RTE_NODE_REGISTER(test_node0);
167
168 uint16_t
169 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
170                         void **objs, uint16_t nb_objs)
171 {
172         uint32_t obj_node0 = rte_rand() % 100, obj_node1;
173         test_main_t *tm = &test_main;
174         struct rte_mbuf *data;
175         void **next_stream;
176         rte_node_t next;
177         uint32_t i;
178
179         RTE_SET_USED(objs);
180         nb_objs = RTE_GRAPH_BURST_SIZE;
181
182         /* Prepare stream for next node 0 */
183         obj_node0 = nb_objs * obj_node0 * 0.01;
184         next = 0;
185         next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
186         for (i = 0; i < obj_node0; i++) {
187                 data = &mbuf[0][i];
188                 *graph_field(data) = ((uint64_t)tm->test_node[0].idx << 32) | i;
189                 if ((i + 1) == obj_node0)
190                         *graph_field(data) |= (1 << 16);
191                 next_stream[i] = &mbuf[0][i];
192         }
193         rte_node_next_stream_put(graph, node, next, obj_node0);
194
195         /* Prepare stream for next node 1 */
196         obj_node1 = nb_objs - obj_node0;
197         next = 1;
198         next_stream = rte_node_next_stream_get(graph, node, next, obj_node1);
199         for (i = 0; i < obj_node1; i++) {
200                 data = &mbuf[0][obj_node0 + i];
201                 *graph_field(data) = ((uint64_t)tm->test_node[1].idx << 32) | i;
202                 if ((i + 1) == obj_node1)
203                         *graph_field(data) |= (1 << 16);
204                 next_stream[i] = &mbuf[0][obj_node0 + i];
205         }
206
207         rte_node_next_stream_put(graph, node, next, obj_node1);
208         obj_stats[0] += nb_objs;
209         fn_calls[0] += 1;
210         return nb_objs;
211 }
212
213 uint16_t
214 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
215                   uint16_t nb_objs)
216 {
217         test_main_t *tm = &test_main;
218
219         if (*(uint32_t *)node->ctx == test_node0.id) {
220                 uint32_t obj_node0 = rte_rand() % 100, obj_node1;
221                 struct rte_mbuf *data;
222                 uint8_t second_pass = 0;
223                 uint32_t count = 0;
224                 uint32_t i;
225
226                 obj_stats[1] += nb_objs;
227                 fn_calls[1] += 1;
228
229                 for (i = 0; i < nb_objs; i++) {
230                         data = (struct rte_mbuf *)objs[i];
231                         if ((*graph_field(data) >> 32) != tm->test_node[0].idx) {
232                                 printf("Data idx miss match at node 0, expected"
233                                        " = %u got = %u\n",
234                                        tm->test_node[0].idx,
235                                        (uint32_t)(*graph_field(data) >> 32));
236                                 goto end;
237                         }
238
239                         if ((*graph_field(data) & 0xffff) != (i - count)) {
240                                 printf("Expected buff count miss match at "
241                                        "node 0\n");
242                                 goto end;
243                         }
244
245                         if (*graph_field(data) & (0x1 << 16))
246                                 count = i + 1;
247                         if (*graph_field(data) & (0x1 << 17))
248                                 second_pass = 1;
249                 }
250
251                 if (count != i) {
252                         printf("Count mismatch at node 0\n");
253                         goto end;
254                 }
255
256                 obj_node0 = nb_objs * obj_node0 * 0.01;
257                 for (i = 0; i < obj_node0; i++) {
258                         data = &mbuf[1][i];
259                         *graph_field(data) =
260                                 ((uint64_t)tm->test_node[1].idx << 32) | i;
261                         if ((i + 1) == obj_node0)
262                                 *graph_field(data) |= (1 << 16);
263                         if (second_pass)
264                                 *graph_field(data) |= (1 << 17);
265                 }
266                 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
267                                  obj_node0);
268
269                 obj_node1 = nb_objs - obj_node0;
270                 for (i = 0; i < obj_node1; i++) {
271                         data = &mbuf[1][obj_node0 + i];
272                         *graph_field(data) =
273                                 ((uint64_t)tm->test_node[2].idx << 32) | i;
274                         if ((i + 1) == obj_node1)
275                                 *graph_field(data) |= (1 << 16);
276                         if (second_pass)
277                                 *graph_field(data) |= (1 << 17);
278                 }
279                 rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
280                                  obj_node1);
281
282         } else if (*(uint32_t *)node->ctx == tm->test_node[1].idx) {
283                 test_node1_worker(graph, node, objs, nb_objs);
284         } else if (*(uint32_t *)node->ctx == tm->test_node[2].idx) {
285                 test_node2_worker(graph, node, objs, nb_objs);
286         } else if (*(uint32_t *)node->ctx == tm->test_node[3].idx) {
287                 test_node3_worker(graph, node, objs, nb_objs);
288         } else {
289                 printf("Unexpected node context\n");
290         }
291
292 end:
293         return nb_objs;
294 }
295
296 uint16_t
297 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
298                   uint16_t nb_objs)
299 {
300         test_main_t *tm = &test_main;
301         uint8_t second_pass = 0;
302         uint32_t obj_node0 = 0;
303         struct rte_mbuf *data;
304         uint32_t count = 0;
305         uint32_t i;
306
307         obj_stats[2] += nb_objs;
308         fn_calls[2] += 1;
309         for (i = 0; i < nb_objs; i++) {
310                 data = (struct rte_mbuf *)objs[i];
311                 if ((*graph_field(data) >> 32) != tm->test_node[1].idx) {
312                         printf("Data idx miss match at node 1, expected = %u"
313                                " got = %u\n",
314                                tm->test_node[1].idx,
315                                (uint32_t)(*graph_field(data) >> 32));
316                         goto end;
317                 }
318
319                 if ((*graph_field(data) & 0xffff) != (i - count)) {
320                         printf("Expected buff count miss match at node 1\n");
321                         goto end;
322                 }
323
324                 if (*graph_field(data) & (0x1 << 16))
325                         count = i + 1;
326                 if (*graph_field(data) & (0x1 << 17))
327                         second_pass = 1;
328         }
329
330         if (count != i) {
331                 printf("Count mismatch at node 1\n");
332                 goto end;
333         }
334
335         obj_node0 = nb_objs;
336         for (i = 0; i < obj_node0; i++) {
337                 data = &mbuf[2][i];
338                 *graph_field(data) = ((uint64_t)tm->test_node[2].idx << 32) | i;
339                 if ((i + 1) == obj_node0)
340                         *graph_field(data) |= (1 << 16);
341                 if (second_pass)
342                         *graph_field(data) |= (1 << 17);
343         }
344         rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
345
346 end:
347         return nb_objs;
348 }
349
350 uint16_t
351 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
352                   uint16_t nb_objs)
353 {
354         test_main_t *tm = &test_main;
355         uint8_t second_pass = 0;
356         struct rte_mbuf *data;
357         uint32_t count = 0;
358         uint32_t obj_node0;
359         uint32_t i;
360
361         obj_stats[3] += nb_objs;
362         fn_calls[3] += 1;
363         for (i = 0; i < nb_objs; i++) {
364                 data = (struct rte_mbuf *)objs[i];
365                 if ((*graph_field(data) >> 32) != tm->test_node[2].idx) {
366                         printf("Data idx miss match at node 2, expected = %u"
367                                " got = %u\n",
368                                tm->test_node[2].idx,
369                                (uint32_t)(*graph_field(data) >> 32));
370                         goto end;
371                 }
372
373                 if ((*graph_field(data) & 0xffff) != (i - count)) {
374                         printf("Expected buff count miss match at node 2\n");
375                         goto end;
376                 }
377
378                 if (*graph_field(data) & (0x1 << 16))
379                         count = i + 1;
380                 if (*graph_field(data) & (0x1 << 17))
381                         second_pass = 1;
382         }
383
384         if (count != i) {
385                 printf("Count mismatch at node 2\n");
386                 goto end;
387         }
388
389         if (!second_pass) {
390                 obj_node0 = nb_objs;
391                 for (i = 0; i < obj_node0; i++) {
392                         data = &mbuf[3][i];
393                         *graph_field(data) =
394                                 ((uint64_t)tm->test_node[3].idx << 32) | i;
395                         if ((i + 1) == obj_node0)
396                                 *graph_field(data) |= (1 << 16);
397                 }
398                 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
399                                  obj_node0);
400         }
401
402 end:
403         return nb_objs;
404 }
405
406 uint16_t
407 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
408                   uint16_t nb_objs)
409 {
410         test_main_t *tm = &test_main;
411         uint8_t second_pass = 0;
412         struct rte_mbuf *data;
413         uint32_t count = 0;
414         uint32_t obj_node0;
415         uint32_t i;
416
417         obj_stats[4] += nb_objs;
418         fn_calls[4] += 1;
419         for (i = 0; i < nb_objs; i++) {
420                 data = (struct rte_mbuf *)objs[i];
421                 if ((*graph_field(data) >> 32) != tm->test_node[3].idx) {
422                         printf("Data idx miss match at node 3, expected = %u"
423                                " got = %u\n",
424                                tm->test_node[3].idx,
425                                (uint32_t)(*graph_field(data) >> 32));
426                         goto end;
427                 }
428
429                 if ((*graph_field(data) & 0xffff) != (i - count)) {
430                         printf("Expected buff count miss match at node 3\n");
431                         goto end;
432                 }
433
434                 if (*graph_field(data) & (0x1 << 16))
435                         count = i + 1;
436                 if (*graph_field(data) & (0x1 << 17))
437                         second_pass = 1;
438         }
439
440         if (count != i) {
441                 printf("Count mismatch at node 3\n");
442                 goto end;
443         }
444
445         if (second_pass) {
446                 printf("Unexpected buffers are at node 3\n");
447                 goto end;
448         } else {
449                 obj_node0 = nb_objs * 2;
450                 for (i = 0; i < obj_node0; i++) {
451                         data = &mbuf[4][i];
452                         *graph_field(data) =
453                                 ((uint64_t)tm->test_node[0].idx << 32) | i;
454                         *graph_field(data) |= (1 << 17);
455                         if ((i + 1) == obj_node0)
456                                 *graph_field(data) |= (1 << 16);
457                 }
458                 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
459                                  obj_node0);
460         }
461
462 end:
463         return nb_objs;
464 }
465
466 static int
467 test_lookup_functions(void)
468 {
469         test_main_t *tm = &test_main;
470         int i;
471
472         /* Verify the name with ID */
473         for (i = 1; i < MAX_NODES; i++) {
474                 char *name = rte_node_id_to_name(tm->test_node[i].idx);
475                 if (strcmp(name, node_names[i]) != 0) {
476                         printf("Test node name verify by ID = %d failed "
477                                "Expected = %s, got %s\n",
478                                i, node_names[i], name);
479                         return -1;
480                 }
481         }
482
483         /* Verify by name */
484         for (i = 1; i < MAX_NODES; i++) {
485                 uint32_t idx = rte_node_from_name(node_names[i]);
486                 if (idx != tm->test_node[i].idx) {
487                         printf("Test node ID verify by name = %s failed "
488                                "Expected = %d, got %d\n",
489                                node_names[i], tm->test_node[i].idx, idx);
490                         return -1;
491                 }
492         }
493
494         /* Verify edge count */
495         for (i = 1; i < MAX_NODES; i++) {
496                 uint32_t count = rte_node_edge_count(tm->test_node[i].idx);
497                 if (count != tm->test_node[i].node.nb_edges) {
498                         printf("Test number of edges for node = %s failed Expected = %d, got = %d\n",
499                                tm->test_node[i].node.name,
500                                tm->test_node[i].node.nb_edges, count);
501                         return -1;
502                 }
503         }
504
505         /* Verify edge names */
506         for (i = 1; i < MAX_NODES; i++) {
507                 uint32_t j, count;
508                 char **next_edges;
509
510                 count = rte_node_edge_get(tm->test_node[i].idx, NULL);
511                 if (count != tm->test_node[i].node.nb_edges * sizeof(char *)) {
512                         printf("Test number of edge count for node = %s failed Expected = %d, got = %d\n",
513                                tm->test_node[i].node.name,
514                                tm->test_node[i].node.nb_edges, count);
515                         return -1;
516                 }
517                 next_edges = malloc(count);
518                 count = rte_node_edge_get(tm->test_node[i].idx, next_edges);
519                 if (count != tm->test_node[i].node.nb_edges) {
520                         printf("Test number of edges for node = %s failed Expected = %d, got %d\n",
521                                tm->test_node[i].node.name,
522                                tm->test_node[i].node.nb_edges, count);
523                         free(next_edges);
524                         return -1;
525                 }
526
527                 for (j = 0; j < count; j++) {
528                         if (strcmp(next_edges[j],
529                                    tm->test_node[i].node.next_nodes[j]) != 0) {
530                                 printf("Edge name miss match, expected = %s got = %s\n",
531                                        tm->test_node[i].node.next_nodes[j],
532                                        next_edges[j]);
533                                 free(next_edges);
534                                 return -1;
535                         }
536                 }
537                 free(next_edges);
538         }
539
540         return 0;
541 }
542
543 static int
544 test_node_clone(void)
545 {
546         test_main_t *tm = &test_main;
547         uint32_t node_id, dummy_id;
548         int i;
549
550         node_id = rte_node_from_name("test_node00");
551         tm->test_node[0].idx = node_id;
552
553         dummy_id = rte_node_clone(node_id, "test_node00");
554         if (rte_node_is_invalid(dummy_id)) {
555                 printf("Got invalid id when clone, Expecting fail\n");
556                 return -1;
557         }
558
559         /* Clone with same name, should fail */
560         dummy_id = rte_node_clone(node_id, "test_node00");
561         if (!rte_node_is_invalid(dummy_id)) {
562                 printf("Got valid id when clone with same name, Expecting fail\n");
563                 return -1;
564         }
565
566         for (i = 1; i < MAX_NODES; i++) {
567                 tm->test_node[i].idx =
568                         rte_node_clone(node_id, tm->test_node[i].node.name);
569                 if (rte_node_is_invalid(tm->test_node[i].idx)) {
570                         printf("Got invalid node id\n");
571                         return -1;
572                 }
573         }
574
575         /* Clone from cloned node should fail */
576         dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node");
577         if (!rte_node_is_invalid(dummy_id)) {
578                 printf("Got valid node id when cloning from cloned node, expected fail\n");
579                 return -1;
580         }
581
582         return 0;
583 }
584
585 static int
586 test_update_edges(void)
587 {
588         test_main_t *tm = &test_main;
589         uint32_t node_id;
590         uint16_t count;
591         int i;
592
593         node_id = rte_node_from_name("test_node00");
594         count = rte_node_edge_update(node_id, 0,
595                                      tm->test_node[0].node.next_nodes,
596                                      tm->test_node[0].node.nb_edges);
597         if (count != tm->test_node[0].node.nb_edges) {
598                 printf("Update edges failed expected: %d got = %d\n",
599                        tm->test_node[0].node.nb_edges, count);
600                 return -1;
601         }
602
603         for (i = 1; i < MAX_NODES; i++) {
604                 count = rte_node_edge_update(tm->test_node[i].idx, 0,
605                                              tm->test_node[i].node.next_nodes,
606                                              tm->test_node[i].node.nb_edges);
607                 if (count != tm->test_node[i].node.nb_edges) {
608                         printf("Update edges failed expected: %d got = %d\n",
609                                tm->test_node[i].node.nb_edges, count);
610                         return -1;
611                 }
612
613                 count = rte_node_edge_shrink(tm->test_node[i].idx,
614                                              tm->test_node[i].node.nb_edges);
615                 if (count != tm->test_node[i].node.nb_edges) {
616                         printf("Shrink edges failed\n");
617                         return -1;
618                 }
619         }
620
621         return 0;
622 }
623
624 static int
625 test_create_graph(void)
626 {
627         static const char *node_patterns_dummy[] = {
628                 "test_node_source1",       "test_node00",
629                 "test_node00-test_node11", "test_node00-test_node22",
630                 "test_node00-test_node33", "test_node00-dummy_node",
631         };
632         struct rte_graph_param gconf = {
633                 .socket_id = SOCKET_ID_ANY,
634                 .nb_node_patterns = 6,
635                 .node_patterns = node_patterns_dummy,
636         };
637         uint32_t dummy_node_id;
638         uint32_t node_id;
639
640         node_id = rte_node_from_name("test_node00");
641         dummy_node_id = rte_node_clone(node_id, "dummy_node");
642         if (rte_node_is_invalid(dummy_node_id)) {
643                 printf("Got invalid node id\n");
644                 return -1;
645         }
646
647         graph_id = rte_graph_create("worker0", &gconf);
648         if (graph_id != RTE_GRAPH_ID_INVALID) {
649                 printf("Graph creation success with isolated node, expected graph creation fail\n");
650                 return -1;
651         }
652
653         gconf.nb_node_patterns = 5;
654         gconf.node_patterns = node_patterns;
655         graph_id = rte_graph_create("worker0", &gconf);
656         if (graph_id == RTE_GRAPH_ID_INVALID) {
657                 printf("Graph creation failed with error = %d\n", rte_errno);
658                 return -1;
659         }
660         return 0;
661 }
662
663 static int
664 test_graph_walk(void)
665 {
666         struct rte_graph *graph = rte_graph_lookup("worker0");
667         int i;
668
669         if (!graph) {
670                 printf("Graph lookup failed\n");
671                 return -1;
672         }
673
674         for (i = 0; i < 5; i++)
675                 rte_graph_walk(graph);
676         return 0;
677 }
678
679 static int
680 test_graph_lookup_functions(void)
681 {
682         test_main_t *tm = &test_main;
683         struct rte_node *node;
684         int i;
685
686         for (i = 0; i < MAX_NODES; i++) {
687                 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
688                 if (!node) {
689                         printf("rte_graph_node_get, failed for node = %d\n",
690                                tm->test_node[i].idx);
691                         return -1;
692                 }
693
694                 if (tm->test_node[i].idx != node->id) {
695                         printf("Node id didn't match, expected = %d got = %d\n",
696                                tm->test_node[i].idx, node->id);
697                         return 0;
698                 }
699
700                 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
701                         printf("Node name didn't match, expected = %s got %s\n",
702                                node_names[i], node->name);
703                         return -1;
704                 }
705         }
706
707         for (i = 0; i < MAX_NODES; i++) {
708                 node = rte_graph_node_get_by_name("worker0", node_names[i]);
709                 if (!node) {
710                         printf("rte_graph_node_get, failed for node = %d\n",
711                                tm->test_node[i].idx);
712                         return -1;
713                 }
714
715                 if (tm->test_node[i].idx != node->id) {
716                         printf("Node id didn't match, expected = %d got = %d\n",
717                                tm->test_node[i].idx, node->id);
718                         return 0;
719                 }
720
721                 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
722                         printf("Node name didn't match, expected = %s got %s\n",
723                                node_names[i], node->name);
724                         return -1;
725                 }
726         }
727
728         return 0;
729 }
730
731 static int
732 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
733                          const struct rte_graph_cluster_node_stats *st)
734 {
735         int i;
736
737         RTE_SET_USED(is_first);
738         RTE_SET_USED(is_last);
739         RTE_SET_USED(cookie);
740
741         for (i = 0; i < MAX_NODES + 1; i++) {
742                 rte_node_t id = rte_node_from_name(node_patterns[i]);
743                 if (id == st->id) {
744                         if (obj_stats[i] != st->objs) {
745                                 printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
746                                        node_patterns[i], obj_stats[i],
747                                        st->objs);
748                                 return -1;
749                         }
750
751                         if (fn_calls[i] != st->calls) {
752                                 printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
753                                        node_patterns[i], fn_calls[i],
754                                        st->calls);
755                                 return -1;
756                         }
757                 }
758         }
759         return 0;
760 }
761
762 static int
763 test_print_stats(void)
764 {
765         struct rte_graph_cluster_stats_param s_param;
766         struct rte_graph_cluster_stats *stats;
767         const char *pattern = "worker0";
768
769         if (!rte_graph_has_stats_feature())
770                 return 0;
771
772         /* Prepare stats object */
773         memset(&s_param, 0, sizeof(s_param));
774         s_param.f = stdout;
775         s_param.socket_id = SOCKET_ID_ANY;
776         s_param.graph_patterns = &pattern;
777         s_param.nb_graph_patterns = 1;
778         s_param.fn = graph_cluster_stats_cb_t;
779
780         stats = rte_graph_cluster_stats_create(&s_param);
781         if (stats == NULL) {
782                 printf("Unable to get stats\n");
783                 return -1;
784         }
785         /* Clear screen and move to top left */
786         rte_graph_cluster_stats_get(stats, 0);
787         rte_graph_cluster_stats_destroy(stats);
788
789         return 0;
790 }
791
792 static int
793 graph_setup(void)
794 {
795         int i, j;
796
797         static const struct rte_mbuf_dynfield graph_dynfield_desc = {
798                 .name = "test_graph_dynfield",
799                 .size = sizeof(graph_dynfield_t),
800                 .align = __alignof__(graph_dynfield_t),
801         };
802         graph_dynfield_offset =
803                 rte_mbuf_dynfield_register(&graph_dynfield_desc);
804         if (graph_dynfield_offset < 0) {
805                 printf("Cannot register mbuf field\n");
806                 return TEST_FAILED;
807         }
808
809         for (i = 0; i <= MAX_NODES; i++) {
810                 for (j = 0; j < MBUFF_SIZE; j++)
811                         mbuf_p[i][j] = &mbuf[i][j];
812         }
813         if (test_node_clone()) {
814                 printf("test_node_clone: fail\n");
815                 return -1;
816         }
817         printf("test_node_clone: pass\n");
818
819         return 0;
820 }
821
822 static void
823 graph_teardown(void)
824 {
825         int id;
826
827         id = rte_graph_destroy(rte_graph_from_name("worker0"));
828         if (id)
829                 printf("Graph Destroy failed\n");
830 }
831
832 static struct unit_test_suite graph_testsuite = {
833         .suite_name = "Graph library test suite",
834         .setup = graph_setup,
835         .teardown = graph_teardown,
836         .unit_test_cases = {
837                 TEST_CASE(test_update_edges),
838                 TEST_CASE(test_lookup_functions),
839                 TEST_CASE(test_create_graph),
840                 TEST_CASE(test_graph_lookup_functions),
841                 TEST_CASE(test_graph_walk),
842                 TEST_CASE(test_print_stats),
843                 TEST_CASES_END(), /**< NULL terminate unit test array */
844         },
845 };
846
847 static int
848 graph_autotest_fn(void)
849 {
850         return unit_test_suite_runner(&graph_testsuite);
851 }
852
853 REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
854
855 static int
856 test_node_list_dump(void)
857 {
858         rte_node_list_dump(stdout);
859
860         return TEST_SUCCESS;
861 }
862
863 #endif /* !RTE_EXEC_ENV_WINDOWS */
864
865 REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);