Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2020 Marvell International Ltd.
3 : : */
4 : :
5 : : #include <stdbool.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_common.h>
12 : : #include <rte_debug.h>
13 : : #include <rte_errno.h>
14 : : #include <rte_string_fns.h>
15 : :
16 : : #include "graph_private.h"
17 : :
18 : : static struct node_head node_list = STAILQ_HEAD_INITIALIZER(node_list);
19 : :
20 : : static struct node *
21 : 2014 : node_from_id(rte_node_t id)
22 : : {
23 : : struct node *node = NULL;
24 : :
25 : 2014 : graph_spinlock_lock();
26 : 2014 : rte_errno = EINVAL;
27 [ + - ]: 18872 : STAILQ_FOREACH(node, &node_list, next) {
28 [ + + ]: 18872 : if (node->id == id) {
29 : 2014 : rte_errno = 0;
30 : 2014 : goto exit;
31 : : }
32 : : }
33 : 0 : exit:
34 : 2014 : graph_spinlock_unlock();
35 : 2014 : return node;
36 : : }
37 : :
38 : : static rte_node_t
39 : : next_next_free_id(void)
40 : : {
41 : : struct node *node;
42 : : rte_node_t id = 0;
43 : :
44 [ + + ]: 151433 : STAILQ_FOREACH(node, &node_list, next) {
45 [ + + ]: 142790 : if (id < node->id)
46 : : break;
47 : 142789 : id = node->id + 1;
48 : : }
49 : : return id;
50 : : }
51 : :
52 : : static void
53 : 8644 : node_insert_ordered(struct node *node)
54 : : {
55 : : struct node *after, *g;
56 : :
57 : : after = NULL;
58 [ + + ]: 151433 : STAILQ_FOREACH(g, &node_list, next) {
59 [ + + ]: 142790 : if (g->id < node->id)
60 : : after = g;
61 [ - + ]: 1 : else if (g->id > node->id)
62 : : break;
63 : : }
64 [ + + ]: 8644 : if (after == NULL)
65 [ + - ]: 254 : STAILQ_INSERT_HEAD(&node_list, node, next);
66 : : else
67 [ + + ]: 8390 : STAILQ_INSERT_AFTER(&node_list, after, node, next);
68 : 8644 : }
69 : :
70 : : /* Private functions */
71 : : struct node_head *
72 : 83 : node_list_head_get(void)
73 : : {
74 : 83 : return &node_list;
75 : : }
76 : :
77 : : struct node *
78 : 297 : node_from_name(const char *name)
79 : : {
80 : : struct node *node;
81 : :
82 [ + - ]: 4848 : STAILQ_FOREACH(node, &node_list, next)
83 [ + + ]: 4848 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
84 : 297 : return node;
85 : :
86 : : return NULL;
87 : : }
88 : :
89 : : static bool
90 : 8645 : node_has_duplicate_entry(const char *name)
91 : : {
92 : : struct node *node;
93 : :
94 : : /* Is duplicate name registered */
95 [ + + ]: 151469 : STAILQ_FOREACH(node, &node_list, next) {
96 [ + + ]: 142825 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) {
97 : 1 : rte_errno = EEXIST;
98 : 1 : return 1;
99 : : }
100 : : }
101 : : return 0;
102 : : }
103 : :
104 : : /* Public functions */
105 : : RTE_EXPORT_SYMBOL(__rte_node_register)
106 : : rte_node_t
107 : 8645 : __rte_node_register(const struct rte_node_register *reg)
108 : : {
109 : : struct node *node;
110 : : rte_edge_t i;
111 : : size_t sz;
112 : :
113 : : /* Limit Node specific metadata to one cacheline on 64B CL machine */
114 : : RTE_BUILD_BUG_ON((offsetof(struct rte_node, nodes) -
115 : : offsetof(struct rte_node, ctx)) !=
116 : : RTE_CACHE_LINE_MIN_SIZE);
117 : :
118 : 8645 : graph_spinlock_lock();
119 : :
120 : : /* Check sanity */
121 [ + - - + ]: 8645 : if (reg == NULL || reg->process == NULL) {
122 : 0 : rte_errno = EINVAL;
123 : 0 : goto fail;
124 : : }
125 : :
126 : : /* Check for duplicate name */
127 [ + + ]: 8645 : if (node_has_duplicate_entry(reg->name))
128 : 1 : goto fail;
129 : :
130 : 8644 : sz = sizeof(struct node) + (reg->nb_edges * RTE_NODE_NAMESIZE);
131 : 8644 : node = calloc(1, sz);
132 [ - + ]: 8644 : if (node == NULL) {
133 : 0 : rte_errno = ENOMEM;
134 : 0 : goto fail;
135 : : }
136 : :
137 [ + + ]: 8644 : if (reg->xstats) {
138 : 1016 : sz = sizeof(*reg->xstats) + (reg->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE);
139 : 1016 : node->xstats = calloc(1, sz);
140 [ - + ]: 1016 : if (node->xstats == NULL) {
141 : 0 : rte_errno = ENOMEM;
142 : 0 : goto free;
143 : : }
144 : :
145 : 1016 : node->xstats->nb_xstats = reg->xstats->nb_xstats;
146 [ + + ]: 2032 : for (i = 0; i < reg->xstats->nb_xstats; i++)
147 [ - + ]: 1016 : if (rte_strscpy(node->xstats->xstat_desc[i], reg->xstats->xstat_desc[i],
148 : : RTE_NODE_XSTAT_DESC_SIZE) < 0)
149 : 0 : goto free_xstat;
150 : : }
151 : :
152 : : /* Initialize the node */
153 [ - + ]: 8644 : if (rte_strscpy(node->name, reg->name, RTE_NODE_NAMESIZE) < 0)
154 : 0 : goto free_xstat;
155 : 8644 : node->flags = reg->flags;
156 : 8644 : node->process = reg->process;
157 : 8644 : node->init = reg->init;
158 : 8644 : node->fini = reg->fini;
159 : 8644 : node->nb_edges = reg->nb_edges;
160 : 8644 : node->parent_id = reg->parent_id;
161 [ + + ]: 19822 : for (i = 0; i < reg->nb_edges; i++) {
162 [ - + ]: 11178 : if (rte_strscpy(node->next_nodes[i], reg->next_nodes[i],
163 : : RTE_NODE_NAMESIZE) < 0)
164 : 0 : goto free_xstat;
165 : : }
166 : :
167 : 8644 : node->lcore_id = RTE_MAX_LCORE;
168 : 8644 : node->id = next_next_free_id();
169 : :
170 : : /* Add the node in ordered list */
171 : 8644 : node_insert_ordered(node);
172 : 8644 : graph_spinlock_unlock();
173 : :
174 : 8644 : return node->id;
175 : 0 : free_xstat:
176 : 0 : free(node->xstats);
177 : 0 : free:
178 : 0 : free(node);
179 : 1 : fail:
180 : 1 : graph_spinlock_unlock();
181 : 1 : return RTE_NODE_ID_INVALID;
182 : : }
183 : :
184 : : static rte_node_t
185 : 10 : node_clone(struct node *node, const char *name)
186 : : {
187 : : rte_node_t rc = RTE_NODE_ID_INVALID;
188 : : struct rte_node_register *reg;
189 : : rte_edge_t i;
190 : :
191 : : /* Don't allow to clone a node from a cloned node */
192 [ + + ]: 10 : if (node->parent_id != RTE_NODE_ID_INVALID) {
193 : 1 : rte_errno = EEXIST;
194 : 1 : goto fail;
195 : : }
196 : :
197 : 9 : reg = calloc(1, sizeof(*reg) + (sizeof(char *) * node->nb_edges));
198 [ - + ]: 9 : if (reg == NULL) {
199 : 0 : rte_errno = ENOMEM;
200 : 0 : goto fail;
201 : : }
202 : :
203 [ - + ]: 9 : if (node->xstats) {
204 : 0 : reg->xstats = calloc(1, sizeof(*node->xstats) +
205 : 0 : (node->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE));
206 [ # # ]: 0 : if (reg->xstats == NULL) {
207 : 0 : rte_errno = ENOMEM;
208 : 0 : goto free;
209 : : }
210 : :
211 [ # # ]: 0 : for (i = 0; i < node->xstats->nb_xstats; i++)
212 [ # # ]: 0 : if (rte_strscpy(reg->xstats->xstat_desc[i], node->xstats->xstat_desc[i],
213 : : RTE_NODE_XSTAT_DESC_SIZE) < 0)
214 : 0 : goto free_xstat;
215 : : }
216 : :
217 : : /* Clone the source node */
218 : 9 : reg->flags = node->flags;
219 : 9 : reg->process = node->process;
220 : 9 : reg->init = node->init;
221 : 9 : reg->fini = node->fini;
222 : 9 : reg->nb_edges = node->nb_edges;
223 : 9 : reg->parent_id = node->id;
224 : :
225 [ + + ]: 11 : for (i = 0; i < node->nb_edges; i++)
226 : 2 : reg->next_nodes[i] = node->next_nodes[i];
227 : :
228 : : /* Naming ceremony of the new node. name is node->name + "-" + name */
229 [ - + ]: 9 : if (clone_name(reg->name, node->name, name))
230 : 0 : goto free_xstat;
231 : :
232 : 9 : rc = __rte_node_register(reg);
233 : 9 : free_xstat:
234 : 9 : free(reg->xstats);
235 : 9 : free:
236 : 9 : free(reg);
237 : 10 : fail:
238 : 10 : return rc;
239 : : }
240 : :
241 : : RTE_EXPORT_SYMBOL(rte_node_clone)
242 : : rte_node_t
243 : 10 : rte_node_clone(rte_node_t id, const char *name)
244 : : {
245 : : struct node *node;
246 : :
247 [ - + ]: 10 : if (node_from_id(id) == NULL)
248 : 0 : goto fail;
249 : :
250 [ + - ]: 54 : STAILQ_FOREACH(node, &node_list, next)
251 [ + + ]: 54 : if (node->id == id)
252 : 10 : return node_clone(node, name);
253 : :
254 : 0 : fail:
255 : : return RTE_NODE_ID_INVALID;
256 : : }
257 : :
258 : : RTE_EXPORT_SYMBOL(rte_node_from_name)
259 : : rte_node_t
260 : 33 : rte_node_from_name(const char *name)
261 : : {
262 : : struct node *node;
263 : :
264 [ + - ]: 691 : STAILQ_FOREACH(node, &node_list, next)
265 [ + + ]: 691 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
266 : 33 : return node->id;
267 : :
268 : : return RTE_NODE_ID_INVALID;
269 : : }
270 : :
271 : : RTE_EXPORT_SYMBOL(rte_node_id_to_name)
272 : : char *
273 : 1377 : rte_node_id_to_name(rte_node_t id)
274 : : {
275 : : struct node *node;
276 : :
277 [ - + ]: 1377 : if (node_from_id(id) == NULL)
278 : 0 : goto fail;
279 [ + - ]: 11567 : STAILQ_FOREACH(node, &node_list, next)
280 [ + + ]: 11567 : if (node->id == id)
281 : 1377 : return node->name;
282 : :
283 : 0 : fail:
284 : : return NULL;
285 : : }
286 : :
287 : : RTE_EXPORT_SYMBOL(rte_node_edge_count)
288 : : rte_edge_t
289 : 19 : rte_node_edge_count(rte_node_t id)
290 : : {
291 : : struct node *node;
292 : :
293 [ - + ]: 19 : if (node_from_id(id) == NULL)
294 : 0 : goto fail;
295 [ + - ]: 262 : STAILQ_FOREACH(node, &node_list, next)
296 [ + + ]: 262 : if (node->id == id)
297 : 19 : return node->nb_edges;
298 : 0 : fail:
299 : : return RTE_EDGE_ID_INVALID;
300 : : }
301 : :
302 : : static rte_edge_t
303 : 20 : edge_update(struct node *node, struct node *prev, rte_edge_t from,
304 : : const char **next_nodes, rte_edge_t nb_edges)
305 : : {
306 : : rte_edge_t i, max_edges, count = 0;
307 : : struct node *new_node;
308 : : bool need_realloc;
309 : : size_t sz;
310 : :
311 [ + + ]: 20 : if (from == RTE_EDGE_ID_INVALID)
312 : 16 : from = node->nb_edges;
313 : :
314 : : /* Don't create hole in next_nodes[] list */
315 [ - + ]: 20 : if (from > node->nb_edges) {
316 : 0 : rte_errno = ENOMEM;
317 : 0 : goto fail;
318 : : }
319 : :
320 : : /* Remove me from list */
321 [ - + - - : 264 : STAILQ_REMOVE(&node_list, node, node, next);
+ + + + ]
322 : :
323 : : /* Allocate the storage space for new node if required */
324 : 20 : max_edges = from + nb_edges;
325 : : need_realloc = max_edges > node->nb_edges;
326 [ + - ]: 20 : if (need_realloc) {
327 : 20 : sz = sizeof(struct node) + (max_edges * RTE_NODE_NAMESIZE);
328 : 20 : new_node = realloc(node, sz);
329 [ - + ]: 20 : if (new_node == NULL) {
330 : 0 : rte_errno = ENOMEM;
331 : 0 : goto restore;
332 : : } else {
333 : : node = new_node;
334 : : }
335 : : }
336 : :
337 : : /* Update the new nodes name */
338 [ + + ]: 41 : for (i = from; i < max_edges; i++, count++) {
339 [ - + ]: 21 : if (rte_strscpy(node->next_nodes[i], next_nodes[count],
340 : : RTE_NODE_NAMESIZE) < 0)
341 : 0 : goto restore;
342 : : }
343 : 20 : restore:
344 : : /* Update the linked list to point new node address in prev node */
345 [ + - ]: 20 : if (prev)
346 [ + + ]: 20 : STAILQ_INSERT_AFTER(&node_list, prev, node, next);
347 : : else
348 [ # # ]: 0 : STAILQ_INSERT_HEAD(&node_list, node, next);
349 : :
350 [ - + ]: 20 : if (need_realloc)
351 : 20 : node->nb_edges = max_edges;
352 : :
353 : 0 : fail:
354 : 20 : return count;
355 : : }
356 : :
357 : : RTE_EXPORT_SYMBOL(rte_node_edge_shrink)
358 : : rte_edge_t
359 : 3 : rte_node_edge_shrink(rte_node_t id, rte_edge_t size)
360 : : {
361 : : rte_edge_t rc = RTE_EDGE_ID_INVALID;
362 : : struct node *node;
363 : :
364 [ - + ]: 3 : if (node_from_id(id) == NULL)
365 : 0 : goto fail;
366 : 3 : graph_spinlock_lock();
367 : :
368 [ + - ]: 111 : STAILQ_FOREACH(node, &node_list, next) {
369 [ + + ]: 111 : if (node->id == id) {
370 [ - + ]: 3 : if (node->nb_edges < size) {
371 : 0 : rte_errno = E2BIG;
372 : : } else {
373 : 3 : node->nb_edges = size;
374 : : rc = size;
375 : : }
376 : : break;
377 : : }
378 : : }
379 : :
380 : 3 : graph_spinlock_unlock();
381 : 3 : fail:
382 : 3 : return rc;
383 : : }
384 : :
385 : : RTE_EXPORT_SYMBOL(rte_node_edge_update)
386 : : rte_edge_t
387 : 20 : rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes,
388 : : uint16_t nb_edges)
389 : : {
390 : : rte_edge_t rc = RTE_EDGE_ID_INVALID;
391 : : struct node *n, *prev;
392 : :
393 [ - + ]: 20 : if (node_from_id(id) == NULL)
394 : 0 : goto fail;
395 : 20 : graph_spinlock_lock();
396 : :
397 : : prev = NULL;
398 [ + - ]: 264 : STAILQ_FOREACH(n, &node_list, next) {
399 [ + + ]: 264 : if (n->id == id) {
400 : 20 : rc = edge_update(n, prev, from, next_nodes, nb_edges);
401 : 20 : break;
402 : : }
403 : : prev = n;
404 : : }
405 : :
406 : 20 : graph_spinlock_unlock();
407 : 20 : fail:
408 : 20 : return rc;
409 : : }
410 : :
411 : : static rte_node_t
412 : : node_copy_edges(struct node *node, char *next_nodes[])
413 : : {
414 : : rte_edge_t i;
415 : :
416 [ + + ]: 913 : for (i = 0; i < node->nb_edges; i++)
417 : 641 : next_nodes[i] = node->next_nodes[i];
418 : :
419 : 272 : return i;
420 : : }
421 : :
422 : : RTE_EXPORT_SYMBOL(rte_node_edge_get)
423 : : rte_node_t
424 : 550 : rte_node_edge_get(rte_node_t id, char *next_nodes[])
425 : : {
426 : : rte_node_t rc = RTE_NODE_ID_INVALID;
427 : : struct node *node;
428 : :
429 [ - + ]: 550 : if (node_from_id(id) == NULL)
430 : 0 : goto fail;
431 : 550 : graph_spinlock_lock();
432 : :
433 [ + - ]: 6048 : STAILQ_FOREACH(node, &node_list, next) {
434 [ + + ]: 6048 : if (node->id == id) {
435 [ + + ]: 550 : if (next_nodes == NULL)
436 : 278 : rc = sizeof(char *) * node->nb_edges;
437 : : else
438 : : rc = node_copy_edges(node, next_nodes);
439 : : break;
440 : : }
441 : : }
442 : :
443 : 550 : graph_spinlock_unlock();
444 : 550 : fail:
445 : 550 : return rc;
446 : : }
447 : :
448 : : static void
449 : 1 : node_scan_dump(FILE *f, rte_node_t id, bool all)
450 : : {
451 : : struct node *node;
452 : :
453 : : RTE_ASSERT(f != NULL);
454 [ - + ]: 1 : if (node_from_id(id) == NULL)
455 : 0 : goto fail;
456 : :
457 [ + + ]: 35 : STAILQ_FOREACH(node, &node_list, next) {
458 [ + - ]: 34 : if (all == true) {
459 : 34 : node_dump(f, node);
460 [ # # ]: 0 : } else if (node->id == id) {
461 : 0 : node_dump(f, node);
462 : 0 : return;
463 : : }
464 : : }
465 : 1 : fail:
466 : : return;
467 : : }
468 : :
469 : : RTE_EXPORT_SYMBOL(rte_node_dump)
470 : : void
471 : 0 : rte_node_dump(FILE *f, rte_node_t id)
472 : : {
473 : 0 : node_scan_dump(f, id, false);
474 : 0 : }
475 : :
476 : : RTE_EXPORT_SYMBOL(rte_node_list_dump)
477 : : void
478 : 1 : rte_node_list_dump(FILE *f)
479 : : {
480 : 1 : node_scan_dump(f, 0, true);
481 : 1 : }
482 : :
483 : : RTE_EXPORT_SYMBOL(rte_node_max_count)
484 : : rte_node_t
485 : 0 : rte_node_max_count(void)
486 : : {
487 : : rte_node_t node_id = 0;
488 : : struct node *node;
489 : :
490 [ # # ]: 0 : STAILQ_FOREACH(node, &node_list, next) {
491 : 0 : if (node_id < node->id)
492 : : node_id = node->id;
493 : : }
494 : 0 : return node_id;
495 : : }
496 : :
497 : : int
498 : 26 : node_override_process_func(rte_node_t id, rte_node_process_t process)
499 : : {
500 : : struct node *node;
501 : :
502 [ - + ]: 26 : if (node_from_id(id) == NULL)
503 : 0 : goto fail;
504 : 26 : graph_spinlock_lock();
505 : :
506 [ + - ]: 270 : STAILQ_FOREACH(node, &node_list, next) {
507 [ + + ]: 270 : if (node->id == id) {
508 : 26 : node->process = process;
509 : 26 : graph_spinlock_unlock();
510 : 26 : return 0;
511 : : }
512 : : }
513 : :
514 : 0 : graph_spinlock_unlock();
515 : :
516 : : fail:
517 : : return -1;
518 : : }
519 : :
520 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_free, 25.07)
521 : : int
522 : 8 : rte_node_free(rte_node_t id)
523 : : {
524 : : struct node *node;
525 : : int rc = -1;
526 : :
527 [ - + ]: 8 : if (node_from_id(id) == NULL)
528 : 0 : goto fail;
529 : :
530 : 8 : graph_spinlock_lock();
531 [ + - ]: 295 : STAILQ_FOREACH(node, &node_list, next) {
532 [ + + ]: 295 : if (id == node->id) {
533 [ + - ]: 8 : if (!graph_is_node_active_in_graph(node)) {
534 [ - + - - : 295 : STAILQ_REMOVE(&node_list, node, node, next);
+ + + + ]
535 : 8 : free(node);
536 : : rc = 0;
537 : : }
538 : : break;
539 : : }
540 : : }
541 : 8 : graph_spinlock_unlock();
542 : 8 : fail:
543 : 8 : return rc;
544 : : }
|