1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
7 #include <sys/socket.h>
8 #include <linux/netlink.h>
10 #include <rte_string_fns.h>
12 #include <rte_compat.h>
14 #include <rte_malloc.h>
15 #include <rte_interrupts.h>
16 #include <rte_alarm.h>
18 #include "eal_private.h"
20 static struct rte_intr_handle intr_handle = {.fd = -1 };
21 static bool monitor_started;
23 #define EAL_UEV_MSG_LEN 4096
24 #define EAL_UEV_MSG_ELEM_LEN 128
26 static void dev_uev_handler(__rte_unused void *param);
28 /* identify the system layer which reports this event. */
29 enum eal_dev_event_subsystem {
30 EAL_DEV_EVENT_SUBSYSTEM_PCI, /* PCI bus device event */
31 EAL_DEV_EVENT_SUBSYSTEM_UIO, /* UIO driver device event */
32 EAL_DEV_EVENT_SUBSYSTEM_VFIO, /* VFIO driver device event */
33 EAL_DEV_EVENT_SUBSYSTEM_MAX
37 dev_uev_socket_fd_create(void)
39 struct sockaddr_nl addr;
42 intr_handle.fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC |
44 NETLINK_KOBJECT_UEVENT);
45 if (intr_handle.fd < 0) {
46 RTE_LOG(ERR, EAL, "create uevent fd failed.\n");
50 memset(&addr, 0, sizeof(addr));
51 addr.nl_family = AF_NETLINK;
53 addr.nl_groups = 0xffffffff;
55 ret = bind(intr_handle.fd, (struct sockaddr *) &addr, sizeof(addr));
57 RTE_LOG(ERR, EAL, "Failed to bind uevent socket.\n");
63 close(intr_handle.fd);
69 dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
71 char action[EAL_UEV_MSG_ELEM_LEN];
72 char subsystem[EAL_UEV_MSG_ELEM_LEN];
73 char pci_slot_name[EAL_UEV_MSG_ELEM_LEN];
76 memset(action, 0, EAL_UEV_MSG_ELEM_LEN);
77 memset(subsystem, 0, EAL_UEV_MSG_ELEM_LEN);
78 memset(pci_slot_name, 0, EAL_UEV_MSG_ELEM_LEN);
81 for (; i < length; i++) {
87 * check device uevent from kernel side, no need to check
90 if (!strncmp(buf, "libudev", 7)) {
95 if (!strncmp(buf, "ACTION=", 7)) {
98 strlcpy(action, buf, sizeof(action));
99 } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
102 strlcpy(subsystem, buf, sizeof(subsystem));
103 } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
106 strlcpy(pci_slot_name, buf, sizeof(subsystem));
107 event->devname = strdup(pci_slot_name);
109 for (; i < length; i++) {
116 /* parse the subsystem layer */
117 if (!strncmp(subsystem, "uio", 3))
118 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_UIO;
119 else if (!strncmp(subsystem, "pci", 3))
120 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_PCI;
121 else if (!strncmp(subsystem, "vfio", 4))
122 event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_VFIO;
126 /* parse the action type */
127 if (!strncmp(action, "add", 3))
128 event->type = RTE_DEV_EVENT_ADD;
129 else if (!strncmp(action, "remove", 6))
130 event->type = RTE_DEV_EVENT_REMOVE;
137 dev_delayed_unregister(void *param)
139 rte_intr_callback_unregister(&intr_handle, dev_uev_handler, param);
140 close(intr_handle.fd);
145 dev_uev_handler(__rte_unused void *param)
147 struct rte_dev_event uevent;
149 char buf[EAL_UEV_MSG_LEN];
151 memset(&uevent, 0, sizeof(struct rte_dev_event));
152 memset(buf, 0, EAL_UEV_MSG_LEN);
154 ret = recv(intr_handle.fd, buf, EAL_UEV_MSG_LEN, MSG_DONTWAIT);
155 if (ret < 0 && errno == EAGAIN)
158 /* connection is closed or broken, can not up again. */
159 RTE_LOG(ERR, EAL, "uevent socket connection is broken.\n");
160 rte_eal_alarm_set(1, dev_delayed_unregister, NULL);
164 ret = dev_uev_parse(buf, &uevent, EAL_UEV_MSG_LEN);
166 RTE_LOG(DEBUG, EAL, "It is not an valid event "
167 "that need to be handle.\n");
171 RTE_LOG(DEBUG, EAL, "receive uevent(name:%s, type:%d, subsystem:%d)\n",
172 uevent.devname, uevent.type, uevent.subsystem);
175 dev_callback_process(uevent.devname, uevent.type);
178 int __rte_experimental
179 rte_dev_event_monitor_start(void)
186 ret = dev_uev_socket_fd_create();
188 RTE_LOG(ERR, EAL, "error create device event fd.\n");
192 intr_handle.type = RTE_INTR_HANDLE_DEV_EVENT;
193 ret = rte_intr_callback_register(&intr_handle, dev_uev_handler, NULL);
196 RTE_LOG(ERR, EAL, "fail to register uevent callback.\n");
200 monitor_started = true;
205 int __rte_experimental
206 rte_dev_event_monitor_stop(void)
210 if (!monitor_started)
213 ret = rte_intr_callback_unregister(&intr_handle, dev_uev_handler,
216 RTE_LOG(ERR, EAL, "fail to unregister uevent callback.\n");
220 close(intr_handle.fd);
222 monitor_started = false;