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