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