1c398230bSWarner Losh /*- 24cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 34cf49a43SJulian Elischer * All rights reserved. 44cf49a43SJulian Elischer * 54cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 64cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 74cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 84cf49a43SJulian Elischer * provided, however, that: 94cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 104cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 114cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 124cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 134cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 144cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 154cf49a43SJulian Elischer * 164cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 174cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 184cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 194cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 204cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 214cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 224cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 234cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 244cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 254cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 264cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 274cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 284cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 294cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 304cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 314cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 324cf49a43SJulian Elischer * OF SUCH DAMAGE. 334cf49a43SJulian Elischer * 34cc3bbd68SJulian Elischer * Authors: Julian Elischer <julian@freebsd.org> 35cc3bbd68SJulian Elischer * Archie Cobbs <archie@freebsd.org> 364cf49a43SJulian Elischer * 374cf49a43SJulian Elischer * $FreeBSD$ 384cf49a43SJulian Elischer * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 394cf49a43SJulian Elischer */ 404cf49a43SJulian Elischer 414cf49a43SJulian Elischer /* 424cf49a43SJulian Elischer * This file implements the base netgraph code. 434cf49a43SJulian Elischer */ 444cf49a43SJulian Elischer 454cf49a43SJulian Elischer #include <sys/param.h> 468e853a2cSGleb Smirnoff #include <sys/systm.h> 4777a58296SGleb Smirnoff #include <sys/ctype.h> 484cf49a43SJulian Elischer #include <sys/errno.h> 49f33ca0c9SMarcel Moolenaar #include <sys/kdb.h> 504cf49a43SJulian Elischer #include <sys/kernel.h> 513b33fbe7SGleb Smirnoff #include <sys/ktr.h> 52104a9b7eSAlexander Kabaev #include <sys/limits.h> 53*c4282b74SGleb Smirnoff #include <sys/lock.h> 544cf49a43SJulian Elischer #include <sys/malloc.h> 554cf49a43SJulian Elischer #include <sys/mbuf.h> 5677a58296SGleb Smirnoff #include <sys/queue.h> 57bfa7e882SJulian Elischer #include <sys/sysctl.h> 5877a58296SGleb Smirnoff #include <sys/syslog.h> 59e088dd4cSAlexander Motin #include <sys/refcount.h> 6081a253a4SAlexander Motin #include <sys/proc.h> 61*c4282b74SGleb Smirnoff #include <sys/rwlock.h> 62f2fbb838SAlexander Motin #include <sys/unistd.h> 63f2fbb838SAlexander Motin #include <sys/kthread.h> 64f2fbb838SAlexander Motin #include <sys/smp.h> 65394cb30aSAlexander Motin #include <machine/cpu.h> 664cf49a43SJulian Elischer 674cf49a43SJulian Elischer #include <net/netisr.h> 68eddfbb76SRobert Watson #include <net/vnet.h> 694cf49a43SJulian Elischer 704cf49a43SJulian Elischer #include <netgraph/ng_message.h> 714cf49a43SJulian Elischer #include <netgraph/netgraph.h> 72f8307e12SArchie Cobbs #include <netgraph/ng_parse.h> 734cf49a43SJulian Elischer 749d72a7a3SJulian Elischer MODULE_VERSION(netgraph, NG_ABI_VERSION); 7599ff8176SPeter Wemm 76ac5dd141SGleb Smirnoff /* Mutex to protect topology events. */ 77ac5dd141SGleb Smirnoff static struct mtx ng_topo_mtx; 78ac5dd141SGleb Smirnoff 7930400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 80cfea3f85SAlexander Motin static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */ 811489164fSGleb Smirnoff static struct mtx ngq_mtx; /* protects the queue item list */ 8230400f03SJulian Elischer 8330400f03SJulian Elischer static SLIST_HEAD(, ng_node) ng_allnodes; 8430400f03SJulian Elischer static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */ 8530400f03SJulian Elischer static SLIST_HEAD(, ng_hook) ng_allhooks; 8630400f03SJulian Elischer static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */ 8730400f03SJulian Elischer 8830400f03SJulian Elischer static void ng_dumpitems(void); 8930400f03SJulian Elischer static void ng_dumpnodes(void); 9030400f03SJulian Elischer static void ng_dumphooks(void); 9130400f03SJulian Elischer 9230400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 93954c4772SJulian Elischer /* 94954c4772SJulian Elischer * DEAD versions of the structures. 95954c4772SJulian Elischer * In order to avoid races, it is sometimes neccesary to point 96954c4772SJulian Elischer * at SOMETHING even though theoretically, the current entity is 97954c4772SJulian Elischer * INVALID. Use these to avoid these races. 98954c4772SJulian Elischer */ 99954c4772SJulian Elischer struct ng_type ng_deadtype = { 100954c4772SJulian Elischer NG_ABI_VERSION, 101954c4772SJulian Elischer "dead", 102954c4772SJulian Elischer NULL, /* modevent */ 103954c4772SJulian Elischer NULL, /* constructor */ 104954c4772SJulian Elischer NULL, /* rcvmsg */ 105954c4772SJulian Elischer NULL, /* shutdown */ 106954c4772SJulian Elischer NULL, /* newhook */ 107954c4772SJulian Elischer NULL, /* findhook */ 108954c4772SJulian Elischer NULL, /* connect */ 109954c4772SJulian Elischer NULL, /* rcvdata */ 110954c4772SJulian Elischer NULL, /* disconnect */ 111954c4772SJulian Elischer NULL, /* cmdlist */ 112954c4772SJulian Elischer }; 11330400f03SJulian Elischer 114954c4772SJulian Elischer struct ng_node ng_deadnode = { 115954c4772SJulian Elischer "dead", 116954c4772SJulian Elischer &ng_deadtype, 117be4252b3SJulian Elischer NGF_INVALID, 118954c4772SJulian Elischer 0, /* numhooks */ 119954c4772SJulian Elischer NULL, /* private */ 120954c4772SJulian Elischer 0, /* ID */ 12113e403fdSAntoine Brodin LIST_HEAD_INITIALIZER(ng_deadnode.nd_hooks), 122954c4772SJulian Elischer {}, /* all_nodes list entry */ 123954c4772SJulian Elischer {}, /* id hashtable list entry */ 124954c4772SJulian Elischer { 0, 1259852972bSAlexander Motin 0, 126954c4772SJulian Elischer {}, /* should never use! (should hang) */ 1279852972bSAlexander Motin {}, /* workqueue entry */ 1289852972bSAlexander Motin STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue), 129954c4772SJulian Elischer }, 1309852972bSAlexander Motin 1, /* refs */ 131a40b7874SMarko Zec NULL, /* vnet */ 132954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 133954c4772SJulian Elischer ND_MAGIC, 134954c4772SJulian Elischer __FILE__, 135954c4772SJulian Elischer __LINE__, 136954c4772SJulian Elischer {NULL} 137954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 138954c4772SJulian Elischer }; 139954c4772SJulian Elischer 140954c4772SJulian Elischer struct ng_hook ng_deadhook = { 141954c4772SJulian Elischer "dead", 142954c4772SJulian Elischer NULL, /* private */ 143954c4772SJulian Elischer HK_INVALID | HK_DEAD, 144e58d779dSGleb Smirnoff 0, /* undefined data link type */ 145954c4772SJulian Elischer &ng_deadhook, /* Peer is self */ 146954c4772SJulian Elischer &ng_deadnode, /* attached to deadnode */ 147954c4772SJulian Elischer {}, /* hooks list */ 148c4b5eea4SJulian Elischer NULL, /* override rcvmsg() */ 149c4b5eea4SJulian Elischer NULL, /* override rcvdata() */ 1509852972bSAlexander Motin 1, /* refs always >= 1 */ 151954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 152954c4772SJulian Elischer HK_MAGIC, 153954c4772SJulian Elischer __FILE__, 154954c4772SJulian Elischer __LINE__, 155954c4772SJulian Elischer {NULL} 156954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 157954c4772SJulian Elischer }; 158954c4772SJulian Elischer 159954c4772SJulian Elischer /* 160954c4772SJulian Elischer * END DEAD STRUCTURES 161954c4772SJulian Elischer */ 162069154d5SJulian Elischer /* List nodes with unallocated work */ 1639852972bSAlexander Motin static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist); 164b57a7965SJulian Elischer static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */ 1654cf49a43SJulian Elischer 1664cf49a43SJulian Elischer /* List of installed types */ 167069154d5SJulian Elischer static LIST_HEAD(, ng_type) ng_typelist; 168*c4282b74SGleb Smirnoff static struct rwlock ng_typelist_lock; 169*c4282b74SGleb Smirnoff #define TYPELIST_RLOCK() rw_rlock(&ng_typelist_lock) 170*c4282b74SGleb Smirnoff #define TYPELIST_RUNLOCK() rw_runlock(&ng_typelist_lock) 171*c4282b74SGleb Smirnoff #define TYPELIST_WLOCK() rw_wlock(&ng_typelist_lock) 172*c4282b74SGleb Smirnoff #define TYPELIST_WUNLOCK() rw_wunlock(&ng_typelist_lock) 1734cf49a43SJulian Elischer 174069154d5SJulian Elischer /* Hash related definitions */ 1750f150d04SJulian Elischer /* XXX Don't need to initialise them because it's a LIST */ 1763e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, ng_node), ng_ID_hash[NG_ID_HASH_SIZE]); 1771e77c105SRobert Watson #define V_ng_ID_hash VNET(ng_ID_hash) 178eddfbb76SRobert Watson 179*c4282b74SGleb Smirnoff static struct rwlock ng_idhash_lock; 180*c4282b74SGleb Smirnoff #define IDHASH_RLOCK() rw_rlock(&ng_idhash_lock) 181*c4282b74SGleb Smirnoff #define IDHASH_RUNLOCK() rw_runlock(&ng_idhash_lock) 182*c4282b74SGleb Smirnoff #define IDHASH_WLOCK() rw_wlock(&ng_idhash_lock) 183*c4282b74SGleb Smirnoff #define IDHASH_WUNLOCK() rw_wunlock(&ng_idhash_lock) 184*c4282b74SGleb Smirnoff 1850f150d04SJulian Elischer /* Method to find a node.. used twice so do it here */ 1860f150d04SJulian Elischer #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE)) 1870f150d04SJulian Elischer #define NG_IDHASH_FIND(ID, node) \ 1880f150d04SJulian Elischer do { \ 189*c4282b74SGleb Smirnoff rw_assert(&ng_idhash_lock, RA_LOCKED); \ 190603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \ 1910f150d04SJulian Elischer nd_idnodes) { \ 1920f150d04SJulian Elischer if (NG_NODE_IS_VALID(node) \ 1930f150d04SJulian Elischer && (NG_NODE_ID(node) == ID)) { \ 1940f150d04SJulian Elischer break; \ 1950f150d04SJulian Elischer } \ 1960f150d04SJulian Elischer } \ 1970f150d04SJulian Elischer } while (0) 198069154d5SJulian Elischer 1993e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, ng_node), ng_name_hash[NG_NAME_HASH_SIZE]); 2001e77c105SRobert Watson #define V_ng_name_hash VNET(ng_name_hash) 201eddfbb76SRobert Watson 202cfea3f85SAlexander Motin #define NG_NAMEHASH(NAME, HASH) \ 203cfea3f85SAlexander Motin do { \ 204cfea3f85SAlexander Motin u_char h = 0; \ 205cfea3f85SAlexander Motin const u_char *c; \ 206cfea3f85SAlexander Motin for (c = (const u_char*)(NAME); *c; c++)\ 207cfea3f85SAlexander Motin h += *c; \ 208cfea3f85SAlexander Motin (HASH) = h % (NG_NAME_HASH_SIZE); \ 209cfea3f85SAlexander Motin } while (0) 210cfea3f85SAlexander Motin 211*c4282b74SGleb Smirnoff static struct rwlock ng_namehash_lock; 212*c4282b74SGleb Smirnoff #define NAMEHASH_RLOCK() rw_rlock(&ng_namehash_lock) 213*c4282b74SGleb Smirnoff #define NAMEHASH_RUNLOCK() rw_runlock(&ng_namehash_lock) 214*c4282b74SGleb Smirnoff #define NAMEHASH_WLOCK() rw_wlock(&ng_namehash_lock) 215*c4282b74SGleb Smirnoff #define NAMEHASH_WUNLOCK() rw_wunlock(&ng_namehash_lock) 216dc90cad9SJulian Elischer 2174cf49a43SJulian Elischer /* Internal functions */ 2184cf49a43SJulian Elischer static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 219069154d5SJulian Elischer static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); 220dc90cad9SJulian Elischer static ng_ID_t ng_decodeidname(const char *name); 2214cf49a43SJulian Elischer static int ngb_mod_event(module_t mod, int event, void *data); 222394cb30aSAlexander Motin static void ng_worklist_add(node_p node); 223f2fbb838SAlexander Motin static void ngthread(void *); 22427757487SGleb Smirnoff static int ng_apply_item(node_p node, item_p item, int rw); 2259852972bSAlexander Motin static void ng_flush_input_queue(node_p node); 226069154d5SJulian Elischer static node_p ng_ID2noderef(ng_ID_t ID); 227e088dd4cSAlexander Motin static int ng_con_nodes(item_p item, node_p node, const char *name, 228e088dd4cSAlexander Motin node_p node2, const char *name2); 229e088dd4cSAlexander Motin static int ng_con_part2(node_p node, item_p item, hook_p hook); 230e088dd4cSAlexander Motin static int ng_con_part3(node_p node, item_p item, hook_p hook); 2316b795970SJulian Elischer static int ng_mkpeer(node_p node, const char *name, 2326b795970SJulian Elischer const char *name2, char *type); 233069154d5SJulian Elischer 2344c9b5910SGleb Smirnoff /* Imported, these used to be externally visible, some may go back. */ 235069154d5SJulian Elischer void ng_destroy_hook(hook_p hook); 236069154d5SJulian Elischer int ng_path2noderef(node_p here, const char *path, 237069154d5SJulian Elischer node_p *dest, hook_p *lasthook); 238069154d5SJulian Elischer int ng_make_node(const char *type, node_p *nodepp); 239069154d5SJulian Elischer int ng_path_parse(char *addr, char **node, char **path, char **hook); 2401acb27c6SJulian Elischer void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3); 24130400f03SJulian Elischer void ng_unname(node_p node); 242069154d5SJulian Elischer 2434cf49a43SJulian Elischer 2444cf49a43SJulian Elischer /* Our own netgraph malloc type */ 2454cf49a43SJulian Elischer MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 246069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); 247d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", 248d745c852SEd Schouten "netgraph hook structures"); 249d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", 250d745c852SEd Schouten "netgraph node structures"); 251d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", 252d745c852SEd Schouten "netgraph item structures"); 253069154d5SJulian Elischer 254069154d5SJulian Elischer /* Should not be visible outside this file */ 25530400f03SJulian Elischer 25630400f03SJulian Elischer #define _NG_ALLOC_HOOK(hook) \ 2571ede983cSDag-Erling Smørgrav hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO) 25830400f03SJulian Elischer #define _NG_ALLOC_NODE(node) \ 2591ede983cSDag-Erling Smørgrav node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO) 26030400f03SJulian Elischer 2612c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK_INIT(n) \ 2624abab3d5SWojciech A. Koszek mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF) 2632c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK(n) \ 2644abab3d5SWojciech A. Koszek mtx_lock(&(n)->q_mtx) 2652c8dda8dSWojciech A. Koszek #define NG_QUEUE_UNLOCK(n) \ 2664abab3d5SWojciech A. Koszek mtx_unlock(&(n)->q_mtx) 2672c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK_INIT() \ 2684abab3d5SWojciech A. Koszek mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF) 2692c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK() \ 2704abab3d5SWojciech A. Koszek mtx_lock(&ng_worklist_mtx) 2712c8dda8dSWojciech A. Koszek #define NG_WORKLIST_UNLOCK() \ 2724abab3d5SWojciech A. Koszek mtx_unlock(&ng_worklist_mtx) 273f2fbb838SAlexander Motin #define NG_WORKLIST_SLEEP() \ 274f2fbb838SAlexander Motin mtx_sleep(&ng_worklist, &ng_worklist_mtx, PI_NET, "sleep", 0) 275f2fbb838SAlexander Motin #define NG_WORKLIST_WAKEUP() \ 276f2fbb838SAlexander Motin wakeup_one(&ng_worklist) 2772c8dda8dSWojciech A. Koszek 27830400f03SJulian Elischer #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 27930400f03SJulian Elischer /* 28030400f03SJulian Elischer * In debug mode: 28130400f03SJulian Elischer * In an attempt to help track reference count screwups 28230400f03SJulian Elischer * we do not free objects back to the malloc system, but keep them 28330400f03SJulian Elischer * in a local cache where we can examine them and keep information safely 28430400f03SJulian Elischer * after they have been freed. 28530400f03SJulian Elischer * We use this scheme for nodes and hooks, and to some extent for items. 28630400f03SJulian Elischer */ 28730400f03SJulian Elischer static __inline hook_p 28830400f03SJulian Elischer ng_alloc_hook(void) 28930400f03SJulian Elischer { 29030400f03SJulian Elischer hook_p hook; 29130400f03SJulian Elischer SLIST_ENTRY(ng_hook) temp; 2929ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 29330400f03SJulian Elischer hook = LIST_FIRST(&ng_freehooks); 29430400f03SJulian Elischer if (hook) { 29530400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 29630400f03SJulian Elischer bcopy(&hook->hk_all, &temp, sizeof(temp)); 29730400f03SJulian Elischer bzero(hook, sizeof(struct ng_hook)); 29830400f03SJulian Elischer bcopy(&temp, &hook->hk_all, sizeof(temp)); 2999ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 30030400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 30130400f03SJulian Elischer } else { 3029ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 30330400f03SJulian Elischer _NG_ALLOC_HOOK(hook); 30430400f03SJulian Elischer if (hook) { 30530400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 3069ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 30730400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all); 3089ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 30930400f03SJulian Elischer } 31030400f03SJulian Elischer } 31130400f03SJulian Elischer return (hook); 31230400f03SJulian Elischer } 31330400f03SJulian Elischer 31430400f03SJulian Elischer static __inline node_p 31530400f03SJulian Elischer ng_alloc_node(void) 31630400f03SJulian Elischer { 31730400f03SJulian Elischer node_p node; 31830400f03SJulian Elischer SLIST_ENTRY(ng_node) temp; 3199ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 32030400f03SJulian Elischer node = LIST_FIRST(&ng_freenodes); 32130400f03SJulian Elischer if (node) { 32230400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 32330400f03SJulian Elischer bcopy(&node->nd_all, &temp, sizeof(temp)); 32430400f03SJulian Elischer bzero(node, sizeof(struct ng_node)); 32530400f03SJulian Elischer bcopy(&temp, &node->nd_all, sizeof(temp)); 3269ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 32730400f03SJulian Elischer node->nd_magic = ND_MAGIC; 32830400f03SJulian Elischer } else { 3299ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 33030400f03SJulian Elischer _NG_ALLOC_NODE(node); 33130400f03SJulian Elischer if (node) { 33230400f03SJulian Elischer node->nd_magic = ND_MAGIC; 3339ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 33430400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all); 3359ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 33630400f03SJulian Elischer } 33730400f03SJulian Elischer } 33830400f03SJulian Elischer return (node); 33930400f03SJulian Elischer } 34030400f03SJulian Elischer 34130400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0) 34230400f03SJulian Elischer #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0) 34330400f03SJulian Elischer 34430400f03SJulian Elischer 34530400f03SJulian Elischer #define NG_FREE_HOOK(hook) \ 34630400f03SJulian Elischer do { \ 3479ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 34830400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \ 34930400f03SJulian Elischer hook->hk_magic = 0; \ 3509ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 35130400f03SJulian Elischer } while (0) 35230400f03SJulian Elischer 35330400f03SJulian Elischer #define NG_FREE_NODE(node) \ 35430400f03SJulian Elischer do { \ 3559ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 35630400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \ 35730400f03SJulian Elischer node->nd_magic = 0; \ 3589ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 35930400f03SJulian Elischer } while (0) 36030400f03SJulian Elischer 36130400f03SJulian Elischer #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 36230400f03SJulian Elischer 36330400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook) 36430400f03SJulian Elischer #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node) 36530400f03SJulian Elischer 3661ede983cSDag-Erling Smørgrav #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0) 3671ede983cSDag-Erling Smørgrav #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0) 36830400f03SJulian Elischer 36930400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 37030400f03SJulian Elischer 371f33ca0c9SMarcel Moolenaar /* Set this to kdb_enter("X") to catch all errors as they occur */ 3724cf49a43SJulian Elischer #ifndef TRAP_ERROR 3736b795970SJulian Elischer #define TRAP_ERROR() 3744cf49a43SJulian Elischer #endif 3754cf49a43SJulian Elischer 3763e288e62SDimitry Andric static VNET_DEFINE(ng_ID_t, nextID) = 1; 3771e77c105SRobert Watson #define V_nextID VNET(nextID) 378dc90cad9SJulian Elischer 379b2da83c2SArchie Cobbs #ifdef INVARIANTS 380b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) do { \ 381b2da83c2SArchie Cobbs struct mbuf *n; \ 382b2da83c2SArchie Cobbs int total; \ 383b2da83c2SArchie Cobbs \ 384fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); \ 385b32cfb32SGleb Smirnoff for (total = 0, n = (m); n != NULL; n = n->m_next) { \ 386b2da83c2SArchie Cobbs total += n->m_len; \ 387b32cfb32SGleb Smirnoff if (n->m_nextpkt != NULL) \ 388b32cfb32SGleb Smirnoff panic("%s: m_nextpkt", __func__); \ 389b32cfb32SGleb Smirnoff } \ 390ba5b359aSGleb Smirnoff \ 391b2da83c2SArchie Cobbs if ((m)->m_pkthdr.len != total) { \ 392b2da83c2SArchie Cobbs panic("%s: %d != %d", \ 3936e551fb6SDavid E. O'Brien __func__, (m)->m_pkthdr.len, total); \ 394b2da83c2SArchie Cobbs } \ 395b2da83c2SArchie Cobbs } while (0) 396b2da83c2SArchie Cobbs #else 397b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) 398b2da83c2SArchie Cobbs #endif 399b2da83c2SArchie Cobbs 400e088dd4cSAlexander Motin #define ERROUT(x) do { error = (x); goto done; } while (0) 401dc90cad9SJulian Elischer 4024cf49a43SJulian Elischer /************************************************************************ 403f8307e12SArchie Cobbs Parse type definitions for generic messages 404f8307e12SArchie Cobbs ************************************************************************/ 405f8307e12SArchie Cobbs 406f8307e12SArchie Cobbs /* Handy structure parse type defining macro */ 407f8307e12SArchie Cobbs #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 408f0184ff8SArchie Cobbs static const struct ng_parse_struct_field \ 409f0184ff8SArchie Cobbs ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 410f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 411f8307e12SArchie Cobbs &ng_parse_struct_type, \ 412f0184ff8SArchie Cobbs &ng_ ## lo ## _type_fields \ 413f8307e12SArchie Cobbs } 414f8307e12SArchie Cobbs 415f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 416f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 417f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 418f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 419f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 420f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 421f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 422f8307e12SArchie Cobbs 423f8307e12SArchie Cobbs /* Get length of an array when the length is stored as a 32 bit 424d7d97eb0SJeroen Ruigrok van der Werven value immediately preceding the array -- as with struct namelist 425f8307e12SArchie Cobbs and struct typelist. */ 426f8307e12SArchie Cobbs static int 427f8307e12SArchie Cobbs ng_generic_list_getLength(const struct ng_parse_type *type, 428f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 429f8307e12SArchie Cobbs { 430f8307e12SArchie Cobbs return *((const u_int32_t *)(buf - 4)); 431f8307e12SArchie Cobbs } 432f8307e12SArchie Cobbs 433f8307e12SArchie Cobbs /* Get length of the array of struct linkinfo inside a struct hooklist */ 434f8307e12SArchie Cobbs static int 435f8307e12SArchie Cobbs ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 436f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 437f8307e12SArchie Cobbs { 438f8307e12SArchie Cobbs const struct hooklist *hl = (const struct hooklist *)start; 439f8307e12SArchie Cobbs 440f8307e12SArchie Cobbs return hl->nodeinfo.hooks; 441f8307e12SArchie Cobbs } 442f8307e12SArchie Cobbs 443f8307e12SArchie Cobbs /* Array type for a variable length array of struct namelist */ 444f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 445f8307e12SArchie Cobbs &ng_generic_nodeinfo_type, 446f8307e12SArchie Cobbs &ng_generic_list_getLength 447f8307e12SArchie Cobbs }; 448f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 449f8307e12SArchie Cobbs &ng_parse_array_type, 450f8307e12SArchie Cobbs &ng_nodeinfoarray_type_info 451f8307e12SArchie Cobbs }; 452f8307e12SArchie Cobbs 453f8307e12SArchie Cobbs /* Array type for a variable length array of struct typelist */ 454f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 455f8307e12SArchie Cobbs &ng_generic_typeinfo_type, 456f8307e12SArchie Cobbs &ng_generic_list_getLength 457f8307e12SArchie Cobbs }; 458f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_typeinfoarray_type = { 459f8307e12SArchie Cobbs &ng_parse_array_type, 460f8307e12SArchie Cobbs &ng_typeinfoarray_type_info 461f8307e12SArchie Cobbs }; 462f8307e12SArchie Cobbs 463f8307e12SArchie Cobbs /* Array type for array of struct linkinfo in struct hooklist */ 464f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 465f8307e12SArchie Cobbs &ng_generic_linkinfo_type, 466f8307e12SArchie Cobbs &ng_generic_linkinfo_getLength 467f8307e12SArchie Cobbs }; 468f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_linkinfo_array_type = { 469f8307e12SArchie Cobbs &ng_parse_array_type, 470f8307e12SArchie Cobbs &ng_generic_linkinfo_array_type_info 471f8307e12SArchie Cobbs }; 472f8307e12SArchie Cobbs 473f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 474f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 475f8307e12SArchie Cobbs (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 476f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 477f8307e12SArchie Cobbs (&ng_generic_nodeinfoarray_type)); 478f8307e12SArchie Cobbs 479f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 480f8307e12SArchie Cobbs static const struct ng_cmdlist ng_generic_cmds[] = { 481f8307e12SArchie Cobbs { 482f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 483f8307e12SArchie Cobbs NGM_SHUTDOWN, 484f8307e12SArchie Cobbs "shutdown", 485f8307e12SArchie Cobbs NULL, 486f8307e12SArchie Cobbs NULL 487f8307e12SArchie Cobbs }, 488f8307e12SArchie Cobbs { 489f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 490f8307e12SArchie Cobbs NGM_MKPEER, 491f8307e12SArchie Cobbs "mkpeer", 492f8307e12SArchie Cobbs &ng_generic_mkpeer_type, 493f8307e12SArchie Cobbs NULL 494f8307e12SArchie Cobbs }, 495f8307e12SArchie Cobbs { 496f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 497f8307e12SArchie Cobbs NGM_CONNECT, 498f8307e12SArchie Cobbs "connect", 499f8307e12SArchie Cobbs &ng_generic_connect_type, 500f8307e12SArchie Cobbs NULL 501f8307e12SArchie Cobbs }, 502f8307e12SArchie Cobbs { 503f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 504f8307e12SArchie Cobbs NGM_NAME, 505f8307e12SArchie Cobbs "name", 506f8307e12SArchie Cobbs &ng_generic_name_type, 507f8307e12SArchie Cobbs NULL 508f8307e12SArchie Cobbs }, 509f8307e12SArchie Cobbs { 510f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 511f8307e12SArchie Cobbs NGM_RMHOOK, 512f8307e12SArchie Cobbs "rmhook", 513f8307e12SArchie Cobbs &ng_generic_rmhook_type, 514f8307e12SArchie Cobbs NULL 515f8307e12SArchie Cobbs }, 516f8307e12SArchie Cobbs { 517f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 518f8307e12SArchie Cobbs NGM_NODEINFO, 519f8307e12SArchie Cobbs "nodeinfo", 520f8307e12SArchie Cobbs NULL, 521f8307e12SArchie Cobbs &ng_generic_nodeinfo_type 522f8307e12SArchie Cobbs }, 523f8307e12SArchie Cobbs { 524f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 525f8307e12SArchie Cobbs NGM_LISTHOOKS, 526f8307e12SArchie Cobbs "listhooks", 527f8307e12SArchie Cobbs NULL, 528f8307e12SArchie Cobbs &ng_generic_hooklist_type 529f8307e12SArchie Cobbs }, 530f8307e12SArchie Cobbs { 531f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 532f8307e12SArchie Cobbs NGM_LISTNAMES, 533f8307e12SArchie Cobbs "listnames", 534f8307e12SArchie Cobbs NULL, 535f8307e12SArchie Cobbs &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 536f8307e12SArchie Cobbs }, 537f8307e12SArchie Cobbs { 538f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 539f8307e12SArchie Cobbs NGM_LISTNODES, 540f8307e12SArchie Cobbs "listnodes", 541f8307e12SArchie Cobbs NULL, 542f8307e12SArchie Cobbs &ng_generic_listnodes_type 543f8307e12SArchie Cobbs }, 544f8307e12SArchie Cobbs { 545f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 546f8307e12SArchie Cobbs NGM_LISTTYPES, 547f8307e12SArchie Cobbs "listtypes", 548f8307e12SArchie Cobbs NULL, 549f8307e12SArchie Cobbs &ng_generic_typeinfo_type 550f8307e12SArchie Cobbs }, 551f8307e12SArchie Cobbs { 552f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 5537095e097SPoul-Henning Kamp NGM_TEXT_CONFIG, 5547095e097SPoul-Henning Kamp "textconfig", 5557095e097SPoul-Henning Kamp NULL, 5567095e097SPoul-Henning Kamp &ng_parse_string_type 5577095e097SPoul-Henning Kamp }, 5587095e097SPoul-Henning Kamp { 5597095e097SPoul-Henning Kamp NGM_GENERIC_COOKIE, 560f8307e12SArchie Cobbs NGM_TEXT_STATUS, 561f8307e12SArchie Cobbs "textstatus", 562f8307e12SArchie Cobbs NULL, 563f8307e12SArchie Cobbs &ng_parse_string_type 564f8307e12SArchie Cobbs }, 565f8307e12SArchie Cobbs { 566f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 567f8307e12SArchie Cobbs NGM_ASCII2BINARY, 568f8307e12SArchie Cobbs "ascii2binary", 569f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 570f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 571f8307e12SArchie Cobbs }, 572f8307e12SArchie Cobbs { 573f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 574f8307e12SArchie Cobbs NGM_BINARY2ASCII, 575f8307e12SArchie Cobbs "binary2ascii", 576f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 577f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 578f8307e12SArchie Cobbs }, 579f8307e12SArchie Cobbs { 0 } 580f8307e12SArchie Cobbs }; 581f8307e12SArchie Cobbs 582f8307e12SArchie Cobbs /************************************************************************ 5834cf49a43SJulian Elischer Node routines 5844cf49a43SJulian Elischer ************************************************************************/ 5854cf49a43SJulian Elischer 5864cf49a43SJulian Elischer /* 5874cf49a43SJulian Elischer * Instantiate a node of the requested type 5884cf49a43SJulian Elischer */ 5894cf49a43SJulian Elischer int 5904cf49a43SJulian Elischer ng_make_node(const char *typename, node_p *nodepp) 5914cf49a43SJulian Elischer { 5924cf49a43SJulian Elischer struct ng_type *type; 593069154d5SJulian Elischer int error; 5944cf49a43SJulian Elischer 5954cf49a43SJulian Elischer /* Check that the type makes sense */ 5964cf49a43SJulian Elischer if (typename == NULL) { 5976b795970SJulian Elischer TRAP_ERROR(); 5984cf49a43SJulian Elischer return (EINVAL); 5994cf49a43SJulian Elischer } 6004cf49a43SJulian Elischer 6017610f574SGleb Smirnoff /* Locate the node type. If we fail we return. Do not try to load 6027610f574SGleb Smirnoff * module. 6037610f574SGleb Smirnoff */ 6044cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) 6054cf49a43SJulian Elischer return (ENXIO); 6064cf49a43SJulian Elischer 607069154d5SJulian Elischer /* 608069154d5SJulian Elischer * If we have a constructor, then make the node and 609069154d5SJulian Elischer * call the constructor to do type specific initialisation. 610069154d5SJulian Elischer */ 611069154d5SJulian Elischer if (type->constructor != NULL) { 612069154d5SJulian Elischer if ((error = ng_make_node_common(type, nodepp)) == 0) { 6135633ca71SGleb Smirnoff if ((error = ((*type->constructor)(*nodepp))) != 0) { 61430400f03SJulian Elischer NG_NODE_UNREF(*nodepp); 615069154d5SJulian Elischer } 616069154d5SJulian Elischer } 617069154d5SJulian Elischer } else { 618069154d5SJulian Elischer /* 619069154d5SJulian Elischer * Node has no constructor. We cannot ask for one 62064efc707SRobert Watson * to be made. It must be brought into existence by 621954c4772SJulian Elischer * some external agency. The external agency should 622069154d5SJulian Elischer * call ng_make_node_common() directly to get the 623069154d5SJulian Elischer * netgraph part initialised. 624069154d5SJulian Elischer */ 6256b795970SJulian Elischer TRAP_ERROR(); 626069154d5SJulian Elischer error = EINVAL; 627069154d5SJulian Elischer } 628069154d5SJulian Elischer return (error); 6294cf49a43SJulian Elischer } 6304cf49a43SJulian Elischer 6314cf49a43SJulian Elischer /* 632069154d5SJulian Elischer * Generic node creation. Called by node initialisation for externally 633069154d5SJulian Elischer * instantiated nodes (e.g. hardware, sockets, etc ). 6344cf49a43SJulian Elischer * The returned node has a reference count of 1. 6354cf49a43SJulian Elischer */ 6364cf49a43SJulian Elischer int 6374cf49a43SJulian Elischer ng_make_node_common(struct ng_type *type, node_p *nodepp) 6384cf49a43SJulian Elischer { 6394cf49a43SJulian Elischer node_p node; 6404cf49a43SJulian Elischer 6414cf49a43SJulian Elischer /* Require the node type to have been already installed */ 6424cf49a43SJulian Elischer if (ng_findtype(type->name) == NULL) { 6436b795970SJulian Elischer TRAP_ERROR(); 6444cf49a43SJulian Elischer return (EINVAL); 6454cf49a43SJulian Elischer } 6464cf49a43SJulian Elischer 6474cf49a43SJulian Elischer /* Make a node and try attach it to the type */ 64830400f03SJulian Elischer NG_ALLOC_NODE(node); 6494cf49a43SJulian Elischer if (node == NULL) { 6506b795970SJulian Elischer TRAP_ERROR(); 6514cf49a43SJulian Elischer return (ENOMEM); 6524cf49a43SJulian Elischer } 65330400f03SJulian Elischer node->nd_type = type; 654bc29160dSMarko Zec #ifdef VIMAGE 655bc29160dSMarko Zec node->nd_vnet = curvnet; 656bc29160dSMarko Zec #endif 65730400f03SJulian Elischer NG_NODE_REF(node); /* note reference */ 6584cf49a43SJulian Elischer type->refs++; 6594cf49a43SJulian Elischer 6602c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK_INIT(&node->nd_input_queue); 6619852972bSAlexander Motin STAILQ_INIT(&node->nd_input_queue.queue); 66230400f03SJulian Elischer node->nd_input_queue.q_flags = 0; 6634cf49a43SJulian Elischer 6644cf49a43SJulian Elischer /* Initialize hook list for new node */ 66530400f03SJulian Elischer LIST_INIT(&node->nd_hooks); 6664cf49a43SJulian Elischer 667cfea3f85SAlexander Motin /* Link us into the name hash. */ 668*c4282b74SGleb Smirnoff NAMEHASH_WLOCK(); 669603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes); 670*c4282b74SGleb Smirnoff NAMEHASH_WUNLOCK(); 671069154d5SJulian Elischer 672dc90cad9SJulian Elischer /* get an ID and put us in the hash chain */ 673*c4282b74SGleb Smirnoff IDHASH_WLOCK(); 67430400f03SJulian Elischer for (;;) { /* wrap protection, even if silly */ 675069154d5SJulian Elischer node_p node2 = NULL; 676ac957cd2SJulian Elischer node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */ 6770f150d04SJulian Elischer 67830400f03SJulian Elischer /* Is there a problem with the new number? */ 6790f150d04SJulian Elischer NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */ 6800f150d04SJulian Elischer if ((node->nd_ID != 0) && (node2 == NULL)) { 68130400f03SJulian Elischer break; 682069154d5SJulian Elischer } 68330400f03SJulian Elischer } 6844bd1b557SGleb Smirnoff LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], node, 6854bd1b557SGleb Smirnoff nd_idnodes); 686*c4282b74SGleb Smirnoff IDHASH_WUNLOCK(); 687dc90cad9SJulian Elischer 6884cf49a43SJulian Elischer /* Done */ 6894cf49a43SJulian Elischer *nodepp = node; 6904cf49a43SJulian Elischer return (0); 6914cf49a43SJulian Elischer } 6924cf49a43SJulian Elischer 6934cf49a43SJulian Elischer /* 6944cf49a43SJulian Elischer * Forceably start the shutdown process on a node. Either call 69564efc707SRobert Watson * its shutdown method, or do the default shutdown if there is 6964cf49a43SJulian Elischer * no type-specific method. 6974cf49a43SJulian Elischer * 69864efc707SRobert Watson * We can only be called from a shutdown message, so we know we have 6993e4084c8SJulian Elischer * a writer lock, and therefore exclusive access. It also means 7003e4084c8SJulian Elischer * that we should not be on the work queue, but we check anyhow. 701069154d5SJulian Elischer * 702069154d5SJulian Elischer * Persistent node types must have a type-specific method which 70364efc707SRobert Watson * allocates a new node in which case, this one is irretrievably going away, 7043e4084c8SJulian Elischer * or cleans up anything it needs, and just makes the node valid again, 7053e4084c8SJulian Elischer * in which case we allow the node to survive. 7063e4084c8SJulian Elischer * 70764efc707SRobert Watson * XXX We need to think of how to tell a persistent node that we 7083e4084c8SJulian Elischer * REALLY need to go away because the hardware has gone or we 7093e4084c8SJulian Elischer * are rebooting.... etc. 7104cf49a43SJulian Elischer */ 7114cf49a43SJulian Elischer void 7121acb27c6SJulian Elischer ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3) 7134cf49a43SJulian Elischer { 7143e4084c8SJulian Elischer hook_p hook; 7153e4084c8SJulian Elischer 7164cf49a43SJulian Elischer /* Check if it's already shutting down */ 717be4252b3SJulian Elischer if ((node->nd_flags & NGF_CLOSING) != 0) 7184cf49a43SJulian Elischer return; 7194cf49a43SJulian Elischer 7201acb27c6SJulian Elischer if (node == &ng_deadnode) { 7211acb27c6SJulian Elischer printf ("shutdown called on deadnode\n"); 7221acb27c6SJulian Elischer return; 7231acb27c6SJulian Elischer } 7241acb27c6SJulian Elischer 7254cf49a43SJulian Elischer /* Add an extra reference so it doesn't go away during this */ 72630400f03SJulian Elischer NG_NODE_REF(node); 7274cf49a43SJulian Elischer 72830400f03SJulian Elischer /* 72930400f03SJulian Elischer * Mark it invalid so any newcomers know not to try use it 73030400f03SJulian Elischer * Also add our own mark so we can't recurse 731be4252b3SJulian Elischer * note that NGF_INVALID does not do this as it's also set during 73230400f03SJulian Elischer * creation 73330400f03SJulian Elischer */ 734be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID|NGF_CLOSING; 7354cf49a43SJulian Elischer 736991fc65aSJulian Elischer /* If node has its pre-shutdown method, then call it first*/ 737991fc65aSJulian Elischer if (node->nd_type && node->nd_type->close) 738991fc65aSJulian Elischer (*node->nd_type->close)(node); 739991fc65aSJulian Elischer 7403e4084c8SJulian Elischer /* Notify all remaining connected nodes to disconnect */ 7413e4084c8SJulian Elischer while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL) 7423e4084c8SJulian Elischer ng_destroy_hook(hook); 74330400f03SJulian Elischer 744069154d5SJulian Elischer /* 745069154d5SJulian Elischer * Drain the input queue forceably. 74630400f03SJulian Elischer * it has no hooks so what's it going to do, bleed on someone? 74730400f03SJulian Elischer * Theoretically we came here from a queue entry that was added 74830400f03SJulian Elischer * Just before the queue was closed, so it should be empty anyway. 749b57a7965SJulian Elischer * Also removes us from worklist if needed. 750069154d5SJulian Elischer */ 7519852972bSAlexander Motin ng_flush_input_queue(node); 752069154d5SJulian Elischer 753069154d5SJulian Elischer /* Ask the type if it has anything to do in this case */ 75430400f03SJulian Elischer if (node->nd_type && node->nd_type->shutdown) { 75530400f03SJulian Elischer (*node->nd_type->shutdown)(node); 75630400f03SJulian Elischer if (NG_NODE_IS_VALID(node)) { 75730400f03SJulian Elischer /* 75830400f03SJulian Elischer * Well, blow me down if the node code hasn't declared 75930400f03SJulian Elischer * that it doesn't want to die. 76030400f03SJulian Elischer * Presumably it is a persistant node. 7611acb27c6SJulian Elischer * If we REALLY want it to go away, 7621acb27c6SJulian Elischer * e.g. hardware going away, 763be4252b3SJulian Elischer * Our caller should set NGF_REALLY_DIE in nd_flags. 76430400f03SJulian Elischer */ 765be4252b3SJulian Elischer node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING); 7661acb27c6SJulian Elischer NG_NODE_UNREF(node); /* Assume they still have theirs */ 76730400f03SJulian Elischer return; 7684cf49a43SJulian Elischer } 7691acb27c6SJulian Elischer } else { /* do the default thing */ 7701acb27c6SJulian Elischer NG_NODE_UNREF(node); 7711acb27c6SJulian Elischer } 7724cf49a43SJulian Elischer 77330400f03SJulian Elischer ng_unname(node); /* basically a NOP these days */ 77430400f03SJulian Elischer 77530400f03SJulian Elischer /* 77630400f03SJulian Elischer * Remove extra reference, possibly the last 77730400f03SJulian Elischer * Possible other holders of references may include 77830400f03SJulian Elischer * timeout callouts, but theoretically the node's supposed to 77930400f03SJulian Elischer * have cancelled them. Possibly hardware dependencies may 78030400f03SJulian Elischer * force a driver to 'linger' with a reference. 78130400f03SJulian Elischer */ 78230400f03SJulian Elischer NG_NODE_UNREF(node); 7834cf49a43SJulian Elischer } 7844cf49a43SJulian Elischer 7855951069aSJulian Elischer /* 7865951069aSJulian Elischer * Remove a reference to the node, possibly the last. 7875951069aSJulian Elischer * deadnode always acts as it it were the last. 7885951069aSJulian Elischer */ 7893fbdf774SGleb Smirnoff void 79030400f03SJulian Elischer ng_unref_node(node_p node) 7914cf49a43SJulian Elischer { 7926b795970SJulian Elischer 7933fbdf774SGleb Smirnoff if (node == &ng_deadnode) 7943fbdf774SGleb Smirnoff return; 7956b795970SJulian Elischer 7963fbdf774SGleb Smirnoff if (refcount_release(&node->nd_refs)) { /* we were the last */ 797069154d5SJulian Elischer 79830400f03SJulian Elischer node->nd_type->refs--; /* XXX maybe should get types lock? */ 799*c4282b74SGleb Smirnoff NAMEHASH_WLOCK(); 80030400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 801*c4282b74SGleb Smirnoff NAMEHASH_WUNLOCK(); 802069154d5SJulian Elischer 803*c4282b74SGleb Smirnoff IDHASH_WLOCK(); 80430400f03SJulian Elischer LIST_REMOVE(node, nd_idnodes); 805*c4282b74SGleb Smirnoff IDHASH_WUNLOCK(); 806069154d5SJulian Elischer 80712574a02SJulian Elischer mtx_destroy(&node->nd_input_queue.q_mtx); 808069154d5SJulian Elischer NG_FREE_NODE(node); 8094cf49a43SJulian Elischer } 8104cf49a43SJulian Elischer } 8114cf49a43SJulian Elischer 8124cf49a43SJulian Elischer /************************************************************************ 813dc90cad9SJulian Elischer Node ID handling 814dc90cad9SJulian Elischer ************************************************************************/ 815dc90cad9SJulian Elischer static node_p 816069154d5SJulian Elischer ng_ID2noderef(ng_ID_t ID) 817dc90cad9SJulian Elischer { 81830400f03SJulian Elischer node_p node; 819*c4282b74SGleb Smirnoff IDHASH_RLOCK(); 8200f150d04SJulian Elischer NG_IDHASH_FIND(ID, node); 82130400f03SJulian Elischer if(node) 82230400f03SJulian Elischer NG_NODE_REF(node); 823*c4282b74SGleb Smirnoff IDHASH_RUNLOCK(); 82430400f03SJulian Elischer return(node); 825dc90cad9SJulian Elischer } 826dc90cad9SJulian Elischer 827dc90cad9SJulian Elischer ng_ID_t 828dc90cad9SJulian Elischer ng_node2ID(node_p node) 829dc90cad9SJulian Elischer { 83070de87f2SJulian Elischer return (node ? NG_NODE_ID(node) : 0); 831dc90cad9SJulian Elischer } 832dc90cad9SJulian Elischer 833dc90cad9SJulian Elischer /************************************************************************ 8344cf49a43SJulian Elischer Node name handling 8354cf49a43SJulian Elischer ************************************************************************/ 8364cf49a43SJulian Elischer 8374cf49a43SJulian Elischer /* 8384bd1b557SGleb Smirnoff * Assign a node a name. 8394cf49a43SJulian Elischer */ 8404cf49a43SJulian Elischer int 8414cf49a43SJulian Elischer ng_name_node(node_p node, const char *name) 8424cf49a43SJulian Elischer { 843cfea3f85SAlexander Motin int i, hash; 844069154d5SJulian Elischer node_p node2; 8454cf49a43SJulian Elischer 8464cf49a43SJulian Elischer /* Check the name is valid */ 84787e2c66aSHartmut Brandt for (i = 0; i < NG_NODESIZ; i++) { 8484cf49a43SJulian Elischer if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 8494cf49a43SJulian Elischer break; 8504cf49a43SJulian Elischer } 8514cf49a43SJulian Elischer if (i == 0 || name[i] != '\0') { 8526b795970SJulian Elischer TRAP_ERROR(); 8534cf49a43SJulian Elischer return (EINVAL); 8544cf49a43SJulian Elischer } 855dc90cad9SJulian Elischer if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 8566b795970SJulian Elischer TRAP_ERROR(); 8574cf49a43SJulian Elischer return (EINVAL); 8584cf49a43SJulian Elischer } 8594cf49a43SJulian Elischer 8604cf49a43SJulian Elischer /* Check the name isn't already being used */ 861069154d5SJulian Elischer if ((node2 = ng_name2noderef(node, name)) != NULL) { 86230400f03SJulian Elischer NG_NODE_UNREF(node2); 8636b795970SJulian Elischer TRAP_ERROR(); 8644cf49a43SJulian Elischer return (EADDRINUSE); 8654cf49a43SJulian Elischer } 8664cf49a43SJulian Elischer 867069154d5SJulian Elischer /* copy it */ 86887e2c66aSHartmut Brandt strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ); 8694cf49a43SJulian Elischer 870cfea3f85SAlexander Motin /* Update name hash. */ 871cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 872*c4282b74SGleb Smirnoff NAMEHASH_WLOCK(); 873cfea3f85SAlexander Motin LIST_REMOVE(node, nd_nodes); 874603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes); 875*c4282b74SGleb Smirnoff NAMEHASH_WUNLOCK(); 876cfea3f85SAlexander Motin 8774cf49a43SJulian Elischer return (0); 8784cf49a43SJulian Elischer } 8794cf49a43SJulian Elischer 8804cf49a43SJulian Elischer /* 8814cf49a43SJulian Elischer * Find a node by absolute name. The name should NOT end with ':' 8824cf49a43SJulian Elischer * The name "." means "this node" and "[xxx]" means "the node 8834cf49a43SJulian Elischer * with ID (ie, at address) xxx". 8844cf49a43SJulian Elischer * 8854cf49a43SJulian Elischer * Returns the node if found, else NULL. 886069154d5SJulian Elischer * Eventually should add something faster than a sequential search. 887e1e8f51bSRobert Watson * Note it acquires a reference on the node so you can be sure it's still 888e1e8f51bSRobert Watson * there. 8894cf49a43SJulian Elischer */ 8904cf49a43SJulian Elischer node_p 891069154d5SJulian Elischer ng_name2noderef(node_p here, const char *name) 8924cf49a43SJulian Elischer { 893dc90cad9SJulian Elischer node_p node; 894dc90cad9SJulian Elischer ng_ID_t temp; 895cfea3f85SAlexander Motin int hash; 8964cf49a43SJulian Elischer 8974cf49a43SJulian Elischer /* "." means "this node" */ 898069154d5SJulian Elischer if (strcmp(name, ".") == 0) { 89930400f03SJulian Elischer NG_NODE_REF(here); 900069154d5SJulian Elischer return(here); 901069154d5SJulian Elischer } 9024cf49a43SJulian Elischer 9034cf49a43SJulian Elischer /* Check for name-by-ID */ 904dc90cad9SJulian Elischer if ((temp = ng_decodeidname(name)) != 0) { 905069154d5SJulian Elischer return (ng_ID2noderef(temp)); 9064cf49a43SJulian Elischer } 9074cf49a43SJulian Elischer 9084cf49a43SJulian Elischer /* Find node by name */ 909cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 910*c4282b74SGleb Smirnoff NAMEHASH_RLOCK(); 911*c4282b74SGleb Smirnoff LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) 912cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 913cfea3f85SAlexander Motin (strcmp(NG_NODE_NAME(node), name) == 0)) { 914*c4282b74SGleb Smirnoff NG_NODE_REF(node); 9154cf49a43SJulian Elischer break; 9164cf49a43SJulian Elischer } 917*c4282b74SGleb Smirnoff NAMEHASH_RUNLOCK(); 918*c4282b74SGleb Smirnoff 9194cf49a43SJulian Elischer return (node); 9204cf49a43SJulian Elischer } 9214cf49a43SJulian Elischer 9224cf49a43SJulian Elischer /* 9239d5abbddSJens Schweikhardt * Decode an ID name, eg. "[f03034de]". Returns 0 if the 924dc90cad9SJulian Elischer * string is not valid, otherwise returns the value. 9254cf49a43SJulian Elischer */ 926dc90cad9SJulian Elischer static ng_ID_t 9274cf49a43SJulian Elischer ng_decodeidname(const char *name) 9284cf49a43SJulian Elischer { 9292b70adcbSArchie Cobbs const int len = strlen(name); 93025792ef3SArchie Cobbs char *eptr; 9312b70adcbSArchie Cobbs u_long val; 9324cf49a43SJulian Elischer 9332b70adcbSArchie Cobbs /* Check for proper length, brackets, no leading junk */ 9344bd1b557SGleb Smirnoff if ((len < 3) || (name[0] != '[') || (name[len - 1] != ']') || 9354bd1b557SGleb Smirnoff (!isxdigit(name[1]))) 93670de87f2SJulian Elischer return ((ng_ID_t)0); 9374cf49a43SJulian Elischer 9382b70adcbSArchie Cobbs /* Decode number */ 9392b70adcbSArchie Cobbs val = strtoul(name + 1, &eptr, 16); 9404bd1b557SGleb Smirnoff if ((eptr - name != len - 1) || (val == ULONG_MAX) || (val == 0)) 94112f035e0SJulian Elischer return ((ng_ID_t)0); 9424bd1b557SGleb Smirnoff 9434bd1b557SGleb Smirnoff return ((ng_ID_t)val); 9444cf49a43SJulian Elischer } 9454cf49a43SJulian Elischer 9464cf49a43SJulian Elischer /* 9474cf49a43SJulian Elischer * Remove a name from a node. This should only be called 9484cf49a43SJulian Elischer * when shutting down and removing the node. 9494cf49a43SJulian Elischer */ 9504cf49a43SJulian Elischer void 9514cf49a43SJulian Elischer ng_unname(node_p node) 9524cf49a43SJulian Elischer { 9534cf49a43SJulian Elischer } 9544cf49a43SJulian Elischer 9554cf49a43SJulian Elischer /************************************************************************ 9564cf49a43SJulian Elischer Hook routines 9574cf49a43SJulian Elischer Names are not optional. Hooks are always connected, except for a 9583e4084c8SJulian Elischer brief moment within these routines. On invalidation or during creation 9593e4084c8SJulian Elischer they are connected to the 'dead' hook. 9604cf49a43SJulian Elischer ************************************************************************/ 9614cf49a43SJulian Elischer 9624cf49a43SJulian Elischer /* 9634cf49a43SJulian Elischer * Remove a hook reference 9644cf49a43SJulian Elischer */ 96530400f03SJulian Elischer void 9664cf49a43SJulian Elischer ng_unref_hook(hook_p hook) 9674cf49a43SJulian Elischer { 9686b795970SJulian Elischer 9693fbdf774SGleb Smirnoff if (hook == &ng_deadhook) 9706b795970SJulian Elischer return; 971018fe3d1SAlexander Motin 9723fbdf774SGleb Smirnoff if (refcount_release(&hook->hk_refs)) { /* we were the last */ 973f573da1aSAlexander Motin if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */ 9746b795970SJulian Elischer _NG_NODE_UNREF((_NG_HOOK_NODE(hook))); 975069154d5SJulian Elischer NG_FREE_HOOK(hook); 976069154d5SJulian Elischer } 9774cf49a43SJulian Elischer } 9784cf49a43SJulian Elischer 9794cf49a43SJulian Elischer /* 9804cf49a43SJulian Elischer * Add an unconnected hook to a node. Only used internally. 9813e4084c8SJulian Elischer * Assumes node is locked. (XXX not yet true ) 9824cf49a43SJulian Elischer */ 9834cf49a43SJulian Elischer static int 9844cf49a43SJulian Elischer ng_add_hook(node_p node, const char *name, hook_p *hookp) 9854cf49a43SJulian Elischer { 9864cf49a43SJulian Elischer hook_p hook; 9874cf49a43SJulian Elischer int error = 0; 9884cf49a43SJulian Elischer 9894cf49a43SJulian Elischer /* Check that the given name is good */ 9904cf49a43SJulian Elischer if (name == NULL) { 9916b795970SJulian Elischer TRAP_ERROR(); 9924cf49a43SJulian Elischer return (EINVAL); 9934cf49a43SJulian Elischer } 994899e9c4eSArchie Cobbs if (ng_findhook(node, name) != NULL) { 9956b795970SJulian Elischer TRAP_ERROR(); 9964cf49a43SJulian Elischer return (EEXIST); 9974cf49a43SJulian Elischer } 9984cf49a43SJulian Elischer 9994cf49a43SJulian Elischer /* Allocate the hook and link it up */ 100030400f03SJulian Elischer NG_ALLOC_HOOK(hook); 10014cf49a43SJulian Elischer if (hook == NULL) { 10026b795970SJulian Elischer TRAP_ERROR(); 10034cf49a43SJulian Elischer return (ENOMEM); 10044cf49a43SJulian Elischer } 10053e4084c8SJulian Elischer hook->hk_refs = 1; /* add a reference for us to return */ 100630400f03SJulian Elischer hook->hk_flags = HK_INVALID; 10073e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* start off this way */ 100830400f03SJulian Elischer hook->hk_node = node; 100930400f03SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 10104cf49a43SJulian Elischer 10113e4084c8SJulian Elischer /* Set hook name */ 101287e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ); 10133e4084c8SJulian Elischer 10143e4084c8SJulian Elischer /* 10153e4084c8SJulian Elischer * Check if the node type code has something to say about it 10163e4084c8SJulian Elischer * If it fails, the unref of the hook will also unref the node. 10173e4084c8SJulian Elischer */ 1018954c4772SJulian Elischer if (node->nd_type->newhook != NULL) { 1019954c4772SJulian Elischer if ((error = (*node->nd_type->newhook)(node, hook, name))) { 102030400f03SJulian Elischer NG_HOOK_UNREF(hook); /* this frees the hook */ 1021069154d5SJulian Elischer return (error); 1022069154d5SJulian Elischer } 1023954c4772SJulian Elischer } 10244cf49a43SJulian Elischer /* 10254cf49a43SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 10264cf49a43SJulian Elischer * We'll ask again later when we actually connect the hooks. 10274cf49a43SJulian Elischer */ 102830400f03SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 102930400f03SJulian Elischer node->nd_numhooks++; 10303e4084c8SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 10314cf49a43SJulian Elischer 10324cf49a43SJulian Elischer if (hookp) 10334cf49a43SJulian Elischer *hookp = hook; 10343e4084c8SJulian Elischer return (0); 10354cf49a43SJulian Elischer } 10364cf49a43SJulian Elischer 10374cf49a43SJulian Elischer /* 1038899e9c4eSArchie Cobbs * Find a hook 1039899e9c4eSArchie Cobbs * 1040899e9c4eSArchie Cobbs * Node types may supply their own optimized routines for finding 1041899e9c4eSArchie Cobbs * hooks. If none is supplied, we just do a linear search. 10423e4084c8SJulian Elischer * XXX Possibly we should add a reference to the hook? 1043899e9c4eSArchie Cobbs */ 1044899e9c4eSArchie Cobbs hook_p 1045899e9c4eSArchie Cobbs ng_findhook(node_p node, const char *name) 1046899e9c4eSArchie Cobbs { 1047899e9c4eSArchie Cobbs hook_p hook; 1048899e9c4eSArchie Cobbs 104930400f03SJulian Elischer if (node->nd_type->findhook != NULL) 105030400f03SJulian Elischer return (*node->nd_type->findhook)(node, name); 105130400f03SJulian Elischer LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 10524bd1b557SGleb Smirnoff if (NG_HOOK_IS_VALID(hook) && 10534bd1b557SGleb Smirnoff (strcmp(NG_HOOK_NAME(hook), name) == 0)) 1054899e9c4eSArchie Cobbs return (hook); 1055899e9c4eSArchie Cobbs } 1056899e9c4eSArchie Cobbs return (NULL); 1057899e9c4eSArchie Cobbs } 1058899e9c4eSArchie Cobbs 1059899e9c4eSArchie Cobbs /* 10604cf49a43SJulian Elischer * Destroy a hook 10614cf49a43SJulian Elischer * 10624cf49a43SJulian Elischer * As hooks are always attached, this really destroys two hooks. 10634cf49a43SJulian Elischer * The one given, and the one attached to it. Disconnect the hooks 10643e4084c8SJulian Elischer * from each other first. We reconnect the peer hook to the 'dead' 10653e4084c8SJulian Elischer * hook so that it can still exist after we depart. We then 10663e4084c8SJulian Elischer * send the peer its own destroy message. This ensures that we only 10673e4084c8SJulian Elischer * interact with the peer's structures when it is locked processing that 10683e4084c8SJulian Elischer * message. We hold a reference to the peer hook so we are guaranteed that 10693e4084c8SJulian Elischer * the peer hook and node are still going to exist until 10703e4084c8SJulian Elischer * we are finished there as the hook holds a ref on the node. 10713e4084c8SJulian Elischer * We run this same code again on the peer hook, but that time it is already 10723e4084c8SJulian Elischer * attached to the 'dead' hook. 10736b795970SJulian Elischer * 10746b795970SJulian Elischer * This routine is called at all stages of hook creation 10756b795970SJulian Elischer * on error detection and must be able to handle any such stage. 10764cf49a43SJulian Elischer */ 10774cf49a43SJulian Elischer void 10784cf49a43SJulian Elischer ng_destroy_hook(hook_p hook) 10794cf49a43SJulian Elischer { 1080ac5dd141SGleb Smirnoff hook_p peer; 1081ac5dd141SGleb Smirnoff node_p node; 10824cf49a43SJulian Elischer 10836b795970SJulian Elischer if (hook == &ng_deadhook) { /* better safe than sorry */ 10846b795970SJulian Elischer printf("ng_destroy_hook called on deadhook\n"); 10856b795970SJulian Elischer return; 10866b795970SJulian Elischer } 1087ac5dd141SGleb Smirnoff 1088ac5dd141SGleb Smirnoff /* 1089ac5dd141SGleb Smirnoff * Protect divorce process with mutex, to avoid races on 1090ac5dd141SGleb Smirnoff * simultaneous disconnect. 1091ac5dd141SGleb Smirnoff */ 1092ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1093ac5dd141SGleb Smirnoff 1094ac5dd141SGleb Smirnoff hook->hk_flags |= HK_INVALID; 1095ac5dd141SGleb Smirnoff 1096ac5dd141SGleb Smirnoff peer = NG_HOOK_PEER(hook); 1097ac5dd141SGleb Smirnoff node = NG_HOOK_NODE(hook); 1098ac5dd141SGleb Smirnoff 10993e4084c8SJulian Elischer if (peer && (peer != &ng_deadhook)) { 11003e4084c8SJulian Elischer /* 11013e4084c8SJulian Elischer * Set the peer to point to ng_deadhook 11023e4084c8SJulian Elischer * from this moment on we are effectively independent it. 11033e4084c8SJulian Elischer * send it an rmhook message of it's own. 11043e4084c8SJulian Elischer */ 11053e4084c8SJulian Elischer peer->hk_peer = &ng_deadhook; /* They no longer know us */ 11063e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* Nor us, them */ 11076b795970SJulian Elischer if (NG_HOOK_NODE(peer) == &ng_deadnode) { 11086b795970SJulian Elischer /* 11096b795970SJulian Elischer * If it's already divorced from a node, 11106b795970SJulian Elischer * just free it. 11116b795970SJulian Elischer */ 1112ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11136b795970SJulian Elischer } else { 1114ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11156b795970SJulian Elischer ng_rmhook_self(peer); /* Send it a surprise */ 11166b795970SJulian Elischer } 111752fa3556SJulian Elischer NG_HOOK_UNREF(peer); /* account for peer link */ 111852fa3556SJulian Elischer NG_HOOK_UNREF(hook); /* account for peer link */ 1119ac5dd141SGleb Smirnoff } else 1120ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1121ac5dd141SGleb Smirnoff 1122ac5dd141SGleb Smirnoff mtx_assert(&ng_topo_mtx, MA_NOTOWNED); 11234cf49a43SJulian Elischer 11244cf49a43SJulian Elischer /* 11254cf49a43SJulian Elischer * Remove the hook from the node's list to avoid possible recursion 11264cf49a43SJulian Elischer * in case the disconnection results in node shutdown. 11274cf49a43SJulian Elischer */ 11286b795970SJulian Elischer if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */ 11296b795970SJulian Elischer return; 11306b795970SJulian Elischer } 113130400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 113230400f03SJulian Elischer node->nd_numhooks--; 113330400f03SJulian Elischer if (node->nd_type->disconnect) { 11344cf49a43SJulian Elischer /* 11356b795970SJulian Elischer * The type handler may elect to destroy the node so don't 113664efc707SRobert Watson * trust its existence after this point. (except 11376b795970SJulian Elischer * that we still hold a reference on it. (which we 11386b795970SJulian Elischer * inherrited from the hook we are destroying) 11394cf49a43SJulian Elischer */ 114030400f03SJulian Elischer (*node->nd_type->disconnect) (hook); 11414cf49a43SJulian Elischer } 11426b795970SJulian Elischer 11436b795970SJulian Elischer /* 11446b795970SJulian Elischer * Note that because we will point to ng_deadnode, the original node 11456b795970SJulian Elischer * is not decremented automatically so we do that manually. 11466b795970SJulian Elischer */ 11476b795970SJulian Elischer _NG_HOOK_NODE(hook) = &ng_deadnode; 11486b795970SJulian Elischer NG_NODE_UNREF(node); /* We no longer point to it so adjust count */ 11496b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Account for linkage (in list) to node */ 11504cf49a43SJulian Elischer } 11514cf49a43SJulian Elischer 11524cf49a43SJulian Elischer /* 11534cf49a43SJulian Elischer * Take two hooks on a node and merge the connection so that the given node 11544cf49a43SJulian Elischer * is effectively bypassed. 11554cf49a43SJulian Elischer */ 11564cf49a43SJulian Elischer int 11574cf49a43SJulian Elischer ng_bypass(hook_p hook1, hook_p hook2) 11584cf49a43SJulian Elischer { 115930400f03SJulian Elischer if (hook1->hk_node != hook2->hk_node) { 11606b795970SJulian Elischer TRAP_ERROR(); 11614cf49a43SJulian Elischer return (EINVAL); 116230400f03SJulian Elischer } 1163a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 116430400f03SJulian Elischer hook1->hk_peer->hk_peer = hook2->hk_peer; 116530400f03SJulian Elischer hook2->hk_peer->hk_peer = hook1->hk_peer; 11664cf49a43SJulian Elischer 11673e4084c8SJulian Elischer hook1->hk_peer = &ng_deadhook; 11683e4084c8SJulian Elischer hook2->hk_peer = &ng_deadhook; 1169a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11703e4084c8SJulian Elischer 1171cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook1); 1172cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook2); 1173cf3254aaSGleb Smirnoff 11744cf49a43SJulian Elischer /* XXX If we ever cache methods on hooks update them as well */ 11754cf49a43SJulian Elischer ng_destroy_hook(hook1); 11764cf49a43SJulian Elischer ng_destroy_hook(hook2); 11774cf49a43SJulian Elischer return (0); 11784cf49a43SJulian Elischer } 11794cf49a43SJulian Elischer 11804cf49a43SJulian Elischer /* 11814cf49a43SJulian Elischer * Install a new netgraph type 11824cf49a43SJulian Elischer */ 11834cf49a43SJulian Elischer int 11844cf49a43SJulian Elischer ng_newtype(struct ng_type *tp) 11854cf49a43SJulian Elischer { 11864cf49a43SJulian Elischer const size_t namelen = strlen(tp->name); 11874cf49a43SJulian Elischer 11884cf49a43SJulian Elischer /* Check version and type name fields */ 11894bd1b557SGleb Smirnoff if ((tp->version != NG_ABI_VERSION) || (namelen == 0) || 11904bd1b557SGleb Smirnoff (namelen >= NG_TYPESIZ)) { 11916b795970SJulian Elischer TRAP_ERROR(); 11928ed370fdSJulian Elischer if (tp->version != NG_ABI_VERSION) { 11934bd1b557SGleb Smirnoff printf("Netgraph: Node type rejected. ABI mismatch. " 11944bd1b557SGleb Smirnoff "Suggest recompile\n"); 11958ed370fdSJulian Elischer } 11964cf49a43SJulian Elischer return (EINVAL); 11974cf49a43SJulian Elischer } 11984cf49a43SJulian Elischer 11994cf49a43SJulian Elischer /* Check for name collision */ 12004cf49a43SJulian Elischer if (ng_findtype(tp->name) != NULL) { 12016b795970SJulian Elischer TRAP_ERROR(); 12024cf49a43SJulian Elischer return (EEXIST); 12034cf49a43SJulian Elischer } 12044cf49a43SJulian Elischer 1205069154d5SJulian Elischer 1206069154d5SJulian Elischer /* Link in new type */ 1207*c4282b74SGleb Smirnoff TYPELIST_WLOCK(); 1208069154d5SJulian Elischer LIST_INSERT_HEAD(&ng_typelist, tp, types); 1209c73b94a2SJulian Elischer tp->refs = 1; /* first ref is linked list */ 1210*c4282b74SGleb Smirnoff TYPELIST_WUNLOCK(); 12114cf49a43SJulian Elischer return (0); 12124cf49a43SJulian Elischer } 12134cf49a43SJulian Elischer 12144cf49a43SJulian Elischer /* 1215c31b4a53SJulian Elischer * unlink a netgraph type 1216c31b4a53SJulian Elischer * If no examples exist 1217c31b4a53SJulian Elischer */ 1218c31b4a53SJulian Elischer int 1219c31b4a53SJulian Elischer ng_rmtype(struct ng_type *tp) 1220c31b4a53SJulian Elischer { 1221c31b4a53SJulian Elischer /* Check for name collision */ 1222c31b4a53SJulian Elischer if (tp->refs != 1) { 1223c31b4a53SJulian Elischer TRAP_ERROR(); 1224c31b4a53SJulian Elischer return (EBUSY); 1225c31b4a53SJulian Elischer } 1226c31b4a53SJulian Elischer 1227c31b4a53SJulian Elischer /* Unlink type */ 1228*c4282b74SGleb Smirnoff TYPELIST_WLOCK(); 1229c31b4a53SJulian Elischer LIST_REMOVE(tp, types); 1230*c4282b74SGleb Smirnoff TYPELIST_WUNLOCK(); 1231c31b4a53SJulian Elischer return (0); 1232c31b4a53SJulian Elischer } 1233c31b4a53SJulian Elischer 1234c31b4a53SJulian Elischer /* 12354cf49a43SJulian Elischer * Look for a type of the name given 12364cf49a43SJulian Elischer */ 12374cf49a43SJulian Elischer struct ng_type * 12384cf49a43SJulian Elischer ng_findtype(const char *typename) 12394cf49a43SJulian Elischer { 12404cf49a43SJulian Elischer struct ng_type *type; 12414cf49a43SJulian Elischer 1242*c4282b74SGleb Smirnoff TYPELIST_RLOCK(); 1243069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 12444cf49a43SJulian Elischer if (strcmp(type->name, typename) == 0) 12454cf49a43SJulian Elischer break; 12464cf49a43SJulian Elischer } 1247*c4282b74SGleb Smirnoff TYPELIST_RUNLOCK(); 12484cf49a43SJulian Elischer return (type); 12494cf49a43SJulian Elischer } 12504cf49a43SJulian Elischer 12514cf49a43SJulian Elischer /************************************************************************ 12524cf49a43SJulian Elischer Composite routines 12534cf49a43SJulian Elischer ************************************************************************/ 12544cf49a43SJulian Elischer /* 12556b795970SJulian Elischer * Connect two nodes using the specified hooks, using queued functions. 12564cf49a43SJulian Elischer */ 1257e088dd4cSAlexander Motin static int 1258e088dd4cSAlexander Motin ng_con_part3(node_p node, item_p item, hook_p hook) 12594cf49a43SJulian Elischer { 1260e088dd4cSAlexander Motin int error = 0; 12614cf49a43SJulian Elischer 12626b795970SJulian Elischer /* 12636b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 12646b795970SJulian Elischer * Our caller has a reference on the hook. 12656b795970SJulian Elischer * Our caller has a reference on the node. 12666b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 12676b795970SJulian Elischer * The peer hook has a reference on the hook. 12681acb27c6SJulian Elischer * We are all set up except for the final call to the node, and 12691acb27c6SJulian Elischer * the clearing of the INVALID flag. 12706b795970SJulian Elischer */ 12716b795970SJulian Elischer if (NG_HOOK_NODE(hook) == &ng_deadnode) { 12726b795970SJulian Elischer /* 12736b795970SJulian Elischer * The node must have been freed again since we last visited 12746b795970SJulian Elischer * here. ng_destry_hook() has this effect but nothing else does. 12756b795970SJulian Elischer * We should just release our references and 12766b795970SJulian Elischer * free anything we can think of. 12776b795970SJulian Elischer * Since we know it's been destroyed, and it's our caller 12786b795970SJulian Elischer * that holds the references, just return. 12796b795970SJulian Elischer */ 1280e088dd4cSAlexander Motin ERROUT(ENOENT); 12816b795970SJulian Elischer } 12826b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1283e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 12846b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 12851acb27c6SJulian Elischer printf("failed in ng_con_part3()\n"); 1286e088dd4cSAlexander Motin ERROUT(error); 12874cf49a43SJulian Elischer } 12886b795970SJulian Elischer } 12896b795970SJulian Elischer /* 12906b795970SJulian Elischer * XXX this is wrong for SMP. Possibly we need 12916b795970SJulian Elischer * to separate out 'create' and 'invalid' flags. 12926b795970SJulian Elischer * should only set flags on hooks we have locked under our node. 12936b795970SJulian Elischer */ 12946b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; 1295e088dd4cSAlexander Motin done: 1296e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1297e088dd4cSAlexander Motin return (error); 12986b795970SJulian Elischer } 12996b795970SJulian Elischer 1300e088dd4cSAlexander Motin static int 1301e088dd4cSAlexander Motin ng_con_part2(node_p node, item_p item, hook_p hook) 13026b795970SJulian Elischer { 1303ac5dd141SGleb Smirnoff hook_p peer; 1304e088dd4cSAlexander Motin int error = 0; 13056b795970SJulian Elischer 13066b795970SJulian Elischer /* 13076b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 13086b795970SJulian Elischer * Our caller has a reference on the hook. 13096b795970SJulian Elischer * Our caller has a reference on the node. 13106b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 13116b795970SJulian Elischer * The peer hook has a reference on the hook. 13126b795970SJulian Elischer * our node pointer points to the 'dead' node. 13136b795970SJulian Elischer * First check the hook name is unique. 13141acb27c6SJulian Elischer * Should not happen because we checked before queueing this. 13156b795970SJulian Elischer */ 13166b795970SJulian Elischer if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) { 13176b795970SJulian Elischer TRAP_ERROR(); 13186b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13191acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1320e088dd4cSAlexander Motin ERROUT(EEXIST); 13216b795970SJulian Elischer } 13226b795970SJulian Elischer /* 13236b795970SJulian Elischer * Check if the node type code has something to say about it 13246b795970SJulian Elischer * If it fails, the unref of the hook will also unref the attached node, 13256b795970SJulian Elischer * however since that node is 'ng_deadnode' this will do nothing. 13266b795970SJulian Elischer * The peer hook will also be destroyed. 13276b795970SJulian Elischer */ 13286b795970SJulian Elischer if (node->nd_type->newhook != NULL) { 1329e088dd4cSAlexander Motin if ((error = (*node->nd_type->newhook)(node, hook, 1330e088dd4cSAlexander Motin hook->hk_name))) { 13316b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13321acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1333e088dd4cSAlexander Motin ERROUT(error); 13346b795970SJulian Elischer } 13356b795970SJulian Elischer } 13366b795970SJulian Elischer 13376b795970SJulian Elischer /* 13386b795970SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 13396b795970SJulian Elischer * We'll ask again later when we actually connect the hooks. 13406b795970SJulian Elischer */ 13416b795970SJulian Elischer hook->hk_node = node; /* just overwrite ng_deadnode */ 13426b795970SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 13436b795970SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 13446b795970SJulian Elischer node->nd_numhooks++; 13456b795970SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 13466b795970SJulian Elischer 13476b795970SJulian Elischer /* 134864efc707SRobert Watson * We now have a symmetrical situation, where both hooks have been 13495951069aSJulian Elischer * linked to their nodes, the newhook methods have been called 13506b795970SJulian Elischer * And the references are all correct. The hooks are still marked 13516b795970SJulian Elischer * as invalid, as we have not called the 'connect' methods 13526b795970SJulian Elischer * yet. 135364efc707SRobert Watson * We can call the local one immediately as we have the 13546b795970SJulian Elischer * node locked, but we need to queue the remote one. 13556b795970SJulian Elischer */ 13566b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1357e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 13586b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 13591acb27c6SJulian Elischer printf("failed in ng_con_part2(A)\n"); 1360e088dd4cSAlexander Motin ERROUT(error); 13616b795970SJulian Elischer } 13626b795970SJulian Elischer } 1363ac5dd141SGleb Smirnoff 1364ac5dd141SGleb Smirnoff /* 1365ac5dd141SGleb Smirnoff * Acquire topo mutex to avoid race with ng_destroy_hook(). 1366ac5dd141SGleb Smirnoff */ 1367ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1368ac5dd141SGleb Smirnoff peer = hook->hk_peer; 1369ac5dd141SGleb Smirnoff if (peer == &ng_deadhook) { 1370ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1371ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(B)\n"); 1372ac5dd141SGleb Smirnoff ng_destroy_hook(hook); 1373e088dd4cSAlexander Motin ERROUT(ENOENT); 1374ac5dd141SGleb Smirnoff } 1375ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1376ac5dd141SGleb Smirnoff 1377b332b91fSGleb Smirnoff if ((error = ng_send_fn2(peer->hk_node, peer, item, &ng_con_part3, 1378b332b91fSGleb Smirnoff NULL, 0, NG_REUSE_ITEM))) { 1379ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(C)\n"); 13801acb27c6SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 1381e088dd4cSAlexander Motin return (error); /* item was consumed. */ 13821acb27c6SJulian Elischer } 13836b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */ 1384e088dd4cSAlexander Motin return (0); /* item was consumed. */ 1385e088dd4cSAlexander Motin done: 1386e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1387e088dd4cSAlexander Motin return (error); 13884cf49a43SJulian Elischer } 13894cf49a43SJulian Elischer 13904cf49a43SJulian Elischer /* 13916b795970SJulian Elischer * Connect this node with another node. We assume that this node is 13926b795970SJulian Elischer * currently locked, as we are only called from an NGM_CONNECT message. 13934cf49a43SJulian Elischer */ 13946b795970SJulian Elischer static int 1395e088dd4cSAlexander Motin ng_con_nodes(item_p item, node_p node, const char *name, 1396e088dd4cSAlexander Motin node_p node2, const char *name2) 13974cf49a43SJulian Elischer { 13984cf49a43SJulian Elischer int error; 13994cf49a43SJulian Elischer hook_p hook; 14004cf49a43SJulian Elischer hook_p hook2; 14014cf49a43SJulian Elischer 14021acb27c6SJulian Elischer if (ng_findhook(node2, name2) != NULL) { 14031acb27c6SJulian Elischer return(EEXIST); 14041acb27c6SJulian Elischer } 14053e4084c8SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) /* gives us a ref */ 14064cf49a43SJulian Elischer return (error); 14076b795970SJulian Elischer /* Allocate the other hook and link it up */ 14086b795970SJulian Elischer NG_ALLOC_HOOK(hook2); 140919724144SGleb Smirnoff if (hook2 == NULL) { 14106b795970SJulian Elischer TRAP_ERROR(); 14116b795970SJulian Elischer ng_destroy_hook(hook); /* XXX check ref counts so far */ 14126b795970SJulian Elischer NG_HOOK_UNREF(hook); /* including our ref */ 14136b795970SJulian Elischer return (ENOMEM); 14146b795970SJulian Elischer } 14156b795970SJulian Elischer hook2->hk_refs = 1; /* start with a reference for us. */ 14166b795970SJulian Elischer hook2->hk_flags = HK_INVALID; 14176b795970SJulian Elischer hook2->hk_peer = hook; /* Link the two together */ 14186b795970SJulian Elischer hook->hk_peer = hook2; 14196b795970SJulian Elischer NG_HOOK_REF(hook); /* Add a ref for the peer to each*/ 14206b795970SJulian Elischer NG_HOOK_REF(hook2); 14216b795970SJulian Elischer hook2->hk_node = &ng_deadnode; 142287e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ); 14236b795970SJulian Elischer 14246b795970SJulian Elischer /* 14256b795970SJulian Elischer * Queue the function above. 14266b795970SJulian Elischer * Procesing continues in that function in the lock context of 14276b795970SJulian Elischer * the other node. 14286b795970SJulian Elischer */ 1429b332b91fSGleb Smirnoff if ((error = ng_send_fn2(node2, hook2, item, &ng_con_part2, NULL, 0, 1430b332b91fSGleb Smirnoff NG_NOFLAGS))) { 14313fb87c24SAlexander Motin printf("failed in ng_con_nodes(): %d\n", error); 14323fb87c24SAlexander Motin ng_destroy_hook(hook); /* also zaps peer */ 14333fb87c24SAlexander Motin } 14346b795970SJulian Elischer 14356b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Let each hook go if it wants to */ 14366b795970SJulian Elischer NG_HOOK_UNREF(hook2); 14373fb87c24SAlexander Motin return (error); 14384cf49a43SJulian Elischer } 14396b795970SJulian Elischer 14406b795970SJulian Elischer /* 14416b795970SJulian Elischer * Make a peer and connect. 14426b795970SJulian Elischer * We assume that the local node is locked. 14436b795970SJulian Elischer * The new node probably doesn't need a lock until 14446b795970SJulian Elischer * it has a hook, because it cannot really have any work until then, 14456b795970SJulian Elischer * but we should think about it a bit more. 14466b795970SJulian Elischer * 14476b795970SJulian Elischer * The problem may come if the other node also fires up 14486b795970SJulian Elischer * some hardware or a timer or some other source of activation, 14496b795970SJulian Elischer * also it may already get a command msg via it's ID. 14506b795970SJulian Elischer * 14516b795970SJulian Elischer * We could use the same method as ng_con_nodes() but we'd have 14526b795970SJulian Elischer * to add ability to remove the node when failing. (Not hard, just 14536b795970SJulian Elischer * make arg1 point to the node to remove). 14546b795970SJulian Elischer * Unless of course we just ignore failure to connect and leave 14556b795970SJulian Elischer * an unconnected node? 14566b795970SJulian Elischer */ 14576b795970SJulian Elischer static int 14586b795970SJulian Elischer ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 14596b795970SJulian Elischer { 14606b795970SJulian Elischer node_p node2; 14614c9b5910SGleb Smirnoff hook_p hook1, hook2; 14626b795970SJulian Elischer int error; 14636b795970SJulian Elischer 14646b795970SJulian Elischer if ((error = ng_make_node(type, &node2))) { 14656b795970SJulian Elischer return (error); 14666b795970SJulian Elischer } 14676b795970SJulian Elischer 14686b795970SJulian Elischer if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */ 14691acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14706b795970SJulian Elischer return (error); 14716b795970SJulian Elischer } 14726b795970SJulian Elischer 14736b795970SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 14741acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14756b795970SJulian Elischer ng_destroy_hook(hook1); 14766b795970SJulian Elischer NG_HOOK_UNREF(hook1); 14776b795970SJulian Elischer return (error); 14786b795970SJulian Elischer } 14796b795970SJulian Elischer 14806b795970SJulian Elischer /* 14816b795970SJulian Elischer * Actually link the two hooks together. 14826b795970SJulian Elischer */ 14836b795970SJulian Elischer hook1->hk_peer = hook2; 14846b795970SJulian Elischer hook2->hk_peer = hook1; 14856b795970SJulian Elischer 14866b795970SJulian Elischer /* Each hook is referenced by the other */ 14876b795970SJulian Elischer NG_HOOK_REF(hook1); 14886b795970SJulian Elischer NG_HOOK_REF(hook2); 14896b795970SJulian Elischer 14906b795970SJulian Elischer /* Give each node the opportunity to veto the pending connection */ 14916b795970SJulian Elischer if (hook1->hk_node->nd_type->connect) { 14926b795970SJulian Elischer error = (*hook1->hk_node->nd_type->connect) (hook1); 14936b795970SJulian Elischer } 14946b795970SJulian Elischer 14956b795970SJulian Elischer if ((error == 0) && hook2->hk_node->nd_type->connect) { 14966b795970SJulian Elischer error = (*hook2->hk_node->nd_type->connect) (hook2); 14976b795970SJulian Elischer 14986b795970SJulian Elischer } 14993e4084c8SJulian Elischer 15003e4084c8SJulian Elischer /* 15013e4084c8SJulian Elischer * drop the references we were holding on the two hooks. 15023e4084c8SJulian Elischer */ 15036b795970SJulian Elischer if (error) { 15046b795970SJulian Elischer ng_destroy_hook(hook2); /* also zaps hook1 */ 15051acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 15066b795970SJulian Elischer } else { 15076b795970SJulian Elischer /* As a last act, allow the hooks to be used */ 15086b795970SJulian Elischer hook1->hk_flags &= ~HK_INVALID; 15096b795970SJulian Elischer hook2->hk_flags &= ~HK_INVALID; 15106b795970SJulian Elischer } 15116b795970SJulian Elischer NG_HOOK_UNREF(hook1); 15123e4084c8SJulian Elischer NG_HOOK_UNREF(hook2); 15133e4084c8SJulian Elischer return (error); 15144cf49a43SJulian Elischer } 15156b795970SJulian Elischer 1516069154d5SJulian Elischer /************************************************************************ 1517069154d5SJulian Elischer Utility routines to send self messages 1518069154d5SJulian Elischer ************************************************************************/ 1519069154d5SJulian Elischer 15201acb27c6SJulian Elischer /* Shut this node down as soon as everyone is clear of it */ 152164efc707SRobert Watson /* Should add arg "immediately" to jump the queue */ 1522069154d5SJulian Elischer int 152315cea89fSAlexander Motin ng_rmnode_self(node_p node) 1524069154d5SJulian Elischer { 15251acb27c6SJulian Elischer int error; 15264cf49a43SJulian Elischer 15271acb27c6SJulian Elischer if (node == &ng_deadnode) 15281acb27c6SJulian Elischer return (0); 1529be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID; 1530be4252b3SJulian Elischer if (node->nd_flags & NGF_CLOSING) 15311acb27c6SJulian Elischer return (0); 1532069154d5SJulian Elischer 153315cea89fSAlexander Motin error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0); 15341acb27c6SJulian Elischer return (error); 1535069154d5SJulian Elischer } 1536069154d5SJulian Elischer 15371acb27c6SJulian Elischer static void 15386b795970SJulian Elischer ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) 15396b795970SJulian Elischer { 15406b795970SJulian Elischer ng_destroy_hook(hook); 15411acb27c6SJulian Elischer return ; 15426b795970SJulian Elischer } 15436b795970SJulian Elischer 1544954c4772SJulian Elischer int 1545954c4772SJulian Elischer ng_rmhook_self(hook_p hook) 1546954c4772SJulian Elischer { 15476b795970SJulian Elischer int error; 1548954c4772SJulian Elischer node_p node = NG_HOOK_NODE(hook); 1549954c4772SJulian Elischer 15506b795970SJulian Elischer if (node == &ng_deadnode) 15516b795970SJulian Elischer return (0); 15526b795970SJulian Elischer 15536b795970SJulian Elischer error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0); 15546b795970SJulian Elischer return (error); 1555954c4772SJulian Elischer } 1556954c4772SJulian Elischer 1557069154d5SJulian Elischer /*********************************************************************** 15584cf49a43SJulian Elischer * Parse and verify a string of the form: <NODE:><PATH> 15594cf49a43SJulian Elischer * 15604cf49a43SJulian Elischer * Such a string can refer to a specific node or a specific hook 15614cf49a43SJulian Elischer * on a specific node, depending on how you look at it. In the 15624cf49a43SJulian Elischer * latter case, the PATH component must not end in a dot. 15634cf49a43SJulian Elischer * 15644cf49a43SJulian Elischer * Both <NODE:> and <PATH> are optional. The <PATH> is a string 15654cf49a43SJulian Elischer * of hook names separated by dots. This breaks out the original 15664cf49a43SJulian Elischer * string, setting *nodep to "NODE" (or NULL if none) and *pathp 15674cf49a43SJulian Elischer * to "PATH" (or NULL if degenerate). Also, *hookp will point to 15684cf49a43SJulian Elischer * the final hook component of <PATH>, if any, otherwise NULL. 15694cf49a43SJulian Elischer * 15704cf49a43SJulian Elischer * This returns -1 if the path is malformed. The char ** are optional. 1571069154d5SJulian Elischer ***********************************************************************/ 15724cf49a43SJulian Elischer int 15734cf49a43SJulian Elischer ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 15744cf49a43SJulian Elischer { 15754cf49a43SJulian Elischer char *node, *path, *hook; 15764cf49a43SJulian Elischer int k; 15774cf49a43SJulian Elischer 15784cf49a43SJulian Elischer /* 15794cf49a43SJulian Elischer * Extract absolute NODE, if any 15804cf49a43SJulian Elischer */ 15814cf49a43SJulian Elischer for (path = addr; *path && *path != ':'; path++); 15824cf49a43SJulian Elischer if (*path) { 15834cf49a43SJulian Elischer node = addr; /* Here's the NODE */ 15844cf49a43SJulian Elischer *path++ = '\0'; /* Here's the PATH */ 15854cf49a43SJulian Elischer 15864cf49a43SJulian Elischer /* Node name must not be empty */ 15874cf49a43SJulian Elischer if (!*node) 15884cf49a43SJulian Elischer return -1; 15894cf49a43SJulian Elischer 15904cf49a43SJulian Elischer /* A name of "." is OK; otherwise '.' not allowed */ 15914cf49a43SJulian Elischer if (strcmp(node, ".") != 0) { 15924cf49a43SJulian Elischer for (k = 0; node[k]; k++) 15934cf49a43SJulian Elischer if (node[k] == '.') 15944cf49a43SJulian Elischer return -1; 15954cf49a43SJulian Elischer } 15964cf49a43SJulian Elischer } else { 15974cf49a43SJulian Elischer node = NULL; /* No absolute NODE */ 15984cf49a43SJulian Elischer path = addr; /* Here's the PATH */ 15994cf49a43SJulian Elischer } 16004cf49a43SJulian Elischer 16014cf49a43SJulian Elischer /* Snoop for illegal characters in PATH */ 16024cf49a43SJulian Elischer for (k = 0; path[k]; k++) 16034cf49a43SJulian Elischer if (path[k] == ':') 16044cf49a43SJulian Elischer return -1; 16054cf49a43SJulian Elischer 16064cf49a43SJulian Elischer /* Check for no repeated dots in PATH */ 16074cf49a43SJulian Elischer for (k = 0; path[k]; k++) 16084cf49a43SJulian Elischer if (path[k] == '.' && path[k + 1] == '.') 16094cf49a43SJulian Elischer return -1; 16104cf49a43SJulian Elischer 16114cf49a43SJulian Elischer /* Remove extra (degenerate) dots from beginning or end of PATH */ 16124cf49a43SJulian Elischer if (path[0] == '.') 16134cf49a43SJulian Elischer path++; 16144cf49a43SJulian Elischer if (*path && path[strlen(path) - 1] == '.') 16154cf49a43SJulian Elischer path[strlen(path) - 1] = 0; 16164cf49a43SJulian Elischer 16174cf49a43SJulian Elischer /* If PATH has a dot, then we're not talking about a hook */ 16184cf49a43SJulian Elischer if (*path) { 16194cf49a43SJulian Elischer for (hook = path, k = 0; path[k]; k++) 16204cf49a43SJulian Elischer if (path[k] == '.') { 16214cf49a43SJulian Elischer hook = NULL; 16224cf49a43SJulian Elischer break; 16234cf49a43SJulian Elischer } 16244cf49a43SJulian Elischer } else 16254cf49a43SJulian Elischer path = hook = NULL; 16264cf49a43SJulian Elischer 16274cf49a43SJulian Elischer /* Done */ 16284cf49a43SJulian Elischer if (nodep) 16294cf49a43SJulian Elischer *nodep = node; 16304cf49a43SJulian Elischer if (pathp) 16314cf49a43SJulian Elischer *pathp = path; 16324cf49a43SJulian Elischer if (hookp) 16334cf49a43SJulian Elischer *hookp = hook; 16344cf49a43SJulian Elischer return (0); 16354cf49a43SJulian Elischer } 16364cf49a43SJulian Elischer 16374cf49a43SJulian Elischer /* 16384cf49a43SJulian Elischer * Given a path, which may be absolute or relative, and a starting node, 1639069154d5SJulian Elischer * return the destination node. 16404cf49a43SJulian Elischer */ 16414cf49a43SJulian Elischer int 16424bd1b557SGleb Smirnoff ng_path2noderef(node_p here, const char *address, node_p *destp, 16434bd1b557SGleb Smirnoff hook_p *lasthook) 16444cf49a43SJulian Elischer { 164587e2c66aSHartmut Brandt char fullpath[NG_PATHSIZ]; 1646a7da736aSGleb Smirnoff char *nodename, *path; 1647069154d5SJulian Elischer node_p node, oldnode; 16484cf49a43SJulian Elischer 16494cf49a43SJulian Elischer /* Initialize */ 165030400f03SJulian Elischer if (destp == NULL) { 16516b795970SJulian Elischer TRAP_ERROR(); 16524cf49a43SJulian Elischer return EINVAL; 165330400f03SJulian Elischer } 16544cf49a43SJulian Elischer *destp = NULL; 16554cf49a43SJulian Elischer 16564cf49a43SJulian Elischer /* Make a writable copy of address for ng_path_parse() */ 16574cf49a43SJulian Elischer strncpy(fullpath, address, sizeof(fullpath) - 1); 16584cf49a43SJulian Elischer fullpath[sizeof(fullpath) - 1] = '\0'; 16594cf49a43SJulian Elischer 16604cf49a43SJulian Elischer /* Parse out node and sequence of hooks */ 16614cf49a43SJulian Elischer if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 16626b795970SJulian Elischer TRAP_ERROR(); 16634cf49a43SJulian Elischer return EINVAL; 16644cf49a43SJulian Elischer } 16654cf49a43SJulian Elischer 1666069154d5SJulian Elischer /* 1667069154d5SJulian Elischer * For an absolute address, jump to the starting node. 1668069154d5SJulian Elischer * Note that this holds a reference on the node for us. 1669069154d5SJulian Elischer * Don't forget to drop the reference if we don't need it. 1670069154d5SJulian Elischer */ 16714cf49a43SJulian Elischer if (nodename) { 1672069154d5SJulian Elischer node = ng_name2noderef(here, nodename); 16734cf49a43SJulian Elischer if (node == NULL) { 16746b795970SJulian Elischer TRAP_ERROR(); 16754cf49a43SJulian Elischer return (ENOENT); 16764cf49a43SJulian Elischer } 1677069154d5SJulian Elischer } else { 1678069154d5SJulian Elischer if (here == NULL) { 16796b795970SJulian Elischer TRAP_ERROR(); 1680069154d5SJulian Elischer return (EINVAL); 1681069154d5SJulian Elischer } 16824cf49a43SJulian Elischer node = here; 168330400f03SJulian Elischer NG_NODE_REF(node); 1684069154d5SJulian Elischer } 16854cf49a43SJulian Elischer 1686a7da736aSGleb Smirnoff if (path == NULL) { 1687a7da736aSGleb Smirnoff if (lasthook != NULL) 1688a7da736aSGleb Smirnoff *lasthook = NULL; 1689a7da736aSGleb Smirnoff *destp = node; 1690a7da736aSGleb Smirnoff return (0); 1691a7da736aSGleb Smirnoff } 1692a7da736aSGleb Smirnoff 1693069154d5SJulian Elischer /* 1694069154d5SJulian Elischer * Now follow the sequence of hooks 1695a7da736aSGleb Smirnoff * 1696a7da736aSGleb Smirnoff * XXXGL: The path may demolish as we go the sequence, but if 1697a7da736aSGleb Smirnoff * we hold the topology mutex at critical places, then, I hope, 1698a7da736aSGleb Smirnoff * we would always have valid pointers in hand, although the 1699a7da736aSGleb Smirnoff * path behind us may no longer exist. 1700069154d5SJulian Elischer */ 1701a7da736aSGleb Smirnoff for (;;) { 1702a7da736aSGleb Smirnoff hook_p hook; 17034cf49a43SJulian Elischer char *segment; 17044cf49a43SJulian Elischer 17054cf49a43SJulian Elischer /* 17064cf49a43SJulian Elischer * Break out the next path segment. Replace the dot we just 1707a7da736aSGleb Smirnoff * found with a NUL; "path" points to the next segment (or the 17084cf49a43SJulian Elischer * NUL at the end). 17094cf49a43SJulian Elischer */ 1710a7da736aSGleb Smirnoff for (segment = path; *path != '\0'; path++) { 1711a7da736aSGleb Smirnoff if (*path == '.') { 1712a7da736aSGleb Smirnoff *path++ = '\0'; 17134cf49a43SJulian Elischer break; 17144cf49a43SJulian Elischer } 17154cf49a43SJulian Elischer } 17164cf49a43SJulian Elischer 17174cf49a43SJulian Elischer /* We have a segment, so look for a hook by that name */ 1718899e9c4eSArchie Cobbs hook = ng_findhook(node, segment); 17194cf49a43SJulian Elischer 1720a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 17214cf49a43SJulian Elischer /* Can't get there from here... */ 17224bd1b557SGleb Smirnoff if (hook == NULL || NG_HOOK_PEER(hook) == NULL || 17234bd1b557SGleb Smirnoff NG_HOOK_NOT_VALID(hook) || 17244bd1b557SGleb Smirnoff NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) { 17256b795970SJulian Elischer TRAP_ERROR(); 172630400f03SJulian Elischer NG_NODE_UNREF(node); 1727a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17284cf49a43SJulian Elischer return (ENOENT); 17294cf49a43SJulian Elischer } 17304cf49a43SJulian Elischer 1731069154d5SJulian Elischer /* 1732069154d5SJulian Elischer * Hop on over to the next node 1733069154d5SJulian Elischer * XXX 1734069154d5SJulian Elischer * Big race conditions here as hooks and nodes go away 1735069154d5SJulian Elischer * *** Idea.. store an ng_ID_t in each hook and use that 1736069154d5SJulian Elischer * instead of the direct hook in this crawl? 1737069154d5SJulian Elischer */ 1738069154d5SJulian Elischer oldnode = node; 173930400f03SJulian Elischer if ((node = NG_PEER_NODE(hook))) 174030400f03SJulian Elischer NG_NODE_REF(node); /* XXX RACE */ 174130400f03SJulian Elischer NG_NODE_UNREF(oldnode); /* XXX another race */ 174230400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 174330400f03SJulian Elischer NG_NODE_UNREF(node); /* XXX more races */ 1744a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17456b795970SJulian Elischer TRAP_ERROR(); 17464cf49a43SJulian Elischer return (ENXIO); 17474cf49a43SJulian Elischer } 17484cf49a43SJulian Elischer 1749a7da736aSGleb Smirnoff if (*path == '\0') { 1750a7da736aSGleb Smirnoff if (lasthook != NULL) { 1751a7da736aSGleb Smirnoff if (hook != NULL) { 1752a7da736aSGleb Smirnoff *lasthook = NG_HOOK_PEER(hook); 1753a7da736aSGleb Smirnoff NG_HOOK_REF(*lasthook); 1754a7da736aSGleb Smirnoff } else 1755a7da736aSGleb Smirnoff *lasthook = NULL; 1756a7da736aSGleb Smirnoff } 1757a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17584cf49a43SJulian Elischer *destp = node; 1759069154d5SJulian Elischer return (0); 1760069154d5SJulian Elischer } 1761a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1762a7da736aSGleb Smirnoff } 1763a7da736aSGleb Smirnoff } 1764069154d5SJulian Elischer 1765069154d5SJulian Elischer /***************************************************************\ 1766069154d5SJulian Elischer * Input queue handling. 1767069154d5SJulian Elischer * All activities are submitted to the node via the input queue 1768069154d5SJulian Elischer * which implements a multiple-reader/single-writer gate. 176964efc707SRobert Watson * Items which cannot be handled immediately are queued. 1770069154d5SJulian Elischer * 1771069154d5SJulian Elischer * read-write queue locking inline functions * 1772069154d5SJulian Elischer \***************************************************************/ 1773069154d5SJulian Elischer 17749852972bSAlexander Motin static __inline void ng_queue_rw(node_p node, item_p item, int rw); 17759852972bSAlexander Motin static __inline item_p ng_dequeue(node_p node, int *rw); 17769852972bSAlexander Motin static __inline item_p ng_acquire_read(node_p node, item_p item); 17779852972bSAlexander Motin static __inline item_p ng_acquire_write(node_p node, item_p item); 17789852972bSAlexander Motin static __inline void ng_leave_read(node_p node); 17799852972bSAlexander Motin static __inline void ng_leave_write(node_p node); 1780069154d5SJulian Elischer 1781069154d5SJulian Elischer /* 1782069154d5SJulian Elischer * Definition of the bits fields in the ng_queue flag word. 1783069154d5SJulian Elischer * Defined here rather than in netgraph.h because no-one should fiddle 1784069154d5SJulian Elischer * with them. 1785069154d5SJulian Elischer * 1786b57a7965SJulian Elischer * The ordering here may be important! don't shuffle these. 1787069154d5SJulian Elischer */ 1788069154d5SJulian Elischer /*- 1789069154d5SJulian Elischer Safety Barrier--------+ (adjustable to suit taste) (not used yet) 1790069154d5SJulian Elischer | 1791069154d5SJulian Elischer V 1792069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 17934be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 17944be59335SGleb Smirnoff | |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |P|A| 17954be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|W| 1796069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 17974be59335SGleb Smirnoff \___________________________ ____________________________/ | | 17984be59335SGleb Smirnoff V | | 17994be59335SGleb Smirnoff [active reader count] | | 1800069154d5SJulian Elischer | | 18014be59335SGleb Smirnoff Operation Pending -------------------------------+ | 1802069154d5SJulian Elischer | 18034be59335SGleb Smirnoff Active Writer ---------------------------------------+ 1804b57a7965SJulian Elischer 18058f9ac44aSAlexander Motin Node queue has such semantics: 18068f9ac44aSAlexander Motin - All flags modifications are atomic. 18078f9ac44aSAlexander Motin - Reader count can be incremented only if there is no writer or pending flags. 18088f9ac44aSAlexander Motin As soon as this can't be done with single operation, it is implemented with 18098f9ac44aSAlexander Motin spin loop and atomic_cmpset(). 18108f9ac44aSAlexander Motin - Writer flag can be set only if there is no any bits set. 18118f9ac44aSAlexander Motin It is implemented with atomic_cmpset(). 18128f9ac44aSAlexander Motin - Pending flag can be set any time, but to avoid collision on queue processing 18138f9ac44aSAlexander Motin all queue fields are protected by the mutex. 18148f9ac44aSAlexander Motin - Queue processing thread reads queue holding the mutex, but releases it while 18158f9ac44aSAlexander Motin processing. When queue is empty pending flag is removed. 1816069154d5SJulian Elischer */ 18178f9ac44aSAlexander Motin 18184be59335SGleb Smirnoff #define WRITER_ACTIVE 0x00000001 18194be59335SGleb Smirnoff #define OP_PENDING 0x00000002 18204be59335SGleb Smirnoff #define READER_INCREMENT 0x00000004 18214be59335SGleb Smirnoff #define READER_MASK 0xfffffffc /* Not valid if WRITER_ACTIVE is set */ 18224be59335SGleb Smirnoff #define SAFETY_BARRIER 0x00100000 /* 128K items queued should be enough */ 1823b57a7965SJulian Elischer 1824b57a7965SJulian Elischer /* Defines of more elaborate states on the queue */ 18254be59335SGleb Smirnoff /* Mask of bits a new read cares about */ 18264be59335SGleb Smirnoff #define NGQ_RMASK (WRITER_ACTIVE|OP_PENDING) 1827b57a7965SJulian Elischer 18284be59335SGleb Smirnoff /* Mask of bits a new write cares about */ 1829b57a7965SJulian Elischer #define NGQ_WMASK (NGQ_RMASK|READER_MASK) 1830b57a7965SJulian Elischer 18314be59335SGleb Smirnoff /* Test to decide if there is something on the queue. */ 18324be59335SGleb Smirnoff #define QUEUE_ACTIVE(QP) ((QP)->q_flags & OP_PENDING) 18334be59335SGleb Smirnoff 18344be59335SGleb Smirnoff /* How to decide what the next queued item is. */ 18359852972bSAlexander Motin #define HEAD_IS_READER(QP) NGI_QUEUED_READER(STAILQ_FIRST(&(QP)->queue)) 18369852972bSAlexander Motin #define HEAD_IS_WRITER(QP) NGI_QUEUED_WRITER(STAILQ_FIRST(&(QP)->queue)) /* notused */ 18374be59335SGleb Smirnoff 18384be59335SGleb Smirnoff /* Read the status to decide if the next item on the queue can now run. */ 18394be59335SGleb Smirnoff #define QUEUED_READER_CAN_PROCEED(QP) \ 18404be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_RMASK & ~OP_PENDING)) == 0) 18414be59335SGleb Smirnoff #define QUEUED_WRITER_CAN_PROCEED(QP) \ 18424be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_WMASK & ~OP_PENDING)) == 0) 1843b57a7965SJulian Elischer 1844b57a7965SJulian Elischer /* Is there a chance of getting ANY work off the queue? */ 18454be59335SGleb Smirnoff #define NEXT_QUEUED_ITEM_CAN_PROCEED(QP) \ 18464be59335SGleb Smirnoff ((HEAD_IS_READER(QP)) ? QUEUED_READER_CAN_PROCEED(QP) : \ 1847394cb30aSAlexander Motin QUEUED_WRITER_CAN_PROCEED(QP)) 18484be59335SGleb Smirnoff 1849714fb865SGleb Smirnoff #define NGQRW_R 0 1850714fb865SGleb Smirnoff #define NGQRW_W 1 1851714fb865SGleb Smirnoff 18529852972bSAlexander Motin #define NGQ2_WORKQ 0x00000001 18539852972bSAlexander Motin 1854069154d5SJulian Elischer /* 1855069154d5SJulian Elischer * Taking into account the current state of the queue and node, possibly take 1856069154d5SJulian Elischer * the next entry off the queue and return it. Return NULL if there was 1857069154d5SJulian Elischer * nothing we could return, either because there really was nothing there, or 1858069154d5SJulian Elischer * because the node was in a state where it cannot yet process the next item 1859069154d5SJulian Elischer * on the queue. 1860069154d5SJulian Elischer */ 1861069154d5SJulian Elischer static __inline item_p 18629852972bSAlexander Motin ng_dequeue(node_p node, int *rw) 1863069154d5SJulian Elischer { 1864069154d5SJulian Elischer item_p item; 18659852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 1866b57a7965SJulian Elischer 18678f9ac44aSAlexander Motin /* This MUST be called with the mutex held. */ 1868d58e678fSGleb Smirnoff mtx_assert(&ngq->q_mtx, MA_OWNED); 18698f9ac44aSAlexander Motin 18708f9ac44aSAlexander Motin /* If there is nothing queued, then just return. */ 18714be59335SGleb Smirnoff if (!QUEUE_ACTIVE(ngq)) { 18722955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queue empty; " 18732955ee18SGleb Smirnoff "queue flags 0x%lx", __func__, 18749852972bSAlexander Motin node->nd_ID, node, ngq->q_flags); 18754be59335SGleb Smirnoff return (NULL); 18764be59335SGleb Smirnoff } 1877d58e678fSGleb Smirnoff 18784be59335SGleb Smirnoff /* 18794be59335SGleb Smirnoff * From here, we can assume there is a head item. 18804be59335SGleb Smirnoff * We need to find out what it is and if it can be dequeued, given 18814be59335SGleb Smirnoff * the current state of the node. 18824be59335SGleb Smirnoff */ 18834be59335SGleb Smirnoff if (HEAD_IS_READER(ngq)) { 1884394cb30aSAlexander Motin while (1) { 1885394cb30aSAlexander Motin long t = ngq->q_flags; 1886394cb30aSAlexander Motin if (t & WRITER_ACTIVE) { 18878f9ac44aSAlexander Motin /* There is writer, reader can't proceed. */ 18884bd1b557SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queued " 18894bd1b557SGleb Smirnoff "reader can't proceed; queue flags 0x%lx", 18904bd1b557SGleb Smirnoff __func__, node->nd_ID, node, t); 18914be59335SGleb Smirnoff return (NULL); 18924be59335SGleb Smirnoff } 18939852972bSAlexander Motin if (atomic_cmpset_acq_int(&ngq->q_flags, t, 1894394cb30aSAlexander Motin t + READER_INCREMENT)) 1895394cb30aSAlexander Motin break; 1896394cb30aSAlexander Motin cpu_spinwait(); 1897394cb30aSAlexander Motin } 18988f9ac44aSAlexander Motin /* We have got reader lock for the node. */ 1899714fb865SGleb Smirnoff *rw = NGQRW_R; 19009852972bSAlexander Motin } else if (atomic_cmpset_acq_int(&ngq->q_flags, OP_PENDING, 1901394cb30aSAlexander Motin OP_PENDING + WRITER_ACTIVE)) { 19028f9ac44aSAlexander Motin /* We have got writer lock for the node. */ 1903714fb865SGleb Smirnoff *rw = NGQRW_W; 1904069154d5SJulian Elischer } else { 19058f9ac44aSAlexander Motin /* There is somebody other, writer can't proceed. */ 19064bd1b557SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queued writer can't " 19074bd1b557SGleb Smirnoff "proceed; queue flags 0x%lx", __func__, node->nd_ID, node, 19084bd1b557SGleb Smirnoff ngq->q_flags); 19094be59335SGleb Smirnoff return (NULL); 19104cf49a43SJulian Elischer } 19114cf49a43SJulian Elischer 19124cf49a43SJulian Elischer /* 1913069154d5SJulian Elischer * Now we dequeue the request (whatever it may be) and correct the 1914069154d5SJulian Elischer * pending flags and the next and last pointers. 19154cf49a43SJulian Elischer */ 19169852972bSAlexander Motin item = STAILQ_FIRST(&ngq->queue); 19179852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 19189852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 19199852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 19204bd1b557SGleb Smirnoff CTR6(KTR_NET, "%20s: node [%x] (%p) returning item %p as %s; queue " 19214bd1b557SGleb Smirnoff "flags 0x%lx", __func__, node->nd_ID, node, item, *rw ? "WRITER" : 19224bd1b557SGleb Smirnoff "READER", ngq->q_flags); 1923069154d5SJulian Elischer return (item); 1924069154d5SJulian Elischer } 1925859a4d16SJulian Elischer 1926859a4d16SJulian Elischer /* 19278f9ac44aSAlexander Motin * Queue a packet to be picked up later by someone else. 19288f9ac44aSAlexander Motin * If the queue could be run now, add node to the queue handler's worklist. 1929859a4d16SJulian Elischer */ 1930069154d5SJulian Elischer static __inline void 19319852972bSAlexander Motin ng_queue_rw(node_p node, item_p item, int rw) 1932069154d5SJulian Elischer { 19339852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 19344be59335SGleb Smirnoff if (rw == NGQRW_W) 19354be59335SGleb Smirnoff NGI_SET_WRITER(item); 19364be59335SGleb Smirnoff else 19374be59335SGleb Smirnoff NGI_SET_READER(item); 1938394cb30aSAlexander Motin 1939394cb30aSAlexander Motin NG_QUEUE_LOCK(ngq); 1940394cb30aSAlexander Motin /* Set OP_PENDING flag and enqueue the item. */ 19419852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 19429852972bSAlexander Motin STAILQ_INSERT_TAIL(&ngq->queue, item, el_next); 1943394cb30aSAlexander Motin 19442955ee18SGleb Smirnoff CTR5(KTR_NET, "%20s: node [%x] (%p) queued item %p as %s", __func__, 19459852972bSAlexander Motin node->nd_ID, node, item, rw ? "WRITER" : "READER" ); 19464be59335SGleb Smirnoff 19474be59335SGleb Smirnoff /* 19484be59335SGleb Smirnoff * We can take the worklist lock with the node locked 19494be59335SGleb Smirnoff * BUT NOT THE REVERSE! 19504be59335SGleb Smirnoff */ 19514be59335SGleb Smirnoff if (NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 19529852972bSAlexander Motin ng_worklist_add(node); 1953394cb30aSAlexander Motin NG_QUEUE_UNLOCK(ngq); 1954069154d5SJulian Elischer } 1955069154d5SJulian Elischer 19568f9ac44aSAlexander Motin /* Acquire reader lock on node. If node is busy, queue the packet. */ 1957069154d5SJulian Elischer static __inline item_p 19589852972bSAlexander Motin ng_acquire_read(node_p node, item_p item) 1959069154d5SJulian Elischer { 19609852972bSAlexander Motin KASSERT(node != &ng_deadnode, 1961ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 1962069154d5SJulian Elischer 1963394cb30aSAlexander Motin /* Reader needs node without writer and pending items. */ 19644bd1b557SGleb Smirnoff for (;;) { 19659852972bSAlexander Motin long t = node->nd_input_queue.q_flags; 1966394cb30aSAlexander Motin if (t & NGQ_RMASK) 1967394cb30aSAlexander Motin break; /* Node is not ready for reader. */ 19684bd1b557SGleb Smirnoff if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, t, 19694bd1b557SGleb Smirnoff t + READER_INCREMENT)) { 1970069154d5SJulian Elischer /* Successfully grabbed node */ 1971394cb30aSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 19729852972bSAlexander Motin __func__, node->nd_ID, node, item); 1973069154d5SJulian Elischer return (item); 1974069154d5SJulian Elischer } 1975394cb30aSAlexander Motin cpu_spinwait(); 1976394cb30aSAlexander Motin }; 1977069154d5SJulian Elischer 1978394cb30aSAlexander Motin /* Queue the request for later. */ 19799852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_R); 1980f912c0f7SGleb Smirnoff 1981f912c0f7SGleb Smirnoff return (NULL); 1982069154d5SJulian Elischer } 1983069154d5SJulian Elischer 19848f9ac44aSAlexander Motin /* Acquire writer lock on node. If node is busy, queue the packet. */ 1985069154d5SJulian Elischer static __inline item_p 19869852972bSAlexander Motin ng_acquire_write(node_p node, item_p item) 1987069154d5SJulian Elischer { 19889852972bSAlexander Motin KASSERT(node != &ng_deadnode, 1989ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 1990ac5dd141SGleb Smirnoff 1991394cb30aSAlexander Motin /* Writer needs completely idle node. */ 19924bd1b557SGleb Smirnoff if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 0, 19934bd1b557SGleb Smirnoff WRITER_ACTIVE)) { 1994394cb30aSAlexander Motin /* Successfully grabbed node */ 19952955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 19969852972bSAlexander Motin __func__, node->nd_ID, node, item); 1997069154d5SJulian Elischer return (item); 1998069154d5SJulian Elischer } 1999069154d5SJulian Elischer 2000394cb30aSAlexander Motin /* Queue the request for later. */ 20019852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_W); 2002f912c0f7SGleb Smirnoff 2003f912c0f7SGleb Smirnoff return (NULL); 2004069154d5SJulian Elischer } 2005069154d5SJulian Elischer 2006262dfd7fSJulian Elischer #if 0 2007262dfd7fSJulian Elischer static __inline item_p 20089852972bSAlexander Motin ng_upgrade_write(node_p node, item_p item) 2009262dfd7fSJulian Elischer { 20109852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 20119852972bSAlexander Motin KASSERT(node != &ng_deadnode, 2012262dfd7fSJulian Elischer ("%s: working on deadnode", __func__)); 2013262dfd7fSJulian Elischer 2014262dfd7fSJulian Elischer NGI_SET_WRITER(item); 2015262dfd7fSJulian Elischer 20169852972bSAlexander Motin NG_QUEUE_LOCK(ngq); 2017262dfd7fSJulian Elischer 2018262dfd7fSJulian Elischer /* 2019262dfd7fSJulian Elischer * There will never be no readers as we are there ourselves. 2020262dfd7fSJulian Elischer * Set the WRITER_ACTIVE flags ASAP to block out fast track readers. 2021262dfd7fSJulian Elischer * The caller we are running from will call ng_leave_read() 2022262dfd7fSJulian Elischer * soon, so we must account for that. We must leave again with the 2023262dfd7fSJulian Elischer * READER lock. If we find other readers, then 2024262dfd7fSJulian Elischer * queue the request for later. However "later" may be rignt now 2025262dfd7fSJulian Elischer * if there are no readers. We don't really care if there are queued 2026262dfd7fSJulian Elischer * items as we will bypass them anyhow. 2027262dfd7fSJulian Elischer */ 20289852972bSAlexander Motin atomic_add_int(&ngq->q_flags, WRITER_ACTIVE - READER_INCREMENT); 20299852972bSAlexander Motin if ((ngq->q_flags & (NGQ_WMASK & ~OP_PENDING)) == WRITER_ACTIVE) { 20309852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2031262dfd7fSJulian Elischer 2032262dfd7fSJulian Elischer /* It's just us, act on the item. */ 2033262dfd7fSJulian Elischer /* will NOT drop writer lock when done */ 2034262dfd7fSJulian Elischer ng_apply_item(node, item, 0); 2035262dfd7fSJulian Elischer 2036262dfd7fSJulian Elischer /* 2037262dfd7fSJulian Elischer * Having acted on the item, atomically 20384bd1b557SGleb Smirnoff * downgrade back to READER and finish up. 2039262dfd7fSJulian Elischer */ 20404bd1b557SGleb Smirnoff atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE); 2041262dfd7fSJulian Elischer 2042262dfd7fSJulian Elischer /* Our caller will call ng_leave_read() */ 2043262dfd7fSJulian Elischer return; 2044262dfd7fSJulian Elischer } 2045262dfd7fSJulian Elischer /* 2046262dfd7fSJulian Elischer * It's not just us active, so queue us AT THE HEAD. 2047262dfd7fSJulian Elischer * "Why?" I hear you ask. 2048262dfd7fSJulian Elischer * Put us at the head of the queue as we've already been 2049262dfd7fSJulian Elischer * through it once. If there is nothing else waiting, 2050262dfd7fSJulian Elischer * set the correct flags. 2051262dfd7fSJulian Elischer */ 20529852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) { 2053262dfd7fSJulian Elischer /* We've gone from, 0 to 1 item in the queue */ 20549852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 2055262dfd7fSJulian Elischer 2056262dfd7fSJulian Elischer CTR3(KTR_NET, "%20s: node [%x] (%p) set OP_PENDING", __func__, 20579852972bSAlexander Motin node->nd_ID, node); 2058262dfd7fSJulian Elischer }; 20599852972bSAlexander Motin STAILQ_INSERT_HEAD(&ngq->queue, item, el_next); 20609852972bSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) requeued item %p as WRITER", 20619852972bSAlexander Motin __func__, node->nd_ID, node, item ); 2062262dfd7fSJulian Elischer 2063262dfd7fSJulian Elischer /* Reverse what we did above. That downgrades us back to reader */ 20649852972bSAlexander Motin atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE); 2065394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 20669852972bSAlexander Motin ng_worklist_add(node); 20679852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2068262dfd7fSJulian Elischer 2069262dfd7fSJulian Elischer return; 2070262dfd7fSJulian Elischer } 2071262dfd7fSJulian Elischer #endif 2072262dfd7fSJulian Elischer 20738f9ac44aSAlexander Motin /* Release reader lock. */ 2074069154d5SJulian Elischer static __inline void 20759852972bSAlexander Motin ng_leave_read(node_p node) 2076069154d5SJulian Elischer { 20779852972bSAlexander Motin atomic_subtract_rel_int(&node->nd_input_queue.q_flags, READER_INCREMENT); 2078069154d5SJulian Elischer } 2079069154d5SJulian Elischer 20808f9ac44aSAlexander Motin /* Release writer lock. */ 2081069154d5SJulian Elischer static __inline void 20829852972bSAlexander Motin ng_leave_write(node_p node) 2083069154d5SJulian Elischer { 20849852972bSAlexander Motin atomic_clear_rel_int(&node->nd_input_queue.q_flags, WRITER_ACTIVE); 2085069154d5SJulian Elischer } 2086069154d5SJulian Elischer 20878f9ac44aSAlexander Motin /* Purge node queue. Called on node shutdown. */ 2088069154d5SJulian Elischer static void 20899852972bSAlexander Motin ng_flush_input_queue(node_p node) 2090069154d5SJulian Elischer { 20919852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 2092069154d5SJulian Elischer item_p item; 2093069154d5SJulian Elischer 20942c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 20959852972bSAlexander Motin while ((item = STAILQ_FIRST(&ngq->queue)) != NULL) { 20969852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 20979852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 20989852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 20992c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 21004be59335SGleb Smirnoff 21014be59335SGleb Smirnoff /* If the item is supplying a callback, call it with an error */ 210210e87318SAlexander Motin if (item->apply != NULL) { 210310e87318SAlexander Motin if (item->depth == 1) 210410e87318SAlexander Motin item->apply->error = ENOENT; 210510e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 210610e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 210710e87318SAlexander Motin item->apply->error); 210810e87318SAlexander Motin } 2109eb2405ddSGleb Smirnoff } 2110505fad52SJulian Elischer NG_FREE_ITEM(item); 21112c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2112069154d5SJulian Elischer } 21132c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2114069154d5SJulian Elischer } 2115069154d5SJulian Elischer 2116069154d5SJulian Elischer /*********************************************************************** 2117069154d5SJulian Elischer * Externally visible method for sending or queueing messages or data. 2118069154d5SJulian Elischer ***********************************************************************/ 2119069154d5SJulian Elischer 2120069154d5SJulian Elischer /* 21211acb27c6SJulian Elischer * The module code should have filled out the item correctly by this stage: 2122069154d5SJulian Elischer * Common: 2123069154d5SJulian Elischer * reference to destination node. 2124069154d5SJulian Elischer * Reference to destination rcv hook if relevant. 2125e088dd4cSAlexander Motin * apply pointer must be or NULL or reference valid struct ng_apply_info. 2126069154d5SJulian Elischer * Data: 2127069154d5SJulian Elischer * pointer to mbuf 2128069154d5SJulian Elischer * Control_Message: 2129069154d5SJulian Elischer * pointer to msg. 2130069154d5SJulian Elischer * ID of original sender node. (return address) 21311acb27c6SJulian Elischer * Function: 21321acb27c6SJulian Elischer * Function pointer 21331acb27c6SJulian Elischer * void * argument 21341acb27c6SJulian Elischer * integer argument 2135069154d5SJulian Elischer * 2136069154d5SJulian Elischer * The nodes have several routines and macros to help with this task: 2137069154d5SJulian Elischer */ 2138069154d5SJulian Elischer 2139069154d5SJulian Elischer int 214042282202SGleb Smirnoff ng_snd_item(item_p item, int flags) 2141069154d5SJulian Elischer { 2142e088dd4cSAlexander Motin hook_p hook; 2143e088dd4cSAlexander Motin node_p node; 214442282202SGleb Smirnoff int queue, rw; 2145e088dd4cSAlexander Motin struct ng_queue *ngq; 214632b33288SGleb Smirnoff int error = 0; 2147069154d5SJulian Elischer 2148f50597f5SAlexander Motin /* We are sending item, so it must be present! */ 2149f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_snd_item: item is NULL")); 2150e088dd4cSAlexander Motin 2151e088dd4cSAlexander Motin #ifdef NETGRAPH_DEBUG 2152e088dd4cSAlexander Motin _ngi_check(item, __FILE__, __LINE__); 2153e088dd4cSAlexander Motin #endif 2154e088dd4cSAlexander Motin 2155f50597f5SAlexander Motin /* Item was sent once more, postpone apply() call. */ 2156e088dd4cSAlexander Motin if (item->apply) 2157e088dd4cSAlexander Motin refcount_acquire(&item->apply->refs); 2158e088dd4cSAlexander Motin 2159e088dd4cSAlexander Motin node = NGI_NODE(item); 2160f50597f5SAlexander Motin /* Node is never optional. */ 2161f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_snd_item: node is NULL")); 2162e088dd4cSAlexander Motin 2163e72a98f4SAlexander Motin hook = NGI_HOOK(item); 2164f50597f5SAlexander Motin /* Valid hook and mbuf are mandatory for data. */ 2165f50597f5SAlexander Motin if ((item->el_flags & NGQF_TYPE) == NGQF_DATA) { 2166f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_snd_item: hook for data is NULL")); 216710204449SJulian Elischer if (NGI_M(item) == NULL) 2168e088dd4cSAlexander Motin ERROUT(EINVAL); 2169069154d5SJulian Elischer CHECK_DATA_MBUF(NGI_M(item)); 21706f683eeeSGleb Smirnoff } 21716f683eeeSGleb Smirnoff 2172069154d5SJulian Elischer /* 2173f50597f5SAlexander Motin * If the item or the node specifies single threading, force 2174f50597f5SAlexander Motin * writer semantics. Similarly, the node may say one hook always 2175f50597f5SAlexander Motin * produces writers. These are overrides. 2176069154d5SJulian Elischer */ 2177db3408aeSAlexander Motin if (((item->el_flags & NGQF_RW) == NGQF_WRITER) || 2178f50597f5SAlexander Motin (node->nd_flags & NGF_FORCE_WRITER) || 2179f50597f5SAlexander Motin (hook && (hook->hk_flags & HK_FORCE_WRITER))) { 2180069154d5SJulian Elischer rw = NGQRW_W; 2181f50597f5SAlexander Motin } else { 2182f50597f5SAlexander Motin rw = NGQRW_R; 2183f50597f5SAlexander Motin } 21846f683eeeSGleb Smirnoff 218581a253a4SAlexander Motin /* 2186f089869fSMarko Zec * If sender or receiver requests queued delivery, or call graph 2187f089869fSMarko Zec * loops back from outbound to inbound path, or stack usage 218881a253a4SAlexander Motin * level is dangerous - enqueue message. 218981a253a4SAlexander Motin */ 219081a253a4SAlexander Motin if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) { 219181a253a4SAlexander Motin queue = 1; 2192f089869fSMarko Zec } else if (hook && (hook->hk_flags & HK_TO_INBOUND) && 2193f089869fSMarko Zec curthread->td_ng_outbound) { 2194f089869fSMarko Zec queue = 1; 2195f50597f5SAlexander Motin } else { 2196f50597f5SAlexander Motin queue = 0; 219781a253a4SAlexander Motin #ifdef GET_STACK_USAGE 2198d4529f98SAlexander Motin /* 2199942fe01fSDmitry Morozovsky * Most of netgraph nodes have small stack consumption and 2200f50597f5SAlexander Motin * for them 25% of free stack space is more than enough. 2201d4529f98SAlexander Motin * Nodes/hooks with higher stack usage should be marked as 2202f9773372SDmitry Morozovsky * HI_STACK. For them 50% of stack will be guaranteed then. 2203f50597f5SAlexander Motin * XXX: Values 25% and 50% are completely empirical. 2204d4529f98SAlexander Motin */ 2205f50597f5SAlexander Motin size_t st, su, sl; 220681a253a4SAlexander Motin GET_STACK_USAGE(st, su); 2207f50597f5SAlexander Motin sl = st - su; 22084bd1b557SGleb Smirnoff if ((sl * 4 < st) || ((sl * 2 < st) && 22094bd1b557SGleb Smirnoff ((node->nd_flags & NGF_HI_STACK) || (hook && 22104bd1b557SGleb Smirnoff (hook->hk_flags & HK_HI_STACK))))) 221181a253a4SAlexander Motin queue = 1; 221281a253a4SAlexander Motin #endif 2213f50597f5SAlexander Motin } 221481a253a4SAlexander Motin 2215069154d5SJulian Elischer if (queue) { 221610e87318SAlexander Motin item->depth = 1; 2217394cb30aSAlexander Motin /* Put it on the queue for that node*/ 22189852972bSAlexander Motin ng_queue_rw(node, item, rw); 2219f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2220069154d5SJulian Elischer } 2221069154d5SJulian Elischer 2222069154d5SJulian Elischer /* 2223069154d5SJulian Elischer * We already decided how we will be queueud or treated. 2224069154d5SJulian Elischer * Try get the appropriate operating permission. 2225069154d5SJulian Elischer */ 222632b33288SGleb Smirnoff if (rw == NGQRW_R) 22279852972bSAlexander Motin item = ng_acquire_read(node, item); 222832b33288SGleb Smirnoff else 22299852972bSAlexander Motin item = ng_acquire_write(node, item); 22304cf49a43SJulian Elischer 2231f50597f5SAlexander Motin /* Item was queued while trying to get permission. */ 2232f50597f5SAlexander Motin if (item == NULL) 2233f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2234069154d5SJulian Elischer 22355951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 22365951069aSJulian Elischer 223710e87318SAlexander Motin item->depth++; 223827757487SGleb Smirnoff error = ng_apply_item(node, item, rw); /* drops r/w lock when done */ 2239069154d5SJulian Elischer 2240394cb30aSAlexander Motin /* If something is waiting on queue and ready, schedule it. */ 22419852972bSAlexander Motin ngq = &node->nd_input_queue; 2242394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq)) { 22432c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2244394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 22459852972bSAlexander Motin ng_worklist_add(node); 22462c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2247394cb30aSAlexander Motin } 2248394cb30aSAlexander Motin 2249394cb30aSAlexander Motin /* 2250394cb30aSAlexander Motin * Node may go away as soon as we remove the reference. 2251394cb30aSAlexander Motin * Whatever we do, DO NOT access the node again! 2252394cb30aSAlexander Motin */ 2253394cb30aSAlexander Motin NG_NODE_UNREF(node); 2254069154d5SJulian Elischer 22551acb27c6SJulian Elischer return (error); 2256e088dd4cSAlexander Motin 2257e088dd4cSAlexander Motin done: 2258f50597f5SAlexander Motin /* If was not sent, apply callback here. */ 225910e87318SAlexander Motin if (item->apply != NULL) { 226010e87318SAlexander Motin if (item->depth == 0 && error != 0) 226110e87318SAlexander Motin item->apply->error = error; 226210e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 226310e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 226410e87318SAlexander Motin item->apply->error); 226510e87318SAlexander Motin } 226610e87318SAlexander Motin } 2267e72a98f4SAlexander Motin 2268e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2269e088dd4cSAlexander Motin return (error); 2270069154d5SJulian Elischer } 2271069154d5SJulian Elischer 2272069154d5SJulian Elischer /* 2273069154d5SJulian Elischer * We have an item that was possibly queued somewhere. 2274069154d5SJulian Elischer * It should contain all the information needed 2275069154d5SJulian Elischer * to run it on the appropriate node/hook. 2276e088dd4cSAlexander Motin * If there is apply pointer and we own the last reference, call apply(). 22774cf49a43SJulian Elischer */ 227827757487SGleb Smirnoff static int 2279714fb865SGleb Smirnoff ng_apply_item(node_p node, item_p item, int rw) 2280069154d5SJulian Elischer { 2281069154d5SJulian Elischer hook_p hook; 2282069154d5SJulian Elischer ng_rcvdata_t *rcvdata; 2283c4b5eea4SJulian Elischer ng_rcvmsg_t *rcvmsg; 2284e088dd4cSAlexander Motin struct ng_apply_info *apply; 228510e87318SAlexander Motin int error = 0, depth; 2286069154d5SJulian Elischer 2287f50597f5SAlexander Motin /* Node and item are never optional. */ 2288f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_apply_item: node is NULL")); 2289f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_apply_item: item is NULL")); 2290f50597f5SAlexander Motin 22911acb27c6SJulian Elischer NGI_GET_HOOK(item, hook); /* clears stored hook */ 229230400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 2293069154d5SJulian Elischer _ngi_check(item, __FILE__, __LINE__); 2294069154d5SJulian Elischer #endif 22958afe16d5SGleb Smirnoff 22968afe16d5SGleb Smirnoff apply = item->apply; 229710e87318SAlexander Motin depth = item->depth; 22988afe16d5SGleb Smirnoff 22996b795970SJulian Elischer switch (item->el_flags & NGQF_TYPE) { 2300069154d5SJulian Elischer case NGQF_DATA: 2301069154d5SJulian Elischer /* 2302069154d5SJulian Elischer * Check things are still ok as when we were queued. 2303069154d5SJulian Elischer */ 2304f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_apply_item: hook for data is NULL")); 2305f50597f5SAlexander Motin if (NG_HOOK_NOT_VALID(hook) || 2306f50597f5SAlexander Motin NG_NODE_NOT_VALID(node)) { 2307a54a69d7SJulian Elischer error = EIO; 2308069154d5SJulian Elischer NG_FREE_ITEM(item); 2309c4b5eea4SJulian Elischer break; 2310069154d5SJulian Elischer } 2311c4b5eea4SJulian Elischer /* 2312c4b5eea4SJulian Elischer * If no receive method, just silently drop it. 23134bd1b557SGleb Smirnoff * Give preference to the hook over-ride method. 2314c4b5eea4SJulian Elischer */ 23154bd1b557SGleb Smirnoff if ((!(rcvdata = hook->hk_rcvdata)) && 23164bd1b557SGleb Smirnoff (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) { 2317c4b5eea4SJulian Elischer error = 0; 2318c4b5eea4SJulian Elischer NG_FREE_ITEM(item); 2319c4b5eea4SJulian Elischer break; 2320c4b5eea4SJulian Elischer } 2321a54a69d7SJulian Elischer error = (*rcvdata)(hook, item); 2322069154d5SJulian Elischer break; 2323069154d5SJulian Elischer case NGQF_MESG: 2324e72a98f4SAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook)) { 2325069154d5SJulian Elischer /* 2326e72a98f4SAlexander Motin * The hook has been zapped then we can't use it. 2327e72a98f4SAlexander Motin * Immediately drop its reference. 2328069154d5SJulian Elischer * The message may not need it. 2329069154d5SJulian Elischer */ 233030400f03SJulian Elischer NG_HOOK_UNREF(hook); 2331069154d5SJulian Elischer hook = NULL; 2332069154d5SJulian Elischer } 2333069154d5SJulian Elischer /* 2334069154d5SJulian Elischer * Similarly, if the node is a zombie there is 2335069154d5SJulian Elischer * nothing we can do with it, drop everything. 2336069154d5SJulian Elischer */ 233730400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 23386b795970SJulian Elischer TRAP_ERROR(); 2339a54a69d7SJulian Elischer error = EINVAL; 2340069154d5SJulian Elischer NG_FREE_ITEM(item); 2341e72a98f4SAlexander Motin break; 2342e72a98f4SAlexander Motin } 2343069154d5SJulian Elischer /* 2344069154d5SJulian Elischer * Call the appropriate message handler for the object. 2345069154d5SJulian Elischer * It is up to the message handler to free the message. 2346069154d5SJulian Elischer * If it's a generic message, handle it generically, 2347e72a98f4SAlexander Motin * otherwise call the type's message handler (if it exists). 2348069154d5SJulian Elischer * XXX (race). Remember that a queued message may 2349069154d5SJulian Elischer * reference a node or hook that has just been 2350069154d5SJulian Elischer * invalidated. It will exist as the queue code 2351069154d5SJulian Elischer * is holding a reference, but.. 2352069154d5SJulian Elischer */ 2353e72a98f4SAlexander Motin if ((NGI_MSG(item)->header.typecookie == NGM_GENERIC_COOKIE) && 2354e72a98f4SAlexander Motin ((NGI_MSG(item)->header.flags & NGF_RESP) == 0)) { 2355a54a69d7SJulian Elischer error = ng_generic_msg(node, item, hook); 2356c4b5eea4SJulian Elischer break; 2357c4b5eea4SJulian Elischer } 2358e72a98f4SAlexander Motin if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) && 2359e72a98f4SAlexander Motin (!(rcvmsg = node->nd_type->rcvmsg))) { 23606b795970SJulian Elischer TRAP_ERROR(); 2361a54a69d7SJulian Elischer error = 0; 2362069154d5SJulian Elischer NG_FREE_ITEM(item); 2363c4b5eea4SJulian Elischer break; 2364069154d5SJulian Elischer } 2365a54a69d7SJulian Elischer error = (*rcvmsg)(node, item, hook); 2366069154d5SJulian Elischer break; 23676b795970SJulian Elischer case NGQF_FN: 2368e088dd4cSAlexander Motin case NGQF_FN2: 2369e088dd4cSAlexander Motin /* 237074c9119dSAlexander Motin * In the case of the shutdown message we allow it to hit 2371e088dd4cSAlexander Motin * even if the node is invalid. 2372e088dd4cSAlexander Motin */ 237374c9119dSAlexander Motin if (NG_NODE_NOT_VALID(node) && 237474c9119dSAlexander Motin NGI_FN(item) != &ng_rmnode) { 2375e088dd4cSAlexander Motin TRAP_ERROR(); 2376e088dd4cSAlexander Motin error = EINVAL; 2377e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2378e088dd4cSAlexander Motin break; 2379e088dd4cSAlexander Motin } 238074c9119dSAlexander Motin /* Same is about some internal functions and invalid hook. */ 238174c9119dSAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook) && 238274c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part2 && 238374c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part3 && 238474c9119dSAlexander Motin NGI_FN(item) != &ng_rmhook_part2) { 238574c9119dSAlexander Motin TRAP_ERROR(); 238674c9119dSAlexander Motin error = EINVAL; 238774c9119dSAlexander Motin NG_FREE_ITEM(item); 238874c9119dSAlexander Motin break; 238974c9119dSAlexander Motin } 239074c9119dSAlexander Motin 2391b332b91fSGleb Smirnoff if ((item->el_flags & NGQF_TYPE) == NGQF_FN) { 2392b332b91fSGleb Smirnoff (*NGI_FN(item))(node, hook, NGI_ARG1(item), 2393b332b91fSGleb Smirnoff NGI_ARG2(item)); 2394b332b91fSGleb Smirnoff NG_FREE_ITEM(item); 2395b332b91fSGleb Smirnoff } else /* it is NGQF_FN2 */ 2396e088dd4cSAlexander Motin error = (*NGI_FN2(item))(node, item, hook); 2397e088dd4cSAlexander Motin break; 2398069154d5SJulian Elischer } 2399069154d5SJulian Elischer /* 2400069154d5SJulian Elischer * We held references on some of the resources 2401069154d5SJulian Elischer * that we took from the item. Now that we have 2402069154d5SJulian Elischer * finished doing everything, drop those references. 2403069154d5SJulian Elischer */ 2404e72a98f4SAlexander Motin if (hook) 240530400f03SJulian Elischer NG_HOOK_UNREF(hook); 2406069154d5SJulian Elischer 2407f50597f5SAlexander Motin if (rw == NGQRW_R) 24089852972bSAlexander Motin ng_leave_read(node); 2409f50597f5SAlexander Motin else 24109852972bSAlexander Motin ng_leave_write(node); 24118afe16d5SGleb Smirnoff 24128afe16d5SGleb Smirnoff /* Apply callback. */ 241310e87318SAlexander Motin if (apply != NULL) { 241410e87318SAlexander Motin if (depth == 1 && error != 0) 241510e87318SAlexander Motin apply->error = error; 241610e87318SAlexander Motin if (refcount_release(&apply->refs)) 241710e87318SAlexander Motin (*apply->apply)(apply->context, apply->error); 241810e87318SAlexander Motin } 24198afe16d5SGleb Smirnoff 242027757487SGleb Smirnoff return (error); 2421069154d5SJulian Elischer } 2422069154d5SJulian Elischer 2423069154d5SJulian Elischer /*********************************************************************** 2424069154d5SJulian Elischer * Implement the 'generic' control messages 2425069154d5SJulian Elischer ***********************************************************************/ 2426069154d5SJulian Elischer static int 2427069154d5SJulian Elischer ng_generic_msg(node_p here, item_p item, hook_p lasthook) 24284cf49a43SJulian Elischer { 24294cf49a43SJulian Elischer int error = 0; 2430069154d5SJulian Elischer struct ng_mesg *msg; 2431069154d5SJulian Elischer struct ng_mesg *resp = NULL; 24324cf49a43SJulian Elischer 2433069154d5SJulian Elischer NGI_GET_MSG(item, msg); 24344cf49a43SJulian Elischer if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 24356b795970SJulian Elischer TRAP_ERROR(); 2436069154d5SJulian Elischer error = EINVAL; 2437069154d5SJulian Elischer goto out; 24384cf49a43SJulian Elischer } 24394cf49a43SJulian Elischer switch (msg->header.cmd) { 24404cf49a43SJulian Elischer case NGM_SHUTDOWN: 24411acb27c6SJulian Elischer ng_rmnode(here, NULL, NULL, 0); 24424cf49a43SJulian Elischer break; 24434cf49a43SJulian Elischer case NGM_MKPEER: 24444cf49a43SJulian Elischer { 24454cf49a43SJulian Elischer struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 24464cf49a43SJulian Elischer 24474cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*mkp)) { 24486b795970SJulian Elischer TRAP_ERROR(); 2449069154d5SJulian Elischer error = EINVAL; 2450069154d5SJulian Elischer break; 24514cf49a43SJulian Elischer } 24524cf49a43SJulian Elischer mkp->type[sizeof(mkp->type) - 1] = '\0'; 24534cf49a43SJulian Elischer mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 24544cf49a43SJulian Elischer mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 24554cf49a43SJulian Elischer error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 24564cf49a43SJulian Elischer break; 24574cf49a43SJulian Elischer } 24584cf49a43SJulian Elischer case NGM_CONNECT: 24594cf49a43SJulian Elischer { 24604cf49a43SJulian Elischer struct ngm_connect *const con = 24614cf49a43SJulian Elischer (struct ngm_connect *) msg->data; 24624cf49a43SJulian Elischer node_p node2; 24634cf49a43SJulian Elischer 24644cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*con)) { 24656b795970SJulian Elischer TRAP_ERROR(); 2466069154d5SJulian Elischer error = EINVAL; 2467069154d5SJulian Elischer break; 24684cf49a43SJulian Elischer } 24694cf49a43SJulian Elischer con->path[sizeof(con->path) - 1] = '\0'; 24704cf49a43SJulian Elischer con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 24714cf49a43SJulian Elischer con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 2472069154d5SJulian Elischer /* Don't forget we get a reference.. */ 2473069154d5SJulian Elischer error = ng_path2noderef(here, con->path, &node2, NULL); 24744cf49a43SJulian Elischer if (error) 24754cf49a43SJulian Elischer break; 2476e088dd4cSAlexander Motin error = ng_con_nodes(item, here, con->ourhook, 2477e088dd4cSAlexander Motin node2, con->peerhook); 247830400f03SJulian Elischer NG_NODE_UNREF(node2); 24794cf49a43SJulian Elischer break; 24804cf49a43SJulian Elischer } 24814cf49a43SJulian Elischer case NGM_NAME: 24824cf49a43SJulian Elischer { 24834cf49a43SJulian Elischer struct ngm_name *const nam = (struct ngm_name *) msg->data; 24844cf49a43SJulian Elischer 24854cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*nam)) { 24866b795970SJulian Elischer TRAP_ERROR(); 2487069154d5SJulian Elischer error = EINVAL; 2488069154d5SJulian Elischer break; 24894cf49a43SJulian Elischer } 24904cf49a43SJulian Elischer nam->name[sizeof(nam->name) - 1] = '\0'; 24914cf49a43SJulian Elischer error = ng_name_node(here, nam->name); 24924cf49a43SJulian Elischer break; 24934cf49a43SJulian Elischer } 24944cf49a43SJulian Elischer case NGM_RMHOOK: 24954cf49a43SJulian Elischer { 24964cf49a43SJulian Elischer struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 24974cf49a43SJulian Elischer hook_p hook; 24984cf49a43SJulian Elischer 24994cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*rmh)) { 25006b795970SJulian Elischer TRAP_ERROR(); 2501069154d5SJulian Elischer error = EINVAL; 2502069154d5SJulian Elischer break; 25034cf49a43SJulian Elischer } 25044cf49a43SJulian Elischer rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 2505899e9c4eSArchie Cobbs if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 25064cf49a43SJulian Elischer ng_destroy_hook(hook); 25074cf49a43SJulian Elischer break; 25084cf49a43SJulian Elischer } 25094cf49a43SJulian Elischer case NGM_NODEINFO: 25104cf49a43SJulian Elischer { 25114cf49a43SJulian Elischer struct nodeinfo *ni; 25124cf49a43SJulian Elischer 2513069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT); 25144cf49a43SJulian Elischer if (resp == NULL) { 25154cf49a43SJulian Elischer error = ENOMEM; 25164cf49a43SJulian Elischer break; 25174cf49a43SJulian Elischer } 25184cf49a43SJulian Elischer 25194cf49a43SJulian Elischer /* Fill in node info */ 2520069154d5SJulian Elischer ni = (struct nodeinfo *) resp->data; 252130400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 252287e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 252387e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2524dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 252530400f03SJulian Elischer ni->hooks = here->nd_numhooks; 25264cf49a43SJulian Elischer break; 25274cf49a43SJulian Elischer } 25284cf49a43SJulian Elischer case NGM_LISTHOOKS: 25294cf49a43SJulian Elischer { 253030400f03SJulian Elischer const int nhooks = here->nd_numhooks; 25314cf49a43SJulian Elischer struct hooklist *hl; 25324cf49a43SJulian Elischer struct nodeinfo *ni; 25334cf49a43SJulian Elischer hook_p hook; 25344cf49a43SJulian Elischer 25354cf49a43SJulian Elischer /* Get response struct */ 25364bd1b557SGleb Smirnoff NG_MKRESPONSE(resp, msg, sizeof(*hl) + 25374bd1b557SGleb Smirnoff (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 2538069154d5SJulian Elischer if (resp == NULL) { 25394cf49a43SJulian Elischer error = ENOMEM; 25404cf49a43SJulian Elischer break; 25414cf49a43SJulian Elischer } 2542069154d5SJulian Elischer hl = (struct hooklist *) resp->data; 25434cf49a43SJulian Elischer ni = &hl->nodeinfo; 25444cf49a43SJulian Elischer 25454cf49a43SJulian Elischer /* Fill in node info */ 254630400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 254787e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 254887e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2549dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 25504cf49a43SJulian Elischer 25514cf49a43SJulian Elischer /* Cycle through the linked list of hooks */ 25524cf49a43SJulian Elischer ni->hooks = 0; 255330400f03SJulian Elischer LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) { 25544cf49a43SJulian Elischer struct linkinfo *const link = &hl->link[ni->hooks]; 25554cf49a43SJulian Elischer 25564cf49a43SJulian Elischer if (ni->hooks >= nhooks) { 25574cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 25586e551fb6SDavid E. O'Brien __func__, "hooks"); 25594cf49a43SJulian Elischer break; 25604cf49a43SJulian Elischer } 256130400f03SJulian Elischer if (NG_HOOK_NOT_VALID(hook)) 25624cf49a43SJulian Elischer continue; 256387e2c66aSHartmut Brandt strcpy(link->ourhook, NG_HOOK_NAME(hook)); 256487e2c66aSHartmut Brandt strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook)); 256530400f03SJulian Elischer if (NG_PEER_NODE_NAME(hook)[0] != '\0') 256687e2c66aSHartmut Brandt strcpy(link->nodeinfo.name, 256787e2c66aSHartmut Brandt NG_PEER_NODE_NAME(hook)); 256887e2c66aSHartmut Brandt strcpy(link->nodeinfo.type, 256987e2c66aSHartmut Brandt NG_PEER_NODE(hook)->nd_type->name); 257030400f03SJulian Elischer link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook)); 257130400f03SJulian Elischer link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks; 25724cf49a43SJulian Elischer ni->hooks++; 25734cf49a43SJulian Elischer } 25744cf49a43SJulian Elischer break; 25754cf49a43SJulian Elischer } 25764cf49a43SJulian Elischer 25774cf49a43SJulian Elischer case NGM_LISTNAMES: 25784cf49a43SJulian Elischer case NGM_LISTNODES: 25794cf49a43SJulian Elischer { 25804cf49a43SJulian Elischer const int unnamed = (msg->header.cmd == NGM_LISTNODES); 25814cf49a43SJulian Elischer struct namelist *nl; 25824cf49a43SJulian Elischer node_p node; 2583cfea3f85SAlexander Motin int num = 0, i; 25844cf49a43SJulian Elischer 2585*c4282b74SGleb Smirnoff NAMEHASH_RLOCK(); 25864cf49a43SJulian Elischer /* Count number of nodes */ 2587cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2588603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2589cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 2590cfea3f85SAlexander Motin (unnamed || NG_NODE_HAS_NAME(node))) { 25914cf49a43SJulian Elischer num++; 25924cf49a43SJulian Elischer } 259370de87f2SJulian Elischer } 2594cfea3f85SAlexander Motin } 25954cf49a43SJulian Elischer 25964cf49a43SJulian Elischer /* Get response struct */ 25974bd1b557SGleb Smirnoff NG_MKRESPONSE(resp, msg, sizeof(*nl) + 25984bd1b557SGleb Smirnoff (num * sizeof(struct nodeinfo)), M_NOWAIT); 2599069154d5SJulian Elischer if (resp == NULL) { 2600*c4282b74SGleb Smirnoff NAMEHASH_RUNLOCK(); 26014cf49a43SJulian Elischer error = ENOMEM; 26024cf49a43SJulian Elischer break; 26034cf49a43SJulian Elischer } 2604069154d5SJulian Elischer nl = (struct namelist *) resp->data; 26054cf49a43SJulian Elischer 26064cf49a43SJulian Elischer /* Cycle through the linked list of nodes */ 26074cf49a43SJulian Elischer nl->numnames = 0; 2608cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2609603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2610cfea3f85SAlexander Motin struct nodeinfo *const np = 2611cfea3f85SAlexander Motin &nl->nodeinfo[nl->numnames]; 26124cf49a43SJulian Elischer 2613b96baf0aSGleb Smirnoff if (NG_NODE_NOT_VALID(node)) 2614b96baf0aSGleb Smirnoff continue; 2615b96baf0aSGleb Smirnoff if (!unnamed && (! NG_NODE_HAS_NAME(node))) 2616b96baf0aSGleb Smirnoff continue; 261730400f03SJulian Elischer if (NG_NODE_HAS_NAME(node)) 261887e2c66aSHartmut Brandt strcpy(np->name, NG_NODE_NAME(node)); 261987e2c66aSHartmut Brandt strcpy(np->type, node->nd_type->name); 2620dc90cad9SJulian Elischer np->id = ng_node2ID(node); 262130400f03SJulian Elischer np->hooks = node->nd_numhooks; 2622*c4282b74SGleb Smirnoff KASSERT(nl->numnames < num, ("%s: no space", 2623*c4282b74SGleb Smirnoff __func__)); 26244cf49a43SJulian Elischer nl->numnames++; 26254cf49a43SJulian Elischer } 2626cfea3f85SAlexander Motin } 2627*c4282b74SGleb Smirnoff NAMEHASH_RUNLOCK(); 26284cf49a43SJulian Elischer break; 26294cf49a43SJulian Elischer } 26304cf49a43SJulian Elischer 26314cf49a43SJulian Elischer case NGM_LISTTYPES: 26324cf49a43SJulian Elischer { 26334cf49a43SJulian Elischer struct typelist *tl; 26344cf49a43SJulian Elischer struct ng_type *type; 26354cf49a43SJulian Elischer int num = 0; 26364cf49a43SJulian Elischer 2637*c4282b74SGleb Smirnoff TYPELIST_RLOCK(); 26384cf49a43SJulian Elischer /* Count number of types */ 2639*c4282b74SGleb Smirnoff LIST_FOREACH(type, &ng_typelist, types) 26404cf49a43SJulian Elischer num++; 26414cf49a43SJulian Elischer 26424cf49a43SJulian Elischer /* Get response struct */ 26434bd1b557SGleb Smirnoff NG_MKRESPONSE(resp, msg, sizeof(*tl) + 26444bd1b557SGleb Smirnoff (num * sizeof(struct typeinfo)), M_NOWAIT); 2645069154d5SJulian Elischer if (resp == NULL) { 2646*c4282b74SGleb Smirnoff TYPELIST_RUNLOCK(); 26474cf49a43SJulian Elischer error = ENOMEM; 26484cf49a43SJulian Elischer break; 26494cf49a43SJulian Elischer } 2650069154d5SJulian Elischer tl = (struct typelist *) resp->data; 26514cf49a43SJulian Elischer 26524cf49a43SJulian Elischer /* Cycle through the linked list of types */ 26534cf49a43SJulian Elischer tl->numtypes = 0; 2654069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 26554cf49a43SJulian Elischer struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 26564cf49a43SJulian Elischer 265787e2c66aSHartmut Brandt strcpy(tp->type_name, type->name); 2658c73b94a2SJulian Elischer tp->numnodes = type->refs - 1; /* don't count list */ 2659*c4282b74SGleb Smirnoff KASSERT(tl->numtypes < num, ("%s: no space", __func__)); 26604cf49a43SJulian Elischer tl->numtypes++; 26614cf49a43SJulian Elischer } 2662*c4282b74SGleb Smirnoff TYPELIST_RUNLOCK(); 26634cf49a43SJulian Elischer break; 26644cf49a43SJulian Elischer } 26654cf49a43SJulian Elischer 2666f8307e12SArchie Cobbs case NGM_BINARY2ASCII: 2667f8307e12SArchie Cobbs { 26687133ac27SArchie Cobbs int bufSize = 20 * 1024; /* XXX hard coded constant */ 2669f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2670f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2671069154d5SJulian Elischer struct ng_mesg *binary, *ascii; 2672f8307e12SArchie Cobbs 2673f8307e12SArchie Cobbs /* Data area must contain a valid netgraph message */ 2674f8307e12SArchie Cobbs binary = (struct ng_mesg *)msg->data; 26754c9b5910SGleb Smirnoff if (msg->header.arglen < sizeof(struct ng_mesg) || 26764c9b5910SGleb Smirnoff (msg->header.arglen - sizeof(struct ng_mesg) < 26774c9b5910SGleb Smirnoff binary->header.arglen)) { 26786b795970SJulian Elischer TRAP_ERROR(); 2679f8307e12SArchie Cobbs error = EINVAL; 2680f8307e12SArchie Cobbs break; 2681f8307e12SArchie Cobbs } 2682f8307e12SArchie Cobbs 2683f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2684069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 2685069154d5SJulian Elischer if (resp == NULL) { 2686f8307e12SArchie Cobbs error = ENOMEM; 2687f8307e12SArchie Cobbs break; 2688f8307e12SArchie Cobbs } 2689069154d5SJulian Elischer ascii = (struct ng_mesg *)resp->data; 2690f8307e12SArchie Cobbs 2691f8307e12SArchie Cobbs /* Copy binary message header to response message payload */ 2692f8307e12SArchie Cobbs bcopy(binary, ascii, sizeof(*binary)); 2693f8307e12SArchie Cobbs 2694f8307e12SArchie Cobbs /* Find command by matching typecookie and command number */ 26954bd1b557SGleb Smirnoff for (c = here->nd_type->cmdlist; c != NULL && c->name != NULL; 26964bd1b557SGleb Smirnoff c++) { 26974bd1b557SGleb Smirnoff if (binary->header.typecookie == c->cookie && 26984bd1b557SGleb Smirnoff binary->header.cmd == c->cmd) 2699f8307e12SArchie Cobbs break; 2700f8307e12SArchie Cobbs } 2701f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2702f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 27034bd1b557SGleb Smirnoff if (binary->header.typecookie == c->cookie && 27044bd1b557SGleb Smirnoff binary->header.cmd == c->cmd) 2705f8307e12SArchie Cobbs break; 2706f8307e12SArchie Cobbs } 2707f8307e12SArchie Cobbs if (c->name == NULL) { 2708069154d5SJulian Elischer NG_FREE_MSG(resp); 2709f8307e12SArchie Cobbs error = ENOSYS; 2710f8307e12SArchie Cobbs break; 2711f8307e12SArchie Cobbs } 2712f8307e12SArchie Cobbs } 2713f8307e12SArchie Cobbs 2714f8307e12SArchie Cobbs /* Convert command name to ASCII */ 2715f8307e12SArchie Cobbs snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 2716f8307e12SArchie Cobbs "%s", c->name); 2717f8307e12SArchie Cobbs 2718f8307e12SArchie Cobbs /* Convert command arguments to ASCII */ 2719f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2720f8307e12SArchie Cobbs c->respType : c->mesgType; 272170de87f2SJulian Elischer if (argstype == NULL) { 2722f8307e12SArchie Cobbs *ascii->data = '\0'; 272370de87f2SJulian Elischer } else { 2724f8307e12SArchie Cobbs if ((error = ng_unparse(argstype, 2725f8307e12SArchie Cobbs (u_char *)binary->data, 2726f8307e12SArchie Cobbs ascii->data, bufSize)) != 0) { 2727069154d5SJulian Elischer NG_FREE_MSG(resp); 2728f8307e12SArchie Cobbs break; 2729f8307e12SArchie Cobbs } 2730f8307e12SArchie Cobbs } 2731f8307e12SArchie Cobbs 2732f8307e12SArchie Cobbs /* Return the result as struct ng_mesg plus ASCII string */ 2733f8307e12SArchie Cobbs bufSize = strlen(ascii->data) + 1; 2734f8307e12SArchie Cobbs ascii->header.arglen = bufSize; 2735069154d5SJulian Elischer resp->header.arglen = sizeof(*ascii) + bufSize; 2736f8307e12SArchie Cobbs break; 2737f8307e12SArchie Cobbs } 2738f8307e12SArchie Cobbs 2739f8307e12SArchie Cobbs case NGM_ASCII2BINARY: 2740f8307e12SArchie Cobbs { 274198a5a343SMarko Zec int bufSize = 20 * 1024; /* XXX hard coded constant */ 2742f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2743f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2744069154d5SJulian Elischer struct ng_mesg *ascii, *binary; 274552ec4a03SArchie Cobbs int off = 0; 2746f8307e12SArchie Cobbs 2747f8307e12SArchie Cobbs /* Data area must contain at least a struct ng_mesg + '\0' */ 2748f8307e12SArchie Cobbs ascii = (struct ng_mesg *)msg->data; 27494c9b5910SGleb Smirnoff if ((msg->header.arglen < sizeof(*ascii) + 1) || 27504c9b5910SGleb Smirnoff (ascii->header.arglen < 1) || 27514c9b5910SGleb Smirnoff (msg->header.arglen < sizeof(*ascii) + 27524c9b5910SGleb Smirnoff ascii->header.arglen)) { 27536b795970SJulian Elischer TRAP_ERROR(); 2754f8307e12SArchie Cobbs error = EINVAL; 2755f8307e12SArchie Cobbs break; 2756f8307e12SArchie Cobbs } 2757f8307e12SArchie Cobbs ascii->data[ascii->header.arglen - 1] = '\0'; 2758f8307e12SArchie Cobbs 2759f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2760069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 2761069154d5SJulian Elischer if (resp == NULL) { 2762f8307e12SArchie Cobbs error = ENOMEM; 2763f8307e12SArchie Cobbs break; 2764f8307e12SArchie Cobbs } 2765069154d5SJulian Elischer binary = (struct ng_mesg *)resp->data; 2766f8307e12SArchie Cobbs 2767f8307e12SArchie Cobbs /* Copy ASCII message header to response message payload */ 2768f8307e12SArchie Cobbs bcopy(ascii, binary, sizeof(*ascii)); 2769f8307e12SArchie Cobbs 2770f8307e12SArchie Cobbs /* Find command by matching ASCII command string */ 277130400f03SJulian Elischer for (c = here->nd_type->cmdlist; 2772f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 2773f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2774f8307e12SArchie Cobbs break; 2775f8307e12SArchie Cobbs } 2776f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2777f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 2778f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2779f8307e12SArchie Cobbs break; 2780f8307e12SArchie Cobbs } 2781f8307e12SArchie Cobbs if (c->name == NULL) { 2782069154d5SJulian Elischer NG_FREE_MSG(resp); 2783f8307e12SArchie Cobbs error = ENOSYS; 2784f8307e12SArchie Cobbs break; 2785f8307e12SArchie Cobbs } 2786f8307e12SArchie Cobbs } 2787f8307e12SArchie Cobbs 2788f8307e12SArchie Cobbs /* Convert command name to binary */ 2789f8307e12SArchie Cobbs binary->header.cmd = c->cmd; 2790f8307e12SArchie Cobbs binary->header.typecookie = c->cookie; 2791f8307e12SArchie Cobbs 2792f8307e12SArchie Cobbs /* Convert command arguments to binary */ 2793f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2794f8307e12SArchie Cobbs c->respType : c->mesgType; 279570de87f2SJulian Elischer if (argstype == NULL) { 2796f8307e12SArchie Cobbs bufSize = 0; 279770de87f2SJulian Elischer } else { 27984bd1b557SGleb Smirnoff if ((error = ng_parse(argstype, ascii->data, &off, 27994bd1b557SGleb Smirnoff (u_char *)binary->data, &bufSize)) != 0) { 2800069154d5SJulian Elischer NG_FREE_MSG(resp); 2801f8307e12SArchie Cobbs break; 2802f8307e12SArchie Cobbs } 2803f8307e12SArchie Cobbs } 2804f8307e12SArchie Cobbs 2805f8307e12SArchie Cobbs /* Return the result */ 2806f8307e12SArchie Cobbs binary->header.arglen = bufSize; 2807069154d5SJulian Elischer resp->header.arglen = sizeof(*binary) + bufSize; 2808f8307e12SArchie Cobbs break; 2809f8307e12SArchie Cobbs } 2810f8307e12SArchie Cobbs 28117095e097SPoul-Henning Kamp case NGM_TEXT_CONFIG: 28124cf49a43SJulian Elischer case NGM_TEXT_STATUS: 28134cf49a43SJulian Elischer /* 28144cf49a43SJulian Elischer * This one is tricky as it passes the command down to the 28154cf49a43SJulian Elischer * actual node, even though it is a generic type command. 2816069154d5SJulian Elischer * This means we must assume that the item/msg is already freed 28174cf49a43SJulian Elischer * when control passes back to us. 28184cf49a43SJulian Elischer */ 281930400f03SJulian Elischer if (here->nd_type->rcvmsg != NULL) { 2820069154d5SJulian Elischer NGI_MSG(item) = msg; /* put it back as we found it */ 282130400f03SJulian Elischer return((*here->nd_type->rcvmsg)(here, item, lasthook)); 28224cf49a43SJulian Elischer } 28234cf49a43SJulian Elischer /* Fall through if rcvmsg not supported */ 28244cf49a43SJulian Elischer default: 28256b795970SJulian Elischer TRAP_ERROR(); 28264cf49a43SJulian Elischer error = EINVAL; 28274cf49a43SJulian Elischer } 2828069154d5SJulian Elischer /* 2829069154d5SJulian Elischer * Sometimes a generic message may be statically allocated 28304bd1b557SGleb Smirnoff * to avoid problems with allocating when in tight memory situations. 2831069154d5SJulian Elischer * Don't free it if it is so. 2832069154d5SJulian Elischer * I break them appart here, because erros may cause a free if the item 2833069154d5SJulian Elischer * in which case we'd be doing it twice. 2834069154d5SJulian Elischer * they are kept together above, to simplify freeing. 2835069154d5SJulian Elischer */ 2836069154d5SJulian Elischer out: 2837069154d5SJulian Elischer NG_RESPOND_MSG(error, here, item, resp); 2838069154d5SJulian Elischer NG_FREE_MSG(msg); 28394cf49a43SJulian Elischer return (error); 28404cf49a43SJulian Elischer } 28414cf49a43SJulian Elischer 28424cf49a43SJulian Elischer /************************************************************************ 28438253c060SGleb Smirnoff Queue element get/free routines 28448253c060SGleb Smirnoff ************************************************************************/ 28458253c060SGleb Smirnoff 28468253c060SGleb Smirnoff uma_zone_t ng_qzone; 28476aa6d011SAlexander Motin uma_zone_t ng_qdzone; 2848f2fbb838SAlexander Motin static int numthreads = 0; /* number of queue threads */ 2849ed75521fSAlexander Motin static int maxalloc = 4096;/* limit the damage of a leak */ 2850ed75521fSAlexander Motin static int maxdata = 512; /* limit the damage of a DoS */ 28518253c060SGleb Smirnoff 2852f2fbb838SAlexander Motin TUNABLE_INT("net.graph.threads", &numthreads); 2853f2fbb838SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, threads, CTLFLAG_RDTUN, &numthreads, 2854f2fbb838SAlexander Motin 0, "Number of queue processing threads"); 28558253c060SGleb Smirnoff TUNABLE_INT("net.graph.maxalloc", &maxalloc); 28568253c060SGleb Smirnoff SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 28576aa6d011SAlexander Motin 0, "Maximum number of non-data queue items to allocate"); 2858ed75521fSAlexander Motin TUNABLE_INT("net.graph.maxdata", &maxdata); 28596aa6d011SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, maxdata, CTLFLAG_RDTUN, &maxdata, 28606aa6d011SAlexander Motin 0, "Maximum number of data queue items to allocate"); 28618253c060SGleb Smirnoff 28628253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 28638253c060SGleb Smirnoff static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist); 28648253c060SGleb Smirnoff static int allocated; /* number of items malloc'd */ 28658253c060SGleb Smirnoff #endif 28668253c060SGleb Smirnoff 28678253c060SGleb Smirnoff /* 28688253c060SGleb Smirnoff * Get a queue entry. 28698253c060SGleb Smirnoff * This is usually called when a packet first enters netgraph. 28708253c060SGleb Smirnoff * By definition, this is usually from an interrupt, or from a user. 28718253c060SGleb Smirnoff * Users are not so important, but try be quick for the times that it's 28728253c060SGleb Smirnoff * an interrupt. 28738253c060SGleb Smirnoff */ 28748253c060SGleb Smirnoff static __inline item_p 28756aa6d011SAlexander Motin ng_alloc_item(int type, int flags) 28768253c060SGleb Smirnoff { 28776aa6d011SAlexander Motin item_p item; 28788253c060SGleb Smirnoff 28796aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 28806aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 288142282202SGleb Smirnoff 28826aa6d011SAlexander Motin item = uma_zalloc((type == NGQF_DATA) ? ng_qdzone : ng_qzone, 28836aa6d011SAlexander Motin ((flags & NG_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO); 28848253c060SGleb Smirnoff 28858253c060SGleb Smirnoff if (item) { 28866aa6d011SAlexander Motin item->el_flags = type; 28876aa6d011SAlexander Motin #ifdef NETGRAPH_DEBUG 28888253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 28898253c060SGleb Smirnoff TAILQ_INSERT_TAIL(&ng_itemlist, item, all); 28908253c060SGleb Smirnoff allocated++; 28918253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 28928253c060SGleb Smirnoff #endif 28936aa6d011SAlexander Motin } 28948253c060SGleb Smirnoff 28958253c060SGleb Smirnoff return (item); 28968253c060SGleb Smirnoff } 28978253c060SGleb Smirnoff 28988253c060SGleb Smirnoff /* 28998253c060SGleb Smirnoff * Release a queue entry 29008253c060SGleb Smirnoff */ 29018253c060SGleb Smirnoff void 29028253c060SGleb Smirnoff ng_free_item(item_p item) 29038253c060SGleb Smirnoff { 29048253c060SGleb Smirnoff /* 29058253c060SGleb Smirnoff * The item may hold resources on it's own. We need to free 29068253c060SGleb Smirnoff * these before we can free the item. What they are depends upon 29078253c060SGleb Smirnoff * what kind of item it is. it is important that nodes zero 29088253c060SGleb Smirnoff * out pointers to resources that they remove from the item 29098253c060SGleb Smirnoff * or we release them again here. 29108253c060SGleb Smirnoff */ 29118253c060SGleb Smirnoff switch (item->el_flags & NGQF_TYPE) { 29128253c060SGleb Smirnoff case NGQF_DATA: 29138253c060SGleb Smirnoff /* If we have an mbuf still attached.. */ 29148253c060SGleb Smirnoff NG_FREE_M(_NGI_M(item)); 29158253c060SGleb Smirnoff break; 29168253c060SGleb Smirnoff case NGQF_MESG: 29178253c060SGleb Smirnoff _NGI_RETADDR(item) = 0; 29188253c060SGleb Smirnoff NG_FREE_MSG(_NGI_MSG(item)); 29198253c060SGleb Smirnoff break; 29208253c060SGleb Smirnoff case NGQF_FN: 2921e088dd4cSAlexander Motin case NGQF_FN2: 29228253c060SGleb Smirnoff /* nothing to free really, */ 29238253c060SGleb Smirnoff _NGI_FN(item) = NULL; 29248253c060SGleb Smirnoff _NGI_ARG1(item) = NULL; 29258253c060SGleb Smirnoff _NGI_ARG2(item) = 0; 29268253c060SGleb Smirnoff break; 29278253c060SGleb Smirnoff } 29288253c060SGleb Smirnoff /* If we still have a node or hook referenced... */ 29298253c060SGleb Smirnoff _NGI_CLR_NODE(item); 29308253c060SGleb Smirnoff _NGI_CLR_HOOK(item); 29318253c060SGleb Smirnoff 29328253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 29338253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 29348253c060SGleb Smirnoff TAILQ_REMOVE(&ng_itemlist, item, all); 29358253c060SGleb Smirnoff allocated--; 29368253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 29378253c060SGleb Smirnoff #endif 29386aa6d011SAlexander Motin uma_zfree(((item->el_flags & NGQF_TYPE) == NGQF_DATA) ? 29396aa6d011SAlexander Motin ng_qdzone : ng_qzone, item); 29406aa6d011SAlexander Motin } 29416aa6d011SAlexander Motin 29426aa6d011SAlexander Motin /* 29436aa6d011SAlexander Motin * Change type of the queue entry. 29446aa6d011SAlexander Motin * Possibly reallocates it from another UMA zone. 29456aa6d011SAlexander Motin */ 29466aa6d011SAlexander Motin static __inline item_p 29476aa6d011SAlexander Motin ng_realloc_item(item_p pitem, int type, int flags) 29486aa6d011SAlexander Motin { 29496aa6d011SAlexander Motin item_p item; 29506aa6d011SAlexander Motin int from, to; 29516aa6d011SAlexander Motin 29526aa6d011SAlexander Motin KASSERT((pitem != NULL), ("%s: can't reallocate NULL", __func__)); 29536aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 29546aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 29556aa6d011SAlexander Motin 29566aa6d011SAlexander Motin from = ((pitem->el_flags & NGQF_TYPE) == NGQF_DATA); 29576aa6d011SAlexander Motin to = (type == NGQF_DATA); 29586aa6d011SAlexander Motin if (from != to) { 29596aa6d011SAlexander Motin /* If reallocation is required do it and copy item. */ 29606aa6d011SAlexander Motin if ((item = ng_alloc_item(type, flags)) == NULL) { 29616aa6d011SAlexander Motin ng_free_item(pitem); 29626aa6d011SAlexander Motin return (NULL); 29636aa6d011SAlexander Motin } 29646aa6d011SAlexander Motin *item = *pitem; 29656aa6d011SAlexander Motin ng_free_item(pitem); 29666aa6d011SAlexander Motin } else 29676aa6d011SAlexander Motin item = pitem; 29686aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_TYPE) | type; 29696aa6d011SAlexander Motin 29706aa6d011SAlexander Motin return (item); 29718253c060SGleb Smirnoff } 29728253c060SGleb Smirnoff 29738253c060SGleb Smirnoff /************************************************************************ 29744cf49a43SJulian Elischer Module routines 29754cf49a43SJulian Elischer ************************************************************************/ 29764cf49a43SJulian Elischer 29774cf49a43SJulian Elischer /* 29784cf49a43SJulian Elischer * Handle the loading/unloading of a netgraph node type module 29794cf49a43SJulian Elischer */ 29804cf49a43SJulian Elischer int 29814cf49a43SJulian Elischer ng_mod_event(module_t mod, int event, void *data) 29824cf49a43SJulian Elischer { 29834cf49a43SJulian Elischer struct ng_type *const type = data; 29844bd1b557SGleb Smirnoff int error = 0; 29854cf49a43SJulian Elischer 29864cf49a43SJulian Elischer switch (event) { 29874cf49a43SJulian Elischer case MOD_LOAD: 29884cf49a43SJulian Elischer 29894cf49a43SJulian Elischer /* Register new netgraph node type */ 29904bd1b557SGleb Smirnoff if ((error = ng_newtype(type)) != 0) 29914cf49a43SJulian Elischer break; 29924cf49a43SJulian Elischer 29934cf49a43SJulian Elischer /* Call type specific code */ 29944cf49a43SJulian Elischer if (type->mod_event != NULL) 2995069154d5SJulian Elischer if ((error = (*type->mod_event)(mod, event, data))) { 2996*c4282b74SGleb Smirnoff TYPELIST_WLOCK(); 2997c73b94a2SJulian Elischer type->refs--; /* undo it */ 29984cf49a43SJulian Elischer LIST_REMOVE(type, types); 2999*c4282b74SGleb Smirnoff TYPELIST_WUNLOCK(); 3000069154d5SJulian Elischer } 30014cf49a43SJulian Elischer break; 30024cf49a43SJulian Elischer 30034cf49a43SJulian Elischer case MOD_UNLOAD: 3004c73b94a2SJulian Elischer if (type->refs > 1) { /* make sure no nodes exist! */ 30054cf49a43SJulian Elischer error = EBUSY; 3006c73b94a2SJulian Elischer } else { 30074bd1b557SGleb Smirnoff if (type->refs == 0) /* failed load, nothing to undo */ 3008c73b94a2SJulian Elischer break; 30094cf49a43SJulian Elischer if (type->mod_event != NULL) { /* check with type */ 30104cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30114bd1b557SGleb Smirnoff if (error != 0) /* type refuses.. */ 30124cf49a43SJulian Elischer break; 30134cf49a43SJulian Elischer } 3014*c4282b74SGleb Smirnoff TYPELIST_WLOCK(); 30154cf49a43SJulian Elischer LIST_REMOVE(type, types); 3016*c4282b74SGleb Smirnoff TYPELIST_WUNLOCK(); 30174cf49a43SJulian Elischer } 30184cf49a43SJulian Elischer break; 30194cf49a43SJulian Elischer 30204cf49a43SJulian Elischer default: 30214cf49a43SJulian Elischer if (type->mod_event != NULL) 30224cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30234cf49a43SJulian Elischer else 30243e019deaSPoul-Henning Kamp error = EOPNOTSUPP; /* XXX ? */ 30254cf49a43SJulian Elischer break; 30264cf49a43SJulian Elischer } 30274cf49a43SJulian Elischer return (error); 30284cf49a43SJulian Elischer } 30294cf49a43SJulian Elischer 3030eddfbb76SRobert Watson #ifdef VIMAGE 3031d0728d71SRobert Watson static void 3032d0728d71SRobert Watson vnet_netgraph_uninit(const void *unused __unused) 3033bc29160dSMarko Zec { 3034a3f93b72SMarko Zec node_p node = NULL, last_killed = NULL; 3035a3f93b72SMarko Zec int i; 3036bc29160dSMarko Zec 3037a3f93b72SMarko Zec do { 3038a3f93b72SMarko Zec /* Find a node to kill */ 3039*c4282b74SGleb Smirnoff NAMEHASH_RLOCK(); 3040a3f93b72SMarko Zec for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 3041a3f93b72SMarko Zec LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 3042a3f93b72SMarko Zec if (node != &ng_deadnode) { 3043a3f93b72SMarko Zec NG_NODE_REF(node); 3044a3f93b72SMarko Zec break; 3045a3f93b72SMarko Zec } 3046a3f93b72SMarko Zec } 3047a3f93b72SMarko Zec if (node != NULL) 3048a3f93b72SMarko Zec break; 3049a3f93b72SMarko Zec } 3050*c4282b74SGleb Smirnoff NAMEHASH_RUNLOCK(); 3051a3f93b72SMarko Zec 3052a3f93b72SMarko Zec /* Attempt to kill it only if it is a regular node */ 3053a3f93b72SMarko Zec if (node != NULL) { 3054bc29160dSMarko Zec if (node == last_killed) { 3055bc29160dSMarko Zec /* This should never happen */ 30564bd1b557SGleb Smirnoff printf("ng node %s needs NGF_REALLY_DIE\n", 30574bd1b557SGleb Smirnoff node->nd_name); 3058a3f93b72SMarko Zec if (node->nd_flags & NGF_REALLY_DIE) 3059a3f93b72SMarko Zec panic("ng node %s won't die", 3060a3f93b72SMarko Zec node->nd_name); 3061bc29160dSMarko Zec node->nd_flags |= NGF_REALLY_DIE; 3062bc29160dSMarko Zec } 3063bc29160dSMarko Zec ng_rmnode(node, NULL, NULL, 0); 3064a3f93b72SMarko Zec NG_NODE_UNREF(node); 3065bc29160dSMarko Zec last_killed = node; 3066bc29160dSMarko Zec } 3067a3f93b72SMarko Zec } while (node != NULL); 3068bc29160dSMarko Zec } 3069a3f93b72SMarko Zec VNET_SYSUNINIT(vnet_netgraph_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 3070d0728d71SRobert Watson vnet_netgraph_uninit, NULL); 3071bc29160dSMarko Zec #endif /* VIMAGE */ 3072bc29160dSMarko Zec 30734cf49a43SJulian Elischer /* 30744cf49a43SJulian Elischer * Handle loading and unloading for this code. 30754cf49a43SJulian Elischer * The only thing we need to link into is the NETISR strucure. 30764cf49a43SJulian Elischer */ 30774cf49a43SJulian Elischer static int 30784cf49a43SJulian Elischer ngb_mod_event(module_t mod, int event, void *data) 30794cf49a43SJulian Elischer { 3080f2fbb838SAlexander Motin struct proc *p; 3081f2fbb838SAlexander Motin struct thread *td; 3082f2fbb838SAlexander Motin int i, error = 0; 30834cf49a43SJulian Elischer 30844cf49a43SJulian Elischer switch (event) { 30854cf49a43SJulian Elischer case MOD_LOAD: 30861489164fSGleb Smirnoff /* Initialize everything. */ 30872c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK_INIT(); 3088*c4282b74SGleb Smirnoff rw_init(&ng_typelist_lock, "netgraph types"); 3089*c4282b74SGleb Smirnoff rw_init(&ng_idhash_lock, "netgraph idhash"); 3090*c4282b74SGleb Smirnoff rw_init(&ng_namehash_lock, "netgraph namehash"); 3091ac5dd141SGleb Smirnoff mtx_init(&ng_topo_mtx, "netgraph topology mutex", NULL, 3092ac5dd141SGleb Smirnoff MTX_DEF); 30931489164fSGleb Smirnoff #ifdef NETGRAPH_DEBUG 3094cfea3f85SAlexander Motin mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL, 3095cfea3f85SAlexander Motin MTX_DEF); 30961489164fSGleb Smirnoff mtx_init(&ngq_mtx, "netgraph item list mutex", NULL, 3097efd8e7c9SDon Lewis MTX_DEF); 30981489164fSGleb Smirnoff #endif 30991489164fSGleb Smirnoff ng_qzone = uma_zcreate("NetGraph items", sizeof(struct ng_item), 31001489164fSGleb Smirnoff NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 31011489164fSGleb Smirnoff uma_zone_set_max(ng_qzone, maxalloc); 31024bd1b557SGleb Smirnoff ng_qdzone = uma_zcreate("NetGraph data items", 31034bd1b557SGleb Smirnoff sizeof(struct ng_item), NULL, NULL, NULL, NULL, 31044bd1b557SGleb Smirnoff UMA_ALIGN_CACHE, 0); 31056aa6d011SAlexander Motin uma_zone_set_max(ng_qdzone, maxdata); 3106f2fbb838SAlexander Motin /* Autoconfigure number of threads. */ 3107f2fbb838SAlexander Motin if (numthreads <= 0) 3108f2fbb838SAlexander Motin numthreads = mp_ncpus; 3109f2fbb838SAlexander Motin /* Create threads. */ 3110f2fbb838SAlexander Motin p = NULL; /* start with no process */ 3111f2fbb838SAlexander Motin for (i = 0; i < numthreads; i++) { 3112f2fbb838SAlexander Motin if (kproc_kthread_add(ngthread, NULL, &p, &td, 3113f2fbb838SAlexander Motin RFHIGHPID, 0, "ng_queue", "ng_queue%d", i)) { 3114f2fbb838SAlexander Motin numthreads = i; 3115f2fbb838SAlexander Motin break; 3116f2fbb838SAlexander Motin } 3117f2fbb838SAlexander Motin } 31184cf49a43SJulian Elischer break; 31194cf49a43SJulian Elischer case MOD_UNLOAD: 312064efc707SRobert Watson /* You can't unload it because an interface may be using it. */ 31214cf49a43SJulian Elischer error = EBUSY; 31224cf49a43SJulian Elischer break; 31234cf49a43SJulian Elischer default: 31244cf49a43SJulian Elischer error = EOPNOTSUPP; 31254cf49a43SJulian Elischer break; 31264cf49a43SJulian Elischer } 31274cf49a43SJulian Elischer return (error); 31284cf49a43SJulian Elischer } 31294cf49a43SJulian Elischer 31304cf49a43SJulian Elischer static moduledata_t netgraph_mod = { 31314cf49a43SJulian Elischer "netgraph", 31324cf49a43SJulian Elischer ngb_mod_event, 31334cf49a43SJulian Elischer (NULL) 31344cf49a43SJulian Elischer }; 3135aa38f8f9SMaksim Yevmenkin DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_NETGRAPH, SI_ORDER_MIDDLE); 3136bfa7e882SJulian Elischer SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 3137bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 3138bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 31394cf49a43SJulian Elischer 314030400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 314130400f03SJulian Elischer void 314230400f03SJulian Elischer dumphook (hook_p hook, char *file, int line) 314330400f03SJulian Elischer { 314430400f03SJulian Elischer printf("hook: name %s, %d refs, Last touched:\n", 314530400f03SJulian Elischer _NG_HOOK_NAME(hook), hook->hk_refs); 314630400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 314730400f03SJulian Elischer hook->lastfile, hook->lastline); 314830400f03SJulian Elischer if (line) { 314930400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 3150e5fe87b3SGleb Smirnoff #ifdef KDB 3151e5fe87b3SGleb Smirnoff kdb_backtrace(); 3152e5fe87b3SGleb Smirnoff #endif 315330400f03SJulian Elischer } 315430400f03SJulian Elischer } 315530400f03SJulian Elischer 315630400f03SJulian Elischer void 315730400f03SJulian Elischer dumpnode(node_p node, char *file, int line) 315830400f03SJulian Elischer { 315930400f03SJulian Elischer printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n", 31606b795970SJulian Elischer _NG_NODE_ID(node), node->nd_type->name, 316130400f03SJulian Elischer node->nd_numhooks, node->nd_flags, 316230400f03SJulian Elischer node->nd_refs, node->nd_name); 316330400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 316430400f03SJulian Elischer node->lastfile, node->lastline); 316530400f03SJulian Elischer if (line) { 316630400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 3167e5fe87b3SGleb Smirnoff #ifdef KDB 3168e5fe87b3SGleb Smirnoff kdb_backtrace(); 3169e5fe87b3SGleb Smirnoff #endif 317030400f03SJulian Elischer } 317130400f03SJulian Elischer } 317230400f03SJulian Elischer 3173069154d5SJulian Elischer void 3174069154d5SJulian Elischer dumpitem(item_p item, char *file, int line) 3175069154d5SJulian Elischer { 3176069154d5SJulian Elischer printf(" ACTIVE item, last used at %s, line %d", 3177069154d5SJulian Elischer item->lastfile, item->lastline); 31786b795970SJulian Elischer switch(item->el_flags & NGQF_TYPE) { 31796b795970SJulian Elischer case NGQF_DATA: 3180069154d5SJulian Elischer printf(" - [data]\n"); 31816b795970SJulian Elischer break; 31826b795970SJulian Elischer case NGQF_MESG: 31836b795970SJulian Elischer printf(" - retaddr[%d]:\n", _NGI_RETADDR(item)); 31846b795970SJulian Elischer break; 31856b795970SJulian Elischer case NGQF_FN: 3186857304e6SRuslan Ermilov printf(" - fn@%p (%p, %p, %p, %d (%x))\n", 3187857304e6SRuslan Ermilov _NGI_FN(item), 3188857304e6SRuslan Ermilov _NGI_NODE(item), 3189857304e6SRuslan Ermilov _NGI_HOOK(item), 3190857304e6SRuslan Ermilov item->body.fn.fn_arg1, 3191857304e6SRuslan Ermilov item->body.fn.fn_arg2, 3192857304e6SRuslan Ermilov item->body.fn.fn_arg2); 3193857304e6SRuslan Ermilov break; 3194e088dd4cSAlexander Motin case NGQF_FN2: 3195eb4687d2SAlexander Motin printf(" - fn2@%p (%p, %p, %p, %d (%x))\n", 3196857304e6SRuslan Ermilov _NGI_FN2(item), 31976064e568SGleb Smirnoff _NGI_NODE(item), 31986064e568SGleb Smirnoff _NGI_HOOK(item), 31996b795970SJulian Elischer item->body.fn.fn_arg1, 32006b795970SJulian Elischer item->body.fn.fn_arg2, 32016b795970SJulian Elischer item->body.fn.fn_arg2); 32026b795970SJulian Elischer break; 3203069154d5SJulian Elischer } 320430400f03SJulian Elischer if (line) { 3205069154d5SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 32066064e568SGleb Smirnoff if (_NGI_NODE(item)) { 320730400f03SJulian Elischer printf("node %p ([%x])\n", 32086064e568SGleb Smirnoff _NGI_NODE(item), ng_node2ID(_NGI_NODE(item))); 3209069154d5SJulian Elischer } 321030400f03SJulian Elischer } 321130400f03SJulian Elischer } 321230400f03SJulian Elischer 321330400f03SJulian Elischer static void 321430400f03SJulian Elischer ng_dumpitems(void) 321530400f03SJulian Elischer { 321630400f03SJulian Elischer item_p item; 321730400f03SJulian Elischer int i = 1; 321830400f03SJulian Elischer TAILQ_FOREACH(item, &ng_itemlist, all) { 321930400f03SJulian Elischer printf("[%d] ", i++); 322030400f03SJulian Elischer dumpitem(item, NULL, 0); 322130400f03SJulian Elischer } 322230400f03SJulian Elischer } 322330400f03SJulian Elischer 322430400f03SJulian Elischer static void 322530400f03SJulian Elischer ng_dumpnodes(void) 322630400f03SJulian Elischer { 322730400f03SJulian Elischer node_p node; 322830400f03SJulian Elischer int i = 1; 322953f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 323030400f03SJulian Elischer SLIST_FOREACH(node, &ng_allnodes, nd_all) { 323130400f03SJulian Elischer printf("[%d] ", i++); 323230400f03SJulian Elischer dumpnode(node, NULL, 0); 323330400f03SJulian Elischer } 323453f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 323530400f03SJulian Elischer } 323630400f03SJulian Elischer 323730400f03SJulian Elischer static void 323830400f03SJulian Elischer ng_dumphooks(void) 323930400f03SJulian Elischer { 324030400f03SJulian Elischer hook_p hook; 324130400f03SJulian Elischer int i = 1; 324253f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 324330400f03SJulian Elischer SLIST_FOREACH(hook, &ng_allhooks, hk_all) { 324430400f03SJulian Elischer printf("[%d] ", i++); 324530400f03SJulian Elischer dumphook(hook, NULL, 0); 324630400f03SJulian Elischer } 324753f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 324830400f03SJulian Elischer } 3249069154d5SJulian Elischer 3250069154d5SJulian Elischer static int 3251069154d5SJulian Elischer sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS) 3252069154d5SJulian Elischer { 3253069154d5SJulian Elischer int error; 3254069154d5SJulian Elischer int val; 3255069154d5SJulian Elischer int i; 3256069154d5SJulian Elischer 3257069154d5SJulian Elischer val = allocated; 3258069154d5SJulian Elischer i = 1; 3259041b706bSDavid Malone error = sysctl_handle_int(oidp, &val, 0, req); 32606b795970SJulian Elischer if (error != 0 || req->newptr == NULL) 32616b795970SJulian Elischer return (error); 32626b795970SJulian Elischer if (val == 42) { 326330400f03SJulian Elischer ng_dumpitems(); 326430400f03SJulian Elischer ng_dumpnodes(); 326530400f03SJulian Elischer ng_dumphooks(); 3266069154d5SJulian Elischer } 32676b795970SJulian Elischer return (0); 3268069154d5SJulian Elischer } 3269069154d5SJulian Elischer 32706b795970SJulian Elischer SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, 32716b795970SJulian Elischer 0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items"); 327230400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 3273069154d5SJulian Elischer 3274069154d5SJulian Elischer 3275069154d5SJulian Elischer /*********************************************************************** 3276069154d5SJulian Elischer * Worklist routines 3277069154d5SJulian Elischer **********************************************************************/ 3278069154d5SJulian Elischer /* 3279069154d5SJulian Elischer * Pick a node off the list of nodes with work, 3280f2fbb838SAlexander Motin * try get an item to process off it. Remove the node from the list. 3281069154d5SJulian Elischer */ 3282069154d5SJulian Elischer static void 3283f2fbb838SAlexander Motin ngthread(void *arg) 3284069154d5SJulian Elischer { 3285069154d5SJulian Elischer for (;;) { 3286394cb30aSAlexander Motin node_p node; 3287394cb30aSAlexander Motin 3288394cb30aSAlexander Motin /* Get node from the worklist. */ 32892c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 3290f2fbb838SAlexander Motin while ((node = STAILQ_FIRST(&ng_worklist)) == NULL) 3291f2fbb838SAlexander Motin NG_WORKLIST_SLEEP(); 32929852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work); 32932c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 3294bc29160dSMarko Zec CURVNET_SET(node->nd_vnet); 32952955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist", 32962955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3297069154d5SJulian Elischer /* 3298069154d5SJulian Elischer * We have the node. We also take over the reference 3299069154d5SJulian Elischer * that the list had on it. 3300069154d5SJulian Elischer * Now process as much as you can, until it won't 3301069154d5SJulian Elischer * let you have another item off the queue. 3302069154d5SJulian Elischer * All this time, keep the reference 3303069154d5SJulian Elischer * that lets us be sure that the node still exists. 3304069154d5SJulian Elischer * Let the reference go at the last minute. 3305069154d5SJulian Elischer */ 3306069154d5SJulian Elischer for (;;) { 3307394cb30aSAlexander Motin item_p item; 3308714fb865SGleb Smirnoff int rw; 3309714fb865SGleb Smirnoff 33102c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(&node->nd_input_queue); 33119852972bSAlexander Motin item = ng_dequeue(node, &rw); 3312069154d5SJulian Elischer if (item == NULL) { 33139852972bSAlexander Motin node->nd_input_queue.q_flags2 &= ~NGQ2_WORKQ; 33142c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 3315069154d5SJulian Elischer break; /* go look for another node */ 3316069154d5SJulian Elischer } else { 33172c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 33185951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 3319714fb865SGleb Smirnoff ng_apply_item(node, item, rw); 33205951069aSJulian Elischer NG_NODE_UNREF(node); 3321069154d5SJulian Elischer } 3322069154d5SJulian Elischer } 3323a96dcd84SJulian Elischer NG_NODE_UNREF(node); 3324bc29160dSMarko Zec CURVNET_RESTORE(); 3325069154d5SJulian Elischer } 3326069154d5SJulian Elischer } 3327069154d5SJulian Elischer 332833338e73SJulian Elischer /* 332933338e73SJulian Elischer * XXX 333033338e73SJulian Elischer * It's posible that a debugging NG_NODE_REF may need 333133338e73SJulian Elischer * to be outside the mutex zone 333233338e73SJulian Elischer */ 3333069154d5SJulian Elischer static void 3334394cb30aSAlexander Motin ng_worklist_add(node_p node) 3335069154d5SJulian Elischer { 3336f912c0f7SGleb Smirnoff 33375bc15201SGleb Smirnoff mtx_assert(&node->nd_input_queue.q_mtx, MA_OWNED); 3338f912c0f7SGleb Smirnoff 33399852972bSAlexander Motin if ((node->nd_input_queue.q_flags2 & NGQ2_WORKQ) == 0) { 3340069154d5SJulian Elischer /* 3341069154d5SJulian Elischer * If we are not already on the work queue, 3342069154d5SJulian Elischer * then put us on. 3343069154d5SJulian Elischer */ 33449852972bSAlexander Motin node->nd_input_queue.q_flags2 |= NGQ2_WORKQ; 33454bd1b557SGleb Smirnoff NG_NODE_REF(node); /* XXX safe in mutex? */ 33462c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 33479852972bSAlexander Motin STAILQ_INSERT_TAIL(&ng_worklist, node, nd_input_queue.q_work); 33482c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 33492955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__, 33502955ee18SGleb Smirnoff node->nd_ID, node); 3351f2fbb838SAlexander Motin NG_WORKLIST_WAKEUP(); 3352394cb30aSAlexander Motin } else { 33532955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist", 33542955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3355394cb30aSAlexander Motin } 3356069154d5SJulian Elischer } 3357069154d5SJulian Elischer 3358069154d5SJulian Elischer 3359069154d5SJulian Elischer /*********************************************************************** 3360069154d5SJulian Elischer * Externally useable functions to set up a queue item ready for sending 3361069154d5SJulian Elischer ***********************************************************************/ 3362069154d5SJulian Elischer 336330400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 336430400f03SJulian Elischer #define ITEM_DEBUG_CHECKS \ 33654cf49a43SJulian Elischer do { \ 33661acb27c6SJulian Elischer if (NGI_NODE(item) ) { \ 3367069154d5SJulian Elischer printf("item already has node"); \ 33683de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has node"); \ 33691acb27c6SJulian Elischer NGI_CLR_NODE(item); \ 3370069154d5SJulian Elischer } \ 33711acb27c6SJulian Elischer if (NGI_HOOK(item) ) { \ 3372069154d5SJulian Elischer printf("item already has hook"); \ 33733de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has hook"); \ 33741acb27c6SJulian Elischer NGI_CLR_HOOK(item); \ 3375069154d5SJulian Elischer } \ 3376069154d5SJulian Elischer } while (0) 3377069154d5SJulian Elischer #else 337830400f03SJulian Elischer #define ITEM_DEBUG_CHECKS 3379069154d5SJulian Elischer #endif 3380069154d5SJulian Elischer 3381069154d5SJulian Elischer /* 33828ed370fdSJulian Elischer * Put mbuf into the item. 3383069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3384069154d5SJulian Elischer * (or equivalent) 3385069154d5SJulian Elischer * (XXX) Unsafe because no reference held by peer on remote node. 3386069154d5SJulian Elischer * remote node might go away in this timescale. 3387069154d5SJulian Elischer * We know the hooks can't go away because that would require getting 3388069154d5SJulian Elischer * a writer item on both nodes and we must have at least a reader 33894be59335SGleb Smirnoff * here to be able to do this. 3390069154d5SJulian Elischer * Note that the hook loaded is the REMOTE hook. 3391069154d5SJulian Elischer * 3392069154d5SJulian Elischer * This is possibly in the critical path for new data. 3393069154d5SJulian Elischer */ 3394069154d5SJulian Elischer item_p 339542282202SGleb Smirnoff ng_package_data(struct mbuf *m, int flags) 3396069154d5SJulian Elischer { 3397069154d5SJulian Elischer item_p item; 3398069154d5SJulian Elischer 33996aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_DATA, flags)) == NULL) { 3400069154d5SJulian Elischer NG_FREE_M(m); 3401069154d5SJulian Elischer return (NULL); 3402069154d5SJulian Elischer } 340330400f03SJulian Elischer ITEM_DEBUG_CHECKS; 34046aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 3405069154d5SJulian Elischer NGI_M(item) = m; 3406069154d5SJulian Elischer return (item); 3407069154d5SJulian Elischer } 3408069154d5SJulian Elischer 3409069154d5SJulian Elischer /* 3410069154d5SJulian Elischer * Allocate a queue item and put items into it.. 3411069154d5SJulian Elischer * Evaluate the address as this will be needed to queue it and 3412069154d5SJulian Elischer * to work out what some of the fields should be. 3413069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3414069154d5SJulian Elischer * (or equivalent) 3415069154d5SJulian Elischer */ 3416069154d5SJulian Elischer item_p 341742282202SGleb Smirnoff ng_package_msg(struct ng_mesg *msg, int flags) 3418069154d5SJulian Elischer { 3419069154d5SJulian Elischer item_p item; 3420069154d5SJulian Elischer 34216aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, flags)) == NULL) { 3422069154d5SJulian Elischer NG_FREE_MSG(msg); 3423069154d5SJulian Elischer return (NULL); 3424069154d5SJulian Elischer } 342530400f03SJulian Elischer ITEM_DEBUG_CHECKS; 34266f683eeeSGleb Smirnoff /* Messages items count as writers unless explicitly exempted. */ 34276f683eeeSGleb Smirnoff if (msg->header.cmd & NGM_READONLY) 34286aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 34296f683eeeSGleb Smirnoff else 34306aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3431069154d5SJulian Elischer /* 3432069154d5SJulian Elischer * Set the current lasthook into the queue item 3433069154d5SJulian Elischer */ 3434069154d5SJulian Elischer NGI_MSG(item) = msg; 3435facfd889SArchie Cobbs NGI_RETADDR(item) = 0; 3436069154d5SJulian Elischer return (item); 3437069154d5SJulian Elischer } 3438069154d5SJulian Elischer 3439069154d5SJulian Elischer 3440069154d5SJulian Elischer 34411acb27c6SJulian Elischer #define SET_RETADDR(item, here, retaddr) \ 34426b795970SJulian Elischer do { /* Data or fn items don't have retaddrs */ \ 34436b795970SJulian Elischer if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \ 3444069154d5SJulian Elischer if (retaddr) { \ 3445069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; \ 34464cf49a43SJulian Elischer } else { \ 3447069154d5SJulian Elischer /* \ 3448069154d5SJulian Elischer * The old return address should be ok. \ 3449069154d5SJulian Elischer * If there isn't one, use the address \ 3450069154d5SJulian Elischer * here. \ 3451069154d5SJulian Elischer */ \ 3452069154d5SJulian Elischer if (NGI_RETADDR(item) == 0) { \ 3453069154d5SJulian Elischer NGI_RETADDR(item) \ 3454069154d5SJulian Elischer = ng_node2ID(here); \ 3455069154d5SJulian Elischer } \ 3456069154d5SJulian Elischer } \ 34574cf49a43SJulian Elischer } \ 34584cf49a43SJulian Elischer } while (0) 34594cf49a43SJulian Elischer 34604cf49a43SJulian Elischer int 3461069154d5SJulian Elischer ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr) 34624cf49a43SJulian Elischer { 34631acb27c6SJulian Elischer hook_p peer; 34641acb27c6SJulian Elischer node_p peernode; 346530400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3466069154d5SJulian Elischer /* 3467069154d5SJulian Elischer * Quick sanity check.. 346830400f03SJulian Elischer * Since a hook holds a reference on it's node, once we know 346930400f03SJulian Elischer * that the peer is still connected (even if invalid,) we know 347030400f03SJulian Elischer * that the peer node is present, though maybe invalid. 3471069154d5SJulian Elischer */ 3472a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 34734bd1b557SGleb Smirnoff if ((hook == NULL) || NG_HOOK_NOT_VALID(hook) || 3474a04e9846SAlexander Motin NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) || 3475a04e9846SAlexander Motin NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) { 3476069154d5SJulian Elischer NG_FREE_ITEM(item); 34776b795970SJulian Elischer TRAP_ERROR(); 3478a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 3479e08d3e3cSJulian Elischer return (ENETDOWN); 34804cf49a43SJulian Elischer } 34814cf49a43SJulian Elischer 34824cf49a43SJulian Elischer /* 3483069154d5SJulian Elischer * Transfer our interest to the other (peer) end. 34844cf49a43SJulian Elischer */ 34851acb27c6SJulian Elischer NG_HOOK_REF(peer); 34861acb27c6SJulian Elischer NG_NODE_REF(peernode); 3487a04e9846SAlexander Motin NGI_SET_HOOK(item, peer); 34881acb27c6SJulian Elischer NGI_SET_NODE(item, peernode); 34898b68f82fSJulian Elischer SET_RETADDR(item, here, retaddr); 3490a7da736aSGleb Smirnoff 3491a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 3492a7da736aSGleb Smirnoff 3493069154d5SJulian Elischer return (0); 3494069154d5SJulian Elischer } 3495069154d5SJulian Elischer 34964cf49a43SJulian Elischer int 3497707d2058SMax Khon ng_address_path(node_p here, item_p item, const char *address, ng_ID_t retaddr) 34984cf49a43SJulian Elischer { 34994cf49a43SJulian Elischer node_p dest = NULL; 3500069154d5SJulian Elischer hook_p hook = NULL; 35014cf49a43SJulian Elischer int error; 3502069154d5SJulian Elischer 350330400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3504069154d5SJulian Elischer /* 3505069154d5SJulian Elischer * Note that ng_path2noderef increments the reference count 3506069154d5SJulian Elischer * on the node for us if it finds one. So we don't have to. 3507069154d5SJulian Elischer */ 3508069154d5SJulian Elischer error = ng_path2noderef(here, address, &dest, &hook); 3509069154d5SJulian Elischer if (error) { 3510069154d5SJulian Elischer NG_FREE_ITEM(item); 351130400f03SJulian Elischer return (error); 3512069154d5SJulian Elischer } 35131acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 3514a7da736aSGleb Smirnoff if (hook) 35151acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 3516a7da736aSGleb Smirnoff 35171acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3518069154d5SJulian Elischer return (0); 3519069154d5SJulian Elischer } 3520069154d5SJulian Elischer 3521069154d5SJulian Elischer int 3522069154d5SJulian Elischer ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr) 3523069154d5SJulian Elischer { 3524069154d5SJulian Elischer node_p dest; 3525069154d5SJulian Elischer 352630400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3527069154d5SJulian Elischer /* 3528069154d5SJulian Elischer * Find the target node. 3529069154d5SJulian Elischer */ 3530069154d5SJulian Elischer dest = ng_ID2noderef(ID); /* GETS REFERENCE! */ 3531069154d5SJulian Elischer if (dest == NULL) { 3532069154d5SJulian Elischer NG_FREE_ITEM(item); 35336b795970SJulian Elischer TRAP_ERROR(); 3534069154d5SJulian Elischer return(EINVAL); 3535069154d5SJulian Elischer } 3536069154d5SJulian Elischer /* Fill out the contents */ 35371acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 35381acb27c6SJulian Elischer NGI_CLR_HOOK(item); 35391acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3540069154d5SJulian Elischer return (0); 3541069154d5SJulian Elischer } 3542069154d5SJulian Elischer 3543069154d5SJulian Elischer /* 3544069154d5SJulian Elischer * special case to send a message to self (e.g. destroy node) 3545069154d5SJulian Elischer * Possibly indicate an arrival hook too. 3546069154d5SJulian Elischer * Useful for removing that hook :-) 3547069154d5SJulian Elischer */ 3548069154d5SJulian Elischer item_p 3549069154d5SJulian Elischer ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg) 3550069154d5SJulian Elischer { 3551069154d5SJulian Elischer item_p item; 35524cf49a43SJulian Elischer 3553859a4d16SJulian Elischer /* 3554859a4d16SJulian Elischer * Find the target node. 3555859a4d16SJulian Elischer * If there is a HOOK argument, then use that in preference 3556859a4d16SJulian Elischer * to the address. 3557859a4d16SJulian Elischer */ 35586aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, NG_NOFLAGS)) == NULL) { 3559069154d5SJulian Elischer NG_FREE_MSG(msg); 3560069154d5SJulian Elischer return (NULL); 35614cf49a43SJulian Elischer } 35624cf49a43SJulian Elischer 35634cf49a43SJulian Elischer /* Fill out the contents */ 35646aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 356530400f03SJulian Elischer NG_NODE_REF(here); 35661acb27c6SJulian Elischer NGI_SET_NODE(item, here); 35671acb27c6SJulian Elischer if (hook) { 356830400f03SJulian Elischer NG_HOOK_REF(hook); 35691acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 35701acb27c6SJulian Elischer } 3571069154d5SJulian Elischer NGI_MSG(item) = msg; 3572069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3573069154d5SJulian Elischer return (item); 35744cf49a43SJulian Elischer } 35754cf49a43SJulian Elischer 3576e088dd4cSAlexander Motin /* 3577e088dd4cSAlexander Motin * Send ng_item_fn function call to the specified node. 3578e088dd4cSAlexander Motin */ 3579e088dd4cSAlexander Motin 358042282202SGleb Smirnoff int 3581b332b91fSGleb Smirnoff ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2) 3582b332b91fSGleb Smirnoff { 3583b332b91fSGleb Smirnoff 3584b332b91fSGleb Smirnoff return ng_send_fn1(node, hook, fn, arg1, arg2, NG_NOFLAGS); 3585b332b91fSGleb Smirnoff } 3586b332b91fSGleb Smirnoff 3587b332b91fSGleb Smirnoff int 3588aacdb114SGleb Smirnoff ng_send_fn1(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2, 358942282202SGleb Smirnoff int flags) 35906b795970SJulian Elischer { 35916b795970SJulian Elischer item_p item; 35926b795970SJulian Elischer 35936aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, flags)) == NULL) { 35946b795970SJulian Elischer return (ENOMEM); 35956b795970SJulian Elischer } 35966aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3597a96dcd84SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 35981acb27c6SJulian Elischer NGI_SET_NODE(item, node); 35991acb27c6SJulian Elischer if (hook) { 36006b795970SJulian Elischer NG_HOOK_REF(hook); 36011acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 36026b795970SJulian Elischer } 36036b795970SJulian Elischer NGI_FN(item) = fn; 36046b795970SJulian Elischer NGI_ARG1(item) = arg1; 36056b795970SJulian Elischer NGI_ARG2(item) = arg2; 360642282202SGleb Smirnoff return(ng_snd_item(item, flags)); 36076b795970SJulian Elischer } 36086b795970SJulian Elischer 36094cf49a43SJulian Elischer /* 3610b332b91fSGleb Smirnoff * Send ng_item_fn2 function call to the specified node. 3611b332b91fSGleb Smirnoff * 3612b332b91fSGleb Smirnoff * If an optional pitem parameter is supplied, its apply 3613b332b91fSGleb Smirnoff * callback will be copied to the new item. If also NG_REUSE_ITEM 3614b332b91fSGleb Smirnoff * flag is set, no new item will be allocated, but pitem will 3615b332b91fSGleb Smirnoff * be used. 3616e088dd4cSAlexander Motin */ 3617e088dd4cSAlexander Motin int 3618b332b91fSGleb Smirnoff ng_send_fn2(node_p node, hook_p hook, item_p pitem, ng_item_fn2 *fn, void *arg1, 3619b332b91fSGleb Smirnoff int arg2, int flags) 3620e088dd4cSAlexander Motin { 3621e088dd4cSAlexander Motin item_p item; 3622e088dd4cSAlexander Motin 3623b332b91fSGleb Smirnoff KASSERT((pitem != NULL || (flags & NG_REUSE_ITEM) == 0), 3624b332b91fSGleb Smirnoff ("%s: NG_REUSE_ITEM but no pitem", __func__)); 3625e088dd4cSAlexander Motin 3626e088dd4cSAlexander Motin /* 3627b332b91fSGleb Smirnoff * Allocate a new item if no supplied or 3628b332b91fSGleb Smirnoff * if we can't use supplied one. 3629e088dd4cSAlexander Motin */ 3630b332b91fSGleb Smirnoff if (pitem == NULL || (flags & NG_REUSE_ITEM) == 0) { 36316aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN2, flags)) == NULL) 3632e088dd4cSAlexander Motin return (ENOMEM); 36336aa6d011SAlexander Motin if (pitem != NULL) 36346aa6d011SAlexander Motin item->apply = pitem->apply; 3635ed75521fSAlexander Motin } else { 36366aa6d011SAlexander Motin if ((item = ng_realloc_item(pitem, NGQF_FN2, flags)) == NULL) 36376aa6d011SAlexander Motin return (ENOMEM); 3638ed75521fSAlexander Motin } 3639b332b91fSGleb Smirnoff 36406aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_RW) | NGQF_WRITER; 3641e088dd4cSAlexander Motin NG_NODE_REF(node); /* and one for the item */ 3642e088dd4cSAlexander Motin NGI_SET_NODE(item, node); 3643e088dd4cSAlexander Motin if (hook) { 3644e088dd4cSAlexander Motin NG_HOOK_REF(hook); 3645e088dd4cSAlexander Motin NGI_SET_HOOK(item, hook); 3646e088dd4cSAlexander Motin } 3647e088dd4cSAlexander Motin NGI_FN2(item) = fn; 3648e088dd4cSAlexander Motin NGI_ARG1(item) = arg1; 3649e088dd4cSAlexander Motin NGI_ARG2(item) = arg2; 3650e088dd4cSAlexander Motin return(ng_snd_item(item, flags)); 3651e088dd4cSAlexander Motin } 3652e088dd4cSAlexander Motin 3653e088dd4cSAlexander Motin /* 3654d2ca21a9SJulian Elischer * Official timeout routines for Netgraph nodes. 3655d2ca21a9SJulian Elischer */ 3656d2ca21a9SJulian Elischer static void 36571fbb36ffSGleb Smirnoff ng_callout_trampoline(void *arg) 3658d2ca21a9SJulian Elischer { 3659d2ca21a9SJulian Elischer item_p item = arg; 3660d2ca21a9SJulian Elischer 3661bc29160dSMarko Zec CURVNET_SET(NGI_NODE(item)->nd_vnet); 3662d2ca21a9SJulian Elischer ng_snd_item(item, 0); 3663bc29160dSMarko Zec CURVNET_RESTORE(); 3664d2ca21a9SJulian Elischer } 3665d2ca21a9SJulian Elischer 3666d2ca21a9SJulian Elischer 366730bef41bSGleb Smirnoff int 3668f9d9e1b4SGleb Smirnoff ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, 3669d2ca21a9SJulian Elischer ng_item_fn *fn, void * arg1, int arg2) 3670d2ca21a9SJulian Elischer { 36711bf8e0faSGleb Smirnoff item_p item, oitem; 3672d2ca21a9SJulian Elischer 36736aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, NG_NOFLAGS)) == NULL) 367430bef41bSGleb Smirnoff return (ENOMEM); 367530bef41bSGleb Smirnoff 36766aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3677d2ca21a9SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 3678d2ca21a9SJulian Elischer NGI_SET_NODE(item, node); 3679d2ca21a9SJulian Elischer if (hook) { 3680d2ca21a9SJulian Elischer NG_HOOK_REF(hook); 3681d2ca21a9SJulian Elischer NGI_SET_HOOK(item, hook); 3682d2ca21a9SJulian Elischer } 3683d2ca21a9SJulian Elischer NGI_FN(item) = fn; 3684d2ca21a9SJulian Elischer NGI_ARG1(item) = arg1; 3685d2ca21a9SJulian Elischer NGI_ARG2(item) = arg2; 36861bf8e0faSGleb Smirnoff oitem = c->c_arg; 36871bf8e0faSGleb Smirnoff if (callout_reset(c, ticks, &ng_callout_trampoline, item) == 1 && 36881bf8e0faSGleb Smirnoff oitem != NULL) 36891bf8e0faSGleb Smirnoff NG_FREE_ITEM(oitem); 369030bef41bSGleb Smirnoff return (0); 3691d2ca21a9SJulian Elischer } 3692d2ca21a9SJulian Elischer 3693d2ca21a9SJulian Elischer /* A special modified version of untimeout() */ 3694d2ca21a9SJulian Elischer int 3695f9d9e1b4SGleb Smirnoff ng_uncallout(struct callout *c, node_p node) 3696d2ca21a9SJulian Elischer { 3697d2ca21a9SJulian Elischer item_p item; 369830bef41bSGleb Smirnoff int rval; 3699d2ca21a9SJulian Elischer 370003b25f5dSGleb Smirnoff KASSERT(c != NULL, ("ng_uncallout: NULL callout")); 370103b25f5dSGleb Smirnoff KASSERT(node != NULL, ("ng_uncallout: NULL node")); 370203b25f5dSGleb Smirnoff 37033eadb26dSGleb Smirnoff rval = callout_stop(c); 370430bef41bSGleb Smirnoff item = c->c_arg; 370530bef41bSGleb Smirnoff /* Do an extra check */ 37061fbb36ffSGleb Smirnoff if ((rval > 0) && (c->c_func == &ng_callout_trampoline) && 370730bef41bSGleb Smirnoff (NGI_NODE(item) == node)) { 3708d2ca21a9SJulian Elischer /* 3709d2ca21a9SJulian Elischer * We successfully removed it from the queue before it ran 3710d2ca21a9SJulian Elischer * So now we need to unreference everything that was 3711d2ca21a9SJulian Elischer * given extra references. (NG_FREE_ITEM does this). 3712d2ca21a9SJulian Elischer */ 3713d2ca21a9SJulian Elischer NG_FREE_ITEM(item); 3714d2ca21a9SJulian Elischer } 37151bf8e0faSGleb Smirnoff c->c_arg = NULL; 371630bef41bSGleb Smirnoff 371730bef41bSGleb Smirnoff return (rval); 3718d2ca21a9SJulian Elischer } 3719d2ca21a9SJulian Elischer 3720d2ca21a9SJulian Elischer /* 3721069154d5SJulian Elischer * Set the address, if none given, give the node here. 37224cf49a43SJulian Elischer */ 3723069154d5SJulian Elischer void 3724069154d5SJulian Elischer ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr) 37254cf49a43SJulian Elischer { 3726069154d5SJulian Elischer if (retaddr) { 3727069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; 3728069154d5SJulian Elischer } else { 3729069154d5SJulian Elischer /* 3730069154d5SJulian Elischer * The old return address should be ok. 3731069154d5SJulian Elischer * If there isn't one, use the address here. 3732069154d5SJulian Elischer */ 3733069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3734069154d5SJulian Elischer } 3735069154d5SJulian Elischer } 3736069154d5SJulian Elischer 3737069154d5SJulian Elischer #define TESTING 3738069154d5SJulian Elischer #ifdef TESTING 3739069154d5SJulian Elischer /* just test all the macros */ 3740069154d5SJulian Elischer void 3741069154d5SJulian Elischer ng_macro_test(item_p item); 3742069154d5SJulian Elischer void 3743069154d5SJulian Elischer ng_macro_test(item_p item) 3744069154d5SJulian Elischer { 3745069154d5SJulian Elischer node_p node = NULL; 3746069154d5SJulian Elischer hook_p hook = NULL; 37474cf49a43SJulian Elischer struct mbuf *m; 37484cf49a43SJulian Elischer struct ng_mesg *msg; 3749069154d5SJulian Elischer ng_ID_t retaddr; 3750069154d5SJulian Elischer int error; 37514cf49a43SJulian Elischer 3752069154d5SJulian Elischer NGI_GET_M(item, m); 3753069154d5SJulian Elischer NGI_GET_MSG(item, msg); 3754069154d5SJulian Elischer retaddr = NGI_RETADDR(item); 37558ed370fdSJulian Elischer NG_SEND_DATA(error, hook, m, NULL); 3756069154d5SJulian Elischer NG_SEND_DATA_ONLY(error, hook, m); 3757069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, hook, m); 375830400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, hook); 3759069154d5SJulian Elischer NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr); 3760069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr); 3761069154d5SJulian Elischer NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr); 3762069154d5SJulian Elischer NG_FWD_MSG_HOOK(error, node, item, hook, retaddr); 37634cf49a43SJulian Elischer } 3764069154d5SJulian Elischer #endif /* TESTING */ 3765