Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142248563
D50244.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D50244.diff
View Options
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -413,6 +413,7 @@
ng_vjc.4 \
ng_vlan.4 \
ng_vlan_rotate.4 \
+ ng_wormhole.4 \
nmdm.4 \
${_ntb.4} \
${_ntb_hw_amd.4} \
diff --git a/share/man/man4/ng_wormhole.4 b/share/man/man4/ng_wormhole.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/ng_wormhole.4
@@ -0,0 +1,213 @@
+.\"
+.\" Copyright (c) 2025 David Marker <dave@freedave.net>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd April 9, 2025
+.Dt NG_WORMHOLE 4
+.Os
+.Sh NAME
+.Nm ng_wormhole
+.Nd "vnet traversing netgraph node type"
+.Sh SYNOPSIS
+.In netgraph/ng_wormhole.h
+.Sh DESCRIPTION
+The
+.Vt wormhole
+node type forwards packets from one
+.Xr vnet 9
+to another.
+To send packets a
+.Vt wormhole
+pair must be established.
+This is done by first creating an
+.Vt wormhole
+in one
+.Xr vnet 9 ,
+and then sending the
+.Ar open
+message with the name of the jail whose
+.Xr vnet 9
+you wish to have connected.
+The connection is established when a
+.Xr netgraph 4
+node from each
+.Xr vnet 9
+is then connected to the
+.Ar evthorizon
+hook of the
+.Vt wormhole .
+.Pp
+There is no limit to the number of
+.Vt wormholes
+that may be created, but each side of an opened wormhole allows exactly one
+connection.
+It has another hook called the
+.Ar warp ,
+but it is only created by the act of opening the wormhole.
+As a convenience the
+.Ar warp
+hooks are labeled with the jail ID of the other side of a wormhole.
+With a jail ID and a
+.Xr netgraph 4
+node ID from one wormhole you can find the other side to attach
+to.
+.Pp
+.Vt wormholes
+are not persistent, but when you
+.Ar open
+the
+.Vt wormhole
+each side has a reference to the other and that prevents either from closing.
+This allows disconnecting and reconnecting to the
+.Ar evthorizon .
+This is useful to change configuration, perhaps insert an
+.Xr ng_pipe 4
+for testing or an
+.Xr ng_vlan 4
+if required.
+This can be done on either or both sides.
+Once a
+.Vt wormhole
+has been opened it will only go away with an explicit
+.Ar shutdown
+message, when the
+.Xr vnet 9
+is removed (the jail is shutdown), or its peer experienced one
+of these conditions.
+.Pp
+There are no other messages, and there are no statistics in order
+to keep overhead from the
+.Vt wormhole
+to a minimum.
+.Pp
+Any node can be connected to the
+.Ar evthorizon ,
+including another
+.Vt wormhole
+via its
+.Ar evthorizon ,
+with one restriction.
+Connecting the event horizons of wormholes collapses two pairs into a single
+pair, which is only possible if the far side (the nodes not being connected)
+reside in a different
+.Xr vnet 9
+from each other.
+This can be used to connect unrelated peer jails via
+.Vt wormhole
+similar to what you might do with
+.Xr epair 4 .
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_WORMHOLE_OPEN Pq Ic open
+This command may be given only to an unopened
+.Nm wormhole ,
+once a
+.Nm wormhole
+pair is established it can not be closed or re-opened.
+This requires a string for the jail name or ID be provided.
+That jail must have a
+.Xr vnet 9
+and it must be different from the
+.Xr vnet 9
+where the original
+.Nm wormhole
+resides.
+.El
+.Sh EXAMPLES
+You need to open the wormhole before disconnecting or it will disappear.
+.Bd -literal -offset 4n
+#!/bin/sh
+
+ngctl -f- << EOF
+mkpeer wormhole w evthorizon
+name .:w wh0a
+msg wh0a: open "testjail"
+EOF
+.Ed
+.Pp
+Once open you will need to
+.Ar show
+the
+.Nm wormhole
+to see the ID of the other side.
+.Bd -literal -offset 4n
+#!/bin/sh
+
+ngctl show wh0a:
+
+Name: wh0a Type: wormhole ID: 0000002c Num hooks: 1
+ Local hook Peer name Peer type Peer ID Peer hook
+ ---------- --------- --------- ------- ---------
+ jid=4 <unnamed> wormhole 00000013 jid=0
+.Ed
+.Pp
+This shows that you created
+.Ar wh0a
+with ID
+.Ar 0000002c
+and opened the other side in the jail with ID
+.Ar 4
+and its
+.Xr netgraph 4
+ID in that jail's
+.Xr vnet 9
+is
+.Ar 00000013 .
+You now have enough information to name the other side.
+.Bd -literal -offset 4n
+#!/bin/sh
+
+jexec 4 ngctl name [00000013]: wh0b
+.Ed
+.Pp
+Finally to make use of this pair you need to connect
+.Ar wh0a
+and
+.Ar wh0b
+to
+.Xr netgraph 4
+nodes, possibly by creating them.
+.Bd -literal -offset 4n
+#!/bin/sh
+
+ngctl -f- << EOF
+mkpeer wh0a: eiface evthorizon ether
+name wh0a:evthorizon tst0a
+EOF
+
+ifn=$(ngctl msg tst0a: getifname | sed '1d' | cut -d\\" -f2)
+ifconfig name $ifn tst0a
+
+jexec testjail ngctl -f- << EOF
+mkpeer wh0b: eiface evthorizon ether
+name wh0b:evthorizon tst0b
+EOF
+
+ifn=$(jexec testjail ngctl msg tst0b: getifname | sed '1d' | cut -d\\" -f2)
+ifconfig -j testjail name $ifn tst0b
+.Ed
+.Pp
+The
+.Xr ng_eiface 4
+.Pq Cm tst0a and Cm tst0b
+can now be configured and used for networking between vnets.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr epair 4 ,
+.Xr netgraph 4 ,
+.Xr ng_eiface 4 ,
+.Xr jexec 8 ,
+.Xr ngctl 8 ,
+.Xr vnet 9
+.Sh HISTORY
+The
+.Nm
+node type was implemented in
+.Fx 15.0 .
+.Sh AUTHORS
+.An David Marker Aq Mt dave@freedave.net
diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile
--- a/sys/modules/netgraph/Makefile
+++ b/sys/modules/netgraph/Makefile
@@ -51,7 +51,8 @@
UI \
vjc \
vlan \
- vlan_rotate
+ vlan_rotate \
+ ${_wormhole}
.if ${MK_BLUETOOTH} != "no" || defined(ALL_MODULES)
_bluetooth= bluetooth
@@ -61,4 +62,8 @@
_mppc= mppc
.endif
+.if ${KERN_OPTS:MVIMAGE}
+_wormhole= wormhole
+.endif
+
.include <bsd.subdir.mk>
diff --git a/sys/modules/netgraph/wormhole/Makefile b/sys/modules/netgraph/wormhole/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/netgraph/wormhole/Makefile
@@ -0,0 +1,4 @@
+KMOD= ng_wormhole
+SRCS= ng_wormhole.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/netgraph/ng_wormhole.h b/sys/netgraph/ng_wormhole.h
new file mode 100644
--- /dev/null
+++ b/sys/netgraph/ng_wormhole.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 David Marker <dave@freedave.net>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _NETGRAPH_NG_WORMHOLE_H_
+#define _NETGRAPH_NG_WORMHOLE_H_
+
+#define NG_WORMHOLE_NODE_TYPE "wormhole"
+#define NGM_WORMHOLE_COOKIE 1742462349
+
+/* this is what user connects to */
+#define NG_WORMHOLE_HOOK "evthorizon"
+
+/* Netgraph commands understood by this node type */
+enum {
+ NGM_WORMHOLE_OPEN = 1,
+};
+
+#endif /* _NETGRAPH_NG_WORMHOLE_H_ */
diff --git a/sys/netgraph/ng_wormhole.c b/sys/netgraph/ng_wormhole.c
new file mode 100644
--- /dev/null
+++ b/sys/netgraph/ng_wormhole.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2025 David Marker <dave@freedave.net>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/ctype.h>
+#include <sys/errno.h>
+#include <sys/jail.h>
+#include <sys/syslog.h>
+#include <net/vnet.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_parse.h>
+#include <netgraph/ng_wormhole.h>
+#include <netgraph/netgraph.h>
+
+#ifdef NG_SEPARATE_MALLOC
+static MALLOC_DEFINE(M_NETGRAPH_WORMHOLE, "netgraph_wormhole",
+ "netgraph wormhole node");
+#else
+#define M_NETGRAPH_WORMHOLE M_NETGRAPH
+#endif
+
+/*
+ * This _requires_ vimage to be useful.
+ */
+#ifndef VIMAGE
+#error ng_wormhole requires VIMAGE.
+#endif /* VIMAGE */
+
+/* we need this from ng_base */
+void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3);
+
+/* we need a flag just for ourselves */
+#define HK_COLLAPSE 0x1000
+
+
+static ng_constructor_t ng_wormhole_constructor;
+static ng_rcvmsg_t ng_wormhole_rcvmsg;
+static ng_shutdown_t ng_wormhole_shutdown;
+static ng_newhook_t ng_wormhole_newhook;
+static ng_connect_t ng_wormhole_connect;
+static ng_rcvdata_t ng_wormhole_rcvdata;
+static ng_disconnect_t ng_wormhole_disconnect;
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_wormhole_cmdlist[] = {
+ {
+ NGM_WORMHOLE_COOKIE,
+ NGM_WORMHOLE_OPEN,
+ "open",
+ &ng_parse_string_type,
+ NULL,
+ },
+ { 0 }
+};
+
+/* Netgraph node type descriptor */
+static struct ng_type typestruct = {
+ .version = NG_ABI_VERSION,
+ .name = NG_WORMHOLE_NODE_TYPE,
+ .constructor = ng_wormhole_constructor,
+ .rcvmsg = ng_wormhole_rcvmsg,
+ .shutdown = ng_wormhole_shutdown,
+ .newhook = ng_wormhole_newhook,
+ .connect = ng_wormhole_connect,
+ .rcvdata = ng_wormhole_rcvdata,
+ .disconnect = ng_wormhole_disconnect,
+ .cmdlist = ng_wormhole_cmdlist,
+};
+NETGRAPH_INIT(wormhole, &typestruct);
+
+struct ng_wormhole_priv {
+ node_p node; /* back pointer to node */
+ hook_p warp; /* connectes to other side */
+ hook_p eh; /* user connection */
+};
+typedef struct ng_wormhole_priv *priv_p;
+
+/*
+ * We don't get to allocate a hook so what we do is allocate `warp` with `priv`.
+ *
+ * This is problematic in the sense that we can't let NG_UNREF_HOOK free the
+ * hook we allocated with `priv`. We give the hooks an extra ref to prevent
+ * that.
+ */
+struct alloc_priv {
+ struct ng_wormhole_priv priv;
+ struct ng_hook hook;
+};
+
+/* At this point we can only open one side of the wormhole. */
+static int
+ng_wormhole_constructor(node_p node)
+{
+ priv_p priv;
+
+ priv = malloc(sizeof(struct alloc_priv), M_NETGRAPH_WORMHOLE,
+ M_WAITOK | M_ZERO);
+ NG_NODE_SET_PRIVATE(node, priv);
+ priv->node = node;
+
+ return (0);
+}
+
+/*
+ * This is really the workhorse that makes it so we can place the other side
+ * and never have to vmove it.
+ *
+ * prison names are array of MAXHOSTNAMELEN which at present is far larger
+ * than NG_HOOKSIZ.
+ *
+ * Obviously that mismatch means we can't just name the hook after the jail.
+ * But even a 64-bit int only needs 19 characters (no commas).
+ *
+ * That even leaves space to store some intent like a prefix of "jid=". That
+ * ought to give users a clue where the other side of the wormhole lives.
+ * And an easy way to go deal with it.
+ */
+static int
+ng_wormhole_open(priv_p pv_near, const char *prison)
+{
+ int rc, jid;
+ char *ep;
+ struct prison *pr_near, *pr_far;
+ priv_p pv_far;
+ hook_p hk_near, hk_far;
+
+ pr_near = curthread->td_ucred->cr_prison;
+ jid = strtoul(prison, &ep, 10); /* may have got number */
+
+ sx_slock(&allprison_lock);
+ if (!*ep)
+ pr_far = prison_find_child(pr_near, jid);
+ else
+ pr_far = prison_find_name(pr_near, prison);
+ sx_sunlock(&allprison_lock);
+ if (pr_far == NULL) {
+ return (EHOSTDOWN); /* jail not found */
+ }
+
+ /*
+ * XXX is this sufficient?
+ *
+ * prison_find_name already made sure it was valid and alive.
+ * We just need to make sure it is vnet enabled and has a *different*
+ * vnet than pr_near.
+ */
+ if (((pr_far->pr_flags & PR_VNET) == 0 ) || /* not vnet */
+ (pr_far->pr_vnet == pr_near->pr_vnet)) { /* not different */
+ mtx_unlock(&pr_far->pr_mtx);
+ return (EINVAL);
+ }
+ prison_hold_locked(pr_far);
+ mtx_unlock(&pr_far->pr_mtx);
+
+ pv_far = malloc(sizeof(struct alloc_priv), M_NETGRAPH_WORMHOLE,
+ M_WAITOK | M_ZERO);
+
+ hk_near = &((struct alloc_priv *)pv_near)->hook;
+ hk_far = &((struct alloc_priv *)pv_far)->hook;
+
+ /* change to that vnet and create where it is needed */
+ CURVNET_SET(pr_far->pr_vnet);
+ if ((rc = ng_make_node_common(&typestruct, &(pv_far->node))) != 0) {
+ prison_free(pr_far);
+ free(pv_far, M_NETGRAPH_WORMHOLE);
+ return (rc);
+ }
+ CURVNET_RESTORE();
+
+ NG_NODE_SET_PRIVATE(pv_far->node, pv_far);
+
+ /*
+ * Fill in hooks and place them on list remembering to give extra
+ * reference. Basically do what ng_add_hook would do except without
+ * calling connect pointer.
+ */
+ snprintf(NG_HOOK_NAME(hk_near), NG_HOOKSIZ, "jid=%d", pr_far->pr_id);
+ snprintf(NG_HOOK_NAME(hk_far), NG_HOOKSIZ, "jid=%d", pr_near->pr_id);
+
+ /*
+ * leave hk_flgs=0. we have the q-lock for ourself and nothing can talk
+ * to the other side but us yet anyway.
+ */
+ hk_far->hk_refs = 3; /* intentional! */
+ hk_near->hk_refs = 3; /* 1 for hook, 1 for node, 1 extra */
+ hk_far->hk_peer = hk_near;
+ hk_near->hk_peer = hk_far;
+ hk_far->hk_node = pv_far->node;
+ hk_near->hk_node = pv_near->node;
+#ifdef NETGRAPH_DEBUG
+ hk_far->hk_magic = HK_MAGIC;
+ hk_near->hk_magic = HK_MAGIC;
+#endif
+ NG_NODE_REF(pv_far->node); /* will now hold each other open */
+ NG_NODE_REF(pv_near->node);
+ LIST_INSERT_HEAD(&pv_far->node->nd_hooks, hk_far, hk_hooks);
+ LIST_INSERT_HEAD(&pv_near->node->nd_hooks, hk_near, hk_hooks);
+ pv_far->node->nd_numhooks++;
+ pv_near->node->nd_numhooks++;
+
+ pv_far->warp = hk_far;
+ pv_near->warp = hk_near;
+
+ /*
+ * At this point if a vnet going down turfs either side of the wormhole
+ * it shutsdown both sides (because it will disconnect `warp`).
+ *
+ * That is fine, we just can't have a one sided wormhole.
+ */
+ prison_free(pr_far);
+
+ return (0);
+}
+
+/*
+ * There is one special case: another wormhole connection.
+ * But we don't have valid hooks on both sides. Wait for connect to deal with.
+ */
+static int
+ng_wormhole_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = NG_NODE_PRIVATE(node);
+
+ if (strcmp(name, NG_WORMHOLE_HOOK))
+ return (EINVAL);
+
+ if (priv->eh != NULL)
+ return (EISCONN);
+
+ /* more commonly just add connection */
+ priv->eh = hook;
+ return (0);
+}
+
+/* at last all 4 nodes are locked */
+static void
+ng_wormhole_collapse2(node_p nd_aa, hook_p dummy1, void *priv, int dummy3)
+{
+ priv_p pv_a = (priv_p)priv; /* just trust pv_a */
+ priv_p pv_b = NG_NODE_PRIVATE(NG_PEER_NODE(pv_a->eh));
+ priv_p pv_aa = NG_NODE_PRIVATE(NG_PEER_NODE(pv_a->warp));
+ priv_p pv_bb = NG_NODE_PRIVATE(NG_PEER_NODE(pv_b->warp));
+
+ /* rearange */
+ pv_a->warp->hk_peer = pv_b->warp;
+ pv_b->warp->hk_peer = pv_a->warp;
+ pv_aa->warp->hk_peer = pv_bb->warp;
+ pv_bb->warp->hk_peer = pv_aa->warp;
+
+ /* gotta fix hook names to show correct info */
+ strncpy(NG_HOOK_NAME(pv_aa->warp), NG_HOOK_NAME(pv_a->warp), NG_HOOKSIZ);
+ strncpy(NG_HOOK_NAME(pv_bb->warp), NG_HOOK_NAME(pv_b->warp), NG_HOOKSIZ);
+
+ /*
+ * Only have to destroy one to remove both circular nodes.
+ * We could try ng_rmnode_self but we can't ask for NG_WAITOK. I do see
+ * lots of calls that don't check return but it could fail. Those calls
+ * are all in disconnect.
+ */
+ ng_rmnode(pv_a->node, NULL, NULL, 0);
+}
+
+/* now nd_bb is locked, only purpose of this, go on to lock nd_aa */
+static void
+ng_wormhole_collapse1(node_p nd_bb, hook_p dummy1, void *priv, int dummy3)
+{
+ int rc;
+ priv_p pv_a = (priv_p)priv; /* just trust pv_a */
+ node_p nd_aa = NG_PEER_NODE(pv_a->warp);
+
+ rc = ng_send_fn1(nd_aa, NULL, &ng_wormhole_collapse2, pv_a, 0,
+ NG_WAITOK);
+ MPASS(rc == 0);
+ (void)(rc);
+}
+
+/*
+ * When two wormhole's event horizons collide they collapse into a single
+ * wormhole.
+ *
+ * Nothing gets to direct connect. But nothing should have more than 2 wormholes
+ * to pass through. And the wormholes hookinfo should always point you to where
+ * packets are flowing.
+ *
+ * This is easier to show than explain. Before connect its all normal.
+ * Just two wormholes (wh0a and wh0b) waiting for a connect:
+ * |
+ * wh0a---warp-+-wh0aa---eh---?
+ * |
+ * +-------------------
+ * |
+ * wh0b---warp-+-wh0bb---eh---?
+ * |
+ *
+ * Now connect wh0a to wh0b (evthorizon to evthorizon) pre-collapse:
+ * (refer to this s/wh0/pv_/g for finding nodes from pv_a)
+ * |
+ * wh0a---warp-+-wh0aa---eh---?
+ * | |
+ * eh +-------------------
+ * | |
+ * wh0b---warp-+-wh0bb---eh---?
+ * |
+ *
+ * But when everything is done:
+ * |
+ * | wh0aa---eh---?
+ * | |
+ * +--warp-------------
+ * | |
+ * | wh0bb---eh---?
+ * |
+ *
+ * Keep that map in mind going through the series of events that start here.
+ * We start with 4 nodes in 3 vnets. We end with 2 nodes in 2 vnets.
+ *
+ * pv_a is going to be our arg to both funtions that use ng_send_fn1 through the
+ * whole process as right up until the end it can get us to pv_b, pv_aa, and
+ * pv_bb (actually so could pv_b).
+ *
+ * This is allows peer jails to have private connections. Similar to if you
+ * pushed the 'a' end of an epair in one jail and the 'b' in another.
+ *
+ * But normally wh0a will just connect to something in our own vnet which is:
+ *
+ * wh0a----eh---?
+ * vnetX |
+ * ------------warp-------------
+ * vnetY |
+ * wh0aa---eh---?
+ *
+ * And when asked to connect to anything but another wormhole we just return 0.
+ * Probably the most common case.
+ *
+ */
+static int
+ng_wormhole_connect(hook_p hook)
+{
+ int rc;
+ priv_p pv_a, pv_b;
+ node_p nd_aa, nd_bb;
+
+ /* user can only connect to `eh` so check its peer type */
+ if (NG_PEER_NODE(hook)->nd_type != &typestruct)
+ return (0);
+
+ pv_a = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ pv_b = NG_NODE_PRIVATE(NG_PEER_NODE(hook));
+
+ /*
+ * We can't allow two wormholes to connect until they are open. Because
+ * a failing collapse (which only happens if they are not both open)
+ * would leave bogus state for the hooks.
+ */
+ if (pv_a->warp == NULL || pv_b->warp == NULL)
+ return (EINVAL);
+
+ /*
+ * We also refuse to connect if these 2 are in the same vnet. That would
+ * technically be a connected path. It just doesn't make sense for both
+ * ends of a wormhole to be in the same vnet. Just connect them if you
+ * want that.
+ */
+ nd_aa = NG_PEER_NODE(pv_a->warp);
+ nd_bb = NG_PEER_NODE(pv_b->warp);
+ if (nd_aa->nd_vnet == nd_bb->nd_vnet)
+ return (EDOOFUS); /* to distinguish not insult */
+
+ /*
+ * The first one in will set HK_COLLAPSE and tag the peer hook. The 2nd
+ * will see its hook is tagged, clear then start the collapse.
+ */
+ if ((hook->hk_flags & HK_COLLAPSE) == 0) {
+ /* first to arrive (not a race both stay locked). */
+ NG_HOOK_PEER(hook)->hk_flags |= HK_COLLAPSE;
+ return (0);
+ }
+ hook->hk_flags &= ~HK_COLLAPSE;
+
+ /*
+ * ng_bypass, sanely, requires hooks to be on same node. This collapse
+ * is a by_pass between 4 nodes. 2 of which will go away soon.
+ *
+ * But before anything can happen we have to do the queue dance to get
+ * them locked. We need to lock nd_bb then nd_aa before proceeding.
+ */
+ rc = ng_send_fn1(nd_bb, NULL, &ng_wormhole_collapse1, pv_a, 0,
+ NG_WAITOK);
+ MPASS(rc == 0);
+ return (rc);
+}
+
+static int
+ng_wormhole_rcvmsg(node_p node, item_p item, hook_p lasthook)
+{
+ const priv_p priv = NG_NODE_PRIVATE(node);
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+ struct ng_mesg *msg;
+
+ NGI_GET_MSG(item, msg);
+ /* Deal with message according to cookie and command */
+ switch (msg->header.typecookie) {
+ case NGM_WORMHOLE_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_WORMHOLE_OPEN:
+ {
+ /* By using a command we can accept any jail name */
+ if (msg->header.arglen == 0 ||
+ msg->header.arglen > MAXHOSTNAMELEN) {
+ error = EINVAL;
+ break;
+ }
+ /* only one move is allowed */
+ if (priv->warp != NULL)
+ return (EISCONN);
+
+ /* ensure we can't walk off the end */
+ ((char *)msg->data)[msg->header.arglen] = '\0';
+
+ error = ng_wormhole_open(priv, (char *)msg->data);
+ break;
+ }
+ default:
+ error = EINVAL; /* unknown command */
+ break;
+ }
+ break;
+ default:
+ error = EINVAL; /* unknown cookie type */
+ break;
+ }
+
+ /* Take care of synchronous response, if any */
+ NG_RESPOND_MSG(error, node, item, resp);
+ /* Free the message and return */
+ NG_FREE_MSG(msg);
+ return(error);
+}
+
+
+/*
+ * A really trivial function.
+ *
+ * By keeping the wormhole in between the two sides you can make some sense of
+ * what is returned from `show`. Yes duplicate IDs are possible but you clearly
+ * see a wormhole (from both sides) and it has hook names of the JID that each
+ * side is located in as another clue.
+ */
+static int
+ng_wormhole_rcvdata(hook_p hook, item_p item )
+{
+ int rc;
+ const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ hook_p dest = (hook == priv->eh) ? priv->warp : priv->eh;
+
+ /* this correctly handles when nothing is connected to either side */
+ NG_FWD_ITEM_HOOK(rc, item, dest);
+
+ return (rc);
+}
+
+/*
+ * shutdown of one side should just shutdown both. This automatically happens
+ * because prior to this being called, ng_base called ng_rmnode which killed
+ * all our hooks. In particular removing `warp` from both sides collapses the
+ * wormhole.
+ *
+ * When this gets called your hooks are removed already.
+ */
+static int
+ng_wormhole_shutdown(node_p node)
+{
+ const priv_p priv = NG_NODE_PRIVATE(node);
+
+ NG_NODE_SET_PRIVATE(node, NULL);
+ NG_NODE_UNREF(node);
+ free(priv, M_NETGRAPH_WORMHOLE);
+
+ return (0);
+}
+
+/*
+ * You can disconnect and reconnect NG_WORMHOLE_HOOK (the `eh` side) as many
+ * times as you want. But if `warp` goes the wormhole collapses.
+ *
+ * This is how we allow either side to do a shutdown.
+ */
+static int
+ng_wormhole_disconnect(hook_p hook)
+{
+ /*
+ * The usual of all hooks gone means shutdown, but we can simplify to
+ * just caring when `warp` goes down since a shutdown will remove all
+ * hooks anyway.
+ */
+ if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) {
+ const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ if (hook == priv->eh)
+ priv->eh = NULL; /* allow new connection */
+ else
+ ng_rmnode_self(NG_HOOK_NODE(hook));
+ }
+
+ return (0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 18, 7:11 PM (50 m, 17 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27716039
Default Alt Text
D50244.diff (21 KB)
Attached To
Mode
D50244: create netgraph ng_wormhole node type
Attached
Detach File
Event Timeline
Log In to Comment