xref: /f-stack/dpdk/lib/librte_graph/graph_ops.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 <stdbool.h>
6*2d9fd380Sjfb8856606 #include <string.h>
7*2d9fd380Sjfb8856606 
8*2d9fd380Sjfb8856606 #include <rte_common.h>
9*2d9fd380Sjfb8856606 #include <rte_errno.h>
10*2d9fd380Sjfb8856606 
11*2d9fd380Sjfb8856606 #include "graph_private.h"
12*2d9fd380Sjfb8856606 
13*2d9fd380Sjfb8856606 /* Check whether a node has next_node to itself */
14*2d9fd380Sjfb8856606 static inline int
node_has_loop_edge(struct node * node)15*2d9fd380Sjfb8856606 node_has_loop_edge(struct node *node)
16*2d9fd380Sjfb8856606 {
17*2d9fd380Sjfb8856606 	rte_edge_t i;
18*2d9fd380Sjfb8856606 	char *name;
19*2d9fd380Sjfb8856606 	int rc = 0;
20*2d9fd380Sjfb8856606 
21*2d9fd380Sjfb8856606 	for (i = 0; i < node->nb_edges; i++) {
22*2d9fd380Sjfb8856606 		if (strncmp(node->name, node->next_nodes[i],
23*2d9fd380Sjfb8856606 			    RTE_NODE_NAMESIZE) == 0) {
24*2d9fd380Sjfb8856606 			name = node->name;
25*2d9fd380Sjfb8856606 			rc = 1;
26*2d9fd380Sjfb8856606 			SET_ERR_JMP(EINVAL, fail, "Node %s has loop to self",
27*2d9fd380Sjfb8856606 				    name);
28*2d9fd380Sjfb8856606 		}
29*2d9fd380Sjfb8856606 	}
30*2d9fd380Sjfb8856606 fail:
31*2d9fd380Sjfb8856606 	return rc;
32*2d9fd380Sjfb8856606 }
33*2d9fd380Sjfb8856606 
34*2d9fd380Sjfb8856606 int
graph_node_has_loop_edge(struct graph * graph)35*2d9fd380Sjfb8856606 graph_node_has_loop_edge(struct graph *graph)
36*2d9fd380Sjfb8856606 {
37*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
38*2d9fd380Sjfb8856606 
39*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
40*2d9fd380Sjfb8856606 		if (node_has_loop_edge(graph_node->node))
41*2d9fd380Sjfb8856606 			return 1;
42*2d9fd380Sjfb8856606 
43*2d9fd380Sjfb8856606 	return 0;
44*2d9fd380Sjfb8856606 }
45*2d9fd380Sjfb8856606 
46*2d9fd380Sjfb8856606 rte_node_t
graph_src_nodes_count(struct graph * graph)47*2d9fd380Sjfb8856606 graph_src_nodes_count(struct graph *graph)
48*2d9fd380Sjfb8856606 {
49*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
50*2d9fd380Sjfb8856606 	rte_node_t rc = 0;
51*2d9fd380Sjfb8856606 
52*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
53*2d9fd380Sjfb8856606 		if (graph_node->node->flags & RTE_NODE_SOURCE_F)
54*2d9fd380Sjfb8856606 			rc++;
55*2d9fd380Sjfb8856606 
56*2d9fd380Sjfb8856606 	if (rc == 0)
57*2d9fd380Sjfb8856606 		SET_ERR_JMP(EINVAL, fail, "Graph needs at least a source node");
58*2d9fd380Sjfb8856606 fail:
59*2d9fd380Sjfb8856606 	return rc;
60*2d9fd380Sjfb8856606 }
61*2d9fd380Sjfb8856606 
62*2d9fd380Sjfb8856606 /* Check whether a node has next_node to a source node */
63*2d9fd380Sjfb8856606 int
graph_node_has_edge_to_src_node(struct graph * graph)64*2d9fd380Sjfb8856606 graph_node_has_edge_to_src_node(struct graph *graph)
65*2d9fd380Sjfb8856606 {
66*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
67*2d9fd380Sjfb8856606 	struct node *node;
68*2d9fd380Sjfb8856606 	rte_edge_t i;
69*2d9fd380Sjfb8856606 
70*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
71*2d9fd380Sjfb8856606 		for (i = 0; i < graph_node->node->nb_edges; i++) {
72*2d9fd380Sjfb8856606 			node = graph_node->adjacency_list[i]->node;
73*2d9fd380Sjfb8856606 			if (node->flags & RTE_NODE_SOURCE_F)
74*2d9fd380Sjfb8856606 				SET_ERR_JMP(
75*2d9fd380Sjfb8856606 					EEXIST, fail,
76*2d9fd380Sjfb8856606 					"Node %s points to the source node %s",
77*2d9fd380Sjfb8856606 					graph_node->node->name, node->name);
78*2d9fd380Sjfb8856606 		}
79*2d9fd380Sjfb8856606 	}
80*2d9fd380Sjfb8856606 
81*2d9fd380Sjfb8856606 	return 0;
82*2d9fd380Sjfb8856606 fail:
83*2d9fd380Sjfb8856606 	return 1;
84*2d9fd380Sjfb8856606 }
85*2d9fd380Sjfb8856606 
86*2d9fd380Sjfb8856606 rte_node_t
graph_nodes_count(struct graph * graph)87*2d9fd380Sjfb8856606 graph_nodes_count(struct graph *graph)
88*2d9fd380Sjfb8856606 {
89*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
90*2d9fd380Sjfb8856606 	rte_node_t count = 0;
91*2d9fd380Sjfb8856606 
92*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
93*2d9fd380Sjfb8856606 		count++;
94*2d9fd380Sjfb8856606 
95*2d9fd380Sjfb8856606 	return count;
96*2d9fd380Sjfb8856606 }
97*2d9fd380Sjfb8856606 
98*2d9fd380Sjfb8856606 void
graph_mark_nodes_as_not_visited(struct graph * graph)99*2d9fd380Sjfb8856606 graph_mark_nodes_as_not_visited(struct graph *graph)
100*2d9fd380Sjfb8856606 {
101*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
102*2d9fd380Sjfb8856606 
103*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
104*2d9fd380Sjfb8856606 		graph_node->visited = false;
105*2d9fd380Sjfb8856606 }
106*2d9fd380Sjfb8856606 
107*2d9fd380Sjfb8856606 int
graph_bfs(struct graph * graph,struct graph_node * start)108*2d9fd380Sjfb8856606 graph_bfs(struct graph *graph, struct graph_node *start)
109*2d9fd380Sjfb8856606 {
110*2d9fd380Sjfb8856606 	struct graph_node **queue, *v, *tmp;
111*2d9fd380Sjfb8856606 	uint16_t head = 0, tail = 0;
112*2d9fd380Sjfb8856606 	rte_edge_t i;
113*2d9fd380Sjfb8856606 	size_t sz;
114*2d9fd380Sjfb8856606 
115*2d9fd380Sjfb8856606 	sz = sizeof(struct graph_node *) * graph_nodes_count(graph);
116*2d9fd380Sjfb8856606 	queue = malloc(sz);
117*2d9fd380Sjfb8856606 	if (queue == NULL)
118*2d9fd380Sjfb8856606 		SET_ERR_JMP(ENOMEM, fail, "Failed to alloc BFS queue of %zu",
119*2d9fd380Sjfb8856606 			    sz);
120*2d9fd380Sjfb8856606 
121*2d9fd380Sjfb8856606 	/* BFS algorithm */
122*2d9fd380Sjfb8856606 	queue[tail++] = start;
123*2d9fd380Sjfb8856606 	start->visited = true;
124*2d9fd380Sjfb8856606 	while (head != tail) {
125*2d9fd380Sjfb8856606 		v = queue[head++];
126*2d9fd380Sjfb8856606 		for (i = 0; i < v->node->nb_edges; i++) {
127*2d9fd380Sjfb8856606 			tmp = v->adjacency_list[i];
128*2d9fd380Sjfb8856606 			if (tmp->visited == false) {
129*2d9fd380Sjfb8856606 				queue[tail++] = tmp;
130*2d9fd380Sjfb8856606 				tmp->visited = true;
131*2d9fd380Sjfb8856606 			}
132*2d9fd380Sjfb8856606 		}
133*2d9fd380Sjfb8856606 	}
134*2d9fd380Sjfb8856606 
135*2d9fd380Sjfb8856606 	free(queue);
136*2d9fd380Sjfb8856606 	return 0;
137*2d9fd380Sjfb8856606 
138*2d9fd380Sjfb8856606 fail:
139*2d9fd380Sjfb8856606 	return -rte_errno;
140*2d9fd380Sjfb8856606 }
141*2d9fd380Sjfb8856606 
142*2d9fd380Sjfb8856606 /* Check whether a node has connected path or parent node */
143*2d9fd380Sjfb8856606 int
graph_has_isolated_node(struct graph * graph)144*2d9fd380Sjfb8856606 graph_has_isolated_node(struct graph *graph)
145*2d9fd380Sjfb8856606 {
146*2d9fd380Sjfb8856606 	struct graph_node *graph_node;
147*2d9fd380Sjfb8856606 
148*2d9fd380Sjfb8856606 	graph_mark_nodes_as_not_visited(graph);
149*2d9fd380Sjfb8856606 
150*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
151*2d9fd380Sjfb8856606 		if (graph_node->node->flags & RTE_NODE_SOURCE_F) {
152*2d9fd380Sjfb8856606 			if (graph_node->node->nb_edges == 0)
153*2d9fd380Sjfb8856606 				SET_ERR_JMP(EINVAL, fail,
154*2d9fd380Sjfb8856606 					    "%s node needs minimum one edge",
155*2d9fd380Sjfb8856606 					    graph_node->node->name);
156*2d9fd380Sjfb8856606 			if (graph_bfs(graph, graph_node))
157*2d9fd380Sjfb8856606 				goto fail;
158*2d9fd380Sjfb8856606 		}
159*2d9fd380Sjfb8856606 	}
160*2d9fd380Sjfb8856606 
161*2d9fd380Sjfb8856606 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
162*2d9fd380Sjfb8856606 		if (graph_node->visited == false)
163*2d9fd380Sjfb8856606 			SET_ERR_JMP(EINVAL, fail, "Found isolated node %s",
164*2d9fd380Sjfb8856606 				    graph_node->node->name);
165*2d9fd380Sjfb8856606 
166*2d9fd380Sjfb8856606 	return 0;
167*2d9fd380Sjfb8856606 fail:
168*2d9fd380Sjfb8856606 	return 1;
169*2d9fd380Sjfb8856606 }
170