1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2020 Marvell International Ltd.
8 #include <rte_common.h>
10 #include <rte_errno.h>
11 #include <rte_malloc.h>
12 #include <rte_memzone.h>
13 #include <rte_spinlock.h>
14 #include <rte_string_fns.h>
16 #include "graph_private.h"
18 static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list);
19 static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER;
20 static rte_graph_t graph_id;
21 int rte_graph_logtype;
23 #define GRAPH_ID_CHECK(id) ID_CHECK(id, graph_id)
25 /* Private functions */
27 graph_list_head_get(void)
33 graph_spinlock_lock(void)
35 rte_spinlock_lock(&graph_lock);
39 graph_spinlock_unlock(void)
41 rte_spinlock_unlock(&graph_lock);
45 graph_node_add(struct graph *graph, struct node *node)
47 struct graph_node *graph_node;
50 /* Skip the duplicate nodes */
51 STAILQ_FOREACH(graph_node, &graph->node_list, next)
52 if (strncmp(node->name, graph_node->node->name,
53 RTE_NODE_NAMESIZE) == 0)
56 /* Allocate new graph node object */
57 sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *);
58 graph_node = calloc(1, sz);
60 if (graph_node == NULL)
61 SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object",
64 /* Initialize the graph node */
65 graph_node->node = node;
67 /* Add to graph node list */
68 STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next);
76 static struct graph_node *
77 node_to_graph_node(struct graph *graph, struct node *node)
79 struct graph_node *graph_node;
81 STAILQ_FOREACH(graph_node, &graph->node_list, next)
82 if (graph_node->node == node)
85 SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name);
91 graph_node_edges_add(struct graph *graph)
93 struct graph_node *graph_node;
94 struct node *adjacency;
98 STAILQ_FOREACH(graph_node, &graph->node_list, next) {
99 for (i = 0; i < graph_node->node->nb_edges; i++) {
100 next = graph_node->node->next_nodes[i];
101 adjacency = node_from_name(next);
102 if (adjacency == NULL)
103 SET_ERR_JMP(EINVAL, fail,
104 "Node %s not registered", next);
105 if (graph_node_add(graph, adjacency))
115 graph_adjacency_list_update(struct graph *graph)
117 struct graph_node *graph_node, *tmp;
118 struct node *adjacency;
122 STAILQ_FOREACH(graph_node, &graph->node_list, next) {
123 for (i = 0; i < graph_node->node->nb_edges; i++) {
124 next = graph_node->node->next_nodes[i];
125 adjacency = node_from_name(next);
126 if (adjacency == NULL)
127 SET_ERR_JMP(EINVAL, fail,
128 "Node %s not registered", next);
129 tmp = node_to_graph_node(graph, adjacency);
132 graph_node->adjacency_list[i] = tmp;
142 expand_pattern_to_node(struct graph *graph, const char *pattern)
144 struct node_head *node_head = node_list_head_get();
148 /* Check for pattern match */
149 STAILQ_FOREACH(node, node_head, next) {
150 if (fnmatch(pattern, node->name, 0) == 0) {
151 if (graph_node_add(graph, node))
157 SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern);
165 graph_cleanup(struct graph *graph)
167 struct graph_node *graph_node;
169 while (!STAILQ_EMPTY(&graph->node_list)) {
170 graph_node = STAILQ_FIRST(&graph->node_list);
171 STAILQ_REMOVE_HEAD(&graph->node_list, next);
177 graph_node_init(struct graph *graph)
179 struct graph_node *graph_node;
183 STAILQ_FOREACH(graph_node, &graph->node_list, next) {
184 if (graph_node->node->init) {
185 name = graph_node->node->name;
186 rc = graph_node->node->init(
188 graph_node_name_to_ptr(graph->graph, name));
190 SET_ERR_JMP(rc, err, "Node %s init() failed",
201 graph_node_fini(struct graph *graph)
203 struct graph_node *graph_node;
205 STAILQ_FOREACH(graph_node, &graph->node_list, next)
206 if (graph_node->node->fini)
207 graph_node->node->fini(
209 graph_node_name_to_ptr(graph->graph,
210 graph_node->node->name));
213 static struct rte_graph *
214 graph_mem_fixup_node_ctx(struct rte_graph *graph)
216 struct rte_node *node;
217 struct node *node_db;
222 rte_graph_foreach_node(count, off, graph, node) {
223 if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
225 else /* Cloned node */
228 node_db = node_from_name(name);
230 SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
231 node->process = node_db->process;
239 static struct rte_graph *
240 graph_mem_fixup_secondary(struct rte_graph *graph)
242 if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
245 return graph_mem_fixup_node_ctx(graph);
249 rte_graph_lookup(const char *name)
251 const struct rte_memzone *mz;
252 struct rte_graph *rc = NULL;
254 mz = rte_memzone_lookup(name);
258 return graph_mem_fixup_secondary(rc);
262 rte_graph_create(const char *name, struct rte_graph_param *prm)
264 rte_node_t src_node_count;
269 graph_spinlock_lock();
271 /* Check arguments sanity */
273 SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
276 SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
278 /* Check for existence of duplicate graph */
279 STAILQ_FOREACH(graph, &graph_list, next)
280 if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
281 SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
284 /* Create graph object */
285 graph = calloc(1, sizeof(*graph));
287 SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
289 /* Initialize the graph object */
290 STAILQ_INIT(&graph->node_list);
291 if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
292 SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
294 /* Expand node pattern and add the nodes to the graph */
295 for (i = 0; i < prm->nb_node_patterns; i++) {
296 pattern = prm->node_patterns[i];
297 if (expand_pattern_to_node(graph, pattern))
301 /* Go over all the nodes edges and add them to the graph */
302 if (graph_node_edges_add(graph))
305 /* Update adjacency list of all nodes in the graph */
306 if (graph_adjacency_list_update(graph))
309 /* Make sure at least a source node present in the graph */
310 src_node_count = graph_src_nodes_count(graph);
311 if (src_node_count == 0)
314 /* Make sure no node is pointing to source node */
315 if (graph_node_has_edge_to_src_node(graph))
318 /* Don't allow node has loop to self */
319 if (graph_node_has_loop_edge(graph))
322 /* Do BFS from src nodes on the graph to find isolated nodes */
323 if (graph_has_isolated_node(graph))
326 /* Initialize graph object */
327 graph->socket = prm->socket_id;
328 graph->src_node_count = src_node_count;
329 graph->node_count = graph_nodes_count(graph);
330 graph->id = graph_id;
332 /* Allocate the Graph fast path memory and populate the data */
333 if (graph_fp_mem_create(graph))
336 /* Call init() of the all the nodes in the graph */
337 if (graph_node_init(graph))
338 goto graph_mem_destroy;
340 /* All good, Lets add the graph to the list */
342 STAILQ_INSERT_TAIL(&graph_list, graph, next);
344 graph_spinlock_unlock();
348 graph_fp_mem_destroy(graph);
350 graph_cleanup(graph);
354 graph_spinlock_unlock();
355 return RTE_GRAPH_ID_INVALID;
359 rte_graph_destroy(rte_graph_t id)
361 struct graph *graph, *tmp;
364 graph_spinlock_lock();
366 graph = STAILQ_FIRST(&graph_list);
367 while (graph != NULL) {
368 tmp = STAILQ_NEXT(graph, next);
369 if (graph->id == id) {
370 /* Call fini() of the all the nodes in the graph */
371 graph_node_fini(graph);
372 /* Destroy graph fast path memory */
373 rc = graph_fp_mem_destroy(graph);
375 SET_ERR_JMP(rc, done, "Graph %s destroy failed",
378 graph_cleanup(graph);
379 STAILQ_REMOVE(&graph_list, graph, graph, next);
387 graph_spinlock_unlock();
392 rte_graph_from_name(const char *name)
396 STAILQ_FOREACH(graph, &graph_list, next)
397 if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
400 return RTE_GRAPH_ID_INVALID;
404 rte_graph_id_to_name(rte_graph_t id)
409 STAILQ_FOREACH(graph, &graph_list, next)
418 rte_graph_node_get(rte_graph_t gid, uint32_t nid)
420 struct rte_node *node;
426 STAILQ_FOREACH(graph, &graph_list, next)
427 if (graph->id == gid) {
428 rte_graph_foreach_node(count, off, graph->graph,
440 rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
442 struct rte_node *node;
447 STAILQ_FOREACH(graph, &graph_list, next)
448 if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
449 rte_graph_foreach_node(count, off, graph->graph,
451 if (!strncmp(node->name, node_name,
462 __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
464 uint16_t size = node->size;
466 RTE_VERIFY(size != UINT16_MAX);
467 /* Allocate double amount of size to avoid immediate realloc */
468 size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
469 node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
470 RTE_CACHE_LINE_SIZE, graph->socket);
471 RTE_VERIFY(node->objs);
473 node->realloc_count++;
477 __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
480 uint16_t size = node->size;
482 RTE_VERIFY(size != UINT16_MAX);
483 /* Allocate double amount of size to avoid immediate realloc */
484 size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
485 node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
486 RTE_CACHE_LINE_SIZE, graph->socket);
487 RTE_VERIFY(node->objs);
489 node->realloc_count++;
493 graph_to_dot(FILE *f, struct graph *graph)
495 const char *src_edge_color = " [color=blue]\n";
496 const char *edge_color = "\n";
497 struct graph_node *graph_node;
502 rc = fprintf(f, "Digraph %s {\n\trankdir=LR;\n", graph->name);
506 STAILQ_FOREACH(graph_node, &graph->node_list, next) {
507 node_name = graph_node->node->name;
508 for (i = 0; i < graph_node->node->nb_edges; i++) {
509 rc = fprintf(f, "\t\"%s\"->\"%s\"%s", node_name,
510 graph_node->adjacency_list[i]->node->name,
511 graph_node->node->flags & RTE_NODE_SOURCE_F
518 rc = fprintf(f, "}\n");
529 rte_graph_export(const char *name, FILE *f)
534 STAILQ_FOREACH(graph, &graph_list, next) {
535 if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
536 rc = graph_to_dot(f, graph);
545 graph_scan_dump(FILE *f, rte_graph_t id, bool all)
552 STAILQ_FOREACH(graph, &graph_list, next) {
554 graph_dump(f, graph);
555 } else if (graph->id == id) {
556 graph_dump(f, graph);
565 rte_graph_dump(FILE *f, rte_graph_t id)
567 graph_scan_dump(f, id, false);
571 rte_graph_list_dump(FILE *f)
573 graph_scan_dump(f, 0, true);
577 rte_graph_max_count(void)
582 RTE_INIT(rte_graph_init_log)
584 rte_graph_logtype = rte_log_register("lib.graph");
585 if (rte_graph_logtype >= 0)
586 rte_log_set_level(rte_graph_logtype, RTE_LOG_INFO);