xref: /dpdk/lib/graph/graph.c (revision 5b8d861cfe89ebcbb08760c7817be0b79b9ff6f9)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(C) 2020 Marvell International Ltd.
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <fnmatch.h>
699a2dd95SBruce Richardson #include <stdbool.h>
772b452c5SDmitry Kozlyuk #include <stdlib.h>
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson #include <rte_common.h>
1099a2dd95SBruce Richardson #include <rte_debug.h>
1199a2dd95SBruce Richardson #include <rte_errno.h>
1299a2dd95SBruce Richardson #include <rte_malloc.h>
1399a2dd95SBruce Richardson #include <rte_memzone.h>
1499a2dd95SBruce Richardson #include <rte_spinlock.h>
1599a2dd95SBruce Richardson #include <rte_string_fns.h>
1699a2dd95SBruce Richardson 
1799a2dd95SBruce Richardson #include "graph_private.h"
189b72ea1fSAmit Prakash Shukla #include "graph_pcap_private.h"
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list);
2199a2dd95SBruce Richardson static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER;
2299a2dd95SBruce Richardson 
2399a2dd95SBruce Richardson /* Private functions */
24d5c8b6bbSRobin Jarry static struct graph *
25d5c8b6bbSRobin Jarry graph_from_id(rte_graph_t id)
26d5c8b6bbSRobin Jarry {
27d5c8b6bbSRobin Jarry 	struct graph *graph;
28d5c8b6bbSRobin Jarry 	STAILQ_FOREACH(graph, &graph_list, next) {
29d5c8b6bbSRobin Jarry 		if (graph->id == id)
30d5c8b6bbSRobin Jarry 			return graph;
31d5c8b6bbSRobin Jarry 	}
32d5c8b6bbSRobin Jarry 	rte_errno = EINVAL;
33d5c8b6bbSRobin Jarry 	return NULL;
34d5c8b6bbSRobin Jarry }
35d5c8b6bbSRobin Jarry 
36d5c8b6bbSRobin Jarry static rte_graph_t
37d5c8b6bbSRobin Jarry graph_next_free_id(void)
38d5c8b6bbSRobin Jarry {
39d5c8b6bbSRobin Jarry 	struct graph *graph;
40d5c8b6bbSRobin Jarry 	rte_graph_t id = 0;
41d5c8b6bbSRobin Jarry 
42d5c8b6bbSRobin Jarry 	STAILQ_FOREACH(graph, &graph_list, next) {
43d5c8b6bbSRobin Jarry 		if (id < graph->id)
44d5c8b6bbSRobin Jarry 			break;
45d5c8b6bbSRobin Jarry 		id = graph->id + 1;
46d5c8b6bbSRobin Jarry 	}
47d5c8b6bbSRobin Jarry 
48d5c8b6bbSRobin Jarry 	return id;
49d5c8b6bbSRobin Jarry }
50d5c8b6bbSRobin Jarry 
51d5c8b6bbSRobin Jarry static void
52d5c8b6bbSRobin Jarry graph_insert_ordered(struct graph *graph)
53d5c8b6bbSRobin Jarry {
54d5c8b6bbSRobin Jarry 	struct graph *after, *g;
55d5c8b6bbSRobin Jarry 
56d5c8b6bbSRobin Jarry 	after = NULL;
57d5c8b6bbSRobin Jarry 	STAILQ_FOREACH(g, &graph_list, next) {
58d5c8b6bbSRobin Jarry 		if (g->id < graph->id)
59d5c8b6bbSRobin Jarry 			after = g;
60d5c8b6bbSRobin Jarry 		else if (g->id > graph->id)
61d5c8b6bbSRobin Jarry 			break;
62d5c8b6bbSRobin Jarry 	}
63d5c8b6bbSRobin Jarry 	if (after == NULL) {
64d5c8b6bbSRobin Jarry 		STAILQ_INSERT_HEAD(&graph_list, graph, next);
65d5c8b6bbSRobin Jarry 	} else {
66d5c8b6bbSRobin Jarry 		STAILQ_INSERT_AFTER(&graph_list, after, graph, next);
67d5c8b6bbSRobin Jarry 	}
68d5c8b6bbSRobin Jarry }
69d5c8b6bbSRobin Jarry 
7099a2dd95SBruce Richardson struct graph_head *
7199a2dd95SBruce Richardson graph_list_head_get(void)
7299a2dd95SBruce Richardson {
7399a2dd95SBruce Richardson 	return &graph_list;
7499a2dd95SBruce Richardson }
7599a2dd95SBruce Richardson 
76476fd9a2SDavid Marchand rte_spinlock_t *
77476fd9a2SDavid Marchand graph_spinlock_get(void)
78476fd9a2SDavid Marchand {
79476fd9a2SDavid Marchand 	return &graph_lock;
80476fd9a2SDavid Marchand }
81476fd9a2SDavid Marchand 
8299a2dd95SBruce Richardson void
8399a2dd95SBruce Richardson graph_spinlock_lock(void)
8499a2dd95SBruce Richardson {
85476fd9a2SDavid Marchand 	rte_spinlock_lock(graph_spinlock_get());
8699a2dd95SBruce Richardson }
8799a2dd95SBruce Richardson 
8899a2dd95SBruce Richardson void
8999a2dd95SBruce Richardson graph_spinlock_unlock(void)
9099a2dd95SBruce Richardson {
91476fd9a2SDavid Marchand 	rte_spinlock_unlock(graph_spinlock_get());
9299a2dd95SBruce Richardson }
9399a2dd95SBruce Richardson 
9499a2dd95SBruce Richardson static int
9599a2dd95SBruce Richardson graph_node_add(struct graph *graph, struct node *node)
9699a2dd95SBruce Richardson {
9799a2dd95SBruce Richardson 	struct graph_node *graph_node;
9899a2dd95SBruce Richardson 	size_t sz;
9999a2dd95SBruce Richardson 
10099a2dd95SBruce Richardson 	/* Skip the duplicate nodes */
10199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
10299a2dd95SBruce Richardson 		if (strncmp(node->name, graph_node->node->name,
10399a2dd95SBruce Richardson 			    RTE_NODE_NAMESIZE) == 0)
10499a2dd95SBruce Richardson 			return 0;
10599a2dd95SBruce Richardson 
10699a2dd95SBruce Richardson 	/* Allocate new graph node object */
10799a2dd95SBruce Richardson 	sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *);
10899a2dd95SBruce Richardson 	graph_node = calloc(1, sz);
10999a2dd95SBruce Richardson 
11099a2dd95SBruce Richardson 	if (graph_node == NULL)
11199a2dd95SBruce Richardson 		SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object",
11299a2dd95SBruce Richardson 			    node->name);
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 	/* Initialize the graph node */
11599a2dd95SBruce Richardson 	graph_node->node = node;
11699a2dd95SBruce Richardson 
11799a2dd95SBruce Richardson 	/* Add to graph node list */
11899a2dd95SBruce Richardson 	STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next);
11999a2dd95SBruce Richardson 	return 0;
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson free:
12299a2dd95SBruce Richardson 	free(graph_node);
12399a2dd95SBruce Richardson 	return -rte_errno;
12499a2dd95SBruce Richardson }
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson static struct graph_node *
12799a2dd95SBruce Richardson node_to_graph_node(struct graph *graph, struct node *node)
12899a2dd95SBruce Richardson {
12999a2dd95SBruce Richardson 	struct graph_node *graph_node;
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
13299a2dd95SBruce Richardson 		if (graph_node->node == node)
13399a2dd95SBruce Richardson 			return graph_node;
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson 	SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name);
13699a2dd95SBruce Richardson fail:
13799a2dd95SBruce Richardson 	return NULL;
13899a2dd95SBruce Richardson }
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson static int
14199a2dd95SBruce Richardson graph_node_edges_add(struct graph *graph)
14299a2dd95SBruce Richardson {
14399a2dd95SBruce Richardson 	struct graph_node *graph_node;
14499a2dd95SBruce Richardson 	struct node *adjacency;
14599a2dd95SBruce Richardson 	const char *next;
14699a2dd95SBruce Richardson 	rte_edge_t i;
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
14999a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
15099a2dd95SBruce Richardson 			next = graph_node->node->next_nodes[i];
15199a2dd95SBruce Richardson 			adjacency = node_from_name(next);
15299a2dd95SBruce Richardson 			if (adjacency == NULL)
15399a2dd95SBruce Richardson 				SET_ERR_JMP(EINVAL, fail,
15499a2dd95SBruce Richardson 					    "Node %s not registered", next);
15599a2dd95SBruce Richardson 			if (graph_node_add(graph, adjacency))
15699a2dd95SBruce Richardson 				goto fail;
15799a2dd95SBruce Richardson 		}
15899a2dd95SBruce Richardson 	}
15999a2dd95SBruce Richardson 	return 0;
16099a2dd95SBruce Richardson fail:
16199a2dd95SBruce Richardson 	return -rte_errno;
16299a2dd95SBruce Richardson }
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson static int
16599a2dd95SBruce Richardson graph_adjacency_list_update(struct graph *graph)
16699a2dd95SBruce Richardson {
16799a2dd95SBruce Richardson 	struct graph_node *graph_node, *tmp;
16899a2dd95SBruce Richardson 	struct node *adjacency;
16999a2dd95SBruce Richardson 	const char *next;
17099a2dd95SBruce Richardson 	rte_edge_t i;
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
17399a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
17499a2dd95SBruce Richardson 			next = graph_node->node->next_nodes[i];
17599a2dd95SBruce Richardson 			adjacency = node_from_name(next);
17699a2dd95SBruce Richardson 			if (adjacency == NULL)
17799a2dd95SBruce Richardson 				SET_ERR_JMP(EINVAL, fail,
17899a2dd95SBruce Richardson 					    "Node %s not registered", next);
17999a2dd95SBruce Richardson 			tmp = node_to_graph_node(graph, adjacency);
18099a2dd95SBruce Richardson 			if (tmp == NULL)
18199a2dd95SBruce Richardson 				goto fail;
18299a2dd95SBruce Richardson 			graph_node->adjacency_list[i] = tmp;
18399a2dd95SBruce Richardson 		}
18499a2dd95SBruce Richardson 	}
18599a2dd95SBruce Richardson 
18699a2dd95SBruce Richardson 	return 0;
18799a2dd95SBruce Richardson fail:
18899a2dd95SBruce Richardson 	return -rte_errno;
18999a2dd95SBruce Richardson }
19099a2dd95SBruce Richardson 
19199a2dd95SBruce Richardson static int
19299a2dd95SBruce Richardson expand_pattern_to_node(struct graph *graph, const char *pattern)
19399a2dd95SBruce Richardson {
19499a2dd95SBruce Richardson 	struct node_head *node_head = node_list_head_get();
19599a2dd95SBruce Richardson 	bool found = false;
19699a2dd95SBruce Richardson 	struct node *node;
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 	/* Check for pattern match */
19999a2dd95SBruce Richardson 	STAILQ_FOREACH(node, node_head, next) {
20099a2dd95SBruce Richardson 		if (fnmatch(pattern, node->name, 0) == 0) {
20199a2dd95SBruce Richardson 			if (graph_node_add(graph, node))
20299a2dd95SBruce Richardson 				goto fail;
20399a2dd95SBruce Richardson 			found = true;
20499a2dd95SBruce Richardson 		}
20599a2dd95SBruce Richardson 	}
20699a2dd95SBruce Richardson 	if (found == false)
20799a2dd95SBruce Richardson 		SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern);
20899a2dd95SBruce Richardson 
20999a2dd95SBruce Richardson 	return 0;
21099a2dd95SBruce Richardson fail:
21199a2dd95SBruce Richardson 	return -rte_errno;
21299a2dd95SBruce Richardson }
21399a2dd95SBruce Richardson 
21499a2dd95SBruce Richardson static void
21599a2dd95SBruce Richardson graph_cleanup(struct graph *graph)
21699a2dd95SBruce Richardson {
21799a2dd95SBruce Richardson 	struct graph_node *graph_node;
21899a2dd95SBruce Richardson 
21999a2dd95SBruce Richardson 	while (!STAILQ_EMPTY(&graph->node_list)) {
22099a2dd95SBruce Richardson 		graph_node = STAILQ_FIRST(&graph->node_list);
22199a2dd95SBruce Richardson 		STAILQ_REMOVE_HEAD(&graph->node_list, next);
22299a2dd95SBruce Richardson 		free(graph_node);
22399a2dd95SBruce Richardson 	}
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson 
22699a2dd95SBruce Richardson static int
22799a2dd95SBruce Richardson graph_node_init(struct graph *graph)
22899a2dd95SBruce Richardson {
22999a2dd95SBruce Richardson 	struct graph_node *graph_node;
23099a2dd95SBruce Richardson 	const char *name;
23199a2dd95SBruce Richardson 	int rc;
23299a2dd95SBruce Richardson 
23399a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
23499a2dd95SBruce Richardson 		if (graph_node->node->init) {
23599a2dd95SBruce Richardson 			name = graph_node->node->name;
23699a2dd95SBruce Richardson 			rc = graph_node->node->init(
23799a2dd95SBruce Richardson 				graph->graph,
23899a2dd95SBruce Richardson 				graph_node_name_to_ptr(graph->graph, name));
23999a2dd95SBruce Richardson 			if (rc)
24099a2dd95SBruce Richardson 				SET_ERR_JMP(rc, err, "Node %s init() failed",
24199a2dd95SBruce Richardson 					    name);
24299a2dd95SBruce Richardson 		}
24399a2dd95SBruce Richardson 	}
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 	return 0;
24699a2dd95SBruce Richardson err:
24799a2dd95SBruce Richardson 	return -rte_errno;
24899a2dd95SBruce Richardson }
24999a2dd95SBruce Richardson 
25099a2dd95SBruce Richardson static void
25199a2dd95SBruce Richardson graph_node_fini(struct graph *graph)
25299a2dd95SBruce Richardson {
25399a2dd95SBruce Richardson 	struct graph_node *graph_node;
25499a2dd95SBruce Richardson 
25599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
25699a2dd95SBruce Richardson 		if (graph_node->node->fini)
25799a2dd95SBruce Richardson 			graph_node->node->fini(
25899a2dd95SBruce Richardson 				graph->graph,
25999a2dd95SBruce Richardson 				graph_node_name_to_ptr(graph->graph,
26099a2dd95SBruce Richardson 						       graph_node->node->name));
26199a2dd95SBruce Richardson }
26299a2dd95SBruce Richardson 
26399a2dd95SBruce Richardson static struct rte_graph *
26499a2dd95SBruce Richardson graph_mem_fixup_node_ctx(struct rte_graph *graph)
26599a2dd95SBruce Richardson {
26699a2dd95SBruce Richardson 	struct rte_node *node;
26799a2dd95SBruce Richardson 	struct node *node_db;
26899a2dd95SBruce Richardson 	rte_graph_off_t off;
26999a2dd95SBruce Richardson 	rte_node_t count;
27099a2dd95SBruce Richardson 	const char *name;
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	rte_graph_foreach_node(count, off, graph, node) {
27399a2dd95SBruce Richardson 		if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
27499a2dd95SBruce Richardson 			name = node->name;
27599a2dd95SBruce Richardson 		else /* Cloned node */
27699a2dd95SBruce Richardson 			name = node->parent;
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson 		node_db = node_from_name(name);
27999a2dd95SBruce Richardson 		if (node_db == NULL)
28099a2dd95SBruce Richardson 			SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
2819b72ea1fSAmit Prakash Shukla 
2829b72ea1fSAmit Prakash Shukla 		if (graph->pcap_enable) {
2839b72ea1fSAmit Prakash Shukla 			node->process = graph_pcap_dispatch;
2849b72ea1fSAmit Prakash Shukla 			node->original_process = node_db->process;
2859b72ea1fSAmit Prakash Shukla 		} else
28699a2dd95SBruce Richardson 			node->process = node_db->process;
28799a2dd95SBruce Richardson 	}
28899a2dd95SBruce Richardson 
28999a2dd95SBruce Richardson 	return graph;
29099a2dd95SBruce Richardson fail:
29199a2dd95SBruce Richardson 	return NULL;
29299a2dd95SBruce Richardson }
29399a2dd95SBruce Richardson 
29499a2dd95SBruce Richardson static struct rte_graph *
29599a2dd95SBruce Richardson graph_mem_fixup_secondary(struct rte_graph *graph)
29699a2dd95SBruce Richardson {
29799a2dd95SBruce Richardson 	if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
29899a2dd95SBruce Richardson 		return graph;
29999a2dd95SBruce Richardson 
3009b72ea1fSAmit Prakash Shukla 	if (graph_pcap_file_open(graph->pcap_filename) || graph_pcap_mp_init())
3019b72ea1fSAmit Prakash Shukla 		graph_pcap_exit(graph);
3029b72ea1fSAmit Prakash Shukla 
30399a2dd95SBruce Richardson 	return graph_mem_fixup_node_ctx(graph);
30499a2dd95SBruce Richardson }
30599a2dd95SBruce Richardson 
306ecb22a29SZhirun Yan static bool
307ecb22a29SZhirun Yan graph_src_node_avail(struct graph *graph)
308ecb22a29SZhirun Yan {
309ecb22a29SZhirun Yan 	struct graph_node *graph_node;
310ecb22a29SZhirun Yan 
311ecb22a29SZhirun Yan 	STAILQ_FOREACH(graph_node, &graph->node_list, next)
312ecb22a29SZhirun Yan 		if ((graph_node->node->flags & RTE_NODE_SOURCE_F) &&
313ecb22a29SZhirun Yan 		    (graph_node->node->lcore_id == RTE_MAX_LCORE ||
314ecb22a29SZhirun Yan 		     graph->lcore_id == graph_node->node->lcore_id))
315ecb22a29SZhirun Yan 			return true;
316ecb22a29SZhirun Yan 
317ecb22a29SZhirun Yan 	return false;
318ecb22a29SZhirun Yan }
319ecb22a29SZhirun Yan 
320ecb22a29SZhirun Yan int
321ecb22a29SZhirun Yan rte_graph_model_mcore_dispatch_core_bind(rte_graph_t id, int lcore)
322ecb22a29SZhirun Yan {
323ecb22a29SZhirun Yan 	struct graph *graph;
324ecb22a29SZhirun Yan 
325d5c8b6bbSRobin Jarry 	if (graph_from_id(id) == NULL)
326d5c8b6bbSRobin Jarry 		goto fail;
327ecb22a29SZhirun Yan 	if (!rte_lcore_is_enabled(lcore))
328ecb22a29SZhirun Yan 		SET_ERR_JMP(ENOLINK, fail, "lcore %d not enabled", lcore);
329ecb22a29SZhirun Yan 
330ecb22a29SZhirun Yan 	STAILQ_FOREACH(graph, &graph_list, next)
331ecb22a29SZhirun Yan 		if (graph->id == id)
332ecb22a29SZhirun Yan 			break;
333ecb22a29SZhirun Yan 
33415f483feSZhirun Yan 	if (graph->graph->model != RTE_GRAPH_MODEL_MCORE_DISPATCH)
335ecb22a29SZhirun Yan 		goto fail;
336ecb22a29SZhirun Yan 
337ecb22a29SZhirun Yan 	graph->lcore_id = lcore;
338e6c67c9eSZhirun Yan 	graph->graph->dispatch.lcore_id = graph->lcore_id;
339ecb22a29SZhirun Yan 	graph->socket = rte_lcore_to_socket_id(lcore);
340ecb22a29SZhirun Yan 
341ecb22a29SZhirun Yan 	/* check the availability of source node */
342ecb22a29SZhirun Yan 	if (!graph_src_node_avail(graph))
343ecb22a29SZhirun Yan 		graph->graph->head = 0;
344ecb22a29SZhirun Yan 
345ecb22a29SZhirun Yan 	return 0;
346ecb22a29SZhirun Yan 
347ecb22a29SZhirun Yan fail:
348ecb22a29SZhirun Yan 	return -rte_errno;
349ecb22a29SZhirun Yan }
350ecb22a29SZhirun Yan 
351ecb22a29SZhirun Yan void
352ecb22a29SZhirun Yan rte_graph_model_mcore_dispatch_core_unbind(rte_graph_t id)
353ecb22a29SZhirun Yan {
354ecb22a29SZhirun Yan 	struct graph *graph;
355ecb22a29SZhirun Yan 
356d5c8b6bbSRobin Jarry 	if (graph_from_id(id) == NULL)
357d5c8b6bbSRobin Jarry 		goto fail;
358ecb22a29SZhirun Yan 	STAILQ_FOREACH(graph, &graph_list, next)
359ecb22a29SZhirun Yan 		if (graph->id == id)
360ecb22a29SZhirun Yan 			break;
361ecb22a29SZhirun Yan 
362ecb22a29SZhirun Yan 	graph->lcore_id = RTE_MAX_LCORE;
363e6c67c9eSZhirun Yan 	graph->graph->dispatch.lcore_id = RTE_MAX_LCORE;
364ecb22a29SZhirun Yan 
365ecb22a29SZhirun Yan fail:
366ecb22a29SZhirun Yan 	return;
367ecb22a29SZhirun Yan }
368ecb22a29SZhirun Yan 
36999a2dd95SBruce Richardson struct rte_graph *
37099a2dd95SBruce Richardson rte_graph_lookup(const char *name)
37199a2dd95SBruce Richardson {
37299a2dd95SBruce Richardson 	const struct rte_memzone *mz;
37399a2dd95SBruce Richardson 	struct rte_graph *rc = NULL;
37499a2dd95SBruce Richardson 
37599a2dd95SBruce Richardson 	mz = rte_memzone_lookup(name);
37699a2dd95SBruce Richardson 	if (mz)
37799a2dd95SBruce Richardson 		rc = mz->addr;
37899a2dd95SBruce Richardson 
37999a2dd95SBruce Richardson 	return graph_mem_fixup_secondary(rc);
38099a2dd95SBruce Richardson }
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson rte_graph_t
38399a2dd95SBruce Richardson rte_graph_create(const char *name, struct rte_graph_param *prm)
38499a2dd95SBruce Richardson {
38599a2dd95SBruce Richardson 	rte_node_t src_node_count;
38699a2dd95SBruce Richardson 	struct graph *graph;
38799a2dd95SBruce Richardson 	const char *pattern;
38899a2dd95SBruce Richardson 	uint16_t i;
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson 	graph_spinlock_lock();
39199a2dd95SBruce Richardson 
39299a2dd95SBruce Richardson 	/* Check arguments sanity */
39399a2dd95SBruce Richardson 	if (prm == NULL)
39499a2dd95SBruce Richardson 		SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
39599a2dd95SBruce Richardson 
39699a2dd95SBruce Richardson 	if (name == NULL)
39799a2dd95SBruce Richardson 		SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
39899a2dd95SBruce Richardson 
39999a2dd95SBruce Richardson 	/* Check for existence of duplicate graph */
40099a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
40199a2dd95SBruce Richardson 		if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
40299a2dd95SBruce Richardson 			SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
40399a2dd95SBruce Richardson 				    name);
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson 	/* Create graph object */
40699a2dd95SBruce Richardson 	graph = calloc(1, sizeof(*graph));
40799a2dd95SBruce Richardson 	if (graph == NULL)
40899a2dd95SBruce Richardson 		SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
40999a2dd95SBruce Richardson 
41099a2dd95SBruce Richardson 	/* Initialize the graph object */
41199a2dd95SBruce Richardson 	STAILQ_INIT(&graph->node_list);
41299a2dd95SBruce Richardson 	if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
41399a2dd95SBruce Richardson 		SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
41499a2dd95SBruce Richardson 
41599a2dd95SBruce Richardson 	/* Expand node pattern and add the nodes to the graph */
41699a2dd95SBruce Richardson 	for (i = 0; i < prm->nb_node_patterns; i++) {
41799a2dd95SBruce Richardson 		pattern = prm->node_patterns[i];
41899a2dd95SBruce Richardson 		if (expand_pattern_to_node(graph, pattern))
41999a2dd95SBruce Richardson 			goto graph_cleanup;
42099a2dd95SBruce Richardson 	}
42199a2dd95SBruce Richardson 
42299a2dd95SBruce Richardson 	/* Go over all the nodes edges and add them to the graph */
42399a2dd95SBruce Richardson 	if (graph_node_edges_add(graph))
42499a2dd95SBruce Richardson 		goto graph_cleanup;
42599a2dd95SBruce Richardson 
42699a2dd95SBruce Richardson 	/* Update adjacency list of all nodes in the graph */
42799a2dd95SBruce Richardson 	if (graph_adjacency_list_update(graph))
42899a2dd95SBruce Richardson 		goto graph_cleanup;
42999a2dd95SBruce Richardson 
43099a2dd95SBruce Richardson 	/* Make sure at least a source node present in the graph */
43199a2dd95SBruce Richardson 	src_node_count = graph_src_nodes_count(graph);
43299a2dd95SBruce Richardson 	if (src_node_count == 0)
43399a2dd95SBruce Richardson 		goto graph_cleanup;
43499a2dd95SBruce Richardson 
43599a2dd95SBruce Richardson 	/* Make sure no node is pointing to source node */
43699a2dd95SBruce Richardson 	if (graph_node_has_edge_to_src_node(graph))
43799a2dd95SBruce Richardson 		goto graph_cleanup;
43899a2dd95SBruce Richardson 
43999a2dd95SBruce Richardson 	/* Don't allow node has loop to self */
44099a2dd95SBruce Richardson 	if (graph_node_has_loop_edge(graph))
44199a2dd95SBruce Richardson 		goto graph_cleanup;
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson 	/* Do BFS from src nodes on the graph to find isolated nodes */
44499a2dd95SBruce Richardson 	if (graph_has_isolated_node(graph))
44599a2dd95SBruce Richardson 		goto graph_cleanup;
44699a2dd95SBruce Richardson 
4479b72ea1fSAmit Prakash Shukla 	/* Initialize pcap config. */
4489b72ea1fSAmit Prakash Shukla 	graph_pcap_enable(prm->pcap_enable);
4499b72ea1fSAmit Prakash Shukla 
45099a2dd95SBruce Richardson 	/* Initialize graph object */
45199a2dd95SBruce Richardson 	graph->socket = prm->socket_id;
45299a2dd95SBruce Richardson 	graph->src_node_count = src_node_count;
45399a2dd95SBruce Richardson 	graph->node_count = graph_nodes_count(graph);
454d5c8b6bbSRobin Jarry 	graph->id = graph_next_free_id();
455d6e2e9d8SZhirun Yan 	graph->parent_id = RTE_GRAPH_ID_INVALID;
456ecb22a29SZhirun Yan 	graph->lcore_id = RTE_MAX_LCORE;
4579b72ea1fSAmit Prakash Shukla 	graph->num_pkt_to_capture = prm->num_pkt_to_capture;
4589b72ea1fSAmit Prakash Shukla 	if (prm->pcap_filename)
4599b72ea1fSAmit Prakash Shukla 		rte_strscpy(graph->pcap_filename, prm->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ);
46099a2dd95SBruce Richardson 
46199a2dd95SBruce Richardson 	/* Allocate the Graph fast path memory and populate the data */
46299a2dd95SBruce Richardson 	if (graph_fp_mem_create(graph))
46399a2dd95SBruce Richardson 		goto graph_cleanup;
46499a2dd95SBruce Richardson 
46599a2dd95SBruce Richardson 	/* Call init() of the all the nodes in the graph */
46699a2dd95SBruce Richardson 	if (graph_node_init(graph))
46799a2dd95SBruce Richardson 		goto graph_mem_destroy;
46899a2dd95SBruce Richardson 
46999a2dd95SBruce Richardson 	/* All good, Lets add the graph to the list */
470d5c8b6bbSRobin Jarry 	graph_insert_ordered(graph);
47199a2dd95SBruce Richardson 
47299a2dd95SBruce Richardson 	graph_spinlock_unlock();
47399a2dd95SBruce Richardson 	return graph->id;
47499a2dd95SBruce Richardson 
47599a2dd95SBruce Richardson graph_mem_destroy:
47699a2dd95SBruce Richardson 	graph_fp_mem_destroy(graph);
47799a2dd95SBruce Richardson graph_cleanup:
47899a2dd95SBruce Richardson 	graph_cleanup(graph);
47999a2dd95SBruce Richardson free:
48099a2dd95SBruce Richardson 	free(graph);
48199a2dd95SBruce Richardson fail:
48299a2dd95SBruce Richardson 	graph_spinlock_unlock();
48399a2dd95SBruce Richardson 	return RTE_GRAPH_ID_INVALID;
48499a2dd95SBruce Richardson }
48599a2dd95SBruce Richardson 
48699a2dd95SBruce Richardson int
48799a2dd95SBruce Richardson rte_graph_destroy(rte_graph_t id)
48899a2dd95SBruce Richardson {
48999a2dd95SBruce Richardson 	struct graph *graph, *tmp;
49099a2dd95SBruce Richardson 	int rc = -ENOENT;
49199a2dd95SBruce Richardson 
49299a2dd95SBruce Richardson 	graph_spinlock_lock();
49399a2dd95SBruce Richardson 
49499a2dd95SBruce Richardson 	graph = STAILQ_FIRST(&graph_list);
49599a2dd95SBruce Richardson 	while (graph != NULL) {
49699a2dd95SBruce Richardson 		tmp = STAILQ_NEXT(graph, next);
49799a2dd95SBruce Richardson 		if (graph->id == id) {
498e7728f6dSZhirun Yan 			/* Destroy the schedule work queue if has */
499e7728f6dSZhirun Yan 			if (rte_graph_worker_model_get(graph->graph) ==
500e7728f6dSZhirun Yan 			    RTE_GRAPH_MODEL_MCORE_DISPATCH)
501e7728f6dSZhirun Yan 				graph_sched_wq_destroy(graph);
502e7728f6dSZhirun Yan 
50399a2dd95SBruce Richardson 			/* Call fini() of the all the nodes in the graph */
50499a2dd95SBruce Richardson 			graph_node_fini(graph);
50599a2dd95SBruce Richardson 			/* Destroy graph fast path memory */
50699a2dd95SBruce Richardson 			rc = graph_fp_mem_destroy(graph);
50799a2dd95SBruce Richardson 			if (rc)
50899a2dd95SBruce Richardson 				SET_ERR_JMP(rc, done, "Graph %s destroy failed",
50999a2dd95SBruce Richardson 					    graph->name);
51099a2dd95SBruce Richardson 
51199a2dd95SBruce Richardson 			graph_cleanup(graph);
51299a2dd95SBruce Richardson 			STAILQ_REMOVE(&graph_list, graph, graph, next);
51399a2dd95SBruce Richardson 			free(graph);
51499a2dd95SBruce Richardson 			goto done;
51599a2dd95SBruce Richardson 		}
51699a2dd95SBruce Richardson 		graph = tmp;
51799a2dd95SBruce Richardson 	}
51899a2dd95SBruce Richardson done:
51999a2dd95SBruce Richardson 	graph_spinlock_unlock();
52099a2dd95SBruce Richardson 	return rc;
52199a2dd95SBruce Richardson }
52299a2dd95SBruce Richardson 
523d6e2e9d8SZhirun Yan static rte_graph_t
5241e2aed1aSZhirun Yan graph_clone(struct graph *parent_graph, const char *name, struct rte_graph_param *prm)
525d6e2e9d8SZhirun Yan {
526d6e2e9d8SZhirun Yan 	struct graph_node *graph_node;
527d6e2e9d8SZhirun Yan 	struct graph *graph;
528d6e2e9d8SZhirun Yan 
529d6e2e9d8SZhirun Yan 	graph_spinlock_lock();
530d6e2e9d8SZhirun Yan 
531d6e2e9d8SZhirun Yan 	/* Don't allow to clone a node from a cloned graph */
532d6e2e9d8SZhirun Yan 	if (parent_graph->parent_id != RTE_GRAPH_ID_INVALID)
533d6e2e9d8SZhirun Yan 		SET_ERR_JMP(EEXIST, fail, "A cloned graph is not allowed to be cloned");
534d6e2e9d8SZhirun Yan 
535d6e2e9d8SZhirun Yan 	/* Create graph object */
536d6e2e9d8SZhirun Yan 	graph = calloc(1, sizeof(*graph));
537d6e2e9d8SZhirun Yan 	if (graph == NULL)
538d6e2e9d8SZhirun Yan 		SET_ERR_JMP(ENOMEM, fail, "Failed to calloc cloned graph object");
539d6e2e9d8SZhirun Yan 
540d6e2e9d8SZhirun Yan 	/* Naming ceremony of the new graph. name is node->name + "-" + name */
541d6e2e9d8SZhirun Yan 	if (clone_name(graph->name, parent_graph->name, name))
542d6e2e9d8SZhirun Yan 		goto free;
543d6e2e9d8SZhirun Yan 
544d6e2e9d8SZhirun Yan 	/* Check for existence of duplicate graph */
545d6e2e9d8SZhirun Yan 	if (rte_graph_from_name(graph->name) != RTE_GRAPH_ID_INVALID)
546d6e2e9d8SZhirun Yan 		SET_ERR_JMP(EEXIST, free, "Found duplicate graph %s",
547d6e2e9d8SZhirun Yan 			    graph->name);
548d6e2e9d8SZhirun Yan 
549d6e2e9d8SZhirun Yan 	/* Clone nodes from parent graph firstly */
550d6e2e9d8SZhirun Yan 	STAILQ_INIT(&graph->node_list);
551d6e2e9d8SZhirun Yan 	STAILQ_FOREACH(graph_node, &parent_graph->node_list, next) {
552d6e2e9d8SZhirun Yan 		if (graph_node_add(graph, graph_node->node))
553d6e2e9d8SZhirun Yan 			goto graph_cleanup;
554d6e2e9d8SZhirun Yan 	}
555d6e2e9d8SZhirun Yan 
556d6e2e9d8SZhirun Yan 	/* Just update adjacency list of all nodes in the graph */
557d6e2e9d8SZhirun Yan 	if (graph_adjacency_list_update(graph))
558d6e2e9d8SZhirun Yan 		goto graph_cleanup;
559d6e2e9d8SZhirun Yan 
560d6e2e9d8SZhirun Yan 	/* Initialize the graph object */
561d6e2e9d8SZhirun Yan 	graph->src_node_count = parent_graph->src_node_count;
562d6e2e9d8SZhirun Yan 	graph->node_count = parent_graph->node_count;
563d6e2e9d8SZhirun Yan 	graph->parent_id = parent_graph->id;
564d6e2e9d8SZhirun Yan 	graph->lcore_id = parent_graph->lcore_id;
565d6e2e9d8SZhirun Yan 	graph->socket = parent_graph->socket;
566d5c8b6bbSRobin Jarry 	graph->id = graph_next_free_id();
567d6e2e9d8SZhirun Yan 
568d6e2e9d8SZhirun Yan 	/* Allocate the Graph fast path memory and populate the data */
569d6e2e9d8SZhirun Yan 	if (graph_fp_mem_create(graph))
570d6e2e9d8SZhirun Yan 		goto graph_cleanup;
571d6e2e9d8SZhirun Yan 
572d6e2e9d8SZhirun Yan 	/* Clone the graph model */
573d6e2e9d8SZhirun Yan 	graph->graph->model = parent_graph->graph->model;
574d6e2e9d8SZhirun Yan 
575e7728f6dSZhirun Yan 	/* Create the graph schedule work queue */
576e7728f6dSZhirun Yan 	if (rte_graph_worker_model_get(graph->graph) == RTE_GRAPH_MODEL_MCORE_DISPATCH &&
577e7728f6dSZhirun Yan 	    graph_sched_wq_create(graph, parent_graph, prm))
578e7728f6dSZhirun Yan 		goto graph_mem_destroy;
579e7728f6dSZhirun Yan 
580d6e2e9d8SZhirun Yan 	/* Call init() of the all the nodes in the graph */
581d6e2e9d8SZhirun Yan 	if (graph_node_init(graph))
582d6e2e9d8SZhirun Yan 		goto graph_mem_destroy;
583d6e2e9d8SZhirun Yan 
584d6e2e9d8SZhirun Yan 	/* All good, Lets add the graph to the list */
585d5c8b6bbSRobin Jarry 	graph_insert_ordered(graph);
586d6e2e9d8SZhirun Yan 
587d6e2e9d8SZhirun Yan 	graph_spinlock_unlock();
588d6e2e9d8SZhirun Yan 	return graph->id;
589d6e2e9d8SZhirun Yan 
590d6e2e9d8SZhirun Yan graph_mem_destroy:
591d6e2e9d8SZhirun Yan 	graph_fp_mem_destroy(graph);
592d6e2e9d8SZhirun Yan graph_cleanup:
593d6e2e9d8SZhirun Yan 	graph_cleanup(graph);
594d6e2e9d8SZhirun Yan free:
595d6e2e9d8SZhirun Yan 	free(graph);
596d6e2e9d8SZhirun Yan fail:
597d6e2e9d8SZhirun Yan 	graph_spinlock_unlock();
598d6e2e9d8SZhirun Yan 	return RTE_GRAPH_ID_INVALID;
599d6e2e9d8SZhirun Yan }
600d6e2e9d8SZhirun Yan 
601d6e2e9d8SZhirun Yan rte_graph_t
6021e2aed1aSZhirun Yan rte_graph_clone(rte_graph_t id, const char *name, struct rte_graph_param *prm)
603d6e2e9d8SZhirun Yan {
604d6e2e9d8SZhirun Yan 	struct graph *graph;
605d6e2e9d8SZhirun Yan 
606d5c8b6bbSRobin Jarry 	if (graph_from_id(id) == NULL)
607d5c8b6bbSRobin Jarry 		goto fail;
608d6e2e9d8SZhirun Yan 	STAILQ_FOREACH(graph, &graph_list, next)
609d6e2e9d8SZhirun Yan 		if (graph->id == id)
6101e2aed1aSZhirun Yan 			return graph_clone(graph, name, prm);
611d6e2e9d8SZhirun Yan 
612d6e2e9d8SZhirun Yan fail:
613d6e2e9d8SZhirun Yan 	return RTE_GRAPH_ID_INVALID;
614d6e2e9d8SZhirun Yan }
615d6e2e9d8SZhirun Yan 
61699a2dd95SBruce Richardson rte_graph_t
61799a2dd95SBruce Richardson rte_graph_from_name(const char *name)
61899a2dd95SBruce Richardson {
61999a2dd95SBruce Richardson 	struct graph *graph;
62099a2dd95SBruce Richardson 
62199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
62299a2dd95SBruce Richardson 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
62399a2dd95SBruce Richardson 			return graph->id;
62499a2dd95SBruce Richardson 
62599a2dd95SBruce Richardson 	return RTE_GRAPH_ID_INVALID;
62699a2dd95SBruce Richardson }
62799a2dd95SBruce Richardson 
62899a2dd95SBruce Richardson char *
62999a2dd95SBruce Richardson rte_graph_id_to_name(rte_graph_t id)
63099a2dd95SBruce Richardson {
63199a2dd95SBruce Richardson 	struct graph *graph;
63299a2dd95SBruce Richardson 
633d5c8b6bbSRobin Jarry 	if (graph_from_id(id) == NULL)
634d5c8b6bbSRobin Jarry 		goto fail;
63599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
63699a2dd95SBruce Richardson 		if (graph->id == id)
63799a2dd95SBruce Richardson 			return graph->name;
63899a2dd95SBruce Richardson 
63999a2dd95SBruce Richardson fail:
64099a2dd95SBruce Richardson 	return NULL;
64199a2dd95SBruce Richardson }
64299a2dd95SBruce Richardson 
64399a2dd95SBruce Richardson struct rte_node *
64499a2dd95SBruce Richardson rte_graph_node_get(rte_graph_t gid, uint32_t nid)
64599a2dd95SBruce Richardson {
64699a2dd95SBruce Richardson 	struct rte_node *node;
64799a2dd95SBruce Richardson 	struct graph *graph;
64899a2dd95SBruce Richardson 	rte_graph_off_t off;
64999a2dd95SBruce Richardson 	rte_node_t count;
65099a2dd95SBruce Richardson 
651d5c8b6bbSRobin Jarry 	if (graph_from_id(gid) == NULL)
652d5c8b6bbSRobin Jarry 		goto fail;
65399a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
65499a2dd95SBruce Richardson 		if (graph->id == gid) {
65599a2dd95SBruce Richardson 			rte_graph_foreach_node(count, off, graph->graph,
65699a2dd95SBruce Richardson 						node) {
65799a2dd95SBruce Richardson 				if (node->id == nid)
65899a2dd95SBruce Richardson 					return node;
65999a2dd95SBruce Richardson 			}
66099a2dd95SBruce Richardson 			break;
66199a2dd95SBruce Richardson 		}
66299a2dd95SBruce Richardson fail:
66399a2dd95SBruce Richardson 	return NULL;
66499a2dd95SBruce Richardson }
66599a2dd95SBruce Richardson 
66699a2dd95SBruce Richardson struct rte_node *
66799a2dd95SBruce Richardson rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
66899a2dd95SBruce Richardson {
66999a2dd95SBruce Richardson 	struct rte_node *node;
67099a2dd95SBruce Richardson 	struct graph *graph;
67199a2dd95SBruce Richardson 	rte_graph_off_t off;
67299a2dd95SBruce Richardson 	rte_node_t count;
67399a2dd95SBruce Richardson 
67499a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next)
67599a2dd95SBruce Richardson 		if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
67699a2dd95SBruce Richardson 			rte_graph_foreach_node(count, off, graph->graph,
67799a2dd95SBruce Richardson 						node) {
67899a2dd95SBruce Richardson 				if (!strncmp(node->name, node_name,
67999a2dd95SBruce Richardson 					     RTE_NODE_NAMESIZE))
68099a2dd95SBruce Richardson 					return node;
68199a2dd95SBruce Richardson 			}
68299a2dd95SBruce Richardson 			break;
68399a2dd95SBruce Richardson 		}
68499a2dd95SBruce Richardson 
68599a2dd95SBruce Richardson 	return NULL;
68699a2dd95SBruce Richardson }
68799a2dd95SBruce Richardson 
68899a2dd95SBruce Richardson void __rte_noinline
68999a2dd95SBruce Richardson __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
69099a2dd95SBruce Richardson {
69199a2dd95SBruce Richardson 	uint16_t size = node->size;
69299a2dd95SBruce Richardson 
69399a2dd95SBruce Richardson 	RTE_VERIFY(size != UINT16_MAX);
69499a2dd95SBruce Richardson 	/* Allocate double amount of size to avoid immediate realloc */
69599a2dd95SBruce Richardson 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
69699a2dd95SBruce Richardson 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
69799a2dd95SBruce Richardson 					RTE_CACHE_LINE_SIZE, graph->socket);
69899a2dd95SBruce Richardson 	RTE_VERIFY(node->objs);
69999a2dd95SBruce Richardson 	node->size = size;
70099a2dd95SBruce Richardson 	node->realloc_count++;
70199a2dd95SBruce Richardson }
70299a2dd95SBruce Richardson 
70399a2dd95SBruce Richardson void __rte_noinline
70499a2dd95SBruce Richardson __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
70599a2dd95SBruce Richardson 			     uint16_t req_size)
70699a2dd95SBruce Richardson {
70799a2dd95SBruce Richardson 	uint16_t size = node->size;
70899a2dd95SBruce Richardson 
70999a2dd95SBruce Richardson 	RTE_VERIFY(size != UINT16_MAX);
71099a2dd95SBruce Richardson 	/* Allocate double amount of size to avoid immediate realloc */
71199a2dd95SBruce Richardson 	size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
71299a2dd95SBruce Richardson 	node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
71399a2dd95SBruce Richardson 					RTE_CACHE_LINE_SIZE, graph->socket);
71499a2dd95SBruce Richardson 	RTE_VERIFY(node->objs);
71599a2dd95SBruce Richardson 	node->size = size;
71699a2dd95SBruce Richardson 	node->realloc_count++;
71799a2dd95SBruce Richardson }
71899a2dd95SBruce Richardson 
71999a2dd95SBruce Richardson static int
72099a2dd95SBruce Richardson graph_to_dot(FILE *f, struct graph *graph)
72199a2dd95SBruce Richardson {
72299a2dd95SBruce Richardson 	struct graph_node *graph_node;
72399a2dd95SBruce Richardson 	char *node_name;
72499a2dd95SBruce Richardson 	rte_edge_t i;
72599a2dd95SBruce Richardson 	int rc;
72699a2dd95SBruce Richardson 
727cd764142SRobin Jarry 	rc = fprintf(f, "digraph \"%s\" {\n\trankdir=LR;\n", graph->name);
728cd764142SRobin Jarry 	if (rc < 0)
729cd764142SRobin Jarry 		goto end;
730cd764142SRobin Jarry 
731cd764142SRobin Jarry 	rc = fprintf(f, "\tnode [margin=0.02 fontsize=11 fontname=sans];\n");
73299a2dd95SBruce Richardson 	if (rc < 0)
73399a2dd95SBruce Richardson 		goto end;
73499a2dd95SBruce Richardson 
73599a2dd95SBruce Richardson 	STAILQ_FOREACH(graph_node, &graph->node_list, next) {
736cd764142SRobin Jarry 		const char *attrs = "";
73799a2dd95SBruce Richardson 		node_name = graph_node->node->name;
738cd764142SRobin Jarry 
739cd764142SRobin Jarry 		rc = fprintf(f, "\t\"%s\"", node_name);
740cd764142SRobin Jarry 		if (rc < 0)
741cd764142SRobin Jarry 			goto end;
742cd764142SRobin Jarry 		if (graph_node->node->flags & RTE_NODE_SOURCE_F) {
743cd764142SRobin Jarry 			attrs = " [color=blue style=bold]";
744cd764142SRobin Jarry 			rc = fprintf(f, "%s", attrs);
745cd764142SRobin Jarry 			if (rc < 0)
746cd764142SRobin Jarry 				goto end;
747cd764142SRobin Jarry 		} else if (graph_node->node->nb_edges == 0) {
748*5b8d861cSRobin Jarry 			rc = fprintf(f, " [fontcolor=darkorange shape=plain]");
749cd764142SRobin Jarry 			if (rc < 0)
750cd764142SRobin Jarry 				goto end;
751cd764142SRobin Jarry 		}
752cd764142SRobin Jarry 		rc = fprintf(f, ";\n");
753cd764142SRobin Jarry 		if (rc < 0)
754cd764142SRobin Jarry 			goto end;
75599a2dd95SBruce Richardson 		for (i = 0; i < graph_node->node->nb_edges; i++) {
756*5b8d861cSRobin Jarry 			const char *node_attrs = attrs;
757*5b8d861cSRobin Jarry 			if (graph_node->adjacency_list[i]->node->nb_edges == 0)
758*5b8d861cSRobin Jarry 				node_attrs = " [color=darkorange]";
759cd764142SRobin Jarry 			rc = fprintf(f, "\t\"%s\" -> \"%s\"%s;\n", node_name,
76099a2dd95SBruce Richardson 				     graph_node->adjacency_list[i]->node->name,
761*5b8d861cSRobin Jarry 				     node_attrs);
76299a2dd95SBruce Richardson 			if (rc < 0)
76399a2dd95SBruce Richardson 				goto end;
76499a2dd95SBruce Richardson 		}
76599a2dd95SBruce Richardson 	}
76699a2dd95SBruce Richardson 	rc = fprintf(f, "}\n");
76799a2dd95SBruce Richardson 	if (rc < 0)
76899a2dd95SBruce Richardson 		goto end;
76999a2dd95SBruce Richardson 
77099a2dd95SBruce Richardson 	return 0;
77199a2dd95SBruce Richardson end:
77299a2dd95SBruce Richardson 	rte_errno = EBADF;
77399a2dd95SBruce Richardson 	return -rte_errno;
77499a2dd95SBruce Richardson }
77599a2dd95SBruce Richardson 
77699a2dd95SBruce Richardson int
77799a2dd95SBruce Richardson rte_graph_export(const char *name, FILE *f)
77899a2dd95SBruce Richardson {
77999a2dd95SBruce Richardson 	struct graph *graph;
78099a2dd95SBruce Richardson 	int rc = ENOENT;
78199a2dd95SBruce Richardson 
78299a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next) {
78399a2dd95SBruce Richardson 		if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
78499a2dd95SBruce Richardson 			rc = graph_to_dot(f, graph);
78599a2dd95SBruce Richardson 			goto end;
78699a2dd95SBruce Richardson 		}
78799a2dd95SBruce Richardson 	}
78899a2dd95SBruce Richardson end:
78999a2dd95SBruce Richardson 	return -rc;
79099a2dd95SBruce Richardson }
79199a2dd95SBruce Richardson 
79299a2dd95SBruce Richardson static void
79399a2dd95SBruce Richardson graph_scan_dump(FILE *f, rte_graph_t id, bool all)
79499a2dd95SBruce Richardson {
79599a2dd95SBruce Richardson 	struct graph *graph;
79699a2dd95SBruce Richardson 
79799a2dd95SBruce Richardson 	RTE_VERIFY(f);
798d5c8b6bbSRobin Jarry 	if (graph_from_id(id) == NULL)
799d5c8b6bbSRobin Jarry 		goto fail;
80099a2dd95SBruce Richardson 
80199a2dd95SBruce Richardson 	STAILQ_FOREACH(graph, &graph_list, next) {
80299a2dd95SBruce Richardson 		if (all == true) {
80399a2dd95SBruce Richardson 			graph_dump(f, graph);
80499a2dd95SBruce Richardson 		} else if (graph->id == id) {
80599a2dd95SBruce Richardson 			graph_dump(f, graph);
80699a2dd95SBruce Richardson 			return;
80799a2dd95SBruce Richardson 		}
80899a2dd95SBruce Richardson 	}
80999a2dd95SBruce Richardson fail:
81099a2dd95SBruce Richardson 	return;
81199a2dd95SBruce Richardson }
81299a2dd95SBruce Richardson 
81399a2dd95SBruce Richardson void
81499a2dd95SBruce Richardson rte_graph_dump(FILE *f, rte_graph_t id)
81599a2dd95SBruce Richardson {
81699a2dd95SBruce Richardson 	graph_scan_dump(f, id, false);
81799a2dd95SBruce Richardson }
81899a2dd95SBruce Richardson 
81999a2dd95SBruce Richardson void
82099a2dd95SBruce Richardson rte_graph_list_dump(FILE *f)
82199a2dd95SBruce Richardson {
82299a2dd95SBruce Richardson 	graph_scan_dump(f, 0, true);
82399a2dd95SBruce Richardson }
82499a2dd95SBruce Richardson 
82599a2dd95SBruce Richardson rte_graph_t
82699a2dd95SBruce Richardson rte_graph_max_count(void)
82799a2dd95SBruce Richardson {
828d5c8b6bbSRobin Jarry 	struct graph *graph;
829d5c8b6bbSRobin Jarry 	rte_graph_t count = 0;
830d5c8b6bbSRobin Jarry 
831d5c8b6bbSRobin Jarry 	STAILQ_FOREACH(graph, &graph_list, next)
832d5c8b6bbSRobin Jarry 		count++;
833d5c8b6bbSRobin Jarry 
834d5c8b6bbSRobin Jarry 	return count;
83599a2dd95SBruce Richardson }
83699a2dd95SBruce Richardson 
837eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(rte_graph_logtype, INFO);
838