]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/lib/librte_eal/linuxapp/eal/eal_dev.c
update download target update for octopus release
[ceph.git] / ceph / src / spdk / dpdk / lib / librte_eal / linuxapp / eal / eal_dev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
3 */
4
5 #include <string.h>
6 #include <unistd.h>
7 #include <sys/socket.h>
8 #include <linux/netlink.h>
9
10 #include <rte_string_fns.h>
11 #include <rte_log.h>
12 #include <rte_compat.h>
13 #include <rte_dev.h>
14 #include <rte_malloc.h>
15 #include <rte_interrupts.h>
16 #include <rte_alarm.h>
17
18 #include "eal_private.h"
19
20 static struct rte_intr_handle intr_handle = {.fd = -1 };
21 static bool monitor_started;
22
23 #define EAL_UEV_MSG_LEN 4096
24 #define EAL_UEV_MSG_ELEM_LEN 128
25
26 static void dev_uev_handler(__rte_unused void *param);
27
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
34 };
35
36 static int
37 dev_uev_socket_fd_create(void)
38 {
39 struct sockaddr_nl addr;
40 int ret;
41
42 intr_handle.fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC |
43 SOCK_NONBLOCK,
44 NETLINK_KOBJECT_UEVENT);
45 if (intr_handle.fd < 0) {
46 RTE_LOG(ERR, EAL, "create uevent fd failed.\n");
47 return -1;
48 }
49
50 memset(&addr, 0, sizeof(addr));
51 addr.nl_family = AF_NETLINK;
52 addr.nl_pid = 0;
53 addr.nl_groups = 0xffffffff;
54
55 ret = bind(intr_handle.fd, (struct sockaddr *) &addr, sizeof(addr));
56 if (ret < 0) {
57 RTE_LOG(ERR, EAL, "Failed to bind uevent socket.\n");
58 goto err;
59 }
60
61 return 0;
62 err:
63 close(intr_handle.fd);
64 intr_handle.fd = -1;
65 return ret;
66 }
67
68 static int
69 dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
70 {
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];
74 int i = 0;
75
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);
79
80 while (i < length) {
81 for (; i < length; i++) {
82 if (*buf)
83 break;
84 buf++;
85 }
86 /**
87 * check device uevent from kernel side, no need to check
88 * uevent from udev.
89 */
90 if (!strncmp(buf, "libudev", 7)) {
91 buf += 7;
92 i += 7;
93 return -1;
94 }
95 if (!strncmp(buf, "ACTION=", 7)) {
96 buf += 7;
97 i += 7;
98 strlcpy(action, buf, sizeof(action));
99 } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
100 buf += 10;
101 i += 10;
102 strlcpy(subsystem, buf, sizeof(subsystem));
103 } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
104 buf += 14;
105 i += 14;
106 strlcpy(pci_slot_name, buf, sizeof(subsystem));
107 event->devname = strdup(pci_slot_name);
108 }
109 for (; i < length; i++) {
110 if (*buf == '\0')
111 break;
112 buf++;
113 }
114 }
115
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;
123 else
124 return -1;
125
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;
131 else
132 return -1;
133 return 0;
134 }
135
136 static void
137 dev_delayed_unregister(void *param)
138 {
139 rte_intr_callback_unregister(&intr_handle, dev_uev_handler, param);
140 close(intr_handle.fd);
141 intr_handle.fd = -1;
142 }
143
144 static void
145 dev_uev_handler(__rte_unused void *param)
146 {
147 struct rte_dev_event uevent;
148 int ret;
149 char buf[EAL_UEV_MSG_LEN];
150
151 memset(&uevent, 0, sizeof(struct rte_dev_event));
152 memset(buf, 0, EAL_UEV_MSG_LEN);
153
154 ret = recv(intr_handle.fd, buf, EAL_UEV_MSG_LEN, MSG_DONTWAIT);
155 if (ret < 0 && errno == EAGAIN)
156 return;
157 else if (ret <= 0) {
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);
161 return;
162 }
163
164 ret = dev_uev_parse(buf, &uevent, EAL_UEV_MSG_LEN);
165 if (ret < 0) {
166 RTE_LOG(DEBUG, EAL, "It is not an valid event "
167 "that need to be handle.\n");
168 return;
169 }
170
171 RTE_LOG(DEBUG, EAL, "receive uevent(name:%s, type:%d, subsystem:%d)\n",
172 uevent.devname, uevent.type, uevent.subsystem);
173
174 if (uevent.devname)
175 dev_callback_process(uevent.devname, uevent.type);
176 }
177
178 int __rte_experimental
179 rte_dev_event_monitor_start(void)
180 {
181 int ret;
182
183 if (monitor_started)
184 return 0;
185
186 ret = dev_uev_socket_fd_create();
187 if (ret) {
188 RTE_LOG(ERR, EAL, "error create device event fd.\n");
189 return -1;
190 }
191
192 intr_handle.type = RTE_INTR_HANDLE_DEV_EVENT;
193 ret = rte_intr_callback_register(&intr_handle, dev_uev_handler, NULL);
194
195 if (ret) {
196 RTE_LOG(ERR, EAL, "fail to register uevent callback.\n");
197 return -1;
198 }
199
200 monitor_started = true;
201
202 return 0;
203 }
204
205 int __rte_experimental
206 rte_dev_event_monitor_stop(void)
207 {
208 int ret;
209
210 if (!monitor_started)
211 return 0;
212
213 ret = rte_intr_callback_unregister(&intr_handle, dev_uev_handler,
214 (void *)-1);
215 if (ret < 0) {
216 RTE_LOG(ERR, EAL, "fail to unregister uevent callback.\n");
217 return ret;
218 }
219
220 close(intr_handle.fd);
221 intr_handle.fd = -1;
222 monitor_started = false;
223 return 0;
224 }