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 : : static rte_node_t node_id;
20 : :
21 : : #define NODE_ID_CHECK(id) ID_CHECK(id, node_id)
22 : :
23 : : /* Private functions */
24 : : struct node_head *
25 : 20 : node_list_head_get(void)
26 : : {
27 : 20 : return &node_list;
28 : : }
29 : :
30 : : struct node *
31 : 123 : node_from_name(const char *name)
32 : : {
33 : : struct node *node;
34 : :
35 [ + - ]: 2096 : STAILQ_FOREACH(node, &node_list, next)
36 [ + + ]: 2096 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
37 : 123 : return node;
38 : :
39 : : return NULL;
40 : : }
41 : :
42 : : static bool
43 : 5046 : node_has_duplicate_entry(const char *name)
44 : : {
45 : : struct node *node;
46 : :
47 : : /* Is duplicate name registered */
48 [ + + ]: 53056 : STAILQ_FOREACH(node, &node_list, next) {
49 [ + + ]: 48011 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) {
50 : 1 : rte_errno = EEXIST;
51 : 1 : return 1;
52 : : }
53 : : }
54 : : return 0;
55 : : }
56 : :
57 : : /* Public functions */
58 : : RTE_EXPORT_SYMBOL(__rte_node_register)
59 : : rte_node_t
60 : 5046 : __rte_node_register(const struct rte_node_register *reg)
61 : : {
62 : : struct node *node;
63 : : rte_edge_t i;
64 : : size_t sz;
65 : :
66 : : /* Limit Node specific metadata to one cacheline on 64B CL machine */
67 : : RTE_BUILD_BUG_ON((offsetof(struct rte_node, nodes) -
68 : : offsetof(struct rte_node, ctx)) !=
69 : : RTE_CACHE_LINE_MIN_SIZE);
70 : :
71 : 5046 : graph_spinlock_lock();
72 : :
73 : : /* Check sanity */
74 [ + - - + ]: 5046 : if (reg == NULL || reg->process == NULL) {
75 : 0 : rte_errno = EINVAL;
76 : 0 : goto fail;
77 : : }
78 : :
79 : : /* Check for duplicate name */
80 [ + + ]: 5046 : if (node_has_duplicate_entry(reg->name))
81 : 1 : goto fail;
82 : :
83 : 5045 : sz = sizeof(struct node) + (reg->nb_edges * RTE_NODE_NAMESIZE);
84 : 5045 : node = calloc(1, sz);
85 [ - + ]: 5045 : if (node == NULL) {
86 : 0 : rte_errno = ENOMEM;
87 : 0 : goto fail;
88 : : }
89 : :
90 [ + + ]: 5045 : if (reg->xstats) {
91 : 504 : sz = sizeof(*reg->xstats) + (reg->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE);
92 : 504 : node->xstats = calloc(1, sz);
93 [ - + ]: 504 : if (node->xstats == NULL) {
94 : 0 : rte_errno = ENOMEM;
95 : 0 : goto free;
96 : : }
97 : :
98 : 504 : node->xstats->nb_xstats = reg->xstats->nb_xstats;
99 [ + + ]: 1008 : for (i = 0; i < reg->xstats->nb_xstats; i++)
100 [ - + ]: 504 : if (rte_strscpy(node->xstats->xstat_desc[i], reg->xstats->xstat_desc[i],
101 : : RTE_NODE_XSTAT_DESC_SIZE) < 0)
102 : 0 : goto free_xstat;
103 : : }
104 : :
105 : : /* Initialize the node */
106 [ - + ]: 5045 : if (rte_strscpy(node->name, reg->name, RTE_NODE_NAMESIZE) < 0)
107 : 0 : goto free_xstat;
108 : 5045 : node->flags = reg->flags;
109 : 5045 : node->process = reg->process;
110 : 5045 : node->init = reg->init;
111 : 5045 : node->fini = reg->fini;
112 : 5045 : node->nb_edges = reg->nb_edges;
113 : 5045 : node->parent_id = reg->parent_id;
114 [ + + ]: 10591 : for (i = 0; i < reg->nb_edges; i++) {
115 [ - + ]: 5546 : if (rte_strscpy(node->next_nodes[i], reg->next_nodes[i],
116 : : RTE_NODE_NAMESIZE) < 0)
117 : 0 : goto free_xstat;
118 : : }
119 : :
120 : 5045 : node->lcore_id = RTE_MAX_LCORE;
121 : 5045 : node->id = node_id++;
122 : :
123 : : /* Add the node at tail */
124 : 5045 : STAILQ_INSERT_TAIL(&node_list, node, next);
125 : 5045 : graph_spinlock_unlock();
126 : :
127 : 5045 : return node->id;
128 : 0 : free_xstat:
129 : 0 : free(node->xstats);
130 : 0 : free:
131 : 0 : free(node);
132 : 1 : fail:
133 : 1 : graph_spinlock_unlock();
134 : 1 : return RTE_NODE_ID_INVALID;
135 : : }
136 : :
137 : : static rte_node_t
138 : 7 : node_clone(struct node *node, const char *name)
139 : : {
140 : : rte_node_t rc = RTE_NODE_ID_INVALID;
141 : : struct rte_node_register *reg;
142 : : rte_edge_t i;
143 : :
144 : : /* Don't allow to clone a node from a cloned node */
145 [ + + ]: 7 : if (node->parent_id != RTE_NODE_ID_INVALID) {
146 : 1 : rte_errno = EEXIST;
147 : 1 : goto fail;
148 : : }
149 : :
150 : 6 : reg = calloc(1, sizeof(*reg) + (sizeof(char *) * node->nb_edges));
151 [ - + ]: 6 : if (reg == NULL) {
152 : 0 : rte_errno = ENOMEM;
153 : 0 : goto fail;
154 : : }
155 : :
156 [ - + ]: 6 : if (node->xstats) {
157 : 0 : reg->xstats = calloc(1, sizeof(*node->xstats) +
158 : 0 : (node->xstats->nb_xstats * RTE_NODE_XSTAT_DESC_SIZE));
159 [ # # ]: 0 : if (reg->xstats == NULL) {
160 : 0 : rte_errno = ENOMEM;
161 : 0 : goto free;
162 : : }
163 : :
164 [ # # ]: 0 : for (i = 0; i < node->xstats->nb_xstats; i++)
165 [ # # ]: 0 : if (rte_strscpy(reg->xstats->xstat_desc[i], node->xstats->xstat_desc[i],
166 : : RTE_NODE_XSTAT_DESC_SIZE) < 0)
167 : 0 : goto free_xstat;
168 : : }
169 : :
170 : : /* Clone the source node */
171 : 6 : reg->flags = node->flags;
172 : 6 : reg->process = node->process;
173 : 6 : reg->init = node->init;
174 : 6 : reg->fini = node->fini;
175 : 6 : reg->nb_edges = node->nb_edges;
176 : 6 : reg->parent_id = node->id;
177 : :
178 [ + + ]: 8 : for (i = 0; i < node->nb_edges; i++)
179 : 2 : reg->next_nodes[i] = node->next_nodes[i];
180 : :
181 : : /* Naming ceremony of the new node. name is node->name + "-" + name */
182 [ - + ]: 6 : if (clone_name(reg->name, node->name, name))
183 : 0 : goto free_xstat;
184 : :
185 : 6 : rc = __rte_node_register(reg);
186 : 6 : free_xstat:
187 : 6 : free(reg->xstats);
188 : 6 : free:
189 : 6 : free(reg);
190 : 7 : fail:
191 : 7 : return rc;
192 : : }
193 : :
194 : : RTE_EXPORT_SYMBOL(rte_node_clone)
195 : : rte_node_t
196 : 7 : rte_node_clone(rte_node_t id, const char *name)
197 : : {
198 : : struct node *node;
199 : :
200 [ - + ]: 7 : NODE_ID_CHECK(id);
201 [ + - ]: 34 : STAILQ_FOREACH(node, &node_list, next)
202 [ + + ]: 34 : if (node->id == id)
203 : 7 : return node_clone(node, name);
204 : :
205 : 0 : fail:
206 : : return RTE_NODE_ID_INVALID;
207 : : }
208 : :
209 : : RTE_EXPORT_SYMBOL(rte_node_from_name)
210 : : rte_node_t
211 : 32 : rte_node_from_name(const char *name)
212 : : {
213 : : struct node *node;
214 : :
215 [ + - ]: 437 : STAILQ_FOREACH(node, &node_list, next)
216 [ + + ]: 437 : if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
217 : 32 : return node->id;
218 : :
219 : : return RTE_NODE_ID_INVALID;
220 : : }
221 : :
222 : : RTE_EXPORT_SYMBOL(rte_node_id_to_name)
223 : : char *
224 : 33 : rte_node_id_to_name(rte_node_t id)
225 : : {
226 : : struct node *node;
227 : :
228 [ - + ]: 33 : NODE_ID_CHECK(id);
229 [ + - ]: 129 : STAILQ_FOREACH(node, &node_list, next)
230 [ + + ]: 129 : if (node->id == id)
231 : 33 : return node->name;
232 : :
233 : 0 : fail:
234 : : return NULL;
235 : : }
236 : :
237 : : RTE_EXPORT_SYMBOL(rte_node_edge_count)
238 : : rte_edge_t
239 : 3 : rte_node_edge_count(rte_node_t id)
240 : : {
241 : : struct node *node;
242 : :
243 [ - + ]: 3 : NODE_ID_CHECK(id);
244 [ + - ]: 69 : STAILQ_FOREACH(node, &node_list, next)
245 [ + + ]: 69 : if (node->id == id)
246 : 3 : return node->nb_edges;
247 : 0 : fail:
248 : : return RTE_EDGE_ID_INVALID;
249 : : }
250 : :
251 : : static rte_edge_t
252 : 4 : edge_update(struct node *node, struct node *prev, rte_edge_t from,
253 : : const char **next_nodes, rte_edge_t nb_edges)
254 : : {
255 : : rte_edge_t i, max_edges, count = 0;
256 : : struct node *new_node;
257 : : bool need_realloc;
258 : : size_t sz;
259 : :
260 [ - + ]: 4 : if (from == RTE_EDGE_ID_INVALID)
261 : 0 : from = node->nb_edges;
262 : :
263 : : /* Don't create hole in next_nodes[] list */
264 [ - + ]: 4 : if (from > node->nb_edges) {
265 : 0 : rte_errno = ENOMEM;
266 : 0 : goto fail;
267 : : }
268 : :
269 : : /* Remove me from list */
270 [ - + - - : 71 : STAILQ_REMOVE(&node_list, node, node, next);
+ + + + ]
271 : :
272 : : /* Allocate the storage space for new node if required */
273 : 4 : max_edges = from + nb_edges;
274 : : need_realloc = max_edges > node->nb_edges;
275 [ + - ]: 4 : if (need_realloc) {
276 : 4 : sz = sizeof(struct node) + (max_edges * RTE_NODE_NAMESIZE);
277 : 4 : new_node = realloc(node, sz);
278 [ - + ]: 4 : if (new_node == NULL) {
279 : 0 : rte_errno = ENOMEM;
280 : 0 : goto restore;
281 : : } else {
282 : : node = new_node;
283 : : }
284 : : }
285 : :
286 : : /* Update the new nodes name */
287 [ + + ]: 9 : for (i = from; i < max_edges; i++, count++) {
288 [ - + ]: 5 : if (rte_strscpy(node->next_nodes[i], next_nodes[count],
289 : : RTE_NODE_NAMESIZE) < 0)
290 : 0 : goto restore;
291 : : }
292 : 4 : restore:
293 : : /* Update the linked list to point new node address in prev node */
294 [ + - ]: 4 : if (prev)
295 [ + + ]: 4 : STAILQ_INSERT_AFTER(&node_list, prev, node, next);
296 : : else
297 [ # # ]: 0 : STAILQ_INSERT_HEAD(&node_list, node, next);
298 : :
299 [ - + ]: 4 : if (need_realloc)
300 : 4 : node->nb_edges = max_edges;
301 : :
302 : 0 : fail:
303 : 4 : return count;
304 : : }
305 : :
306 : : RTE_EXPORT_SYMBOL(rte_node_edge_shrink)
307 : : rte_edge_t
308 : 3 : rte_node_edge_shrink(rte_node_t id, rte_edge_t size)
309 : : {
310 : : rte_edge_t rc = RTE_EDGE_ID_INVALID;
311 : : struct node *node;
312 : :
313 [ - + ]: 3 : NODE_ID_CHECK(id);
314 : 3 : graph_spinlock_lock();
315 : :
316 [ + - ]: 69 : STAILQ_FOREACH(node, &node_list, next) {
317 [ + + ]: 69 : if (node->id == id) {
318 [ - + ]: 3 : if (node->nb_edges < size) {
319 : 0 : rte_errno = E2BIG;
320 : : } else {
321 : 3 : node->nb_edges = size;
322 : : rc = size;
323 : : }
324 : : break;
325 : : }
326 : : }
327 : :
328 : 3 : graph_spinlock_unlock();
329 : 3 : fail:
330 : 3 : return rc;
331 : : }
332 : :
333 : : RTE_EXPORT_SYMBOL(rte_node_edge_update)
334 : : rte_edge_t
335 : 4 : rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes,
336 : : uint16_t nb_edges)
337 : : {
338 : : rte_edge_t rc = RTE_EDGE_ID_INVALID;
339 : : struct node *n, *prev;
340 : :
341 [ - + ]: 4 : NODE_ID_CHECK(id);
342 : 4 : graph_spinlock_lock();
343 : :
344 : : prev = NULL;
345 [ + - ]: 71 : STAILQ_FOREACH(n, &node_list, next) {
346 [ + + ]: 71 : if (n->id == id) {
347 : 4 : rc = edge_update(n, prev, from, next_nodes, nb_edges);
348 : 4 : break;
349 : : }
350 : : prev = n;
351 : : }
352 : :
353 : 4 : graph_spinlock_unlock();
354 : 4 : fail:
355 : 4 : return rc;
356 : : }
357 : :
358 : : static rte_node_t
359 : : node_copy_edges(struct node *node, char *next_nodes[])
360 : : {
361 : : rte_edge_t i;
362 : :
363 [ + + ]: 6 : for (i = 0; i < node->nb_edges; i++)
364 : 3 : next_nodes[i] = node->next_nodes[i];
365 : :
366 : 3 : return i;
367 : : }
368 : :
369 : : RTE_EXPORT_SYMBOL(rte_node_edge_get)
370 : : rte_node_t
371 : 6 : rte_node_edge_get(rte_node_t id, char *next_nodes[])
372 : : {
373 : : rte_node_t rc = RTE_NODE_ID_INVALID;
374 : : struct node *node;
375 : :
376 [ - + ]: 6 : NODE_ID_CHECK(id);
377 : 6 : graph_spinlock_lock();
378 : :
379 [ + - ]: 138 : STAILQ_FOREACH(node, &node_list, next) {
380 [ + + ]: 138 : if (node->id == id) {
381 [ + + ]: 6 : if (next_nodes == NULL)
382 : 3 : rc = sizeof(char *) * node->nb_edges;
383 : : else
384 : : rc = node_copy_edges(node, next_nodes);
385 : : break;
386 : : }
387 : : }
388 : :
389 : 6 : graph_spinlock_unlock();
390 : 6 : fail:
391 : 6 : return rc;
392 : : }
393 : :
394 : : static void
395 : 1 : node_scan_dump(FILE *f, rte_node_t id, bool all)
396 : : {
397 : : struct node *node;
398 : :
399 : : RTE_ASSERT(f != NULL);
400 [ - + ]: 1 : NODE_ID_CHECK(id);
401 : :
402 [ + + ]: 21 : STAILQ_FOREACH(node, &node_list, next) {
403 [ + - ]: 20 : if (all == true) {
404 : 20 : node_dump(f, node);
405 [ # # ]: 0 : } else if (node->id == id) {
406 : 0 : node_dump(f, node);
407 : 0 : return;
408 : : }
409 : : }
410 : 1 : fail:
411 : : return;
412 : : }
413 : :
414 : : RTE_EXPORT_SYMBOL(rte_node_dump)
415 : : void
416 : 0 : rte_node_dump(FILE *f, rte_node_t id)
417 : : {
418 : 0 : node_scan_dump(f, id, false);
419 : 0 : }
420 : :
421 : : RTE_EXPORT_SYMBOL(rte_node_list_dump)
422 : : void
423 : 1 : rte_node_list_dump(FILE *f)
424 : : {
425 : 1 : node_scan_dump(f, 0, true);
426 : 1 : }
427 : :
428 : : RTE_EXPORT_SYMBOL(rte_node_max_count)
429 : : rte_node_t
430 : 0 : rte_node_max_count(void)
431 : : {
432 : 0 : return node_id;
433 : : }
|