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