Page MenuHomeFreeBSD

D49158.id.diff
No OneTemporary

D49158.id.diff

diff --git a/share/examples/jails/jei b/share/examples/jails/jei
new file mode 100755
--- /dev/null
+++ b/share/examples/jails/jei
@@ -0,0 +1,291 @@
+#!/bin/sh
+#-
+# Copyright (c) 2025 David Marker
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ IDENT(1)
+#
+# $Title: ng_eiface(4) management script for vnet jails $
+#
+############################################################ INFORMATION
+#
+# Use this tool manually or with jail.conf(5) to add `net' interfaces to jails.
+# Unlike jng this is only for ng_eiface(4) and it only creates them and sends
+# them to jails. It waits until the interface is moved to rename it. This
+# means you can create a "jail0" interface for all your jails and configure
+# it the same in all of them. No numbering scheme required.
+#
+# This will also send "setvnethome" to the ng_eiface(4), this means the network
+# interface is not returned when the jail is shutdown (or indeed ever). Rather
+# the netgraph(4) node will be destroyed automatically when the jail is torn
+# down. It does *NOT* return. This is meant for creating ephemeral interfaces
+# with well known names for jails.
+#
+# This will not create netgraph(4) bridges or other nodes for you at all.
+# It is assumed you already have a means to do that. The example config assumes
+# you have two ng_bridge(4) nodes: br0 and br1
+#
+# In jail.conf(5) format:
+#
+# ### BEGIN EXCERPT ###
+#
+# xxx {
+# host.hostname = "xxx.yyy";
+# path = "/vm/xxx";
+#
+# #
+# # NB: Below line required
+# #
+# vnet;
+#
+# exec.clean;
+# exec.system_user = "root";
+# exec.jail_user = "root";
+#
+# #
+# # NB: Below 2-lines or similar required (any number of interface)
+# # NB: You can connect the ng_eiface(4) to any netgraph(4) node
+# # these examples show connecting to a bridge.
+# # NB: You can assign a MAC address here too for DHCP.
+# #
+# exec.created += "jei $name lan0 br0:link 00:0C:29:39:B4:4D";
+# exec.created += "jei $name jail0 br1:link";
+#
+# # Standard recipe
+# exec.start += "/bin/sh /etc/rc";
+# exec.stop = "/bin/sh /etc/rc.shutdown jail";
+#
+# exec.consolelog = "/var/log/jail_xxx_console.log";
+# mount.devfs;
+#
+# # Optional (default off)
+# #allow.mount;
+# #allow.set_hostname = 1;
+# #allow.sysvipc = 1;
+# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP
+# }
+#
+# ### END EXCERPT ###
+#
+# ASIDE: dhclient(8) inside a vnet jail...
+#
+# To allow dhclient(8) to work inside a vnet jail, make sure the following
+# appears in /etc/devfs.rules (which should be created if it doesn't exist):
+#
+# [devfsrules_jail=11]
+# add include $devfsrules_hide_all
+# add include $devfsrules_unhide_basic
+# add include $devfsrules_unhide_login
+# add path 'bpf*' unhide
+#
+# And set ether devfs.ruleset="11" (jail.conf(5)) or
+# jail_{name}_devfs_ruleset="11" (rc.conf(5)).
+#
+############################################################ GLOBALS
+
+pgm="${0##*/}" # Program basename
+
+#
+# Global exit status
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+usage()
+{
+ exec >&2
+ echo "Usage: $pgm <jail> <eiface> <hookpath> [MAC]"
+ echo ""
+ echo "<jail> must be a valid argument for jexec(8)."
+ echo "<eiface> must be a valid name for an interface for both"
+ echo "netgraph(4) and ifconfig(8)."
+ echo "<hookpath> is any valid node:hook path for netgraph(4)."
+ echo ""
+ echo "Example:"
+ echo " jei myjail lan0 br0:link"
+ echo ""
+
+ exit $FAILURE
+}
+
+
+mustberoot_to_continue()
+{
+ if [ "$( id -u )" -ne 0 ]; then
+ echo "Must run as root!" >&2
+ exit $FAILURE
+ fi
+}
+
+
+# Don't assume you can use the attach point to find the eiface.
+# A bridge can be connected to by `[up]linkX` where X is known but also by
+# `[up]link` which uses next available number.
+#
+# Also don't rename until the ng_eiface(4) has been moved to the jail.
+#
+# Create the ng_eiface(4) leave unconnected, they are persistent. Return the
+# node id-name. This won't change even if there is a clash moving to jail. If
+# that happens we have to clean up and this name will let us do that.
+eiface_create()
+{
+ nid=`ngctl -f- <<- EOF 2>/dev/null | awk '{print $6}'
+ mkpeer . eiface e ether
+ show -n .:e
+ disconnect .: e
+ EOF`
+
+ echo "[${nid}]:"
+}
+
+
+# call this to try to shutdown the eiface.
+eiface_xerr()
+{
+ local node=$1
+ local msg=$2
+ local jail=${3-""}
+
+ if [ -z $jail ]; then
+ ngctl shutdown $node 2>/dev/null
+ else
+ jexec $jail ngctl shutdown $node 2>/dev/null
+ fi
+ echo "$msg" >&2
+ exit $FAILURE
+}
+
+
+# This has no idea what you are trying to connect to. probably a bridge, but
+# it could be a vlan connected to a bridge or any other configuration allowed by
+# netgraph(4). We know it was valid if it works. If you didn't want it connected
+# you could just `ngctl mkpeer ...` in the jail.
+eiface_connect()
+{
+ local node=$1
+ local hookpath=$2
+
+ # There should be just one ':' in hookpath so use that to pivot.
+ nd2=${hookpath%%:*} # delete everything after and include first ':'
+ ph=${hookpath#*:} # delete everything before and inc first ':'
+
+ ngctl connect $node ${nd2}: ether $ph 2>/dev/null ||
+ eiface_xerr $node "$node unable to connect to \"${hookpath}\""
+}
+
+
+eiface_getifname()
+{
+ local node=$1
+ local jail=$2
+
+ if [ -z $jail ]; then
+ IFS='"' read _ ifname <<- EOF
+ $(ngctl msg $node getifname | sed '1d')
+ EOF
+ else
+ IFS='"' read _ ifname <<- EOF
+ $(jexec $jail ngctl msg $node getifname | sed '1d')
+ EOF
+ fi
+
+ if [ $? -ne 0 ]; then
+ eiface_xerr $node "$node unable to getifname" $jail
+ fi
+
+ echo $ifname
+}
+
+
+eiface_vmove()
+{
+ local node=$1
+ local jail=$2
+ local ifname=$(eiface_getifname $node)
+
+ ifconfig $ifname vnet $jail ||
+ eiface_xerr $node "uname to move \"$ifname\" to \"$jail\""
+
+ # also change ownership of netgraph node to the jail
+ jexec $jail ngctl msg $node setvnethome 2>/dev/null ||
+ eiface_xerr $node "$node unable to setvnethome" $jail
+}
+
+eiface_set_name()
+{
+ local node=$1
+ local jail=$2
+ local name=$3
+ local ifname=$(eiface_getifname $node $jail)
+
+ jexec $jail ngctl name $node $name ||
+ eiface_xerr $node "$node unable to set name to \"$name\"" $jail
+ jexec $jail ifconfig $ifname name $name ||
+ eiface_xerr $node "\"$ifname\" couldn't be changed to \"$name\"" $jail
+}
+
+
+eiface_set_mac()
+{
+ local node=$1
+ local jail=$2
+ local mac=$3
+
+ jexec $jail ngctl msg $node set $mac 2>/dev/null ||
+ eiface_xerr $node "$node unable to set mac" $jail
+
+}
+
+
+############################################################ MAIN
+
+#
+# Command-line arguments
+#
+jail="$1"
+iface="$2"
+hookpath="$3"
+mac="${4}"
+
+if [ $# -lt 3 -o $# -gt 4 ]; then
+ usage
+fi
+
+mustberoot_to_continue
+
+node=$(eiface_create)
+eiface_connect $node $hookpath
+eiface_vmove $node $jail
+eiface_set_name $node $jail $iface
+
+if [ ! -z $mac ]; then
+ eiface_set_mac $node $jail $mac
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/share/man/man4/ng_eiface.4 b/share/man/man4/ng_eiface.4
--- a/share/man/man4/ng_eiface.4
+++ b/share/man/man4/ng_eiface.4
@@ -81,6 +81,19 @@
string.
.It Dv NGM_EIFACE_GET_IFADDRS
Return the list of link-level addresses associated with the node.
+.It Dv NGM_EIFACE_SET_VNETHOME Pq Ic setvnethome
+Changes the
+.Xr vnet 9
+home of the iterface to its current
+.Xr vnet 9 .
+This has the effect of shutting down the interface with the jail it is in
+rather than returning it to its parent. The parent can still use
+.Xr ifconfig 8
+with -vnet to retreive the
+.Nm iface .
+This message should be sent again to reset the
+.Nm iface
+home as well.
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a
diff --git a/share/man/man4/ng_iface.4 b/share/man/man4/ng_iface.4
--- a/share/man/man4/ng_iface.4
+++ b/share/man/man4/ng_iface.4
@@ -103,6 +103,19 @@
.It Dv NGM_IFACE_BROADCAST Pq Ic broadcast
Set the interface to broadcast mode.
The interface must not currently be up.
+.It Dv NGM_IFACE_SET_VNETHOME Pq Ic setvnethome
+Changes the
+.Xr vnet 9
+home of the iterface to its current
+.Xr vnet 9 .
+This has the effect of shutting down the interface with the jail it is in
+rather than returning it to its parent. The parent can still use
+.Xr ifconfig 8
+with -vnet to retreive the
+.Nm iface .
+This message should be sent again to reset the
+.Nm iface
+home as well.
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a
diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h
--- a/sys/netgraph/netgraph.h
+++ b/sys/netgraph/netgraph.h
@@ -1167,6 +1167,9 @@
int ng_callout(struct callout *c, node_p node, hook_p hook, int ticks,
ng_item_fn *fn, void * arg1, int arg2);
#define ng_callout_init(c) callout_init(c, 1)
+#ifdef VIMAGE
+void ng_node_vmove(node_p node, struct vnet *new_vnet);
+#endif
/* Flags for netgraph functions. */
#define NG_NOFLAGS 0x00000000 /* no special options */
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -378,8 +378,9 @@
#define TRAP_ERROR()
#endif
-VNET_DEFINE_STATIC(ng_ID_t, nextID) = 1;
-#define V_nextID VNET(nextID)
+/* node IDs must be unique even when node moves to a different vnet. */
+static struct mtx id_unit_lock;
+static struct unrhdr *id_unit;
#ifdef INVARIANTS
#define CHECK_DATA_MBUF(m) do { \
@@ -670,17 +671,8 @@
LIST_INIT(&node->nd_hooks);
/* Get an ID and put us in the hash chain. */
+ node->nd_ID = alloc_unr(id_unit);
IDHASH_WLOCK();
- for (;;) { /* wrap protection, even if silly */
- node_p node2 = NULL;
- node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */
-
- /* Is there a problem with the new number? */
- NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */
- if ((node->nd_ID != 0) && (node2 == NULL)) {
- break;
- }
- }
V_ng_nodes++;
if (V_ng_nodes * 2 > V_ng_ID_hmask)
ng_ID_rehash();
@@ -785,6 +777,74 @@
NG_NODE_UNREF(node);
}
+/*
+ * If your node "owns" a struct ifnet you probably need to implement if_reassign
+ * and have it call this function. You also need to add another special case in
+ * ng_ether_attach to skip attaching if your node is the driver.
+ */
+#ifdef VIMAGE
+void
+ng_node_vmove(node_p node, struct vnet *new_vnet)
+{
+ /* pull node off hashes (its moving) */
+ NAMEHASH_WLOCK();
+ if (NG_NODE_HAS_NAME(node)) {
+ V_ng_named_nodes--;
+ LIST_REMOVE(node, nd_nodes);
+ }
+ NAMEHASH_WUNLOCK();
+
+ IDHASH_WLOCK();
+ V_ng_nodes--;
+ LIST_REMOVE(node, nd_idnodes);
+ IDHASH_WUNLOCK();
+
+ /* switch current vnet and add back everywhere. */
+ CURVNET_SET(new_vnet);
+ if (NG_NODE_HAS_NAME(node)) {
+ node_p node2;
+ char *name = NG_NODE_NAME(node);
+ uint32_t hash;
+ bool name_used = false;
+
+ NAMEHASH_WLOCK();
+ if (V_ng_named_nodes * 2 > V_ng_name_hmask)
+ ng_name_rehash();
+
+ hash = hash32_str(name, HASHINIT) & V_ng_name_hmask;
+ LIST_FOREACH(node2, &V_ng_name_hash[hash], nd_nodes)
+ if (NG_NODE_IS_VALID(node2) &&
+ (strcmp(NG_NODE_NAME(node2), name) == 0)) {
+ name_used = true;
+ }
+
+ /*
+ * This should be a rare event and requires that user is setting
+ * names as all numbering is global (e.g. ngethX or ngX).
+ * But its not a tragedy if the user has to access by ID.
+ */
+ if (name_used) {
+ name[0] = '\0';
+ } else {
+ LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes);
+ V_ng_named_nodes++;
+ }
+ NAMEHASH_WUNLOCK();
+ }
+
+ IDHASH_WLOCK();
+ V_ng_nodes++;
+ if (V_ng_nodes * 2 > V_ng_ID_hmask)
+ ng_ID_rehash();
+ LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], node,
+ nd_idnodes);
+ IDHASH_WUNLOCK();
+
+ node->nd_vnet = new_vnet;
+ CURVNET_RESTORE();
+}
+#endif
+
/*
* Remove a reference to the node, possibly the last.
* deadnode always acts as it were the last.
@@ -799,7 +859,7 @@
CURVNET_SET(node->nd_vnet);
if (refcount_release(&node->nd_refs)) { /* we were the last */
-
+ ng_ID_t id = node->nd_ID;
node->nd_type->refs--; /* XXX maybe should get types lock? */
NAMEHASH_WLOCK();
if (NG_NODE_HAS_NAME(node)) {
@@ -815,6 +875,7 @@
mtx_destroy(&node->nd_input_queue.q_mtx);
NG_FREE_NODE(node);
+ free_unr(id_unit, id);
}
CURVNET_RESTORE();
}
@@ -1772,6 +1833,10 @@
if (path == NULL) {
if (lasthook != NULL)
*lasthook = NULL;
+#ifdef VIMAGE
+ if (node->nd_vnet != curvnet)
+ return EACCES; /* node not in current vnet */
+#endif
*destp = node;
return (0);
}
@@ -1841,6 +1906,10 @@
*lasthook = NULL;
}
TOPOLOGY_WUNLOCK();
+#ifdef VIMAGE
+ if (node->nd_vnet != curvnet)
+ return EACCES; /* node not in current vnet */
+#endif
*destp = node;
return (0);
}
@@ -3217,6 +3286,11 @@
mtx_init(&ngq_mtx, "netgraph item list mutex", NULL,
MTX_DEF);
#endif
+ /* ID 0 indicates not found, disallow that value */
+ mtx_init(&id_unit_lock, "netgraph node id unr(9) mutex", NULL,
+ MTX_DEF);
+ id_unit = new_unrhdr(1, INT_MAX, &id_unit_lock);
+
ng_qzone = uma_zcreate("NetGraph items", sizeof(struct ng_item),
NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0);
uma_zone_set_max(ng_qzone, maxalloc);
@@ -3240,6 +3314,7 @@
case MOD_UNLOAD:
/* You can't unload it because an interface may be using it. */
error = EBUSY;
+ /* delete_unrhdr(id_unit); */
break;
default:
error = EOPNOTSUPP;
diff --git a/sys/netgraph/ng_eiface.h b/sys/netgraph/ng_eiface.h
--- a/sys/netgraph/ng_eiface.h
+++ b/sys/netgraph/ng_eiface.h
@@ -54,6 +54,9 @@
NGM_EIFACE_GET_IFNAME = 1, /* get the interface name */
NGM_EIFACE_GET_IFADDRS, /* returns list of addresses */
NGM_EIFACE_SET, /* set ethernet address */
+#ifdef VIMAGE
+ NGM_EIFACE_SET_VNETHOME, /* set current vnet as home */
+#endif
};
#endif /* _NETGRAPH_NG_EIFACE_H_ */
diff --git a/sys/netgraph/ng_eiface.c b/sys/netgraph/ng_eiface.c
--- a/sys/netgraph/ng_eiface.c
+++ b/sys/netgraph/ng_eiface.c
@@ -41,6 +41,7 @@
#include <sys/socket.h>
#include <sys/syslog.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_media.h>
@@ -74,6 +75,13 @@
&ng_parse_enaddr_type,
NULL
},
+ {
+ NGM_EIFACE_COOKIE,
+ NGM_EIFACE_SET_VNETHOME,
+ "setvnethome",
+ NULL,
+ NULL
+ },
{ 0 }
};
@@ -92,6 +100,9 @@
static void ng_eiface_init(void *xsc);
static void ng_eiface_start(struct ifnet *ifp);
static int ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+#ifdef VIMAGE
+static void ng_if_reassign(struct ifnet *, struct vnet *, char *);
+#endif
#ifdef DEBUG
static void ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
#endif
@@ -120,8 +131,7 @@
};
NETGRAPH_INIT(eiface, &typestruct);
-VNET_DEFINE_STATIC(struct unrhdr *, ng_eiface_unit);
-#define V_ng_eiface_unit VNET(ng_eiface_unit)
+static struct unrhdr *ng_eiface_unit;
/************************************************************************
INTERFACE STUFF
@@ -197,6 +207,15 @@
return (error);
}
+#ifdef VIMAGE
+static void
+ng_if_reassign(struct ifnet *ifp, struct vnet *vn, char *arg)
+{
+ ng_node_vmove(((priv_p)(ifp->if_softc))->node, vn);
+ ether_reassign(ifp, vn, arg);
+}
+#endif
+
static void
ng_eiface_init(void *xsc)
{
@@ -394,7 +413,7 @@
ifp->if_softc = priv;
/* Get an interface unit number */
- priv->unit = alloc_unr(V_ng_eiface_unit);
+ priv->unit = alloc_unr(ng_eiface_unit);
/* Link together node and private info */
NG_NODE_SET_PRIVATE(node, priv);
@@ -431,6 +450,9 @@
/* Attach the interface */
ether_gen_addr(ifp, &eaddr);
ether_ifattach(ifp, eaddr.octet);
+#ifdef VIMAGE
+ if_setreassignfn(ifp, ng_if_reassign);
+#endif
ifp->if_baudrate = ifmedia_baudrate(IFM_ETHER | IFM_1000_T);
/* Done */
@@ -534,7 +556,20 @@
NET_EPOCH_EXIT(et);
break;
}
-
+#ifdef VIMAGE
+ case NGM_EIFACE_SET_VNETHOME:
+ /*
+ * By setting ifp->if_home_vnet to the node->nd_vnet it
+ * will not be returned by vnet_if_return. It is simply
+ * destroyed with the jail at VNET_SYSUNINIT time.
+ *
+ * This does not "stick". If a sub-jail is gifted an
+ * interface it needs this called again. Even true if
+ * system `ifconfig ifname -nvet jname` to retrieve it.
+ */
+ ifp->if_home_vnet = node->nd_vnet;
+ break;
+#endif
default:
error = EINVAL;
break;
@@ -620,7 +655,7 @@
ifmedia_removeall(&priv->media);
if_free(ifp);
CURVNET_RESTORE();
- free_unr(V_ng_eiface_unit, priv->unit);
+ free_unr(ng_eiface_unit, priv->unit);
free(priv, M_NETGRAPH);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
@@ -653,7 +688,10 @@
switch (event) {
case MOD_LOAD:
+ ng_eiface_unit = new_unrhdr(0, 0xffff, NULL);
+ break;
case MOD_UNLOAD:
+ delete_unrhdr(ng_eiface_unit);
break;
default:
error = EOPNOTSUPP;
@@ -661,21 +699,3 @@
}
return (error);
}
-
-static void
-vnet_ng_eiface_init(const void *unused)
-{
-
- V_ng_eiface_unit = new_unrhdr(0, 0xffff, NULL);
-}
-VNET_SYSINIT(vnet_ng_eiface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
- vnet_ng_eiface_init, NULL);
-
-static void
-vnet_ng_eiface_uninit(const void *unused)
-{
-
- delete_unrhdr(V_ng_eiface_unit);
-}
-VNET_SYSUNINIT(vnet_ng_eiface_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
- vnet_ng_eiface_uninit, NULL);
diff --git a/sys/netgraph/ng_ether.c b/sys/netgraph/ng_ether.c
--- a/sys/netgraph/ng_ether.c
+++ b/sys/netgraph/ng_ether.c
@@ -70,6 +70,8 @@
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/ng_ether.h>
+#include <netgraph/ng_eiface.h>
+#include <netgraph/ng_iface.h>
MODULE_VERSION(ng_ether, 1);
@@ -302,22 +304,28 @@
static void
ng_ether_attach(struct ifnet *ifp)
{
+ const char *dname;
char name[IFNAMSIZ];
priv_p priv;
node_p node;
/*
- * Do not create / attach an ether node to this ifnet if
- * a netgraph node with the same name already exists.
- * This should prevent ether nodes to become attached to
- * eiface nodes, which may be problematic due to naming
- * clashes.
+ * Do not create / attach an ether node to this ifnet the driver name
+ * indicates this is a netgraph node. This should prevent ether nodes
+ * becoming attached to eiface nodes, which may be problematic due to
+ * naming clashes.
+ *
+ * All netgraph nodes that contain a `struct ifnet` need a check here.
+ *
+ * ether_reassign handles actual interfaces with ng_ether as it detaches
+ * and re-attaches.
*/
- ng_ether_sanitize_ifname(ifp->if_xname, name);
- if ((node = ng_name2noderef(NULL, name)) != NULL) {
- NG_NODE_UNREF(node);
+ dname = if_getdname(ifp); /* more reliable for eiface/iface */
+ if (strcmp(NG_EIFACE_EIFACE_NAME, dname) == 0 ||
+ strcmp(NG_IFACE_IFACE_NAME, dname) == 0) {
return;
}
+ ng_ether_sanitize_ifname(ifp->if_xname, name);
/* Create node */
KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
diff --git a/sys/netgraph/ng_iface.h b/sys/netgraph/ng_iface.h
--- a/sys/netgraph/ng_iface.h
+++ b/sys/netgraph/ng_iface.h
@@ -64,6 +64,9 @@
NGM_IFACE_POINT2POINT,
NGM_IFACE_BROADCAST,
NGM_IFACE_GET_IFINDEX,
+#ifdef VIMAGE
+ NGM_IFACE_SET_VNETHOME,
+#endif
};
#endif /* _NETGRAPH_NG_IFACE_H_ */
diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c
--- a/sys/netgraph/ng_iface.c
+++ b/sys/netgraph/ng_iface.c
@@ -70,6 +70,7 @@
#include <sys/syslog.h>
#include <sys/libkern.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_private.h>
@@ -137,6 +138,9 @@
struct mbuf *m, sa_family_t family);
static int ng_iface_send(struct ifnet *ifp, struct mbuf *m,
sa_family_t sa);
+#ifdef VIMAGE
+static void ng_if_reassign(struct ifnet *, struct vnet *, char *);
+#endif
#ifdef DEBUG
static void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
#endif
@@ -186,6 +190,13 @@
NULL,
&ng_parse_uint32_type
},
+ {
+ NGM_IFACE_COOKIE,
+ NGM_IFACE_SET_VNETHOME,
+ "setvnethome",
+ NULL,
+ NULL
+ },
{ 0 }
};
@@ -204,8 +215,7 @@
};
NETGRAPH_INIT(iface, &typestruct);
-VNET_DEFINE_STATIC(struct unrhdr *, ng_iface_unit);
-#define V_ng_iface_unit VNET(ng_iface_unit)
+static struct unrhdr *ng_iface_unit;
/************************************************************************
HELPER STUFF
@@ -338,6 +348,15 @@
return (error);
}
+#ifdef VIMAGE
+static void
+ng_if_reassign(struct ifnet *ifp, struct vnet *vn, char *arg)
+{
+ ng_node_vmove(((priv_p)(ifp->if_softc))->node, vn);
+ ether_reassign(ifp, vn, arg);
+}
+#endif
+
/*
* This routine is called to deliver a packet out the interface.
* We simply look at the address family and relay the packet to
@@ -532,7 +551,7 @@
priv->ifp = ifp;
/* Get an interface unit number */
- priv->unit = alloc_unr(V_ng_iface_unit);
+ priv->unit = alloc_unr(ng_iface_unit);
/* Link together node and private info */
NG_NODE_SET_PRIVATE(node, priv);
@@ -560,6 +579,9 @@
/* Attach the interface */
if_attach(ifp);
+#ifdef VIMAGE
+ if_setreassignfn(ifp, ng_if_reassign);
+#endif
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
/* Done */
@@ -645,7 +667,20 @@
}
*((uint32_t *)resp->data) = priv->ifp->if_index;
break;
-
+#ifdef VIMAGE
+ case NGM_IFACE_SET_VNETHOME:
+ /*
+ * By setting ifp->if_home_vnet to the node->nd_vnet it
+ * will not be returned by vnet_if_return. It is simply
+ * destroyed with the jail at VNET_SYSUNINIT time.
+ *
+ * This does not "stick". If a sub-jail is gifted an
+ * interface it needs this called again. Even true if
+ * system `ifconfig ifname -nvet jname` to retrieve it.
+ */
+ ifp->if_home_vnet = node->nd_vnet;
+ break;
+#endif
default:
error = EINVAL;
break;
@@ -749,7 +784,7 @@
if_free(priv->ifp);
CURVNET_RESTORE();
priv->ifp = NULL;
- free_unr(V_ng_iface_unit, priv->unit);
+ free_unr(ng_iface_unit, priv->unit);
rm_destroy(&priv->lock);
free(priv, M_NETGRAPH_IFACE);
NG_NODE_SET_PRIVATE(node, NULL);
@@ -785,7 +820,11 @@
switch (event) {
case MOD_LOAD:
+ ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
+ break;
+
case MOD_UNLOAD:
+ delete_unrhdr(ng_iface_unit);
break;
default:
error = EOPNOTSUPP;
@@ -793,21 +832,3 @@
}
return (error);
}
-
-static void
-vnet_ng_iface_init(const void *unused)
-{
-
- V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
-}
-VNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
- vnet_ng_iface_init, NULL);
-
-static void
-vnet_ng_iface_uninit(const void *unused)
-{
-
- delete_unrhdr(V_ng_iface_unit);
-}
-VNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
- vnet_ng_iface_uninit, NULL);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 12, 12:51 PM (9 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25211638
Default Alt Text
D49158.id.diff (23 KB)

Event Timeline