xref: /dpdk/drivers/net/mlx5/mlx5_mac.c (revision 5a4806d304e084573eb2193341add736ef0af50f)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 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 <stddef.h>
35 #include <assert.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <inttypes.h>
39 #include <errno.h>
40 #include <netinet/in.h>
41 #include <sys/ioctl.h>
42 #include <arpa/inet.h>
43 
44 /* Verbs header. */
45 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
46 #ifdef PEDANTIC
47 #pragma GCC diagnostic ignored "-Wpedantic"
48 #endif
49 #include <infiniband/verbs.h>
50 #ifdef PEDANTIC
51 #pragma GCC diagnostic error "-Wpedantic"
52 #endif
53 
54 #include <rte_ether.h>
55 #include <rte_ethdev.h>
56 #include <rte_common.h>
57 
58 #include "mlx5.h"
59 #include "mlx5_utils.h"
60 #include "mlx5_rxtx.h"
61 #include "mlx5_defs.h"
62 
63 /**
64  * Get MAC address by querying netdevice.
65  *
66  * @param[in] priv
67  *   struct priv for the requested device.
68  * @param[out] mac
69  *   MAC address output buffer.
70  *
71  * @return
72  *   0 on success, -1 on failure and errno is set.
73  */
74 int
75 priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])
76 {
77 	struct ifreq request;
78 
79 	if (priv_ifreq(priv, SIOCGIFHWADDR, &request))
80 		return -1;
81 	memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
82 	return 0;
83 }
84 
85 /**
86  * Delete MAC flow steering rule.
87  *
88  * @param hash_rxq
89  *   Pointer to hash RX queue structure.
90  * @param mac_index
91  *   MAC address index.
92  * @param vlan_index
93  *   VLAN index to use.
94  */
95 static void
96 hash_rxq_del_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,
97 		      unsigned int vlan_index)
98 {
99 #ifndef NDEBUG
100 	const uint8_t (*mac)[ETHER_ADDR_LEN] =
101 		(const uint8_t (*)[ETHER_ADDR_LEN])
102 		hash_rxq->priv->mac[mac_index].addr_bytes;
103 #endif
104 
105 	assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
106 	assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));
107 	if (hash_rxq->mac_flow[mac_index][vlan_index] == NULL)
108 		return;
109 	DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u"
110 	      " VLAN index %u",
111 	      (void *)hash_rxq,
112 	      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
113 	      mac_index,
114 	      vlan_index);
115 	claim_zero(ibv_destroy_flow(hash_rxq->mac_flow
116 				    [mac_index][vlan_index]));
117 	hash_rxq->mac_flow[mac_index][vlan_index] = NULL;
118 }
119 
120 /**
121  * Unregister a MAC address from a hash RX queue.
122  *
123  * @param hash_rxq
124  *   Pointer to hash RX queue structure.
125  * @param mac_index
126  *   MAC address index.
127  */
128 static void
129 hash_rxq_mac_addr_del(struct hash_rxq *hash_rxq, unsigned int mac_index)
130 {
131 	unsigned int i;
132 
133 	assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
134 	for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow[mac_index])); ++i)
135 		hash_rxq_del_mac_flow(hash_rxq, mac_index, i);
136 }
137 
138 /**
139  * Unregister all MAC addresses from a hash RX queue.
140  *
141  * @param hash_rxq
142  *   Pointer to hash RX queue structure.
143  */
144 void
145 hash_rxq_mac_addrs_del(struct hash_rxq *hash_rxq)
146 {
147 	unsigned int i;
148 
149 	for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow)); ++i)
150 		hash_rxq_mac_addr_del(hash_rxq, i);
151 }
152 
153 /**
154  * Unregister a MAC address.
155  *
156  * This is done for each hash RX queue.
157  *
158  * @param priv
159  *   Pointer to private structure.
160  * @param mac_index
161  *   MAC address index.
162  */
163 static void
164 priv_mac_addr_del(struct priv *priv, unsigned int mac_index)
165 {
166 	unsigned int i;
167 
168 	assert(mac_index < RTE_DIM(priv->mac));
169 	if (!BITFIELD_ISSET(priv->mac_configured, mac_index))
170 		return;
171 	for (i = 0; (i != priv->hash_rxqs_n); ++i)
172 		hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[i], mac_index);
173 	BITFIELD_RESET(priv->mac_configured, mac_index);
174 }
175 
176 /**
177  * Unregister all MAC addresses from all hash RX queues.
178  *
179  * @param priv
180  *   Pointer to private structure.
181  */
182 void
183 priv_mac_addrs_disable(struct priv *priv)
184 {
185 	unsigned int i;
186 
187 	for (i = 0; (i != priv->hash_rxqs_n); ++i)
188 		hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[i]);
189 }
190 
191 /**
192  * DPDK callback to remove a MAC address.
193  *
194  * @param dev
195  *   Pointer to Ethernet device structure.
196  * @param index
197  *   MAC address index.
198  */
199 void
200 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
201 {
202 	struct priv *priv = dev->data->dev_private;
203 
204 	if (mlx5_is_secondary())
205 		return;
206 
207 	priv_lock(priv);
208 	DEBUG("%p: removing MAC address from index %" PRIu32,
209 	      (void *)dev, index);
210 	if (index >= RTE_DIM(priv->mac))
211 		goto end;
212 	priv_mac_addr_del(priv, index);
213 end:
214 	priv_unlock(priv);
215 }
216 
217 /**
218  * Add MAC flow steering rule.
219  *
220  * @param hash_rxq
221  *   Pointer to hash RX queue structure.
222  * @param mac_index
223  *   MAC address index to register.
224  * @param vlan_index
225  *   VLAN index to use.
226  *
227  * @return
228  *   0 on success, errno value on failure.
229  */
230 static int
231 hash_rxq_add_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,
232 		      unsigned int vlan_index)
233 {
234 	struct ibv_flow *flow;
235 	struct priv *priv = hash_rxq->priv;
236 	const uint8_t (*mac)[ETHER_ADDR_LEN] =
237 			(const uint8_t (*)[ETHER_ADDR_LEN])
238 			priv->mac[mac_index].addr_bytes;
239 	FLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, hash_rxq->type));
240 	struct ibv_flow_attr *attr = &data->attr;
241 	struct ibv_flow_spec_eth *spec = &data->spec;
242 	unsigned int vlan_enabled = !!priv->vlan_filter_n;
243 	unsigned int vlan_id = priv->vlan_filter[vlan_index];
244 
245 	assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
246 	assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));
247 	if (hash_rxq->mac_flow[mac_index][vlan_index] != NULL)
248 		return 0;
249 	/*
250 	 * No padding must be inserted by the compiler between attr and spec.
251 	 * This layout is expected by libibverbs.
252 	 */
253 	assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);
254 	priv_flow_attr(priv, attr, sizeof(data), hash_rxq->type);
255 	/* The first specification must be Ethernet. */
256 	assert(spec->type == IBV_FLOW_SPEC_ETH);
257 	assert(spec->size == sizeof(*spec));
258 	*spec = (struct ibv_flow_spec_eth){
259 		.type = IBV_FLOW_SPEC_ETH,
260 		.size = sizeof(*spec),
261 		.val = {
262 			.dst_mac = {
263 				(*mac)[0], (*mac)[1], (*mac)[2],
264 				(*mac)[3], (*mac)[4], (*mac)[5]
265 			},
266 			.vlan_tag = (vlan_enabled ?
267 				     rte_cpu_to_be_16(vlan_id)
268 				     : 0),
269 		},
270 		.mask = {
271 			.dst_mac = "\xff\xff\xff\xff\xff\xff",
272 			.vlan_tag = (vlan_enabled ?
273 				     rte_cpu_to_be_16(0xfff) :
274 				     0),
275 		},
276 	};
277 	DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u"
278 	      " VLAN index %u filtering %s, ID %u",
279 	      (void *)hash_rxq,
280 	      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
281 	      mac_index,
282 	      vlan_index,
283 	      (vlan_enabled ? "enabled" : "disabled"),
284 	      vlan_id);
285 	/* Create related flow. */
286 	errno = 0;
287 	flow = ibv_create_flow(hash_rxq->qp, attr);
288 	if (flow == NULL) {
289 		/* It's not clear whether errno is always set in this case. */
290 		ERROR("%p: flow configuration failed, errno=%d: %s",
291 		      (void *)hash_rxq, errno,
292 		      (errno ? strerror(errno) : "Unknown error"));
293 		if (errno)
294 			return errno;
295 		return EINVAL;
296 	}
297 	hash_rxq->mac_flow[mac_index][vlan_index] = flow;
298 	return 0;
299 }
300 
301 /**
302  * Register a MAC address in a hash RX queue.
303  *
304  * @param hash_rxq
305  *   Pointer to hash RX queue structure.
306  * @param mac_index
307  *   MAC address index to register.
308  *
309  * @return
310  *   0 on success, errno value on failure.
311  */
312 static int
313 hash_rxq_mac_addr_add(struct hash_rxq *hash_rxq, unsigned int mac_index)
314 {
315 	struct priv *priv = hash_rxq->priv;
316 	unsigned int i = 0;
317 	int ret;
318 
319 	assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
320 	assert(RTE_DIM(hash_rxq->mac_flow[mac_index]) ==
321 	       RTE_DIM(priv->vlan_filter));
322 	/* Add a MAC address for each VLAN filter, or at least once. */
323 	do {
324 		ret = hash_rxq_add_mac_flow(hash_rxq, mac_index, i);
325 		if (ret) {
326 			/* Failure, rollback. */
327 			while (i != 0)
328 				hash_rxq_del_mac_flow(hash_rxq, mac_index,
329 						      --i);
330 			return ret;
331 		}
332 	} while (++i < priv->vlan_filter_n);
333 	return 0;
334 }
335 
336 /**
337  * Register all MAC addresses in a hash RX queue.
338  *
339  * @param hash_rxq
340  *   Pointer to hash RX queue structure.
341  *
342  * @return
343  *   0 on success, errno value on failure.
344  */
345 int
346 hash_rxq_mac_addrs_add(struct hash_rxq *hash_rxq)
347 {
348 	struct priv *priv = hash_rxq->priv;
349 	unsigned int i;
350 	int ret;
351 
352 	assert(RTE_DIM(priv->mac) == RTE_DIM(hash_rxq->mac_flow));
353 	for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
354 		if (!BITFIELD_ISSET(priv->mac_configured, i))
355 			continue;
356 		ret = hash_rxq_mac_addr_add(hash_rxq, i);
357 		if (!ret)
358 			continue;
359 		/* Failure, rollback. */
360 		while (i != 0)
361 			hash_rxq_mac_addr_del(hash_rxq, --i);
362 		assert(ret > 0);
363 		return ret;
364 	}
365 	return 0;
366 }
367 
368 /**
369  * Register a MAC address.
370  *
371  * This is done for each hash RX queue.
372  *
373  * @param priv
374  *   Pointer to private structure.
375  * @param mac_index
376  *   MAC address index to use.
377  * @param mac
378  *   MAC address to register.
379  *
380  * @return
381  *   0 on success, errno value on failure.
382  */
383 int
384 priv_mac_addr_add(struct priv *priv, unsigned int mac_index,
385 		  const uint8_t (*mac)[ETHER_ADDR_LEN])
386 {
387 	unsigned int i;
388 	int ret;
389 
390 	assert(mac_index < RTE_DIM(priv->mac));
391 	/* First, make sure this address isn't already configured. */
392 	for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
393 		/* Skip this index, it's going to be reconfigured. */
394 		if (i == mac_index)
395 			continue;
396 		if (!BITFIELD_ISSET(priv->mac_configured, i))
397 			continue;
398 		if (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac)))
399 			continue;
400 		/* Address already configured elsewhere, return with error. */
401 		return EADDRINUSE;
402 	}
403 	if (BITFIELD_ISSET(priv->mac_configured, mac_index))
404 		priv_mac_addr_del(priv, mac_index);
405 	priv->mac[mac_index] = (struct ether_addr){
406 		{
407 			(*mac)[0], (*mac)[1], (*mac)[2],
408 			(*mac)[3], (*mac)[4], (*mac)[5]
409 		}
410 	};
411 	if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))
412 		goto end;
413 	for (i = 0; (i != priv->hash_rxqs_n); ++i) {
414 		ret = hash_rxq_mac_addr_add(&(*priv->hash_rxqs)[i], mac_index);
415 		if (!ret)
416 			continue;
417 		/* Failure, rollback. */
418 		while (i != 0)
419 			hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[--i],
420 					      mac_index);
421 		return ret;
422 	}
423 end:
424 	BITFIELD_SET(priv->mac_configured, mac_index);
425 	return 0;
426 }
427 
428 /**
429  * Register all MAC addresses in all hash RX queues.
430  *
431  * @param priv
432  *   Pointer to private structure.
433  *
434  * @return
435  *   0 on success, errno value on failure.
436  */
437 int
438 priv_mac_addrs_enable(struct priv *priv)
439 {
440 	unsigned int i;
441 	int ret;
442 
443 	if (priv->isolated)
444 		return 0;
445 	if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))
446 		return 0;
447 	for (i = 0; (i != priv->hash_rxqs_n); ++i) {
448 		ret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]);
449 		if (!ret)
450 			continue;
451 		/* Failure, rollback. */
452 		while (i != 0)
453 			hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]);
454 		assert(ret > 0);
455 		return ret;
456 	}
457 	return 0;
458 }
459 
460 /**
461  * DPDK callback to add a MAC address.
462  *
463  * @param dev
464  *   Pointer to Ethernet device structure.
465  * @param mac_addr
466  *   MAC address to register.
467  * @param index
468  *   MAC address index.
469  * @param vmdq
470  *   VMDq pool index to associate address with (ignored).
471  */
472 int
473 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
474 		  uint32_t index, uint32_t vmdq)
475 {
476 	struct priv *priv = dev->data->dev_private;
477 	int re;
478 
479 	if (mlx5_is_secondary())
480 		return -ENOTSUP;
481 
482 	(void)vmdq;
483 	priv_lock(priv);
484 	DEBUG("%p: adding MAC address at index %" PRIu32,
485 	      (void *)dev, index);
486 	if (index >= RTE_DIM(priv->mac)) {
487 		re = EINVAL;
488 		goto end;
489 	}
490 	re = priv_mac_addr_add(priv, index,
491 			       (const uint8_t (*)[ETHER_ADDR_LEN])
492 			       mac_addr->addr_bytes);
493 end:
494 	priv_unlock(priv);
495 	return -re;
496 }
497 
498 /**
499  * DPDK callback to set primary MAC address.
500  *
501  * @param dev
502  *   Pointer to Ethernet device structure.
503  * @param mac_addr
504  *   MAC address to register.
505  */
506 void
507 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
508 {
509 	DEBUG("%p: setting primary MAC address", (void *)dev);
510 	mlx5_mac_addr_remove(dev, 0);
511 	mlx5_mac_addr_add(dev, mac_addr, 0, 0);
512 }
513