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