xref: /dpdk/drivers/net/failsafe/failsafe_ether.c (revision 3998e2a07220844d3f3c17f76a781ced3efe0de0)
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 #include <rte_cycles.h>
39 
40 #include "failsafe_private.h"
41 
42 /** Print a message out of a flow error. */
43 static int
44 fs_flow_complain(struct rte_flow_error *error)
45 {
46 	static const char *const errstrlist[] = {
47 		[RTE_FLOW_ERROR_TYPE_NONE] = "no error",
48 		[RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
49 		[RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
50 		[RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
51 		[RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
52 		[RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
53 		[RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
54 		[RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
55 		[RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
56 		[RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
57 		[RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
58 		[RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
59 	};
60 	const char *errstr;
61 	char buf[32];
62 	int err = rte_errno;
63 
64 	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
65 			!errstrlist[error->type])
66 		errstr = "unknown type";
67 	else
68 		errstr = errstrlist[error->type];
69 	ERROR("Caught error type %d (%s): %s%s\n",
70 		error->type, errstr,
71 		error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
72 				error->cause), buf) : "",
73 		error->message ? error->message : "(no stated reason)");
74 	return -err;
75 }
76 
77 static int
78 eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
79 			 struct sub_device *sdev)
80 {
81 	struct rte_flow_error ferror;
82 	int ret;
83 
84 	if (!PRIV(dev)->flow_isolated) {
85 		DEBUG("Flow isolation already disabled");
86 	} else {
87 		DEBUG("Enabling flow isolation");
88 		ret = rte_flow_isolate(PORT_ID(sdev),
89 				       PRIV(dev)->flow_isolated,
90 				       &ferror);
91 		if (ret) {
92 			fs_flow_complain(&ferror);
93 			return ret;
94 		}
95 	}
96 	return 0;
97 }
98 
99 static int
100 fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
101 		struct sub_device *sdev)
102 {
103 	struct rte_eth_dev *edev;
104 	struct rte_vlan_filter_conf *vfc1;
105 	struct rte_vlan_filter_conf *vfc2;
106 	struct rte_flow *flow;
107 	struct rte_flow_error ferror;
108 	uint32_t i;
109 	int ret;
110 
111 	edev = ETH(sdev);
112 	/* RX queue setup */
113 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
114 		struct rxq *rxq;
115 
116 		rxq = dev->data->rx_queues[i];
117 		ret = rte_eth_rx_queue_setup(PORT_ID(sdev), i,
118 				rxq->info.nb_desc, rxq->socket_id,
119 				&rxq->info.conf, rxq->info.mp);
120 		if (ret) {
121 			ERROR("rx_queue_setup failed");
122 			return ret;
123 		}
124 	}
125 	/* TX queue setup */
126 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
127 		struct txq *txq;
128 
129 		txq = dev->data->tx_queues[i];
130 		ret = rte_eth_tx_queue_setup(PORT_ID(sdev), i,
131 				txq->info.nb_desc, txq->socket_id,
132 				&txq->info.conf);
133 		if (ret) {
134 			ERROR("tx_queue_setup failed");
135 			return ret;
136 		}
137 	}
138 	/* dev_link.link_status */
139 	if (dev->data->dev_link.link_status !=
140 	    edev->data->dev_link.link_status) {
141 		DEBUG("Configuring link_status");
142 		if (dev->data->dev_link.link_status)
143 			ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
144 		else
145 			ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
146 		if (ret) {
147 			ERROR("Failed to apply link_status");
148 			return ret;
149 		}
150 	} else {
151 		DEBUG("link_status already set");
152 	}
153 	/* promiscuous */
154 	if (dev->data->promiscuous != edev->data->promiscuous) {
155 		DEBUG("Configuring promiscuous");
156 		if (dev->data->promiscuous)
157 			rte_eth_promiscuous_enable(PORT_ID(sdev));
158 		else
159 			rte_eth_promiscuous_disable(PORT_ID(sdev));
160 	} else {
161 		DEBUG("promiscuous already set");
162 	}
163 	/* all_multicast */
164 	if (dev->data->all_multicast != edev->data->all_multicast) {
165 		DEBUG("Configuring all_multicast");
166 		if (dev->data->all_multicast)
167 			rte_eth_allmulticast_enable(PORT_ID(sdev));
168 		else
169 			rte_eth_allmulticast_disable(PORT_ID(sdev));
170 	} else {
171 		DEBUG("all_multicast already set");
172 	}
173 	/* MTU */
174 	if (dev->data->mtu != edev->data->mtu) {
175 		DEBUG("Configuring MTU");
176 		ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu);
177 		if (ret) {
178 			ERROR("Failed to apply MTU");
179 			return ret;
180 		}
181 	} else {
182 		DEBUG("MTU already set");
183 	}
184 	/* default MAC */
185 	DEBUG("Configuring default MAC address");
186 	ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
187 			&dev->data->mac_addrs[0]);
188 	if (ret) {
189 		ERROR("Setting default MAC address failed");
190 		return ret;
191 	}
192 	/* additional MAC */
193 	if (PRIV(dev)->nb_mac_addr > 1)
194 		DEBUG("Configure additional MAC address%s",
195 			(PRIV(dev)->nb_mac_addr > 2 ? "es" : ""));
196 	for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) {
197 		struct ether_addr *ea;
198 
199 		ea = &dev->data->mac_addrs[i];
200 		ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
201 				PRIV(dev)->mac_addr_pool[i]);
202 		if (ret) {
203 			char ea_fmt[ETHER_ADDR_FMT_SIZE];
204 
205 			ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea);
206 			ERROR("Adding MAC address %s failed", ea_fmt);
207 			return ret;
208 		}
209 	}
210 	/* VLAN filter */
211 	vfc1 = &dev->data->vlan_filter_conf;
212 	vfc2 = &edev->data->vlan_filter_conf;
213 	if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) {
214 		uint64_t vbit;
215 		uint64_t ids;
216 		size_t i;
217 		uint16_t vlan_id;
218 
219 		DEBUG("Configuring VLAN filter");
220 		for (i = 0; i < RTE_DIM(vfc1->ids); i++) {
221 			if (vfc1->ids[i] == 0)
222 				continue;
223 			ids = vfc1->ids[i];
224 			while (ids) {
225 				vlan_id = 64 * i;
226 				/* count trailing zeroes */
227 				vbit = ~ids & (ids - 1);
228 				/* clear least significant bit set */
229 				ids ^= (ids ^ (ids - 1)) ^ vbit;
230 				for (; vbit; vlan_id++)
231 					vbit >>= 1;
232 				ret = rte_eth_dev_vlan_filter(
233 					PORT_ID(sdev), vlan_id, 1);
234 				if (ret) {
235 					ERROR("Failed to apply VLAN filter %hu",
236 						vlan_id);
237 					return ret;
238 				}
239 			}
240 		}
241 	} else {
242 		DEBUG("VLAN filter already set");
243 	}
244 	/* rte_flow */
245 	if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) {
246 		DEBUG("rte_flow already set");
247 	} else {
248 		DEBUG("Resetting rte_flow configuration");
249 		ret = rte_flow_flush(PORT_ID(sdev), &ferror);
250 		if (ret) {
251 			fs_flow_complain(&ferror);
252 			return ret;
253 		}
254 		i = 0;
255 		rte_errno = 0;
256 		DEBUG("Configuring rte_flow");
257 		TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) {
258 			DEBUG("Creating flow #%" PRIu32, i++);
259 			flow->flows[SUB_ID(sdev)] =
260 				rte_flow_create(PORT_ID(sdev),
261 						&flow->fd->attr,
262 						flow->fd->items,
263 						flow->fd->actions,
264 						&ferror);
265 			ret = rte_errno;
266 			if (ret)
267 				break;
268 		}
269 		if (ret) {
270 			fs_flow_complain(&ferror);
271 			return ret;
272 		}
273 	}
274 	return 0;
275 }
276 
277 static void
278 fs_dev_remove(struct sub_device *sdev)
279 {
280 	int ret;
281 
282 	if (sdev == NULL)
283 		return;
284 	switch (sdev->state) {
285 	case DEV_STARTED:
286 		rte_eth_dev_stop(PORT_ID(sdev));
287 		sdev->state = DEV_ACTIVE;
288 		/* fallthrough */
289 	case DEV_ACTIVE:
290 		rte_eth_dev_close(PORT_ID(sdev));
291 		sdev->state = DEV_PROBED;
292 		/* fallthrough */
293 	case DEV_PROBED:
294 		ret = rte_eal_hotplug_remove(sdev->bus->name,
295 					     sdev->dev->name);
296 		if (ret) {
297 			ERROR("Bus detach failed for sub_device %u",
298 			      SUB_ID(sdev));
299 		} else {
300 			ETH(sdev)->state = RTE_ETH_DEV_UNUSED;
301 		}
302 		sdev->state = DEV_PARSED;
303 		/* fallthrough */
304 	case DEV_PARSED:
305 	case DEV_UNDEFINED:
306 		sdev->state = DEV_UNDEFINED;
307 		/* the end */
308 		break;
309 	}
310 	failsafe_hotplug_alarm_install(sdev->fs_dev);
311 }
312 
313 static void
314 fs_dev_stats_save(struct sub_device *sdev)
315 {
316 	struct rte_eth_stats stats;
317 	int err;
318 
319 	/* Attempt to read current stats. */
320 	err = rte_eth_stats_get(PORT_ID(sdev), &stats);
321 	if (err) {
322 		uint64_t timestamp = sdev->stats_snapshot.timestamp;
323 
324 		WARN("Could not access latest statistics from sub-device %d.\n",
325 			 SUB_ID(sdev));
326 		if (timestamp != 0)
327 			WARN("Using latest snapshot taken before %"PRIu64" seconds.\n",
328 				 (rte_rdtsc() - timestamp) / rte_get_tsc_hz());
329 	}
330 	failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator,
331 			err ? &sdev->stats_snapshot.stats : &stats);
332 	memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot));
333 }
334 
335 static inline int
336 fs_rxtx_clean(struct sub_device *sdev)
337 {
338 	uint16_t i;
339 
340 	for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++)
341 		if (FS_ATOMIC_RX(sdev, i))
342 			return 0;
343 	for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++)
344 		if (FS_ATOMIC_TX(sdev, i))
345 			return 0;
346 	return 1;
347 }
348 
349 void
350 failsafe_dev_remove(struct rte_eth_dev *dev)
351 {
352 	struct sub_device *sdev;
353 	uint8_t i;
354 
355 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
356 		if (sdev->remove && fs_rxtx_clean(sdev)) {
357 			fs_dev_stats_save(sdev);
358 			fs_dev_remove(sdev);
359 		}
360 }
361 
362 int
363 failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
364 {
365 	struct sub_device *sdev;
366 	uint32_t inactive;
367 	int ret;
368 	uint8_t i;
369 
370 	if (PRIV(dev)->state < DEV_PARSED)
371 		return 0;
372 
373 	ret = failsafe_args_parse_subs(dev);
374 	if (ret)
375 		goto err_remove;
376 
377 	if (PRIV(dev)->state < DEV_PROBED)
378 		return 0;
379 	ret = failsafe_eal_init(dev);
380 	if (ret)
381 		goto err_remove;
382 	if (PRIV(dev)->state < DEV_ACTIVE)
383 		return 0;
384 	inactive = 0;
385 	FOREACH_SUBDEV(sdev, i, dev) {
386 		if (sdev->state == DEV_PROBED) {
387 			inactive |= UINT32_C(1) << i;
388 			ret = eth_dev_flow_isolate_set(dev, sdev);
389 			if (ret) {
390 				ERROR("Could not apply configuration to sub_device %d",
391 				      i);
392 				goto err_remove;
393 			}
394 		}
395 	}
396 	ret = dev->dev_ops->dev_configure(dev);
397 	if (ret)
398 		goto err_remove;
399 	FOREACH_SUBDEV(sdev, i, dev) {
400 		if (inactive & (UINT32_C(1) << i)) {
401 			ret = fs_eth_dev_conf_apply(dev, sdev);
402 			if (ret) {
403 				ERROR("Could not apply configuration to sub_device %d",
404 				      i);
405 				goto err_remove;
406 			}
407 		}
408 	}
409 	/*
410 	 * If new devices have been configured, check if
411 	 * the link state has changed.
412 	 */
413 	if (inactive)
414 		dev->dev_ops->link_update(dev, 1);
415 	if (PRIV(dev)->state < DEV_STARTED)
416 		return 0;
417 	ret = dev->dev_ops->dev_start(dev);
418 	if (ret)
419 		goto err_remove;
420 	return 0;
421 err_remove:
422 	FOREACH_SUBDEV(sdev, i, dev)
423 		if (sdev->state != PRIV(dev)->state)
424 			sdev->remove = 1;
425 	return ret;
426 }
427 
428 void
429 failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from)
430 {
431 	uint32_t i;
432 
433 	RTE_ASSERT(to != NULL && from != NULL);
434 	to->ipackets += from->ipackets;
435 	to->opackets += from->opackets;
436 	to->ibytes += from->ibytes;
437 	to->obytes += from->obytes;
438 	to->imissed += from->imissed;
439 	to->ierrors += from->ierrors;
440 	to->oerrors += from->oerrors;
441 	to->rx_nombuf += from->rx_nombuf;
442 	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
443 		to->q_ipackets[i] += from->q_ipackets[i];
444 		to->q_opackets[i] += from->q_opackets[i];
445 		to->q_ibytes[i] += from->q_ibytes[i];
446 		to->q_obytes[i] += from->q_obytes[i];
447 		to->q_errors[i] += from->q_errors[i];
448 	}
449 }
450 
451 int
452 failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
453 				enum rte_eth_event_type event __rte_unused,
454 				void *cb_arg, void *out __rte_unused)
455 {
456 	struct sub_device *sdev = cb_arg;
457 
458 	/* Switch as soon as possible tx_dev. */
459 	fs_switch_dev(sdev->fs_dev, sdev);
460 	/* Use safe bursts in any case. */
461 	set_burst_fn(sdev->fs_dev, 1);
462 	/*
463 	 * Async removal, the sub-PMD will try to unregister
464 	 * the callback at the source of the current thread context.
465 	 */
466 	sdev->remove = 1;
467 	return 0;
468 }
469 
470 int
471 failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
472 				enum rte_eth_event_type event __rte_unused,
473 				void *cb_arg, void *out __rte_unused)
474 {
475 	struct rte_eth_dev *dev = cb_arg;
476 	int ret;
477 
478 	ret = dev->dev_ops->link_update(dev, 0);
479 	/* We must pass on the LSC event */
480 	if (ret)
481 		return _rte_eth_dev_callback_process(dev,
482 						     RTE_ETH_EVENT_INTR_LSC,
483 						     NULL, NULL);
484 	else
485 		return 0;
486 }
487