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 /* 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 goto restore; 278 } 279 restore: 280 /* Update the linked list to point new node address in prev node */ 281 if (prev) 282 STAILQ_INSERT_AFTER(&node_list, prev, node, next); 283 else 284 STAILQ_INSERT_HEAD(&node_list, node, next); 285 286 if (need_realloc) 287 node->nb_edges = max_edges; 288 289 fail: 290 return count; 291 } 292 293 rte_edge_t 294 rte_node_edge_shrink(rte_node_t id, rte_edge_t size) 295 { 296 rte_edge_t rc = RTE_EDGE_ID_INVALID; 297 struct node *node; 298 299 NODE_ID_CHECK(id); 300 graph_spinlock_lock(); 301 302 STAILQ_FOREACH(node, &node_list, next) { 303 if (node->id == id) { 304 if (node->nb_edges < size) { 305 rte_errno = E2BIG; 306 goto fail; 307 } 308 node->nb_edges = size; 309 rc = size; 310 break; 311 } 312 } 313 314 fail: 315 graph_spinlock_unlock(); 316 return rc; 317 } 318 319 rte_edge_t 320 rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes, 321 uint16_t nb_edges) 322 { 323 rte_edge_t rc = RTE_EDGE_ID_INVALID; 324 struct node *n, *prev; 325 326 NODE_ID_CHECK(id); 327 graph_spinlock_lock(); 328 329 prev = NULL; 330 STAILQ_FOREACH(n, &node_list, next) { 331 if (n->id == id) { 332 rc = edge_update(n, prev, from, next_nodes, nb_edges); 333 break; 334 } 335 prev = n; 336 } 337 338 graph_spinlock_unlock(); 339 fail: 340 return rc; 341 } 342 343 static rte_node_t 344 node_copy_edges(struct node *node, char *next_nodes[]) 345 { 346 rte_edge_t i; 347 348 for (i = 0; i < node->nb_edges; i++) 349 next_nodes[i] = node->next_nodes[i]; 350 351 return i; 352 } 353 354 rte_node_t 355 rte_node_edge_get(rte_node_t id, char *next_nodes[]) 356 { 357 rte_node_t rc = RTE_NODE_ID_INVALID; 358 struct node *node; 359 360 NODE_ID_CHECK(id); 361 graph_spinlock_lock(); 362 363 STAILQ_FOREACH(node, &node_list, next) { 364 if (node->id == id) { 365 if (next_nodes == NULL) 366 rc = sizeof(char *) * node->nb_edges; 367 else 368 rc = node_copy_edges(node, next_nodes); 369 break; 370 } 371 } 372 373 graph_spinlock_unlock(); 374 fail: 375 return rc; 376 } 377 378 static void 379 node_scan_dump(FILE *f, rte_node_t id, bool all) 380 { 381 struct node *node; 382 383 RTE_ASSERT(f != NULL); 384 NODE_ID_CHECK(id); 385 386 STAILQ_FOREACH(node, &node_list, next) { 387 if (all == true) { 388 node_dump(f, node); 389 } else if (node->id == id) { 390 node_dump(f, node); 391 return; 392 } 393 } 394 fail: 395 return; 396 } 397 398 void 399 rte_node_dump(FILE *f, rte_node_t id) 400 { 401 node_scan_dump(f, id, false); 402 } 403 404 void 405 rte_node_list_dump(FILE *f) 406 { 407 node_scan_dump(f, 0, true); 408 } 409 410 rte_node_t 411 rte_node_max_count(void) 412 { 413 return node_id; 414 } 415