xref: /dpdk/drivers/net/failsafe/failsafe.c (revision d429cc0b53735cc7b1e304ec1d0f35ae06ace7d0)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 6WIND S.A.
3  * Copyright 2017 Mellanox.
4  */
5 
6 #include <rte_alarm.h>
7 #include <rte_malloc.h>
8 #include <rte_ethdev_driver.h>
9 #include <rte_ethdev_vdev.h>
10 #include <rte_devargs.h>
11 #include <rte_kvargs.h>
12 #include <rte_bus_vdev.h>
13 
14 #include "failsafe_private.h"
15 
16 const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
17 static const struct rte_eth_link eth_link = {
18 	.link_speed = ETH_SPEED_NUM_10G,
19 	.link_duplex = ETH_LINK_FULL_DUPLEX,
20 	.link_status = ETH_LINK_UP,
21 	.link_autoneg = ETH_LINK_AUTONEG,
22 };
23 
24 static int
25 fs_sub_device_alloc(struct rte_eth_dev *dev,
26 		const char *params)
27 {
28 	uint8_t nb_subs;
29 	int ret;
30 	int i;
31 
32 	ret = failsafe_args_count_subdevice(dev, params);
33 	if (ret)
34 		return ret;
35 	if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
36 		ERROR("Cannot allocate more than %d ports",
37 			FAILSAFE_MAX_ETHPORTS);
38 		return -ENOSPC;
39 	}
40 	nb_subs = PRIV(dev)->subs_tail;
41 	PRIV(dev)->subs = rte_zmalloc(NULL,
42 			sizeof(struct sub_device) * nb_subs,
43 			RTE_CACHE_LINE_SIZE);
44 	if (PRIV(dev)->subs == NULL) {
45 		ERROR("Could not allocate sub_devices");
46 		return -ENOMEM;
47 	}
48 	/* Initiate static sub devices linked list. */
49 	for (i = 1; i < nb_subs; i++)
50 		PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
51 	PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
52 	return 0;
53 }
54 
55 static void
56 fs_sub_device_free(struct rte_eth_dev *dev)
57 {
58 	rte_free(PRIV(dev)->subs);
59 }
60 
61 static void fs_hotplug_alarm(void *arg);
62 
63 int
64 failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
65 {
66 	int ret;
67 
68 	if (dev == NULL)
69 		return -EINVAL;
70 	if (PRIV(dev)->pending_alarm)
71 		return 0;
72 	ret = rte_eal_alarm_set(hotplug_poll * 1000,
73 				fs_hotplug_alarm,
74 				dev);
75 	if (ret) {
76 		ERROR("Could not set up plug-in event detection");
77 		return ret;
78 	}
79 	PRIV(dev)->pending_alarm = 1;
80 	return 0;
81 }
82 
83 int
84 failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
85 {
86 	int ret = 0;
87 
88 	rte_errno = 0;
89 	rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
90 	if (rte_errno) {
91 		ERROR("rte_eal_alarm_cancel failed (errno: %s)",
92 		      strerror(rte_errno));
93 		ret = -rte_errno;
94 	} else {
95 		PRIV(dev)->pending_alarm = 0;
96 	}
97 	return ret;
98 }
99 
100 static void
101 fs_hotplug_alarm(void *arg)
102 {
103 	struct rte_eth_dev *dev = arg;
104 	struct sub_device *sdev;
105 	int ret;
106 	uint8_t i;
107 
108 	if (!PRIV(dev)->pending_alarm)
109 		return;
110 	PRIV(dev)->pending_alarm = 0;
111 	FOREACH_SUBDEV(sdev, i, dev)
112 		if (sdev->state != PRIV(dev)->state)
113 			break;
114 	/* if we have non-probed device */
115 	if (i != PRIV(dev)->subs_tail) {
116 		if (fs_lock(dev, 1) != 0)
117 			goto reinstall;
118 		ret = failsafe_eth_dev_state_sync(dev);
119 		fs_unlock(dev, 1);
120 		if (ret)
121 			ERROR("Unable to synchronize sub_device state");
122 	}
123 	failsafe_dev_remove(dev);
124 reinstall:
125 	ret = failsafe_hotplug_alarm_install(dev);
126 	if (ret)
127 		ERROR("Unable to set up next alarm");
128 }
129 
130 static int
131 fs_mutex_init(struct fs_priv *priv)
132 {
133 	int ret;
134 	pthread_mutexattr_t attr;
135 
136 	ret = pthread_mutexattr_init(&attr);
137 	if (ret) {
138 		ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
139 		return ret;
140 	}
141 	/* Allow mutex relocks for the thread holding the mutex. */
142 	ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
143 	if (ret) {
144 		ERROR("Cannot set mutex type - %s", strerror(ret));
145 		return ret;
146 	}
147 	ret = pthread_mutex_init(&priv->hotplug_mutex, &attr);
148 	if (ret) {
149 		ERROR("Cannot initiate mutex - %s", strerror(ret));
150 		return ret;
151 	}
152 	return 0;
153 }
154 
155 static int
156 fs_eth_dev_create(struct rte_vdev_device *vdev)
157 {
158 	struct rte_eth_dev *dev;
159 	struct ether_addr *mac;
160 	struct fs_priv *priv;
161 	struct sub_device *sdev;
162 	const char *params;
163 	unsigned int socket_id;
164 	uint8_t i;
165 	int ret;
166 
167 	dev = NULL;
168 	priv = NULL;
169 	socket_id = rte_socket_id();
170 	INFO("Creating fail-safe device on NUMA socket %u", socket_id);
171 	params = rte_vdev_device_args(vdev);
172 	if (params == NULL) {
173 		ERROR("This PMD requires sub-devices, none provided");
174 		return -1;
175 	}
176 	dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
177 	if (dev == NULL) {
178 		ERROR("Unable to allocate rte_eth_dev");
179 		return -1;
180 	}
181 	priv = PRIV(dev);
182 	priv->dev = dev;
183 	dev->dev_ops = &failsafe_ops;
184 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
185 	dev->data->dev_link = eth_link;
186 	PRIV(dev)->nb_mac_addr = 1;
187 	TAILQ_INIT(&PRIV(dev)->flow_list);
188 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
189 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
190 	ret = fs_sub_device_alloc(dev, params);
191 	if (ret) {
192 		ERROR("Could not allocate sub_devices");
193 		goto free_dev;
194 	}
195 	ret = failsafe_args_parse(dev, params);
196 	if (ret)
197 		goto free_subs;
198 	ret = rte_eth_dev_owner_new(&priv->my_owner.id);
199 	if (ret) {
200 		ERROR("Failed to get unique owner identifier");
201 		goto free_args;
202 	}
203 	snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
204 		 FAILSAFE_OWNER_NAME);
205 	ret = failsafe_eal_init(dev);
206 	if (ret)
207 		goto free_args;
208 	ret = fs_mutex_init(priv);
209 	if (ret)
210 		goto free_args;
211 	ret = failsafe_hotplug_alarm_install(dev);
212 	if (ret) {
213 		ERROR("Could not set up plug-in event detection");
214 		goto free_args;
215 	}
216 	mac = &dev->data->mac_addrs[0];
217 	if (mac_from_arg) {
218 		/*
219 		 * If MAC address was provided as a parameter,
220 		 * apply to all probed slaves.
221 		 */
222 		FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
223 			ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
224 							       mac);
225 			if (ret) {
226 				ERROR("Failed to set default MAC address");
227 				goto free_args;
228 			}
229 		}
230 	} else {
231 		/*
232 		 * Use the ether_addr from first probed
233 		 * device, either preferred or fallback.
234 		 */
235 		FOREACH_SUBDEV(sdev, i, dev)
236 			if (sdev->state >= DEV_PROBED) {
237 				ether_addr_copy(&ETH(sdev)->data->mac_addrs[0],
238 						mac);
239 				break;
240 			}
241 		/*
242 		 * If no device has been probed and no ether_addr
243 		 * has been provided on the command line, use a random
244 		 * valid one.
245 		 * It will be applied during future slave state syncs to
246 		 * probed slaves.
247 		 */
248 		if (i == priv->subs_tail)
249 			eth_random_addr(&mac->addr_bytes[0]);
250 	}
251 	INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
252 		mac->addr_bytes[0], mac->addr_bytes[1],
253 		mac->addr_bytes[2], mac->addr_bytes[3],
254 		mac->addr_bytes[4], mac->addr_bytes[5]);
255 	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
256 	PRIV(dev)->intr_handle = (struct rte_intr_handle){
257 		.fd = -1,
258 		.type = RTE_INTR_HANDLE_EXT,
259 	};
260 	return 0;
261 free_args:
262 	failsafe_args_free(dev);
263 free_subs:
264 	fs_sub_device_free(dev);
265 free_dev:
266 	rte_free(PRIV(dev));
267 	rte_eth_dev_release_port(dev);
268 	return -1;
269 }
270 
271 static int
272 fs_rte_eth_free(const char *name)
273 {
274 	struct rte_eth_dev *dev;
275 	int ret;
276 
277 	dev = rte_eth_dev_allocated(name);
278 	if (dev == NULL)
279 		return -ENODEV;
280 	ret = failsafe_eal_uninit(dev);
281 	if (ret)
282 		ERROR("Error while uninitializing sub-EAL");
283 	failsafe_args_free(dev);
284 	fs_sub_device_free(dev);
285 	ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex);
286 	if (ret)
287 		ERROR("Error while destroying hotplug mutex");
288 	rte_free(PRIV(dev));
289 	rte_eth_dev_release_port(dev);
290 	return ret;
291 }
292 
293 static int
294 rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
295 {
296 	const char *name;
297 
298 	name = rte_vdev_device_name(vdev);
299 	INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
300 			name);
301 	return fs_eth_dev_create(vdev);
302 }
303 
304 static int
305 rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
306 {
307 	const char *name;
308 
309 	name = rte_vdev_device_name(vdev);
310 	INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
311 	return fs_rte_eth_free(name);
312 }
313 
314 static struct rte_vdev_driver failsafe_drv = {
315 	.probe = rte_pmd_failsafe_probe,
316 	.remove = rte_pmd_failsafe_remove,
317 };
318 
319 RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
320 RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
321