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