0652d40c24fdb435a63278764e4a8e595b15058e
[dpdk.git] / lib / librte_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         graph_spinlock_lock();
65
66         /* Check sanity */
67         if (reg == NULL || reg->process == NULL) {
68                 rte_errno = EINVAL;
69                 goto fail;
70         }
71
72         /* Check for duplicate name */
73         if (node_has_duplicate_entry(reg->name))
74                 goto fail;
75
76         sz = sizeof(struct node) + (reg->nb_edges * RTE_NODE_NAMESIZE);
77         node = calloc(1, sz);
78         if (node == NULL) {
79                 rte_errno = ENOMEM;
80                 goto fail;
81         }
82
83         /* Initialize the node */
84         if (rte_strscpy(node->name, reg->name, RTE_NODE_NAMESIZE) < 0) {
85                 rte_errno = E2BIG;
86                 goto free;
87         }
88         node->flags = reg->flags;
89         node->process = reg->process;
90         node->init = reg->init;
91         node->fini = reg->fini;
92         node->nb_edges = reg->nb_edges;
93         node->parent_id = reg->parent_id;
94         for (i = 0; i < reg->nb_edges; i++) {
95                 if (rte_strscpy(node->next_nodes[i], reg->next_nodes[i],
96                                 RTE_NODE_NAMESIZE) < 0) {
97                         rte_errno = E2BIG;
98                         goto free;
99                 }
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         /* Check for duplicate name */
154         if (node_has_duplicate_entry(name))
155                 goto fail;
156
157         reg = calloc(1, sizeof(*reg) + (sizeof(char *) * node->nb_edges));
158         if (reg == NULL) {
159                 rte_errno = ENOMEM;
160                 goto fail;
161         }
162
163         /* Clone the source node */
164         reg->flags = node->flags;
165         reg->process = node->process;
166         reg->init = node->init;
167         reg->fini = node->fini;
168         reg->nb_edges = node->nb_edges;
169         reg->parent_id = node->id;
170
171         for (i = 0; i < node->nb_edges; i++)
172                 reg->next_nodes[i] = node->next_nodes[i];
173
174         /* Naming ceremony of the new node. name is node->name + "-" + name */
175         if (clone_name(reg, node, name))
176                 goto free;
177
178         rc = __rte_node_register(reg);
179 free:
180         free(reg);
181 fail:
182         return rc;
183 }
184
185 rte_node_t
186 rte_node_clone(rte_node_t id, const char *name)
187 {
188         struct node *node;
189
190         NODE_ID_CHECK(id);
191         STAILQ_FOREACH(node, &node_list, next)
192                 if (node->id == id)
193                         return node_clone(node, name);
194
195 fail:
196         return RTE_NODE_ID_INVALID;
197 }
198
199 rte_node_t
200 rte_node_from_name(const char *name)
201 {
202         struct node *node;
203
204         STAILQ_FOREACH(node, &node_list, next)
205                 if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0)
206                         return node->id;
207
208         return RTE_NODE_ID_INVALID;
209 }
210
211 char *
212 rte_node_id_to_name(rte_node_t id)
213 {
214         struct node *node;
215
216         NODE_ID_CHECK(id);
217         STAILQ_FOREACH(node, &node_list, next)
218                 if (node->id == id)
219                         return node->name;
220
221 fail:
222         return NULL;
223 }
224
225 rte_edge_t
226 rte_node_edge_count(rte_node_t id)
227 {
228         struct node *node;
229
230         NODE_ID_CHECK(id);
231         STAILQ_FOREACH(node, &node_list, next)
232                 if (node->id == id)
233                         return node->nb_edges;
234 fail:
235         return RTE_EDGE_ID_INVALID;
236 }
237
238 static rte_edge_t
239 edge_update(struct node *node, struct node *prev, rte_edge_t from,
240             const char **next_nodes, rte_edge_t nb_edges)
241 {
242         rte_edge_t i, max_edges, count = 0;
243         struct node *new_node;
244         bool need_realloc;
245         size_t sz;
246
247         if (from == RTE_EDGE_ID_INVALID)
248                 from = node->nb_edges;
249
250         /* Don't create hole in next_nodes[] list */
251         if (from > node->nb_edges) {
252                 rte_errno = ENOMEM;
253                 goto fail;
254         }
255
256         /* Remove me from list */
257         STAILQ_REMOVE(&node_list, node, node, next);
258
259         /* Allocate the storage space for new node if required */
260         max_edges = from + nb_edges;
261         need_realloc = max_edges > node->nb_edges;
262         if (need_realloc) {
263                 sz = sizeof(struct node) + (max_edges * RTE_NODE_NAMESIZE);
264                 new_node = realloc(node, sz);
265                 if (new_node == NULL) {
266                         rte_errno = ENOMEM;
267                         goto restore;
268                 } else {
269                         node = new_node;
270                 }
271         }
272
273         /* Update the new nodes name */
274         for (i = from; i < max_edges; i++, count++) {
275                 if (rte_strscpy(node->next_nodes[i], next_nodes[count],
276                                 RTE_NODE_NAMESIZE) < 0) {
277                         rte_errno = E2BIG;
278                         goto restore;
279                 }
280         }
281 restore:
282         /* Update the linked list to point new node address in prev node */
283         if (prev)
284                 STAILQ_INSERT_AFTER(&node_list, prev, node, next);
285         else
286                 STAILQ_INSERT_HEAD(&node_list, node, next);
287
288         if (need_realloc)
289                 node->nb_edges = max_edges;
290
291 fail:
292         return count;
293 }
294
295 rte_edge_t
296 rte_node_edge_shrink(rte_node_t id, rte_edge_t size)
297 {
298         rte_edge_t rc = RTE_EDGE_ID_INVALID;
299         struct node *node;
300
301         NODE_ID_CHECK(id);
302         graph_spinlock_lock();
303
304         STAILQ_FOREACH(node, &node_list, next) {
305                 if (node->id == id) {
306                         if (node->nb_edges < size) {
307                                 rte_errno = E2BIG;
308                                 goto fail;
309                         }
310                         node->nb_edges = size;
311                         rc = size;
312                         break;
313                 }
314         }
315
316 fail:
317         graph_spinlock_unlock();
318         return rc;
319 }
320
321 rte_edge_t
322 rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes,
323                      uint16_t nb_edges)
324 {
325         rte_edge_t rc = RTE_EDGE_ID_INVALID;
326         struct node *n, *prev;
327
328         NODE_ID_CHECK(id);
329         graph_spinlock_lock();
330
331         prev = NULL;
332         STAILQ_FOREACH(n, &node_list, next) {
333                 if (n->id == id) {
334                         rc = edge_update(n, prev, from, next_nodes, nb_edges);
335                         break;
336                 }
337                 prev = n;
338         }
339
340         graph_spinlock_unlock();
341 fail:
342         return rc;
343 }
344
345 static rte_node_t
346 node_copy_edges(struct node *node, char *next_nodes[])
347 {
348         rte_edge_t i;
349
350         for (i = 0; i < node->nb_edges; i++)
351                 next_nodes[i] = node->next_nodes[i];
352
353         return i;
354 }
355
356 rte_node_t
357 rte_node_edge_get(rte_node_t id, char *next_nodes[])
358 {
359         rte_node_t rc = RTE_NODE_ID_INVALID;
360         struct node *node;
361
362         NODE_ID_CHECK(id);
363         graph_spinlock_lock();
364
365         STAILQ_FOREACH(node, &node_list, next) {
366                 if (node->id == id) {
367                         if (next_nodes == NULL)
368                                 rc = sizeof(char *) * node->nb_edges;
369                         else
370                                 rc = node_copy_edges(node, next_nodes);
371                         break;
372                 }
373         }
374
375         graph_spinlock_unlock();
376 fail:
377         return rc;
378 }
379
380 static void
381 node_scan_dump(FILE *f, rte_node_t id, bool all)
382 {
383         struct node *node;
384
385         RTE_ASSERT(f != NULL);
386         NODE_ID_CHECK(id);
387
388         STAILQ_FOREACH(node, &node_list, next) {
389                 if (all == true) {
390                         node_dump(f, node);
391                 } else if (node->id == id) {
392                         node_dump(f, node);
393                         return;
394                 }
395         }
396 fail:
397         return;
398 }
399
400 void
401 rte_node_dump(FILE *f, rte_node_t id)
402 {
403         node_scan_dump(f, id, false);
404 }
405
406 void
407 rte_node_list_dump(FILE *f)
408 {
409         node_scan_dump(f, 0, true);
410 }
411
412 rte_node_t
413 rte_node_max_count(void)
414 {
415         return node_id;
416 }