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