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 <assert.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <inttypes.h> 11 #include <errno.h> 12 #include <netinet/in.h> 13 #include <sys/ioctl.h> 14 #include <arpa/inet.h> 15 16 /* Verbs header. */ 17 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 18 #ifdef PEDANTIC 19 #pragma GCC diagnostic ignored "-Wpedantic" 20 #endif 21 #include <infiniband/verbs.h> 22 #ifdef PEDANTIC 23 #pragma GCC diagnostic error "-Wpedantic" 24 #endif 25 26 #include <rte_ether.h> 27 #include <rte_ethdev_driver.h> 28 #include <rte_common.h> 29 30 #include "mlx5.h" 31 #include "mlx5_utils.h" 32 #include "mlx5_rxtx.h" 33 #include "mlx5_defs.h" 34 35 /** 36 * Get MAC address by querying netdevice. 37 * 38 * @param[in] dev 39 * Pointer to Ethernet device. 40 * @param[out] mac 41 * MAC address output buffer. 42 * 43 * @return 44 * 0 on success, a negative errno value otherwise and rte_errno is set. 45 */ 46 int 47 mlx5_get_mac(struct rte_eth_dev *dev, uint8_t (*mac)[RTE_ETHER_ADDR_LEN]) 48 { 49 struct ifreq request; 50 int ret; 51 52 ret = mlx5_ifreq(dev, SIOCGIFHWADDR, &request); 53 if (ret) 54 return ret; 55 memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN); 56 return 0; 57 } 58 59 /** 60 * Remove a MAC address from the internal array. 61 * 62 * @param dev 63 * Pointer to Ethernet device structure. 64 * @param index 65 * MAC address index. 66 */ 67 static void 68 mlx5_internal_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 69 { 70 struct mlx5_priv *priv = dev->data->dev_private; 71 const int vf = priv->config.vf; 72 73 assert(index < MLX5_MAX_MAC_ADDRESSES); 74 if (rte_is_zero_ether_addr(&dev->data->mac_addrs[index])) 75 return; 76 if (vf) 77 mlx5_nl_mac_addr_remove(dev, &dev->data->mac_addrs[index], 78 index); 79 memset(&dev->data->mac_addrs[index], 0, sizeof(struct rte_ether_addr)); 80 } 81 82 /** 83 * Adds a MAC address to the internal array. 84 * 85 * @param dev 86 * Pointer to Ethernet device structure. 87 * @param mac_addr 88 * MAC address to register. 89 * @param index 90 * MAC address index. 91 * 92 * @return 93 * 0 on success, a negative errno value otherwise and rte_errno is set. 94 */ 95 static int 96 mlx5_internal_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac, 97 uint32_t index) 98 { 99 struct mlx5_priv *priv = dev->data->dev_private; 100 const int vf = priv->config.vf; 101 unsigned int i; 102 103 assert(index < MLX5_MAX_MAC_ADDRESSES); 104 if (rte_is_zero_ether_addr(mac)) { 105 rte_errno = EINVAL; 106 return -rte_errno; 107 } 108 /* First, make sure this address isn't already configured. */ 109 for (i = 0; (i != MLX5_MAX_MAC_ADDRESSES); ++i) { 110 /* Skip this index, it's going to be reconfigured. */ 111 if (i == index) 112 continue; 113 if (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac))) 114 continue; 115 /* Address already configured elsewhere, return with error. */ 116 rte_errno = EADDRINUSE; 117 return -rte_errno; 118 } 119 if (vf) { 120 int ret = mlx5_nl_mac_addr_add(dev, mac, index); 121 122 if (ret) 123 return ret; 124 } 125 dev->data->mac_addrs[index] = *mac; 126 return 0; 127 } 128 129 /** 130 * DPDK callback to remove a MAC address. 131 * 132 * @param dev 133 * Pointer to Ethernet device structure. 134 * @param index 135 * MAC address index. 136 */ 137 void 138 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 139 { 140 int ret; 141 142 if (index >= MLX5_MAX_UC_MAC_ADDRESSES) 143 return; 144 mlx5_internal_mac_addr_remove(dev, index); 145 if (!dev->data->promiscuous) { 146 ret = mlx5_traffic_restart(dev); 147 if (ret) 148 DRV_LOG(ERR, "port %u cannot restart traffic: %s", 149 dev->data->port_id, strerror(rte_errno)); 150 } 151 } 152 153 /** 154 * DPDK callback to add a MAC address. 155 * 156 * @param dev 157 * Pointer to Ethernet device structure. 158 * @param mac_addr 159 * MAC address to register. 160 * @param index 161 * MAC address index. 162 * @param vmdq 163 * VMDq pool index to associate address with (ignored). 164 * 165 * @return 166 * 0 on success, a negative errno value otherwise and rte_errno is set. 167 */ 168 int 169 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac, 170 uint32_t index, uint32_t vmdq __rte_unused) 171 { 172 int ret; 173 174 if (index >= MLX5_MAX_UC_MAC_ADDRESSES) { 175 rte_errno = EINVAL; 176 return -rte_errno; 177 } 178 ret = mlx5_internal_mac_addr_add(dev, mac, index); 179 if (ret < 0) 180 return ret; 181 if (!dev->data->promiscuous) 182 return mlx5_traffic_restart(dev); 183 return 0; 184 } 185 186 /** 187 * DPDK callback to set primary MAC address. 188 * 189 * @param dev 190 * Pointer to Ethernet device structure. 191 * @param mac_addr 192 * MAC address to register. 193 * 194 * @return 195 * 0 on success, a negative errno value otherwise and rte_errno is set. 196 */ 197 int 198 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr) 199 { 200 DRV_LOG(DEBUG, "port %u setting primary MAC address", 201 dev->data->port_id); 202 return mlx5_mac_addr_add(dev, mac_addr, 0, 0); 203 } 204 205 /** 206 * DPDK callback to set multicast addresses list. 207 * 208 * @see rte_eth_dev_set_mc_addr_list() 209 */ 210 int 211 mlx5_set_mc_addr_list(struct rte_eth_dev *dev, 212 struct rte_ether_addr *mc_addr_set, uint32_t nb_mc_addr) 213 { 214 uint32_t i; 215 int ret; 216 217 if (nb_mc_addr >= MLX5_MAX_MC_MAC_ADDRESSES) { 218 rte_errno = ENOSPC; 219 return -rte_errno; 220 } 221 for (i = MLX5_MAX_UC_MAC_ADDRESSES; i != MLX5_MAX_MAC_ADDRESSES; ++i) 222 mlx5_internal_mac_addr_remove(dev, i); 223 i = MLX5_MAX_UC_MAC_ADDRESSES; 224 while (nb_mc_addr--) { 225 ret = mlx5_internal_mac_addr_add(dev, mc_addr_set++, i++); 226 if (ret) 227 return ret; 228 } 229 if (!dev->data->promiscuous) 230 return mlx5_traffic_restart(dev); 231 return 0; 232 } 233