xref: /dpdk/lib/graph/node.c (revision 5e65cd4a722ec7f277a70447db318953252bf6f9)
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>
699a2dd95SBruce Richardson #include <stdio.h>
772b452c5SDmitry Kozlyuk #include <stdlib.h>
899a2dd95SBruce Richardson #include <string.h>
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #include <rte_common.h>
1199a2dd95SBruce Richardson #include <rte_debug.h>
1299a2dd95SBruce Richardson #include <rte_errno.h>
1399a2dd95SBruce Richardson #include <rte_string_fns.h>
1499a2dd95SBruce Richardson 
1599a2dd95SBruce Richardson #include "graph_private.h"
1699a2dd95SBruce Richardson 
1799a2dd95SBruce Richardson static struct node_head node_list = STAILQ_HEAD_INITIALIZER(node_list);
1899a2dd95SBruce Richardson static rte_node_t node_id;
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson #define NODE_ID_CHECK(id) ID_CHECK(id, node_id)
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson /* Private functions */
2399a2dd95SBruce Richardson struct node_head *
2499a2dd95SBruce Richardson node_list_head_get(void)
2599a2dd95SBruce Richardson {
2699a2dd95SBruce Richardson 	return &node_list;
2799a2dd95SBruce Richardson }
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson struct node *
3099a2dd95SBruce Richardson node_from_name(const char *name)
3199a2dd95SBruce Richardson {
3299a2dd95SBruce Richardson 	struct node *node;
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next)
3599a2dd95SBruce Richardson 		if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
3699a2dd95SBruce Richardson 			return node;
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson 	return NULL;
3999a2dd95SBruce Richardson }
4099a2dd95SBruce Richardson 
4199a2dd95SBruce Richardson static bool
4299a2dd95SBruce Richardson node_has_duplicate_entry(const char *name)
4399a2dd95SBruce Richardson {
4499a2dd95SBruce Richardson 	struct node *node;
4599a2dd95SBruce Richardson 
4699a2dd95SBruce Richardson 	/* Is duplicate name registered */
4799a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next) {
4899a2dd95SBruce Richardson 		if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) {
4999a2dd95SBruce Richardson 			rte_errno = EEXIST;
5099a2dd95SBruce Richardson 			return 1;
5199a2dd95SBruce Richardson 		}
5299a2dd95SBruce Richardson 	}
5399a2dd95SBruce Richardson 	return 0;
5499a2dd95SBruce Richardson }
5599a2dd95SBruce Richardson 
5699a2dd95SBruce Richardson /* Public functions */
5799a2dd95SBruce Richardson rte_node_t
5899a2dd95SBruce Richardson __rte_node_register(const struct rte_node_register *reg)
5999a2dd95SBruce Richardson {
6099a2dd95SBruce Richardson 	struct node *node;
6199a2dd95SBruce Richardson 	rte_edge_t i;
6299a2dd95SBruce Richardson 	size_t sz;
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson 	/* Limit Node specific metadata to one cacheline on 64B CL machine */
6599a2dd95SBruce Richardson 	RTE_BUILD_BUG_ON((offsetof(struct rte_node, nodes) -
6699a2dd95SBruce Richardson 			  offsetof(struct rte_node, ctx)) !=
6799a2dd95SBruce Richardson 			 RTE_CACHE_LINE_MIN_SIZE);
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	graph_spinlock_lock();
7099a2dd95SBruce Richardson 
7199a2dd95SBruce Richardson 	/* Check sanity */
7299a2dd95SBruce Richardson 	if (reg == NULL || reg->process == NULL) {
7399a2dd95SBruce Richardson 		rte_errno = EINVAL;
7499a2dd95SBruce Richardson 		goto fail;
7599a2dd95SBruce Richardson 	}
7699a2dd95SBruce Richardson 
7799a2dd95SBruce Richardson 	/* Check for duplicate name */
7899a2dd95SBruce Richardson 	if (node_has_duplicate_entry(reg->name))
7999a2dd95SBruce Richardson 		goto fail;
8099a2dd95SBruce Richardson 
8199a2dd95SBruce Richardson 	sz = sizeof(struct node) + (reg->nb_edges * RTE_NODE_NAMESIZE);
8299a2dd95SBruce Richardson 	node = calloc(1, sz);
8399a2dd95SBruce Richardson 	if (node == NULL) {
8499a2dd95SBruce Richardson 		rte_errno = ENOMEM;
8599a2dd95SBruce Richardson 		goto fail;
8699a2dd95SBruce Richardson 	}
8799a2dd95SBruce Richardson 
88070db97eSPavan Nikhilesh 	if (reg->xstats) {
89070db97eSPavan Nikhilesh 		sz = sizeof(*reg->xstats) + (reg->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE);
90070db97eSPavan Nikhilesh 		node->xstats = calloc(1, sz);
91070db97eSPavan Nikhilesh 		if (node->xstats == NULL) {
92070db97eSPavan Nikhilesh 			rte_errno = ENOMEM;
93070db97eSPavan Nikhilesh 			goto free;
94070db97eSPavan Nikhilesh 		}
95070db97eSPavan Nikhilesh 
96070db97eSPavan Nikhilesh 		node->xstats->nb_xstats = reg->xstats->nb_xstats;
97070db97eSPavan Nikhilesh 		for (i = 0; i < reg->xstats->nb_xstats; i++)
98070db97eSPavan Nikhilesh 			if (rte_strscpy(node->xstats->xstat_desc[i], reg->xstats->xstat_desc[i],
99070db97eSPavan Nikhilesh 					RTE_NODE_XSTAT_DESC_SIZE) < 0)
100070db97eSPavan Nikhilesh 				goto free_xstat;
101070db97eSPavan Nikhilesh 	}
102070db97eSPavan Nikhilesh 
10399a2dd95SBruce Richardson 	/* Initialize the node */
104dbba7c9eSThomas Monjalon 	if (rte_strscpy(node->name, reg->name, RTE_NODE_NAMESIZE) < 0)
105070db97eSPavan Nikhilesh 		goto free_xstat;
10699a2dd95SBruce Richardson 	node->flags = reg->flags;
10799a2dd95SBruce Richardson 	node->process = reg->process;
10899a2dd95SBruce Richardson 	node->init = reg->init;
10999a2dd95SBruce Richardson 	node->fini = reg->fini;
11099a2dd95SBruce Richardson 	node->nb_edges = reg->nb_edges;
11199a2dd95SBruce Richardson 	node->parent_id = reg->parent_id;
11299a2dd95SBruce Richardson 	for (i = 0; i < reg->nb_edges; i++) {
11399a2dd95SBruce Richardson 		if (rte_strscpy(node->next_nodes[i], reg->next_nodes[i],
114dbba7c9eSThomas Monjalon 				RTE_NODE_NAMESIZE) < 0)
115070db97eSPavan Nikhilesh 			goto free_xstat;
11699a2dd95SBruce Richardson 	}
11799a2dd95SBruce Richardson 
1181d08f290SZhirun Yan 	node->lcore_id = RTE_MAX_LCORE;
11999a2dd95SBruce Richardson 	node->id = node_id++;
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson 	/* Add the node at tail */
12299a2dd95SBruce Richardson 	STAILQ_INSERT_TAIL(&node_list, node, next);
12399a2dd95SBruce Richardson 	graph_spinlock_unlock();
12499a2dd95SBruce Richardson 
12599a2dd95SBruce Richardson 	return node->id;
126070db97eSPavan Nikhilesh free_xstat:
127070db97eSPavan Nikhilesh 	free(node->xstats);
12899a2dd95SBruce Richardson free:
12999a2dd95SBruce Richardson 	free(node);
13099a2dd95SBruce Richardson fail:
13199a2dd95SBruce Richardson 	graph_spinlock_unlock();
13299a2dd95SBruce Richardson 	return RTE_NODE_ID_INVALID;
13399a2dd95SBruce Richardson }
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson static rte_node_t
13699a2dd95SBruce Richardson node_clone(struct node *node, const char *name)
13799a2dd95SBruce Richardson {
13899a2dd95SBruce Richardson 	rte_node_t rc = RTE_NODE_ID_INVALID;
13999a2dd95SBruce Richardson 	struct rte_node_register *reg;
14099a2dd95SBruce Richardson 	rte_edge_t i;
14199a2dd95SBruce Richardson 
14299a2dd95SBruce Richardson 	/* Don't allow to clone a node from a cloned node */
14399a2dd95SBruce Richardson 	if (node->parent_id != RTE_NODE_ID_INVALID) {
14499a2dd95SBruce Richardson 		rte_errno = EEXIST;
14599a2dd95SBruce Richardson 		goto fail;
14699a2dd95SBruce Richardson 	}
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	reg = calloc(1, sizeof(*reg) + (sizeof(char *) * node->nb_edges));
14999a2dd95SBruce Richardson 	if (reg == NULL) {
15099a2dd95SBruce Richardson 		rte_errno = ENOMEM;
15199a2dd95SBruce Richardson 		goto fail;
15299a2dd95SBruce Richardson 	}
15399a2dd95SBruce Richardson 
154070db97eSPavan Nikhilesh 	if (node->xstats) {
155070db97eSPavan Nikhilesh 		reg->xstats = calloc(1, sizeof(*node->xstats) +
156070db97eSPavan Nikhilesh 				     (node->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE));
157070db97eSPavan Nikhilesh 		if (reg->xstats == NULL) {
158070db97eSPavan Nikhilesh 			rte_errno = ENOMEM;
159*5e65cd4aSPavan Nikhilesh 			goto free;
160070db97eSPavan Nikhilesh 		}
161070db97eSPavan Nikhilesh 
162070db97eSPavan Nikhilesh 		for (i = 0; i < node->xstats->nb_xstats; i++)
163070db97eSPavan Nikhilesh 			if (rte_strscpy(reg->xstats->xstat_desc[i], node->xstats->xstat_desc[i],
164070db97eSPavan Nikhilesh 					RTE_NODE_XSTAT_DESC_SIZE) < 0)
165070db97eSPavan Nikhilesh 				goto free_xstat;
166070db97eSPavan Nikhilesh 	}
167070db97eSPavan Nikhilesh 
16899a2dd95SBruce Richardson 	/* Clone the source node */
16999a2dd95SBruce Richardson 	reg->flags = node->flags;
17099a2dd95SBruce Richardson 	reg->process = node->process;
17199a2dd95SBruce Richardson 	reg->init = node->init;
17299a2dd95SBruce Richardson 	reg->fini = node->fini;
17399a2dd95SBruce Richardson 	reg->nb_edges = node->nb_edges;
17499a2dd95SBruce Richardson 	reg->parent_id = node->id;
17599a2dd95SBruce Richardson 
17699a2dd95SBruce Richardson 	for (i = 0; i < node->nb_edges; i++)
17799a2dd95SBruce Richardson 		reg->next_nodes[i] = node->next_nodes[i];
17899a2dd95SBruce Richardson 
17999a2dd95SBruce Richardson 	/* Naming ceremony of the new node. name is node->name + "-" + name */
180b6ef3794SZhirun Yan 	if (clone_name(reg->name, node->name, name))
181*5e65cd4aSPavan Nikhilesh 		goto free_xstat;
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 	rc = __rte_node_register(reg);
184070db97eSPavan Nikhilesh free_xstat:
185070db97eSPavan Nikhilesh 	free(reg->xstats);
18699a2dd95SBruce Richardson free:
18799a2dd95SBruce Richardson 	free(reg);
18899a2dd95SBruce Richardson fail:
18999a2dd95SBruce Richardson 	return rc;
19099a2dd95SBruce Richardson }
19199a2dd95SBruce Richardson 
19299a2dd95SBruce Richardson rte_node_t
19399a2dd95SBruce Richardson rte_node_clone(rte_node_t id, const char *name)
19499a2dd95SBruce Richardson {
19599a2dd95SBruce Richardson 	struct node *node;
19699a2dd95SBruce Richardson 
19799a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
19899a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next)
19999a2dd95SBruce Richardson 		if (node->id == id)
20099a2dd95SBruce Richardson 			return node_clone(node, name);
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson fail:
20399a2dd95SBruce Richardson 	return RTE_NODE_ID_INVALID;
20499a2dd95SBruce Richardson }
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson rte_node_t
20799a2dd95SBruce Richardson rte_node_from_name(const char *name)
20899a2dd95SBruce Richardson {
20999a2dd95SBruce Richardson 	struct node *node;
21099a2dd95SBruce Richardson 
21199a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next)
21299a2dd95SBruce Richardson 		if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
21399a2dd95SBruce Richardson 			return node->id;
21499a2dd95SBruce Richardson 
21599a2dd95SBruce Richardson 	return RTE_NODE_ID_INVALID;
21699a2dd95SBruce Richardson }
21799a2dd95SBruce Richardson 
21899a2dd95SBruce Richardson char *
21999a2dd95SBruce Richardson rte_node_id_to_name(rte_node_t id)
22099a2dd95SBruce Richardson {
22199a2dd95SBruce Richardson 	struct node *node;
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
22499a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next)
22599a2dd95SBruce Richardson 		if (node->id == id)
22699a2dd95SBruce Richardson 			return node->name;
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson fail:
22999a2dd95SBruce Richardson 	return NULL;
23099a2dd95SBruce Richardson }
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson rte_edge_t
23399a2dd95SBruce Richardson rte_node_edge_count(rte_node_t id)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 	struct node *node;
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
23899a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next)
23999a2dd95SBruce Richardson 		if (node->id == id)
24099a2dd95SBruce Richardson 			return node->nb_edges;
24199a2dd95SBruce Richardson fail:
24299a2dd95SBruce Richardson 	return RTE_EDGE_ID_INVALID;
24399a2dd95SBruce Richardson }
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson static rte_edge_t
24699a2dd95SBruce Richardson edge_update(struct node *node, struct node *prev, rte_edge_t from,
24799a2dd95SBruce Richardson 	    const char **next_nodes, rte_edge_t nb_edges)
24899a2dd95SBruce Richardson {
24999a2dd95SBruce Richardson 	rte_edge_t i, max_edges, count = 0;
25099a2dd95SBruce Richardson 	struct node *new_node;
25199a2dd95SBruce Richardson 	bool need_realloc;
25299a2dd95SBruce Richardson 	size_t sz;
25399a2dd95SBruce Richardson 
25499a2dd95SBruce Richardson 	if (from == RTE_EDGE_ID_INVALID)
25599a2dd95SBruce Richardson 		from = node->nb_edges;
25699a2dd95SBruce Richardson 
25799a2dd95SBruce Richardson 	/* Don't create hole in next_nodes[] list */
25899a2dd95SBruce Richardson 	if (from > node->nb_edges) {
25999a2dd95SBruce Richardson 		rte_errno = ENOMEM;
26099a2dd95SBruce Richardson 		goto fail;
26199a2dd95SBruce Richardson 	}
26299a2dd95SBruce Richardson 
26399a2dd95SBruce Richardson 	/* Remove me from list */
26499a2dd95SBruce Richardson 	STAILQ_REMOVE(&node_list, node, node, next);
26599a2dd95SBruce Richardson 
26699a2dd95SBruce Richardson 	/* Allocate the storage space for new node if required */
26799a2dd95SBruce Richardson 	max_edges = from + nb_edges;
26899a2dd95SBruce Richardson 	need_realloc = max_edges > node->nb_edges;
26999a2dd95SBruce Richardson 	if (need_realloc) {
27099a2dd95SBruce Richardson 		sz = sizeof(struct node) + (max_edges * RTE_NODE_NAMESIZE);
27199a2dd95SBruce Richardson 		new_node = realloc(node, sz);
27299a2dd95SBruce Richardson 		if (new_node == NULL) {
27399a2dd95SBruce Richardson 			rte_errno = ENOMEM;
27499a2dd95SBruce Richardson 			goto restore;
27599a2dd95SBruce Richardson 		} else {
27699a2dd95SBruce Richardson 			node = new_node;
27799a2dd95SBruce Richardson 		}
27899a2dd95SBruce Richardson 	}
27999a2dd95SBruce Richardson 
28099a2dd95SBruce Richardson 	/* Update the new nodes name */
28199a2dd95SBruce Richardson 	for (i = from; i < max_edges; i++, count++) {
28299a2dd95SBruce Richardson 		if (rte_strscpy(node->next_nodes[i], next_nodes[count],
283dbba7c9eSThomas Monjalon 				RTE_NODE_NAMESIZE) < 0)
28499a2dd95SBruce Richardson 			goto restore;
28599a2dd95SBruce Richardson 	}
28699a2dd95SBruce Richardson restore:
28799a2dd95SBruce Richardson 	/* Update the linked list to point new node address in prev node */
28899a2dd95SBruce Richardson 	if (prev)
28999a2dd95SBruce Richardson 		STAILQ_INSERT_AFTER(&node_list, prev, node, next);
29099a2dd95SBruce Richardson 	else
29199a2dd95SBruce Richardson 		STAILQ_INSERT_HEAD(&node_list, node, next);
29299a2dd95SBruce Richardson 
29399a2dd95SBruce Richardson 	if (need_realloc)
29499a2dd95SBruce Richardson 		node->nb_edges = max_edges;
29599a2dd95SBruce Richardson 
29699a2dd95SBruce Richardson fail:
29799a2dd95SBruce Richardson 	return count;
29899a2dd95SBruce Richardson }
29999a2dd95SBruce Richardson 
30099a2dd95SBruce Richardson rte_edge_t
30199a2dd95SBruce Richardson rte_node_edge_shrink(rte_node_t id, rte_edge_t size)
30299a2dd95SBruce Richardson {
30399a2dd95SBruce Richardson 	rte_edge_t rc = RTE_EDGE_ID_INVALID;
30499a2dd95SBruce Richardson 	struct node *node;
30599a2dd95SBruce Richardson 
30699a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
30799a2dd95SBruce Richardson 	graph_spinlock_lock();
30899a2dd95SBruce Richardson 
30999a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next) {
31099a2dd95SBruce Richardson 		if (node->id == id) {
31199a2dd95SBruce Richardson 			if (node->nb_edges < size) {
31299a2dd95SBruce Richardson 				rte_errno = E2BIG;
31399cc0a9aSDavid Marchand 			} else {
31499a2dd95SBruce Richardson 				node->nb_edges = size;
31599a2dd95SBruce Richardson 				rc = size;
31699cc0a9aSDavid Marchand 			}
31799a2dd95SBruce Richardson 			break;
31899a2dd95SBruce Richardson 		}
31999a2dd95SBruce Richardson 	}
32099a2dd95SBruce Richardson 
32199a2dd95SBruce Richardson 	graph_spinlock_unlock();
32299cc0a9aSDavid Marchand fail:
32399a2dd95SBruce Richardson 	return rc;
32499a2dd95SBruce Richardson }
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson rte_edge_t
32799a2dd95SBruce Richardson rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes,
32899a2dd95SBruce Richardson 		     uint16_t nb_edges)
32999a2dd95SBruce Richardson {
33099a2dd95SBruce Richardson 	rte_edge_t rc = RTE_EDGE_ID_INVALID;
33199a2dd95SBruce Richardson 	struct node *n, *prev;
33299a2dd95SBruce Richardson 
33399a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
33499a2dd95SBruce Richardson 	graph_spinlock_lock();
33599a2dd95SBruce Richardson 
33699a2dd95SBruce Richardson 	prev = NULL;
33799a2dd95SBruce Richardson 	STAILQ_FOREACH(n, &node_list, next) {
33899a2dd95SBruce Richardson 		if (n->id == id) {
33999a2dd95SBruce Richardson 			rc = edge_update(n, prev, from, next_nodes, nb_edges);
34099a2dd95SBruce Richardson 			break;
34199a2dd95SBruce Richardson 		}
34299a2dd95SBruce Richardson 		prev = n;
34399a2dd95SBruce Richardson 	}
34499a2dd95SBruce Richardson 
34599a2dd95SBruce Richardson 	graph_spinlock_unlock();
34699a2dd95SBruce Richardson fail:
34799a2dd95SBruce Richardson 	return rc;
34899a2dd95SBruce Richardson }
34999a2dd95SBruce Richardson 
35099a2dd95SBruce Richardson static rte_node_t
35199a2dd95SBruce Richardson node_copy_edges(struct node *node, char *next_nodes[])
35299a2dd95SBruce Richardson {
35399a2dd95SBruce Richardson 	rte_edge_t i;
35499a2dd95SBruce Richardson 
35599a2dd95SBruce Richardson 	for (i = 0; i < node->nb_edges; i++)
35699a2dd95SBruce Richardson 		next_nodes[i] = node->next_nodes[i];
35799a2dd95SBruce Richardson 
35899a2dd95SBruce Richardson 	return i;
35999a2dd95SBruce Richardson }
36099a2dd95SBruce Richardson 
36199a2dd95SBruce Richardson rte_node_t
36299a2dd95SBruce Richardson rte_node_edge_get(rte_node_t id, char *next_nodes[])
36399a2dd95SBruce Richardson {
36499a2dd95SBruce Richardson 	rte_node_t rc = RTE_NODE_ID_INVALID;
36599a2dd95SBruce Richardson 	struct node *node;
36699a2dd95SBruce Richardson 
36799a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
36899a2dd95SBruce Richardson 	graph_spinlock_lock();
36999a2dd95SBruce Richardson 
37099a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next) {
37199a2dd95SBruce Richardson 		if (node->id == id) {
37299a2dd95SBruce Richardson 			if (next_nodes == NULL)
37399a2dd95SBruce Richardson 				rc = sizeof(char *) * node->nb_edges;
37499a2dd95SBruce Richardson 			else
37599a2dd95SBruce Richardson 				rc = node_copy_edges(node, next_nodes);
37699a2dd95SBruce Richardson 			break;
37799a2dd95SBruce Richardson 		}
37899a2dd95SBruce Richardson 	}
37999a2dd95SBruce Richardson 
38099a2dd95SBruce Richardson 	graph_spinlock_unlock();
38199a2dd95SBruce Richardson fail:
38299a2dd95SBruce Richardson 	return rc;
38399a2dd95SBruce Richardson }
38499a2dd95SBruce Richardson 
38599a2dd95SBruce Richardson static void
38699a2dd95SBruce Richardson node_scan_dump(FILE *f, rte_node_t id, bool all)
38799a2dd95SBruce Richardson {
38899a2dd95SBruce Richardson 	struct node *node;
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson 	RTE_ASSERT(f != NULL);
39199a2dd95SBruce Richardson 	NODE_ID_CHECK(id);
39299a2dd95SBruce Richardson 
39399a2dd95SBruce Richardson 	STAILQ_FOREACH(node, &node_list, next) {
39499a2dd95SBruce Richardson 		if (all == true) {
39599a2dd95SBruce Richardson 			node_dump(f, node);
39699a2dd95SBruce Richardson 		} else if (node->id == id) {
39799a2dd95SBruce Richardson 			node_dump(f, node);
39899a2dd95SBruce Richardson 			return;
39999a2dd95SBruce Richardson 		}
40099a2dd95SBruce Richardson 	}
40199a2dd95SBruce Richardson fail:
40299a2dd95SBruce Richardson 	return;
40399a2dd95SBruce Richardson }
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson void
40699a2dd95SBruce Richardson rte_node_dump(FILE *f, rte_node_t id)
40799a2dd95SBruce Richardson {
40899a2dd95SBruce Richardson 	node_scan_dump(f, id, false);
40999a2dd95SBruce Richardson }
41099a2dd95SBruce Richardson 
41199a2dd95SBruce Richardson void
41299a2dd95SBruce Richardson rte_node_list_dump(FILE *f)
41399a2dd95SBruce Richardson {
41499a2dd95SBruce Richardson 	node_scan_dump(f, 0, true);
41599a2dd95SBruce Richardson }
41699a2dd95SBruce Richardson 
41799a2dd95SBruce Richardson rte_node_t
41899a2dd95SBruce Richardson rte_node_max_count(void)
41999a2dd95SBruce Richardson {
42099a2dd95SBruce Richardson 	return node_id;
42199a2dd95SBruce Richardson }
422