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> 64603724d3SBjoern A. Zeeb #include <sys/vimage.h> 65f2fbb838SAlexander Motin #include <sys/unistd.h> 66f2fbb838SAlexander Motin #include <sys/kthread.h> 67f2fbb838SAlexander Motin #include <sys/smp.h> 68394cb30aSAlexander Motin #include <machine/cpu.h> 694cf49a43SJulian Elischer 704cf49a43SJulian Elischer #include <net/netisr.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 78385195c0SMarko Zec #ifndef VIMAGE 79385195c0SMarko Zec #ifndef VIMAGE_GLOBALS 80385195c0SMarko Zec struct vnet_netgraph vnet_netgraph_0; 81385195c0SMarko Zec #endif 82385195c0SMarko Zec #endif 83385195c0SMarko Zec 84ac5dd141SGleb Smirnoff /* Mutex to protect topology events. */ 85ac5dd141SGleb Smirnoff static struct mtx ng_topo_mtx; 86ac5dd141SGleb Smirnoff 8730400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 88cfea3f85SAlexander Motin static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */ 891489164fSGleb Smirnoff static struct mtx ngq_mtx; /* protects the queue item list */ 9030400f03SJulian Elischer 9130400f03SJulian Elischer static SLIST_HEAD(, ng_node) ng_allnodes; 9230400f03SJulian Elischer static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */ 9330400f03SJulian Elischer static SLIST_HEAD(, ng_hook) ng_allhooks; 9430400f03SJulian Elischer static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */ 9530400f03SJulian Elischer 9630400f03SJulian Elischer static void ng_dumpitems(void); 9730400f03SJulian Elischer static void ng_dumpnodes(void); 9830400f03SJulian Elischer static void ng_dumphooks(void); 9930400f03SJulian Elischer 10030400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 101954c4772SJulian Elischer /* 102954c4772SJulian Elischer * DEAD versions of the structures. 103954c4772SJulian Elischer * In order to avoid races, it is sometimes neccesary to point 104954c4772SJulian Elischer * at SOMETHING even though theoretically, the current entity is 105954c4772SJulian Elischer * INVALID. Use these to avoid these races. 106954c4772SJulian Elischer */ 107954c4772SJulian Elischer struct ng_type ng_deadtype = { 108954c4772SJulian Elischer NG_ABI_VERSION, 109954c4772SJulian Elischer "dead", 110954c4772SJulian Elischer NULL, /* modevent */ 111954c4772SJulian Elischer NULL, /* constructor */ 112954c4772SJulian Elischer NULL, /* rcvmsg */ 113954c4772SJulian Elischer NULL, /* shutdown */ 114954c4772SJulian Elischer NULL, /* newhook */ 115954c4772SJulian Elischer NULL, /* findhook */ 116954c4772SJulian Elischer NULL, /* connect */ 117954c4772SJulian Elischer NULL, /* rcvdata */ 118954c4772SJulian Elischer NULL, /* disconnect */ 119954c4772SJulian Elischer NULL, /* cmdlist */ 120954c4772SJulian Elischer }; 12130400f03SJulian Elischer 122954c4772SJulian Elischer struct ng_node ng_deadnode = { 123954c4772SJulian Elischer "dead", 124954c4772SJulian Elischer &ng_deadtype, 125be4252b3SJulian Elischer NGF_INVALID, 126954c4772SJulian Elischer 0, /* numhooks */ 127954c4772SJulian Elischer NULL, /* private */ 128954c4772SJulian Elischer 0, /* ID */ 129954c4772SJulian Elischer LIST_HEAD_INITIALIZER(ng_deadnode.hooks), 130954c4772SJulian Elischer {}, /* all_nodes list entry */ 131954c4772SJulian Elischer {}, /* id hashtable list entry */ 132954c4772SJulian Elischer { 0, 1339852972bSAlexander Motin 0, 134954c4772SJulian Elischer {}, /* should never use! (should hang) */ 1359852972bSAlexander Motin {}, /* workqueue entry */ 1369852972bSAlexander Motin STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue), 137954c4772SJulian Elischer }, 1389852972bSAlexander Motin 1, /* refs */ 139954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 140954c4772SJulian Elischer ND_MAGIC, 141954c4772SJulian Elischer __FILE__, 142954c4772SJulian Elischer __LINE__, 143954c4772SJulian Elischer {NULL} 144954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 145954c4772SJulian Elischer }; 146954c4772SJulian Elischer 147954c4772SJulian Elischer struct ng_hook ng_deadhook = { 148954c4772SJulian Elischer "dead", 149954c4772SJulian Elischer NULL, /* private */ 150954c4772SJulian Elischer HK_INVALID | HK_DEAD, 151e58d779dSGleb Smirnoff 0, /* undefined data link type */ 152954c4772SJulian Elischer &ng_deadhook, /* Peer is self */ 153954c4772SJulian Elischer &ng_deadnode, /* attached to deadnode */ 154954c4772SJulian Elischer {}, /* hooks list */ 155c4b5eea4SJulian Elischer NULL, /* override rcvmsg() */ 156c4b5eea4SJulian Elischer NULL, /* override rcvdata() */ 1579852972bSAlexander Motin 1, /* refs always >= 1 */ 158954c4772SJulian Elischer #ifdef NETGRAPH_DEBUG 159954c4772SJulian Elischer HK_MAGIC, 160954c4772SJulian Elischer __FILE__, 161954c4772SJulian Elischer __LINE__, 162954c4772SJulian Elischer {NULL} 163954c4772SJulian Elischer #endif /* NETGRAPH_DEBUG */ 164954c4772SJulian Elischer }; 165954c4772SJulian Elischer 166954c4772SJulian Elischer /* 167954c4772SJulian Elischer * END DEAD STRUCTURES 168954c4772SJulian Elischer */ 169069154d5SJulian Elischer /* List nodes with unallocated work */ 1709852972bSAlexander Motin static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist); 171b57a7965SJulian Elischer static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */ 1724cf49a43SJulian Elischer 1734cf49a43SJulian Elischer /* List of installed types */ 174069154d5SJulian Elischer static LIST_HEAD(, ng_type) ng_typelist; 175069154d5SJulian Elischer static struct mtx ng_typelist_mtx; 1764cf49a43SJulian Elischer 177069154d5SJulian Elischer /* Hash related definitions */ 1780f150d04SJulian Elischer /* XXX Don't need to initialise them because it's a LIST */ 179385195c0SMarko Zec #ifdef VIMAGE_GLOBALS 1800f150d04SJulian Elischer static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE]; 181385195c0SMarko Zec #endif 182069154d5SJulian Elischer static struct mtx ng_idhash_mtx; 1830f150d04SJulian Elischer /* Method to find a node.. used twice so do it here */ 1840f150d04SJulian Elischer #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE)) 1850f150d04SJulian Elischer #define NG_IDHASH_FIND(ID, node) \ 1860f150d04SJulian Elischer do { \ 18753f9c5e9SRobert Watson mtx_assert(&ng_idhash_mtx, MA_OWNED); \ 188603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \ 1890f150d04SJulian Elischer nd_idnodes) { \ 1900f150d04SJulian Elischer if (NG_NODE_IS_VALID(node) \ 1910f150d04SJulian Elischer && (NG_NODE_ID(node) == ID)) { \ 1920f150d04SJulian Elischer break; \ 1930f150d04SJulian Elischer } \ 1940f150d04SJulian Elischer } \ 1950f150d04SJulian Elischer } while (0) 196069154d5SJulian Elischer 197385195c0SMarko Zec #ifdef VIMAGE_GLOBALS 198cfea3f85SAlexander Motin static LIST_HEAD(, ng_node) ng_name_hash[NG_NAME_HASH_SIZE]; 199385195c0SMarko Zec #endif 200cfea3f85SAlexander Motin static struct mtx ng_namehash_mtx; 201cfea3f85SAlexander Motin #define NG_NAMEHASH(NAME, HASH) \ 202cfea3f85SAlexander Motin do { \ 203cfea3f85SAlexander Motin u_char h = 0; \ 204cfea3f85SAlexander Motin const u_char *c; \ 205cfea3f85SAlexander Motin for (c = (const u_char*)(NAME); *c; c++)\ 206cfea3f85SAlexander Motin h += *c; \ 207cfea3f85SAlexander Motin (HASH) = h % (NG_NAME_HASH_SIZE); \ 208cfea3f85SAlexander Motin } while (0) 209cfea3f85SAlexander Motin 210dc90cad9SJulian Elischer 2114cf49a43SJulian Elischer /* Internal functions */ 2124cf49a43SJulian Elischer static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 213069154d5SJulian Elischer static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); 214dc90cad9SJulian Elischer static ng_ID_t ng_decodeidname(const char *name); 2154cf49a43SJulian Elischer static int ngb_mod_event(module_t mod, int event, void *data); 216394cb30aSAlexander Motin static void ng_worklist_add(node_p node); 217f2fbb838SAlexander Motin static void ngthread(void *); 21827757487SGleb Smirnoff static int ng_apply_item(node_p node, item_p item, int rw); 2199852972bSAlexander Motin static void ng_flush_input_queue(node_p node); 220069154d5SJulian Elischer static node_p ng_ID2noderef(ng_ID_t ID); 221e088dd4cSAlexander Motin static int ng_con_nodes(item_p item, node_p node, const char *name, 222e088dd4cSAlexander Motin node_p node2, const char *name2); 223e088dd4cSAlexander Motin static int ng_con_part2(node_p node, item_p item, hook_p hook); 224e088dd4cSAlexander Motin static int ng_con_part3(node_p node, item_p item, hook_p hook); 2256b795970SJulian Elischer static int ng_mkpeer(node_p node, const char *name, 2266b795970SJulian Elischer const char *name2, char *type); 227069154d5SJulian Elischer 2284c9b5910SGleb Smirnoff /* Imported, these used to be externally visible, some may go back. */ 229069154d5SJulian Elischer void ng_destroy_hook(hook_p hook); 230069154d5SJulian Elischer node_p ng_name2noderef(node_p node, const char *name); 231069154d5SJulian Elischer int ng_path2noderef(node_p here, const char *path, 232069154d5SJulian Elischer node_p *dest, hook_p *lasthook); 233069154d5SJulian Elischer int ng_make_node(const char *type, node_p *nodepp); 234069154d5SJulian Elischer int ng_path_parse(char *addr, char **node, char **path, char **hook); 2351acb27c6SJulian Elischer void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3); 23630400f03SJulian Elischer void ng_unname(node_p node); 237069154d5SJulian Elischer 2384cf49a43SJulian Elischer 2394cf49a43SJulian Elischer /* Our own netgraph malloc type */ 2404cf49a43SJulian Elischer MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 241069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures"); 242069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures"); 243069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures"); 244069154d5SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); 245069154d5SJulian Elischer 246069154d5SJulian Elischer /* Should not be visible outside this file */ 24730400f03SJulian Elischer 24830400f03SJulian Elischer #define _NG_ALLOC_HOOK(hook) \ 2491ede983cSDag-Erling Smørgrav hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO) 25030400f03SJulian Elischer #define _NG_ALLOC_NODE(node) \ 2511ede983cSDag-Erling Smørgrav node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO) 25230400f03SJulian Elischer 2532c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK_INIT(n) \ 2544abab3d5SWojciech A. Koszek mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF) 2552c8dda8dSWojciech A. Koszek #define NG_QUEUE_LOCK(n) \ 2564abab3d5SWojciech A. Koszek mtx_lock(&(n)->q_mtx) 2572c8dda8dSWojciech A. Koszek #define NG_QUEUE_UNLOCK(n) \ 2584abab3d5SWojciech A. Koszek mtx_unlock(&(n)->q_mtx) 2592c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK_INIT() \ 2604abab3d5SWojciech A. Koszek mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF) 2612c8dda8dSWojciech A. Koszek #define NG_WORKLIST_LOCK() \ 2624abab3d5SWojciech A. Koszek mtx_lock(&ng_worklist_mtx) 2632c8dda8dSWojciech A. Koszek #define NG_WORKLIST_UNLOCK() \ 2644abab3d5SWojciech A. Koszek mtx_unlock(&ng_worklist_mtx) 265f2fbb838SAlexander Motin #define NG_WORKLIST_SLEEP() \ 266f2fbb838SAlexander Motin mtx_sleep(&ng_worklist, &ng_worklist_mtx, PI_NET, "sleep", 0) 267f2fbb838SAlexander Motin #define NG_WORKLIST_WAKEUP() \ 268f2fbb838SAlexander Motin wakeup_one(&ng_worklist) 2692c8dda8dSWojciech A. Koszek 27030400f03SJulian Elischer #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 27130400f03SJulian Elischer /* 27230400f03SJulian Elischer * In debug mode: 27330400f03SJulian Elischer * In an attempt to help track reference count screwups 27430400f03SJulian Elischer * we do not free objects back to the malloc system, but keep them 27530400f03SJulian Elischer * in a local cache where we can examine them and keep information safely 27630400f03SJulian Elischer * after they have been freed. 27730400f03SJulian Elischer * We use this scheme for nodes and hooks, and to some extent for items. 27830400f03SJulian Elischer */ 27930400f03SJulian Elischer static __inline hook_p 28030400f03SJulian Elischer ng_alloc_hook(void) 28130400f03SJulian Elischer { 28230400f03SJulian Elischer hook_p hook; 28330400f03SJulian Elischer SLIST_ENTRY(ng_hook) temp; 2849ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 28530400f03SJulian Elischer hook = LIST_FIRST(&ng_freehooks); 28630400f03SJulian Elischer if (hook) { 28730400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 28830400f03SJulian Elischer bcopy(&hook->hk_all, &temp, sizeof(temp)); 28930400f03SJulian Elischer bzero(hook, sizeof(struct ng_hook)); 29030400f03SJulian Elischer bcopy(&temp, &hook->hk_all, sizeof(temp)); 2919ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 29230400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 29330400f03SJulian Elischer } else { 2949ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 29530400f03SJulian Elischer _NG_ALLOC_HOOK(hook); 29630400f03SJulian Elischer if (hook) { 29730400f03SJulian Elischer hook->hk_magic = HK_MAGIC; 2989ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 29930400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all); 3009ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 30130400f03SJulian Elischer } 30230400f03SJulian Elischer } 30330400f03SJulian Elischer return (hook); 30430400f03SJulian Elischer } 30530400f03SJulian Elischer 30630400f03SJulian Elischer static __inline node_p 30730400f03SJulian Elischer ng_alloc_node(void) 30830400f03SJulian Elischer { 30930400f03SJulian Elischer node_p node; 31030400f03SJulian Elischer SLIST_ENTRY(ng_node) temp; 3119ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 31230400f03SJulian Elischer node = LIST_FIRST(&ng_freenodes); 31330400f03SJulian Elischer if (node) { 31430400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 31530400f03SJulian Elischer bcopy(&node->nd_all, &temp, sizeof(temp)); 31630400f03SJulian Elischer bzero(node, sizeof(struct ng_node)); 31730400f03SJulian Elischer bcopy(&temp, &node->nd_all, sizeof(temp)); 3189ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 31930400f03SJulian Elischer node->nd_magic = ND_MAGIC; 32030400f03SJulian Elischer } else { 3219ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 32230400f03SJulian Elischer _NG_ALLOC_NODE(node); 32330400f03SJulian Elischer if (node) { 32430400f03SJulian Elischer node->nd_magic = ND_MAGIC; 3259ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); 32630400f03SJulian Elischer SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all); 3279ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); 32830400f03SJulian Elischer } 32930400f03SJulian Elischer } 33030400f03SJulian Elischer return (node); 33130400f03SJulian Elischer } 33230400f03SJulian Elischer 33330400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0) 33430400f03SJulian Elischer #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0) 33530400f03SJulian Elischer 33630400f03SJulian Elischer 33730400f03SJulian Elischer #define NG_FREE_HOOK(hook) \ 33830400f03SJulian Elischer do { \ 3399ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 34030400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \ 34130400f03SJulian Elischer hook->hk_magic = 0; \ 3429ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 34330400f03SJulian Elischer } while (0) 34430400f03SJulian Elischer 34530400f03SJulian Elischer #define NG_FREE_NODE(node) \ 34630400f03SJulian Elischer do { \ 3479ed346baSBosko Milekic mtx_lock(&ng_nodelist_mtx); \ 34830400f03SJulian Elischer LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \ 34930400f03SJulian Elischer node->nd_magic = 0; \ 3509ed346baSBosko Milekic mtx_unlock(&ng_nodelist_mtx); \ 35130400f03SJulian Elischer } while (0) 35230400f03SJulian Elischer 35330400f03SJulian Elischer #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 35430400f03SJulian Elischer 35530400f03SJulian Elischer #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook) 35630400f03SJulian Elischer #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node) 35730400f03SJulian Elischer 3581ede983cSDag-Erling Smørgrav #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0) 3591ede983cSDag-Erling Smørgrav #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0) 36030400f03SJulian Elischer 36130400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 36230400f03SJulian Elischer 363f33ca0c9SMarcel Moolenaar /* Set this to kdb_enter("X") to catch all errors as they occur */ 3644cf49a43SJulian Elischer #ifndef TRAP_ERROR 3656b795970SJulian Elischer #define TRAP_ERROR() 3664cf49a43SJulian Elischer #endif 3674cf49a43SJulian Elischer 368385195c0SMarko Zec #ifdef VIMAGE_GLOBALS 369385195c0SMarko Zec static ng_ID_t nextID; 370385195c0SMarko Zec #endif 371dc90cad9SJulian Elischer 372b2da83c2SArchie Cobbs #ifdef INVARIANTS 373b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) do { \ 374b2da83c2SArchie Cobbs struct mbuf *n; \ 375b2da83c2SArchie Cobbs int total; \ 376b2da83c2SArchie Cobbs \ 377fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); \ 378b32cfb32SGleb Smirnoff for (total = 0, n = (m); n != NULL; n = n->m_next) { \ 379b2da83c2SArchie Cobbs total += n->m_len; \ 380b32cfb32SGleb Smirnoff if (n->m_nextpkt != NULL) \ 381b32cfb32SGleb Smirnoff panic("%s: m_nextpkt", __func__); \ 382b32cfb32SGleb Smirnoff } \ 383ba5b359aSGleb Smirnoff \ 384b2da83c2SArchie Cobbs if ((m)->m_pkthdr.len != total) { \ 385b2da83c2SArchie Cobbs panic("%s: %d != %d", \ 3866e551fb6SDavid E. O'Brien __func__, (m)->m_pkthdr.len, total); \ 387b2da83c2SArchie Cobbs } \ 388b2da83c2SArchie Cobbs } while (0) 389b2da83c2SArchie Cobbs #else 390b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) 391b2da83c2SArchie Cobbs #endif 392b2da83c2SArchie Cobbs 393e088dd4cSAlexander Motin #define ERROUT(x) do { error = (x); goto done; } while (0) 394dc90cad9SJulian Elischer 3954cf49a43SJulian Elischer /************************************************************************ 396f8307e12SArchie Cobbs Parse type definitions for generic messages 397f8307e12SArchie Cobbs ************************************************************************/ 398f8307e12SArchie Cobbs 399f8307e12SArchie Cobbs /* Handy structure parse type defining macro */ 400f8307e12SArchie Cobbs #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 401f0184ff8SArchie Cobbs static const struct ng_parse_struct_field \ 402f0184ff8SArchie Cobbs ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 403f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 404f8307e12SArchie Cobbs &ng_parse_struct_type, \ 405f0184ff8SArchie Cobbs &ng_ ## lo ## _type_fields \ 406f8307e12SArchie Cobbs } 407f8307e12SArchie Cobbs 408f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 409f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 410f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 411f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 412f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 413f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 414f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 415f8307e12SArchie Cobbs 416f8307e12SArchie Cobbs /* Get length of an array when the length is stored as a 32 bit 417d7d97eb0SJeroen Ruigrok van der Werven value immediately preceding the array -- as with struct namelist 418f8307e12SArchie Cobbs and struct typelist. */ 419f8307e12SArchie Cobbs static int 420f8307e12SArchie Cobbs ng_generic_list_getLength(const struct ng_parse_type *type, 421f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 422f8307e12SArchie Cobbs { 423f8307e12SArchie Cobbs return *((const u_int32_t *)(buf - 4)); 424f8307e12SArchie Cobbs } 425f8307e12SArchie Cobbs 426f8307e12SArchie Cobbs /* Get length of the array of struct linkinfo inside a struct hooklist */ 427f8307e12SArchie Cobbs static int 428f8307e12SArchie Cobbs ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 429f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 430f8307e12SArchie Cobbs { 431f8307e12SArchie Cobbs const struct hooklist *hl = (const struct hooklist *)start; 432f8307e12SArchie Cobbs 433f8307e12SArchie Cobbs return hl->nodeinfo.hooks; 434f8307e12SArchie Cobbs } 435f8307e12SArchie Cobbs 436f8307e12SArchie Cobbs /* Array type for a variable length array of struct namelist */ 437f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 438f8307e12SArchie Cobbs &ng_generic_nodeinfo_type, 439f8307e12SArchie Cobbs &ng_generic_list_getLength 440f8307e12SArchie Cobbs }; 441f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 442f8307e12SArchie Cobbs &ng_parse_array_type, 443f8307e12SArchie Cobbs &ng_nodeinfoarray_type_info 444f8307e12SArchie Cobbs }; 445f8307e12SArchie Cobbs 446f8307e12SArchie Cobbs /* Array type for a variable length array of struct typelist */ 447f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 448f8307e12SArchie Cobbs &ng_generic_typeinfo_type, 449f8307e12SArchie Cobbs &ng_generic_list_getLength 450f8307e12SArchie Cobbs }; 451f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_typeinfoarray_type = { 452f8307e12SArchie Cobbs &ng_parse_array_type, 453f8307e12SArchie Cobbs &ng_typeinfoarray_type_info 454f8307e12SArchie Cobbs }; 455f8307e12SArchie Cobbs 456f8307e12SArchie Cobbs /* Array type for array of struct linkinfo in struct hooklist */ 457f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 458f8307e12SArchie Cobbs &ng_generic_linkinfo_type, 459f8307e12SArchie Cobbs &ng_generic_linkinfo_getLength 460f8307e12SArchie Cobbs }; 461f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_linkinfo_array_type = { 462f8307e12SArchie Cobbs &ng_parse_array_type, 463f8307e12SArchie Cobbs &ng_generic_linkinfo_array_type_info 464f8307e12SArchie Cobbs }; 465f8307e12SArchie Cobbs 466f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 467f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 468f8307e12SArchie Cobbs (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 469f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 470f8307e12SArchie Cobbs (&ng_generic_nodeinfoarray_type)); 471f8307e12SArchie Cobbs 472f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 473f8307e12SArchie Cobbs static const struct ng_cmdlist ng_generic_cmds[] = { 474f8307e12SArchie Cobbs { 475f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 476f8307e12SArchie Cobbs NGM_SHUTDOWN, 477f8307e12SArchie Cobbs "shutdown", 478f8307e12SArchie Cobbs NULL, 479f8307e12SArchie Cobbs NULL 480f8307e12SArchie Cobbs }, 481f8307e12SArchie Cobbs { 482f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 483f8307e12SArchie Cobbs NGM_MKPEER, 484f8307e12SArchie Cobbs "mkpeer", 485f8307e12SArchie Cobbs &ng_generic_mkpeer_type, 486f8307e12SArchie Cobbs NULL 487f8307e12SArchie Cobbs }, 488f8307e12SArchie Cobbs { 489f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 490f8307e12SArchie Cobbs NGM_CONNECT, 491f8307e12SArchie Cobbs "connect", 492f8307e12SArchie Cobbs &ng_generic_connect_type, 493f8307e12SArchie Cobbs NULL 494f8307e12SArchie Cobbs }, 495f8307e12SArchie Cobbs { 496f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 497f8307e12SArchie Cobbs NGM_NAME, 498f8307e12SArchie Cobbs "name", 499f8307e12SArchie Cobbs &ng_generic_name_type, 500f8307e12SArchie Cobbs NULL 501f8307e12SArchie Cobbs }, 502f8307e12SArchie Cobbs { 503f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 504f8307e12SArchie Cobbs NGM_RMHOOK, 505f8307e12SArchie Cobbs "rmhook", 506f8307e12SArchie Cobbs &ng_generic_rmhook_type, 507f8307e12SArchie Cobbs NULL 508f8307e12SArchie Cobbs }, 509f8307e12SArchie Cobbs { 510f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 511f8307e12SArchie Cobbs NGM_NODEINFO, 512f8307e12SArchie Cobbs "nodeinfo", 513f8307e12SArchie Cobbs NULL, 514f8307e12SArchie Cobbs &ng_generic_nodeinfo_type 515f8307e12SArchie Cobbs }, 516f8307e12SArchie Cobbs { 517f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 518f8307e12SArchie Cobbs NGM_LISTHOOKS, 519f8307e12SArchie Cobbs "listhooks", 520f8307e12SArchie Cobbs NULL, 521f8307e12SArchie Cobbs &ng_generic_hooklist_type 522f8307e12SArchie Cobbs }, 523f8307e12SArchie Cobbs { 524f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 525f8307e12SArchie Cobbs NGM_LISTNAMES, 526f8307e12SArchie Cobbs "listnames", 527f8307e12SArchie Cobbs NULL, 528f8307e12SArchie Cobbs &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 529f8307e12SArchie Cobbs }, 530f8307e12SArchie Cobbs { 531f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 532f8307e12SArchie Cobbs NGM_LISTNODES, 533f8307e12SArchie Cobbs "listnodes", 534f8307e12SArchie Cobbs NULL, 535f8307e12SArchie Cobbs &ng_generic_listnodes_type 536f8307e12SArchie Cobbs }, 537f8307e12SArchie Cobbs { 538f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 539f8307e12SArchie Cobbs NGM_LISTTYPES, 540f8307e12SArchie Cobbs "listtypes", 541f8307e12SArchie Cobbs NULL, 542f8307e12SArchie Cobbs &ng_generic_typeinfo_type 543f8307e12SArchie Cobbs }, 544f8307e12SArchie Cobbs { 545f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 5467095e097SPoul-Henning Kamp NGM_TEXT_CONFIG, 5477095e097SPoul-Henning Kamp "textconfig", 5487095e097SPoul-Henning Kamp NULL, 5497095e097SPoul-Henning Kamp &ng_parse_string_type 5507095e097SPoul-Henning Kamp }, 5517095e097SPoul-Henning Kamp { 5527095e097SPoul-Henning Kamp NGM_GENERIC_COOKIE, 553f8307e12SArchie Cobbs NGM_TEXT_STATUS, 554f8307e12SArchie Cobbs "textstatus", 555f8307e12SArchie Cobbs NULL, 556f8307e12SArchie Cobbs &ng_parse_string_type 557f8307e12SArchie Cobbs }, 558f8307e12SArchie Cobbs { 559f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 560f8307e12SArchie Cobbs NGM_ASCII2BINARY, 561f8307e12SArchie Cobbs "ascii2binary", 562f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 563f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 564f8307e12SArchie Cobbs }, 565f8307e12SArchie Cobbs { 566f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 567f8307e12SArchie Cobbs NGM_BINARY2ASCII, 568f8307e12SArchie Cobbs "binary2ascii", 569f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 570f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 571f8307e12SArchie Cobbs }, 572f8307e12SArchie Cobbs { 0 } 573f8307e12SArchie Cobbs }; 574f8307e12SArchie Cobbs 575f8307e12SArchie Cobbs /************************************************************************ 5764cf49a43SJulian Elischer Node routines 5774cf49a43SJulian Elischer ************************************************************************/ 5784cf49a43SJulian Elischer 5794cf49a43SJulian Elischer /* 5804cf49a43SJulian Elischer * Instantiate a node of the requested type 5814cf49a43SJulian Elischer */ 5824cf49a43SJulian Elischer int 5834cf49a43SJulian Elischer ng_make_node(const char *typename, node_p *nodepp) 5844cf49a43SJulian Elischer { 5854cf49a43SJulian Elischer struct ng_type *type; 586069154d5SJulian Elischer int error; 5874cf49a43SJulian Elischer 5884cf49a43SJulian Elischer /* Check that the type makes sense */ 5894cf49a43SJulian Elischer if (typename == NULL) { 5906b795970SJulian Elischer TRAP_ERROR(); 5914cf49a43SJulian Elischer return (EINVAL); 5924cf49a43SJulian Elischer } 5934cf49a43SJulian Elischer 5947610f574SGleb Smirnoff /* Locate the node type. If we fail we return. Do not try to load 5957610f574SGleb Smirnoff * module. 5967610f574SGleb Smirnoff */ 5974cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) 5984cf49a43SJulian Elischer return (ENXIO); 5994cf49a43SJulian Elischer 600069154d5SJulian Elischer /* 601069154d5SJulian Elischer * If we have a constructor, then make the node and 602069154d5SJulian Elischer * call the constructor to do type specific initialisation. 603069154d5SJulian Elischer */ 604069154d5SJulian Elischer if (type->constructor != NULL) { 605069154d5SJulian Elischer if ((error = ng_make_node_common(type, nodepp)) == 0) { 606069154d5SJulian Elischer if ((error = ((*type->constructor)(*nodepp)) != 0)) { 60730400f03SJulian Elischer NG_NODE_UNREF(*nodepp); 608069154d5SJulian Elischer } 609069154d5SJulian Elischer } 610069154d5SJulian Elischer } else { 611069154d5SJulian Elischer /* 612069154d5SJulian Elischer * Node has no constructor. We cannot ask for one 61364efc707SRobert Watson * to be made. It must be brought into existence by 614954c4772SJulian Elischer * some external agency. The external agency should 615069154d5SJulian Elischer * call ng_make_node_common() directly to get the 616069154d5SJulian Elischer * netgraph part initialised. 617069154d5SJulian Elischer */ 6186b795970SJulian Elischer TRAP_ERROR(); 619069154d5SJulian Elischer error = EINVAL; 620069154d5SJulian Elischer } 621069154d5SJulian Elischer return (error); 6224cf49a43SJulian Elischer } 6234cf49a43SJulian Elischer 6244cf49a43SJulian Elischer /* 625069154d5SJulian Elischer * Generic node creation. Called by node initialisation for externally 626069154d5SJulian Elischer * instantiated nodes (e.g. hardware, sockets, etc ). 6274cf49a43SJulian Elischer * The returned node has a reference count of 1. 6284cf49a43SJulian Elischer */ 6294cf49a43SJulian Elischer int 6304cf49a43SJulian Elischer ng_make_node_common(struct ng_type *type, node_p *nodepp) 6314cf49a43SJulian Elischer { 6328b615593SMarko Zec INIT_VNET_NETGRAPH(curvnet); 6334cf49a43SJulian Elischer node_p node; 6344cf49a43SJulian Elischer 6354cf49a43SJulian Elischer /* Require the node type to have been already installed */ 6364cf49a43SJulian Elischer if (ng_findtype(type->name) == NULL) { 6376b795970SJulian Elischer TRAP_ERROR(); 6384cf49a43SJulian Elischer return (EINVAL); 6394cf49a43SJulian Elischer } 6404cf49a43SJulian Elischer 6414cf49a43SJulian Elischer /* Make a node and try attach it to the type */ 64230400f03SJulian Elischer NG_ALLOC_NODE(node); 6434cf49a43SJulian Elischer if (node == NULL) { 6446b795970SJulian Elischer TRAP_ERROR(); 6454cf49a43SJulian Elischer return (ENOMEM); 6464cf49a43SJulian Elischer } 64730400f03SJulian Elischer node->nd_type = type; 64830400f03SJulian Elischer NG_NODE_REF(node); /* note reference */ 6494cf49a43SJulian Elischer type->refs++; 6504cf49a43SJulian Elischer 6512c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK_INIT(&node->nd_input_queue); 6529852972bSAlexander Motin STAILQ_INIT(&node->nd_input_queue.queue); 65330400f03SJulian Elischer node->nd_input_queue.q_flags = 0; 6544cf49a43SJulian Elischer 6554cf49a43SJulian Elischer /* Initialize hook list for new node */ 65630400f03SJulian Elischer LIST_INIT(&node->nd_hooks); 6574cf49a43SJulian Elischer 658cfea3f85SAlexander Motin /* Link us into the name hash. */ 659cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 660603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes); 661cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 662069154d5SJulian Elischer 663dc90cad9SJulian Elischer /* get an ID and put us in the hash chain */ 6649ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 66530400f03SJulian Elischer for (;;) { /* wrap protection, even if silly */ 666069154d5SJulian Elischer node_p node2 = NULL; 667ac957cd2SJulian Elischer node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */ 6680f150d04SJulian Elischer 66930400f03SJulian Elischer /* Is there a problem with the new number? */ 6700f150d04SJulian Elischer NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */ 6710f150d04SJulian Elischer if ((node->nd_ID != 0) && (node2 == NULL)) { 67230400f03SJulian Elischer break; 673069154d5SJulian Elischer } 67430400f03SJulian Elischer } 675603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], 67630400f03SJulian Elischer node, nd_idnodes); 6779ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 678dc90cad9SJulian Elischer 6794cf49a43SJulian Elischer /* Done */ 6804cf49a43SJulian Elischer *nodepp = node; 6814cf49a43SJulian Elischer return (0); 6824cf49a43SJulian Elischer } 6834cf49a43SJulian Elischer 6844cf49a43SJulian Elischer /* 6854cf49a43SJulian Elischer * Forceably start the shutdown process on a node. Either call 68664efc707SRobert Watson * its shutdown method, or do the default shutdown if there is 6874cf49a43SJulian Elischer * no type-specific method. 6884cf49a43SJulian Elischer * 68964efc707SRobert Watson * We can only be called from a shutdown message, so we know we have 6903e4084c8SJulian Elischer * a writer lock, and therefore exclusive access. It also means 6913e4084c8SJulian Elischer * that we should not be on the work queue, but we check anyhow. 692069154d5SJulian Elischer * 693069154d5SJulian Elischer * Persistent node types must have a type-specific method which 69464efc707SRobert Watson * allocates a new node in which case, this one is irretrievably going away, 6953e4084c8SJulian Elischer * or cleans up anything it needs, and just makes the node valid again, 6963e4084c8SJulian Elischer * in which case we allow the node to survive. 6973e4084c8SJulian Elischer * 69864efc707SRobert Watson * XXX We need to think of how to tell a persistent node that we 6993e4084c8SJulian Elischer * REALLY need to go away because the hardware has gone or we 7003e4084c8SJulian Elischer * are rebooting.... etc. 7014cf49a43SJulian Elischer */ 7024cf49a43SJulian Elischer void 7031acb27c6SJulian Elischer ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3) 7044cf49a43SJulian Elischer { 7053e4084c8SJulian Elischer hook_p hook; 7063e4084c8SJulian Elischer 7074cf49a43SJulian Elischer /* Check if it's already shutting down */ 708be4252b3SJulian Elischer if ((node->nd_flags & NGF_CLOSING) != 0) 7094cf49a43SJulian Elischer return; 7104cf49a43SJulian Elischer 7111acb27c6SJulian Elischer if (node == &ng_deadnode) { 7121acb27c6SJulian Elischer printf ("shutdown called on deadnode\n"); 7131acb27c6SJulian Elischer return; 7141acb27c6SJulian Elischer } 7151acb27c6SJulian Elischer 7164cf49a43SJulian Elischer /* Add an extra reference so it doesn't go away during this */ 71730400f03SJulian Elischer NG_NODE_REF(node); 7184cf49a43SJulian Elischer 71930400f03SJulian Elischer /* 72030400f03SJulian Elischer * Mark it invalid so any newcomers know not to try use it 72130400f03SJulian Elischer * Also add our own mark so we can't recurse 722be4252b3SJulian Elischer * note that NGF_INVALID does not do this as it's also set during 72330400f03SJulian Elischer * creation 72430400f03SJulian Elischer */ 725be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID|NGF_CLOSING; 7264cf49a43SJulian Elischer 727991fc65aSJulian Elischer /* If node has its pre-shutdown method, then call it first*/ 728991fc65aSJulian Elischer if (node->nd_type && node->nd_type->close) 729991fc65aSJulian Elischer (*node->nd_type->close)(node); 730991fc65aSJulian Elischer 7313e4084c8SJulian Elischer /* Notify all remaining connected nodes to disconnect */ 7323e4084c8SJulian Elischer while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL) 7333e4084c8SJulian Elischer ng_destroy_hook(hook); 73430400f03SJulian Elischer 735069154d5SJulian Elischer /* 736069154d5SJulian Elischer * Drain the input queue forceably. 73730400f03SJulian Elischer * it has no hooks so what's it going to do, bleed on someone? 73830400f03SJulian Elischer * Theoretically we came here from a queue entry that was added 73930400f03SJulian Elischer * Just before the queue was closed, so it should be empty anyway. 740b57a7965SJulian Elischer * Also removes us from worklist if needed. 741069154d5SJulian Elischer */ 7429852972bSAlexander Motin ng_flush_input_queue(node); 743069154d5SJulian Elischer 744069154d5SJulian Elischer /* Ask the type if it has anything to do in this case */ 74530400f03SJulian Elischer if (node->nd_type && node->nd_type->shutdown) { 74630400f03SJulian Elischer (*node->nd_type->shutdown)(node); 74730400f03SJulian Elischer if (NG_NODE_IS_VALID(node)) { 74830400f03SJulian Elischer /* 74930400f03SJulian Elischer * Well, blow me down if the node code hasn't declared 75030400f03SJulian Elischer * that it doesn't want to die. 75130400f03SJulian Elischer * Presumably it is a persistant node. 7521acb27c6SJulian Elischer * If we REALLY want it to go away, 7531acb27c6SJulian Elischer * e.g. hardware going away, 754be4252b3SJulian Elischer * Our caller should set NGF_REALLY_DIE in nd_flags. 75530400f03SJulian Elischer */ 756be4252b3SJulian Elischer node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING); 7571acb27c6SJulian Elischer NG_NODE_UNREF(node); /* Assume they still have theirs */ 75830400f03SJulian Elischer return; 7594cf49a43SJulian Elischer } 7601acb27c6SJulian Elischer } else { /* do the default thing */ 7611acb27c6SJulian Elischer NG_NODE_UNREF(node); 7621acb27c6SJulian Elischer } 7634cf49a43SJulian Elischer 76430400f03SJulian Elischer ng_unname(node); /* basically a NOP these days */ 76530400f03SJulian Elischer 76630400f03SJulian Elischer /* 76730400f03SJulian Elischer * Remove extra reference, possibly the last 76830400f03SJulian Elischer * Possible other holders of references may include 76930400f03SJulian Elischer * timeout callouts, but theoretically the node's supposed to 77030400f03SJulian Elischer * have cancelled them. Possibly hardware dependencies may 77130400f03SJulian Elischer * force a driver to 'linger' with a reference. 77230400f03SJulian Elischer */ 77330400f03SJulian Elischer NG_NODE_UNREF(node); 7744cf49a43SJulian Elischer } 7754cf49a43SJulian Elischer 7765951069aSJulian Elischer /* 7775951069aSJulian Elischer * Remove a reference to the node, possibly the last. 7785951069aSJulian Elischer * deadnode always acts as it it were the last. 7795951069aSJulian Elischer */ 7805951069aSJulian Elischer int 78130400f03SJulian Elischer ng_unref_node(node_p node) 7824cf49a43SJulian Elischer { 78330400f03SJulian Elischer int v; 7846b795970SJulian Elischer 7856b795970SJulian Elischer if (node == &ng_deadnode) { 7865951069aSJulian Elischer return (0); 7876b795970SJulian Elischer } 7886b795970SJulian Elischer 789018fe3d1SAlexander Motin v = atomic_fetchadd_int(&node->nd_refs, -1); 790e8a49db2SJulian Elischer 791018fe3d1SAlexander Motin if (v == 1) { /* we were the last */ 792069154d5SJulian Elischer 793cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 79430400f03SJulian Elischer node->nd_type->refs--; /* XXX maybe should get types lock? */ 79530400f03SJulian Elischer LIST_REMOVE(node, nd_nodes); 796cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 797069154d5SJulian Elischer 7989ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 79930400f03SJulian Elischer LIST_REMOVE(node, nd_idnodes); 8009ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 801069154d5SJulian Elischer 80212574a02SJulian Elischer mtx_destroy(&node->nd_input_queue.q_mtx); 803069154d5SJulian Elischer NG_FREE_NODE(node); 8044cf49a43SJulian Elischer } 805018fe3d1SAlexander Motin return (v - 1); 8064cf49a43SJulian Elischer } 8074cf49a43SJulian Elischer 8084cf49a43SJulian Elischer /************************************************************************ 809dc90cad9SJulian Elischer Node ID handling 810dc90cad9SJulian Elischer ************************************************************************/ 811dc90cad9SJulian Elischer static node_p 812069154d5SJulian Elischer ng_ID2noderef(ng_ID_t ID) 813dc90cad9SJulian Elischer { 8148b615593SMarko Zec INIT_VNET_NETGRAPH(curvnet); 81530400f03SJulian Elischer node_p node; 8169ed346baSBosko Milekic mtx_lock(&ng_idhash_mtx); 8170f150d04SJulian Elischer NG_IDHASH_FIND(ID, node); 81830400f03SJulian Elischer if(node) 81930400f03SJulian Elischer NG_NODE_REF(node); 8209ed346baSBosko Milekic mtx_unlock(&ng_idhash_mtx); 82130400f03SJulian Elischer return(node); 822dc90cad9SJulian Elischer } 823dc90cad9SJulian Elischer 824dc90cad9SJulian Elischer ng_ID_t 825dc90cad9SJulian Elischer ng_node2ID(node_p node) 826dc90cad9SJulian Elischer { 82770de87f2SJulian Elischer return (node ? NG_NODE_ID(node) : 0); 828dc90cad9SJulian Elischer } 829dc90cad9SJulian Elischer 830dc90cad9SJulian Elischer /************************************************************************ 8314cf49a43SJulian Elischer Node name handling 8324cf49a43SJulian Elischer ************************************************************************/ 8334cf49a43SJulian Elischer 8344cf49a43SJulian Elischer /* 8354cf49a43SJulian Elischer * Assign a node a name. Once assigned, the name cannot be changed. 8364cf49a43SJulian Elischer */ 8374cf49a43SJulian Elischer int 8384cf49a43SJulian Elischer ng_name_node(node_p node, const char *name) 8394cf49a43SJulian Elischer { 8408b615593SMarko Zec INIT_VNET_NETGRAPH(curvnet); 841cfea3f85SAlexander Motin int i, hash; 842069154d5SJulian Elischer node_p node2; 8434cf49a43SJulian Elischer 8444cf49a43SJulian Elischer /* Check the name is valid */ 84587e2c66aSHartmut Brandt for (i = 0; i < NG_NODESIZ; i++) { 8464cf49a43SJulian Elischer if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 8474cf49a43SJulian Elischer break; 8484cf49a43SJulian Elischer } 8494cf49a43SJulian Elischer if (i == 0 || name[i] != '\0') { 8506b795970SJulian Elischer TRAP_ERROR(); 8514cf49a43SJulian Elischer return (EINVAL); 8524cf49a43SJulian Elischer } 853dc90cad9SJulian Elischer if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 8546b795970SJulian Elischer TRAP_ERROR(); 8554cf49a43SJulian Elischer return (EINVAL); 8564cf49a43SJulian Elischer } 8574cf49a43SJulian Elischer 8584cf49a43SJulian Elischer /* Check the name isn't already being used */ 859069154d5SJulian Elischer if ((node2 = ng_name2noderef(node, name)) != NULL) { 86030400f03SJulian Elischer NG_NODE_UNREF(node2); 8616b795970SJulian Elischer TRAP_ERROR(); 8624cf49a43SJulian Elischer return (EADDRINUSE); 8634cf49a43SJulian Elischer } 8644cf49a43SJulian Elischer 865069154d5SJulian Elischer /* copy it */ 86687e2c66aSHartmut Brandt strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ); 8674cf49a43SJulian Elischer 868cfea3f85SAlexander Motin /* Update name hash. */ 869cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 870cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 871cfea3f85SAlexander Motin LIST_REMOVE(node, nd_nodes); 872603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes); 873cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 874cfea3f85SAlexander Motin 8754cf49a43SJulian Elischer return (0); 8764cf49a43SJulian Elischer } 8774cf49a43SJulian Elischer 8784cf49a43SJulian Elischer /* 8794cf49a43SJulian Elischer * Find a node by absolute name. The name should NOT end with ':' 8804cf49a43SJulian Elischer * The name "." means "this node" and "[xxx]" means "the node 8814cf49a43SJulian Elischer * with ID (ie, at address) xxx". 8824cf49a43SJulian Elischer * 8834cf49a43SJulian Elischer * Returns the node if found, else NULL. 884069154d5SJulian Elischer * Eventually should add something faster than a sequential search. 885e1e8f51bSRobert Watson * Note it acquires a reference on the node so you can be sure it's still 886e1e8f51bSRobert Watson * there. 8874cf49a43SJulian Elischer */ 8884cf49a43SJulian Elischer node_p 889069154d5SJulian Elischer ng_name2noderef(node_p here, const char *name) 8904cf49a43SJulian Elischer { 8918b615593SMarko Zec INIT_VNET_NETGRAPH(curvnet); 892dc90cad9SJulian Elischer node_p node; 893dc90cad9SJulian Elischer ng_ID_t temp; 894cfea3f85SAlexander Motin int hash; 8954cf49a43SJulian Elischer 8964cf49a43SJulian Elischer /* "." means "this node" */ 897069154d5SJulian Elischer if (strcmp(name, ".") == 0) { 89830400f03SJulian Elischer NG_NODE_REF(here); 899069154d5SJulian Elischer return(here); 900069154d5SJulian Elischer } 9014cf49a43SJulian Elischer 9024cf49a43SJulian Elischer /* Check for name-by-ID */ 903dc90cad9SJulian Elischer if ((temp = ng_decodeidname(name)) != 0) { 904069154d5SJulian Elischer return (ng_ID2noderef(temp)); 9054cf49a43SJulian Elischer } 9064cf49a43SJulian Elischer 9074cf49a43SJulian Elischer /* Find node by name */ 908cfea3f85SAlexander Motin NG_NAMEHASH(name, hash); 909cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 910603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) { 911cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 912cfea3f85SAlexander Motin (strcmp(NG_NODE_NAME(node), name) == 0)) { 9134cf49a43SJulian Elischer break; 9144cf49a43SJulian Elischer } 91570de87f2SJulian Elischer } 916069154d5SJulian Elischer if (node) 91730400f03SJulian Elischer NG_NODE_REF(node); 918cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 9194cf49a43SJulian Elischer return (node); 9204cf49a43SJulian Elischer } 9214cf49a43SJulian Elischer 9224cf49a43SJulian Elischer /* 9239d5abbddSJens Schweikhardt * Decode an ID name, eg. "[f03034de]". Returns 0 if the 924dc90cad9SJulian Elischer * string is not valid, otherwise returns the value. 9254cf49a43SJulian Elischer */ 926dc90cad9SJulian Elischer static ng_ID_t 9274cf49a43SJulian Elischer ng_decodeidname(const char *name) 9284cf49a43SJulian Elischer { 9292b70adcbSArchie Cobbs const int len = strlen(name); 93025792ef3SArchie Cobbs char *eptr; 9312b70adcbSArchie Cobbs u_long val; 9324cf49a43SJulian Elischer 9332b70adcbSArchie Cobbs /* Check for proper length, brackets, no leading junk */ 93470de87f2SJulian Elischer if ((len < 3) 93570de87f2SJulian Elischer || (name[0] != '[') 93670de87f2SJulian Elischer || (name[len - 1] != ']') 93770de87f2SJulian Elischer || (!isxdigit(name[1]))) { 93870de87f2SJulian Elischer return ((ng_ID_t)0); 93970de87f2SJulian Elischer } 9404cf49a43SJulian Elischer 9412b70adcbSArchie Cobbs /* Decode number */ 9422b70adcbSArchie Cobbs val = strtoul(name + 1, &eptr, 16); 94370de87f2SJulian Elischer if ((eptr - name != len - 1) 94470de87f2SJulian Elischer || (val == ULONG_MAX) 94570de87f2SJulian Elischer || (val == 0)) { 94612f035e0SJulian Elischer return ((ng_ID_t)0); 94770de87f2SJulian Elischer } 9482b70adcbSArchie Cobbs return (ng_ID_t)val; 9494cf49a43SJulian Elischer } 9504cf49a43SJulian Elischer 9514cf49a43SJulian Elischer /* 9524cf49a43SJulian Elischer * Remove a name from a node. This should only be called 9534cf49a43SJulian Elischer * when shutting down and removing the node. 95464efc707SRobert Watson * IF we allow name changing this may be more resurrected. 9554cf49a43SJulian Elischer */ 9564cf49a43SJulian Elischer void 9574cf49a43SJulian Elischer ng_unname(node_p node) 9584cf49a43SJulian Elischer { 9594cf49a43SJulian Elischer } 9604cf49a43SJulian Elischer 9614cf49a43SJulian Elischer /************************************************************************ 9624cf49a43SJulian Elischer Hook routines 9634cf49a43SJulian Elischer Names are not optional. Hooks are always connected, except for a 9643e4084c8SJulian Elischer brief moment within these routines. On invalidation or during creation 9653e4084c8SJulian Elischer they are connected to the 'dead' hook. 9664cf49a43SJulian Elischer ************************************************************************/ 9674cf49a43SJulian Elischer 9684cf49a43SJulian Elischer /* 9694cf49a43SJulian Elischer * Remove a hook reference 9704cf49a43SJulian Elischer */ 97130400f03SJulian Elischer void 9724cf49a43SJulian Elischer ng_unref_hook(hook_p hook) 9734cf49a43SJulian Elischer { 97430400f03SJulian Elischer int v; 9756b795970SJulian Elischer 9766b795970SJulian Elischer if (hook == &ng_deadhook) { 9776b795970SJulian Elischer return; 9786b795970SJulian Elischer } 979018fe3d1SAlexander Motin 980018fe3d1SAlexander Motin v = atomic_fetchadd_int(&hook->hk_refs, -1); 981e8a49db2SJulian Elischer 98230400f03SJulian Elischer if (v == 1) { /* we were the last */ 983f573da1aSAlexander Motin if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */ 9846b795970SJulian Elischer _NG_NODE_UNREF((_NG_HOOK_NODE(hook))); 985069154d5SJulian Elischer NG_FREE_HOOK(hook); 986069154d5SJulian Elischer } 9874cf49a43SJulian Elischer } 9884cf49a43SJulian Elischer 9894cf49a43SJulian Elischer /* 9904cf49a43SJulian Elischer * Add an unconnected hook to a node. Only used internally. 9913e4084c8SJulian Elischer * Assumes node is locked. (XXX not yet true ) 9924cf49a43SJulian Elischer */ 9934cf49a43SJulian Elischer static int 9944cf49a43SJulian Elischer ng_add_hook(node_p node, const char *name, hook_p *hookp) 9954cf49a43SJulian Elischer { 9964cf49a43SJulian Elischer hook_p hook; 9974cf49a43SJulian Elischer int error = 0; 9984cf49a43SJulian Elischer 9994cf49a43SJulian Elischer /* Check that the given name is good */ 10004cf49a43SJulian Elischer if (name == NULL) { 10016b795970SJulian Elischer TRAP_ERROR(); 10024cf49a43SJulian Elischer return (EINVAL); 10034cf49a43SJulian Elischer } 1004899e9c4eSArchie Cobbs if (ng_findhook(node, name) != NULL) { 10056b795970SJulian Elischer TRAP_ERROR(); 10064cf49a43SJulian Elischer return (EEXIST); 10074cf49a43SJulian Elischer } 10084cf49a43SJulian Elischer 10094cf49a43SJulian Elischer /* Allocate the hook and link it up */ 101030400f03SJulian Elischer NG_ALLOC_HOOK(hook); 10114cf49a43SJulian Elischer if (hook == NULL) { 10126b795970SJulian Elischer TRAP_ERROR(); 10134cf49a43SJulian Elischer return (ENOMEM); 10144cf49a43SJulian Elischer } 10153e4084c8SJulian Elischer hook->hk_refs = 1; /* add a reference for us to return */ 101630400f03SJulian Elischer hook->hk_flags = HK_INVALID; 10173e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* start off this way */ 101830400f03SJulian Elischer hook->hk_node = node; 101930400f03SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 10204cf49a43SJulian Elischer 10213e4084c8SJulian Elischer /* Set hook name */ 102287e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ); 10233e4084c8SJulian Elischer 10243e4084c8SJulian Elischer /* 10253e4084c8SJulian Elischer * Check if the node type code has something to say about it 10263e4084c8SJulian Elischer * If it fails, the unref of the hook will also unref the node. 10273e4084c8SJulian Elischer */ 1028954c4772SJulian Elischer if (node->nd_type->newhook != NULL) { 1029954c4772SJulian Elischer if ((error = (*node->nd_type->newhook)(node, hook, name))) { 103030400f03SJulian Elischer NG_HOOK_UNREF(hook); /* this frees the hook */ 1031069154d5SJulian Elischer return (error); 1032069154d5SJulian Elischer } 1033954c4772SJulian Elischer } 10344cf49a43SJulian Elischer /* 10354cf49a43SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 10364cf49a43SJulian Elischer * We'll ask again later when we actually connect the hooks. 10374cf49a43SJulian Elischer */ 103830400f03SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 103930400f03SJulian Elischer node->nd_numhooks++; 10403e4084c8SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 10414cf49a43SJulian Elischer 10424cf49a43SJulian Elischer if (hookp) 10434cf49a43SJulian Elischer *hookp = hook; 10443e4084c8SJulian Elischer return (0); 10454cf49a43SJulian Elischer } 10464cf49a43SJulian Elischer 10474cf49a43SJulian Elischer /* 1048899e9c4eSArchie Cobbs * Find a hook 1049899e9c4eSArchie Cobbs * 1050899e9c4eSArchie Cobbs * Node types may supply their own optimized routines for finding 1051899e9c4eSArchie Cobbs * hooks. If none is supplied, we just do a linear search. 10523e4084c8SJulian Elischer * XXX Possibly we should add a reference to the hook? 1053899e9c4eSArchie Cobbs */ 1054899e9c4eSArchie Cobbs hook_p 1055899e9c4eSArchie Cobbs ng_findhook(node_p node, const char *name) 1056899e9c4eSArchie Cobbs { 1057899e9c4eSArchie Cobbs hook_p hook; 1058899e9c4eSArchie Cobbs 105930400f03SJulian Elischer if (node->nd_type->findhook != NULL) 106030400f03SJulian Elischer return (*node->nd_type->findhook)(node, name); 106130400f03SJulian Elischer LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 106270de87f2SJulian Elischer if (NG_HOOK_IS_VALID(hook) 1063ce5e5f99SArchie Cobbs && (strcmp(NG_HOOK_NAME(hook), name) == 0)) 1064899e9c4eSArchie Cobbs return (hook); 1065899e9c4eSArchie Cobbs } 1066899e9c4eSArchie Cobbs return (NULL); 1067899e9c4eSArchie Cobbs } 1068899e9c4eSArchie Cobbs 1069899e9c4eSArchie Cobbs /* 10704cf49a43SJulian Elischer * Destroy a hook 10714cf49a43SJulian Elischer * 10724cf49a43SJulian Elischer * As hooks are always attached, this really destroys two hooks. 10734cf49a43SJulian Elischer * The one given, and the one attached to it. Disconnect the hooks 10743e4084c8SJulian Elischer * from each other first. We reconnect the peer hook to the 'dead' 10753e4084c8SJulian Elischer * hook so that it can still exist after we depart. We then 10763e4084c8SJulian Elischer * send the peer its own destroy message. This ensures that we only 10773e4084c8SJulian Elischer * interact with the peer's structures when it is locked processing that 10783e4084c8SJulian Elischer * message. We hold a reference to the peer hook so we are guaranteed that 10793e4084c8SJulian Elischer * the peer hook and node are still going to exist until 10803e4084c8SJulian Elischer * we are finished there as the hook holds a ref on the node. 10813e4084c8SJulian Elischer * We run this same code again on the peer hook, but that time it is already 10823e4084c8SJulian Elischer * attached to the 'dead' hook. 10836b795970SJulian Elischer * 10846b795970SJulian Elischer * This routine is called at all stages of hook creation 10856b795970SJulian Elischer * on error detection and must be able to handle any such stage. 10864cf49a43SJulian Elischer */ 10874cf49a43SJulian Elischer void 10884cf49a43SJulian Elischer ng_destroy_hook(hook_p hook) 10894cf49a43SJulian Elischer { 1090ac5dd141SGleb Smirnoff hook_p peer; 1091ac5dd141SGleb Smirnoff node_p node; 10924cf49a43SJulian Elischer 10936b795970SJulian Elischer if (hook == &ng_deadhook) { /* better safe than sorry */ 10946b795970SJulian Elischer printf("ng_destroy_hook called on deadhook\n"); 10956b795970SJulian Elischer return; 10966b795970SJulian Elischer } 1097ac5dd141SGleb Smirnoff 1098ac5dd141SGleb Smirnoff /* 1099ac5dd141SGleb Smirnoff * Protect divorce process with mutex, to avoid races on 1100ac5dd141SGleb Smirnoff * simultaneous disconnect. 1101ac5dd141SGleb Smirnoff */ 1102ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1103ac5dd141SGleb Smirnoff 1104ac5dd141SGleb Smirnoff hook->hk_flags |= HK_INVALID; 1105ac5dd141SGleb Smirnoff 1106ac5dd141SGleb Smirnoff peer = NG_HOOK_PEER(hook); 1107ac5dd141SGleb Smirnoff node = NG_HOOK_NODE(hook); 1108ac5dd141SGleb Smirnoff 11093e4084c8SJulian Elischer if (peer && (peer != &ng_deadhook)) { 11103e4084c8SJulian Elischer /* 11113e4084c8SJulian Elischer * Set the peer to point to ng_deadhook 11123e4084c8SJulian Elischer * from this moment on we are effectively independent it. 11133e4084c8SJulian Elischer * send it an rmhook message of it's own. 11143e4084c8SJulian Elischer */ 11153e4084c8SJulian Elischer peer->hk_peer = &ng_deadhook; /* They no longer know us */ 11163e4084c8SJulian Elischer hook->hk_peer = &ng_deadhook; /* Nor us, them */ 11176b795970SJulian Elischer if (NG_HOOK_NODE(peer) == &ng_deadnode) { 11186b795970SJulian Elischer /* 11196b795970SJulian Elischer * If it's already divorced from a node, 11206b795970SJulian Elischer * just free it. 11216b795970SJulian Elischer */ 1122ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11236b795970SJulian Elischer } else { 1124ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 11256b795970SJulian Elischer ng_rmhook_self(peer); /* Send it a surprise */ 11266b795970SJulian Elischer } 112752fa3556SJulian Elischer NG_HOOK_UNREF(peer); /* account for peer link */ 112852fa3556SJulian Elischer NG_HOOK_UNREF(hook); /* account for peer link */ 1129ac5dd141SGleb Smirnoff } else 1130ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1131ac5dd141SGleb Smirnoff 1132ac5dd141SGleb Smirnoff mtx_assert(&ng_topo_mtx, MA_NOTOWNED); 11334cf49a43SJulian Elischer 11344cf49a43SJulian Elischer /* 11354cf49a43SJulian Elischer * Remove the hook from the node's list to avoid possible recursion 11364cf49a43SJulian Elischer * in case the disconnection results in node shutdown. 11374cf49a43SJulian Elischer */ 11386b795970SJulian Elischer if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */ 11396b795970SJulian Elischer return; 11406b795970SJulian Elischer } 114130400f03SJulian Elischer LIST_REMOVE(hook, hk_hooks); 114230400f03SJulian Elischer node->nd_numhooks--; 114330400f03SJulian Elischer if (node->nd_type->disconnect) { 11444cf49a43SJulian Elischer /* 11456b795970SJulian Elischer * The type handler may elect to destroy the node so don't 114664efc707SRobert Watson * trust its existence after this point. (except 11476b795970SJulian Elischer * that we still hold a reference on it. (which we 11486b795970SJulian Elischer * inherrited from the hook we are destroying) 11494cf49a43SJulian Elischer */ 115030400f03SJulian Elischer (*node->nd_type->disconnect) (hook); 11514cf49a43SJulian Elischer } 11526b795970SJulian Elischer 11536b795970SJulian Elischer /* 11546b795970SJulian Elischer * Note that because we will point to ng_deadnode, the original node 11556b795970SJulian Elischer * is not decremented automatically so we do that manually. 11566b795970SJulian Elischer */ 11576b795970SJulian Elischer _NG_HOOK_NODE(hook) = &ng_deadnode; 11586b795970SJulian Elischer NG_NODE_UNREF(node); /* We no longer point to it so adjust count */ 11596b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Account for linkage (in list) to node */ 11604cf49a43SJulian Elischer } 11614cf49a43SJulian Elischer 11624cf49a43SJulian Elischer /* 11634cf49a43SJulian Elischer * Take two hooks on a node and merge the connection so that the given node 11644cf49a43SJulian Elischer * is effectively bypassed. 11654cf49a43SJulian Elischer */ 11664cf49a43SJulian Elischer int 11674cf49a43SJulian Elischer ng_bypass(hook_p hook1, hook_p hook2) 11684cf49a43SJulian Elischer { 116930400f03SJulian Elischer if (hook1->hk_node != hook2->hk_node) { 11706b795970SJulian Elischer TRAP_ERROR(); 11714cf49a43SJulian Elischer return (EINVAL); 117230400f03SJulian Elischer } 117330400f03SJulian Elischer hook1->hk_peer->hk_peer = hook2->hk_peer; 117430400f03SJulian Elischer hook2->hk_peer->hk_peer = hook1->hk_peer; 11754cf49a43SJulian Elischer 11763e4084c8SJulian Elischer hook1->hk_peer = &ng_deadhook; 11773e4084c8SJulian Elischer hook2->hk_peer = &ng_deadhook; 11783e4084c8SJulian Elischer 1179cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook1); 1180cf3254aaSGleb Smirnoff NG_HOOK_UNREF(hook2); 1181cf3254aaSGleb Smirnoff 11824cf49a43SJulian Elischer /* XXX If we ever cache methods on hooks update them as well */ 11834cf49a43SJulian Elischer ng_destroy_hook(hook1); 11844cf49a43SJulian Elischer ng_destroy_hook(hook2); 11854cf49a43SJulian Elischer return (0); 11864cf49a43SJulian Elischer } 11874cf49a43SJulian Elischer 11884cf49a43SJulian Elischer /* 11894cf49a43SJulian Elischer * Install a new netgraph type 11904cf49a43SJulian Elischer */ 11914cf49a43SJulian Elischer int 11924cf49a43SJulian Elischer ng_newtype(struct ng_type *tp) 11934cf49a43SJulian Elischer { 11944cf49a43SJulian Elischer const size_t namelen = strlen(tp->name); 11954cf49a43SJulian Elischer 11964cf49a43SJulian Elischer /* Check version and type name fields */ 1197589f6ed8SJulian Elischer if ((tp->version != NG_ABI_VERSION) 1198589f6ed8SJulian Elischer || (namelen == 0) 119987e2c66aSHartmut Brandt || (namelen >= NG_TYPESIZ)) { 12006b795970SJulian Elischer TRAP_ERROR(); 12018ed370fdSJulian Elischer if (tp->version != NG_ABI_VERSION) { 12028ed370fdSJulian Elischer printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n"); 12038ed370fdSJulian Elischer } 12044cf49a43SJulian Elischer return (EINVAL); 12054cf49a43SJulian Elischer } 12064cf49a43SJulian Elischer 12074cf49a43SJulian Elischer /* Check for name collision */ 12084cf49a43SJulian Elischer if (ng_findtype(tp->name) != NULL) { 12096b795970SJulian Elischer TRAP_ERROR(); 12104cf49a43SJulian Elischer return (EEXIST); 12114cf49a43SJulian Elischer } 12124cf49a43SJulian Elischer 1213069154d5SJulian Elischer 1214069154d5SJulian Elischer /* Link in new type */ 12159ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 1216069154d5SJulian Elischer LIST_INSERT_HEAD(&ng_typelist, tp, types); 1217c73b94a2SJulian Elischer tp->refs = 1; /* first ref is linked list */ 12189ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 12194cf49a43SJulian Elischer return (0); 12204cf49a43SJulian Elischer } 12214cf49a43SJulian Elischer 12224cf49a43SJulian Elischer /* 1223c31b4a53SJulian Elischer * unlink a netgraph type 1224c31b4a53SJulian Elischer * If no examples exist 1225c31b4a53SJulian Elischer */ 1226c31b4a53SJulian Elischer int 1227c31b4a53SJulian Elischer ng_rmtype(struct ng_type *tp) 1228c31b4a53SJulian Elischer { 1229c31b4a53SJulian Elischer /* Check for name collision */ 1230c31b4a53SJulian Elischer if (tp->refs != 1) { 1231c31b4a53SJulian Elischer TRAP_ERROR(); 1232c31b4a53SJulian Elischer return (EBUSY); 1233c31b4a53SJulian Elischer } 1234c31b4a53SJulian Elischer 1235c31b4a53SJulian Elischer /* Unlink type */ 1236c31b4a53SJulian Elischer mtx_lock(&ng_typelist_mtx); 1237c31b4a53SJulian Elischer LIST_REMOVE(tp, types); 1238c31b4a53SJulian Elischer mtx_unlock(&ng_typelist_mtx); 1239c31b4a53SJulian Elischer return (0); 1240c31b4a53SJulian Elischer } 1241c31b4a53SJulian Elischer 1242c31b4a53SJulian Elischer /* 12434cf49a43SJulian Elischer * Look for a type of the name given 12444cf49a43SJulian Elischer */ 12454cf49a43SJulian Elischer struct ng_type * 12464cf49a43SJulian Elischer ng_findtype(const char *typename) 12474cf49a43SJulian Elischer { 12484cf49a43SJulian Elischer struct ng_type *type; 12494cf49a43SJulian Elischer 12509ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 1251069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 12524cf49a43SJulian Elischer if (strcmp(type->name, typename) == 0) 12534cf49a43SJulian Elischer break; 12544cf49a43SJulian Elischer } 12559ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 12564cf49a43SJulian Elischer return (type); 12574cf49a43SJulian Elischer } 12584cf49a43SJulian Elischer 12594cf49a43SJulian Elischer /************************************************************************ 12604cf49a43SJulian Elischer Composite routines 12614cf49a43SJulian Elischer ************************************************************************/ 12624cf49a43SJulian Elischer /* 12636b795970SJulian Elischer * Connect two nodes using the specified hooks, using queued functions. 12644cf49a43SJulian Elischer */ 1265e088dd4cSAlexander Motin static int 1266e088dd4cSAlexander Motin ng_con_part3(node_p node, item_p item, hook_p hook) 12674cf49a43SJulian Elischer { 1268e088dd4cSAlexander Motin int error = 0; 12694cf49a43SJulian Elischer 12706b795970SJulian Elischer /* 12716b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 12726b795970SJulian Elischer * Our caller has a reference on the hook. 12736b795970SJulian Elischer * Our caller has a reference on the node. 12746b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 12756b795970SJulian Elischer * The peer hook has a reference on the hook. 12761acb27c6SJulian Elischer * We are all set up except for the final call to the node, and 12771acb27c6SJulian Elischer * the clearing of the INVALID flag. 12786b795970SJulian Elischer */ 12796b795970SJulian Elischer if (NG_HOOK_NODE(hook) == &ng_deadnode) { 12806b795970SJulian Elischer /* 12816b795970SJulian Elischer * The node must have been freed again since we last visited 12826b795970SJulian Elischer * here. ng_destry_hook() has this effect but nothing else does. 12836b795970SJulian Elischer * We should just release our references and 12846b795970SJulian Elischer * free anything we can think of. 12856b795970SJulian Elischer * Since we know it's been destroyed, and it's our caller 12866b795970SJulian Elischer * that holds the references, just return. 12876b795970SJulian Elischer */ 1288e088dd4cSAlexander Motin ERROUT(ENOENT); 12896b795970SJulian Elischer } 12906b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1291e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 12926b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 12931acb27c6SJulian Elischer printf("failed in ng_con_part3()\n"); 1294e088dd4cSAlexander Motin ERROUT(error); 12954cf49a43SJulian Elischer } 12966b795970SJulian Elischer } 12976b795970SJulian Elischer /* 12986b795970SJulian Elischer * XXX this is wrong for SMP. Possibly we need 12996b795970SJulian Elischer * to separate out 'create' and 'invalid' flags. 13006b795970SJulian Elischer * should only set flags on hooks we have locked under our node. 13016b795970SJulian Elischer */ 13026b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; 1303e088dd4cSAlexander Motin done: 1304e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1305e088dd4cSAlexander Motin return (error); 13066b795970SJulian Elischer } 13076b795970SJulian Elischer 1308e088dd4cSAlexander Motin static int 1309e088dd4cSAlexander Motin ng_con_part2(node_p node, item_p item, hook_p hook) 13106b795970SJulian Elischer { 1311ac5dd141SGleb Smirnoff hook_p peer; 1312e088dd4cSAlexander Motin int error = 0; 13136b795970SJulian Elischer 13146b795970SJulian Elischer /* 13156b795970SJulian Elischer * When we run, we know that the node 'node' is locked for us. 13166b795970SJulian Elischer * Our caller has a reference on the hook. 13176b795970SJulian Elischer * Our caller has a reference on the node. 13186b795970SJulian Elischer * (In this case our caller is ng_apply_item() ). 13196b795970SJulian Elischer * The peer hook has a reference on the hook. 13206b795970SJulian Elischer * our node pointer points to the 'dead' node. 13216b795970SJulian Elischer * First check the hook name is unique. 13221acb27c6SJulian Elischer * Should not happen because we checked before queueing this. 13236b795970SJulian Elischer */ 13246b795970SJulian Elischer if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) { 13256b795970SJulian Elischer TRAP_ERROR(); 13266b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13271acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1328e088dd4cSAlexander Motin ERROUT(EEXIST); 13296b795970SJulian Elischer } 13306b795970SJulian Elischer /* 13316b795970SJulian Elischer * Check if the node type code has something to say about it 13326b795970SJulian Elischer * If it fails, the unref of the hook will also unref the attached node, 13336b795970SJulian Elischer * however since that node is 'ng_deadnode' this will do nothing. 13346b795970SJulian Elischer * The peer hook will also be destroyed. 13356b795970SJulian Elischer */ 13366b795970SJulian Elischer if (node->nd_type->newhook != NULL) { 1337e088dd4cSAlexander Motin if ((error = (*node->nd_type->newhook)(node, hook, 1338e088dd4cSAlexander Motin hook->hk_name))) { 13396b795970SJulian Elischer ng_destroy_hook(hook); /* should destroy peer too */ 13401acb27c6SJulian Elischer printf("failed in ng_con_part2()\n"); 1341e088dd4cSAlexander Motin ERROUT(error); 13426b795970SJulian Elischer } 13436b795970SJulian Elischer } 13446b795970SJulian Elischer 13456b795970SJulian Elischer /* 13466b795970SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 13476b795970SJulian Elischer * We'll ask again later when we actually connect the hooks. 13486b795970SJulian Elischer */ 13496b795970SJulian Elischer hook->hk_node = node; /* just overwrite ng_deadnode */ 13506b795970SJulian Elischer NG_NODE_REF(node); /* each hook counts as a reference */ 13516b795970SJulian Elischer LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 13526b795970SJulian Elischer node->nd_numhooks++; 13536b795970SJulian Elischer NG_HOOK_REF(hook); /* one for the node */ 13546b795970SJulian Elischer 13556b795970SJulian Elischer /* 135664efc707SRobert Watson * We now have a symmetrical situation, where both hooks have been 13575951069aSJulian Elischer * linked to their nodes, the newhook methods have been called 13586b795970SJulian Elischer * And the references are all correct. The hooks are still marked 13596b795970SJulian Elischer * as invalid, as we have not called the 'connect' methods 13606b795970SJulian Elischer * yet. 136164efc707SRobert Watson * We can call the local one immediately as we have the 13626b795970SJulian Elischer * node locked, but we need to queue the remote one. 13636b795970SJulian Elischer */ 13646b795970SJulian Elischer if (hook->hk_node->nd_type->connect) { 1365e088dd4cSAlexander Motin if ((error = (*hook->hk_node->nd_type->connect) (hook))) { 13666b795970SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 13671acb27c6SJulian Elischer printf("failed in ng_con_part2(A)\n"); 1368e088dd4cSAlexander Motin ERROUT(error); 13696b795970SJulian Elischer } 13706b795970SJulian Elischer } 1371ac5dd141SGleb Smirnoff 1372ac5dd141SGleb Smirnoff /* 1373ac5dd141SGleb Smirnoff * Acquire topo mutex to avoid race with ng_destroy_hook(). 1374ac5dd141SGleb Smirnoff */ 1375ac5dd141SGleb Smirnoff mtx_lock(&ng_topo_mtx); 1376ac5dd141SGleb Smirnoff peer = hook->hk_peer; 1377ac5dd141SGleb Smirnoff if (peer == &ng_deadhook) { 1378ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1379ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(B)\n"); 1380ac5dd141SGleb Smirnoff ng_destroy_hook(hook); 1381e088dd4cSAlexander Motin ERROUT(ENOENT); 1382ac5dd141SGleb Smirnoff } 1383ac5dd141SGleb Smirnoff mtx_unlock(&ng_topo_mtx); 1384ac5dd141SGleb Smirnoff 1385b332b91fSGleb Smirnoff if ((error = ng_send_fn2(peer->hk_node, peer, item, &ng_con_part3, 1386b332b91fSGleb Smirnoff NULL, 0, NG_REUSE_ITEM))) { 1387ac5dd141SGleb Smirnoff printf("failed in ng_con_part2(C)\n"); 13881acb27c6SJulian Elischer ng_destroy_hook(hook); /* also zaps peer */ 1389e088dd4cSAlexander Motin return (error); /* item was consumed. */ 13901acb27c6SJulian Elischer } 13916b795970SJulian Elischer hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */ 1392e088dd4cSAlexander Motin return (0); /* item was consumed. */ 1393e088dd4cSAlexander Motin done: 1394e088dd4cSAlexander Motin NG_FREE_ITEM(item); 1395e088dd4cSAlexander Motin return (error); 13964cf49a43SJulian Elischer } 13974cf49a43SJulian Elischer 13984cf49a43SJulian Elischer /* 13996b795970SJulian Elischer * Connect this node with another node. We assume that this node is 14006b795970SJulian Elischer * currently locked, as we are only called from an NGM_CONNECT message. 14014cf49a43SJulian Elischer */ 14026b795970SJulian Elischer static int 1403e088dd4cSAlexander Motin ng_con_nodes(item_p item, node_p node, const char *name, 1404e088dd4cSAlexander Motin node_p node2, const char *name2) 14054cf49a43SJulian Elischer { 14064cf49a43SJulian Elischer int error; 14074cf49a43SJulian Elischer hook_p hook; 14084cf49a43SJulian Elischer hook_p hook2; 14094cf49a43SJulian Elischer 14101acb27c6SJulian Elischer if (ng_findhook(node2, name2) != NULL) { 14111acb27c6SJulian Elischer return(EEXIST); 14121acb27c6SJulian Elischer } 14133e4084c8SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) /* gives us a ref */ 14144cf49a43SJulian Elischer return (error); 14156b795970SJulian Elischer /* Allocate the other hook and link it up */ 14166b795970SJulian Elischer NG_ALLOC_HOOK(hook2); 141719724144SGleb Smirnoff if (hook2 == NULL) { 14186b795970SJulian Elischer TRAP_ERROR(); 14196b795970SJulian Elischer ng_destroy_hook(hook); /* XXX check ref counts so far */ 14206b795970SJulian Elischer NG_HOOK_UNREF(hook); /* including our ref */ 14216b795970SJulian Elischer return (ENOMEM); 14226b795970SJulian Elischer } 14236b795970SJulian Elischer hook2->hk_refs = 1; /* start with a reference for us. */ 14246b795970SJulian Elischer hook2->hk_flags = HK_INVALID; 14256b795970SJulian Elischer hook2->hk_peer = hook; /* Link the two together */ 14266b795970SJulian Elischer hook->hk_peer = hook2; 14276b795970SJulian Elischer NG_HOOK_REF(hook); /* Add a ref for the peer to each*/ 14286b795970SJulian Elischer NG_HOOK_REF(hook2); 14296b795970SJulian Elischer hook2->hk_node = &ng_deadnode; 143087e2c66aSHartmut Brandt strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ); 14316b795970SJulian Elischer 14326b795970SJulian Elischer /* 14336b795970SJulian Elischer * Queue the function above. 14346b795970SJulian Elischer * Procesing continues in that function in the lock context of 14356b795970SJulian Elischer * the other node. 14366b795970SJulian Elischer */ 1437b332b91fSGleb Smirnoff if ((error = ng_send_fn2(node2, hook2, item, &ng_con_part2, NULL, 0, 1438b332b91fSGleb Smirnoff NG_NOFLAGS))) { 14393fb87c24SAlexander Motin printf("failed in ng_con_nodes(): %d\n", error); 14403fb87c24SAlexander Motin ng_destroy_hook(hook); /* also zaps peer */ 14413fb87c24SAlexander Motin } 14426b795970SJulian Elischer 14436b795970SJulian Elischer NG_HOOK_UNREF(hook); /* Let each hook go if it wants to */ 14446b795970SJulian Elischer NG_HOOK_UNREF(hook2); 14453fb87c24SAlexander Motin return (error); 14464cf49a43SJulian Elischer } 14476b795970SJulian Elischer 14486b795970SJulian Elischer /* 14496b795970SJulian Elischer * Make a peer and connect. 14506b795970SJulian Elischer * We assume that the local node is locked. 14516b795970SJulian Elischer * The new node probably doesn't need a lock until 14526b795970SJulian Elischer * it has a hook, because it cannot really have any work until then, 14536b795970SJulian Elischer * but we should think about it a bit more. 14546b795970SJulian Elischer * 14556b795970SJulian Elischer * The problem may come if the other node also fires up 14566b795970SJulian Elischer * some hardware or a timer or some other source of activation, 14576b795970SJulian Elischer * also it may already get a command msg via it's ID. 14586b795970SJulian Elischer * 14596b795970SJulian Elischer * We could use the same method as ng_con_nodes() but we'd have 14606b795970SJulian Elischer * to add ability to remove the node when failing. (Not hard, just 14616b795970SJulian Elischer * make arg1 point to the node to remove). 14626b795970SJulian Elischer * Unless of course we just ignore failure to connect and leave 14636b795970SJulian Elischer * an unconnected node? 14646b795970SJulian Elischer */ 14656b795970SJulian Elischer static int 14666b795970SJulian Elischer ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 14676b795970SJulian Elischer { 14686b795970SJulian Elischer node_p node2; 14694c9b5910SGleb Smirnoff hook_p hook1, hook2; 14706b795970SJulian Elischer int error; 14716b795970SJulian Elischer 14726b795970SJulian Elischer if ((error = ng_make_node(type, &node2))) { 14736b795970SJulian Elischer return (error); 14746b795970SJulian Elischer } 14756b795970SJulian Elischer 14766b795970SJulian Elischer if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */ 14771acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14786b795970SJulian Elischer return (error); 14796b795970SJulian Elischer } 14806b795970SJulian Elischer 14816b795970SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 14821acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 14836b795970SJulian Elischer ng_destroy_hook(hook1); 14846b795970SJulian Elischer NG_HOOK_UNREF(hook1); 14856b795970SJulian Elischer return (error); 14866b795970SJulian Elischer } 14876b795970SJulian Elischer 14886b795970SJulian Elischer /* 14896b795970SJulian Elischer * Actually link the two hooks together. 14906b795970SJulian Elischer */ 14916b795970SJulian Elischer hook1->hk_peer = hook2; 14926b795970SJulian Elischer hook2->hk_peer = hook1; 14936b795970SJulian Elischer 14946b795970SJulian Elischer /* Each hook is referenced by the other */ 14956b795970SJulian Elischer NG_HOOK_REF(hook1); 14966b795970SJulian Elischer NG_HOOK_REF(hook2); 14976b795970SJulian Elischer 14986b795970SJulian Elischer /* Give each node the opportunity to veto the pending connection */ 14996b795970SJulian Elischer if (hook1->hk_node->nd_type->connect) { 15006b795970SJulian Elischer error = (*hook1->hk_node->nd_type->connect) (hook1); 15016b795970SJulian Elischer } 15026b795970SJulian Elischer 15036b795970SJulian Elischer if ((error == 0) && hook2->hk_node->nd_type->connect) { 15046b795970SJulian Elischer error = (*hook2->hk_node->nd_type->connect) (hook2); 15056b795970SJulian Elischer 15066b795970SJulian Elischer } 15073e4084c8SJulian Elischer 15083e4084c8SJulian Elischer /* 15093e4084c8SJulian Elischer * drop the references we were holding on the two hooks. 15103e4084c8SJulian Elischer */ 15116b795970SJulian Elischer if (error) { 15126b795970SJulian Elischer ng_destroy_hook(hook2); /* also zaps hook1 */ 15131acb27c6SJulian Elischer ng_rmnode(node2, NULL, NULL, 0); 15146b795970SJulian Elischer } else { 15156b795970SJulian Elischer /* As a last act, allow the hooks to be used */ 15166b795970SJulian Elischer hook1->hk_flags &= ~HK_INVALID; 15176b795970SJulian Elischer hook2->hk_flags &= ~HK_INVALID; 15186b795970SJulian Elischer } 15196b795970SJulian Elischer NG_HOOK_UNREF(hook1); 15203e4084c8SJulian Elischer NG_HOOK_UNREF(hook2); 15213e4084c8SJulian Elischer return (error); 15224cf49a43SJulian Elischer } 15236b795970SJulian Elischer 1524069154d5SJulian Elischer /************************************************************************ 1525069154d5SJulian Elischer Utility routines to send self messages 1526069154d5SJulian Elischer ************************************************************************/ 1527069154d5SJulian Elischer 15281acb27c6SJulian Elischer /* Shut this node down as soon as everyone is clear of it */ 152964efc707SRobert Watson /* Should add arg "immediately" to jump the queue */ 1530069154d5SJulian Elischer int 153115cea89fSAlexander Motin ng_rmnode_self(node_p node) 1532069154d5SJulian Elischer { 15331acb27c6SJulian Elischer int error; 15344cf49a43SJulian Elischer 15351acb27c6SJulian Elischer if (node == &ng_deadnode) 15361acb27c6SJulian Elischer return (0); 1537be4252b3SJulian Elischer node->nd_flags |= NGF_INVALID; 1538be4252b3SJulian Elischer if (node->nd_flags & NGF_CLOSING) 15391acb27c6SJulian Elischer return (0); 1540069154d5SJulian Elischer 154115cea89fSAlexander Motin error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0); 15421acb27c6SJulian Elischer return (error); 1543069154d5SJulian Elischer } 1544069154d5SJulian Elischer 15451acb27c6SJulian Elischer static void 15466b795970SJulian Elischer ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) 15476b795970SJulian Elischer { 15486b795970SJulian Elischer ng_destroy_hook(hook); 15491acb27c6SJulian Elischer return ; 15506b795970SJulian Elischer } 15516b795970SJulian Elischer 1552954c4772SJulian Elischer int 1553954c4772SJulian Elischer ng_rmhook_self(hook_p hook) 1554954c4772SJulian Elischer { 15556b795970SJulian Elischer int error; 1556954c4772SJulian Elischer node_p node = NG_HOOK_NODE(hook); 1557954c4772SJulian Elischer 15586b795970SJulian Elischer if (node == &ng_deadnode) 15596b795970SJulian Elischer return (0); 15606b795970SJulian Elischer 15616b795970SJulian Elischer error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0); 15626b795970SJulian Elischer return (error); 1563954c4772SJulian Elischer } 1564954c4772SJulian Elischer 1565069154d5SJulian Elischer /*********************************************************************** 15664cf49a43SJulian Elischer * Parse and verify a string of the form: <NODE:><PATH> 15674cf49a43SJulian Elischer * 15684cf49a43SJulian Elischer * Such a string can refer to a specific node or a specific hook 15694cf49a43SJulian Elischer * on a specific node, depending on how you look at it. In the 15704cf49a43SJulian Elischer * latter case, the PATH component must not end in a dot. 15714cf49a43SJulian Elischer * 15724cf49a43SJulian Elischer * Both <NODE:> and <PATH> are optional. The <PATH> is a string 15734cf49a43SJulian Elischer * of hook names separated by dots. This breaks out the original 15744cf49a43SJulian Elischer * string, setting *nodep to "NODE" (or NULL if none) and *pathp 15754cf49a43SJulian Elischer * to "PATH" (or NULL if degenerate). Also, *hookp will point to 15764cf49a43SJulian Elischer * the final hook component of <PATH>, if any, otherwise NULL. 15774cf49a43SJulian Elischer * 15784cf49a43SJulian Elischer * This returns -1 if the path is malformed. The char ** are optional. 1579069154d5SJulian Elischer ***********************************************************************/ 15804cf49a43SJulian Elischer int 15814cf49a43SJulian Elischer ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 15824cf49a43SJulian Elischer { 15834cf49a43SJulian Elischer char *node, *path, *hook; 15844cf49a43SJulian Elischer int k; 15854cf49a43SJulian Elischer 15864cf49a43SJulian Elischer /* 15874cf49a43SJulian Elischer * Extract absolute NODE, if any 15884cf49a43SJulian Elischer */ 15894cf49a43SJulian Elischer for (path = addr; *path && *path != ':'; path++); 15904cf49a43SJulian Elischer if (*path) { 15914cf49a43SJulian Elischer node = addr; /* Here's the NODE */ 15924cf49a43SJulian Elischer *path++ = '\0'; /* Here's the PATH */ 15934cf49a43SJulian Elischer 15944cf49a43SJulian Elischer /* Node name must not be empty */ 15954cf49a43SJulian Elischer if (!*node) 15964cf49a43SJulian Elischer return -1; 15974cf49a43SJulian Elischer 15984cf49a43SJulian Elischer /* A name of "." is OK; otherwise '.' not allowed */ 15994cf49a43SJulian Elischer if (strcmp(node, ".") != 0) { 16004cf49a43SJulian Elischer for (k = 0; node[k]; k++) 16014cf49a43SJulian Elischer if (node[k] == '.') 16024cf49a43SJulian Elischer return -1; 16034cf49a43SJulian Elischer } 16044cf49a43SJulian Elischer } else { 16054cf49a43SJulian Elischer node = NULL; /* No absolute NODE */ 16064cf49a43SJulian Elischer path = addr; /* Here's the PATH */ 16074cf49a43SJulian Elischer } 16084cf49a43SJulian Elischer 16094cf49a43SJulian Elischer /* Snoop for illegal characters in PATH */ 16104cf49a43SJulian Elischer for (k = 0; path[k]; k++) 16114cf49a43SJulian Elischer if (path[k] == ':') 16124cf49a43SJulian Elischer return -1; 16134cf49a43SJulian Elischer 16144cf49a43SJulian Elischer /* Check for no repeated dots in PATH */ 16154cf49a43SJulian Elischer for (k = 0; path[k]; k++) 16164cf49a43SJulian Elischer if (path[k] == '.' && path[k + 1] == '.') 16174cf49a43SJulian Elischer return -1; 16184cf49a43SJulian Elischer 16194cf49a43SJulian Elischer /* Remove extra (degenerate) dots from beginning or end of PATH */ 16204cf49a43SJulian Elischer if (path[0] == '.') 16214cf49a43SJulian Elischer path++; 16224cf49a43SJulian Elischer if (*path && path[strlen(path) - 1] == '.') 16234cf49a43SJulian Elischer path[strlen(path) - 1] = 0; 16244cf49a43SJulian Elischer 16254cf49a43SJulian Elischer /* If PATH has a dot, then we're not talking about a hook */ 16264cf49a43SJulian Elischer if (*path) { 16274cf49a43SJulian Elischer for (hook = path, k = 0; path[k]; k++) 16284cf49a43SJulian Elischer if (path[k] == '.') { 16294cf49a43SJulian Elischer hook = NULL; 16304cf49a43SJulian Elischer break; 16314cf49a43SJulian Elischer } 16324cf49a43SJulian Elischer } else 16334cf49a43SJulian Elischer path = hook = NULL; 16344cf49a43SJulian Elischer 16354cf49a43SJulian Elischer /* Done */ 16364cf49a43SJulian Elischer if (nodep) 16374cf49a43SJulian Elischer *nodep = node; 16384cf49a43SJulian Elischer if (pathp) 16394cf49a43SJulian Elischer *pathp = path; 16404cf49a43SJulian Elischer if (hookp) 16414cf49a43SJulian Elischer *hookp = hook; 16424cf49a43SJulian Elischer return (0); 16434cf49a43SJulian Elischer } 16444cf49a43SJulian Elischer 16454cf49a43SJulian Elischer /* 16464cf49a43SJulian Elischer * Given a path, which may be absolute or relative, and a starting node, 1647069154d5SJulian Elischer * return the destination node. 16484cf49a43SJulian Elischer */ 16494cf49a43SJulian Elischer int 1650069154d5SJulian Elischer ng_path2noderef(node_p here, const char *address, 1651069154d5SJulian Elischer node_p *destp, hook_p *lasthook) 16524cf49a43SJulian Elischer { 165387e2c66aSHartmut Brandt char fullpath[NG_PATHSIZ]; 16544cf49a43SJulian Elischer char *nodename, *path, pbuf[2]; 1655069154d5SJulian Elischer node_p node, oldnode; 16564cf49a43SJulian Elischer char *cp; 1657a4ec03cfSJulian Elischer hook_p hook = NULL; 16584cf49a43SJulian Elischer 16594cf49a43SJulian Elischer /* Initialize */ 166030400f03SJulian Elischer if (destp == NULL) { 16616b795970SJulian Elischer TRAP_ERROR(); 16624cf49a43SJulian Elischer return EINVAL; 166330400f03SJulian Elischer } 16644cf49a43SJulian Elischer *destp = NULL; 16654cf49a43SJulian Elischer 16664cf49a43SJulian Elischer /* Make a writable copy of address for ng_path_parse() */ 16674cf49a43SJulian Elischer strncpy(fullpath, address, sizeof(fullpath) - 1); 16684cf49a43SJulian Elischer fullpath[sizeof(fullpath) - 1] = '\0'; 16694cf49a43SJulian Elischer 16704cf49a43SJulian Elischer /* Parse out node and sequence of hooks */ 16714cf49a43SJulian Elischer if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 16726b795970SJulian Elischer TRAP_ERROR(); 16734cf49a43SJulian Elischer return EINVAL; 16744cf49a43SJulian Elischer } 16754cf49a43SJulian Elischer if (path == NULL) { 16764cf49a43SJulian Elischer pbuf[0] = '.'; /* Needs to be writable */ 16774cf49a43SJulian Elischer pbuf[1] = '\0'; 16784cf49a43SJulian Elischer path = pbuf; 16794cf49a43SJulian Elischer } 16804cf49a43SJulian Elischer 1681069154d5SJulian Elischer /* 1682069154d5SJulian Elischer * For an absolute address, jump to the starting node. 1683069154d5SJulian Elischer * Note that this holds a reference on the node for us. 1684069154d5SJulian Elischer * Don't forget to drop the reference if we don't need it. 1685069154d5SJulian Elischer */ 16864cf49a43SJulian Elischer if (nodename) { 1687069154d5SJulian Elischer node = ng_name2noderef(here, nodename); 16884cf49a43SJulian Elischer if (node == NULL) { 16896b795970SJulian Elischer TRAP_ERROR(); 16904cf49a43SJulian Elischer return (ENOENT); 16914cf49a43SJulian Elischer } 1692069154d5SJulian Elischer } else { 1693069154d5SJulian Elischer if (here == NULL) { 16946b795970SJulian Elischer TRAP_ERROR(); 1695069154d5SJulian Elischer return (EINVAL); 1696069154d5SJulian Elischer } 16974cf49a43SJulian Elischer node = here; 169830400f03SJulian Elischer NG_NODE_REF(node); 1699069154d5SJulian Elischer } 17004cf49a43SJulian Elischer 1701069154d5SJulian Elischer /* 1702069154d5SJulian Elischer * Now follow the sequence of hooks 1703069154d5SJulian Elischer * XXX 1704069154d5SJulian Elischer * We actually cannot guarantee that the sequence 1705069154d5SJulian Elischer * is not being demolished as we crawl along it 1706069154d5SJulian Elischer * without extra-ordinary locking etc. 1707069154d5SJulian Elischer * So this is a bit dodgy to say the least. 1708069154d5SJulian Elischer * We can probably hold up some things by holding 1709069154d5SJulian Elischer * the nodelist mutex for the time of this 1710069154d5SJulian Elischer * crawl if we wanted.. At least that way we wouldn't have to 171164efc707SRobert Watson * worry about the nodes disappearing, but the hooks would still 1712069154d5SJulian Elischer * be a problem. 1713069154d5SJulian Elischer */ 17144cf49a43SJulian Elischer for (cp = path; node != NULL && *cp != '\0'; ) { 17154cf49a43SJulian Elischer char *segment; 17164cf49a43SJulian Elischer 17174cf49a43SJulian Elischer /* 17184cf49a43SJulian Elischer * Break out the next path segment. Replace the dot we just 17194cf49a43SJulian Elischer * found with a NUL; "cp" points to the next segment (or the 17204cf49a43SJulian Elischer * NUL at the end). 17214cf49a43SJulian Elischer */ 17224cf49a43SJulian Elischer for (segment = cp; *cp != '\0'; cp++) { 17234cf49a43SJulian Elischer if (*cp == '.') { 17244cf49a43SJulian Elischer *cp++ = '\0'; 17254cf49a43SJulian Elischer break; 17264cf49a43SJulian Elischer } 17274cf49a43SJulian Elischer } 17284cf49a43SJulian Elischer 17294cf49a43SJulian Elischer /* Empty segment */ 17304cf49a43SJulian Elischer if (*segment == '\0') 17314cf49a43SJulian Elischer continue; 17324cf49a43SJulian Elischer 17334cf49a43SJulian Elischer /* We have a segment, so look for a hook by that name */ 1734899e9c4eSArchie Cobbs hook = ng_findhook(node, segment); 17354cf49a43SJulian Elischer 17364cf49a43SJulian Elischer /* Can't get there from here... */ 17374cf49a43SJulian Elischer if (hook == NULL 173830400f03SJulian Elischer || NG_HOOK_PEER(hook) == NULL 173930400f03SJulian Elischer || NG_HOOK_NOT_VALID(hook) 174030400f03SJulian Elischer || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) { 17416b795970SJulian Elischer TRAP_ERROR(); 174230400f03SJulian Elischer NG_NODE_UNREF(node); 174330400f03SJulian Elischer #if 0 174430400f03SJulian Elischer printf("hooknotvalid %s %s %d %d %d %d ", 174530400f03SJulian Elischer path, 174630400f03SJulian Elischer segment, 174730400f03SJulian Elischer hook == NULL, 174830400f03SJulian Elischer NG_HOOK_PEER(hook) == NULL, 174930400f03SJulian Elischer NG_HOOK_NOT_VALID(hook), 175030400f03SJulian Elischer NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))); 175130400f03SJulian Elischer #endif 17524cf49a43SJulian Elischer return (ENOENT); 17534cf49a43SJulian Elischer } 17544cf49a43SJulian Elischer 1755069154d5SJulian Elischer /* 1756069154d5SJulian Elischer * Hop on over to the next node 1757069154d5SJulian Elischer * XXX 1758069154d5SJulian Elischer * Big race conditions here as hooks and nodes go away 1759069154d5SJulian Elischer * *** Idea.. store an ng_ID_t in each hook and use that 1760069154d5SJulian Elischer * instead of the direct hook in this crawl? 1761069154d5SJulian Elischer */ 1762069154d5SJulian Elischer oldnode = node; 176330400f03SJulian Elischer if ((node = NG_PEER_NODE(hook))) 176430400f03SJulian Elischer NG_NODE_REF(node); /* XXX RACE */ 176530400f03SJulian Elischer NG_NODE_UNREF(oldnode); /* XXX another race */ 176630400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 176730400f03SJulian Elischer NG_NODE_UNREF(node); /* XXX more races */ 1768069154d5SJulian Elischer node = NULL; 1769069154d5SJulian Elischer } 17704cf49a43SJulian Elischer } 17714cf49a43SJulian Elischer 17724cf49a43SJulian Elischer /* If node somehow missing, fail here (probably this is not needed) */ 17734cf49a43SJulian Elischer if (node == NULL) { 17746b795970SJulian Elischer TRAP_ERROR(); 17754cf49a43SJulian Elischer return (ENXIO); 17764cf49a43SJulian Elischer } 17774cf49a43SJulian Elischer 17784cf49a43SJulian Elischer /* Done */ 17794cf49a43SJulian Elischer *destp = node; 17801bdebe4dSArchie Cobbs if (lasthook != NULL) 178130400f03SJulian Elischer *lasthook = (hook ? NG_HOOK_PEER(hook) : NULL); 1782069154d5SJulian Elischer return (0); 1783069154d5SJulian Elischer } 1784069154d5SJulian Elischer 1785069154d5SJulian Elischer /***************************************************************\ 1786069154d5SJulian Elischer * Input queue handling. 1787069154d5SJulian Elischer * All activities are submitted to the node via the input queue 1788069154d5SJulian Elischer * which implements a multiple-reader/single-writer gate. 178964efc707SRobert Watson * Items which cannot be handled immediately are queued. 1790069154d5SJulian Elischer * 1791069154d5SJulian Elischer * read-write queue locking inline functions * 1792069154d5SJulian Elischer \***************************************************************/ 1793069154d5SJulian Elischer 17949852972bSAlexander Motin static __inline void ng_queue_rw(node_p node, item_p item, int rw); 17959852972bSAlexander Motin static __inline item_p ng_dequeue(node_p node, int *rw); 17969852972bSAlexander Motin static __inline item_p ng_acquire_read(node_p node, item_p item); 17979852972bSAlexander Motin static __inline item_p ng_acquire_write(node_p node, item_p item); 17989852972bSAlexander Motin static __inline void ng_leave_read(node_p node); 17999852972bSAlexander Motin static __inline void ng_leave_write(node_p node); 1800069154d5SJulian Elischer 1801069154d5SJulian Elischer /* 1802069154d5SJulian Elischer * Definition of the bits fields in the ng_queue flag word. 1803069154d5SJulian Elischer * Defined here rather than in netgraph.h because no-one should fiddle 1804069154d5SJulian Elischer * with them. 1805069154d5SJulian Elischer * 1806b57a7965SJulian Elischer * The ordering here may be important! don't shuffle these. 1807069154d5SJulian Elischer */ 1808069154d5SJulian Elischer /*- 1809069154d5SJulian Elischer Safety Barrier--------+ (adjustable to suit taste) (not used yet) 1810069154d5SJulian Elischer | 1811069154d5SJulian Elischer V 1812069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 18134be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 18144be59335SGleb Smirnoff | |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |P|A| 18154be59335SGleb Smirnoff | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|W| 1816069154d5SJulian Elischer +-------+-------+-------+-------+-------+-------+-------+-------+ 18174be59335SGleb Smirnoff \___________________________ ____________________________/ | | 18184be59335SGleb Smirnoff V | | 18194be59335SGleb Smirnoff [active reader count] | | 1820069154d5SJulian Elischer | | 18214be59335SGleb Smirnoff Operation Pending -------------------------------+ | 1822069154d5SJulian Elischer | 18234be59335SGleb Smirnoff Active Writer ---------------------------------------+ 1824b57a7965SJulian Elischer 18258f9ac44aSAlexander Motin Node queue has such semantics: 18268f9ac44aSAlexander Motin - All flags modifications are atomic. 18278f9ac44aSAlexander Motin - Reader count can be incremented only if there is no writer or pending flags. 18288f9ac44aSAlexander Motin As soon as this can't be done with single operation, it is implemented with 18298f9ac44aSAlexander Motin spin loop and atomic_cmpset(). 18308f9ac44aSAlexander Motin - Writer flag can be set only if there is no any bits set. 18318f9ac44aSAlexander Motin It is implemented with atomic_cmpset(). 18328f9ac44aSAlexander Motin - Pending flag can be set any time, but to avoid collision on queue processing 18338f9ac44aSAlexander Motin all queue fields are protected by the mutex. 18348f9ac44aSAlexander Motin - Queue processing thread reads queue holding the mutex, but releases it while 18358f9ac44aSAlexander Motin processing. When queue is empty pending flag is removed. 1836069154d5SJulian Elischer */ 18378f9ac44aSAlexander Motin 18384be59335SGleb Smirnoff #define WRITER_ACTIVE 0x00000001 18394be59335SGleb Smirnoff #define OP_PENDING 0x00000002 18404be59335SGleb Smirnoff #define READER_INCREMENT 0x00000004 18414be59335SGleb Smirnoff #define READER_MASK 0xfffffffc /* Not valid if WRITER_ACTIVE is set */ 18424be59335SGleb Smirnoff #define SAFETY_BARRIER 0x00100000 /* 128K items queued should be enough */ 1843b57a7965SJulian Elischer 1844b57a7965SJulian Elischer /* Defines of more elaborate states on the queue */ 18454be59335SGleb Smirnoff /* Mask of bits a new read cares about */ 18464be59335SGleb Smirnoff #define NGQ_RMASK (WRITER_ACTIVE|OP_PENDING) 1847b57a7965SJulian Elischer 18484be59335SGleb Smirnoff /* Mask of bits a new write cares about */ 1849b57a7965SJulian Elischer #define NGQ_WMASK (NGQ_RMASK|READER_MASK) 1850b57a7965SJulian Elischer 18514be59335SGleb Smirnoff /* Test to decide if there is something on the queue. */ 18524be59335SGleb Smirnoff #define QUEUE_ACTIVE(QP) ((QP)->q_flags & OP_PENDING) 18534be59335SGleb Smirnoff 18544be59335SGleb Smirnoff /* How to decide what the next queued item is. */ 18559852972bSAlexander Motin #define HEAD_IS_READER(QP) NGI_QUEUED_READER(STAILQ_FIRST(&(QP)->queue)) 18569852972bSAlexander Motin #define HEAD_IS_WRITER(QP) NGI_QUEUED_WRITER(STAILQ_FIRST(&(QP)->queue)) /* notused */ 18574be59335SGleb Smirnoff 18584be59335SGleb Smirnoff /* Read the status to decide if the next item on the queue can now run. */ 18594be59335SGleb Smirnoff #define QUEUED_READER_CAN_PROCEED(QP) \ 18604be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_RMASK & ~OP_PENDING)) == 0) 18614be59335SGleb Smirnoff #define QUEUED_WRITER_CAN_PROCEED(QP) \ 18624be59335SGleb Smirnoff (((QP)->q_flags & (NGQ_WMASK & ~OP_PENDING)) == 0) 1863b57a7965SJulian Elischer 1864b57a7965SJulian Elischer /* Is there a chance of getting ANY work off the queue? */ 18654be59335SGleb Smirnoff #define NEXT_QUEUED_ITEM_CAN_PROCEED(QP) \ 18664be59335SGleb Smirnoff ((HEAD_IS_READER(QP)) ? QUEUED_READER_CAN_PROCEED(QP) : \ 1867394cb30aSAlexander Motin QUEUED_WRITER_CAN_PROCEED(QP)) 18684be59335SGleb Smirnoff 1869714fb865SGleb Smirnoff #define NGQRW_R 0 1870714fb865SGleb Smirnoff #define NGQRW_W 1 1871714fb865SGleb Smirnoff 18729852972bSAlexander Motin #define NGQ2_WORKQ 0x00000001 18739852972bSAlexander Motin 1874069154d5SJulian Elischer /* 1875069154d5SJulian Elischer * Taking into account the current state of the queue and node, possibly take 1876069154d5SJulian Elischer * the next entry off the queue and return it. Return NULL if there was 1877069154d5SJulian Elischer * nothing we could return, either because there really was nothing there, or 1878069154d5SJulian Elischer * because the node was in a state where it cannot yet process the next item 1879069154d5SJulian Elischer * on the queue. 1880069154d5SJulian Elischer */ 1881069154d5SJulian Elischer static __inline item_p 18829852972bSAlexander Motin ng_dequeue(node_p node, int *rw) 1883069154d5SJulian Elischer { 1884069154d5SJulian Elischer item_p item; 18859852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 1886b57a7965SJulian Elischer 18878f9ac44aSAlexander Motin /* This MUST be called with the mutex held. */ 1888d58e678fSGleb Smirnoff mtx_assert(&ngq->q_mtx, MA_OWNED); 18898f9ac44aSAlexander Motin 18908f9ac44aSAlexander Motin /* If there is nothing queued, then just return. */ 18914be59335SGleb Smirnoff if (!QUEUE_ACTIVE(ngq)) { 18922955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queue empty; " 18932955ee18SGleb Smirnoff "queue flags 0x%lx", __func__, 18949852972bSAlexander Motin node->nd_ID, node, ngq->q_flags); 18954be59335SGleb Smirnoff return (NULL); 18964be59335SGleb Smirnoff } 1897d58e678fSGleb Smirnoff 18984be59335SGleb Smirnoff /* 18994be59335SGleb Smirnoff * From here, we can assume there is a head item. 19004be59335SGleb Smirnoff * We need to find out what it is and if it can be dequeued, given 19014be59335SGleb Smirnoff * the current state of the node. 19024be59335SGleb Smirnoff */ 19034be59335SGleb Smirnoff if (HEAD_IS_READER(ngq)) { 1904394cb30aSAlexander Motin while (1) { 1905394cb30aSAlexander Motin long t = ngq->q_flags; 1906394cb30aSAlexander Motin if (t & WRITER_ACTIVE) { 19078f9ac44aSAlexander Motin /* There is writer, reader can't proceed. */ 19082955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) queued reader " 19092955ee18SGleb Smirnoff "can't proceed; queue flags 0x%lx", __func__, 19109852972bSAlexander Motin node->nd_ID, node, t); 19114be59335SGleb Smirnoff return (NULL); 19124be59335SGleb Smirnoff } 19139852972bSAlexander Motin if (atomic_cmpset_acq_int(&ngq->q_flags, t, 1914394cb30aSAlexander Motin t + READER_INCREMENT)) 1915394cb30aSAlexander Motin break; 1916394cb30aSAlexander Motin cpu_spinwait(); 1917394cb30aSAlexander Motin } 19188f9ac44aSAlexander Motin /* We have got reader lock for the node. */ 1919714fb865SGleb Smirnoff *rw = NGQRW_R; 19209852972bSAlexander Motin } else if (atomic_cmpset_acq_int(&ngq->q_flags, OP_PENDING, 1921394cb30aSAlexander Motin OP_PENDING + WRITER_ACTIVE)) { 19228f9ac44aSAlexander Motin /* We have got writer lock for the node. */ 1923714fb865SGleb Smirnoff *rw = NGQRW_W; 1924069154d5SJulian Elischer } else { 19258f9ac44aSAlexander Motin /* There is somebody other, writer can't proceed. */ 1926394cb30aSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) queued writer " 1927394cb30aSAlexander Motin "can't proceed; queue flags 0x%lx", __func__, 19289852972bSAlexander Motin node->nd_ID, node, ngq->q_flags); 19294be59335SGleb Smirnoff return (NULL); 19304cf49a43SJulian Elischer } 19314cf49a43SJulian Elischer 19324cf49a43SJulian Elischer /* 1933069154d5SJulian Elischer * Now we dequeue the request (whatever it may be) and correct the 1934069154d5SJulian Elischer * pending flags and the next and last pointers. 19354cf49a43SJulian Elischer */ 19369852972bSAlexander Motin item = STAILQ_FIRST(&ngq->queue); 19379852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 19389852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 19399852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 19402955ee18SGleb Smirnoff CTR6(KTR_NET, "%20s: node [%x] (%p) returning item %p as %s; " 19412955ee18SGleb Smirnoff "queue flags 0x%lx", __func__, 19429852972bSAlexander Motin node->nd_ID, node, item, *rw ? "WRITER" : "READER" , 19433b33fbe7SGleb Smirnoff ngq->q_flags); 1944069154d5SJulian Elischer return (item); 1945069154d5SJulian Elischer } 1946859a4d16SJulian Elischer 1947859a4d16SJulian Elischer /* 19488f9ac44aSAlexander Motin * Queue a packet to be picked up later by someone else. 19498f9ac44aSAlexander Motin * If the queue could be run now, add node to the queue handler's worklist. 1950859a4d16SJulian Elischer */ 1951069154d5SJulian Elischer static __inline void 19529852972bSAlexander Motin ng_queue_rw(node_p node, item_p item, int rw) 1953069154d5SJulian Elischer { 19549852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 19554be59335SGleb Smirnoff if (rw == NGQRW_W) 19564be59335SGleb Smirnoff NGI_SET_WRITER(item); 19574be59335SGleb Smirnoff else 19584be59335SGleb Smirnoff NGI_SET_READER(item); 1959394cb30aSAlexander Motin 1960394cb30aSAlexander Motin NG_QUEUE_LOCK(ngq); 1961394cb30aSAlexander Motin /* Set OP_PENDING flag and enqueue the item. */ 19629852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 19639852972bSAlexander Motin STAILQ_INSERT_TAIL(&ngq->queue, item, el_next); 1964394cb30aSAlexander Motin 19652955ee18SGleb Smirnoff CTR5(KTR_NET, "%20s: node [%x] (%p) queued item %p as %s", __func__, 19669852972bSAlexander Motin node->nd_ID, node, item, rw ? "WRITER" : "READER" ); 19674be59335SGleb Smirnoff 19684be59335SGleb Smirnoff /* 19694be59335SGleb Smirnoff * We can take the worklist lock with the node locked 19704be59335SGleb Smirnoff * BUT NOT THE REVERSE! 19714be59335SGleb Smirnoff */ 19724be59335SGleb Smirnoff if (NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 19739852972bSAlexander Motin ng_worklist_add(node); 1974394cb30aSAlexander Motin NG_QUEUE_UNLOCK(ngq); 1975069154d5SJulian Elischer } 1976069154d5SJulian Elischer 19778f9ac44aSAlexander Motin /* Acquire reader lock on node. If node is busy, queue the packet. */ 1978069154d5SJulian Elischer static __inline item_p 19799852972bSAlexander Motin ng_acquire_read(node_p node, item_p item) 1980069154d5SJulian Elischer { 19819852972bSAlexander Motin KASSERT(node != &ng_deadnode, 1982ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 1983069154d5SJulian Elischer 1984394cb30aSAlexander Motin /* Reader needs node without writer and pending items. */ 1985394cb30aSAlexander Motin while (1) { 19869852972bSAlexander Motin long t = node->nd_input_queue.q_flags; 1987394cb30aSAlexander Motin if (t & NGQ_RMASK) 1988394cb30aSAlexander Motin break; /* Node is not ready for reader. */ 19899852972bSAlexander Motin if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 19909852972bSAlexander Motin t, t + READER_INCREMENT)) { 1991069154d5SJulian Elischer /* Successfully grabbed node */ 1992394cb30aSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 19939852972bSAlexander Motin __func__, node->nd_ID, node, item); 1994069154d5SJulian Elischer return (item); 1995069154d5SJulian Elischer } 1996394cb30aSAlexander Motin cpu_spinwait(); 1997394cb30aSAlexander Motin }; 1998069154d5SJulian Elischer 1999394cb30aSAlexander Motin /* Queue the request for later. */ 20009852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_R); 2001f912c0f7SGleb Smirnoff 2002f912c0f7SGleb Smirnoff return (NULL); 2003069154d5SJulian Elischer } 2004069154d5SJulian Elischer 20058f9ac44aSAlexander Motin /* Acquire writer lock on node. If node is busy, queue the packet. */ 2006069154d5SJulian Elischer static __inline item_p 20079852972bSAlexander Motin ng_acquire_write(node_p node, item_p item) 2008069154d5SJulian Elischer { 20099852972bSAlexander Motin KASSERT(node != &ng_deadnode, 2010ac5dd141SGleb Smirnoff ("%s: working on deadnode", __func__)); 2011ac5dd141SGleb Smirnoff 2012394cb30aSAlexander Motin /* Writer needs completely idle node. */ 20139852972bSAlexander Motin if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags, 20149852972bSAlexander Motin 0, WRITER_ACTIVE)) { 2015394cb30aSAlexander Motin /* Successfully grabbed node */ 20162955ee18SGleb Smirnoff CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p", 20179852972bSAlexander Motin __func__, node->nd_ID, node, item); 2018069154d5SJulian Elischer return (item); 2019069154d5SJulian Elischer } 2020069154d5SJulian Elischer 2021394cb30aSAlexander Motin /* Queue the request for later. */ 20229852972bSAlexander Motin ng_queue_rw(node, item, NGQRW_W); 2023f912c0f7SGleb Smirnoff 2024f912c0f7SGleb Smirnoff return (NULL); 2025069154d5SJulian Elischer } 2026069154d5SJulian Elischer 2027262dfd7fSJulian Elischer #if 0 2028262dfd7fSJulian Elischer static __inline item_p 20299852972bSAlexander Motin ng_upgrade_write(node_p node, item_p item) 2030262dfd7fSJulian Elischer { 20319852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 20329852972bSAlexander Motin KASSERT(node != &ng_deadnode, 2033262dfd7fSJulian Elischer ("%s: working on deadnode", __func__)); 2034262dfd7fSJulian Elischer 2035262dfd7fSJulian Elischer NGI_SET_WRITER(item); 2036262dfd7fSJulian Elischer 20379852972bSAlexander Motin NG_QUEUE_LOCK(ngq); 2038262dfd7fSJulian Elischer 2039262dfd7fSJulian Elischer /* 2040262dfd7fSJulian Elischer * There will never be no readers as we are there ourselves. 2041262dfd7fSJulian Elischer * Set the WRITER_ACTIVE flags ASAP to block out fast track readers. 2042262dfd7fSJulian Elischer * The caller we are running from will call ng_leave_read() 2043262dfd7fSJulian Elischer * soon, so we must account for that. We must leave again with the 2044262dfd7fSJulian Elischer * READER lock. If we find other readers, then 2045262dfd7fSJulian Elischer * queue the request for later. However "later" may be rignt now 2046262dfd7fSJulian Elischer * if there are no readers. We don't really care if there are queued 2047262dfd7fSJulian Elischer * items as we will bypass them anyhow. 2048262dfd7fSJulian Elischer */ 20499852972bSAlexander Motin atomic_add_int(&ngq->q_flags, WRITER_ACTIVE - READER_INCREMENT); 20509852972bSAlexander Motin if ((ngq->q_flags & (NGQ_WMASK & ~OP_PENDING)) == WRITER_ACTIVE) { 20519852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2052262dfd7fSJulian Elischer 2053262dfd7fSJulian Elischer /* It's just us, act on the item. */ 2054262dfd7fSJulian Elischer /* will NOT drop writer lock when done */ 2055262dfd7fSJulian Elischer ng_apply_item(node, item, 0); 2056262dfd7fSJulian Elischer 2057262dfd7fSJulian Elischer /* 2058262dfd7fSJulian Elischer * Having acted on the item, atomically 2059262dfd7fSJulian Elischer * down grade back to READER and finish up 2060262dfd7fSJulian Elischer */ 20619852972bSAlexander Motin atomic_add_int(&ngq->q_flags, 2062262dfd7fSJulian Elischer READER_INCREMENT - WRITER_ACTIVE); 2063262dfd7fSJulian Elischer 2064262dfd7fSJulian Elischer /* Our caller will call ng_leave_read() */ 2065262dfd7fSJulian Elischer return; 2066262dfd7fSJulian Elischer } 2067262dfd7fSJulian Elischer /* 2068262dfd7fSJulian Elischer * It's not just us active, so queue us AT THE HEAD. 2069262dfd7fSJulian Elischer * "Why?" I hear you ask. 2070262dfd7fSJulian Elischer * Put us at the head of the queue as we've already been 2071262dfd7fSJulian Elischer * through it once. If there is nothing else waiting, 2072262dfd7fSJulian Elischer * set the correct flags. 2073262dfd7fSJulian Elischer */ 20749852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) { 2075262dfd7fSJulian Elischer /* We've gone from, 0 to 1 item in the queue */ 20769852972bSAlexander Motin atomic_set_int(&ngq->q_flags, OP_PENDING); 2077262dfd7fSJulian Elischer 2078262dfd7fSJulian Elischer CTR3(KTR_NET, "%20s: node [%x] (%p) set OP_PENDING", __func__, 20799852972bSAlexander Motin node->nd_ID, node); 2080262dfd7fSJulian Elischer }; 20819852972bSAlexander Motin STAILQ_INSERT_HEAD(&ngq->queue, item, el_next); 20829852972bSAlexander Motin CTR4(KTR_NET, "%20s: node [%x] (%p) requeued item %p as WRITER", 20839852972bSAlexander Motin __func__, node->nd_ID, node, item ); 2084262dfd7fSJulian Elischer 2085262dfd7fSJulian Elischer /* Reverse what we did above. That downgrades us back to reader */ 20869852972bSAlexander Motin atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE); 2087394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 20889852972bSAlexander Motin ng_worklist_add(node); 20899852972bSAlexander Motin NG_QUEUE_UNLOCK(ngq); 2090262dfd7fSJulian Elischer 2091262dfd7fSJulian Elischer return; 2092262dfd7fSJulian Elischer } 2093262dfd7fSJulian Elischer #endif 2094262dfd7fSJulian Elischer 20958f9ac44aSAlexander Motin /* Release reader lock. */ 2096069154d5SJulian Elischer static __inline void 20979852972bSAlexander Motin ng_leave_read(node_p node) 2098069154d5SJulian Elischer { 20999852972bSAlexander Motin atomic_subtract_rel_int(&node->nd_input_queue.q_flags, READER_INCREMENT); 2100069154d5SJulian Elischer } 2101069154d5SJulian Elischer 21028f9ac44aSAlexander Motin /* Release writer lock. */ 2103069154d5SJulian Elischer static __inline void 21049852972bSAlexander Motin ng_leave_write(node_p node) 2105069154d5SJulian Elischer { 21069852972bSAlexander Motin atomic_clear_rel_int(&node->nd_input_queue.q_flags, WRITER_ACTIVE); 2107069154d5SJulian Elischer } 2108069154d5SJulian Elischer 21098f9ac44aSAlexander Motin /* Purge node queue. Called on node shutdown. */ 2110069154d5SJulian Elischer static void 21119852972bSAlexander Motin ng_flush_input_queue(node_p node) 2112069154d5SJulian Elischer { 21139852972bSAlexander Motin struct ng_queue *ngq = &node->nd_input_queue; 2114069154d5SJulian Elischer item_p item; 2115069154d5SJulian Elischer 21162c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 21179852972bSAlexander Motin while ((item = STAILQ_FIRST(&ngq->queue)) != NULL) { 21189852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ngq->queue, el_next); 21199852972bSAlexander Motin if (STAILQ_EMPTY(&ngq->queue)) 21209852972bSAlexander Motin atomic_clear_int(&ngq->q_flags, OP_PENDING); 21212c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 21224be59335SGleb Smirnoff 21234be59335SGleb Smirnoff /* If the item is supplying a callback, call it with an error */ 212410e87318SAlexander Motin if (item->apply != NULL) { 212510e87318SAlexander Motin if (item->depth == 1) 212610e87318SAlexander Motin item->apply->error = ENOENT; 212710e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 212810e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 212910e87318SAlexander Motin item->apply->error); 213010e87318SAlexander Motin } 2131eb2405ddSGleb Smirnoff } 2132505fad52SJulian Elischer NG_FREE_ITEM(item); 21332c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2134069154d5SJulian Elischer } 21352c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2136069154d5SJulian Elischer } 2137069154d5SJulian Elischer 2138069154d5SJulian Elischer /*********************************************************************** 2139069154d5SJulian Elischer * Externally visible method for sending or queueing messages or data. 2140069154d5SJulian Elischer ***********************************************************************/ 2141069154d5SJulian Elischer 2142069154d5SJulian Elischer /* 21431acb27c6SJulian Elischer * The module code should have filled out the item correctly by this stage: 2144069154d5SJulian Elischer * Common: 2145069154d5SJulian Elischer * reference to destination node. 2146069154d5SJulian Elischer * Reference to destination rcv hook if relevant. 2147e088dd4cSAlexander Motin * apply pointer must be or NULL or reference valid struct ng_apply_info. 2148069154d5SJulian Elischer * Data: 2149069154d5SJulian Elischer * pointer to mbuf 2150069154d5SJulian Elischer * Control_Message: 2151069154d5SJulian Elischer * pointer to msg. 2152069154d5SJulian Elischer * ID of original sender node. (return address) 21531acb27c6SJulian Elischer * Function: 21541acb27c6SJulian Elischer * Function pointer 21551acb27c6SJulian Elischer * void * argument 21561acb27c6SJulian Elischer * integer argument 2157069154d5SJulian Elischer * 2158069154d5SJulian Elischer * The nodes have several routines and macros to help with this task: 2159069154d5SJulian Elischer */ 2160069154d5SJulian Elischer 2161069154d5SJulian Elischer int 216242282202SGleb Smirnoff ng_snd_item(item_p item, int flags) 2163069154d5SJulian Elischer { 2164e088dd4cSAlexander Motin hook_p hook; 2165e088dd4cSAlexander Motin node_p node; 216642282202SGleb Smirnoff int queue, rw; 2167e088dd4cSAlexander Motin struct ng_queue *ngq; 216832b33288SGleb Smirnoff int error = 0; 2169069154d5SJulian Elischer 2170f50597f5SAlexander Motin /* We are sending item, so it must be present! */ 2171f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_snd_item: item is NULL")); 2172e088dd4cSAlexander Motin 2173e088dd4cSAlexander Motin #ifdef NETGRAPH_DEBUG 2174e088dd4cSAlexander Motin _ngi_check(item, __FILE__, __LINE__); 2175e088dd4cSAlexander Motin #endif 2176e088dd4cSAlexander Motin 2177f50597f5SAlexander Motin /* Item was sent once more, postpone apply() call. */ 2178e088dd4cSAlexander Motin if (item->apply) 2179e088dd4cSAlexander Motin refcount_acquire(&item->apply->refs); 2180e088dd4cSAlexander Motin 2181e088dd4cSAlexander Motin node = NGI_NODE(item); 2182f50597f5SAlexander Motin /* Node is never optional. */ 2183f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_snd_item: node is NULL")); 2184e088dd4cSAlexander Motin 2185e72a98f4SAlexander Motin hook = NGI_HOOK(item); 2186f50597f5SAlexander Motin /* Valid hook and mbuf are mandatory for data. */ 2187f50597f5SAlexander Motin if ((item->el_flags & NGQF_TYPE) == NGQF_DATA) { 2188f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_snd_item: hook for data is NULL")); 218910204449SJulian Elischer if (NGI_M(item) == NULL) 2190e088dd4cSAlexander Motin ERROUT(EINVAL); 2191069154d5SJulian Elischer CHECK_DATA_MBUF(NGI_M(item)); 21926f683eeeSGleb Smirnoff } 21936f683eeeSGleb Smirnoff 2194069154d5SJulian Elischer /* 2195f50597f5SAlexander Motin * If the item or the node specifies single threading, force 2196f50597f5SAlexander Motin * writer semantics. Similarly, the node may say one hook always 2197f50597f5SAlexander Motin * produces writers. These are overrides. 2198069154d5SJulian Elischer */ 2199db3408aeSAlexander Motin if (((item->el_flags & NGQF_RW) == NGQF_WRITER) || 2200f50597f5SAlexander Motin (node->nd_flags & NGF_FORCE_WRITER) || 2201f50597f5SAlexander Motin (hook && (hook->hk_flags & HK_FORCE_WRITER))) { 2202069154d5SJulian Elischer rw = NGQRW_W; 2203f50597f5SAlexander Motin } else { 2204f50597f5SAlexander Motin rw = NGQRW_R; 2205f50597f5SAlexander Motin } 22066f683eeeSGleb Smirnoff 220781a253a4SAlexander Motin /* 220881a253a4SAlexander Motin * If sender or receiver requests queued delivery or stack usage 220981a253a4SAlexander Motin * level is dangerous - enqueue message. 221081a253a4SAlexander Motin */ 221181a253a4SAlexander Motin if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) { 221281a253a4SAlexander Motin queue = 1; 2213f50597f5SAlexander Motin } else { 2214f50597f5SAlexander Motin queue = 0; 221581a253a4SAlexander Motin #ifdef GET_STACK_USAGE 2216d4529f98SAlexander Motin /* 2217942fe01fSDmitry Morozovsky * Most of netgraph nodes have small stack consumption and 2218f50597f5SAlexander Motin * for them 25% of free stack space is more than enough. 2219d4529f98SAlexander Motin * Nodes/hooks with higher stack usage should be marked as 2220f9773372SDmitry Morozovsky * HI_STACK. For them 50% of stack will be guaranteed then. 2221f50597f5SAlexander Motin * XXX: Values 25% and 50% are completely empirical. 2222d4529f98SAlexander Motin */ 2223f50597f5SAlexander Motin size_t st, su, sl; 222481a253a4SAlexander Motin GET_STACK_USAGE(st, su); 2225f50597f5SAlexander Motin sl = st - su; 2226f50597f5SAlexander Motin if ((sl * 4 < st) || 2227f50597f5SAlexander Motin ((sl * 2 < st) && ((node->nd_flags & NGF_HI_STACK) || 222881a253a4SAlexander Motin (hook && (hook->hk_flags & HK_HI_STACK))))) { 222981a253a4SAlexander Motin queue = 1; 223081a253a4SAlexander Motin } 223181a253a4SAlexander Motin #endif 2232f50597f5SAlexander Motin } 223381a253a4SAlexander Motin 2234069154d5SJulian Elischer if (queue) { 223510e87318SAlexander Motin item->depth = 1; 2236394cb30aSAlexander Motin /* Put it on the queue for that node*/ 22379852972bSAlexander Motin ng_queue_rw(node, item, rw); 2238f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2239069154d5SJulian Elischer } 2240069154d5SJulian Elischer 2241069154d5SJulian Elischer /* 2242069154d5SJulian Elischer * We already decided how we will be queueud or treated. 2243069154d5SJulian Elischer * Try get the appropriate operating permission. 2244069154d5SJulian Elischer */ 224532b33288SGleb Smirnoff if (rw == NGQRW_R) 22469852972bSAlexander Motin item = ng_acquire_read(node, item); 224732b33288SGleb Smirnoff else 22489852972bSAlexander Motin item = ng_acquire_write(node, item); 22494cf49a43SJulian Elischer 2250f50597f5SAlexander Motin /* Item was queued while trying to get permission. */ 2251f50597f5SAlexander Motin if (item == NULL) 2252f50597f5SAlexander Motin return ((flags & NG_PROGRESS) ? EINPROGRESS : 0); 2253069154d5SJulian Elischer 22545951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 22555951069aSJulian Elischer 225610e87318SAlexander Motin item->depth++; 225727757487SGleb Smirnoff error = ng_apply_item(node, item, rw); /* drops r/w lock when done */ 2258069154d5SJulian Elischer 2259394cb30aSAlexander Motin /* If something is waiting on queue and ready, schedule it. */ 22609852972bSAlexander Motin ngq = &node->nd_input_queue; 2261394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq)) { 22622c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(ngq); 2263394cb30aSAlexander Motin if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq)) 22649852972bSAlexander Motin ng_worklist_add(node); 22652c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(ngq); 2266394cb30aSAlexander Motin } 2267394cb30aSAlexander Motin 2268394cb30aSAlexander Motin /* 2269394cb30aSAlexander Motin * Node may go away as soon as we remove the reference. 2270394cb30aSAlexander Motin * Whatever we do, DO NOT access the node again! 2271394cb30aSAlexander Motin */ 2272394cb30aSAlexander Motin NG_NODE_UNREF(node); 2273069154d5SJulian Elischer 22741acb27c6SJulian Elischer return (error); 2275e088dd4cSAlexander Motin 2276e088dd4cSAlexander Motin done: 2277f50597f5SAlexander Motin /* If was not sent, apply callback here. */ 227810e87318SAlexander Motin if (item->apply != NULL) { 227910e87318SAlexander Motin if (item->depth == 0 && error != 0) 228010e87318SAlexander Motin item->apply->error = error; 228110e87318SAlexander Motin if (refcount_release(&item->apply->refs)) { 228210e87318SAlexander Motin (*item->apply->apply)(item->apply->context, 228310e87318SAlexander Motin item->apply->error); 228410e87318SAlexander Motin } 228510e87318SAlexander Motin } 2286e72a98f4SAlexander Motin 2287e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2288e088dd4cSAlexander Motin return (error); 2289069154d5SJulian Elischer } 2290069154d5SJulian Elischer 2291069154d5SJulian Elischer /* 2292069154d5SJulian Elischer * We have an item that was possibly queued somewhere. 2293069154d5SJulian Elischer * It should contain all the information needed 2294069154d5SJulian Elischer * to run it on the appropriate node/hook. 2295e088dd4cSAlexander Motin * If there is apply pointer and we own the last reference, call apply(). 22964cf49a43SJulian Elischer */ 229727757487SGleb Smirnoff static int 2298714fb865SGleb Smirnoff ng_apply_item(node_p node, item_p item, int rw) 2299069154d5SJulian Elischer { 2300069154d5SJulian Elischer hook_p hook; 2301069154d5SJulian Elischer ng_rcvdata_t *rcvdata; 2302c4b5eea4SJulian Elischer ng_rcvmsg_t *rcvmsg; 2303e088dd4cSAlexander Motin struct ng_apply_info *apply; 230410e87318SAlexander Motin int error = 0, depth; 2305069154d5SJulian Elischer 2306f50597f5SAlexander Motin /* Node and item are never optional. */ 2307f50597f5SAlexander Motin KASSERT(node != NULL, ("ng_apply_item: node is NULL")); 2308f50597f5SAlexander Motin KASSERT(item != NULL, ("ng_apply_item: item is NULL")); 2309f50597f5SAlexander Motin 23101acb27c6SJulian Elischer NGI_GET_HOOK(item, hook); /* clears stored hook */ 231130400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 2312069154d5SJulian Elischer _ngi_check(item, __FILE__, __LINE__); 2313069154d5SJulian Elischer #endif 23148afe16d5SGleb Smirnoff 23158afe16d5SGleb Smirnoff apply = item->apply; 231610e87318SAlexander Motin depth = item->depth; 23178afe16d5SGleb Smirnoff 23186b795970SJulian Elischer switch (item->el_flags & NGQF_TYPE) { 2319069154d5SJulian Elischer case NGQF_DATA: 2320069154d5SJulian Elischer /* 2321069154d5SJulian Elischer * Check things are still ok as when we were queued. 2322069154d5SJulian Elischer */ 2323f50597f5SAlexander Motin KASSERT(hook != NULL, ("ng_apply_item: hook for data is NULL")); 2324f50597f5SAlexander Motin if (NG_HOOK_NOT_VALID(hook) || 2325f50597f5SAlexander Motin NG_NODE_NOT_VALID(node)) { 2326a54a69d7SJulian Elischer error = EIO; 2327069154d5SJulian Elischer NG_FREE_ITEM(item); 2328c4b5eea4SJulian Elischer break; 2329069154d5SJulian Elischer } 2330c4b5eea4SJulian Elischer /* 2331c4b5eea4SJulian Elischer * If no receive method, just silently drop it. 2332c4b5eea4SJulian Elischer * Give preference to the hook over-ride method 2333c4b5eea4SJulian Elischer */ 2334c4b5eea4SJulian Elischer if ((!(rcvdata = hook->hk_rcvdata)) 2335c4b5eea4SJulian Elischer && (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) { 2336c4b5eea4SJulian Elischer error = 0; 2337c4b5eea4SJulian Elischer NG_FREE_ITEM(item); 2338c4b5eea4SJulian Elischer break; 2339c4b5eea4SJulian Elischer } 2340a54a69d7SJulian Elischer error = (*rcvdata)(hook, item); 2341069154d5SJulian Elischer break; 2342069154d5SJulian Elischer case NGQF_MESG: 2343e72a98f4SAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook)) { 2344069154d5SJulian Elischer /* 2345e72a98f4SAlexander Motin * The hook has been zapped then we can't use it. 2346e72a98f4SAlexander Motin * Immediately drop its reference. 2347069154d5SJulian Elischer * The message may not need it. 2348069154d5SJulian Elischer */ 234930400f03SJulian Elischer NG_HOOK_UNREF(hook); 2350069154d5SJulian Elischer hook = NULL; 2351069154d5SJulian Elischer } 2352069154d5SJulian Elischer /* 2353069154d5SJulian Elischer * Similarly, if the node is a zombie there is 2354069154d5SJulian Elischer * nothing we can do with it, drop everything. 2355069154d5SJulian Elischer */ 235630400f03SJulian Elischer if (NG_NODE_NOT_VALID(node)) { 23576b795970SJulian Elischer TRAP_ERROR(); 2358a54a69d7SJulian Elischer error = EINVAL; 2359069154d5SJulian Elischer NG_FREE_ITEM(item); 2360e72a98f4SAlexander Motin break; 2361e72a98f4SAlexander Motin } 2362069154d5SJulian Elischer /* 2363069154d5SJulian Elischer * Call the appropriate message handler for the object. 2364069154d5SJulian Elischer * It is up to the message handler to free the message. 2365069154d5SJulian Elischer * If it's a generic message, handle it generically, 2366e72a98f4SAlexander Motin * otherwise call the type's message handler (if it exists). 2367069154d5SJulian Elischer * XXX (race). Remember that a queued message may 2368069154d5SJulian Elischer * reference a node or hook that has just been 2369069154d5SJulian Elischer * invalidated. It will exist as the queue code 2370069154d5SJulian Elischer * is holding a reference, but.. 2371069154d5SJulian Elischer */ 2372e72a98f4SAlexander Motin if ((NGI_MSG(item)->header.typecookie == NGM_GENERIC_COOKIE) && 2373e72a98f4SAlexander Motin ((NGI_MSG(item)->header.flags & NGF_RESP) == 0)) { 2374a54a69d7SJulian Elischer error = ng_generic_msg(node, item, hook); 2375c4b5eea4SJulian Elischer break; 2376c4b5eea4SJulian Elischer } 2377e72a98f4SAlexander Motin if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) && 2378e72a98f4SAlexander Motin (!(rcvmsg = node->nd_type->rcvmsg))) { 23796b795970SJulian Elischer TRAP_ERROR(); 2380a54a69d7SJulian Elischer error = 0; 2381069154d5SJulian Elischer NG_FREE_ITEM(item); 2382c4b5eea4SJulian Elischer break; 2383069154d5SJulian Elischer } 2384a54a69d7SJulian Elischer error = (*rcvmsg)(node, item, hook); 2385069154d5SJulian Elischer break; 23866b795970SJulian Elischer case NGQF_FN: 2387e088dd4cSAlexander Motin case NGQF_FN2: 2388e088dd4cSAlexander Motin /* 238974c9119dSAlexander Motin * In the case of the shutdown message we allow it to hit 2390e088dd4cSAlexander Motin * even if the node is invalid. 2391e088dd4cSAlexander Motin */ 239274c9119dSAlexander Motin if (NG_NODE_NOT_VALID(node) && 239374c9119dSAlexander Motin NGI_FN(item) != &ng_rmnode) { 2394e088dd4cSAlexander Motin TRAP_ERROR(); 2395e088dd4cSAlexander Motin error = EINVAL; 2396e088dd4cSAlexander Motin NG_FREE_ITEM(item); 2397e088dd4cSAlexander Motin break; 2398e088dd4cSAlexander Motin } 239974c9119dSAlexander Motin /* Same is about some internal functions and invalid hook. */ 240074c9119dSAlexander Motin if (hook && NG_HOOK_NOT_VALID(hook) && 240174c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part2 && 240274c9119dSAlexander Motin NGI_FN2(item) != &ng_con_part3 && 240374c9119dSAlexander Motin NGI_FN(item) != &ng_rmhook_part2) { 240474c9119dSAlexander Motin TRAP_ERROR(); 240574c9119dSAlexander Motin error = EINVAL; 240674c9119dSAlexander Motin NG_FREE_ITEM(item); 240774c9119dSAlexander Motin break; 240874c9119dSAlexander Motin } 240974c9119dSAlexander Motin 2410b332b91fSGleb Smirnoff if ((item->el_flags & NGQF_TYPE) == NGQF_FN) { 2411b332b91fSGleb Smirnoff (*NGI_FN(item))(node, hook, NGI_ARG1(item), 2412b332b91fSGleb Smirnoff NGI_ARG2(item)); 2413b332b91fSGleb Smirnoff NG_FREE_ITEM(item); 2414b332b91fSGleb Smirnoff } else /* it is NGQF_FN2 */ 2415e088dd4cSAlexander Motin error = (*NGI_FN2(item))(node, item, hook); 2416e088dd4cSAlexander Motin break; 2417069154d5SJulian Elischer } 2418069154d5SJulian Elischer /* 2419069154d5SJulian Elischer * We held references on some of the resources 2420069154d5SJulian Elischer * that we took from the item. Now that we have 2421069154d5SJulian Elischer * finished doing everything, drop those references. 2422069154d5SJulian Elischer */ 2423e72a98f4SAlexander Motin if (hook) 242430400f03SJulian Elischer NG_HOOK_UNREF(hook); 2425069154d5SJulian Elischer 2426f50597f5SAlexander Motin if (rw == NGQRW_R) 24279852972bSAlexander Motin ng_leave_read(node); 2428f50597f5SAlexander Motin else 24299852972bSAlexander Motin ng_leave_write(node); 24308afe16d5SGleb Smirnoff 24318afe16d5SGleb Smirnoff /* Apply callback. */ 243210e87318SAlexander Motin if (apply != NULL) { 243310e87318SAlexander Motin if (depth == 1 && error != 0) 243410e87318SAlexander Motin apply->error = error; 243510e87318SAlexander Motin if (refcount_release(&apply->refs)) 243610e87318SAlexander Motin (*apply->apply)(apply->context, apply->error); 243710e87318SAlexander Motin } 24388afe16d5SGleb Smirnoff 243927757487SGleb Smirnoff return (error); 2440069154d5SJulian Elischer } 2441069154d5SJulian Elischer 2442069154d5SJulian Elischer /*********************************************************************** 2443069154d5SJulian Elischer * Implement the 'generic' control messages 2444069154d5SJulian Elischer ***********************************************************************/ 2445069154d5SJulian Elischer static int 2446069154d5SJulian Elischer ng_generic_msg(node_p here, item_p item, hook_p lasthook) 24474cf49a43SJulian Elischer { 24488b615593SMarko Zec INIT_VNET_NETGRAPH(curvnet); 24494cf49a43SJulian Elischer int error = 0; 2450069154d5SJulian Elischer struct ng_mesg *msg; 2451069154d5SJulian Elischer struct ng_mesg *resp = NULL; 24524cf49a43SJulian Elischer 2453069154d5SJulian Elischer NGI_GET_MSG(item, msg); 24544cf49a43SJulian Elischer if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 24556b795970SJulian Elischer TRAP_ERROR(); 2456069154d5SJulian Elischer error = EINVAL; 2457069154d5SJulian Elischer goto out; 24584cf49a43SJulian Elischer } 24594cf49a43SJulian Elischer switch (msg->header.cmd) { 24604cf49a43SJulian Elischer case NGM_SHUTDOWN: 24611acb27c6SJulian Elischer ng_rmnode(here, NULL, NULL, 0); 24624cf49a43SJulian Elischer break; 24634cf49a43SJulian Elischer case NGM_MKPEER: 24644cf49a43SJulian Elischer { 24654cf49a43SJulian Elischer struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 24664cf49a43SJulian Elischer 24674cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*mkp)) { 24686b795970SJulian Elischer TRAP_ERROR(); 2469069154d5SJulian Elischer error = EINVAL; 2470069154d5SJulian Elischer break; 24714cf49a43SJulian Elischer } 24724cf49a43SJulian Elischer mkp->type[sizeof(mkp->type) - 1] = '\0'; 24734cf49a43SJulian Elischer mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 24744cf49a43SJulian Elischer mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 24754cf49a43SJulian Elischer error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 24764cf49a43SJulian Elischer break; 24774cf49a43SJulian Elischer } 24784cf49a43SJulian Elischer case NGM_CONNECT: 24794cf49a43SJulian Elischer { 24804cf49a43SJulian Elischer struct ngm_connect *const con = 24814cf49a43SJulian Elischer (struct ngm_connect *) msg->data; 24824cf49a43SJulian Elischer node_p node2; 24834cf49a43SJulian Elischer 24844cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*con)) { 24856b795970SJulian Elischer TRAP_ERROR(); 2486069154d5SJulian Elischer error = EINVAL; 2487069154d5SJulian Elischer break; 24884cf49a43SJulian Elischer } 24894cf49a43SJulian Elischer con->path[sizeof(con->path) - 1] = '\0'; 24904cf49a43SJulian Elischer con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 24914cf49a43SJulian Elischer con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 2492069154d5SJulian Elischer /* Don't forget we get a reference.. */ 2493069154d5SJulian Elischer error = ng_path2noderef(here, con->path, &node2, NULL); 24944cf49a43SJulian Elischer if (error) 24954cf49a43SJulian Elischer break; 2496e088dd4cSAlexander Motin error = ng_con_nodes(item, here, con->ourhook, 2497e088dd4cSAlexander Motin node2, con->peerhook); 249830400f03SJulian Elischer NG_NODE_UNREF(node2); 24994cf49a43SJulian Elischer break; 25004cf49a43SJulian Elischer } 25014cf49a43SJulian Elischer case NGM_NAME: 25024cf49a43SJulian Elischer { 25034cf49a43SJulian Elischer struct ngm_name *const nam = (struct ngm_name *) msg->data; 25044cf49a43SJulian Elischer 25054cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*nam)) { 25066b795970SJulian Elischer TRAP_ERROR(); 2507069154d5SJulian Elischer error = EINVAL; 2508069154d5SJulian Elischer break; 25094cf49a43SJulian Elischer } 25104cf49a43SJulian Elischer nam->name[sizeof(nam->name) - 1] = '\0'; 25114cf49a43SJulian Elischer error = ng_name_node(here, nam->name); 25124cf49a43SJulian Elischer break; 25134cf49a43SJulian Elischer } 25144cf49a43SJulian Elischer case NGM_RMHOOK: 25154cf49a43SJulian Elischer { 25164cf49a43SJulian Elischer struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 25174cf49a43SJulian Elischer hook_p hook; 25184cf49a43SJulian Elischer 25194cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*rmh)) { 25206b795970SJulian Elischer TRAP_ERROR(); 2521069154d5SJulian Elischer error = EINVAL; 2522069154d5SJulian Elischer break; 25234cf49a43SJulian Elischer } 25244cf49a43SJulian Elischer rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 2525899e9c4eSArchie Cobbs if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 25264cf49a43SJulian Elischer ng_destroy_hook(hook); 25274cf49a43SJulian Elischer break; 25284cf49a43SJulian Elischer } 25294cf49a43SJulian Elischer case NGM_NODEINFO: 25304cf49a43SJulian Elischer { 25314cf49a43SJulian Elischer struct nodeinfo *ni; 25324cf49a43SJulian Elischer 2533069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT); 25344cf49a43SJulian Elischer if (resp == NULL) { 25354cf49a43SJulian Elischer error = ENOMEM; 25364cf49a43SJulian Elischer break; 25374cf49a43SJulian Elischer } 25384cf49a43SJulian Elischer 25394cf49a43SJulian Elischer /* Fill in node info */ 2540069154d5SJulian Elischer ni = (struct nodeinfo *) resp->data; 254130400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 254287e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 254387e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2544dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 254530400f03SJulian Elischer ni->hooks = here->nd_numhooks; 25464cf49a43SJulian Elischer break; 25474cf49a43SJulian Elischer } 25484cf49a43SJulian Elischer case NGM_LISTHOOKS: 25494cf49a43SJulian Elischer { 255030400f03SJulian Elischer const int nhooks = here->nd_numhooks; 25514cf49a43SJulian Elischer struct hooklist *hl; 25524cf49a43SJulian Elischer struct nodeinfo *ni; 25534cf49a43SJulian Elischer hook_p hook; 25544cf49a43SJulian Elischer 25554cf49a43SJulian Elischer /* Get response struct */ 2556069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*hl) 25574cf49a43SJulian Elischer + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 2558069154d5SJulian Elischer if (resp == NULL) { 25594cf49a43SJulian Elischer error = ENOMEM; 25604cf49a43SJulian Elischer break; 25614cf49a43SJulian Elischer } 2562069154d5SJulian Elischer hl = (struct hooklist *) resp->data; 25634cf49a43SJulian Elischer ni = &hl->nodeinfo; 25644cf49a43SJulian Elischer 25654cf49a43SJulian Elischer /* Fill in node info */ 256630400f03SJulian Elischer if (NG_NODE_HAS_NAME(here)) 256787e2c66aSHartmut Brandt strcpy(ni->name, NG_NODE_NAME(here)); 256887e2c66aSHartmut Brandt strcpy(ni->type, here->nd_type->name); 2569dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 25704cf49a43SJulian Elischer 25714cf49a43SJulian Elischer /* Cycle through the linked list of hooks */ 25724cf49a43SJulian Elischer ni->hooks = 0; 257330400f03SJulian Elischer LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) { 25744cf49a43SJulian Elischer struct linkinfo *const link = &hl->link[ni->hooks]; 25754cf49a43SJulian Elischer 25764cf49a43SJulian Elischer if (ni->hooks >= nhooks) { 25774cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 25786e551fb6SDavid E. O'Brien __func__, "hooks"); 25794cf49a43SJulian Elischer break; 25804cf49a43SJulian Elischer } 258130400f03SJulian Elischer if (NG_HOOK_NOT_VALID(hook)) 25824cf49a43SJulian Elischer continue; 258387e2c66aSHartmut Brandt strcpy(link->ourhook, NG_HOOK_NAME(hook)); 258487e2c66aSHartmut Brandt strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook)); 258530400f03SJulian Elischer if (NG_PEER_NODE_NAME(hook)[0] != '\0') 258687e2c66aSHartmut Brandt strcpy(link->nodeinfo.name, 258787e2c66aSHartmut Brandt NG_PEER_NODE_NAME(hook)); 258887e2c66aSHartmut Brandt strcpy(link->nodeinfo.type, 258987e2c66aSHartmut Brandt NG_PEER_NODE(hook)->nd_type->name); 259030400f03SJulian Elischer link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook)); 259130400f03SJulian Elischer link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks; 25924cf49a43SJulian Elischer ni->hooks++; 25934cf49a43SJulian Elischer } 25944cf49a43SJulian Elischer break; 25954cf49a43SJulian Elischer } 25964cf49a43SJulian Elischer 25974cf49a43SJulian Elischer case NGM_LISTNAMES: 25984cf49a43SJulian Elischer case NGM_LISTNODES: 25994cf49a43SJulian Elischer { 26004cf49a43SJulian Elischer const int unnamed = (msg->header.cmd == NGM_LISTNODES); 26014cf49a43SJulian Elischer struct namelist *nl; 26024cf49a43SJulian Elischer node_p node; 2603cfea3f85SAlexander Motin int num = 0, i; 26044cf49a43SJulian Elischer 2605cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 26064cf49a43SJulian Elischer /* Count number of nodes */ 2607cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2608603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2609cfea3f85SAlexander Motin if (NG_NODE_IS_VALID(node) && 2610cfea3f85SAlexander Motin (unnamed || NG_NODE_HAS_NAME(node))) { 26114cf49a43SJulian Elischer num++; 26124cf49a43SJulian Elischer } 261370de87f2SJulian Elischer } 2614cfea3f85SAlexander Motin } 2615cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 26164cf49a43SJulian Elischer 26174cf49a43SJulian Elischer /* Get response struct */ 2618069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*nl) 26194cf49a43SJulian Elischer + (num * sizeof(struct nodeinfo)), M_NOWAIT); 2620069154d5SJulian Elischer if (resp == NULL) { 26214cf49a43SJulian Elischer error = ENOMEM; 26224cf49a43SJulian Elischer break; 26234cf49a43SJulian Elischer } 2624069154d5SJulian Elischer nl = (struct namelist *) resp->data; 26254cf49a43SJulian Elischer 26264cf49a43SJulian Elischer /* Cycle through the linked list of nodes */ 26274cf49a43SJulian Elischer nl->numnames = 0; 2628cfea3f85SAlexander Motin mtx_lock(&ng_namehash_mtx); 2629cfea3f85SAlexander Motin for (i = 0; i < NG_NAME_HASH_SIZE; i++) { 2630603724d3SBjoern A. Zeeb LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) { 2631cfea3f85SAlexander Motin struct nodeinfo *const np = 2632cfea3f85SAlexander Motin &nl->nodeinfo[nl->numnames]; 26334cf49a43SJulian Elischer 2634b96baf0aSGleb Smirnoff if (NG_NODE_NOT_VALID(node)) 2635b96baf0aSGleb Smirnoff continue; 2636b96baf0aSGleb Smirnoff if (!unnamed && (! NG_NODE_HAS_NAME(node))) 2637b96baf0aSGleb Smirnoff continue; 26384cf49a43SJulian Elischer if (nl->numnames >= num) { 2639cfea3f85SAlexander Motin log(LOG_ERR, "%s: number of nodes changed\n", 2640cfea3f85SAlexander Motin __func__); 26414cf49a43SJulian Elischer break; 26424cf49a43SJulian Elischer } 264330400f03SJulian Elischer if (NG_NODE_HAS_NAME(node)) 264487e2c66aSHartmut Brandt strcpy(np->name, NG_NODE_NAME(node)); 264587e2c66aSHartmut Brandt strcpy(np->type, node->nd_type->name); 2646dc90cad9SJulian Elischer np->id = ng_node2ID(node); 264730400f03SJulian Elischer np->hooks = node->nd_numhooks; 26484cf49a43SJulian Elischer nl->numnames++; 26494cf49a43SJulian Elischer } 2650cfea3f85SAlexander Motin } 2651cfea3f85SAlexander Motin mtx_unlock(&ng_namehash_mtx); 26524cf49a43SJulian Elischer break; 26534cf49a43SJulian Elischer } 26544cf49a43SJulian Elischer 26554cf49a43SJulian Elischer case NGM_LISTTYPES: 26564cf49a43SJulian Elischer { 26574cf49a43SJulian Elischer struct typelist *tl; 26584cf49a43SJulian Elischer struct ng_type *type; 26594cf49a43SJulian Elischer int num = 0; 26604cf49a43SJulian Elischer 26619ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 26624cf49a43SJulian Elischer /* Count number of types */ 266370de87f2SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 26644cf49a43SJulian Elischer num++; 266570de87f2SJulian Elischer } 26669ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 26674cf49a43SJulian Elischer 26684cf49a43SJulian Elischer /* Get response struct */ 2669069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*tl) 26704cf49a43SJulian Elischer + (num * sizeof(struct typeinfo)), M_NOWAIT); 2671069154d5SJulian Elischer if (resp == NULL) { 26724cf49a43SJulian Elischer error = ENOMEM; 26734cf49a43SJulian Elischer break; 26744cf49a43SJulian Elischer } 2675069154d5SJulian Elischer tl = (struct typelist *) resp->data; 26764cf49a43SJulian Elischer 26774cf49a43SJulian Elischer /* Cycle through the linked list of types */ 26784cf49a43SJulian Elischer tl->numtypes = 0; 26799ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 2680069154d5SJulian Elischer LIST_FOREACH(type, &ng_typelist, types) { 26814cf49a43SJulian Elischer struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 26824cf49a43SJulian Elischer 26834cf49a43SJulian Elischer if (tl->numtypes >= num) { 26844cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 26856e551fb6SDavid E. O'Brien __func__, "types"); 26864cf49a43SJulian Elischer break; 26874cf49a43SJulian Elischer } 268887e2c66aSHartmut Brandt strcpy(tp->type_name, type->name); 2689c73b94a2SJulian Elischer tp->numnodes = type->refs - 1; /* don't count list */ 26904cf49a43SJulian Elischer tl->numtypes++; 26914cf49a43SJulian Elischer } 26929ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 26934cf49a43SJulian Elischer break; 26944cf49a43SJulian Elischer } 26954cf49a43SJulian Elischer 2696f8307e12SArchie Cobbs case NGM_BINARY2ASCII: 2697f8307e12SArchie Cobbs { 26987133ac27SArchie Cobbs int bufSize = 20 * 1024; /* XXX hard coded constant */ 2699f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2700f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2701069154d5SJulian Elischer struct ng_mesg *binary, *ascii; 2702f8307e12SArchie Cobbs 2703f8307e12SArchie Cobbs /* Data area must contain a valid netgraph message */ 2704f8307e12SArchie Cobbs binary = (struct ng_mesg *)msg->data; 27054c9b5910SGleb Smirnoff if (msg->header.arglen < sizeof(struct ng_mesg) || 27064c9b5910SGleb Smirnoff (msg->header.arglen - sizeof(struct ng_mesg) < 27074c9b5910SGleb Smirnoff binary->header.arglen)) { 27086b795970SJulian Elischer TRAP_ERROR(); 2709f8307e12SArchie Cobbs error = EINVAL; 2710f8307e12SArchie Cobbs break; 2711f8307e12SArchie Cobbs } 2712f8307e12SArchie Cobbs 2713f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2714069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 2715069154d5SJulian Elischer if (resp == NULL) { 2716f8307e12SArchie Cobbs error = ENOMEM; 2717f8307e12SArchie Cobbs break; 2718f8307e12SArchie Cobbs } 2719069154d5SJulian Elischer ascii = (struct ng_mesg *)resp->data; 2720f8307e12SArchie Cobbs 2721f8307e12SArchie Cobbs /* Copy binary message header to response message payload */ 2722f8307e12SArchie Cobbs bcopy(binary, ascii, sizeof(*binary)); 2723f8307e12SArchie Cobbs 2724f8307e12SArchie Cobbs /* Find command by matching typecookie and command number */ 272530400f03SJulian Elischer for (c = here->nd_type->cmdlist; 2726f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 2727f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 2728f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 2729f8307e12SArchie Cobbs break; 2730f8307e12SArchie Cobbs } 2731f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2732f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 2733f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 2734f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 2735f8307e12SArchie Cobbs break; 2736f8307e12SArchie Cobbs } 2737f8307e12SArchie Cobbs if (c->name == NULL) { 2738069154d5SJulian Elischer NG_FREE_MSG(resp); 2739f8307e12SArchie Cobbs error = ENOSYS; 2740f8307e12SArchie Cobbs break; 2741f8307e12SArchie Cobbs } 2742f8307e12SArchie Cobbs } 2743f8307e12SArchie Cobbs 2744f8307e12SArchie Cobbs /* Convert command name to ASCII */ 2745f8307e12SArchie Cobbs snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 2746f8307e12SArchie Cobbs "%s", c->name); 2747f8307e12SArchie Cobbs 2748f8307e12SArchie Cobbs /* Convert command arguments to ASCII */ 2749f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2750f8307e12SArchie Cobbs c->respType : c->mesgType; 275170de87f2SJulian Elischer if (argstype == NULL) { 2752f8307e12SArchie Cobbs *ascii->data = '\0'; 275370de87f2SJulian Elischer } else { 2754f8307e12SArchie Cobbs if ((error = ng_unparse(argstype, 2755f8307e12SArchie Cobbs (u_char *)binary->data, 2756f8307e12SArchie Cobbs ascii->data, bufSize)) != 0) { 2757069154d5SJulian Elischer NG_FREE_MSG(resp); 2758f8307e12SArchie Cobbs break; 2759f8307e12SArchie Cobbs } 2760f8307e12SArchie Cobbs } 2761f8307e12SArchie Cobbs 2762f8307e12SArchie Cobbs /* Return the result as struct ng_mesg plus ASCII string */ 2763f8307e12SArchie Cobbs bufSize = strlen(ascii->data) + 1; 2764f8307e12SArchie Cobbs ascii->header.arglen = bufSize; 2765069154d5SJulian Elischer resp->header.arglen = sizeof(*ascii) + bufSize; 2766f8307e12SArchie Cobbs break; 2767f8307e12SArchie Cobbs } 2768f8307e12SArchie Cobbs 2769f8307e12SArchie Cobbs case NGM_ASCII2BINARY: 2770f8307e12SArchie Cobbs { 2771f8307e12SArchie Cobbs int bufSize = 2000; /* XXX hard coded constant */ 2772f8307e12SArchie Cobbs const struct ng_cmdlist *c; 2773f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 2774069154d5SJulian Elischer struct ng_mesg *ascii, *binary; 277552ec4a03SArchie Cobbs int off = 0; 2776f8307e12SArchie Cobbs 2777f8307e12SArchie Cobbs /* Data area must contain at least a struct ng_mesg + '\0' */ 2778f8307e12SArchie Cobbs ascii = (struct ng_mesg *)msg->data; 27794c9b5910SGleb Smirnoff if ((msg->header.arglen < sizeof(*ascii) + 1) || 27804c9b5910SGleb Smirnoff (ascii->header.arglen < 1) || 27814c9b5910SGleb Smirnoff (msg->header.arglen < sizeof(*ascii) + 27824c9b5910SGleb Smirnoff ascii->header.arglen)) { 27836b795970SJulian Elischer TRAP_ERROR(); 2784f8307e12SArchie Cobbs error = EINVAL; 2785f8307e12SArchie Cobbs break; 2786f8307e12SArchie Cobbs } 2787f8307e12SArchie Cobbs ascii->data[ascii->header.arglen - 1] = '\0'; 2788f8307e12SArchie Cobbs 2789f8307e12SArchie Cobbs /* Get a response message with lots of room */ 2790069154d5SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 2791069154d5SJulian Elischer if (resp == NULL) { 2792f8307e12SArchie Cobbs error = ENOMEM; 2793f8307e12SArchie Cobbs break; 2794f8307e12SArchie Cobbs } 2795069154d5SJulian Elischer binary = (struct ng_mesg *)resp->data; 2796f8307e12SArchie Cobbs 2797f8307e12SArchie Cobbs /* Copy ASCII message header to response message payload */ 2798f8307e12SArchie Cobbs bcopy(ascii, binary, sizeof(*ascii)); 2799f8307e12SArchie Cobbs 2800f8307e12SArchie Cobbs /* Find command by matching ASCII command string */ 280130400f03SJulian Elischer for (c = here->nd_type->cmdlist; 2802f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 2803f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2804f8307e12SArchie Cobbs break; 2805f8307e12SArchie Cobbs } 2806f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 2807f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 2808f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 2809f8307e12SArchie Cobbs break; 2810f8307e12SArchie Cobbs } 2811f8307e12SArchie Cobbs if (c->name == NULL) { 2812069154d5SJulian Elischer NG_FREE_MSG(resp); 2813f8307e12SArchie Cobbs error = ENOSYS; 2814f8307e12SArchie Cobbs break; 2815f8307e12SArchie Cobbs } 2816f8307e12SArchie Cobbs } 2817f8307e12SArchie Cobbs 2818f8307e12SArchie Cobbs /* Convert command name to binary */ 2819f8307e12SArchie Cobbs binary->header.cmd = c->cmd; 2820f8307e12SArchie Cobbs binary->header.typecookie = c->cookie; 2821f8307e12SArchie Cobbs 2822f8307e12SArchie Cobbs /* Convert command arguments to binary */ 2823f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 2824f8307e12SArchie Cobbs c->respType : c->mesgType; 282570de87f2SJulian Elischer if (argstype == NULL) { 2826f8307e12SArchie Cobbs bufSize = 0; 282770de87f2SJulian Elischer } else { 2828f8307e12SArchie Cobbs if ((error = ng_parse(argstype, ascii->data, 2829f8307e12SArchie Cobbs &off, (u_char *)binary->data, &bufSize)) != 0) { 2830069154d5SJulian Elischer NG_FREE_MSG(resp); 2831f8307e12SArchie Cobbs break; 2832f8307e12SArchie Cobbs } 2833f8307e12SArchie Cobbs } 2834f8307e12SArchie Cobbs 2835f8307e12SArchie Cobbs /* Return the result */ 2836f8307e12SArchie Cobbs binary->header.arglen = bufSize; 2837069154d5SJulian Elischer resp->header.arglen = sizeof(*binary) + bufSize; 2838f8307e12SArchie Cobbs break; 2839f8307e12SArchie Cobbs } 2840f8307e12SArchie Cobbs 28417095e097SPoul-Henning Kamp case NGM_TEXT_CONFIG: 28424cf49a43SJulian Elischer case NGM_TEXT_STATUS: 28434cf49a43SJulian Elischer /* 28444cf49a43SJulian Elischer * This one is tricky as it passes the command down to the 28454cf49a43SJulian Elischer * actual node, even though it is a generic type command. 2846069154d5SJulian Elischer * This means we must assume that the item/msg is already freed 28474cf49a43SJulian Elischer * when control passes back to us. 28484cf49a43SJulian Elischer */ 284930400f03SJulian Elischer if (here->nd_type->rcvmsg != NULL) { 2850069154d5SJulian Elischer NGI_MSG(item) = msg; /* put it back as we found it */ 285130400f03SJulian Elischer return((*here->nd_type->rcvmsg)(here, item, lasthook)); 28524cf49a43SJulian Elischer } 28534cf49a43SJulian Elischer /* Fall through if rcvmsg not supported */ 28544cf49a43SJulian Elischer default: 28556b795970SJulian Elischer TRAP_ERROR(); 28564cf49a43SJulian Elischer error = EINVAL; 28574cf49a43SJulian Elischer } 2858069154d5SJulian Elischer /* 2859069154d5SJulian Elischer * Sometimes a generic message may be statically allocated 2860069154d5SJulian Elischer * to avoid problems with allocating when in tight memeory situations. 2861069154d5SJulian Elischer * Don't free it if it is so. 2862069154d5SJulian Elischer * I break them appart here, because erros may cause a free if the item 2863069154d5SJulian Elischer * in which case we'd be doing it twice. 2864069154d5SJulian Elischer * they are kept together above, to simplify freeing. 2865069154d5SJulian Elischer */ 2866069154d5SJulian Elischer out: 2867069154d5SJulian Elischer NG_RESPOND_MSG(error, here, item, resp); 2868069154d5SJulian Elischer NG_FREE_MSG(msg); 28694cf49a43SJulian Elischer return (error); 28704cf49a43SJulian Elischer } 28714cf49a43SJulian Elischer 28724cf49a43SJulian Elischer /************************************************************************ 28738253c060SGleb Smirnoff Queue element get/free routines 28748253c060SGleb Smirnoff ************************************************************************/ 28758253c060SGleb Smirnoff 28768253c060SGleb Smirnoff uma_zone_t ng_qzone; 28776aa6d011SAlexander Motin uma_zone_t ng_qdzone; 2878f2fbb838SAlexander Motin static int numthreads = 0; /* number of queue threads */ 2879ed75521fSAlexander Motin static int maxalloc = 4096;/* limit the damage of a leak */ 2880ed75521fSAlexander Motin static int maxdata = 512; /* limit the damage of a DoS */ 28818253c060SGleb Smirnoff 2882f2fbb838SAlexander Motin TUNABLE_INT("net.graph.threads", &numthreads); 2883f2fbb838SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, threads, CTLFLAG_RDTUN, &numthreads, 2884f2fbb838SAlexander Motin 0, "Number of queue processing threads"); 28858253c060SGleb Smirnoff TUNABLE_INT("net.graph.maxalloc", &maxalloc); 28868253c060SGleb Smirnoff SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 28876aa6d011SAlexander Motin 0, "Maximum number of non-data queue items to allocate"); 2888ed75521fSAlexander Motin TUNABLE_INT("net.graph.maxdata", &maxdata); 28896aa6d011SAlexander Motin SYSCTL_INT(_net_graph, OID_AUTO, maxdata, CTLFLAG_RDTUN, &maxdata, 28906aa6d011SAlexander Motin 0, "Maximum number of data queue items to allocate"); 28918253c060SGleb Smirnoff 28928253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 28938253c060SGleb Smirnoff static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist); 28948253c060SGleb Smirnoff static int allocated; /* number of items malloc'd */ 28958253c060SGleb Smirnoff #endif 28968253c060SGleb Smirnoff 28978253c060SGleb Smirnoff /* 28988253c060SGleb Smirnoff * Get a queue entry. 28998253c060SGleb Smirnoff * This is usually called when a packet first enters netgraph. 29008253c060SGleb Smirnoff * By definition, this is usually from an interrupt, or from a user. 29018253c060SGleb Smirnoff * Users are not so important, but try be quick for the times that it's 29028253c060SGleb Smirnoff * an interrupt. 29038253c060SGleb Smirnoff */ 29048253c060SGleb Smirnoff static __inline item_p 29056aa6d011SAlexander Motin ng_alloc_item(int type, int flags) 29068253c060SGleb Smirnoff { 29076aa6d011SAlexander Motin item_p item; 29088253c060SGleb Smirnoff 29096aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 29106aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 291142282202SGleb Smirnoff 29126aa6d011SAlexander Motin item = uma_zalloc((type == NGQF_DATA)?ng_qdzone:ng_qzone, 29136aa6d011SAlexander Motin ((flags & NG_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO); 29148253c060SGleb Smirnoff 29158253c060SGleb Smirnoff if (item) { 29166aa6d011SAlexander Motin item->el_flags = type; 29176aa6d011SAlexander Motin #ifdef NETGRAPH_DEBUG 29188253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 29198253c060SGleb Smirnoff TAILQ_INSERT_TAIL(&ng_itemlist, item, all); 29208253c060SGleb Smirnoff allocated++; 29218253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 29228253c060SGleb Smirnoff #endif 29236aa6d011SAlexander Motin } 29248253c060SGleb Smirnoff 29258253c060SGleb Smirnoff return (item); 29268253c060SGleb Smirnoff } 29278253c060SGleb Smirnoff 29288253c060SGleb Smirnoff /* 29298253c060SGleb Smirnoff * Release a queue entry 29308253c060SGleb Smirnoff */ 29318253c060SGleb Smirnoff void 29328253c060SGleb Smirnoff ng_free_item(item_p item) 29338253c060SGleb Smirnoff { 29348253c060SGleb Smirnoff /* 29358253c060SGleb Smirnoff * The item may hold resources on it's own. We need to free 29368253c060SGleb Smirnoff * these before we can free the item. What they are depends upon 29378253c060SGleb Smirnoff * what kind of item it is. it is important that nodes zero 29388253c060SGleb Smirnoff * out pointers to resources that they remove from the item 29398253c060SGleb Smirnoff * or we release them again here. 29408253c060SGleb Smirnoff */ 29418253c060SGleb Smirnoff switch (item->el_flags & NGQF_TYPE) { 29428253c060SGleb Smirnoff case NGQF_DATA: 29438253c060SGleb Smirnoff /* If we have an mbuf still attached.. */ 29448253c060SGleb Smirnoff NG_FREE_M(_NGI_M(item)); 29458253c060SGleb Smirnoff break; 29468253c060SGleb Smirnoff case NGQF_MESG: 29478253c060SGleb Smirnoff _NGI_RETADDR(item) = 0; 29488253c060SGleb Smirnoff NG_FREE_MSG(_NGI_MSG(item)); 29498253c060SGleb Smirnoff break; 29508253c060SGleb Smirnoff case NGQF_FN: 2951e088dd4cSAlexander Motin case NGQF_FN2: 29528253c060SGleb Smirnoff /* nothing to free really, */ 29538253c060SGleb Smirnoff _NGI_FN(item) = NULL; 29548253c060SGleb Smirnoff _NGI_ARG1(item) = NULL; 29558253c060SGleb Smirnoff _NGI_ARG2(item) = 0; 29568253c060SGleb Smirnoff break; 29578253c060SGleb Smirnoff } 29588253c060SGleb Smirnoff /* If we still have a node or hook referenced... */ 29598253c060SGleb Smirnoff _NGI_CLR_NODE(item); 29608253c060SGleb Smirnoff _NGI_CLR_HOOK(item); 29618253c060SGleb Smirnoff 29628253c060SGleb Smirnoff #ifdef NETGRAPH_DEBUG 29638253c060SGleb Smirnoff mtx_lock(&ngq_mtx); 29648253c060SGleb Smirnoff TAILQ_REMOVE(&ng_itemlist, item, all); 29658253c060SGleb Smirnoff allocated--; 29668253c060SGleb Smirnoff mtx_unlock(&ngq_mtx); 29678253c060SGleb Smirnoff #endif 29686aa6d011SAlexander Motin uma_zfree(((item->el_flags & NGQF_TYPE) == NGQF_DATA)? 29696aa6d011SAlexander Motin ng_qdzone:ng_qzone, item); 29706aa6d011SAlexander Motin } 29716aa6d011SAlexander Motin 29726aa6d011SAlexander Motin /* 29736aa6d011SAlexander Motin * Change type of the queue entry. 29746aa6d011SAlexander Motin * Possibly reallocates it from another UMA zone. 29756aa6d011SAlexander Motin */ 29766aa6d011SAlexander Motin static __inline item_p 29776aa6d011SAlexander Motin ng_realloc_item(item_p pitem, int type, int flags) 29786aa6d011SAlexander Motin { 29796aa6d011SAlexander Motin item_p item; 29806aa6d011SAlexander Motin int from, to; 29816aa6d011SAlexander Motin 29826aa6d011SAlexander Motin KASSERT((pitem != NULL), ("%s: can't reallocate NULL", __func__)); 29836aa6d011SAlexander Motin KASSERT(((type & ~NGQF_TYPE) == 0), 29846aa6d011SAlexander Motin ("%s: incorrect item type: %d", __func__, type)); 29856aa6d011SAlexander Motin 29866aa6d011SAlexander Motin from = ((pitem->el_flags & NGQF_TYPE) == NGQF_DATA); 29876aa6d011SAlexander Motin to = (type == NGQF_DATA); 29886aa6d011SAlexander Motin if (from != to) { 29896aa6d011SAlexander Motin /* If reallocation is required do it and copy item. */ 29906aa6d011SAlexander Motin if ((item = ng_alloc_item(type, flags)) == NULL) { 29916aa6d011SAlexander Motin ng_free_item(pitem); 29926aa6d011SAlexander Motin return (NULL); 29936aa6d011SAlexander Motin } 29946aa6d011SAlexander Motin *item = *pitem; 29956aa6d011SAlexander Motin ng_free_item(pitem); 29966aa6d011SAlexander Motin } else 29976aa6d011SAlexander Motin item = pitem; 29986aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_TYPE) | type; 29996aa6d011SAlexander Motin 30006aa6d011SAlexander Motin return (item); 30018253c060SGleb Smirnoff } 30028253c060SGleb Smirnoff 30038253c060SGleb Smirnoff /************************************************************************ 30044cf49a43SJulian Elischer Module routines 30054cf49a43SJulian Elischer ************************************************************************/ 30064cf49a43SJulian Elischer 30074cf49a43SJulian Elischer /* 30084cf49a43SJulian Elischer * Handle the loading/unloading of a netgraph node type module 30094cf49a43SJulian Elischer */ 30104cf49a43SJulian Elischer int 30114cf49a43SJulian Elischer ng_mod_event(module_t mod, int event, void *data) 30124cf49a43SJulian Elischer { 30134cf49a43SJulian Elischer struct ng_type *const type = data; 30144cf49a43SJulian Elischer int s, error = 0; 30154cf49a43SJulian Elischer 30164cf49a43SJulian Elischer switch (event) { 30174cf49a43SJulian Elischer case MOD_LOAD: 30184cf49a43SJulian Elischer 30194cf49a43SJulian Elischer /* Register new netgraph node type */ 30204cf49a43SJulian Elischer s = splnet(); 30214cf49a43SJulian Elischer if ((error = ng_newtype(type)) != 0) { 30224cf49a43SJulian Elischer splx(s); 30234cf49a43SJulian Elischer break; 30244cf49a43SJulian Elischer } 30254cf49a43SJulian Elischer 30264cf49a43SJulian Elischer /* Call type specific code */ 30274cf49a43SJulian Elischer if (type->mod_event != NULL) 3028069154d5SJulian Elischer if ((error = (*type->mod_event)(mod, event, data))) { 30299ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 3030c73b94a2SJulian Elischer type->refs--; /* undo it */ 30314cf49a43SJulian Elischer LIST_REMOVE(type, types); 30329ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 3033069154d5SJulian Elischer } 30344cf49a43SJulian Elischer splx(s); 30354cf49a43SJulian Elischer break; 30364cf49a43SJulian Elischer 30374cf49a43SJulian Elischer case MOD_UNLOAD: 30384cf49a43SJulian Elischer s = splnet(); 3039c73b94a2SJulian Elischer if (type->refs > 1) { /* make sure no nodes exist! */ 30404cf49a43SJulian Elischer error = EBUSY; 3041c73b94a2SJulian Elischer } else { 3042c73b94a2SJulian Elischer if (type->refs == 0) { 3043c73b94a2SJulian Elischer /* failed load, nothing to undo */ 3044c73b94a2SJulian Elischer splx(s); 3045c73b94a2SJulian Elischer break; 3046c73b94a2SJulian Elischer } 30474cf49a43SJulian Elischer if (type->mod_event != NULL) { /* check with type */ 30484cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30494cf49a43SJulian Elischer if (error != 0) { /* type refuses.. */ 30504cf49a43SJulian Elischer splx(s); 30514cf49a43SJulian Elischer break; 30524cf49a43SJulian Elischer } 30534cf49a43SJulian Elischer } 30549ed346baSBosko Milekic mtx_lock(&ng_typelist_mtx); 30554cf49a43SJulian Elischer LIST_REMOVE(type, types); 30569ed346baSBosko Milekic mtx_unlock(&ng_typelist_mtx); 30574cf49a43SJulian Elischer } 30584cf49a43SJulian Elischer splx(s); 30594cf49a43SJulian Elischer break; 30604cf49a43SJulian Elischer 30614cf49a43SJulian Elischer default: 30624cf49a43SJulian Elischer if (type->mod_event != NULL) 30634cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 30644cf49a43SJulian Elischer else 30653e019deaSPoul-Henning Kamp error = EOPNOTSUPP; /* XXX ? */ 30664cf49a43SJulian Elischer break; 30674cf49a43SJulian Elischer } 30684cf49a43SJulian Elischer return (error); 30694cf49a43SJulian Elischer } 30704cf49a43SJulian Elischer 30714cf49a43SJulian Elischer /* 30724cf49a43SJulian Elischer * Handle loading and unloading for this code. 30734cf49a43SJulian Elischer * The only thing we need to link into is the NETISR strucure. 30744cf49a43SJulian Elischer */ 30754cf49a43SJulian Elischer static int 30764cf49a43SJulian Elischer ngb_mod_event(module_t mod, int event, void *data) 30774cf49a43SJulian Elischer { 3078f2fbb838SAlexander Motin struct proc *p; 3079f2fbb838SAlexander Motin struct thread *td; 3080f2fbb838SAlexander Motin int i, error = 0; 30814cf49a43SJulian Elischer 30824cf49a43SJulian Elischer switch (event) { 30834cf49a43SJulian Elischer case MOD_LOAD: 30841489164fSGleb Smirnoff /* Initialize everything. */ 3085385195c0SMarko Zec V_nextID = 1; 30862c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK_INIT(); 3087efd8e7c9SDon Lewis mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL, 3088efd8e7c9SDon Lewis MTX_DEF); 3089efd8e7c9SDon Lewis mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL, 3090efd8e7c9SDon Lewis MTX_DEF); 3091cfea3f85SAlexander Motin mtx_init(&ng_namehash_mtx, "netgraph namehash mutex", NULL, 3092cfea3f85SAlexander Motin MTX_DEF); 3093ac5dd141SGleb Smirnoff mtx_init(&ng_topo_mtx, "netgraph topology mutex", NULL, 3094ac5dd141SGleb Smirnoff MTX_DEF); 30951489164fSGleb Smirnoff #ifdef NETGRAPH_DEBUG 3096cfea3f85SAlexander Motin mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL, 3097cfea3f85SAlexander Motin MTX_DEF); 30981489164fSGleb Smirnoff mtx_init(&ngq_mtx, "netgraph item list mutex", NULL, 3099efd8e7c9SDon Lewis MTX_DEF); 31001489164fSGleb Smirnoff #endif 31011489164fSGleb Smirnoff ng_qzone = uma_zcreate("NetGraph items", sizeof(struct ng_item), 31021489164fSGleb Smirnoff NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 31031489164fSGleb Smirnoff uma_zone_set_max(ng_qzone, maxalloc); 31046aa6d011SAlexander Motin ng_qdzone = uma_zcreate("NetGraph data items", sizeof(struct ng_item), 31056aa6d011SAlexander Motin NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); 31066aa6d011SAlexander Motin uma_zone_set_max(ng_qdzone, maxdata); 3107f2fbb838SAlexander Motin /* Autoconfigure number of threads. */ 3108f2fbb838SAlexander Motin if (numthreads <= 0) 3109f2fbb838SAlexander Motin numthreads = mp_ncpus; 3110f2fbb838SAlexander Motin /* Create threads. */ 3111f2fbb838SAlexander Motin p = NULL; /* start with no process */ 3112f2fbb838SAlexander Motin for (i = 0; i < numthreads; i++) { 3113f2fbb838SAlexander Motin if (kproc_kthread_add(ngthread, NULL, &p, &td, 3114f2fbb838SAlexander Motin RFHIGHPID, 0, "ng_queue", "ng_queue%d", i)) { 3115f2fbb838SAlexander Motin numthreads = i; 3116f2fbb838SAlexander Motin break; 3117f2fbb838SAlexander Motin } 3118f2fbb838SAlexander Motin } 31194cf49a43SJulian Elischer break; 31204cf49a43SJulian Elischer case MOD_UNLOAD: 312164efc707SRobert Watson /* You can't unload it because an interface may be using it. */ 31224cf49a43SJulian Elischer error = EBUSY; 31234cf49a43SJulian Elischer break; 31244cf49a43SJulian Elischer default: 31254cf49a43SJulian Elischer error = EOPNOTSUPP; 31264cf49a43SJulian Elischer break; 31274cf49a43SJulian Elischer } 31284cf49a43SJulian Elischer return (error); 31294cf49a43SJulian Elischer } 31304cf49a43SJulian Elischer 31314cf49a43SJulian Elischer static moduledata_t netgraph_mod = { 31324cf49a43SJulian Elischer "netgraph", 31334cf49a43SJulian Elischer ngb_mod_event, 31344cf49a43SJulian Elischer (NULL) 31354cf49a43SJulian Elischer }; 3136aa38f8f9SMaksim Yevmenkin DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_NETGRAPH, SI_ORDER_MIDDLE); 3137bfa7e882SJulian Elischer SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 3138bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 3139bfa7e882SJulian Elischer SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 31404cf49a43SJulian Elischer 314130400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 314230400f03SJulian Elischer void 314330400f03SJulian Elischer dumphook (hook_p hook, char *file, int line) 314430400f03SJulian Elischer { 314530400f03SJulian Elischer printf("hook: name %s, %d refs, Last touched:\n", 314630400f03SJulian Elischer _NG_HOOK_NAME(hook), hook->hk_refs); 314730400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 314830400f03SJulian Elischer hook->lastfile, hook->lastline); 314930400f03SJulian Elischer if (line) { 315030400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 315130400f03SJulian Elischer } 315230400f03SJulian Elischer } 315330400f03SJulian Elischer 315430400f03SJulian Elischer void 315530400f03SJulian Elischer dumpnode(node_p node, char *file, int line) 315630400f03SJulian Elischer { 315730400f03SJulian Elischer printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n", 31586b795970SJulian Elischer _NG_NODE_ID(node), node->nd_type->name, 315930400f03SJulian Elischer node->nd_numhooks, node->nd_flags, 316030400f03SJulian Elischer node->nd_refs, node->nd_name); 316130400f03SJulian Elischer printf(" Last active @ %s, line %d\n", 316230400f03SJulian Elischer node->lastfile, node->lastline); 316330400f03SJulian Elischer if (line) { 316430400f03SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 316530400f03SJulian Elischer } 316630400f03SJulian Elischer } 316730400f03SJulian Elischer 3168069154d5SJulian Elischer void 3169069154d5SJulian Elischer dumpitem(item_p item, char *file, int line) 3170069154d5SJulian Elischer { 3171069154d5SJulian Elischer printf(" ACTIVE item, last used at %s, line %d", 3172069154d5SJulian Elischer item->lastfile, item->lastline); 31736b795970SJulian Elischer switch(item->el_flags & NGQF_TYPE) { 31746b795970SJulian Elischer case NGQF_DATA: 3175069154d5SJulian Elischer printf(" - [data]\n"); 31766b795970SJulian Elischer break; 31776b795970SJulian Elischer case NGQF_MESG: 31786b795970SJulian Elischer printf(" - retaddr[%d]:\n", _NGI_RETADDR(item)); 31796b795970SJulian Elischer break; 31806b795970SJulian Elischer case NGQF_FN: 3181857304e6SRuslan Ermilov printf(" - fn@%p (%p, %p, %p, %d (%x))\n", 3182857304e6SRuslan Ermilov _NGI_FN(item), 3183857304e6SRuslan Ermilov _NGI_NODE(item), 3184857304e6SRuslan Ermilov _NGI_HOOK(item), 3185857304e6SRuslan Ermilov item->body.fn.fn_arg1, 3186857304e6SRuslan Ermilov item->body.fn.fn_arg2, 3187857304e6SRuslan Ermilov item->body.fn.fn_arg2); 3188857304e6SRuslan Ermilov break; 3189e088dd4cSAlexander Motin case NGQF_FN2: 3190eb4687d2SAlexander Motin printf(" - fn2@%p (%p, %p, %p, %d (%x))\n", 3191857304e6SRuslan Ermilov _NGI_FN2(item), 31926064e568SGleb Smirnoff _NGI_NODE(item), 31936064e568SGleb Smirnoff _NGI_HOOK(item), 31946b795970SJulian Elischer item->body.fn.fn_arg1, 31956b795970SJulian Elischer item->body.fn.fn_arg2, 31966b795970SJulian Elischer item->body.fn.fn_arg2); 31976b795970SJulian Elischer break; 3198069154d5SJulian Elischer } 319930400f03SJulian Elischer if (line) { 3200069154d5SJulian Elischer printf(" problem discovered at file %s, line %d\n", file, line); 32016064e568SGleb Smirnoff if (_NGI_NODE(item)) { 320230400f03SJulian Elischer printf("node %p ([%x])\n", 32036064e568SGleb Smirnoff _NGI_NODE(item), ng_node2ID(_NGI_NODE(item))); 3204069154d5SJulian Elischer } 320530400f03SJulian Elischer } 320630400f03SJulian Elischer } 320730400f03SJulian Elischer 320830400f03SJulian Elischer static void 320930400f03SJulian Elischer ng_dumpitems(void) 321030400f03SJulian Elischer { 321130400f03SJulian Elischer item_p item; 321230400f03SJulian Elischer int i = 1; 321330400f03SJulian Elischer TAILQ_FOREACH(item, &ng_itemlist, all) { 321430400f03SJulian Elischer printf("[%d] ", i++); 321530400f03SJulian Elischer dumpitem(item, NULL, 0); 321630400f03SJulian Elischer } 321730400f03SJulian Elischer } 321830400f03SJulian Elischer 321930400f03SJulian Elischer static void 322030400f03SJulian Elischer ng_dumpnodes(void) 322130400f03SJulian Elischer { 322230400f03SJulian Elischer node_p node; 322330400f03SJulian Elischer int i = 1; 322453f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 322530400f03SJulian Elischer SLIST_FOREACH(node, &ng_allnodes, nd_all) { 322630400f03SJulian Elischer printf("[%d] ", i++); 322730400f03SJulian Elischer dumpnode(node, NULL, 0); 322830400f03SJulian Elischer } 322953f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 323030400f03SJulian Elischer } 323130400f03SJulian Elischer 323230400f03SJulian Elischer static void 323330400f03SJulian Elischer ng_dumphooks(void) 323430400f03SJulian Elischer { 323530400f03SJulian Elischer hook_p hook; 323630400f03SJulian Elischer int i = 1; 323753f9c5e9SRobert Watson mtx_lock(&ng_nodelist_mtx); 323830400f03SJulian Elischer SLIST_FOREACH(hook, &ng_allhooks, hk_all) { 323930400f03SJulian Elischer printf("[%d] ", i++); 324030400f03SJulian Elischer dumphook(hook, NULL, 0); 324130400f03SJulian Elischer } 324253f9c5e9SRobert Watson mtx_unlock(&ng_nodelist_mtx); 324330400f03SJulian Elischer } 3244069154d5SJulian Elischer 3245069154d5SJulian Elischer static int 3246069154d5SJulian Elischer sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS) 3247069154d5SJulian Elischer { 3248069154d5SJulian Elischer int error; 3249069154d5SJulian Elischer int val; 3250069154d5SJulian Elischer int i; 3251069154d5SJulian Elischer 3252069154d5SJulian Elischer val = allocated; 3253069154d5SJulian Elischer i = 1; 3254041b706bSDavid Malone error = sysctl_handle_int(oidp, &val, 0, req); 32556b795970SJulian Elischer if (error != 0 || req->newptr == NULL) 32566b795970SJulian Elischer return (error); 32576b795970SJulian Elischer if (val == 42) { 325830400f03SJulian Elischer ng_dumpitems(); 325930400f03SJulian Elischer ng_dumpnodes(); 326030400f03SJulian Elischer ng_dumphooks(); 3261069154d5SJulian Elischer } 32626b795970SJulian Elischer return (0); 3263069154d5SJulian Elischer } 3264069154d5SJulian Elischer 32656b795970SJulian Elischer SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, 32666b795970SJulian Elischer 0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items"); 326730400f03SJulian Elischer #endif /* NETGRAPH_DEBUG */ 3268069154d5SJulian Elischer 3269069154d5SJulian Elischer 3270069154d5SJulian Elischer /*********************************************************************** 3271069154d5SJulian Elischer * Worklist routines 3272069154d5SJulian Elischer **********************************************************************/ 3273069154d5SJulian Elischer /* 3274069154d5SJulian Elischer * Pick a node off the list of nodes with work, 3275f2fbb838SAlexander Motin * try get an item to process off it. Remove the node from the list. 3276069154d5SJulian Elischer */ 3277069154d5SJulian Elischer static void 3278f2fbb838SAlexander Motin ngthread(void *arg) 3279069154d5SJulian Elischer { 3280069154d5SJulian Elischer for (;;) { 3281394cb30aSAlexander Motin node_p node; 3282394cb30aSAlexander Motin 3283394cb30aSAlexander Motin /* Get node from the worklist. */ 32842c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 3285f2fbb838SAlexander Motin while ((node = STAILQ_FIRST(&ng_worklist)) == NULL) 3286f2fbb838SAlexander Motin NG_WORKLIST_SLEEP(); 32879852972bSAlexander Motin STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work); 32882c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 32892955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist", 32902955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3291069154d5SJulian Elischer /* 3292069154d5SJulian Elischer * We have the node. We also take over the reference 3293069154d5SJulian Elischer * that the list had on it. 3294069154d5SJulian Elischer * Now process as much as you can, until it won't 3295069154d5SJulian Elischer * let you have another item off the queue. 3296069154d5SJulian Elischer * All this time, keep the reference 3297069154d5SJulian Elischer * that lets us be sure that the node still exists. 3298069154d5SJulian Elischer * Let the reference go at the last minute. 3299069154d5SJulian Elischer */ 3300069154d5SJulian Elischer for (;;) { 3301394cb30aSAlexander Motin item_p item; 3302714fb865SGleb Smirnoff int rw; 3303714fb865SGleb Smirnoff 33042c8dda8dSWojciech A. Koszek NG_QUEUE_LOCK(&node->nd_input_queue); 33059852972bSAlexander Motin item = ng_dequeue(node, &rw); 3306069154d5SJulian Elischer if (item == NULL) { 33079852972bSAlexander Motin node->nd_input_queue.q_flags2 &= ~NGQ2_WORKQ; 33082c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 3309069154d5SJulian Elischer break; /* go look for another node */ 3310069154d5SJulian Elischer } else { 33112c8dda8dSWojciech A. Koszek NG_QUEUE_UNLOCK(&node->nd_input_queue); 33125951069aSJulian Elischer NGI_GET_NODE(item, node); /* zaps stored node */ 3313714fb865SGleb Smirnoff ng_apply_item(node, item, rw); 33145951069aSJulian Elischer NG_NODE_UNREF(node); 3315069154d5SJulian Elischer } 3316069154d5SJulian Elischer } 3317a96dcd84SJulian Elischer NG_NODE_UNREF(node); 3318069154d5SJulian Elischer } 3319069154d5SJulian Elischer } 3320069154d5SJulian Elischer 332133338e73SJulian Elischer /* 332233338e73SJulian Elischer * XXX 332333338e73SJulian Elischer * It's posible that a debugging NG_NODE_REF may need 332433338e73SJulian Elischer * to be outside the mutex zone 332533338e73SJulian Elischer */ 3326069154d5SJulian Elischer static void 3327394cb30aSAlexander Motin ng_worklist_add(node_p node) 3328069154d5SJulian Elischer { 3329f912c0f7SGleb Smirnoff 33305bc15201SGleb Smirnoff mtx_assert(&node->nd_input_queue.q_mtx, MA_OWNED); 3331f912c0f7SGleb Smirnoff 33329852972bSAlexander Motin if ((node->nd_input_queue.q_flags2 & NGQ2_WORKQ) == 0) { 3333069154d5SJulian Elischer /* 3334069154d5SJulian Elischer * If we are not already on the work queue, 3335069154d5SJulian Elischer * then put us on. 3336069154d5SJulian Elischer */ 33379852972bSAlexander Motin node->nd_input_queue.q_flags2 |= NGQ2_WORKQ; 3338394cb30aSAlexander Motin NG_NODE_REF(node); /* XXX fafe in mutex? */ 33392c8dda8dSWojciech A. Koszek NG_WORKLIST_LOCK(); 33409852972bSAlexander Motin STAILQ_INSERT_TAIL(&ng_worklist, node, nd_input_queue.q_work); 33412c8dda8dSWojciech A. Koszek NG_WORKLIST_UNLOCK(); 33422955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__, 33432955ee18SGleb Smirnoff node->nd_ID, node); 3344f2fbb838SAlexander Motin NG_WORKLIST_WAKEUP(); 3345394cb30aSAlexander Motin } else { 33462955ee18SGleb Smirnoff CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist", 33472955ee18SGleb Smirnoff __func__, node->nd_ID, node); 3348394cb30aSAlexander Motin } 3349069154d5SJulian Elischer } 3350069154d5SJulian Elischer 3351069154d5SJulian Elischer 3352069154d5SJulian Elischer /*********************************************************************** 3353069154d5SJulian Elischer * Externally useable functions to set up a queue item ready for sending 3354069154d5SJulian Elischer ***********************************************************************/ 3355069154d5SJulian Elischer 335630400f03SJulian Elischer #ifdef NETGRAPH_DEBUG 335730400f03SJulian Elischer #define ITEM_DEBUG_CHECKS \ 33584cf49a43SJulian Elischer do { \ 33591acb27c6SJulian Elischer if (NGI_NODE(item) ) { \ 3360069154d5SJulian Elischer printf("item already has node"); \ 33613de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has node"); \ 33621acb27c6SJulian Elischer NGI_CLR_NODE(item); \ 3363069154d5SJulian Elischer } \ 33641acb27c6SJulian Elischer if (NGI_HOOK(item) ) { \ 3365069154d5SJulian Elischer printf("item already has hook"); \ 33663de213ccSRobert Watson kdb_enter(KDB_WHY_NETGRAPH, "has hook"); \ 33671acb27c6SJulian Elischer NGI_CLR_HOOK(item); \ 3368069154d5SJulian Elischer } \ 3369069154d5SJulian Elischer } while (0) 3370069154d5SJulian Elischer #else 337130400f03SJulian Elischer #define ITEM_DEBUG_CHECKS 3372069154d5SJulian Elischer #endif 3373069154d5SJulian Elischer 3374069154d5SJulian Elischer /* 33758ed370fdSJulian Elischer * Put mbuf into the item. 3376069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3377069154d5SJulian Elischer * (or equivalent) 3378069154d5SJulian Elischer * (XXX) Unsafe because no reference held by peer on remote node. 3379069154d5SJulian Elischer * remote node might go away in this timescale. 3380069154d5SJulian Elischer * We know the hooks can't go away because that would require getting 3381069154d5SJulian Elischer * a writer item on both nodes and we must have at least a reader 33824be59335SGleb Smirnoff * here to be able to do this. 3383069154d5SJulian Elischer * Note that the hook loaded is the REMOTE hook. 3384069154d5SJulian Elischer * 3385069154d5SJulian Elischer * This is possibly in the critical path for new data. 3386069154d5SJulian Elischer */ 3387069154d5SJulian Elischer item_p 338842282202SGleb Smirnoff ng_package_data(struct mbuf *m, int flags) 3389069154d5SJulian Elischer { 3390069154d5SJulian Elischer item_p item; 3391069154d5SJulian Elischer 33926aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_DATA, flags)) == NULL) { 3393069154d5SJulian Elischer NG_FREE_M(m); 3394069154d5SJulian Elischer return (NULL); 3395069154d5SJulian Elischer } 339630400f03SJulian Elischer ITEM_DEBUG_CHECKS; 33976aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 3398069154d5SJulian Elischer NGI_M(item) = m; 3399069154d5SJulian Elischer return (item); 3400069154d5SJulian Elischer } 3401069154d5SJulian Elischer 3402069154d5SJulian Elischer /* 3403069154d5SJulian Elischer * Allocate a queue item and put items into it.. 3404069154d5SJulian Elischer * Evaluate the address as this will be needed to queue it and 3405069154d5SJulian Elischer * to work out what some of the fields should be. 3406069154d5SJulian Elischer * Hook and node references will be removed when the item is dequeued. 3407069154d5SJulian Elischer * (or equivalent) 3408069154d5SJulian Elischer */ 3409069154d5SJulian Elischer item_p 341042282202SGleb Smirnoff ng_package_msg(struct ng_mesg *msg, int flags) 3411069154d5SJulian Elischer { 3412069154d5SJulian Elischer item_p item; 3413069154d5SJulian Elischer 34146aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, flags)) == NULL) { 3415069154d5SJulian Elischer NG_FREE_MSG(msg); 3416069154d5SJulian Elischer return (NULL); 3417069154d5SJulian Elischer } 341830400f03SJulian Elischer ITEM_DEBUG_CHECKS; 34196f683eeeSGleb Smirnoff /* Messages items count as writers unless explicitly exempted. */ 34206f683eeeSGleb Smirnoff if (msg->header.cmd & NGM_READONLY) 34216aa6d011SAlexander Motin item->el_flags |= NGQF_READER; 34226f683eeeSGleb Smirnoff else 34236aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3424069154d5SJulian Elischer /* 3425069154d5SJulian Elischer * Set the current lasthook into the queue item 3426069154d5SJulian Elischer */ 3427069154d5SJulian Elischer NGI_MSG(item) = msg; 3428facfd889SArchie Cobbs NGI_RETADDR(item) = 0; 3429069154d5SJulian Elischer return (item); 3430069154d5SJulian Elischer } 3431069154d5SJulian Elischer 3432069154d5SJulian Elischer 3433069154d5SJulian Elischer 34341acb27c6SJulian Elischer #define SET_RETADDR(item, here, retaddr) \ 34356b795970SJulian Elischer do { /* Data or fn items don't have retaddrs */ \ 34366b795970SJulian Elischer if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \ 3437069154d5SJulian Elischer if (retaddr) { \ 3438069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; \ 34394cf49a43SJulian Elischer } else { \ 3440069154d5SJulian Elischer /* \ 3441069154d5SJulian Elischer * The old return address should be ok. \ 3442069154d5SJulian Elischer * If there isn't one, use the address \ 3443069154d5SJulian Elischer * here. \ 3444069154d5SJulian Elischer */ \ 3445069154d5SJulian Elischer if (NGI_RETADDR(item) == 0) { \ 3446069154d5SJulian Elischer NGI_RETADDR(item) \ 3447069154d5SJulian Elischer = ng_node2ID(here); \ 3448069154d5SJulian Elischer } \ 3449069154d5SJulian Elischer } \ 34504cf49a43SJulian Elischer } \ 34514cf49a43SJulian Elischer } while (0) 34524cf49a43SJulian Elischer 34534cf49a43SJulian Elischer int 3454069154d5SJulian Elischer ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr) 34554cf49a43SJulian Elischer { 34561acb27c6SJulian Elischer hook_p peer; 34571acb27c6SJulian Elischer node_p peernode; 345830400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3459069154d5SJulian Elischer /* 3460069154d5SJulian Elischer * Quick sanity check.. 346130400f03SJulian Elischer * Since a hook holds a reference on it's node, once we know 346230400f03SJulian Elischer * that the peer is still connected (even if invalid,) we know 346330400f03SJulian Elischer * that the peer node is present, though maybe invalid. 3464069154d5SJulian Elischer */ 3465a04e9846SAlexander Motin if ((hook == NULL) || 3466a04e9846SAlexander Motin NG_HOOK_NOT_VALID(hook) || 3467a04e9846SAlexander Motin NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) || 3468a04e9846SAlexander Motin NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) { 3469069154d5SJulian Elischer NG_FREE_ITEM(item); 34706b795970SJulian Elischer TRAP_ERROR(); 3471e08d3e3cSJulian Elischer return (ENETDOWN); 34724cf49a43SJulian Elischer } 34734cf49a43SJulian Elischer 34744cf49a43SJulian Elischer /* 3475069154d5SJulian Elischer * Transfer our interest to the other (peer) end. 34764cf49a43SJulian Elischer */ 34771acb27c6SJulian Elischer NG_HOOK_REF(peer); 34781acb27c6SJulian Elischer NG_NODE_REF(peernode); 3479a04e9846SAlexander Motin NGI_SET_HOOK(item, peer); 34801acb27c6SJulian Elischer NGI_SET_NODE(item, peernode); 34818b68f82fSJulian Elischer SET_RETADDR(item, here, retaddr); 3482069154d5SJulian Elischer return (0); 3483069154d5SJulian Elischer } 3484069154d5SJulian Elischer 34854cf49a43SJulian Elischer int 3486069154d5SJulian Elischer ng_address_path(node_p here, item_p item, char *address, ng_ID_t retaddr) 34874cf49a43SJulian Elischer { 34884cf49a43SJulian Elischer node_p dest = NULL; 3489069154d5SJulian Elischer hook_p hook = NULL; 34904cf49a43SJulian Elischer int error; 3491069154d5SJulian Elischer 349230400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3493069154d5SJulian Elischer /* 3494069154d5SJulian Elischer * Note that ng_path2noderef increments the reference count 3495069154d5SJulian Elischer * on the node for us if it finds one. So we don't have to. 3496069154d5SJulian Elischer */ 3497069154d5SJulian Elischer error = ng_path2noderef(here, address, &dest, &hook); 3498069154d5SJulian Elischer if (error) { 3499069154d5SJulian Elischer NG_FREE_ITEM(item); 350030400f03SJulian Elischer return (error); 3501069154d5SJulian Elischer } 35021acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 35031acb27c6SJulian Elischer if ( hook) { 350430400f03SJulian Elischer NG_HOOK_REF(hook); /* don't let it go while on the queue */ 35051acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 35061acb27c6SJulian Elischer } 35071acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3508069154d5SJulian Elischer return (0); 3509069154d5SJulian Elischer } 3510069154d5SJulian Elischer 3511069154d5SJulian Elischer int 3512069154d5SJulian Elischer ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr) 3513069154d5SJulian Elischer { 3514069154d5SJulian Elischer node_p dest; 3515069154d5SJulian Elischer 351630400f03SJulian Elischer ITEM_DEBUG_CHECKS; 3517069154d5SJulian Elischer /* 3518069154d5SJulian Elischer * Find the target node. 3519069154d5SJulian Elischer */ 3520069154d5SJulian Elischer dest = ng_ID2noderef(ID); /* GETS REFERENCE! */ 3521069154d5SJulian Elischer if (dest == NULL) { 3522069154d5SJulian Elischer NG_FREE_ITEM(item); 35236b795970SJulian Elischer TRAP_ERROR(); 3524069154d5SJulian Elischer return(EINVAL); 3525069154d5SJulian Elischer } 3526069154d5SJulian Elischer /* Fill out the contents */ 35271acb27c6SJulian Elischer NGI_SET_NODE(item, dest); 35281acb27c6SJulian Elischer NGI_CLR_HOOK(item); 35291acb27c6SJulian Elischer SET_RETADDR(item, here, retaddr); 3530069154d5SJulian Elischer return (0); 3531069154d5SJulian Elischer } 3532069154d5SJulian Elischer 3533069154d5SJulian Elischer /* 3534069154d5SJulian Elischer * special case to send a message to self (e.g. destroy node) 3535069154d5SJulian Elischer * Possibly indicate an arrival hook too. 3536069154d5SJulian Elischer * Useful for removing that hook :-) 3537069154d5SJulian Elischer */ 3538069154d5SJulian Elischer item_p 3539069154d5SJulian Elischer ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg) 3540069154d5SJulian Elischer { 3541069154d5SJulian Elischer item_p item; 35424cf49a43SJulian Elischer 3543859a4d16SJulian Elischer /* 3544859a4d16SJulian Elischer * Find the target node. 3545859a4d16SJulian Elischer * If there is a HOOK argument, then use that in preference 3546859a4d16SJulian Elischer * to the address. 3547859a4d16SJulian Elischer */ 35486aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_MESG, NG_NOFLAGS)) == NULL) { 3549069154d5SJulian Elischer NG_FREE_MSG(msg); 3550069154d5SJulian Elischer return (NULL); 35514cf49a43SJulian Elischer } 35524cf49a43SJulian Elischer 35534cf49a43SJulian Elischer /* Fill out the contents */ 35546aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 355530400f03SJulian Elischer NG_NODE_REF(here); 35561acb27c6SJulian Elischer NGI_SET_NODE(item, here); 35571acb27c6SJulian Elischer if (hook) { 355830400f03SJulian Elischer NG_HOOK_REF(hook); 35591acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 35601acb27c6SJulian Elischer } 3561069154d5SJulian Elischer NGI_MSG(item) = msg; 3562069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3563069154d5SJulian Elischer return (item); 35644cf49a43SJulian Elischer } 35654cf49a43SJulian Elischer 3566e088dd4cSAlexander Motin /* 3567e088dd4cSAlexander Motin * Send ng_item_fn function call to the specified node. 3568e088dd4cSAlexander Motin */ 3569e088dd4cSAlexander Motin 357042282202SGleb Smirnoff int 3571b332b91fSGleb Smirnoff ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2) 3572b332b91fSGleb Smirnoff { 3573b332b91fSGleb Smirnoff 3574b332b91fSGleb Smirnoff return ng_send_fn1(node, hook, fn, arg1, arg2, NG_NOFLAGS); 3575b332b91fSGleb Smirnoff } 3576b332b91fSGleb Smirnoff 3577b332b91fSGleb Smirnoff int 3578aacdb114SGleb Smirnoff ng_send_fn1(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2, 357942282202SGleb Smirnoff int flags) 35806b795970SJulian Elischer { 35816b795970SJulian Elischer item_p item; 35826b795970SJulian Elischer 35836aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, flags)) == NULL) { 35846b795970SJulian Elischer return (ENOMEM); 35856b795970SJulian Elischer } 35866aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3587a96dcd84SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 35881acb27c6SJulian Elischer NGI_SET_NODE(item, node); 35891acb27c6SJulian Elischer if (hook) { 35906b795970SJulian Elischer NG_HOOK_REF(hook); 35911acb27c6SJulian Elischer NGI_SET_HOOK(item, hook); 35926b795970SJulian Elischer } 35936b795970SJulian Elischer NGI_FN(item) = fn; 35946b795970SJulian Elischer NGI_ARG1(item) = arg1; 35956b795970SJulian Elischer NGI_ARG2(item) = arg2; 359642282202SGleb Smirnoff return(ng_snd_item(item, flags)); 35976b795970SJulian Elischer } 35986b795970SJulian Elischer 35994cf49a43SJulian Elischer /* 3600b332b91fSGleb Smirnoff * Send ng_item_fn2 function call to the specified node. 3601b332b91fSGleb Smirnoff * 3602b332b91fSGleb Smirnoff * If an optional pitem parameter is supplied, its apply 3603b332b91fSGleb Smirnoff * callback will be copied to the new item. If also NG_REUSE_ITEM 3604b332b91fSGleb Smirnoff * flag is set, no new item will be allocated, but pitem will 3605b332b91fSGleb Smirnoff * be used. 3606e088dd4cSAlexander Motin */ 3607e088dd4cSAlexander Motin int 3608b332b91fSGleb Smirnoff ng_send_fn2(node_p node, hook_p hook, item_p pitem, ng_item_fn2 *fn, void *arg1, 3609b332b91fSGleb Smirnoff int arg2, int flags) 3610e088dd4cSAlexander Motin { 3611e088dd4cSAlexander Motin item_p item; 3612e088dd4cSAlexander Motin 3613b332b91fSGleb Smirnoff KASSERT((pitem != NULL || (flags & NG_REUSE_ITEM) == 0), 3614b332b91fSGleb Smirnoff ("%s: NG_REUSE_ITEM but no pitem", __func__)); 3615e088dd4cSAlexander Motin 3616e088dd4cSAlexander Motin /* 3617b332b91fSGleb Smirnoff * Allocate a new item if no supplied or 3618b332b91fSGleb Smirnoff * if we can't use supplied one. 3619e088dd4cSAlexander Motin */ 3620b332b91fSGleb Smirnoff if (pitem == NULL || (flags & NG_REUSE_ITEM) == 0) { 36216aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN2, flags)) == NULL) 3622e088dd4cSAlexander Motin return (ENOMEM); 36236aa6d011SAlexander Motin if (pitem != NULL) 36246aa6d011SAlexander Motin item->apply = pitem->apply; 3625ed75521fSAlexander Motin } else { 36266aa6d011SAlexander Motin if ((item = ng_realloc_item(pitem, NGQF_FN2, flags)) == NULL) 36276aa6d011SAlexander Motin return (ENOMEM); 3628ed75521fSAlexander Motin } 3629b332b91fSGleb Smirnoff 36306aa6d011SAlexander Motin item->el_flags = (item->el_flags & ~NGQF_RW) | NGQF_WRITER; 3631e088dd4cSAlexander Motin NG_NODE_REF(node); /* and one for the item */ 3632e088dd4cSAlexander Motin NGI_SET_NODE(item, node); 3633e088dd4cSAlexander Motin if (hook) { 3634e088dd4cSAlexander Motin NG_HOOK_REF(hook); 3635e088dd4cSAlexander Motin NGI_SET_HOOK(item, hook); 3636e088dd4cSAlexander Motin } 3637e088dd4cSAlexander Motin NGI_FN2(item) = fn; 3638e088dd4cSAlexander Motin NGI_ARG1(item) = arg1; 3639e088dd4cSAlexander Motin NGI_ARG2(item) = arg2; 3640e088dd4cSAlexander Motin return(ng_snd_item(item, flags)); 3641e088dd4cSAlexander Motin } 3642e088dd4cSAlexander Motin 3643e088dd4cSAlexander Motin /* 3644d2ca21a9SJulian Elischer * Official timeout routines for Netgraph nodes. 3645d2ca21a9SJulian Elischer */ 3646d2ca21a9SJulian Elischer static void 36471fbb36ffSGleb Smirnoff ng_callout_trampoline(void *arg) 3648d2ca21a9SJulian Elischer { 3649d2ca21a9SJulian Elischer item_p item = arg; 3650d2ca21a9SJulian Elischer 3651d2ca21a9SJulian Elischer ng_snd_item(item, 0); 3652d2ca21a9SJulian Elischer } 3653d2ca21a9SJulian Elischer 3654d2ca21a9SJulian Elischer 365530bef41bSGleb Smirnoff int 3656f9d9e1b4SGleb Smirnoff ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, 3657d2ca21a9SJulian Elischer ng_item_fn *fn, void * arg1, int arg2) 3658d2ca21a9SJulian Elischer { 36591bf8e0faSGleb Smirnoff item_p item, oitem; 3660d2ca21a9SJulian Elischer 36616aa6d011SAlexander Motin if ((item = ng_alloc_item(NGQF_FN, NG_NOFLAGS)) == NULL) 366230bef41bSGleb Smirnoff return (ENOMEM); 366330bef41bSGleb Smirnoff 36646aa6d011SAlexander Motin item->el_flags |= NGQF_WRITER; 3665d2ca21a9SJulian Elischer NG_NODE_REF(node); /* and one for the item */ 3666d2ca21a9SJulian Elischer NGI_SET_NODE(item, node); 3667d2ca21a9SJulian Elischer if (hook) { 3668d2ca21a9SJulian Elischer NG_HOOK_REF(hook); 3669d2ca21a9SJulian Elischer NGI_SET_HOOK(item, hook); 3670d2ca21a9SJulian Elischer } 3671d2ca21a9SJulian Elischer NGI_FN(item) = fn; 3672d2ca21a9SJulian Elischer NGI_ARG1(item) = arg1; 3673d2ca21a9SJulian Elischer NGI_ARG2(item) = arg2; 36741bf8e0faSGleb Smirnoff oitem = c->c_arg; 36751bf8e0faSGleb Smirnoff if (callout_reset(c, ticks, &ng_callout_trampoline, item) == 1 && 36761bf8e0faSGleb Smirnoff oitem != NULL) 36771bf8e0faSGleb Smirnoff NG_FREE_ITEM(oitem); 367830bef41bSGleb Smirnoff return (0); 3679d2ca21a9SJulian Elischer } 3680d2ca21a9SJulian Elischer 3681d2ca21a9SJulian Elischer /* A special modified version of untimeout() */ 3682d2ca21a9SJulian Elischer int 3683f9d9e1b4SGleb Smirnoff ng_uncallout(struct callout *c, node_p node) 3684d2ca21a9SJulian Elischer { 3685d2ca21a9SJulian Elischer item_p item; 368630bef41bSGleb Smirnoff int rval; 3687d2ca21a9SJulian Elischer 368803b25f5dSGleb Smirnoff KASSERT(c != NULL, ("ng_uncallout: NULL callout")); 368903b25f5dSGleb Smirnoff KASSERT(node != NULL, ("ng_uncallout: NULL node")); 369003b25f5dSGleb Smirnoff 36913eadb26dSGleb Smirnoff rval = callout_stop(c); 369230bef41bSGleb Smirnoff item = c->c_arg; 369330bef41bSGleb Smirnoff /* Do an extra check */ 36941fbb36ffSGleb Smirnoff if ((rval > 0) && (c->c_func == &ng_callout_trampoline) && 369530bef41bSGleb Smirnoff (NGI_NODE(item) == node)) { 3696d2ca21a9SJulian Elischer /* 3697d2ca21a9SJulian Elischer * We successfully removed it from the queue before it ran 3698d2ca21a9SJulian Elischer * So now we need to unreference everything that was 3699d2ca21a9SJulian Elischer * given extra references. (NG_FREE_ITEM does this). 3700d2ca21a9SJulian Elischer */ 3701d2ca21a9SJulian Elischer NG_FREE_ITEM(item); 3702d2ca21a9SJulian Elischer } 37031bf8e0faSGleb Smirnoff c->c_arg = NULL; 370430bef41bSGleb Smirnoff 370530bef41bSGleb Smirnoff return (rval); 3706d2ca21a9SJulian Elischer } 3707d2ca21a9SJulian Elischer 3708d2ca21a9SJulian Elischer /* 3709069154d5SJulian Elischer * Set the address, if none given, give the node here. 37104cf49a43SJulian Elischer */ 3711069154d5SJulian Elischer void 3712069154d5SJulian Elischer ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr) 37134cf49a43SJulian Elischer { 3714069154d5SJulian Elischer if (retaddr) { 3715069154d5SJulian Elischer NGI_RETADDR(item) = retaddr; 3716069154d5SJulian Elischer } else { 3717069154d5SJulian Elischer /* 3718069154d5SJulian Elischer * The old return address should be ok. 3719069154d5SJulian Elischer * If there isn't one, use the address here. 3720069154d5SJulian Elischer */ 3721069154d5SJulian Elischer NGI_RETADDR(item) = ng_node2ID(here); 3722069154d5SJulian Elischer } 3723069154d5SJulian Elischer } 3724069154d5SJulian Elischer 3725069154d5SJulian Elischer #define TESTING 3726069154d5SJulian Elischer #ifdef TESTING 3727069154d5SJulian Elischer /* just test all the macros */ 3728069154d5SJulian Elischer void 3729069154d5SJulian Elischer ng_macro_test(item_p item); 3730069154d5SJulian Elischer void 3731069154d5SJulian Elischer ng_macro_test(item_p item) 3732069154d5SJulian Elischer { 3733069154d5SJulian Elischer node_p node = NULL; 3734069154d5SJulian Elischer hook_p hook = NULL; 37354cf49a43SJulian Elischer struct mbuf *m; 37364cf49a43SJulian Elischer struct ng_mesg *msg; 3737069154d5SJulian Elischer ng_ID_t retaddr; 3738069154d5SJulian Elischer int error; 37394cf49a43SJulian Elischer 3740069154d5SJulian Elischer NGI_GET_M(item, m); 3741069154d5SJulian Elischer NGI_GET_MSG(item, msg); 3742069154d5SJulian Elischer retaddr = NGI_RETADDR(item); 37438ed370fdSJulian Elischer NG_SEND_DATA(error, hook, m, NULL); 3744069154d5SJulian Elischer NG_SEND_DATA_ONLY(error, hook, m); 3745069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, hook, m); 374630400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, hook); 3747069154d5SJulian Elischer NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr); 3748069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr); 3749069154d5SJulian Elischer NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr); 3750069154d5SJulian Elischer NG_FWD_MSG_HOOK(error, node, item, hook, retaddr); 37514cf49a43SJulian Elischer } 3752069154d5SJulian Elischer #endif /* TESTING */ 37534cf49a43SJulian Elischer 3754