xref: /dpdk/drivers/net/mlx5/mlx5_mac.c (revision f5057be340e44f3edc0fe90fa875eb89a4c49b4f)
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 #include <netinet/in.h>
12 
13 #include <rte_ether.h>
14 #include <rte_ethdev_driver.h>
15 #include <rte_common.h>
16 
17 #include "mlx5_defs.h"
18 #include "mlx5.h"
19 #include "mlx5_utils.h"
20 #include "mlx5_rxtx.h"
21 
22 /**
23  * Remove a MAC address from the internal array.
24  *
25  * @param dev
26  *   Pointer to Ethernet device structure.
27  * @param index
28  *   MAC address index.
29  */
30 static void
31 mlx5_internal_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
32 {
33 	MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
34 	if (rte_is_zero_ether_addr(&dev->data->mac_addrs[index]))
35 		return;
36 	mlx5_os_mac_addr_remove(dev, index);
37 	memset(&dev->data->mac_addrs[index], 0, sizeof(struct rte_ether_addr));
38 }
39 
40 /**
41  * Adds a MAC address to the internal array.
42  *
43  * @param dev
44  *   Pointer to Ethernet device structure.
45  * @param mac_addr
46  *   MAC address to register.
47  * @param index
48  *   MAC address index.
49  *
50  * @return
51  *   0 on success, a negative errno value otherwise and rte_errno is set.
52  */
53 static int
54 mlx5_internal_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
55 			   uint32_t index)
56 {
57 	unsigned int i;
58 	int ret;
59 
60 	MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
61 	if (rte_is_zero_ether_addr(mac)) {
62 		rte_errno = EINVAL;
63 		return -rte_errno;
64 	}
65 	/* First, make sure this address isn't already configured. */
66 	for (i = 0; (i != MLX5_MAX_MAC_ADDRESSES); ++i) {
67 		/* Skip this index, it's going to be reconfigured. */
68 		if (i == index)
69 			continue;
70 		if (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac)))
71 			continue;
72 		/* Address already configured elsewhere, return with error. */
73 		rte_errno = EADDRINUSE;
74 		return -rte_errno;
75 	}
76 	ret = mlx5_os_mac_addr_add(dev, mac, index);
77 	if (ret)
78 		return ret;
79 
80 	dev->data->mac_addrs[index] = *mac;
81 	return 0;
82 }
83 
84 /**
85  * DPDK callback to remove a MAC address.
86  *
87  * @param dev
88  *   Pointer to Ethernet device structure.
89  * @param index
90  *   MAC address index.
91  */
92 void
93 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
94 {
95 	int ret;
96 
97 	if (index >= MLX5_MAX_UC_MAC_ADDRESSES)
98 		return;
99 	mlx5_internal_mac_addr_remove(dev, index);
100 	if (!dev->data->promiscuous) {
101 		ret = mlx5_traffic_restart(dev);
102 		if (ret)
103 			DRV_LOG(ERR, "port %u cannot restart traffic: %s",
104 				dev->data->port_id, strerror(rte_errno));
105 	}
106 }
107 
108 /**
109  * DPDK callback to add a MAC address.
110  *
111  * @param dev
112  *   Pointer to Ethernet device structure.
113  * @param mac_addr
114  *   MAC address to register.
115  * @param index
116  *   MAC address index.
117  * @param vmdq
118  *   VMDq pool index to associate address with (ignored).
119  *
120  * @return
121  *   0 on success, a negative errno value otherwise and rte_errno is set.
122  */
123 int
124 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
125 		  uint32_t index, uint32_t vmdq __rte_unused)
126 {
127 	int ret;
128 
129 	if (index >= MLX5_MAX_UC_MAC_ADDRESSES) {
130 		rte_errno = EINVAL;
131 		return -rte_errno;
132 	}
133 	ret = mlx5_internal_mac_addr_add(dev, mac, index);
134 	if (ret < 0)
135 		return ret;
136 	if (!dev->data->promiscuous)
137 		return mlx5_traffic_restart(dev);
138 	return 0;
139 }
140 
141 /**
142  * DPDK callback to set primary MAC address.
143  *
144  * @param dev
145  *   Pointer to Ethernet device structure.
146  * @param mac_addr
147  *   MAC address to register.
148  *
149  * @return
150  *   0 on success, a negative errno value otherwise and rte_errno is set.
151  */
152 int
153 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
154 {
155 	uint16_t port_id;
156 	struct mlx5_priv *priv = dev->data->dev_private;
157 
158 	/*
159 	 * Configuring the VF instead of its representor,
160 	 * need to skip the special case of HPF on Bluefield.
161 	 */
162 	if (priv->representor && priv->representor_id >= 0) {
163 		DRV_LOG(DEBUG, "VF represented by port %u setting primary MAC address",
164 			dev->data->port_id);
165 		RTE_ETH_FOREACH_DEV_SIBLING(port_id, dev->data->port_id) {
166 			priv = rte_eth_devices[port_id].data->dev_private;
167 			if (priv->master == 1) {
168 				priv = dev->data->dev_private;
169 				return mlx5_os_vf_mac_addr_modify
170 				       (priv,
171 					mlx5_ifindex(&rte_eth_devices[port_id]),
172 					mac_addr, priv->representor_id);
173 			}
174 		}
175 		rte_errno = -ENOTSUP;
176 		return rte_errno;
177 	}
178 
179 	DRV_LOG(DEBUG, "port %u setting primary MAC address",
180 		dev->data->port_id);
181 	return mlx5_mac_addr_add(dev, mac_addr, 0, 0);
182 }
183 
184 /**
185  * DPDK callback to set multicast addresses list.
186  *
187  * @see rte_eth_dev_set_mc_addr_list()
188  */
189 int
190 mlx5_set_mc_addr_list(struct rte_eth_dev *dev,
191 		      struct rte_ether_addr *mc_addr_set, uint32_t nb_mc_addr)
192 {
193 	uint32_t i;
194 	int ret;
195 
196 	if (nb_mc_addr >= MLX5_MAX_MC_MAC_ADDRESSES) {
197 		rte_errno = ENOSPC;
198 		return -rte_errno;
199 	}
200 	for (i = MLX5_MAX_UC_MAC_ADDRESSES; i != MLX5_MAX_MAC_ADDRESSES; ++i)
201 		mlx5_internal_mac_addr_remove(dev, i);
202 	i = MLX5_MAX_UC_MAC_ADDRESSES;
203 	while (nb_mc_addr--) {
204 		ret = mlx5_internal_mac_addr_add(dev, mc_addr_set++, i++);
205 		if (ret)
206 			return ret;
207 	}
208 	if (!dev->data->promiscuous)
209 		return mlx5_traffic_restart(dev);
210 	return 0;
211 }
212