diff --git a/sys/modules/Makefile b/sys/modules/Makefile --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -276,6 +276,7 @@ nfsd \ nfslockd \ nfssvc \ + nlsysevent \ nge \ nmdm \ nullfs \ diff --git a/sys/modules/nlsysevent/Makefile b/sys/modules/nlsysevent/Makefile new file mode 100644 --- /dev/null +++ b/sys/modules/nlsysevent/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/netlink/ + +KMOD= nlsysevent +SRCS= netlink_sysevent.c + +CFLAGS+= -I${SRCTOP}/sys/contrib/netlink +EXPORT_SYMS= yes + +.include diff --git a/sys/netlink/netlink_sysevent.h b/sys/netlink/netlink_sysevent.h new file mode 100644 --- /dev/null +++ b/sys/netlink/netlink_sysevent.h @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2022 Baptiste Daroussin + * + * 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. + */ + +#ifndef _NETLINK_SYSEVENT_H_ +#define _NETLINK_SYSEVENT_H_ + +enum { + NLSE_UNSPEC = 0, + NLSE_SYSTEM = 1, + NLSE_SUBSYSTEM = 2, + NLSE_TYPE = 3, + NLSE_DATA = 4, + __NLSE_MAX, +}; +#define NLSE_MAX (__NLSE_MAX -1) + +/* available commands */ +enum { + NLSE_CMD_UNSPEC = 0, + NLSE_CMD_NEWEVENT = 1, + __NLSE_CMD_MAX, +}; +#define NLSE_CMD_MAX (__NLSE_CMD_MAX -1) + +#endif diff --git a/sys/netlink/netlink_sysevent.c b/sys/netlink/netlink_sysevent.c new file mode 100644 --- /dev/null +++ b/sys/netlink/netlink_sysevent.c @@ -0,0 +1,169 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2022 Baptiste Daroussin + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_MOD_NAME nl_sysevent +#define DEBUG_MAX_LEVEL LOG_DEBUG3 +#include +_DECLARE_DEBUG(LOG_DEBUG3); + +#include "netlink_sysevent.h" + +#define CTRL_FAMILY_NAME "nlsysevent" +static uint32_t family_id; + +static struct sysevent { + uint32_t id; + const char *name; +} sysevents [] = { + { 0, "ACPI"}, + { 0, "AEON"}, + { 0, "CAM"}, + { 0, "CARP"}, + { 0, "coretemp"}, + { 0, "DEVFS"}, + { 0, "ETHERNET"}, + { 0, "GEOM"}, + { 0, "HYPERV_NIC_VF"}, + { 0, "IFNET"}, + { 0, "INFINIBAND"}, + { 0, "kern"}, + { 0, "kernel"}, + { 0, "nvme"}, + { 0, "PMU"}, + { 0, "RCTL"}, + { 0, "USB"}, + { 0, "VFS"}, + { 0, "VT"}, + { 0, "ZFS"}, +}; + +static void +sysevent_send_to_group(uint32_t gid, const char *system, const char *subsystem, + const char *type, const char *data) +{ + struct nl_writer nw = {}; + struct nlmsghdr hdr = { .nlmsg_type = family_id }; + struct genlmsghdr *ghdr; + + if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_GENERIC, gid)) { + printf("nlsysevent: error allocating group writer"); + return; + } + if (!nlmsg_reply(&nw, &hdr, sizeof(struct genlmsghdr))) + return; + + ghdr = nlmsg_reserve_object(&nw, struct genlmsghdr); + if (ghdr == NULL) { + NL_LOG(LOG_ERR, "nlsysevent: unable to allocate memory"); + return; + } + ghdr->version = 0; + ghdr->cmd = NLSE_CMD_NEWEVENT; + ghdr->reserved = 0; + nlattr_add_string(&nw, NLSE_SYSTEM, system); + nlattr_add_string(&nw, NLSE_SUBSYSTEM, subsystem); + nlattr_add_string(&nw, NLSE_TYPE, type); + if (data != NULL) + nlattr_add_string(&nw, NLSE_DATA, data); + nlmsg_end(&nw); + nlmsg_flush(&nw); +} + +static void +sysevent_send(const char *system, const char *subsystem, const char *type, + const char *data) +{ + uint32_t group_id = 0; + + for (size_t i = 0; nitems(sysevents); i++) { + if (strcmp(sysevents[i].name, system) == 0) { + group_id = sysevents[i].id; + break; + } + } + + if (group_id == 0) { + NL_LOG(LOG_ERR, "nlsysevent: unknown system for '%s'\n", + system); + return; + } + CURVNET_SET(vnet0); + sysevent_send_to_group(group_id, system, subsystem, type, data); + CURVNET_RESTORE(); +} + +static void +nlsysevent_load(void) +{ + devctl_set_notify_hook(sysevent_send); + family_id = genl_register_family(CTRL_FAMILY_NAME, 0, 2, CTRL_ATTR_MAX); + for (size_t i = 0; i < nitems(sysevents); i++) + sysevents[i].id = genl_register_group(CTRL_FAMILY_NAME, sysevents[i].name); +} + +static void +nlsysevent_unload(void) +{ + devctl_unset_notify_hook(); + genl_unregister_family(CTRL_FAMILY_NAME); +} + +static int +nlsysevent_loader(module_t mod __unused, int what, void *priv __unused) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: + nlsysevent_load(); + break; + case MOD_UNLOAD: + nlsysevent_unload(); + break; + default: + err = EOPNOTSUPP; + break; + } + return (err); +} +static moduledata_t nlsysevent_mod = { "nlsysevent", nlsysevent_loader, NULL}; + +DECLARE_MODULE(nlsysevent, nlsysevent_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_DEPEND(nlsysevent, netlink, 1, 1, 1); +MODULE_VERSION(nlsysevent, 1);