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