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 : : static struct rte_graph *
281 : 0 : graph_mem_fixup_node_ctx(struct rte_graph *graph)
282 : : {
283 : : struct rte_node *node;
284 : : struct node *node_db;
285 : : rte_graph_off_t off;
286 : : rte_node_t count;
287 : : const char *name;
288 : :
289 [ # # ]: 0 : rte_graph_foreach_node(count, off, graph, node) {
290 [ # # ]: 0 : if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */
291 : 0 : name = node->name;
292 : : else /* Cloned node */
293 : 0 : name = node->parent;
294 : :
295 : 0 : node_db = node_from_name(name);
296 [ # # ]: 0 : if (node_db == NULL)
297 : 0 : SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name);
298 : :
299 [ # # ]: 0 : if (graph->pcap_enable) {
300 : 0 : node->process = graph_pcap_dispatch;
301 : 0 : node->original_process = node_db->process;
302 : : } else
303 : 0 : node->process = node_db->process;
304 : : }
305 : :
306 : : return graph;
307 : : fail:
308 : 0 : return NULL;
309 : : }
310 : :
311 : : static struct rte_graph *
312 : 5 : graph_mem_fixup_secondary(struct rte_graph *graph)
313 : : {
314 [ + - + - ]: 5 : if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY)
315 : 5 : return graph;
316 : :
317 [ # # # # ]: 0 : if (graph_pcap_file_open(graph->pcap_filename) || graph_pcap_mp_init())
318 : 0 : graph_pcap_exit(graph);
319 : :
320 : 0 : return graph_mem_fixup_node_ctx(graph);
321 : : }
322 : :
323 : : static bool
324 : : graph_src_node_avail(struct graph *graph)
325 : : {
326 : : struct graph_node *graph_node;
327 : :
328 [ + - ]: 1 : STAILQ_FOREACH(graph_node, &graph->node_list, next)
329 [ + - ]: 1 : if ((graph_node->node->flags & RTE_NODE_SOURCE_F) &&
330 [ - + ]: 1 : (graph_node->node->lcore_id == RTE_MAX_LCORE ||
331 [ # # ]: 0 : graph->lcore_id == graph_node->node->lcore_id))
332 : : return true;
333 : :
334 : : return false;
335 : : }
336 : :
337 : : RTE_EXPORT_SYMBOL(rte_graph_model_mcore_dispatch_core_bind)
338 : : int
339 : 1 : rte_graph_model_mcore_dispatch_core_bind(rte_graph_t id, int lcore)
340 : : {
341 : : struct graph *graph;
342 : :
343 : : if (graph_from_id(id) == NULL)
344 : 0 : goto fail;
345 [ - + ]: 1 : if (!rte_lcore_is_enabled(lcore))
346 : 0 : SET_ERR_JMP(ENOLINK, fail, "lcore %d not enabled", lcore);
347 : :
348 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
349 [ + + ]: 2 : if (graph->id == id)
350 : : break;
351 : :
352 [ - + ]: 1 : if (graph->graph->model != RTE_GRAPH_MODEL_MCORE_DISPATCH)
353 : 0 : goto fail;
354 : :
355 : 1 : graph->lcore_id = lcore;
356 : 1 : graph->graph->dispatch.lcore_id = graph->lcore_id;
357 : 1 : graph->socket = rte_lcore_to_socket_id(lcore);
358 : :
359 : : /* check the availability of source node */
360 [ - + ]: 1 : if (!graph_src_node_avail(graph))
361 : 0 : graph->graph->head = 0;
362 : :
363 : : return 0;
364 : :
365 : 0 : fail:
366 : 0 : return -rte_errno;
367 : : }
368 : :
369 : : RTE_EXPORT_SYMBOL(rte_graph_model_mcore_dispatch_core_unbind)
370 : : void
371 : 1 : rte_graph_model_mcore_dispatch_core_unbind(rte_graph_t id)
372 : : {
373 : : struct graph *graph;
374 : :
375 : : if (graph_from_id(id) == NULL)
376 : 0 : goto fail;
377 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
378 [ + + ]: 2 : if (graph->id == id)
379 : : break;
380 : :
381 : 1 : graph->lcore_id = RTE_MAX_LCORE;
382 : 1 : graph->graph->dispatch.lcore_id = RTE_MAX_LCORE;
383 : :
384 : 1 : fail:
385 : 1 : return;
386 : : }
387 : :
388 : : RTE_EXPORT_SYMBOL(rte_graph_lookup)
389 : : struct rte_graph *
390 : 5 : rte_graph_lookup(const char *name)
391 : : {
392 : : const struct rte_memzone *mz;
393 : : struct rte_graph *rc = NULL;
394 : :
395 : 5 : mz = rte_memzone_lookup(name);
396 [ + - ]: 5 : if (mz)
397 : 5 : rc = mz->addr;
398 : :
399 : 5 : return graph_mem_fixup_secondary(rc);
400 : : }
401 : :
402 : : RTE_EXPORT_SYMBOL(rte_graph_create)
403 : : rte_graph_t
404 : 9 : rte_graph_create(const char *name, struct rte_graph_param *prm)
405 : : {
406 : : rte_node_t src_node_count;
407 : : struct graph *graph;
408 : : const char *pattern;
409 : : uint16_t i;
410 : :
411 : 9 : graph_spinlock_lock();
412 : :
413 : : /* Check arguments sanity */
414 [ - + ]: 9 : if (prm == NULL)
415 : 0 : SET_ERR_JMP(EINVAL, fail, "Param should not be NULL");
416 : :
417 [ - + ]: 9 : if (name == NULL)
418 : 0 : SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL");
419 : :
420 : : /* Check for existence of duplicate graph */
421 [ + + ]: 18 : STAILQ_FOREACH(graph, &graph_list, next)
422 [ - + ]: 9 : if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0)
423 : 0 : SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s",
424 : : name);
425 : :
426 : : /* Create graph object */
427 : 9 : graph = calloc(1, sizeof(*graph));
428 [ - + ]: 9 : if (graph == NULL)
429 : 0 : SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object");
430 : :
431 : : /* Initialize the graph object */
432 : 9 : STAILQ_INIT(&graph->node_list);
433 [ - + ]: 9 : if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0)
434 : 0 : SET_ERR_JMP(E2BIG, free, "Too big name=%s", name);
435 : :
436 : : /* Expand node pattern and add the nodes to the graph */
437 [ + + ]: 61 : for (i = 0; i < prm->nb_node_patterns; i++) {
438 : 52 : pattern = prm->node_patterns[i];
439 [ - + ]: 52 : if (expand_pattern_to_node(graph, pattern))
440 : 0 : goto graph_cleanup;
441 : : }
442 : :
443 : : /* Go over all the nodes edges and add them to the graph */
444 [ - + ]: 9 : if (graph_node_edges_add(graph))
445 : 0 : goto graph_cleanup;
446 : :
447 : : /* Update adjacency list of all nodes in the graph */
448 [ - + ]: 9 : if (graph_adjacency_list_update(graph))
449 : 0 : goto graph_cleanup;
450 : :
451 : : /* Make sure at least a source node present in the graph */
452 : 9 : src_node_count = graph_src_nodes_count(graph);
453 [ - + ]: 9 : if (src_node_count == 0)
454 : 0 : goto graph_cleanup;
455 : :
456 : : /* Make sure no node is pointing to source node */
457 [ - + ]: 9 : if (graph_node_has_edge_to_src_node(graph))
458 : 0 : goto graph_cleanup;
459 : :
460 : : /* Don't allow node has loop to self */
461 [ - + ]: 9 : if (graph_node_has_loop_edge(graph))
462 : 0 : goto graph_cleanup;
463 : :
464 : : /* Do BFS from src nodes on the graph to find isolated nodes */
465 [ + + ]: 9 : if (graph_has_isolated_node(graph))
466 : 1 : goto graph_cleanup;
467 : :
468 : : /* Initialize pcap config. */
469 : 8 : graph_pcap_enable(prm->pcap_enable);
470 : :
471 : : /* Initialize graph object */
472 : 8 : graph->socket = prm->socket_id;
473 : 8 : graph->src_node_count = src_node_count;
474 : 8 : graph->node_count = graph_nodes_count(graph);
475 : 8 : graph->id = graph_next_free_id();
476 : 8 : graph->parent_id = RTE_GRAPH_ID_INVALID;
477 : 8 : graph->lcore_id = RTE_MAX_LCORE;
478 : 8 : graph->num_pkt_to_capture = prm->num_pkt_to_capture;
479 [ - + ]: 8 : if (prm->pcap_filename)
480 : 0 : rte_strscpy(graph->pcap_filename, prm->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ);
481 : :
482 : : /* Allocate the Graph fast path memory and populate the data */
483 [ - + ]: 8 : if (graph_fp_mem_create(graph))
484 : 0 : goto graph_cleanup;
485 : :
486 : : /* Call init() of the all the nodes in the graph */
487 [ - + ]: 8 : if (graph_node_init(graph))
488 : 0 : goto graph_mem_destroy;
489 : :
490 : : /* All good, Lets add the graph to the list */
491 : 8 : graph_insert_ordered(graph);
492 : :
493 : 8 : graph_spinlock_unlock();
494 : 8 : return graph->id;
495 : :
496 : : graph_mem_destroy:
497 : 0 : graph_fp_mem_destroy(graph);
498 : : graph_cleanup:
499 : : graph_cleanup(graph);
500 : 1 : free:
501 : 1 : free(graph);
502 : 1 : fail:
503 : 1 : graph_spinlock_unlock();
504 : 1 : return RTE_GRAPH_ID_INVALID;
505 : : }
506 : :
507 : : RTE_EXPORT_SYMBOL(rte_graph_destroy)
508 : : int
509 : 13 : rte_graph_destroy(rte_graph_t id)
510 : : {
511 : : struct graph *graph, *tmp;
512 : : int rc = -ENOENT;
513 : :
514 : 13 : graph_spinlock_lock();
515 : :
516 : 13 : graph = STAILQ_FIRST(&graph_list);
517 [ + - ]: 26 : while (graph != NULL) {
518 : 26 : tmp = STAILQ_NEXT(graph, next);
519 [ + + ]: 26 : if (graph->id == id) {
520 : : /* Destroy the schedule work queue if has */
521 [ + + ]: 13 : if (rte_graph_worker_model_get(graph->graph) ==
522 : : RTE_GRAPH_MODEL_MCORE_DISPATCH)
523 : 3 : graph_sched_wq_destroy(graph);
524 : :
525 : : /* Call fini() of the all the nodes in the graph */
526 : 13 : graph_node_fini(graph);
527 : : /* Destroy graph fast path memory */
528 : 13 : rc = graph_fp_mem_destroy(graph);
529 [ + - ]: 13 : if (rc)
530 : 0 : SET_ERR_JMP(rc, done, "Graph %s destroy failed",
531 : : graph->name);
532 : :
533 : : graph_cleanup(graph);
534 [ + + + - : 26 : STAILQ_REMOVE(&graph_list, graph, graph, next);
+ + + + ]
535 : 13 : free(graph);
536 : 13 : goto done;
537 : : }
538 : : graph = tmp;
539 : : }
540 : 0 : done:
541 : 13 : graph_spinlock_unlock();
542 : 13 : return rc;
543 : : }
544 : :
545 : : static rte_graph_t
546 : 5 : graph_clone(struct graph *parent_graph, const char *name, struct rte_graph_param *prm)
547 : : {
548 : : struct graph_node *graph_node;
549 : : struct graph *graph;
550 : :
551 : 5 : graph_spinlock_lock();
552 : :
553 : : /* Don't allow to clone a node from a cloned graph */
554 [ - + ]: 5 : if (parent_graph->parent_id != RTE_GRAPH_ID_INVALID)
555 : 0 : SET_ERR_JMP(EEXIST, fail, "A cloned graph is not allowed to be cloned");
556 : :
557 : : /* Create graph object */
558 : 5 : graph = calloc(1, sizeof(*graph));
559 [ - + ]: 5 : if (graph == NULL)
560 : 0 : SET_ERR_JMP(ENOMEM, fail, "Failed to calloc cloned graph object");
561 : :
562 : : /* Naming ceremony of the new graph. name is node->name + "-" + name */
563 [ - + ]: 5 : if (clone_name(graph->name, parent_graph->name, name))
564 : 0 : goto free;
565 : :
566 : : /* Check for existence of duplicate graph */
567 [ - + ]: 5 : if (rte_graph_from_name(graph->name) != RTE_GRAPH_ID_INVALID)
568 : 0 : SET_ERR_JMP(EEXIST, free, "Found duplicate graph %s",
569 : : graph->name);
570 : :
571 : : /* Clone nodes from parent graph firstly */
572 : 5 : STAILQ_INIT(&graph->node_list);
573 [ + + ]: 30 : STAILQ_FOREACH(graph_node, &parent_graph->node_list, next) {
574 [ - + ]: 25 : if (graph_node_add(graph, graph_node->node))
575 : 0 : goto graph_cleanup;
576 : : }
577 : :
578 : : /* Just update adjacency list of all nodes in the graph */
579 [ - + ]: 5 : if (graph_adjacency_list_update(graph))
580 : 0 : goto graph_cleanup;
581 : :
582 : : /* Initialize the graph object */
583 : 5 : graph->src_node_count = parent_graph->src_node_count;
584 : 5 : graph->node_count = parent_graph->node_count;
585 : 5 : graph->parent_id = parent_graph->id;
586 : 5 : graph->lcore_id = parent_graph->lcore_id;
587 : 5 : graph->socket = parent_graph->socket;
588 : 5 : graph->id = graph_next_free_id();
589 : :
590 : : /* Allocate the Graph fast path memory and populate the data */
591 [ - + ]: 5 : if (graph_fp_mem_create(graph))
592 : 0 : goto graph_cleanup;
593 : :
594 : : /* Clone the graph model */
595 : 5 : graph->graph->model = parent_graph->graph->model;
596 : :
597 : : /* Create the graph schedule work queue */
598 [ + + - + ]: 6 : if (rte_graph_worker_model_get(graph->graph) == RTE_GRAPH_MODEL_MCORE_DISPATCH &&
599 : 1 : graph_sched_wq_create(graph, parent_graph, prm))
600 : 0 : goto graph_mem_destroy;
601 : :
602 : : /* Call init() of the all the nodes in the graph */
603 [ - + ]: 5 : if (graph_node_init(graph))
604 : 0 : goto graph_mem_destroy;
605 : :
606 : : /* All good, Lets add the graph to the list */
607 : 5 : graph_insert_ordered(graph);
608 : :
609 : 5 : graph_spinlock_unlock();
610 : 5 : return graph->id;
611 : :
612 : 0 : graph_mem_destroy:
613 : 0 : graph_fp_mem_destroy(graph);
614 : : graph_cleanup:
615 : : graph_cleanup(graph);
616 : 0 : free:
617 : 0 : free(graph);
618 : 0 : fail:
619 : 0 : graph_spinlock_unlock();
620 : 0 : return RTE_GRAPH_ID_INVALID;
621 : : }
622 : :
623 : : RTE_EXPORT_SYMBOL(rte_graph_clone)
624 : : rte_graph_t
625 : 5 : rte_graph_clone(rte_graph_t id, const char *name, struct rte_graph_param *prm)
626 : : {
627 : : struct graph *graph;
628 : :
629 : : if (graph_from_id(id) == NULL)
630 : 0 : goto fail;
631 [ + - ]: 6 : STAILQ_FOREACH(graph, &graph_list, next)
632 [ + + ]: 6 : if (graph->id == id)
633 : 5 : return graph_clone(graph, name, prm);
634 : :
635 : 0 : fail:
636 : : return RTE_GRAPH_ID_INVALID;
637 : : }
638 : :
639 : : RTE_EXPORT_SYMBOL(rte_graph_from_name)
640 : : rte_graph_t
641 : 7 : rte_graph_from_name(const char *name)
642 : : {
643 : : struct graph *graph;
644 : :
645 [ + + ]: 15 : STAILQ_FOREACH(graph, &graph_list, next)
646 [ + + ]: 10 : if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0)
647 : 2 : return graph->id;
648 : :
649 : : return RTE_GRAPH_ID_INVALID;
650 : : }
651 : :
652 : : RTE_EXPORT_SYMBOL(rte_graph_id_to_name)
653 : : char *
654 : 1 : rte_graph_id_to_name(rte_graph_t id)
655 : : {
656 : : struct graph *graph;
657 : :
658 : : if (graph_from_id(id) == NULL)
659 : 0 : goto fail;
660 [ + - ]: 2 : STAILQ_FOREACH(graph, &graph_list, next)
661 [ + + ]: 2 : if (graph->id == id)
662 : 1 : return graph->name;
663 : :
664 : 0 : fail:
665 : : return NULL;
666 : : }
667 : :
668 : : RTE_EXPORT_SYMBOL(rte_graph_node_get)
669 : : struct rte_node *
670 : 5 : rte_graph_node_get(rte_graph_t gid, uint32_t nid)
671 : : {
672 : : struct rte_node *node;
673 : : struct graph *graph;
674 : : rte_graph_off_t off;
675 : : rte_node_t count;
676 : :
677 : : if (graph_from_id(gid) == NULL)
678 : 0 : goto fail;
679 [ + - ]: 6 : STAILQ_FOREACH(graph, &graph_list, next)
680 [ + + ]: 6 : if (graph->id == gid) {
681 [ + - ]: 16 : rte_graph_foreach_node(count, off, graph->graph,
682 : : node) {
683 [ + + ]: 16 : if (node->id == nid)
684 : 5 : return node;
685 : : }
686 : : break;
687 : : }
688 : 0 : fail:
689 : : return NULL;
690 : : }
691 : :
692 : : RTE_EXPORT_SYMBOL(rte_graph_node_get_by_name)
693 : : struct rte_node *
694 : 4 : rte_graph_node_get_by_name(const char *graph_name, const char *node_name)
695 : : {
696 : : struct rte_node *node;
697 : : struct graph *graph;
698 : : rte_graph_off_t off;
699 : : rte_node_t count;
700 : :
701 [ + - ]: 4 : STAILQ_FOREACH(graph, &graph_list, next)
702 [ + - ]: 4 : if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) {
703 [ + - ]: 14 : rte_graph_foreach_node(count, off, graph->graph,
704 : : node) {
705 [ + + ]: 14 : if (!strncmp(node->name, node_name,
706 : : RTE_NODE_NAMESIZE))
707 : 4 : return node;
708 : : }
709 : : break;
710 : : }
711 : :
712 : : return NULL;
713 : : }
714 : :
715 : : RTE_EXPORT_SYMBOL(__rte_node_stream_alloc)
716 : : void __rte_noinline
717 : 96 : __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node)
718 : : {
719 : 96 : uint16_t size = node->size;
720 : :
721 [ - + ]: 96 : RTE_VERIFY(size != UINT16_MAX);
722 : : /* Allocate double amount of size to avoid immediate realloc */
723 : 96 : size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2));
724 : 96 : node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
725 : : RTE_CACHE_LINE_SIZE, graph->socket);
726 [ - + ]: 96 : RTE_VERIFY(node->objs);
727 : 96 : node->size = size;
728 : 96 : node->realloc_count++;
729 : 96 : }
730 : :
731 : : RTE_EXPORT_SYMBOL(__rte_node_stream_alloc_size)
732 : : void __rte_noinline
733 : 0 : __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node,
734 : : uint16_t req_size)
735 : : {
736 : 0 : uint16_t size = node->size;
737 : :
738 [ # # ]: 0 : RTE_VERIFY(size != UINT16_MAX);
739 : : /* Allocate double amount of size to avoid immediate realloc */
740 : 0 : size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2));
741 : 0 : node->objs = rte_realloc_socket(node->objs, size * sizeof(void *),
742 : : RTE_CACHE_LINE_SIZE, graph->socket);
743 [ # # ]: 0 : RTE_VERIFY(node->objs);
744 : 0 : node->size = size;
745 : 0 : node->realloc_count++;
746 : 0 : }
747 : :
748 : : static int
749 : 0 : graph_to_dot(FILE *f, struct graph *graph)
750 : : {
751 : : struct graph_node *graph_node;
752 : : char *node_name;
753 : : rte_edge_t i;
754 : : int rc;
755 : :
756 : 0 : rc = fprintf(f, "digraph \"%s\" {\n\trankdir=LR;\n", graph->name);
757 [ # # ]: 0 : if (rc < 0)
758 : 0 : goto end;
759 : :
760 : : rc = fprintf(f, "\tnode [margin=0.02 fontsize=11 fontname=sans];\n");
761 [ # # ]: 0 : if (rc < 0)
762 : 0 : goto end;
763 : :
764 [ # # ]: 0 : STAILQ_FOREACH(graph_node, &graph->node_list, next) {
765 : : const char *attrs = "";
766 : 0 : node_name = graph_node->node->name;
767 : :
768 : : rc = fprintf(f, "\t\"%s\"", node_name);
769 [ # # ]: 0 : if (rc < 0)
770 : 0 : goto end;
771 [ # # ]: 0 : if (graph_node->node->flags & RTE_NODE_SOURCE_F) {
772 : : attrs = " [color=blue style=bold]";
773 : : rc = fprintf(f, "%s", attrs);
774 [ # # ]: 0 : if (rc < 0)
775 : 0 : goto end;
776 [ # # ]: 0 : } else if (graph_node->node->nb_edges == 0) {
777 : : rc = fprintf(f, " [fontcolor=darkorange shape=plain]");
778 [ # # ]: 0 : if (rc < 0)
779 : 0 : goto end;
780 : : }
781 : : rc = fprintf(f, ";\n");
782 [ # # ]: 0 : if (rc < 0)
783 : 0 : goto end;
784 [ # # ]: 0 : for (i = 0; i < graph_node->node->nb_edges; i++) {
785 : : const char *node_attrs = attrs;
786 [ # # ]: 0 : if (graph_node->adjacency_list[i]->node->nb_edges == 0)
787 : : node_attrs = " [color=darkorange]";
788 : : rc = fprintf(f, "\t\"%s\" -> \"%s\"%s;\n", node_name,
789 : 0 : graph_node->adjacency_list[i]->node->name,
790 : : node_attrs);
791 [ # # ]: 0 : if (rc < 0)
792 : 0 : goto end;
793 : : }
794 : : }
795 : : rc = fprintf(f, "}\n");
796 [ # # ]: 0 : if (rc < 0)
797 : 0 : goto end;
798 : :
799 : : return 0;
800 : 0 : end:
801 : 0 : rte_errno = EBADF;
802 : 0 : return -rte_errno;
803 : : }
804 : :
805 : : RTE_EXPORT_SYMBOL(rte_graph_export)
806 : : int
807 : 0 : rte_graph_export(const char *name, FILE *f)
808 : : {
809 : : struct graph *graph;
810 : : int rc = ENOENT;
811 : :
812 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next) {
813 [ # # ]: 0 : if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) {
814 : 0 : rc = graph_to_dot(f, graph);
815 : 0 : goto end;
816 : : }
817 : : }
818 : 0 : end:
819 : 0 : return -rc;
820 : : }
821 : :
822 : : static void
823 : 0 : graph_scan_dump(FILE *f, rte_graph_t id, bool all)
824 : : {
825 : : struct graph *graph;
826 : :
827 [ # # ]: 0 : RTE_VERIFY(f);
828 : : if (graph_from_id(id) == NULL)
829 : 0 : goto fail;
830 : :
831 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next) {
832 [ # # ]: 0 : if (all == true) {
833 : 0 : graph_dump(f, graph);
834 [ # # ]: 0 : } else if (graph->id == id) {
835 : 0 : graph_dump(f, graph);
836 : 0 : return;
837 : : }
838 : : }
839 : 0 : fail:
840 : : return;
841 : : }
842 : :
843 : : RTE_EXPORT_SYMBOL(rte_graph_dump)
844 : : void
845 : 0 : rte_graph_dump(FILE *f, rte_graph_t id)
846 : : {
847 : 0 : graph_scan_dump(f, id, false);
848 : 0 : }
849 : :
850 : : RTE_EXPORT_SYMBOL(rte_graph_list_dump)
851 : : void
852 : 0 : rte_graph_list_dump(FILE *f)
853 : : {
854 : 0 : graph_scan_dump(f, 0, true);
855 : 0 : }
856 : :
857 : : RTE_EXPORT_SYMBOL(rte_graph_max_count)
858 : : rte_graph_t
859 : 0 : rte_graph_max_count(void)
860 : : {
861 : : struct graph *graph;
862 : : rte_graph_t count = 0;
863 : :
864 [ # # ]: 0 : STAILQ_FOREACH(graph, &graph_list, next)
865 : 0 : count++;
866 : :
867 : 0 : return count;
868 : : }
869 : :
870 [ - + ]: 254 : RTE_LOG_REGISTER_DEFAULT(rte_graph_logtype, INFO);
|