1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2018 Mellanox Technologies, Ltd 3 */ 4 5 #include <netinet/in.h> 6 #include <sys/queue.h> 7 #include <stdalign.h> 8 #include <stdint.h> 9 #include <string.h> 10 11 /* Verbs header. */ 12 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 13 #ifdef PEDANTIC 14 #pragma GCC diagnostic ignored "-Wpedantic" 15 #endif 16 #include <infiniband/verbs.h> 17 #ifdef PEDANTIC 18 #pragma GCC diagnostic error "-Wpedantic" 19 #endif 20 21 #include <rte_common.h> 22 #include <rte_ether.h> 23 #include <rte_ethdev_driver.h> 24 #include <rte_flow.h> 25 #include <rte_flow_driver.h> 26 #include <rte_malloc.h> 27 #include <rte_ip.h> 28 29 #include "mlx5.h" 30 #include "mlx5_defs.h" 31 #include "mlx5_flow.h" 32 #include "mlx5_glue.h" 33 #include "mlx5_prm.h" 34 #include "mlx5_rxtx.h" 35 36 #define VERBS_SPEC_INNER(item_flags) \ 37 (!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0) 38 39 /** 40 * Create Verbs flow counter with Verbs library. 41 * 42 * @param[in] dev 43 * Pointer to the Ethernet device structure. 44 * @param[in, out] counter 45 * mlx5 flow counter object, contains the counter id, 46 * handle of created Verbs flow counter is returned 47 * in cs field (if counters are supported). 48 * 49 * @return 50 * 0 On success else a negative errno value is returned 51 * and rte_errno is set. 52 */ 53 static int 54 flow_verbs_counter_create(struct rte_eth_dev *dev, 55 struct mlx5_flow_counter *counter) 56 { 57 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) 58 struct mlx5_priv *priv = dev->data->dev_private; 59 struct ibv_context *ctx = priv->sh->ctx; 60 struct ibv_counter_set_init_attr init = { 61 .counter_set_id = counter->id}; 62 63 counter->cs = mlx5_glue->create_counter_set(ctx, &init); 64 if (!counter->cs) { 65 rte_errno = ENOTSUP; 66 return -ENOTSUP; 67 } 68 return 0; 69 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 70 struct mlx5_priv *priv = dev->data->dev_private; 71 struct ibv_context *ctx = priv->sh->ctx; 72 struct ibv_counters_init_attr init = {0}; 73 struct ibv_counter_attach_attr attach; 74 int ret; 75 76 memset(&attach, 0, sizeof(attach)); 77 counter->cs = mlx5_glue->create_counters(ctx, &init); 78 if (!counter->cs) { 79 rte_errno = ENOTSUP; 80 return -ENOTSUP; 81 } 82 attach.counter_desc = IBV_COUNTER_PACKETS; 83 attach.index = 0; 84 ret = mlx5_glue->attach_counters(counter->cs, &attach, NULL); 85 if (!ret) { 86 attach.counter_desc = IBV_COUNTER_BYTES; 87 attach.index = 1; 88 ret = mlx5_glue->attach_counters 89 (counter->cs, &attach, NULL); 90 } 91 if (ret) { 92 claim_zero(mlx5_glue->destroy_counters(counter->cs)); 93 counter->cs = NULL; 94 rte_errno = ret; 95 return -ret; 96 } 97 return 0; 98 #else 99 (void)dev; 100 (void)counter; 101 rte_errno = ENOTSUP; 102 return -ENOTSUP; 103 #endif 104 } 105 106 /** 107 * Get a flow counter. 108 * 109 * @param[in] dev 110 * Pointer to the Ethernet device structure. 111 * @param[in] shared 112 * Indicate if this counter is shared with other flows. 113 * @param[in] id 114 * Counter identifier. 115 * 116 * @return 117 * A pointer to the counter, NULL otherwise and rte_errno is set. 118 */ 119 static struct mlx5_flow_counter * 120 flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id) 121 { 122 struct mlx5_priv *priv = dev->data->dev_private; 123 struct mlx5_flow_counter *cnt; 124 int ret; 125 126 if (shared) { 127 TAILQ_FOREACH(cnt, &priv->sh->cmng.flow_counters, next) { 128 if (cnt->shared && cnt->id == id) { 129 cnt->ref_cnt++; 130 return cnt; 131 } 132 } 133 } 134 cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0); 135 if (!cnt) { 136 rte_errno = ENOMEM; 137 return NULL; 138 } 139 cnt->id = id; 140 cnt->shared = shared; 141 cnt->ref_cnt = 1; 142 cnt->hits = 0; 143 cnt->bytes = 0; 144 /* Create counter with Verbs. */ 145 ret = flow_verbs_counter_create(dev, cnt); 146 if (!ret) { 147 TAILQ_INSERT_HEAD(&priv->sh->cmng.flow_counters, cnt, next); 148 return cnt; 149 } 150 /* Some error occurred in Verbs library. */ 151 rte_free(cnt); 152 rte_errno = -ret; 153 return NULL; 154 } 155 156 /** 157 * Release a flow counter. 158 * 159 * @param[in] dev 160 * Pointer to the Ethernet device structure. 161 * @param[in] counter 162 * Pointer to the counter handler. 163 */ 164 static void 165 flow_verbs_counter_release(struct rte_eth_dev *dev, 166 struct mlx5_flow_counter *counter) 167 { 168 struct mlx5_priv *priv = dev->data->dev_private; 169 170 if (--counter->ref_cnt == 0) { 171 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) 172 claim_zero(mlx5_glue->destroy_counter_set(counter->cs)); 173 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 174 claim_zero(mlx5_glue->destroy_counters(counter->cs)); 175 #endif 176 TAILQ_REMOVE(&priv->sh->cmng.flow_counters, counter, next); 177 rte_free(counter); 178 } 179 } 180 181 /** 182 * Query a flow counter via Verbs library call. 183 * 184 * @see rte_flow_query() 185 * @see rte_flow_ops 186 */ 187 static int 188 flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused, 189 struct rte_flow *flow, void *data, 190 struct rte_flow_error *error) 191 { 192 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ 193 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 194 if (flow->actions & MLX5_FLOW_ACTION_COUNT) { 195 struct rte_flow_query_count *qc = data; 196 uint64_t counters[2] = {0, 0}; 197 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) 198 struct ibv_query_counter_set_attr query_cs_attr = { 199 .cs = flow->counter->cs, 200 .query_flags = IBV_COUNTER_SET_FORCE_UPDATE, 201 }; 202 struct ibv_counter_set_data query_out = { 203 .out = counters, 204 .outlen = 2 * sizeof(uint64_t), 205 }; 206 int err = mlx5_glue->query_counter_set(&query_cs_attr, 207 &query_out); 208 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 209 int err = mlx5_glue->query_counters 210 (flow->counter->cs, counters, 211 RTE_DIM(counters), 212 IBV_READ_COUNTERS_ATTR_PREFER_CACHED); 213 #endif 214 if (err) 215 return rte_flow_error_set 216 (error, err, 217 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 218 NULL, 219 "cannot read counter"); 220 qc->hits_set = 1; 221 qc->bytes_set = 1; 222 qc->hits = counters[0] - flow->counter->hits; 223 qc->bytes = counters[1] - flow->counter->bytes; 224 if (qc->reset) { 225 flow->counter->hits = counters[0]; 226 flow->counter->bytes = counters[1]; 227 } 228 return 0; 229 } 230 return rte_flow_error_set(error, EINVAL, 231 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 232 NULL, 233 "flow does not have counter"); 234 #else 235 (void)flow; 236 (void)data; 237 return rte_flow_error_set(error, ENOTSUP, 238 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 239 NULL, 240 "counters are not available"); 241 #endif 242 } 243 244 /** 245 * Add a verbs item specification into @p verbs. 246 * 247 * @param[out] verbs 248 * Pointer to verbs structure. 249 * @param[in] src 250 * Create specification. 251 * @param[in] size 252 * Size in bytes of the specification to copy. 253 */ 254 static void 255 flow_verbs_spec_add(struct mlx5_flow_verbs *verbs, void *src, unsigned int size) 256 { 257 void *dst; 258 259 if (!verbs) 260 return; 261 assert(verbs->specs); 262 dst = (void *)(verbs->specs + verbs->size); 263 memcpy(dst, src, size); 264 ++verbs->attr->num_of_specs; 265 verbs->size += size; 266 } 267 268 /** 269 * Convert the @p item into a Verbs specification. This function assumes that 270 * the input is valid and that there is space to insert the requested item 271 * into the flow. 272 * 273 * @param[in, out] dev_flow 274 * Pointer to dev_flow structure. 275 * @param[in] item 276 * Item specification. 277 * @param[in] item_flags 278 * Parsed item flags. 279 */ 280 static void 281 flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow, 282 const struct rte_flow_item *item, 283 uint64_t item_flags) 284 { 285 const struct rte_flow_item_eth *spec = item->spec; 286 const struct rte_flow_item_eth *mask = item->mask; 287 const unsigned int size = sizeof(struct ibv_flow_spec_eth); 288 struct ibv_flow_spec_eth eth = { 289 .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags), 290 .size = size, 291 }; 292 293 if (!mask) 294 mask = &rte_flow_item_eth_mask; 295 if (spec) { 296 unsigned int i; 297 298 memcpy(ð.val.dst_mac, spec->dst.addr_bytes, 299 RTE_ETHER_ADDR_LEN); 300 memcpy(ð.val.src_mac, spec->src.addr_bytes, 301 RTE_ETHER_ADDR_LEN); 302 eth.val.ether_type = spec->type; 303 memcpy(ð.mask.dst_mac, mask->dst.addr_bytes, 304 RTE_ETHER_ADDR_LEN); 305 memcpy(ð.mask.src_mac, mask->src.addr_bytes, 306 RTE_ETHER_ADDR_LEN); 307 eth.mask.ether_type = mask->type; 308 /* Remove unwanted bits from values. */ 309 for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) { 310 eth.val.dst_mac[i] &= eth.mask.dst_mac[i]; 311 eth.val.src_mac[i] &= eth.mask.src_mac[i]; 312 } 313 eth.val.ether_type &= eth.mask.ether_type; 314 } 315 flow_verbs_spec_add(&dev_flow->verbs, ð, size); 316 } 317 318 /** 319 * Update the VLAN tag in the Verbs Ethernet specification. 320 * This function assumes that the input is valid and there is space to add 321 * the requested item. 322 * 323 * @param[in, out] attr 324 * Pointer to Verbs attributes structure. 325 * @param[in] eth 326 * Verbs structure containing the VLAN information to copy. 327 */ 328 static void 329 flow_verbs_item_vlan_update(struct ibv_flow_attr *attr, 330 struct ibv_flow_spec_eth *eth) 331 { 332 unsigned int i; 333 const enum ibv_flow_spec_type search = eth->type; 334 struct ibv_spec_header *hdr = (struct ibv_spec_header *) 335 ((uint8_t *)attr + sizeof(struct ibv_flow_attr)); 336 337 for (i = 0; i != attr->num_of_specs; ++i) { 338 if (hdr->type == search) { 339 struct ibv_flow_spec_eth *e = 340 (struct ibv_flow_spec_eth *)hdr; 341 342 e->val.vlan_tag = eth->val.vlan_tag; 343 e->mask.vlan_tag = eth->mask.vlan_tag; 344 e->val.ether_type = eth->val.ether_type; 345 e->mask.ether_type = eth->mask.ether_type; 346 break; 347 } 348 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size); 349 } 350 } 351 352 /** 353 * Convert the @p item into a Verbs specification. This function assumes that 354 * the input is valid and that there is space to insert the requested item 355 * into the flow. 356 * 357 * @param[in, out] dev_flow 358 * Pointer to dev_flow structure. 359 * @param[in] item 360 * Item specification. 361 * @param[in] item_flags 362 * Parsed item flags. 363 */ 364 static void 365 flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow, 366 const struct rte_flow_item *item, 367 uint64_t item_flags) 368 { 369 const struct rte_flow_item_vlan *spec = item->spec; 370 const struct rte_flow_item_vlan *mask = item->mask; 371 unsigned int size = sizeof(struct ibv_flow_spec_eth); 372 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 373 struct ibv_flow_spec_eth eth = { 374 .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags), 375 .size = size, 376 }; 377 const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 378 MLX5_FLOW_LAYER_OUTER_L2; 379 380 if (!mask) 381 mask = &rte_flow_item_vlan_mask; 382 if (spec) { 383 eth.val.vlan_tag = spec->tci; 384 eth.mask.vlan_tag = mask->tci; 385 eth.val.vlan_tag &= eth.mask.vlan_tag; 386 eth.val.ether_type = spec->inner_type; 387 eth.mask.ether_type = mask->inner_type; 388 eth.val.ether_type &= eth.mask.ether_type; 389 } 390 if (!(item_flags & l2m)) 391 flow_verbs_spec_add(&dev_flow->verbs, ð, size); 392 else 393 flow_verbs_item_vlan_update(dev_flow->verbs.attr, ð); 394 } 395 396 /** 397 * Convert the @p item into a Verbs specification. This function assumes that 398 * the input is valid and that there is space to insert the requested item 399 * into the flow. 400 * 401 * @param[in, out] dev_flow 402 * Pointer to dev_flow structure. 403 * @param[in] item 404 * Item specification. 405 * @param[in] item_flags 406 * Parsed item flags. 407 */ 408 static void 409 flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow, 410 const struct rte_flow_item *item, 411 uint64_t item_flags) 412 { 413 const struct rte_flow_item_ipv4 *spec = item->spec; 414 const struct rte_flow_item_ipv4 *mask = item->mask; 415 unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext); 416 struct ibv_flow_spec_ipv4_ext ipv4 = { 417 .type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags), 418 .size = size, 419 }; 420 421 if (!mask) 422 mask = &rte_flow_item_ipv4_mask; 423 if (spec) { 424 ipv4.val = (struct ibv_flow_ipv4_ext_filter){ 425 .src_ip = spec->hdr.src_addr, 426 .dst_ip = spec->hdr.dst_addr, 427 .proto = spec->hdr.next_proto_id, 428 .tos = spec->hdr.type_of_service, 429 }; 430 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){ 431 .src_ip = mask->hdr.src_addr, 432 .dst_ip = mask->hdr.dst_addr, 433 .proto = mask->hdr.next_proto_id, 434 .tos = mask->hdr.type_of_service, 435 }; 436 /* Remove unwanted bits from values. */ 437 ipv4.val.src_ip &= ipv4.mask.src_ip; 438 ipv4.val.dst_ip &= ipv4.mask.dst_ip; 439 ipv4.val.proto &= ipv4.mask.proto; 440 ipv4.val.tos &= ipv4.mask.tos; 441 } 442 flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size); 443 } 444 445 /** 446 * Convert the @p item into a Verbs specification. This function assumes that 447 * the input is valid and that there is space to insert the requested item 448 * into the flow. 449 * 450 * @param[in, out] dev_flow 451 * Pointer to dev_flow structure. 452 * @param[in] item 453 * Item specification. 454 * @param[in] item_flags 455 * Parsed item flags. 456 */ 457 static void 458 flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow, 459 const struct rte_flow_item *item, 460 uint64_t item_flags) 461 { 462 const struct rte_flow_item_ipv6 *spec = item->spec; 463 const struct rte_flow_item_ipv6 *mask = item->mask; 464 unsigned int size = sizeof(struct ibv_flow_spec_ipv6); 465 struct ibv_flow_spec_ipv6 ipv6 = { 466 .type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags), 467 .size = size, 468 }; 469 470 if (!mask) 471 mask = &rte_flow_item_ipv6_mask; 472 if (spec) { 473 unsigned int i; 474 uint32_t vtc_flow_val; 475 uint32_t vtc_flow_mask; 476 477 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr, 478 RTE_DIM(ipv6.val.src_ip)); 479 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr, 480 RTE_DIM(ipv6.val.dst_ip)); 481 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr, 482 RTE_DIM(ipv6.mask.src_ip)); 483 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr, 484 RTE_DIM(ipv6.mask.dst_ip)); 485 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow); 486 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow); 487 ipv6.val.flow_label = 488 rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >> 489 RTE_IPV6_HDR_FL_SHIFT); 490 ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >> 491 RTE_IPV6_HDR_TC_SHIFT; 492 ipv6.val.next_hdr = spec->hdr.proto; 493 ipv6.val.hop_limit = spec->hdr.hop_limits; 494 ipv6.mask.flow_label = 495 rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >> 496 RTE_IPV6_HDR_FL_SHIFT); 497 ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >> 498 RTE_IPV6_HDR_TC_SHIFT; 499 ipv6.mask.next_hdr = mask->hdr.proto; 500 ipv6.mask.hop_limit = mask->hdr.hop_limits; 501 /* Remove unwanted bits from values. */ 502 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) { 503 ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i]; 504 ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i]; 505 } 506 ipv6.val.flow_label &= ipv6.mask.flow_label; 507 ipv6.val.traffic_class &= ipv6.mask.traffic_class; 508 ipv6.val.next_hdr &= ipv6.mask.next_hdr; 509 ipv6.val.hop_limit &= ipv6.mask.hop_limit; 510 } 511 flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size); 512 } 513 514 /** 515 * Convert the @p item into a Verbs specification. This function assumes that 516 * the input is valid and that there is space to insert the requested item 517 * into the flow. 518 * 519 * @param[in, out] dev_flow 520 * Pointer to dev_flow structure. 521 * @param[in] item 522 * Item specification. 523 * @param[in] item_flags 524 * Parsed item flags. 525 */ 526 static void 527 flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow, 528 const struct rte_flow_item *item, 529 uint64_t item_flags __rte_unused) 530 { 531 const struct rte_flow_item_tcp *spec = item->spec; 532 const struct rte_flow_item_tcp *mask = item->mask; 533 unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp); 534 struct ibv_flow_spec_tcp_udp tcp = { 535 .type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags), 536 .size = size, 537 }; 538 539 if (!mask) 540 mask = &rte_flow_item_tcp_mask; 541 if (spec) { 542 tcp.val.dst_port = spec->hdr.dst_port; 543 tcp.val.src_port = spec->hdr.src_port; 544 tcp.mask.dst_port = mask->hdr.dst_port; 545 tcp.mask.src_port = mask->hdr.src_port; 546 /* Remove unwanted bits from values. */ 547 tcp.val.src_port &= tcp.mask.src_port; 548 tcp.val.dst_port &= tcp.mask.dst_port; 549 } 550 flow_verbs_spec_add(&dev_flow->verbs, &tcp, size); 551 } 552 553 /** 554 * Convert the @p item into a Verbs specification. This function assumes that 555 * the input is valid and that there is space to insert the requested item 556 * into the flow. 557 * 558 * @param[in, out] dev_flow 559 * Pointer to dev_flow structure. 560 * @param[in] item 561 * Item specification. 562 * @param[in] item_flags 563 * Parsed item flags. 564 */ 565 static void 566 flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow, 567 const struct rte_flow_item *item, 568 uint64_t item_flags __rte_unused) 569 { 570 const struct rte_flow_item_udp *spec = item->spec; 571 const struct rte_flow_item_udp *mask = item->mask; 572 unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp); 573 struct ibv_flow_spec_tcp_udp udp = { 574 .type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags), 575 .size = size, 576 }; 577 578 if (!mask) 579 mask = &rte_flow_item_udp_mask; 580 if (spec) { 581 udp.val.dst_port = spec->hdr.dst_port; 582 udp.val.src_port = spec->hdr.src_port; 583 udp.mask.dst_port = mask->hdr.dst_port; 584 udp.mask.src_port = mask->hdr.src_port; 585 /* Remove unwanted bits from values. */ 586 udp.val.src_port &= udp.mask.src_port; 587 udp.val.dst_port &= udp.mask.dst_port; 588 } 589 flow_verbs_spec_add(&dev_flow->verbs, &udp, size); 590 } 591 592 /** 593 * Convert the @p item into a Verbs specification. This function assumes that 594 * the input is valid and that there is space to insert the requested item 595 * into the flow. 596 * 597 * @param[in, out] dev_flow 598 * Pointer to dev_flow structure. 599 * @param[in] item 600 * Item specification. 601 * @param[in] item_flags 602 * Parsed item flags. 603 */ 604 static void 605 flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow, 606 const struct rte_flow_item *item, 607 uint64_t item_flags __rte_unused) 608 { 609 const struct rte_flow_item_vxlan *spec = item->spec; 610 const struct rte_flow_item_vxlan *mask = item->mask; 611 unsigned int size = sizeof(struct ibv_flow_spec_tunnel); 612 struct ibv_flow_spec_tunnel vxlan = { 613 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL, 614 .size = size, 615 }; 616 union vni { 617 uint32_t vlan_id; 618 uint8_t vni[4]; 619 } id = { .vlan_id = 0, }; 620 621 if (!mask) 622 mask = &rte_flow_item_vxlan_mask; 623 if (spec) { 624 memcpy(&id.vni[1], spec->vni, 3); 625 vxlan.val.tunnel_id = id.vlan_id; 626 memcpy(&id.vni[1], mask->vni, 3); 627 vxlan.mask.tunnel_id = id.vlan_id; 628 /* Remove unwanted bits from values. */ 629 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id; 630 } 631 flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size); 632 } 633 634 /** 635 * Convert the @p item into a Verbs specification. This function assumes that 636 * the input is valid and that there is space to insert the requested item 637 * into the flow. 638 * 639 * @param[in, out] dev_flow 640 * Pointer to dev_flow structure. 641 * @param[in] item 642 * Item specification. 643 * @param[in] item_flags 644 * Parsed item flags. 645 */ 646 static void 647 flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow, 648 const struct rte_flow_item *item, 649 uint64_t item_flags __rte_unused) 650 { 651 const struct rte_flow_item_vxlan_gpe *spec = item->spec; 652 const struct rte_flow_item_vxlan_gpe *mask = item->mask; 653 unsigned int size = sizeof(struct ibv_flow_spec_tunnel); 654 struct ibv_flow_spec_tunnel vxlan_gpe = { 655 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL, 656 .size = size, 657 }; 658 union vni { 659 uint32_t vlan_id; 660 uint8_t vni[4]; 661 } id = { .vlan_id = 0, }; 662 663 if (!mask) 664 mask = &rte_flow_item_vxlan_gpe_mask; 665 if (spec) { 666 memcpy(&id.vni[1], spec->vni, 3); 667 vxlan_gpe.val.tunnel_id = id.vlan_id; 668 memcpy(&id.vni[1], mask->vni, 3); 669 vxlan_gpe.mask.tunnel_id = id.vlan_id; 670 /* Remove unwanted bits from values. */ 671 vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id; 672 } 673 flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size); 674 } 675 676 /** 677 * Update the protocol in Verbs IPv4/IPv6 spec. 678 * 679 * @param[in, out] attr 680 * Pointer to Verbs attributes structure. 681 * @param[in] search 682 * Specification type to search in order to update the IP protocol. 683 * @param[in] protocol 684 * Protocol value to set if none is present in the specification. 685 */ 686 static void 687 flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr, 688 enum ibv_flow_spec_type search, 689 uint8_t protocol) 690 { 691 unsigned int i; 692 struct ibv_spec_header *hdr = (struct ibv_spec_header *) 693 ((uint8_t *)attr + sizeof(struct ibv_flow_attr)); 694 695 if (!attr) 696 return; 697 for (i = 0; i != attr->num_of_specs; ++i) { 698 if (hdr->type == search) { 699 union { 700 struct ibv_flow_spec_ipv4_ext *ipv4; 701 struct ibv_flow_spec_ipv6 *ipv6; 702 } ip; 703 704 switch (search) { 705 case IBV_FLOW_SPEC_IPV4_EXT: 706 ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr; 707 if (!ip.ipv4->val.proto) { 708 ip.ipv4->val.proto = protocol; 709 ip.ipv4->mask.proto = 0xff; 710 } 711 break; 712 case IBV_FLOW_SPEC_IPV6: 713 ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr; 714 if (!ip.ipv6->val.next_hdr) { 715 ip.ipv6->val.next_hdr = protocol; 716 ip.ipv6->mask.next_hdr = 0xff; 717 } 718 break; 719 default: 720 break; 721 } 722 break; 723 } 724 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size); 725 } 726 } 727 728 /** 729 * Convert the @p item into a Verbs specification. This function assumes that 730 * the input is valid and that there is space to insert the requested item 731 * into the flow. 732 * 733 * @param[in, out] dev_flow 734 * Pointer to dev_flow structure. 735 * @param[in] item 736 * Item specification. 737 * @param[in] item_flags 738 * Parsed item flags. 739 */ 740 static void 741 flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow, 742 const struct rte_flow_item *item __rte_unused, 743 uint64_t item_flags) 744 { 745 struct mlx5_flow_verbs *verbs = &dev_flow->verbs; 746 #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT 747 unsigned int size = sizeof(struct ibv_flow_spec_tunnel); 748 struct ibv_flow_spec_tunnel tunnel = { 749 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL, 750 .size = size, 751 }; 752 #else 753 const struct rte_flow_item_gre *spec = item->spec; 754 const struct rte_flow_item_gre *mask = item->mask; 755 unsigned int size = sizeof(struct ibv_flow_spec_gre); 756 struct ibv_flow_spec_gre tunnel = { 757 .type = IBV_FLOW_SPEC_GRE, 758 .size = size, 759 }; 760 761 if (!mask) 762 mask = &rte_flow_item_gre_mask; 763 if (spec) { 764 tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver; 765 tunnel.val.protocol = spec->protocol; 766 tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver; 767 tunnel.mask.protocol = mask->protocol; 768 /* Remove unwanted bits from values. */ 769 tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver; 770 tunnel.val.protocol &= tunnel.mask.protocol; 771 tunnel.val.key &= tunnel.mask.key; 772 } 773 #endif 774 if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) 775 flow_verbs_item_gre_ip_protocol_update(verbs->attr, 776 IBV_FLOW_SPEC_IPV4_EXT, 777 IPPROTO_GRE); 778 else 779 flow_verbs_item_gre_ip_protocol_update(verbs->attr, 780 IBV_FLOW_SPEC_IPV6, 781 IPPROTO_GRE); 782 flow_verbs_spec_add(verbs, &tunnel, size); 783 } 784 785 /** 786 * Convert the @p action into a Verbs specification. This function assumes that 787 * the input is valid and that there is space to insert the requested action 788 * into the flow. This function also return the action that was added. 789 * 790 * @param[in, out] dev_flow 791 * Pointer to dev_flow structure. 792 * @param[in] item 793 * Item specification. 794 * @param[in] item_flags 795 * Parsed item flags. 796 */ 797 static void 798 flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused, 799 const struct rte_flow_item *item __rte_unused, 800 uint64_t item_flags __rte_unused) 801 { 802 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT 803 const struct rte_flow_item_mpls *spec = item->spec; 804 const struct rte_flow_item_mpls *mask = item->mask; 805 unsigned int size = sizeof(struct ibv_flow_spec_mpls); 806 struct ibv_flow_spec_mpls mpls = { 807 .type = IBV_FLOW_SPEC_MPLS, 808 .size = size, 809 }; 810 811 if (!mask) 812 mask = &rte_flow_item_mpls_mask; 813 if (spec) { 814 memcpy(&mpls.val.label, spec, sizeof(mpls.val.label)); 815 memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label)); 816 /* Remove unwanted bits from values. */ 817 mpls.val.label &= mpls.mask.label; 818 } 819 flow_verbs_spec_add(&dev_flow->verbs, &mpls, size); 820 #endif 821 } 822 823 /** 824 * Convert the @p action into a Verbs specification. This function assumes that 825 * the input is valid and that there is space to insert the requested action 826 * into the flow. 827 * 828 * @param[in] dev_flow 829 * Pointer to mlx5_flow. 830 * @param[in] action 831 * Action configuration. 832 */ 833 static void 834 flow_verbs_translate_action_drop 835 (struct mlx5_flow *dev_flow, 836 const struct rte_flow_action *action __rte_unused) 837 { 838 unsigned int size = sizeof(struct ibv_flow_spec_action_drop); 839 struct ibv_flow_spec_action_drop drop = { 840 .type = IBV_FLOW_SPEC_ACTION_DROP, 841 .size = size, 842 }; 843 844 flow_verbs_spec_add(&dev_flow->verbs, &drop, size); 845 } 846 847 /** 848 * Convert the @p action into a Verbs specification. This function assumes that 849 * the input is valid and that there is space to insert the requested action 850 * into the flow. 851 * 852 * @param[in] dev_flow 853 * Pointer to mlx5_flow. 854 * @param[in] action 855 * Action configuration. 856 */ 857 static void 858 flow_verbs_translate_action_queue(struct mlx5_flow *dev_flow, 859 const struct rte_flow_action *action) 860 { 861 const struct rte_flow_action_queue *queue = action->conf; 862 struct rte_flow *flow = dev_flow->flow; 863 864 if (flow->queue) 865 (*flow->queue)[0] = queue->index; 866 flow->rss.queue_num = 1; 867 } 868 869 /** 870 * Convert the @p action into a Verbs specification. This function assumes that 871 * the input is valid and that there is space to insert the requested action 872 * into the flow. 873 * 874 * @param[in] action 875 * Action configuration. 876 * @param[in, out] action_flags 877 * Pointer to the detected actions. 878 * @param[in] dev_flow 879 * Pointer to mlx5_flow. 880 */ 881 static void 882 flow_verbs_translate_action_rss(struct mlx5_flow *dev_flow, 883 const struct rte_flow_action *action) 884 { 885 const struct rte_flow_action_rss *rss = action->conf; 886 const uint8_t *rss_key; 887 struct rte_flow *flow = dev_flow->flow; 888 889 if (flow->queue) 890 memcpy((*flow->queue), rss->queue, 891 rss->queue_num * sizeof(uint16_t)); 892 flow->rss.queue_num = rss->queue_num; 893 /* NULL RSS key indicates default RSS key. */ 894 rss_key = !rss->key ? rss_hash_default_key : rss->key; 895 memcpy(flow->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 896 /* RSS type 0 indicates default RSS type (ETH_RSS_IP). */ 897 flow->rss.types = !rss->types ? ETH_RSS_IP : rss->types; 898 flow->rss.level = rss->level; 899 } 900 901 /** 902 * Convert the @p action into a Verbs specification. This function assumes that 903 * the input is valid and that there is space to insert the requested action 904 * into the flow. 905 * 906 * @param[in] dev_flow 907 * Pointer to mlx5_flow. 908 * @param[in] action 909 * Action configuration. 910 */ 911 static void 912 flow_verbs_translate_action_flag 913 (struct mlx5_flow *dev_flow, 914 const struct rte_flow_action *action __rte_unused) 915 { 916 unsigned int size = sizeof(struct ibv_flow_spec_action_tag); 917 struct ibv_flow_spec_action_tag tag = { 918 .type = IBV_FLOW_SPEC_ACTION_TAG, 919 .size = size, 920 .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT), 921 }; 922 923 flow_verbs_spec_add(&dev_flow->verbs, &tag, size); 924 } 925 926 /** 927 * Convert the @p action into a Verbs specification. This function assumes that 928 * the input is valid and that there is space to insert the requested action 929 * into the flow. 930 * 931 * @param[in] dev_flow 932 * Pointer to mlx5_flow. 933 * @param[in] action 934 * Action configuration. 935 */ 936 static void 937 flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow, 938 const struct rte_flow_action *action) 939 { 940 const struct rte_flow_action_mark *mark = action->conf; 941 unsigned int size = sizeof(struct ibv_flow_spec_action_tag); 942 struct ibv_flow_spec_action_tag tag = { 943 .type = IBV_FLOW_SPEC_ACTION_TAG, 944 .size = size, 945 .tag_id = mlx5_flow_mark_set(mark->id), 946 }; 947 948 flow_verbs_spec_add(&dev_flow->verbs, &tag, size); 949 } 950 951 /** 952 * Convert the @p action into a Verbs specification. This function assumes that 953 * the input is valid and that there is space to insert the requested action 954 * into the flow. 955 * 956 * @param[in] dev 957 * Pointer to the Ethernet device structure. 958 * @param[in] action 959 * Action configuration. 960 * @param[in] dev_flow 961 * Pointer to mlx5_flow. 962 * @param[out] error 963 * Pointer to error structure. 964 * 965 * @return 966 * 0 On success else a negative errno value is returned and rte_errno is set. 967 */ 968 static int 969 flow_verbs_translate_action_count(struct mlx5_flow *dev_flow, 970 const struct rte_flow_action *action, 971 struct rte_eth_dev *dev, 972 struct rte_flow_error *error) 973 { 974 const struct rte_flow_action_count *count = action->conf; 975 struct rte_flow *flow = dev_flow->flow; 976 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ 977 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 978 unsigned int size = sizeof(struct ibv_flow_spec_counter_action); 979 struct ibv_flow_spec_counter_action counter = { 980 .type = IBV_FLOW_SPEC_ACTION_COUNT, 981 .size = size, 982 }; 983 #endif 984 985 if (!flow->counter) { 986 flow->counter = flow_verbs_counter_new(dev, count->shared, 987 count->id); 988 if (!flow->counter) 989 return rte_flow_error_set(error, rte_errno, 990 RTE_FLOW_ERROR_TYPE_ACTION, 991 action, 992 "cannot get counter" 993 " context."); 994 } 995 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) 996 counter.counter_set_handle = flow->counter->cs->handle; 997 flow_verbs_spec_add(&dev_flow->verbs, &counter, size); 998 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 999 counter.counters = flow->counter->cs; 1000 flow_verbs_spec_add(&dev_flow->verbs, &counter, size); 1001 #endif 1002 return 0; 1003 } 1004 1005 /** 1006 * Internal validation function. For validating both actions and items. 1007 * 1008 * @param[in] dev 1009 * Pointer to the Ethernet device structure. 1010 * @param[in] attr 1011 * Pointer to the flow attributes. 1012 * @param[in] items 1013 * Pointer to the list of items. 1014 * @param[in] actions 1015 * Pointer to the list of actions. 1016 * @param[out] error 1017 * Pointer to the error structure. 1018 * 1019 * @return 1020 * 0 on success, a negative errno value otherwise and rte_errno is set. 1021 */ 1022 static int 1023 flow_verbs_validate(struct rte_eth_dev *dev, 1024 const struct rte_flow_attr *attr, 1025 const struct rte_flow_item items[], 1026 const struct rte_flow_action actions[], 1027 struct rte_flow_error *error) 1028 { 1029 int ret; 1030 uint64_t action_flags = 0; 1031 uint64_t item_flags = 0; 1032 uint64_t last_item = 0; 1033 uint8_t next_protocol = 0xff; 1034 1035 if (items == NULL) 1036 return -1; 1037 ret = mlx5_flow_validate_attributes(dev, attr, error); 1038 if (ret < 0) 1039 return ret; 1040 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 1041 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 1042 int ret = 0; 1043 1044 switch (items->type) { 1045 case RTE_FLOW_ITEM_TYPE_VOID: 1046 break; 1047 case RTE_FLOW_ITEM_TYPE_ETH: 1048 ret = mlx5_flow_validate_item_eth(items, item_flags, 1049 error); 1050 if (ret < 0) 1051 return ret; 1052 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 1053 MLX5_FLOW_LAYER_OUTER_L2; 1054 break; 1055 case RTE_FLOW_ITEM_TYPE_VLAN: 1056 ret = mlx5_flow_validate_item_vlan(items, item_flags, 1057 error); 1058 if (ret < 0) 1059 return ret; 1060 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 1061 MLX5_FLOW_LAYER_INNER_VLAN) : 1062 (MLX5_FLOW_LAYER_OUTER_L2 | 1063 MLX5_FLOW_LAYER_OUTER_VLAN); 1064 break; 1065 case RTE_FLOW_ITEM_TYPE_IPV4: 1066 ret = mlx5_flow_validate_item_ipv4(items, item_flags, 1067 NULL, error); 1068 if (ret < 0) 1069 return ret; 1070 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 1071 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 1072 if (items->mask != NULL && 1073 ((const struct rte_flow_item_ipv4 *) 1074 items->mask)->hdr.next_proto_id) { 1075 next_protocol = 1076 ((const struct rte_flow_item_ipv4 *) 1077 (items->spec))->hdr.next_proto_id; 1078 next_protocol &= 1079 ((const struct rte_flow_item_ipv4 *) 1080 (items->mask))->hdr.next_proto_id; 1081 } else { 1082 /* Reset for inner layer. */ 1083 next_protocol = 0xff; 1084 } 1085 break; 1086 case RTE_FLOW_ITEM_TYPE_IPV6: 1087 ret = mlx5_flow_validate_item_ipv6(items, item_flags, 1088 NULL, error); 1089 if (ret < 0) 1090 return ret; 1091 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 1092 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 1093 if (items->mask != NULL && 1094 ((const struct rte_flow_item_ipv6 *) 1095 items->mask)->hdr.proto) { 1096 next_protocol = 1097 ((const struct rte_flow_item_ipv6 *) 1098 items->spec)->hdr.proto; 1099 next_protocol &= 1100 ((const struct rte_flow_item_ipv6 *) 1101 items->mask)->hdr.proto; 1102 } else { 1103 /* Reset for inner layer. */ 1104 next_protocol = 0xff; 1105 } 1106 break; 1107 case RTE_FLOW_ITEM_TYPE_UDP: 1108 ret = mlx5_flow_validate_item_udp(items, item_flags, 1109 next_protocol, 1110 error); 1111 if (ret < 0) 1112 return ret; 1113 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 1114 MLX5_FLOW_LAYER_OUTER_L4_UDP; 1115 break; 1116 case RTE_FLOW_ITEM_TYPE_TCP: 1117 ret = mlx5_flow_validate_item_tcp 1118 (items, item_flags, 1119 next_protocol, 1120 &rte_flow_item_tcp_mask, 1121 error); 1122 if (ret < 0) 1123 return ret; 1124 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 1125 MLX5_FLOW_LAYER_OUTER_L4_TCP; 1126 break; 1127 case RTE_FLOW_ITEM_TYPE_VXLAN: 1128 ret = mlx5_flow_validate_item_vxlan(items, item_flags, 1129 error); 1130 if (ret < 0) 1131 return ret; 1132 last_item = MLX5_FLOW_LAYER_VXLAN; 1133 break; 1134 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 1135 ret = mlx5_flow_validate_item_vxlan_gpe(items, 1136 item_flags, 1137 dev, error); 1138 if (ret < 0) 1139 return ret; 1140 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 1141 break; 1142 case RTE_FLOW_ITEM_TYPE_GRE: 1143 ret = mlx5_flow_validate_item_gre(items, item_flags, 1144 next_protocol, error); 1145 if (ret < 0) 1146 return ret; 1147 last_item = MLX5_FLOW_LAYER_GRE; 1148 break; 1149 case RTE_FLOW_ITEM_TYPE_MPLS: 1150 ret = mlx5_flow_validate_item_mpls(dev, items, 1151 item_flags, 1152 last_item, error); 1153 if (ret < 0) 1154 return ret; 1155 last_item = MLX5_FLOW_LAYER_MPLS; 1156 break; 1157 default: 1158 return rte_flow_error_set(error, ENOTSUP, 1159 RTE_FLOW_ERROR_TYPE_ITEM, 1160 NULL, "item not supported"); 1161 } 1162 item_flags |= last_item; 1163 } 1164 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 1165 switch (actions->type) { 1166 case RTE_FLOW_ACTION_TYPE_VOID: 1167 break; 1168 case RTE_FLOW_ACTION_TYPE_FLAG: 1169 ret = mlx5_flow_validate_action_flag(action_flags, 1170 attr, 1171 error); 1172 if (ret < 0) 1173 return ret; 1174 action_flags |= MLX5_FLOW_ACTION_FLAG; 1175 break; 1176 case RTE_FLOW_ACTION_TYPE_MARK: 1177 ret = mlx5_flow_validate_action_mark(actions, 1178 action_flags, 1179 attr, 1180 error); 1181 if (ret < 0) 1182 return ret; 1183 action_flags |= MLX5_FLOW_ACTION_MARK; 1184 break; 1185 case RTE_FLOW_ACTION_TYPE_DROP: 1186 ret = mlx5_flow_validate_action_drop(action_flags, 1187 attr, 1188 error); 1189 if (ret < 0) 1190 return ret; 1191 action_flags |= MLX5_FLOW_ACTION_DROP; 1192 break; 1193 case RTE_FLOW_ACTION_TYPE_QUEUE: 1194 ret = mlx5_flow_validate_action_queue(actions, 1195 action_flags, dev, 1196 attr, 1197 error); 1198 if (ret < 0) 1199 return ret; 1200 action_flags |= MLX5_FLOW_ACTION_QUEUE; 1201 break; 1202 case RTE_FLOW_ACTION_TYPE_RSS: 1203 ret = mlx5_flow_validate_action_rss(actions, 1204 action_flags, dev, 1205 attr, item_flags, 1206 error); 1207 if (ret < 0) 1208 return ret; 1209 action_flags |= MLX5_FLOW_ACTION_RSS; 1210 break; 1211 case RTE_FLOW_ACTION_TYPE_COUNT: 1212 ret = mlx5_flow_validate_action_count(dev, attr, error); 1213 if (ret < 0) 1214 return ret; 1215 action_flags |= MLX5_FLOW_ACTION_COUNT; 1216 break; 1217 default: 1218 return rte_flow_error_set(error, ENOTSUP, 1219 RTE_FLOW_ERROR_TYPE_ACTION, 1220 actions, 1221 "action not supported"); 1222 } 1223 } 1224 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS)) 1225 return rte_flow_error_set(error, EINVAL, 1226 RTE_FLOW_ERROR_TYPE_ACTION, actions, 1227 "no fate action is found"); 1228 return 0; 1229 } 1230 1231 /** 1232 * Calculate the required bytes that are needed for the action part of the verbs 1233 * flow. 1234 * 1235 * @param[in] actions 1236 * Pointer to the list of actions. 1237 * 1238 * @return 1239 * The size of the memory needed for all actions. 1240 */ 1241 static int 1242 flow_verbs_get_actions_size(const struct rte_flow_action actions[]) 1243 { 1244 int size = 0; 1245 1246 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 1247 switch (actions->type) { 1248 case RTE_FLOW_ACTION_TYPE_VOID: 1249 break; 1250 case RTE_FLOW_ACTION_TYPE_FLAG: 1251 size += sizeof(struct ibv_flow_spec_action_tag); 1252 break; 1253 case RTE_FLOW_ACTION_TYPE_MARK: 1254 size += sizeof(struct ibv_flow_spec_action_tag); 1255 break; 1256 case RTE_FLOW_ACTION_TYPE_DROP: 1257 size += sizeof(struct ibv_flow_spec_action_drop); 1258 break; 1259 case RTE_FLOW_ACTION_TYPE_QUEUE: 1260 break; 1261 case RTE_FLOW_ACTION_TYPE_RSS: 1262 break; 1263 case RTE_FLOW_ACTION_TYPE_COUNT: 1264 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ 1265 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) 1266 size += sizeof(struct ibv_flow_spec_counter_action); 1267 #endif 1268 break; 1269 default: 1270 break; 1271 } 1272 } 1273 return size; 1274 } 1275 1276 /** 1277 * Calculate the required bytes that are needed for the item part of the verbs 1278 * flow. 1279 * 1280 * @param[in] items 1281 * Pointer to the list of items. 1282 * 1283 * @return 1284 * The size of the memory needed for all items. 1285 */ 1286 static int 1287 flow_verbs_get_items_size(const struct rte_flow_item items[]) 1288 { 1289 int size = 0; 1290 1291 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 1292 switch (items->type) { 1293 case RTE_FLOW_ITEM_TYPE_VOID: 1294 break; 1295 case RTE_FLOW_ITEM_TYPE_ETH: 1296 size += sizeof(struct ibv_flow_spec_eth); 1297 break; 1298 case RTE_FLOW_ITEM_TYPE_VLAN: 1299 size += sizeof(struct ibv_flow_spec_eth); 1300 break; 1301 case RTE_FLOW_ITEM_TYPE_IPV4: 1302 size += sizeof(struct ibv_flow_spec_ipv4_ext); 1303 break; 1304 case RTE_FLOW_ITEM_TYPE_IPV6: 1305 size += sizeof(struct ibv_flow_spec_ipv6); 1306 break; 1307 case RTE_FLOW_ITEM_TYPE_UDP: 1308 size += sizeof(struct ibv_flow_spec_tcp_udp); 1309 break; 1310 case RTE_FLOW_ITEM_TYPE_TCP: 1311 size += sizeof(struct ibv_flow_spec_tcp_udp); 1312 break; 1313 case RTE_FLOW_ITEM_TYPE_VXLAN: 1314 size += sizeof(struct ibv_flow_spec_tunnel); 1315 break; 1316 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 1317 size += sizeof(struct ibv_flow_spec_tunnel); 1318 break; 1319 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT 1320 case RTE_FLOW_ITEM_TYPE_GRE: 1321 size += sizeof(struct ibv_flow_spec_gre); 1322 break; 1323 case RTE_FLOW_ITEM_TYPE_MPLS: 1324 size += sizeof(struct ibv_flow_spec_mpls); 1325 break; 1326 #else 1327 case RTE_FLOW_ITEM_TYPE_GRE: 1328 size += sizeof(struct ibv_flow_spec_tunnel); 1329 break; 1330 #endif 1331 default: 1332 break; 1333 } 1334 } 1335 return size; 1336 } 1337 1338 /** 1339 * Internal preparation function. Allocate mlx5_flow with the required size. 1340 * The required size is calculate based on the actions and items. This function 1341 * also returns the detected actions and items for later use. 1342 * 1343 * @param[in] attr 1344 * Pointer to the flow attributes. 1345 * @param[in] items 1346 * Pointer to the list of items. 1347 * @param[in] actions 1348 * Pointer to the list of actions. 1349 * @param[out] error 1350 * Pointer to the error structure. 1351 * 1352 * @return 1353 * Pointer to mlx5_flow object on success, otherwise NULL and rte_errno 1354 * is set. 1355 */ 1356 static struct mlx5_flow * 1357 flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused, 1358 const struct rte_flow_item items[], 1359 const struct rte_flow_action actions[], 1360 struct rte_flow_error *error) 1361 { 1362 uint32_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr); 1363 struct mlx5_flow *flow; 1364 1365 size += flow_verbs_get_actions_size(actions); 1366 size += flow_verbs_get_items_size(items); 1367 flow = rte_calloc(__func__, 1, size, 0); 1368 if (!flow) { 1369 rte_flow_error_set(error, ENOMEM, 1370 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1371 "not enough memory to create flow"); 1372 return NULL; 1373 } 1374 flow->verbs.attr = (void *)(flow + 1); 1375 flow->verbs.specs = 1376 (uint8_t *)(flow + 1) + sizeof(struct ibv_flow_attr); 1377 return flow; 1378 } 1379 1380 /** 1381 * Fill the flow with verb spec. 1382 * 1383 * @param[in] dev 1384 * Pointer to Ethernet device. 1385 * @param[in, out] dev_flow 1386 * Pointer to the mlx5 flow. 1387 * @param[in] attr 1388 * Pointer to the flow attributes. 1389 * @param[in] items 1390 * Pointer to the list of items. 1391 * @param[in] actions 1392 * Pointer to the list of actions. 1393 * @param[out] error 1394 * Pointer to the error structure. 1395 * 1396 * @return 1397 * 0 on success, else a negative errno value otherwise and rte_errno is set. 1398 */ 1399 static int 1400 flow_verbs_translate(struct rte_eth_dev *dev, 1401 struct mlx5_flow *dev_flow, 1402 const struct rte_flow_attr *attr, 1403 const struct rte_flow_item items[], 1404 const struct rte_flow_action actions[], 1405 struct rte_flow_error *error) 1406 { 1407 struct rte_flow *flow = dev_flow->flow; 1408 uint64_t item_flags = 0; 1409 uint64_t action_flags = 0; 1410 uint64_t priority = attr->priority; 1411 uint32_t subpriority = 0; 1412 struct mlx5_priv *priv = dev->data->dev_private; 1413 1414 if (priority == MLX5_FLOW_PRIO_RSVD) 1415 priority = priv->config.flow_prio - 1; 1416 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 1417 int ret; 1418 1419 switch (actions->type) { 1420 case RTE_FLOW_ACTION_TYPE_VOID: 1421 break; 1422 case RTE_FLOW_ACTION_TYPE_FLAG: 1423 flow_verbs_translate_action_flag(dev_flow, actions); 1424 action_flags |= MLX5_FLOW_ACTION_FLAG; 1425 break; 1426 case RTE_FLOW_ACTION_TYPE_MARK: 1427 flow_verbs_translate_action_mark(dev_flow, actions); 1428 action_flags |= MLX5_FLOW_ACTION_MARK; 1429 break; 1430 case RTE_FLOW_ACTION_TYPE_DROP: 1431 flow_verbs_translate_action_drop(dev_flow, actions); 1432 action_flags |= MLX5_FLOW_ACTION_DROP; 1433 break; 1434 case RTE_FLOW_ACTION_TYPE_QUEUE: 1435 flow_verbs_translate_action_queue(dev_flow, actions); 1436 action_flags |= MLX5_FLOW_ACTION_QUEUE; 1437 break; 1438 case RTE_FLOW_ACTION_TYPE_RSS: 1439 flow_verbs_translate_action_rss(dev_flow, actions); 1440 action_flags |= MLX5_FLOW_ACTION_RSS; 1441 break; 1442 case RTE_FLOW_ACTION_TYPE_COUNT: 1443 ret = flow_verbs_translate_action_count(dev_flow, 1444 actions, 1445 dev, error); 1446 if (ret < 0) 1447 return ret; 1448 action_flags |= MLX5_FLOW_ACTION_COUNT; 1449 break; 1450 default: 1451 return rte_flow_error_set(error, ENOTSUP, 1452 RTE_FLOW_ERROR_TYPE_ACTION, 1453 actions, 1454 "action not supported"); 1455 } 1456 } 1457 flow->actions = action_flags; 1458 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 1459 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 1460 1461 switch (items->type) { 1462 case RTE_FLOW_ITEM_TYPE_VOID: 1463 break; 1464 case RTE_FLOW_ITEM_TYPE_ETH: 1465 flow_verbs_translate_item_eth(dev_flow, items, 1466 item_flags); 1467 subpriority = MLX5_PRIORITY_MAP_L2; 1468 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 1469 MLX5_FLOW_LAYER_OUTER_L2; 1470 break; 1471 case RTE_FLOW_ITEM_TYPE_VLAN: 1472 flow_verbs_translate_item_vlan(dev_flow, items, 1473 item_flags); 1474 subpriority = MLX5_PRIORITY_MAP_L2; 1475 item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 1476 MLX5_FLOW_LAYER_INNER_VLAN) : 1477 (MLX5_FLOW_LAYER_OUTER_L2 | 1478 MLX5_FLOW_LAYER_OUTER_VLAN); 1479 break; 1480 case RTE_FLOW_ITEM_TYPE_IPV4: 1481 flow_verbs_translate_item_ipv4(dev_flow, items, 1482 item_flags); 1483 subpriority = MLX5_PRIORITY_MAP_L3; 1484 dev_flow->verbs.hash_fields |= 1485 mlx5_flow_hashfields_adjust 1486 (dev_flow, tunnel, 1487 MLX5_IPV4_LAYER_TYPES, 1488 MLX5_IPV4_IBV_RX_HASH); 1489 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 1490 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 1491 break; 1492 case RTE_FLOW_ITEM_TYPE_IPV6: 1493 flow_verbs_translate_item_ipv6(dev_flow, items, 1494 item_flags); 1495 subpriority = MLX5_PRIORITY_MAP_L3; 1496 dev_flow->verbs.hash_fields |= 1497 mlx5_flow_hashfields_adjust 1498 (dev_flow, tunnel, 1499 MLX5_IPV6_LAYER_TYPES, 1500 MLX5_IPV6_IBV_RX_HASH); 1501 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 1502 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 1503 break; 1504 case RTE_FLOW_ITEM_TYPE_TCP: 1505 flow_verbs_translate_item_tcp(dev_flow, items, 1506 item_flags); 1507 subpriority = MLX5_PRIORITY_MAP_L4; 1508 dev_flow->verbs.hash_fields |= 1509 mlx5_flow_hashfields_adjust 1510 (dev_flow, tunnel, ETH_RSS_TCP, 1511 (IBV_RX_HASH_SRC_PORT_TCP | 1512 IBV_RX_HASH_DST_PORT_TCP)); 1513 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 1514 MLX5_FLOW_LAYER_OUTER_L4_TCP; 1515 break; 1516 case RTE_FLOW_ITEM_TYPE_UDP: 1517 flow_verbs_translate_item_udp(dev_flow, items, 1518 item_flags); 1519 subpriority = MLX5_PRIORITY_MAP_L4; 1520 dev_flow->verbs.hash_fields |= 1521 mlx5_flow_hashfields_adjust 1522 (dev_flow, tunnel, ETH_RSS_UDP, 1523 (IBV_RX_HASH_SRC_PORT_UDP | 1524 IBV_RX_HASH_DST_PORT_UDP)); 1525 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 1526 MLX5_FLOW_LAYER_OUTER_L4_UDP; 1527 break; 1528 case RTE_FLOW_ITEM_TYPE_VXLAN: 1529 flow_verbs_translate_item_vxlan(dev_flow, items, 1530 item_flags); 1531 subpriority = MLX5_PRIORITY_MAP_L2; 1532 item_flags |= MLX5_FLOW_LAYER_VXLAN; 1533 break; 1534 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 1535 flow_verbs_translate_item_vxlan_gpe(dev_flow, items, 1536 item_flags); 1537 subpriority = MLX5_PRIORITY_MAP_L2; 1538 item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE; 1539 break; 1540 case RTE_FLOW_ITEM_TYPE_GRE: 1541 flow_verbs_translate_item_gre(dev_flow, items, 1542 item_flags); 1543 subpriority = MLX5_PRIORITY_MAP_L2; 1544 item_flags |= MLX5_FLOW_LAYER_GRE; 1545 break; 1546 case RTE_FLOW_ITEM_TYPE_MPLS: 1547 flow_verbs_translate_item_mpls(dev_flow, items, 1548 item_flags); 1549 subpriority = MLX5_PRIORITY_MAP_L2; 1550 item_flags |= MLX5_FLOW_LAYER_MPLS; 1551 break; 1552 default: 1553 return rte_flow_error_set(error, ENOTSUP, 1554 RTE_FLOW_ERROR_TYPE_ITEM, 1555 NULL, 1556 "item not supported"); 1557 } 1558 } 1559 dev_flow->layers = item_flags; 1560 dev_flow->verbs.attr->priority = 1561 mlx5_flow_adjust_priority(dev, priority, subpriority); 1562 dev_flow->verbs.attr->port = (uint8_t)priv->ibv_port; 1563 return 0; 1564 } 1565 1566 /** 1567 * Remove the flow from the NIC but keeps it in memory. 1568 * 1569 * @param[in] dev 1570 * Pointer to the Ethernet device structure. 1571 * @param[in, out] flow 1572 * Pointer to flow structure. 1573 */ 1574 static void 1575 flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow) 1576 { 1577 struct mlx5_flow_verbs *verbs; 1578 struct mlx5_flow *dev_flow; 1579 1580 if (!flow) 1581 return; 1582 LIST_FOREACH(dev_flow, &flow->dev_flows, next) { 1583 verbs = &dev_flow->verbs; 1584 if (verbs->flow) { 1585 claim_zero(mlx5_glue->destroy_flow(verbs->flow)); 1586 verbs->flow = NULL; 1587 } 1588 if (verbs->hrxq) { 1589 if (flow->actions & MLX5_FLOW_ACTION_DROP) 1590 mlx5_hrxq_drop_release(dev); 1591 else 1592 mlx5_hrxq_release(dev, verbs->hrxq); 1593 verbs->hrxq = NULL; 1594 } 1595 } 1596 } 1597 1598 /** 1599 * Remove the flow from the NIC and the memory. 1600 * 1601 * @param[in] dev 1602 * Pointer to the Ethernet device structure. 1603 * @param[in, out] flow 1604 * Pointer to flow structure. 1605 */ 1606 static void 1607 flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) 1608 { 1609 struct mlx5_flow *dev_flow; 1610 1611 if (!flow) 1612 return; 1613 flow_verbs_remove(dev, flow); 1614 while (!LIST_EMPTY(&flow->dev_flows)) { 1615 dev_flow = LIST_FIRST(&flow->dev_flows); 1616 LIST_REMOVE(dev_flow, next); 1617 rte_free(dev_flow); 1618 } 1619 if (flow->counter) { 1620 flow_verbs_counter_release(dev, flow->counter); 1621 flow->counter = NULL; 1622 } 1623 } 1624 1625 /** 1626 * Apply the flow to the NIC. 1627 * 1628 * @param[in] dev 1629 * Pointer to the Ethernet device structure. 1630 * @param[in, out] flow 1631 * Pointer to flow structure. 1632 * @param[out] error 1633 * Pointer to error structure. 1634 * 1635 * @return 1636 * 0 on success, a negative errno value otherwise and rte_errno is set. 1637 */ 1638 static int 1639 flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow, 1640 struct rte_flow_error *error) 1641 { 1642 struct mlx5_flow_verbs *verbs; 1643 struct mlx5_flow *dev_flow; 1644 int err; 1645 1646 LIST_FOREACH(dev_flow, &flow->dev_flows, next) { 1647 verbs = &dev_flow->verbs; 1648 if (flow->actions & MLX5_FLOW_ACTION_DROP) { 1649 verbs->hrxq = mlx5_hrxq_drop_new(dev); 1650 if (!verbs->hrxq) { 1651 rte_flow_error_set 1652 (error, errno, 1653 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1654 "cannot get drop hash queue"); 1655 goto error; 1656 } 1657 } else { 1658 struct mlx5_hrxq *hrxq; 1659 1660 hrxq = mlx5_hrxq_get(dev, flow->key, 1661 MLX5_RSS_HASH_KEY_LEN, 1662 verbs->hash_fields, 1663 (*flow->queue), 1664 flow->rss.queue_num); 1665 if (!hrxq) 1666 hrxq = mlx5_hrxq_new(dev, flow->key, 1667 MLX5_RSS_HASH_KEY_LEN, 1668 verbs->hash_fields, 1669 (*flow->queue), 1670 flow->rss.queue_num, 1671 !!(dev_flow->layers & 1672 MLX5_FLOW_LAYER_TUNNEL)); 1673 if (!hrxq) { 1674 rte_flow_error_set 1675 (error, rte_errno, 1676 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1677 "cannot get hash queue"); 1678 goto error; 1679 } 1680 verbs->hrxq = hrxq; 1681 } 1682 verbs->flow = mlx5_glue->create_flow(verbs->hrxq->qp, 1683 verbs->attr); 1684 if (!verbs->flow) { 1685 rte_flow_error_set(error, errno, 1686 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 1687 NULL, 1688 "hardware refuses to create flow"); 1689 goto error; 1690 } 1691 } 1692 return 0; 1693 error: 1694 err = rte_errno; /* Save rte_errno before cleanup. */ 1695 LIST_FOREACH(dev_flow, &flow->dev_flows, next) { 1696 verbs = &dev_flow->verbs; 1697 if (verbs->hrxq) { 1698 if (flow->actions & MLX5_FLOW_ACTION_DROP) 1699 mlx5_hrxq_drop_release(dev); 1700 else 1701 mlx5_hrxq_release(dev, verbs->hrxq); 1702 verbs->hrxq = NULL; 1703 } 1704 } 1705 rte_errno = err; /* Restore rte_errno. */ 1706 return -rte_errno; 1707 } 1708 1709 /** 1710 * Query a flow. 1711 * 1712 * @see rte_flow_query() 1713 * @see rte_flow_ops 1714 */ 1715 static int 1716 flow_verbs_query(struct rte_eth_dev *dev, 1717 struct rte_flow *flow, 1718 const struct rte_flow_action *actions, 1719 void *data, 1720 struct rte_flow_error *error) 1721 { 1722 int ret = -EINVAL; 1723 1724 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 1725 switch (actions->type) { 1726 case RTE_FLOW_ACTION_TYPE_VOID: 1727 break; 1728 case RTE_FLOW_ACTION_TYPE_COUNT: 1729 ret = flow_verbs_counter_query(dev, flow, data, error); 1730 break; 1731 default: 1732 return rte_flow_error_set(error, ENOTSUP, 1733 RTE_FLOW_ERROR_TYPE_ACTION, 1734 actions, 1735 "action not supported"); 1736 } 1737 } 1738 return ret; 1739 } 1740 1741 const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = { 1742 .validate = flow_verbs_validate, 1743 .prepare = flow_verbs_prepare, 1744 .translate = flow_verbs_translate, 1745 .apply = flow_verbs_apply, 1746 .remove = flow_verbs_remove, 1747 .destroy = flow_verbs_destroy, 1748 .query = flow_verbs_query, 1749 }; 1750