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