xref: /dpdk/lib/graph/graph.c (revision eeded204)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(C) 2020 Marvell International Ltd.
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <fnmatch.h>
699a2dd95SBruce Richardson #include <stdbool.h>
799a2dd95SBruce Richardson 
899a2dd95SBruce Richardson #include <rte_common.h>
999a2dd95SBruce Richardson #include <rte_debug.h>
1099a2dd95SBruce Richardson #include <rte_errno.h>
1199a2dd95SBruce Richardson #include <rte_malloc.h>
1299a2dd95SBruce Richardson #include <rte_memzone.h>
1399a2dd95SBruce Richardson #include <rte_spinlock.h>
1499a2dd95SBruce Richardson #include <rte_string_fns.h>
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #include "graph_private.h"
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list);
1999a2dd95SBruce Richardson static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER;
2099a2dd95SBruce Richardson static rte_graph_t graph_id;
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson #define GRAPH_ID_CHECK(id) ID_CHECK(id, graph_id)
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson /* Private functions */
2599a2dd95SBruce Richardson struct graph_head *
graph_list_head_get(void)2699a2dd95SBruce Richardson graph_list_head_get(void)
2799a2dd95SBruce Richardson {
2899a2dd95SBruce Richardson 	return &graph_list;
2999a2dd95SBruce Richardson }
3099a2dd95SBruce Richardson 
3199a2dd95SBruce Richardson void
graph_spinlock_lock(void)3299a2dd95SBruce Richardson graph_spinlock_lock(void)
3399a2dd95SBruce Richardson {
3499a2dd95SBruce Richardson 	rte_spinlock_lock(&graph_lock);
3599a2dd95SBruce Richardson }
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson void
graph_spinlock_unlock(void)3899a2dd95SBruce Richardson graph_spinlock_unlock(void)
3999a2dd95SBruce Richardson {
4099a2dd95SBruce Richardson 	rte_spinlock_unlock(&graph_lock);
4199a2dd95SBruce Richardson }
4299a2dd95SBruce Richardson 
4399a2dd95SBruce Richardson static int
graph_node_add(struct graph * graph,struct node * node)4499a2dd95SBruce Richardson graph_node_add(struct graph *graph, struct node *node)
4599a2dd95SBruce Richardson {
4699a2dd95SBruce Richardson 	struct graph_node *graph_node;
4799a2dd95SBruce Richardson 	size_t sz;
4899a2dd95SBruce Richardson 
4999a2dd95SBruce Richardson 	/* Skip the duplicate nodes */
5099a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
5199a2dd95SBruce Richardson 		if (strncmp(node->name, graph_node->node->name,
5299a2dd95SBruce Richardson 			    RTE_NODE_NAMESIZE) == 0)
5399a2dd95SBruce Richardson 			return 0;
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson 	/* Allocate new graph node object */
5699a2dd95SBruce Richardson 	sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *);
5799a2dd95SBruce Richardson 	graph_node = calloc(1, sz);
5899a2dd95SBruce Richardson 
5999a2dd95SBruce Richardson 	if (graph_node == NULL)
6099a2dd95SBruce Richardson 		SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object",
6199a2dd95SBruce Richardson 			    node->name);
6299a2dd95SBruce Richardson 
6399a2dd95SBruce Richardson 	/* Initialize the graph node */
6499a2dd95SBruce Richardson 	graph_node->node = node;
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson 	/* Add to graph node list */
6799a2dd95SBruce Richardson 	STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next);
6899a2dd95SBruce Richardson 	return 0;
6999a2dd95SBruce Richardson 
7099a2dd95SBruce Richardson free:
7199a2dd95SBruce Richardson 	free(graph_node);
7299a2dd95SBruce Richardson 	return -rte_errno;
7399a2dd95SBruce Richardson }
7499a2dd95SBruce Richardson 
7599a2dd95SBruce Richardson static struct graph_node *
node_to_graph_node(struct graph * graph,struct node * node)7699a2dd95SBruce Richardson node_to_graph_node(struct graph *graph, struct node *node)
7799a2dd95SBruce Richardson {
7899a2dd95SBruce Richardson 	struct graph_node *graph_node;
7999a2dd95SBruce Richardson 
8099a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
8199a2dd95SBruce Richardson 		if (graph_node->node == node)
8299a2dd95SBruce Richardson 			return graph_node;
8399a2dd95SBruce Richardson 
8499a2dd95SBruce Richardson 	SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name);
8599a2dd95SBruce Richardson fail:
8699a2dd95SBruce Richardson 	return NULL;
8799a2dd95SBruce Richardson }
8899a2dd95SBruce Richardson 
8999a2dd95SBruce Richardson static int
graph_node_edges_add(struct graph * graph)9099a2dd95SBruce Richardson graph_node_edges_add(struct graph *graph)
9199a2dd95SBruce Richardson {
9299a2dd95SBruce Richardson 	struct graph_node *graph_node;
9399a2dd95SBruce Richardson 	struct node *adjacency;
9499a2dd95SBruce Richardson 	const char *next;
9599a2dd95SBruce Richardson 	rte_edge_t i;
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
9899a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
9999a2dd95SBruce Richardson 			next = graph_node->node->next_nodes[i];
10099a2dd95SBruce Richardson 			adjacency = node_from_name(next);
10199a2dd95SBruce Richardson 			if (adjacency == NULL)
10299a2dd95SBruce Richardson 				SET_ERR_JMP(EINVAL, fail,
10399a2dd95SBruce Richardson 					    "Node %s not registered", next);
10499a2dd95SBruce Richardson 			if (graph_node_add(graph, adjacency))
10599a2dd95SBruce Richardson 				goto fail;
10699a2dd95SBruce Richardson 		}
10799a2dd95SBruce Richardson 	}
10899a2dd95SBruce Richardson 	return 0;
10999a2dd95SBruce Richardson fail:
11099a2dd95SBruce Richardson 	return -rte_errno;
11199a2dd95SBruce Richardson }
11299a2dd95SBruce Richardson 
11399a2dd95SBruce Richardson static int
graph_adjacency_list_update(struct graph * graph)11499a2dd95SBruce Richardson graph_adjacency_list_update(struct graph *graph)
11599a2dd95SBruce Richardson {
11699a2dd95SBruce Richardson 	struct graph_node *graph_node, *tmp;
11799a2dd95SBruce Richardson 	struct node *adjacency;
11899a2dd95SBruce Richardson 	const char *next;
11999a2dd95SBruce Richardson 	rte_edge_t i;
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
12299a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
12399a2dd95SBruce Richardson 			next = graph_node->node->next_nodes[i];
12499a2dd95SBruce Richardson 			adjacency = node_from_name(next);
12599a2dd95SBruce Richardson 			if (adjacency == NULL)
12699a2dd95SBruce Richardson 				SET_ERR_JMP(EINVAL, fail,
12799a2dd95SBruce Richardson 					    "Node %s not registered", next);
12899a2dd95SBruce Richardson 			tmp = node_to_graph_node(graph, adjacency);
12999a2dd95SBruce Richardson 			if (tmp == NULL)
13099a2dd95SBruce Richardson 				goto fail;
13199a2dd95SBruce Richardson 			graph_node->adjacency_list[i] = tmp;
13299a2dd95SBruce Richardson 		}
13399a2dd95SBruce Richardson 	}
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson 	return 0;
13699a2dd95SBruce Richardson fail:
13799a2dd95SBruce Richardson 	return -rte_errno;
13899a2dd95SBruce Richardson }
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson static int
expand_pattern_to_node(struct graph * graph,const char * pattern)14199a2dd95SBruce Richardson expand_pattern_to_node(struct graph *graph, const char *pattern)
14299a2dd95SBruce Richardson {
14399a2dd95SBruce Richardson 	struct node_head *node_head = node_list_head_get();
14499a2dd95SBruce Richardson 	bool found = false;
14599a2dd95SBruce Richardson 	struct node *node;
14699a2dd95SBruce Richardson 
14799a2dd95SBruce Richardson 	/* Check for pattern match */
14899a2dd95SBruce Richardson 	STAILQ_FOREACH(node, node_head, next) {
14999a2dd95SBruce Richardson 		if (fnmatch(pattern, node->name, 0) == 0) {
15099a2dd95SBruce Richardson 			if (graph_node_add(graph, node))
15199a2dd95SBruce Richardson 				goto fail;
15299a2dd95SBruce Richardson 			found = true;
15399a2dd95SBruce Richardson 		}
15499a2dd95SBruce Richardson 	}
15599a2dd95SBruce Richardson 	if (found == false)
15699a2dd95SBruce Richardson 		SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern);
15799a2dd95SBruce Richardson 
15899a2dd95SBruce Richardson 	return 0;
15999a2dd95SBruce Richardson fail:
16099a2dd95SBruce Richardson 	return -rte_errno;
16199a2dd95SBruce Richardson }
16299a2dd95SBruce Richardson 
16399a2dd95SBruce Richardson static void
graph_cleanup(struct graph * graph)16499a2dd95SBruce Richardson graph_cleanup(struct graph *graph)
16599a2dd95SBruce Richardson {
16699a2dd95SBruce Richardson 	struct graph_node *graph_node;
16799a2dd95SBruce Richardson 
16899a2dd95SBruce Richardson 	while (!STAILQ_EMPTY(&graph->node_list)) {
16999a2dd95SBruce Richardson 		graph_node = STAILQ_FIRST(&graph->node_list);
17099a2dd95SBruce Richardson 		STAILQ_REMOVE_HEAD(&graph->node_list, next);
17199a2dd95SBruce Richardson 		free(graph_node);
17299a2dd95SBruce Richardson 	}
17399a2dd95SBruce Richardson }
17499a2dd95SBruce Richardson 
17599a2dd95SBruce Richardson static int
graph_node_init(struct graph * graph)17699a2dd95SBruce Richardson graph_node_init(struct graph *graph)
17799a2dd95SBruce Richardson {
17899a2dd95SBruce Richardson 	struct graph_node *graph_node;
17999a2dd95SBruce Richardson 	const char *name;
18099a2dd95SBruce Richardson 	int rc;
18199a2dd95SBruce Richardson 
18299a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
18399a2dd95SBruce Richardson 		if (graph_node->node->init) {
18499a2dd95SBruce Richardson 			name = graph_node->node->name;
18599a2dd95SBruce Richardson 			rc = graph_node->node->init(
18699a2dd95SBruce Richardson 				graph->graph,
18799a2dd95SBruce Richardson 				graph_node_name_to_ptr(graph->graph, name));
18899a2dd95SBruce Richardson 			if (rc)
18999a2dd95SBruce Richardson 				SET_ERR_JMP(rc, err, "Node %s init() failed",
19099a2dd95SBruce Richardson 					    name);
19199a2dd95SBruce Richardson 		}
19299a2dd95SBruce Richardson 	}
19399a2dd95SBruce Richardson 
19499a2dd95SBruce Richardson 	return 0;
19599a2dd95SBruce Richardson err:
19699a2dd95SBruce Richardson 	return -rte_errno;
19799a2dd95SBruce Richardson }
19899a2dd95SBruce Richardson 
19999a2dd95SBruce Richardson static void
graph_node_fini(struct graph * graph)20099a2dd95SBruce Richardson graph_node_fini(struct graph *graph)
20199a2dd95SBruce Richardson {
20299a2dd95SBruce Richardson 	struct graph_node *graph_node;
20399a2dd95SBruce Richardson 
20499a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
20599a2dd95SBruce Richardson 		if (graph_node->node->fini)
20699a2dd95SBruce Richardson 			graph_node->node->fini(
20799a2dd95SBruce Richardson 				graph->graph,
20899a2dd95SBruce Richardson 				graph_node_name_to_ptr(graph->graph,
20999a2dd95SBruce Richardson 						       graph_node->node->name));
21099a2dd95SBruce Richardson }
21199a2dd95SBruce Richardson 
21299a2dd95SBruce Richardson static struct rte_graph *
graph_mem_fixup_node_ctx(struct rte_graph * graph)21399a2dd95SBruce Richardson graph_mem_fixup_node_ctx(struct rte_graph *graph)
21499a2dd95SBruce Richardson {
21599a2dd95SBruce Richardson 	struct rte_node *node;
21699a2dd95SBruce Richardson 	struct node *node_db;
21799a2dd95SBruce Richardson 	rte_graph_off_t off;
21899a2dd95SBruce Richardson 	rte_node_t count;
21999a2dd95SBruce Richardson 	const char *name;
22099a2dd95SBruce Richardson 
22199a2dd95SBruce Richardson 	rte_graph_foreach_node(count, off, graph, node) {
22299a2dd95SBruce Richardson 		if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
22399a2dd95SBruce Richardson 			name = node->name;
22499a2dd95SBruce Richardson 		else /* Cloned node */
22599a2dd95SBruce Richardson 			name = node->parent;
22699a2dd95SBruce Richardson 
22799a2dd95SBruce Richardson 		node_db = node_from_name(name);
22899a2dd95SBruce Richardson 		if (node_db == NULL)
22999a2dd95SBruce Richardson 			SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
23099a2dd95SBruce Richardson 		node->process = node_db->process;
23199a2dd95SBruce Richardson 	}
23299a2dd95SBruce Richardson 
23399a2dd95SBruce Richardson 	return graph;
23499a2dd95SBruce Richardson fail:
23599a2dd95SBruce Richardson 	return NULL;
23699a2dd95SBruce Richardson }
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson static struct rte_graph *
graph_mem_fixup_secondary(struct rte_graph * graph)23999a2dd95SBruce Richardson graph_mem_fixup_secondary(struct rte_graph *graph)
24099a2dd95SBruce Richardson {
24199a2dd95SBruce Richardson 	if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
24299a2dd95SBruce Richardson 		return graph;
24399a2dd95SBruce Richardson 
24499a2dd95SBruce Richardson 	return graph_mem_fixup_node_ctx(graph);
24599a2dd95SBruce Richardson }
24699a2dd95SBruce Richardson 
24799a2dd95SBruce Richardson struct rte_graph *
rte_graph_lookup(const char * name)24899a2dd95SBruce Richardson rte_graph_lookup(const char *name)
24999a2dd95SBruce Richardson {
25099a2dd95SBruce Richardson 	const struct rte_memzone *mz;
25199a2dd95SBruce Richardson 	struct rte_graph *rc = NULL;
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson 	mz = rte_memzone_lookup(name);
25499a2dd95SBruce Richardson 	if (mz)
25599a2dd95SBruce Richardson 		rc = mz->addr;
25699a2dd95SBruce Richardson 
25799a2dd95SBruce Richardson 	return graph_mem_fixup_secondary(rc);
25899a2dd95SBruce Richardson }
25999a2dd95SBruce Richardson 
26099a2dd95SBruce Richardson rte_graph_t
rte_graph_create(const char * name,struct rte_graph_param * prm)26199a2dd95SBruce Richardson rte_graph_create(const char *name, struct rte_graph_param *prm)
26299a2dd95SBruce Richardson {
26399a2dd95SBruce Richardson 	rte_node_t src_node_count;
26499a2dd95SBruce Richardson 	struct graph *graph;
26599a2dd95SBruce Richardson 	const char *pattern;
26699a2dd95SBruce Richardson 	uint16_t i;
26799a2dd95SBruce Richardson 
26899a2dd95SBruce Richardson 	graph_spinlock_lock();
26999a2dd95SBruce Richardson 
27099a2dd95SBruce Richardson 	/* Check arguments sanity */
27199a2dd95SBruce Richardson 	if (prm == NULL)
27299a2dd95SBruce Richardson 		SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
27399a2dd95SBruce Richardson 
27499a2dd95SBruce Richardson 	if (name == NULL)
27599a2dd95SBruce Richardson 		SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
27699a2dd95SBruce Richardson 
27799a2dd95SBruce Richardson 	/* Check for existence of duplicate graph */
27899a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
27999a2dd95SBruce Richardson 		if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
28099a2dd95SBruce Richardson 			SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
28199a2dd95SBruce Richardson 				    name);
28299a2dd95SBruce Richardson 
28399a2dd95SBruce Richardson 	/* Create graph object */
28499a2dd95SBruce Richardson 	graph = calloc(1, sizeof(*graph));
28599a2dd95SBruce Richardson 	if (graph == NULL)
28699a2dd95SBruce Richardson 		SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
28799a2dd95SBruce Richardson 
28899a2dd95SBruce Richardson 	/* Initialize the graph object */
28999a2dd95SBruce Richardson 	STAILQ_INIT(&graph->node_list);
29099a2dd95SBruce Richardson 	if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
29199a2dd95SBruce Richardson 		SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
29299a2dd95SBruce Richardson 
29399a2dd95SBruce Richardson 	/* Expand node pattern and add the nodes to the graph */
29499a2dd95SBruce Richardson 	for (i = 0; i < prm->nb_node_patterns; i++) {
29599a2dd95SBruce Richardson 		pattern = prm->node_patterns[i];
29699a2dd95SBruce Richardson 		if (expand_pattern_to_node(graph, pattern))
29799a2dd95SBruce Richardson 			goto graph_cleanup;
29899a2dd95SBruce Richardson 	}
29999a2dd95SBruce Richardson 
30099a2dd95SBruce Richardson 	/* Go over all the nodes edges and add them to the graph */
30199a2dd95SBruce Richardson 	if (graph_node_edges_add(graph))
30299a2dd95SBruce Richardson 		goto graph_cleanup;
30399a2dd95SBruce Richardson 
30499a2dd95SBruce Richardson 	/* Update adjacency list of all nodes in the graph */
30599a2dd95SBruce Richardson 	if (graph_adjacency_list_update(graph))
30699a2dd95SBruce Richardson 		goto graph_cleanup;
30799a2dd95SBruce Richardson 
30899a2dd95SBruce Richardson 	/* Make sure at least a source node present in the graph */
30999a2dd95SBruce Richardson 	src_node_count = graph_src_nodes_count(graph);
31099a2dd95SBruce Richardson 	if (src_node_count == 0)
31199a2dd95SBruce Richardson 		goto graph_cleanup;
31299a2dd95SBruce Richardson 
31399a2dd95SBruce Richardson 	/* Make sure no node is pointing to source node */
31499a2dd95SBruce Richardson 	if (graph_node_has_edge_to_src_node(graph))
31599a2dd95SBruce Richardson 		goto graph_cleanup;
31699a2dd95SBruce Richardson 
31799a2dd95SBruce Richardson 	/* Don't allow node has loop to self */
31899a2dd95SBruce Richardson 	if (graph_node_has_loop_edge(graph))
31999a2dd95SBruce Richardson 		goto graph_cleanup;
32099a2dd95SBruce Richardson 
32199a2dd95SBruce Richardson 	/* Do BFS from src nodes on the graph to find isolated nodes */
32299a2dd95SBruce Richardson 	if (graph_has_isolated_node(graph))
32399a2dd95SBruce Richardson 		goto graph_cleanup;
32499a2dd95SBruce Richardson 
32599a2dd95SBruce Richardson 	/* Initialize graph object */
32699a2dd95SBruce Richardson 	graph->socket = prm->socket_id;
32799a2dd95SBruce Richardson 	graph->src_node_count = src_node_count;
32899a2dd95SBruce Richardson 	graph->node_count = graph_nodes_count(graph);
32999a2dd95SBruce Richardson 	graph->id = graph_id;
33099a2dd95SBruce Richardson 
33199a2dd95SBruce Richardson 	/* Allocate the Graph fast path memory and populate the data */
33299a2dd95SBruce Richardson 	if (graph_fp_mem_create(graph))
33399a2dd95SBruce Richardson 		goto graph_cleanup;
33499a2dd95SBruce Richardson 
33599a2dd95SBruce Richardson 	/* Call init() of the all the nodes in the graph */
33699a2dd95SBruce Richardson 	if (graph_node_init(graph))
33799a2dd95SBruce Richardson 		goto graph_mem_destroy;
33899a2dd95SBruce Richardson 
33999a2dd95SBruce Richardson 	/* All good, Lets add the graph to the list */
34099a2dd95SBruce Richardson 	graph_id++;
34199a2dd95SBruce Richardson 	STAILQ_INSERT_TAIL(&graph_list, graph, next);
34299a2dd95SBruce Richardson 
34399a2dd95SBruce Richardson 	graph_spinlock_unlock();
34499a2dd95SBruce Richardson 	return graph->id;
34599a2dd95SBruce Richardson 
34699a2dd95SBruce Richardson graph_mem_destroy:
34799a2dd95SBruce Richardson 	graph_fp_mem_destroy(graph);
34899a2dd95SBruce Richardson graph_cleanup:
34999a2dd95SBruce Richardson 	graph_cleanup(graph);
35099a2dd95SBruce Richardson free:
35199a2dd95SBruce Richardson 	free(graph);
35299a2dd95SBruce Richardson fail:
35399a2dd95SBruce Richardson 	graph_spinlock_unlock();
35499a2dd95SBruce Richardson 	return RTE_GRAPH_ID_INVALID;
35599a2dd95SBruce Richardson }
35699a2dd95SBruce Richardson 
35799a2dd95SBruce Richardson int
rte_graph_destroy(rte_graph_t id)35899a2dd95SBruce Richardson rte_graph_destroy(rte_graph_t id)
35999a2dd95SBruce Richardson {
36099a2dd95SBruce Richardson 	struct graph *graph, *tmp;
36199a2dd95SBruce Richardson 	int rc = -ENOENT;
36299a2dd95SBruce Richardson 
36399a2dd95SBruce Richardson 	graph_spinlock_lock();
36499a2dd95SBruce Richardson 
36599a2dd95SBruce Richardson 	graph = STAILQ_FIRST(&graph_list);
36699a2dd95SBruce Richardson 	while (graph != NULL) {
36799a2dd95SBruce Richardson 		tmp = STAILQ_NEXT(graph, next);
36899a2dd95SBruce Richardson 		if (graph->id == id) {
36999a2dd95SBruce Richardson 			/* Call fini() of the all the nodes in the graph */
37099a2dd95SBruce Richardson 			graph_node_fini(graph);
37199a2dd95SBruce Richardson 			/* Destroy graph fast path memory */
37299a2dd95SBruce Richardson 			rc = graph_fp_mem_destroy(graph);
37399a2dd95SBruce Richardson 			if (rc)
37499a2dd95SBruce Richardson 				SET_ERR_JMP(rc, done, "Graph %s destroy failed",
37599a2dd95SBruce Richardson 					    graph->name);
37699a2dd95SBruce Richardson 
37799a2dd95SBruce Richardson 			graph_cleanup(graph);
37899a2dd95SBruce Richardson 			STAILQ_REMOVE(&graph_list, graph, graph, next);
37999a2dd95SBruce Richardson 			free(graph);
38099a2dd95SBruce Richardson 			graph_id--;
38199a2dd95SBruce Richardson 			goto done;
38299a2dd95SBruce Richardson 		}
38399a2dd95SBruce Richardson 		graph = tmp;
38499a2dd95SBruce Richardson 	}
38599a2dd95SBruce Richardson done:
38699a2dd95SBruce Richardson 	graph_spinlock_unlock();
38799a2dd95SBruce Richardson 	return rc;
38899a2dd95SBruce Richardson }
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson rte_graph_t
rte_graph_from_name(const char * name)39199a2dd95SBruce Richardson rte_graph_from_name(const char *name)
39299a2dd95SBruce Richardson {
39399a2dd95SBruce Richardson 	struct graph *graph;
39499a2dd95SBruce Richardson 
39599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
39699a2dd95SBruce Richardson 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
39799a2dd95SBruce Richardson 			return graph->id;
39899a2dd95SBruce Richardson 
39999a2dd95SBruce Richardson 	return RTE_GRAPH_ID_INVALID;
40099a2dd95SBruce Richardson }
40199a2dd95SBruce Richardson 
40299a2dd95SBruce Richardson char *
rte_graph_id_to_name(rte_graph_t id)40399a2dd95SBruce Richardson rte_graph_id_to_name(rte_graph_t id)
40499a2dd95SBruce Richardson {
40599a2dd95SBruce Richardson 	struct graph *graph;
40699a2dd95SBruce Richardson 
40799a2dd95SBruce Richardson 	GRAPH_ID_CHECK(id);
40899a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
40999a2dd95SBruce Richardson 		if (graph->id == id)
41099a2dd95SBruce Richardson 			return graph->name;
41199a2dd95SBruce Richardson 
41299a2dd95SBruce Richardson fail:
41399a2dd95SBruce Richardson 	return NULL;
41499a2dd95SBruce Richardson }
41599a2dd95SBruce Richardson 
41699a2dd95SBruce Richardson struct rte_node *
rte_graph_node_get(rte_graph_t gid,uint32_t nid)41799a2dd95SBruce Richardson rte_graph_node_get(rte_graph_t gid, uint32_t nid)
41899a2dd95SBruce Richardson {
41999a2dd95SBruce Richardson 	struct rte_node *node;
42099a2dd95SBruce Richardson 	struct graph *graph;
42199a2dd95SBruce Richardson 	rte_graph_off_t off;
42299a2dd95SBruce Richardson 	rte_node_t count;
42399a2dd95SBruce Richardson 
42499a2dd95SBruce Richardson 	GRAPH_ID_CHECK(gid);
42599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
42699a2dd95SBruce Richardson 		if (graph->id == gid) {
42799a2dd95SBruce Richardson 			rte_graph_foreach_node(count, off, graph->graph,
42899a2dd95SBruce Richardson 						node) {
42999a2dd95SBruce Richardson 				if (node->id == nid)
43099a2dd95SBruce Richardson 					return node;
43199a2dd95SBruce Richardson 			}
43299a2dd95SBruce Richardson 			break;
43399a2dd95SBruce Richardson 		}
43499a2dd95SBruce Richardson fail:
43599a2dd95SBruce Richardson 	return NULL;
43699a2dd95SBruce Richardson }
43799a2dd95SBruce Richardson 
43899a2dd95SBruce Richardson struct rte_node *
rte_graph_node_get_by_name(const char * graph_name,const char * node_name)43999a2dd95SBruce Richardson rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
44099a2dd95SBruce Richardson {
44199a2dd95SBruce Richardson 	struct rte_node *node;
44299a2dd95SBruce Richardson 	struct graph *graph;
44399a2dd95SBruce Richardson 	rte_graph_off_t off;
44499a2dd95SBruce Richardson 	rte_node_t count;
44599a2dd95SBruce Richardson 
44699a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
44799a2dd95SBruce Richardson 		if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
44899a2dd95SBruce Richardson 			rte_graph_foreach_node(count, off, graph->graph,
44999a2dd95SBruce Richardson 						node) {
45099a2dd95SBruce Richardson 				if (!strncmp(node->name, node_name,
45199a2dd95SBruce Richardson 					     RTE_NODE_NAMESIZE))
45299a2dd95SBruce Richardson 					return node;
45399a2dd95SBruce Richardson 			}
45499a2dd95SBruce Richardson 			break;
45599a2dd95SBruce Richardson 		}
45699a2dd95SBruce Richardson 
45799a2dd95SBruce Richardson 	return NULL;
45899a2dd95SBruce Richardson }
45999a2dd95SBruce Richardson 
46099a2dd95SBruce Richardson void __rte_noinline
__rte_node_stream_alloc(struct rte_graph * graph,struct rte_node * node)46199a2dd95SBruce Richardson __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
46299a2dd95SBruce Richardson {
46399a2dd95SBruce Richardson 	uint16_t size = node->size;
46499a2dd95SBruce Richardson 
46599a2dd95SBruce Richardson 	RTE_VERIFY(size != UINT16_MAX);
46699a2dd95SBruce Richardson 	/* Allocate double amount of size to avoid immediate realloc */
46799a2dd95SBruce Richardson 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
46899a2dd95SBruce Richardson 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
46999a2dd95SBruce Richardson 					RTE_CACHE_LINE_SIZE, graph->socket);
47099a2dd95SBruce Richardson 	RTE_VERIFY(node->objs);
47199a2dd95SBruce Richardson 	node->size = size;
47299a2dd95SBruce Richardson 	node->realloc_count++;
47399a2dd95SBruce Richardson }
47499a2dd95SBruce Richardson 
47599a2dd95SBruce Richardson void __rte_noinline
__rte_node_stream_alloc_size(struct rte_graph * graph,struct rte_node * node,uint16_t req_size)47699a2dd95SBruce Richardson __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
47799a2dd95SBruce Richardson 			     uint16_t req_size)
47899a2dd95SBruce Richardson {
47999a2dd95SBruce Richardson 	uint16_t size = node->size;
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson 	RTE_VERIFY(size != UINT16_MAX);
48299a2dd95SBruce Richardson 	/* Allocate double amount of size to avoid immediate realloc */
48399a2dd95SBruce Richardson 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
48499a2dd95SBruce Richardson 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
48599a2dd95SBruce Richardson 					RTE_CACHE_LINE_SIZE, graph->socket);
48699a2dd95SBruce Richardson 	RTE_VERIFY(node->objs);
48799a2dd95SBruce Richardson 	node->size = size;
48899a2dd95SBruce Richardson 	node->realloc_count++;
48999a2dd95SBruce Richardson }
49099a2dd95SBruce Richardson 
49199a2dd95SBruce Richardson static int
graph_to_dot(FILE * f,struct graph * graph)49299a2dd95SBruce Richardson graph_to_dot(FILE *f, struct graph *graph)
49399a2dd95SBruce Richardson {
49499a2dd95SBruce Richardson 	const char *src_edge_color = " [color=blue]\n";
49599a2dd95SBruce Richardson 	const char *edge_color = "\n";
49699a2dd95SBruce Richardson 	struct graph_node *graph_node;
49799a2dd95SBruce Richardson 	char *node_name;
49899a2dd95SBruce Richardson 	rte_edge_t i;
49999a2dd95SBruce Richardson 	int rc;
50099a2dd95SBruce Richardson 
50199a2dd95SBruce Richardson 	rc = fprintf(f, "Digraph %s {\n\trankdir=LR;\n", graph->name);
50299a2dd95SBruce Richardson 	if (rc < 0)
50399a2dd95SBruce Richardson 		goto end;
50499a2dd95SBruce Richardson 
50599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
50699a2dd95SBruce Richardson 		node_name = graph_node->node->name;
50799a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
50899a2dd95SBruce Richardson 			rc = fprintf(f, "\t\"%s\"->\"%s\"%s", node_name,
50999a2dd95SBruce Richardson 				     graph_node->adjacency_list[i]->node->name,
51099a2dd95SBruce Richardson 				     graph_node->node->flags & RTE_NODE_SOURCE_F
51199a2dd95SBruce Richardson 					     ? src_edge_color
51299a2dd95SBruce Richardson 					     : edge_color);
51399a2dd95SBruce Richardson 			if (rc < 0)
51499a2dd95SBruce Richardson 				goto end;
51599a2dd95SBruce Richardson 		}
51699a2dd95SBruce Richardson 	}
51799a2dd95SBruce Richardson 	rc = fprintf(f, "}\n");
51899a2dd95SBruce Richardson 	if (rc < 0)
51999a2dd95SBruce Richardson 		goto end;
52099a2dd95SBruce Richardson 
52199a2dd95SBruce Richardson 	return 0;
52299a2dd95SBruce Richardson end:
52399a2dd95SBruce Richardson 	rte_errno = EBADF;
52499a2dd95SBruce Richardson 	return -rte_errno;
52599a2dd95SBruce Richardson }
52699a2dd95SBruce Richardson 
52799a2dd95SBruce Richardson int
rte_graph_export(const char * name,FILE * f)52899a2dd95SBruce Richardson rte_graph_export(const char *name, FILE *f)
52999a2dd95SBruce Richardson {
53099a2dd95SBruce Richardson 	struct graph *graph;
53199a2dd95SBruce Richardson 	int rc = ENOENT;
53299a2dd95SBruce Richardson 
53399a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next) {
53499a2dd95SBruce Richardson 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
53599a2dd95SBruce Richardson 			rc = graph_to_dot(f, graph);
53699a2dd95SBruce Richardson 			goto end;
53799a2dd95SBruce Richardson 		}
53899a2dd95SBruce Richardson 	}
53999a2dd95SBruce Richardson end:
54099a2dd95SBruce Richardson 	return -rc;
54199a2dd95SBruce Richardson }
54299a2dd95SBruce Richardson 
54399a2dd95SBruce Richardson static void
graph_scan_dump(FILE * f,rte_graph_t id,bool all)54499a2dd95SBruce Richardson graph_scan_dump(FILE *f, rte_graph_t id, bool all)
54599a2dd95SBruce Richardson {
54699a2dd95SBruce Richardson 	struct graph *graph;
54799a2dd95SBruce Richardson 
54899a2dd95SBruce Richardson 	RTE_VERIFY(f);
54999a2dd95SBruce Richardson 	GRAPH_ID_CHECK(id);
55099a2dd95SBruce Richardson 
55199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next) {
55299a2dd95SBruce Richardson 		if (all == true) {
55399a2dd95SBruce Richardson 			graph_dump(f, graph);
55499a2dd95SBruce Richardson 		} else if (graph->id == id) {
55599a2dd95SBruce Richardson 			graph_dump(f, graph);
55699a2dd95SBruce Richardson 			return;
55799a2dd95SBruce Richardson 		}
55899a2dd95SBruce Richardson 	}
55999a2dd95SBruce Richardson fail:
56099a2dd95SBruce Richardson 	return;
56199a2dd95SBruce Richardson }
56299a2dd95SBruce Richardson 
56399a2dd95SBruce Richardson void
rte_graph_dump(FILE * f,rte_graph_t id)56499a2dd95SBruce Richardson rte_graph_dump(FILE *f, rte_graph_t id)
56599a2dd95SBruce Richardson {
56699a2dd95SBruce Richardson 	graph_scan_dump(f, id, false);
56799a2dd95SBruce Richardson }
56899a2dd95SBruce Richardson 
56999a2dd95SBruce Richardson void
rte_graph_list_dump(FILE * f)57099a2dd95SBruce Richardson rte_graph_list_dump(FILE *f)
57199a2dd95SBruce Richardson {
57299a2dd95SBruce Richardson 	graph_scan_dump(f, 0, true);
57399a2dd95SBruce Richardson }
57499a2dd95SBruce Richardson 
57599a2dd95SBruce Richardson rte_graph_t
rte_graph_max_count(void)57699a2dd95SBruce Richardson rte_graph_max_count(void)
57799a2dd95SBruce Richardson {
57899a2dd95SBruce Richardson 	return graph_id;
57999a2dd95SBruce Richardson }
58099a2dd95SBruce Richardson 
581*eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(rte_graph_logtype, INFO);
582