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