diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -4216,6 +4216,7 @@ case PRIV_NET_SETIFVNET: case PRIV_NET_SETIFFIB: case PRIV_NET_OVPN: + case PRIV_NET_VXLAN: case PRIV_NET_ME: case PRIV_NET_WG: diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -406,21 +406,24 @@ static int vxlan_tunable_int(struct vxlan_softc *, const char *, int); static void vxlan_ifdetach_event(void *, struct ifnet *); -static void vxlan_load(void); -static void vxlan_unload(void); +static void vnet_vxlan_load(void); +static void vnet_vxlan_unload(void); static int vxlan_modevent(module_t, int, void *); static const char vxlan_name[] = "vxlan"; static MALLOC_DEFINE(M_VXLAN, vxlan_name, "Virtual eXtensible LAN Interface"); -static struct if_clone *vxlan_cloner; +VNET_DEFINE_STATIC(struct if_clone *, vxlan_cloner); +#define V_vxlan_cloner VNET(vxlan_cloner) -static struct mtx vxlan_list_mtx; -#define VXLAN_LIST_LOCK() mtx_lock(&vxlan_list_mtx) -#define VXLAN_LIST_UNLOCK() mtx_unlock(&vxlan_list_mtx) +VNET_DEFINE_STATIC(struct mtx, vxlan_list_mtx); +#define V_vxlan_list_mtx VNET(vxlan_list_mtx) -static LIST_HEAD(, vxlan_socket) vxlan_socket_list = - LIST_HEAD_INITIALIZER(vxlan_socket_list); +#define VXLAN_LIST_LOCK() mtx_lock(&V_vxlan_list_mtx) +#define VXLAN_LIST_UNLOCK() mtx_unlock(&V_vxlan_list_mtx) + +VNET_DEFINE_STATIC(LIST_HEAD(, vxlan_socket), vxlan_socket_list); +#define V_vxlan_socket_list VNET(vxlan_socket_list) static eventhandler_tag vxlan_ifdetach_event_tag; @@ -962,7 +965,7 @@ struct vxlan_socket *vso; VXLAN_LIST_LOCK(); - LIST_FOREACH(vso, &vxlan_socket_list, vxlso_entry) { + LIST_FOREACH(vso, &V_vxlan_socket_list, vxlso_entry) { if (vxlan_sockaddr_cmp(&vso->vxlso_laddr, &vxlsa->sa) == 0) { VXLAN_SO_ACQUIRE(vso); break; @@ -979,7 +982,7 @@ VXLAN_LIST_LOCK(); VXLAN_SO_ACQUIRE(vso); - LIST_INSERT_HEAD(&vxlan_socket_list, vso, vxlso_entry); + LIST_INSERT_HEAD(&V_vxlan_socket_list, vso, vxlso_entry); VXLAN_LIST_UNLOCK(); } @@ -3237,7 +3240,12 @@ sc->vxl_port_hash_key = arc4random(); vxlan_ftable_init(sc); - vxlan_sysctl_setup(sc); + /* + * We can't easily have per-vnet sysctl entries (as in, OIDs only visible + * in a specific jail) so just don't add the nodes in jails. + */ + if (IS_DEFAULT_VNET(curvnet)) + vxlan_sysctl_setup(sc); ifp->if_softc = sc; if_initname(ifp, vxlan_name, ifd->unit); @@ -3593,6 +3601,9 @@ vxlan_sysctl_destroy(struct vxlan_softc *sc) { + if (sc->vxl_sysctl_node == NULL) + return; + sysctl_ctx_free(&sc->vxl_sysctl_ctx); sc->vxl_sysctl_node = NULL; } @@ -3621,8 +3632,11 @@ if ((ifp->if_flags & IFF_MULTICAST) == 0) return; + if (LIST_EMPTY(&V_vxlan_socket_list)) + return; + VXLAN_LIST_LOCK(); - LIST_FOREACH(vso, &vxlan_socket_list, vxlso_entry) + LIST_FOREACH(vso, &V_vxlan_socket_list, vxlso_entry) vxlan_socket_ifdetach(vso, ifp, &list); VXLAN_LIST_UNLOCK(); @@ -3639,31 +3653,31 @@ } static void -vxlan_load(void) +vnet_vxlan_load(void) { - mtx_init(&vxlan_list_mtx, "vxlan list", NULL, MTX_DEF); - vxlan_ifdetach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, - vxlan_ifdetach_event, NULL, EVENTHANDLER_PRI_ANY); + mtx_init(&V_vxlan_list_mtx, "vxlan list", NULL, MTX_DEF); struct if_clone_addreq req = { .create_f = vxlan_clone_create, .destroy_f = vxlan_clone_destroy, .flags = IFC_F_AUTOUNIT, }; - vxlan_cloner = ifc_attach_cloner(vxlan_name, &req); + V_vxlan_cloner = ifc_attach_cloner(vxlan_name, &req); } +VNET_SYSINIT(vnet_vxlan_load, SI_SUB_PSEUDO, SI_ORDER_ANY, + vnet_vxlan_load, NULL); static void -vxlan_unload(void) +vnet_vxlan_unload(void) { - EVENTHANDLER_DEREGISTER(ifnet_departure_event, - vxlan_ifdetach_event_tag); - ifc_detach_cloner(vxlan_cloner); - mtx_destroy(&vxlan_list_mtx); - MPASS(LIST_EMPTY(&vxlan_socket_list)); + ifc_detach_cloner(V_vxlan_cloner); + mtx_destroy(&V_vxlan_list_mtx); + MPASS(LIST_EMPTY(&V_vxlan_socket_list)); } +VNET_SYSUNINIT(vnet_vxlan_unload, SI_SUB_PSEUDO, SI_ORDER_ANY, + vnet_vxlan_unload, NULL); static int vxlan_modevent(module_t mod, int type, void *unused) @@ -3674,10 +3688,12 @@ switch (type) { case MOD_LOAD: - vxlan_load(); + vxlan_ifdetach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, + vxlan_ifdetach_event, NULL, EVENTHANDLER_PRI_ANY); break; case MOD_UNLOAD: - vxlan_unload(); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, + vxlan_ifdetach_event_tag); break; default: error = ENOTSUP; diff --git a/tests/sys/net/Makefile b/tests/sys/net/Makefile --- a/tests/sys/net/Makefile +++ b/tests/sys/net/Makefile @@ -14,6 +14,9 @@ ATF_TESTS_SH+= if_stf ATF_TESTS_SH+= if_tun_test ATF_TESTS_SH+= if_vlan +ATF_TESTS_SH+= if_vxlan +TEST_METADATA.if_vxlan+= execenv="jail" +TEST_METADATA.if_vxlan+= execenv_jail_params="vnet allow.raw_sockets" ATF_TESTS_SH+= if_wg TESTS_SUBDIRS+= bpf diff --git a/tests/sys/net/if_vxlan.sh b/tests/sys/net/if_vxlan.sh new file mode 100644 --- /dev/null +++ b/tests/sys/net/if_vxlan.sh @@ -0,0 +1,68 @@ +## +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2025 Rubicon Communications, LLC ("Netgate") +# +# 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. + +. $(atf_get_srcdir)/../common/vnet.subr + +atf_test_case "basic" "cleanup" +basic_head() +{ + atf_set descr 'Basic VXLAN in bridge test' + atf_set require.user root +} + +basic_body() +{ + vnet_init + + epair_link=$(vnet_mkepair) + + vnet_mkjail a ${epair_link}a + jexec a ifconfig ${epair_link}a inet 192.0.2.1/24 up + vnet_mkjail b ${epair_link}b + jexec b ifconfig ${epair_link}b inet 192.0.2.2/24 up + + atf_check -s exit:0 -o ignore \ + jexec a ping -c 1 192.0.2.2 + + vxlan_a=$(jexec a ifconfig vxlan create vxlanid 108 vxlanlocal 192.0.2.1 vxlanremote 192.0.2.2) + vxlan_b=$(jexec b ifconfig vxlan create vxlanid 108 vxlanlocal 192.0.2.2 vxlanremote 192.0.2.1) + + jexec a ifconfig ${vxlan_a} inet 198.51.100.1/24 up + jexec b ifconfig ${vxlan_b} inet 198.51.100.2/24 up + + atf_check -s exit:0 -o ignore \ + jexec a ping -c 1 198.51.100.2 +} + +basic_cleanup() +{ + vnet_cleanup +} + +atf_init_test_cases() +{ + atf_add_test_case "basic" +}