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