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