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