2 * Copyright (c) 1996-1999 Whistle Communications, Inc.
5 * Subject to the following obligations and disclaimer of warranty, use and
6 * redistribution of this software, in source or object code forms, with or
7 * without modifications are expressly permitted by Whistle Communications;
8 * provided, however, that:
9 * 1. Any and all reproductions of the source or object code must include the
10 * copyright notice above and the following disclaimer of warranties; and
11 * 2. No rights are granted, in any manner or form, to use Whistle
12 * Communications, Inc. trademarks, including the mark "WHISTLE
13 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
14 * such appears in the above copyright notice or in the software.
16 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
17 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
18 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
19 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
21 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
22 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
23 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
24 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
25 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
26 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34 * Authors: Julian Elischer <julian@freebsd.org>
35 * Archie Cobbs <archie@freebsd.org>
37 * $FreeBSD: src/sys/netgraph/ng_base.c,v 1.159 2008/04/19 05:30:49 mav Exp $
38 * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $
42 * This file implements the base netgraph code.
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/ctype.h>
48 #include <sys/errno.h>
50 /*#include <sys/kdb.h>*/
51 #include <sys/kernel.h>
52 #include <sys/limits.h>
53 #include <sys/malloc.h>
55 #include <sys/msgport2.h>
56 #include <sys/mutex2.h>
57 #include <sys/objcache.h>
59 #include <sys/queue.h>
60 #include <sys/refcount.h>
61 #include <sys/sysctl.h>
62 #include <sys/syslog.h>
63 #include <machine/cpu.h>
65 #include <netgraph7/netgraph.h>
66 #include <netgraph7/netgraph2.h>
67 #include <netgraph7/ng_parse.h>
69 MODULE_VERSION(netgraph
, NG_ABI_VERSION
);
71 /* Token to protect topology events. */
72 static struct lwkt_token ng_topo_token
;
73 #define TOPOLOGY_RLOCK() lwkt_gettoken_shared(&ng_topo_token)
74 #define TOPOLOGY_RUNLOCK() lwkt_reltoken(&ng_topo_token)
75 #define TOPOLOGY_WLOCK() lwkt_gettoken(&ng_topo_token)
76 #define TOPOLOGY_WUNLOCK() lwkt_reltoken(&ng_topo_token)
77 #define TOPOLOGY_NOTOWNED() KKASSERT(!LWKT_TOKEN_HELD_ANY(&ng_topo_token))
80 static struct mtx ng_nodelist_mtx
; /* protects global node/hook lists */
81 static struct mtx ngq_mtx
; /* protects the queue item list */
83 static SLIST_HEAD(, ng_node
) ng_allnodes
;
84 static LIST_HEAD(, ng_node
) ng_freenodes
; /* in debug, we never free() them */
85 static SLIST_HEAD(, ng_hook
) ng_allhooks
;
86 static LIST_HEAD(, ng_hook
) ng_freehooks
; /* in debug, we never free() them */
88 static void ng_dumpitems(void);
89 static void ng_dumpnodes(void);
90 static void ng_dumphooks(void);
92 #endif /* NETGRAPH_DEBUG */
94 * DEAD versions of the structures.
95 * In order to avoid races, it is sometimes necessary to point
96 * at SOMETHING even though theoretically, the current entity is
97 * INVALID. Use these to avoid these races.
99 struct ng_type ng_deadtype
= {
103 NULL
, /* constructor */
110 NULL
, /* disconnect */
114 struct ng_node ng_deadnode
= {
121 LIST_HEAD_INITIALIZER(ng_deadnode
.hooks
),
122 {}, /* all_nodes list entry */
123 {}, /* id hashtable list entry */
131 #ifdef NETGRAPH_DEBUG
136 #endif /* NETGRAPH_DEBUG */
139 struct ng_hook ng_deadhook
= {
142 HK_INVALID
| HK_DEAD
,
143 0, /* undefined data link type */
144 &ng_deadhook
, /* Peer is self */
145 &ng_deadnode
, /* attached to deadnode */
147 NULL
, /* override rcvmsg() */
148 NULL
, /* override rcvdata() */
149 1, /* refs always >= 1 */
150 #ifdef NETGRAPH_DEBUG
155 #endif /* NETGRAPH_DEBUG */
159 * END DEAD STRUCTURES
162 /* We don't want our messages to be replied. This is our panic reply port. */
163 static struct lwkt_port ng_panic_reply_port
;
165 /* Array of per-CPU target ports */
166 struct lwkt_port
*ng_msgport
[MAXCPU
];
168 /* List of installed types */
169 static LIST_HEAD(, ng_type
) ng_typelist
;
170 static struct lwkt_token ng_typelist_token
;
171 #define TYPELIST_RLOCK() lwkt_gettoken_shared(&ng_typelist_token)
172 #define TYPELIST_RUNLOCK() lwkt_reltoken(&ng_typelist_token)
173 #define TYPELIST_WLOCK() lwkt_gettoken(&ng_typelist_token)
174 #define TYPELIST_WUNLOCK() lwkt_reltoken(&ng_typelist_token)
176 /* Hash related definitions */
177 LIST_HEAD(nodehash
, ng_node
);
178 static struct nodehash
*ng_ID_hash
;
179 static u_long ng_ID_hmask
;
180 static u_long ng_nodes
;
181 static struct nodehash
*ng_name_hash
;
182 static u_long ng_name_hmask
;
183 static u_long ng_named_nodes
;
184 static struct lwkt_token ng_idhash_token
;
185 #define IDHASH_RLOCK() lwkt_gettoken_shared(&ng_idhash_token)
186 #define IDHASH_RUNLOCK() lwkt_reltoken(&ng_idhash_token)
187 #define IDHASH_WLOCK() lwkt_gettoken(&ng_idhash_token)
188 #define IDHASH_WUNLOCK() lwkt_reltoken(&ng_idhash_token)
189 #define IDHASH_ASSERT_LOCKED() KKASSERT(LWKT_TOKEN_HELD_ANY(&ng_idhash_token));
190 /* Method to find a node.. used twice so do it here */
191 #define NG_IDHASH_FN(ID) ((ID) % (ng_ID_hmask + 1))
192 #define NG_IDHASH_FIND(ID, node) \
194 IDHASH_ASSERT_LOCKED(); \
195 LIST_FOREACH(node, &ng_ID_hash[NG_IDHASH_FN(ID)], \
197 if (NG_NODE_IS_VALID(node) \
198 && (NG_NODE_ID(node) == ID)) { \
204 static struct lwkt_token ng_namehash_token
;
205 #define NAMEHASH_RLOCK() lwkt_gettoken_shared(&ng_namehash_token)
206 #define NAMEHASH_RUNLOCK() lwkt_reltoken(&ng_namehash_token)
207 #define NAMEHASH_WLOCK() lwkt_gettoken(&ng_namehash_token)
208 #define NAMEHASH_WUNLOCK() lwkt_reltoken(&ng_namehash_token)
209 #define NAMEHASH_ASSERT_LOCKED() KKASSERT(LWKT_TOKEN_HELD_ANY(&ng_namehash_token));
211 /* Internal functions */
212 static int ng_add_hook(node_p node
, const char *name
, hook_p
* hookp
);
213 static int ng_generic_msg(node_p here
, item_p item
, hook_p lasthook
);
214 static ng_ID_t
ng_decodeidname(const char *name
);
215 static int ngb_mod_event(module_t mod
, int event
, void *data
);
216 static void ngthread(void *dummy
);
217 static int ng_apply_item(item_p item
);
218 static node_p
ng_ID2noderef(ng_ID_t ID
);
219 static int ng_con_nodes(item_p item
, node_p node
, const char *name
,
220 node_p node2
, const char *name2
);
221 static int ng_con_part2(node_p node
, item_p item
, hook_p hook
);
222 static int ng_con_part3(node_p node
, item_p item
, hook_p hook
);
223 static int ng_mkpeer(node_p node
, const char *name
, const char *name2
,
225 static void ng_name_rehash(void);
226 static void ng_ID_rehash(void);
227 static boolean_t
bzero_ctor(void *obj
, void *private, int ocflags
);
229 /* Imported, these used to be externally visible, some may go back. */
230 void ng_destroy_hook(hook_p hook
);
231 node_p
ng_name2noderef(node_p node
, const char *name
);
232 int ng_path2noderef(node_p here
, const char *path
,
233 node_p
*dest
, hook_p
*lasthook
);
234 int ng_make_node(const char *type
, node_p
*nodepp
);
235 int ng_path_parse(char *addr
, char **node
, char **path
, char **hook
);
236 void ng_rmnode(node_p node
, hook_p dummy1
, void *dummy2
, int dummy3
);
237 void ng_unname(node_p node
);
240 /* Our own netgraph malloc type */
241 MALLOC_DEFINE(M_NETGRAPH
, "netgraph", "netgraph structures and ctrl messages");
242 MALLOC_DEFINE(M_NETGRAPH_HOOK
, "netgraph_hook", "netgraph hook structures");
243 MALLOC_DEFINE(M_NETGRAPH_NODE
, "netgraph_node", "netgraph node structures");
244 MALLOC_DEFINE(M_NETGRAPH_MSG
, "netgraph_msg", "netgraph name storage");
245 MALLOC_DEFINE(M_NETGRAPH_APPLY
, "netgraph_apply", "netgraph apply_info structures");
247 /* Should not be visible outside this file */
249 #define _NG_ALLOC_HOOK(hook) \
250 hook = kmalloc(sizeof(*hook), M_NETGRAPH_HOOK, \
251 M_WAITOK | M_NULLOK | M_ZERO)
252 #define _NG_ALLOC_NODE(node) \
253 node = kmalloc(sizeof(*node), M_NETGRAPH_NODE, \
254 M_WAITOK | M_NULLOK | M_ZERO)
256 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/
259 * In an attempt to help track reference count screwups
260 * we do not free objects back to the malloc system, but keep them
261 * in a local cache where we can examine them and keep information safely
262 * after they have been freed.
263 * We use this scheme for nodes and hooks, and to some extent for items.
265 static __inline hook_p
269 SLIST_ENTRY(ng_hook
) temp
;
270 mtx_lock(&ng_nodelist_mtx
);
271 hook
= LIST_FIRST(&ng_freehooks
);
273 LIST_REMOVE(hook
, hk_hooks
);
274 bcopy(&hook
->hk_all
, &temp
, sizeof(temp
));
275 bzero(hook
, sizeof(struct ng_hook
));
276 bcopy(&temp
, &hook
->hk_all
, sizeof(temp
));
277 mtx_unlock(&ng_nodelist_mtx
);
278 hook
->hk_magic
= HK_MAGIC
;
280 mtx_unlock(&ng_nodelist_mtx
);
281 _NG_ALLOC_HOOK(hook
);
283 hook
->hk_magic
= HK_MAGIC
;
284 mtx_lock(&ng_nodelist_mtx
);
285 SLIST_INSERT_HEAD(&ng_allhooks
, hook
, hk_all
);
286 mtx_unlock(&ng_nodelist_mtx
);
292 static __inline node_p
296 SLIST_ENTRY(ng_node
) temp
;
297 mtx_lock(&ng_nodelist_mtx
);
298 node
= LIST_FIRST(&ng_freenodes
);
300 LIST_REMOVE(node
, nd_nodes
);
301 bcopy(&node
->nd_all
, &temp
, sizeof(temp
));
302 bzero(node
, sizeof(struct ng_node
));
303 bcopy(&temp
, &node
->nd_all
, sizeof(temp
));
304 mtx_unlock(&ng_nodelist_mtx
);
305 node
->nd_magic
= ND_MAGIC
;
307 mtx_unlock(&ng_nodelist_mtx
);
308 _NG_ALLOC_NODE(node
);
310 node
->nd_magic
= ND_MAGIC
;
311 mtx_lock(&ng_nodelist_mtx
);
312 SLIST_INSERT_HEAD(&ng_allnodes
, node
, nd_all
);
313 mtx_unlock(&ng_nodelist_mtx
);
319 #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0)
320 #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0)
323 #define NG_FREE_HOOK(hook) \
325 mtx_lock(&ng_nodelist_mtx); \
326 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \
327 hook->hk_magic = 0; \
328 mtx_unlock(&ng_nodelist_mtx); \
331 #define NG_FREE_NODE(node) \
333 mtx_lock(&ng_nodelist_mtx); \
334 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \
335 node->nd_magic = 0; \
336 mtx_unlock(&ng_nodelist_mtx); \
339 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
341 #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook)
342 #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node)
344 #define NG_FREE_HOOK(hook) do { kfree((hook), M_NETGRAPH_HOOK); } while (0)
345 #define NG_FREE_NODE(node) do { kfree((node), M_NETGRAPH_NODE); } while (0)
347 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
349 /* Set this to kdb_enter("X") to catch all errors as they occur */
354 static ng_ID_t nextID
= 1;
357 #define CHECK_DATA_MBUF(m) do { \
362 for (total = 0, n = (m); n != NULL; n = n->m_next) { \
364 if (n->m_nextpkt != NULL) \
365 panic("%s: m_nextpkt", __func__); \
368 if ((m)->m_pkthdr.len != total) { \
369 panic("%s: %d != %d", \
370 __func__, (m)->m_pkthdr.len, total); \
374 #define CHECK_DATA_MBUF(m)
377 #define ERROUT(x) do { error = (x); goto done; } while (0)
379 /************************************************************************
380 Parse type definitions for generic messages
381 ************************************************************************/
383 /* Handy structure parse type defining macro */
384 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \
385 static const struct ng_parse_struct_field \
386 ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \
387 static const struct ng_parse_type ng_generic_ ## lo ## _type = { \
388 &ng_parse_struct_type, \
389 &ng_ ## lo ## _type_fields \
392 DEFINE_PARSE_STRUCT_TYPE(mkpeer
, MKPEER
, ());
393 DEFINE_PARSE_STRUCT_TYPE(connect
, CONNECT
, ());
394 DEFINE_PARSE_STRUCT_TYPE(name
, NAME
, ());
395 DEFINE_PARSE_STRUCT_TYPE(rmhook
, RMHOOK
, ());
396 DEFINE_PARSE_STRUCT_TYPE(nodeinfo
, NODEINFO
, ());
397 DEFINE_PARSE_STRUCT_TYPE(typeinfo
, TYPEINFO
, ());
398 DEFINE_PARSE_STRUCT_TYPE(linkinfo
, LINKINFO
, (&ng_generic_nodeinfo_type
));
400 /* Get length of an array when the length is stored as a 32 bit
401 value immediately preceding the array -- as with struct namelist
402 and struct typelist. */
404 ng_generic_list_getLength(const struct ng_parse_type
*type
,
405 const u_char
*start
, const u_char
*buf
)
407 return *((const u_int32_t
*)(buf
- 4));
410 /* Get length of the array of struct linkinfo inside a struct hooklist */
412 ng_generic_linkinfo_getLength(const struct ng_parse_type
*type
,
413 const u_char
*start
, const u_char
*buf
)
415 const struct hooklist
*hl
= (const struct hooklist
*)start
;
417 return hl
->nodeinfo
.hooks
;
420 /* Array type for a variable length array of struct namelist */
421 static const struct ng_parse_array_info ng_nodeinfoarray_type_info
= {
422 &ng_generic_nodeinfo_type
,
423 &ng_generic_list_getLength
425 static const struct ng_parse_type ng_generic_nodeinfoarray_type
= {
426 &ng_parse_array_type
,
427 &ng_nodeinfoarray_type_info
430 /* Array type for a variable length array of struct typelist */
431 static const struct ng_parse_array_info ng_typeinfoarray_type_info
= {
432 &ng_generic_typeinfo_type
,
433 &ng_generic_list_getLength
435 static const struct ng_parse_type ng_generic_typeinfoarray_type
= {
436 &ng_parse_array_type
,
437 &ng_typeinfoarray_type_info
440 /* Array type for array of struct linkinfo in struct hooklist */
441 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info
= {
442 &ng_generic_linkinfo_type
,
443 &ng_generic_linkinfo_getLength
445 static const struct ng_parse_type ng_generic_linkinfo_array_type
= {
446 &ng_parse_array_type
,
447 &ng_generic_linkinfo_array_type_info
450 DEFINE_PARSE_STRUCT_TYPE(typelist
, TYPELIST
, (&ng_generic_typeinfoarray_type
));
451 DEFINE_PARSE_STRUCT_TYPE(hooklist
, HOOKLIST
,
452 (&ng_generic_nodeinfo_type
, &ng_generic_linkinfo_array_type
));
453 DEFINE_PARSE_STRUCT_TYPE(listnodes
, LISTNODES
,
454 (&ng_generic_nodeinfoarray_type
));
456 /* List of commands and how to convert arguments to/from ASCII */
457 static const struct ng_cmdlist ng_generic_cmds
[] = {
469 &ng_generic_mkpeer_type
,
476 &ng_generic_connect_type
,
483 &ng_generic_name_type
,
490 &ng_generic_rmhook_type
,
498 &ng_generic_nodeinfo_type
505 &ng_generic_hooklist_type
512 &ng_generic_listnodes_type
/* same as NGM_LISTNODES */
519 &ng_generic_listnodes_type
526 &ng_generic_typeinfo_type
533 &ng_parse_string_type
540 &ng_parse_string_type
546 &ng_parse_ng_mesg_type
,
547 &ng_parse_ng_mesg_type
553 &ng_parse_ng_mesg_type
,
554 &ng_parse_ng_mesg_type
559 /************************************************************************
561 ************************************************************************/
564 * Instantiate a node of the requested type
567 ng_make_node(const char *typename
, node_p
*nodepp
)
569 struct ng_type
*type
;
572 /* Check that the type makes sense */
573 if (typename
== NULL
) {
578 /* Locate the node type. If we fail we return. Do not try to load
581 if ((type
= ng_findtype(typename
)) == NULL
)
585 * If we have a constructor, then make the node and
586 * call the constructor to do type specific initialisation.
588 if (type
->constructor
!= NULL
) {
589 if ((error
= ng_make_node_common(type
, nodepp
)) == 0) {
590 if ((error
= ((*type
->constructor
)(*nodepp
))) != 0) {
591 NG_NODE_UNREF(*nodepp
);
596 * Node has no constructor. We cannot ask for one
597 * to be made. It must be brought into existence by
598 * some external agency. The external agency should
599 * call ng_make_node_common() directly to get the
600 * netgraph part initialised.
609 * Generic node creation. Called by node initialisation for externally
610 * instantiated nodes (e.g. hardware, sockets, etc ).
611 * The returned node has a reference count of 1.
614 ng_make_node_common(struct ng_type
*type
, node_p
*nodepp
)
618 /* Require the node type to have been already installed */
619 if (ng_findtype(type
->name
) == NULL
) {
624 /* Make a node and try attach it to the type */
630 node
->nd_type
= type
;
631 NG_NODE_REF(node
); /* note reference */
634 /* Initialize the reader/writer shared token */
635 lwkt_token_init(&node
->nd_token
, type
->name
);
637 /* Initialize hook list for new node */
638 LIST_INIT(&node
->nd_hooks
);
640 /* Get an ID and put us in the hash chain. */
642 for (;;) { /* wrap protection, even if silly */
644 node
->nd_ID
= nextID
++; /* 137/second for 1 year before wrap */
646 /* Is there a problem with the new number? */
647 NG_IDHASH_FIND(node
->nd_ID
, node2
); /* already taken? */
648 if ((node
->nd_ID
!= 0) && (node2
== NULL
)) {
653 if (ng_nodes
* 2 > ng_ID_hmask
)
655 LIST_INSERT_HEAD(&ng_ID_hash
[NG_IDHASH_FN(node
->nd_ID
)], node
,
665 * Forceably start the shutdown process on a node. Either call
666 * its shutdown method, or do the default shutdown if there is
667 * no type-specific method.
669 * We can only be called from a shutdown message, so we know we have
670 * a writer lock, and therefore exclusive access.
672 * Persistent node types must have a type-specific method which
673 * allocates a new node in which case, this one is irretrievably going away,
674 * or cleans up anything it needs, and just makes the node valid again,
675 * in which case we allow the node to survive.
677 * XXX We need to think of how to tell a persistent node that we
678 * REALLY need to go away because the hardware has gone or we
679 * are rebooting.... etc.
682 ng_rmnode(node_p node
, hook_p dummy1
, void *dummy2
, int dummy3
)
686 /* Check if it's already shutting down */
687 if ((node
->nd_flags
& NGF_CLOSING
) != 0)
690 if (node
== &ng_deadnode
) {
691 kprintf ("shutdown called on deadnode\n");
695 /* Add an extra reference so it doesn't go away during this */
699 * Mark it invalid so any newcomers know not to try use it
700 * Also add our own mark so we can't recurse
701 * note that NGF_INVALID does not do this as it's also set during
704 node
->nd_flags
|= NGF_INVALID
|NGF_CLOSING
;
706 /* If node has its pre-shutdown method, then call it first*/
707 if (node
->nd_type
&& node
->nd_type
->close
)
708 (*node
->nd_type
->close
)(node
);
710 /* Notify all remaining connected nodes to disconnect */
711 while ((hook
= LIST_FIRST(&node
->nd_hooks
)) != NULL
)
712 ng_destroy_hook(hook
);
714 /* Ask the type if it has anything to do in this case */
715 if (node
->nd_type
&& node
->nd_type
->shutdown
) {
716 (*node
->nd_type
->shutdown
)(node
);
717 if (NG_NODE_IS_VALID(node
)) {
719 * Well, blow me down if the node code hasn't declared
720 * that it doesn't want to die.
721 * Presumably it is a persistant node.
722 * If we REALLY want it to go away,
723 * e.g. hardware going away,
724 * Our caller should set NGF_REALLY_DIE in nd_flags.
726 node
->nd_flags
&= ~(NGF_INVALID
|NGF_CLOSING
);
727 NG_NODE_UNREF(node
); /* Assume they still have theirs */
730 } else { /* do the default thing */
734 ng_unname(node
); /* basically a NOP these days */
737 * Remove extra reference, possibly the last
738 * Possible other holders of references may include
739 * timeout callouts, but theoretically the node's supposed to
740 * have cancelled them. Possibly hardware dependencies may
741 * force a driver to 'linger' with a reference.
747 * Remove a reference to the node, possibly the last.
748 * deadnode always acts as it it were the last.
751 ng_unref_node(node_p node
)
754 if (node
== &ng_deadnode
)
757 if (refcount_release(&node
->nd_refs
)) { /* we were the last */
759 node
->nd_type
->refs
--; /* XXX maybe should get types lock? */
761 if (NG_NODE_HAS_NAME(node
)) {
763 LIST_REMOVE(node
, nd_nodes
);
769 LIST_REMOVE(node
, nd_idnodes
);
776 /************************************************************************
778 ************************************************************************/
780 ng_ID2noderef(ng_ID_t ID
)
785 NG_IDHASH_FIND(ID
, node
);
793 ng_node2ID(node_p node
)
795 return (node
? NG_NODE_ID(node
) : 0);
798 /************************************************************************
800 ************************************************************************/
803 * Assign a node a name.
806 ng_name_node(node_p node
, const char *name
)
812 /* Check the name is valid */
813 for (i
= 0; i
< NG_NODESIZ
; i
++) {
814 if (name
[i
] == '\0' || name
[i
] == '.' || name
[i
] == ':')
817 if (i
== 0 || name
[i
] != '\0') {
821 if (ng_decodeidname(name
) != 0) { /* valid IDs not allowed here */
827 if (ng_named_nodes
* 2 > ng_name_hmask
)
830 hash
= hash32_str(name
, HASHINIT
) & ng_name_hmask
;
831 /* Check the name isn't already being used. */
832 LIST_FOREACH(node2
, &ng_name_hash
[hash
], nd_nodes
)
833 if (NG_NODE_IS_VALID(node2
) &&
834 (strcmp(NG_NODE_NAME(node2
), name
) == 0)) {
839 if (NG_NODE_HAS_NAME(node
))
840 LIST_REMOVE(node
, nd_nodes
);
844 strlcpy(NG_NODE_NAME(node
), name
, NG_NODESIZ
);
846 /* Update name hash. */
847 LIST_INSERT_HEAD(&ng_name_hash
[hash
], node
, nd_nodes
);
854 * Find a node by absolute name. The name should NOT end with ':'
855 * The name "." means "this node" and "[xxx]" means "the node
856 * with ID (ie, at address) xxx".
858 * Returns the node if found, else NULL.
859 * Eventually should add something faster than a sequential search.
860 * Note it acquires a reference on the node so you can be sure it's still
864 ng_name2noderef(node_p here
, const char *name
)
870 /* "." means "this node" */
871 if (strcmp(name
, ".") == 0) {
876 /* Check for name-by-ID */
877 if ((temp
= ng_decodeidname(name
)) != 0) {
878 return (ng_ID2noderef(temp
));
881 /* Find node by name. */
882 hash
= hash32_str(name
, HASHINIT
) & ng_name_hmask
;
884 LIST_FOREACH(node
, &ng_name_hash
[hash
], nd_nodes
)
885 if (NG_NODE_IS_VALID(node
) &&
886 (strcmp(NG_NODE_NAME(node
), name
) == 0)) {
896 * Decode an ID name, eg. "[f03034de]". Returns 0 if the
897 * string is not valid, otherwise returns the value.
900 ng_decodeidname(const char *name
)
902 const int len
= strlen(name
);
906 /* Check for proper length, brackets, no leading junk */
909 || (name
[len
- 1] != ']')
910 || (!isxdigit(name
[1]))) {
915 val
= strtoul(name
+ 1, &eptr
, 16);
916 if ((eptr
- name
!= len
- 1)
917 || (val
== ULONG_MAX
)
925 * Remove a name from a node. This should only be called
926 * when shutting down and removing the node.
929 ng_unname(node_p node
)
934 * Allocate a bigger name hash.
939 struct nodehash
*new;
945 NAMEHASH_ASSERT_LOCKED();
946 new = hashinit((ng_name_hmask
+ 1) * 2, M_NETGRAPH_NODE
, &hmask
);
950 for (i
= 0; i
<= ng_name_hmask
; i
++) {
951 LIST_FOREACH_MUTABLE(node
, &ng_name_hash
[i
], nd_nodes
, node2
) {
953 LIST_REMOVE(node
, nd_nodes
);
955 hash
= hash32_str(NG_NODE_NAME(node
), HASHINIT
) & hmask
;
956 LIST_INSERT_HEAD(&new[hash
], node
, nd_nodes
);
960 hashdestroy(ng_name_hash
, M_NETGRAPH_NODE
, ng_name_hmask
);
962 ng_name_hmask
= hmask
;
966 * Allocate a bigger ID hash.
971 struct nodehash
*new;
977 IDHASH_ASSERT_LOCKED();
978 new = hashinit((ng_ID_hmask
+ 1) * 2, M_NETGRAPH_NODE
, &hmask
);
982 for (i
= 0; i
<= ng_ID_hmask
; i
++) {
983 LIST_FOREACH_MUTABLE(node
, &ng_ID_hash
[i
], nd_idnodes
, node2
) {
985 LIST_REMOVE(node
, nd_idnodes
);
987 hash
= (node
->nd_ID
% (hmask
+ 1));
988 LIST_INSERT_HEAD(&new[hash
], node
, nd_idnodes
);
992 hashdestroy(ng_ID_hash
, M_NETGRAPH_NODE
, ng_name_hmask
);
997 /************************************************************************
999 Names are not optional. Hooks are always connected, except for a
1000 brief moment within these routines. On invalidation or during creation
1001 they are connected to the 'dead' hook.
1002 ************************************************************************/
1005 * Remove a hook reference
1008 ng_unref_hook(hook_p hook
)
1012 if (hook
== &ng_deadhook
) {
1016 v
= atomic_fetchadd_int(&hook
->hk_refs
, -1);
1018 if (v
== 1) { /* we were the last */
1019 if (_NG_HOOK_NODE(hook
)) /* it'll probably be ng_deadnode */
1020 _NG_NODE_UNREF((_NG_HOOK_NODE(hook
)));
1026 * Add an unconnected hook to a node. Only used internally.
1027 * Assumes node is locked. (XXX not yet true )
1030 ng_add_hook(node_p node
, const char *name
, hook_p
*hookp
)
1035 /* Check that the given name is good */
1040 if (ng_findhook(node
, name
) != NULL
) {
1045 /* Allocate the hook and link it up */
1046 NG_ALLOC_HOOK(hook
);
1051 hook
->hk_refs
= 1; /* add a reference for us to return */
1052 hook
->hk_flags
= HK_INVALID
;
1053 hook
->hk_peer
= &ng_deadhook
; /* start off this way */
1054 hook
->hk_node
= node
;
1055 NG_NODE_REF(node
); /* each hook counts as a reference */
1058 strlcpy(NG_HOOK_NAME(hook
), name
, NG_HOOKSIZ
);
1061 * Check if the node type code has something to say about it
1062 * If it fails, the unref of the hook will also unref the node.
1064 if (node
->nd_type
->newhook
!= NULL
) {
1065 if ((error
= (*node
->nd_type
->newhook
)(node
, hook
, name
))) {
1066 NG_HOOK_UNREF(hook
); /* this frees the hook */
1071 * The 'type' agrees so far, so go ahead and link it in.
1072 * We'll ask again later when we actually connect the hooks.
1074 LIST_INSERT_HEAD(&node
->nd_hooks
, hook
, hk_hooks
);
1075 node
->nd_numhooks
++;
1076 NG_HOOK_REF(hook
); /* one for the node */
1086 * Node types may supply their own optimized routines for finding
1087 * hooks. If none is supplied, we just do a linear search.
1088 * XXX Possibly we should add a reference to the hook?
1091 ng_findhook(node_p node
, const char *name
)
1095 if (node
->nd_type
->findhook
!= NULL
)
1096 return (*node
->nd_type
->findhook
)(node
, name
);
1097 LIST_FOREACH(hook
, &node
->nd_hooks
, hk_hooks
) {
1098 if (NG_HOOK_IS_VALID(hook
)
1099 && (strcmp(NG_HOOK_NAME(hook
), name
) == 0))
1108 * As hooks are always attached, this really destroys two hooks.
1109 * The one given, and the one attached to it. Disconnect the hooks
1110 * from each other first. We reconnect the peer hook to the 'dead'
1111 * hook so that it can still exist after we depart. We then
1112 * send the peer its own destroy message. This ensures that we only
1113 * interact with the peer's structures when it is locked processing that
1114 * message. We hold a reference to the peer hook so we are guaranteed that
1115 * the peer hook and node are still going to exist until
1116 * we are finished there as the hook holds a ref on the node.
1117 * We run this same code again on the peer hook, but that time it is already
1118 * attached to the 'dead' hook.
1120 * This routine is called at all stages of hook creation
1121 * on error detection and must be able to handle any such stage.
1124 ng_destroy_hook(hook_p hook
)
1129 if (hook
== &ng_deadhook
) { /* better safe than sorry */
1130 kprintf("ng_destroy_hook called on deadhook\n");
1135 * Protect divorce process with mutex, to avoid races on
1136 * simultaneous disconnect.
1140 hook
->hk_flags
|= HK_INVALID
;
1142 peer
= NG_HOOK_PEER(hook
);
1143 node
= NG_HOOK_NODE(hook
);
1145 if (peer
&& (peer
!= &ng_deadhook
)) {
1147 * Set the peer to point to ng_deadhook
1148 * from this moment on we are effectively independent it.
1149 * send it an rmhook message of it's own.
1151 peer
->hk_peer
= &ng_deadhook
; /* They no longer know us */
1152 hook
->hk_peer
= &ng_deadhook
; /* Nor us, them */
1153 if (NG_HOOK_NODE(peer
) == &ng_deadnode
) {
1155 * If it's already divorced from a node,
1161 ng_rmhook_self(peer
); /* Send it a surprise */
1163 NG_HOOK_UNREF(peer
); /* account for peer link */
1164 NG_HOOK_UNREF(hook
); /* account for peer link */
1168 TOPOLOGY_NOTOWNED();
1171 * Remove the hook from the node's list to avoid possible recursion
1172 * in case the disconnection results in node shutdown.
1174 if (node
== &ng_deadnode
) { /* happens if called from ng_con_nodes() */
1177 LIST_REMOVE(hook
, hk_hooks
);
1178 node
->nd_numhooks
--;
1179 if (node
->nd_type
->disconnect
) {
1181 * The type handler may elect to destroy the node so don't
1182 * trust its existence after this point. (except
1183 * that we still hold a reference on it. (which we
1184 * inherrited from the hook we are destroying)
1186 (*node
->nd_type
->disconnect
) (hook
);
1190 * Note that because we will point to ng_deadnode, the original node
1191 * is not decremented automatically so we do that manually.
1193 _NG_HOOK_NODE(hook
) = &ng_deadnode
;
1194 NG_NODE_UNREF(node
); /* We no longer point to it so adjust count */
1195 NG_HOOK_UNREF(hook
); /* Account for linkage (in list) to node */
1199 * Take two hooks on a node and merge the connection so that the given node
1200 * is effectively bypassed.
1203 ng_bypass(hook_p hook1
, hook_p hook2
)
1205 if (hook1
->hk_node
!= hook2
->hk_node
) {
1209 hook1
->hk_peer
->hk_peer
= hook2
->hk_peer
;
1210 hook2
->hk_peer
->hk_peer
= hook1
->hk_peer
;
1212 hook1
->hk_peer
= &ng_deadhook
;
1213 hook2
->hk_peer
= &ng_deadhook
;
1215 NG_HOOK_UNREF(hook1
);
1216 NG_HOOK_UNREF(hook2
);
1218 /* XXX If we ever cache methods on hooks update them as well */
1219 ng_destroy_hook(hook1
);
1220 ng_destroy_hook(hook2
);
1225 * Install a new netgraph type
1228 ng_newtype(struct ng_type
*tp
)
1230 const size_t namelen
= strlen(tp
->name
);
1232 /* Check version and type name fields */
1233 if ((tp
->version
!= NG_ABI_VERSION
)
1235 || (namelen
>= NG_TYPESIZ
)) {
1237 if (tp
->version
!= NG_ABI_VERSION
) {
1238 kprintf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n");
1243 /* Check for name collision */
1244 if (ng_findtype(tp
->name
) != NULL
) {
1249 /* Link in new type */
1251 LIST_INSERT_HEAD(&ng_typelist
, tp
, types
);
1252 tp
->refs
= 1; /* first ref is linked list */
1258 * unlink a netgraph type
1259 * If no examples exist
1262 ng_rmtype(struct ng_type
*tp
)
1264 /* Check for name collision */
1265 if (tp
->refs
!= 1) {
1272 LIST_REMOVE(tp
, types
);
1278 * Look for a type of the name given
1281 ng_findtype(const char *typename
)
1283 struct ng_type
*type
;
1286 LIST_FOREACH(type
, &ng_typelist
, types
) {
1287 if (strcmp(type
->name
, typename
) == 0)
1294 /************************************************************************
1296 ************************************************************************/
1298 * Connect two nodes using the specified hooks, using queued functions.
1301 ng_con_part3(node_p node
, item_p item
, hook_p hook
)
1306 * When we run, we know that the node 'node' is locked for us.
1307 * Our caller has a reference on the hook.
1308 * Our caller has a reference on the node.
1309 * (In this case our caller is ng_apply_item() ).
1310 * The peer hook has a reference on the hook.
1311 * We are all set up except for the final call to the node, and
1312 * the clearing of the INVALID flag.
1314 if (NG_HOOK_NODE(hook
) == &ng_deadnode
) {
1316 * The node must have been freed again since we last visited
1317 * here. ng_destry_hook() has this effect but nothing else does.
1318 * We should just release our references and
1319 * free anything we can think of.
1320 * Since we know it's been destroyed, and it's our caller
1321 * that holds the references, just return.
1325 if (hook
->hk_node
->nd_type
->connect
) {
1326 if ((error
= (*hook
->hk_node
->nd_type
->connect
) (hook
))) {
1327 ng_destroy_hook(hook
); /* also zaps peer */
1328 kprintf("failed in ng_con_part3()\n");
1333 * XXX this is wrong for SMP. Possibly we need
1334 * to separate out 'create' and 'invalid' flags.
1335 * should only set flags on hooks we have locked under our node.
1337 hook
->hk_flags
&= ~HK_INVALID
;
1344 ng_con_part2(node_p node
, item_p item
, hook_p hook
)
1350 * When we run, we know that the node 'node' is locked for us.
1351 * Our caller has a reference on the hook.
1352 * Our caller has a reference on the node.
1353 * (In this case our caller is ng_apply_item() ).
1354 * The peer hook has a reference on the hook.
1355 * our node pointer points to the 'dead' node.
1356 * First check the hook name is unique.
1357 * Should not happen because we checked before queueing this.
1359 if (ng_findhook(node
, NG_HOOK_NAME(hook
)) != NULL
) {
1361 ng_destroy_hook(hook
); /* should destroy peer too */
1362 kprintf("failed in ng_con_part2()\n");
1366 * Check if the node type code has something to say about it
1367 * If it fails, the unref of the hook will also unref the attached node,
1368 * however since that node is 'ng_deadnode' this will do nothing.
1369 * The peer hook will also be destroyed.
1371 if (node
->nd_type
->newhook
!= NULL
) {
1372 if ((error
= (*node
->nd_type
->newhook
)(node
, hook
,
1374 ng_destroy_hook(hook
); /* should destroy peer too */
1375 kprintf("failed in ng_con_part2()\n");
1381 * The 'type' agrees so far, so go ahead and link it in.
1382 * We'll ask again later when we actually connect the hooks.
1384 hook
->hk_node
= node
; /* just overwrite ng_deadnode */
1385 NG_NODE_REF(node
); /* each hook counts as a reference */
1386 LIST_INSERT_HEAD(&node
->nd_hooks
, hook
, hk_hooks
);
1387 node
->nd_numhooks
++;
1388 NG_HOOK_REF(hook
); /* one for the node */
1391 * We now have a symmetrical situation, where both hooks have been
1392 * linked to their nodes, the newhook methods have been called
1393 * And the references are all correct. The hooks are still marked
1394 * as invalid, as we have not called the 'connect' methods
1396 * We can call the local one immediately as we have the
1397 * node locked, but we need to queue the remote one.
1399 if (hook
->hk_node
->nd_type
->connect
) {
1400 if ((error
= (*hook
->hk_node
->nd_type
->connect
) (hook
))) {
1401 ng_destroy_hook(hook
); /* also zaps peer */
1402 kprintf("failed in ng_con_part2(A)\n");
1408 * Acquire topo token to avoid race with ng_destroy_hook().
1411 peer
= hook
->hk_peer
;
1412 if (peer
== &ng_deadhook
) {
1414 kprintf("failed in ng_con_part2(B)\n");
1415 ng_destroy_hook(hook
);
1420 if ((error
= ng_send_fn2(peer
->hk_node
, peer
, item
, &ng_con_part3
,
1421 NULL
, 0, NG_REUSE_ITEM
))) {
1422 kprintf("failed in ng_con_part2(C)\n");
1423 ng_destroy_hook(hook
); /* also zaps peer */
1424 return (error
); /* item was consumed. */
1426 hook
->hk_flags
&= ~HK_INVALID
; /* need both to be able to work */
1427 return (0); /* item was consumed. */
1434 * Connect this node with another node. We assume that this node is
1435 * currently locked, as we are only called from an NGM_CONNECT message.
1438 ng_con_nodes(item_p item
, node_p node
, const char *name
,
1439 node_p node2
, const char *name2
)
1445 if (ng_findhook(node2
, name2
) != NULL
) {
1448 if ((error
= ng_add_hook(node
, name
, &hook
))) /* gives us a ref */
1450 /* Allocate the other hook and link it up */
1451 NG_ALLOC_HOOK(hook2
);
1452 if (hook2
== NULL
) {
1454 ng_destroy_hook(hook
); /* XXX check ref counts so far */
1455 NG_HOOK_UNREF(hook
); /* including our ref */
1458 hook2
->hk_refs
= 1; /* start with a reference for us. */
1459 hook2
->hk_flags
= HK_INVALID
;
1460 hook2
->hk_peer
= hook
; /* Link the two together */
1461 hook
->hk_peer
= hook2
;
1462 NG_HOOK_REF(hook
); /* Add a ref for the peer to each*/
1464 hook2
->hk_node
= &ng_deadnode
;
1465 strlcpy(NG_HOOK_NAME(hook2
), name2
, NG_HOOKSIZ
);
1468 * Queue the function above.
1469 * Procesing continues in that function in the lock context of
1472 if ((error
= ng_send_fn2(node2
, hook2
, item
, &ng_con_part2
, NULL
, 0,
1474 kprintf("failed in ng_con_nodes(): %d\n", error
);
1475 ng_destroy_hook(hook
); /* also zaps peer */
1478 NG_HOOK_UNREF(hook
); /* Let each hook go if it wants to */
1479 NG_HOOK_UNREF(hook2
);
1484 * Make a peer and connect.
1485 * We assume that the local node is locked.
1486 * The new node probably doesn't need a lock until
1487 * it has a hook, because it cannot really have any work until then,
1488 * but we should think about it a bit more.
1490 * The problem may come if the other node also fires up
1491 * some hardware or a timer or some other source of activation,
1492 * also it may already get a command msg via it's ID.
1494 * We could use the same method as ng_con_nodes() but we'd have
1495 * to add ability to remove the node when failing. (Not hard, just
1496 * make arg1 point to the node to remove).
1497 * Unless of course we just ignore failure to connect and leave
1498 * an unconnected node?
1501 ng_mkpeer(node_p node
, const char *name
, const char *name2
, char *type
)
1504 hook_p hook1
, hook2
;
1507 if ((error
= ng_make_node(type
, &node2
))) {
1511 if ((error
= ng_add_hook(node
, name
, &hook1
))) { /* gives us a ref */
1512 ng_rmnode(node2
, NULL
, NULL
, 0);
1516 if ((error
= ng_add_hook(node2
, name2
, &hook2
))) {
1517 ng_rmnode(node2
, NULL
, NULL
, 0);
1518 ng_destroy_hook(hook1
);
1519 NG_HOOK_UNREF(hook1
);
1524 * Actually link the two hooks together.
1526 hook1
->hk_peer
= hook2
;
1527 hook2
->hk_peer
= hook1
;
1529 /* Each hook is referenced by the other */
1533 /* Give each node the opportunity to veto the pending connection */
1534 if (hook1
->hk_node
->nd_type
->connect
) {
1535 error
= (*hook1
->hk_node
->nd_type
->connect
) (hook1
);
1538 if ((error
== 0) && hook2
->hk_node
->nd_type
->connect
) {
1539 error
= (*hook2
->hk_node
->nd_type
->connect
) (hook2
);
1544 * drop the references we were holding on the two hooks.
1547 ng_destroy_hook(hook2
); /* also zaps hook1 */
1548 ng_rmnode(node2
, NULL
, NULL
, 0);
1550 /* As a last act, allow the hooks to be used */
1551 hook1
->hk_flags
&= ~HK_INVALID
;
1552 hook2
->hk_flags
&= ~HK_INVALID
;
1554 NG_HOOK_UNREF(hook1
);
1555 NG_HOOK_UNREF(hook2
);
1559 /************************************************************************
1560 Utility routines to send self messages
1561 ************************************************************************/
1563 /* Shut this node down as soon as everyone is clear of it */
1564 /* Should add arg "immediately" to jump the queue */
1566 ng_rmnode_self(node_p node
)
1570 if (node
== &ng_deadnode
)
1572 node
->nd_flags
|= NGF_INVALID
;
1573 if (node
->nd_flags
& NGF_CLOSING
)
1576 error
= ng_send_fn(node
, NULL
, &ng_rmnode
, NULL
, 0);
1581 ng_rmhook_part2(node_p node
, hook_p hook
, void *arg1
, int arg2
)
1583 ng_destroy_hook(hook
);
1588 ng_rmhook_self(hook_p hook
)
1591 node_p node
= NG_HOOK_NODE(hook
);
1593 if (node
== &ng_deadnode
)
1596 error
= ng_send_fn(node
, hook
, &ng_rmhook_part2
, NULL
, 0);
1600 /***********************************************************************
1601 * Parse and verify a string of the form: <NODE:><PATH>
1603 * Such a string can refer to a specific node or a specific hook
1604 * on a specific node, depending on how you look at it. In the
1605 * latter case, the PATH component must not end in a dot.
1607 * Both <NODE:> and <PATH> are optional. The <PATH> is a string
1608 * of hook names separated by dots. This breaks out the original
1609 * string, setting *nodep to "NODE" (or NULL if none) and *pathp
1610 * to "PATH" (or NULL if degenerate). Also, *hookp will point to
1611 * the final hook component of <PATH>, if any, otherwise NULL.
1613 * This returns -1 if the path is malformed. The char ** are optional.
1614 ***********************************************************************/
1616 ng_path_parse(char *addr
, char **nodep
, char **pathp
, char **hookp
)
1618 char *node
, *path
, *hook
;
1622 * Extract absolute NODE, if any
1624 for (path
= addr
; *path
&& *path
!= ':'; path
++);
1626 node
= addr
; /* Here's the NODE */
1627 *path
++ = '\0'; /* Here's the PATH */
1629 /* Node name must not be empty */
1633 /* A name of "." is OK; otherwise '.' not allowed */
1634 if (strcmp(node
, ".") != 0) {
1635 for (k
= 0; node
[k
]; k
++)
1640 node
= NULL
; /* No absolute NODE */
1641 path
= addr
; /* Here's the PATH */
1644 /* Snoop for illegal characters in PATH */
1645 for (k
= 0; path
[k
]; k
++)
1649 /* Check for no repeated dots in PATH */
1650 for (k
= 0; path
[k
]; k
++)
1651 if (path
[k
] == '.' && path
[k
+ 1] == '.')
1654 /* Remove extra (degenerate) dots from beginning or end of PATH */
1657 if (*path
&& path
[strlen(path
) - 1] == '.')
1658 path
[strlen(path
) - 1] = 0;
1660 /* If PATH has a dot, then we're not talking about a hook */
1662 for (hook
= path
, k
= 0; path
[k
]; k
++)
1663 if (path
[k
] == '.') {
1681 * Given a path, which may be absolute or relative, and a starting node,
1682 * return the destination node.
1685 ng_path2noderef(node_p here
, const char *address
,
1686 node_p
*destp
, hook_p
*lasthook
)
1688 char fullpath
[NG_PATHSIZ
];
1689 char *nodename
, *path
, pbuf
[2];
1690 node_p node
, oldnode
;
1695 if (destp
== NULL
) {
1701 /* Make a writable copy of address for ng_path_parse() */
1702 strncpy(fullpath
, address
, sizeof(fullpath
) - 1);
1703 fullpath
[sizeof(fullpath
) - 1] = '\0';
1705 /* Parse out node and sequence of hooks */
1706 if (ng_path_parse(fullpath
, &nodename
, &path
, NULL
) < 0) {
1711 pbuf
[0] = '.'; /* Needs to be writable */
1717 * For an absolute address, jump to the starting node.
1718 * Note that this holds a reference on the node for us.
1719 * Don't forget to drop the reference if we don't need it.
1722 node
= ng_name2noderef(here
, nodename
);
1737 * Now follow the sequence of hooks
1739 * We actually cannot guarantee that the sequence
1740 * is not being demolished as we crawl along it
1741 * without extra-ordinary locking etc.
1742 * So this is a bit dodgy to say the least.
1743 * We can probably hold up some things by holding
1744 * the nodelist mutex for the time of this
1745 * crawl if we wanted.. At least that way we wouldn't have to
1746 * worry about the nodes disappearing, but the hooks would still
1749 for (cp
= path
; node
!= NULL
&& *cp
!= '\0'; ) {
1753 * Break out the next path segment. Replace the dot we just
1754 * found with a NUL; "cp" points to the next segment (or the
1757 for (segment
= cp
; *cp
!= '\0'; cp
++) {
1765 if (*segment
== '\0')
1768 /* We have a segment, so look for a hook by that name */
1769 hook
= ng_findhook(node
, segment
);
1771 /* Can't get there from here... */
1773 || NG_HOOK_PEER(hook
) == NULL
1774 || NG_HOOK_NOT_VALID(hook
)
1775 || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook
))) {
1777 NG_NODE_UNREF(node
);
1779 kprintf("hooknotvalid %s %s %d %d %d %d ",
1783 NG_HOOK_PEER(hook
) == NULL
,
1784 NG_HOOK_NOT_VALID(hook
),
1785 NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook
)));
1791 * Hop on over to the next node
1793 * Big race conditions here as hooks and nodes go away
1794 * *** Idea.. store an ng_ID_t in each hook and use that
1795 * instead of the direct hook in this crawl?
1798 if ((node
= NG_PEER_NODE(hook
)))
1799 NG_NODE_REF(node
); /* XXX RACE */
1800 NG_NODE_UNREF(oldnode
); /* XXX another race */
1801 if (NG_NODE_NOT_VALID(node
)) {
1802 NG_NODE_UNREF(node
); /* XXX more races */
1807 /* If node somehow missing, fail here (probably this is not needed) */
1815 if (lasthook
!= NULL
)
1816 *lasthook
= (hook
? NG_HOOK_PEER(hook
) : NULL
);
1820 /*********************************************************************\
1821 * Inter-CPU node synchronization
1823 * All activities are submitted to one of the netgraph per-CPU threads.
1824 * There is one item input queue per CPU, not one per node as in
1825 * FreeBSD. If the item is entering netgraph for the first time, it is
1826 * queued to the thread's msgport. Otherwise it is applied directly.
1827 * From start to finish, the item is processed on the same CPU. Items
1828 * are distributed based on the ingress node, to keep item ordering.
1829 \***************************************************************/
1831 static __inline
void ng_acquire_read(node_p node
);
1832 static __inline
void ng_acquire_write(node_p node
);
1833 static __inline
void ng_leave_readwrite(node_p node
);
1835 static __inline
void
1836 ng_acquire_read(node_p node
)
1838 KASSERT(node
!= &ng_deadnode
,
1839 ("%s: working on deadnode", __func__
));
1841 lwkt_gettoken_shared(&node
->nd_token
);
1844 /* Acquire writer lock on node. If node is busy, sleep. */
1845 static __inline
void
1846 ng_acquire_write(node_p node
)
1848 KASSERT(node
!= &ng_deadnode
,
1849 ("%s: working on deadnode", __func__
));
1851 lwkt_gettoken(&node
->nd_token
);
1854 /* Release reader or writer lock. */
1855 static __inline
void
1856 ng_leave_readwrite(node_p node
)
1858 lwkt_reltoken(&node
->nd_token
);
1861 /***********************************************************************
1863 **********************************************************************/
1864 /* NETGRAPH thread routine
1866 * Pick an item from our thread's queue and apply it.
1869 ngthread(void *dummy __unused
)
1873 while ((msg
= lwkt_waitport(&curthread
->td_msgport
, 0)) != NULL
) {
1874 item_p item
= (void *)msg
;
1876 ng_apply_item(item
);
1877 /* Do not reply to the message */
1881 /***********************************************************************
1882 * Externally visible method for sending or queueing messages or data.
1883 ***********************************************************************/
1886 * The module code should have filled out the item correctly by this stage:
1888 * reference to destination node.
1889 * Reference to destination rcv hook if relevant.
1890 * apply pointer must be or NULL or reference valid struct ng_apply_info.
1895 * ID of original sender node. (return address)
1901 * The nodes have several routines and macros to help with this task:
1905 ng_snd_item(item_p item
, int flags
)
1911 /* We are sending item, so it must be present! */
1912 KASSERT(item
!= NULL
, ("ng_snd_item: item is NULL"));
1914 #ifdef NETGRAPH_DEBUG
1915 _ngi_check(item
, __FILE__
, __LINE__
);
1919 * Every time an item is sent or forwarded we hold a reference on it
1920 * to postone the callback (if there is one) and item freedom.
1925 * Node is never optional.
1927 node
= NGI_NODE(item
);
1928 KASSERT(node
!= NULL
, ("ng_snd_item: node is NULL"));
1931 * Valid hook and mbuf are mandatory for data.
1933 hook
= NGI_HOOK(item
);
1934 if ((item
->el_flags
& NGQF_TYPE
) == NGQF_DATA
) {
1935 KASSERT(hook
!= NULL
, ("ng_snd_item: hook for data is NULL"));
1936 if (NGI_M(item
) == NULL
)
1938 CHECK_DATA_MBUF(NGI_M(item
));
1942 * Always queue items entering netgraph for the first time.
1944 if (item
->refs
== 1) {
1945 struct lwkt_msg
*msg
= &item
->el_lmsg
;
1947 lwkt_initmsg(msg
, &ng_panic_reply_port
, 0);
1948 /* Always send to cpu0 for now */
1949 lwkt_sendmsg(ng_cpuport(0), msg
);
1951 return ((flags
& NG_PROGRESS
) ? EINPROGRESS
: 0);
1955 * The item wasn't queued. Process it synchronously.
1957 error
= ng_apply_item(item
);
1964 * We have an item that was possibly queued somewhere.
1965 * It should contain all the information needed
1966 * to run it on the appropriate node/hook.
1967 * If there is apply pointer and we own the last reference, call apply().
1970 ng_apply_item(item_p item
)
1974 ng_rcvdata_t
*rcvdata
;
1975 ng_rcvmsg_t
*rcvmsg
;
1978 /* Node and item are never optional. */
1979 KASSERT(item
!= NULL
, ("ng_apply_item: item is NULL"));
1980 NGI_GET_NODE(item
, node
); /* zaps stored node */
1981 KASSERT(node
!= NULL
, ("ng_apply_item: node is NULL"));
1982 NGI_GET_HOOK(item
, hook
); /* clears stored hook */
1985 * If the item or the node specifies single threading, force
1986 * writer semantics. Similarly, the node may say one hook always
1987 * produces writers. These are overrides.
1989 if (((item
->el_flags
& NGQF_RW
) == NGQF_WRITER
) ||
1990 (node
->nd_flags
& NGF_FORCE_WRITER
) ||
1991 (hook
&& (hook
->hk_flags
& HK_FORCE_WRITER
))) {
1992 ng_acquire_write(node
);
1994 ng_acquire_read(node
);
1997 #ifdef NETGRAPH_DEBUG
1998 _ngi_check(item
, __FILE__
, __LINE__
);
2001 switch (item
->el_flags
& NGQF_TYPE
) {
2004 * Check things are still ok as when we were queued.
2006 KASSERT(hook
!= NULL
, ("ng_apply_item: hook for data is NULL"));
2007 if (NG_HOOK_NOT_VALID(hook
) ||
2008 NG_NODE_NOT_VALID(node
)) {
2014 * If no receive method, just silently drop it.
2015 * Give preference to the hook over-ride method
2017 if ((!(rcvdata
= hook
->hk_rcvdata
))
2018 && (!(rcvdata
= NG_HOOK_NODE(hook
)->nd_type
->rcvdata
))) {
2023 error
= (*rcvdata
)(hook
, item
);
2026 if (hook
&& NG_HOOK_NOT_VALID(hook
)) {
2028 * The hook has been zapped then we can't use it.
2029 * Immediately drop its reference.
2030 * The message may not need it.
2032 NG_HOOK_UNREF(hook
);
2036 * Similarly, if the node is a zombie there is
2037 * nothing we can do with it, drop everything.
2039 if (NG_NODE_NOT_VALID(node
)) {
2046 * Call the appropriate message handler for the object.
2047 * It is up to the message handler to free the message.
2048 * If it's a generic message, handle it generically,
2049 * otherwise call the type's message handler (if it exists).
2050 * XXX (race). Remember that a queued message may
2051 * reference a node or hook that has just been
2052 * invalidated. It will exist as the queue code
2053 * is holding a reference, but..
2055 if ((NGI_MSG(item
)->header
.typecookie
== NGM_GENERIC_COOKIE
) &&
2056 ((NGI_MSG(item
)->header
.flags
& NGF_RESP
) == 0)) {
2057 error
= ng_generic_msg(node
, item
, hook
);
2060 if (((!hook
) || (!(rcvmsg
= hook
->hk_rcvmsg
))) &&
2061 (!(rcvmsg
= node
->nd_type
->rcvmsg
))) {
2067 error
= (*rcvmsg
)(node
, item
, hook
);
2072 * We have to implicitly trust the hook,
2073 * as some of these are used for system purposes
2074 * where the hook is invalid. In the case of
2075 * the shutdown message we allow it to hit
2076 * even if the node is invalid.
2078 if ((NG_NODE_NOT_VALID(node
))
2079 && (NGI_FN(item
) != &ng_rmnode
)) {
2085 if ((item
->el_flags
& NGQF_TYPE
) == NGQF_FN
) {
2086 (*NGI_FN(item
))(node
, hook
, NGI_ARG1(item
),
2089 } else /* it is NGQF_FN2 */
2090 error
= (*NGI_FN2(item
))(node
, item
, hook
);
2094 * We held references on some of the resources
2095 * that we took from the item. Now that we have
2096 * finished doing everything, drop those references.
2099 NG_HOOK_UNREF(hook
);
2101 /* Release our node's token */
2102 ng_leave_readwrite(node
);
2104 /* Free the item if we own the last reference to it. */
2105 ng_unref_item(item
, error
);
2107 NG_NODE_UNREF(node
);
2112 /***********************************************************************
2113 * Implement the 'generic' control messages
2114 ***********************************************************************/
2116 ng_generic_msg(node_p here
, item_p item
, hook_p lasthook
)
2119 struct ng_mesg
*msg
;
2120 struct ng_mesg
*resp
= NULL
;
2122 NGI_GET_MSG(item
, msg
);
2123 if (msg
->header
.typecookie
!= NGM_GENERIC_COOKIE
) {
2128 switch (msg
->header
.cmd
) {
2130 ng_rmnode(here
, NULL
, NULL
, 0);
2134 struct ngm_mkpeer
*const mkp
= (struct ngm_mkpeer
*) msg
->data
;
2136 if (msg
->header
.arglen
!= sizeof(*mkp
)) {
2141 mkp
->type
[sizeof(mkp
->type
) - 1] = '\0';
2142 mkp
->ourhook
[sizeof(mkp
->ourhook
) - 1] = '\0';
2143 mkp
->peerhook
[sizeof(mkp
->peerhook
) - 1] = '\0';
2144 error
= ng_mkpeer(here
, mkp
->ourhook
, mkp
->peerhook
, mkp
->type
);
2149 struct ngm_connect
*const con
=
2150 (struct ngm_connect
*) msg
->data
;
2153 if (msg
->header
.arglen
!= sizeof(*con
)) {
2158 con
->path
[sizeof(con
->path
) - 1] = '\0';
2159 con
->ourhook
[sizeof(con
->ourhook
) - 1] = '\0';
2160 con
->peerhook
[sizeof(con
->peerhook
) - 1] = '\0';
2161 /* Don't forget we get a reference.. */
2162 error
= ng_path2noderef(here
, con
->path
, &node2
, NULL
);
2165 error
= ng_con_nodes(item
, here
, con
->ourhook
,
2166 node2
, con
->peerhook
);
2167 NG_NODE_UNREF(node2
);
2172 struct ngm_name
*const nam
= (struct ngm_name
*) msg
->data
;
2174 if (msg
->header
.arglen
!= sizeof(*nam
)) {
2179 nam
->name
[sizeof(nam
->name
) - 1] = '\0';
2180 error
= ng_name_node(here
, nam
->name
);
2185 struct ngm_rmhook
*const rmh
= (struct ngm_rmhook
*) msg
->data
;
2188 if (msg
->header
.arglen
!= sizeof(*rmh
)) {
2193 rmh
->ourhook
[sizeof(rmh
->ourhook
) - 1] = '\0';
2194 if ((hook
= ng_findhook(here
, rmh
->ourhook
)) != NULL
)
2195 ng_destroy_hook(hook
);
2200 struct nodeinfo
*ni
;
2202 NG_MKRESPONSE(resp
, msg
, sizeof(*ni
), M_WAITOK
| M_NULLOK
);
2208 /* Fill in node info */
2209 ni
= (struct nodeinfo
*) resp
->data
;
2210 if (NG_NODE_HAS_NAME(here
))
2211 strcpy(ni
->name
, NG_NODE_NAME(here
));
2212 strcpy(ni
->type
, here
->nd_type
->name
);
2213 ni
->id
= ng_node2ID(here
);
2214 ni
->hooks
= here
->nd_numhooks
;
2219 const int nhooks
= here
->nd_numhooks
;
2220 struct hooklist
*hl
;
2221 struct nodeinfo
*ni
;
2224 /* Get response struct */
2225 NG_MKRESPONSE(resp
, msg
, sizeof(*hl
)
2226 + (nhooks
* sizeof(struct linkinfo
)), M_WAITOK
| M_NULLOK
);
2231 hl
= (struct hooklist
*) resp
->data
;
2234 /* Fill in node info */
2235 if (NG_NODE_HAS_NAME(here
))
2236 strcpy(ni
->name
, NG_NODE_NAME(here
));
2237 strcpy(ni
->type
, here
->nd_type
->name
);
2238 ni
->id
= ng_node2ID(here
);
2240 /* Cycle through the linked list of hooks */
2242 LIST_FOREACH(hook
, &here
->nd_hooks
, hk_hooks
) {
2243 struct linkinfo
*const link
= &hl
->link
[ni
->hooks
];
2245 if (ni
->hooks
>= nhooks
) {
2246 log(LOG_ERR
, "%s: number of %s changed\n",
2250 if (NG_HOOK_NOT_VALID(hook
))
2252 strcpy(link
->ourhook
, NG_HOOK_NAME(hook
));
2253 strcpy(link
->peerhook
, NG_PEER_HOOK_NAME(hook
));
2254 if (NG_PEER_NODE_NAME(hook
)[0] != '\0')
2255 strcpy(link
->nodeinfo
.name
,
2256 NG_PEER_NODE_NAME(hook
));
2257 strcpy(link
->nodeinfo
.type
,
2258 NG_PEER_NODE(hook
)->nd_type
->name
);
2259 link
->nodeinfo
.id
= ng_node2ID(NG_PEER_NODE(hook
));
2260 link
->nodeinfo
.hooks
= NG_PEER_NODE(hook
)->nd_numhooks
;
2268 struct namelist
*nl
;
2273 /* Get response struct. */
2274 NG_MKRESPONSE(resp
, msg
, sizeof(*nl
) +
2275 (ng_nodes
* sizeof(struct nodeinfo
)), M_NOWAIT
| M_ZERO
);
2281 nl
= (struct namelist
*) resp
->data
;
2283 /* Cycle through the lists of nodes. */
2285 for (i
= 0; i
<= ng_ID_hmask
; i
++) {
2286 LIST_FOREACH(node
, &ng_ID_hash
[i
], nd_idnodes
) {
2287 struct nodeinfo
*const np
=
2288 &nl
->nodeinfo
[nl
->numnames
];
2290 if (NG_NODE_NOT_VALID(node
))
2292 if (NG_NODE_HAS_NAME(node
))
2293 strcpy(np
->name
, NG_NODE_NAME(node
));
2294 strcpy(np
->type
, node
->nd_type
->name
);
2295 np
->id
= ng_node2ID(node
);
2296 np
->hooks
= node
->nd_numhooks
;
2297 KASSERT(nl
->numnames
< ng_nodes
,
2298 ("%s: no space", __func__
));
2307 struct namelist
*nl
;
2312 /* Get response struct. */
2313 NG_MKRESPONSE(resp
, msg
, sizeof(*nl
) +
2314 (ng_named_nodes
* sizeof(struct nodeinfo
)), M_NOWAIT
);
2320 nl
= (struct namelist
*) resp
->data
;
2322 /* Cycle through the lists of nodes. */
2324 for (i
= 0; i
<= ng_name_hmask
; i
++) {
2325 LIST_FOREACH(node
, &ng_name_hash
[i
], nd_nodes
) {
2326 struct nodeinfo
*const np
=
2327 &nl
->nodeinfo
[nl
->numnames
];
2329 if (NG_NODE_NOT_VALID(node
))
2331 strcpy(np
->name
, NG_NODE_NAME(node
));
2332 strcpy(np
->type
, node
->nd_type
->name
);
2333 np
->id
= ng_node2ID(node
);
2334 np
->hooks
= node
->nd_numhooks
;
2335 KASSERT(nl
->numnames
< ng_named_nodes
,
2336 ("%s: no space", __func__
));
2346 struct typelist
*tl
;
2347 struct ng_type
*type
;
2351 /* Count number of types */
2352 LIST_FOREACH(type
, &ng_typelist
, types
)
2355 /* Get response struct */
2356 NG_MKRESPONSE(resp
, msg
, sizeof(*tl
)
2357 + (num
* sizeof(struct typeinfo
)), M_WAITOK
| M_NULLOK
);
2363 tl
= (struct typelist
*) resp
->data
;
2365 /* Cycle through the linked list of types */
2367 LIST_FOREACH(type
, &ng_typelist
, types
) {
2368 struct typeinfo
*const tp
= &tl
->typeinfo
[tl
->numtypes
];
2370 strcpy(tp
->type_name
, type
->name
);
2371 tp
->numnodes
= type
->refs
- 1; /* don't count list */
2372 KASSERT(tl
->numtypes
< num
, ("%s: no space", __func__
));
2379 case NGM_BINARY2ASCII
:
2381 int bufSize
= 20 * 1024; /* XXX hard coded constant */
2382 const struct ng_parse_type
*argstype
;
2383 const struct ng_cmdlist
*c
;
2384 struct ng_mesg
*binary
, *ascii
;
2386 /* Data area must contain a valid netgraph message */
2387 binary
= (struct ng_mesg
*)msg
->data
;
2388 if (msg
->header
.arglen
< sizeof(struct ng_mesg
) ||
2389 (msg
->header
.arglen
- sizeof(struct ng_mesg
) <
2390 binary
->header
.arglen
)) {
2396 /* Get a response message with lots of room */
2397 NG_MKRESPONSE(resp
, msg
, sizeof(*ascii
) + bufSize
, M_WAITOK
| M_NULLOK
);
2402 ascii
= (struct ng_mesg
*)resp
->data
;
2404 /* Copy binary message header to response message payload */
2405 bcopy(binary
, ascii
, sizeof(*binary
));
2407 /* Find command by matching typecookie and command number */
2408 for (c
= here
->nd_type
->cmdlist
;
2409 c
!= NULL
&& c
->name
!= NULL
; c
++) {
2410 if (binary
->header
.typecookie
== c
->cookie
2411 && binary
->header
.cmd
== c
->cmd
)
2414 if (c
== NULL
|| c
->name
== NULL
) {
2415 for (c
= ng_generic_cmds
; c
->name
!= NULL
; c
++) {
2416 if (binary
->header
.typecookie
== c
->cookie
2417 && binary
->header
.cmd
== c
->cmd
)
2420 if (c
->name
== NULL
) {
2427 /* Convert command name to ASCII */
2428 ksnprintf(ascii
->header
.cmdstr
, sizeof(ascii
->header
.cmdstr
),
2431 /* Convert command arguments to ASCII */
2432 argstype
= (binary
->header
.flags
& NGF_RESP
) ?
2433 c
->respType
: c
->mesgType
;
2434 if (argstype
== NULL
) {
2435 *ascii
->data
= '\0';
2437 if ((error
= ng_unparse(argstype
,
2438 (u_char
*)binary
->data
,
2439 ascii
->data
, bufSize
)) != 0) {
2445 /* Return the result as struct ng_mesg plus ASCII string */
2446 bufSize
= strlen(ascii
->data
) + 1;
2447 ascii
->header
.arglen
= bufSize
;
2448 resp
->header
.arglen
= sizeof(*ascii
) + bufSize
;
2452 case NGM_ASCII2BINARY
:
2454 int bufSize
= 2000; /* XXX hard coded constant */
2455 const struct ng_cmdlist
*c
;
2456 const struct ng_parse_type
*argstype
;
2457 struct ng_mesg
*ascii
, *binary
;
2460 /* Data area must contain at least a struct ng_mesg + '\0' */
2461 ascii
= (struct ng_mesg
*)msg
->data
;
2462 if ((msg
->header
.arglen
< sizeof(*ascii
) + 1) ||
2463 (ascii
->header
.arglen
< 1) ||
2464 (msg
->header
.arglen
< sizeof(*ascii
) +
2465 ascii
->header
.arglen
)) {
2470 ascii
->data
[ascii
->header
.arglen
- 1] = '\0';
2472 /* Get a response message with lots of room */
2473 NG_MKRESPONSE(resp
, msg
, sizeof(*binary
) + bufSize
, M_WAITOK
| M_NULLOK
);
2478 binary
= (struct ng_mesg
*)resp
->data
;
2480 /* Copy ASCII message header to response message payload */
2481 bcopy(ascii
, binary
, sizeof(*ascii
));
2483 /* Find command by matching ASCII command string */
2484 for (c
= here
->nd_type
->cmdlist
;
2485 c
!= NULL
&& c
->name
!= NULL
; c
++) {
2486 if (strcmp(ascii
->header
.cmdstr
, c
->name
) == 0)
2489 if (c
== NULL
|| c
->name
== NULL
) {
2490 for (c
= ng_generic_cmds
; c
->name
!= NULL
; c
++) {
2491 if (strcmp(ascii
->header
.cmdstr
, c
->name
) == 0)
2494 if (c
->name
== NULL
) {
2501 /* Convert command name to binary */
2502 binary
->header
.cmd
= c
->cmd
;
2503 binary
->header
.typecookie
= c
->cookie
;
2505 /* Convert command arguments to binary */
2506 argstype
= (binary
->header
.flags
& NGF_RESP
) ?
2507 c
->respType
: c
->mesgType
;
2508 if (argstype
== NULL
) {
2511 if ((error
= ng_parse(argstype
, ascii
->data
,
2512 &off
, (u_char
*)binary
->data
, &bufSize
)) != 0) {
2518 /* Return the result */
2519 binary
->header
.arglen
= bufSize
;
2520 resp
->header
.arglen
= sizeof(*binary
) + bufSize
;
2524 case NGM_TEXT_CONFIG
:
2525 case NGM_TEXT_STATUS
:
2527 * This one is tricky as it passes the command down to the
2528 * actual node, even though it is a generic type command.
2529 * This means we must assume that the item/msg is already freed
2530 * when control passes back to us.
2532 if (here
->nd_type
->rcvmsg
!= NULL
) {
2533 NGI_MSG(item
) = msg
; /* put it back as we found it */
2534 return((*here
->nd_type
->rcvmsg
)(here
, item
, lasthook
));
2536 /* Fall through if rcvmsg not supported */
2542 * Sometimes a generic message may be statically allocated
2543 * to avoid problems with allocating when in tight memeory situations.
2544 * Don't free it if it is so.
2545 * I break them appart here, because erros may cause a free if the item
2546 * in which case we'd be doing it twice.
2547 * they are kept together above, to simplify freeing.
2550 NG_RESPOND_MSG(error
, here
, item
, resp
);
2556 /************************************************************************
2557 Queue element get/free routines
2558 ************************************************************************/
2560 static struct objcache
*ng_oc
;
2561 static struct objcache
*ng_apply_oc
;
2562 static int maxalloc
= 4096; /* limit the damage of a leak */
2564 TUNABLE_INT("net.graph.maxalloc", &maxalloc
);
2565 SYSCTL_INT(_net_graph
, OID_AUTO
, maxalloc
, CTLFLAG_RD
, &maxalloc
,
2566 0, "Maximum number of queue items to allocate");
2568 #ifdef NETGRAPH_DEBUG
2569 static TAILQ_HEAD(, ng_item
) ng_itemlist
= TAILQ_HEAD_INITIALIZER(ng_itemlist
);
2570 static int allocated
; /* number of items malloc'd */
2574 * Get a queue entry.
2575 * This is usually called when a packet first enters netgraph.
2576 * By definition, this is usually from an interrupt, or from a user.
2577 * Users are not so important, but try be quick for the times that it's
2580 static __inline item_p
2581 ng_alloc_item(int type
, int flags
)
2585 KASSERT(((type
& ~NGQF_TYPE
) == 0),
2586 ("%s: incorrect item type: %d", __func__
, type
));
2588 item
= objcache_get(ng_oc
,
2589 (flags
& NG_WAITOK
) ? M_WAITOK
: M_NOWAIT
);
2592 item
->el_flags
= type
;
2593 #ifdef NETGRAPH_DEBUG
2595 TAILQ_INSERT_TAIL(&ng_itemlist
, item
, all
);
2597 mtx_unlock(&ngq_mtx
);
2605 * Release a queue entry
2608 ng_free_item(item_p item
)
2611 * If the item still has an apply callback registered, it is
2612 * being freed too early.
2614 KASSERT(item
->apply
== NULL
, ("freeing item with registered callback"));
2617 * Make sure the reference count has reached zero.
2619 KASSERT(item
->refs
== 0, ("freeing item with non-zero refcount"));
2622 * The item may hold resources on it's own. We need to free
2623 * these before we can free the item. What they are depends upon
2624 * what kind of item it is. it is important that nodes zero
2625 * out pointers to resources that they remove from the item
2626 * or we release them again here.
2628 switch (item
->el_flags
& NGQF_TYPE
) {
2630 /* If we have an mbuf still attached.. */
2631 NG_FREE_M(_NGI_M(item
));
2634 _NGI_RETADDR(item
) = 0;
2635 NG_FREE_MSG(_NGI_MSG(item
));
2639 /* nothing to free really, */
2640 _NGI_FN(item
) = NULL
;
2641 _NGI_ARG1(item
) = NULL
;
2642 _NGI_ARG2(item
) = 0;
2645 /* If we still have a node or hook referenced... */
2646 _NGI_CLR_NODE(item
);
2647 _NGI_CLR_HOOK(item
);
2649 #ifdef NETGRAPH_DEBUG
2651 TAILQ_REMOVE(&ng_itemlist
, item
, all
);
2653 mtx_unlock(&ngq_mtx
);
2655 /* Object must be initialized before returning to objcache */
2656 bzero(item
, sizeof(struct ng_item
));
2657 objcache_put(ng_oc
, item
);
2661 * Change type of the queue entry.
2663 static __inline item_p
2664 ng_realloc_item(item_p item
, int type
, int flags
)
2667 KASSERT((item
!= NULL
), ("%s: can't reallocate NULL", __func__
));
2668 KASSERT(((type
& ~NGQF_TYPE
) == 0),
2669 ("%s: incorrect item type: %d", __func__
, type
));
2671 item
->el_flags
= (item
->el_flags
& ~NGQF_TYPE
) | type
;
2677 ng_alloc_apply(void)
2679 return (objcache_get(ng_apply_oc
, M_WAITOK
));
2683 ng_free_apply(apply_p apply
)
2685 objcache_put(ng_apply_oc
, apply
);
2688 /************************************************************************
2690 ************************************************************************/
2693 * Handle the loading/unloading of a netgraph node type module
2696 ng_mod_event(module_t mod
, int event
, void *data
)
2698 struct ng_type
*const type
= data
;
2704 /* Register new netgraph node type */
2705 if ((error
= ng_newtype(type
)) != 0) {
2709 /* Call type specific code */
2710 if (type
->mod_event
!= NULL
)
2711 if ((error
= (*type
->mod_event
)(mod
, event
, data
))) {
2713 type
->refs
--; /* undo it */
2714 LIST_REMOVE(type
, types
);
2720 if (type
->refs
> 1) { /* make sure no nodes exist! */
2723 if (type
->refs
== 0) {
2724 /* failed load, nothing to undo */
2727 if (type
->mod_event
!= NULL
) { /* check with type */
2728 error
= (*type
->mod_event
)(mod
, event
, data
);
2729 if (error
!= 0) { /* type refuses.. */
2734 LIST_REMOVE(type
, types
);
2740 if (type
->mod_event
!= NULL
)
2741 error
= (*type
->mod_event
)(mod
, event
, data
);
2743 error
= EOPNOTSUPP
; /* XXX ? */
2750 * Handle loading and unloading for this code.
2753 ngb_mod_event(module_t mod
, int event
, void *data
)
2759 /* Initialize everything. */
2760 lwkt_token_init(&ng_typelist_token
, "ng typelist");
2761 lwkt_token_init(&ng_idhash_token
, "ng idhash");
2762 lwkt_token_init(&ng_namehash_token
, "ng namehash");
2763 lwkt_token_init(&ng_topo_token
, "ng topology");
2764 #ifdef NETGRAPH_DEBUG
2765 mtx_init(&ng_nodelist_mtx
, "ng nodelist");
2766 mtx_init(&ngq_mtx
, "ng queue");
2768 ng_oc
= objcache_create_mbacked(M_NETGRAPH
,
2769 sizeof(struct ng_item
), maxalloc
, 0, bzero_ctor
,
2771 ng_apply_oc
= objcache_create_mbacked(M_NETGRAPH_APPLY
,
2772 sizeof(struct ng_apply_info
), 0, 0, bzero_ctor
,
2775 /* We start with small hashes, but they can grow. */
2776 ng_ID_hash
= hashinit(16, M_NETGRAPH_NODE
, &ng_ID_hmask
);
2777 ng_name_hash
= hashinit(16, M_NETGRAPH_NODE
, &ng_name_hmask
);
2779 lwkt_initport_panic(&ng_panic_reply_port
);
2780 for (i
= 0; i
< ncpus
; ++i
) {
2783 lwkt_create(ngthread
, NULL
, &td
,
2784 NULL
, 0, i
, "netgraph %d", i
);
2785 ng_msgport
[i
] = &td
->td_msgport
;
2790 hashdestroy(V_ng_name_hash
, M_NETGRAPH_NODE
, V_ng_name_hmask
);
2791 hashdestroy(V_ng_ID_hash
, M_NETGRAPH_NODE
, V_ng_ID_hmask
);
2793 /* Destroy the lwkt threads too */
2795 objcache_destroy(ng_apply_oc
);
2796 objcache_destroy(ng_oc
);
2798 /* You can't unload it because an interface may be using it. */
2808 static moduledata_t netgraph_mod
= {
2813 DECLARE_MODULE(netgraph
, netgraph_mod
, SI_SUB_NETGRAPH
, SI_ORDER_MIDDLE
);
2814 SYSCTL_NODE(_net
, OID_AUTO
, graph
, CTLFLAG_RW
, 0, "netgraph Family");
2815 SYSCTL_INT(_net_graph
, OID_AUTO
, abi_version
, CTLFLAG_RD
, 0, NG_ABI_VERSION
,"");
2816 SYSCTL_INT(_net_graph
, OID_AUTO
, msg_version
, CTLFLAG_RD
, 0, NG_VERSION
, "");
2818 #ifdef NETGRAPH_DEBUG
2820 dumphook (hook_p hook
, char *file
, int line
)
2822 kprintf("hook: name %s, %d refs, Last touched:\n",
2823 _NG_HOOK_NAME(hook
), hook
->hk_refs
);
2824 kprintf(" Last active @ %s, line %d\n",
2825 hook
->lastfile
, hook
->lastline
);
2827 kprintf(" problem discovered at file %s, line %d\n", file
, line
);
2832 dumpnode(node_p node
, char *file
, int line
)
2834 kprintf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n",
2835 _NG_NODE_ID(node
), node
->nd_type
->name
,
2836 node
->nd_numhooks
, node
->nd_flags
,
2837 node
->nd_refs
, node
->nd_name
);
2838 kprintf(" Last active @ %s, line %d\n",
2839 node
->lastfile
, node
->lastline
);
2841 kprintf(" problem discovered at file %s, line %d\n", file
, line
);
2846 dumpitem(item_p item
, char *file
, int line
)
2848 kprintf(" ACTIVE item, last used at %s, line %d",
2849 item
->lastfile
, item
->lastline
);
2850 switch(item
->el_flags
& NGQF_TYPE
) {
2852 kprintf(" - [data]\n");
2855 kprintf(" - retaddr[%d]:\n", _NGI_RETADDR(item
));
2858 kprintf(" - fn@%p (%p, %p, %p, %d (%x))\n",
2862 item
->body
.fn
.fn_arg1
,
2863 item
->body
.fn
.fn_arg2
,
2864 item
->body
.fn
.fn_arg2
);
2867 kprintf(" - fn2@%p (%p, %p, %p, %d (%x))\n",
2871 item
->body
.fn
.fn_arg1
,
2872 item
->body
.fn
.fn_arg2
,
2873 item
->body
.fn
.fn_arg2
);
2877 kprintf(" problem discovered at file %s, line %d\n", file
, line
);
2878 if (_NGI_NODE(item
)) {
2879 kprintf("node %p ([%x])\n",
2880 _NGI_NODE(item
), ng_node2ID(_NGI_NODE(item
)));
2890 TAILQ_FOREACH(item
, &ng_itemlist
, all
) {
2891 kprintf("[%d] ", i
++);
2892 dumpitem(item
, NULL
, 0);
2901 mtx_lock(&ng_nodelist_mtx
);
2902 SLIST_FOREACH(node
, &ng_allnodes
, nd_all
) {
2903 kprintf("[%d] ", i
++);
2904 dumpnode(node
, NULL
, 0);
2906 mtx_unlock(&ng_nodelist_mtx
);
2914 mtx_lock(&ng_nodelist_mtx
);
2915 SLIST_FOREACH(hook
, &ng_allhooks
, hk_all
) {
2916 kprintf("[%d] ", i
++);
2917 dumphook(hook
, NULL
, 0);
2919 mtx_unlock(&ng_nodelist_mtx
);
2923 sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS
)
2929 error
= sysctl_handle_int(oidp
, &val
, 0, req
);
2930 if (error
!= 0 || req
->newptr
== NULL
)
2940 SYSCTL_PROC(_debug
, OID_AUTO
, ng_dump_items
, CTLTYPE_INT
| CTLFLAG_RW
,
2941 0, sizeof(int), sysctl_debug_ng_dump_items
, "I", "Number of allocated items");
2942 #endif /* NETGRAPH_DEBUG */
2945 /***********************************************************************
2946 * Externally useable functions to set up a queue item ready for sending
2947 ***********************************************************************/
2949 #ifdef NETGRAPH_DEBUG
2950 #define ITEM_DEBUG_CHECKS \
2952 if (NGI_NODE(item) ) { \
2953 kprintf("item already has node"); \
2954 kdb_enter(KDB_WHY_NETGRAPH, "has node"); \
2955 NGI_CLR_NODE(item); \
2957 if (NGI_HOOK(item) ) { \
2958 kprintf("item already has hook"); \
2959 kdb_enter(KDB_WHY_NETGRAPH, "has hook"); \
2960 NGI_CLR_HOOK(item); \
2964 #define ITEM_DEBUG_CHECKS
2968 * Put mbuf into the item.
2969 * Hook and node references will be removed when the item is dequeued.
2971 * (XXX) Unsafe because no reference held by peer on remote node.
2972 * remote node might go away in this timescale.
2973 * We know the hooks can't go away because that would require getting
2974 * a writer item on both nodes and we must have at least a reader
2975 * here to be able to do this.
2976 * Note that the hook loaded is the REMOTE hook.
2978 * This is possibly in the critical path for new data.
2981 ng_package_data(struct mbuf
*m
, int flags
)
2985 if ((item
= ng_alloc_item(NGQF_DATA
, flags
)) == NULL
) {
2990 item
->el_flags
|= NGQF_READER
;
2996 * Allocate a queue item and put items into it..
2997 * Evaluate the address as this will be needed to queue it and
2998 * to work out what some of the fields should be.
2999 * Hook and node references will be removed when the item is dequeued.
3003 ng_package_msg(struct ng_mesg
*msg
, int flags
)
3007 if ((item
= ng_alloc_item(NGQF_MESG
, flags
)) == NULL
) {
3012 /* Messages items count as writers unless explicitly exempted. */
3013 if (msg
->header
.cmd
& NGM_READONLY
)
3014 item
->el_flags
|= NGQF_READER
;
3016 item
->el_flags
|= NGQF_WRITER
;
3018 * Set the current lasthook into the queue item
3020 NGI_MSG(item
) = msg
;
3021 NGI_RETADDR(item
) = 0;
3027 #define SET_RETADDR(item, here, retaddr) \
3028 do { /* Data or fn items don't have retaddrs */ \
3029 if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \
3031 NGI_RETADDR(item) = retaddr; \
3034 * The old return address should be ok. \
3035 * If there isn't one, use the address \
3038 if (NGI_RETADDR(item) == 0) { \
3040 = ng_node2ID(here); \
3047 ng_address_hook(node_p here
, item_p item
, hook_p hook
, ng_ID_t retaddr
)
3053 * Quick sanity check..
3054 * Since a hook holds a reference on it's node, once we know
3055 * that the peer is still connected (even if invalid,) we know
3056 * that the peer node is present, though maybe invalid.
3058 if ((hook
== NULL
) ||
3059 NG_HOOK_NOT_VALID(hook
) ||
3060 NG_HOOK_NOT_VALID(peer
= NG_HOOK_PEER(hook
)) ||
3061 NG_NODE_NOT_VALID(peernode
= NG_PEER_NODE(hook
))) {
3068 * Transfer our interest to the other (peer) end.
3071 NG_NODE_REF(peernode
);
3072 NGI_SET_HOOK(item
, peer
);
3073 NGI_SET_NODE(item
, peernode
);
3074 SET_RETADDR(item
, here
, retaddr
);
3079 ng_address_path(node_p here
, item_p item
, char *address
, ng_ID_t retaddr
)
3087 * Note that ng_path2noderef increments the reference count
3088 * on the node for us if it finds one. So we don't have to.
3090 error
= ng_path2noderef(here
, address
, &dest
, &hook
);
3095 NGI_SET_NODE(item
, dest
);
3097 NG_HOOK_REF(hook
); /* don't let it go while on the queue */
3098 NGI_SET_HOOK(item
, hook
);
3100 SET_RETADDR(item
, here
, retaddr
);
3105 ng_address_ID(node_p here
, item_p item
, ng_ID_t ID
, ng_ID_t retaddr
)
3111 * Find the target node.
3113 dest
= ng_ID2noderef(ID
); /* GETS REFERENCE! */
3119 /* Fill out the contents */
3120 NGI_SET_NODE(item
, dest
);
3122 SET_RETADDR(item
, here
, retaddr
);
3127 * special case to send a message to self (e.g. destroy node)
3128 * Possibly indicate an arrival hook too.
3129 * Useful for removing that hook :-)
3132 ng_package_msg_self(node_p here
, hook_p hook
, struct ng_mesg
*msg
)
3137 * Find the target node.
3138 * If there is a HOOK argument, then use that in preference
3141 if ((item
= ng_alloc_item(NGQF_MESG
, NG_NOFLAGS
)) == NULL
) {
3146 /* Fill out the contents */
3147 item
->el_flags
|= NGQF_WRITER
;
3149 NGI_SET_NODE(item
, here
);
3152 NGI_SET_HOOK(item
, hook
);
3154 NGI_MSG(item
) = msg
;
3155 NGI_RETADDR(item
) = ng_node2ID(here
);
3160 * Send ng_item_fn function call to the specified node.
3164 ng_send_fn(node_p node
, hook_p hook
, ng_item_fn
*fn
, void * arg1
, int arg2
)
3166 return ng_send_fn1(node
, hook
, fn
, arg1
, arg2
, NG_NOFLAGS
);
3170 ng_send_fn1(node_p node
, hook_p hook
, ng_item_fn
*fn
, void * arg1
, int arg2
,
3175 if ((item
= ng_alloc_item(NGQF_FN
, flags
)) == NULL
) {
3178 item
->el_flags
|= NGQF_WRITER
;
3179 NG_NODE_REF(node
); /* and one for the item */
3180 NGI_SET_NODE(item
, node
);
3183 NGI_SET_HOOK(item
, hook
);
3186 NGI_ARG1(item
) = arg1
;
3187 NGI_ARG2(item
) = arg2
;
3188 return(ng_snd_item(item
, flags
));
3192 * Send ng_item_fn2 function call to the specified node.
3194 * If NG_REUSE_ITEM flag is set, no new item will be allocated,
3195 * pitem will be used instead.
3198 ng_send_fn2(node_p node
, hook_p hook
, item_p pitem
, ng_item_fn2
*fn
, void *arg1
,
3199 int arg2
, int flags
)
3203 KASSERT((pitem
!= NULL
|| (flags
& NG_REUSE_ITEM
) == 0),
3204 ("%s: NG_REUSE_ITEM but no pitem", __func__
));
3207 * Allocate a new item if no supplied or
3208 * if we can't use supplied one.
3210 if (pitem
== NULL
|| (flags
& NG_REUSE_ITEM
) == 0) {
3211 if ((item
= ng_alloc_item(NGQF_FN2
, flags
)) == NULL
)
3214 if ((item
= ng_realloc_item(pitem
, NGQF_FN2
, flags
)) == NULL
)
3218 item
->el_flags
= (item
->el_flags
& ~NGQF_RW
) | NGQF_WRITER
;
3219 NG_NODE_REF(node
); /* and one for the item */
3220 NGI_SET_NODE(item
, node
);
3223 NGI_SET_HOOK(item
, hook
);
3226 NGI_ARG1(item
) = arg1
;
3227 NGI_ARG2(item
) = arg2
;
3228 return(ng_snd_item(item
, flags
));
3232 * Official timeout routines for Netgraph nodes.
3235 ng_callout_trampoline(void *arg
)
3239 ng_snd_item(item
, 0);
3244 ng_callout(struct callout
*c
, node_p node
, hook_p hook
, int ticks
,
3245 ng_item_fn
*fn
, void * arg1
, int arg2
)
3249 if ((item
= ng_alloc_item(NGQF_FN
, NG_NOFLAGS
)) == NULL
)
3252 item
->el_flags
|= NGQF_WRITER
;
3253 NG_NODE_REF(node
); /* and one for the item */
3254 NGI_SET_NODE(item
, node
);
3257 NGI_SET_HOOK(item
, hook
);
3260 NGI_ARG1(item
) = arg1
;
3261 NGI_ARG2(item
) = arg2
;
3263 callout_reset(c
, ticks
, &ng_callout_trampoline
, item
);
3267 /* A special modified version of untimeout() */
3269 ng_uncallout(struct callout
*c
, node_p node
)
3274 KASSERT(c
!= NULL
, ("ng_uncallout: NULL callout"));
3275 KASSERT(node
!= NULL
, ("ng_uncallout: NULL node"));
3277 rval
= callout_stop(c
);
3279 /* Do an extra check */
3280 if ((rval
> 0) && (c
->c_func
== &ng_callout_trampoline
) &&
3281 (NGI_NODE(item
) == node
)) {
3283 * We successfully removed it from the queue before it ran
3284 * So now we need to unreference everything that was
3285 * given extra references. (NG_FREE_ITEM does this).
3295 * Set the address, if none given, give the node here.
3298 ng_replace_retaddr(node_p here
, item_p item
, ng_ID_t retaddr
)
3301 NGI_RETADDR(item
) = retaddr
;
3304 * The old return address should be ok.
3305 * If there isn't one, use the address here.
3307 NGI_RETADDR(item
) = ng_node2ID(here
);
3312 bzero_ctor(void *obj
, void *private, int ocflags
)
3314 struct ng_item
*i
= obj
;
3316 bzero(i
, sizeof(struct ng_item
));
3322 /* just test all the macros */
3324 ng_macro_test(item_p item
);
3326 ng_macro_test(item_p item
)
3331 struct ng_mesg
*msg
;
3336 NGI_GET_MSG(item
, msg
);
3337 retaddr
= NGI_RETADDR(item
);
3338 NG_SEND_DATA(error
, hook
, m
, NULL
);
3339 NG_SEND_DATA_ONLY(error
, hook
, m
);
3340 NG_FWD_NEW_DATA(error
, item
, hook
, m
);
3341 NG_FWD_ITEM_HOOK(error
, item
, hook
);
3342 NG_SEND_MSG_HOOK(error
, node
, msg
, hook
, retaddr
);
3343 NG_SEND_MSG_ID(error
, node
, msg
, retaddr
, retaddr
);
3344 NG_SEND_MSG_PATH(error
, node
, msg
, ".:", retaddr
);
3345 NG_FWD_MSG_HOOK(error
, node
, item
, hook
, retaddr
);
3347 #endif /* TESTING */