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