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