xref: /f-stack/dpdk/lib/librte_graph/graph.c (revision 2d9fd380)
1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606  * Copyright(C) 2020 Marvell International Ltd.
3*2d9fd380Sjfb8856606  */
4*2d9fd380Sjfb8856606 
5*2d9fd380Sjfb8856606 #include <fnmatch.h>
6*2d9fd380Sjfb8856606 #include <stdbool.h>
7*2d9fd380Sjfb8856606 
8*2d9fd380Sjfb8856606 #include <rte_common.h>
9*2d9fd380Sjfb8856606 #include <rte_debug.h>
10*2d9fd380Sjfb8856606 #include <rte_errno.h>
11*2d9fd380Sjfb8856606 #include <rte_malloc.h>
12*2d9fd380Sjfb8856606 #include <rte_memzone.h>
13*2d9fd380Sjfb8856606 #include <rte_spinlock.h>
14*2d9fd380Sjfb8856606 #include <rte_string_fns.h>
15*2d9fd380Sjfb8856606 
16*2d9fd380Sjfb8856606 #include "graph_private.h"
17*2d9fd380Sjfb8856606 
18*2d9fd380Sjfb8856606 static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list);
19*2d9fd380Sjfb8856606 static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER;
20*2d9fd380Sjfb8856606 static rte_graph_t graph_id;
21*2d9fd380Sjfb8856606 
22*2d9fd380Sjfb8856606 #define GRAPH_ID_CHECK(id) ID_CHECK(id, graph_id)
23*2d9fd380Sjfb8856606 
24*2d9fd380Sjfb8856606 /* Private functions */
25*2d9fd380Sjfb8856606 struct graph_head *
graph_list_head_get(void)26*2d9fd380Sjfb8856606 graph_list_head_get(void)
27*2d9fd380Sjfb8856606 {
28*2d9fd380Sjfb8856606 	return &graph_list;
29*2d9fd380Sjfb8856606 }
30*2d9fd380Sjfb8856606 
31*2d9fd380Sjfb8856606 void
graph_spinlock_lock(void)32*2d9fd380Sjfb8856606 graph_spinlock_lock(void)
33*2d9fd380Sjfb8856606 {
34*2d9fd380Sjfb8856606 	rte_spinlock_lock(&graph_lock);
35*2d9fd380Sjfb8856606 }
36*2d9fd380Sjfb8856606 
37*2d9fd380Sjfb8856606 void
graph_spinlock_unlock(void)38*2d9fd380Sjfb8856606 graph_spinlock_unlock(void)
39*2d9fd380Sjfb8856606 {
40*2d9fd380Sjfb8856606 	rte_spinlock_unlock(&graph_lock);
41*2d9fd380Sjfb8856606 }
42*2d9fd380Sjfb8856606 
43*2d9fd380Sjfb8856606 static int
graph_node_add(struct graph * graph,struct node * node)44*2d9fd380Sjfb8856606 graph_node_add(struct graph *graph, struct node *node)
45*2d9fd380Sjfb8856606 {
46*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
47*2d9fd380Sjfb8856606 	size_t sz;
48*2d9fd380Sjfb8856606 
49*2d9fd380Sjfb8856606 	/* Skip the duplicate nodes */
50*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
51*2d9fd380Sjfb8856606 		if (strncmp(node->name, graph_node->node->name,
52*2d9fd380Sjfb8856606 			    RTE_NODE_NAMESIZE) == 0)
53*2d9fd380Sjfb8856606 			return 0;
54*2d9fd380Sjfb8856606 
55*2d9fd380Sjfb8856606 	/* Allocate new graph node object */
56*2d9fd380Sjfb8856606 	sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *);
57*2d9fd380Sjfb8856606 	graph_node = calloc(1, sz);
58*2d9fd380Sjfb8856606 
59*2d9fd380Sjfb8856606 	if (graph_node == NULL)
60*2d9fd380Sjfb8856606 		SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object",
61*2d9fd380Sjfb8856606 			    node->name);
62*2d9fd380Sjfb8856606 
63*2d9fd380Sjfb8856606 	/* Initialize the graph node */
64*2d9fd380Sjfb8856606 	graph_node->node = node;
65*2d9fd380Sjfb8856606 
66*2d9fd380Sjfb8856606 	/* Add to graph node list */
67*2d9fd380Sjfb8856606 	STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next);
68*2d9fd380Sjfb8856606 	return 0;
69*2d9fd380Sjfb8856606 
70*2d9fd380Sjfb8856606 free:
71*2d9fd380Sjfb8856606 	free(graph_node);
72*2d9fd380Sjfb8856606 	return -rte_errno;
73*2d9fd380Sjfb8856606 }
74*2d9fd380Sjfb8856606 
75*2d9fd380Sjfb8856606 static struct graph_node *
node_to_graph_node(struct graph * graph,struct node * node)76*2d9fd380Sjfb8856606 node_to_graph_node(struct graph *graph, struct node *node)
77*2d9fd380Sjfb8856606 {
78*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
79*2d9fd380Sjfb8856606 
80*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
81*2d9fd380Sjfb8856606 		if (graph_node->node == node)
82*2d9fd380Sjfb8856606 			return graph_node;
83*2d9fd380Sjfb8856606 
84*2d9fd380Sjfb8856606 	SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name);
85*2d9fd380Sjfb8856606 fail:
86*2d9fd380Sjfb8856606 	return NULL;
87*2d9fd380Sjfb8856606 }
88*2d9fd380Sjfb8856606 
89*2d9fd380Sjfb8856606 static int
graph_node_edges_add(struct graph * graph)90*2d9fd380Sjfb8856606 graph_node_edges_add(struct graph *graph)
91*2d9fd380Sjfb8856606 {
92*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
93*2d9fd380Sjfb8856606 	struct node *adjacency;
94*2d9fd380Sjfb8856606 	const char *next;
95*2d9fd380Sjfb8856606 	rte_edge_t i;
96*2d9fd380Sjfb8856606 
97*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
98*2d9fd380Sjfb8856606 		for (i = 0; i < graph_node->node->nb_edges; i++) {
99*2d9fd380Sjfb8856606 			next = graph_node->node->next_nodes[i];
100*2d9fd380Sjfb8856606 			adjacency = node_from_name(next);
101*2d9fd380Sjfb8856606 			if (adjacency == NULL)
102*2d9fd380Sjfb8856606 				SET_ERR_JMP(EINVAL, fail,
103*2d9fd380Sjfb8856606 					    "Node %s not registered", next);
104*2d9fd380Sjfb8856606 			if (graph_node_add(graph, adjacency))
105*2d9fd380Sjfb8856606 				goto fail;
106*2d9fd380Sjfb8856606 		}
107*2d9fd380Sjfb8856606 	}
108*2d9fd380Sjfb8856606 	return 0;
109*2d9fd380Sjfb8856606 fail:
110*2d9fd380Sjfb8856606 	return -rte_errno;
111*2d9fd380Sjfb8856606 }
112*2d9fd380Sjfb8856606 
113*2d9fd380Sjfb8856606 static int
graph_adjacency_list_update(struct graph * graph)114*2d9fd380Sjfb8856606 graph_adjacency_list_update(struct graph *graph)
115*2d9fd380Sjfb8856606 {
116*2d9fd380Sjfb8856606 	struct graph_node *graph_node, *tmp;
117*2d9fd380Sjfb8856606 	struct node *adjacency;
118*2d9fd380Sjfb8856606 	const char *next;
119*2d9fd380Sjfb8856606 	rte_edge_t i;
120*2d9fd380Sjfb8856606 
121*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
122*2d9fd380Sjfb8856606 		for (i = 0; i < graph_node->node->nb_edges; i++) {
123*2d9fd380Sjfb8856606 			next = graph_node->node->next_nodes[i];
124*2d9fd380Sjfb8856606 			adjacency = node_from_name(next);
125*2d9fd380Sjfb8856606 			if (adjacency == NULL)
126*2d9fd380Sjfb8856606 				SET_ERR_JMP(EINVAL, fail,
127*2d9fd380Sjfb8856606 					    "Node %s not registered", next);
128*2d9fd380Sjfb8856606 			tmp = node_to_graph_node(graph, adjacency);
129*2d9fd380Sjfb8856606 			if (tmp == NULL)
130*2d9fd380Sjfb8856606 				goto fail;
131*2d9fd380Sjfb8856606 			graph_node->adjacency_list[i] = tmp;
132*2d9fd380Sjfb8856606 		}
133*2d9fd380Sjfb8856606 	}
134*2d9fd380Sjfb8856606 
135*2d9fd380Sjfb8856606 	return 0;
136*2d9fd380Sjfb8856606 fail:
137*2d9fd380Sjfb8856606 	return -rte_errno;
138*2d9fd380Sjfb8856606 }
139*2d9fd380Sjfb8856606 
140*2d9fd380Sjfb8856606 static int
expand_pattern_to_node(struct graph * graph,const char * pattern)141*2d9fd380Sjfb8856606 expand_pattern_to_node(struct graph *graph, const char *pattern)
142*2d9fd380Sjfb8856606 {
143*2d9fd380Sjfb8856606 	struct node_head *node_head = node_list_head_get();
144*2d9fd380Sjfb8856606 	bool found = false;
145*2d9fd380Sjfb8856606 	struct node *node;
146*2d9fd380Sjfb8856606 
147*2d9fd380Sjfb8856606 	/* Check for pattern match */
148*2d9fd380Sjfb8856606 	STAILQ_FOREACH(node, node_head, next) {
149*2d9fd380Sjfb8856606 		if (fnmatch(pattern, node->name, 0) == 0) {
150*2d9fd380Sjfb8856606 			if (graph_node_add(graph, node))
151*2d9fd380Sjfb8856606 				goto fail;
152*2d9fd380Sjfb8856606 			found = true;
153*2d9fd380Sjfb8856606 		}
154*2d9fd380Sjfb8856606 	}
155*2d9fd380Sjfb8856606 	if (found == false)
156*2d9fd380Sjfb8856606 		SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern);
157*2d9fd380Sjfb8856606 
158*2d9fd380Sjfb8856606 	return 0;
159*2d9fd380Sjfb8856606 fail:
160*2d9fd380Sjfb8856606 	return -rte_errno;
161*2d9fd380Sjfb8856606 }
162*2d9fd380Sjfb8856606 
163*2d9fd380Sjfb8856606 static void
graph_cleanup(struct graph * graph)164*2d9fd380Sjfb8856606 graph_cleanup(struct graph *graph)
165*2d9fd380Sjfb8856606 {
166*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
167*2d9fd380Sjfb8856606 
168*2d9fd380Sjfb8856606 	while (!STAILQ_EMPTY(&graph->node_list)) {
169*2d9fd380Sjfb8856606 		graph_node = STAILQ_FIRST(&graph->node_list);
170*2d9fd380Sjfb8856606 		STAILQ_REMOVE_HEAD(&graph->node_list, next);
171*2d9fd380Sjfb8856606 		free(graph_node);
172*2d9fd380Sjfb8856606 	}
173*2d9fd380Sjfb8856606 }
174*2d9fd380Sjfb8856606 
175*2d9fd380Sjfb8856606 static int
graph_node_init(struct graph * graph)176*2d9fd380Sjfb8856606 graph_node_init(struct graph *graph)
177*2d9fd380Sjfb8856606 {
178*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
179*2d9fd380Sjfb8856606 	const char *name;
180*2d9fd380Sjfb8856606 	int rc;
181*2d9fd380Sjfb8856606 
182*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
183*2d9fd380Sjfb8856606 		if (graph_node->node->init) {
184*2d9fd380Sjfb8856606 			name = graph_node->node->name;
185*2d9fd380Sjfb8856606 			rc = graph_node->node->init(
186*2d9fd380Sjfb8856606 				graph->graph,
187*2d9fd380Sjfb8856606 				graph_node_name_to_ptr(graph->graph, name));
188*2d9fd380Sjfb8856606 			if (rc)
189*2d9fd380Sjfb8856606 				SET_ERR_JMP(rc, err, "Node %s init() failed",
190*2d9fd380Sjfb8856606 					    name);
191*2d9fd380Sjfb8856606 		}
192*2d9fd380Sjfb8856606 	}
193*2d9fd380Sjfb8856606 
194*2d9fd380Sjfb8856606 	return 0;
195*2d9fd380Sjfb8856606 err:
196*2d9fd380Sjfb8856606 	return -rte_errno;
197*2d9fd380Sjfb8856606 }
198*2d9fd380Sjfb8856606 
199*2d9fd380Sjfb8856606 static void
graph_node_fini(struct graph * graph)200*2d9fd380Sjfb8856606 graph_node_fini(struct graph *graph)
201*2d9fd380Sjfb8856606 {
202*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
203*2d9fd380Sjfb8856606 
204*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
205*2d9fd380Sjfb8856606 		if (graph_node->node->fini)
206*2d9fd380Sjfb8856606 			graph_node->node->fini(
207*2d9fd380Sjfb8856606 				graph->graph,
208*2d9fd380Sjfb8856606 				graph_node_name_to_ptr(graph->graph,
209*2d9fd380Sjfb8856606 						       graph_node->node->name));
210*2d9fd380Sjfb8856606 }
211*2d9fd380Sjfb8856606 
212*2d9fd380Sjfb8856606 static struct rte_graph *
graph_mem_fixup_node_ctx(struct rte_graph * graph)213*2d9fd380Sjfb8856606 graph_mem_fixup_node_ctx(struct rte_graph *graph)
214*2d9fd380Sjfb8856606 {
215*2d9fd380Sjfb8856606 	struct rte_node *node;
216*2d9fd380Sjfb8856606 	struct node *node_db;
217*2d9fd380Sjfb8856606 	rte_graph_off_t off;
218*2d9fd380Sjfb8856606 	rte_node_t count;
219*2d9fd380Sjfb8856606 	const char *name;
220*2d9fd380Sjfb8856606 
221*2d9fd380Sjfb8856606 	rte_graph_foreach_node(count, off, graph, node) {
222*2d9fd380Sjfb8856606 		if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
223*2d9fd380Sjfb8856606 			name = node->name;
224*2d9fd380Sjfb8856606 		else /* Cloned node */
225*2d9fd380Sjfb8856606 			name = node->parent;
226*2d9fd380Sjfb8856606 
227*2d9fd380Sjfb8856606 		node_db = node_from_name(name);
228*2d9fd380Sjfb8856606 		if (node_db == NULL)
229*2d9fd380Sjfb8856606 			SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
230*2d9fd380Sjfb8856606 		node->process = node_db->process;
231*2d9fd380Sjfb8856606 	}
232*2d9fd380Sjfb8856606 
233*2d9fd380Sjfb8856606 	return graph;
234*2d9fd380Sjfb8856606 fail:
235*2d9fd380Sjfb8856606 	return NULL;
236*2d9fd380Sjfb8856606 }
237*2d9fd380Sjfb8856606 
238*2d9fd380Sjfb8856606 static struct rte_graph *
graph_mem_fixup_secondary(struct rte_graph * graph)239*2d9fd380Sjfb8856606 graph_mem_fixup_secondary(struct rte_graph *graph)
240*2d9fd380Sjfb8856606 {
241*2d9fd380Sjfb8856606 	if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
242*2d9fd380Sjfb8856606 		return graph;
243*2d9fd380Sjfb8856606 
244*2d9fd380Sjfb8856606 	return graph_mem_fixup_node_ctx(graph);
245*2d9fd380Sjfb8856606 }
246*2d9fd380Sjfb8856606 
247*2d9fd380Sjfb8856606 struct rte_graph *
rte_graph_lookup(const char * name)248*2d9fd380Sjfb8856606 rte_graph_lookup(const char *name)
249*2d9fd380Sjfb8856606 {
250*2d9fd380Sjfb8856606 	const struct rte_memzone *mz;
251*2d9fd380Sjfb8856606 	struct rte_graph *rc = NULL;
252*2d9fd380Sjfb8856606 
253*2d9fd380Sjfb8856606 	mz = rte_memzone_lookup(name);
254*2d9fd380Sjfb8856606 	if (mz)
255*2d9fd380Sjfb8856606 		rc = mz->addr;
256*2d9fd380Sjfb8856606 
257*2d9fd380Sjfb8856606 	return graph_mem_fixup_secondary(rc);
258*2d9fd380Sjfb8856606 }
259*2d9fd380Sjfb8856606 
260*2d9fd380Sjfb8856606 rte_graph_t
rte_graph_create(const char * name,struct rte_graph_param * prm)261*2d9fd380Sjfb8856606 rte_graph_create(const char *name, struct rte_graph_param *prm)
262*2d9fd380Sjfb8856606 {
263*2d9fd380Sjfb8856606 	rte_node_t src_node_count;
264*2d9fd380Sjfb8856606 	struct graph *graph;
265*2d9fd380Sjfb8856606 	const char *pattern;
266*2d9fd380Sjfb8856606 	uint16_t i;
267*2d9fd380Sjfb8856606 
268*2d9fd380Sjfb8856606 	graph_spinlock_lock();
269*2d9fd380Sjfb8856606 
270*2d9fd380Sjfb8856606 	/* Check arguments sanity */
271*2d9fd380Sjfb8856606 	if (prm == NULL)
272*2d9fd380Sjfb8856606 		SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
273*2d9fd380Sjfb8856606 
274*2d9fd380Sjfb8856606 	if (name == NULL)
275*2d9fd380Sjfb8856606 		SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
276*2d9fd380Sjfb8856606 
277*2d9fd380Sjfb8856606 	/* Check for existence of duplicate graph */
278*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next)
279*2d9fd380Sjfb8856606 		if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
280*2d9fd380Sjfb8856606 			SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
281*2d9fd380Sjfb8856606 				    name);
282*2d9fd380Sjfb8856606 
283*2d9fd380Sjfb8856606 	/* Create graph object */
284*2d9fd380Sjfb8856606 	graph = calloc(1, sizeof(*graph));
285*2d9fd380Sjfb8856606 	if (graph == NULL)
286*2d9fd380Sjfb8856606 		SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
287*2d9fd380Sjfb8856606 
288*2d9fd380Sjfb8856606 	/* Initialize the graph object */
289*2d9fd380Sjfb8856606 	STAILQ_INIT(&graph->node_list);
290*2d9fd380Sjfb8856606 	if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
291*2d9fd380Sjfb8856606 		SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
292*2d9fd380Sjfb8856606 
293*2d9fd380Sjfb8856606 	/* Expand node pattern and add the nodes to the graph */
294*2d9fd380Sjfb8856606 	for (i = 0; i < prm->nb_node_patterns; i++) {
295*2d9fd380Sjfb8856606 		pattern = prm->node_patterns[i];
296*2d9fd380Sjfb8856606 		if (expand_pattern_to_node(graph, pattern))
297*2d9fd380Sjfb8856606 			goto graph_cleanup;
298*2d9fd380Sjfb8856606 	}
299*2d9fd380Sjfb8856606 
300*2d9fd380Sjfb8856606 	/* Go over all the nodes edges and add them to the graph */
301*2d9fd380Sjfb8856606 	if (graph_node_edges_add(graph))
302*2d9fd380Sjfb8856606 		goto graph_cleanup;
303*2d9fd380Sjfb8856606 
304*2d9fd380Sjfb8856606 	/* Update adjacency list of all nodes in the graph */
305*2d9fd380Sjfb8856606 	if (graph_adjacency_list_update(graph))
306*2d9fd380Sjfb8856606 		goto graph_cleanup;
307*2d9fd380Sjfb8856606 
308*2d9fd380Sjfb8856606 	/* Make sure at least a source node present in the graph */
309*2d9fd380Sjfb8856606 	src_node_count = graph_src_nodes_count(graph);
310*2d9fd380Sjfb8856606 	if (src_node_count == 0)
311*2d9fd380Sjfb8856606 		goto graph_cleanup;
312*2d9fd380Sjfb8856606 
313*2d9fd380Sjfb8856606 	/* Make sure no node is pointing to source node */
314*2d9fd380Sjfb8856606 	if (graph_node_has_edge_to_src_node(graph))
315*2d9fd380Sjfb8856606 		goto graph_cleanup;
316*2d9fd380Sjfb8856606 
317*2d9fd380Sjfb8856606 	/* Don't allow node has loop to self */
318*2d9fd380Sjfb8856606 	if (graph_node_has_loop_edge(graph))
319*2d9fd380Sjfb8856606 		goto graph_cleanup;
320*2d9fd380Sjfb8856606 
321*2d9fd380Sjfb8856606 	/* Do BFS from src nodes on the graph to find isolated nodes */
322*2d9fd380Sjfb8856606 	if (graph_has_isolated_node(graph))
323*2d9fd380Sjfb8856606 		goto graph_cleanup;
324*2d9fd380Sjfb8856606 
325*2d9fd380Sjfb8856606 	/* Initialize graph object */
326*2d9fd380Sjfb8856606 	graph->socket = prm->socket_id;
327*2d9fd380Sjfb8856606 	graph->src_node_count = src_node_count;
328*2d9fd380Sjfb8856606 	graph->node_count = graph_nodes_count(graph);
329*2d9fd380Sjfb8856606 	graph->id = graph_id;
330*2d9fd380Sjfb8856606 
331*2d9fd380Sjfb8856606 	/* Allocate the Graph fast path memory and populate the data */
332*2d9fd380Sjfb8856606 	if (graph_fp_mem_create(graph))
333*2d9fd380Sjfb8856606 		goto graph_cleanup;
334*2d9fd380Sjfb8856606 
335*2d9fd380Sjfb8856606 	/* Call init() of the all the nodes in the graph */
336*2d9fd380Sjfb8856606 	if (graph_node_init(graph))
337*2d9fd380Sjfb8856606 		goto graph_mem_destroy;
338*2d9fd380Sjfb8856606 
339*2d9fd380Sjfb8856606 	/* All good, Lets add the graph to the list */
340*2d9fd380Sjfb8856606 	graph_id++;
341*2d9fd380Sjfb8856606 	STAILQ_INSERT_TAIL(&graph_list, graph, next);
342*2d9fd380Sjfb8856606 
343*2d9fd380Sjfb8856606 	graph_spinlock_unlock();
344*2d9fd380Sjfb8856606 	return graph->id;
345*2d9fd380Sjfb8856606 
346*2d9fd380Sjfb8856606 graph_mem_destroy:
347*2d9fd380Sjfb8856606 	graph_fp_mem_destroy(graph);
348*2d9fd380Sjfb8856606 graph_cleanup:
349*2d9fd380Sjfb8856606 	graph_cleanup(graph);
350*2d9fd380Sjfb8856606 free:
351*2d9fd380Sjfb8856606 	free(graph);
352*2d9fd380Sjfb8856606 fail:
353*2d9fd380Sjfb8856606 	graph_spinlock_unlock();
354*2d9fd380Sjfb8856606 	return RTE_GRAPH_ID_INVALID;
355*2d9fd380Sjfb8856606 }
356*2d9fd380Sjfb8856606 
357*2d9fd380Sjfb8856606 int
rte_graph_destroy(rte_graph_t id)358*2d9fd380Sjfb8856606 rte_graph_destroy(rte_graph_t id)
359*2d9fd380Sjfb8856606 {
360*2d9fd380Sjfb8856606 	struct graph *graph, *tmp;
361*2d9fd380Sjfb8856606 	int rc = -ENOENT;
362*2d9fd380Sjfb8856606 
363*2d9fd380Sjfb8856606 	graph_spinlock_lock();
364*2d9fd380Sjfb8856606 
365*2d9fd380Sjfb8856606 	graph = STAILQ_FIRST(&graph_list);
366*2d9fd380Sjfb8856606 	while (graph != NULL) {
367*2d9fd380Sjfb8856606 		tmp = STAILQ_NEXT(graph, next);
368*2d9fd380Sjfb8856606 		if (graph->id == id) {
369*2d9fd380Sjfb8856606 			/* Call fini() of the all the nodes in the graph */
370*2d9fd380Sjfb8856606 			graph_node_fini(graph);
371*2d9fd380Sjfb8856606 			/* Destroy graph fast path memory */
372*2d9fd380Sjfb8856606 			rc = graph_fp_mem_destroy(graph);
373*2d9fd380Sjfb8856606 			if (rc)
374*2d9fd380Sjfb8856606 				SET_ERR_JMP(rc, done, "Graph %s destroy failed",
375*2d9fd380Sjfb8856606 					    graph->name);
376*2d9fd380Sjfb8856606 
377*2d9fd380Sjfb8856606 			graph_cleanup(graph);
378*2d9fd380Sjfb8856606 			STAILQ_REMOVE(&graph_list, graph, graph, next);
379*2d9fd380Sjfb8856606 			free(graph);
380*2d9fd380Sjfb8856606 			graph_id--;
381*2d9fd380Sjfb8856606 			goto done;
382*2d9fd380Sjfb8856606 		}
383*2d9fd380Sjfb8856606 		graph = tmp;
384*2d9fd380Sjfb8856606 	}
385*2d9fd380Sjfb8856606 done:
386*2d9fd380Sjfb8856606 	graph_spinlock_unlock();
387*2d9fd380Sjfb8856606 	return rc;
388*2d9fd380Sjfb8856606 }
389*2d9fd380Sjfb8856606 
390*2d9fd380Sjfb8856606 rte_graph_t
rte_graph_from_name(const char * name)391*2d9fd380Sjfb8856606 rte_graph_from_name(const char *name)
392*2d9fd380Sjfb8856606 {
393*2d9fd380Sjfb8856606 	struct graph *graph;
394*2d9fd380Sjfb8856606 
395*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next)
396*2d9fd380Sjfb8856606 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
397*2d9fd380Sjfb8856606 			return graph->id;
398*2d9fd380Sjfb8856606 
399*2d9fd380Sjfb8856606 	return RTE_GRAPH_ID_INVALID;
400*2d9fd380Sjfb8856606 }
401*2d9fd380Sjfb8856606 
402*2d9fd380Sjfb8856606 char *
rte_graph_id_to_name(rte_graph_t id)403*2d9fd380Sjfb8856606 rte_graph_id_to_name(rte_graph_t id)
404*2d9fd380Sjfb8856606 {
405*2d9fd380Sjfb8856606 	struct graph *graph;
406*2d9fd380Sjfb8856606 
407*2d9fd380Sjfb8856606 	GRAPH_ID_CHECK(id);
408*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next)
409*2d9fd380Sjfb8856606 		if (graph->id == id)
410*2d9fd380Sjfb8856606 			return graph->name;
411*2d9fd380Sjfb8856606 
412*2d9fd380Sjfb8856606 fail:
413*2d9fd380Sjfb8856606 	return NULL;
414*2d9fd380Sjfb8856606 }
415*2d9fd380Sjfb8856606 
416*2d9fd380Sjfb8856606 struct rte_node *
rte_graph_node_get(rte_graph_t gid,uint32_t nid)417*2d9fd380Sjfb8856606 rte_graph_node_get(rte_graph_t gid, uint32_t nid)
418*2d9fd380Sjfb8856606 {
419*2d9fd380Sjfb8856606 	struct rte_node *node;
420*2d9fd380Sjfb8856606 	struct graph *graph;
421*2d9fd380Sjfb8856606 	rte_graph_off_t off;
422*2d9fd380Sjfb8856606 	rte_node_t count;
423*2d9fd380Sjfb8856606 
424*2d9fd380Sjfb8856606 	GRAPH_ID_CHECK(gid);
425*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next)
426*2d9fd380Sjfb8856606 		if (graph->id == gid) {
427*2d9fd380Sjfb8856606 			rte_graph_foreach_node(count, off, graph->graph,
428*2d9fd380Sjfb8856606 						node) {
429*2d9fd380Sjfb8856606 				if (node->id == nid)
430*2d9fd380Sjfb8856606 					return node;
431*2d9fd380Sjfb8856606 			}
432*2d9fd380Sjfb8856606 			break;
433*2d9fd380Sjfb8856606 		}
434*2d9fd380Sjfb8856606 fail:
435*2d9fd380Sjfb8856606 	return NULL;
436*2d9fd380Sjfb8856606 }
437*2d9fd380Sjfb8856606 
438*2d9fd380Sjfb8856606 struct rte_node *
rte_graph_node_get_by_name(const char * graph_name,const char * node_name)439*2d9fd380Sjfb8856606 rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
440*2d9fd380Sjfb8856606 {
441*2d9fd380Sjfb8856606 	struct rte_node *node;
442*2d9fd380Sjfb8856606 	struct graph *graph;
443*2d9fd380Sjfb8856606 	rte_graph_off_t off;
444*2d9fd380Sjfb8856606 	rte_node_t count;
445*2d9fd380Sjfb8856606 
446*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next)
447*2d9fd380Sjfb8856606 		if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
448*2d9fd380Sjfb8856606 			rte_graph_foreach_node(count, off, graph->graph,
449*2d9fd380Sjfb8856606 						node) {
450*2d9fd380Sjfb8856606 				if (!strncmp(node->name, node_name,
451*2d9fd380Sjfb8856606 					     RTE_NODE_NAMESIZE))
452*2d9fd380Sjfb8856606 					return node;
453*2d9fd380Sjfb8856606 			}
454*2d9fd380Sjfb8856606 			break;
455*2d9fd380Sjfb8856606 		}
456*2d9fd380Sjfb8856606 
457*2d9fd380Sjfb8856606 	return NULL;
458*2d9fd380Sjfb8856606 }
459*2d9fd380Sjfb8856606 
460*2d9fd380Sjfb8856606 void __rte_noinline
__rte_node_stream_alloc(struct rte_graph * graph,struct rte_node * node)461*2d9fd380Sjfb8856606 __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
462*2d9fd380Sjfb8856606 {
463*2d9fd380Sjfb8856606 	uint16_t size = node->size;
464*2d9fd380Sjfb8856606 
465*2d9fd380Sjfb8856606 	RTE_VERIFY(size != UINT16_MAX);
466*2d9fd380Sjfb8856606 	/* Allocate double amount of size to avoid immediate realloc */
467*2d9fd380Sjfb8856606 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
468*2d9fd380Sjfb8856606 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
469*2d9fd380Sjfb8856606 					RTE_CACHE_LINE_SIZE, graph->socket);
470*2d9fd380Sjfb8856606 	RTE_VERIFY(node->objs);
471*2d9fd380Sjfb8856606 	node->size = size;
472*2d9fd380Sjfb8856606 	node->realloc_count++;
473*2d9fd380Sjfb8856606 }
474*2d9fd380Sjfb8856606 
475*2d9fd380Sjfb8856606 void __rte_noinline
__rte_node_stream_alloc_size(struct rte_graph * graph,struct rte_node * node,uint16_t req_size)476*2d9fd380Sjfb8856606 __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
477*2d9fd380Sjfb8856606 			     uint16_t req_size)
478*2d9fd380Sjfb8856606 {
479*2d9fd380Sjfb8856606 	uint16_t size = node->size;
480*2d9fd380Sjfb8856606 
481*2d9fd380Sjfb8856606 	RTE_VERIFY(size != UINT16_MAX);
482*2d9fd380Sjfb8856606 	/* Allocate double amount of size to avoid immediate realloc */
483*2d9fd380Sjfb8856606 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
484*2d9fd380Sjfb8856606 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
485*2d9fd380Sjfb8856606 					RTE_CACHE_LINE_SIZE, graph->socket);
486*2d9fd380Sjfb8856606 	RTE_VERIFY(node->objs);
487*2d9fd380Sjfb8856606 	node->size = size;
488*2d9fd380Sjfb8856606 	node->realloc_count++;
489*2d9fd380Sjfb8856606 }
490*2d9fd380Sjfb8856606 
491*2d9fd380Sjfb8856606 static int
graph_to_dot(FILE * f,struct graph * graph)492*2d9fd380Sjfb8856606 graph_to_dot(FILE *f, struct graph *graph)
493*2d9fd380Sjfb8856606 {
494*2d9fd380Sjfb8856606 	const char *src_edge_color = " [color=blue]\n";
495*2d9fd380Sjfb8856606 	const char *edge_color = "\n";
496*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
497*2d9fd380Sjfb8856606 	char *node_name;
498*2d9fd380Sjfb8856606 	rte_edge_t i;
499*2d9fd380Sjfb8856606 	int rc;
500*2d9fd380Sjfb8856606 
501*2d9fd380Sjfb8856606 	rc = fprintf(f, "Digraph %s {\n\trankdir=LR;\n", graph->name);
502*2d9fd380Sjfb8856606 	if (rc < 0)
503*2d9fd380Sjfb8856606 		goto end;
504*2d9fd380Sjfb8856606 
505*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
506*2d9fd380Sjfb8856606 		node_name = graph_node->node->name;
507*2d9fd380Sjfb8856606 		for (i = 0; i < graph_node->node->nb_edges; i++) {
508*2d9fd380Sjfb8856606 			rc = fprintf(f, "\t\"%s\"->\"%s\"%s", node_name,
509*2d9fd380Sjfb8856606 				     graph_node->adjacency_list[i]->node->name,
510*2d9fd380Sjfb8856606 				     graph_node->node->flags & RTE_NODE_SOURCE_F
511*2d9fd380Sjfb8856606 					     ? src_edge_color
512*2d9fd380Sjfb8856606 					     : edge_color);
513*2d9fd380Sjfb8856606 			if (rc < 0)
514*2d9fd380Sjfb8856606 				goto end;
515*2d9fd380Sjfb8856606 		}
516*2d9fd380Sjfb8856606 	}
517*2d9fd380Sjfb8856606 	rc = fprintf(f, "}\n");
518*2d9fd380Sjfb8856606 	if (rc < 0)
519*2d9fd380Sjfb8856606 		goto end;
520*2d9fd380Sjfb8856606 
521*2d9fd380Sjfb8856606 	return 0;
522*2d9fd380Sjfb8856606 end:
523*2d9fd380Sjfb8856606 	rte_errno = EBADF;
524*2d9fd380Sjfb8856606 	return -rte_errno;
525*2d9fd380Sjfb8856606 }
526*2d9fd380Sjfb8856606 
527*2d9fd380Sjfb8856606 int
rte_graph_export(const char * name,FILE * f)528*2d9fd380Sjfb8856606 rte_graph_export(const char *name, FILE *f)
529*2d9fd380Sjfb8856606 {
530*2d9fd380Sjfb8856606 	struct graph *graph;
531*2d9fd380Sjfb8856606 	int rc = ENOENT;
532*2d9fd380Sjfb8856606 
533*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next) {
534*2d9fd380Sjfb8856606 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
535*2d9fd380Sjfb8856606 			rc = graph_to_dot(f, graph);
536*2d9fd380Sjfb8856606 			goto end;
537*2d9fd380Sjfb8856606 		}
538*2d9fd380Sjfb8856606 	}
539*2d9fd380Sjfb8856606 end:
540*2d9fd380Sjfb8856606 	return -rc;
541*2d9fd380Sjfb8856606 }
542*2d9fd380Sjfb8856606 
543*2d9fd380Sjfb8856606 static void
graph_scan_dump(FILE * f,rte_graph_t id,bool all)544*2d9fd380Sjfb8856606 graph_scan_dump(FILE *f, rte_graph_t id, bool all)
545*2d9fd380Sjfb8856606 {
546*2d9fd380Sjfb8856606 	struct graph *graph;
547*2d9fd380Sjfb8856606 
548*2d9fd380Sjfb8856606 	RTE_VERIFY(f);
549*2d9fd380Sjfb8856606 	GRAPH_ID_CHECK(id);
550*2d9fd380Sjfb8856606 
551*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph, &graph_list, next) {
552*2d9fd380Sjfb8856606 		if (all == true) {
553*2d9fd380Sjfb8856606 			graph_dump(f, graph);
554*2d9fd380Sjfb8856606 		} else if (graph->id == id) {
555*2d9fd380Sjfb8856606 			graph_dump(f, graph);
556*2d9fd380Sjfb8856606 			return;
557*2d9fd380Sjfb8856606 		}
558*2d9fd380Sjfb8856606 	}
559*2d9fd380Sjfb8856606 fail:
560*2d9fd380Sjfb8856606 	return;
561*2d9fd380Sjfb8856606 }
562*2d9fd380Sjfb8856606 
563*2d9fd380Sjfb8856606 void
rte_graph_dump(FILE * f,rte_graph_t id)564*2d9fd380Sjfb8856606 rte_graph_dump(FILE *f, rte_graph_t id)
565*2d9fd380Sjfb8856606 {
566*2d9fd380Sjfb8856606 	graph_scan_dump(f, id, false);
567*2d9fd380Sjfb8856606 }
568*2d9fd380Sjfb8856606 
569*2d9fd380Sjfb8856606 void
rte_graph_list_dump(FILE * f)570*2d9fd380Sjfb8856606 rte_graph_list_dump(FILE *f)
571*2d9fd380Sjfb8856606 {
572*2d9fd380Sjfb8856606 	graph_scan_dump(f, 0, true);
573*2d9fd380Sjfb8856606 }
574*2d9fd380Sjfb8856606 
575*2d9fd380Sjfb8856606 rte_graph_t
rte_graph_max_count(void)576*2d9fd380Sjfb8856606 rte_graph_max_count(void)
577*2d9fd380Sjfb8856606 {
578*2d9fd380Sjfb8856606 	return graph_id;
579*2d9fd380Sjfb8856606 }
580*2d9fd380Sjfb8856606 
581*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(rte_graph_logtype, lib.graph, INFO);
582