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