xref: /dpdk/lib/graph/graph_ops.c (revision 72b452c5f2599f970f47fd17d3e8e5d60bfebe7a)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(C) 2020 Marvell International Ltd.
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <stdbool.h>
6*72b452c5SDmitry Kozlyuk #include <stdlib.h>
799a2dd95SBruce Richardson #include <string.h>
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson #include <rte_errno.h>
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #include "graph_private.h"
1299a2dd95SBruce Richardson 
1399a2dd95SBruce Richardson /* Check whether a node has next_node to itself */
1499a2dd95SBruce Richardson static inline int
node_has_loop_edge(struct node * node)1599a2dd95SBruce Richardson node_has_loop_edge(struct node *node)
1699a2dd95SBruce Richardson {
1799a2dd95SBruce Richardson 	rte_edge_t i;
1899a2dd95SBruce Richardson 	char *name;
1999a2dd95SBruce Richardson 	int rc = 0;
2099a2dd95SBruce Richardson 
2199a2dd95SBruce Richardson 	for (i = 0; i < node->nb_edges; i++) {
2299a2dd95SBruce Richardson 		if (strncmp(node->name, node->next_nodes[i],
2399a2dd95SBruce Richardson 			    RTE_NODE_NAMESIZE) == 0) {
2499a2dd95SBruce Richardson 			name = node->name;
2599a2dd95SBruce Richardson 			rc = 1;
2699a2dd95SBruce Richardson 			SET_ERR_JMP(EINVAL, fail, "Node %s has loop to self",
2799a2dd95SBruce Richardson 				    name);
2899a2dd95SBruce Richardson 		}
2999a2dd95SBruce Richardson 	}
3099a2dd95SBruce Richardson fail:
3199a2dd95SBruce Richardson 	return rc;
3299a2dd95SBruce Richardson }
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson int
graph_node_has_loop_edge(struct graph * graph)3599a2dd95SBruce Richardson graph_node_has_loop_edge(struct graph *graph)
3699a2dd95SBruce Richardson {
3799a2dd95SBruce Richardson 	struct graph_node *graph_node;
3899a2dd95SBruce Richardson 
3999a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
4099a2dd95SBruce Richardson 		if (node_has_loop_edge(graph_node->node))
4199a2dd95SBruce Richardson 			return 1;
4299a2dd95SBruce Richardson 
4399a2dd95SBruce Richardson 	return 0;
4499a2dd95SBruce Richardson }
4599a2dd95SBruce Richardson 
4699a2dd95SBruce Richardson rte_node_t
graph_src_nodes_count(struct graph * graph)4799a2dd95SBruce Richardson graph_src_nodes_count(struct graph *graph)
4899a2dd95SBruce Richardson {
4999a2dd95SBruce Richardson 	struct graph_node *graph_node;
5099a2dd95SBruce Richardson 	rte_node_t rc = 0;
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
5399a2dd95SBruce Richardson 		if (graph_node->node->flags & RTE_NODE_SOURCE_F)
5499a2dd95SBruce Richardson 			rc++;
5599a2dd95SBruce Richardson 
5699a2dd95SBruce Richardson 	if (rc == 0)
5799a2dd95SBruce Richardson 		SET_ERR_JMP(EINVAL, fail, "Graph needs at least a source node");
5899a2dd95SBruce Richardson fail:
5999a2dd95SBruce Richardson 	return rc;
6099a2dd95SBruce Richardson }
6199a2dd95SBruce Richardson 
6299a2dd95SBruce Richardson /* Check whether a node has next_node to a source node */
6399a2dd95SBruce Richardson int
graph_node_has_edge_to_src_node(struct graph * graph)6499a2dd95SBruce Richardson graph_node_has_edge_to_src_node(struct graph *graph)
6599a2dd95SBruce Richardson {
6699a2dd95SBruce Richardson 	struct graph_node *graph_node;
6799a2dd95SBruce Richardson 	struct node *node;
6899a2dd95SBruce Richardson 	rte_edge_t i;
6999a2dd95SBruce Richardson 
7099a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
7199a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
7299a2dd95SBruce Richardson 			node = graph_node->adjacency_list[i]->node;
7399a2dd95SBruce Richardson 			if (node->flags & RTE_NODE_SOURCE_F)
7499a2dd95SBruce Richardson 				SET_ERR_JMP(
7599a2dd95SBruce Richardson 					EEXIST, fail,
7699a2dd95SBruce Richardson 					"Node %s points to the source node %s",
7799a2dd95SBruce Richardson 					graph_node->node->name, node->name);
7899a2dd95SBruce Richardson 		}
7999a2dd95SBruce Richardson 	}
8099a2dd95SBruce Richardson 
8199a2dd95SBruce Richardson 	return 0;
8299a2dd95SBruce Richardson fail:
8399a2dd95SBruce Richardson 	return 1;
8499a2dd95SBruce Richardson }
8599a2dd95SBruce Richardson 
8699a2dd95SBruce Richardson rte_node_t
graph_nodes_count(struct graph * graph)8799a2dd95SBruce Richardson graph_nodes_count(struct graph *graph)
8899a2dd95SBruce Richardson {
8999a2dd95SBruce Richardson 	struct graph_node *graph_node;
9099a2dd95SBruce Richardson 	rte_node_t count = 0;
9199a2dd95SBruce Richardson 
9299a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
9399a2dd95SBruce Richardson 		count++;
9499a2dd95SBruce Richardson 
9599a2dd95SBruce Richardson 	return count;
9699a2dd95SBruce Richardson }
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson void
graph_mark_nodes_as_not_visited(struct graph * graph)9999a2dd95SBruce Richardson graph_mark_nodes_as_not_visited(struct graph *graph)
10099a2dd95SBruce Richardson {
10199a2dd95SBruce Richardson 	struct graph_node *graph_node;
10299a2dd95SBruce Richardson 
10399a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
10499a2dd95SBruce Richardson 		graph_node->visited = false;
10599a2dd95SBruce Richardson }
10699a2dd95SBruce Richardson 
10799a2dd95SBruce Richardson int
graph_bfs(struct graph * graph,struct graph_node * start)10899a2dd95SBruce Richardson graph_bfs(struct graph *graph, struct graph_node *start)
10999a2dd95SBruce Richardson {
11099a2dd95SBruce Richardson 	struct graph_node **queue, *v, *tmp;
11199a2dd95SBruce Richardson 	uint16_t head = 0, tail = 0;
11299a2dd95SBruce Richardson 	rte_edge_t i;
11399a2dd95SBruce Richardson 	size_t sz;
11499a2dd95SBruce Richardson 
11599a2dd95SBruce Richardson 	sz = sizeof(struct graph_node *) * graph_nodes_count(graph);
11699a2dd95SBruce Richardson 	queue = malloc(sz);
11799a2dd95SBruce Richardson 	if (queue == NULL)
11899a2dd95SBruce Richardson 		SET_ERR_JMP(ENOMEM, fail, "Failed to alloc BFS queue of %zu",
11999a2dd95SBruce Richardson 			    sz);
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson 	/* BFS algorithm */
12299a2dd95SBruce Richardson 	queue[tail++] = start;
12399a2dd95SBruce Richardson 	start->visited = true;
12499a2dd95SBruce Richardson 	while (head != tail) {
12599a2dd95SBruce Richardson 		v = queue[head++];
12699a2dd95SBruce Richardson 		for (i = 0; i < v->node->nb_edges; i++) {
12799a2dd95SBruce Richardson 			tmp = v->adjacency_list[i];
12899a2dd95SBruce Richardson 			if (tmp->visited == false) {
12999a2dd95SBruce Richardson 				queue[tail++] = tmp;
13099a2dd95SBruce Richardson 				tmp->visited = true;
13199a2dd95SBruce Richardson 			}
13299a2dd95SBruce Richardson 		}
13399a2dd95SBruce Richardson 	}
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson 	free(queue);
13699a2dd95SBruce Richardson 	return 0;
13799a2dd95SBruce Richardson 
13899a2dd95SBruce Richardson fail:
13999a2dd95SBruce Richardson 	return -rte_errno;
14099a2dd95SBruce Richardson }
14199a2dd95SBruce Richardson 
14299a2dd95SBruce Richardson /* Check whether a node has connected path or parent node */
14399a2dd95SBruce Richardson int
graph_has_isolated_node(struct graph * graph)14499a2dd95SBruce Richardson graph_has_isolated_node(struct graph *graph)
14599a2dd95SBruce Richardson {
14699a2dd95SBruce Richardson 	struct graph_node *graph_node;
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	graph_mark_nodes_as_not_visited(graph);
14999a2dd95SBruce Richardson 
15099a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
15199a2dd95SBruce Richardson 		if (graph_node->node->flags & RTE_NODE_SOURCE_F) {
15299a2dd95SBruce Richardson 			if (graph_node->node->nb_edges == 0)
15399a2dd95SBruce Richardson 				SET_ERR_JMP(EINVAL, fail,
15499a2dd95SBruce Richardson 					    "%s node needs minimum one edge",
15599a2dd95SBruce Richardson 					    graph_node->node->name);
15699a2dd95SBruce Richardson 			if (graph_bfs(graph, graph_node))
15799a2dd95SBruce Richardson 				goto fail;
15899a2dd95SBruce Richardson 		}
15999a2dd95SBruce Richardson 	}
16099a2dd95SBruce Richardson 
16199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
16299a2dd95SBruce Richardson 		if (graph_node->visited == false)
16399a2dd95SBruce Richardson 			SET_ERR_JMP(EINVAL, fail, "Found isolated node %s",
16499a2dd95SBruce Richardson 				    graph_node->node->name);
16599a2dd95SBruce Richardson 
16699a2dd95SBruce Richardson 	return 0;
16799a2dd95SBruce Richardson fail:
16899a2dd95SBruce Richardson 	return 1;
16999a2dd95SBruce Richardson }
170