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