Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netlink/netlink_sysevent.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2023 Baptiste Daroussin <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/types.h>
30
#include <sys/devctl.h>
31
#include <sys/errno.h>
32
#include <sys/module.h>
33
#include <sys/kernel.h>
34
#include <sys/malloc.h>
35
#include <net/vnet.h>
36
#include <netlink/netlink.h>
37
#include <netlink/netlink_ctl.h>
38
#include <netlink/netlink_generic.h>
39
#include <netlink/netlink_sysevent.h>
40
41
#define DEBUG_MOD_NAME nl_sysevent
42
#define DEBUG_MAX_LEVEL LOG_DEBUG3
43
#include <netlink/netlink_debug.h>
44
_DECLARE_DEBUG(LOG_INFO);
45
46
MALLOC_DEFINE(M_NLSE, "nlsysevent", "Memory used for Netlink sysevent");
47
#define NLSE_FAMILY_NAME "nlsysevent"
48
static uint16_t ctrl_family_id;
49
50
#define MAX_SYSEVENT_GROUPS 64
51
static struct sysevent_group {
52
char *name;
53
uint32_t id;
54
} sysevent_groups[MAX_SYSEVENT_GROUPS] = {};
55
56
static const char *devctl_systems[] = {
57
"ACPI",
58
"AEON",
59
"CAM",
60
"CARP",
61
"coretemp",
62
"DEVFS",
63
"device",
64
"ETHERNET",
65
"GEOM",
66
"HYPERV_NIC_VF",
67
"IFNET",
68
"INFINIBAND",
69
"KERNEL",
70
"nvme",
71
"PMU",
72
"RCTL",
73
"USB",
74
"VFS",
75
"VT",
76
"ZFS",
77
};
78
79
static void
80
sysevent_write(struct sysevent_group *se, const char *subsystem, const char *type,
81
const char *data)
82
{
83
struct nl_writer nw;
84
85
if (!nl_writer_group(&nw, NLMSG_LARGE, NETLINK_GENERIC, se->id, 0,
86
false)) {
87
NL_LOG(LOG_DEBUG, "error allocating group writer");
88
return;
89
}
90
struct nlmsghdr hdr = { .nlmsg_type = ctrl_family_id };
91
if (!nlmsg_reply(&nw, &hdr, sizeof(struct genlmsghdr))) {
92
return;
93
}
94
95
struct genlmsghdr *ghdr = nlmsg_reserve_object(&nw, struct genlmsghdr);
96
if (ghdr == NULL) {
97
NL_LOG(LOG_DEBUG, "unable to allocate memory");
98
return;
99
}
100
ghdr->version = 0;
101
ghdr->cmd = NLSE_CMD_NEWEVENT;
102
ghdr->reserved = 0;
103
nlattr_add_string(&nw, NLSE_ATTR_SYSTEM, se->name);
104
nlattr_add_string(&nw, NLSE_ATTR_SUBSYSTEM, subsystem);
105
nlattr_add_string(&nw, NLSE_ATTR_TYPE, type);
106
if (data != NULL)
107
nlattr_add_string(&nw, NLSE_ATTR_DATA, data);
108
nlmsg_end(&nw);
109
nlmsg_flush(&nw);
110
}
111
112
static void
113
sysevent_new_group(size_t index, const char *name)
114
{
115
if (index >= MAX_SYSEVENT_GROUPS) {
116
NL_LOG(LOG_WARNING, "impossible to add the event %s, "
117
"too many event groups\n", name);
118
return;
119
}
120
sysevent_groups[index].name = strdup(name, M_NLSE);
121
sysevent_groups[index].id = genl_register_group(ctrl_family_id,
122
sysevent_groups[index].name);
123
}
124
125
static struct sysevent_group *
126
sysevent_get_group(const char *system)
127
{
128
for (size_t i = 0; i < MAX_SYSEVENT_GROUPS; i++) {
129
if (sysevent_groups[i].name == NULL) {
130
sysevent_new_group(i, system);
131
return (&sysevent_groups[i]);
132
}
133
if (strcmp(sysevent_groups[i].name, system) == 0)
134
return (&sysevent_groups[i]);
135
}
136
137
return (NULL);
138
}
139
140
static void
141
sysevent_send(const char *system, const char *subsystem, const char *type,
142
const char *data)
143
{
144
struct sysevent_group *se = sysevent_get_group(system);
145
146
if (se == NULL) {
147
NL_LOG(LOG_WARNING, "impossible to add the event %s, "
148
"too many event groups\n", system);
149
return;
150
}
151
152
CURVNET_SET(vnet0);
153
sysevent_write(se, subsystem, type, data);
154
CURVNET_RESTORE();
155
}
156
157
static void
158
nlsysevent_load(void)
159
{
160
devctl_set_notify_hook(sysevent_send);
161
ctrl_family_id = genl_register_family(NLSE_FAMILY_NAME, 0, 2, NLSE_ATTR_MAX);
162
for (size_t i = 0; i < nitems(devctl_systems); i++) {
163
if (i >= MAX_SYSEVENT_GROUPS) {
164
NL_LOG(LOG_WARNING, "impossible to add the event %s, too many events\n", devctl_systems[i]);
165
continue;
166
}
167
sysevent_new_group(i, devctl_systems[i]);
168
}
169
}
170
171
static void
172
nlsysevent_unload(void)
173
{
174
devctl_unset_notify_hook();
175
genl_unregister_family(ctrl_family_id);
176
for (size_t i = 0; i < MAX_SYSEVENT_GROUPS; i++) {
177
if (sysevent_groups[i].name == NULL)
178
break;
179
free(sysevent_groups[i].name, M_NLSE);
180
}
181
}
182
183
static int
184
nlsysevent_loader(module_t mod __unused, int what, void *priv __unused)
185
{
186
int err = 0;
187
188
switch (what) {
189
case MOD_LOAD:
190
nlsysevent_load();
191
break;
192
case MOD_UNLOAD:
193
nlsysevent_unload();
194
break;
195
default:
196
err = EOPNOTSUPP;
197
break;
198
}
199
return (err);
200
}
201
static moduledata_t nlsysevent_mod = { "nlsysevent", nlsysevent_loader, NULL};
202
203
DECLARE_MODULE(nlsysevent, nlsysevent_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
204
MODULE_DEPEND(nlsysevent, netlink, 1, 1, 1);
205
MODULE_VERSION(nlsysevent, 1);
206
207