xref: /dpdk/drivers/net/mlx5/mlx5_mac.c (revision 465328609aeca77f455175b12440233dbcc5a826)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2015 6WIND S.A.
3  * Copyright 2015 Mellanox Technologies, Ltd
4  */
5 
6 #include <stddef.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <inttypes.h>
10 #include <errno.h>
11 
12 #include <rte_ether.h>
13 #include <ethdev_driver.h>
14 #include <rte_common.h>
15 
16 #include "mlx5_defs.h"
17 #include "mlx5.h"
18 #include "mlx5_utils.h"
19 #include "mlx5_rxtx.h"
20 
21 /**
22  * Remove a MAC address from the internal array.
23  *
24  * @param dev
25  *   Pointer to Ethernet device structure.
26  * @param index
27  *   MAC address index.
28  * @param addr
29  *   If MAC address is actually removed, it will be stored here if pointer is not a NULL.
30  *
31  * @return
32  *   True if there was a MAC address under given index.
33  */
34 static bool
35 mlx5_internal_mac_addr_remove(struct rte_eth_dev *dev,
36 			      uint32_t index,
37 			      struct rte_ether_addr *addr)
38 {
39 	MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
40 	if (rte_is_zero_ether_addr(&dev->data->mac_addrs[index]))
41 		return false;
42 	mlx5_os_mac_addr_remove(dev, index);
43 	if (addr != NULL)
44 		*addr = dev->data->mac_addrs[index];
45 	memset(&dev->data->mac_addrs[index], 0, sizeof(struct rte_ether_addr));
46 	return true;
47 }
48 
49 /**
50  * Adds a MAC address to the internal array.
51  *
52  * @param dev
53  *   Pointer to Ethernet device structure.
54  * @param mac_addr
55  *   MAC address to register.
56  * @param index
57  *   MAC address index.
58  *
59  * @return
60  *   0 on success, a negative errno value otherwise and rte_errno is set.
61  */
62 static int
63 mlx5_internal_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
64 			   uint32_t index)
65 {
66 	unsigned int i;
67 	int ret;
68 
69 	MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
70 	if (rte_is_zero_ether_addr(mac)) {
71 		rte_errno = EINVAL;
72 		return -rte_errno;
73 	}
74 	/* First, make sure this address isn't already configured. */
75 	for (i = 0; (i != MLX5_MAX_MAC_ADDRESSES); ++i) {
76 		/* Skip this index, it's going to be reconfigured. */
77 		if (i == index)
78 			continue;
79 		if (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac)))
80 			continue;
81 		/* Address already configured elsewhere, return with error. */
82 		rte_errno = EADDRINUSE;
83 		return -rte_errno;
84 	}
85 	ret = mlx5_os_mac_addr_add(dev, mac, index);
86 	if (ret)
87 		return ret;
88 
89 	dev->data->mac_addrs[index] = *mac;
90 	return 0;
91 }
92 
93 /**
94  * DPDK callback to remove a MAC address.
95  *
96  * @param dev
97  *   Pointer to Ethernet device structure.
98  * @param index
99  *   MAC address index.
100  */
101 void
102 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
103 {
104 	struct rte_ether_addr addr = { 0 };
105 	int ret;
106 
107 	if (index >= MLX5_MAX_UC_MAC_ADDRESSES)
108 		return;
109 	if (mlx5_internal_mac_addr_remove(dev, index, &addr)) {
110 		ret = mlx5_traffic_mac_remove(dev, &addr);
111 		if (ret)
112 			DRV_LOG(ERR, "port %u cannot update control flow rules: %s",
113 				dev->data->port_id, strerror(rte_errno));
114 	}
115 }
116 
117 /**
118  * DPDK callback to add a MAC address.
119  *
120  * @param dev
121  *   Pointer to Ethernet device structure.
122  * @param mac_addr
123  *   MAC address to register.
124  * @param index
125  *   MAC address index.
126  * @param vmdq
127  *   VMDq pool index to associate address with (ignored).
128  *
129  * @return
130  *   0 on success, a negative errno value otherwise and rte_errno is set.
131  */
132 int
133 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
134 		  uint32_t index, uint32_t vmdq __rte_unused)
135 {
136 	int ret;
137 
138 	if (index >= MLX5_MAX_UC_MAC_ADDRESSES) {
139 		rte_errno = EINVAL;
140 		return -rte_errno;
141 	}
142 	ret = mlx5_internal_mac_addr_add(dev, mac, index);
143 	if (ret < 0)
144 		return ret;
145 	return mlx5_traffic_mac_add(dev, mac);
146 }
147 
148 /**
149  * DPDK callback to set primary MAC address.
150  *
151  * @param dev
152  *   Pointer to Ethernet device structure.
153  * @param mac_addr
154  *   MAC address to register.
155  *
156  * @return
157  *   0 on success, a negative errno value otherwise and rte_errno is set.
158  */
159 int
160 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
161 {
162 	uint16_t port_id;
163 	struct mlx5_priv *priv = dev->data->dev_private;
164 	struct mlx5_priv *pf_priv;
165 	struct rte_ether_addr old_mac_addr = dev->data->mac_addrs[0];
166 	int ret;
167 
168 	/* ethdev does not check if new default address is the same as the old one. */
169 	if (rte_is_same_ether_addr(mac_addr, &old_mac_addr))
170 		return 0;
171 
172 	/*
173 	 * Configuring the VF instead of its representor,
174 	 * need to skip the special cases:
175 	 * - HPF on BlueField,
176 	 * - SF representors,
177 	 * - uplink ports when running in MPESW mode.
178 	 */
179 	if (priv->representor && !mlx5_is_hpf(dev) && !mlx5_is_sf_repr(dev) &&
180 	    !priv->mpesw_uplink) {
181 		DRV_LOG(DEBUG, "VF represented by port %u setting primary MAC address",
182 			dev->data->port_id);
183 		if (priv->pf_bond >= 0) {
184 			/* Bonding, get owner PF ifindex from shared data. */
185 			return mlx5_os_vf_mac_addr_modify
186 			       (priv,
187 				priv->sh->bond.ports[priv->pf_bond].ifindex,
188 				mac_addr,
189 				MLX5_REPRESENTOR_REPR(priv->representor_id));
190 		}
191 		RTE_ETH_FOREACH_DEV_SIBLING(port_id, dev->data->port_id) {
192 			pf_priv = rte_eth_devices[port_id].data->dev_private;
193 			if (pf_priv->master == 1)
194 				return mlx5_os_vf_mac_addr_modify
195 				       (priv, pf_priv->if_index, mac_addr,
196 					MLX5_REPRESENTOR_REPR
197 						(priv->representor_id));
198 		}
199 		rte_errno = -ENOTSUP;
200 		return rte_errno;
201 	}
202 
203 	DRV_LOG(DEBUG, "port %u setting primary MAC address",
204 		dev->data->port_id);
205 	ret = mlx5_mac_addr_add(dev, mac_addr, 0, 0);
206 	if (ret)
207 		return ret;
208 	return mlx5_traffic_mac_remove(dev, &old_mac_addr);
209 }
210 
211 /**
212  * DPDK callback to set multicast addresses list.
213  *
214  * @see rte_eth_dev_set_mc_addr_list()
215  */
216 int
217 mlx5_set_mc_addr_list(struct rte_eth_dev *dev,
218 		      struct rte_ether_addr *mc_addr_set, uint32_t nb_mc_addr)
219 {
220 	uint32_t i;
221 	int ret;
222 
223 	if (nb_mc_addr >= MLX5_MAX_MC_MAC_ADDRESSES) {
224 		rte_errno = ENOSPC;
225 		return -rte_errno;
226 	}
227 	for (i = MLX5_MAX_UC_MAC_ADDRESSES; i != MLX5_MAX_MAC_ADDRESSES; ++i)
228 		mlx5_internal_mac_addr_remove(dev, i, NULL);
229 	i = MLX5_MAX_UC_MAC_ADDRESSES;
230 	while (nb_mc_addr--) {
231 		ret = mlx5_internal_mac_addr_add(dev, mc_addr_set++, i++);
232 		if (ret)
233 			return ret;
234 	}
235 	if (!dev->data->promiscuous)
236 		return mlx5_traffic_restart(dev);
237 	return 0;
238 }
239