xref: /dpdk/lib/graph/node.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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 }
416