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 */
81int
82priv_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 */
102static void
103hash_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 */
135static void
136hash_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 */
151void
152hash_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 */
170static void
171priv_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 */
189void
190priv_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 */
206void
207mlx5_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);
220end:
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 */
237static int
238hash_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 */
315static int
316hash_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 */
348int
349hash_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 */
386int
387priv_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	}
426end:
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 */
440int
441priv_mac_addrs_enable(struct priv *priv)
442{
443	unsigned int i;
444	int ret;
445
446	if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))
447		return 0;
448	for (i = 0; (i != priv->hash_rxqs_n); ++i) {
449		ret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]);
450		if (!ret)
451			continue;
452		/* Failure, rollback. */
453		while (i != 0)
454			hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]);
455		assert(ret > 0);
456		return ret;
457	}
458	return 0;
459}
460
461/**
462 * DPDK callback to add a MAC address.
463 *
464 * @param dev
465 *   Pointer to Ethernet device structure.
466 * @param mac_addr
467 *   MAC address to register.
468 * @param index
469 *   MAC address index.
470 * @param vmdq
471 *   VMDq pool index to associate address with (ignored).
472 */
473void
474mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
475		  uint32_t index, uint32_t vmdq)
476{
477	struct priv *priv = dev->data->dev_private;
478
479	if (mlx5_is_secondary())
480		return;
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		goto end;
488	priv_mac_addr_add(priv, index,
489			  (const uint8_t (*)[ETHER_ADDR_LEN])
490			  mac_addr->addr_bytes);
491end:
492	priv_unlock(priv);
493}
494
495/**
496 * DPDK callback to set primary MAC address.
497 *
498 * @param dev
499 *   Pointer to Ethernet device structure.
500 * @param mac_addr
501 *   MAC address to register.
502 */
503void
504mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
505{
506	DEBUG("%p: setting primary MAC address", (void *)dev);
507	mlx5_mac_addr_remove(dev, 0);
508	mlx5_mac_addr_add(dev, mac_addr, 0, 0);
509}
510