14cf49a43SJulian Elischer /* 24cf49a43SJulian Elischer * ng_base.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 64cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 74cf49a43SJulian Elischer * All rights reserved. 84cf49a43SJulian Elischer * 94cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 104cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 114cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 124cf49a43SJulian Elischer * provided, however, that: 134cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 144cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 154cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 164cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 174cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 184cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 194cf49a43SJulian Elischer * 204cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 214cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 224cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 234cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 244cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 254cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 264cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 274cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 284cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 294cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 304cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 314cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 324cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 334cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 344cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 354cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 364cf49a43SJulian Elischer * OF SUCH DAMAGE. 374cf49a43SJulian Elischer * 38cc3bbd68SJulian Elischer * Authors: Julian Elischer <julian@freebsd.org> 39cc3bbd68SJulian Elischer * Archie Cobbs <archie@freebsd.org> 404cf49a43SJulian Elischer * 414cf49a43SJulian Elischer * $FreeBSD$ 424cf49a43SJulian Elischer * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 434cf49a43SJulian Elischer */ 444cf49a43SJulian Elischer 454cf49a43SJulian Elischer /* 464cf49a43SJulian Elischer * This file implements the base netgraph code. 474cf49a43SJulian Elischer */ 484cf49a43SJulian Elischer 494cf49a43SJulian Elischer #include <sys/param.h> 508e853a2cSGleb Smirnoff #include <sys/systm.h> 5177a58296SGleb Smirnoff #include <sys/ctype.h> 524cf49a43SJulian Elischer #include <sys/errno.h> 53f33ca0c9SMarcel Moolenaar #include <sys/kdb.h> 544cf49a43SJulian Elischer #include <sys/kernel.h> 553b33fbe7SGleb Smirnoff #include <sys/ktr.h> 56104a9b7eSAlexander Kabaev #include <sys/limits.h> 574cf49a43SJulian Elischer #include <sys/malloc.h> 584cf49a43SJulian Elischer #include <sys/mbuf.h> 5977a58296SGleb Smirnoff #include <sys/queue.h> 60bfa7e882SJulian Elischer #include <sys/sysctl.h> 6177a58296SGleb Smirnoff #include <sys/syslog.h> 62e088dd4cSAlexander Motin #include <sys/refcount.h> 6381a253a4SAlexander Motin #include <sys/proc.h> 64f2fbb838SAlexander Motin #include <sys/unistd.h> 65f2fbb838SAlexander Motin #include <sys/kthread.h> 66f2fbb838SAlexander Motin #include <sys/smp.h> 67394cb30aSAlexander Motin #include <machine/cpu.h> 684cf49a43SJulian Elischer 694cf49a43SJulian Elischer #include <net/netisr.h> 70eddfbb76SRobert Watson #include <net/vnet.h> 714cf49a43SJulian Elischer 724cf49a43SJulian Elischer #include <netgraph/ng_message.h> 734cf49a43SJulian Elischer #include <netgraph/netgraph.h> 74f8307e12SArchie Cobbs #include <netgraph/ng_parse.h> 754cf49a43SJulian Elischer 769d72a7a3SJulian Elischer MODULE_VERSION(netgraph, NG_ABI_VERSION); 7799ff8176SPeter Wemm 78ac5dd141SGleb Smirnoff /* Mutex to protect topology events. */ 79ac5dd141SGleb Smirnoff static struct mtx ng_topo_mtx; 80ac5dd141SGleb Smirnoff 8130400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 82cfea3f85SAlexander Motin static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */ 831489164fSGleb Smirnoff static struct mtx ngq_mtx; /* protects the queue item list */ 8430400f03SJulian Elischer 8530400f03SJulian Elischer static SLIST_HEAD(, ng_node) ng_allnodes; 8630400f03SJulian Elischer static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */ 8730400f03SJulian Elischer static SLIST_HEAD(, ng_hook) ng_allhooks; 8830400f03SJulian Elischer static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */ 8930400f03SJulian Elischer 9030400f03SJulian Elischer static void ng_dumpitems(void); 9130400f03SJulian Elischer static void ng_dumpnodes(void); 9230400f03SJulian Elischer static void ng_dumphooks(void); 9330400f03SJulian Elischer 9430400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 95954c4772SJulian Elischer /* 96954c4772SJulian Elischer * DEAD versions of the structures. 97954c4772SJulian Elischer * In order to avoid races, it is sometimes neccesary to point 98954c4772SJulian Elischer * at SOMETHING even though theoretically, the current entity is 99954c4772SJulian Elischer * INVALID. Use these to avoid these races. 100954c4772SJulian Elischer */ 101954c4772SJulian Elischer struct ng_type ng_deadtype = { 102954c4772SJulian Elischer NG_ABI_VERSION, 103954c4772SJulian Elischer "dead", 104954c4772SJulian Elischer NULL, /* modevent */ 105954c4772SJulian Elischer NULL, /* constructor */ 106954c4772SJulian Elischer NULL, /* rcvmsg */ 107954c4772SJulian Elischer NULL, /* shutdown */ 108954c4772SJulian Elischer NULL, /* newhook */ 109954c4772SJulian Elischer NULL, /* findhook */ 110954c4772SJulian Elischer NULL, /* connect */ 111954c4772SJulian Elischer NULL, /* rcvdata */ 112954c4772SJulian Elischer NULL, /* disconnect */ 113954c4772SJulian Elischer NULL, /* cmdlist */ 114954c4772SJulian Elischer }; 11530400f03SJulian Elischer 116954c4772SJulian Elischer struct ng_node ng_deadnode = { 117954c4772SJulian Elischer "dead", 118954c4772SJulian Elischer &ng_deadtype, 119be4252b3SJulian Elischer NGF_INVALID, 120954c4772SJulian Elischer 0, /* numhooks */ 121954c4772SJulian Elischer NULL, /* private */ 122954c4772SJulian Elischer 0, /* ID */ 12313e403fdSAntoine Brodin LIST_HEAD_INITIALIZER(ng_deadnode.nd_hooks), 124954c4772SJulian Elischer {}, /* all_nodes list entry */ 125954c4772SJulian Elischer {}, /* id hashtable list entry */ 126954c4772SJulian Elischer { 0, 1279852972bSAlexander Motin 0, 128954c4772SJulian Elischer {}, /* should never use! (should hang) */ 1299852972bSAlexander Motin {}, /* workqueue entry */ 1309852972bSAlexander Motin STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue), 131954c4772SJulian Elischer }, 1329852972bSAlexander Motin 1, /* refs */ 133a40b7874SMarko Zec NULL, /* vnet */ 134954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 135954c4772SJulian Elischer ND_MAGIC, 136954c4772SJulian Elischer __FILE__, 137954c4772SJulian Elischer __LINE__, 138954c4772SJulian Elischer {NULL} 139954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 140954c4772SJulian Elischer }; 141954c4772SJulian Elischer 142954c4772SJulian Elischer struct ng_hook ng_deadhook = { 143954c4772SJulian Elischer "dead", 144954c4772SJulian Elischer NULL, /* private */ 145954c4772SJulian Elischer HK_INVALID | HK_DEAD, 146e58d779dSGleb Smirnoff 0, /* undefined data link type */ 147954c4772SJulian Elischer &ng_deadhook, /* Peer is self */ 148954c4772SJulian Elischer &ng_deadnode, /* attached to deadnode */ 149954c4772SJulian Elischer {}, /* hooks list */ 150c4b5eea4SJulian Elischer NULL, /* override rcvmsg() */ 151c4b5eea4SJulian Elischer NULL, /* override rcvdata() */ 1529852972bSAlexander Motin 1, /* refs always >= 1 */ 153954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 154954c4772SJulian Elischer HK_MAGIC, 155954c4772SJulian Elischer __FILE__, 156954c4772SJulian Elischer __LINE__, 157954c4772SJulian Elischer {NULL} 158954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 159954c4772SJulian Elischer }; 160954c4772SJulian Elischer 161954c4772SJulian Elischer /* 162954c4772SJulian Elischer * END DEAD STRUCTURES 163954c4772SJulian Elischer */ 164069154d5SJulian Elischer /* List nodes with unallocated work */ 1659852972bSAlexander Motin static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist); 166b57a7965SJulian Elischer static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */ 1674cf49a43SJulian Elischer 1684cf49a43SJulian Elischer /* List of installed types */ 169069154d5SJulian Elischer static LIST_HEAD(, ng_type) ng_typelist; 170069154d5SJulian Elischer static struct mtx ng_typelist_mtx; 1714cf49a43SJulian Elischer 172069154d5SJulian Elischer /* Hash related definitions */ 1730f150d04SJulian Elischer /* XXX Don't need to initialise them because it's a LIST */ 1743e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, ng_node), ng_ID_hash[NG_ID_HASH_SIZE]); 1751e77c105SRobert Watson #define V_ng_ID_hash VNET(ng_ID_hash) 176eddfbb76SRobert Watson 177069154d5SJulian Elischer static struct mtx ng_idhash_mtx; 1780f150d04SJulian Elischer /* Method to find a node.. used twice so do it here */ 1790f150d04SJulian Elischer #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE)) 1800f150d04SJulian Elischer #define NG_IDHASH_FIND(ID, node) \ 1810f150d04SJulian Elischer do { \ 18253f9c5e9SRobert Watson mtx_assert(&ng_idhash_mtx, MA_OWNED); \ 183603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \ 1840f150d04SJulian Elischer nd_idnodes) { \ 1850f150d04SJulian Elischer if (NG_NODE_IS_VALID(node) \ 1860f150d04SJulian Elischer && (NG_NODE_ID(node) == ID)) { \ 1870f150d04SJulian Elischer break; \ 1880f150d04SJulian Elischer } \ 1890f150d04SJulian Elischer } \ 1900f150d04SJulian Elischer } while (0) 191069154d5SJulian Elischer 1923e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, ng_node), ng_name_hash[NG_NAME_HASH_SIZE]); 1931e77c105SRobert Watson #define V_ng_name_hash VNET(ng_name_hash) 194eddfbb76SRobert Watson 195cfea3f85SAlexander Motin static struct mtx ng_namehash_mtx; 196cfea3f85SAlexander Motin #define NG_NAMEHASH(NAME, HASH) \ 197cfea3f85SAlexander Motin do { \ 198cfea3f85SAlexander Motin u_char h = 0; \ 199cfea3f85SAlexander Motin const u_char *c; \ 200cfea3f85SAlexander Motin for (c = (const u_char*)(NAME); *c; c++)\ 201cfea3f85SAlexander Motin h += *c; \ 202cfea3f85SAlexander Motin (HASH) = h % (NG_NAME_HASH_SIZE); \ 203cfea3f85SAlexander Motin } while (0) 204cfea3f85SAlexander Motin 205dc90cad9SJulian Elischer 2064cf49a43SJulian Elischer /* Internal functions */ 2074cf49a43SJulian Elischer static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 208069154d5SJulian Elischer static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); 209dc90cad9SJulian Elischer static ng_ID_t ng_decodeidname(const char *name); 2104cf49a43SJulian Elischer static int ngb_mod_event(module_t mod, int event, void *data); 211394cb30aSAlexander Motin static void ng_worklist_add(node_p node); 212f2fbb838SAlexander Motin static void ngthread(void *); 21327757487SGleb Smirnoff static int ng_apply_item(node_p node, item_p item, int rw); 2149852972bSAlexander Motin static void ng_flush_input_queue(node_p node); 215069154d5SJulian Elischer static node_p ng_ID2noderef(ng_ID_t ID); 216e088dd4cSAlexander Motin static int ng_con_nodes(item_p item, node_p node, const char *name, 217e088dd4cSAlexander Motin node_p node2, const char *name2); 218e088dd4cSAlexander Motin static int ng_con_part2(node_p node, item_p item, hook_p hook); 219e088dd4cSAlexander Motin static int ng_con_part3(node_p node, item_p item, hook_p hook); 2206b795970SJulian Elischer static int ng_mkpeer(node_p node, const char *name, 2216b795970SJulian Elischer const char *name2, char *type); 222069154d5SJulian Elischer 2234c9b5910SGleb Smirnoff /* Imported, these used to be externally visible, some may go back. */ 224069154d5SJulian Elischer void ng_destroy_hook(hook_p hook); 225069154d5SJulian Elischer int ng_path2noderef(node_p here, const char *path, 226069154d5SJulian Elischer node_p *dest, hook_p *lasthook); 227069154d5SJulian Elischer int ng_make_node(const char *type, node_p *nodepp); 228069154d5SJulian Elischer int ng_path_parse(char *addr, char **node, char **path, char **hook); 2291acb27c6SJulian Elischer void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3); 23030400f03SJulian Elischer void ng_unname(node_p node); 231069154d5SJulian Elischer 2324cf49a43SJulian Elischer 2334cf49a43SJulian Elischer /* Our own netgraph malloc type */ 2344cf49a43SJulian Elischer MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 235069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures"); 236069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures"); 237069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures"); 238069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); 239069154d5SJulian Elischer 240069154d5SJulian Elischer /* Should not be visible outside this file */ 24130400f03SJulian Elischer 24230400f03SJulian Elischer #define _NG_ALLOC_HOOK(hook) \ 2431ede983cSDag-Erling Smørgrav hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO) 24430400f03SJulian Elischer #define _NG_ALLOC_NODE(node) \ 2451ede983cSDag-Erling Smørgrav node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO) 24630400f03SJulian Elischer 2472c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK_INIT(n) \ 2484abab3d5SWojciech A. Koszek mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF) 2492c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK(n) \ 2504abab3d5SWojciech A. Koszek mtx_lock(&(n)->q_mtx) 2512c8dda8dSWojciech A. Koszek #define NG_QUEUE_UNLOCK(n) \ 2524abab3d5SWojciech A. Koszek mtx_unlock(&(n)->q_mtx) 2532c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK_INIT() \ 2544abab3d5SWojciech A. Koszek mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF) 2552c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK() \ 2564abab3d5SWojciech A. Koszek mtx_lock(&ng_worklist_mtx) 2572c8dda8dSWojciech A. Koszek #define NG_WORKLIST_UNLOCK() \ 2584abab3d5SWojciech A. Koszek mtx_unlock(&ng_worklist_mtx) 259f2fbb838SAlexander Motin #define NG_WORKLIST_SLEEP() \ 260f2fbb838SAlexander Motin mtx_sleep(&ng_worklist, &ng_worklist_mtx, PI_NET, "sleep", 0) 261f2fbb838SAlexander Motin #define NG_WORKLIST_WAKEUP() \ 262f2fbb838SAlexander Motin wakeup_one(&ng_worklist) 2632c8dda8dSWojciech A. Koszek 26430400f03SJulian Elischer #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 26530400f03SJulian Elischer /* 26630400f03SJulian Elischer * In debug mode: 26730400f03SJulian Elischer * In an attempt to help track reference count screwups 26830400f03SJulian Elischer * we do not free objects back to the malloc system, but keep them 26930400f03SJulian Elischer * in a local cache where we can examine them and keep information safely 27030400f03SJulian Elischer * after they have been freed. 27130400f03SJulian Elischer * We use this scheme for nodes and hooks, and to some extent for items. 27230400f03SJulian Elischer */ 27330400f03SJulian Elischer static __inline hook_p 27430400f03SJulian Elischer ng_alloc_hook(void) 27530400f03SJulian Elischer { 27630400f03SJulian Elischer hook_p hook; 27730400f03SJulian Elischer SLIST_ENTRY(ng_hook) temp; 2789ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 27930400f03SJulian Elischer hook = LIST_FIRST(&ng_freehooks); 28030400f03SJulian Elischer if (hook) { 28130400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 28230400f03SJulian Elischer bcopy(&hook->hk_all, &temp, sizeof(temp)); 28330400f03SJulian Elischer bzero(hook, sizeof(struct ng_hook)); 28430400f03SJulian Elischer bcopy(&temp, &hook->hk_all, sizeof(temp)); 2859ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 28630400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 28730400f03SJulian Elischer } else { 2889ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 28930400f03SJulian Elischer _NG_ALLOC_HOOK(hook); 29030400f03SJulian Elischer if (hook) { 29130400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 2929ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 29330400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all); 2949ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 29530400f03SJulian Elischer } 29630400f03SJulian Elischer } 29730400f03SJulian Elischer return (hook); 29830400f03SJulian Elischer } 29930400f03SJulian Elischer 30030400f03SJulian Elischer static __inline node_p 30130400f03SJulian Elischer ng_alloc_node(void) 30230400f03SJulian Elischer { 30330400f03SJulian Elischer node_p node; 30430400f03SJulian Elischer SLIST_ENTRY(ng_node) temp; 3059ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 30630400f03SJulian Elischer node = LIST_FIRST(&ng_freenodes); 30730400f03SJulian Elischer if (node) { 30830400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 30930400f03SJulian Elischer bcopy(&node->nd_all, &temp, sizeof(temp)); 31030400f03SJulian Elischer bzero(node, sizeof(struct ng_node)); 31130400f03SJulian Elischer bcopy(&temp, &node->nd_all, sizeof(temp)); 3129ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 31330400f03SJulian Elischer node->nd_magic = ND_MAGIC; 31430400f03SJulian Elischer } else { 3159ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 31630400f03SJulian Elischer _NG_ALLOC_NODE(node); 31730400f03SJulian Elischer if (node) { 31830400f03SJulian Elischer node->nd_magic = ND_MAGIC; 3199ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 32030400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all); 3219ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 32230400f03SJulian Elischer } 32330400f03SJulian Elischer } 32430400f03SJulian Elischer return (node); 32530400f03SJulian Elischer } 32630400f03SJulian Elischer 32730400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0) 32830400f03SJulian Elischer #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0) 32930400f03SJulian Elischer 33030400f03SJulian Elischer 33130400f03SJulian Elischer #define NG_FREE_HOOK(hook) \ 33230400f03SJulian Elischer do { \ 3339ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 33430400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \ 33530400f03SJulian Elischer hook->hk_magic = 0; \ 3369ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 33730400f03SJulian Elischer } while (0) 33830400f03SJulian Elischer 33930400f03SJulian Elischer #define NG_FREE_NODE(node) \ 34030400f03SJulian Elischer do { \ 3419ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 34230400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \ 34330400f03SJulian Elischer node->nd_magic = 0; \ 3449ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 34530400f03SJulian Elischer } while (0) 34630400f03SJulian Elischer 34730400f03SJulian Elischer #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 34830400f03SJulian Elischer 34930400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook) 35030400f03SJulian Elischer #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node) 35130400f03SJulian Elischer 3521ede983cSDag-Erling Smørgrav #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0) 3531ede983cSDag-Erling Smørgrav #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0) 35430400f03SJulian Elischer 35530400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 35630400f03SJulian Elischer 357f33ca0c9SMarcel Moolenaar /* Set this to kdb_enter("X") to catch all errors as they occur */ 3584cf49a43SJulian Elischer #ifndef TRAP_ERROR 3596b795970SJulian Elischer #define TRAP_ERROR() 3604cf49a43SJulian Elischer #endif 3614cf49a43SJulian Elischer 3623e288e62SDimitry Andric static VNET_DEFINE(ng_ID_t, nextID) = 1; 3631e77c105SRobert Watson #define V_nextID VNET(nextID) 364dc90cad9SJulian Elischer 365b2da83c2SArchie Cobbs #ifdef INVARIANTS 366b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) do { \ 367b2da83c2SArchie Cobbs struct mbuf *n; \ 368b2da83c2SArchie Cobbs int total; \ 369b2da83c2SArchie Cobbs \ 370fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); \ 371b32cfb32SGleb Smirnoff for (total = 0, n = (m); n != NULL; n = n->m_next) { \ 372b2da83c2SArchie Cobbs total += n->m_len; \ 373b32cfb32SGleb Smirnoff if (n->m_nextpkt != NULL) \ 374b32cfb32SGleb Smirnoff panic("%s: m_nextpkt", __func__); \ 375b32cfb32SGleb Smirnoff } \ 376ba5b359aSGleb Smirnoff \ 377b2da83c2SArchie Cobbs if ((m)->m_pkthdr.len != total) { \ 378b2da83c2SArchie Cobbs panic("%s: %d != %d", \ 3796e551fb6SDavid E. O'Brien __func__, (m)->m_pkthdr.len, total); \ 380b2da83c2SArchie Cobbs } \ 381b2da83c2SArchie Cobbs } while (0) 382b2da83c2SArchie Cobbs #else 383b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) 384b2da83c2SArchie Cobbs #endif 385b2da83c2SArchie Cobbs 386e088dd4cSAlexander Motin #define ERROUT(x) do { error = (x); goto done; } while (0) 387dc90cad9SJulian Elischer 3884cf49a43SJulian Elischer /************************************************************************ 389f8307e12SArchie Cobbs Parse type definitions for generic messages 390f8307e12SArchie Cobbs ************************************************************************/ 391f8307e12SArchie Cobbs 392f8307e12SArchie Cobbs /* Handy structure parse type defining macro */ 393f8307e12SArchie Cobbs #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 394f0184ff8SArchie Cobbs static const struct ng_parse_struct_field \ 395f0184ff8SArchie Cobbs ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 396f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 397f8307e12SArchie Cobbs &ng_parse_struct_type, \ 398f0184ff8SArchie Cobbs &ng_ ## lo ## _type_fields \ 399f8307e12SArchie Cobbs } 400f8307e12SArchie Cobbs 401f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 402f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 403f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 404f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 405f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 406f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 407f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 408f8307e12SArchie Cobbs 409f8307e12SArchie Cobbs /* Get length of an array when the length is stored as a 32 bit 410d7d97eb0SJeroen Ruigrok van der Werven value immediately preceding the array -- as with struct namelist 411f8307e12SArchie Cobbs and struct typelist. */ 412f8307e12SArchie Cobbs static int 413f8307e12SArchie Cobbs ng_generic_list_getLength(const struct ng_parse_type *type, 414f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 415f8307e12SArchie Cobbs { 416f8307e12SArchie Cobbs return *((const u_int32_t *)(buf - 4)); 417f8307e12SArchie Cobbs } 418f8307e12SArchie Cobbs 419f8307e12SArchie Cobbs /* Get length of the array of struct linkinfo inside a struct hooklist */ 420f8307e12SArchie Cobbs static int 421f8307e12SArchie Cobbs ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 422f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 423f8307e12SArchie Cobbs { 424f8307e12SArchie Cobbs const struct hooklist *hl = (const struct hooklist *)start; 425f8307e12SArchie Cobbs 426f8307e12SArchie Cobbs return hl->nodeinfo.hooks; 427f8307e12SArchie Cobbs } 428f8307e12SArchie Cobbs 429f8307e12SArchie Cobbs /* Array type for a variable length array of struct namelist */ 430f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 431f8307e12SArchie Cobbs &ng_generic_nodeinfo_type, 432f8307e12SArchie Cobbs &ng_generic_list_getLength 433f8307e12SArchie Cobbs }; 434f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 435f8307e12SArchie Cobbs &ng_parse_array_type, 436f8307e12SArchie Cobbs &ng_nodeinfoarray_type_info 437f8307e12SArchie Cobbs }; 438f8307e12SArchie Cobbs 439f8307e12SArchie Cobbs /* Array type for a variable length array of struct typelist */ 440f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 441f8307e12SArchie Cobbs &ng_generic_typeinfo_type, 442f8307e12SArchie Cobbs &ng_generic_list_getLength 443f8307e12SArchie Cobbs }; 444f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_typeinfoarray_type = { 445f8307e12SArchie Cobbs &ng_parse_array_type, 446f8307e12SArchie Cobbs &ng_typeinfoarray_type_info 447f8307e12SArchie Cobbs }; 448f8307e12SArchie Cobbs 449f8307e12SArchie Cobbs /* Array type for array of struct linkinfo in struct hooklist */ 450f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 451f8307e12SArchie Cobbs &ng_generic_linkinfo_type, 452f8307e12SArchie Cobbs &ng_generic_linkinfo_getLength 453f8307e12SArchie Cobbs }; 454f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_linkinfo_array_type = { 455f8307e12SArchie Cobbs &ng_parse_array_type, 456f8307e12SArchie Cobbs &ng_generic_linkinfo_array_type_info 457f8307e12SArchie Cobbs }; 458f8307e12SArchie Cobbs 459f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 460f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 461f8307e12SArchie Cobbs (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 462f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 463f8307e12SArchie Cobbs (&ng_generic_nodeinfoarray_type)); 464f8307e12SArchie Cobbs 465f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 466f8307e12SArchie Cobbs static const struct ng_cmdlist ng_generic_cmds[] = { 467f8307e12SArchie Cobbs { 468f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 469f8307e12SArchie Cobbs NGM_SHUTDOWN, 470f8307e12SArchie Cobbs "shutdown", 471f8307e12SArchie Cobbs NULL, 472f8307e12SArchie Cobbs NULL 473f8307e12SArchie Cobbs }, 474f8307e12SArchie Cobbs { 475f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 476f8307e12SArchie Cobbs NGM_MKPEER, 477f8307e12SArchie Cobbs "mkpeer", 478f8307e12SArchie Cobbs &ng_generic_mkpeer_type, 479f8307e12SArchie Cobbs NULL 480f8307e12SArchie Cobbs }, 481f8307e12SArchie Cobbs { 482f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 483f8307e12SArchie Cobbs NGM_CONNECT, 484f8307e12SArchie Cobbs "connect", 485f8307e12SArchie Cobbs &ng_generic_connect_type, 486f8307e12SArchie Cobbs NULL 487f8307e12SArchie Cobbs }, 488f8307e12SArchie Cobbs { 489f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 490f8307e12SArchie Cobbs NGM_NAME, 491f8307e12SArchie Cobbs "name", 492f8307e12SArchie Cobbs &ng_generic_name_type, 493f8307e12SArchie Cobbs NULL 494f8307e12SArchie Cobbs }, 495f8307e12SArchie Cobbs { 496f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 497f8307e12SArchie Cobbs NGM_RMHOOK, 498f8307e12SArchie Cobbs "rmhook", 499f8307e12SArchie Cobbs &ng_generic_rmhook_type, 500f8307e12SArchie Cobbs NULL 501f8307e12SArchie Cobbs }, 502f8307e12SArchie Cobbs { 503f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 504f8307e12SArchie Cobbs NGM_NODEINFO, 505f8307e12SArchie Cobbs "nodeinfo", 506f8307e12SArchie Cobbs NULL, 507f8307e12SArchie Cobbs &ng_generic_nodeinfo_type 508f8307e12SArchie Cobbs }, 509f8307e12SArchie Cobbs { 510f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 511f8307e12SArchie Cobbs NGM_LISTHOOKS, 512f8307e12SArchie Cobbs "listhooks", 513f8307e12SArchie Cobbs NULL, 514f8307e12SArchie Cobbs &ng_generic_hooklist_type 515f8307e12SArchie Cobbs }, 516f8307e12SArchie Cobbs { 517f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 518f8307e12SArchie Cobbs NGM_LISTNAMES, 519f8307e12SArchie Cobbs "listnames", 520f8307e12SArchie Cobbs NULL, 521f8307e12SArchie Cobbs &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 522f8307e12SArchie Cobbs }, 523f8307e12SArchie Cobbs { 524f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 525f8307e12SArchie Cobbs NGM_LISTNODES, 526f8307e12SArchie Cobbs "listnodes", 527f8307e12SArchie Cobbs NULL, 528f8307e12SArchie Cobbs &ng_generic_listnodes_type 529f8307e12SArchie Cobbs }, 530f8307e12SArchie Cobbs { 531f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 532f8307e12SArchie Cobbs NGM_LISTTYPES, 533f8307e12SArchie Cobbs "listtypes", 534f8307e12SArchie Cobbs NULL, 535f8307e12SArchie Cobbs &ng_generic_typeinfo_type 536f8307e12SArchie Cobbs }, 537f8307e12SArchie Cobbs { 538f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 5397095e097SPoul-Henning Kamp NGM_TEXT_CONFIG, 5407095e097SPoul-Henning Kamp "textconfig", 5417095e097SPoul-Henning Kamp NULL, 5427095e097SPoul-Henning Kamp &ng_parse_string_type 5437095e097SPoul-Henning Kamp }, 5447095e097SPoul-Henning Kamp { 5457095e097SPoul-Henning Kamp NGM_GENERIC_COOKIE, 546f8307e12SArchie Cobbs NGM_TEXT_STATUS, 547f8307e12SArchie Cobbs "textstatus", 548f8307e12SArchie Cobbs NULL, 549f8307e12SArchie Cobbs &ng_parse_string_type 550f8307e12SArchie Cobbs }, 551f8307e12SArchie Cobbs { 552f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 553f8307e12SArchie Cobbs NGM_ASCII2BINARY, 554f8307e12SArchie Cobbs "ascii2binary", 555f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 556f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 557f8307e12SArchie Cobbs }, 558f8307e12SArchie Cobbs { 559f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 560f8307e12SArchie Cobbs NGM_BINARY2ASCII, 561f8307e12SArchie Cobbs "binary2ascii", 562f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 563f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 564f8307e12SArchie Cobbs }, 565f8307e12SArchie Cobbs { 0 } 566f8307e12SArchie Cobbs }; 567f8307e12SArchie Cobbs 568f8307e12SArchie Cobbs /************************************************************************ 5694cf49a43SJulian Elischer Node routines 5704cf49a43SJulian Elischer ************************************************************************/ 5714cf49a43SJulian Elischer 5724cf49a43SJulian Elischer /* 5734cf49a43SJulian Elischer * Instantiate a node of the requested type 5744cf49a43SJulian Elischer */ 5754cf49a43SJulian Elischer int 5764cf49a43SJulian Elischer ng_make_node(const char *typename, node_p *nodepp) 5774cf49a43SJulian Elischer { 5784cf49a43SJulian Elischer struct ng_type *type; 579069154d5SJulian Elischer int error; 5804cf49a43SJulian Elischer 5814cf49a43SJulian Elischer /* Check that the type makes sense */ 5824cf49a43SJulian Elischer if (typename == NULL) { 5836b795970SJulian Elischer TRAP_ERROR(); 5844cf49a43SJulian Elischer return (EINVAL); 5854cf49a43SJulian Elischer } 5864cf49a43SJulian Elischer 5877610f574SGleb Smirnoff /* Locate the node type. If we fail we return. Do not try to load 5887610f574SGleb Smirnoff * module. 5897610f574SGleb Smirnoff */ 5904cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) 5914cf49a43SJulian Elischer return (ENXIO); 5924cf49a43SJulian Elischer 593069154d5SJulian Elischer /* 594069154d5SJulian Elischer * If we have a constructor, then make the node and 595069154d5SJulian Elischer * call the constructor to do type specific initialisation. 596069154d5SJulian Elischer */ 597069154d5SJulian Elischer if (type->constructor != NULL) { 598069154d5SJulian Elischer if ((error = ng_make_node_common(type, nodepp)) == 0) { 5995633ca71SGleb Smirnoff if ((error = ((*type->constructor)(*nodepp))) != 0) { 60030400f03SJulian Elischer NG_NODE_UNREF(*nodepp); 601069154d5SJulian Elischer } 602069154d5SJulian Elischer } 603069154d5SJulian Elischer } else { 604069154d5SJulian Elischer /* 605069154d5SJulian Elischer * Node has no constructor. We cannot ask for one 60664efc707SRobert Watson * to be made. It must be brought into existence by 607954c4772SJulian Elischer * some external agency. The external agency should 608069154d5SJulian Elischer * call ng_make_node_common() directly to get the 609069154d5SJulian Elischer * netgraph part initialised. 610069154d5SJulian Elischer */ 6116b795970SJulian Elischer TRAP_ERROR(); 612069154d5SJulian Elischer error = EINVAL; 613069154d5SJulian Elischer } 614069154d5SJulian Elischer return (error); 6154cf49a43SJulian Elischer } 6164cf49a43SJulian Elischer 6174cf49a43SJulian Elischer /* 618069154d5SJulian Elischer * Generic node creation. Called by node initialisation for externally 619069154d5SJulian Elischer * instantiated nodes (e.g. hardware, sockets, etc ). 6204cf49a43SJulian Elischer * The returned node has a reference count of 1. 6214cf49a43SJulian Elischer */ 6224cf49a43SJulian Elischer int 6234cf49a43SJulian Elischer ng_make_node_common(struct ng_type *type, node_p *nodepp) 6244cf49a43SJulian Elischer { 6254cf49a43SJulian Elischer node_p node; 6264cf49a43SJulian Elischer 6274cf49a43SJulian Elischer /* Require the node type to have been already installed */ 6284cf49a43SJulian Elischer if (ng_findtype(type->name) == NULL) { 6296b795970SJulian Elischer TRAP_ERROR(); 6304cf49a43SJulian Elischer return (EINVAL); 6314cf49a43SJulian Elischer } 6324cf49a43SJulian Elischer 6334cf49a43SJulian Elischer /* Make a node and try attach it to the type */ 63430400f03SJulian Elischer NG_ALLOC_NODE(node); 6354cf49a43SJulian Elischer if (node == NULL) { 6366b795970SJulian Elischer TRAP_ERROR(); 6374cf49a43SJulian Elischer return (ENOMEM); 6384cf49a43SJulian Elischer } 63930400f03SJulian Elischer node->nd_type = type; 640bc29160dSMarko Zec #ifdef VIMAGE 641bc29160dSMarko Zec node->nd_vnet = curvnet; 642bc29160dSMarko Zec #endif 64330400f03SJulian Elischer NG_NODE_REF(node); /* note reference */ 6444cf49a43SJulian Elischer type->refs++; 6454cf49a43SJulian Elischer 6462c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK_INIT(&node->nd_input_queue); 6479852972bSAlexander Motin STAILQ_INIT(&node->nd_input_queue.queue); 64830400f03SJulian Elischer node->nd_input_queue.q_flags = 0; 6494cf49a43SJulian Elischer 6504cf49a43SJulian Elischer /* Initialize hook list for new node */ 65130400f03SJulian Elischer LIST_INIT(&node->nd_hooks); 6524cf49a43SJulian Elischer 653cfea3f85SAlexander Motin /* Link us into the name hash. */ 654cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 655603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes); 656cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 657069154d5SJulian Elischer 658dc90cad9SJulian Elischer /* get an ID and put us in the hash chain */ 6599ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 66030400f03SJulian Elischer for (;;) { /* wrap protection, even if silly */ 661069154d5SJulian Elischer node_p node2 = NULL; 662ac957cd2SJulian Elischer node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */ 6630f150d04SJulian Elischer 66430400f03SJulian Elischer /* Is there a problem with the new number? */ 6650f150d04SJulian Elischer NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */ 6660f150d04SJulian Elischer if ((node->nd_ID != 0) && (node2 == NULL)) { 66730400f03SJulian Elischer break; 668069154d5SJulian Elischer } 66930400f03SJulian Elischer } 670603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], 67130400f03SJulian Elischer node, nd_idnodes); 6729ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 673dc90cad9SJulian Elischer 6744cf49a43SJulian Elischer /* Done */ 6754cf49a43SJulian Elischer *nodepp = node; 6764cf49a43SJulian Elischer return (0); 6774cf49a43SJulian Elischer } 6784cf49a43SJulian Elischer 6794cf49a43SJulian Elischer /* 6804cf49a43SJulian Elischer * Forceably start the shutdown process on a node. Either call 68164efc707SRobert Watson * its shutdown method, or do the default shutdown if there is 6824cf49a43SJulian Elischer * no type-specific method. 6834cf49a43SJulian Elischer * 68464efc707SRobert Watson * We can only be called from a shutdown message, so we know we have 6853e4084c8SJulian Elischer * a writer lock, and therefore exclusive access. It also means 6863e4084c8SJulian Elischer * that we should not be on the work queue, but we check anyhow. 687069154d5SJulian Elischer * 688069154d5SJulian Elischer * Persistent node types must have a type-specific method which 68964efc707SRobert Watson * allocates a new node in which case, this one is irretrievably going away, 6903e4084c8SJulian Elischer * or cleans up anything it needs, and just makes the node valid again, 6913e4084c8SJulian Elischer * in which case we allow the node to survive. 6923e4084c8SJulian Elischer * 69364efc707SRobert Watson * XXX We need to think of how to tell a persistent node that we 6943e4084c8SJulian Elischer * REALLY need to go away because the hardware has gone or we 6953e4084c8SJulian Elischer * are rebooting.... etc. 6964cf49a43SJulian Elischer */ 6974cf49a43SJulian Elischer void 6981acb27c6SJulian Elischer ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3) 6994cf49a43SJulian Elischer { 7003e4084c8SJulian Elischer hook_p hook; 7013e4084c8SJulian Elischer 7024cf49a43SJulian Elischer /* Check if it's already shutting down */ 703be4252b3SJulian Elischer if ((node->nd_flags & NGF_CLOSING) != 0) 7044cf49a43SJulian Elischer return; 7054cf49a43SJulian Elischer 7061acb27c6SJulian Elischer if (node == &ng_deadnode) { 7071acb27c6SJulian Elischer printf ("shutdown called on deadnode\n"); 7081acb27c6SJulian Elischer return; 7091acb27c6SJulian Elischer } 7101acb27c6SJulian Elischer 7114cf49a43SJulian Elischer /* Add an extra reference so it doesn't go away during this */ 71230400f03SJulian Elischer NG_NODE_REF(node); 7134cf49a43SJulian Elischer 71430400f03SJulian Elischer /* 71530400f03SJulian Elischer * Mark it invalid so any newcomers know not to try use it 71630400f03SJulian Elischer * Also add our own mark so we can't recurse 717be4252b3SJulian Elischer * note that NGF_INVALID does not do this as it's also set during 71830400f03SJulian Elischer * creation 71930400f03SJulian Elischer */ 720be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID|NGF_CLOSING; 7214cf49a43SJulian Elischer 722991fc65aSJulian Elischer /* If node has its pre-shutdown method, then call it first*/ 723991fc65aSJulian Elischer if (node->nd_type && node->nd_type->close) 724991fc65aSJulian Elischer (*node->nd_type->close)(node); 725991fc65aSJulian Elischer 7263e4084c8SJulian Elischer /* Notify all remaining connected nodes to disconnect */ 7273e4084c8SJulian Elischer while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL) 7283e4084c8SJulian Elischer ng_destroy_hook(hook); 72930400f03SJulian Elischer 730069154d5SJulian Elischer /* 731069154d5SJulian Elischer * Drain the input queue forceably. 73230400f03SJulian Elischer * it has no hooks so what's it going to do, bleed on someone? 73330400f03SJulian Elischer * Theoretically we came here from a queue entry that was added 73430400f03SJulian Elischer * Just before the queue was closed, so it should be empty anyway. 735b57a7965SJulian Elischer * Also removes us from worklist if needed. 736069154d5SJulian Elischer */ 7379852972bSAlexander Motin ng_flush_input_queue(node); 738069154d5SJulian Elischer 739069154d5SJulian Elischer /* Ask the type if it has anything to do in this case */ 74030400f03SJulian Elischer if (node->nd_type && node->nd_type->shutdown) { 74130400f03SJulian Elischer (*node->nd_type->shutdown)(node); 74230400f03SJulian Elischer if (NG_NODE_IS_VALID(node)) { 74330400f03SJulian Elischer /* 74430400f03SJulian Elischer * Well, blow me down if the node code hasn't declared 74530400f03SJulian Elischer * that it doesn't want to die. 74630400f03SJulian Elischer * Presumably it is a persistant node. 7471acb27c6SJulian Elischer * If we REALLY want it to go away, 7481acb27c6SJulian Elischer * e.g. hardware going away, 749be4252b3SJulian Elischer * Our caller should set NGF_REALLY_DIE in nd_flags. 75030400f03SJulian Elischer */ 751be4252b3SJulian Elischer node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING); 7521acb27c6SJulian Elischer NG_NODE_UNREF(node); /* Assume they still have theirs */ 75330400f03SJulian Elischer return; 7544cf49a43SJulian Elischer } 7551acb27c6SJulian Elischer } else { /* do the default thing */ 7561acb27c6SJulian Elischer NG_NODE_UNREF(node); 7571acb27c6SJulian Elischer } 7584cf49a43SJulian Elischer 75930400f03SJulian Elischer ng_unname(node); /* basically a NOP these days */ 76030400f03SJulian Elischer 76130400f03SJulian Elischer /* 76230400f03SJulian Elischer * Remove extra reference, possibly the last 76330400f03SJulian Elischer * Possible other holders of references may include 76430400f03SJulian Elischer * timeout callouts, but theoretically the node's supposed to 76530400f03SJulian Elischer * have cancelled them. Possibly hardware dependencies may 76630400f03SJulian Elischer * force a driver to 'linger' with a reference. 76730400f03SJulian Elischer */ 76830400f03SJulian Elischer NG_NODE_UNREF(node); 7694cf49a43SJulian Elischer } 7704cf49a43SJulian Elischer 7715951069aSJulian Elischer /* 7725951069aSJulian Elischer * Remove a reference to the node, possibly the last. 7735951069aSJulian Elischer * deadnode always acts as it it were the last. 7745951069aSJulian Elischer */ 7753fbdf774SGleb Smirnoff void 77630400f03SJulian Elischer ng_unref_node(node_p node) 7774cf49a43SJulian Elischer { 7786b795970SJulian Elischer 7793fbdf774SGleb Smirnoff if (node == &ng_deadnode) 7803fbdf774SGleb Smirnoff return; 7816b795970SJulian Elischer 7823fbdf774SGleb Smirnoff if (refcount_release(&node->nd_refs)) { /* we were the last */ 783069154d5SJulian Elischer 784cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 78530400f03SJulian Elischer node->nd_type->refs--; /* XXX maybe should get types lock? */ 78630400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 787cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 788069154d5SJulian Elischer 7899ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 79030400f03SJulian Elischer LIST_REMOVE(node, nd_idnodes); 7919ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 792069154d5SJulian Elischer 79312574a02SJulian Elischer mtx_destroy(&node->nd_input_queue.q_mtx); 794069154d5SJulian Elischer NG_FREE_NODE(node); 7954cf49a43SJulian Elischer } 7964cf49a43SJulian Elischer } 7974cf49a43SJulian Elischer 7984cf49a43SJulian Elischer /************************************************************************ 799dc90cad9SJulian Elischer Node ID handling 800dc90cad9SJulian Elischer ************************************************************************/ 801dc90cad9SJulian Elischer static node_p 802069154d5SJulian Elischer ng_ID2noderef(ng_ID_t ID) 803dc90cad9SJulian Elischer { 80430400f03SJulian Elischer node_p node; 8059ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 8060f150d04SJulian Elischer NG_IDHASH_FIND(ID, node); 80730400f03SJulian Elischer if(node) 80830400f03SJulian Elischer NG_NODE_REF(node); 8099ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 81030400f03SJulian Elischer return(node); 811dc90cad9SJulian Elischer } 812dc90cad9SJulian Elischer 813dc90cad9SJulian Elischer ng_ID_t 814dc90cad9SJulian Elischer ng_node2ID(node_p node) 815dc90cad9SJulian Elischer { 81670de87f2SJulian Elischer return (node ? NG_NODE_ID(node) : 0); 817dc90cad9SJulian Elischer } 818dc90cad9SJulian Elischer 819dc90cad9SJulian Elischer /************************************************************************ 8204cf49a43SJulian Elischer Node name handling 8214cf49a43SJulian Elischer ************************************************************************/ 8224cf49a43SJulian Elischer 8234cf49a43SJulian Elischer /* 8244cf49a43SJulian Elischer * Assign a node a name. Once assigned, the name cannot be changed. 8254cf49a43SJulian Elischer */ 8264cf49a43SJulian Elischer int 8274cf49a43SJulian Elischer ng_name_node(node_p node, const char *name) 8284cf49a43SJulian Elischer { 829cfea3f85SAlexander Motin int i, hash; 830069154d5SJulian Elischer node_p node2; 8314cf49a43SJulian Elischer 8324cf49a43SJulian Elischer /* Check the name is valid */ 83387e2c66aSHartmut Brandt for (i = 0; i < NG_NODESIZ; i++) { 8344cf49a43SJulian Elischer if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 8354cf49a43SJulian Elischer break; 8364cf49a43SJulian Elischer } 8374cf49a43SJulian Elischer if (i == 0 || name[i] != '\0') { 8386b795970SJulian Elischer TRAP_ERROR(); 8394cf49a43SJulian Elischer return (EINVAL); 8404cf49a43SJulian Elischer } 841dc90cad9SJulian Elischer if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 8426b795970SJulian Elischer TRAP_ERROR(); 8434cf49a43SJulian Elischer return (EINVAL); 8444cf49a43SJulian Elischer } 8454cf49a43SJulian Elischer 8464cf49a43SJulian Elischer /* Check the name isn't already being used */ 847069154d5SJulian Elischer if ((node2 = ng_name2noderef(node, name)) != NULL) { 84830400f03SJulian Elischer NG_NODE_UNREF(node2); 8496b795970SJulian Elischer TRAP_ERROR(); 8504cf49a43SJulian Elischer return (EADDRINUSE); 8514cf49a43SJulian Elischer } 8524cf49a43SJulian Elischer 853069154d5SJulian Elischer /* copy it */ 85487e2c66aSHartmut Brandt strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ); 8554cf49a43SJulian Elischer 856cfea3f85SAlexander Motin /* Update name hash. */ 857cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 858cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 859cfea3f85SAlexander Motin LIST_REMOVE(node, nd_nodes); 860603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes); 861cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 862cfea3f85SAlexander Motin 8634cf49a43SJulian Elischer return (0); 8644cf49a43SJulian Elischer } 8654cf49a43SJulian Elischer 8664cf49a43SJulian Elischer /* 8674cf49a43SJulian Elischer * Find a node by absolute name. The name should NOT end with ':' 8684cf49a43SJulian Elischer * The name "." means "this node" and "[xxx]" means "the node 8694cf49a43SJulian Elischer * with ID (ie, at address) xxx". 8704cf49a43SJulian Elischer * 8714cf49a43SJulian Elischer * Returns the node if found, else NULL. 872069154d5SJulian Elischer * Eventually should add something faster than a sequential search. 873e1e8f51bSRobert Watson * Note it acquires a reference on the node so you can be sure it's still 874e1e8f51bSRobert Watson * there. 8754cf49a43SJulian Elischer */ 8764cf49a43SJulian Elischer node_p 877069154d5SJulian Elischer ng_name2noderef(node_p here, const char *name) 8784cf49a43SJulian Elischer { 879dc90cad9SJulian Elischer node_p node; 880dc90cad9SJulian Elischer ng_ID_t temp; 881cfea3f85SAlexander Motin int hash; 8824cf49a43SJulian Elischer 8834cf49a43SJulian Elischer /* "." means "this node" */ 884069154d5SJulian Elischer if (strcmp(name, ".") == 0) { 88530400f03SJulian Elischer NG_NODE_REF(here); 886069154d5SJulian Elischer return(here); 887069154d5SJulian Elischer } 8884cf49a43SJulian Elischer 8894cf49a43SJulian Elischer /* Check for name-by-ID */ 890dc90cad9SJulian Elischer if ((temp = ng_decodeidname(name)) != 0) { 891069154d5SJulian Elischer return (ng_ID2noderef(temp)); 8924cf49a43SJulian Elischer } 8934cf49a43SJulian Elischer 8944cf49a43SJulian Elischer /* Find node by name */ 895cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 896cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 897603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) { 898cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 899cfea3f85SAlexander Motin (strcmp(NG_NODE_NAME(node), name) == 0)) { 9004cf49a43SJulian Elischer break; 9014cf49a43SJulian Elischer } 90270de87f2SJulian Elischer } 903069154d5SJulian Elischer if (node) 90430400f03SJulian Elischer NG_NODE_REF(node); 905cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 9064cf49a43SJulian Elischer return (node); 9074cf49a43SJulian Elischer } 9084cf49a43SJulian Elischer 9094cf49a43SJulian Elischer /* 9109d5abbddSJens Schweikhardt * Decode an ID name, eg. "[f03034de]". Returns 0 if the 911dc90cad9SJulian Elischer * string is not valid, otherwise returns the value. 9124cf49a43SJulian Elischer */ 913dc90cad9SJulian Elischer static ng_ID_t 9144cf49a43SJulian Elischer ng_decodeidname(const char *name) 9154cf49a43SJulian Elischer { 9162b70adcbSArchie Cobbs const int len = strlen(name); 91725792ef3SArchie Cobbs char *eptr; 9182b70adcbSArchie Cobbs u_long val; 9194cf49a43SJulian Elischer 9202b70adcbSArchie Cobbs /* Check for proper length, brackets, no leading junk */ 92170de87f2SJulian Elischer if ((len < 3) 92270de87f2SJulian Elischer || (name[0] != '[') 92370de87f2SJulian Elischer || (name[len - 1] != ']') 92470de87f2SJulian Elischer || (!isxdigit(name[1]))) { 92570de87f2SJulian Elischer return ((ng_ID_t)0); 92670de87f2SJulian Elischer } 9274cf49a43SJulian Elischer 9282b70adcbSArchie Cobbs /* Decode number */ 9292b70adcbSArchie Cobbs val = strtoul(name + 1, &eptr, 16); 93070de87f2SJulian Elischer if ((eptr - name != len - 1) 93170de87f2SJulian Elischer || (val == ULONG_MAX) 93270de87f2SJulian Elischer || (val == 0)) { 93312f035e0SJulian Elischer return ((ng_ID_t)0); 93470de87f2SJulian Elischer } 9352b70adcbSArchie Cobbs return (ng_ID_t)val; 9364cf49a43SJulian Elischer } 9374cf49a43SJulian Elischer 9384cf49a43SJulian Elischer /* 9394cf49a43SJulian Elischer * Remove a name from a node. This should only be called 9404cf49a43SJulian Elischer * when shutting down and removing the node. 94164efc707SRobert Watson * IF we allow name changing this may be more resurrected. 9424cf49a43SJulian Elischer */ 9434cf49a43SJulian Elischer void 9444cf49a43SJulian Elischer ng_unname(node_p node) 9454cf49a43SJulian Elischer { 9464cf49a43SJulian Elischer } 9474cf49a43SJulian Elischer 9484cf49a43SJulian Elischer /************************************************************************ 9494cf49a43SJulian Elischer Hook routines 9504cf49a43SJulian Elischer Names are not optional. Hooks are always connected, except for a 9513e4084c8SJulian Elischer brief moment within these routines. On invalidation or during creation 9523e4084c8SJulian Elischer they are connected to the 'dead' hook. 9534cf49a43SJulian Elischer ************************************************************************/ 9544cf49a43SJulian Elischer 9554cf49a43SJulian Elischer /* 9564cf49a43SJulian Elischer * Remove a hook reference 9574cf49a43SJulian Elischer */ 95830400f03SJulian Elischer void 9594cf49a43SJulian Elischer ng_unref_hook(hook_p hook) 9604cf49a43SJulian Elischer { 9616b795970SJulian Elischer 9623fbdf774SGleb Smirnoff if (hook == &ng_deadhook) 9636b795970SJulian Elischer return; 964018fe3d1SAlexander Motin 9653fbdf774SGleb Smirnoff if (refcount_release(&hook->hk_refs)) { /* we were the last */ 966f573da1aSAlexander Motin if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */ 9676b795970SJulian Elischer _NG_NODE_UNREF((_NG_HOOK_NODE(hook))); 968069154d5SJulian Elischer NG_FREE_HOOK(hook); 969069154d5SJulian Elischer } 9704cf49a43SJulian Elischer } 9714cf49a43SJulian Elischer 9724cf49a43SJulian Elischer /* 9734cf49a43SJulian Elischer * Add an unconnected hook to a node. Only used internally. 9743e4084c8SJulian Elischer * Assumes node is locked. (XXX not yet true ) 9754cf49a43SJulian Elischer */ 9764cf49a43SJulian Elischer static int 9774cf49a43SJulian Elischer ng_add_hook(node_p node, const char *name, hook_p *hookp) 9784cf49a43SJulian Elischer { 9794cf49a43SJulian Elischer hook_p hook; 9804cf49a43SJulian Elischer int error = 0; 9814cf49a43SJulian Elischer 9824cf49a43SJulian Elischer /* Check that the given name is good */ 9834cf49a43SJulian Elischer if (name == NULL) { 9846b795970SJulian Elischer TRAP_ERROR(); 9854cf49a43SJulian Elischer return (EINVAL); 9864cf49a43SJulian Elischer } 987899e9c4eSArchie Cobbs if (ng_findhook(node, name) != NULL) { 9886b795970SJulian Elischer TRAP_ERROR(); 9894cf49a43SJulian Elischer return (EEXIST); 9904cf49a43SJulian Elischer } 9914cf49a43SJulian Elischer 9924cf49a43SJulian Elischer /* Allocate the hook and link it up */ 99330400f03SJulian Elischer NG_ALLOC_HOOK(hook); 9944cf49a43SJulian Elischer if (hook == NULL) { 9956b795970SJulian Elischer TRAP_ERROR(); 9964cf49a43SJulian Elischer return (ENOMEM); 9974cf49a43SJulian Elischer } 9983e4084c8SJulian Elischer hook->hk_refs = 1; /* add a reference for us to return */ 99930400f03SJulian Elischer hook->hk_flags = HK_INVALID; 10003e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* start off this way */ 100130400f03SJulian Elischer hook->hk_node = node; 100230400f03SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 10034cf49a43SJulian Elischer 10043e4084c8SJulian Elischer /* Set hook name */ 100587e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ); 10063e4084c8SJulian Elischer 10073e4084c8SJulian Elischer /* 10083e4084c8SJulian Elischer * Check if the node type code has something to say about it 10093e4084c8SJulian Elischer * If it fails, the unref of the hook will also unref the node. 10103e4084c8SJulian Elischer */ 1011954c4772SJulian Elischer if (node->nd_type->newhook != NULL) { 1012954c4772SJulian Elischer if ((error = (*node->nd_type->newhook)(node, hook, name))) { 101330400f03SJulian Elischer NG_HOOK_UNREF(hook); /* this frees the hook */ 1014069154d5SJulian Elischer return (error); 1015069154d5SJulian Elischer } 1016954c4772SJulian Elischer } 10174cf49a43SJulian Elischer /* 10184cf49a43SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 10194cf49a43SJulian Elischer * We'll ask again later when we actually connect the hooks. 10204cf49a43SJulian Elischer */ 102130400f03SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 102230400f03SJulian Elischer node->nd_numhooks++; 10233e4084c8SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 10244cf49a43SJulian Elischer 10254cf49a43SJulian Elischer if (hookp) 10264cf49a43SJulian Elischer *hookp = hook; 10273e4084c8SJulian Elischer return (0); 10284cf49a43SJulian Elischer } 10294cf49a43SJulian Elischer 10304cf49a43SJulian Elischer /* 1031899e9c4eSArchie Cobbs * Find a hook 1032899e9c4eSArchie Cobbs * 1033899e9c4eSArchie Cobbs * Node types may supply their own optimized routines for finding 1034899e9c4eSArchie Cobbs * hooks. If none is supplied, we just do a linear search. 10353e4084c8SJulian Elischer * XXX Possibly we should add a reference to the hook? 1036899e9c4eSArchie Cobbs */ 1037899e9c4eSArchie Cobbs hook_p 1038899e9c4eSArchie Cobbs ng_findhook(node_p node, const char *name) 1039899e9c4eSArchie Cobbs { 1040899e9c4eSArchie Cobbs hook_p hook; 1041899e9c4eSArchie Cobbs 104230400f03SJulian Elischer if (node->nd_type->findhook != NULL) 104330400f03SJulian Elischer return (*node->nd_type->findhook)(node, name); 104430400f03SJulian Elischer LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 104570de87f2SJulian Elischer if (NG_HOOK_IS_VALID(hook) 1046ce5e5f99SArchie Cobbs && (strcmp(NG_HOOK_NAME(hook), name) == 0)) 1047899e9c4eSArchie Cobbs return (hook); 1048899e9c4eSArchie Cobbs } 1049899e9c4eSArchie Cobbs return (NULL); 1050899e9c4eSArchie Cobbs } 1051899e9c4eSArchie Cobbs 1052899e9c4eSArchie Cobbs /* 10534cf49a43SJulian Elischer * Destroy a hook 10544cf49a43SJulian Elischer * 10554cf49a43SJulian Elischer * As hooks are always attached, this really destroys two hooks. 10564cf49a43SJulian Elischer * The one given, and the one attached to it. Disconnect the hooks 10573e4084c8SJulian Elischer * from each other first. We reconnect the peer hook to the 'dead' 10583e4084c8SJulian Elischer * hook so that it can still exist after we depart. We then 10593e4084c8SJulian Elischer * send the peer its own destroy message. This ensures that we only 10603e4084c8SJulian Elischer * interact with the peer's structures when it is locked processing that 10613e4084c8SJulian Elischer * message. We hold a reference to the peer hook so we are guaranteed that 10623e4084c8SJulian Elischer * the peer hook and node are still going to exist until 10633e4084c8SJulian Elischer * we are finished there as the hook holds a ref on the node. 10643e4084c8SJulian Elischer * We run this same code again on the peer hook, but that time it is already 10653e4084c8SJulian Elischer * attached to the 'dead' hook. 10666b795970SJulian Elischer * 10676b795970SJulian Elischer * This routine is called at all stages of hook creation 10686b795970SJulian Elischer * on error detection and must be able to handle any such stage. 10694cf49a43SJulian Elischer */ 10704cf49a43SJulian Elischer void 10714cf49a43SJulian Elischer ng_destroy_hook(hook_p hook) 10724cf49a43SJulian Elischer { 1073ac5dd141SGleb Smirnoff hook_p peer; 1074ac5dd141SGleb Smirnoff node_p node; 10754cf49a43SJulian Elischer 10766b795970SJulian Elischer if (hook == &ng_deadhook) { /* better safe than sorry */ 10776b795970SJulian Elischer printf("ng_destroy_hook called on deadhook\n"); 10786b795970SJulian Elischer return; 10796b795970SJulian Elischer } 1080ac5dd141SGleb Smirnoff 1081ac5dd141SGleb Smirnoff /* 1082ac5dd141SGleb Smirnoff * Protect divorce process with mutex, to avoid races on 1083ac5dd141SGleb Smirnoff * simultaneous disconnect. 1084ac5dd141SGleb Smirnoff */ 1085ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1086ac5dd141SGleb Smirnoff 1087ac5dd141SGleb Smirnoff hook->hk_flags |= HK_INVALID; 1088ac5dd141SGleb Smirnoff 1089ac5dd141SGleb Smirnoff peer = NG_HOOK_PEER(hook); 1090ac5dd141SGleb Smirnoff node = NG_HOOK_NODE(hook); 1091ac5dd141SGleb Smirnoff 10923e4084c8SJulian Elischer if (peer && (peer != &ng_deadhook)) { 10933e4084c8SJulian Elischer /* 10943e4084c8SJulian Elischer * Set the peer to point to ng_deadhook 10953e4084c8SJulian Elischer * from this moment on we are effectively independent it. 10963e4084c8SJulian Elischer * send it an rmhook message of it's own. 10973e4084c8SJulian Elischer */ 10983e4084c8SJulian Elischer peer->hk_peer = &ng_deadhook; /* They no longer know us */ 10993e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* Nor us, them */ 11006b795970SJulian Elischer if (NG_HOOK_NODE(peer) == &ng_deadnode) { 11016b795970SJulian Elischer /* 11026b795970SJulian Elischer * If it's already divorced from a node, 11036b795970SJulian Elischer * just free it. 11046b795970SJulian Elischer */ 1105ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11066b795970SJulian Elischer } else { 1107ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11086b795970SJulian Elischer ng_rmhook_self(peer); /* Send it a surprise */ 11096b795970SJulian Elischer } 111052fa3556SJulian Elischer NG_HOOK_UNREF(peer); /* account for peer link */ 111152fa3556SJulian Elischer NG_HOOK_UNREF(hook); /* account for peer link */ 1112ac5dd141SGleb Smirnoff } else 1113ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1114ac5dd141SGleb Smirnoff 1115ac5dd141SGleb Smirnoff mtx_assert(&ng_topo_mtx, MA_NOTOWNED); 11164cf49a43SJulian Elischer 11174cf49a43SJulian Elischer /* 11184cf49a43SJulian Elischer * Remove the hook from the node's list to avoid possible recursion 11194cf49a43SJulian Elischer * in case the disconnection results in node shutdown. 11204cf49a43SJulian Elischer */ 11216b795970SJulian Elischer if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */ 11226b795970SJulian Elischer return; 11236b795970SJulian Elischer } 112430400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 112530400f03SJulian Elischer node->nd_numhooks--; 112630400f03SJulian Elischer if (node->nd_type->disconnect) { 11274cf49a43SJulian Elischer /* 11286b795970SJulian Elischer * The type handler may elect to destroy the node so don't 112964efc707SRobert Watson * trust its existence after this point. (except 11306b795970SJulian Elischer * that we still hold a reference on it. (which we 11316b795970SJulian Elischer * inherrited from the hook we are destroying) 11324cf49a43SJulian Elischer */ 113330400f03SJulian Elischer (*node->nd_type->disconnect) (hook); 11344cf49a43SJulian Elischer } 11356b795970SJulian Elischer 11366b795970SJulian Elischer /* 11376b795970SJulian Elischer * Note that because we will point to ng_deadnode, the original node 11386b795970SJulian Elischer * is not decremented automatically so we do that manually. 11396b795970SJulian Elischer */ 11406b795970SJulian Elischer _NG_HOOK_NODE(hook) = &ng_deadnode; 11416b795970SJulian Elischer NG_NODE_UNREF(node); /* We no longer point to it so adjust count */ 11426b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Account for linkage (in list) to node */ 11434cf49a43SJulian Elischer } 11444cf49a43SJulian Elischer 11454cf49a43SJulian Elischer /* 11464cf49a43SJulian Elischer * Take two hooks on a node and merge the connection so that the given node 11474cf49a43SJulian Elischer * is effectively bypassed. 11484cf49a43SJulian Elischer */ 11494cf49a43SJulian Elischer int 11504cf49a43SJulian Elischer ng_bypass(hook_p hook1, hook_p hook2) 11514cf49a43SJulian Elischer { 115230400f03SJulian Elischer if (hook1->hk_node != hook2->hk_node) { 11536b795970SJulian Elischer TRAP_ERROR(); 11544cf49a43SJulian Elischer return (EINVAL); 115530400f03SJulian Elischer } 1156a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 115730400f03SJulian Elischer hook1->hk_peer->hk_peer = hook2->hk_peer; 115830400f03SJulian Elischer hook2->hk_peer->hk_peer = hook1->hk_peer; 11594cf49a43SJulian Elischer 11603e4084c8SJulian Elischer hook1->hk_peer = &ng_deadhook; 11613e4084c8SJulian Elischer hook2->hk_peer = &ng_deadhook; 1162a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11633e4084c8SJulian Elischer 1164cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook1); 1165cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook2); 1166cf3254aaSGleb Smirnoff 11674cf49a43SJulian Elischer /* XXX If we ever cache methods on hooks update them as well */ 11684cf49a43SJulian Elischer ng_destroy_hook(hook1); 11694cf49a43SJulian Elischer ng_destroy_hook(hook2); 11704cf49a43SJulian Elischer return (0); 11714cf49a43SJulian Elischer } 11724cf49a43SJulian Elischer 11734cf49a43SJulian Elischer /* 11744cf49a43SJulian Elischer * Install a new netgraph type 11754cf49a43SJulian Elischer */ 11764cf49a43SJulian Elischer int 11774cf49a43SJulian Elischer ng_newtype(struct ng_type *tp) 11784cf49a43SJulian Elischer { 11794cf49a43SJulian Elischer const size_t namelen = strlen(tp->name); 11804cf49a43SJulian Elischer 11814cf49a43SJulian Elischer /* Check version and type name fields */ 1182589f6ed8SJulian Elischer if ((tp->version != NG_ABI_VERSION) 1183589f6ed8SJulian Elischer || (namelen == 0) 118487e2c66aSHartmut Brandt || (namelen >= NG_TYPESIZ)) { 11856b795970SJulian Elischer TRAP_ERROR(); 11868ed370fdSJulian Elischer if (tp->version != NG_ABI_VERSION) { 11878ed370fdSJulian Elischer printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n"); 11888ed370fdSJulian Elischer } 11894cf49a43SJulian Elischer return (EINVAL); 11904cf49a43SJulian Elischer } 11914cf49a43SJulian Elischer 11924cf49a43SJulian Elischer /* Check for name collision */ 11934cf49a43SJulian Elischer if (ng_findtype(tp->name) != NULL) { 11946b795970SJulian Elischer TRAP_ERROR(); 11954cf49a43SJulian Elischer return (EEXIST); 11964cf49a43SJulian Elischer } 11974cf49a43SJulian Elischer 1198069154d5SJulian Elischer 1199069154d5SJulian Elischer /* Link in new type */ 12009ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 1201069154d5SJulian Elischer LIST_INSERT_HEAD(&ng_typelist, tp, types); 1202c73b94a2SJulian Elischer tp->refs = 1; /* first ref is linked list */ 12039ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 12044cf49a43SJulian Elischer return (0); 12054cf49a43SJulian Elischer } 12064cf49a43SJulian Elischer 12074cf49a43SJulian Elischer /* 1208c31b4a53SJulian Elischer * unlink a netgraph type 1209c31b4a53SJulian Elischer * If no examples exist 1210c31b4a53SJulian Elischer */ 1211c31b4a53SJulian Elischer int 1212c31b4a53SJulian Elischer ng_rmtype(struct ng_type *tp) 1213c31b4a53SJulian Elischer { 1214c31b4a53SJulian Elischer /* Check for name collision */ 1215c31b4a53SJulian Elischer if (tp->refs != 1) { 1216c31b4a53SJulian Elischer TRAP_ERROR(); 1217c31b4a53SJulian Elischer return (EBUSY); 1218c31b4a53SJulian Elischer } 1219c31b4a53SJulian Elischer 1220c31b4a53SJulian Elischer /* Unlink type */ 1221c31b4a53SJulian Elischer mtx_lock(&ng_typelist_mtx); 1222c31b4a53SJulian Elischer LIST_REMOVE(tp, types); 1223c31b4a53SJulian Elischer mtx_unlock(&ng_typelist_mtx); 1224c31b4a53SJulian Elischer return (0); 1225c31b4a53SJulian Elischer } 1226c31b4a53SJulian Elischer 1227c31b4a53SJulian Elischer /* 12284cf49a43SJulian Elischer * Look for a type of the name given 12294cf49a43SJulian Elischer */ 12304cf49a43SJulian Elischer struct ng_type * 12314cf49a43SJulian Elischer ng_findtype(const char *typename) 12324cf49a43SJulian Elischer { 12334cf49a43SJulian Elischer struct ng_type *type; 12344cf49a43SJulian Elischer 12359ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 1236069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 12374cf49a43SJulian Elischer if (strcmp(type->name, typename) == 0) 12384cf49a43SJulian Elischer break; 12394cf49a43SJulian Elischer } 12409ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 12414cf49a43SJulian Elischer return (type); 12424cf49a43SJulian Elischer } 12434cf49a43SJulian Elischer 12444cf49a43SJulian Elischer /************************************************************************ 12454cf49a43SJulian Elischer Composite routines 12464cf49a43SJulian Elischer ************************************************************************/ 12474cf49a43SJulian Elischer /* 12486b795970SJulian Elischer * Connect two nodes using the specified hooks, using queued functions. 12494cf49a43SJulian Elischer */ 1250e088dd4cSAlexander Motin static int 1251e088dd4cSAlexander Motin ng_con_part3(node_p node, item_p item, hook_p hook) 12524cf49a43SJulian Elischer { 1253e088dd4cSAlexander Motin int error = 0; 12544cf49a43SJulian Elischer 12556b795970SJulian Elischer /* 12566b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 12576b795970SJulian Elischer * Our caller has a reference on the hook. 12586b795970SJulian Elischer * Our caller has a reference on the node. 12596b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 12606b795970SJulian Elischer * The peer hook has a reference on the hook. 12611acb27c6SJulian Elischer * We are all set up except for the final call to the node, and 12621acb27c6SJulian Elischer * the clearing of the INVALID flag. 12636b795970SJulian Elischer */ 12646b795970SJulian Elischer if (NG_HOOK_NODE(hook) == &ng_deadnode) { 12656b795970SJulian Elischer /* 12666b795970SJulian Elischer * The node must have been freed again since we last visited 12676b795970SJulian Elischer * here. ng_destry_hook() has this effect but nothing else does. 12686b795970SJulian Elischer * We should just release our references and 12696b795970SJulian Elischer * free anything we can think of. 12706b795970SJulian Elischer * Since we know it's been destroyed, and it's our caller 12716b795970SJulian Elischer * that holds the references, just return. 12726b795970SJulian Elischer */ 1273e088dd4cSAlexander Motin ERROUT(ENOENT); 12746b795970SJulian Elischer } 12756b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1276e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 12776b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 12781acb27c6SJulian Elischer printf("failed in ng_con_part3()\n"); 1279e088dd4cSAlexander Motin ERROUT(error); 12804cf49a43SJulian Elischer } 12816b795970SJulian Elischer } 12826b795970SJulian Elischer /* 12836b795970SJulian Elischer * XXX this is wrong for SMP. Possibly we need 12846b795970SJulian Elischer * to separate out 'create' and 'invalid' flags. 12856b795970SJulian Elischer * should only set flags on hooks we have locked under our node. 12866b795970SJulian Elischer */ 12876b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; 1288e088dd4cSAlexander Motin done: 1289e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1290e088dd4cSAlexander Motin return (error); 12916b795970SJulian Elischer } 12926b795970SJulian Elischer 1293e088dd4cSAlexander Motin static int 1294e088dd4cSAlexander Motin ng_con_part2(node_p node, item_p item, hook_p hook) 12956b795970SJulian Elischer { 1296ac5dd141SGleb Smirnoff hook_p peer; 1297e088dd4cSAlexander Motin int error = 0; 12986b795970SJulian Elischer 12996b795970SJulian Elischer /* 13006b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 13016b795970SJulian Elischer * Our caller has a reference on the hook. 13026b795970SJulian Elischer * Our caller has a reference on the node. 13036b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 13046b795970SJulian Elischer * The peer hook has a reference on the hook. 13056b795970SJulian Elischer * our node pointer points to the 'dead' node. 13066b795970SJulian Elischer * First check the hook name is unique. 13071acb27c6SJulian Elischer * Should not happen because we checked before queueing this. 13086b795970SJulian Elischer */ 13096b795970SJulian Elischer if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) { 13106b795970SJulian Elischer TRAP_ERROR(); 13116b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13121acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1313e088dd4cSAlexander Motin ERROUT(EEXIST); 13146b795970SJulian Elischer } 13156b795970SJulian Elischer /* 13166b795970SJulian Elischer * Check if the node type code has something to say about it 13176b795970SJulian Elischer * If it fails, the unref of the hook will also unref the attached node, 13186b795970SJulian Elischer * however since that node is 'ng_deadnode' this will do nothing. 13196b795970SJulian Elischer * The peer hook will also be destroyed. 13206b795970SJulian Elischer */ 13216b795970SJulian Elischer if (node->nd_type->newhook != NULL) { 1322e088dd4cSAlexander Motin if ((error = (*node->nd_type->newhook)(node, hook, 1323e088dd4cSAlexander Motin hook->hk_name))) { 13246b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13251acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1326e088dd4cSAlexander Motin ERROUT(error); 13276b795970SJulian Elischer } 13286b795970SJulian Elischer } 13296b795970SJulian Elischer 13306b795970SJulian Elischer /* 13316b795970SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 13326b795970SJulian Elischer * We'll ask again later when we actually connect the hooks. 13336b795970SJulian Elischer */ 13346b795970SJulian Elischer hook->hk_node = node; /* just overwrite ng_deadnode */ 13356b795970SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 13366b795970SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 13376b795970SJulian Elischer node->nd_numhooks++; 13386b795970SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 13396b795970SJulian Elischer 13406b795970SJulian Elischer /* 134164efc707SRobert Watson * We now have a symmetrical situation, where both hooks have been 13425951069aSJulian Elischer * linked to their nodes, the newhook methods have been called 13436b795970SJulian Elischer * And the references are all correct. The hooks are still marked 13446b795970SJulian Elischer * as invalid, as we have not called the 'connect' methods 13456b795970SJulian Elischer * yet. 134664efc707SRobert Watson * We can call the local one immediately as we have the 13476b795970SJulian Elischer * node locked, but we need to queue the remote one. 13486b795970SJulian Elischer */ 13496b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1350e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 13516b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 13521acb27c6SJulian Elischer printf("failed in ng_con_part2(A)\n"); 1353e088dd4cSAlexander Motin ERROUT(error); 13546b795970SJulian Elischer } 13556b795970SJulian Elischer } 1356ac5dd141SGleb Smirnoff 1357ac5dd141SGleb Smirnoff /* 1358ac5dd141SGleb Smirnoff * Acquire topo mutex to avoid race with ng_destroy_hook(). 1359ac5dd141SGleb Smirnoff */ 1360ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1361ac5dd141SGleb Smirnoff peer = hook->hk_peer; 1362ac5dd141SGleb Smirnoff if (peer == &ng_deadhook) { 1363ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1364ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(B)\n"); 1365ac5dd141SGleb Smirnoff ng_destroy_hook(hook); 1366e088dd4cSAlexander Motin ERROUT(ENOENT); 1367ac5dd141SGleb Smirnoff } 1368ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1369ac5dd141SGleb Smirnoff 1370b332b91fSGleb Smirnoff if ((error = ng_send_fn2(peer->hk_node, peer, item, &ng_con_part3, 1371b332b91fSGleb Smirnoff NULL, 0, NG_REUSE_ITEM))) { 1372ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(C)\n"); 13731acb27c6SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 1374e088dd4cSAlexander Motin return (error); /* item was consumed. */ 13751acb27c6SJulian Elischer } 13766b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */ 1377e088dd4cSAlexander Motin return (0); /* item was consumed. */ 1378e088dd4cSAlexander Motin done: 1379e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1380e088dd4cSAlexander Motin return (error); 13814cf49a43SJulian Elischer } 13824cf49a43SJulian Elischer 13834cf49a43SJulian Elischer /* 13846b795970SJulian Elischer * Connect this node with another node. We assume that this node is 13856b795970SJulian Elischer * currently locked, as we are only called from an NGM_CONNECT message. 13864cf49a43SJulian Elischer */ 13876b795970SJulian Elischer static int 1388e088dd4cSAlexander Motin ng_con_nodes(item_p item, node_p node, const char *name, 1389e088dd4cSAlexander Motin node_p node2, const char *name2) 13904cf49a43SJulian Elischer { 13914cf49a43SJulian Elischer int error; 13924cf49a43SJulian Elischer hook_p hook; 13934cf49a43SJulian Elischer hook_p hook2; 13944cf49a43SJulian Elischer 13951acb27c6SJulian Elischer if (ng_findhook(node2, name2) != NULL) { 13961acb27c6SJulian Elischer return(EEXIST); 13971acb27c6SJulian Elischer } 13983e4084c8SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) /* gives us a ref */ 13994cf49a43SJulian Elischer return (error); 14006b795970SJulian Elischer /* Allocate the other hook and link it up */ 14016b795970SJulian Elischer NG_ALLOC_HOOK(hook2); 140219724144SGleb Smirnoff if (hook2 == NULL) { 14036b795970SJulian Elischer TRAP_ERROR(); 14046b795970SJulian Elischer ng_destroy_hook(hook); /* XXX check ref counts so far */ 14056b795970SJulian Elischer NG_HOOK_UNREF(hook); /* including our ref */ 14066b795970SJulian Elischer return (ENOMEM); 14076b795970SJulian Elischer } 14086b795970SJulian Elischer hook2->hk_refs = 1; /* start with a reference for us. */ 14096b795970SJulian Elischer hook2->hk_flags = HK_INVALID; 14106b795970SJulian Elischer hook2->hk_peer = hook; /* Link the two together */ 14116b795970SJulian Elischer hook->hk_peer = hook2; 14126b795970SJulian Elischer NG_HOOK_REF(hook); /* Add a ref for the peer to each*/ 14136b795970SJulian Elischer NG_HOOK_REF(hook2); 14146b795970SJulian Elischer hook2->hk_node = &ng_deadnode; 141587e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ); 14166b795970SJulian Elischer 14176b795970SJulian Elischer /* 14186b795970SJulian Elischer * Queue the function above. 14196b795970SJulian Elischer * Procesing continues in that function in the lock context of 14206b795970SJulian Elischer * the other node. 14216b795970SJulian Elischer */ 1422b332b91fSGleb Smirnoff if ((error = ng_send_fn2(node2, hook2, item, &ng_con_part2, NULL, 0, 1423b332b91fSGleb Smirnoff NG_NOFLAGS))) { 14243fb87c24SAlexander Motin printf("failed in ng_con_nodes(): %d\n", error); 14253fb87c24SAlexander Motin ng_destroy_hook(hook); /* also zaps peer */ 14263fb87c24SAlexander Motin } 14276b795970SJulian Elischer 14286b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Let each hook go if it wants to */ 14296b795970SJulian Elischer NG_HOOK_UNREF(hook2); 14303fb87c24SAlexander Motin return (error); 14314cf49a43SJulian Elischer } 14326b795970SJulian Elischer 14336b795970SJulian Elischer /* 14346b795970SJulian Elischer * Make a peer and connect. 14356b795970SJulian Elischer * We assume that the local node is locked. 14366b795970SJulian Elischer * The new node probably doesn't need a lock until 14376b795970SJulian Elischer * it has a hook, because it cannot really have any work until then, 14386b795970SJulian Elischer * but we should think about it a bit more. 14396b795970SJulian Elischer * 14406b795970SJulian Elischer * The problem may come if the other node also fires up 14416b795970SJulian Elischer * some hardware or a timer or some other source of activation, 14426b795970SJulian Elischer * also it may already get a command msg via it's ID. 14436b795970SJulian Elischer * 14446b795970SJulian Elischer * We could use the same method as ng_con_nodes() but we'd have 14456b795970SJulian Elischer * to add ability to remove the node when failing. (Not hard, just 14466b795970SJulian Elischer * make arg1 point to the node to remove). 14476b795970SJulian Elischer * Unless of course we just ignore failure to connect and leave 14486b795970SJulian Elischer * an unconnected node? 14496b795970SJulian Elischer */ 14506b795970SJulian Elischer static int 14516b795970SJulian Elischer ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 14526b795970SJulian Elischer { 14536b795970SJulian Elischer node_p node2; 14544c9b5910SGleb Smirnoff hook_p hook1, hook2; 14556b795970SJulian Elischer int error; 14566b795970SJulian Elischer 14576b795970SJulian Elischer if ((error = ng_make_node(type, &node2))) { 14586b795970SJulian Elischer return (error); 14596b795970SJulian Elischer } 14606b795970SJulian Elischer 14616b795970SJulian Elischer if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */ 14621acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14636b795970SJulian Elischer return (error); 14646b795970SJulian Elischer } 14656b795970SJulian Elischer 14666b795970SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 14671acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14686b795970SJulian Elischer ng_destroy_hook(hook1); 14696b795970SJulian Elischer NG_HOOK_UNREF(hook1); 14706b795970SJulian Elischer return (error); 14716b795970SJulian Elischer } 14726b795970SJulian Elischer 14736b795970SJulian Elischer /* 14746b795970SJulian Elischer * Actually link the two hooks together. 14756b795970SJulian Elischer */ 14766b795970SJulian Elischer hook1->hk_peer = hook2; 14776b795970SJulian Elischer hook2->hk_peer = hook1; 14786b795970SJulian Elischer 14796b795970SJulian Elischer /* Each hook is referenced by the other */ 14806b795970SJulian Elischer NG_HOOK_REF(hook1); 14816b795970SJulian Elischer NG_HOOK_REF(hook2); 14826b795970SJulian Elischer 14836b795970SJulian Elischer /* Give each node the opportunity to veto the pending connection */ 14846b795970SJulian Elischer if (hook1->hk_node->nd_type->connect) { 14856b795970SJulian Elischer error = (*hook1->hk_node->nd_type->connect) (hook1); 14866b795970SJulian Elischer } 14876b795970SJulian Elischer 14886b795970SJulian Elischer if ((error == 0) && hook2->hk_node->nd_type->connect) { 14896b795970SJulian Elischer error = (*hook2->hk_node->nd_type->connect) (hook2); 14906b795970SJulian Elischer 14916b795970SJulian Elischer } 14923e4084c8SJulian Elischer 14933e4084c8SJulian Elischer /* 14943e4084c8SJulian Elischer * drop the references we were holding on the two hooks. 14953e4084c8SJulian Elischer */ 14966b795970SJulian Elischer if (error) { 14976b795970SJulian Elischer ng_destroy_hook(hook2); /* also zaps hook1 */ 14981acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14996b795970SJulian Elischer } else { 15006b795970SJulian Elischer /* As a last act, allow the hooks to be used */ 15016b795970SJulian Elischer hook1->hk_flags &= ~HK_INVALID; 15026b795970SJulian Elischer hook2->hk_flags &= ~HK_INVALID; 15036b795970SJulian Elischer } 15046b795970SJulian Elischer NG_HOOK_UNREF(hook1); 15053e4084c8SJulian Elischer NG_HOOK_UNREF(hook2); 15063e4084c8SJulian Elischer return (error); 15074cf49a43SJulian Elischer } 15086b795970SJulian Elischer 1509069154d5SJulian Elischer /************************************************************************ 1510069154d5SJulian Elischer Utility routines to send self messages 1511069154d5SJulian Elischer ************************************************************************/ 1512069154d5SJulian Elischer 15131acb27c6SJulian Elischer /* Shut this node down as soon as everyone is clear of it */ 151464efc707SRobert Watson /* Should add arg "immediately" to jump the queue */ 1515069154d5SJulian Elischer int 151615cea89fSAlexander Motin ng_rmnode_self(node_p node) 1517069154d5SJulian Elischer { 15181acb27c6SJulian Elischer int error; 15194cf49a43SJulian Elischer 15201acb27c6SJulian Elischer if (node == &ng_deadnode) 15211acb27c6SJulian Elischer return (0); 1522be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID; 1523be4252b3SJulian Elischer if (node->nd_flags & NGF_CLOSING) 15241acb27c6SJulian Elischer return (0); 1525069154d5SJulian Elischer 152615cea89fSAlexander Motin error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0); 15271acb27c6SJulian Elischer return (error); 1528069154d5SJulian Elischer } 1529069154d5SJulian Elischer 15301acb27c6SJulian Elischer static void 15316b795970SJulian Elischer ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) 15326b795970SJulian Elischer { 15336b795970SJulian Elischer ng_destroy_hook(hook); 15341acb27c6SJulian Elischer return ; 15356b795970SJulian Elischer } 15366b795970SJulian Elischer 1537954c4772SJulian Elischer int 1538954c4772SJulian Elischer ng_rmhook_self(hook_p hook) 1539954c4772SJulian Elischer { 15406b795970SJulian Elischer int error; 1541954c4772SJulian Elischer node_p node = NG_HOOK_NODE(hook); 1542954c4772SJulian Elischer 15436b795970SJulian Elischer if (node == &ng_deadnode) 15446b795970SJulian Elischer return (0); 15456b795970SJulian Elischer 15466b795970SJulian Elischer error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0); 15476b795970SJulian Elischer return (error); 1548954c4772SJulian Elischer } 1549954c4772SJulian Elischer 1550069154d5SJulian Elischer /*********************************************************************** 15514cf49a43SJulian Elischer * Parse and verify a string of the form: <NODE:><PATH> 15524cf49a43SJulian Elischer * 15534cf49a43SJulian Elischer * Such a string can refer to a specific node or a specific hook 15544cf49a43SJulian Elischer * on a specific node, depending on how you look at it. In the 15554cf49a43SJulian Elischer * latter case, the PATH component must not end in a dot. 15564cf49a43SJulian Elischer * 15574cf49a43SJulian Elischer * Both <NODE:> and <PATH> are optional. The <PATH> is a string 15584cf49a43SJulian Elischer * of hook names separated by dots. This breaks out the original 15594cf49a43SJulian Elischer * string, setting *nodep to "NODE" (or NULL if none) and *pathp 15604cf49a43SJulian Elischer * to "PATH" (or NULL if degenerate). Also, *hookp will point to 15614cf49a43SJulian Elischer * the final hook component of <PATH>, if any, otherwise NULL. 15624cf49a43SJulian Elischer * 15634cf49a43SJulian Elischer * This returns -1 if the path is malformed. The char ** are optional. 1564069154d5SJulian Elischer ***********************************************************************/ 15654cf49a43SJulian Elischer int 15664cf49a43SJulian Elischer ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 15674cf49a43SJulian Elischer { 15684cf49a43SJulian Elischer char *node, *path, *hook; 15694cf49a43SJulian Elischer int k; 15704cf49a43SJulian Elischer 15714cf49a43SJulian Elischer /* 15724cf49a43SJulian Elischer * Extract absolute NODE, if any 15734cf49a43SJulian Elischer */ 15744cf49a43SJulian Elischer for (path = addr; *path && *path != ':'; path++); 15754cf49a43SJulian Elischer if (*path) { 15764cf49a43SJulian Elischer node = addr; /* Here's the NODE */ 15774cf49a43SJulian Elischer *path++ = '\0'; /* Here's the PATH */ 15784cf49a43SJulian Elischer 15794cf49a43SJulian Elischer /* Node name must not be empty */ 15804cf49a43SJulian Elischer if (!*node) 15814cf49a43SJulian Elischer return -1; 15824cf49a43SJulian Elischer 15834cf49a43SJulian Elischer /* A name of "." is OK; otherwise '.' not allowed */ 15844cf49a43SJulian Elischer if (strcmp(node, ".") != 0) { 15854cf49a43SJulian Elischer for (k = 0; node[k]; k++) 15864cf49a43SJulian Elischer if (node[k] == '.') 15874cf49a43SJulian Elischer return -1; 15884cf49a43SJulian Elischer } 15894cf49a43SJulian Elischer } else { 15904cf49a43SJulian Elischer node = NULL; /* No absolute NODE */ 15914cf49a43SJulian Elischer path = addr; /* Here's the PATH */ 15924cf49a43SJulian Elischer } 15934cf49a43SJulian Elischer 15944cf49a43SJulian Elischer /* Snoop for illegal characters in PATH */ 15954cf49a43SJulian Elischer for (k = 0; path[k]; k++) 15964cf49a43SJulian Elischer if (path[k] == ':') 15974cf49a43SJulian Elischer return -1; 15984cf49a43SJulian Elischer 15994cf49a43SJulian Elischer /* Check for no repeated dots in PATH */ 16004cf49a43SJulian Elischer for (k = 0; path[k]; k++) 16014cf49a43SJulian Elischer if (path[k] == '.' && path[k + 1] == '.') 16024cf49a43SJulian Elischer return -1; 16034cf49a43SJulian Elischer 16044cf49a43SJulian Elischer /* Remove extra (degenerate) dots from beginning or end of PATH */ 16054cf49a43SJulian Elischer if (path[0] == '.') 16064cf49a43SJulian Elischer path++; 16074cf49a43SJulian Elischer if (*path && path[strlen(path) - 1] == '.') 16084cf49a43SJulian Elischer path[strlen(path) - 1] = 0; 16094cf49a43SJulian Elischer 16104cf49a43SJulian Elischer /* If PATH has a dot, then we're not talking about a hook */ 16114cf49a43SJulian Elischer if (*path) { 16124cf49a43SJulian Elischer for (hook = path, k = 0; path[k]; k++) 16134cf49a43SJulian Elischer if (path[k] == '.') { 16144cf49a43SJulian Elischer hook = NULL; 16154cf49a43SJulian Elischer break; 16164cf49a43SJulian Elischer } 16174cf49a43SJulian Elischer } else 16184cf49a43SJulian Elischer path = hook = NULL; 16194cf49a43SJulian Elischer 16204cf49a43SJulian Elischer /* Done */ 16214cf49a43SJulian Elischer if (nodep) 16224cf49a43SJulian Elischer *nodep = node; 16234cf49a43SJulian Elischer if (pathp) 16244cf49a43SJulian Elischer *pathp = path; 16254cf49a43SJulian Elischer if (hookp) 16264cf49a43SJulian Elischer *hookp = hook; 16274cf49a43SJulian Elischer return (0); 16284cf49a43SJulian Elischer } 16294cf49a43SJulian Elischer 16304cf49a43SJulian Elischer /* 16314cf49a43SJulian Elischer * Given a path, which may be absolute or relative, and a starting node, 1632069154d5SJulian Elischer * return the destination node. 16334cf49a43SJulian Elischer */ 16344cf49a43SJulian Elischer int 1635069154d5SJulian Elischer ng_path2noderef(node_p here, const char *address, 1636069154d5SJulian Elischer node_p *destp, hook_p *lasthook) 16374cf49a43SJulian Elischer { 163887e2c66aSHartmut Brandt char fullpath[NG_PATHSIZ]; 1639a7da736aSGleb Smirnoff char *nodename, *path; 1640069154d5SJulian Elischer node_p node, oldnode; 16414cf49a43SJulian Elischer 16424cf49a43SJulian Elischer /* Initialize */ 164330400f03SJulian Elischer if (destp == NULL) { 16446b795970SJulian Elischer TRAP_ERROR(); 16454cf49a43SJulian Elischer return EINVAL; 164630400f03SJulian Elischer } 16474cf49a43SJulian Elischer *destp = NULL; 16484cf49a43SJulian Elischer 16494cf49a43SJulian Elischer /* Make a writable copy of address for ng_path_parse() */ 16504cf49a43SJulian Elischer strncpy(fullpath, address, sizeof(fullpath) - 1); 16514cf49a43SJulian Elischer fullpath[sizeof(fullpath) - 1] = '\0'; 16524cf49a43SJulian Elischer 16534cf49a43SJulian Elischer /* Parse out node and sequence of hooks */ 16544cf49a43SJulian Elischer if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 16556b795970SJulian Elischer TRAP_ERROR(); 16564cf49a43SJulian Elischer return EINVAL; 16574cf49a43SJulian Elischer } 16584cf49a43SJulian Elischer 1659069154d5SJulian Elischer /* 1660069154d5SJulian Elischer * For an absolute address, jump to the starting node. 1661069154d5SJulian Elischer * Note that this holds a reference on the node for us. 1662069154d5SJulian Elischer * Don't forget to drop the reference if we don't need it. 1663069154d5SJulian Elischer */ 16644cf49a43SJulian Elischer if (nodename) { 1665069154d5SJulian Elischer node = ng_name2noderef(here, nodename); 16664cf49a43SJulian Elischer if (node == NULL) { 16676b795970SJulian Elischer TRAP_ERROR(); 16684cf49a43SJulian Elischer return (ENOENT); 16694cf49a43SJulian Elischer } 1670069154d5SJulian Elischer } else { 1671069154d5SJulian Elischer if (here == NULL) { 16726b795970SJulian Elischer TRAP_ERROR(); 1673069154d5SJulian Elischer return (EINVAL); 1674069154d5SJulian Elischer } 16754cf49a43SJulian Elischer node = here; 167630400f03SJulian Elischer NG_NODE_REF(node); 1677069154d5SJulian Elischer } 16784cf49a43SJulian Elischer 1679a7da736aSGleb Smirnoff if (path == NULL) { 1680a7da736aSGleb Smirnoff if (lasthook != NULL) 1681a7da736aSGleb Smirnoff *lasthook = NULL; 1682a7da736aSGleb Smirnoff *destp = node; 1683a7da736aSGleb Smirnoff return (0); 1684a7da736aSGleb Smirnoff } 1685a7da736aSGleb Smirnoff 1686069154d5SJulian Elischer /* 1687069154d5SJulian Elischer * Now follow the sequence of hooks 1688a7da736aSGleb Smirnoff * 1689a7da736aSGleb Smirnoff * XXXGL: The path may demolish as we go the sequence, but if 1690a7da736aSGleb Smirnoff * we hold the topology mutex at critical places, then, I hope, 1691a7da736aSGleb Smirnoff * we would always have valid pointers in hand, although the 1692a7da736aSGleb Smirnoff * path behind us may no longer exist. 1693069154d5SJulian Elischer */ 1694a7da736aSGleb Smirnoff for (;;) { 1695a7da736aSGleb Smirnoff hook_p hook; 16964cf49a43SJulian Elischer char *segment; 16974cf49a43SJulian Elischer 16984cf49a43SJulian Elischer /* 16994cf49a43SJulian Elischer * Break out the next path segment. Replace the dot we just 1700a7da736aSGleb Smirnoff * found with a NUL; "path" points to the next segment (or the 17014cf49a43SJulian Elischer * NUL at the end). 17024cf49a43SJulian Elischer */ 1703a7da736aSGleb Smirnoff for (segment = path; *path != '\0'; path++) { 1704a7da736aSGleb Smirnoff if (*path == '.') { 1705a7da736aSGleb Smirnoff *path++ = '\0'; 17064cf49a43SJulian Elischer break; 17074cf49a43SJulian Elischer } 17084cf49a43SJulian Elischer } 17094cf49a43SJulian Elischer 17104cf49a43SJulian Elischer /* We have a segment, so look for a hook by that name */ 1711899e9c4eSArchie Cobbs hook = ng_findhook(node, segment); 17124cf49a43SJulian Elischer 1713a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 17144cf49a43SJulian Elischer /* Can't get there from here... */ 17154cf49a43SJulian Elischer if (hook == NULL 171630400f03SJulian Elischer || NG_HOOK_PEER(hook) == NULL 171730400f03SJulian Elischer || NG_HOOK_NOT_VALID(hook) 171830400f03SJulian Elischer || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) { 17196b795970SJulian Elischer TRAP_ERROR(); 172030400f03SJulian Elischer NG_NODE_UNREF(node); 1721a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17224cf49a43SJulian Elischer return (ENOENT); 17234cf49a43SJulian Elischer } 17244cf49a43SJulian Elischer 1725069154d5SJulian Elischer /* 1726069154d5SJulian Elischer * Hop on over to the next node 1727069154d5SJulian Elischer * XXX 1728069154d5SJulian Elischer * Big race conditions here as hooks and nodes go away 1729069154d5SJulian Elischer * *** Idea.. store an ng_ID_t in each hook and use that 1730069154d5SJulian Elischer * instead of the direct hook in this crawl? 1731069154d5SJulian Elischer */ 1732069154d5SJulian Elischer oldnode = node; 173330400f03SJulian Elischer if ((node = NG_PEER_NODE(hook))) 173430400f03SJulian Elischer NG_NODE_REF(node); /* XXX RACE */ 173530400f03SJulian Elischer NG_NODE_UNREF(oldnode); /* XXX another race */ 173630400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 173730400f03SJulian Elischer NG_NODE_UNREF(node); /* XXX more races */ 1738a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17396b795970SJulian Elischer TRAP_ERROR(); 17404cf49a43SJulian Elischer return (ENXIO); 17414cf49a43SJulian Elischer } 17424cf49a43SJulian Elischer 1743a7da736aSGleb Smirnoff if (*path == '\0') { 1744a7da736aSGleb Smirnoff if (lasthook != NULL) { 1745a7da736aSGleb Smirnoff if (hook != NULL) { 1746a7da736aSGleb Smirnoff *lasthook = NG_HOOK_PEER(hook); 1747a7da736aSGleb Smirnoff NG_HOOK_REF(*lasthook); 1748a7da736aSGleb Smirnoff } else 1749a7da736aSGleb Smirnoff *lasthook = NULL; 1750a7da736aSGleb Smirnoff } 1751a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 17524cf49a43SJulian Elischer *destp = node; 1753069154d5SJulian Elischer return (0); 1754069154d5SJulian Elischer } 1755a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1756a7da736aSGleb Smirnoff } 1757a7da736aSGleb Smirnoff } 1758069154d5SJulian Elischer 1759069154d5SJulian Elischer /***************************************************************\ 1760069154d5SJulian Elischer * Input queue handling. 1761069154d5SJulian Elischer * All activities are submitted to the node via the input queue 1762069154d5SJulian Elischer * which implements a multiple-reader/single-writer gate. 176364efc707SRobert Watson * Items which cannot be handled immediately are queued. 1764069154d5SJulian Elischer * 1765069154d5SJulian Elischer * read-write queue locking inline functions * 1766069154d5SJulian Elischer \***************************************************************/ 1767069154d5SJulian Elischer 17689852972bSAlexander Motin static __inline void ng_queue_rw(node_p node, item_p item, int rw); 17699852972bSAlexander Motin static __inline item_p ng_dequeue(node_p node, int *rw); 17709852972bSAlexander Motin static __inline item_p ng_acquire_read(node_p node, item_p item); 17719852972bSAlexander Motin static __inline item_p ng_acquire_write(node_p node, item_p item); 17729852972bSAlexander Motin static __inline void ng_leave_read(node_p node); 17739852972bSAlexander Motin static __inline void ng_leave_write(node_p node); 1774069154d5SJulian Elischer 1775069154d5SJulian Elischer /* 1776069154d5SJulian Elischer * Definition of the bits fields in the ng_queue flag word. 1777069154d5SJulian Elischer * Defined here rather than in netgraph.h because no-one should fiddle 1778069154d5SJulian Elischer * with them. 1779069154d5SJulian Elischer * 1780b57a7965SJulian Elischer * The ordering here may be important! don't shuffle these. 1781069154d5SJulian Elischer */ 1782069154d5SJulian Elischer /*- 1783069154d5SJulian Elischer Safety Barrier--------+ (adjustable to suit taste) (not used yet) 1784069154d5SJulian Elischer | 1785069154d5SJulian Elischer V 1786069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 17874be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 17884be59335SGleb Smirnoff | |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |P|A| 17894be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|W| 1790069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 17914be59335SGleb Smirnoff \___________________________ ____________________________/ | | 17924be59335SGleb Smirnoff V | | 17934be59335SGleb Smirnoff [active reader count] | | 1794069154d5SJulian Elischer | | 17954be59335SGleb Smirnoff Operation Pending -------------------------------+ | 1796069154d5SJulian Elischer | 17974be59335SGleb Smirnoff Active Writer ---------------------------------------+ 1798b57a7965SJulian Elischer 17998f9ac44aSAlexander Motin Node queue has such semantics: 18008f9ac44aSAlexander Motin - All flags modifications are atomic. 18018f9ac44aSAlexander Motin - Reader count can be incremented only if there is no writer or pending flags. 18028f9ac44aSAlexander Motin As soon as this can't be done with single operation, it is implemented with 18038f9ac44aSAlexander Motin spin loop and atomic_cmpset(). 18048f9ac44aSAlexander Motin - Writer flag can be set only if there is no any bits set. 18058f9ac44aSAlexander Motin It is implemented with atomic_cmpset(). 18068f9ac44aSAlexander Motin - Pending flag can be set any time, but to avoid collision on queue processing 18078f9ac44aSAlexander Motin all queue fields are protected by the mutex. 18088f9ac44aSAlexander Motin - Queue processing thread reads queue holding the mutex, but releases it while 18098f9ac44aSAlexander Motin processing. When queue is empty pending flag is removed. 1810069154d5SJulian Elischer */ 18118f9ac44aSAlexander Motin 18124be59335SGleb Smirnoff #define WRITER_ACTIVE 0x00000001 18134be59335SGleb Smirnoff #define OP_PENDING 0x00000002 18144be59335SGleb Smirnoff #define READER_INCREMENT 0x00000004 18154be59335SGleb Smirnoff #define READER_MASK 0xfffffffc /* Not valid if WRITER_ACTIVE is set */ 18164be59335SGleb Smirnoff #define SAFETY_BARRIER 0x00100000 /* 128K items queued should be enough */ 1817b57a7965SJulian Elischer 1818b57a7965SJulian Elischer /* Defines of more elaborate states on the queue */ 18194be59335SGleb Smirnoff /* Mask of bits a new read cares about */ 18204be59335SGleb Smirnoff #define NGQ_RMASK (WRITER_ACTIVE|OP_PENDING) 1821b57a7965SJulian Elischer 18224be59335SGleb Smirnoff /* Mask of bits a new write cares about */ 1823b57a7965SJulian Elischer #define NGQ_WMASK (NGQ_RMASK|READER_MASK) 1824b57a7965SJulian Elischer 18254be59335SGleb Smirnoff /* Test to decide if there is something on the queue. */ 18264be59335SGleb Smirnoff #define QUEUE_ACTIVE(QP) ((QP)->q_flags & OP_PENDING) 18274be59335SGleb Smirnoff 18284be59335SGleb Smirnoff /* How to decide what the next queued item is. */ 18299852972bSAlexander Motin #define HEAD_IS_READER(QP) NGI_QUEUED_READER(STAILQ_FIRST(&(QP)->queue)) 18309852972bSAlexander Motin #define HEAD_IS_WRITER(QP) NGI_QUEUED_WRITER(STAILQ_FIRST(&(QP)->queue)) /* notused */ 18314be59335SGleb Smirnoff 18324be59335SGleb Smirnoff /* Read the status to decide if the next item on the queue can now run. */ 18334be59335SGleb Smirnoff #define QUEUED_READER_CAN_PROCEED(QP) \ 18344be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_RMASK & ~OP_PENDING)) == 0) 18354be59335SGleb Smirnoff #define QUEUED_WRITER_CAN_PROCEED(QP) \ 18364be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_WMASK & ~OP_PENDING)) == 0) 1837b57a7965SJulian Elischer 1838b57a7965SJulian Elischer /* Is there a chance of getting ANY work off the queue? */ 18394be59335SGleb Smirnoff #define NEXT_QUEUED_ITEM_CAN_PROCEED(QP) \ 18404be59335SGleb Smirnoff ((HEAD_IS_READER(QP)) ? QUEUED_READER_CAN_PROCEED(QP) : \ 1841394cb30aSAlexander Motin QUEUED_WRITER_CAN_PROCEED(QP)) 18424be59335SGleb Smirnoff 1843714fb865SGleb Smirnoff #define NGQRW_R 0 1844714fb865SGleb Smirnoff #define NGQRW_W 1 1845714fb865SGleb Smirnoff 18469852972bSAlexander Motin #define NGQ2_WORKQ 0x00000001 18479852972bSAlexander Motin 1848069154d5SJulian Elischer /* 1849069154d5SJulian Elischer * Taking into account the current state of the queue and node, possibly take 1850069154d5SJulian Elischer * the next entry off the queue and return it. Return NULL if there was 1851069154d5SJulian Elischer * nothing we could return, either because there really was nothing there, or 1852069154d5SJulian Elischer * because the node was in a state where it cannot yet process the next item 1853069154d5SJulian Elischer * on the queue. 1854069154d5SJulian Elischer */ 1855069154d5SJulian Elischer static __inline item_p 18569852972bSAlexander Motin ng_dequeue(node_p node, int *rw) 1857069154d5SJulian Elischer { 1858069154d5SJulian Elischer item_p item; 18599852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 1860b57a7965SJulian Elischer 18618f9ac44aSAlexander Motin /* This MUST be called with the mutex held. */ 1862d58e678fSGleb Smirnoff mtx_assert(&ngq->q_mtx, MA_OWNED); 18638f9ac44aSAlexander Motin 18648f9ac44aSAlexander Motin /* If there is nothing queued, then just return. */ 18654be59335SGleb Smirnoff if (!QUEUE_ACTIVE(ngq)) { 18662955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queue empty; " 18672955ee18SGleb Smirnoff "queue flags 0x%lx", __func__, 18689852972bSAlexander Motin node->nd_ID, node, ngq->q_flags); 18694be59335SGleb Smirnoff return (NULL); 18704be59335SGleb Smirnoff } 1871d58e678fSGleb Smirnoff 18724be59335SGleb Smirnoff /* 18734be59335SGleb Smirnoff * From here, we can assume there is a head item. 18744be59335SGleb Smirnoff * We need to find out what it is and if it can be dequeued, given 18754be59335SGleb Smirnoff * the current state of the node. 18764be59335SGleb Smirnoff */ 18774be59335SGleb Smirnoff if (HEAD_IS_READER(ngq)) { 1878394cb30aSAlexander Motin while (1) { 1879394cb30aSAlexander Motin long t = ngq->q_flags; 1880394cb30aSAlexander Motin if (t & WRITER_ACTIVE) { 18818f9ac44aSAlexander Motin /* There is writer, reader can't proceed. */ 18822955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queued reader " 18832955ee18SGleb Smirnoff "can't proceed; queue flags 0x%lx", __func__, 18849852972bSAlexander Motin node->nd_ID, node, t); 18854be59335SGleb Smirnoff return (NULL); 18864be59335SGleb Smirnoff } 18879852972bSAlexander Motin if (atomic_cmpset_acq_int(&ngq->q_flags, t, 1888394cb30aSAlexander Motin t + READER_INCREMENT)) 1889394cb30aSAlexander Motin break; 1890394cb30aSAlexander Motin cpu_spinwait(); 1891394cb30aSAlexander Motin } 18928f9ac44aSAlexander Motin /* We have got reader lock for the node. */ 1893714fb865SGleb Smirnoff *rw = NGQRW_R; 18949852972bSAlexander Motin } else if (atomic_cmpset_acq_int(&ngq->q_flags, OP_PENDING, 1895394cb30aSAlexander Motin OP_PENDING + WRITER_ACTIVE)) { 18968f9ac44aSAlexander Motin /* We have got writer lock for the node. */ 1897714fb865SGleb Smirnoff *rw = NGQRW_W; 1898069154d5SJulian Elischer } else { 18998f9ac44aSAlexander Motin /* There is somebody other, writer can't proceed. */ 1900394cb30aSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) queued writer " 1901394cb30aSAlexander Motin "can't proceed; queue flags 0x%lx", __func__, 19029852972bSAlexander Motin node->nd_ID, node, ngq->q_flags); 19034be59335SGleb Smirnoff return (NULL); 19044cf49a43SJulian Elischer } 19054cf49a43SJulian Elischer 19064cf49a43SJulian Elischer /* 1907069154d5SJulian Elischer * Now we dequeue the request (whatever it may be) and correct the 1908069154d5SJulian Elischer * pending flags and the next and last pointers. 19094cf49a43SJulian Elischer */ 19109852972bSAlexander Motin item = STAILQ_FIRST(&ngq->queue); 19119852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 19129852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 19139852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 19142955ee18SGleb Smirnoff CTR6(KTR_NET, "%20s: node [%x] (%p) returning item %p as %s; " 19152955ee18SGleb Smirnoff "queue flags 0x%lx", __func__, 19169852972bSAlexander Motin node->nd_ID, node, item, *rw ? "WRITER" : "READER" , 19173b33fbe7SGleb Smirnoff ngq->q_flags); 1918069154d5SJulian Elischer return (item); 1919069154d5SJulian Elischer } 1920859a4d16SJulian Elischer 1921859a4d16SJulian Elischer /* 19228f9ac44aSAlexander Motin * Queue a packet to be picked up later by someone else. 19238f9ac44aSAlexander Motin * If the queue could be run now, add node to the queue handler's worklist. 1924859a4d16SJulian Elischer */ 1925069154d5SJulian Elischer static __inline void 19269852972bSAlexander Motin ng_queue_rw(node_p node, item_p item, int rw) 1927069154d5SJulian Elischer { 19289852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 19294be59335SGleb Smirnoff if (rw == NGQRW_W) 19304be59335SGleb Smirnoff NGI_SET_WRITER(item); 19314be59335SGleb Smirnoff else 19324be59335SGleb Smirnoff NGI_SET_READER(item); 1933394cb30aSAlexander Motin 1934394cb30aSAlexander Motin NG_QUEUE_LOCK(ngq); 1935394cb30aSAlexander Motin /* Set OP_PENDING flag and enqueue the item. */ 19369852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 19379852972bSAlexander Motin STAILQ_INSERT_TAIL(&ngq->queue, item, el_next); 1938394cb30aSAlexander Motin 19392955ee18SGleb Smirnoff CTR5(KTR_NET, "%20s: node [%x] (%p) queued item %p as %s", __func__, 19409852972bSAlexander Motin node->nd_ID, node, item, rw ? "WRITER" : "READER" ); 19414be59335SGleb Smirnoff 19424be59335SGleb Smirnoff /* 19434be59335SGleb Smirnoff * We can take the worklist lock with the node locked 19444be59335SGleb Smirnoff * BUT NOT THE REVERSE! 19454be59335SGleb Smirnoff */ 19464be59335SGleb Smirnoff if (NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 19479852972bSAlexander Motin ng_worklist_add(node); 1948394cb30aSAlexander Motin NG_QUEUE_UNLOCK(ngq); 1949069154d5SJulian Elischer } 1950069154d5SJulian Elischer 19518f9ac44aSAlexander Motin /* Acquire reader lock on node. If node is busy, queue the packet. */ 1952069154d5SJulian Elischer static __inline item_p 19539852972bSAlexander Motin ng_acquire_read(node_p node, item_p item) 1954069154d5SJulian Elischer { 19559852972bSAlexander Motin KASSERT(node != &ng_deadnode, 1956ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 1957069154d5SJulian Elischer 1958394cb30aSAlexander Motin /* Reader needs node without writer and pending items. */ 1959394cb30aSAlexander Motin while (1) { 19609852972bSAlexander Motin long t = node->nd_input_queue.q_flags; 1961394cb30aSAlexander Motin if (t & NGQ_RMASK) 1962394cb30aSAlexander Motin break; /* Node is not ready for reader. */ 19639852972bSAlexander Motin if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 19649852972bSAlexander Motin t, t + READER_INCREMENT)) { 1965069154d5SJulian Elischer /* Successfully grabbed node */ 1966394cb30aSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 19679852972bSAlexander Motin __func__, node->nd_ID, node, item); 1968069154d5SJulian Elischer return (item); 1969069154d5SJulian Elischer } 1970394cb30aSAlexander Motin cpu_spinwait(); 1971394cb30aSAlexander Motin }; 1972069154d5SJulian Elischer 1973394cb30aSAlexander Motin /* Queue the request for later. */ 19749852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_R); 1975f912c0f7SGleb Smirnoff 1976f912c0f7SGleb Smirnoff return (NULL); 1977069154d5SJulian Elischer } 1978069154d5SJulian Elischer 19798f9ac44aSAlexander Motin /* Acquire writer lock on node. If node is busy, queue the packet. */ 1980069154d5SJulian Elischer static __inline item_p 19819852972bSAlexander Motin ng_acquire_write(node_p node, item_p item) 1982069154d5SJulian Elischer { 19839852972bSAlexander Motin KASSERT(node != &ng_deadnode, 1984ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 1985ac5dd141SGleb Smirnoff 1986394cb30aSAlexander Motin /* Writer needs completely idle node. */ 19879852972bSAlexander Motin if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 19889852972bSAlexander Motin 0, WRITER_ACTIVE)) { 1989394cb30aSAlexander Motin /* Successfully grabbed node */ 19902955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 19919852972bSAlexander Motin __func__, node->nd_ID, node, item); 1992069154d5SJulian Elischer return (item); 1993069154d5SJulian Elischer } 1994069154d5SJulian Elischer 1995394cb30aSAlexander Motin /* Queue the request for later. */ 19969852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_W); 1997f912c0f7SGleb Smirnoff 1998f912c0f7SGleb Smirnoff return (NULL); 1999069154d5SJulian Elischer } 2000069154d5SJulian Elischer 2001262dfd7fSJulian Elischer #if 0 2002262dfd7fSJulian Elischer static __inline item_p 20039852972bSAlexander Motin ng_upgrade_write(node_p node, item_p item) 2004262dfd7fSJulian Elischer { 20059852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 20069852972bSAlexander Motin KASSERT(node != &ng_deadnode, 2007262dfd7fSJulian Elischer ("%s: working on deadnode", __func__)); 2008262dfd7fSJulian Elischer 2009262dfd7fSJulian Elischer NGI_SET_WRITER(item); 2010262dfd7fSJulian Elischer 20119852972bSAlexander Motin NG_QUEUE_LOCK(ngq); 2012262dfd7fSJulian Elischer 2013262dfd7fSJulian Elischer /* 2014262dfd7fSJulian Elischer * There will never be no readers as we are there ourselves. 2015262dfd7fSJulian Elischer * Set the WRITER_ACTIVE flags ASAP to block out fast track readers. 2016262dfd7fSJulian Elischer * The caller we are running from will call ng_leave_read() 2017262dfd7fSJulian Elischer * soon, so we must account for that. We must leave again with the 2018262dfd7fSJulian Elischer * READER lock. If we find other readers, then 2019262dfd7fSJulian Elischer * queue the request for later. However "later" may be rignt now 2020262dfd7fSJulian Elischer * if there are no readers. We don't really care if there are queued 2021262dfd7fSJulian Elischer * items as we will bypass them anyhow. 2022262dfd7fSJulian Elischer */ 20239852972bSAlexander Motin atomic_add_int(&ngq->q_flags, WRITER_ACTIVE - READER_INCREMENT); 20249852972bSAlexander Motin if ((ngq->q_flags & (NGQ_WMASK & ~OP_PENDING)) == WRITER_ACTIVE) { 20259852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2026262dfd7fSJulian Elischer 2027262dfd7fSJulian Elischer /* It's just us, act on the item. */ 2028262dfd7fSJulian Elischer /* will NOT drop writer lock when done */ 2029262dfd7fSJulian Elischer ng_apply_item(node, item, 0); 2030262dfd7fSJulian Elischer 2031262dfd7fSJulian Elischer /* 2032262dfd7fSJulian Elischer * Having acted on the item, atomically 2033262dfd7fSJulian Elischer * down grade back to READER and finish up 2034262dfd7fSJulian Elischer */ 20359852972bSAlexander Motin atomic_add_int(&ngq->q_flags, 2036262dfd7fSJulian Elischer READER_INCREMENT - WRITER_ACTIVE); 2037262dfd7fSJulian Elischer 2038262dfd7fSJulian Elischer /* Our caller will call ng_leave_read() */ 2039262dfd7fSJulian Elischer return; 2040262dfd7fSJulian Elischer } 2041262dfd7fSJulian Elischer /* 2042262dfd7fSJulian Elischer * It's not just us active, so queue us AT THE HEAD. 2043262dfd7fSJulian Elischer * "Why?" I hear you ask. 2044262dfd7fSJulian Elischer * Put us at the head of the queue as we've already been 2045262dfd7fSJulian Elischer * through it once. If there is nothing else waiting, 2046262dfd7fSJulian Elischer * set the correct flags. 2047262dfd7fSJulian Elischer */ 20489852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) { 2049262dfd7fSJulian Elischer /* We've gone from, 0 to 1 item in the queue */ 20509852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 2051262dfd7fSJulian Elischer 2052262dfd7fSJulian Elischer CTR3(KTR_NET, "%20s: node [%x] (%p) set OP_PENDING", __func__, 20539852972bSAlexander Motin node->nd_ID, node); 2054262dfd7fSJulian Elischer }; 20559852972bSAlexander Motin STAILQ_INSERT_HEAD(&ngq->queue, item, el_next); 20569852972bSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) requeued item %p as WRITER", 20579852972bSAlexander Motin __func__, node->nd_ID, node, item ); 2058262dfd7fSJulian Elischer 2059262dfd7fSJulian Elischer /* Reverse what we did above. That downgrades us back to reader */ 20609852972bSAlexander Motin atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE); 2061394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 20629852972bSAlexander Motin ng_worklist_add(node); 20639852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2064262dfd7fSJulian Elischer 2065262dfd7fSJulian Elischer return; 2066262dfd7fSJulian Elischer } 2067262dfd7fSJulian Elischer #endif 2068262dfd7fSJulian Elischer 20698f9ac44aSAlexander Motin /* Release reader lock. */ 2070069154d5SJulian Elischer static __inline void 20719852972bSAlexander Motin ng_leave_read(node_p node) 2072069154d5SJulian Elischer { 20739852972bSAlexander Motin atomic_subtract_rel_int(&node->nd_input_queue.q_flags, READER_INCREMENT); 2074069154d5SJulian Elischer } 2075069154d5SJulian Elischer 20768f9ac44aSAlexander Motin /* Release writer lock. */ 2077069154d5SJulian Elischer static __inline void 20789852972bSAlexander Motin ng_leave_write(node_p node) 2079069154d5SJulian Elischer { 20809852972bSAlexander Motin atomic_clear_rel_int(&node->nd_input_queue.q_flags, WRITER_ACTIVE); 2081069154d5SJulian Elischer } 2082069154d5SJulian Elischer 20838f9ac44aSAlexander Motin /* Purge node queue. Called on node shutdown. */ 2084069154d5SJulian Elischer static void 20859852972bSAlexander Motin ng_flush_input_queue(node_p node) 2086069154d5SJulian Elischer { 20879852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 2088069154d5SJulian Elischer item_p item; 2089069154d5SJulian Elischer 20902c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 20919852972bSAlexander Motin while ((item = STAILQ_FIRST(&ngq->queue)) != NULL) { 20929852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 20939852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 20949852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 20952c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 20964be59335SGleb Smirnoff 20974be59335SGleb Smirnoff /* If the item is supplying a callback, call it with an error */ 209810e87318SAlexander Motin if (item->apply != NULL) { 209910e87318SAlexander Motin if (item->depth == 1) 210010e87318SAlexander Motin item->apply->error = ENOENT; 210110e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 210210e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 210310e87318SAlexander Motin item->apply->error); 210410e87318SAlexander Motin } 2105eb2405ddSGleb Smirnoff } 2106505fad52SJulian Elischer NG_FREE_ITEM(item); 21072c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2108069154d5SJulian Elischer } 21092c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2110069154d5SJulian Elischer } 2111069154d5SJulian Elischer 2112069154d5SJulian Elischer /*********************************************************************** 2113069154d5SJulian Elischer * Externally visible method for sending or queueing messages or data. 2114069154d5SJulian Elischer ***********************************************************************/ 2115069154d5SJulian Elischer 2116069154d5SJulian Elischer /* 21171acb27c6SJulian Elischer * The module code should have filled out the item correctly by this stage: 2118069154d5SJulian Elischer * Common: 2119069154d5SJulian Elischer * reference to destination node. 2120069154d5SJulian Elischer * Reference to destination rcv hook if relevant. 2121e088dd4cSAlexander Motin * apply pointer must be or NULL or reference valid struct ng_apply_info. 2122069154d5SJulian Elischer * Data: 2123069154d5SJulian Elischer * pointer to mbuf 2124069154d5SJulian Elischer * Control_Message: 2125069154d5SJulian Elischer * pointer to msg. 2126069154d5SJulian Elischer * ID of original sender node. (return address) 21271acb27c6SJulian Elischer * Function: 21281acb27c6SJulian Elischer * Function pointer 21291acb27c6SJulian Elischer * void * argument 21301acb27c6SJulian Elischer * integer argument 2131069154d5SJulian Elischer * 2132069154d5SJulian Elischer * The nodes have several routines and macros to help with this task: 2133069154d5SJulian Elischer */ 2134069154d5SJulian Elischer 2135069154d5SJulian Elischer int 213642282202SGleb Smirnoff ng_snd_item(item_p item, int flags) 2137069154d5SJulian Elischer { 2138e088dd4cSAlexander Motin hook_p hook; 2139e088dd4cSAlexander Motin node_p node; 214042282202SGleb Smirnoff int queue, rw; 2141e088dd4cSAlexander Motin struct ng_queue *ngq; 214232b33288SGleb Smirnoff int error = 0; 2143069154d5SJulian Elischer 2144f50597f5SAlexander Motin /* We are sending item, so it must be present! */ 2145f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_snd_item: item is NULL")); 2146e088dd4cSAlexander Motin 2147e088dd4cSAlexander Motin #ifdef NETGRAPH_DEBUG 2148e088dd4cSAlexander Motin _ngi_check(item, __FILE__, __LINE__); 2149e088dd4cSAlexander Motin #endif 2150e088dd4cSAlexander Motin 2151f50597f5SAlexander Motin /* Item was sent once more, postpone apply() call. */ 2152e088dd4cSAlexander Motin if (item->apply) 2153e088dd4cSAlexander Motin refcount_acquire(&item->apply->refs); 2154e088dd4cSAlexander Motin 2155e088dd4cSAlexander Motin node = NGI_NODE(item); 2156f50597f5SAlexander Motin /* Node is never optional. */ 2157f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_snd_item: node is NULL")); 2158e088dd4cSAlexander Motin 2159e72a98f4SAlexander Motin hook = NGI_HOOK(item); 2160f50597f5SAlexander Motin /* Valid hook and mbuf are mandatory for data. */ 2161f50597f5SAlexander Motin if ((item->el_flags & NGQF_TYPE) == NGQF_DATA) { 2162f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_snd_item: hook for data is NULL")); 216310204449SJulian Elischer if (NGI_M(item) == NULL) 2164e088dd4cSAlexander Motin ERROUT(EINVAL); 2165069154d5SJulian Elischer CHECK_DATA_MBUF(NGI_M(item)); 21666f683eeeSGleb Smirnoff } 21676f683eeeSGleb Smirnoff 2168069154d5SJulian Elischer /* 2169f50597f5SAlexander Motin * If the item or the node specifies single threading, force 2170f50597f5SAlexander Motin * writer semantics. Similarly, the node may say one hook always 2171f50597f5SAlexander Motin * produces writers. These are overrides. 2172069154d5SJulian Elischer */ 2173db3408aeSAlexander Motin if (((item->el_flags & NGQF_RW) == NGQF_WRITER) || 2174f50597f5SAlexander Motin (node->nd_flags & NGF_FORCE_WRITER) || 2175f50597f5SAlexander Motin (hook && (hook->hk_flags & HK_FORCE_WRITER))) { 2176069154d5SJulian Elischer rw = NGQRW_W; 2177f50597f5SAlexander Motin } else { 2178f50597f5SAlexander Motin rw = NGQRW_R; 2179f50597f5SAlexander Motin } 21806f683eeeSGleb Smirnoff 218181a253a4SAlexander Motin /* 2182f089869fSMarko Zec * If sender or receiver requests queued delivery, or call graph 2183f089869fSMarko Zec * loops back from outbound to inbound path, or stack usage 218481a253a4SAlexander Motin * level is dangerous - enqueue message. 218581a253a4SAlexander Motin */ 218681a253a4SAlexander Motin if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) { 218781a253a4SAlexander Motin queue = 1; 2188f089869fSMarko Zec } else if (hook && (hook->hk_flags & HK_TO_INBOUND) && 2189f089869fSMarko Zec curthread->td_ng_outbound) { 2190f089869fSMarko Zec queue = 1; 2191f50597f5SAlexander Motin } else { 2192f50597f5SAlexander Motin queue = 0; 219381a253a4SAlexander Motin #ifdef GET_STACK_USAGE 2194d4529f98SAlexander Motin /* 2195942fe01fSDmitry Morozovsky * Most of netgraph nodes have small stack consumption and 2196f50597f5SAlexander Motin * for them 25% of free stack space is more than enough. 2197d4529f98SAlexander Motin * Nodes/hooks with higher stack usage should be marked as 2198f9773372SDmitry Morozovsky * HI_STACK. For them 50% of stack will be guaranteed then. 2199f50597f5SAlexander Motin * XXX: Values 25% and 50% are completely empirical. 2200d4529f98SAlexander Motin */ 2201f50597f5SAlexander Motin size_t st, su, sl; 220281a253a4SAlexander Motin GET_STACK_USAGE(st, su); 2203f50597f5SAlexander Motin sl = st - su; 2204f50597f5SAlexander Motin if ((sl * 4 < st) || 2205f50597f5SAlexander Motin ((sl * 2 < st) && ((node->nd_flags & NGF_HI_STACK) || 220681a253a4SAlexander Motin (hook && (hook->hk_flags & HK_HI_STACK))))) { 220781a253a4SAlexander Motin queue = 1; 220881a253a4SAlexander Motin } 220981a253a4SAlexander Motin #endif 2210f50597f5SAlexander Motin } 221181a253a4SAlexander Motin 2212069154d5SJulian Elischer if (queue) { 221310e87318SAlexander Motin item->depth = 1; 2214394cb30aSAlexander Motin /* Put it on the queue for that node*/ 22159852972bSAlexander Motin ng_queue_rw(node, item, rw); 2216f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2217069154d5SJulian Elischer } 2218069154d5SJulian Elischer 2219069154d5SJulian Elischer /* 2220069154d5SJulian Elischer * We already decided how we will be queueud or treated. 2221069154d5SJulian Elischer * Try get the appropriate operating permission. 2222069154d5SJulian Elischer */ 222332b33288SGleb Smirnoff if (rw == NGQRW_R) 22249852972bSAlexander Motin item = ng_acquire_read(node, item); 222532b33288SGleb Smirnoff else 22269852972bSAlexander Motin item = ng_acquire_write(node, item); 22274cf49a43SJulian Elischer 2228f50597f5SAlexander Motin /* Item was queued while trying to get permission. */ 2229f50597f5SAlexander Motin if (item == NULL) 2230f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2231069154d5SJulian Elischer 22325951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 22335951069aSJulian Elischer 223410e87318SAlexander Motin item->depth++; 223527757487SGleb Smirnoff error = ng_apply_item(node, item, rw); /* drops r/w lock when done */ 2236069154d5SJulian Elischer 2237394cb30aSAlexander Motin /* If something is waiting on queue and ready, schedule it. */ 22389852972bSAlexander Motin ngq = &node->nd_input_queue; 2239394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq)) { 22402c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2241394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 22429852972bSAlexander Motin ng_worklist_add(node); 22432c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2244394cb30aSAlexander Motin } 2245394cb30aSAlexander Motin 2246394cb30aSAlexander Motin /* 2247394cb30aSAlexander Motin * Node may go away as soon as we remove the reference. 2248394cb30aSAlexander Motin * Whatever we do, DO NOT access the node again! 2249394cb30aSAlexander Motin */ 2250394cb30aSAlexander Motin NG_NODE_UNREF(node); 2251069154d5SJulian Elischer 22521acb27c6SJulian Elischer return (error); 2253e088dd4cSAlexander Motin 2254e088dd4cSAlexander Motin done: 2255f50597f5SAlexander Motin /* If was not sent, apply callback here. */ 225610e87318SAlexander Motin if (item->apply != NULL) { 225710e87318SAlexander Motin if (item->depth == 0 && error != 0) 225810e87318SAlexander Motin item->apply->error = error; 225910e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 226010e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 226110e87318SAlexander Motin item->apply->error); 226210e87318SAlexander Motin } 226310e87318SAlexander Motin } 2264e72a98f4SAlexander Motin 2265e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2266e088dd4cSAlexander Motin return (error); 2267069154d5SJulian Elischer } 2268069154d5SJulian Elischer 2269069154d5SJulian Elischer /* 2270069154d5SJulian Elischer * We have an item that was possibly queued somewhere. 2271069154d5SJulian Elischer * It should contain all the information needed 2272069154d5SJulian Elischer * to run it on the appropriate node/hook. 2273e088dd4cSAlexander Motin * If there is apply pointer and we own the last reference, call apply(). 22744cf49a43SJulian Elischer */ 227527757487SGleb Smirnoff static int 2276714fb865SGleb Smirnoff ng_apply_item(node_p node, item_p item, int rw) 2277069154d5SJulian Elischer { 2278069154d5SJulian Elischer hook_p hook; 2279069154d5SJulian Elischer ng_rcvdata_t *rcvdata; 2280c4b5eea4SJulian Elischer ng_rcvmsg_t *rcvmsg; 2281e088dd4cSAlexander Motin struct ng_apply_info *apply; 228210e87318SAlexander Motin int error = 0, depth; 2283069154d5SJulian Elischer 2284f50597f5SAlexander Motin /* Node and item are never optional. */ 2285f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_apply_item: node is NULL")); 2286f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_apply_item: item is NULL")); 2287f50597f5SAlexander Motin 22881acb27c6SJulian Elischer NGI_GET_HOOK(item, hook); /* clears stored hook */ 228930400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 2290069154d5SJulian Elischer _ngi_check(item, __FILE__, __LINE__); 2291069154d5SJulian Elischer #endif 22928afe16d5SGleb Smirnoff 22938afe16d5SGleb Smirnoff apply = item->apply; 229410e87318SAlexander Motin depth = item->depth; 22958afe16d5SGleb Smirnoff 22966b795970SJulian Elischer switch (item->el_flags & NGQF_TYPE) { 2297069154d5SJulian Elischer case NGQF_DATA: 2298069154d5SJulian Elischer /* 2299069154d5SJulian Elischer * Check things are still ok as when we were queued. 2300069154d5SJulian Elischer */ 2301f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_apply_item: hook for data is NULL")); 2302f50597f5SAlexander Motin if (NG_HOOK_NOT_VALID(hook) || 2303f50597f5SAlexander Motin NG_NODE_NOT_VALID(node)) { 2304a54a69d7SJulian Elischer error = EIO; 2305069154d5SJulian Elischer NG_FREE_ITEM(item); 2306c4b5eea4SJulian Elischer break; 2307069154d5SJulian Elischer } 2308c4b5eea4SJulian Elischer /* 2309c4b5eea4SJulian Elischer * If no receive method, just silently drop it. 2310c4b5eea4SJulian Elischer * Give preference to the hook over-ride method 2311c4b5eea4SJulian Elischer */ 2312c4b5eea4SJulian Elischer if ((!(rcvdata = hook->hk_rcvdata)) 2313c4b5eea4SJulian Elischer && (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) { 2314c4b5eea4SJulian Elischer error = 0; 2315c4b5eea4SJulian Elischer NG_FREE_ITEM(item); 2316c4b5eea4SJulian Elischer break; 2317c4b5eea4SJulian Elischer } 2318a54a69d7SJulian Elischer error = (*rcvdata)(hook, item); 2319069154d5SJulian Elischer break; 2320069154d5SJulian Elischer case NGQF_MESG: 2321e72a98f4SAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook)) { 2322069154d5SJulian Elischer /* 2323e72a98f4SAlexander Motin * The hook has been zapped then we can't use it. 2324e72a98f4SAlexander Motin * Immediately drop its reference. 2325069154d5SJulian Elischer * The message may not need it. 2326069154d5SJulian Elischer */ 232730400f03SJulian Elischer NG_HOOK_UNREF(hook); 2328069154d5SJulian Elischer hook = NULL; 2329069154d5SJulian Elischer } 2330069154d5SJulian Elischer /* 2331069154d5SJulian Elischer * Similarly, if the node is a zombie there is 2332069154d5SJulian Elischer * nothing we can do with it, drop everything. 2333069154d5SJulian Elischer */ 233430400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 23356b795970SJulian Elischer TRAP_ERROR(); 2336a54a69d7SJulian Elischer error = EINVAL; 2337069154d5SJulian Elischer NG_FREE_ITEM(item); 2338e72a98f4SAlexander Motin break; 2339e72a98f4SAlexander Motin } 2340069154d5SJulian Elischer /* 2341069154d5SJulian Elischer * Call the appropriate message handler for the object. 2342069154d5SJulian Elischer * It is up to the message handler to free the message. 2343069154d5SJulian Elischer * If it's a generic message, handle it generically, 2344e72a98f4SAlexander Motin * otherwise call the type's message handler (if it exists). 2345069154d5SJulian Elischer * XXX (race). Remember that a queued message may 2346069154d5SJulian Elischer * reference a node or hook that has just been 2347069154d5SJulian Elischer * invalidated. It will exist as the queue code 2348069154d5SJulian Elischer * is holding a reference, but.. 2349069154d5SJulian Elischer */ 2350e72a98f4SAlexander Motin if ((NGI_MSG(item)->header.typecookie == NGM_GENERIC_COOKIE) && 2351e72a98f4SAlexander Motin ((NGI_MSG(item)->header.flags & NGF_RESP) == 0)) { 2352a54a69d7SJulian Elischer error = ng_generic_msg(node, item, hook); 2353c4b5eea4SJulian Elischer break; 2354c4b5eea4SJulian Elischer } 2355e72a98f4SAlexander Motin if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) && 2356e72a98f4SAlexander Motin (!(rcvmsg = node->nd_type->rcvmsg))) { 23576b795970SJulian Elischer TRAP_ERROR(); 2358a54a69d7SJulian Elischer error = 0; 2359069154d5SJulian Elischer NG_FREE_ITEM(item); 2360c4b5eea4SJulian Elischer break; 2361069154d5SJulian Elischer } 2362a54a69d7SJulian Elischer error = (*rcvmsg)(node, item, hook); 2363069154d5SJulian Elischer break; 23646b795970SJulian Elischer case NGQF_FN: 2365e088dd4cSAlexander Motin case NGQF_FN2: 2366e088dd4cSAlexander Motin /* 236774c9119dSAlexander Motin * In the case of the shutdown message we allow it to hit 2368e088dd4cSAlexander Motin * even if the node is invalid. 2369e088dd4cSAlexander Motin */ 237074c9119dSAlexander Motin if (NG_NODE_NOT_VALID(node) && 237174c9119dSAlexander Motin NGI_FN(item) != &ng_rmnode) { 2372e088dd4cSAlexander Motin TRAP_ERROR(); 2373e088dd4cSAlexander Motin error = EINVAL; 2374e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2375e088dd4cSAlexander Motin break; 2376e088dd4cSAlexander Motin } 237774c9119dSAlexander Motin /* Same is about some internal functions and invalid hook. */ 237874c9119dSAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook) && 237974c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part2 && 238074c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part3 && 238174c9119dSAlexander Motin NGI_FN(item) != &ng_rmhook_part2) { 238274c9119dSAlexander Motin TRAP_ERROR(); 238374c9119dSAlexander Motin error = EINVAL; 238474c9119dSAlexander Motin NG_FREE_ITEM(item); 238574c9119dSAlexander Motin break; 238674c9119dSAlexander Motin } 238774c9119dSAlexander Motin 2388b332b91fSGleb Smirnoff if ((item->el_flags & NGQF_TYPE) == NGQF_FN) { 2389b332b91fSGleb Smirnoff (*NGI_FN(item))(node, hook, NGI_ARG1(item), 2390b332b91fSGleb Smirnoff NGI_ARG2(item)); 2391b332b91fSGleb Smirnoff NG_FREE_ITEM(item); 2392b332b91fSGleb Smirnoff } else /* it is NGQF_FN2 */ 2393e088dd4cSAlexander Motin error = (*NGI_FN2(item))(node, item, hook); 2394e088dd4cSAlexander Motin break; 2395069154d5SJulian Elischer } 2396069154d5SJulian Elischer /* 2397069154d5SJulian Elischer * We held references on some of the resources 2398069154d5SJulian Elischer * that we took from the item. Now that we have 2399069154d5SJulian Elischer * finished doing everything, drop those references. 2400069154d5SJulian Elischer */ 2401e72a98f4SAlexander Motin if (hook) 240230400f03SJulian Elischer NG_HOOK_UNREF(hook); 2403069154d5SJulian Elischer 2404f50597f5SAlexander Motin if (rw == NGQRW_R) 24059852972bSAlexander Motin ng_leave_read(node); 2406f50597f5SAlexander Motin else 24079852972bSAlexander Motin ng_leave_write(node); 24088afe16d5SGleb Smirnoff 24098afe16d5SGleb Smirnoff /* Apply callback. */ 241010e87318SAlexander Motin if (apply != NULL) { 241110e87318SAlexander Motin if (depth == 1 && error != 0) 241210e87318SAlexander Motin apply->error = error; 241310e87318SAlexander Motin if (refcount_release(&apply->refs)) 241410e87318SAlexander Motin (*apply->apply)(apply->context, apply->error); 241510e87318SAlexander Motin } 24168afe16d5SGleb Smirnoff 241727757487SGleb Smirnoff return (error); 2418069154d5SJulian Elischer } 2419069154d5SJulian Elischer 2420069154d5SJulian Elischer /*********************************************************************** 2421069154d5SJulian Elischer * Implement the 'generic' control messages 2422069154d5SJulian Elischer ***********************************************************************/ 2423069154d5SJulian Elischer static int 2424069154d5SJulian Elischer ng_generic_msg(node_p here, item_p item, hook_p lasthook) 24254cf49a43SJulian Elischer { 24264cf49a43SJulian Elischer int error = 0; 2427069154d5SJulian Elischer struct ng_mesg *msg; 2428069154d5SJulian Elischer struct ng_mesg *resp = NULL; 24294cf49a43SJulian Elischer 2430069154d5SJulian Elischer NGI_GET_MSG(item, msg); 24314cf49a43SJulian Elischer if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 24326b795970SJulian Elischer TRAP_ERROR(); 2433069154d5SJulian Elischer error = EINVAL; 2434069154d5SJulian Elischer goto out; 24354cf49a43SJulian Elischer } 24364cf49a43SJulian Elischer switch (msg->header.cmd) { 24374cf49a43SJulian Elischer case NGM_SHUTDOWN: 24381acb27c6SJulian Elischer ng_rmnode(here, NULL, NULL, 0); 24394cf49a43SJulian Elischer break; 24404cf49a43SJulian Elischer case NGM_MKPEER: 24414cf49a43SJulian Elischer { 24424cf49a43SJulian Elischer struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 24434cf49a43SJulian Elischer 24444cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*mkp)) { 24456b795970SJulian Elischer TRAP_ERROR(); 2446069154d5SJulian Elischer error = EINVAL; 2447069154d5SJulian Elischer break; 24484cf49a43SJulian Elischer } 24494cf49a43SJulian Elischer mkp->type[sizeof(mkp->type) - 1] = '\0'; 24504cf49a43SJulian Elischer mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 24514cf49a43SJulian Elischer mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 24524cf49a43SJulian Elischer error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 24534cf49a43SJulian Elischer break; 24544cf49a43SJulian Elischer } 24554cf49a43SJulian Elischer case NGM_CONNECT: 24564cf49a43SJulian Elischer { 24574cf49a43SJulian Elischer struct ngm_connect *const con = 24584cf49a43SJulian Elischer (struct ngm_connect *) msg->data; 24594cf49a43SJulian Elischer node_p node2; 24604cf49a43SJulian Elischer 24614cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*con)) { 24626b795970SJulian Elischer TRAP_ERROR(); 2463069154d5SJulian Elischer error = EINVAL; 2464069154d5SJulian Elischer break; 24654cf49a43SJulian Elischer } 24664cf49a43SJulian Elischer con->path[sizeof(con->path) - 1] = '\0'; 24674cf49a43SJulian Elischer con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 24684cf49a43SJulian Elischer con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 2469069154d5SJulian Elischer /* Don't forget we get a reference.. */ 2470069154d5SJulian Elischer error = ng_path2noderef(here, con->path, &node2, NULL); 24714cf49a43SJulian Elischer if (error) 24724cf49a43SJulian Elischer break; 2473e088dd4cSAlexander Motin error = ng_con_nodes(item, here, con->ourhook, 2474e088dd4cSAlexander Motin node2, con->peerhook); 247530400f03SJulian Elischer NG_NODE_UNREF(node2); 24764cf49a43SJulian Elischer break; 24774cf49a43SJulian Elischer } 24784cf49a43SJulian Elischer case NGM_NAME: 24794cf49a43SJulian Elischer { 24804cf49a43SJulian Elischer struct ngm_name *const nam = (struct ngm_name *) msg->data; 24814cf49a43SJulian Elischer 24824cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*nam)) { 24836b795970SJulian Elischer TRAP_ERROR(); 2484069154d5SJulian Elischer error = EINVAL; 2485069154d5SJulian Elischer break; 24864cf49a43SJulian Elischer } 24874cf49a43SJulian Elischer nam->name[sizeof(nam->name) - 1] = '\0'; 24884cf49a43SJulian Elischer error = ng_name_node(here, nam->name); 24894cf49a43SJulian Elischer break; 24904cf49a43SJulian Elischer } 24914cf49a43SJulian Elischer case NGM_RMHOOK: 24924cf49a43SJulian Elischer { 24934cf49a43SJulian Elischer struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 24944cf49a43SJulian Elischer hook_p hook; 24954cf49a43SJulian Elischer 24964cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*rmh)) { 24976b795970SJulian Elischer TRAP_ERROR(); 2498069154d5SJulian Elischer error = EINVAL; 2499069154d5SJulian Elischer break; 25004cf49a43SJulian Elischer } 25014cf49a43SJulian Elischer rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 2502899e9c4eSArchie Cobbs if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 25034cf49a43SJulian Elischer ng_destroy_hook(hook); 25044cf49a43SJulian Elischer break; 25054cf49a43SJulian Elischer } 25064cf49a43SJulian Elischer case NGM_NODEINFO: 25074cf49a43SJulian Elischer { 25084cf49a43SJulian Elischer struct nodeinfo *ni; 25094cf49a43SJulian Elischer 2510069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT); 25114cf49a43SJulian Elischer if (resp == NULL) { 25124cf49a43SJulian Elischer error = ENOMEM; 25134cf49a43SJulian Elischer break; 25144cf49a43SJulian Elischer } 25154cf49a43SJulian Elischer 25164cf49a43SJulian Elischer /* Fill in node info */ 2517069154d5SJulian Elischer ni = (struct nodeinfo *) resp->data; 251830400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 251987e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 252087e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2521dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 252230400f03SJulian Elischer ni->hooks = here->nd_numhooks; 25234cf49a43SJulian Elischer break; 25244cf49a43SJulian Elischer } 25254cf49a43SJulian Elischer case NGM_LISTHOOKS: 25264cf49a43SJulian Elischer { 252730400f03SJulian Elischer const int nhooks = here->nd_numhooks; 25284cf49a43SJulian Elischer struct hooklist *hl; 25294cf49a43SJulian Elischer struct nodeinfo *ni; 25304cf49a43SJulian Elischer hook_p hook; 25314cf49a43SJulian Elischer 25324cf49a43SJulian Elischer /* Get response struct */ 2533069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*hl) 25344cf49a43SJulian Elischer + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 2535069154d5SJulian Elischer if (resp == NULL) { 25364cf49a43SJulian Elischer error = ENOMEM; 25374cf49a43SJulian Elischer break; 25384cf49a43SJulian Elischer } 2539069154d5SJulian Elischer hl = (struct hooklist *) resp->data; 25404cf49a43SJulian Elischer ni = &hl->nodeinfo; 25414cf49a43SJulian Elischer 25424cf49a43SJulian Elischer /* Fill in node info */ 254330400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 254487e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 254587e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2546dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 25474cf49a43SJulian Elischer 25484cf49a43SJulian Elischer /* Cycle through the linked list of hooks */ 25494cf49a43SJulian Elischer ni->hooks = 0; 255030400f03SJulian Elischer LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) { 25514cf49a43SJulian Elischer struct linkinfo *const link = &hl->link[ni->hooks]; 25524cf49a43SJulian Elischer 25534cf49a43SJulian Elischer if (ni->hooks >= nhooks) { 25544cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 25556e551fb6SDavid E. O'Brien __func__, "hooks"); 25564cf49a43SJulian Elischer break; 25574cf49a43SJulian Elischer } 255830400f03SJulian Elischer if (NG_HOOK_NOT_VALID(hook)) 25594cf49a43SJulian Elischer continue; 256087e2c66aSHartmut Brandt strcpy(link->ourhook, NG_HOOK_NAME(hook)); 256187e2c66aSHartmut Brandt strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook)); 256230400f03SJulian Elischer if (NG_PEER_NODE_NAME(hook)[0] != '\0') 256387e2c66aSHartmut Brandt strcpy(link->nodeinfo.name, 256487e2c66aSHartmut Brandt NG_PEER_NODE_NAME(hook)); 256587e2c66aSHartmut Brandt strcpy(link->nodeinfo.type, 256687e2c66aSHartmut Brandt NG_PEER_NODE(hook)->nd_type->name); 256730400f03SJulian Elischer link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook)); 256830400f03SJulian Elischer link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks; 25694cf49a43SJulian Elischer ni->hooks++; 25704cf49a43SJulian Elischer } 25714cf49a43SJulian Elischer break; 25724cf49a43SJulian Elischer } 25734cf49a43SJulian Elischer 25744cf49a43SJulian Elischer case NGM_LISTNAMES: 25754cf49a43SJulian Elischer case NGM_LISTNODES: 25764cf49a43SJulian Elischer { 25774cf49a43SJulian Elischer const int unnamed = (msg->header.cmd == NGM_LISTNODES); 25784cf49a43SJulian Elischer struct namelist *nl; 25794cf49a43SJulian Elischer node_p node; 2580cfea3f85SAlexander Motin int num = 0, i; 25814cf49a43SJulian Elischer 2582cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 25834cf49a43SJulian Elischer /* Count number of nodes */ 2584cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2585603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2586cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 2587cfea3f85SAlexander Motin (unnamed || NG_NODE_HAS_NAME(node))) { 25884cf49a43SJulian Elischer num++; 25894cf49a43SJulian Elischer } 259070de87f2SJulian Elischer } 2591cfea3f85SAlexander Motin } 2592cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 25934cf49a43SJulian Elischer 25944cf49a43SJulian Elischer /* Get response struct */ 2595069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*nl) 25964cf49a43SJulian Elischer + (num * sizeof(struct nodeinfo)), M_NOWAIT); 2597069154d5SJulian Elischer if (resp == NULL) { 25984cf49a43SJulian Elischer error = ENOMEM; 25994cf49a43SJulian Elischer break; 26004cf49a43SJulian Elischer } 2601069154d5SJulian Elischer nl = (struct namelist *) resp->data; 26024cf49a43SJulian Elischer 26034cf49a43SJulian Elischer /* Cycle through the linked list of nodes */ 26044cf49a43SJulian Elischer nl->numnames = 0; 2605cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 2606cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2607603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2608cfea3f85SAlexander Motin struct nodeinfo *const np = 2609cfea3f85SAlexander Motin &nl->nodeinfo[nl->numnames]; 26104cf49a43SJulian Elischer 2611b96baf0aSGleb Smirnoff if (NG_NODE_NOT_VALID(node)) 2612b96baf0aSGleb Smirnoff continue; 2613b96baf0aSGleb Smirnoff if (!unnamed && (! NG_NODE_HAS_NAME(node))) 2614b96baf0aSGleb Smirnoff continue; 26154cf49a43SJulian Elischer if (nl->numnames >= num) { 2616cfea3f85SAlexander Motin log(LOG_ERR, "%s: number of nodes changed\n", 2617cfea3f85SAlexander Motin __func__); 26184cf49a43SJulian Elischer break; 26194cf49a43SJulian Elischer } 262030400f03SJulian Elischer if (NG_NODE_HAS_NAME(node)) 262187e2c66aSHartmut Brandt strcpy(np->name, NG_NODE_NAME(node)); 262287e2c66aSHartmut Brandt strcpy(np->type, node->nd_type->name); 2623dc90cad9SJulian Elischer np->id = ng_node2ID(node); 262430400f03SJulian Elischer np->hooks = node->nd_numhooks; 26254cf49a43SJulian Elischer nl->numnames++; 26264cf49a43SJulian Elischer } 2627cfea3f85SAlexander Motin } 2628cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 26294cf49a43SJulian Elischer break; 26304cf49a43SJulian Elischer } 26314cf49a43SJulian Elischer 26324cf49a43SJulian Elischer case NGM_LISTTYPES: 26334cf49a43SJulian Elischer { 26344cf49a43SJulian Elischer struct typelist *tl; 26354cf49a43SJulian Elischer struct ng_type *type; 26364cf49a43SJulian Elischer int num = 0; 26374cf49a43SJulian Elischer 26389ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 26394cf49a43SJulian Elischer /* Count number of types */ 264070de87f2SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 26414cf49a43SJulian Elischer num++; 264270de87f2SJulian Elischer } 26439ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 26444cf49a43SJulian Elischer 26454cf49a43SJulian Elischer /* Get response struct */ 2646069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*tl) 26474cf49a43SJulian Elischer + (num * sizeof(struct typeinfo)), M_NOWAIT); 2648069154d5SJulian Elischer if (resp == NULL) { 26494cf49a43SJulian Elischer error = ENOMEM; 26504cf49a43SJulian Elischer break; 26514cf49a43SJulian Elischer } 2652069154d5SJulian Elischer tl = (struct typelist *) resp->data; 26534cf49a43SJulian Elischer 26544cf49a43SJulian Elischer /* Cycle through the linked list of types */ 26554cf49a43SJulian Elischer tl->numtypes = 0; 26569ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 2657069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 26584cf49a43SJulian Elischer struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 26594cf49a43SJulian Elischer 26604cf49a43SJulian Elischer if (tl->numtypes >= num) { 26614cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 26626e551fb6SDavid E. O'Brien __func__, "types"); 26634cf49a43SJulian Elischer break; 26644cf49a43SJulian Elischer } 266587e2c66aSHartmut Brandt strcpy(tp->type_name, type->name); 2666c73b94a2SJulian Elischer tp->numnodes = type->refs - 1; /* don't count list */ 26674cf49a43SJulian Elischer tl->numtypes++; 26684cf49a43SJulian Elischer } 26699ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 26704cf49a43SJulian Elischer break; 26714cf49a43SJulian Elischer } 26724cf49a43SJulian Elischer 2673f8307e12SArchie Cobbs case NGM_BINARY2ASCII: 2674f8307e12SArchie Cobbs { 26757133ac27SArchie Cobbs int bufSize = 20 * 1024; /* XXX hard coded constant */ 2676f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2677f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2678069154d5SJulian Elischer struct ng_mesg *binary, *ascii; 2679f8307e12SArchie Cobbs 2680f8307e12SArchie Cobbs /* Data area must contain a valid netgraph message */ 2681f8307e12SArchie Cobbs binary = (struct ng_mesg *)msg->data; 26824c9b5910SGleb Smirnoff if (msg->header.arglen < sizeof(struct ng_mesg) || 26834c9b5910SGleb Smirnoff (msg->header.arglen - sizeof(struct ng_mesg) < 26844c9b5910SGleb Smirnoff binary->header.arglen)) { 26856b795970SJulian Elischer TRAP_ERROR(); 2686f8307e12SArchie Cobbs error = EINVAL; 2687f8307e12SArchie Cobbs break; 2688f8307e12SArchie Cobbs } 2689f8307e12SArchie Cobbs 2690f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2691069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 2692069154d5SJulian Elischer if (resp == NULL) { 2693f8307e12SArchie Cobbs error = ENOMEM; 2694f8307e12SArchie Cobbs break; 2695f8307e12SArchie Cobbs } 2696069154d5SJulian Elischer ascii = (struct ng_mesg *)resp->data; 2697f8307e12SArchie Cobbs 2698f8307e12SArchie Cobbs /* Copy binary message header to response message payload */ 2699f8307e12SArchie Cobbs bcopy(binary, ascii, sizeof(*binary)); 2700f8307e12SArchie Cobbs 2701f8307e12SArchie Cobbs /* Find command by matching typecookie and command number */ 270230400f03SJulian Elischer for (c = here->nd_type->cmdlist; 2703f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 2704f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 2705f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 2706f8307e12SArchie Cobbs break; 2707f8307e12SArchie Cobbs } 2708f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2709f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 2710f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 2711f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 2712f8307e12SArchie Cobbs break; 2713f8307e12SArchie Cobbs } 2714f8307e12SArchie Cobbs if (c->name == NULL) { 2715069154d5SJulian Elischer NG_FREE_MSG(resp); 2716f8307e12SArchie Cobbs error = ENOSYS; 2717f8307e12SArchie Cobbs break; 2718f8307e12SArchie Cobbs } 2719f8307e12SArchie Cobbs } 2720f8307e12SArchie Cobbs 2721f8307e12SArchie Cobbs /* Convert command name to ASCII */ 2722f8307e12SArchie Cobbs snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 2723f8307e12SArchie Cobbs "%s", c->name); 2724f8307e12SArchie Cobbs 2725f8307e12SArchie Cobbs /* Convert command arguments to ASCII */ 2726f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2727f8307e12SArchie Cobbs c->respType : c->mesgType; 272870de87f2SJulian Elischer if (argstype == NULL) { 2729f8307e12SArchie Cobbs *ascii->data = '\0'; 273070de87f2SJulian Elischer } else { 2731f8307e12SArchie Cobbs if ((error = ng_unparse(argstype, 2732f8307e12SArchie Cobbs (u_char *)binary->data, 2733f8307e12SArchie Cobbs ascii->data, bufSize)) != 0) { 2734069154d5SJulian Elischer NG_FREE_MSG(resp); 2735f8307e12SArchie Cobbs break; 2736f8307e12SArchie Cobbs } 2737f8307e12SArchie Cobbs } 2738f8307e12SArchie Cobbs 2739f8307e12SArchie Cobbs /* Return the result as struct ng_mesg plus ASCII string */ 2740f8307e12SArchie Cobbs bufSize = strlen(ascii->data) + 1; 2741f8307e12SArchie Cobbs ascii->header.arglen = bufSize; 2742069154d5SJulian Elischer resp->header.arglen = sizeof(*ascii) + bufSize; 2743f8307e12SArchie Cobbs break; 2744f8307e12SArchie Cobbs } 2745f8307e12SArchie Cobbs 2746f8307e12SArchie Cobbs case NGM_ASCII2BINARY: 2747f8307e12SArchie Cobbs { 274898a5a343SMarko Zec int bufSize = 20 * 1024; /* XXX hard coded constant */ 2749f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2750f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2751069154d5SJulian Elischer struct ng_mesg *ascii, *binary; 275252ec4a03SArchie Cobbs int off = 0; 2753f8307e12SArchie Cobbs 2754f8307e12SArchie Cobbs /* Data area must contain at least a struct ng_mesg + '\0' */ 2755f8307e12SArchie Cobbs ascii = (struct ng_mesg *)msg->data; 27564c9b5910SGleb Smirnoff if ((msg->header.arglen < sizeof(*ascii) + 1) || 27574c9b5910SGleb Smirnoff (ascii->header.arglen < 1) || 27584c9b5910SGleb Smirnoff (msg->header.arglen < sizeof(*ascii) + 27594c9b5910SGleb Smirnoff ascii->header.arglen)) { 27606b795970SJulian Elischer TRAP_ERROR(); 2761f8307e12SArchie Cobbs error = EINVAL; 2762f8307e12SArchie Cobbs break; 2763f8307e12SArchie Cobbs } 2764f8307e12SArchie Cobbs ascii->data[ascii->header.arglen - 1] = '\0'; 2765f8307e12SArchie Cobbs 2766f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2767069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 2768069154d5SJulian Elischer if (resp == NULL) { 2769f8307e12SArchie Cobbs error = ENOMEM; 2770f8307e12SArchie Cobbs break; 2771f8307e12SArchie Cobbs } 2772069154d5SJulian Elischer binary = (struct ng_mesg *)resp->data; 2773f8307e12SArchie Cobbs 2774f8307e12SArchie Cobbs /* Copy ASCII message header to response message payload */ 2775f8307e12SArchie Cobbs bcopy(ascii, binary, sizeof(*ascii)); 2776f8307e12SArchie Cobbs 2777f8307e12SArchie Cobbs /* Find command by matching ASCII command string */ 277830400f03SJulian Elischer for (c = here->nd_type->cmdlist; 2779f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 2780f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2781f8307e12SArchie Cobbs break; 2782f8307e12SArchie Cobbs } 2783f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2784f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 2785f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2786f8307e12SArchie Cobbs break; 2787f8307e12SArchie Cobbs } 2788f8307e12SArchie Cobbs if (c->name == NULL) { 2789069154d5SJulian Elischer NG_FREE_MSG(resp); 2790f8307e12SArchie Cobbs error = ENOSYS; 2791f8307e12SArchie Cobbs break; 2792f8307e12SArchie Cobbs } 2793f8307e12SArchie Cobbs } 2794f8307e12SArchie Cobbs 2795f8307e12SArchie Cobbs /* Convert command name to binary */ 2796f8307e12SArchie Cobbs binary->header.cmd = c->cmd; 2797f8307e12SArchie Cobbs binary->header.typecookie = c->cookie; 2798f8307e12SArchie Cobbs 2799f8307e12SArchie Cobbs /* Convert command arguments to binary */ 2800f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2801f8307e12SArchie Cobbs c->respType : c->mesgType; 280270de87f2SJulian Elischer if (argstype == NULL) { 2803f8307e12SArchie Cobbs bufSize = 0; 280470de87f2SJulian Elischer } else { 2805f8307e12SArchie Cobbs if ((error = ng_parse(argstype, ascii->data, 2806f8307e12SArchie Cobbs &off, (u_char *)binary->data, &bufSize)) != 0) { 2807069154d5SJulian Elischer NG_FREE_MSG(resp); 2808f8307e12SArchie Cobbs break; 2809f8307e12SArchie Cobbs } 2810f8307e12SArchie Cobbs } 2811f8307e12SArchie Cobbs 2812f8307e12SArchie Cobbs /* Return the result */ 2813f8307e12SArchie Cobbs binary->header.arglen = bufSize; 2814069154d5SJulian Elischer resp->header.arglen = sizeof(*binary) + bufSize; 2815f8307e12SArchie Cobbs break; 2816f8307e12SArchie Cobbs } 2817f8307e12SArchie Cobbs 28187095e097SPoul-Henning Kamp case NGM_TEXT_CONFIG: 28194cf49a43SJulian Elischer case NGM_TEXT_STATUS: 28204cf49a43SJulian Elischer /* 28214cf49a43SJulian Elischer * This one is tricky as it passes the command down to the 28224cf49a43SJulian Elischer * actual node, even though it is a generic type command. 2823069154d5SJulian Elischer * This means we must assume that the item/msg is already freed 28244cf49a43SJulian Elischer * when control passes back to us. 28254cf49a43SJulian Elischer */ 282630400f03SJulian Elischer if (here->nd_type->rcvmsg != NULL) { 2827069154d5SJulian Elischer NGI_MSG(item) = msg; /* put it back as we found it */ 282830400f03SJulian Elischer return((*here->nd_type->rcvmsg)(here, item, lasthook)); 28294cf49a43SJulian Elischer } 28304cf49a43SJulian Elischer /* Fall through if rcvmsg not supported */ 28314cf49a43SJulian Elischer default: 28326b795970SJulian Elischer TRAP_ERROR(); 28334cf49a43SJulian Elischer error = EINVAL; 28344cf49a43SJulian Elischer } 2835069154d5SJulian Elischer /* 2836069154d5SJulian Elischer * Sometimes a generic message may be statically allocated 2837069154d5SJulian Elischer * to avoid problems with allocating when in tight memeory situations. 2838069154d5SJulian Elischer * Don't free it if it is so. 2839069154d5SJulian Elischer * I break them appart here, because erros may cause a free if the item 2840069154d5SJulian Elischer * in which case we'd be doing it twice. 2841069154d5SJulian Elischer * they are kept together above, to simplify freeing. 2842069154d5SJulian Elischer */ 2843069154d5SJulian Elischer out: 2844069154d5SJulian Elischer NG_RESPOND_MSG(error, here, item, resp); 2845069154d5SJulian Elischer NG_FREE_MSG(msg); 28464cf49a43SJulian Elischer return (error); 28474cf49a43SJulian Elischer } 28484cf49a43SJulian Elischer 28494cf49a43SJulian Elischer /************************************************************************ 28508253c060SGleb Smirnoff Queue element get/free routines 28518253c060SGleb Smirnoff ************************************************************************/ 28528253c060SGleb Smirnoff 28538253c060SGleb Smirnoff uma_zone_t ng_qzone; 28546aa6d011SAlexander Motin uma_zone_t ng_qdzone; 2855f2fbb838SAlexander Motin static int numthreads = 0; /* number of queue threads */ 2856ed75521fSAlexander Motin static int maxalloc = 4096;/* limit the damage of a leak */ 2857ed75521fSAlexander Motin static int maxdata = 512; /* limit the damage of a DoS */ 28588253c060SGleb Smirnoff 2859f2fbb838SAlexander Motin TUNABLE_INT("net.graph.threads", &numthreads); 2860f2fbb838SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, threads, CTLFLAG_RDTUN, &numthreads, 2861f2fbb838SAlexander Motin 0, "Number of queue processing threads"); 28628253c060SGleb Smirnoff TUNABLE_INT("net.graph.maxalloc", &maxalloc); 28638253c060SGleb Smirnoff SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 28646aa6d011SAlexander Motin 0, "Maximum number of non-data queue items to allocate"); 2865ed75521fSAlexander Motin TUNABLE_INT("net.graph.maxdata", &maxdata); 28666aa6d011SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, maxdata, CTLFLAG_RDTUN, &maxdata, 28676aa6d011SAlexander Motin 0, "Maximum number of data queue items to allocate"); 28688253c060SGleb Smirnoff 28698253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 28708253c060SGleb Smirnoff static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist); 28718253c060SGleb Smirnoff static int allocated; /* number of items malloc'd */ 28728253c060SGleb Smirnoff #endif 28738253c060SGleb Smirnoff 28748253c060SGleb Smirnoff /* 28758253c060SGleb Smirnoff * Get a queue entry. 28768253c060SGleb Smirnoff * This is usually called when a packet first enters netgraph. 28778253c060SGleb Smirnoff * By definition, this is usually from an interrupt, or from a user. 28788253c060SGleb Smirnoff * Users are not so important, but try be quick for the times that it's 28798253c060SGleb Smirnoff * an interrupt. 28808253c060SGleb Smirnoff */ 28818253c060SGleb Smirnoff static __inline item_p 28826aa6d011SAlexander Motin ng_alloc_item(int type, int flags) 28838253c060SGleb Smirnoff { 28846aa6d011SAlexander Motin item_p item; 28858253c060SGleb Smirnoff 28866aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 28876aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 288842282202SGleb Smirnoff 28896aa6d011SAlexander Motin item = uma_zalloc((type == NGQF_DATA)?ng_qdzone:ng_qzone, 28906aa6d011SAlexander Motin ((flags & NG_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO); 28918253c060SGleb Smirnoff 28928253c060SGleb Smirnoff if (item) { 28936aa6d011SAlexander Motin item->el_flags = type; 28946aa6d011SAlexander Motin #ifdef NETGRAPH_DEBUG 28958253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 28968253c060SGleb Smirnoff TAILQ_INSERT_TAIL(&ng_itemlist, item, all); 28978253c060SGleb Smirnoff allocated++; 28988253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 28998253c060SGleb Smirnoff #endif 29006aa6d011SAlexander Motin } 29018253c060SGleb Smirnoff 29028253c060SGleb Smirnoff return (item); 29038253c060SGleb Smirnoff } 29048253c060SGleb Smirnoff 29058253c060SGleb Smirnoff /* 29068253c060SGleb Smirnoff * Release a queue entry 29078253c060SGleb Smirnoff */ 29088253c060SGleb Smirnoff void 29098253c060SGleb Smirnoff ng_free_item(item_p item) 29108253c060SGleb Smirnoff { 29118253c060SGleb Smirnoff /* 29128253c060SGleb Smirnoff * The item may hold resources on it's own. We need to free 29138253c060SGleb Smirnoff * these before we can free the item. What they are depends upon 29148253c060SGleb Smirnoff * what kind of item it is. it is important that nodes zero 29158253c060SGleb Smirnoff * out pointers to resources that they remove from the item 29168253c060SGleb Smirnoff * or we release them again here. 29178253c060SGleb Smirnoff */ 29188253c060SGleb Smirnoff switch (item->el_flags & NGQF_TYPE) { 29198253c060SGleb Smirnoff case NGQF_DATA: 29208253c060SGleb Smirnoff /* If we have an mbuf still attached.. */ 29218253c060SGleb Smirnoff NG_FREE_M(_NGI_M(item)); 29228253c060SGleb Smirnoff break; 29238253c060SGleb Smirnoff case NGQF_MESG: 29248253c060SGleb Smirnoff _NGI_RETADDR(item) = 0; 29258253c060SGleb Smirnoff NG_FREE_MSG(_NGI_MSG(item)); 29268253c060SGleb Smirnoff break; 29278253c060SGleb Smirnoff case NGQF_FN: 2928e088dd4cSAlexander Motin case NGQF_FN2: 29298253c060SGleb Smirnoff /* nothing to free really, */ 29308253c060SGleb Smirnoff _NGI_FN(item) = NULL; 29318253c060SGleb Smirnoff _NGI_ARG1(item) = NULL; 29328253c060SGleb Smirnoff _NGI_ARG2(item) = 0; 29338253c060SGleb Smirnoff break; 29348253c060SGleb Smirnoff } 29358253c060SGleb Smirnoff /* If we still have a node or hook referenced... */ 29368253c060SGleb Smirnoff _NGI_CLR_NODE(item); 29378253c060SGleb Smirnoff _NGI_CLR_HOOK(item); 29388253c060SGleb Smirnoff 29398253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 29408253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 29418253c060SGleb Smirnoff TAILQ_REMOVE(&ng_itemlist, item, all); 29428253c060SGleb Smirnoff allocated--; 29438253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 29448253c060SGleb Smirnoff #endif 29456aa6d011SAlexander Motin uma_zfree(((item->el_flags & NGQF_TYPE) == NGQF_DATA)? 29466aa6d011SAlexander Motin ng_qdzone:ng_qzone, item); 29476aa6d011SAlexander Motin } 29486aa6d011SAlexander Motin 29496aa6d011SAlexander Motin /* 29506aa6d011SAlexander Motin * Change type of the queue entry. 29516aa6d011SAlexander Motin * Possibly reallocates it from another UMA zone. 29526aa6d011SAlexander Motin */ 29536aa6d011SAlexander Motin static __inline item_p 29546aa6d011SAlexander Motin ng_realloc_item(item_p pitem, int type, int flags) 29556aa6d011SAlexander Motin { 29566aa6d011SAlexander Motin item_p item; 29576aa6d011SAlexander Motin int from, to; 29586aa6d011SAlexander Motin 29596aa6d011SAlexander Motin KASSERT((pitem != NULL), ("%s: can't reallocate NULL", __func__)); 29606aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 29616aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 29626aa6d011SAlexander Motin 29636aa6d011SAlexander Motin from = ((pitem->el_flags & NGQF_TYPE) == NGQF_DATA); 29646aa6d011SAlexander Motin to = (type == NGQF_DATA); 29656aa6d011SAlexander Motin if (from != to) { 29666aa6d011SAlexander Motin /* If reallocation is required do it and copy item. */ 29676aa6d011SAlexander Motin if ((item = ng_alloc_item(type, flags)) == NULL) { 29686aa6d011SAlexander Motin ng_free_item(pitem); 29696aa6d011SAlexander Motin return (NULL); 29706aa6d011SAlexander Motin } 29716aa6d011SAlexander Motin *item = *pitem; 29726aa6d011SAlexander Motin ng_free_item(pitem); 29736aa6d011SAlexander Motin } else 29746aa6d011SAlexander Motin item = pitem; 29756aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_TYPE) | type; 29766aa6d011SAlexander Motin 29776aa6d011SAlexander Motin return (item); 29788253c060SGleb Smirnoff } 29798253c060SGleb Smirnoff 29808253c060SGleb Smirnoff /************************************************************************ 29814cf49a43SJulian Elischer Module routines 29824cf49a43SJulian Elischer ************************************************************************/ 29834cf49a43SJulian Elischer 29844cf49a43SJulian Elischer /* 29854cf49a43SJulian Elischer * Handle the loading/unloading of a netgraph node type module 29864cf49a43SJulian Elischer */ 29874cf49a43SJulian Elischer int 29884cf49a43SJulian Elischer ng_mod_event(module_t mod, int event, void *data) 29894cf49a43SJulian Elischer { 29904cf49a43SJulian Elischer struct ng_type *const type = data; 29914cf49a43SJulian Elischer int s, error = 0; 29924cf49a43SJulian Elischer 29934cf49a43SJulian Elischer switch (event) { 29944cf49a43SJulian Elischer case MOD_LOAD: 29954cf49a43SJulian Elischer 29964cf49a43SJulian Elischer /* Register new netgraph node type */ 29974cf49a43SJulian Elischer s = splnet(); 29984cf49a43SJulian Elischer if ((error = ng_newtype(type)) != 0) { 29994cf49a43SJulian Elischer splx(s); 30004cf49a43SJulian Elischer break; 30014cf49a43SJulian Elischer } 30024cf49a43SJulian Elischer 30034cf49a43SJulian Elischer /* Call type specific code */ 30044cf49a43SJulian Elischer if (type->mod_event != NULL) 3005069154d5SJulian Elischer if ((error = (*type->mod_event)(mod, event, data))) { 30069ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 3007c73b94a2SJulian Elischer type->refs--; /* undo it */ 30084cf49a43SJulian Elischer LIST_REMOVE(type, types); 30099ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 3010069154d5SJulian Elischer } 30114cf49a43SJulian Elischer splx(s); 30124cf49a43SJulian Elischer break; 30134cf49a43SJulian Elischer 30144cf49a43SJulian Elischer case MOD_UNLOAD: 30154cf49a43SJulian Elischer s = splnet(); 3016c73b94a2SJulian Elischer if (type->refs > 1) { /* make sure no nodes exist! */ 30174cf49a43SJulian Elischer error = EBUSY; 3018c73b94a2SJulian Elischer } else { 3019c73b94a2SJulian Elischer if (type->refs == 0) { 3020c73b94a2SJulian Elischer /* failed load, nothing to undo */ 3021c73b94a2SJulian Elischer splx(s); 3022c73b94a2SJulian Elischer break; 3023c73b94a2SJulian Elischer } 30244cf49a43SJulian Elischer if (type->mod_event != NULL) { /* check with type */ 30254cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30264cf49a43SJulian Elischer if (error != 0) { /* type refuses.. */ 30274cf49a43SJulian Elischer splx(s); 30284cf49a43SJulian Elischer break; 30294cf49a43SJulian Elischer } 30304cf49a43SJulian Elischer } 30319ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 30324cf49a43SJulian Elischer LIST_REMOVE(type, types); 30339ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 30344cf49a43SJulian Elischer } 30354cf49a43SJulian Elischer splx(s); 30364cf49a43SJulian Elischer break; 30374cf49a43SJulian Elischer 30384cf49a43SJulian Elischer default: 30394cf49a43SJulian Elischer if (type->mod_event != NULL) 30404cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30414cf49a43SJulian Elischer else 30423e019deaSPoul-Henning Kamp error = EOPNOTSUPP; /* XXX ? */ 30434cf49a43SJulian Elischer break; 30444cf49a43SJulian Elischer } 30454cf49a43SJulian Elischer return (error); 30464cf49a43SJulian Elischer } 30474cf49a43SJulian Elischer 3048eddfbb76SRobert Watson #ifdef VIMAGE 3049d0728d71SRobert Watson static void 3050d0728d71SRobert Watson vnet_netgraph_uninit(const void *unused __unused) 3051bc29160dSMarko Zec { 3052a3f93b72SMarko Zec node_p node = NULL, last_killed = NULL; 3053a3f93b72SMarko Zec int i; 3054bc29160dSMarko Zec 3055a3f93b72SMarko Zec do { 3056a3f93b72SMarko Zec /* Find a node to kill */ 3057a3f93b72SMarko Zec mtx_lock(&ng_namehash_mtx); 3058a3f93b72SMarko Zec for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 3059a3f93b72SMarko Zec LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 3060a3f93b72SMarko Zec if (node != &ng_deadnode) { 3061a3f93b72SMarko Zec NG_NODE_REF(node); 3062a3f93b72SMarko Zec break; 3063a3f93b72SMarko Zec } 3064a3f93b72SMarko Zec } 3065a3f93b72SMarko Zec if (node != NULL) 3066a3f93b72SMarko Zec break; 3067a3f93b72SMarko Zec } 3068a3f93b72SMarko Zec mtx_unlock(&ng_namehash_mtx); 3069a3f93b72SMarko Zec 3070a3f93b72SMarko Zec /* Attempt to kill it only if it is a regular node */ 3071a3f93b72SMarko Zec if (node != NULL) { 3072bc29160dSMarko Zec if (node == last_killed) { 3073bc29160dSMarko Zec /* This should never happen */ 3074a3f93b72SMarko Zec printf("ng node %s needs" 3075a3f93b72SMarko Zec "NGF_REALLY_DIE\n", node->nd_name); 3076a3f93b72SMarko Zec if (node->nd_flags & NGF_REALLY_DIE) 3077a3f93b72SMarko Zec panic("ng node %s won't die", 3078a3f93b72SMarko Zec node->nd_name); 3079bc29160dSMarko Zec node->nd_flags |= NGF_REALLY_DIE; 3080bc29160dSMarko Zec } 3081bc29160dSMarko Zec ng_rmnode(node, NULL, NULL, 0); 3082a3f93b72SMarko Zec NG_NODE_UNREF(node); 3083bc29160dSMarko Zec last_killed = node; 3084bc29160dSMarko Zec } 3085a3f93b72SMarko Zec } while (node != NULL); 3086bc29160dSMarko Zec } 3087a3f93b72SMarko Zec VNET_SYSUNINIT(vnet_netgraph_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 3088d0728d71SRobert Watson vnet_netgraph_uninit, NULL); 3089bc29160dSMarko Zec #endif /* VIMAGE */ 3090bc29160dSMarko Zec 30914cf49a43SJulian Elischer /* 30924cf49a43SJulian Elischer * Handle loading and unloading for this code. 30934cf49a43SJulian Elischer * The only thing we need to link into is the NETISR strucure. 30944cf49a43SJulian Elischer */ 30954cf49a43SJulian Elischer static int 30964cf49a43SJulian Elischer ngb_mod_event(module_t mod, int event, void *data) 30974cf49a43SJulian Elischer { 3098f2fbb838SAlexander Motin struct proc *p; 3099f2fbb838SAlexander Motin struct thread *td; 3100f2fbb838SAlexander Motin int i, error = 0; 31014cf49a43SJulian Elischer 31024cf49a43SJulian Elischer switch (event) { 31034cf49a43SJulian Elischer case MOD_LOAD: 31041489164fSGleb Smirnoff /* Initialize everything. */ 31052c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK_INIT(); 3106efd8e7c9SDon Lewis mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL, 3107efd8e7c9SDon Lewis MTX_DEF); 3108efd8e7c9SDon Lewis mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL, 3109efd8e7c9SDon Lewis MTX_DEF); 3110cfea3f85SAlexander Motin mtx_init(&ng_namehash_mtx, "netgraph namehash mutex", NULL, 3111cfea3f85SAlexander Motin MTX_DEF); 3112ac5dd141SGleb Smirnoff mtx_init(&ng_topo_mtx, "netgraph topology mutex", NULL, 3113ac5dd141SGleb Smirnoff MTX_DEF); 31141489164fSGleb Smirnoff #ifdef NETGRAPH_DEBUG 3115cfea3f85SAlexander Motin mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL, 3116cfea3f85SAlexander Motin MTX_DEF); 31171489164fSGleb Smirnoff mtx_init(&ngq_mtx, "netgraph item list mutex", NULL, 3118efd8e7c9SDon Lewis MTX_DEF); 31191489164fSGleb Smirnoff #endif 31201489164fSGleb Smirnoff ng_qzone = uma_zcreate("NetGraph items", sizeof(struct ng_item), 31211489164fSGleb Smirnoff NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 31221489164fSGleb Smirnoff uma_zone_set_max(ng_qzone, maxalloc); 31236aa6d011SAlexander Motin ng_qdzone = uma_zcreate("NetGraph data items", sizeof(struct ng_item), 31246aa6d011SAlexander Motin NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 31256aa6d011SAlexander Motin uma_zone_set_max(ng_qdzone, maxdata); 3126f2fbb838SAlexander Motin /* Autoconfigure number of threads. */ 3127f2fbb838SAlexander Motin if (numthreads <= 0) 3128f2fbb838SAlexander Motin numthreads = mp_ncpus; 3129f2fbb838SAlexander Motin /* Create threads. */ 3130f2fbb838SAlexander Motin p = NULL; /* start with no process */ 3131f2fbb838SAlexander Motin for (i = 0; i < numthreads; i++) { 3132f2fbb838SAlexander Motin if (kproc_kthread_add(ngthread, NULL, &p, &td, 3133f2fbb838SAlexander Motin RFHIGHPID, 0, "ng_queue", "ng_queue%d", i)) { 3134f2fbb838SAlexander Motin numthreads = i; 3135f2fbb838SAlexander Motin break; 3136f2fbb838SAlexander Motin } 3137f2fbb838SAlexander Motin } 31384cf49a43SJulian Elischer break; 31394cf49a43SJulian Elischer case MOD_UNLOAD: 314064efc707SRobert Watson /* You can't unload it because an interface may be using it. */ 31414cf49a43SJulian Elischer error = EBUSY; 31424cf49a43SJulian Elischer break; 31434cf49a43SJulian Elischer default: 31444cf49a43SJulian Elischer error = EOPNOTSUPP; 31454cf49a43SJulian Elischer break; 31464cf49a43SJulian Elischer } 31474cf49a43SJulian Elischer return (error); 31484cf49a43SJulian Elischer } 31494cf49a43SJulian Elischer 31504cf49a43SJulian Elischer static moduledata_t netgraph_mod = { 31514cf49a43SJulian Elischer "netgraph", 31524cf49a43SJulian Elischer ngb_mod_event, 31534cf49a43SJulian Elischer (NULL) 31544cf49a43SJulian Elischer }; 3155aa38f8f9SMaksim Yevmenkin DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_NETGRAPH, SI_ORDER_MIDDLE); 3156bfa7e882SJulian Elischer SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 3157bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 3158bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 31594cf49a43SJulian Elischer 316030400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 316130400f03SJulian Elischer void 316230400f03SJulian Elischer dumphook (hook_p hook, char *file, int line) 316330400f03SJulian Elischer { 316430400f03SJulian Elischer printf("hook: name %s, %d refs, Last touched:\n", 316530400f03SJulian Elischer _NG_HOOK_NAME(hook), hook->hk_refs); 316630400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 316730400f03SJulian Elischer hook->lastfile, hook->lastline); 316830400f03SJulian Elischer if (line) { 316930400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 3170*e5fe87b3SGleb Smirnoff #ifdef KDB 3171*e5fe87b3SGleb Smirnoff kdb_backtrace(); 3172*e5fe87b3SGleb Smirnoff #endif 317330400f03SJulian Elischer } 317430400f03SJulian Elischer } 317530400f03SJulian Elischer 317630400f03SJulian Elischer void 317730400f03SJulian Elischer dumpnode(node_p node, char *file, int line) 317830400f03SJulian Elischer { 317930400f03SJulian Elischer printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n", 31806b795970SJulian Elischer _NG_NODE_ID(node), node->nd_type->name, 318130400f03SJulian Elischer node->nd_numhooks, node->nd_flags, 318230400f03SJulian Elischer node->nd_refs, node->nd_name); 318330400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 318430400f03SJulian Elischer node->lastfile, node->lastline); 318530400f03SJulian Elischer if (line) { 318630400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 3187*e5fe87b3SGleb Smirnoff #ifdef KDB 3188*e5fe87b3SGleb Smirnoff kdb_backtrace(); 3189*e5fe87b3SGleb Smirnoff #endif 319030400f03SJulian Elischer } 319130400f03SJulian Elischer } 319230400f03SJulian Elischer 3193069154d5SJulian Elischer void 3194069154d5SJulian Elischer dumpitem(item_p item, char *file, int line) 3195069154d5SJulian Elischer { 3196069154d5SJulian Elischer printf(" ACTIVE item, last used at %s, line %d", 3197069154d5SJulian Elischer item->lastfile, item->lastline); 31986b795970SJulian Elischer switch(item->el_flags & NGQF_TYPE) { 31996b795970SJulian Elischer case NGQF_DATA: 3200069154d5SJulian Elischer printf(" - [data]\n"); 32016b795970SJulian Elischer break; 32026b795970SJulian Elischer case NGQF_MESG: 32036b795970SJulian Elischer printf(" - retaddr[%d]:\n", _NGI_RETADDR(item)); 32046b795970SJulian Elischer break; 32056b795970SJulian Elischer case NGQF_FN: 3206857304e6SRuslan Ermilov printf(" - fn@%p (%p, %p, %p, %d (%x))\n", 3207857304e6SRuslan Ermilov _NGI_FN(item), 3208857304e6SRuslan Ermilov _NGI_NODE(item), 3209857304e6SRuslan Ermilov _NGI_HOOK(item), 3210857304e6SRuslan Ermilov item->body.fn.fn_arg1, 3211857304e6SRuslan Ermilov item->body.fn.fn_arg2, 3212857304e6SRuslan Ermilov item->body.fn.fn_arg2); 3213857304e6SRuslan Ermilov break; 3214e088dd4cSAlexander Motin case NGQF_FN2: 3215eb4687d2SAlexander Motin printf(" - fn2@%p (%p, %p, %p, %d (%x))\n", 3216857304e6SRuslan Ermilov _NGI_FN2(item), 32176064e568SGleb Smirnoff _NGI_NODE(item), 32186064e568SGleb Smirnoff _NGI_HOOK(item), 32196b795970SJulian Elischer item->body.fn.fn_arg1, 32206b795970SJulian Elischer item->body.fn.fn_arg2, 32216b795970SJulian Elischer item->body.fn.fn_arg2); 32226b795970SJulian Elischer break; 3223069154d5SJulian Elischer } 322430400f03SJulian Elischer if (line) { 3225069154d5SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 32266064e568SGleb Smirnoff if (_NGI_NODE(item)) { 322730400f03SJulian Elischer printf("node %p ([%x])\n", 32286064e568SGleb Smirnoff _NGI_NODE(item), ng_node2ID(_NGI_NODE(item))); 3229069154d5SJulian Elischer } 323030400f03SJulian Elischer } 323130400f03SJulian Elischer } 323230400f03SJulian Elischer 323330400f03SJulian Elischer static void 323430400f03SJulian Elischer ng_dumpitems(void) 323530400f03SJulian Elischer { 323630400f03SJulian Elischer item_p item; 323730400f03SJulian Elischer int i = 1; 323830400f03SJulian Elischer TAILQ_FOREACH(item, &ng_itemlist, all) { 323930400f03SJulian Elischer printf("[%d] ", i++); 324030400f03SJulian Elischer dumpitem(item, NULL, 0); 324130400f03SJulian Elischer } 324230400f03SJulian Elischer } 324330400f03SJulian Elischer 324430400f03SJulian Elischer static void 324530400f03SJulian Elischer ng_dumpnodes(void) 324630400f03SJulian Elischer { 324730400f03SJulian Elischer node_p node; 324830400f03SJulian Elischer int i = 1; 324953f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 325030400f03SJulian Elischer SLIST_FOREACH(node, &ng_allnodes, nd_all) { 325130400f03SJulian Elischer printf("[%d] ", i++); 325230400f03SJulian Elischer dumpnode(node, NULL, 0); 325330400f03SJulian Elischer } 325453f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 325530400f03SJulian Elischer } 325630400f03SJulian Elischer 325730400f03SJulian Elischer static void 325830400f03SJulian Elischer ng_dumphooks(void) 325930400f03SJulian Elischer { 326030400f03SJulian Elischer hook_p hook; 326130400f03SJulian Elischer int i = 1; 326253f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 326330400f03SJulian Elischer SLIST_FOREACH(hook, &ng_allhooks, hk_all) { 326430400f03SJulian Elischer printf("[%d] ", i++); 326530400f03SJulian Elischer dumphook(hook, NULL, 0); 326630400f03SJulian Elischer } 326753f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 326830400f03SJulian Elischer } 3269069154d5SJulian Elischer 3270069154d5SJulian Elischer static int 3271069154d5SJulian Elischer sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS) 3272069154d5SJulian Elischer { 3273069154d5SJulian Elischer int error; 3274069154d5SJulian Elischer int val; 3275069154d5SJulian Elischer int i; 3276069154d5SJulian Elischer 3277069154d5SJulian Elischer val = allocated; 3278069154d5SJulian Elischer i = 1; 3279041b706bSDavid Malone error = sysctl_handle_int(oidp, &val, 0, req); 32806b795970SJulian Elischer if (error != 0 || req->newptr == NULL) 32816b795970SJulian Elischer return (error); 32826b795970SJulian Elischer if (val == 42) { 328330400f03SJulian Elischer ng_dumpitems(); 328430400f03SJulian Elischer ng_dumpnodes(); 328530400f03SJulian Elischer ng_dumphooks(); 3286069154d5SJulian Elischer } 32876b795970SJulian Elischer return (0); 3288069154d5SJulian Elischer } 3289069154d5SJulian Elischer 32906b795970SJulian Elischer SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, 32916b795970SJulian Elischer 0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items"); 329230400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 3293069154d5SJulian Elischer 3294069154d5SJulian Elischer 3295069154d5SJulian Elischer /*********************************************************************** 3296069154d5SJulian Elischer * Worklist routines 3297069154d5SJulian Elischer **********************************************************************/ 3298069154d5SJulian Elischer /* 3299069154d5SJulian Elischer * Pick a node off the list of nodes with work, 3300f2fbb838SAlexander Motin * try get an item to process off it. Remove the node from the list. 3301069154d5SJulian Elischer */ 3302069154d5SJulian Elischer static void 3303f2fbb838SAlexander Motin ngthread(void *arg) 3304069154d5SJulian Elischer { 3305069154d5SJulian Elischer for (;;) { 3306394cb30aSAlexander Motin node_p node; 3307394cb30aSAlexander Motin 3308394cb30aSAlexander Motin /* Get node from the worklist. */ 33092c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 3310f2fbb838SAlexander Motin while ((node = STAILQ_FIRST(&ng_worklist)) == NULL) 3311f2fbb838SAlexander Motin NG_WORKLIST_SLEEP(); 33129852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work); 33132c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 3314bc29160dSMarko Zec CURVNET_SET(node->nd_vnet); 33152955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist", 33162955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3317069154d5SJulian Elischer /* 3318069154d5SJulian Elischer * We have the node. We also take over the reference 3319069154d5SJulian Elischer * that the list had on it. 3320069154d5SJulian Elischer * Now process as much as you can, until it won't 3321069154d5SJulian Elischer * let you have another item off the queue. 3322069154d5SJulian Elischer * All this time, keep the reference 3323069154d5SJulian Elischer * that lets us be sure that the node still exists. 3324069154d5SJulian Elischer * Let the reference go at the last minute. 3325069154d5SJulian Elischer */ 3326069154d5SJulian Elischer for (;;) { 3327394cb30aSAlexander Motin item_p item; 3328714fb865SGleb Smirnoff int rw; 3329714fb865SGleb Smirnoff 33302c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(&node->nd_input_queue); 33319852972bSAlexander Motin item = ng_dequeue(node, &rw); 3332069154d5SJulian Elischer if (item == NULL) { 33339852972bSAlexander Motin node->nd_input_queue.q_flags2 &= ~NGQ2_WORKQ; 33342c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 3335069154d5SJulian Elischer break; /* go look for another node */ 3336069154d5SJulian Elischer } else { 33372c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 33385951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 3339714fb865SGleb Smirnoff ng_apply_item(node, item, rw); 33405951069aSJulian Elischer NG_NODE_UNREF(node); 3341069154d5SJulian Elischer } 3342069154d5SJulian Elischer } 3343a96dcd84SJulian Elischer NG_NODE_UNREF(node); 3344bc29160dSMarko Zec CURVNET_RESTORE(); 3345069154d5SJulian Elischer } 3346069154d5SJulian Elischer } 3347069154d5SJulian Elischer 334833338e73SJulian Elischer /* 334933338e73SJulian Elischer * XXX 335033338e73SJulian Elischer * It's posible that a debugging NG_NODE_REF may need 335133338e73SJulian Elischer * to be outside the mutex zone 335233338e73SJulian Elischer */ 3353069154d5SJulian Elischer static void 3354394cb30aSAlexander Motin ng_worklist_add(node_p node) 3355069154d5SJulian Elischer { 3356f912c0f7SGleb Smirnoff 33575bc15201SGleb Smirnoff mtx_assert(&node->nd_input_queue.q_mtx, MA_OWNED); 3358f912c0f7SGleb Smirnoff 33599852972bSAlexander Motin if ((node->nd_input_queue.q_flags2 & NGQ2_WORKQ) == 0) { 3360069154d5SJulian Elischer /* 3361069154d5SJulian Elischer * If we are not already on the work queue, 3362069154d5SJulian Elischer * then put us on. 3363069154d5SJulian Elischer */ 33649852972bSAlexander Motin node->nd_input_queue.q_flags2 |= NGQ2_WORKQ; 3365394cb30aSAlexander Motin NG_NODE_REF(node); /* XXX fafe in mutex? */ 33662c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 33679852972bSAlexander Motin STAILQ_INSERT_TAIL(&ng_worklist, node, nd_input_queue.q_work); 33682c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 33692955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__, 33702955ee18SGleb Smirnoff node->nd_ID, node); 3371f2fbb838SAlexander Motin NG_WORKLIST_WAKEUP(); 3372394cb30aSAlexander Motin } else { 33732955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist", 33742955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3375394cb30aSAlexander Motin } 3376069154d5SJulian Elischer } 3377069154d5SJulian Elischer 3378069154d5SJulian Elischer 3379069154d5SJulian Elischer /*********************************************************************** 3380069154d5SJulian Elischer * Externally useable functions to set up a queue item ready for sending 3381069154d5SJulian Elischer ***********************************************************************/ 3382069154d5SJulian Elischer 338330400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 338430400f03SJulian Elischer #define ITEM_DEBUG_CHECKS \ 33854cf49a43SJulian Elischer do { \ 33861acb27c6SJulian Elischer if (NGI_NODE(item) ) { \ 3387069154d5SJulian Elischer printf("item already has node"); \ 33883de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has node"); \ 33891acb27c6SJulian Elischer NGI_CLR_NODE(item); \ 3390069154d5SJulian Elischer } \ 33911acb27c6SJulian Elischer if (NGI_HOOK(item) ) { \ 3392069154d5SJulian Elischer printf("item already has hook"); \ 33933de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has hook"); \ 33941acb27c6SJulian Elischer NGI_CLR_HOOK(item); \ 3395069154d5SJulian Elischer } \ 3396069154d5SJulian Elischer } while (0) 3397069154d5SJulian Elischer #else 339830400f03SJulian Elischer #define ITEM_DEBUG_CHECKS 3399069154d5SJulian Elischer #endif 3400069154d5SJulian Elischer 3401069154d5SJulian Elischer /* 34028ed370fdSJulian Elischer * Put mbuf into the item. 3403069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3404069154d5SJulian Elischer * (or equivalent) 3405069154d5SJulian Elischer * (XXX) Unsafe because no reference held by peer on remote node. 3406069154d5SJulian Elischer * remote node might go away in this timescale. 3407069154d5SJulian Elischer * We know the hooks can't go away because that would require getting 3408069154d5SJulian Elischer * a writer item on both nodes and we must have at least a reader 34094be59335SGleb Smirnoff * here to be able to do this. 3410069154d5SJulian Elischer * Note that the hook loaded is the REMOTE hook. 3411069154d5SJulian Elischer * 3412069154d5SJulian Elischer * This is possibly in the critical path for new data. 3413069154d5SJulian Elischer */ 3414069154d5SJulian Elischer item_p 341542282202SGleb Smirnoff ng_package_data(struct mbuf *m, int flags) 3416069154d5SJulian Elischer { 3417069154d5SJulian Elischer item_p item; 3418069154d5SJulian Elischer 34196aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_DATA, flags)) == NULL) { 3420069154d5SJulian Elischer NG_FREE_M(m); 3421069154d5SJulian Elischer return (NULL); 3422069154d5SJulian Elischer } 342330400f03SJulian Elischer ITEM_DEBUG_CHECKS; 34246aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 3425069154d5SJulian Elischer NGI_M(item) = m; 3426069154d5SJulian Elischer return (item); 3427069154d5SJulian Elischer } 3428069154d5SJulian Elischer 3429069154d5SJulian Elischer /* 3430069154d5SJulian Elischer * Allocate a queue item and put items into it.. 3431069154d5SJulian Elischer * Evaluate the address as this will be needed to queue it and 3432069154d5SJulian Elischer * to work out what some of the fields should be. 3433069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3434069154d5SJulian Elischer * (or equivalent) 3435069154d5SJulian Elischer */ 3436069154d5SJulian Elischer item_p 343742282202SGleb Smirnoff ng_package_msg(struct ng_mesg *msg, int flags) 3438069154d5SJulian Elischer { 3439069154d5SJulian Elischer item_p item; 3440069154d5SJulian Elischer 34416aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, flags)) == NULL) { 3442069154d5SJulian Elischer NG_FREE_MSG(msg); 3443069154d5SJulian Elischer return (NULL); 3444069154d5SJulian Elischer } 344530400f03SJulian Elischer ITEM_DEBUG_CHECKS; 34466f683eeeSGleb Smirnoff /* Messages items count as writers unless explicitly exempted. */ 34476f683eeeSGleb Smirnoff if (msg->header.cmd & NGM_READONLY) 34486aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 34496f683eeeSGleb Smirnoff else 34506aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3451069154d5SJulian Elischer /* 3452069154d5SJulian Elischer * Set the current lasthook into the queue item 3453069154d5SJulian Elischer */ 3454069154d5SJulian Elischer NGI_MSG(item) = msg; 3455facfd889SArchie Cobbs NGI_RETADDR(item) = 0; 3456069154d5SJulian Elischer return (item); 3457069154d5SJulian Elischer } 3458069154d5SJulian Elischer 3459069154d5SJulian Elischer 3460069154d5SJulian Elischer 34611acb27c6SJulian Elischer #define SET_RETADDR(item, here, retaddr) \ 34626b795970SJulian Elischer do { /* Data or fn items don't have retaddrs */ \ 34636b795970SJulian Elischer if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \ 3464069154d5SJulian Elischer if (retaddr) { \ 3465069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; \ 34664cf49a43SJulian Elischer } else { \ 3467069154d5SJulian Elischer /* \ 3468069154d5SJulian Elischer * The old return address should be ok. \ 3469069154d5SJulian Elischer * If there isn't one, use the address \ 3470069154d5SJulian Elischer * here. \ 3471069154d5SJulian Elischer */ \ 3472069154d5SJulian Elischer if (NGI_RETADDR(item) == 0) { \ 3473069154d5SJulian Elischer NGI_RETADDR(item) \ 3474069154d5SJulian Elischer = ng_node2ID(here); \ 3475069154d5SJulian Elischer } \ 3476069154d5SJulian Elischer } \ 34774cf49a43SJulian Elischer } \ 34784cf49a43SJulian Elischer } while (0) 34794cf49a43SJulian Elischer 34804cf49a43SJulian Elischer int 3481069154d5SJulian Elischer ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr) 34824cf49a43SJulian Elischer { 34831acb27c6SJulian Elischer hook_p peer; 34841acb27c6SJulian Elischer node_p peernode; 348530400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3486069154d5SJulian Elischer /* 3487069154d5SJulian Elischer * Quick sanity check.. 348830400f03SJulian Elischer * Since a hook holds a reference on it's node, once we know 348930400f03SJulian Elischer * that the peer is still connected (even if invalid,) we know 349030400f03SJulian Elischer * that the peer node is present, though maybe invalid. 3491069154d5SJulian Elischer */ 3492a7da736aSGleb Smirnoff mtx_lock(&ng_topo_mtx); 3493a04e9846SAlexander Motin if ((hook == NULL) || 3494a04e9846SAlexander Motin NG_HOOK_NOT_VALID(hook) || 3495a04e9846SAlexander Motin NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) || 3496a04e9846SAlexander Motin NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) { 3497069154d5SJulian Elischer NG_FREE_ITEM(item); 34986b795970SJulian Elischer TRAP_ERROR(); 3499a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 3500e08d3e3cSJulian Elischer return (ENETDOWN); 35014cf49a43SJulian Elischer } 35024cf49a43SJulian Elischer 35034cf49a43SJulian Elischer /* 3504069154d5SJulian Elischer * Transfer our interest to the other (peer) end. 35054cf49a43SJulian Elischer */ 35061acb27c6SJulian Elischer NG_HOOK_REF(peer); 35071acb27c6SJulian Elischer NG_NODE_REF(peernode); 3508a04e9846SAlexander Motin NGI_SET_HOOK(item, peer); 35091acb27c6SJulian Elischer NGI_SET_NODE(item, peernode); 35108b68f82fSJulian Elischer SET_RETADDR(item, here, retaddr); 3511a7da736aSGleb Smirnoff 3512a7da736aSGleb Smirnoff mtx_unlock(&ng_topo_mtx); 3513a7da736aSGleb Smirnoff 3514069154d5SJulian Elischer return (0); 3515069154d5SJulian Elischer } 3516069154d5SJulian Elischer 35174cf49a43SJulian Elischer int 3518069154d5SJulian Elischer ng_address_path(node_p here, item_p item, char *address, ng_ID_t retaddr) 35194cf49a43SJulian Elischer { 35204cf49a43SJulian Elischer node_p dest = NULL; 3521069154d5SJulian Elischer hook_p hook = NULL; 35224cf49a43SJulian Elischer int error; 3523069154d5SJulian Elischer 352430400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3525069154d5SJulian Elischer /* 3526069154d5SJulian Elischer * Note that ng_path2noderef increments the reference count 3527069154d5SJulian Elischer * on the node for us if it finds one. So we don't have to. 3528069154d5SJulian Elischer */ 3529069154d5SJulian Elischer error = ng_path2noderef(here, address, &dest, &hook); 3530069154d5SJulian Elischer if (error) { 3531069154d5SJulian Elischer NG_FREE_ITEM(item); 353230400f03SJulian Elischer return (error); 3533069154d5SJulian Elischer } 35341acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 3535a7da736aSGleb Smirnoff if (hook) 35361acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 3537a7da736aSGleb Smirnoff 35381acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3539069154d5SJulian Elischer return (0); 3540069154d5SJulian Elischer } 3541069154d5SJulian Elischer 3542069154d5SJulian Elischer int 3543069154d5SJulian Elischer ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr) 3544069154d5SJulian Elischer { 3545069154d5SJulian Elischer node_p dest; 3546069154d5SJulian Elischer 354730400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3548069154d5SJulian Elischer /* 3549069154d5SJulian Elischer * Find the target node. 3550069154d5SJulian Elischer */ 3551069154d5SJulian Elischer dest = ng_ID2noderef(ID); /* GETS REFERENCE! */ 3552069154d5SJulian Elischer if (dest == NULL) { 3553069154d5SJulian Elischer NG_FREE_ITEM(item); 35546b795970SJulian Elischer TRAP_ERROR(); 3555069154d5SJulian Elischer return(EINVAL); 3556069154d5SJulian Elischer } 3557069154d5SJulian Elischer /* Fill out the contents */ 35581acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 35591acb27c6SJulian Elischer NGI_CLR_HOOK(item); 35601acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3561069154d5SJulian Elischer return (0); 3562069154d5SJulian Elischer } 3563069154d5SJulian Elischer 3564069154d5SJulian Elischer /* 3565069154d5SJulian Elischer * special case to send a message to self (e.g. destroy node) 3566069154d5SJulian Elischer * Possibly indicate an arrival hook too. 3567069154d5SJulian Elischer * Useful for removing that hook :-) 3568069154d5SJulian Elischer */ 3569069154d5SJulian Elischer item_p 3570069154d5SJulian Elischer ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg) 3571069154d5SJulian Elischer { 3572069154d5SJulian Elischer item_p item; 35734cf49a43SJulian Elischer 3574859a4d16SJulian Elischer /* 3575859a4d16SJulian Elischer * Find the target node. 3576859a4d16SJulian Elischer * If there is a HOOK argument, then use that in preference 3577859a4d16SJulian Elischer * to the address. 3578859a4d16SJulian Elischer */ 35796aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, NG_NOFLAGS)) == NULL) { 3580069154d5SJulian Elischer NG_FREE_MSG(msg); 3581069154d5SJulian Elischer return (NULL); 35824cf49a43SJulian Elischer } 35834cf49a43SJulian Elischer 35844cf49a43SJulian Elischer /* Fill out the contents */ 35856aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 358630400f03SJulian Elischer NG_NODE_REF(here); 35871acb27c6SJulian Elischer NGI_SET_NODE(item, here); 35881acb27c6SJulian Elischer if (hook) { 358930400f03SJulian Elischer NG_HOOK_REF(hook); 35901acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 35911acb27c6SJulian Elischer } 3592069154d5SJulian Elischer NGI_MSG(item) = msg; 3593069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3594069154d5SJulian Elischer return (item); 35954cf49a43SJulian Elischer } 35964cf49a43SJulian Elischer 3597e088dd4cSAlexander Motin /* 3598e088dd4cSAlexander Motin * Send ng_item_fn function call to the specified node. 3599e088dd4cSAlexander Motin */ 3600e088dd4cSAlexander Motin 360142282202SGleb Smirnoff int 3602b332b91fSGleb Smirnoff ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2) 3603b332b91fSGleb Smirnoff { 3604b332b91fSGleb Smirnoff 3605b332b91fSGleb Smirnoff return ng_send_fn1(node, hook, fn, arg1, arg2, NG_NOFLAGS); 3606b332b91fSGleb Smirnoff } 3607b332b91fSGleb Smirnoff 3608b332b91fSGleb Smirnoff int 3609aacdb114SGleb Smirnoff ng_send_fn1(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2, 361042282202SGleb Smirnoff int flags) 36116b795970SJulian Elischer { 36126b795970SJulian Elischer item_p item; 36136b795970SJulian Elischer 36146aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, flags)) == NULL) { 36156b795970SJulian Elischer return (ENOMEM); 36166b795970SJulian Elischer } 36176aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3618a96dcd84SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 36191acb27c6SJulian Elischer NGI_SET_NODE(item, node); 36201acb27c6SJulian Elischer if (hook) { 36216b795970SJulian Elischer NG_HOOK_REF(hook); 36221acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 36236b795970SJulian Elischer } 36246b795970SJulian Elischer NGI_FN(item) = fn; 36256b795970SJulian Elischer NGI_ARG1(item) = arg1; 36266b795970SJulian Elischer NGI_ARG2(item) = arg2; 362742282202SGleb Smirnoff return(ng_snd_item(item, flags)); 36286b795970SJulian Elischer } 36296b795970SJulian Elischer 36304cf49a43SJulian Elischer /* 3631b332b91fSGleb Smirnoff * Send ng_item_fn2 function call to the specified node. 3632b332b91fSGleb Smirnoff * 3633b332b91fSGleb Smirnoff * If an optional pitem parameter is supplied, its apply 3634b332b91fSGleb Smirnoff * callback will be copied to the new item. If also NG_REUSE_ITEM 3635b332b91fSGleb Smirnoff * flag is set, no new item will be allocated, but pitem will 3636b332b91fSGleb Smirnoff * be used. 3637e088dd4cSAlexander Motin */ 3638e088dd4cSAlexander Motin int 3639b332b91fSGleb Smirnoff ng_send_fn2(node_p node, hook_p hook, item_p pitem, ng_item_fn2 *fn, void *arg1, 3640b332b91fSGleb Smirnoff int arg2, int flags) 3641e088dd4cSAlexander Motin { 3642e088dd4cSAlexander Motin item_p item; 3643e088dd4cSAlexander Motin 3644b332b91fSGleb Smirnoff KASSERT((pitem != NULL || (flags & NG_REUSE_ITEM) == 0), 3645b332b91fSGleb Smirnoff ("%s: NG_REUSE_ITEM but no pitem", __func__)); 3646e088dd4cSAlexander Motin 3647e088dd4cSAlexander Motin /* 3648b332b91fSGleb Smirnoff * Allocate a new item if no supplied or 3649b332b91fSGleb Smirnoff * if we can't use supplied one. 3650e088dd4cSAlexander Motin */ 3651b332b91fSGleb Smirnoff if (pitem == NULL || (flags & NG_REUSE_ITEM) == 0) { 36526aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN2, flags)) == NULL) 3653e088dd4cSAlexander Motin return (ENOMEM); 36546aa6d011SAlexander Motin if (pitem != NULL) 36556aa6d011SAlexander Motin item->apply = pitem->apply; 3656ed75521fSAlexander Motin } else { 36576aa6d011SAlexander Motin if ((item = ng_realloc_item(pitem, NGQF_FN2, flags)) == NULL) 36586aa6d011SAlexander Motin return (ENOMEM); 3659ed75521fSAlexander Motin } 3660b332b91fSGleb Smirnoff 36616aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_RW) | NGQF_WRITER; 3662e088dd4cSAlexander Motin NG_NODE_REF(node); /* and one for the item */ 3663e088dd4cSAlexander Motin NGI_SET_NODE(item, node); 3664e088dd4cSAlexander Motin if (hook) { 3665e088dd4cSAlexander Motin NG_HOOK_REF(hook); 3666e088dd4cSAlexander Motin NGI_SET_HOOK(item, hook); 3667e088dd4cSAlexander Motin } 3668e088dd4cSAlexander Motin NGI_FN2(item) = fn; 3669e088dd4cSAlexander Motin NGI_ARG1(item) = arg1; 3670e088dd4cSAlexander Motin NGI_ARG2(item) = arg2; 3671e088dd4cSAlexander Motin return(ng_snd_item(item, flags)); 3672e088dd4cSAlexander Motin } 3673e088dd4cSAlexander Motin 3674e088dd4cSAlexander Motin /* 3675d2ca21a9SJulian Elischer * Official timeout routines for Netgraph nodes. 3676d2ca21a9SJulian Elischer */ 3677d2ca21a9SJulian Elischer static void 36781fbb36ffSGleb Smirnoff ng_callout_trampoline(void *arg) 3679d2ca21a9SJulian Elischer { 3680d2ca21a9SJulian Elischer item_p item = arg; 3681d2ca21a9SJulian Elischer 3682bc29160dSMarko Zec CURVNET_SET(NGI_NODE(item)->nd_vnet); 3683d2ca21a9SJulian Elischer ng_snd_item(item, 0); 3684bc29160dSMarko Zec CURVNET_RESTORE(); 3685d2ca21a9SJulian Elischer } 3686d2ca21a9SJulian Elischer 3687d2ca21a9SJulian Elischer 368830bef41bSGleb Smirnoff int 3689f9d9e1b4SGleb Smirnoff ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, 3690d2ca21a9SJulian Elischer ng_item_fn *fn, void * arg1, int arg2) 3691d2ca21a9SJulian Elischer { 36921bf8e0faSGleb Smirnoff item_p item, oitem; 3693d2ca21a9SJulian Elischer 36946aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, NG_NOFLAGS)) == NULL) 369530bef41bSGleb Smirnoff return (ENOMEM); 369630bef41bSGleb Smirnoff 36976aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3698d2ca21a9SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 3699d2ca21a9SJulian Elischer NGI_SET_NODE(item, node); 3700d2ca21a9SJulian Elischer if (hook) { 3701d2ca21a9SJulian Elischer NG_HOOK_REF(hook); 3702d2ca21a9SJulian Elischer NGI_SET_HOOK(item, hook); 3703d2ca21a9SJulian Elischer } 3704d2ca21a9SJulian Elischer NGI_FN(item) = fn; 3705d2ca21a9SJulian Elischer NGI_ARG1(item) = arg1; 3706d2ca21a9SJulian Elischer NGI_ARG2(item) = arg2; 37071bf8e0faSGleb Smirnoff oitem = c->c_arg; 37081bf8e0faSGleb Smirnoff if (callout_reset(c, ticks, &ng_callout_trampoline, item) == 1 && 37091bf8e0faSGleb Smirnoff oitem != NULL) 37101bf8e0faSGleb Smirnoff NG_FREE_ITEM(oitem); 371130bef41bSGleb Smirnoff return (0); 3712d2ca21a9SJulian Elischer } 3713d2ca21a9SJulian Elischer 3714d2ca21a9SJulian Elischer /* A special modified version of untimeout() */ 3715d2ca21a9SJulian Elischer int 3716f9d9e1b4SGleb Smirnoff ng_uncallout(struct callout *c, node_p node) 3717d2ca21a9SJulian Elischer { 3718d2ca21a9SJulian Elischer item_p item; 371930bef41bSGleb Smirnoff int rval; 3720d2ca21a9SJulian Elischer 372103b25f5dSGleb Smirnoff KASSERT(c != NULL, ("ng_uncallout: NULL callout")); 372203b25f5dSGleb Smirnoff KASSERT(node != NULL, ("ng_uncallout: NULL node")); 372303b25f5dSGleb Smirnoff 37243eadb26dSGleb Smirnoff rval = callout_stop(c); 372530bef41bSGleb Smirnoff item = c->c_arg; 372630bef41bSGleb Smirnoff /* Do an extra check */ 37271fbb36ffSGleb Smirnoff if ((rval > 0) && (c->c_func == &ng_callout_trampoline) && 372830bef41bSGleb Smirnoff (NGI_NODE(item) == node)) { 3729d2ca21a9SJulian Elischer /* 3730d2ca21a9SJulian Elischer * We successfully removed it from the queue before it ran 3731d2ca21a9SJulian Elischer * So now we need to unreference everything that was 3732d2ca21a9SJulian Elischer * given extra references. (NG_FREE_ITEM does this). 3733d2ca21a9SJulian Elischer */ 3734d2ca21a9SJulian Elischer NG_FREE_ITEM(item); 3735d2ca21a9SJulian Elischer } 37361bf8e0faSGleb Smirnoff c->c_arg = NULL; 373730bef41bSGleb Smirnoff 373830bef41bSGleb Smirnoff return (rval); 3739d2ca21a9SJulian Elischer } 3740d2ca21a9SJulian Elischer 3741d2ca21a9SJulian Elischer /* 3742069154d5SJulian Elischer * Set the address, if none given, give the node here. 37434cf49a43SJulian Elischer */ 3744069154d5SJulian Elischer void 3745069154d5SJulian Elischer ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr) 37464cf49a43SJulian Elischer { 3747069154d5SJulian Elischer if (retaddr) { 3748069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; 3749069154d5SJulian Elischer } else { 3750069154d5SJulian Elischer /* 3751069154d5SJulian Elischer * The old return address should be ok. 3752069154d5SJulian Elischer * If there isn't one, use the address here. 3753069154d5SJulian Elischer */ 3754069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3755069154d5SJulian Elischer } 3756069154d5SJulian Elischer } 3757069154d5SJulian Elischer 3758069154d5SJulian Elischer #define TESTING 3759069154d5SJulian Elischer #ifdef TESTING 3760069154d5SJulian Elischer /* just test all the macros */ 3761069154d5SJulian Elischer void 3762069154d5SJulian Elischer ng_macro_test(item_p item); 3763069154d5SJulian Elischer void 3764069154d5SJulian Elischer ng_macro_test(item_p item) 3765069154d5SJulian Elischer { 3766069154d5SJulian Elischer node_p node = NULL; 3767069154d5SJulian Elischer hook_p hook = NULL; 37684cf49a43SJulian Elischer struct mbuf *m; 37694cf49a43SJulian Elischer struct ng_mesg *msg; 3770069154d5SJulian Elischer ng_ID_t retaddr; 3771069154d5SJulian Elischer int error; 37724cf49a43SJulian Elischer 3773069154d5SJulian Elischer NGI_GET_M(item, m); 3774069154d5SJulian Elischer NGI_GET_MSG(item, msg); 3775069154d5SJulian Elischer retaddr = NGI_RETADDR(item); 37768ed370fdSJulian Elischer NG_SEND_DATA(error, hook, m, NULL); 3777069154d5SJulian Elischer NG_SEND_DATA_ONLY(error, hook, m); 3778069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, hook, m); 377930400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, hook); 3780069154d5SJulian Elischer NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr); 3781069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr); 3782069154d5SJulian Elischer NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr); 3783069154d5SJulian Elischer NG_FWD_MSG_HOOK(error, node, item, hook, retaddr); 37844cf49a43SJulian Elischer } 3785069154d5SJulian Elischer #endif /* TESTING */ 37864cf49a43SJulian Elischer 3787