1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2015 6WIND S.A. 5 * Copyright 2015 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stddef.h> 35 #include <assert.h> 36 #include <stdint.h> 37 #include <string.h> 38 #include <inttypes.h> 39 #include <errno.h> 40 #include <netinet/in.h> 41 #include <linux/if.h> 42 #include <sys/ioctl.h> 43 #include <arpa/inet.h> 44 45 /* Verbs header. */ 46 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 47 #ifdef PEDANTIC 48 #pragma GCC diagnostic ignored "-pedantic" 49 #endif 50 #include <infiniband/verbs.h> 51 #ifdef PEDANTIC 52 #pragma GCC diagnostic error "-pedantic" 53 #endif 54 55 /* DPDK headers don't like -pedantic. */ 56 #ifdef PEDANTIC 57 #pragma GCC diagnostic ignored "-pedantic" 58 #endif 59 #include <rte_ether.h> 60 #include <rte_ethdev.h> 61 #include <rte_common.h> 62 #ifdef PEDANTIC 63 #pragma GCC diagnostic error "-pedantic" 64 #endif 65 66 #include "mlx5.h" 67 #include "mlx5_utils.h" 68 #include "mlx5_rxtx.h" 69 #include "mlx5_defs.h" 70 71 /** 72 * Get MAC address by querying netdevice. 73 * 74 * @param[in] priv 75 * struct priv for the requested device. 76 * @param[out] mac 77 * MAC address output buffer. 78 * 79 * @return 80 * 0 on success, -1 on failure and errno is set. 81 */ 82 int 83 priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN]) 84 { 85 struct ifreq request; 86 87 if (priv_ifreq(priv, SIOCGIFHWADDR, &request)) 88 return -1; 89 memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); 90 return 0; 91 } 92 93 /** 94 * Delete MAC flow steering rule. 95 * 96 * @param hash_rxq 97 * Pointer to hash RX queue structure. 98 * @param mac_index 99 * MAC address index. 100 * @param vlan_index 101 * VLAN index to use. 102 */ 103 static void 104 hash_rxq_del_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index, 105 unsigned int vlan_index) 106 { 107 #ifndef NDEBUG 108 const uint8_t (*mac)[ETHER_ADDR_LEN] = 109 (const uint8_t (*)[ETHER_ADDR_LEN]) 110 hash_rxq->priv->mac[mac_index].addr_bytes; 111 #endif 112 113 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 114 assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index])); 115 if (hash_rxq->mac_flow[mac_index][vlan_index] == NULL) 116 return; 117 DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" 118 " VLAN index %u", 119 (void *)hash_rxq, 120 (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], 121 mac_index, 122 vlan_index); 123 claim_zero(ibv_destroy_flow(hash_rxq->mac_flow 124 [mac_index][vlan_index])); 125 hash_rxq->mac_flow[mac_index][vlan_index] = NULL; 126 } 127 128 /** 129 * Unregister a MAC address from a hash RX queue. 130 * 131 * @param hash_rxq 132 * Pointer to hash RX queue structure. 133 * @param mac_index 134 * MAC address index. 135 */ 136 static void 137 hash_rxq_mac_addr_del(struct hash_rxq *hash_rxq, unsigned int mac_index) 138 { 139 unsigned int i; 140 141 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 142 for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow[mac_index])); ++i) 143 hash_rxq_del_mac_flow(hash_rxq, mac_index, i); 144 } 145 146 /** 147 * Unregister all MAC addresses from a hash RX queue. 148 * 149 * @param hash_rxq 150 * Pointer to hash RX queue structure. 151 */ 152 void 153 hash_rxq_mac_addrs_del(struct hash_rxq *hash_rxq) 154 { 155 unsigned int i; 156 157 for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow)); ++i) 158 hash_rxq_mac_addr_del(hash_rxq, i); 159 } 160 161 /** 162 * Unregister a MAC address. 163 * 164 * This is done for each hash RX queue. 165 * 166 * @param priv 167 * Pointer to private structure. 168 * @param mac_index 169 * MAC address index. 170 */ 171 static void 172 priv_mac_addr_del(struct priv *priv, unsigned int mac_index) 173 { 174 unsigned int i; 175 176 assert(mac_index < RTE_DIM(priv->mac)); 177 if (!BITFIELD_ISSET(priv->mac_configured, mac_index)) 178 return; 179 for (i = 0; (i != priv->hash_rxqs_n); ++i) 180 hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[i], mac_index); 181 BITFIELD_RESET(priv->mac_configured, mac_index); 182 } 183 184 /** 185 * Unregister all MAC addresses from all hash RX queues. 186 * 187 * @param priv 188 * Pointer to private structure. 189 */ 190 void 191 priv_mac_addrs_disable(struct priv *priv) 192 { 193 unsigned int i; 194 195 for (i = 0; (i != priv->hash_rxqs_n); ++i) 196 hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[i]); 197 } 198 199 /** 200 * DPDK callback to remove a MAC address. 201 * 202 * @param dev 203 * Pointer to Ethernet device structure. 204 * @param index 205 * MAC address index. 206 */ 207 void 208 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 209 { 210 struct priv *priv = dev->data->dev_private; 211 212 priv_lock(priv); 213 DEBUG("%p: removing MAC address from index %" PRIu32, 214 (void *)dev, index); 215 /* Last array entry is reserved for broadcast. */ 216 if (index >= (RTE_DIM(priv->mac) - 1)) 217 goto end; 218 priv_mac_addr_del(priv, index); 219 end: 220 priv_unlock(priv); 221 } 222 223 /** 224 * Add MAC flow steering rule. 225 * 226 * @param hash_rxq 227 * Pointer to hash RX queue structure. 228 * @param mac_index 229 * MAC address index to register. 230 * @param vlan_index 231 * VLAN index to use. 232 * 233 * @return 234 * 0 on success, errno value on failure. 235 */ 236 static int 237 hash_rxq_add_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index, 238 unsigned int vlan_index) 239 { 240 struct ibv_flow *flow; 241 struct priv *priv = hash_rxq->priv; 242 const uint8_t (*mac)[ETHER_ADDR_LEN] = 243 (const uint8_t (*)[ETHER_ADDR_LEN]) 244 priv->mac[mac_index].addr_bytes; 245 FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0)); 246 struct ibv_flow_attr *attr = &data->attr; 247 struct ibv_flow_spec_eth *spec = &data->spec; 248 unsigned int vlan_enabled = !!priv->vlan_filter_n; 249 unsigned int vlan_id = priv->vlan_filter[vlan_index]; 250 251 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 252 assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index])); 253 if (hash_rxq->mac_flow[mac_index][vlan_index] != NULL) 254 return 0; 255 /* 256 * No padding must be inserted by the compiler between attr and spec. 257 * This layout is expected by libibverbs. 258 */ 259 assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec); 260 hash_rxq_flow_attr(hash_rxq, attr, sizeof(data)); 261 /* The first specification must be Ethernet. */ 262 assert(spec->type == IBV_FLOW_SPEC_ETH); 263 assert(spec->size == sizeof(*spec)); 264 *spec = (struct ibv_flow_spec_eth){ 265 .type = IBV_FLOW_SPEC_ETH, 266 .size = sizeof(*spec), 267 .val = { 268 .dst_mac = { 269 (*mac)[0], (*mac)[1], (*mac)[2], 270 (*mac)[3], (*mac)[4], (*mac)[5] 271 }, 272 .vlan_tag = (vlan_enabled ? htons(vlan_id) : 0), 273 }, 274 .mask = { 275 .dst_mac = "\xff\xff\xff\xff\xff\xff", 276 .vlan_tag = (vlan_enabled ? htons(0xfff) : 0), 277 }, 278 }; 279 DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" 280 " VLAN index %u filtering %s, ID %u", 281 (void *)hash_rxq, 282 (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], 283 mac_index, 284 vlan_index, 285 (vlan_enabled ? "enabled" : "disabled"), 286 vlan_id); 287 /* Create related flow. */ 288 errno = 0; 289 flow = ibv_create_flow(hash_rxq->qp, attr); 290 if (flow == NULL) { 291 /* It's not clear whether errno is always set in this case. */ 292 ERROR("%p: flow configuration failed, errno=%d: %s", 293 (void *)hash_rxq, errno, 294 (errno ? strerror(errno) : "Unknown error")); 295 if (errno) 296 return errno; 297 return EINVAL; 298 } 299 hash_rxq->mac_flow[mac_index][vlan_index] = flow; 300 return 0; 301 } 302 303 /** 304 * Register a MAC address in a hash RX queue. 305 * 306 * @param hash_rxq 307 * Pointer to hash RX queue structure. 308 * @param mac_index 309 * MAC address index to register. 310 * 311 * @return 312 * 0 on success, errno value on failure. 313 */ 314 static int 315 hash_rxq_mac_addr_add(struct hash_rxq *hash_rxq, unsigned int mac_index) 316 { 317 struct priv *priv = hash_rxq->priv; 318 unsigned int i = 0; 319 int ret; 320 321 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 322 assert(RTE_DIM(hash_rxq->mac_flow[mac_index]) == 323 RTE_DIM(priv->vlan_filter)); 324 /* Add a MAC address for each VLAN filter, or at least once. */ 325 do { 326 ret = hash_rxq_add_mac_flow(hash_rxq, mac_index, i); 327 if (ret) { 328 /* Failure, rollback. */ 329 while (i != 0) 330 hash_rxq_del_mac_flow(hash_rxq, mac_index, 331 --i); 332 return ret; 333 } 334 } while (++i < priv->vlan_filter_n); 335 return 0; 336 } 337 338 /** 339 * Register all MAC addresses in a hash RX queue. 340 * 341 * @param hash_rxq 342 * Pointer to hash RX queue structure. 343 * 344 * @return 345 * 0 on success, errno value on failure. 346 */ 347 int 348 hash_rxq_mac_addrs_add(struct hash_rxq *hash_rxq) 349 { 350 struct priv *priv = hash_rxq->priv; 351 unsigned int i; 352 int ret; 353 354 assert(RTE_DIM(priv->mac) == RTE_DIM(hash_rxq->mac_flow)); 355 for (i = 0; (i != RTE_DIM(priv->mac)); ++i) { 356 if (!BITFIELD_ISSET(priv->mac_configured, i)) 357 continue; 358 ret = hash_rxq_mac_addr_add(hash_rxq, i); 359 if (!ret) 360 continue; 361 /* Failure, rollback. */ 362 while (i != 0) 363 hash_rxq_mac_addr_del(hash_rxq, --i); 364 assert(ret > 0); 365 return ret; 366 } 367 return 0; 368 } 369 370 /** 371 * Register a MAC address. 372 * 373 * This is done for each hash RX queue. 374 * 375 * @param priv 376 * Pointer to private structure. 377 * @param mac_index 378 * MAC address index to use. 379 * @param mac 380 * MAC address to register. 381 * 382 * @return 383 * 0 on success, errno value on failure. 384 */ 385 int 386 priv_mac_addr_add(struct priv *priv, unsigned int mac_index, 387 const uint8_t (*mac)[ETHER_ADDR_LEN]) 388 { 389 unsigned int i; 390 int ret; 391 392 assert(mac_index < RTE_DIM(priv->mac)); 393 /* First, make sure this address isn't already configured. */ 394 for (i = 0; (i != RTE_DIM(priv->mac)); ++i) { 395 /* Skip this index, it's going to be reconfigured. */ 396 if (i == mac_index) 397 continue; 398 if (!BITFIELD_ISSET(priv->mac_configured, i)) 399 continue; 400 if (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac))) 401 continue; 402 /* Address already configured elsewhere, return with error. */ 403 return EADDRINUSE; 404 } 405 if (BITFIELD_ISSET(priv->mac_configured, mac_index)) 406 priv_mac_addr_del(priv, mac_index); 407 priv->mac[mac_index] = (struct ether_addr){ 408 { 409 (*mac)[0], (*mac)[1], (*mac)[2], 410 (*mac)[3], (*mac)[4], (*mac)[5] 411 } 412 }; 413 for (i = 0; (i != priv->hash_rxqs_n); ++i) { 414 ret = hash_rxq_mac_addr_add(&(*priv->hash_rxqs)[i], mac_index); 415 if (!ret) 416 continue; 417 /* Failure, rollback. */ 418 while (i != 0) 419 hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[--i], 420 mac_index); 421 return ret; 422 } 423 BITFIELD_SET(priv->mac_configured, mac_index); 424 return 0; 425 } 426 427 /** 428 * Register all MAC addresses in all hash RX queues. 429 * 430 * @param priv 431 * Pointer to private structure. 432 * 433 * @return 434 * 0 on success, errno value on failure. 435 */ 436 int 437 priv_mac_addrs_enable(struct priv *priv) 438 { 439 unsigned int i; 440 int ret; 441 442 for (i = 0; (i != priv->hash_rxqs_n); ++i) { 443 ret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]); 444 if (!ret) 445 continue; 446 /* Failure, rollback. */ 447 while (i != 0) 448 hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]); 449 assert(ret > 0); 450 return ret; 451 } 452 return 0; 453 } 454 455 /** 456 * DPDK callback to add a MAC address. 457 * 458 * @param dev 459 * Pointer to Ethernet device structure. 460 * @param mac_addr 461 * MAC address to register. 462 * @param index 463 * MAC address index. 464 * @param vmdq 465 * VMDq pool index to associate address with (ignored). 466 */ 467 void 468 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr, 469 uint32_t index, uint32_t vmdq) 470 { 471 struct priv *priv = dev->data->dev_private; 472 473 (void)vmdq; 474 priv_lock(priv); 475 DEBUG("%p: adding MAC address at index %" PRIu32, 476 (void *)dev, index); 477 /* Last array entry is reserved for broadcast. */ 478 if (index >= (RTE_DIM(priv->mac) - 1)) 479 goto end; 480 priv_mac_addr_add(priv, index, 481 (const uint8_t (*)[ETHER_ADDR_LEN]) 482 mac_addr->addr_bytes); 483 end: 484 priv_unlock(priv); 485 } 486