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 <sys/ioctl.h> 42 #include <arpa/inet.h> 43 44 /* Verbs header. */ 45 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 46 #ifdef PEDANTIC 47 #pragma GCC diagnostic ignored "-Wpedantic" 48 #endif 49 #include <infiniband/verbs.h> 50 #ifdef PEDANTIC 51 #pragma GCC diagnostic error "-Wpedantic" 52 #endif 53 54 #include <rte_ether.h> 55 #include <rte_ethdev.h> 56 #include <rte_common.h> 57 58 #include "mlx5.h" 59 #include "mlx5_utils.h" 60 #include "mlx5_rxtx.h" 61 #include "mlx5_defs.h" 62 63 /** 64 * Get MAC address by querying netdevice. 65 * 66 * @param[in] priv 67 * struct priv for the requested device. 68 * @param[out] mac 69 * MAC address output buffer. 70 * 71 * @return 72 * 0 on success, -1 on failure and errno is set. 73 */ 74 int 75 priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN]) 76 { 77 struct ifreq request; 78 79 if (priv_ifreq(priv, SIOCGIFHWADDR, &request)) 80 return -1; 81 memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); 82 return 0; 83 } 84 85 /** 86 * Delete MAC flow steering rule. 87 * 88 * @param hash_rxq 89 * Pointer to hash RX queue structure. 90 * @param mac_index 91 * MAC address index. 92 * @param vlan_index 93 * VLAN index to use. 94 */ 95 static void 96 hash_rxq_del_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index, 97 unsigned int vlan_index) 98 { 99 #ifndef NDEBUG 100 const uint8_t (*mac)[ETHER_ADDR_LEN] = 101 (const uint8_t (*)[ETHER_ADDR_LEN]) 102 hash_rxq->priv->mac[mac_index].addr_bytes; 103 #endif 104 105 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 106 assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index])); 107 if (hash_rxq->mac_flow[mac_index][vlan_index] == NULL) 108 return; 109 DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" 110 " VLAN index %u", 111 (void *)hash_rxq, 112 (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], 113 mac_index, 114 vlan_index); 115 claim_zero(ibv_destroy_flow(hash_rxq->mac_flow 116 [mac_index][vlan_index])); 117 hash_rxq->mac_flow[mac_index][vlan_index] = NULL; 118 } 119 120 /** 121 * Unregister a MAC address from a hash RX queue. 122 * 123 * @param hash_rxq 124 * Pointer to hash RX queue structure. 125 * @param mac_index 126 * MAC address index. 127 */ 128 static void 129 hash_rxq_mac_addr_del(struct hash_rxq *hash_rxq, unsigned int mac_index) 130 { 131 unsigned int i; 132 133 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 134 for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow[mac_index])); ++i) 135 hash_rxq_del_mac_flow(hash_rxq, mac_index, i); 136 } 137 138 /** 139 * Unregister all MAC addresses from a hash RX queue. 140 * 141 * @param hash_rxq 142 * Pointer to hash RX queue structure. 143 */ 144 void 145 hash_rxq_mac_addrs_del(struct hash_rxq *hash_rxq) 146 { 147 unsigned int i; 148 149 for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow)); ++i) 150 hash_rxq_mac_addr_del(hash_rxq, i); 151 } 152 153 /** 154 * Unregister a MAC address. 155 * 156 * This is done for each hash RX queue. 157 * 158 * @param priv 159 * Pointer to private structure. 160 * @param mac_index 161 * MAC address index. 162 */ 163 static void 164 priv_mac_addr_del(struct priv *priv, unsigned int mac_index) 165 { 166 unsigned int i; 167 168 assert(mac_index < RTE_DIM(priv->mac)); 169 if (!BITFIELD_ISSET(priv->mac_configured, mac_index)) 170 return; 171 for (i = 0; (i != priv->hash_rxqs_n); ++i) 172 hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[i], mac_index); 173 BITFIELD_RESET(priv->mac_configured, mac_index); 174 } 175 176 /** 177 * Unregister all MAC addresses from all hash RX queues. 178 * 179 * @param priv 180 * Pointer to private structure. 181 */ 182 void 183 priv_mac_addrs_disable(struct priv *priv) 184 { 185 unsigned int i; 186 187 for (i = 0; (i != priv->hash_rxqs_n); ++i) 188 hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[i]); 189 } 190 191 /** 192 * DPDK callback to remove a MAC address. 193 * 194 * @param dev 195 * Pointer to Ethernet device structure. 196 * @param index 197 * MAC address index. 198 */ 199 void 200 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 201 { 202 struct priv *priv = dev->data->dev_private; 203 204 if (mlx5_is_secondary()) 205 return; 206 207 priv_lock(priv); 208 DEBUG("%p: removing MAC address from index %" PRIu32, 209 (void *)dev, index); 210 if (index >= RTE_DIM(priv->mac)) 211 goto end; 212 priv_mac_addr_del(priv, index); 213 end: 214 priv_unlock(priv); 215 } 216 217 /** 218 * Add MAC flow steering rule. 219 * 220 * @param hash_rxq 221 * Pointer to hash RX queue structure. 222 * @param mac_index 223 * MAC address index to register. 224 * @param vlan_index 225 * VLAN index to use. 226 * 227 * @return 228 * 0 on success, errno value on failure. 229 */ 230 static int 231 hash_rxq_add_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index, 232 unsigned int vlan_index) 233 { 234 struct ibv_flow *flow; 235 struct priv *priv = hash_rxq->priv; 236 const uint8_t (*mac)[ETHER_ADDR_LEN] = 237 (const uint8_t (*)[ETHER_ADDR_LEN]) 238 priv->mac[mac_index].addr_bytes; 239 FLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, hash_rxq->type)); 240 struct ibv_flow_attr *attr = &data->attr; 241 struct ibv_flow_spec_eth *spec = &data->spec; 242 unsigned int vlan_enabled = !!priv->vlan_filter_n; 243 unsigned int vlan_id = priv->vlan_filter[vlan_index]; 244 245 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 246 assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index])); 247 if (hash_rxq->mac_flow[mac_index][vlan_index] != NULL) 248 return 0; 249 /* 250 * No padding must be inserted by the compiler between attr and spec. 251 * This layout is expected by libibverbs. 252 */ 253 assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec); 254 priv_flow_attr(priv, attr, sizeof(data), hash_rxq->type); 255 /* The first specification must be Ethernet. */ 256 assert(spec->type == IBV_FLOW_SPEC_ETH); 257 assert(spec->size == sizeof(*spec)); 258 *spec = (struct ibv_flow_spec_eth){ 259 .type = IBV_FLOW_SPEC_ETH, 260 .size = sizeof(*spec), 261 .val = { 262 .dst_mac = { 263 (*mac)[0], (*mac)[1], (*mac)[2], 264 (*mac)[3], (*mac)[4], (*mac)[5] 265 }, 266 .vlan_tag = (vlan_enabled ? 267 rte_cpu_to_be_16(vlan_id) 268 : 0), 269 }, 270 .mask = { 271 .dst_mac = "\xff\xff\xff\xff\xff\xff", 272 .vlan_tag = (vlan_enabled ? 273 rte_cpu_to_be_16(0xfff) : 274 0), 275 }, 276 }; 277 DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" 278 " VLAN index %u filtering %s, ID %u", 279 (void *)hash_rxq, 280 (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], 281 mac_index, 282 vlan_index, 283 (vlan_enabled ? "enabled" : "disabled"), 284 vlan_id); 285 /* Create related flow. */ 286 errno = 0; 287 flow = ibv_create_flow(hash_rxq->qp, attr); 288 if (flow == NULL) { 289 /* It's not clear whether errno is always set in this case. */ 290 ERROR("%p: flow configuration failed, errno=%d: %s", 291 (void *)hash_rxq, errno, 292 (errno ? strerror(errno) : "Unknown error")); 293 if (errno) 294 return errno; 295 return EINVAL; 296 } 297 hash_rxq->mac_flow[mac_index][vlan_index] = flow; 298 return 0; 299 } 300 301 /** 302 * Register a MAC address in a hash RX queue. 303 * 304 * @param hash_rxq 305 * Pointer to hash RX queue structure. 306 * @param mac_index 307 * MAC address index to register. 308 * 309 * @return 310 * 0 on success, errno value on failure. 311 */ 312 static int 313 hash_rxq_mac_addr_add(struct hash_rxq *hash_rxq, unsigned int mac_index) 314 { 315 struct priv *priv = hash_rxq->priv; 316 unsigned int i = 0; 317 int ret; 318 319 assert(mac_index < RTE_DIM(hash_rxq->mac_flow)); 320 assert(RTE_DIM(hash_rxq->mac_flow[mac_index]) == 321 RTE_DIM(priv->vlan_filter)); 322 /* Add a MAC address for each VLAN filter, or at least once. */ 323 do { 324 ret = hash_rxq_add_mac_flow(hash_rxq, mac_index, i); 325 if (ret) { 326 /* Failure, rollback. */ 327 while (i != 0) 328 hash_rxq_del_mac_flow(hash_rxq, mac_index, 329 --i); 330 return ret; 331 } 332 } while (++i < priv->vlan_filter_n); 333 return 0; 334 } 335 336 /** 337 * Register all MAC addresses in a hash RX queue. 338 * 339 * @param hash_rxq 340 * Pointer to hash RX queue structure. 341 * 342 * @return 343 * 0 on success, errno value on failure. 344 */ 345 int 346 hash_rxq_mac_addrs_add(struct hash_rxq *hash_rxq) 347 { 348 struct priv *priv = hash_rxq->priv; 349 unsigned int i; 350 int ret; 351 352 assert(RTE_DIM(priv->mac) == RTE_DIM(hash_rxq->mac_flow)); 353 for (i = 0; (i != RTE_DIM(priv->mac)); ++i) { 354 if (!BITFIELD_ISSET(priv->mac_configured, i)) 355 continue; 356 ret = hash_rxq_mac_addr_add(hash_rxq, i); 357 if (!ret) 358 continue; 359 /* Failure, rollback. */ 360 while (i != 0) 361 hash_rxq_mac_addr_del(hash_rxq, --i); 362 assert(ret > 0); 363 return ret; 364 } 365 return 0; 366 } 367 368 /** 369 * Register a MAC address. 370 * 371 * This is done for each hash RX queue. 372 * 373 * @param priv 374 * Pointer to private structure. 375 * @param mac_index 376 * MAC address index to use. 377 * @param mac 378 * MAC address to register. 379 * 380 * @return 381 * 0 on success, errno value on failure. 382 */ 383 int 384 priv_mac_addr_add(struct priv *priv, unsigned int mac_index, 385 const uint8_t (*mac)[ETHER_ADDR_LEN]) 386 { 387 unsigned int i; 388 int ret; 389 390 assert(mac_index < RTE_DIM(priv->mac)); 391 /* First, make sure this address isn't already configured. */ 392 for (i = 0; (i != RTE_DIM(priv->mac)); ++i) { 393 /* Skip this index, it's going to be reconfigured. */ 394 if (i == mac_index) 395 continue; 396 if (!BITFIELD_ISSET(priv->mac_configured, i)) 397 continue; 398 if (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac))) 399 continue; 400 /* Address already configured elsewhere, return with error. */ 401 return EADDRINUSE; 402 } 403 if (BITFIELD_ISSET(priv->mac_configured, mac_index)) 404 priv_mac_addr_del(priv, mac_index); 405 priv->mac[mac_index] = (struct ether_addr){ 406 { 407 (*mac)[0], (*mac)[1], (*mac)[2], 408 (*mac)[3], (*mac)[4], (*mac)[5] 409 } 410 }; 411 if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC)) 412 goto end; 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 end: 424 BITFIELD_SET(priv->mac_configured, mac_index); 425 return 0; 426 } 427 428 /** 429 * Register all MAC addresses in all hash RX queues. 430 * 431 * @param priv 432 * Pointer to private structure. 433 * 434 * @return 435 * 0 on success, errno value on failure. 436 */ 437 int 438 priv_mac_addrs_enable(struct priv *priv) 439 { 440 unsigned int i; 441 int ret; 442 443 if (priv->isolated) 444 return 0; 445 if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC)) 446 return 0; 447 for (i = 0; (i != priv->hash_rxqs_n); ++i) { 448 ret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]); 449 if (!ret) 450 continue; 451 /* Failure, rollback. */ 452 while (i != 0) 453 hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]); 454 assert(ret > 0); 455 return ret; 456 } 457 return 0; 458 } 459 460 /** 461 * DPDK callback to add a MAC address. 462 * 463 * @param dev 464 * Pointer to Ethernet device structure. 465 * @param mac_addr 466 * MAC address to register. 467 * @param index 468 * MAC address index. 469 * @param vmdq 470 * VMDq pool index to associate address with (ignored). 471 */ 472 int 473 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr, 474 uint32_t index, uint32_t vmdq) 475 { 476 struct priv *priv = dev->data->dev_private; 477 int re; 478 479 if (mlx5_is_secondary()) 480 return -ENOTSUP; 481 482 (void)vmdq; 483 priv_lock(priv); 484 DEBUG("%p: adding MAC address at index %" PRIu32, 485 (void *)dev, index); 486 if (index >= RTE_DIM(priv->mac)) { 487 re = EINVAL; 488 goto end; 489 } 490 re = priv_mac_addr_add(priv, index, 491 (const uint8_t (*)[ETHER_ADDR_LEN]) 492 mac_addr->addr_bytes); 493 end: 494 priv_unlock(priv); 495 return -re; 496 } 497 498 /** 499 * DPDK callback to set primary MAC address. 500 * 501 * @param dev 502 * Pointer to Ethernet device structure. 503 * @param mac_addr 504 * MAC address to register. 505 */ 506 void 507 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) 508 { 509 DEBUG("%p: setting primary MAC address", (void *)dev); 510 mlx5_mac_addr_remove(dev, 0); 511 mlx5_mac_addr_add(dev, mac_addr, 0, 0); 512 } 513