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