1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2020 Marvell International Ltd. 3 */ 4 5 #include <fnmatch.h> 6 #include <stdbool.h> 7 #include <stdlib.h> 8 9 #include <rte_common.h> 10 #include <rte_debug.h> 11 #include <rte_errno.h> 12 #include <rte_malloc.h> 13 #include <rte_memzone.h> 14 #include <rte_spinlock.h> 15 #include <rte_string_fns.h> 16 17 #include "graph_private.h" 18 #include "graph_pcap_private.h" 19 20 static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list); 21 static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER; 22 static rte_graph_t graph_id; 23 24 #define GRAPH_ID_CHECK(id) ID_CHECK(id, graph_id) 25 26 /* Private functions */ 27 struct graph_head * 28 graph_list_head_get(void) 29 { 30 return &graph_list; 31 } 32 33 void 34 graph_spinlock_lock(void) 35 { 36 rte_spinlock_lock(&graph_lock); 37 } 38 39 void 40 graph_spinlock_unlock(void) 41 { 42 rte_spinlock_unlock(&graph_lock); 43 } 44 45 static int 46 graph_node_add(struct graph *graph, struct node *node) 47 { 48 struct graph_node *graph_node; 49 size_t sz; 50 51 /* Skip the duplicate nodes */ 52 STAILQ_FOREACH(graph_node, &graph->node_list, next) 53 if (strncmp(node->name, graph_node->node->name, 54 RTE_NODE_NAMESIZE) == 0) 55 return 0; 56 57 /* Allocate new graph node object */ 58 sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *); 59 graph_node = calloc(1, sz); 60 61 if (graph_node == NULL) 62 SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object", 63 node->name); 64 65 /* Initialize the graph node */ 66 graph_node->node = node; 67 68 /* Add to graph node list */ 69 STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next); 70 return 0; 71 72 free: 73 free(graph_node); 74 return -rte_errno; 75 } 76 77 static struct graph_node * 78 node_to_graph_node(struct graph *graph, struct node *node) 79 { 80 struct graph_node *graph_node; 81 82 STAILQ_FOREACH(graph_node, &graph->node_list, next) 83 if (graph_node->node == node) 84 return graph_node; 85 86 SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name); 87 fail: 88 return NULL; 89 } 90 91 static int 92 graph_node_edges_add(struct graph *graph) 93 { 94 struct graph_node *graph_node; 95 struct node *adjacency; 96 const char *next; 97 rte_edge_t i; 98 99 STAILQ_FOREACH(graph_node, &graph->node_list, next) { 100 for (i = 0; i < graph_node->node->nb_edges; i++) { 101 next = graph_node->node->next_nodes[i]; 102 adjacency = node_from_name(next); 103 if (adjacency == NULL) 104 SET_ERR_JMP(EINVAL, fail, 105 "Node %s not registered", next); 106 if (graph_node_add(graph, adjacency)) 107 goto fail; 108 } 109 } 110 return 0; 111 fail: 112 return -rte_errno; 113 } 114 115 static int 116 graph_adjacency_list_update(struct graph *graph) 117 { 118 struct graph_node *graph_node, *tmp; 119 struct node *adjacency; 120 const char *next; 121 rte_edge_t i; 122 123 STAILQ_FOREACH(graph_node, &graph->node_list, next) { 124 for (i = 0; i < graph_node->node->nb_edges; i++) { 125 next = graph_node->node->next_nodes[i]; 126 adjacency = node_from_name(next); 127 if (adjacency == NULL) 128 SET_ERR_JMP(EINVAL, fail, 129 "Node %s not registered", next); 130 tmp = node_to_graph_node(graph, adjacency); 131 if (tmp == NULL) 132 goto fail; 133 graph_node->adjacency_list[i] = tmp; 134 } 135 } 136 137 return 0; 138 fail: 139 return -rte_errno; 140 } 141 142 static int 143 expand_pattern_to_node(struct graph *graph, const char *pattern) 144 { 145 struct node_head *node_head = node_list_head_get(); 146 bool found = false; 147 struct node *node; 148 149 /* Check for pattern match */ 150 STAILQ_FOREACH(node, node_head, next) { 151 if (fnmatch(pattern, node->name, 0) == 0) { 152 if (graph_node_add(graph, node)) 153 goto fail; 154 found = true; 155 } 156 } 157 if (found == false) 158 SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern); 159 160 return 0; 161 fail: 162 return -rte_errno; 163 } 164 165 static void 166 graph_cleanup(struct graph *graph) 167 { 168 struct graph_node *graph_node; 169 170 while (!STAILQ_EMPTY(&graph->node_list)) { 171 graph_node = STAILQ_FIRST(&graph->node_list); 172 STAILQ_REMOVE_HEAD(&graph->node_list, next); 173 free(graph_node); 174 } 175 } 176 177 static int 178 graph_node_init(struct graph *graph) 179 { 180 struct graph_node *graph_node; 181 const char *name; 182 int rc; 183 184 STAILQ_FOREACH(graph_node, &graph->node_list, next) { 185 if (graph_node->node->init) { 186 name = graph_node->node->name; 187 rc = graph_node->node->init( 188 graph->graph, 189 graph_node_name_to_ptr(graph->graph, name)); 190 if (rc) 191 SET_ERR_JMP(rc, err, "Node %s init() failed", 192 name); 193 } 194 } 195 196 return 0; 197 err: 198 return -rte_errno; 199 } 200 201 static void 202 graph_node_fini(struct graph *graph) 203 { 204 struct graph_node *graph_node; 205 206 STAILQ_FOREACH(graph_node, &graph->node_list, next) 207 if (graph_node->node->fini) 208 graph_node->node->fini( 209 graph->graph, 210 graph_node_name_to_ptr(graph->graph, 211 graph_node->node->name)); 212 } 213 214 static struct rte_graph * 215 graph_mem_fixup_node_ctx(struct rte_graph *graph) 216 { 217 struct rte_node *node; 218 struct node *node_db; 219 rte_graph_off_t off; 220 rte_node_t count; 221 const char *name; 222 223 rte_graph_foreach_node(count, off, graph, node) { 224 if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */ 225 name = node->name; 226 else /* Cloned node */ 227 name = node->parent; 228 229 node_db = node_from_name(name); 230 if (node_db == NULL) 231 SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name); 232 233 if (graph->pcap_enable) { 234 node->process = graph_pcap_dispatch; 235 node->original_process = node_db->process; 236 } else 237 node->process = node_db->process; 238 } 239 240 return graph; 241 fail: 242 return NULL; 243 } 244 245 static struct rte_graph * 246 graph_mem_fixup_secondary(struct rte_graph *graph) 247 { 248 if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY) 249 return graph; 250 251 if (graph_pcap_file_open(graph->pcap_filename) || graph_pcap_mp_init()) 252 graph_pcap_exit(graph); 253 254 return graph_mem_fixup_node_ctx(graph); 255 } 256 257 struct rte_graph * 258 rte_graph_lookup(const char *name) 259 { 260 const struct rte_memzone *mz; 261 struct rte_graph *rc = NULL; 262 263 mz = rte_memzone_lookup(name); 264 if (mz) 265 rc = mz->addr; 266 267 return graph_mem_fixup_secondary(rc); 268 } 269 270 rte_graph_t 271 rte_graph_create(const char *name, struct rte_graph_param *prm) 272 { 273 rte_node_t src_node_count; 274 struct graph *graph; 275 const char *pattern; 276 uint16_t i; 277 278 graph_spinlock_lock(); 279 280 /* Check arguments sanity */ 281 if (prm == NULL) 282 SET_ERR_JMP(EINVAL, fail, "Param should not be NULL"); 283 284 if (name == NULL) 285 SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL"); 286 287 /* Check for existence of duplicate graph */ 288 STAILQ_FOREACH(graph, &graph_list, next) 289 if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0) 290 SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s", 291 name); 292 293 /* Create graph object */ 294 graph = calloc(1, sizeof(*graph)); 295 if (graph == NULL) 296 SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object"); 297 298 /* Initialize the graph object */ 299 STAILQ_INIT(&graph->node_list); 300 if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0) 301 SET_ERR_JMP(E2BIG, free, "Too big name=%s", name); 302 303 /* Expand node pattern and add the nodes to the graph */ 304 for (i = 0; i < prm->nb_node_patterns; i++) { 305 pattern = prm->node_patterns[i]; 306 if (expand_pattern_to_node(graph, pattern)) 307 goto graph_cleanup; 308 } 309 310 /* Go over all the nodes edges and add them to the graph */ 311 if (graph_node_edges_add(graph)) 312 goto graph_cleanup; 313 314 /* Update adjacency list of all nodes in the graph */ 315 if (graph_adjacency_list_update(graph)) 316 goto graph_cleanup; 317 318 /* Make sure at least a source node present in the graph */ 319 src_node_count = graph_src_nodes_count(graph); 320 if (src_node_count == 0) 321 goto graph_cleanup; 322 323 /* Make sure no node is pointing to source node */ 324 if (graph_node_has_edge_to_src_node(graph)) 325 goto graph_cleanup; 326 327 /* Don't allow node has loop to self */ 328 if (graph_node_has_loop_edge(graph)) 329 goto graph_cleanup; 330 331 /* Do BFS from src nodes on the graph to find isolated nodes */ 332 if (graph_has_isolated_node(graph)) 333 goto graph_cleanup; 334 335 /* Initialize pcap config. */ 336 graph_pcap_enable(prm->pcap_enable); 337 338 /* Initialize graph object */ 339 graph->socket = prm->socket_id; 340 graph->src_node_count = src_node_count; 341 graph->node_count = graph_nodes_count(graph); 342 graph->id = graph_id; 343 graph->num_pkt_to_capture = prm->num_pkt_to_capture; 344 if (prm->pcap_filename) 345 rte_strscpy(graph->pcap_filename, prm->pcap_filename, RTE_GRAPH_PCAP_FILE_SZ); 346 347 /* Allocate the Graph fast path memory and populate the data */ 348 if (graph_fp_mem_create(graph)) 349 goto graph_cleanup; 350 351 /* Call init() of the all the nodes in the graph */ 352 if (graph_node_init(graph)) 353 goto graph_mem_destroy; 354 355 /* All good, Lets add the graph to the list */ 356 graph_id++; 357 STAILQ_INSERT_TAIL(&graph_list, graph, next); 358 359 graph_spinlock_unlock(); 360 return graph->id; 361 362 graph_mem_destroy: 363 graph_fp_mem_destroy(graph); 364 graph_cleanup: 365 graph_cleanup(graph); 366 free: 367 free(graph); 368 fail: 369 graph_spinlock_unlock(); 370 return RTE_GRAPH_ID_INVALID; 371 } 372 373 int 374 rte_graph_destroy(rte_graph_t id) 375 { 376 struct graph *graph, *tmp; 377 int rc = -ENOENT; 378 379 graph_spinlock_lock(); 380 381 graph = STAILQ_FIRST(&graph_list); 382 while (graph != NULL) { 383 tmp = STAILQ_NEXT(graph, next); 384 if (graph->id == id) { 385 /* Call fini() of the all the nodes in the graph */ 386 graph_node_fini(graph); 387 /* Destroy graph fast path memory */ 388 rc = graph_fp_mem_destroy(graph); 389 if (rc) 390 SET_ERR_JMP(rc, done, "Graph %s destroy failed", 391 graph->name); 392 393 graph_cleanup(graph); 394 STAILQ_REMOVE(&graph_list, graph, graph, next); 395 free(graph); 396 graph_id--; 397 goto done; 398 } 399 graph = tmp; 400 } 401 done: 402 graph_spinlock_unlock(); 403 return rc; 404 } 405 406 rte_graph_t 407 rte_graph_from_name(const char *name) 408 { 409 struct graph *graph; 410 411 STAILQ_FOREACH(graph, &graph_list, next) 412 if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) 413 return graph->id; 414 415 return RTE_GRAPH_ID_INVALID; 416 } 417 418 char * 419 rte_graph_id_to_name(rte_graph_t id) 420 { 421 struct graph *graph; 422 423 GRAPH_ID_CHECK(id); 424 STAILQ_FOREACH(graph, &graph_list, next) 425 if (graph->id == id) 426 return graph->name; 427 428 fail: 429 return NULL; 430 } 431 432 struct rte_node * 433 rte_graph_node_get(rte_graph_t gid, uint32_t nid) 434 { 435 struct rte_node *node; 436 struct graph *graph; 437 rte_graph_off_t off; 438 rte_node_t count; 439 440 GRAPH_ID_CHECK(gid); 441 STAILQ_FOREACH(graph, &graph_list, next) 442 if (graph->id == gid) { 443 rte_graph_foreach_node(count, off, graph->graph, 444 node) { 445 if (node->id == nid) 446 return node; 447 } 448 break; 449 } 450 fail: 451 return NULL; 452 } 453 454 struct rte_node * 455 rte_graph_node_get_by_name(const char *graph_name, const char *node_name) 456 { 457 struct rte_node *node; 458 struct graph *graph; 459 rte_graph_off_t off; 460 rte_node_t count; 461 462 STAILQ_FOREACH(graph, &graph_list, next) 463 if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) { 464 rte_graph_foreach_node(count, off, graph->graph, 465 node) { 466 if (!strncmp(node->name, node_name, 467 RTE_NODE_NAMESIZE)) 468 return node; 469 } 470 break; 471 } 472 473 return NULL; 474 } 475 476 void __rte_noinline 477 __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) 478 { 479 uint16_t size = node->size; 480 481 RTE_VERIFY(size != UINT16_MAX); 482 /* Allocate double amount of size to avoid immediate realloc */ 483 size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2)); 484 node->objs = rte_realloc_socket(node->objs, size * sizeof(void *), 485 RTE_CACHE_LINE_SIZE, graph->socket); 486 RTE_VERIFY(node->objs); 487 node->size = size; 488 node->realloc_count++; 489 } 490 491 void __rte_noinline 492 __rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node, 493 uint16_t req_size) 494 { 495 uint16_t size = node->size; 496 497 RTE_VERIFY(size != UINT16_MAX); 498 /* Allocate double amount of size to avoid immediate realloc */ 499 size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2)); 500 node->objs = rte_realloc_socket(node->objs, size * sizeof(void *), 501 RTE_CACHE_LINE_SIZE, graph->socket); 502 RTE_VERIFY(node->objs); 503 node->size = size; 504 node->realloc_count++; 505 } 506 507 static int 508 graph_to_dot(FILE *f, struct graph *graph) 509 { 510 const char *src_edge_color = " [color=blue]\n"; 511 const char *edge_color = "\n"; 512 struct graph_node *graph_node; 513 char *node_name; 514 rte_edge_t i; 515 int rc; 516 517 rc = fprintf(f, "Digraph %s {\n\trankdir=LR;\n", graph->name); 518 if (rc < 0) 519 goto end; 520 521 STAILQ_FOREACH(graph_node, &graph->node_list, next) { 522 node_name = graph_node->node->name; 523 for (i = 0; i < graph_node->node->nb_edges; i++) { 524 rc = fprintf(f, "\t\"%s\"->\"%s\"%s", node_name, 525 graph_node->adjacency_list[i]->node->name, 526 graph_node->node->flags & RTE_NODE_SOURCE_F 527 ? src_edge_color 528 : edge_color); 529 if (rc < 0) 530 goto end; 531 } 532 } 533 rc = fprintf(f, "}\n"); 534 if (rc < 0) 535 goto end; 536 537 return 0; 538 end: 539 rte_errno = EBADF; 540 return -rte_errno; 541 } 542 543 int 544 rte_graph_export(const char *name, FILE *f) 545 { 546 struct graph *graph; 547 int rc = ENOENT; 548 549 STAILQ_FOREACH(graph, &graph_list, next) { 550 if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) { 551 rc = graph_to_dot(f, graph); 552 goto end; 553 } 554 } 555 end: 556 return -rc; 557 } 558 559 static void 560 graph_scan_dump(FILE *f, rte_graph_t id, bool all) 561 { 562 struct graph *graph; 563 564 RTE_VERIFY(f); 565 GRAPH_ID_CHECK(id); 566 567 STAILQ_FOREACH(graph, &graph_list, next) { 568 if (all == true) { 569 graph_dump(f, graph); 570 } else if (graph->id == id) { 571 graph_dump(f, graph); 572 return; 573 } 574 } 575 fail: 576 return; 577 } 578 579 void 580 rte_graph_dump(FILE *f, rte_graph_t id) 581 { 582 graph_scan_dump(f, id, false); 583 } 584 585 void 586 rte_graph_list_dump(FILE *f) 587 { 588 graph_scan_dump(f, 0, true); 589 } 590 591 rte_graph_t 592 rte_graph_max_count(void) 593 { 594 return graph_id; 595 } 596 597 RTE_LOG_REGISTER_DEFAULT(rte_graph_logtype, INFO); 598