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