1 /* 2 * ng_base.c 3 */ 4 5 /*- 6 * Copyright (c) 1996-1999 Whistle Communications, Inc. 7 * All rights reserved. 8 * 9 * Subject to the following obligations and disclaimer of warranty, use and 10 * redistribution of this software, in source or object code forms, with or 11 * without modifications are expressly permitted by Whistle Communications; 12 * provided, however, that: 13 * 1. Any and all reproductions of the source or object code must include the 14 * copyright notice above and the following disclaimer of warranties; and 15 * 2. No rights are granted, in any manner or form, to use Whistle 16 * Communications, Inc. trademarks, including the mark "WHISTLE 17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18 * such appears in the above copyright notice or in the software. 19 * 20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36 * OF SUCH DAMAGE. 37 * 38 * Authors: Julian Elischer <julian@freebsd.org> 39 * Archie Cobbs <archie@freebsd.org> 40 * 41 * $FreeBSD$ 42 * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 43 */ 44 45 /* 46 * This file implements the base netgraph code. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/ctype.h> 52 #include <sys/errno.h> 53 #include <sys/kdb.h> 54 #include <sys/kernel.h> 55 #include <sys/ktr.h> 56 #include <sys/limits.h> 57 #include <sys/malloc.h> 58 #include <sys/mbuf.h> 59 #include <sys/queue.h> 60 #include <sys/sysctl.h> 61 #include <sys/syslog.h> 62 #include <sys/refcount.h> 63 #include <sys/proc.h> 64 #include <sys/vimage.h> 65 #include <machine/cpu.h> 66 67 #include <net/netisr.h> 68 69 #include <netgraph/ng_message.h> 70 #include <netgraph/netgraph.h> 71 #include <netgraph/ng_parse.h> 72 73 MODULE_VERSION(netgraph, NG_ABI_VERSION); 74 75 /* Mutex to protect topology events. */ 76 static struct mtx ng_topo_mtx; 77 78 #ifdef NETGRAPH_DEBUG 79 static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */ 80 static struct mtx ngq_mtx; /* protects the queue item list */ 81 82 static SLIST_HEAD(, ng_node) ng_allnodes; 83 static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */ 84 static SLIST_HEAD(, ng_hook) ng_allhooks; 85 static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */ 86 87 static void ng_dumpitems(void); 88 static void ng_dumpnodes(void); 89 static void ng_dumphooks(void); 90 91 #endif /* NETGRAPH_DEBUG */ 92 /* 93 * DEAD versions of the structures. 94 * In order to avoid races, it is sometimes neccesary to point 95 * at SOMETHING even though theoretically, the current entity is 96 * INVALID. Use these to avoid these races. 97 */ 98 struct ng_type ng_deadtype = { 99 NG_ABI_VERSION, 100 "dead", 101 NULL, /* modevent */ 102 NULL, /* constructor */ 103 NULL, /* rcvmsg */ 104 NULL, /* shutdown */ 105 NULL, /* newhook */ 106 NULL, /* findhook */ 107 NULL, /* connect */ 108 NULL, /* rcvdata */ 109 NULL, /* disconnect */ 110 NULL, /* cmdlist */ 111 }; 112 113 struct ng_node ng_deadnode = { 114 "dead", 115 &ng_deadtype, 116 NGF_INVALID, 117 0, /* numhooks */ 118 NULL, /* private */ 119 0, /* ID */ 120 LIST_HEAD_INITIALIZER(ng_deadnode.hooks), 121 {}, /* all_nodes list entry */ 122 {}, /* id hashtable list entry */ 123 { 0, 124 0, 125 {}, /* should never use! (should hang) */ 126 {}, /* workqueue entry */ 127 STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue), 128 }, 129 1, /* refs */ 130 #ifdef NETGRAPH_DEBUG 131 ND_MAGIC, 132 __FILE__, 133 __LINE__, 134 {NULL} 135 #endif /* NETGRAPH_DEBUG */ 136 }; 137 138 struct ng_hook ng_deadhook = { 139 "dead", 140 NULL, /* private */ 141 HK_INVALID | HK_DEAD, 142 0, /* undefined data link type */ 143 &ng_deadhook, /* Peer is self */ 144 &ng_deadnode, /* attached to deadnode */ 145 {}, /* hooks list */ 146 NULL, /* override rcvmsg() */ 147 NULL, /* override rcvdata() */ 148 1, /* refs always >= 1 */ 149 #ifdef NETGRAPH_DEBUG 150 HK_MAGIC, 151 __FILE__, 152 __LINE__, 153 {NULL} 154 #endif /* NETGRAPH_DEBUG */ 155 }; 156 157 /* 158 * END DEAD STRUCTURES 159 */ 160 /* List nodes with unallocated work */ 161 static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist); 162 static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */ 163 164 /* List of installed types */ 165 static LIST_HEAD(, ng_type) ng_typelist; 166 static struct mtx ng_typelist_mtx; 167 168 /* Hash related definitions */ 169 /* XXX Don't need to initialise them because it's a LIST */ 170 static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE]; 171 static struct mtx ng_idhash_mtx; 172 /* Method to find a node.. used twice so do it here */ 173 #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE)) 174 #define NG_IDHASH_FIND(ID, node) \ 175 do { \ 176 mtx_assert(&ng_idhash_mtx, MA_OWNED); \ 177 LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \ 178 nd_idnodes) { \ 179 if (NG_NODE_IS_VALID(node) \ 180 && (NG_NODE_ID(node) == ID)) { \ 181 break; \ 182 } \ 183 } \ 184 } while (0) 185 186 #define NG_NAME_HASH_SIZE 128 /* most systems wont need even this many */ 187 static LIST_HEAD(, ng_node) ng_name_hash[NG_NAME_HASH_SIZE]; 188 static struct mtx ng_namehash_mtx; 189 #define NG_NAMEHASH(NAME, HASH) \ 190 do { \ 191 u_char h = 0; \ 192 const u_char *c; \ 193 for (c = (const u_char*)(NAME); *c; c++)\ 194 h += *c; \ 195 (HASH) = h % (NG_NAME_HASH_SIZE); \ 196 } while (0) 197 198 199 /* Internal functions */ 200 static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 201 static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); 202 static ng_ID_t ng_decodeidname(const char *name); 203 static int ngb_mod_event(module_t mod, int event, void *data); 204 static void ng_worklist_add(node_p node); 205 static void ngintr(void); 206 static int ng_apply_item(node_p node, item_p item, int rw); 207 static void ng_flush_input_queue(node_p node); 208 static node_p ng_ID2noderef(ng_ID_t ID); 209 static int ng_con_nodes(item_p item, node_p node, const char *name, 210 node_p node2, const char *name2); 211 static int ng_con_part2(node_p node, item_p item, hook_p hook); 212 static int ng_con_part3(node_p node, item_p item, hook_p hook); 213 static int ng_mkpeer(node_p node, const char *name, 214 const char *name2, char *type); 215 216 /* Imported, these used to be externally visible, some may go back. */ 217 void ng_destroy_hook(hook_p hook); 218 node_p ng_name2noderef(node_p node, const char *name); 219 int ng_path2noderef(node_p here, const char *path, 220 node_p *dest, hook_p *lasthook); 221 int ng_make_node(const char *type, node_p *nodepp); 222 int ng_path_parse(char *addr, char **node, char **path, char **hook); 223 void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3); 224 void ng_unname(node_p node); 225 226 227 /* Our own netgraph malloc type */ 228 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 229 MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures"); 230 MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures"); 231 MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures"); 232 MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); 233 234 /* Should not be visible outside this file */ 235 236 #define _NG_ALLOC_HOOK(hook) \ 237 hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO) 238 #define _NG_ALLOC_NODE(node) \ 239 node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO) 240 241 #define NG_QUEUE_LOCK_INIT(n) \ 242 mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF) 243 #define NG_QUEUE_LOCK(n) \ 244 mtx_lock(&(n)->q_mtx) 245 #define NG_QUEUE_UNLOCK(n) \ 246 mtx_unlock(&(n)->q_mtx) 247 #define NG_WORKLIST_LOCK_INIT() \ 248 mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF) 249 #define NG_WORKLIST_LOCK() \ 250 mtx_lock(&ng_worklist_mtx) 251 #define NG_WORKLIST_UNLOCK() \ 252 mtx_unlock(&ng_worklist_mtx) 253 254 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 255 /* 256 * In debug mode: 257 * In an attempt to help track reference count screwups 258 * we do not free objects back to the malloc system, but keep them 259 * in a local cache where we can examine them and keep information safely 260 * after they have been freed. 261 * We use this scheme for nodes and hooks, and to some extent for items. 262 */ 263 static __inline hook_p 264 ng_alloc_hook(void) 265 { 266 hook_p hook; 267 SLIST_ENTRY(ng_hook) temp; 268 mtx_lock(&ng_nodelist_mtx); 269 hook = LIST_FIRST(&ng_freehooks); 270 if (hook) { 271 LIST_REMOVE(hook, hk_hooks); 272 bcopy(&hook->hk_all, &temp, sizeof(temp)); 273 bzero(hook, sizeof(struct ng_hook)); 274 bcopy(&temp, &hook->hk_all, sizeof(temp)); 275 mtx_unlock(&ng_nodelist_mtx); 276 hook->hk_magic = HK_MAGIC; 277 } else { 278 mtx_unlock(&ng_nodelist_mtx); 279 _NG_ALLOC_HOOK(hook); 280 if (hook) { 281 hook->hk_magic = HK_MAGIC; 282 mtx_lock(&ng_nodelist_mtx); 283 SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all); 284 mtx_unlock(&ng_nodelist_mtx); 285 } 286 } 287 return (hook); 288 } 289 290 static __inline node_p 291 ng_alloc_node(void) 292 { 293 node_p node; 294 SLIST_ENTRY(ng_node) temp; 295 mtx_lock(&ng_nodelist_mtx); 296 node = LIST_FIRST(&ng_freenodes); 297 if (node) { 298 LIST_REMOVE(node, nd_nodes); 299 bcopy(&node->nd_all, &temp, sizeof(temp)); 300 bzero(node, sizeof(struct ng_node)); 301 bcopy(&temp, &node->nd_all, sizeof(temp)); 302 mtx_unlock(&ng_nodelist_mtx); 303 node->nd_magic = ND_MAGIC; 304 } else { 305 mtx_unlock(&ng_nodelist_mtx); 306 _NG_ALLOC_NODE(node); 307 if (node) { 308 node->nd_magic = ND_MAGIC; 309 mtx_lock(&ng_nodelist_mtx); 310 SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all); 311 mtx_unlock(&ng_nodelist_mtx); 312 } 313 } 314 return (node); 315 } 316 317 #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0) 318 #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0) 319 320 321 #define NG_FREE_HOOK(hook) \ 322 do { \ 323 mtx_lock(&ng_nodelist_mtx); \ 324 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \ 325 hook->hk_magic = 0; \ 326 mtx_unlock(&ng_nodelist_mtx); \ 327 } while (0) 328 329 #define NG_FREE_NODE(node) \ 330 do { \ 331 mtx_lock(&ng_nodelist_mtx); \ 332 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \ 333 node->nd_magic = 0; \ 334 mtx_unlock(&ng_nodelist_mtx); \ 335 } while (0) 336 337 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 338 339 #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook) 340 #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node) 341 342 #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0) 343 #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0) 344 345 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 346 347 /* Set this to kdb_enter("X") to catch all errors as they occur */ 348 #ifndef TRAP_ERROR 349 #define TRAP_ERROR() 350 #endif 351 352 static ng_ID_t nextID = 1; 353 354 #ifdef INVARIANTS 355 #define CHECK_DATA_MBUF(m) do { \ 356 struct mbuf *n; \ 357 int total; \ 358 \ 359 M_ASSERTPKTHDR(m); \ 360 for (total = 0, n = (m); n != NULL; n = n->m_next) { \ 361 total += n->m_len; \ 362 if (n->m_nextpkt != NULL) \ 363 panic("%s: m_nextpkt", __func__); \ 364 } \ 365 \ 366 if ((m)->m_pkthdr.len != total) { \ 367 panic("%s: %d != %d", \ 368 __func__, (m)->m_pkthdr.len, total); \ 369 } \ 370 } while (0) 371 #else 372 #define CHECK_DATA_MBUF(m) 373 #endif 374 375 #define ERROUT(x) do { error = (x); goto done; } while (0) 376 377 /************************************************************************ 378 Parse type definitions for generic messages 379 ************************************************************************/ 380 381 /* Handy structure parse type defining macro */ 382 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 383 static const struct ng_parse_struct_field \ 384 ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 385 static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 386 &ng_parse_struct_type, \ 387 &ng_ ## lo ## _type_fields \ 388 } 389 390 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 391 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 392 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 393 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 394 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 395 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 396 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 397 398 /* Get length of an array when the length is stored as a 32 bit 399 value immediately preceding the array -- as with struct namelist 400 and struct typelist. */ 401 static int 402 ng_generic_list_getLength(const struct ng_parse_type *type, 403 const u_char *start, const u_char *buf) 404 { 405 return *((const u_int32_t *)(buf - 4)); 406 } 407 408 /* Get length of the array of struct linkinfo inside a struct hooklist */ 409 static int 410 ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 411 const u_char *start, const u_char *buf) 412 { 413 const struct hooklist *hl = (const struct hooklist *)start; 414 415 return hl->nodeinfo.hooks; 416 } 417 418 /* Array type for a variable length array of struct namelist */ 419 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 420 &ng_generic_nodeinfo_type, 421 &ng_generic_list_getLength 422 }; 423 static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 424 &ng_parse_array_type, 425 &ng_nodeinfoarray_type_info 426 }; 427 428 /* Array type for a variable length array of struct typelist */ 429 static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 430 &ng_generic_typeinfo_type, 431 &ng_generic_list_getLength 432 }; 433 static const struct ng_parse_type ng_generic_typeinfoarray_type = { 434 &ng_parse_array_type, 435 &ng_typeinfoarray_type_info 436 }; 437 438 /* Array type for array of struct linkinfo in struct hooklist */ 439 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 440 &ng_generic_linkinfo_type, 441 &ng_generic_linkinfo_getLength 442 }; 443 static const struct ng_parse_type ng_generic_linkinfo_array_type = { 444 &ng_parse_array_type, 445 &ng_generic_linkinfo_array_type_info 446 }; 447 448 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 449 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 450 (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 451 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 452 (&ng_generic_nodeinfoarray_type)); 453 454 /* List of commands and how to convert arguments to/from ASCII */ 455 static const struct ng_cmdlist ng_generic_cmds[] = { 456 { 457 NGM_GENERIC_COOKIE, 458 NGM_SHUTDOWN, 459 "shutdown", 460 NULL, 461 NULL 462 }, 463 { 464 NGM_GENERIC_COOKIE, 465 NGM_MKPEER, 466 "mkpeer", 467 &ng_generic_mkpeer_type, 468 NULL 469 }, 470 { 471 NGM_GENERIC_COOKIE, 472 NGM_CONNECT, 473 "connect", 474 &ng_generic_connect_type, 475 NULL 476 }, 477 { 478 NGM_GENERIC_COOKIE, 479 NGM_NAME, 480 "name", 481 &ng_generic_name_type, 482 NULL 483 }, 484 { 485 NGM_GENERIC_COOKIE, 486 NGM_RMHOOK, 487 "rmhook", 488 &ng_generic_rmhook_type, 489 NULL 490 }, 491 { 492 NGM_GENERIC_COOKIE, 493 NGM_NODEINFO, 494 "nodeinfo", 495 NULL, 496 &ng_generic_nodeinfo_type 497 }, 498 { 499 NGM_GENERIC_COOKIE, 500 NGM_LISTHOOKS, 501 "listhooks", 502 NULL, 503 &ng_generic_hooklist_type 504 }, 505 { 506 NGM_GENERIC_COOKIE, 507 NGM_LISTNAMES, 508 "listnames", 509 NULL, 510 &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 511 }, 512 { 513 NGM_GENERIC_COOKIE, 514 NGM_LISTNODES, 515 "listnodes", 516 NULL, 517 &ng_generic_listnodes_type 518 }, 519 { 520 NGM_GENERIC_COOKIE, 521 NGM_LISTTYPES, 522 "listtypes", 523 NULL, 524 &ng_generic_typeinfo_type 525 }, 526 { 527 NGM_GENERIC_COOKIE, 528 NGM_TEXT_CONFIG, 529 "textconfig", 530 NULL, 531 &ng_parse_string_type 532 }, 533 { 534 NGM_GENERIC_COOKIE, 535 NGM_TEXT_STATUS, 536 "textstatus", 537 NULL, 538 &ng_parse_string_type 539 }, 540 { 541 NGM_GENERIC_COOKIE, 542 NGM_ASCII2BINARY, 543 "ascii2binary", 544 &ng_parse_ng_mesg_type, 545 &ng_parse_ng_mesg_type 546 }, 547 { 548 NGM_GENERIC_COOKIE, 549 NGM_BINARY2ASCII, 550 "binary2ascii", 551 &ng_parse_ng_mesg_type, 552 &ng_parse_ng_mesg_type 553 }, 554 { 0 } 555 }; 556 557 /************************************************************************ 558 Node routines 559 ************************************************************************/ 560 561 /* 562 * Instantiate a node of the requested type 563 */ 564 int 565 ng_make_node(const char *typename, node_p *nodepp) 566 { 567 struct ng_type *type; 568 int error; 569 570 /* Check that the type makes sense */ 571 if (typename == NULL) { 572 TRAP_ERROR(); 573 return (EINVAL); 574 } 575 576 /* Locate the node type. If we fail we return. Do not try to load 577 * module. 578 */ 579 if ((type = ng_findtype(typename)) == NULL) 580 return (ENXIO); 581 582 /* 583 * If we have a constructor, then make the node and 584 * call the constructor to do type specific initialisation. 585 */ 586 if (type->constructor != NULL) { 587 if ((error = ng_make_node_common(type, nodepp)) == 0) { 588 if ((error = ((*type->constructor)(*nodepp)) != 0)) { 589 NG_NODE_UNREF(*nodepp); 590 } 591 } 592 } else { 593 /* 594 * Node has no constructor. We cannot ask for one 595 * to be made. It must be brought into existence by 596 * some external agency. The external agency should 597 * call ng_make_node_common() directly to get the 598 * netgraph part initialised. 599 */ 600 TRAP_ERROR(); 601 error = EINVAL; 602 } 603 return (error); 604 } 605 606 /* 607 * Generic node creation. Called by node initialisation for externally 608 * instantiated nodes (e.g. hardware, sockets, etc ). 609 * The returned node has a reference count of 1. 610 */ 611 int 612 ng_make_node_common(struct ng_type *type, node_p *nodepp) 613 { 614 INIT_VNET_NETGRAPH(curvnet); 615 node_p node; 616 617 /* Require the node type to have been already installed */ 618 if (ng_findtype(type->name) == NULL) { 619 TRAP_ERROR(); 620 return (EINVAL); 621 } 622 623 /* Make a node and try attach it to the type */ 624 NG_ALLOC_NODE(node); 625 if (node == NULL) { 626 TRAP_ERROR(); 627 return (ENOMEM); 628 } 629 node->nd_type = type; 630 NG_NODE_REF(node); /* note reference */ 631 type->refs++; 632 633 NG_QUEUE_LOCK_INIT(&node->nd_input_queue); 634 STAILQ_INIT(&node->nd_input_queue.queue); 635 node->nd_input_queue.q_flags = 0; 636 637 /* Initialize hook list for new node */ 638 LIST_INIT(&node->nd_hooks); 639 640 /* Link us into the name hash. */ 641 mtx_lock(&ng_namehash_mtx); 642 LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes); 643 mtx_unlock(&ng_namehash_mtx); 644 645 /* get an ID and put us in the hash chain */ 646 mtx_lock(&ng_idhash_mtx); 647 for (;;) { /* wrap protection, even if silly */ 648 node_p node2 = NULL; 649 node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */ 650 651 /* Is there a problem with the new number? */ 652 NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */ 653 if ((node->nd_ID != 0) && (node2 == NULL)) { 654 break; 655 } 656 } 657 LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], 658 node, nd_idnodes); 659 mtx_unlock(&ng_idhash_mtx); 660 661 /* Done */ 662 *nodepp = node; 663 return (0); 664 } 665 666 /* 667 * Forceably start the shutdown process on a node. Either call 668 * its shutdown method, or do the default shutdown if there is 669 * no type-specific method. 670 * 671 * We can only be called from a shutdown message, so we know we have 672 * a writer lock, and therefore exclusive access. It also means 673 * that we should not be on the work queue, but we check anyhow. 674 * 675 * Persistent node types must have a type-specific method which 676 * allocates a new node in which case, this one is irretrievably going away, 677 * or cleans up anything it needs, and just makes the node valid again, 678 * in which case we allow the node to survive. 679 * 680 * XXX We need to think of how to tell a persistent node that we 681 * REALLY need to go away because the hardware has gone or we 682 * are rebooting.... etc. 683 */ 684 void 685 ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3) 686 { 687 hook_p hook; 688 689 /* Check if it's already shutting down */ 690 if ((node->nd_flags & NGF_CLOSING) != 0) 691 return; 692 693 if (node == &ng_deadnode) { 694 printf ("shutdown called on deadnode\n"); 695 return; 696 } 697 698 /* Add an extra reference so it doesn't go away during this */ 699 NG_NODE_REF(node); 700 701 /* 702 * Mark it invalid so any newcomers know not to try use it 703 * Also add our own mark so we can't recurse 704 * note that NGF_INVALID does not do this as it's also set during 705 * creation 706 */ 707 node->nd_flags |= NGF_INVALID|NGF_CLOSING; 708 709 /* If node has its pre-shutdown method, then call it first*/ 710 if (node->nd_type && node->nd_type->close) 711 (*node->nd_type->close)(node); 712 713 /* Notify all remaining connected nodes to disconnect */ 714 while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL) 715 ng_destroy_hook(hook); 716 717 /* 718 * Drain the input queue forceably. 719 * it has no hooks so what's it going to do, bleed on someone? 720 * Theoretically we came here from a queue entry that was added 721 * Just before the queue was closed, so it should be empty anyway. 722 * Also removes us from worklist if needed. 723 */ 724 ng_flush_input_queue(node); 725 726 /* Ask the type if it has anything to do in this case */ 727 if (node->nd_type && node->nd_type->shutdown) { 728 (*node->nd_type->shutdown)(node); 729 if (NG_NODE_IS_VALID(node)) { 730 /* 731 * Well, blow me down if the node code hasn't declared 732 * that it doesn't want to die. 733 * Presumably it is a persistant node. 734 * If we REALLY want it to go away, 735 * e.g. hardware going away, 736 * Our caller should set NGF_REALLY_DIE in nd_flags. 737 */ 738 node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING); 739 NG_NODE_UNREF(node); /* Assume they still have theirs */ 740 return; 741 } 742 } else { /* do the default thing */ 743 NG_NODE_UNREF(node); 744 } 745 746 ng_unname(node); /* basically a NOP these days */ 747 748 /* 749 * Remove extra reference, possibly the last 750 * Possible other holders of references may include 751 * timeout callouts, but theoretically the node's supposed to 752 * have cancelled them. Possibly hardware dependencies may 753 * force a driver to 'linger' with a reference. 754 */ 755 NG_NODE_UNREF(node); 756 } 757 758 /* 759 * Remove a reference to the node, possibly the last. 760 * deadnode always acts as it it were the last. 761 */ 762 int 763 ng_unref_node(node_p node) 764 { 765 int v; 766 767 if (node == &ng_deadnode) { 768 return (0); 769 } 770 771 v = atomic_fetchadd_int(&node->nd_refs, -1); 772 773 if (v == 1) { /* we were the last */ 774 775 mtx_lock(&ng_namehash_mtx); 776 node->nd_type->refs--; /* XXX maybe should get types lock? */ 777 LIST_REMOVE(node, nd_nodes); 778 mtx_unlock(&ng_namehash_mtx); 779 780 mtx_lock(&ng_idhash_mtx); 781 LIST_REMOVE(node, nd_idnodes); 782 mtx_unlock(&ng_idhash_mtx); 783 784 mtx_destroy(&node->nd_input_queue.q_mtx); 785 NG_FREE_NODE(node); 786 } 787 return (v - 1); 788 } 789 790 /************************************************************************ 791 Node ID handling 792 ************************************************************************/ 793 static node_p 794 ng_ID2noderef(ng_ID_t ID) 795 { 796 INIT_VNET_NETGRAPH(curvnet); 797 node_p node; 798 mtx_lock(&ng_idhash_mtx); 799 NG_IDHASH_FIND(ID, node); 800 if(node) 801 NG_NODE_REF(node); 802 mtx_unlock(&ng_idhash_mtx); 803 return(node); 804 } 805 806 ng_ID_t 807 ng_node2ID(node_p node) 808 { 809 return (node ? NG_NODE_ID(node) : 0); 810 } 811 812 /************************************************************************ 813 Node name handling 814 ************************************************************************/ 815 816 /* 817 * Assign a node a name. Once assigned, the name cannot be changed. 818 */ 819 int 820 ng_name_node(node_p node, const char *name) 821 { 822 INIT_VNET_NETGRAPH(curvnet); 823 int i, hash; 824 node_p node2; 825 826 /* Check the name is valid */ 827 for (i = 0; i < NG_NODESIZ; i++) { 828 if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 829 break; 830 } 831 if (i == 0 || name[i] != '\0') { 832 TRAP_ERROR(); 833 return (EINVAL); 834 } 835 if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 836 TRAP_ERROR(); 837 return (EINVAL); 838 } 839 840 /* Check the name isn't already being used */ 841 if ((node2 = ng_name2noderef(node, name)) != NULL) { 842 NG_NODE_UNREF(node2); 843 TRAP_ERROR(); 844 return (EADDRINUSE); 845 } 846 847 /* copy it */ 848 strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ); 849 850 /* Update name hash. */ 851 NG_NAMEHASH(name, hash); 852 mtx_lock(&ng_namehash_mtx); 853 LIST_REMOVE(node, nd_nodes); 854 LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes); 855 mtx_unlock(&ng_namehash_mtx); 856 857 return (0); 858 } 859 860 /* 861 * Find a node by absolute name. The name should NOT end with ':' 862 * The name "." means "this node" and "[xxx]" means "the node 863 * with ID (ie, at address) xxx". 864 * 865 * Returns the node if found, else NULL. 866 * Eventually should add something faster than a sequential search. 867 * Note it acquires a reference on the node so you can be sure it's still 868 * there. 869 */ 870 node_p 871 ng_name2noderef(node_p here, const char *name) 872 { 873 INIT_VNET_NETGRAPH(curvnet); 874 node_p node; 875 ng_ID_t temp; 876 int hash; 877 878 /* "." means "this node" */ 879 if (strcmp(name, ".") == 0) { 880 NG_NODE_REF(here); 881 return(here); 882 } 883 884 /* Check for name-by-ID */ 885 if ((temp = ng_decodeidname(name)) != 0) { 886 return (ng_ID2noderef(temp)); 887 } 888 889 /* Find node by name */ 890 NG_NAMEHASH(name, hash); 891 mtx_lock(&ng_namehash_mtx); 892 LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) { 893 if (NG_NODE_IS_VALID(node) && 894 (strcmp(NG_NODE_NAME(node), name) == 0)) { 895 break; 896 } 897 } 898 if (node) 899 NG_NODE_REF(node); 900 mtx_unlock(&ng_namehash_mtx); 901 return (node); 902 } 903 904 /* 905 * Decode an ID name, eg. "[f03034de]". Returns 0 if the 906 * string is not valid, otherwise returns the value. 907 */ 908 static ng_ID_t 909 ng_decodeidname(const char *name) 910 { 911 const int len = strlen(name); 912 char *eptr; 913 u_long val; 914 915 /* Check for proper length, brackets, no leading junk */ 916 if ((len < 3) 917 || (name[0] != '[') 918 || (name[len - 1] != ']') 919 || (!isxdigit(name[1]))) { 920 return ((ng_ID_t)0); 921 } 922 923 /* Decode number */ 924 val = strtoul(name + 1, &eptr, 16); 925 if ((eptr - name != len - 1) 926 || (val == ULONG_MAX) 927 || (val == 0)) { 928 return ((ng_ID_t)0); 929 } 930 return (ng_ID_t)val; 931 } 932 933 /* 934 * Remove a name from a node. This should only be called 935 * when shutting down and removing the node. 936 * IF we allow name changing this may be more resurrected. 937 */ 938 void 939 ng_unname(node_p node) 940 { 941 } 942 943 /************************************************************************ 944 Hook routines 945 Names are not optional. Hooks are always connected, except for a 946 brief moment within these routines. On invalidation or during creation 947 they are connected to the 'dead' hook. 948 ************************************************************************/ 949 950 /* 951 * Remove a hook reference 952 */ 953 void 954 ng_unref_hook(hook_p hook) 955 { 956 int v; 957 958 if (hook == &ng_deadhook) { 959 return; 960 } 961 962 v = atomic_fetchadd_int(&hook->hk_refs, -1); 963 964 if (v == 1) { /* we were the last */ 965 if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */ 966 _NG_NODE_UNREF((_NG_HOOK_NODE(hook))); 967 NG_FREE_HOOK(hook); 968 } 969 } 970 971 /* 972 * Add an unconnected hook to a node. Only used internally. 973 * Assumes node is locked. (XXX not yet true ) 974 */ 975 static int 976 ng_add_hook(node_p node, const char *name, hook_p *hookp) 977 { 978 hook_p hook; 979 int error = 0; 980 981 /* Check that the given name is good */ 982 if (name == NULL) { 983 TRAP_ERROR(); 984 return (EINVAL); 985 } 986 if (ng_findhook(node, name) != NULL) { 987 TRAP_ERROR(); 988 return (EEXIST); 989 } 990 991 /* Allocate the hook and link it up */ 992 NG_ALLOC_HOOK(hook); 993 if (hook == NULL) { 994 TRAP_ERROR(); 995 return (ENOMEM); 996 } 997 hook->hk_refs = 1; /* add a reference for us to return */ 998 hook->hk_flags = HK_INVALID; 999 hook->hk_peer = &ng_deadhook; /* start off this way */ 1000 hook->hk_node = node; 1001 NG_NODE_REF(node); /* each hook counts as a reference */ 1002 1003 /* Set hook name */ 1004 strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ); 1005 1006 /* 1007 * Check if the node type code has something to say about it 1008 * If it fails, the unref of the hook will also unref the node. 1009 */ 1010 if (node->nd_type->newhook != NULL) { 1011 if ((error = (*node->nd_type->newhook)(node, hook, name))) { 1012 NG_HOOK_UNREF(hook); /* this frees the hook */ 1013 return (error); 1014 } 1015 } 1016 /* 1017 * The 'type' agrees so far, so go ahead and link it in. 1018 * We'll ask again later when we actually connect the hooks. 1019 */ 1020 LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 1021 node->nd_numhooks++; 1022 NG_HOOK_REF(hook); /* one for the node */ 1023 1024 if (hookp) 1025 *hookp = hook; 1026 return (0); 1027 } 1028 1029 /* 1030 * Find a hook 1031 * 1032 * Node types may supply their own optimized routines for finding 1033 * hooks. If none is supplied, we just do a linear search. 1034 * XXX Possibly we should add a reference to the hook? 1035 */ 1036 hook_p 1037 ng_findhook(node_p node, const char *name) 1038 { 1039 hook_p hook; 1040 1041 if (node->nd_type->findhook != NULL) 1042 return (*node->nd_type->findhook)(node, name); 1043 LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 1044 if (NG_HOOK_IS_VALID(hook) 1045 && (strcmp(NG_HOOK_NAME(hook), name) == 0)) 1046 return (hook); 1047 } 1048 return (NULL); 1049 } 1050 1051 /* 1052 * Destroy a hook 1053 * 1054 * As hooks are always attached, this really destroys two hooks. 1055 * The one given, and the one attached to it. Disconnect the hooks 1056 * from each other first. We reconnect the peer hook to the 'dead' 1057 * hook so that it can still exist after we depart. We then 1058 * send the peer its own destroy message. This ensures that we only 1059 * interact with the peer's structures when it is locked processing that 1060 * message. We hold a reference to the peer hook so we are guaranteed that 1061 * the peer hook and node are still going to exist until 1062 * we are finished there as the hook holds a ref on the node. 1063 * We run this same code again on the peer hook, but that time it is already 1064 * attached to the 'dead' hook. 1065 * 1066 * This routine is called at all stages of hook creation 1067 * on error detection and must be able to handle any such stage. 1068 */ 1069 void 1070 ng_destroy_hook(hook_p hook) 1071 { 1072 hook_p peer; 1073 node_p node; 1074 1075 if (hook == &ng_deadhook) { /* better safe than sorry */ 1076 printf("ng_destroy_hook called on deadhook\n"); 1077 return; 1078 } 1079 1080 /* 1081 * Protect divorce process with mutex, to avoid races on 1082 * simultaneous disconnect. 1083 */ 1084 mtx_lock(&ng_topo_mtx); 1085 1086 hook->hk_flags |= HK_INVALID; 1087 1088 peer = NG_HOOK_PEER(hook); 1089 node = NG_HOOK_NODE(hook); 1090 1091 if (peer && (peer != &ng_deadhook)) { 1092 /* 1093 * Set the peer to point to ng_deadhook 1094 * from this moment on we are effectively independent it. 1095 * send it an rmhook message of it's own. 1096 */ 1097 peer->hk_peer = &ng_deadhook; /* They no longer know us */ 1098 hook->hk_peer = &ng_deadhook; /* Nor us, them */ 1099 if (NG_HOOK_NODE(peer) == &ng_deadnode) { 1100 /* 1101 * If it's already divorced from a node, 1102 * just free it. 1103 */ 1104 mtx_unlock(&ng_topo_mtx); 1105 } else { 1106 mtx_unlock(&ng_topo_mtx); 1107 ng_rmhook_self(peer); /* Send it a surprise */ 1108 } 1109 NG_HOOK_UNREF(peer); /* account for peer link */ 1110 NG_HOOK_UNREF(hook); /* account for peer link */ 1111 } else 1112 mtx_unlock(&ng_topo_mtx); 1113 1114 mtx_assert(&ng_topo_mtx, MA_NOTOWNED); 1115 1116 /* 1117 * Remove the hook from the node's list to avoid possible recursion 1118 * in case the disconnection results in node shutdown. 1119 */ 1120 if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */ 1121 return; 1122 } 1123 LIST_REMOVE(hook, hk_hooks); 1124 node->nd_numhooks--; 1125 if (node->nd_type->disconnect) { 1126 /* 1127 * The type handler may elect to destroy the node so don't 1128 * trust its existence after this point. (except 1129 * that we still hold a reference on it. (which we 1130 * inherrited from the hook we are destroying) 1131 */ 1132 (*node->nd_type->disconnect) (hook); 1133 } 1134 1135 /* 1136 * Note that because we will point to ng_deadnode, the original node 1137 * is not decremented automatically so we do that manually. 1138 */ 1139 _NG_HOOK_NODE(hook) = &ng_deadnode; 1140 NG_NODE_UNREF(node); /* We no longer point to it so adjust count */ 1141 NG_HOOK_UNREF(hook); /* Account for linkage (in list) to node */ 1142 } 1143 1144 /* 1145 * Take two hooks on a node and merge the connection so that the given node 1146 * is effectively bypassed. 1147 */ 1148 int 1149 ng_bypass(hook_p hook1, hook_p hook2) 1150 { 1151 if (hook1->hk_node != hook2->hk_node) { 1152 TRAP_ERROR(); 1153 return (EINVAL); 1154 } 1155 hook1->hk_peer->hk_peer = hook2->hk_peer; 1156 hook2->hk_peer->hk_peer = hook1->hk_peer; 1157 1158 hook1->hk_peer = &ng_deadhook; 1159 hook2->hk_peer = &ng_deadhook; 1160 1161 NG_HOOK_UNREF(hook1); 1162 NG_HOOK_UNREF(hook2); 1163 1164 /* XXX If we ever cache methods on hooks update them as well */ 1165 ng_destroy_hook(hook1); 1166 ng_destroy_hook(hook2); 1167 return (0); 1168 } 1169 1170 /* 1171 * Install a new netgraph type 1172 */ 1173 int 1174 ng_newtype(struct ng_type *tp) 1175 { 1176 const size_t namelen = strlen(tp->name); 1177 1178 /* Check version and type name fields */ 1179 if ((tp->version != NG_ABI_VERSION) 1180 || (namelen == 0) 1181 || (namelen >= NG_TYPESIZ)) { 1182 TRAP_ERROR(); 1183 if (tp->version != NG_ABI_VERSION) { 1184 printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n"); 1185 } 1186 return (EINVAL); 1187 } 1188 1189 /* Check for name collision */ 1190 if (ng_findtype(tp->name) != NULL) { 1191 TRAP_ERROR(); 1192 return (EEXIST); 1193 } 1194 1195 1196 /* Link in new type */ 1197 mtx_lock(&ng_typelist_mtx); 1198 LIST_INSERT_HEAD(&ng_typelist, tp, types); 1199 tp->refs = 1; /* first ref is linked list */ 1200 mtx_unlock(&ng_typelist_mtx); 1201 return (0); 1202 } 1203 1204 /* 1205 * unlink a netgraph type 1206 * If no examples exist 1207 */ 1208 int 1209 ng_rmtype(struct ng_type *tp) 1210 { 1211 /* Check for name collision */ 1212 if (tp->refs != 1) { 1213 TRAP_ERROR(); 1214 return (EBUSY); 1215 } 1216 1217 /* Unlink type */ 1218 mtx_lock(&ng_typelist_mtx); 1219 LIST_REMOVE(tp, types); 1220 mtx_unlock(&ng_typelist_mtx); 1221 return (0); 1222 } 1223 1224 /* 1225 * Look for a type of the name given 1226 */ 1227 struct ng_type * 1228 ng_findtype(const char *typename) 1229 { 1230 struct ng_type *type; 1231 1232 mtx_lock(&ng_typelist_mtx); 1233 LIST_FOREACH(type, &ng_typelist, types) { 1234 if (strcmp(type->name, typename) == 0) 1235 break; 1236 } 1237 mtx_unlock(&ng_typelist_mtx); 1238 return (type); 1239 } 1240 1241 /************************************************************************ 1242 Composite routines 1243 ************************************************************************/ 1244 /* 1245 * Connect two nodes using the specified hooks, using queued functions. 1246 */ 1247 static int 1248 ng_con_part3(node_p node, item_p item, hook_p hook) 1249 { 1250 int error = 0; 1251 1252 /* 1253 * When we run, we know that the node 'node' is locked for us. 1254 * Our caller has a reference on the hook. 1255 * Our caller has a reference on the node. 1256 * (In this case our caller is ng_apply_item() ). 1257 * The peer hook has a reference on the hook. 1258 * We are all set up except for the final call to the node, and 1259 * the clearing of the INVALID flag. 1260 */ 1261 if (NG_HOOK_NODE(hook) == &ng_deadnode) { 1262 /* 1263 * The node must have been freed again since we last visited 1264 * here. ng_destry_hook() has this effect but nothing else does. 1265 * We should just release our references and 1266 * free anything we can think of. 1267 * Since we know it's been destroyed, and it's our caller 1268 * that holds the references, just return. 1269 */ 1270 ERROUT(ENOENT); 1271 } 1272 if (hook->hk_node->nd_type->connect) { 1273 if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 1274 ng_destroy_hook(hook); /* also zaps peer */ 1275 printf("failed in ng_con_part3()\n"); 1276 ERROUT(error); 1277 } 1278 } 1279 /* 1280 * XXX this is wrong for SMP. Possibly we need 1281 * to separate out 'create' and 'invalid' flags. 1282 * should only set flags on hooks we have locked under our node. 1283 */ 1284 hook->hk_flags &= ~HK_INVALID; 1285 done: 1286 NG_FREE_ITEM(item); 1287 return (error); 1288 } 1289 1290 static int 1291 ng_con_part2(node_p node, item_p item, hook_p hook) 1292 { 1293 hook_p peer; 1294 int error = 0; 1295 1296 /* 1297 * When we run, we know that the node 'node' is locked for us. 1298 * Our caller has a reference on the hook. 1299 * Our caller has a reference on the node. 1300 * (In this case our caller is ng_apply_item() ). 1301 * The peer hook has a reference on the hook. 1302 * our node pointer points to the 'dead' node. 1303 * First check the hook name is unique. 1304 * Should not happen because we checked before queueing this. 1305 */ 1306 if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) { 1307 TRAP_ERROR(); 1308 ng_destroy_hook(hook); /* should destroy peer too */ 1309 printf("failed in ng_con_part2()\n"); 1310 ERROUT(EEXIST); 1311 } 1312 /* 1313 * Check if the node type code has something to say about it 1314 * If it fails, the unref of the hook will also unref the attached node, 1315 * however since that node is 'ng_deadnode' this will do nothing. 1316 * The peer hook will also be destroyed. 1317 */ 1318 if (node->nd_type->newhook != NULL) { 1319 if ((error = (*node->nd_type->newhook)(node, hook, 1320 hook->hk_name))) { 1321 ng_destroy_hook(hook); /* should destroy peer too */ 1322 printf("failed in ng_con_part2()\n"); 1323 ERROUT(error); 1324 } 1325 } 1326 1327 /* 1328 * The 'type' agrees so far, so go ahead and link it in. 1329 * We'll ask again later when we actually connect the hooks. 1330 */ 1331 hook->hk_node = node; /* just overwrite ng_deadnode */ 1332 NG_NODE_REF(node); /* each hook counts as a reference */ 1333 LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 1334 node->nd_numhooks++; 1335 NG_HOOK_REF(hook); /* one for the node */ 1336 1337 /* 1338 * We now have a symmetrical situation, where both hooks have been 1339 * linked to their nodes, the newhook methods have been called 1340 * And the references are all correct. The hooks are still marked 1341 * as invalid, as we have not called the 'connect' methods 1342 * yet. 1343 * We can call the local one immediately as we have the 1344 * node locked, but we need to queue the remote one. 1345 */ 1346 if (hook->hk_node->nd_type->connect) { 1347 if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 1348 ng_destroy_hook(hook); /* also zaps peer */ 1349 printf("failed in ng_con_part2(A)\n"); 1350 ERROUT(error); 1351 } 1352 } 1353 1354 /* 1355 * Acquire topo mutex to avoid race with ng_destroy_hook(). 1356 */ 1357 mtx_lock(&ng_topo_mtx); 1358 peer = hook->hk_peer; 1359 if (peer == &ng_deadhook) { 1360 mtx_unlock(&ng_topo_mtx); 1361 printf("failed in ng_con_part2(B)\n"); 1362 ng_destroy_hook(hook); 1363 ERROUT(ENOENT); 1364 } 1365 mtx_unlock(&ng_topo_mtx); 1366 1367 if ((error = ng_send_fn2(peer->hk_node, peer, item, &ng_con_part3, 1368 NULL, 0, NG_REUSE_ITEM))) { 1369 printf("failed in ng_con_part2(C)\n"); 1370 ng_destroy_hook(hook); /* also zaps peer */ 1371 return (error); /* item was consumed. */ 1372 } 1373 hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */ 1374 return (0); /* item was consumed. */ 1375 done: 1376 NG_FREE_ITEM(item); 1377 return (error); 1378 } 1379 1380 /* 1381 * Connect this node with another node. We assume that this node is 1382 * currently locked, as we are only called from an NGM_CONNECT message. 1383 */ 1384 static int 1385 ng_con_nodes(item_p item, node_p node, const char *name, 1386 node_p node2, const char *name2) 1387 { 1388 int error; 1389 hook_p hook; 1390 hook_p hook2; 1391 1392 if (ng_findhook(node2, name2) != NULL) { 1393 return(EEXIST); 1394 } 1395 if ((error = ng_add_hook(node, name, &hook))) /* gives us a ref */ 1396 return (error); 1397 /* Allocate the other hook and link it up */ 1398 NG_ALLOC_HOOK(hook2); 1399 if (hook2 == NULL) { 1400 TRAP_ERROR(); 1401 ng_destroy_hook(hook); /* XXX check ref counts so far */ 1402 NG_HOOK_UNREF(hook); /* including our ref */ 1403 return (ENOMEM); 1404 } 1405 hook2->hk_refs = 1; /* start with a reference for us. */ 1406 hook2->hk_flags = HK_INVALID; 1407 hook2->hk_peer = hook; /* Link the two together */ 1408 hook->hk_peer = hook2; 1409 NG_HOOK_REF(hook); /* Add a ref for the peer to each*/ 1410 NG_HOOK_REF(hook2); 1411 hook2->hk_node = &ng_deadnode; 1412 strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ); 1413 1414 /* 1415 * Queue the function above. 1416 * Procesing continues in that function in the lock context of 1417 * the other node. 1418 */ 1419 if ((error = ng_send_fn2(node2, hook2, item, &ng_con_part2, NULL, 0, 1420 NG_NOFLAGS))) { 1421 printf("failed in ng_con_nodes(): %d\n", error); 1422 ng_destroy_hook(hook); /* also zaps peer */ 1423 } 1424 1425 NG_HOOK_UNREF(hook); /* Let each hook go if it wants to */ 1426 NG_HOOK_UNREF(hook2); 1427 return (error); 1428 } 1429 1430 /* 1431 * Make a peer and connect. 1432 * We assume that the local node is locked. 1433 * The new node probably doesn't need a lock until 1434 * it has a hook, because it cannot really have any work until then, 1435 * but we should think about it a bit more. 1436 * 1437 * The problem may come if the other node also fires up 1438 * some hardware or a timer or some other source of activation, 1439 * also it may already get a command msg via it's ID. 1440 * 1441 * We could use the same method as ng_con_nodes() but we'd have 1442 * to add ability to remove the node when failing. (Not hard, just 1443 * make arg1 point to the node to remove). 1444 * Unless of course we just ignore failure to connect and leave 1445 * an unconnected node? 1446 */ 1447 static int 1448 ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 1449 { 1450 node_p node2; 1451 hook_p hook1, hook2; 1452 int error; 1453 1454 if ((error = ng_make_node(type, &node2))) { 1455 return (error); 1456 } 1457 1458 if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */ 1459 ng_rmnode(node2, NULL, NULL, 0); 1460 return (error); 1461 } 1462 1463 if ((error = ng_add_hook(node2, name2, &hook2))) { 1464 ng_rmnode(node2, NULL, NULL, 0); 1465 ng_destroy_hook(hook1); 1466 NG_HOOK_UNREF(hook1); 1467 return (error); 1468 } 1469 1470 /* 1471 * Actually link the two hooks together. 1472 */ 1473 hook1->hk_peer = hook2; 1474 hook2->hk_peer = hook1; 1475 1476 /* Each hook is referenced by the other */ 1477 NG_HOOK_REF(hook1); 1478 NG_HOOK_REF(hook2); 1479 1480 /* Give each node the opportunity to veto the pending connection */ 1481 if (hook1->hk_node->nd_type->connect) { 1482 error = (*hook1->hk_node->nd_type->connect) (hook1); 1483 } 1484 1485 if ((error == 0) && hook2->hk_node->nd_type->connect) { 1486 error = (*hook2->hk_node->nd_type->connect) (hook2); 1487 1488 } 1489 1490 /* 1491 * drop the references we were holding on the two hooks. 1492 */ 1493 if (error) { 1494 ng_destroy_hook(hook2); /* also zaps hook1 */ 1495 ng_rmnode(node2, NULL, NULL, 0); 1496 } else { 1497 /* As a last act, allow the hooks to be used */ 1498 hook1->hk_flags &= ~HK_INVALID; 1499 hook2->hk_flags &= ~HK_INVALID; 1500 } 1501 NG_HOOK_UNREF(hook1); 1502 NG_HOOK_UNREF(hook2); 1503 return (error); 1504 } 1505 1506 /************************************************************************ 1507 Utility routines to send self messages 1508 ************************************************************************/ 1509 1510 /* Shut this node down as soon as everyone is clear of it */ 1511 /* Should add arg "immediately" to jump the queue */ 1512 int 1513 ng_rmnode_flags(node_p node, int flags) 1514 { 1515 int error; 1516 1517 if (node == &ng_deadnode) 1518 return (0); 1519 node->nd_flags |= NGF_INVALID; 1520 if (node->nd_flags & NGF_CLOSING) 1521 return (0); 1522 1523 error = ng_send_fn1(node, NULL, &ng_rmnode, NULL, 0, flags); 1524 return (error); 1525 } 1526 1527 int 1528 ng_rmnode_self(node_p node) 1529 { 1530 return (ng_rmnode_flags(node, NG_NOFLAGS)); 1531 } 1532 1533 static void 1534 ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) 1535 { 1536 ng_destroy_hook(hook); 1537 return ; 1538 } 1539 1540 int 1541 ng_rmhook_self(hook_p hook) 1542 { 1543 int error; 1544 node_p node = NG_HOOK_NODE(hook); 1545 1546 if (node == &ng_deadnode) 1547 return (0); 1548 1549 error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0); 1550 return (error); 1551 } 1552 1553 /*********************************************************************** 1554 * Parse and verify a string of the form: <NODE:><PATH> 1555 * 1556 * Such a string can refer to a specific node or a specific hook 1557 * on a specific node, depending on how you look at it. In the 1558 * latter case, the PATH component must not end in a dot. 1559 * 1560 * Both <NODE:> and <PATH> are optional. The <PATH> is a string 1561 * of hook names separated by dots. This breaks out the original 1562 * string, setting *nodep to "NODE" (or NULL if none) and *pathp 1563 * to "PATH" (or NULL if degenerate). Also, *hookp will point to 1564 * the final hook component of <PATH>, if any, otherwise NULL. 1565 * 1566 * This returns -1 if the path is malformed. The char ** are optional. 1567 ***********************************************************************/ 1568 int 1569 ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 1570 { 1571 char *node, *path, *hook; 1572 int k; 1573 1574 /* 1575 * Extract absolute NODE, if any 1576 */ 1577 for (path = addr; *path && *path != ':'; path++); 1578 if (*path) { 1579 node = addr; /* Here's the NODE */ 1580 *path++ = '\0'; /* Here's the PATH */ 1581 1582 /* Node name must not be empty */ 1583 if (!*node) 1584 return -1; 1585 1586 /* A name of "." is OK; otherwise '.' not allowed */ 1587 if (strcmp(node, ".") != 0) { 1588 for (k = 0; node[k]; k++) 1589 if (node[k] == '.') 1590 return -1; 1591 } 1592 } else { 1593 node = NULL; /* No absolute NODE */ 1594 path = addr; /* Here's the PATH */ 1595 } 1596 1597 /* Snoop for illegal characters in PATH */ 1598 for (k = 0; path[k]; k++) 1599 if (path[k] == ':') 1600 return -1; 1601 1602 /* Check for no repeated dots in PATH */ 1603 for (k = 0; path[k]; k++) 1604 if (path[k] == '.' && path[k + 1] == '.') 1605 return -1; 1606 1607 /* Remove extra (degenerate) dots from beginning or end of PATH */ 1608 if (path[0] == '.') 1609 path++; 1610 if (*path && path[strlen(path) - 1] == '.') 1611 path[strlen(path) - 1] = 0; 1612 1613 /* If PATH has a dot, then we're not talking about a hook */ 1614 if (*path) { 1615 for (hook = path, k = 0; path[k]; k++) 1616 if (path[k] == '.') { 1617 hook = NULL; 1618 break; 1619 } 1620 } else 1621 path = hook = NULL; 1622 1623 /* Done */ 1624 if (nodep) 1625 *nodep = node; 1626 if (pathp) 1627 *pathp = path; 1628 if (hookp) 1629 *hookp = hook; 1630 return (0); 1631 } 1632 1633 /* 1634 * Given a path, which may be absolute or relative, and a starting node, 1635 * return the destination node. 1636 */ 1637 int 1638 ng_path2noderef(node_p here, const char *address, 1639 node_p *destp, hook_p *lasthook) 1640 { 1641 char fullpath[NG_PATHSIZ]; 1642 char *nodename, *path, pbuf[2]; 1643 node_p node, oldnode; 1644 char *cp; 1645 hook_p hook = NULL; 1646 1647 /* Initialize */ 1648 if (destp == NULL) { 1649 TRAP_ERROR(); 1650 return EINVAL; 1651 } 1652 *destp = NULL; 1653 1654 /* Make a writable copy of address for ng_path_parse() */ 1655 strncpy(fullpath, address, sizeof(fullpath) - 1); 1656 fullpath[sizeof(fullpath) - 1] = '\0'; 1657 1658 /* Parse out node and sequence of hooks */ 1659 if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 1660 TRAP_ERROR(); 1661 return EINVAL; 1662 } 1663 if (path == NULL) { 1664 pbuf[0] = '.'; /* Needs to be writable */ 1665 pbuf[1] = '\0'; 1666 path = pbuf; 1667 } 1668 1669 /* 1670 * For an absolute address, jump to the starting node. 1671 * Note that this holds a reference on the node for us. 1672 * Don't forget to drop the reference if we don't need it. 1673 */ 1674 if (nodename) { 1675 node = ng_name2noderef(here, nodename); 1676 if (node == NULL) { 1677 TRAP_ERROR(); 1678 return (ENOENT); 1679 } 1680 } else { 1681 if (here == NULL) { 1682 TRAP_ERROR(); 1683 return (EINVAL); 1684 } 1685 node = here; 1686 NG_NODE_REF(node); 1687 } 1688 1689 /* 1690 * Now follow the sequence of hooks 1691 * XXX 1692 * We actually cannot guarantee that the sequence 1693 * is not being demolished as we crawl along it 1694 * without extra-ordinary locking etc. 1695 * So this is a bit dodgy to say the least. 1696 * We can probably hold up some things by holding 1697 * the nodelist mutex for the time of this 1698 * crawl if we wanted.. At least that way we wouldn't have to 1699 * worry about the nodes disappearing, but the hooks would still 1700 * be a problem. 1701 */ 1702 for (cp = path; node != NULL && *cp != '\0'; ) { 1703 char *segment; 1704 1705 /* 1706 * Break out the next path segment. Replace the dot we just 1707 * found with a NUL; "cp" points to the next segment (or the 1708 * NUL at the end). 1709 */ 1710 for (segment = cp; *cp != '\0'; cp++) { 1711 if (*cp == '.') { 1712 *cp++ = '\0'; 1713 break; 1714 } 1715 } 1716 1717 /* Empty segment */ 1718 if (*segment == '\0') 1719 continue; 1720 1721 /* We have a segment, so look for a hook by that name */ 1722 hook = ng_findhook(node, segment); 1723 1724 /* Can't get there from here... */ 1725 if (hook == NULL 1726 || NG_HOOK_PEER(hook) == NULL 1727 || NG_HOOK_NOT_VALID(hook) 1728 || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) { 1729 TRAP_ERROR(); 1730 NG_NODE_UNREF(node); 1731 #if 0 1732 printf("hooknotvalid %s %s %d %d %d %d ", 1733 path, 1734 segment, 1735 hook == NULL, 1736 NG_HOOK_PEER(hook) == NULL, 1737 NG_HOOK_NOT_VALID(hook), 1738 NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))); 1739 #endif 1740 return (ENOENT); 1741 } 1742 1743 /* 1744 * Hop on over to the next node 1745 * XXX 1746 * Big race conditions here as hooks and nodes go away 1747 * *** Idea.. store an ng_ID_t in each hook and use that 1748 * instead of the direct hook in this crawl? 1749 */ 1750 oldnode = node; 1751 if ((node = NG_PEER_NODE(hook))) 1752 NG_NODE_REF(node); /* XXX RACE */ 1753 NG_NODE_UNREF(oldnode); /* XXX another race */ 1754 if (NG_NODE_NOT_VALID(node)) { 1755 NG_NODE_UNREF(node); /* XXX more races */ 1756 node = NULL; 1757 } 1758 } 1759 1760 /* If node somehow missing, fail here (probably this is not needed) */ 1761 if (node == NULL) { 1762 TRAP_ERROR(); 1763 return (ENXIO); 1764 } 1765 1766 /* Done */ 1767 *destp = node; 1768 if (lasthook != NULL) 1769 *lasthook = (hook ? NG_HOOK_PEER(hook) : NULL); 1770 return (0); 1771 } 1772 1773 /***************************************************************\ 1774 * Input queue handling. 1775 * All activities are submitted to the node via the input queue 1776 * which implements a multiple-reader/single-writer gate. 1777 * Items which cannot be handled immediately are queued. 1778 * 1779 * read-write queue locking inline functions * 1780 \***************************************************************/ 1781 1782 static __inline void ng_queue_rw(node_p node, item_p item, int rw); 1783 static __inline item_p ng_dequeue(node_p node, int *rw); 1784 static __inline item_p ng_acquire_read(node_p node, item_p item); 1785 static __inline item_p ng_acquire_write(node_p node, item_p item); 1786 static __inline void ng_leave_read(node_p node); 1787 static __inline void ng_leave_write(node_p node); 1788 1789 /* 1790 * Definition of the bits fields in the ng_queue flag word. 1791 * Defined here rather than in netgraph.h because no-one should fiddle 1792 * with them. 1793 * 1794 * The ordering here may be important! don't shuffle these. 1795 */ 1796 /*- 1797 Safety Barrier--------+ (adjustable to suit taste) (not used yet) 1798 | 1799 V 1800 +-------+-------+-------+-------+-------+-------+-------+-------+ 1801 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1802 | |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |P|A| 1803 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|W| 1804 +-------+-------+-------+-------+-------+-------+-------+-------+ 1805 \___________________________ ____________________________/ | | 1806 V | | 1807 [active reader count] | | 1808 | | 1809 Operation Pending -------------------------------+ | 1810 | 1811 Active Writer ---------------------------------------+ 1812 1813 Node queue has such semantics: 1814 - All flags modifications are atomic. 1815 - Reader count can be incremented only if there is no writer or pending flags. 1816 As soon as this can't be done with single operation, it is implemented with 1817 spin loop and atomic_cmpset(). 1818 - Writer flag can be set only if there is no any bits set. 1819 It is implemented with atomic_cmpset(). 1820 - Pending flag can be set any time, but to avoid collision on queue processing 1821 all queue fields are protected by the mutex. 1822 - Queue processing thread reads queue holding the mutex, but releases it while 1823 processing. When queue is empty pending flag is removed. 1824 */ 1825 1826 #define WRITER_ACTIVE 0x00000001 1827 #define OP_PENDING 0x00000002 1828 #define READER_INCREMENT 0x00000004 1829 #define READER_MASK 0xfffffffc /* Not valid if WRITER_ACTIVE is set */ 1830 #define SAFETY_BARRIER 0x00100000 /* 128K items queued should be enough */ 1831 1832 /* Defines of more elaborate states on the queue */ 1833 /* Mask of bits a new read cares about */ 1834 #define NGQ_RMASK (WRITER_ACTIVE|OP_PENDING) 1835 1836 /* Mask of bits a new write cares about */ 1837 #define NGQ_WMASK (NGQ_RMASK|READER_MASK) 1838 1839 /* Test to decide if there is something on the queue. */ 1840 #define QUEUE_ACTIVE(QP) ((QP)->q_flags & OP_PENDING) 1841 1842 /* How to decide what the next queued item is. */ 1843 #define HEAD_IS_READER(QP) NGI_QUEUED_READER(STAILQ_FIRST(&(QP)->queue)) 1844 #define HEAD_IS_WRITER(QP) NGI_QUEUED_WRITER(STAILQ_FIRST(&(QP)->queue)) /* notused */ 1845 1846 /* Read the status to decide if the next item on the queue can now run. */ 1847 #define QUEUED_READER_CAN_PROCEED(QP) \ 1848 (((QP)->q_flags & (NGQ_RMASK & ~OP_PENDING)) == 0) 1849 #define QUEUED_WRITER_CAN_PROCEED(QP) \ 1850 (((QP)->q_flags & (NGQ_WMASK & ~OP_PENDING)) == 0) 1851 1852 /* Is there a chance of getting ANY work off the queue? */ 1853 #define NEXT_QUEUED_ITEM_CAN_PROCEED(QP) \ 1854 ((HEAD_IS_READER(QP)) ? QUEUED_READER_CAN_PROCEED(QP) : \ 1855 QUEUED_WRITER_CAN_PROCEED(QP)) 1856 1857 #define NGQRW_R 0 1858 #define NGQRW_W 1 1859 1860 #define NGQ2_WORKQ 0x00000001 1861 1862 /* 1863 * Taking into account the current state of the queue and node, possibly take 1864 * the next entry off the queue and return it. Return NULL if there was 1865 * nothing we could return, either because there really was nothing there, or 1866 * because the node was in a state where it cannot yet process the next item 1867 * on the queue. 1868 */ 1869 static __inline item_p 1870 ng_dequeue(node_p node, int *rw) 1871 { 1872 item_p item; 1873 struct ng_queue *ngq = &node->nd_input_queue; 1874 1875 /* This MUST be called with the mutex held. */ 1876 mtx_assert(&ngq->q_mtx, MA_OWNED); 1877 1878 /* If there is nothing queued, then just return. */ 1879 if (!QUEUE_ACTIVE(ngq)) { 1880 CTR4(KTR_NET, "%20s: node [%x] (%p) queue empty; " 1881 "queue flags 0x%lx", __func__, 1882 node->nd_ID, node, ngq->q_flags); 1883 return (NULL); 1884 } 1885 1886 /* 1887 * From here, we can assume there is a head item. 1888 * We need to find out what it is and if it can be dequeued, given 1889 * the current state of the node. 1890 */ 1891 if (HEAD_IS_READER(ngq)) { 1892 while (1) { 1893 long t = ngq->q_flags; 1894 if (t & WRITER_ACTIVE) { 1895 /* There is writer, reader can't proceed. */ 1896 CTR4(KTR_NET, "%20s: node [%x] (%p) queued reader " 1897 "can't proceed; queue flags 0x%lx", __func__, 1898 node->nd_ID, node, t); 1899 return (NULL); 1900 } 1901 if (atomic_cmpset_acq_int(&ngq->q_flags, t, 1902 t + READER_INCREMENT)) 1903 break; 1904 cpu_spinwait(); 1905 } 1906 /* We have got reader lock for the node. */ 1907 *rw = NGQRW_R; 1908 } else if (atomic_cmpset_acq_int(&ngq->q_flags, OP_PENDING, 1909 OP_PENDING + WRITER_ACTIVE)) { 1910 /* We have got writer lock for the node. */ 1911 *rw = NGQRW_W; 1912 } else { 1913 /* There is somebody other, writer can't proceed. */ 1914 CTR4(KTR_NET, "%20s: node [%x] (%p) queued writer " 1915 "can't proceed; queue flags 0x%lx", __func__, 1916 node->nd_ID, node, ngq->q_flags); 1917 return (NULL); 1918 } 1919 1920 /* 1921 * Now we dequeue the request (whatever it may be) and correct the 1922 * pending flags and the next and last pointers. 1923 */ 1924 item = STAILQ_FIRST(&ngq->queue); 1925 STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 1926 if (STAILQ_EMPTY(&ngq->queue)) 1927 atomic_clear_int(&ngq->q_flags, OP_PENDING); 1928 CTR6(KTR_NET, "%20s: node [%x] (%p) returning item %p as %s; " 1929 "queue flags 0x%lx", __func__, 1930 node->nd_ID, node, item, *rw ? "WRITER" : "READER" , 1931 ngq->q_flags); 1932 return (item); 1933 } 1934 1935 /* 1936 * Queue a packet to be picked up later by someone else. 1937 * If the queue could be run now, add node to the queue handler's worklist. 1938 */ 1939 static __inline void 1940 ng_queue_rw(node_p node, item_p item, int rw) 1941 { 1942 struct ng_queue *ngq = &node->nd_input_queue; 1943 if (rw == NGQRW_W) 1944 NGI_SET_WRITER(item); 1945 else 1946 NGI_SET_READER(item); 1947 1948 NG_QUEUE_LOCK(ngq); 1949 /* Set OP_PENDING flag and enqueue the item. */ 1950 atomic_set_int(&ngq->q_flags, OP_PENDING); 1951 STAILQ_INSERT_TAIL(&ngq->queue, item, el_next); 1952 1953 CTR5(KTR_NET, "%20s: node [%x] (%p) queued item %p as %s", __func__, 1954 node->nd_ID, node, item, rw ? "WRITER" : "READER" ); 1955 1956 /* 1957 * We can take the worklist lock with the node locked 1958 * BUT NOT THE REVERSE! 1959 */ 1960 if (NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 1961 ng_worklist_add(node); 1962 NG_QUEUE_UNLOCK(ngq); 1963 } 1964 1965 /* Acquire reader lock on node. If node is busy, queue the packet. */ 1966 static __inline item_p 1967 ng_acquire_read(node_p node, item_p item) 1968 { 1969 KASSERT(node != &ng_deadnode, 1970 ("%s: working on deadnode", __func__)); 1971 1972 /* Reader needs node without writer and pending items. */ 1973 while (1) { 1974 long t = node->nd_input_queue.q_flags; 1975 if (t & NGQ_RMASK) 1976 break; /* Node is not ready for reader. */ 1977 if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 1978 t, t + READER_INCREMENT)) { 1979 /* Successfully grabbed node */ 1980 CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 1981 __func__, node->nd_ID, node, item); 1982 return (item); 1983 } 1984 cpu_spinwait(); 1985 }; 1986 1987 /* Queue the request for later. */ 1988 ng_queue_rw(node, item, NGQRW_R); 1989 1990 return (NULL); 1991 } 1992 1993 /* Acquire writer lock on node. If node is busy, queue the packet. */ 1994 static __inline item_p 1995 ng_acquire_write(node_p node, item_p item) 1996 { 1997 KASSERT(node != &ng_deadnode, 1998 ("%s: working on deadnode", __func__)); 1999 2000 /* Writer needs completely idle node. */ 2001 if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 2002 0, WRITER_ACTIVE)) { 2003 /* Successfully grabbed node */ 2004 CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 2005 __func__, node->nd_ID, node, item); 2006 return (item); 2007 } 2008 2009 /* Queue the request for later. */ 2010 ng_queue_rw(node, item, NGQRW_W); 2011 2012 return (NULL); 2013 } 2014 2015 #if 0 2016 static __inline item_p 2017 ng_upgrade_write(node_p node, item_p item) 2018 { 2019 struct ng_queue *ngq = &node->nd_input_queue; 2020 KASSERT(node != &ng_deadnode, 2021 ("%s: working on deadnode", __func__)); 2022 2023 NGI_SET_WRITER(item); 2024 2025 NG_QUEUE_LOCK(ngq); 2026 2027 /* 2028 * There will never be no readers as we are there ourselves. 2029 * Set the WRITER_ACTIVE flags ASAP to block out fast track readers. 2030 * The caller we are running from will call ng_leave_read() 2031 * soon, so we must account for that. We must leave again with the 2032 * READER lock. If we find other readers, then 2033 * queue the request for later. However "later" may be rignt now 2034 * if there are no readers. We don't really care if there are queued 2035 * items as we will bypass them anyhow. 2036 */ 2037 atomic_add_int(&ngq->q_flags, WRITER_ACTIVE - READER_INCREMENT); 2038 if ((ngq->q_flags & (NGQ_WMASK & ~OP_PENDING)) == WRITER_ACTIVE) { 2039 NG_QUEUE_UNLOCK(ngq); 2040 2041 /* It's just us, act on the item. */ 2042 /* will NOT drop writer lock when done */ 2043 ng_apply_item(node, item, 0); 2044 2045 /* 2046 * Having acted on the item, atomically 2047 * down grade back to READER and finish up 2048 */ 2049 atomic_add_int(&ngq->q_flags, 2050 READER_INCREMENT - WRITER_ACTIVE); 2051 2052 /* Our caller will call ng_leave_read() */ 2053 return; 2054 } 2055 /* 2056 * It's not just us active, so queue us AT THE HEAD. 2057 * "Why?" I hear you ask. 2058 * Put us at the head of the queue as we've already been 2059 * through it once. If there is nothing else waiting, 2060 * set the correct flags. 2061 */ 2062 if (STAILQ_EMPTY(&ngq->queue)) { 2063 /* We've gone from, 0 to 1 item in the queue */ 2064 atomic_set_int(&ngq->q_flags, OP_PENDING); 2065 2066 CTR3(KTR_NET, "%20s: node [%x] (%p) set OP_PENDING", __func__, 2067 node->nd_ID, node); 2068 }; 2069 STAILQ_INSERT_HEAD(&ngq->queue, item, el_next); 2070 CTR4(KTR_NET, "%20s: node [%x] (%p) requeued item %p as WRITER", 2071 __func__, node->nd_ID, node, item ); 2072 2073 /* Reverse what we did above. That downgrades us back to reader */ 2074 atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE); 2075 if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 2076 ng_worklist_add(node); 2077 NG_QUEUE_UNLOCK(ngq); 2078 2079 return; 2080 } 2081 #endif 2082 2083 /* Release reader lock. */ 2084 static __inline void 2085 ng_leave_read(node_p node) 2086 { 2087 atomic_subtract_rel_int(&node->nd_input_queue.q_flags, READER_INCREMENT); 2088 } 2089 2090 /* Release writer lock. */ 2091 static __inline void 2092 ng_leave_write(node_p node) 2093 { 2094 atomic_clear_rel_int(&node->nd_input_queue.q_flags, WRITER_ACTIVE); 2095 } 2096 2097 /* Purge node queue. Called on node shutdown. */ 2098 static void 2099 ng_flush_input_queue(node_p node) 2100 { 2101 struct ng_queue *ngq = &node->nd_input_queue; 2102 item_p item; 2103 2104 NG_QUEUE_LOCK(ngq); 2105 while ((item = STAILQ_FIRST(&ngq->queue)) != NULL) { 2106 STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 2107 if (STAILQ_EMPTY(&ngq->queue)) 2108 atomic_clear_int(&ngq->q_flags, OP_PENDING); 2109 NG_QUEUE_UNLOCK(ngq); 2110 2111 /* If the item is supplying a callback, call it with an error */ 2112 if (item->apply != NULL) { 2113 if (item->depth == 1) 2114 item->apply->error = ENOENT; 2115 if (refcount_release(&item->apply->refs)) { 2116 (*item->apply->apply)(item->apply->context, 2117 item->apply->error); 2118 } 2119 } 2120 NG_FREE_ITEM(item); 2121 NG_QUEUE_LOCK(ngq); 2122 } 2123 NG_QUEUE_UNLOCK(ngq); 2124 } 2125 2126 /*********************************************************************** 2127 * Externally visible method for sending or queueing messages or data. 2128 ***********************************************************************/ 2129 2130 /* 2131 * The module code should have filled out the item correctly by this stage: 2132 * Common: 2133 * reference to destination node. 2134 * Reference to destination rcv hook if relevant. 2135 * apply pointer must be or NULL or reference valid struct ng_apply_info. 2136 * Data: 2137 * pointer to mbuf 2138 * Control_Message: 2139 * pointer to msg. 2140 * ID of original sender node. (return address) 2141 * Function: 2142 * Function pointer 2143 * void * argument 2144 * integer argument 2145 * 2146 * The nodes have several routines and macros to help with this task: 2147 */ 2148 2149 int 2150 ng_snd_item(item_p item, int flags) 2151 { 2152 hook_p hook; 2153 node_p node; 2154 int queue, rw; 2155 struct ng_queue *ngq; 2156 int error = 0; 2157 2158 /* We are sending item, so it must be present! */ 2159 KASSERT(item != NULL, ("ng_snd_item: item is NULL")); 2160 2161 #ifdef NETGRAPH_DEBUG 2162 _ngi_check(item, __FILE__, __LINE__); 2163 #endif 2164 2165 /* Item was sent once more, postpone apply() call. */ 2166 if (item->apply) 2167 refcount_acquire(&item->apply->refs); 2168 2169 node = NGI_NODE(item); 2170 /* Node is never optional. */ 2171 KASSERT(node != NULL, ("ng_snd_item: node is NULL")); 2172 2173 hook = NGI_HOOK(item); 2174 /* Valid hook and mbuf are mandatory for data. */ 2175 if ((item->el_flags & NGQF_TYPE) == NGQF_DATA) { 2176 KASSERT(hook != NULL, ("ng_snd_item: hook for data is NULL")); 2177 if (NGI_M(item) == NULL) 2178 ERROUT(EINVAL); 2179 CHECK_DATA_MBUF(NGI_M(item)); 2180 } 2181 2182 /* 2183 * If the item or the node specifies single threading, force 2184 * writer semantics. Similarly, the node may say one hook always 2185 * produces writers. These are overrides. 2186 */ 2187 if (((item->el_flags & NGQF_RW) == NGQF_WRITER) || 2188 (node->nd_flags & NGF_FORCE_WRITER) || 2189 (hook && (hook->hk_flags & HK_FORCE_WRITER))) { 2190 rw = NGQRW_W; 2191 } else { 2192 rw = NGQRW_R; 2193 } 2194 2195 /* 2196 * If sender or receiver requests queued delivery or stack usage 2197 * level is dangerous - enqueue message. 2198 */ 2199 if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) { 2200 queue = 1; 2201 } else { 2202 queue = 0; 2203 #ifdef GET_STACK_USAGE 2204 /* 2205 * Most of netgraph nodes have small stack consumption and 2206 * for them 25% of free stack space is more than enough. 2207 * Nodes/hooks with higher stack usage should be marked as 2208 * HI_STACK. For them 50% of stack will be guaranteed then. 2209 * XXX: Values 25% and 50% are completely empirical. 2210 */ 2211 size_t st, su, sl; 2212 GET_STACK_USAGE(st, su); 2213 sl = st - su; 2214 if ((sl * 4 < st) || 2215 ((sl * 2 < st) && ((node->nd_flags & NGF_HI_STACK) || 2216 (hook && (hook->hk_flags & HK_HI_STACK))))) { 2217 queue = 1; 2218 } 2219 #endif 2220 } 2221 2222 if (queue) { 2223 item->depth = 1; 2224 /* Put it on the queue for that node*/ 2225 ng_queue_rw(node, item, rw); 2226 return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2227 } 2228 2229 /* 2230 * We already decided how we will be queueud or treated. 2231 * Try get the appropriate operating permission. 2232 */ 2233 if (rw == NGQRW_R) 2234 item = ng_acquire_read(node, item); 2235 else 2236 item = ng_acquire_write(node, item); 2237 2238 /* Item was queued while trying to get permission. */ 2239 if (item == NULL) 2240 return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2241 2242 NGI_GET_NODE(item, node); /* zaps stored node */ 2243 2244 item->depth++; 2245 error = ng_apply_item(node, item, rw); /* drops r/w lock when done */ 2246 2247 /* If something is waiting on queue and ready, schedule it. */ 2248 ngq = &node->nd_input_queue; 2249 if (QUEUE_ACTIVE(ngq)) { 2250 NG_QUEUE_LOCK(ngq); 2251 if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 2252 ng_worklist_add(node); 2253 NG_QUEUE_UNLOCK(ngq); 2254 } 2255 2256 /* 2257 * Node may go away as soon as we remove the reference. 2258 * Whatever we do, DO NOT access the node again! 2259 */ 2260 NG_NODE_UNREF(node); 2261 2262 return (error); 2263 2264 done: 2265 /* If was not sent, apply callback here. */ 2266 if (item->apply != NULL) { 2267 if (item->depth == 0 && error != 0) 2268 item->apply->error = error; 2269 if (refcount_release(&item->apply->refs)) { 2270 (*item->apply->apply)(item->apply->context, 2271 item->apply->error); 2272 } 2273 } 2274 2275 NG_FREE_ITEM(item); 2276 return (error); 2277 } 2278 2279 /* 2280 * We have an item that was possibly queued somewhere. 2281 * It should contain all the information needed 2282 * to run it on the appropriate node/hook. 2283 * If there is apply pointer and we own the last reference, call apply(). 2284 */ 2285 static int 2286 ng_apply_item(node_p node, item_p item, int rw) 2287 { 2288 hook_p hook; 2289 ng_rcvdata_t *rcvdata; 2290 ng_rcvmsg_t *rcvmsg; 2291 struct ng_apply_info *apply; 2292 int error = 0, depth; 2293 2294 /* Node and item are never optional. */ 2295 KASSERT(node != NULL, ("ng_apply_item: node is NULL")); 2296 KASSERT(item != NULL, ("ng_apply_item: item is NULL")); 2297 2298 NGI_GET_HOOK(item, hook); /* clears stored hook */ 2299 #ifdef NETGRAPH_DEBUG 2300 _ngi_check(item, __FILE__, __LINE__); 2301 #endif 2302 2303 apply = item->apply; 2304 depth = item->depth; 2305 2306 switch (item->el_flags & NGQF_TYPE) { 2307 case NGQF_DATA: 2308 /* 2309 * Check things are still ok as when we were queued. 2310 */ 2311 KASSERT(hook != NULL, ("ng_apply_item: hook for data is NULL")); 2312 if (NG_HOOK_NOT_VALID(hook) || 2313 NG_NODE_NOT_VALID(node)) { 2314 error = EIO; 2315 NG_FREE_ITEM(item); 2316 break; 2317 } 2318 /* 2319 * If no receive method, just silently drop it. 2320 * Give preference to the hook over-ride method 2321 */ 2322 if ((!(rcvdata = hook->hk_rcvdata)) 2323 && (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) { 2324 error = 0; 2325 NG_FREE_ITEM(item); 2326 break; 2327 } 2328 error = (*rcvdata)(hook, item); 2329 break; 2330 case NGQF_MESG: 2331 if (hook && NG_HOOK_NOT_VALID(hook)) { 2332 /* 2333 * The hook has been zapped then we can't use it. 2334 * Immediately drop its reference. 2335 * The message may not need it. 2336 */ 2337 NG_HOOK_UNREF(hook); 2338 hook = NULL; 2339 } 2340 /* 2341 * Similarly, if the node is a zombie there is 2342 * nothing we can do with it, drop everything. 2343 */ 2344 if (NG_NODE_NOT_VALID(node)) { 2345 TRAP_ERROR(); 2346 error = EINVAL; 2347 NG_FREE_ITEM(item); 2348 break; 2349 } 2350 /* 2351 * Call the appropriate message handler for the object. 2352 * It is up to the message handler to free the message. 2353 * If it's a generic message, handle it generically, 2354 * otherwise call the type's message handler (if it exists). 2355 * XXX (race). Remember that a queued message may 2356 * reference a node or hook that has just been 2357 * invalidated. It will exist as the queue code 2358 * is holding a reference, but.. 2359 */ 2360 if ((NGI_MSG(item)->header.typecookie == NGM_GENERIC_COOKIE) && 2361 ((NGI_MSG(item)->header.flags & NGF_RESP) == 0)) { 2362 error = ng_generic_msg(node, item, hook); 2363 break; 2364 } 2365 if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) && 2366 (!(rcvmsg = node->nd_type->rcvmsg))) { 2367 TRAP_ERROR(); 2368 error = 0; 2369 NG_FREE_ITEM(item); 2370 break; 2371 } 2372 error = (*rcvmsg)(node, item, hook); 2373 break; 2374 case NGQF_FN: 2375 case NGQF_FN2: 2376 /* 2377 * In the case of the shutdown message we allow it to hit 2378 * even if the node is invalid. 2379 */ 2380 if (NG_NODE_NOT_VALID(node) && 2381 NGI_FN(item) != &ng_rmnode) { 2382 TRAP_ERROR(); 2383 error = EINVAL; 2384 NG_FREE_ITEM(item); 2385 break; 2386 } 2387 /* Same is about some internal functions and invalid hook. */ 2388 if (hook && NG_HOOK_NOT_VALID(hook) && 2389 NGI_FN2(item) != &ng_con_part2 && 2390 NGI_FN2(item) != &ng_con_part3 && 2391 NGI_FN(item) != &ng_rmhook_part2) { 2392 TRAP_ERROR(); 2393 error = EINVAL; 2394 NG_FREE_ITEM(item); 2395 break; 2396 } 2397 2398 if ((item->el_flags & NGQF_TYPE) == NGQF_FN) { 2399 (*NGI_FN(item))(node, hook, NGI_ARG1(item), 2400 NGI_ARG2(item)); 2401 NG_FREE_ITEM(item); 2402 } else /* it is NGQF_FN2 */ 2403 error = (*NGI_FN2(item))(node, item, hook); 2404 break; 2405 } 2406 /* 2407 * We held references on some of the resources 2408 * that we took from the item. Now that we have 2409 * finished doing everything, drop those references. 2410 */ 2411 if (hook) 2412 NG_HOOK_UNREF(hook); 2413 2414 if (rw == NGQRW_R) 2415 ng_leave_read(node); 2416 else 2417 ng_leave_write(node); 2418 2419 /* Apply callback. */ 2420 if (apply != NULL) { 2421 if (depth == 1 && error != 0) 2422 apply->error = error; 2423 if (refcount_release(&apply->refs)) 2424 (*apply->apply)(apply->context, apply->error); 2425 } 2426 2427 return (error); 2428 } 2429 2430 /*********************************************************************** 2431 * Implement the 'generic' control messages 2432 ***********************************************************************/ 2433 static int 2434 ng_generic_msg(node_p here, item_p item, hook_p lasthook) 2435 { 2436 INIT_VNET_NETGRAPH(curvnet); 2437 int error = 0; 2438 struct ng_mesg *msg; 2439 struct ng_mesg *resp = NULL; 2440 2441 NGI_GET_MSG(item, msg); 2442 if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 2443 TRAP_ERROR(); 2444 error = EINVAL; 2445 goto out; 2446 } 2447 switch (msg->header.cmd) { 2448 case NGM_SHUTDOWN: 2449 ng_rmnode(here, NULL, NULL, 0); 2450 break; 2451 case NGM_MKPEER: 2452 { 2453 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 2454 2455 if (msg->header.arglen != sizeof(*mkp)) { 2456 TRAP_ERROR(); 2457 error = EINVAL; 2458 break; 2459 } 2460 mkp->type[sizeof(mkp->type) - 1] = '\0'; 2461 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 2462 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 2463 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 2464 break; 2465 } 2466 case NGM_CONNECT: 2467 { 2468 struct ngm_connect *const con = 2469 (struct ngm_connect *) msg->data; 2470 node_p node2; 2471 2472 if (msg->header.arglen != sizeof(*con)) { 2473 TRAP_ERROR(); 2474 error = EINVAL; 2475 break; 2476 } 2477 con->path[sizeof(con->path) - 1] = '\0'; 2478 con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 2479 con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 2480 /* Don't forget we get a reference.. */ 2481 error = ng_path2noderef(here, con->path, &node2, NULL); 2482 if (error) 2483 break; 2484 error = ng_con_nodes(item, here, con->ourhook, 2485 node2, con->peerhook); 2486 NG_NODE_UNREF(node2); 2487 break; 2488 } 2489 case NGM_NAME: 2490 { 2491 struct ngm_name *const nam = (struct ngm_name *) msg->data; 2492 2493 if (msg->header.arglen != sizeof(*nam)) { 2494 TRAP_ERROR(); 2495 error = EINVAL; 2496 break; 2497 } 2498 nam->name[sizeof(nam->name) - 1] = '\0'; 2499 error = ng_name_node(here, nam->name); 2500 break; 2501 } 2502 case NGM_RMHOOK: 2503 { 2504 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 2505 hook_p hook; 2506 2507 if (msg->header.arglen != sizeof(*rmh)) { 2508 TRAP_ERROR(); 2509 error = EINVAL; 2510 break; 2511 } 2512 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 2513 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 2514 ng_destroy_hook(hook); 2515 break; 2516 } 2517 case NGM_NODEINFO: 2518 { 2519 struct nodeinfo *ni; 2520 2521 NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT); 2522 if (resp == NULL) { 2523 error = ENOMEM; 2524 break; 2525 } 2526 2527 /* Fill in node info */ 2528 ni = (struct nodeinfo *) resp->data; 2529 if (NG_NODE_HAS_NAME(here)) 2530 strcpy(ni->name, NG_NODE_NAME(here)); 2531 strcpy(ni->type, here->nd_type->name); 2532 ni->id = ng_node2ID(here); 2533 ni->hooks = here->nd_numhooks; 2534 break; 2535 } 2536 case NGM_LISTHOOKS: 2537 { 2538 const int nhooks = here->nd_numhooks; 2539 struct hooklist *hl; 2540 struct nodeinfo *ni; 2541 hook_p hook; 2542 2543 /* Get response struct */ 2544 NG_MKRESPONSE(resp, msg, sizeof(*hl) 2545 + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 2546 if (resp == NULL) { 2547 error = ENOMEM; 2548 break; 2549 } 2550 hl = (struct hooklist *) resp->data; 2551 ni = &hl->nodeinfo; 2552 2553 /* Fill in node info */ 2554 if (NG_NODE_HAS_NAME(here)) 2555 strcpy(ni->name, NG_NODE_NAME(here)); 2556 strcpy(ni->type, here->nd_type->name); 2557 ni->id = ng_node2ID(here); 2558 2559 /* Cycle through the linked list of hooks */ 2560 ni->hooks = 0; 2561 LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) { 2562 struct linkinfo *const link = &hl->link[ni->hooks]; 2563 2564 if (ni->hooks >= nhooks) { 2565 log(LOG_ERR, "%s: number of %s changed\n", 2566 __func__, "hooks"); 2567 break; 2568 } 2569 if (NG_HOOK_NOT_VALID(hook)) 2570 continue; 2571 strcpy(link->ourhook, NG_HOOK_NAME(hook)); 2572 strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook)); 2573 if (NG_PEER_NODE_NAME(hook)[0] != '\0') 2574 strcpy(link->nodeinfo.name, 2575 NG_PEER_NODE_NAME(hook)); 2576 strcpy(link->nodeinfo.type, 2577 NG_PEER_NODE(hook)->nd_type->name); 2578 link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook)); 2579 link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks; 2580 ni->hooks++; 2581 } 2582 break; 2583 } 2584 2585 case NGM_LISTNAMES: 2586 case NGM_LISTNODES: 2587 { 2588 const int unnamed = (msg->header.cmd == NGM_LISTNODES); 2589 struct namelist *nl; 2590 node_p node; 2591 int num = 0, i; 2592 2593 mtx_lock(&ng_namehash_mtx); 2594 /* Count number of nodes */ 2595 for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2596 LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2597 if (NG_NODE_IS_VALID(node) && 2598 (unnamed || NG_NODE_HAS_NAME(node))) { 2599 num++; 2600 } 2601 } 2602 } 2603 mtx_unlock(&ng_namehash_mtx); 2604 2605 /* Get response struct */ 2606 NG_MKRESPONSE(resp, msg, sizeof(*nl) 2607 + (num * sizeof(struct nodeinfo)), M_NOWAIT); 2608 if (resp == NULL) { 2609 error = ENOMEM; 2610 break; 2611 } 2612 nl = (struct namelist *) resp->data; 2613 2614 /* Cycle through the linked list of nodes */ 2615 nl->numnames = 0; 2616 mtx_lock(&ng_namehash_mtx); 2617 for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2618 LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2619 struct nodeinfo *const np = 2620 &nl->nodeinfo[nl->numnames]; 2621 2622 if (NG_NODE_NOT_VALID(node)) 2623 continue; 2624 if (!unnamed && (! NG_NODE_HAS_NAME(node))) 2625 continue; 2626 if (nl->numnames >= num) { 2627 log(LOG_ERR, "%s: number of nodes changed\n", 2628 __func__); 2629 break; 2630 } 2631 if (NG_NODE_HAS_NAME(node)) 2632 strcpy(np->name, NG_NODE_NAME(node)); 2633 strcpy(np->type, node->nd_type->name); 2634 np->id = ng_node2ID(node); 2635 np->hooks = node->nd_numhooks; 2636 nl->numnames++; 2637 } 2638 } 2639 mtx_unlock(&ng_namehash_mtx); 2640 break; 2641 } 2642 2643 case NGM_LISTTYPES: 2644 { 2645 struct typelist *tl; 2646 struct ng_type *type; 2647 int num = 0; 2648 2649 mtx_lock(&ng_typelist_mtx); 2650 /* Count number of types */ 2651 LIST_FOREACH(type, &ng_typelist, types) { 2652 num++; 2653 } 2654 mtx_unlock(&ng_typelist_mtx); 2655 2656 /* Get response struct */ 2657 NG_MKRESPONSE(resp, msg, sizeof(*tl) 2658 + (num * sizeof(struct typeinfo)), M_NOWAIT); 2659 if (resp == NULL) { 2660 error = ENOMEM; 2661 break; 2662 } 2663 tl = (struct typelist *) resp->data; 2664 2665 /* Cycle through the linked list of types */ 2666 tl->numtypes = 0; 2667 mtx_lock(&ng_typelist_mtx); 2668 LIST_FOREACH(type, &ng_typelist, types) { 2669 struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 2670 2671 if (tl->numtypes >= num) { 2672 log(LOG_ERR, "%s: number of %s changed\n", 2673 __func__, "types"); 2674 break; 2675 } 2676 strcpy(tp->type_name, type->name); 2677 tp->numnodes = type->refs - 1; /* don't count list */ 2678 tl->numtypes++; 2679 } 2680 mtx_unlock(&ng_typelist_mtx); 2681 break; 2682 } 2683 2684 case NGM_BINARY2ASCII: 2685 { 2686 int bufSize = 20 * 1024; /* XXX hard coded constant */ 2687 const struct ng_parse_type *argstype; 2688 const struct ng_cmdlist *c; 2689 struct ng_mesg *binary, *ascii; 2690 2691 /* Data area must contain a valid netgraph message */ 2692 binary = (struct ng_mesg *)msg->data; 2693 if (msg->header.arglen < sizeof(struct ng_mesg) || 2694 (msg->header.arglen - sizeof(struct ng_mesg) < 2695 binary->header.arglen)) { 2696 TRAP_ERROR(); 2697 error = EINVAL; 2698 break; 2699 } 2700 2701 /* Get a response message with lots of room */ 2702 NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 2703 if (resp == NULL) { 2704 error = ENOMEM; 2705 break; 2706 } 2707 ascii = (struct ng_mesg *)resp->data; 2708 2709 /* Copy binary message header to response message payload */ 2710 bcopy(binary, ascii, sizeof(*binary)); 2711 2712 /* Find command by matching typecookie and command number */ 2713 for (c = here->nd_type->cmdlist; 2714 c != NULL && c->name != NULL; c++) { 2715 if (binary->header.typecookie == c->cookie 2716 && binary->header.cmd == c->cmd) 2717 break; 2718 } 2719 if (c == NULL || c->name == NULL) { 2720 for (c = ng_generic_cmds; c->name != NULL; c++) { 2721 if (binary->header.typecookie == c->cookie 2722 && binary->header.cmd == c->cmd) 2723 break; 2724 } 2725 if (c->name == NULL) { 2726 NG_FREE_MSG(resp); 2727 error = ENOSYS; 2728 break; 2729 } 2730 } 2731 2732 /* Convert command name to ASCII */ 2733 snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 2734 "%s", c->name); 2735 2736 /* Convert command arguments to ASCII */ 2737 argstype = (binary->header.flags & NGF_RESP) ? 2738 c->respType : c->mesgType; 2739 if (argstype == NULL) { 2740 *ascii->data = '\0'; 2741 } else { 2742 if ((error = ng_unparse(argstype, 2743 (u_char *)binary->data, 2744 ascii->data, bufSize)) != 0) { 2745 NG_FREE_MSG(resp); 2746 break; 2747 } 2748 } 2749 2750 /* Return the result as struct ng_mesg plus ASCII string */ 2751 bufSize = strlen(ascii->data) + 1; 2752 ascii->header.arglen = bufSize; 2753 resp->header.arglen = sizeof(*ascii) + bufSize; 2754 break; 2755 } 2756 2757 case NGM_ASCII2BINARY: 2758 { 2759 int bufSize = 2000; /* XXX hard coded constant */ 2760 const struct ng_cmdlist *c; 2761 const struct ng_parse_type *argstype; 2762 struct ng_mesg *ascii, *binary; 2763 int off = 0; 2764 2765 /* Data area must contain at least a struct ng_mesg + '\0' */ 2766 ascii = (struct ng_mesg *)msg->data; 2767 if ((msg->header.arglen < sizeof(*ascii) + 1) || 2768 (ascii->header.arglen < 1) || 2769 (msg->header.arglen < sizeof(*ascii) + 2770 ascii->header.arglen)) { 2771 TRAP_ERROR(); 2772 error = EINVAL; 2773 break; 2774 } 2775 ascii->data[ascii->header.arglen - 1] = '\0'; 2776 2777 /* Get a response message with lots of room */ 2778 NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 2779 if (resp == NULL) { 2780 error = ENOMEM; 2781 break; 2782 } 2783 binary = (struct ng_mesg *)resp->data; 2784 2785 /* Copy ASCII message header to response message payload */ 2786 bcopy(ascii, binary, sizeof(*ascii)); 2787 2788 /* Find command by matching ASCII command string */ 2789 for (c = here->nd_type->cmdlist; 2790 c != NULL && c->name != NULL; c++) { 2791 if (strcmp(ascii->header.cmdstr, c->name) == 0) 2792 break; 2793 } 2794 if (c == NULL || c->name == NULL) { 2795 for (c = ng_generic_cmds; c->name != NULL; c++) { 2796 if (strcmp(ascii->header.cmdstr, c->name) == 0) 2797 break; 2798 } 2799 if (c->name == NULL) { 2800 NG_FREE_MSG(resp); 2801 error = ENOSYS; 2802 break; 2803 } 2804 } 2805 2806 /* Convert command name to binary */ 2807 binary->header.cmd = c->cmd; 2808 binary->header.typecookie = c->cookie; 2809 2810 /* Convert command arguments to binary */ 2811 argstype = (binary->header.flags & NGF_RESP) ? 2812 c->respType : c->mesgType; 2813 if (argstype == NULL) { 2814 bufSize = 0; 2815 } else { 2816 if ((error = ng_parse(argstype, ascii->data, 2817 &off, (u_char *)binary->data, &bufSize)) != 0) { 2818 NG_FREE_MSG(resp); 2819 break; 2820 } 2821 } 2822 2823 /* Return the result */ 2824 binary->header.arglen = bufSize; 2825 resp->header.arglen = sizeof(*binary) + bufSize; 2826 break; 2827 } 2828 2829 case NGM_TEXT_CONFIG: 2830 case NGM_TEXT_STATUS: 2831 /* 2832 * This one is tricky as it passes the command down to the 2833 * actual node, even though it is a generic type command. 2834 * This means we must assume that the item/msg is already freed 2835 * when control passes back to us. 2836 */ 2837 if (here->nd_type->rcvmsg != NULL) { 2838 NGI_MSG(item) = msg; /* put it back as we found it */ 2839 return((*here->nd_type->rcvmsg)(here, item, lasthook)); 2840 } 2841 /* Fall through if rcvmsg not supported */ 2842 default: 2843 TRAP_ERROR(); 2844 error = EINVAL; 2845 } 2846 /* 2847 * Sometimes a generic message may be statically allocated 2848 * to avoid problems with allocating when in tight memeory situations. 2849 * Don't free it if it is so. 2850 * I break them appart here, because erros may cause a free if the item 2851 * in which case we'd be doing it twice. 2852 * they are kept together above, to simplify freeing. 2853 */ 2854 out: 2855 NG_RESPOND_MSG(error, here, item, resp); 2856 if (msg) 2857 NG_FREE_MSG(msg); 2858 return (error); 2859 } 2860 2861 /************************************************************************ 2862 Queue element get/free routines 2863 ************************************************************************/ 2864 2865 uma_zone_t ng_qzone; 2866 uma_zone_t ng_qdzone; 2867 static int maxalloc = 4096;/* limit the damage of a leak */ 2868 static int maxdata = 512; /* limit the damage of a DoS */ 2869 2870 TUNABLE_INT("net.graph.maxalloc", &maxalloc); 2871 SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 2872 0, "Maximum number of non-data queue items to allocate"); 2873 TUNABLE_INT("net.graph.maxdata", &maxdata); 2874 SYSCTL_INT(_net_graph, OID_AUTO, maxdata, CTLFLAG_RDTUN, &maxdata, 2875 0, "Maximum number of data queue items to allocate"); 2876 2877 #ifdef NETGRAPH_DEBUG 2878 static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist); 2879 static int allocated; /* number of items malloc'd */ 2880 #endif 2881 2882 /* 2883 * Get a queue entry. 2884 * This is usually called when a packet first enters netgraph. 2885 * By definition, this is usually from an interrupt, or from a user. 2886 * Users are not so important, but try be quick for the times that it's 2887 * an interrupt. 2888 */ 2889 static __inline item_p 2890 ng_alloc_item(int type, int flags) 2891 { 2892 item_p item; 2893 2894 KASSERT(((type & ~NGQF_TYPE) == 0), 2895 ("%s: incorrect item type: %d", __func__, type)); 2896 2897 item = uma_zalloc((type == NGQF_DATA)?ng_qdzone:ng_qzone, 2898 ((flags & NG_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO); 2899 2900 if (item) { 2901 item->el_flags = type; 2902 #ifdef NETGRAPH_DEBUG 2903 mtx_lock(&ngq_mtx); 2904 TAILQ_INSERT_TAIL(&ng_itemlist, item, all); 2905 allocated++; 2906 mtx_unlock(&ngq_mtx); 2907 #endif 2908 } 2909 2910 return (item); 2911 } 2912 2913 /* 2914 * Release a queue entry 2915 */ 2916 void 2917 ng_free_item(item_p item) 2918 { 2919 /* 2920 * The item may hold resources on it's own. We need to free 2921 * these before we can free the item. What they are depends upon 2922 * what kind of item it is. it is important that nodes zero 2923 * out pointers to resources that they remove from the item 2924 * or we release them again here. 2925 */ 2926 switch (item->el_flags & NGQF_TYPE) { 2927 case NGQF_DATA: 2928 /* If we have an mbuf still attached.. */ 2929 NG_FREE_M(_NGI_M(item)); 2930 break; 2931 case NGQF_MESG: 2932 _NGI_RETADDR(item) = 0; 2933 NG_FREE_MSG(_NGI_MSG(item)); 2934 break; 2935 case NGQF_FN: 2936 case NGQF_FN2: 2937 /* nothing to free really, */ 2938 _NGI_FN(item) = NULL; 2939 _NGI_ARG1(item) = NULL; 2940 _NGI_ARG2(item) = 0; 2941 break; 2942 } 2943 /* If we still have a node or hook referenced... */ 2944 _NGI_CLR_NODE(item); 2945 _NGI_CLR_HOOK(item); 2946 2947 #ifdef NETGRAPH_DEBUG 2948 mtx_lock(&ngq_mtx); 2949 TAILQ_REMOVE(&ng_itemlist, item, all); 2950 allocated--; 2951 mtx_unlock(&ngq_mtx); 2952 #endif 2953 uma_zfree(((item->el_flags & NGQF_TYPE) == NGQF_DATA)? 2954 ng_qdzone:ng_qzone, item); 2955 } 2956 2957 /* 2958 * Change type of the queue entry. 2959 * Possibly reallocates it from another UMA zone. 2960 */ 2961 static __inline item_p 2962 ng_realloc_item(item_p pitem, int type, int flags) 2963 { 2964 item_p item; 2965 int from, to; 2966 2967 KASSERT((pitem != NULL), ("%s: can't reallocate NULL", __func__)); 2968 KASSERT(((type & ~NGQF_TYPE) == 0), 2969 ("%s: incorrect item type: %d", __func__, type)); 2970 2971 from = ((pitem->el_flags & NGQF_TYPE) == NGQF_DATA); 2972 to = (type == NGQF_DATA); 2973 if (from != to) { 2974 /* If reallocation is required do it and copy item. */ 2975 if ((item = ng_alloc_item(type, flags)) == NULL) { 2976 ng_free_item(pitem); 2977 return (NULL); 2978 } 2979 *item = *pitem; 2980 ng_free_item(pitem); 2981 } else 2982 item = pitem; 2983 item->el_flags = (item->el_flags & ~NGQF_TYPE) | type; 2984 2985 return (item); 2986 } 2987 2988 /************************************************************************ 2989 Module routines 2990 ************************************************************************/ 2991 2992 /* 2993 * Handle the loading/unloading of a netgraph node type module 2994 */ 2995 int 2996 ng_mod_event(module_t mod, int event, void *data) 2997 { 2998 struct ng_type *const type = data; 2999 int s, error = 0; 3000 3001 switch (event) { 3002 case MOD_LOAD: 3003 3004 /* Register new netgraph node type */ 3005 s = splnet(); 3006 if ((error = ng_newtype(type)) != 0) { 3007 splx(s); 3008 break; 3009 } 3010 3011 /* Call type specific code */ 3012 if (type->mod_event != NULL) 3013 if ((error = (*type->mod_event)(mod, event, data))) { 3014 mtx_lock(&ng_typelist_mtx); 3015 type->refs--; /* undo it */ 3016 LIST_REMOVE(type, types); 3017 mtx_unlock(&ng_typelist_mtx); 3018 } 3019 splx(s); 3020 break; 3021 3022 case MOD_UNLOAD: 3023 s = splnet(); 3024 if (type->refs > 1) { /* make sure no nodes exist! */ 3025 error = EBUSY; 3026 } else { 3027 if (type->refs == 0) { 3028 /* failed load, nothing to undo */ 3029 splx(s); 3030 break; 3031 } 3032 if (type->mod_event != NULL) { /* check with type */ 3033 error = (*type->mod_event)(mod, event, data); 3034 if (error != 0) { /* type refuses.. */ 3035 splx(s); 3036 break; 3037 } 3038 } 3039 mtx_lock(&ng_typelist_mtx); 3040 LIST_REMOVE(type, types); 3041 mtx_unlock(&ng_typelist_mtx); 3042 } 3043 splx(s); 3044 break; 3045 3046 default: 3047 if (type->mod_event != NULL) 3048 error = (*type->mod_event)(mod, event, data); 3049 else 3050 error = EOPNOTSUPP; /* XXX ? */ 3051 break; 3052 } 3053 return (error); 3054 } 3055 3056 /* 3057 * Handle loading and unloading for this code. 3058 * The only thing we need to link into is the NETISR strucure. 3059 */ 3060 static int 3061 ngb_mod_event(module_t mod, int event, void *data) 3062 { 3063 int error = 0; 3064 3065 switch (event) { 3066 case MOD_LOAD: 3067 /* Initialize everything. */ 3068 NG_WORKLIST_LOCK_INIT(); 3069 mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL, 3070 MTX_DEF); 3071 mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL, 3072 MTX_DEF); 3073 mtx_init(&ng_namehash_mtx, "netgraph namehash mutex", NULL, 3074 MTX_DEF); 3075 mtx_init(&ng_topo_mtx, "netgraph topology mutex", NULL, 3076 MTX_DEF); 3077 #ifdef NETGRAPH_DEBUG 3078 mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL, 3079 MTX_DEF); 3080 mtx_init(&ngq_mtx, "netgraph item list mutex", NULL, 3081 MTX_DEF); 3082 #endif 3083 ng_qzone = uma_zcreate("NetGraph items", sizeof(struct ng_item), 3084 NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 3085 uma_zone_set_max(ng_qzone, maxalloc); 3086 ng_qdzone = uma_zcreate("NetGraph data items", sizeof(struct ng_item), 3087 NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 3088 uma_zone_set_max(ng_qdzone, maxdata); 3089 netisr_register(NETISR_NETGRAPH, (netisr_t *)ngintr, NULL, 0); 3090 break; 3091 case MOD_UNLOAD: 3092 /* You can't unload it because an interface may be using it. */ 3093 error = EBUSY; 3094 break; 3095 default: 3096 error = EOPNOTSUPP; 3097 break; 3098 } 3099 return (error); 3100 } 3101 3102 static moduledata_t netgraph_mod = { 3103 "netgraph", 3104 ngb_mod_event, 3105 (NULL) 3106 }; 3107 DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_NETGRAPH, SI_ORDER_MIDDLE); 3108 SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 3109 SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 3110 SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 3111 3112 #ifdef NETGRAPH_DEBUG 3113 void 3114 dumphook (hook_p hook, char *file, int line) 3115 { 3116 printf("hook: name %s, %d refs, Last touched:\n", 3117 _NG_HOOK_NAME(hook), hook->hk_refs); 3118 printf(" Last active @ %s, line %d\n", 3119 hook->lastfile, hook->lastline); 3120 if (line) { 3121 printf(" problem discovered at file %s, line %d\n", file, line); 3122 } 3123 } 3124 3125 void 3126 dumpnode(node_p node, char *file, int line) 3127 { 3128 printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n", 3129 _NG_NODE_ID(node), node->nd_type->name, 3130 node->nd_numhooks, node->nd_flags, 3131 node->nd_refs, node->nd_name); 3132 printf(" Last active @ %s, line %d\n", 3133 node->lastfile, node->lastline); 3134 if (line) { 3135 printf(" problem discovered at file %s, line %d\n", file, line); 3136 } 3137 } 3138 3139 void 3140 dumpitem(item_p item, char *file, int line) 3141 { 3142 printf(" ACTIVE item, last used at %s, line %d", 3143 item->lastfile, item->lastline); 3144 switch(item->el_flags & NGQF_TYPE) { 3145 case NGQF_DATA: 3146 printf(" - [data]\n"); 3147 break; 3148 case NGQF_MESG: 3149 printf(" - retaddr[%d]:\n", _NGI_RETADDR(item)); 3150 break; 3151 case NGQF_FN: 3152 printf(" - fn@%p (%p, %p, %p, %d (%x))\n", 3153 _NGI_FN(item), 3154 _NGI_NODE(item), 3155 _NGI_HOOK(item), 3156 item->body.fn.fn_arg1, 3157 item->body.fn.fn_arg2, 3158 item->body.fn.fn_arg2); 3159 break; 3160 case NGQF_FN2: 3161 printf(" - fn2@%p (%p, %p, %p, %d (%x))\n", 3162 _NGI_FN2(item), 3163 _NGI_NODE(item), 3164 _NGI_HOOK(item), 3165 item->body.fn.fn_arg1, 3166 item->body.fn.fn_arg2, 3167 item->body.fn.fn_arg2); 3168 break; 3169 } 3170 if (line) { 3171 printf(" problem discovered at file %s, line %d\n", file, line); 3172 if (_NGI_NODE(item)) { 3173 printf("node %p ([%x])\n", 3174 _NGI_NODE(item), ng_node2ID(_NGI_NODE(item))); 3175 } 3176 } 3177 } 3178 3179 static void 3180 ng_dumpitems(void) 3181 { 3182 item_p item; 3183 int i = 1; 3184 TAILQ_FOREACH(item, &ng_itemlist, all) { 3185 printf("[%d] ", i++); 3186 dumpitem(item, NULL, 0); 3187 } 3188 } 3189 3190 static void 3191 ng_dumpnodes(void) 3192 { 3193 node_p node; 3194 int i = 1; 3195 mtx_lock(&ng_nodelist_mtx); 3196 SLIST_FOREACH(node, &ng_allnodes, nd_all) { 3197 printf("[%d] ", i++); 3198 dumpnode(node, NULL, 0); 3199 } 3200 mtx_unlock(&ng_nodelist_mtx); 3201 } 3202 3203 static void 3204 ng_dumphooks(void) 3205 { 3206 hook_p hook; 3207 int i = 1; 3208 mtx_lock(&ng_nodelist_mtx); 3209 SLIST_FOREACH(hook, &ng_allhooks, hk_all) { 3210 printf("[%d] ", i++); 3211 dumphook(hook, NULL, 0); 3212 } 3213 mtx_unlock(&ng_nodelist_mtx); 3214 } 3215 3216 static int 3217 sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS) 3218 { 3219 int error; 3220 int val; 3221 int i; 3222 3223 val = allocated; 3224 i = 1; 3225 error = sysctl_handle_int(oidp, &val, 0, req); 3226 if (error != 0 || req->newptr == NULL) 3227 return (error); 3228 if (val == 42) { 3229 ng_dumpitems(); 3230 ng_dumpnodes(); 3231 ng_dumphooks(); 3232 } 3233 return (0); 3234 } 3235 3236 SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, 3237 0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items"); 3238 #endif /* NETGRAPH_DEBUG */ 3239 3240 3241 /*********************************************************************** 3242 * Worklist routines 3243 **********************************************************************/ 3244 /* NETISR thread enters here */ 3245 /* 3246 * Pick a node off the list of nodes with work, 3247 * try get an item to process off it. 3248 * If there are no more, remove the node from the list. 3249 */ 3250 static void 3251 ngintr(void) 3252 { 3253 for (;;) { 3254 node_p node; 3255 3256 /* Get node from the worklist. */ 3257 NG_WORKLIST_LOCK(); 3258 node = STAILQ_FIRST(&ng_worklist); 3259 if (!node) { 3260 NG_WORKLIST_UNLOCK(); 3261 break; 3262 } 3263 STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work); 3264 NG_WORKLIST_UNLOCK(); 3265 CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist", 3266 __func__, node->nd_ID, node); 3267 /* 3268 * We have the node. We also take over the reference 3269 * that the list had on it. 3270 * Now process as much as you can, until it won't 3271 * let you have another item off the queue. 3272 * All this time, keep the reference 3273 * that lets us be sure that the node still exists. 3274 * Let the reference go at the last minute. 3275 */ 3276 for (;;) { 3277 item_p item; 3278 int rw; 3279 3280 NG_QUEUE_LOCK(&node->nd_input_queue); 3281 item = ng_dequeue(node, &rw); 3282 if (item == NULL) { 3283 node->nd_input_queue.q_flags2 &= ~NGQ2_WORKQ; 3284 NG_QUEUE_UNLOCK(&node->nd_input_queue); 3285 break; /* go look for another node */ 3286 } else { 3287 NG_QUEUE_UNLOCK(&node->nd_input_queue); 3288 NGI_GET_NODE(item, node); /* zaps stored node */ 3289 ng_apply_item(node, item, rw); 3290 NG_NODE_UNREF(node); 3291 } 3292 } 3293 NG_NODE_UNREF(node); 3294 } 3295 } 3296 3297 /* 3298 * XXX 3299 * It's posible that a debugging NG_NODE_REF may need 3300 * to be outside the mutex zone 3301 */ 3302 static void 3303 ng_worklist_add(node_p node) 3304 { 3305 3306 mtx_assert(&node->nd_input_queue.q_mtx, MA_OWNED); 3307 3308 if ((node->nd_input_queue.q_flags2 & NGQ2_WORKQ) == 0) { 3309 /* 3310 * If we are not already on the work queue, 3311 * then put us on. 3312 */ 3313 node->nd_input_queue.q_flags2 |= NGQ2_WORKQ; 3314 NG_NODE_REF(node); /* XXX fafe in mutex? */ 3315 NG_WORKLIST_LOCK(); 3316 STAILQ_INSERT_TAIL(&ng_worklist, node, nd_input_queue.q_work); 3317 NG_WORKLIST_UNLOCK(); 3318 schednetisr(NETISR_NETGRAPH); 3319 CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__, 3320 node->nd_ID, node); 3321 } else { 3322 CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist", 3323 __func__, node->nd_ID, node); 3324 } 3325 } 3326 3327 3328 /*********************************************************************** 3329 * Externally useable functions to set up a queue item ready for sending 3330 ***********************************************************************/ 3331 3332 #ifdef NETGRAPH_DEBUG 3333 #define ITEM_DEBUG_CHECKS \ 3334 do { \ 3335 if (NGI_NODE(item) ) { \ 3336 printf("item already has node"); \ 3337 kdb_enter(KDB_WHY_NETGRAPH, "has node"); \ 3338 NGI_CLR_NODE(item); \ 3339 } \ 3340 if (NGI_HOOK(item) ) { \ 3341 printf("item already has hook"); \ 3342 kdb_enter(KDB_WHY_NETGRAPH, "has hook"); \ 3343 NGI_CLR_HOOK(item); \ 3344 } \ 3345 } while (0) 3346 #else 3347 #define ITEM_DEBUG_CHECKS 3348 #endif 3349 3350 /* 3351 * Put mbuf into the item. 3352 * Hook and node references will be removed when the item is dequeued. 3353 * (or equivalent) 3354 * (XXX) Unsafe because no reference held by peer on remote node. 3355 * remote node might go away in this timescale. 3356 * We know the hooks can't go away because that would require getting 3357 * a writer item on both nodes and we must have at least a reader 3358 * here to be able to do this. 3359 * Note that the hook loaded is the REMOTE hook. 3360 * 3361 * This is possibly in the critical path for new data. 3362 */ 3363 item_p 3364 ng_package_data(struct mbuf *m, int flags) 3365 { 3366 item_p item; 3367 3368 if ((item = ng_alloc_item(NGQF_DATA, flags)) == NULL) { 3369 NG_FREE_M(m); 3370 return (NULL); 3371 } 3372 ITEM_DEBUG_CHECKS; 3373 item->el_flags |= NGQF_READER; 3374 NGI_M(item) = m; 3375 return (item); 3376 } 3377 3378 /* 3379 * Allocate a queue item and put items into it.. 3380 * Evaluate the address as this will be needed to queue it and 3381 * to work out what some of the fields should be. 3382 * Hook and node references will be removed when the item is dequeued. 3383 * (or equivalent) 3384 */ 3385 item_p 3386 ng_package_msg(struct ng_mesg *msg, int flags) 3387 { 3388 item_p item; 3389 3390 if ((item = ng_alloc_item(NGQF_MESG, flags)) == NULL) { 3391 NG_FREE_MSG(msg); 3392 return (NULL); 3393 } 3394 ITEM_DEBUG_CHECKS; 3395 /* Messages items count as writers unless explicitly exempted. */ 3396 if (msg->header.cmd & NGM_READONLY) 3397 item->el_flags |= NGQF_READER; 3398 else 3399 item->el_flags |= NGQF_WRITER; 3400 /* 3401 * Set the current lasthook into the queue item 3402 */ 3403 NGI_MSG(item) = msg; 3404 NGI_RETADDR(item) = 0; 3405 return (item); 3406 } 3407 3408 3409 3410 #define SET_RETADDR(item, here, retaddr) \ 3411 do { /* Data or fn items don't have retaddrs */ \ 3412 if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \ 3413 if (retaddr) { \ 3414 NGI_RETADDR(item) = retaddr; \ 3415 } else { \ 3416 /* \ 3417 * The old return address should be ok. \ 3418 * If there isn't one, use the address \ 3419 * here. \ 3420 */ \ 3421 if (NGI_RETADDR(item) == 0) { \ 3422 NGI_RETADDR(item) \ 3423 = ng_node2ID(here); \ 3424 } \ 3425 } \ 3426 } \ 3427 } while (0) 3428 3429 int 3430 ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr) 3431 { 3432 hook_p peer; 3433 node_p peernode; 3434 ITEM_DEBUG_CHECKS; 3435 /* 3436 * Quick sanity check.. 3437 * Since a hook holds a reference on it's node, once we know 3438 * that the peer is still connected (even if invalid,) we know 3439 * that the peer node is present, though maybe invalid. 3440 */ 3441 if ((hook == NULL) || 3442 NG_HOOK_NOT_VALID(hook) || 3443 NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) || 3444 NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) { 3445 NG_FREE_ITEM(item); 3446 TRAP_ERROR(); 3447 return (ENETDOWN); 3448 } 3449 3450 /* 3451 * Transfer our interest to the other (peer) end. 3452 */ 3453 NG_HOOK_REF(peer); 3454 NG_NODE_REF(peernode); 3455 NGI_SET_HOOK(item, peer); 3456 NGI_SET_NODE(item, peernode); 3457 SET_RETADDR(item, here, retaddr); 3458 return (0); 3459 } 3460 3461 int 3462 ng_address_path(node_p here, item_p item, char *address, ng_ID_t retaddr) 3463 { 3464 node_p dest = NULL; 3465 hook_p hook = NULL; 3466 int error; 3467 3468 ITEM_DEBUG_CHECKS; 3469 /* 3470 * Note that ng_path2noderef increments the reference count 3471 * on the node for us if it finds one. So we don't have to. 3472 */ 3473 error = ng_path2noderef(here, address, &dest, &hook); 3474 if (error) { 3475 NG_FREE_ITEM(item); 3476 return (error); 3477 } 3478 NGI_SET_NODE(item, dest); 3479 if ( hook) { 3480 NG_HOOK_REF(hook); /* don't let it go while on the queue */ 3481 NGI_SET_HOOK(item, hook); 3482 } 3483 SET_RETADDR(item, here, retaddr); 3484 return (0); 3485 } 3486 3487 int 3488 ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr) 3489 { 3490 node_p dest; 3491 3492 ITEM_DEBUG_CHECKS; 3493 /* 3494 * Find the target node. 3495 */ 3496 dest = ng_ID2noderef(ID); /* GETS REFERENCE! */ 3497 if (dest == NULL) { 3498 NG_FREE_ITEM(item); 3499 TRAP_ERROR(); 3500 return(EINVAL); 3501 } 3502 /* Fill out the contents */ 3503 NGI_SET_NODE(item, dest); 3504 NGI_CLR_HOOK(item); 3505 SET_RETADDR(item, here, retaddr); 3506 return (0); 3507 } 3508 3509 /* 3510 * special case to send a message to self (e.g. destroy node) 3511 * Possibly indicate an arrival hook too. 3512 * Useful for removing that hook :-) 3513 */ 3514 item_p 3515 ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg) 3516 { 3517 item_p item; 3518 3519 /* 3520 * Find the target node. 3521 * If there is a HOOK argument, then use that in preference 3522 * to the address. 3523 */ 3524 if ((item = ng_alloc_item(NGQF_MESG, NG_NOFLAGS)) == NULL) { 3525 NG_FREE_MSG(msg); 3526 return (NULL); 3527 } 3528 3529 /* Fill out the contents */ 3530 item->el_flags |= NGQF_WRITER; 3531 NG_NODE_REF(here); 3532 NGI_SET_NODE(item, here); 3533 if (hook) { 3534 NG_HOOK_REF(hook); 3535 NGI_SET_HOOK(item, hook); 3536 } 3537 NGI_MSG(item) = msg; 3538 NGI_RETADDR(item) = ng_node2ID(here); 3539 return (item); 3540 } 3541 3542 /* 3543 * Send ng_item_fn function call to the specified node. 3544 */ 3545 3546 int 3547 ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2) 3548 { 3549 3550 return ng_send_fn1(node, hook, fn, arg1, arg2, NG_NOFLAGS); 3551 } 3552 3553 int 3554 ng_send_fn1(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2, 3555 int flags) 3556 { 3557 item_p item; 3558 3559 if ((item = ng_alloc_item(NGQF_FN, flags)) == NULL) { 3560 return (ENOMEM); 3561 } 3562 item->el_flags |= NGQF_WRITER; 3563 NG_NODE_REF(node); /* and one for the item */ 3564 NGI_SET_NODE(item, node); 3565 if (hook) { 3566 NG_HOOK_REF(hook); 3567 NGI_SET_HOOK(item, hook); 3568 } 3569 NGI_FN(item) = fn; 3570 NGI_ARG1(item) = arg1; 3571 NGI_ARG2(item) = arg2; 3572 return(ng_snd_item(item, flags)); 3573 } 3574 3575 /* 3576 * Send ng_item_fn2 function call to the specified node. 3577 * 3578 * If an optional pitem parameter is supplied, its apply 3579 * callback will be copied to the new item. If also NG_REUSE_ITEM 3580 * flag is set, no new item will be allocated, but pitem will 3581 * be used. 3582 */ 3583 int 3584 ng_send_fn2(node_p node, hook_p hook, item_p pitem, ng_item_fn2 *fn, void *arg1, 3585 int arg2, int flags) 3586 { 3587 item_p item; 3588 3589 KASSERT((pitem != NULL || (flags & NG_REUSE_ITEM) == 0), 3590 ("%s: NG_REUSE_ITEM but no pitem", __func__)); 3591 3592 /* 3593 * Allocate a new item if no supplied or 3594 * if we can't use supplied one. 3595 */ 3596 if (pitem == NULL || (flags & NG_REUSE_ITEM) == 0) { 3597 if ((item = ng_alloc_item(NGQF_FN2, flags)) == NULL) 3598 return (ENOMEM); 3599 if (pitem != NULL) 3600 item->apply = pitem->apply; 3601 } else { 3602 if ((item = ng_realloc_item(pitem, NGQF_FN2, flags)) == NULL) 3603 return (ENOMEM); 3604 } 3605 3606 item->el_flags = (item->el_flags & ~NGQF_RW) | NGQF_WRITER; 3607 NG_NODE_REF(node); /* and one for the item */ 3608 NGI_SET_NODE(item, node); 3609 if (hook) { 3610 NG_HOOK_REF(hook); 3611 NGI_SET_HOOK(item, hook); 3612 } 3613 NGI_FN2(item) = fn; 3614 NGI_ARG1(item) = arg1; 3615 NGI_ARG2(item) = arg2; 3616 return(ng_snd_item(item, flags)); 3617 } 3618 3619 /* 3620 * Official timeout routines for Netgraph nodes. 3621 */ 3622 static void 3623 ng_callout_trampoline(void *arg) 3624 { 3625 item_p item = arg; 3626 3627 ng_snd_item(item, 0); 3628 } 3629 3630 3631 int 3632 ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, 3633 ng_item_fn *fn, void * arg1, int arg2) 3634 { 3635 item_p item, oitem; 3636 3637 if ((item = ng_alloc_item(NGQF_FN, NG_NOFLAGS)) == NULL) 3638 return (ENOMEM); 3639 3640 item->el_flags |= NGQF_WRITER; 3641 NG_NODE_REF(node); /* and one for the item */ 3642 NGI_SET_NODE(item, node); 3643 if (hook) { 3644 NG_HOOK_REF(hook); 3645 NGI_SET_HOOK(item, hook); 3646 } 3647 NGI_FN(item) = fn; 3648 NGI_ARG1(item) = arg1; 3649 NGI_ARG2(item) = arg2; 3650 oitem = c->c_arg; 3651 if (callout_reset(c, ticks, &ng_callout_trampoline, item) == 1 && 3652 oitem != NULL) 3653 NG_FREE_ITEM(oitem); 3654 return (0); 3655 } 3656 3657 /* A special modified version of untimeout() */ 3658 int 3659 ng_uncallout(struct callout *c, node_p node) 3660 { 3661 item_p item; 3662 int rval; 3663 3664 KASSERT(c != NULL, ("ng_uncallout: NULL callout")); 3665 KASSERT(node != NULL, ("ng_uncallout: NULL node")); 3666 3667 rval = callout_stop(c); 3668 item = c->c_arg; 3669 /* Do an extra check */ 3670 if ((rval > 0) && (c->c_func == &ng_callout_trampoline) && 3671 (NGI_NODE(item) == node)) { 3672 /* 3673 * We successfully removed it from the queue before it ran 3674 * So now we need to unreference everything that was 3675 * given extra references. (NG_FREE_ITEM does this). 3676 */ 3677 NG_FREE_ITEM(item); 3678 } 3679 c->c_arg = NULL; 3680 3681 return (rval); 3682 } 3683 3684 /* 3685 * Set the address, if none given, give the node here. 3686 */ 3687 void 3688 ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr) 3689 { 3690 if (retaddr) { 3691 NGI_RETADDR(item) = retaddr; 3692 } else { 3693 /* 3694 * The old return address should be ok. 3695 * If there isn't one, use the address here. 3696 */ 3697 NGI_RETADDR(item) = ng_node2ID(here); 3698 } 3699 } 3700 3701 #define TESTING 3702 #ifdef TESTING 3703 /* just test all the macros */ 3704 void 3705 ng_macro_test(item_p item); 3706 void 3707 ng_macro_test(item_p item) 3708 { 3709 node_p node = NULL; 3710 hook_p hook = NULL; 3711 struct mbuf *m; 3712 struct ng_mesg *msg; 3713 ng_ID_t retaddr; 3714 int error; 3715 3716 NGI_GET_M(item, m); 3717 NGI_GET_MSG(item, msg); 3718 retaddr = NGI_RETADDR(item); 3719 NG_SEND_DATA(error, hook, m, NULL); 3720 NG_SEND_DATA_ONLY(error, hook, m); 3721 NG_FWD_NEW_DATA(error, item, hook, m); 3722 NG_FWD_ITEM_HOOK(error, item, hook); 3723 NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr); 3724 NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr); 3725 NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr); 3726 NG_FWD_MSG_HOOK(error, node, item, hook, retaddr); 3727 } 3728 #endif /* TESTING */ 3729 3730