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