Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2020 Marvell International Ltd.
3 : : */
4 : :
5 : : #include <fnmatch.h>
6 : : #include <stdbool.h>
7 : : #include <stdlib.h>
8 : :
9 : : #include <rte_common.h>
10 : : #include <rte_debug.h>
11 : : #include <rte_errno.h>
12 : : #include <rte_malloc.h>
13 : : #include <rte_memzone.h>
14 : : #include <rte_spinlock.h>
15 : : #include <rte_string_fns.h>
16 : :
17 : : #include "graph_private.h"
18 : : #include "graph_pcap_private.h"
19 : :
20 : : static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list);
21 : : static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER;
22 : :
23 : : /* Private functions */
24 : : static struct graph *
25 : : graph_from_id(rte_graph_t id)
26 : : {
27 : : struct graph *graph;
28 [ - - + - : 18 : STAILQ_FOREACH(graph, &graph_list, next) {
+ - + - +
- + - ]
29 [ - - + + : 18 : if (graph->id == id)
+ + + + +
+ + + ]
30 : : return graph;
31 : : }
32 : 0 : rte_errno = EINVAL;
33 : : return NULL;
34 : : }
35 : :
36 : : static rte_graph_t
37 : : graph_next_free_id(void)
38 : : {
39 : : struct graph *graph;
40 : : rte_graph_t id = 0;
41 : :
42 [ + + + + ]: 26 : STAILQ_FOREACH(graph, &graph_list, next) {
43 [ + - + + ]: 17 : if (id < graph->id)
44 : : break;
45 : 16 : id = graph->id + 1;
46 : : }
47 : :
48 : : return id;
49 : : }
50 : :
51 : : static void
52 : 10 : graph_insert_ordered(struct graph *graph)
53 : : {
54 : : struct graph *after, *g;
55 : :
56 : : after = NULL;
57 [ + + ]: 26 : STAILQ_FOREACH(g, &graph_list, next) {
58 [ + + ]: 17 : if (g->id < graph->id)
59 : : after = g;
60 [ - + ]: 1 : else if (g->id > graph->id)
61 : : break;
62 : : }
63 [ + + ]: 10 : if (after == NULL) {
64 [ + - ]: 1 : STAILQ_INSERT_HEAD(&graph_list, graph, next);
65 : : } else {
66 [ + + ]: 9 : STAILQ_INSERT_AFTER(&graph_list, after, graph, next);
67 : : }
68 : 10 : }
69 : :
70 : : struct graph_head *
71 : 3 : graph_list_head_get(void)
72 : : {
73 : 3 : return &graph_list;
74 : : }
75 : :
76 : : rte_spinlock_t *
77 : 10164 : graph_spinlock_get(void)
78 : : {
79 : 10164 : return &graph_lock;
80 : : }
81 : :
82 : : void
83 : 5082 : graph_spinlock_lock(void)
84 : : {
85 : 5082 : rte_spinlock_lock(graph_spinlock_get());
86 : 5082 : }
87 : :
88 : : void
89 : 5082 : graph_spinlock_unlock(void)
90 : : {
91 : 5082 : rte_spinlock_unlock(graph_spinlock_get());
92 : 5082 : }
93 : :
94 : : static int
95 : 88 : graph_node_add(struct graph *graph, struct node *node)
96 : : {
97 : : struct graph_node *graph_node;
98 : : size_t sz;
99 : :
100 : : /* Skip the duplicate nodes */
101 [ + + ]: 268 : STAILQ_FOREACH(graph_node, &graph->node_list, next)
102 [ + + ]: 212 : if (strncmp(node->name, graph_node->node->name,
103 : : RTE_NODE_NAMESIZE) == 0)
104 : : return 0;
105 : :
106 : : /* Allocate new graph node object */
107 : 56 : sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *);
108 : 56 : graph_node = calloc(1, sz);
109 : :
110 [ - + ]: 56 : if (graph_node == NULL)
111 : 0 : SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object",
112 : : node->name);
113 : :
114 : : /* Initialize the graph node */
115 : 56 : graph_node->node = node;
116 : :
117 : : /* Add to graph node list */
118 : 56 : STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next);
119 : 56 : return 0;
120 : :
121 : : free:
122 : : free(graph_node);
123 : 0 : return -rte_errno;
124 : : }
125 : :
126 : : static struct graph_node *
127 : 79 : node_to_graph_node(struct graph *graph, struct node *node)
128 : : {
129 : : struct graph_node *graph_node;
130 : :
131 [ + - ]: 260 : STAILQ_FOREACH(graph_node, &graph->node_list, next)
132 [ + + ]: 260 : if (graph_node->node == node)
133 : 79 : return graph_node;
134 : :
135 : 0 : SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name);
136 : : fail:
137 : 0 : return NULL;
138 : : }
139 : :
140 : : static int
141 : 6 : graph_node_edges_add(struct graph *graph)
142 : : {
143 : : struct graph_node *graph_node;
144 : : struct node *adjacency;
145 : : const char *next;
146 : : rte_edge_t i;
147 : :
148 [ + + ]: 37 : STAILQ_FOREACH(graph_node, &graph->node_list, next) {
149 [ + + ]: 75 : for (i = 0; i < graph_node->node->nb_edges; i++) {
150 : 44 : next = graph_node->node->next_nodes[i];
151 : 44 : adjacency = node_from_name(next);
152 [ - + ]: 44 : if (adjacency == NULL)
153 : 0 : SET_ERR_JMP(EINVAL, fail,
154 : : "Node %s not registered", next);
155 [ - + ]: 44 : if (graph_node_add(graph, adjacency))
156 : 0 : goto fail;
157 : : }
158 : : }
159 : : return 0;
160 : 0 : fail:
161 : 0 : return -rte_errno;
162 : : }
163 : :
164 : : static int
165 : 11 : graph_adjacency_list_update(struct graph *graph)
166 : : {
167 : : struct graph_node *graph_node, *tmp;
168 : : struct node *adjacency;
169 : : const char *next;
170 : : rte_edge_t i;
171 : :
172 [ + + ]: 67 : STAILQ_FOREACH(graph_node, &graph->node_list, next) {
173 [ + + ]: 135 : for (i = 0; i < graph_node->node->nb_edges; i++) {
174 : 79 : next = graph_node->node->next_nodes[i];
175 : 79 : adjacency = node_from_name(next);
176 [ - + ]: 79 : if (adjacency == NULL)
177 : 0 : SET_ERR_JMP(EINVAL, fail,
178 : : "Node %s not registered", next);
179 : 79 : tmp = node_to_graph_node(graph, adjacency);
180 [ - + ]: 79 : if (tmp == NULL)
181 : 0 : goto fail;
182 : 79 : graph_node->adjacency_list[i] = tmp;
183 : : }
184 : : }
185 : :
186 : : return 0;
187 : 0 : fail:
188 : 0 : return -rte_errno;
189 : : }
190 : :
191 : : static int
192 : 19 : expand_pattern_to_node(struct graph *graph, const char *pattern)
193 : : {
194 : 19 : struct node_head *node_head = node_list_head_get();
195 : : bool found = false;
196 : : struct node *node;
197 : :
198 : : /* Check for pattern match */
199 [ + + ]: 494 : STAILQ_FOREACH(node, node_head, next) {
200 [ + + ]: 475 : if (fnmatch(pattern, node->name, 0) == 0) {
201 [ - + ]: 19 : if (graph_node_add(graph, node))
202 : 0 : goto fail;
203 : : found = true;
204 : : }
205 : : }
206 [ - + ]: 19 : if (found == false)
207 : 0 : SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern);
208 : :
209 : : return 0;
210 : 0 : fail:
211 : 0 : return -rte_errno;
212 : : }
213 : :
214 : : static void
215 : : graph_cleanup(struct graph *graph)
216 : : {
217 : : struct graph_node *graph_node;
218 : :
219 [ - - + + : 67 : while (!STAILQ_EMPTY(&graph->node_list)) {
+ + ]
220 : : graph_node = STAILQ_FIRST(&graph->node_list);
221 [ - - + + : 56 : STAILQ_REMOVE_HEAD(&graph->node_list, next);
+ + ]
222 : 56 : free(graph_node);
223 : : }
224 : : }
225 : :
226 : : static int
227 : 10 : graph_node_init(struct graph *graph)
228 : : {
229 : : struct graph_node *graph_node;
230 : : const char *name;
231 : : int rc;
232 : :
233 [ + + ]: 60 : STAILQ_FOREACH(graph_node, &graph->node_list, next) {
234 [ + - ]: 50 : if (graph_node->node->init) {
235 : 50 : name = graph_node->node->name;
236 : 100 : rc = graph_node->node->init(
237 : 50 : graph->graph,
238 : 50 : graph_node_name_to_ptr(graph->graph, name));
239 [ - + ]: 50 : if (rc)
240 : 0 : SET_ERR_JMP(rc, err, "Node %s init() failed",
241 : : name);
242 : : }
243 : : }
244 : :
245 : : return 0;
246 : : err:
247 : 0 : return -rte_errno;
248 : : }
249 : :
250 : : static void
251 : 10 : graph_node_fini(struct graph *graph)
252 : : {
253 : : struct graph_node *graph_node;
254 : :
255 [ + + ]: 60 : STAILQ_FOREACH(graph_node, &graph->node_list, next)
256 [ - + ]: 50 : if (graph_node->node->fini)
257 : 0 : graph_node->node->fini(
258 : 0 : graph->graph,
259 : 0 : graph_node_name_to_ptr(graph->graph,
260 : 0 : graph_node->node->name));
261 : 10 : }
262 : :
263 : : static struct rte_graph *
264 : 0 : graph_mem_fixup_node_ctx(struct rte_graph *graph)
265 : : {
266 : : struct rte_node *node;
267 : : struct node *node_db;
268 : : rte_graph_off_t off;
269 : : rte_node_t count;
270 : : const char *name;
271 : :
272 [ # # ]: 0 : rte_graph_foreach_node(count, off, graph, node) {
273 [ # # ]: 0 : if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
274 : 0 : name = node->name;
275 : : else /* Cloned node */
276 : 0 : name = node->parent;
277 : :
278 : 0 : node_db = node_from_name(name);
279 [ # # ]: 0 : if (node_db == NULL)
280 : 0 : SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
281 : :
282 [ # # ]: 0 : if (graph->pcap_enable) {
283 : 0 : node->process = graph_pcap_dispatch;
284 : 0 : node->original_process = node_db->process;
285 : : } else
286 : 0 : node->process = node_db->process;
287 : : }
288 : :
289 : : return graph;
290 : : fail:
291 : 0 : return NULL;
292 : : }
293 : :
294 : : static struct rte_graph *
295 : 3 : graph_mem_fixup_secondary(struct rte_graph *graph)
296 : : {
297 [ + - + - ]: 3 : if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
298 : 3 : return graph;
299 : :
300 [ # # # # ]: 0 : if (graph_pcap_file_open(graph->pcap_filename) || graph_pcap_mp_init())
301 : 0 : graph_pcap_exit(graph);
302 : :
303 : 0 : return graph_mem_fixup_node_ctx(graph);
304 : : }
305 : :
306 : : static bool
307 : : graph_src_node_avail(struct graph *graph)
308 : : {
309 : : struct graph_node *graph_node;
310 : :
311 [ + - ]: 1 : STAILQ_FOREACH(graph_node, &graph->node_list, next)
312 [ + - ]: 1 : if ((graph_node->node->flags & RTE_NODE_SOURCE_F) &&
313 [ - + ]: 1 : (graph_node->node->lcore_id == RTE_MAX_LCORE ||
314 [ # # ]: 0 : graph->lcore_id == graph_node->node->lcore_id))
315 : : return true;
316 : :
317 : : return false;
318 : : }
319 : :
320 : : int
321 : 1 : rte_graph_model_mcore_dispatch_core_bind(rte_graph_t id, int lcore)
322 : : {
323 : : struct graph *graph;
324 : :
325 : : if (graph_from_id(id) == NULL)
326 : 0 : goto fail;
327 [ - + ]: 1 : if (!rte_lcore_is_enabled(lcore))
328 : 0 : SET_ERR_JMP(ENOLINK, fail, "lcore %d not enabled", lcore);
329 : :
330 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
331 [ + + ]: 2 : if (graph->id == id)
332 : : break;
333 : :
334 [ - + ]: 1 : if (graph->graph->model != RTE_GRAPH_MODEL_MCORE_DISPATCH)
335 : 0 : goto fail;
336 : :
337 : 1 : graph->lcore_id = lcore;
338 : 1 : graph->graph->dispatch.lcore_id = graph->lcore_id;
339 : 1 : graph->socket = rte_lcore_to_socket_id(lcore);
340 : :
341 : : /* check the availability of source node */
342 [ - + ]: 1 : if (!graph_src_node_avail(graph))
343 : 0 : graph->graph->head = 0;
344 : :
345 : : return 0;
346 : :
347 : 0 : fail:
348 : 0 : return -rte_errno;
349 : : }
350 : :
351 : : void
352 : 1 : rte_graph_model_mcore_dispatch_core_unbind(rte_graph_t id)
353 : : {
354 : : struct graph *graph;
355 : :
356 : : if (graph_from_id(id) == NULL)
357 : 0 : goto fail;
358 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
359 [ + + ]: 2 : if (graph->id == id)
360 : : break;
361 : :
362 : 1 : graph->lcore_id = RTE_MAX_LCORE;
363 : 1 : graph->graph->dispatch.lcore_id = RTE_MAX_LCORE;
364 : :
365 : 1 : fail:
366 : 1 : return;
367 : : }
368 : :
369 : : struct rte_graph *
370 : 3 : rte_graph_lookup(const char *name)
371 : : {
372 : : const struct rte_memzone *mz;
373 : : struct rte_graph *rc = NULL;
374 : :
375 : 3 : mz = rte_memzone_lookup(name);
376 [ + - ]: 3 : if (mz)
377 : 3 : rc = mz->addr;
378 : :
379 : 3 : return graph_mem_fixup_secondary(rc);
380 : : }
381 : :
382 : : rte_graph_t
383 : 6 : rte_graph_create(const char *name, struct rte_graph_param *prm)
384 : : {
385 : : rte_node_t src_node_count;
386 : : struct graph *graph;
387 : : const char *pattern;
388 : : uint16_t i;
389 : :
390 : 6 : graph_spinlock_lock();
391 : :
392 : : /* Check arguments sanity */
393 [ - + ]: 6 : if (prm == NULL)
394 : 0 : SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
395 : :
396 [ - + ]: 6 : if (name == NULL)
397 : 0 : SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
398 : :
399 : : /* Check for existence of duplicate graph */
400 [ + + ]: 15 : STAILQ_FOREACH(graph, &graph_list, next)
401 [ - + ]: 9 : if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
402 : 0 : SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
403 : : name);
404 : :
405 : : /* Create graph object */
406 : 6 : graph = calloc(1, sizeof(*graph));
407 [ - + ]: 6 : if (graph == NULL)
408 : 0 : SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
409 : :
410 : : /* Initialize the graph object */
411 : 6 : STAILQ_INIT(&graph->node_list);
412 [ - + ]: 6 : if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
413 : 0 : SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
414 : :
415 : : /* Expand node pattern and add the nodes to the graph */
416 [ + + ]: 25 : for (i = 0; i < prm->nb_node_patterns; i++) {
417 : 19 : pattern = prm->node_patterns[i];
418 [ - + ]: 19 : if (expand_pattern_to_node(graph, pattern))
419 : 0 : goto graph_cleanup;
420 : : }
421 : :
422 : : /* Go over all the nodes edges and add them to the graph */
423 [ - + ]: 6 : if (graph_node_edges_add(graph))
424 : 0 : goto graph_cleanup;
425 : :
426 : : /* Update adjacency list of all nodes in the graph */
427 [ - + ]: 6 : if (graph_adjacency_list_update(graph))
428 : 0 : goto graph_cleanup;
429 : :
430 : : /* Make sure at least a source node present in the graph */
431 : 6 : src_node_count = graph_src_nodes_count(graph);
432 [ - + ]: 6 : if (src_node_count == 0)
433 : 0 : goto graph_cleanup;
434 : :
435 : : /* Make sure no node is pointing to source node */
436 [ - + ]: 6 : if (graph_node_has_edge_to_src_node(graph))
437 : 0 : goto graph_cleanup;
438 : :
439 : : /* Don't allow node has loop to self */
440 [ - + ]: 6 : if (graph_node_has_loop_edge(graph))
441 : 0 : goto graph_cleanup;
442 : :
443 : : /* Do BFS from src nodes on the graph to find isolated nodes */
444 [ + + ]: 6 : if (graph_has_isolated_node(graph))
445 : 1 : goto graph_cleanup;
446 : :
447 : : /* Initialize pcap config. */
448 : 5 : graph_pcap_enable(prm->pcap_enable);
449 : :
450 : : /* Initialize graph object */
451 : 5 : graph->socket = prm->socket_id;
452 : 5 : graph->src_node_count = src_node_count;
453 : 5 : graph->node_count = graph_nodes_count(graph);
454 : 5 : graph->id = graph_next_free_id();
455 : 5 : graph->parent_id = RTE_GRAPH_ID_INVALID;
456 : 5 : graph->lcore_id = RTE_MAX_LCORE;
457 : 5 : graph->num_pkt_to_capture = prm->num_pkt_to_capture;
458 [ - + ]: 5 : if (prm->pcap_filename)
459 : 0 : rte_strscpy(graph->pcap_filename, prm->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ);
460 : :
461 : : /* Allocate the Graph fast path memory and populate the data */
462 [ - + ]: 5 : if (graph_fp_mem_create(graph))
463 : 0 : goto graph_cleanup;
464 : :
465 : : /* Call init() of the all the nodes in the graph */
466 [ - + ]: 5 : if (graph_node_init(graph))
467 : 0 : goto graph_mem_destroy;
468 : :
469 : : /* All good, Lets add the graph to the list */
470 : 5 : graph_insert_ordered(graph);
471 : :
472 : 5 : graph_spinlock_unlock();
473 : 5 : return graph->id;
474 : :
475 : : graph_mem_destroy:
476 : 0 : graph_fp_mem_destroy(graph);
477 : : graph_cleanup:
478 : : graph_cleanup(graph);
479 : 1 : free:
480 : 1 : free(graph);
481 : 1 : fail:
482 : 1 : graph_spinlock_unlock();
483 : 1 : return RTE_GRAPH_ID_INVALID;
484 : : }
485 : :
486 : : int
487 : 10 : rte_graph_destroy(rte_graph_t id)
488 : : {
489 : : struct graph *graph, *tmp;
490 : : int rc = -ENOENT;
491 : :
492 : 10 : graph_spinlock_lock();
493 : :
494 : 10 : graph = STAILQ_FIRST(&graph_list);
495 [ + - ]: 23 : while (graph != NULL) {
496 : 23 : tmp = STAILQ_NEXT(graph, next);
497 [ + + ]: 23 : if (graph->id == id) {
498 : : /* Destroy the schedule work queue if has */
499 [ + + ]: 10 : if (rte_graph_worker_model_get(graph->graph) ==
500 : : RTE_GRAPH_MODEL_MCORE_DISPATCH)
501 : 3 : graph_sched_wq_destroy(graph);
502 : :
503 : : /* Call fini() of the all the nodes in the graph */
504 : 10 : graph_node_fini(graph);
505 : : /* Destroy graph fast path memory */
506 : 10 : rc = graph_fp_mem_destroy(graph);
507 [ + - ]: 10 : if (rc)
508 : 0 : SET_ERR_JMP(rc, done, "Graph %s destroy failed",
509 : : graph->name);
510 : :
511 : : graph_cleanup(graph);
512 [ + + + - : 23 : STAILQ_REMOVE(&graph_list, graph, graph, next);
+ + + + ]
513 : 10 : free(graph);
514 : 10 : goto done;
515 : : }
516 : : graph = tmp;
517 : : }
518 : 0 : done:
519 : 10 : graph_spinlock_unlock();
520 : 10 : return rc;
521 : : }
522 : :
523 : : static rte_graph_t
524 : 5 : graph_clone(struct graph *parent_graph, const char *name, struct rte_graph_param *prm)
525 : : {
526 : : struct graph_node *graph_node;
527 : : struct graph *graph;
528 : :
529 : 5 : graph_spinlock_lock();
530 : :
531 : : /* Don't allow to clone a node from a cloned graph */
532 [ - + ]: 5 : if (parent_graph->parent_id != RTE_GRAPH_ID_INVALID)
533 : 0 : SET_ERR_JMP(EEXIST, fail, "A cloned graph is not allowed to be cloned");
534 : :
535 : : /* Create graph object */
536 : 5 : graph = calloc(1, sizeof(*graph));
537 [ - + ]: 5 : if (graph == NULL)
538 : 0 : SET_ERR_JMP(ENOMEM, fail, "Failed to calloc cloned graph object");
539 : :
540 : : /* Naming ceremony of the new graph. name is node->name + "-" + name */
541 [ - + ]: 5 : if (clone_name(graph->name, parent_graph->name, name))
542 : 0 : goto free;
543 : :
544 : : /* Check for existence of duplicate graph */
545 [ - + ]: 5 : if (rte_graph_from_name(graph->name) != RTE_GRAPH_ID_INVALID)
546 : 0 : SET_ERR_JMP(EEXIST, free, "Found duplicate graph %s",
547 : : graph->name);
548 : :
549 : : /* Clone nodes from parent graph firstly */
550 : 5 : STAILQ_INIT(&graph->node_list);
551 [ + + ]: 30 : STAILQ_FOREACH(graph_node, &parent_graph->node_list, next) {
552 [ - + ]: 25 : if (graph_node_add(graph, graph_node->node))
553 : 0 : goto graph_cleanup;
554 : : }
555 : :
556 : : /* Just update adjacency list of all nodes in the graph */
557 [ - + ]: 5 : if (graph_adjacency_list_update(graph))
558 : 0 : goto graph_cleanup;
559 : :
560 : : /* Initialize the graph object */
561 : 5 : graph->src_node_count = parent_graph->src_node_count;
562 : 5 : graph->node_count = parent_graph->node_count;
563 : 5 : graph->parent_id = parent_graph->id;
564 : 5 : graph->lcore_id = parent_graph->lcore_id;
565 : 5 : graph->socket = parent_graph->socket;
566 : 5 : graph->id = graph_next_free_id();
567 : :
568 : : /* Allocate the Graph fast path memory and populate the data */
569 [ - + ]: 5 : if (graph_fp_mem_create(graph))
570 : 0 : goto graph_cleanup;
571 : :
572 : : /* Clone the graph model */
573 : 5 : graph->graph->model = parent_graph->graph->model;
574 : :
575 : : /* Create the graph schedule work queue */
576 [ + + - + ]: 6 : if (rte_graph_worker_model_get(graph->graph) == RTE_GRAPH_MODEL_MCORE_DISPATCH &&
577 : 1 : graph_sched_wq_create(graph, parent_graph, prm))
578 : 0 : goto graph_mem_destroy;
579 : :
580 : : /* Call init() of the all the nodes in the graph */
581 [ - + ]: 5 : if (graph_node_init(graph))
582 : 0 : goto graph_mem_destroy;
583 : :
584 : : /* All good, Lets add the graph to the list */
585 : 5 : graph_insert_ordered(graph);
586 : :
587 : 5 : graph_spinlock_unlock();
588 : 5 : return graph->id;
589 : :
590 : 0 : graph_mem_destroy:
591 : 0 : graph_fp_mem_destroy(graph);
592 : : graph_cleanup:
593 : : graph_cleanup(graph);
594 : 0 : free:
595 : 0 : free(graph);
596 : 0 : fail:
597 : 0 : graph_spinlock_unlock();
598 : 0 : return RTE_GRAPH_ID_INVALID;
599 : : }
600 : :
601 : : rte_graph_t
602 : 5 : rte_graph_clone(rte_graph_t id, const char *name, struct rte_graph_param *prm)
603 : : {
604 : : struct graph *graph;
605 : :
606 : : if (graph_from_id(id) == NULL)
607 : 0 : goto fail;
608 [ + - ]: 6 : STAILQ_FOREACH(graph, &graph_list, next)
609 [ + + ]: 6 : if (graph->id == id)
610 : 5 : return graph_clone(graph, name, prm);
611 : :
612 : 0 : fail:
613 : : return RTE_GRAPH_ID_INVALID;
614 : : }
615 : :
616 : : rte_graph_t
617 : 7 : rte_graph_from_name(const char *name)
618 : : {
619 : : struct graph *graph;
620 : :
621 [ + + ]: 15 : STAILQ_FOREACH(graph, &graph_list, next)
622 [ + + ]: 10 : if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
623 : 2 : return graph->id;
624 : :
625 : : return RTE_GRAPH_ID_INVALID;
626 : : }
627 : :
628 : : char *
629 : 1 : rte_graph_id_to_name(rte_graph_t id)
630 : : {
631 : : struct graph *graph;
632 : :
633 : : if (graph_from_id(id) == NULL)
634 : 0 : goto fail;
635 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
636 [ + + ]: 2 : if (graph->id == id)
637 : 1 : return graph->name;
638 : :
639 : 0 : fail:
640 : : return NULL;
641 : : }
642 : :
643 : : struct rte_node *
644 : 5 : rte_graph_node_get(rte_graph_t gid, uint32_t nid)
645 : : {
646 : : struct rte_node *node;
647 : : struct graph *graph;
648 : : rte_graph_off_t off;
649 : : rte_node_t count;
650 : :
651 : : if (graph_from_id(gid) == NULL)
652 : 0 : goto fail;
653 [ + - ]: 6 : STAILQ_FOREACH(graph, &graph_list, next)
654 [ + + ]: 6 : if (graph->id == gid) {
655 [ + - ]: 16 : rte_graph_foreach_node(count, off, graph->graph,
656 : : node) {
657 [ + + ]: 16 : if (node->id == nid)
658 : 5 : return node;
659 : : }
660 : : break;
661 : : }
662 : 0 : fail:
663 : : return NULL;
664 : : }
665 : :
666 : : struct rte_node *
667 : 4 : rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
668 : : {
669 : : struct rte_node *node;
670 : : struct graph *graph;
671 : : rte_graph_off_t off;
672 : : rte_node_t count;
673 : :
674 [ + - ]: 4 : STAILQ_FOREACH(graph, &graph_list, next)
675 [ + - ]: 4 : if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
676 [ + - ]: 14 : rte_graph_foreach_node(count, off, graph->graph,
677 : : node) {
678 [ + + ]: 14 : if (!strncmp(node->name, node_name,
679 : : RTE_NODE_NAMESIZE))
680 : 4 : return node;
681 : : }
682 : : break;
683 : : }
684 : :
685 : : return NULL;
686 : : }
687 : :
688 : : void __rte_noinline
689 : 60 : __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
690 : : {
691 : 60 : uint16_t size = node->size;
692 : :
693 [ - + ]: 60 : RTE_VERIFY(size != UINT16_MAX);
694 : : /* Allocate double amount of size to avoid immediate realloc */
695 : 60 : size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
696 : 60 : node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
697 : : RTE_CACHE_LINE_SIZE, graph->socket);
698 [ - + ]: 60 : RTE_VERIFY(node->objs);
699 : 60 : node->size = size;
700 : 60 : node->realloc_count++;
701 : 60 : }
702 : :
703 : : void __rte_noinline
704 : 0 : __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
705 : : uint16_t req_size)
706 : : {
707 : 0 : uint16_t size = node->size;
708 : :
709 [ # # ]: 0 : RTE_VERIFY(size != UINT16_MAX);
710 : : /* Allocate double amount of size to avoid immediate realloc */
711 : 0 : size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
712 : 0 : node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
713 : : RTE_CACHE_LINE_SIZE, graph->socket);
714 [ # # ]: 0 : RTE_VERIFY(node->objs);
715 : 0 : node->size = size;
716 : 0 : node->realloc_count++;
717 : 0 : }
718 : :
719 : : static int
720 : 0 : graph_to_dot(FILE *f, struct graph *graph)
721 : : {
722 : : struct graph_node *graph_node;
723 : : char *node_name;
724 : : rte_edge_t i;
725 : : int rc;
726 : :
727 : 0 : rc = fprintf(f, "digraph \"%s\" {\n\trankdir=LR;\n", graph->name);
728 [ # # ]: 0 : if (rc < 0)
729 : 0 : goto end;
730 : :
731 : : rc = fprintf(f, "\tnode [margin=0.02 fontsize=11 fontname=sans];\n");
732 [ # # ]: 0 : if (rc < 0)
733 : 0 : goto end;
734 : :
735 [ # # ]: 0 : STAILQ_FOREACH(graph_node, &graph->node_list, next) {
736 : : const char *attrs = "";
737 : 0 : node_name = graph_node->node->name;
738 : :
739 : : rc = fprintf(f, "\t\"%s\"", node_name);
740 [ # # ]: 0 : if (rc < 0)
741 : 0 : goto end;
742 [ # # ]: 0 : if (graph_node->node->flags & RTE_NODE_SOURCE_F) {
743 : : attrs = " [color=blue style=bold]";
744 : : rc = fprintf(f, "%s", attrs);
745 [ # # ]: 0 : if (rc < 0)
746 : 0 : goto end;
747 [ # # ]: 0 : } else if (graph_node->node->nb_edges == 0) {
748 : : rc = fprintf(f, " [fontcolor=darkorange shape=plain]");
749 [ # # ]: 0 : if (rc < 0)
750 : 0 : goto end;
751 : : }
752 : : rc = fprintf(f, ";\n");
753 [ # # ]: 0 : if (rc < 0)
754 : 0 : goto end;
755 [ # # ]: 0 : for (i = 0; i < graph_node->node->nb_edges; i++) {
756 : : const char *node_attrs = attrs;
757 [ # # ]: 0 : if (graph_node->adjacency_list[i]->node->nb_edges == 0)
758 : : node_attrs = " [color=darkorange]";
759 : : rc = fprintf(f, "\t\"%s\" -> \"%s\"%s;\n", node_name,
760 : 0 : graph_node->adjacency_list[i]->node->name,
761 : : node_attrs);
762 [ # # ]: 0 : if (rc < 0)
763 : 0 : goto end;
764 : : }
765 : : }
766 : : rc = fprintf(f, "}\n");
767 [ # # ]: 0 : if (rc < 0)
768 : 0 : goto end;
769 : :
770 : : return 0;
771 : 0 : end:
772 : 0 : rte_errno = EBADF;
773 : 0 : return -rte_errno;
774 : : }
775 : :
776 : : int
777 : 0 : rte_graph_export(const char *name, FILE *f)
778 : : {
779 : : struct graph *graph;
780 : : int rc = ENOENT;
781 : :
782 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next) {
783 [ # # ]: 0 : if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
784 : 0 : rc = graph_to_dot(f, graph);
785 : 0 : goto end;
786 : : }
787 : : }
788 : 0 : end:
789 : 0 : return -rc;
790 : : }
791 : :
792 : : static void
793 : 0 : graph_scan_dump(FILE *f, rte_graph_t id, bool all)
794 : : {
795 : : struct graph *graph;
796 : :
797 [ # # ]: 0 : RTE_VERIFY(f);
798 : : if (graph_from_id(id) == NULL)
799 : 0 : goto fail;
800 : :
801 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next) {
802 [ # # ]: 0 : if (all == true) {
803 : 0 : graph_dump(f, graph);
804 [ # # ]: 0 : } else if (graph->id == id) {
805 : 0 : graph_dump(f, graph);
806 : 0 : return;
807 : : }
808 : : }
809 : 0 : fail:
810 : : return;
811 : : }
812 : :
813 : : void
814 : 0 : rte_graph_dump(FILE *f, rte_graph_t id)
815 : : {
816 : 0 : graph_scan_dump(f, id, false);
817 : 0 : }
818 : :
819 : : void
820 : 0 : rte_graph_list_dump(FILE *f)
821 : : {
822 : 0 : graph_scan_dump(f, 0, true);
823 : 0 : }
824 : :
825 : : rte_graph_t
826 : 0 : rte_graph_max_count(void)
827 : : {
828 : : struct graph *graph;
829 : : rte_graph_t count = 0;
830 : :
831 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next)
832 : 0 : count++;
833 : :
834 : 0 : return count;
835 : : }
836 : :
837 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(rte_graph_logtype, INFO);
|