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