xref: /dpdk/drivers/net/failsafe/failsafe_ether.c (revision eb6d5a0af9a05bf940ba19ec1ddbe575b5e7540b)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2017 6WIND S.A.
5  *   Copyright 2017 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <unistd.h>
35 
36 #include <rte_flow.h>
37 #include <rte_flow_driver.h>
38 
39 #include "failsafe_private.h"
40 
41 /** Print a message out of a flow error. */
42 static int
43 fs_flow_complain(struct rte_flow_error *error)
44 {
45 	static const char *const errstrlist[] = {
46 		[RTE_FLOW_ERROR_TYPE_NONE] = "no error",
47 		[RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
48 		[RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
49 		[RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
50 		[RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
51 		[RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
52 		[RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
53 		[RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
54 		[RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
55 		[RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
56 		[RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
57 		[RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
58 	};
59 	const char *errstr;
60 	char buf[32];
61 	int err = rte_errno;
62 
63 	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
64 			!errstrlist[error->type])
65 		errstr = "unknown type";
66 	else
67 		errstr = errstrlist[error->type];
68 	ERROR("Caught error type %d (%s): %s%s\n",
69 		error->type, errstr,
70 		error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
71 				error->cause), buf) : "",
72 		error->message ? error->message : "(no stated reason)");
73 	return -err;
74 }
75 
76 static int
77 eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
78 			 struct sub_device *sdev)
79 {
80 	struct rte_flow_error ferror;
81 	int ret;
82 
83 	if (!PRIV(dev)->flow_isolated) {
84 		DEBUG("Flow isolation already disabled");
85 	} else {
86 		DEBUG("Enabling flow isolation");
87 		ret = rte_flow_isolate(PORT_ID(sdev),
88 				       PRIV(dev)->flow_isolated,
89 				       &ferror);
90 		if (ret) {
91 			fs_flow_complain(&ferror);
92 			return ret;
93 		}
94 	}
95 	return 0;
96 }
97 
98 static int
99 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
100 		struct sub_device *sdev)
101 {
102 	struct rte_eth_dev *edev;
103 	struct rte_vlan_filter_conf *vfc1;
104 	struct rte_vlan_filter_conf *vfc2;
105 	struct rte_flow *flow;
106 	struct rte_flow_error ferror;
107 	uint32_t i;
108 	int ret;
109 
110 	edev = ETH(sdev);
111 	/* RX queue setup */
112 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
113 		struct rxq *rxq;
114 
115 		rxq = dev->data->rx_queues[i];
116 		ret = rte_eth_rx_queue_setup(PORT_ID(sdev), i,
117 				rxq->info.nb_desc, rxq->socket_id,
118 				&rxq->info.conf, rxq->info.mp);
119 		if (ret) {
120 			ERROR("rx_queue_setup failed");
121 			return ret;
122 		}
123 	}
124 	/* TX queue setup */
125 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
126 		struct txq *txq;
127 
128 		txq = dev->data->tx_queues[i];
129 		ret = rte_eth_tx_queue_setup(PORT_ID(sdev), i,
130 				txq->info.nb_desc, txq->socket_id,
131 				&txq->info.conf);
132 		if (ret) {
133 			ERROR("tx_queue_setup failed");
134 			return ret;
135 		}
136 	}
137 	/* dev_link.link_status */
138 	if (dev->data->dev_link.link_status !=
139 	    edev->data->dev_link.link_status) {
140 		DEBUG("Configuring link_status");
141 		if (dev->data->dev_link.link_status)
142 			ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
143 		else
144 			ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
145 		if (ret) {
146 			ERROR("Failed to apply link_status");
147 			return ret;
148 		}
149 	} else {
150 		DEBUG("link_status already set");
151 	}
152 	/* promiscuous */
153 	if (dev->data->promiscuous != edev->data->promiscuous) {
154 		DEBUG("Configuring promiscuous");
155 		if (dev->data->promiscuous)
156 			rte_eth_promiscuous_enable(PORT_ID(sdev));
157 		else
158 			rte_eth_promiscuous_disable(PORT_ID(sdev));
159 	} else {
160 		DEBUG("promiscuous already set");
161 	}
162 	/* all_multicast */
163 	if (dev->data->all_multicast != edev->data->all_multicast) {
164 		DEBUG("Configuring all_multicast");
165 		if (dev->data->all_multicast)
166 			rte_eth_allmulticast_enable(PORT_ID(sdev));
167 		else
168 			rte_eth_allmulticast_disable(PORT_ID(sdev));
169 	} else {
170 		DEBUG("all_multicast already set");
171 	}
172 	/* MTU */
173 	if (dev->data->mtu != edev->data->mtu) {
174 		DEBUG("Configuring MTU");
175 		ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu);
176 		if (ret) {
177 			ERROR("Failed to apply MTU");
178 			return ret;
179 		}
180 	} else {
181 		DEBUG("MTU already set");
182 	}
183 	/* default MAC */
184 	DEBUG("Configuring default MAC address");
185 	ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
186 			&dev->data->mac_addrs[0]);
187 	if (ret) {
188 		ERROR("Setting default MAC address failed");
189 		return ret;
190 	}
191 	/* additional MAC */
192 	if (PRIV(dev)->nb_mac_addr > 1)
193 		DEBUG("Configure additional MAC address%s",
194 			(PRIV(dev)->nb_mac_addr > 2 ? "es" : ""));
195 	for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) {
196 		struct ether_addr *ea;
197 
198 		ea = &dev->data->mac_addrs[i];
199 		ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
200 				PRIV(dev)->mac_addr_pool[i]);
201 		if (ret) {
202 			char ea_fmt[ETHER_ADDR_FMT_SIZE];
203 
204 			ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea);
205 			ERROR("Adding MAC address %s failed", ea_fmt);
206 			return ret;
207 		}
208 	}
209 	/* VLAN filter */
210 	vfc1 = &dev->data->vlan_filter_conf;
211 	vfc2 = &edev->data->vlan_filter_conf;
212 	if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) {
213 		uint64_t vbit;
214 		uint64_t ids;
215 		size_t i;
216 		uint16_t vlan_id;
217 
218 		DEBUG("Configuring VLAN filter");
219 		for (i = 0; i < RTE_DIM(vfc1->ids); i++) {
220 			if (vfc1->ids[i] == 0)
221 				continue;
222 			ids = vfc1->ids[i];
223 			while (ids) {
224 				vlan_id = 64 * i;
225 				/* count trailing zeroes */
226 				vbit = ~ids & (ids - 1);
227 				/* clear least significant bit set */
228 				ids ^= (ids ^ (ids - 1)) ^ vbit;
229 				for (; vbit; vlan_id++)
230 					vbit >>= 1;
231 				ret = rte_eth_dev_vlan_filter(
232 					PORT_ID(sdev), vlan_id, 1);
233 				if (ret) {
234 					ERROR("Failed to apply VLAN filter %hu",
235 						vlan_id);
236 					return ret;
237 				}
238 			}
239 		}
240 	} else {
241 		DEBUG("VLAN filter already set");
242 	}
243 	/* rte_flow */
244 	if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) {
245 		DEBUG("rte_flow already set");
246 	} else {
247 		DEBUG("Resetting rte_flow configuration");
248 		ret = rte_flow_flush(PORT_ID(sdev), &ferror);
249 		if (ret) {
250 			fs_flow_complain(&ferror);
251 			return ret;
252 		}
253 		i = 0;
254 		rte_errno = 0;
255 		DEBUG("Configuring rte_flow");
256 		TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) {
257 			DEBUG("Creating flow #%" PRIu32, i++);
258 			flow->flows[SUB_ID(sdev)] =
259 				rte_flow_create(PORT_ID(sdev),
260 						&flow->fd->attr,
261 						flow->fd->items,
262 						flow->fd->actions,
263 						&ferror);
264 			ret = rte_errno;
265 			if (ret)
266 				break;
267 		}
268 		if (ret) {
269 			fs_flow_complain(&ferror);
270 			return ret;
271 		}
272 	}
273 	return 0;
274 }
275 
276 static void
277 fs_dev_remove(struct sub_device *sdev)
278 {
279 	int ret;
280 
281 	if (sdev == NULL)
282 		return;
283 	switch (sdev->state) {
284 	case DEV_STARTED:
285 		rte_eth_dev_stop(PORT_ID(sdev));
286 		sdev->state = DEV_ACTIVE;
287 		/* fallthrough */
288 	case DEV_ACTIVE:
289 		rte_eth_dev_close(PORT_ID(sdev));
290 		sdev->state = DEV_PROBED;
291 		/* fallthrough */
292 	case DEV_PROBED:
293 		ret = rte_eal_hotplug_remove(sdev->bus->name,
294 					     sdev->dev->name);
295 		if (ret) {
296 			ERROR("Bus detach failed for sub_device %u",
297 			      SUB_ID(sdev));
298 		} else {
299 			ETH(sdev)->state = RTE_ETH_DEV_UNUSED;
300 		}
301 		sdev->state = DEV_PARSED;
302 		/* fallthrough */
303 	case DEV_PARSED:
304 	case DEV_UNDEFINED:
305 		sdev->state = DEV_UNDEFINED;
306 		/* the end */
307 		break;
308 	}
309 	failsafe_hotplug_alarm_install(sdev->fs_dev);
310 }
311 
312 static void
313 fs_dev_stats_save(struct sub_device *sdev)
314 {
315 	failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator,
316 			&sdev->stats_snapshot);
317 	memset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats));
318 }
319 
320 static inline int
321 fs_rxtx_clean(struct sub_device *sdev)
322 {
323 	uint16_t i;
324 
325 	for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++)
326 		if (FS_ATOMIC_RX(sdev, i))
327 			return 0;
328 	for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++)
329 		if (FS_ATOMIC_TX(sdev, i))
330 			return 0;
331 	return 1;
332 }
333 
334 void
335 failsafe_dev_remove(struct rte_eth_dev *dev)
336 {
337 	struct sub_device *sdev;
338 	uint8_t i;
339 
340 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
341 		if (sdev->remove && fs_rxtx_clean(sdev)) {
342 			fs_dev_stats_save(sdev);
343 			fs_dev_remove(sdev);
344 		}
345 }
346 
347 int
348 failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
349 {
350 	struct sub_device *sdev;
351 	uint32_t inactive;
352 	int ret;
353 	uint8_t i;
354 
355 	if (PRIV(dev)->state < DEV_PARSED)
356 		return 0;
357 
358 	ret = failsafe_args_parse_subs(dev);
359 	if (ret)
360 		goto err_remove;
361 
362 	if (PRIV(dev)->state < DEV_PROBED)
363 		return 0;
364 	ret = failsafe_eal_init(dev);
365 	if (ret)
366 		goto err_remove;
367 	if (PRIV(dev)->state < DEV_ACTIVE)
368 		return 0;
369 	inactive = 0;
370 	FOREACH_SUBDEV(sdev, i, dev) {
371 		if (sdev->state == DEV_PROBED) {
372 			inactive |= UINT32_C(1) << i;
373 			ret = eth_dev_flow_isolate_set(dev, sdev);
374 			if (ret) {
375 				ERROR("Could not apply configuration to sub_device %d",
376 				      i);
377 				goto err_remove;
378 			}
379 		}
380 	}
381 	ret = dev->dev_ops->dev_configure(dev);
382 	if (ret)
383 		goto err_remove;
384 	FOREACH_SUBDEV(sdev, i, dev) {
385 		if (inactive & (UINT32_C(1) << i)) {
386 			ret = fs_eth_dev_conf_apply(dev, sdev);
387 			if (ret) {
388 				ERROR("Could not apply configuration to sub_device %d",
389 				      i);
390 				goto err_remove;
391 			}
392 		}
393 	}
394 	/*
395 	 * If new devices have been configured, check if
396 	 * the link state has changed.
397 	 */
398 	if (inactive)
399 		dev->dev_ops->link_update(dev, 1);
400 	if (PRIV(dev)->state < DEV_STARTED)
401 		return 0;
402 	ret = dev->dev_ops->dev_start(dev);
403 	if (ret)
404 		goto err_remove;
405 	return 0;
406 err_remove:
407 	FOREACH_SUBDEV(sdev, i, dev)
408 		if (sdev->state != PRIV(dev)->state)
409 			sdev->remove = 1;
410 	return ret;
411 }
412 
413 void
414 failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from)
415 {
416 	uint32_t i;
417 
418 	RTE_ASSERT(to != NULL && from != NULL);
419 	to->ipackets += from->ipackets;
420 	to->opackets += from->opackets;
421 	to->ibytes += from->ibytes;
422 	to->obytes += from->obytes;
423 	to->imissed += from->imissed;
424 	to->ierrors += from->ierrors;
425 	to->oerrors += from->oerrors;
426 	to->rx_nombuf += from->rx_nombuf;
427 	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
428 		to->q_ipackets[i] += from->q_ipackets[i];
429 		to->q_opackets[i] += from->q_opackets[i];
430 		to->q_ibytes[i] += from->q_ibytes[i];
431 		to->q_obytes[i] += from->q_obytes[i];
432 		to->q_errors[i] += from->q_errors[i];
433 	}
434 }
435 
436 int
437 failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
438 				enum rte_eth_event_type event __rte_unused,
439 				void *cb_arg, void *out __rte_unused)
440 {
441 	struct sub_device *sdev = cb_arg;
442 
443 	/* Switch as soon as possible tx_dev. */
444 	fs_switch_dev(sdev->fs_dev, sdev);
445 	/* Use safe bursts in any case. */
446 	set_burst_fn(sdev->fs_dev, 1);
447 	/*
448 	 * Async removal, the sub-PMD will try to unregister
449 	 * the callback at the source of the current thread context.
450 	 */
451 	sdev->remove = 1;
452 	return 0;
453 }
454 
455 int
456 failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
457 				enum rte_eth_event_type event __rte_unused,
458 				void *cb_arg, void *out __rte_unused)
459 {
460 	struct rte_eth_dev *dev = cb_arg;
461 	int ret;
462 
463 	ret = dev->dev_ops->link_update(dev, 0);
464 	/* We must pass on the LSC event */
465 	if (ret)
466 		return _rte_eth_dev_callback_process(dev,
467 						     RTE_ETH_EVENT_INTR_LSC,
468 						     NULL, NULL);
469 	else
470 		return 0;
471 }
472