1 /*
2 * ng_base.c
3 */
4
5 /*-
6 * Copyright (c) 1996-1999 Whistle Communications, Inc.
7 * All rights reserved.
8 *
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 * copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 * Communications, Inc. trademarks, including the mark "WHISTLE
17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 * such appears in the above copyright notice or in the software.
19 *
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * Authors: Julian Elischer <julian@freebsd.org>
39 * Archie Cobbs <archie@freebsd.org>
40 *
41 * $FreeBSD: src/sys/netgraph/ng_base.c,v 1.168 2008/11/28 23:30:51 zec Exp $
42 * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $
43 */
44
45 /*
46 * This file implements the base netgraph code.
47 */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/ctype.h>
52 #include <sys/errno.h>
53 #include <sys/kdb.h>
54 #include <sys/kernel.h>
55 #include <sys/ktr.h>
56 #include <sys/limits.h>
57 #include <sys/malloc.h>
58 #include <sys/mbuf.h>
59 #include <sys/queue.h>
60 #include <sys/sysctl.h>
61 #include <sys/syslog.h>
62 #include <sys/refcount.h>
63 #include <sys/proc.h>
64 #include <sys/vimage.h>
65 #include <machine/cpu.h>
66
67 #include <net/netisr.h>
68
69 #include <netgraph/ng_message.h>
70 #include <netgraph/netgraph.h>
71 #include <netgraph/ng_parse.h>
72
73 MODULE_VERSION(netgraph, NG_ABI_VERSION);
74
75 /* Mutex to protect topology events. */
76 static struct mtx ng_topo_mtx;
77
78 #ifdef NETGRAPH_DEBUG
79 static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */
80 static struct mtx ngq_mtx; /* protects the queue item list */
81
82 static SLIST_HEAD(, ng_node) ng_allnodes;
83 static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */
84 static SLIST_HEAD(, ng_hook) ng_allhooks;
85 static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */
86
87 static void ng_dumpitems(void);
88 static void ng_dumpnodes(void);
89 static void ng_dumphooks(void);
90
91 #endif /* NETGRAPH_DEBUG */
92 /*
93 * DEAD versions of the structures.
94 * In order to avoid races, it is sometimes neccesary to point
95 * at SOMETHING even though theoretically, the current entity is
96 * INVALID. Use these to avoid these races.
97 */
98 struct ng_type ng_deadtype = {
99 NG_ABI_VERSION,
100 "dead",
101 NULL, /* modevent */
102 NULL, /* constructor */
103 NULL, /* rcvmsg */
104 NULL, /* shutdown */
105 NULL, /* newhook */
106 NULL, /* findhook */
107 NULL, /* connect */
108 NULL, /* rcvdata */
109 NULL, /* disconnect */
110 NULL, /* cmdlist */
111 };
112
113 struct ng_node ng_deadnode = {
114 "dead",
115 &ng_deadtype,
116 NGF_INVALID,
117 0, /* numhooks */
118 NULL, /* private */
119 0, /* ID */
120 LIST_HEAD_INITIALIZER(ng_deadnode.hooks),
121 {}, /* all_nodes list entry */
122 {}, /* id hashtable list entry */
123 { 0,
124 0,
125 {}, /* should never use! (should hang) */
126 {}, /* workqueue entry */
127 STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue),
128 },
129 1, /* refs */
130 #ifdef NETGRAPH_DEBUG
131 ND_MAGIC,
132 __FILE__,
133 __LINE__,
134 {NULL}
135 #endif /* NETGRAPH_DEBUG */
136 };
137
138 struct ng_hook ng_deadhook = {
139 "dead",
140 NULL, /* private */
141 HK_INVALID | HK_DEAD,
142 0, /* undefined data link type */
143 &ng_deadhook, /* Peer is self */
144 &ng_deadnode, /* attached to deadnode */
145 {}, /* hooks list */
146 NULL, /* override rcvmsg() */
147 NULL, /* override rcvdata() */
148 1, /* refs always >= 1 */
149 #ifdef NETGRAPH_DEBUG
150 HK_MAGIC,
151 __FILE__,
152 __LINE__,
153 {NULL}
154 #endif /* NETGRAPH_DEBUG */
155 };
156
157 /*
158 * END DEAD STRUCTURES
159 */
160 /* List nodes with unallocated work */
161 static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist);
162 static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */
163
164 /* List of installed types */
165 static LIST_HEAD(, ng_type) ng_typelist;
166 static struct mtx ng_typelist_mtx;
167
168 /* Hash related definitions */
169 /* XXX Don't need to initialise them because it's a LIST */
170 static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE];
171 static struct mtx ng_idhash_mtx;
172 /* Method to find a node.. used twice so do it here */
173 #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE))
174 #define NG_IDHASH_FIND(ID, node) \
175 do { \
176 mtx_assert(&ng_idhash_mtx, MA_OWNED); \
177 LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \
178 nd_idnodes) { \
179 if (NG_NODE_IS_VALID(node) \
180 && (NG_NODE_ID(node) == ID)) { \
181 break; \
182 } \
183 } \
184 } while (0)
185
186 static LIST_HEAD(, ng_node) ng_name_hash[NG_NAME_HASH_SIZE];
187 static struct mtx ng_namehash_mtx;
188 #define NG_NAMEHASH(NAME, HASH) \
189 do { \
190 u_char h = 0; \
191 const u_char *c; \
192 for (c = (const u_char*)(NAME); *c; c++)\
193 h += *c; \
194 (HASH) = h % (NG_NAME_HASH_SIZE); \
195 } while (0)
196
197
198 /* Internal functions */
199 static int ng_add_hook(node_p node, const char *name, hook_p * hookp);
200 static int ng_generic_msg(node_p here, item_p item, hook_p lasthook);
201 static ng_ID_t ng_decodeidname(const char *name);
202 static int ngb_mod_event(module_t mod, int event, void *data);
203 static void ng_worklist_add(node_p node);
204 static void ngintr(void);
205 static int ng_apply_item(node_p node, item_p item, int rw);
206 static void ng_flush_input_queue(node_p node);
207 static node_p ng_ID2noderef(ng_ID_t ID);
208 static int ng_con_nodes(item_p item, node_p node, const char *name,
209 node_p node2, const char *name2);
210 static int ng_con_part2(node_p node, item_p item, hook_p hook);
211 static int ng_con_part3(node_p node, item_p item, hook_p hook);
212 static int ng_mkpeer(node_p node, const char *name,
213 const char *name2, char *type);
214
215 /* Imported, these used to be externally visible, some may go back. */
216 void ng_destroy_hook(hook_p hook);
217 node_p ng_name2noderef(node_p node, const char *name);
218 int ng_path2noderef(node_p here, const char *path,
219 node_p *dest, hook_p *lasthook);
220 int ng_make_node(const char *type, node_p *nodepp);
221 int ng_path_parse(char *addr, char **node, char **path, char **hook);
222 void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3);
223 void ng_unname(node_p node);
224
225
226 /* Our own netgraph malloc type */
227 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
228 MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures");
229 MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures");
230 MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures");
231 MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage");
232
233 /* Should not be visible outside this file */
234
235 #define _NG_ALLOC_HOOK(hook) \
236 hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO)
237 #define _NG_ALLOC_NODE(node) \
238 node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO)
239
240 #define NG_QUEUE_LOCK_INIT(n) \
241 mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF)
242 #define NG_QUEUE_LOCK(n) \
243 mtx_lock(&(n)->q_mtx)
244 #define NG_QUEUE_UNLOCK(n) \
245 mtx_unlock(&(n)->q_mtx)
246 #define NG_WORKLIST_LOCK_INIT() \
247 mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF)
248 #define NG_WORKLIST_LOCK() \
249 mtx_lock(&ng_worklist_mtx)
250 #define NG_WORKLIST_UNLOCK() \
251 mtx_unlock(&ng_worklist_mtx)
252
253 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/
254 /*
255 * In debug mode:
256 * In an attempt to help track reference count screwups
257 * we do not free objects back to the malloc system, but keep them
258 * in a local cache where we can examine them and keep information safely
259 * after they have been freed.
260 * We use this scheme for nodes and hooks, and to some extent for items.
261 */
262 static __inline hook_p
263 ng_alloc_hook(void)
264 {
265 hook_p hook;
266 SLIST_ENTRY(ng_hook) temp;
267 mtx_lock(&ng_nodelist_mtx);
268 hook = LIST_FIRST(&ng_freehooks);
269 if (hook) {
270 LIST_REMOVE(hook, hk_hooks);
271 bcopy(&hook->hk_all, &temp, sizeof(temp));
272 bzero(hook, sizeof(struct ng_hook));
273 bcopy(&temp, &hook->hk_all, sizeof(temp));
274 mtx_unlock(&ng_nodelist_mtx);
275 hook->hk_magic = HK_MAGIC;
276 } else {
277 mtx_unlock(&ng_nodelist_mtx);
278 _NG_ALLOC_HOOK(hook);
279 if (hook) {
280 hook->hk_magic = HK_MAGIC;
281 mtx_lock(&ng_nodelist_mtx);
282 SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all);
283 mtx_unlock(&ng_nodelist_mtx);
284 }
285 }
286 return (hook);
287 }
288
289 static __inline node_p
290 ng_alloc_node(void)
291 {
292 node_p node;
293 SLIST_ENTRY(ng_node) temp;
294 mtx_lock(&ng_nodelist_mtx);
295 node = LIST_FIRST(&ng_freenodes);
296 if (node) {
297 LIST_REMOVE(node, nd_nodes);
298 bcopy(&node->nd_all, &temp, sizeof(temp));
299 bzero(node, sizeof(struct ng_node));
300 bcopy(&temp, &node->nd_all, sizeof(temp));
301 mtx_unlock(&ng_nodelist_mtx);
302 node->nd_magic = ND_MAGIC;
303 } else {
304 mtx_unlock(&ng_nodelist_mtx);
305 _NG_ALLOC_NODE(node);
306 if (node) {
307 node->nd_magic = ND_MAGIC;
308 mtx_lock(&ng_nodelist_mtx);
309 SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all);
310 mtx_unlock(&ng_nodelist_mtx);
311 }
312 }
313 return (node);
314 }
315
316 #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0)
317 #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0)
318
319
320 #define NG_FREE_HOOK(hook) \
321 do { \
322 mtx_lock(&ng_nodelist_mtx); \
323 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \
324 hook->hk_magic = 0; \
325 mtx_unlock(&ng_nodelist_mtx); \
326 } while (0)
327
328 #define NG_FREE_NODE(node) \
329 do { \
330 mtx_lock(&ng_nodelist_mtx); \
331 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \
332 node->nd_magic = 0; \
333 mtx_unlock(&ng_nodelist_mtx); \
334 } while (0)
335
336 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
337
338 #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook)
339 #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node)
340
341 #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0)
342 #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0)
343
344 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
345
346 /* Set this to kdb_enter("X") to catch all errors as they occur */
347 #ifndef TRAP_ERROR
348 #define TRAP_ERROR()
349 #endif
350
351 static ng_ID_t nextID = 1;
352
353 #ifdef INVARIANTS
354 #define CHECK_DATA_MBUF(m) do { \
355 struct mbuf *n; \
356 int total; \
357 \
358 M_ASSERTPKTHDR(m); \
359 for (total = 0, n = (m); n != NULL; n = n->m_next) { \
360 total += n->m_len; \
361 if (n->m_nextpkt != NULL) \
362 panic("%s: m_nextpkt", __func__); \
363 } \
364 \
365 if ((m)->m_pkthdr.len != total) { \
366 panic("%s: %d != %d", \
367 __func__, (m)->m_pkthdr.len, total); \
368 } \
369 } while (0)
370 #else
371 #define CHECK_DATA_MBUF(m)
372 #endif
373
374 #define ERROUT(x) do { error = (x); goto done; } while (0)
375
376 /************************************************************************
377 Parse type definitions for generic messages
378 ************************************************************************/
379
380 /* Handy structure parse type defining macro */
381 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \
382 static const struct ng_parse_struct_field \
383 ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \
384 static const struct ng_parse_type ng_generic_ ## lo ## _type = { \
385 &ng_parse_struct_type, \
386 &ng_ ## lo ## _type_fields \
387 }
388
389 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
390 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
391 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
392 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
393 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
394 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
395 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
396
397 /* Get length of an array when the length is stored as a 32 bit
398 value immediately preceding the array -- as with struct namelist
399 and struct typelist. */
400 static int
401 ng_generic_list_getLength(const struct ng_parse_type *type,
402 const u_char *start, const u_char *buf)
403 {
404 return *((const u_int32_t *)(buf - 4));
405 }
406
407 /* Get length of the array of struct linkinfo inside a struct hooklist */
408 static int
409 ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
410 const u_char *start, const u_char *buf)
411 {
412 const struct hooklist *hl = (const struct hooklist *)start;
413
414 return hl->nodeinfo.hooks;
415 }
416
417 /* Array type for a variable length array of struct namelist */
418 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
419 &ng_generic_nodeinfo_type,
420 &ng_generic_list_getLength
421 };
422 static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
423 &ng_parse_array_type,
424 &ng_nodeinfoarray_type_info
425 };
426
427 /* Array type for a variable length array of struct typelist */
428 static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
429 &ng_generic_typeinfo_type,
430 &ng_generic_list_getLength
431 };
432 static const struct ng_parse_type ng_generic_typeinfoarray_type = {
433 &ng_parse_array_type,
434 &ng_typeinfoarray_type_info
435 };
436
437 /* Array type for array of struct linkinfo in struct hooklist */
438 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
439 &ng_generic_linkinfo_type,
440 &ng_generic_linkinfo_getLength
441 };
442 static const struct ng_parse_type ng_generic_linkinfo_array_type = {
443 &ng_parse_array_type,
444 &ng_generic_linkinfo_array_type_info
445 };
446
447 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
448 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
449 (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
450 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
451 (&ng_generic_nodeinfoarray_type));
452
453 /* List of commands and how to convert arguments to/from ASCII */
454 static const struct ng_cmdlist ng_generic_cmds[] = {
455 {
456 NGM_GENERIC_COOKIE,
457 NGM_SHUTDOWN,
458 "shutdown",
459 NULL,
460 NULL
461 },
462 {
463 NGM_GENERIC_COOKIE,
464 NGM_MKPEER,
465 "mkpeer",
466 &ng_generic_mkpeer_type,
467 NULL
468 },
469 {
470 NGM_GENERIC_COOKIE,
471 NGM_CONNECT,
472 "connect",
473 &ng_generic_connect_type,
474 NULL
475 },
476 {
477 NGM_GENERIC_COOKIE,
478 NGM_NAME,
479 "name",
480 &ng_generic_name_type,
481 NULL
482 },
483 {
484 NGM_GENERIC_COOKIE,
485 NGM_RMHOOK,
486 "rmhook",
487 &ng_generic_rmhook_type,
488 NULL
489 },
490 {
491 NGM_GENERIC_COOKIE,
492 NGM_NODEINFO,
493 "nodeinfo",
494 NULL,
495 &ng_generic_nodeinfo_type
496 },
497 {
498 NGM_GENERIC_COOKIE,
499 NGM_LISTHOOKS,
500 "listhooks",
501 NULL,
502 &ng_generic_hooklist_type
503 },
504 {
505 NGM_GENERIC_COOKIE,
506 NGM_LISTNAMES,
507 "listnames",
508 NULL,
509 &ng_generic_listnodes_type /* same as NGM_LISTNODES */
510 },
511 {
512 NGM_GENERIC_COOKIE,
513 NGM_LISTNODES,
514 "listnodes",
515 NULL,
516 &ng_generic_listnodes_type
517 },
518 {
519 NGM_GENERIC_COOKIE,
520 NGM_LISTTYPES,
521 "listtypes",
522 NULL,
523 &ng_generic_typeinfo_type
524 },
525 {
526 NGM_GENERIC_COOKIE,
527 NGM_TEXT_CONFIG,
528 "textconfig",
529 NULL,
530 &ng_parse_string_type
531 },
532 {
533 NGM_GENERIC_COOKIE,
534 NGM_TEXT_STATUS,
535 "textstatus",
536 NULL,
537 &ng_parse_string_type
538 },
539 {
540 NGM_GENERIC_COOKIE,
541 NGM_ASCII2BINARY,
542 "ascii2binary",
543 &ng_parse_ng_mesg_type,
544 &ng_parse_ng_mesg_type
545 },
546 {
547 NGM_GENERIC_COOKIE,
548 NGM_BINARY2ASCII,
549 "binary2ascii",
550 &ng_parse_ng_mesg_type,
551 &ng_parse_ng_mesg_type
552 },
553 { 0 }
554 };
555
556 /************************************************************************
557 Node routines
558 ************************************************************************/
559
560 /*
561 * Instantiate a node of the requested type
562 */
563 int
564 ng_make_node(const char *typename, node_p *nodepp)
565 {
566 struct ng_type *type;
567 int error;
568
569 /* Check that the type makes sense */
570 if (typename == NULL) {
571 TRAP_ERROR();
572 return (EINVAL);
573 }
574
575 /* Locate the node type. If we fail we return. Do not try to load
576 * module.
577 */
578 if ((type = ng_findtype(typename)) == NULL)
579 return (ENXIO);
580
581 /*
582 * If we have a constructor, then make the node and
583 * call the constructor to do type specific initialisation.
584 */
585 if (type->constructor != NULL) {
586 if ((error = ng_make_node_common(type, nodepp)) == 0) {
587 if ((error = ((*type->constructor)(*nodepp)) != 0)) {
588 NG_NODE_UNREF(*nodepp);
589 }
590 }
591 } else {
592 /*
593 * Node has no constructor. We cannot ask for one
594 * to be made. It must be brought into existence by
595 * some external agency. The external agency should
596 * call ng_make_node_common() directly to get the
597 * netgraph part initialised.
598 */
599 TRAP_ERROR();
600 error = EINVAL;
601 }
602 return (error);
603 }
604
605 /*
606 * Generic node creation. Called by node initialisation for externally
607 * instantiated nodes (e.g. hardware, sockets, etc ).
608 * The returned node has a reference count of 1.
609 */
610 int
611 ng_make_node_common(struct ng_type *type, node_p *nodepp)
612 {
613 INIT_VNET_NETGRAPH(curvnet);
614 node_p node;
615
616 /* Require the node type to have been already installed */
617 if (ng_findtype(type->name) == NULL) {
618 TRAP_ERROR();
619 return (EINVAL);
620 }
621
622 /* Make a node and try attach it to the type */
623 NG_ALLOC_NODE(node);
624 if (node == NULL) {
625 TRAP_ERROR();
626 return (ENOMEM);
627 }
628 node->nd_type = type;
629 NG_NODE_REF(node); /* note reference */
630 type->refs++;
631
632 NG_QUEUE_LOCK_INIT(&node->nd_input_queue);
633 STAILQ_INIT(&node->nd_input_queue.queue);
634 node->nd_input_queue.q_flags = 0;
635
636 /* Initialize hook list for new node */
637 LIST_INIT(&node->nd_hooks);
638
639 /* Link us into the name hash. */
640 mtx_lock(&ng_namehash_mtx);
641 LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes);
642 mtx_unlock(&ng_namehash_mtx);
643
644 /* get an ID and put us in the hash chain */
645 mtx_lock(&ng_idhash_mtx);
646 for (;;) { /* wrap protection, even if silly */
647 node_p node2 = NULL;
648 node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */
649
650 /* Is there a problem with the new number? */
651 NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */
652 if ((node->nd_ID != 0) && (node2 == NULL)) {
653 break;
654 }
655 }
656 LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)],
657 node, nd_idnodes);
658 mtx_unlock(&ng_idhash_mtx);
659
660 /* Done */
661 *nodepp = node;
662 return (0);
663 }
664
665 /*
666 * Forceably start the shutdown process on a node. Either call
667 * its shutdown method, or do the default shutdown if there is
668 * no type-specific method.
669 *
670 * We can only be called from a shutdown message, so we know we have
671 * a writer lock, and therefore exclusive access. It also means
672 * that we should not be on the work queue, but we check anyhow.
673 *
674 * Persistent node types must have a type-specific method which
675 * allocates a new node in which case, this one is irretrievably going away,
676 * or cleans up anything it needs, and just makes the node valid again,
677 * in which case we allow the node to survive.
678 *
679 * XXX We need to think of how to tell a persistent node that we
680 * REALLY need to go away because the hardware has gone or we
681 * are rebooting.... etc.
682 */
683 void
684 ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3)
685 {
686 hook_p hook;
687
688 /* Check if it's already shutting down */
689 if ((node->nd_flags & NGF_CLOSING) != 0)
690 return;
691
692 if (node == &ng_deadnode) {
693 printf ("shutdown called on deadnode\n");
694 return;
695 }
696
697 /* Add an extra reference so it doesn't go away during this */
698 NG_NODE_REF(node);
699
700 /*
701 * Mark it invalid so any newcomers know not to try use it
702 * Also add our own mark so we can't recurse
703 * note that NGF_INVALID does not do this as it's also set during
704 * creation
705 */
706 node->nd_flags |= NGF_INVALID|NGF_CLOSING;
707
708 /* If node has its pre-shutdown method, then call it first*/
709 if (node->nd_type && node->nd_type->close)
710 (*node->nd_type->close)(node);
711
712 /* Notify all remaining connected nodes to disconnect */
713 while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL)
714 ng_destroy_hook(hook);
715
716 /*
717 * Drain the input queue forceably.
718 * it has no hooks so what's it going to do, bleed on someone?
719 * Theoretically we came here from a queue entry that was added
720 * Just before the queue was closed, so it should be empty anyway.
721 * Also removes us from worklist if needed.
722 */
723 ng_flush_input_queue(node);
724
725 /* Ask the type if it has anything to do in this case */
726 if (node->nd_type && node->nd_type->shutdown) {
727 (*node->nd_type->shutdown)(node);
728 if (NG_NODE_IS_VALID(node)) {
729 /*
730 * Well, blow me down if the node code hasn't declared
731 * that it doesn't want to die.
732 * Presumably it is a persistant node.
733 * If we REALLY want it to go away,
734 * e.g. hardware going away,
735 * Our caller should set NGF_REALLY_DIE in nd_flags.
736 */
737 node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING);
738 NG_NODE_UNREF(node); /* Assume they still have theirs */
739 return;
740 }
741 } else { /* do the default thing */
742 NG_NODE_UNREF(node);
743 }
744
745 ng_unname(node); /* basically a NOP these days */
746
747 /*
748 * Remove extra reference, possibly the last
749 * Possible other holders of references may include
750 * timeout callouts, but theoretically the node's supposed to
751 * have cancelled them. Possibly hardware dependencies may
752 * force a driver to 'linger' with a reference.
753 */
754 NG_NODE_UNREF(node);
755 }
756
757 /*
758 * Remove a reference to the node, possibly the last.
759 * deadnode always acts as it it were the last.
760 */
761 int
762 ng_unref_node(node_p node)
763 {
764 int v;
765
766 if (node == &ng_deadnode) {
767 return (0);
768 }
769
770 v = atomic_fetchadd_int(&node->nd_refs, -1);
771
772 if (v == 1) { /* we were the last */
773
774 mtx_lock(&ng_namehash_mtx);
775 node->nd_type->refs--; /* XXX maybe should get types lock? */
776 LIST_REMOVE(node, nd_nodes);
777 mtx_unlock(&ng_namehash_mtx);
778
779 mtx_lock(&ng_idhash_mtx);
780 LIST_REMOVE(node, nd_idnodes);
781 mtx_unlock(&ng_idhash_mtx);
782
783 mtx_destroy(&node->nd_input_queue.q_mtx);
784 NG_FREE_NODE(node);
785 }
786 return (v - 1);
787 }
788
789 /************************************************************************
790 Node ID handling
791 ************************************************************************/
792 static node_p
793 ng_ID2noderef(ng_ID_t ID)
794 {
795 INIT_VNET_NETGRAPH(curvnet);
796 node_p node;
797 mtx_lock(&ng_idhash_mtx);
798 NG_IDHASH_FIND(ID, node);
799 if(node)
800 NG_NODE_REF(node);
801 mtx_unlock(&ng_idhash_mtx);
802 return(node);
803 }
804
805 ng_ID_t
806 ng_node2ID(node_p node)
807 {
808 return (node ? NG_NODE_ID(node) : 0);
809 }
810
811 /************************************************************************
812 Node name handling
813 ************************************************************************/
814
815 /*
816 * Assign a node a name. Once assigned, the name cannot be changed.
817 */
818 int
819 ng_name_node(node_p node, const char *name)
820 {
821 INIT_VNET_NETGRAPH(curvnet);
822 int i, hash;
823 node_p node2;
824
825 /* Check the name is valid */
826 for (i = 0; i < NG_NODESIZ; i++) {
827 if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
828 break;
829 }
830 if (i == 0 || name[i] != '\0') {
831 TRAP_ERROR();
832 return (EINVAL);
833 }
834 if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
835 TRAP_ERROR();
836 return (EINVAL);
837 }
838
839 /* Check the name isn't already being used */
840 if ((node2 = ng_name2noderef(node, name)) != NULL) {
841 NG_NODE_UNREF(node2);
842 TRAP_ERROR();
843 return (EADDRINUSE);
844 }
845
846 /* copy it */
847 strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ);
848
849 /* Update name hash. */
850 NG_NAMEHASH(name, hash);
851 mtx_lock(&ng_namehash_mtx);
852 LIST_REMOVE(node, nd_nodes);
853 LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes);
854 mtx_unlock(&ng_namehash_mtx);
855
856 return (0);
857 }
858
859 /*
860 * Find a node by absolute name. The name should NOT end with ':'
861 * The name "." means "this node" and "[xxx]" means "the node
862 * with ID (ie, at address) xxx".
863 *
864 * Returns the node if found, else NULL.
865 * Eventually should add something faster than a sequential search.
866 * Note it acquires a reference on the node so you can be sure it's still
867 * there.
868 */
869 node_p
870 ng_name2noderef(node_p here, const char *name)
871 {
872 INIT_VNET_NETGRAPH(curvnet);
873 node_p node;
874 ng_ID_t temp;
875 int hash;
876
877 /* "." means "this node" */
878 if (strcmp(name, ".") == 0) {
879 NG_NODE_REF(here);
880 return(here);
881 }
882
883 /* Check for name-by-ID */
884 if ((temp = ng_decodeidname(name)) != 0) {
885 return (ng_ID2noderef(temp));
886 }
887
888 /* Find node by name */
889 NG_NAMEHASH(name, hash);
890 mtx_lock(&ng_namehash_mtx);
891 LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) {
892 if (NG_NODE_IS_VALID(node) &&
893 (strcmp(NG_NODE_NAME(node), name) == 0)) {
894 break;
895 }
896 }
897 if (node)
898 NG_NODE_REF(node);
899 mtx_unlock(&ng_namehash_mtx);
900 return (node);
901 }
902
903 /*
904 * Decode an ID name, eg. "[f03034de]". Returns 0 if the
905 * string is not valid, otherwise returns the value.
906 */
907 static ng_ID_t
908 ng_decodeidname(const char *name)
909 {
910 const int len = strlen(name);
911 char *eptr;
912 u_long val;
913
914 /* Check for proper length, brackets, no leading junk */
915 if ((len < 3)
916 || (name[0] != '[')
917 || (name[len - 1] != ']')
918 || (!isxdigit(name[1]))) {
919 return ((ng_ID_t)0);
920 }
921
922 /* Decode number */
923 val = strtoul(name + 1, &eptr, 16);
924 if ((eptr - name != len - 1)
925 || (val == ULONG_MAX)
926 || (val == 0)) {
927 return ((ng_ID_t)0);
928 }
929 return (ng_ID_t)val;
930 }
931
932 /*
933 * Remove a name from a node. This should only be called
934 * when shutting down and removing the node.
935 * IF we allow name changing this may be more resurrected.
936 */
937 void
938 ng_unname(node_p node)
939 {
940 }
941
942 /************************************************************************
943 Hook routines
944 Names are not optional. Hooks are always connected, except for a
945 brief moment within these routines. On invalidation or during creation
946 they are connected to the 'dead' hook.
947 ************************************************************************/
948
949 /*
950 * Remove a hook reference
951 */
952 void
953 ng_unref_hook(hook_p hook)
954 {
955 int v;
956
957 if (hook == &ng_deadhook) {
958 return;
959 }
960
961 v = atomic_fetchadd_int(&hook->hk_refs, -1);
962
963 if (v == 1) { /* we were the last */
964 if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */
965 _NG_NODE_UNREF((_NG_HOOK_NODE(hook)));
966 NG_FREE_HOOK(hook);
967 }
968 }
969
970 /*
971 * Add an unconnected hook to a node. Only used internally.
972 * Assumes node is locked. (XXX not yet true )
973 */
974 static int
975 ng_add_hook(node_p node, const char *name, hook_p *hookp)
976 {
977 hook_p hook;
978 int error = 0;
979
980 /* Check that the given name is good */
981 if (name == NULL) {
982 TRAP_ERROR();
983 return (EINVAL);
984 }
985 if (ng_findhook(node, name) != NULL) {
986 TRAP_ERROR();
987 return (EEXIST);
988 }
989
990 /* Allocate the hook and link it up */
991 NG_ALLOC_HOOK(hook);
992 if (hook == NULL) {
993 TRAP_ERROR();
994 return (ENOMEM);
995 }
996 hook->hk_refs = 1; /* add a reference for us to return */
997 hook->hk_flags = HK_INVALID;
998 hook->hk_peer = &ng_deadhook; /* start off this way */
999 hook->hk_node = node;
1000 NG_NODE_REF(node); /* each hook counts as a reference */
1001
1002 /* Set hook name */
1003 strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ);
1004
1005 /*
1006 * Check if the node type code has something to say about it
1007 * If it fails, the unref of the hook will also unref the node.
1008 */
1009 if (node->nd_type->newhook != NULL) {
1010 if ((error = (*node->nd_type->newhook)(node, hook, name))) {
1011 NG_HOOK_UNREF(hook); /* this frees the hook */
1012 return (error);
1013 }
1014 }
1015 /*
1016 * The 'type' agrees so far, so go ahead and link it in.
1017 * We'll ask again later when we actually connect the hooks.
1018 */
1019 LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks);
1020 node->nd_numhooks++;
1021 |