1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
7 #include <sys/socket.h>
8 #include <linux/netlink.h>
11 #include <rte_compat.h>
13 #include <rte_malloc.h>
14 #include <rte_interrupts.h>
15 #include <rte_alarm.h>
17 #include "eal_private.h"
19 static struct rte_intr_handle intr_handle = {.fd = -1 };
20 static bool monitor_started;
22 #define EAL_UEV_MSG_LEN 4096
23 #define EAL_UEV_MSG_ELEM_LEN 128
25 static void dev_uev_handler(__rte_unused void *param);
27 /* identify the system layer which reports this event. */
28 enum eal_dev_event_subsystem {
29 EAL_DEV_EVENT_SUBSYSTEM_PCI, /* PCI bus device event */
30 EAL_DEV_EVENT_SUBSYSTEM_UIO, /* UIO driver device event */
31 EAL_DEV_EVENT_SUBSYSTEM_VFIO, /* VFIO driver device event */
32 EAL_DEV_EVENT_SUBSYSTEM_MAX
36 dev_uev_socket_fd_create(void)
38 struct sockaddr_nl addr;
41 intr_handle.fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC |
43 NETLINK_KOBJECT_UEVENT);
44 if (intr_handle.fd < 0) {
45 RTE_LOG(ERR, EAL, "create uevent fd failed.\n");
49 memset(&addr, 0, sizeof(addr));
50 addr.nl_family = AF_NETLINK;
52 addr.nl_groups = 0xffffffff;
54 ret = bind(intr_handle.fd, (struct sockaddr *) &addr, sizeof(addr));
56 RTE_LOG(ERR, EAL, "Failed to bind uevent socket.\n");
62 close(intr_handle.fd);
68 dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
70 char action[EAL_UEV_MSG_ELEM_LEN];
71 char subsystem[EAL_UEV_MSG_ELEM_LEN];
72 char pci_slot_name[EAL_UEV_MSG_ELEM_LEN];
75 memset(action, 0, EAL_UEV_MSG_ELEM_LEN);
76 memset(subsystem, 0, EAL_UEV_MSG_ELEM_LEN);
77 memset(pci_slot_name, 0, EAL_UEV_MSG_ELEM_LEN);
80 for (; i < length; i++) {
86 * check device uevent from kernel side, no need to check
89 if (!strncmp(buf, "libudev", 7)) {
94 if (!strncmp(buf, "ACTION=", 7)) {
97 snprintf(action, sizeof(action), "%s", buf);
98 } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
101 snprintf(subsystem, sizeof(subsystem), "%s", buf);
102 } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
105 snprintf(pci_slot_name, sizeof(subsystem), "%s", buf);
106 event->devname = strdup(pci_slot_name);
108 for (; i < length; i++) {
115 /* parse the subsystem layer */
116 if (!strncmp(subsystem, "uio", 3))
117 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_UIO;
118 else if (!strncmp(subsystem, "pci", 3))
119 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_PCI;
120 else if (!strncmp(subsystem, "vfio", 4))
121 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_VFIO;
125 /* parse the action type */
126 if (!strncmp(action, "add", 3))
127 event->type = RTE_DEV_EVENT_ADD;
128 else if (!strncmp(action, "remove", 6))
129 event->type = RTE_DEV_EVENT_REMOVE;
136 dev_delayed_unregister(void *param)
138 rte_intr_callback_unregister(&intr_handle, dev_uev_handler, param);
139 close(intr_handle.fd);
144 dev_uev_handler(__rte_unused void *param)
146 struct rte_dev_event uevent;
148 char buf[EAL_UEV_MSG_LEN];
150 memset(&uevent, 0, sizeof(struct rte_dev_event));
151 memset(buf, 0, EAL_UEV_MSG_LEN);
153 ret = recv(intr_handle.fd, buf, EAL_UEV_MSG_LEN, MSG_DONTWAIT);
154 if (ret < 0 && errno == EAGAIN)
157 /* connection is closed or broken, can not up again. */
158 RTE_LOG(ERR, EAL, "uevent socket connection is broken.\n");
159 rte_eal_alarm_set(1, dev_delayed_unregister, NULL);
163 ret = dev_uev_parse(buf, &uevent, EAL_UEV_MSG_LEN);
165 RTE_LOG(DEBUG, EAL, "It is not an valid event "
166 "that need to be handle.\n");
170 RTE_LOG(DEBUG, EAL, "receive uevent(name:%s, type:%d, subsystem:%d)\n",
171 uevent.devname, uevent.type, uevent.subsystem);
174 dev_callback_process(uevent.devname, uevent.type);
177 int __rte_experimental
178 rte_dev_event_monitor_start(void)
185 ret = dev_uev_socket_fd_create();
187 RTE_LOG(ERR, EAL, "error create device event fd.\n");
191 intr_handle.type = RTE_INTR_HANDLE_DEV_EVENT;
192 ret = rte_intr_callback_register(&intr_handle, dev_uev_handler, NULL);
195 RTE_LOG(ERR, EAL, "fail to register uevent callback.\n");
199 monitor_started = true;
204 int __rte_experimental
205 rte_dev_event_monitor_stop(void)
209 if (!monitor_started)
212 ret = rte_intr_callback_unregister(&intr_handle, dev_uev_handler,
215 RTE_LOG(ERR, EAL, "fail to unregister uevent callback.\n");
219 close(intr_handle.fd);
221 monitor_started = false;