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