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