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