Page MenuHomeFreeBSD

D50244.diff
No OneTemporary

D50244.diff

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

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)

Event Timeline