Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135640377
D49158.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
D49158.id.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D49158: ng_eiface(4) and ng_iface(4) should play better with vnet(9)
Attached
Detach File
Event Timeline
Log In to Comment