net/mlx5: fix VF MAC address set over BlueField
[dpdk.git] / drivers / net / mlx5 / mlx5_mac.c
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 }