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;