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