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