xref: /freebsd/sys/compat/linsysfs/linsysfs_net.c (revision 88362a00)
17ae0972cSDmitry Chagin /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
37ae0972cSDmitry Chagin  *
47ae0972cSDmitry Chagin  * Copyright (c) 2023 Dmitry Chagin <dchagin@FreeBSD.org>
57ae0972cSDmitry Chagin  *
67ae0972cSDmitry Chagin  * Redistribution and use in source and binary forms, with or without
77ae0972cSDmitry Chagin  * modification, are permitted provided that the following conditions
87ae0972cSDmitry Chagin  * are met:
97ae0972cSDmitry Chagin  * 1. Redistributions of source code must retain the above copyright
107ae0972cSDmitry Chagin  *    notice, this list of conditions and the following disclaimer.
117ae0972cSDmitry Chagin  * 2. Redistributions in binary form must reproduce the above copyright
127ae0972cSDmitry Chagin  *    notice, this list of conditions and the following disclaimer in the
137ae0972cSDmitry Chagin  *    documentation and/or other materials provided with the distribution.
147ae0972cSDmitry Chagin  *
157ae0972cSDmitry Chagin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
167ae0972cSDmitry Chagin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177ae0972cSDmitry Chagin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187ae0972cSDmitry Chagin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197ae0972cSDmitry Chagin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207ae0972cSDmitry Chagin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217ae0972cSDmitry Chagin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227ae0972cSDmitry Chagin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237ae0972cSDmitry Chagin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247ae0972cSDmitry Chagin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257ae0972cSDmitry Chagin  * SUCH DAMAGE.
267ae0972cSDmitry Chagin  */
277ae0972cSDmitry Chagin 
287ae0972cSDmitry Chagin #include <sys/param.h>
297ae0972cSDmitry Chagin #include <sys/eventhandler.h>
307ae0972cSDmitry Chagin #include <sys/kernel.h>
317ae0972cSDmitry Chagin #include <sys/lock.h>
327ae0972cSDmitry Chagin #include <sys/malloc.h>
337ae0972cSDmitry Chagin #include <sys/mutex.h>
347ae0972cSDmitry Chagin #include <sys/sbuf.h>
357ae0972cSDmitry Chagin #include <sys/socket.h>
367ae0972cSDmitry Chagin 
377ae0972cSDmitry Chagin #include <net/if.h>
387ae0972cSDmitry Chagin #include <net/if_var.h>
397ae0972cSDmitry Chagin #include <net/vnet.h>
407ae0972cSDmitry Chagin 
417ae0972cSDmitry Chagin #include <compat/linux/linux.h>
427ae0972cSDmitry Chagin #include <compat/linux/linux_common.h>
437ae0972cSDmitry Chagin #include <fs/pseudofs/pseudofs.h>
447ae0972cSDmitry Chagin 
457ae0972cSDmitry Chagin #include <compat/linsysfs/linsysfs.h>
467ae0972cSDmitry Chagin 
477ae0972cSDmitry Chagin struct pfs_node *net;
487ae0972cSDmitry Chagin static eventhandler_tag if_arrival_tag, if_departure_tag;
497ae0972cSDmitry Chagin 
507ae0972cSDmitry Chagin static uint32_t net_latch_count = 0;
517ae0972cSDmitry Chagin static struct mtx net_latch_mtx;
527ae0972cSDmitry Chagin MTX_SYSINIT(net_latch_mtx, &net_latch_mtx, "lsfnet", MTX_DEF);
537ae0972cSDmitry Chagin 
547ae0972cSDmitry Chagin struct ifp_nodes_queue {
557ae0972cSDmitry Chagin 	TAILQ_ENTRY(ifp_nodes_queue) ifp_nodes_next;
567ae0972cSDmitry Chagin 	if_t ifp;
577ae0972cSDmitry Chagin 	struct vnet *vnet;
587ae0972cSDmitry Chagin 	struct pfs_node *pn;
597ae0972cSDmitry Chagin };
607ae0972cSDmitry Chagin TAILQ_HEAD(,ifp_nodes_queue) ifp_nodes_q;
617ae0972cSDmitry Chagin 
627ae0972cSDmitry Chagin static void
linsysfs_net_latch_hold(void)637ae0972cSDmitry Chagin linsysfs_net_latch_hold(void)
647ae0972cSDmitry Chagin {
657ae0972cSDmitry Chagin 
667ae0972cSDmitry Chagin 	mtx_lock(&net_latch_mtx);
677ae0972cSDmitry Chagin 	if (net_latch_count++ > 0)
687ae0972cSDmitry Chagin 		mtx_sleep(&net_latch_count, &net_latch_mtx, PDROP, "lsfnet", 0);
697ae0972cSDmitry Chagin 	else
707ae0972cSDmitry Chagin 		mtx_unlock(&net_latch_mtx);
717ae0972cSDmitry Chagin }
727ae0972cSDmitry Chagin 
737ae0972cSDmitry Chagin static void
linsysfs_net_latch_rele(void)747ae0972cSDmitry Chagin linsysfs_net_latch_rele(void)
757ae0972cSDmitry Chagin {
767ae0972cSDmitry Chagin 
777ae0972cSDmitry Chagin 	mtx_lock(&net_latch_mtx);
787ae0972cSDmitry Chagin 	if (--net_latch_count > 0)
797ae0972cSDmitry Chagin 		wakeup_one(&net_latch_count);
807ae0972cSDmitry Chagin 	mtx_unlock(&net_latch_mtx);
817ae0972cSDmitry Chagin }
827ae0972cSDmitry Chagin 
837ae0972cSDmitry Chagin static int
linsysfs_if_addr(PFS_FILL_ARGS)847ae0972cSDmitry Chagin linsysfs_if_addr(PFS_FILL_ARGS)
857ae0972cSDmitry Chagin {
867ae0972cSDmitry Chagin 	struct epoch_tracker et;
877ae0972cSDmitry Chagin 	struct l_sockaddr lsa;
887ae0972cSDmitry Chagin 	if_t ifp;
897ae0972cSDmitry Chagin 	int error;
907ae0972cSDmitry Chagin 
917ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
927ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
937ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
947ae0972cSDmitry Chagin 	if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0)
957ae0972cSDmitry Chagin 		error = sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
967ae0972cSDmitry Chagin 		    lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2],
977ae0972cSDmitry Chagin 		    lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]);
987ae0972cSDmitry Chagin 	else
997ae0972cSDmitry Chagin 		error = ENOENT;
1007ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
1017ae0972cSDmitry Chagin 	CURVNET_RESTORE();
1027ae0972cSDmitry Chagin 	return (error == -1 ? ERANGE : error);
1037ae0972cSDmitry Chagin }
1047ae0972cSDmitry Chagin 
1057ae0972cSDmitry Chagin static int
linsysfs_if_addrlen(PFS_FILL_ARGS)1067ae0972cSDmitry Chagin linsysfs_if_addrlen(PFS_FILL_ARGS)
1077ae0972cSDmitry Chagin {
1087ae0972cSDmitry Chagin 
1097ae0972cSDmitry Chagin 	sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
1107ae0972cSDmitry Chagin 	return (0);
1117ae0972cSDmitry Chagin }
1127ae0972cSDmitry Chagin 
1137ae0972cSDmitry Chagin static int
linsysfs_if_flags(PFS_FILL_ARGS)1147ae0972cSDmitry Chagin linsysfs_if_flags(PFS_FILL_ARGS)
1157ae0972cSDmitry Chagin {
1167ae0972cSDmitry Chagin 	struct epoch_tracker et;
1177ae0972cSDmitry Chagin 	if_t ifp;
1187ae0972cSDmitry Chagin 	int error;
1197ae0972cSDmitry Chagin 
1207ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
1217ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
1227ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
1237ae0972cSDmitry Chagin 	if (ifp != NULL)
1247ae0972cSDmitry Chagin 		error = sbuf_printf(sb, "0x%x\n", linux_ifflags(ifp));
1257ae0972cSDmitry Chagin 	else
1267ae0972cSDmitry Chagin 		error = ENOENT;
1277ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
1287ae0972cSDmitry Chagin 	CURVNET_RESTORE();
1297ae0972cSDmitry Chagin 	return (error == -1 ? ERANGE : error);
1307ae0972cSDmitry Chagin }
1317ae0972cSDmitry Chagin 
1327ae0972cSDmitry Chagin static int
linsysfs_if_ifindex(PFS_FILL_ARGS)1337ae0972cSDmitry Chagin linsysfs_if_ifindex(PFS_FILL_ARGS)
1347ae0972cSDmitry Chagin {
1357ae0972cSDmitry Chagin 	struct epoch_tracker et;
1367ae0972cSDmitry Chagin 	if_t ifp;
1377ae0972cSDmitry Chagin 	int error;
1387ae0972cSDmitry Chagin 
1397ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
1407ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
1417ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
1427ae0972cSDmitry Chagin 	if (ifp != NULL)
1437ae0972cSDmitry Chagin 		error = sbuf_printf(sb, "%u\n", if_getindex(ifp));
1447ae0972cSDmitry Chagin 	else
1457ae0972cSDmitry Chagin 		error = ENOENT;
1467ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
1477ae0972cSDmitry Chagin 	CURVNET_RESTORE();
1487ae0972cSDmitry Chagin 	return (error == -1 ? ERANGE : error);
1497ae0972cSDmitry Chagin }
1507ae0972cSDmitry Chagin 
1517ae0972cSDmitry Chagin static int
linsysfs_if_mtu(PFS_FILL_ARGS)1527ae0972cSDmitry Chagin linsysfs_if_mtu(PFS_FILL_ARGS)
1537ae0972cSDmitry Chagin {
1547ae0972cSDmitry Chagin 	struct epoch_tracker et;
1557ae0972cSDmitry Chagin 	if_t ifp;
1567ae0972cSDmitry Chagin 	int error;
1577ae0972cSDmitry Chagin 
1587ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
1597ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
1607ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
1617ae0972cSDmitry Chagin 	if (ifp != NULL)
1627ae0972cSDmitry Chagin 		error = sbuf_printf(sb, "%u\n", if_getmtu(ifp));
1637ae0972cSDmitry Chagin 	else
1647ae0972cSDmitry Chagin 		error = ENOENT;
1657ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
1667ae0972cSDmitry Chagin 	CURVNET_RESTORE();
1677ae0972cSDmitry Chagin 	return (error == -1 ? ERANGE : error);
1687ae0972cSDmitry Chagin }
1697ae0972cSDmitry Chagin 
1707ae0972cSDmitry Chagin static int
linsysfs_if_txq_len(PFS_FILL_ARGS)1717ae0972cSDmitry Chagin linsysfs_if_txq_len(PFS_FILL_ARGS)
1727ae0972cSDmitry Chagin {
1737ae0972cSDmitry Chagin 
1747ae0972cSDmitry Chagin 	/* XXX */
1757ae0972cSDmitry Chagin 	sbuf_printf(sb, "1000\n");
1767ae0972cSDmitry Chagin 	return (0);
1777ae0972cSDmitry Chagin }
1787ae0972cSDmitry Chagin 
1797ae0972cSDmitry Chagin static int
linsysfs_if_type(PFS_FILL_ARGS)1807ae0972cSDmitry Chagin linsysfs_if_type(PFS_FILL_ARGS)
1817ae0972cSDmitry Chagin {
1827ae0972cSDmitry Chagin 	struct epoch_tracker et;
1837ae0972cSDmitry Chagin 	struct l_sockaddr lsa;
1847ae0972cSDmitry Chagin 	if_t ifp;
1857ae0972cSDmitry Chagin 	int error;
1867ae0972cSDmitry Chagin 
1877ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
1887ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
1897ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
1907ae0972cSDmitry Chagin 	if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0)
1917ae0972cSDmitry Chagin 		error = sbuf_printf(sb, "%d\n", lsa.sa_family);
1927ae0972cSDmitry Chagin 	else
1937ae0972cSDmitry Chagin 		error = ENOENT;
1947ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
1957ae0972cSDmitry Chagin 	CURVNET_RESTORE();
1967ae0972cSDmitry Chagin 	return (error == -1 ? ERANGE : error);
1977ae0972cSDmitry Chagin }
1987ae0972cSDmitry Chagin 
1997ae0972cSDmitry Chagin static int
linsysfs_if_visible(PFS_VIS_ARGS)2007ae0972cSDmitry Chagin linsysfs_if_visible(PFS_VIS_ARGS)
2017ae0972cSDmitry Chagin {
2027ae0972cSDmitry Chagin 	struct ifp_nodes_queue *nq, *nq_tmp;
2037ae0972cSDmitry Chagin 	struct epoch_tracker et;
2047ae0972cSDmitry Chagin 	if_t ifp;
2057ae0972cSDmitry Chagin 	int visible;
2067ae0972cSDmitry Chagin 
2077ae0972cSDmitry Chagin 	visible = 0;
2087ae0972cSDmitry Chagin 	CURVNET_SET(TD_TO_VNET(td));
2097ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
2107ae0972cSDmitry Chagin 	ifp = ifname_linux_to_ifp(td, pn->pn_name);
2117ae0972cSDmitry Chagin 	if (ifp != NULL) {
2127ae0972cSDmitry Chagin 		TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
2137ae0972cSDmitry Chagin 			if (nq->ifp == ifp && nq->vnet == curvnet) {
2147ae0972cSDmitry Chagin 				visible = 1;
2157ae0972cSDmitry Chagin 				break;
2167ae0972cSDmitry Chagin 			}
2177ae0972cSDmitry Chagin 		}
2187ae0972cSDmitry Chagin 	}
2197ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
2207ae0972cSDmitry Chagin 	CURVNET_RESTORE();
2217ae0972cSDmitry Chagin 	return (visible);
2227ae0972cSDmitry Chagin }
2237ae0972cSDmitry Chagin 
2247ae0972cSDmitry Chagin static int
linsysfs_net_addif(if_t ifp,void * arg)2257ae0972cSDmitry Chagin linsysfs_net_addif(if_t ifp, void *arg)
2267ae0972cSDmitry Chagin {
2277ae0972cSDmitry Chagin 	struct ifp_nodes_queue *nq, *nq_tmp;
2287ae0972cSDmitry Chagin 	struct pfs_node *nic, *dir = arg;
2297ae0972cSDmitry Chagin 	char ifname[LINUX_IFNAMSIZ];
2307ae0972cSDmitry Chagin 	struct epoch_tracker et;
2317ae0972cSDmitry Chagin 	int ret __diagused;
2327ae0972cSDmitry Chagin 
2337ae0972cSDmitry Chagin 	NET_EPOCH_ENTER(et);
2347ae0972cSDmitry Chagin 	ret = ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname));
2357ae0972cSDmitry Chagin 	NET_EPOCH_EXIT(et);
2367ae0972cSDmitry Chagin 	KASSERT(ret > 0, ("Interface (%s) is not converted", if_name(ifp)));
2377ae0972cSDmitry Chagin 
2387ae0972cSDmitry Chagin 	nic = pfs_find_node(dir, ifname);
2397ae0972cSDmitry Chagin 	if (nic == NULL) {
2407ae0972cSDmitry Chagin 		nic = pfs_create_dir(dir, ifname, NULL, linsysfs_if_visible,
2417ae0972cSDmitry Chagin 		    NULL, 0);
2427ae0972cSDmitry Chagin 		pfs_create_file(nic, "address", &linsysfs_if_addr,
2437ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2447ae0972cSDmitry Chagin 		pfs_create_file(nic, "addr_len", &linsysfs_if_addrlen,
2457ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2467ae0972cSDmitry Chagin 		pfs_create_file(nic, "flags", &linsysfs_if_flags,
2477ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2487ae0972cSDmitry Chagin 		pfs_create_file(nic, "ifindex", &linsysfs_if_ifindex,
2497ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2507ae0972cSDmitry Chagin 		pfs_create_file(nic, "mtu", &linsysfs_if_mtu,
2517ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2527ae0972cSDmitry Chagin 		pfs_create_file(nic, "tx_queue_len", &linsysfs_if_txq_len,
2537ae0972cSDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
2547ae0972cSDmitry Chagin 		pfs_create_file(nic, "type", &linsysfs_if_type,
2557ae0972cSDmitry Chagin 		NULL, NULL, NULL, PFS_RD);
2567ae0972cSDmitry Chagin 	}
2577ae0972cSDmitry Chagin 	/*
2587ae0972cSDmitry Chagin 	 * There is a small window between registering the if_arrival
2597ae0972cSDmitry Chagin 	 * eventhandler and creating a list of interfaces.
2607ae0972cSDmitry Chagin 	 */
2617ae0972cSDmitry Chagin 	TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
2627ae0972cSDmitry Chagin 		if (nq->ifp == ifp && nq->vnet == curvnet)
2637ae0972cSDmitry Chagin 			return (0);
2647ae0972cSDmitry Chagin 	}
2657ae0972cSDmitry Chagin 	nq = malloc(sizeof(*nq), M_LINSYSFS, M_WAITOK);
2667ae0972cSDmitry Chagin 	nq->pn = nic;
2677ae0972cSDmitry Chagin 	nq->ifp = ifp;
2687ae0972cSDmitry Chagin 	nq->vnet = curvnet;
2697ae0972cSDmitry Chagin 	TAILQ_INSERT_TAIL(&ifp_nodes_q, nq, ifp_nodes_next);
2707ae0972cSDmitry Chagin 	return (0);
2717ae0972cSDmitry Chagin }
2727ae0972cSDmitry Chagin 
2737ae0972cSDmitry Chagin static void
linsysfs_net_delif(if_t ifp)2747ae0972cSDmitry Chagin linsysfs_net_delif(if_t ifp)
2757ae0972cSDmitry Chagin {
2767ae0972cSDmitry Chagin 	struct ifp_nodes_queue *nq, *nq_tmp;
2777ae0972cSDmitry Chagin 	struct pfs_node *pn;
2787ae0972cSDmitry Chagin 
2797ae0972cSDmitry Chagin 	pn = NULL;
2807ae0972cSDmitry Chagin 	TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
2817ae0972cSDmitry Chagin 		if (nq->ifp == ifp && nq->vnet == curvnet) {
2827ae0972cSDmitry Chagin 			TAILQ_REMOVE(&ifp_nodes_q, nq, ifp_nodes_next);
2837ae0972cSDmitry Chagin 			pn = nq->pn;
2847ae0972cSDmitry Chagin 			free(nq, M_LINSYSFS);
2857ae0972cSDmitry Chagin 			break;
2867ae0972cSDmitry Chagin 		}
2877ae0972cSDmitry Chagin 	}
2887ae0972cSDmitry Chagin 	if (pn == NULL)
2897ae0972cSDmitry Chagin 		return;
2907ae0972cSDmitry Chagin 	TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
2917ae0972cSDmitry Chagin 		if (nq->pn == pn)
2927ae0972cSDmitry Chagin 			return;
2937ae0972cSDmitry Chagin 	}
2947ae0972cSDmitry Chagin 	pfs_destroy(pn);
2957ae0972cSDmitry Chagin }
2967ae0972cSDmitry Chagin 
2977ae0972cSDmitry Chagin static void
linsysfs_if_arrival(void * arg __unused,if_t ifp)2987ae0972cSDmitry Chagin linsysfs_if_arrival(void *arg __unused, if_t ifp)
2997ae0972cSDmitry Chagin {
3007ae0972cSDmitry Chagin 
3017ae0972cSDmitry Chagin 	linsysfs_net_latch_hold();
3027ae0972cSDmitry Chagin 	(void)linsysfs_net_addif(ifp, net);
3037ae0972cSDmitry Chagin 	linsysfs_net_latch_rele();
3047ae0972cSDmitry Chagin }
3057ae0972cSDmitry Chagin 
3067ae0972cSDmitry Chagin static void
linsysfs_if_departure(void * arg __unused,if_t ifp)3077ae0972cSDmitry Chagin linsysfs_if_departure(void *arg __unused, if_t ifp)
3087ae0972cSDmitry Chagin {
3097ae0972cSDmitry Chagin 
3107ae0972cSDmitry Chagin 	linsysfs_net_latch_hold();
3117ae0972cSDmitry Chagin 	linsysfs_net_delif(ifp);
3127ae0972cSDmitry Chagin 	linsysfs_net_latch_rele();
3137ae0972cSDmitry Chagin }
3147ae0972cSDmitry Chagin 
3157ae0972cSDmitry Chagin void
linsysfs_net_init(void)3167ae0972cSDmitry Chagin linsysfs_net_init(void)
3177ae0972cSDmitry Chagin {
3187ae0972cSDmitry Chagin 	VNET_ITERATOR_DECL(vnet_iter);
3197ae0972cSDmitry Chagin 
3207ae0972cSDmitry Chagin 	MPASS(net != NULL);
3217ae0972cSDmitry Chagin 	TAILQ_INIT(&ifp_nodes_q);
3227ae0972cSDmitry Chagin 
3237ae0972cSDmitry Chagin 	if_arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event,
3247ae0972cSDmitry Chagin 	    linsysfs_if_arrival, NULL, EVENTHANDLER_PRI_ANY);
3257ae0972cSDmitry Chagin 	if_departure_tag = EVENTHANDLER_REGISTER(ifnet_departure_event,
3267ae0972cSDmitry Chagin 	    linsysfs_if_departure, NULL, EVENTHANDLER_PRI_ANY);
3277ae0972cSDmitry Chagin 
3287ae0972cSDmitry Chagin 	linsysfs_net_latch_hold();
3297ae0972cSDmitry Chagin 	VNET_LIST_RLOCK();
3307ae0972cSDmitry Chagin 	VNET_FOREACH(vnet_iter) {
3317ae0972cSDmitry Chagin 		CURVNET_SET(vnet_iter);
3327ae0972cSDmitry Chagin 		if_foreach_sleep(NULL, NULL, linsysfs_net_addif, net);
3337ae0972cSDmitry Chagin 		CURVNET_RESTORE();
3347ae0972cSDmitry Chagin 	}
3357ae0972cSDmitry Chagin 	VNET_LIST_RUNLOCK();
3367ae0972cSDmitry Chagin 	linsysfs_net_latch_rele();
3377ae0972cSDmitry Chagin }
3387ae0972cSDmitry Chagin 
3397ae0972cSDmitry Chagin void
linsysfs_net_uninit(void)3407ae0972cSDmitry Chagin linsysfs_net_uninit(void)
3417ae0972cSDmitry Chagin {
3427ae0972cSDmitry Chagin 	struct ifp_nodes_queue *nq, *nq_tmp;
3437ae0972cSDmitry Chagin 
3447ae0972cSDmitry Chagin 	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, if_arrival_tag);
3457ae0972cSDmitry Chagin 	EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_departure_tag);
3467ae0972cSDmitry Chagin 
3477ae0972cSDmitry Chagin 	linsysfs_net_latch_hold();
3487ae0972cSDmitry Chagin 	TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
3497ae0972cSDmitry Chagin 		TAILQ_REMOVE(&ifp_nodes_q, nq, ifp_nodes_next);
3507ae0972cSDmitry Chagin 		free(nq, M_LINSYSFS);
3517ae0972cSDmitry Chagin 	}
3527ae0972cSDmitry Chagin 	linsysfs_net_latch_rele();
3537ae0972cSDmitry Chagin }
354