1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2018 Mellanox Technologies, Ltd 3 */ 4 5 #include <sys/queue.h> 6 #include <stdalign.h> 7 #include <stdint.h> 8 #include <string.h> 9 #include <unistd.h> 10 11 #include <rte_common.h> 12 #include <rte_ether.h> 13 #include <ethdev_driver.h> 14 #include <rte_flow.h> 15 #include <rte_flow_driver.h> 16 #include <rte_malloc.h> 17 #include <rte_cycles.h> 18 #include <rte_bus_pci.h> 19 #include <rte_ip.h> 20 #include <rte_gre.h> 21 #include <rte_vxlan.h> 22 #include <rte_gtp.h> 23 #include <rte_eal_paging.h> 24 #include <rte_mpls.h> 25 #include <rte_mtr.h> 26 #include <rte_mtr_driver.h> 27 #include <rte_tailq.h> 28 29 #include <mlx5_glue.h> 30 #include <mlx5_devx_cmds.h> 31 #include <mlx5_prm.h> 32 #include <mlx5_malloc.h> 33 34 #include "mlx5_defs.h" 35 #include "mlx5.h" 36 #include "mlx5_common_os.h" 37 #include "mlx5_flow.h" 38 #include "mlx5_flow_os.h" 39 #include "mlx5_rx.h" 40 #include "mlx5_tx.h" 41 #include "rte_pmd_mlx5.h" 42 43 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) 44 45 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS 46 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0 47 #endif 48 49 #ifndef HAVE_MLX5DV_DR_ESWITCH 50 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB 51 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0 52 #endif 53 #endif 54 55 #ifndef HAVE_MLX5DV_DR 56 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1 57 #endif 58 59 /* VLAN header definitions */ 60 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13 61 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT) 62 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff 63 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK) 64 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK) 65 66 union flow_dv_attr { 67 struct { 68 uint32_t valid:1; 69 uint32_t ipv4:1; 70 uint32_t ipv6:1; 71 uint32_t tcp:1; 72 uint32_t udp:1; 73 uint32_t reserved:27; 74 }; 75 uint32_t attr; 76 }; 77 78 static int 79 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 80 struct mlx5_flow_tbl_resource *tbl); 81 82 static int 83 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 84 uint32_t encap_decap_idx); 85 86 static int 87 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 88 uint32_t port_id); 89 static void 90 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss); 91 92 static int 93 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 94 uint32_t rix_jump); 95 96 static int16_t 97 flow_dv_get_esw_manager_vport_id(struct rte_eth_dev *dev) 98 { 99 struct mlx5_priv *priv = dev->data->dev_private; 100 101 if (priv->pci_dev == NULL) 102 return 0; 103 switch (priv->pci_dev->id.device_id) { 104 case PCI_DEVICE_ID_MELLANOX_CONNECTX5BF: 105 case PCI_DEVICE_ID_MELLANOX_CONNECTX6DXBF: 106 case PCI_DEVICE_ID_MELLANOX_CONNECTX7BF: 107 return (int16_t)0xfffe; 108 default: 109 return 0; 110 } 111 } 112 113 /** 114 * Initialize flow attributes structure according to flow items' types. 115 * 116 * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel 117 * mode. For tunnel mode, the items to be modified are the outermost ones. 118 * 119 * @param[in] item 120 * Pointer to item specification. 121 * @param[out] attr 122 * Pointer to flow attributes structure. 123 * @param[in] dev_flow 124 * Pointer to the sub flow. 125 * @param[in] tunnel_decap 126 * Whether action is after tunnel decapsulation. 127 */ 128 static void 129 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr, 130 struct mlx5_flow *dev_flow, bool tunnel_decap) 131 { 132 uint64_t layers = dev_flow->handle->layers; 133 134 /* 135 * If layers is already initialized, it means this dev_flow is the 136 * suffix flow, the layers flags is set by the prefix flow. Need to 137 * use the layer flags from prefix flow as the suffix flow may not 138 * have the user defined items as the flow is split. 139 */ 140 if (layers) { 141 if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4) 142 attr->ipv4 = 1; 143 else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6) 144 attr->ipv6 = 1; 145 if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP) 146 attr->tcp = 1; 147 else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP) 148 attr->udp = 1; 149 attr->valid = 1; 150 return; 151 } 152 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 153 uint8_t next_protocol = 0xff; 154 switch (item->type) { 155 case RTE_FLOW_ITEM_TYPE_GRE: 156 case RTE_FLOW_ITEM_TYPE_NVGRE: 157 case RTE_FLOW_ITEM_TYPE_VXLAN: 158 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 159 case RTE_FLOW_ITEM_TYPE_GENEVE: 160 case RTE_FLOW_ITEM_TYPE_MPLS: 161 if (tunnel_decap) 162 attr->attr = 0; 163 break; 164 case RTE_FLOW_ITEM_TYPE_IPV4: 165 if (!attr->ipv6) 166 attr->ipv4 = 1; 167 if (item->mask != NULL && 168 ((const struct rte_flow_item_ipv4 *) 169 item->mask)->hdr.next_proto_id) 170 next_protocol = 171 ((const struct rte_flow_item_ipv4 *) 172 (item->spec))->hdr.next_proto_id & 173 ((const struct rte_flow_item_ipv4 *) 174 (item->mask))->hdr.next_proto_id; 175 if ((next_protocol == IPPROTO_IPIP || 176 next_protocol == IPPROTO_IPV6) && tunnel_decap) 177 attr->attr = 0; 178 break; 179 case RTE_FLOW_ITEM_TYPE_IPV6: 180 if (!attr->ipv4) 181 attr->ipv6 = 1; 182 if (item->mask != NULL && 183 ((const struct rte_flow_item_ipv6 *) 184 item->mask)->hdr.proto) 185 next_protocol = 186 ((const struct rte_flow_item_ipv6 *) 187 (item->spec))->hdr.proto & 188 ((const struct rte_flow_item_ipv6 *) 189 (item->mask))->hdr.proto; 190 if ((next_protocol == IPPROTO_IPIP || 191 next_protocol == IPPROTO_IPV6) && tunnel_decap) 192 attr->attr = 0; 193 break; 194 case RTE_FLOW_ITEM_TYPE_UDP: 195 if (!attr->tcp) 196 attr->udp = 1; 197 break; 198 case RTE_FLOW_ITEM_TYPE_TCP: 199 if (!attr->udp) 200 attr->tcp = 1; 201 break; 202 default: 203 break; 204 } 205 } 206 attr->valid = 1; 207 } 208 209 /* 210 * Convert rte_mtr_color to mlx5 color. 211 * 212 * @param[in] rcol 213 * rte_mtr_color. 214 * 215 * @return 216 * mlx5 color. 217 */ 218 static inline int 219 rte_col_2_mlx5_col(enum rte_color rcol) 220 { 221 switch (rcol) { 222 case RTE_COLOR_GREEN: 223 return MLX5_FLOW_COLOR_GREEN; 224 case RTE_COLOR_YELLOW: 225 return MLX5_FLOW_COLOR_YELLOW; 226 case RTE_COLOR_RED: 227 return MLX5_FLOW_COLOR_RED; 228 default: 229 break; 230 } 231 return MLX5_FLOW_COLOR_UNDEFINED; 232 } 233 234 struct field_modify_info { 235 uint32_t size; /* Size of field in protocol header, in bytes. */ 236 uint32_t offset; /* Offset of field in protocol header, in bytes. */ 237 enum mlx5_modification_field id; 238 }; 239 240 struct field_modify_info modify_eth[] = { 241 {4, 0, MLX5_MODI_OUT_DMAC_47_16}, 242 {2, 4, MLX5_MODI_OUT_DMAC_15_0}, 243 {4, 6, MLX5_MODI_OUT_SMAC_47_16}, 244 {2, 10, MLX5_MODI_OUT_SMAC_15_0}, 245 {0, 0, 0}, 246 }; 247 248 struct field_modify_info modify_vlan_out_first_vid[] = { 249 /* Size in bits !!! */ 250 {12, 0, MLX5_MODI_OUT_FIRST_VID}, 251 {0, 0, 0}, 252 }; 253 254 struct field_modify_info modify_ipv4[] = { 255 {1, 1, MLX5_MODI_OUT_IP_DSCP}, 256 {1, 8, MLX5_MODI_OUT_IPV4_TTL}, 257 {4, 12, MLX5_MODI_OUT_SIPV4}, 258 {4, 16, MLX5_MODI_OUT_DIPV4}, 259 {0, 0, 0}, 260 }; 261 262 struct field_modify_info modify_ipv6[] = { 263 {1, 0, MLX5_MODI_OUT_IP_DSCP}, 264 {1, 7, MLX5_MODI_OUT_IPV6_HOPLIMIT}, 265 {4, 8, MLX5_MODI_OUT_SIPV6_127_96}, 266 {4, 12, MLX5_MODI_OUT_SIPV6_95_64}, 267 {4, 16, MLX5_MODI_OUT_SIPV6_63_32}, 268 {4, 20, MLX5_MODI_OUT_SIPV6_31_0}, 269 {4, 24, MLX5_MODI_OUT_DIPV6_127_96}, 270 {4, 28, MLX5_MODI_OUT_DIPV6_95_64}, 271 {4, 32, MLX5_MODI_OUT_DIPV6_63_32}, 272 {4, 36, MLX5_MODI_OUT_DIPV6_31_0}, 273 {0, 0, 0}, 274 }; 275 276 struct field_modify_info modify_udp[] = { 277 {2, 0, MLX5_MODI_OUT_UDP_SPORT}, 278 {2, 2, MLX5_MODI_OUT_UDP_DPORT}, 279 {0, 0, 0}, 280 }; 281 282 struct field_modify_info modify_tcp[] = { 283 {2, 0, MLX5_MODI_OUT_TCP_SPORT}, 284 {2, 2, MLX5_MODI_OUT_TCP_DPORT}, 285 {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM}, 286 {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM}, 287 {0, 0, 0}, 288 }; 289 290 static const struct rte_flow_item * 291 mlx5_flow_find_tunnel_item(const struct rte_flow_item *item) 292 { 293 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 294 switch (item->type) { 295 default: 296 break; 297 case RTE_FLOW_ITEM_TYPE_VXLAN: 298 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 299 case RTE_FLOW_ITEM_TYPE_GRE: 300 case RTE_FLOW_ITEM_TYPE_MPLS: 301 case RTE_FLOW_ITEM_TYPE_NVGRE: 302 case RTE_FLOW_ITEM_TYPE_GENEVE: 303 return item; 304 case RTE_FLOW_ITEM_TYPE_IPV4: 305 case RTE_FLOW_ITEM_TYPE_IPV6: 306 if (item[1].type == RTE_FLOW_ITEM_TYPE_IPV4 || 307 item[1].type == RTE_FLOW_ITEM_TYPE_IPV6) 308 return item; 309 break; 310 } 311 } 312 return NULL; 313 } 314 315 static void 316 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused, 317 uint8_t next_protocol, uint64_t *item_flags, 318 int *tunnel) 319 { 320 MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 || 321 item->type == RTE_FLOW_ITEM_TYPE_IPV6); 322 if (next_protocol == IPPROTO_IPIP) { 323 *item_flags |= MLX5_FLOW_LAYER_IPIP; 324 *tunnel = 1; 325 } 326 if (next_protocol == IPPROTO_IPV6) { 327 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP; 328 *tunnel = 1; 329 } 330 } 331 332 static inline struct mlx5_hlist * 333 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl, 334 const char *name, uint32_t size, bool direct_key, 335 bool lcores_share, void *ctx, 336 mlx5_list_create_cb cb_create, 337 mlx5_list_match_cb cb_match, 338 mlx5_list_remove_cb cb_remove, 339 mlx5_list_clone_cb cb_clone, 340 mlx5_list_clone_free_cb cb_clone_free) 341 { 342 struct mlx5_hlist *hl; 343 struct mlx5_hlist *expected = NULL; 344 char s[MLX5_NAME_SIZE]; 345 346 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 347 if (likely(hl)) 348 return hl; 349 snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name); 350 hl = mlx5_hlist_create(s, size, direct_key, lcores_share, 351 ctx, cb_create, cb_match, cb_remove, cb_clone, 352 cb_clone_free); 353 if (!hl) { 354 DRV_LOG(ERR, "%s hash creation failed", name); 355 rte_errno = ENOMEM; 356 return NULL; 357 } 358 if (!__atomic_compare_exchange_n(phl, &expected, hl, false, 359 __ATOMIC_SEQ_CST, 360 __ATOMIC_SEQ_CST)) { 361 mlx5_hlist_destroy(hl); 362 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 363 } 364 return hl; 365 } 366 367 /* Update VLAN's VID/PCP based on input rte_flow_action. 368 * 369 * @param[in] action 370 * Pointer to struct rte_flow_action. 371 * @param[out] vlan 372 * Pointer to struct rte_vlan_hdr. 373 */ 374 static void 375 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, 376 struct rte_vlan_hdr *vlan) 377 { 378 uint16_t vlan_tci; 379 if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) { 380 vlan_tci = 381 ((const struct rte_flow_action_of_set_vlan_pcp *) 382 action->conf)->vlan_pcp; 383 vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT; 384 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 385 vlan->vlan_tci |= vlan_tci; 386 } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) { 387 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 388 vlan->vlan_tci |= rte_be_to_cpu_16 389 (((const struct rte_flow_action_of_set_vlan_vid *) 390 action->conf)->vlan_vid); 391 } 392 } 393 394 /** 395 * Fetch 1, 2, 3 or 4 byte field from the byte array 396 * and return as unsigned integer in host-endian format. 397 * 398 * @param[in] data 399 * Pointer to data array. 400 * @param[in] size 401 * Size of field to extract. 402 * 403 * @return 404 * converted field in host endian format. 405 */ 406 static inline uint32_t 407 flow_dv_fetch_field(const uint8_t *data, uint32_t size) 408 { 409 uint32_t ret; 410 411 switch (size) { 412 case 1: 413 ret = *data; 414 break; 415 case 2: 416 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 417 break; 418 case 3: 419 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 420 ret = (ret << 8) | *(data + sizeof(uint16_t)); 421 break; 422 case 4: 423 ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); 424 break; 425 default: 426 MLX5_ASSERT(false); 427 ret = 0; 428 break; 429 } 430 return ret; 431 } 432 433 /** 434 * Convert modify-header action to DV specification. 435 * 436 * Data length of each action is determined by provided field description 437 * and the item mask. Data bit offset and width of each action is determined 438 * by provided item mask. 439 * 440 * @param[in] item 441 * Pointer to item specification. 442 * @param[in] field 443 * Pointer to field modification information. 444 * For MLX5_MODIFICATION_TYPE_SET specifies destination field. 445 * For MLX5_MODIFICATION_TYPE_ADD specifies destination field. 446 * For MLX5_MODIFICATION_TYPE_COPY specifies source field. 447 * @param[in] dcopy 448 * Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type. 449 * Negative offset value sets the same offset as source offset. 450 * size field is ignored, value is taken from source field. 451 * @param[in,out] resource 452 * Pointer to the modify-header resource. 453 * @param[in] type 454 * Type of modification. 455 * @param[out] error 456 * Pointer to the error structure. 457 * 458 * @return 459 * 0 on success, a negative errno value otherwise and rte_errno is set. 460 */ 461 static int 462 flow_dv_convert_modify_action(struct rte_flow_item *item, 463 struct field_modify_info *field, 464 struct field_modify_info *dcopy, 465 struct mlx5_flow_dv_modify_hdr_resource *resource, 466 uint32_t type, struct rte_flow_error *error) 467 { 468 uint32_t i = resource->actions_num; 469 struct mlx5_modification_cmd *actions = resource->actions; 470 uint32_t carry_b = 0; 471 472 /* 473 * The item and mask are provided in big-endian format. 474 * The fields should be presented as in big-endian format either. 475 * Mask must be always present, it defines the actual field width. 476 */ 477 MLX5_ASSERT(item->mask); 478 MLX5_ASSERT(field->size); 479 do { 480 uint32_t size_b; 481 uint32_t off_b; 482 uint32_t mask; 483 uint32_t data; 484 bool next_field = true; 485 bool next_dcopy = true; 486 487 if (i >= MLX5_MAX_MODIFY_NUM) 488 return rte_flow_error_set(error, EINVAL, 489 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 490 "too many items to modify"); 491 /* Fetch variable byte size mask from the array. */ 492 mask = flow_dv_fetch_field((const uint8_t *)item->mask + 493 field->offset, field->size); 494 if (!mask) { 495 ++field; 496 continue; 497 } 498 /* Deduce actual data width in bits from mask value. */ 499 off_b = rte_bsf32(mask) + carry_b; 500 size_b = sizeof(uint32_t) * CHAR_BIT - 501 off_b - __builtin_clz(mask); 502 MLX5_ASSERT(size_b); 503 actions[i] = (struct mlx5_modification_cmd) { 504 .action_type = type, 505 .field = field->id, 506 .offset = off_b, 507 .length = (size_b == sizeof(uint32_t) * CHAR_BIT) ? 508 0 : size_b, 509 }; 510 if (type == MLX5_MODIFICATION_TYPE_COPY) { 511 MLX5_ASSERT(dcopy); 512 actions[i].dst_field = dcopy->id; 513 actions[i].dst_offset = 514 (int)dcopy->offset < 0 ? off_b : dcopy->offset; 515 /* Convert entire record to big-endian format. */ 516 actions[i].data1 = rte_cpu_to_be_32(actions[i].data1); 517 /* 518 * Destination field overflow. Copy leftovers of 519 * a source field to the next destination field. 520 */ 521 carry_b = 0; 522 if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) && 523 dcopy->size != 0) { 524 actions[i].length = 525 dcopy->size * CHAR_BIT - dcopy->offset; 526 carry_b = actions[i].length; 527 next_field = false; 528 } 529 /* 530 * Not enough bits in a source filed to fill a 531 * destination field. Switch to the next source. 532 */ 533 if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) && 534 (size_b == field->size * CHAR_BIT - off_b)) { 535 actions[i].length = 536 field->size * CHAR_BIT - off_b; 537 dcopy->offset += actions[i].length; 538 next_dcopy = false; 539 } 540 if (next_dcopy) 541 ++dcopy; 542 } else { 543 MLX5_ASSERT(item->spec); 544 data = flow_dv_fetch_field((const uint8_t *)item->spec + 545 field->offset, field->size); 546 /* Shift out the trailing masked bits from data. */ 547 data = (data & mask) >> off_b; 548 actions[i].data1 = rte_cpu_to_be_32(data); 549 } 550 /* Convert entire record to expected big-endian format. */ 551 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 552 if (next_field) 553 ++field; 554 ++i; 555 } while (field->size); 556 if (resource->actions_num == i) 557 return rte_flow_error_set(error, EINVAL, 558 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 559 "invalid modification flow item"); 560 resource->actions_num = i; 561 return 0; 562 } 563 564 /** 565 * Convert modify-header set IPv4 address action to DV specification. 566 * 567 * @param[in,out] resource 568 * Pointer to the modify-header resource. 569 * @param[in] action 570 * Pointer to action specification. 571 * @param[out] error 572 * Pointer to the error structure. 573 * 574 * @return 575 * 0 on success, a negative errno value otherwise and rte_errno is set. 576 */ 577 static int 578 flow_dv_convert_action_modify_ipv4 579 (struct mlx5_flow_dv_modify_hdr_resource *resource, 580 const struct rte_flow_action *action, 581 struct rte_flow_error *error) 582 { 583 const struct rte_flow_action_set_ipv4 *conf = 584 (const struct rte_flow_action_set_ipv4 *)(action->conf); 585 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 586 struct rte_flow_item_ipv4 ipv4; 587 struct rte_flow_item_ipv4 ipv4_mask; 588 589 memset(&ipv4, 0, sizeof(ipv4)); 590 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 591 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) { 592 ipv4.hdr.src_addr = conf->ipv4_addr; 593 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr; 594 } else { 595 ipv4.hdr.dst_addr = conf->ipv4_addr; 596 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr; 597 } 598 item.spec = &ipv4; 599 item.mask = &ipv4_mask; 600 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 601 MLX5_MODIFICATION_TYPE_SET, error); 602 } 603 604 /** 605 * Convert modify-header set IPv6 address action to DV specification. 606 * 607 * @param[in,out] resource 608 * Pointer to the modify-header resource. 609 * @param[in] action 610 * Pointer to action specification. 611 * @param[out] error 612 * Pointer to the error structure. 613 * 614 * @return 615 * 0 on success, a negative errno value otherwise and rte_errno is set. 616 */ 617 static int 618 flow_dv_convert_action_modify_ipv6 619 (struct mlx5_flow_dv_modify_hdr_resource *resource, 620 const struct rte_flow_action *action, 621 struct rte_flow_error *error) 622 { 623 const struct rte_flow_action_set_ipv6 *conf = 624 (const struct rte_flow_action_set_ipv6 *)(action->conf); 625 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 626 struct rte_flow_item_ipv6 ipv6; 627 struct rte_flow_item_ipv6 ipv6_mask; 628 629 memset(&ipv6, 0, sizeof(ipv6)); 630 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 631 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) { 632 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr, 633 sizeof(ipv6.hdr.src_addr)); 634 memcpy(&ipv6_mask.hdr.src_addr, 635 &rte_flow_item_ipv6_mask.hdr.src_addr, 636 sizeof(ipv6.hdr.src_addr)); 637 } else { 638 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr, 639 sizeof(ipv6.hdr.dst_addr)); 640 memcpy(&ipv6_mask.hdr.dst_addr, 641 &rte_flow_item_ipv6_mask.hdr.dst_addr, 642 sizeof(ipv6.hdr.dst_addr)); 643 } 644 item.spec = &ipv6; 645 item.mask = &ipv6_mask; 646 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 647 MLX5_MODIFICATION_TYPE_SET, error); 648 } 649 650 /** 651 * Convert modify-header set MAC address action to DV specification. 652 * 653 * @param[in,out] resource 654 * Pointer to the modify-header resource. 655 * @param[in] action 656 * Pointer to action specification. 657 * @param[out] error 658 * Pointer to the error structure. 659 * 660 * @return 661 * 0 on success, a negative errno value otherwise and rte_errno is set. 662 */ 663 static int 664 flow_dv_convert_action_modify_mac 665 (struct mlx5_flow_dv_modify_hdr_resource *resource, 666 const struct rte_flow_action *action, 667 struct rte_flow_error *error) 668 { 669 const struct rte_flow_action_set_mac *conf = 670 (const struct rte_flow_action_set_mac *)(action->conf); 671 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH }; 672 struct rte_flow_item_eth eth; 673 struct rte_flow_item_eth eth_mask; 674 675 memset(ð, 0, sizeof(eth)); 676 memset(ð_mask, 0, sizeof(eth_mask)); 677 if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) { 678 memcpy(ð.src.addr_bytes, &conf->mac_addr, 679 sizeof(eth.src.addr_bytes)); 680 memcpy(ð_mask.src.addr_bytes, 681 &rte_flow_item_eth_mask.src.addr_bytes, 682 sizeof(eth_mask.src.addr_bytes)); 683 } else { 684 memcpy(ð.dst.addr_bytes, &conf->mac_addr, 685 sizeof(eth.dst.addr_bytes)); 686 memcpy(ð_mask.dst.addr_bytes, 687 &rte_flow_item_eth_mask.dst.addr_bytes, 688 sizeof(eth_mask.dst.addr_bytes)); 689 } 690 item.spec = ð 691 item.mask = ð_mask; 692 return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource, 693 MLX5_MODIFICATION_TYPE_SET, error); 694 } 695 696 /** 697 * Convert modify-header set VLAN VID action to DV specification. 698 * 699 * @param[in,out] resource 700 * Pointer to the modify-header resource. 701 * @param[in] action 702 * Pointer to action specification. 703 * @param[out] error 704 * Pointer to the error structure. 705 * 706 * @return 707 * 0 on success, a negative errno value otherwise and rte_errno is set. 708 */ 709 static int 710 flow_dv_convert_action_modify_vlan_vid 711 (struct mlx5_flow_dv_modify_hdr_resource *resource, 712 const struct rte_flow_action *action, 713 struct rte_flow_error *error) 714 { 715 const struct rte_flow_action_of_set_vlan_vid *conf = 716 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf); 717 int i = resource->actions_num; 718 struct mlx5_modification_cmd *actions = resource->actions; 719 struct field_modify_info *field = modify_vlan_out_first_vid; 720 721 if (i >= MLX5_MAX_MODIFY_NUM) 722 return rte_flow_error_set(error, EINVAL, 723 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 724 "too many items to modify"); 725 actions[i] = (struct mlx5_modification_cmd) { 726 .action_type = MLX5_MODIFICATION_TYPE_SET, 727 .field = field->id, 728 .length = field->size, 729 .offset = field->offset, 730 }; 731 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 732 actions[i].data1 = conf->vlan_vid; 733 actions[i].data1 = actions[i].data1 << 16; 734 resource->actions_num = ++i; 735 return 0; 736 } 737 738 /** 739 * Convert modify-header set TP action to DV specification. 740 * 741 * @param[in,out] resource 742 * Pointer to the modify-header resource. 743 * @param[in] action 744 * Pointer to action specification. 745 * @param[in] items 746 * Pointer to rte_flow_item objects list. 747 * @param[in] attr 748 * Pointer to flow attributes structure. 749 * @param[in] dev_flow 750 * Pointer to the sub flow. 751 * @param[in] tunnel_decap 752 * Whether action is after tunnel decapsulation. 753 * @param[out] error 754 * Pointer to the error structure. 755 * 756 * @return 757 * 0 on success, a negative errno value otherwise and rte_errno is set. 758 */ 759 static int 760 flow_dv_convert_action_modify_tp 761 (struct mlx5_flow_dv_modify_hdr_resource *resource, 762 const struct rte_flow_action *action, 763 const struct rte_flow_item *items, 764 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 765 bool tunnel_decap, struct rte_flow_error *error) 766 { 767 const struct rte_flow_action_set_tp *conf = 768 (const struct rte_flow_action_set_tp *)(action->conf); 769 struct rte_flow_item item; 770 struct rte_flow_item_udp udp; 771 struct rte_flow_item_udp udp_mask; 772 struct rte_flow_item_tcp tcp; 773 struct rte_flow_item_tcp tcp_mask; 774 struct field_modify_info *field; 775 776 if (!attr->valid) 777 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 778 if (attr->udp) { 779 memset(&udp, 0, sizeof(udp)); 780 memset(&udp_mask, 0, sizeof(udp_mask)); 781 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 782 udp.hdr.src_port = conf->port; 783 udp_mask.hdr.src_port = 784 rte_flow_item_udp_mask.hdr.src_port; 785 } else { 786 udp.hdr.dst_port = conf->port; 787 udp_mask.hdr.dst_port = 788 rte_flow_item_udp_mask.hdr.dst_port; 789 } 790 item.type = RTE_FLOW_ITEM_TYPE_UDP; 791 item.spec = &udp; 792 item.mask = &udp_mask; 793 field = modify_udp; 794 } else { 795 MLX5_ASSERT(attr->tcp); 796 memset(&tcp, 0, sizeof(tcp)); 797 memset(&tcp_mask, 0, sizeof(tcp_mask)); 798 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 799 tcp.hdr.src_port = conf->port; 800 tcp_mask.hdr.src_port = 801 rte_flow_item_tcp_mask.hdr.src_port; 802 } else { 803 tcp.hdr.dst_port = conf->port; 804 tcp_mask.hdr.dst_port = 805 rte_flow_item_tcp_mask.hdr.dst_port; 806 } 807 item.type = RTE_FLOW_ITEM_TYPE_TCP; 808 item.spec = &tcp; 809 item.mask = &tcp_mask; 810 field = modify_tcp; 811 } 812 return flow_dv_convert_modify_action(&item, field, NULL, resource, 813 MLX5_MODIFICATION_TYPE_SET, error); 814 } 815 816 /** 817 * Convert modify-header set TTL action to DV specification. 818 * 819 * @param[in,out] resource 820 * Pointer to the modify-header resource. 821 * @param[in] action 822 * Pointer to action specification. 823 * @param[in] items 824 * Pointer to rte_flow_item objects list. 825 * @param[in] attr 826 * Pointer to flow attributes structure. 827 * @param[in] dev_flow 828 * Pointer to the sub flow. 829 * @param[in] tunnel_decap 830 * Whether action is after tunnel decapsulation. 831 * @param[out] error 832 * Pointer to the error structure. 833 * 834 * @return 835 * 0 on success, a negative errno value otherwise and rte_errno is set. 836 */ 837 static int 838 flow_dv_convert_action_modify_ttl 839 (struct mlx5_flow_dv_modify_hdr_resource *resource, 840 const struct rte_flow_action *action, 841 const struct rte_flow_item *items, 842 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 843 bool tunnel_decap, struct rte_flow_error *error) 844 { 845 const struct rte_flow_action_set_ttl *conf = 846 (const struct rte_flow_action_set_ttl *)(action->conf); 847 struct rte_flow_item item; 848 struct rte_flow_item_ipv4 ipv4; 849 struct rte_flow_item_ipv4 ipv4_mask; 850 struct rte_flow_item_ipv6 ipv6; 851 struct rte_flow_item_ipv6 ipv6_mask; 852 struct field_modify_info *field; 853 854 if (!attr->valid) 855 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 856 if (attr->ipv4) { 857 memset(&ipv4, 0, sizeof(ipv4)); 858 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 859 ipv4.hdr.time_to_live = conf->ttl_value; 860 ipv4_mask.hdr.time_to_live = 0xFF; 861 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 862 item.spec = &ipv4; 863 item.mask = &ipv4_mask; 864 field = modify_ipv4; 865 } else { 866 MLX5_ASSERT(attr->ipv6); 867 memset(&ipv6, 0, sizeof(ipv6)); 868 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 869 ipv6.hdr.hop_limits = conf->ttl_value; 870 ipv6_mask.hdr.hop_limits = 0xFF; 871 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 872 item.spec = &ipv6; 873 item.mask = &ipv6_mask; 874 field = modify_ipv6; 875 } 876 return flow_dv_convert_modify_action(&item, field, NULL, resource, 877 MLX5_MODIFICATION_TYPE_SET, error); 878 } 879 880 /** 881 * Convert modify-header decrement TTL action to DV specification. 882 * 883 * @param[in,out] resource 884 * Pointer to the modify-header resource. 885 * @param[in] action 886 * Pointer to action specification. 887 * @param[in] items 888 * Pointer to rte_flow_item objects list. 889 * @param[in] attr 890 * Pointer to flow attributes structure. 891 * @param[in] dev_flow 892 * Pointer to the sub flow. 893 * @param[in] tunnel_decap 894 * Whether action is after tunnel decapsulation. 895 * @param[out] error 896 * Pointer to the error structure. 897 * 898 * @return 899 * 0 on success, a negative errno value otherwise and rte_errno is set. 900 */ 901 static int 902 flow_dv_convert_action_modify_dec_ttl 903 (struct mlx5_flow_dv_modify_hdr_resource *resource, 904 const struct rte_flow_item *items, 905 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 906 bool tunnel_decap, struct rte_flow_error *error) 907 { 908 struct rte_flow_item item; 909 struct rte_flow_item_ipv4 ipv4; 910 struct rte_flow_item_ipv4 ipv4_mask; 911 struct rte_flow_item_ipv6 ipv6; 912 struct rte_flow_item_ipv6 ipv6_mask; 913 struct field_modify_info *field; 914 915 if (!attr->valid) 916 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 917 if (attr->ipv4) { 918 memset(&ipv4, 0, sizeof(ipv4)); 919 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 920 ipv4.hdr.time_to_live = 0xFF; 921 ipv4_mask.hdr.time_to_live = 0xFF; 922 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 923 item.spec = &ipv4; 924 item.mask = &ipv4_mask; 925 field = modify_ipv4; 926 } else { 927 MLX5_ASSERT(attr->ipv6); 928 memset(&ipv6, 0, sizeof(ipv6)); 929 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 930 ipv6.hdr.hop_limits = 0xFF; 931 ipv6_mask.hdr.hop_limits = 0xFF; 932 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 933 item.spec = &ipv6; 934 item.mask = &ipv6_mask; 935 field = modify_ipv6; 936 } 937 return flow_dv_convert_modify_action(&item, field, NULL, resource, 938 MLX5_MODIFICATION_TYPE_ADD, error); 939 } 940 941 /** 942 * Convert modify-header increment/decrement TCP Sequence number 943 * to DV specification. 944 * 945 * @param[in,out] resource 946 * Pointer to the modify-header resource. 947 * @param[in] action 948 * Pointer to action specification. 949 * @param[out] error 950 * Pointer to the error structure. 951 * 952 * @return 953 * 0 on success, a negative errno value otherwise and rte_errno is set. 954 */ 955 static int 956 flow_dv_convert_action_modify_tcp_seq 957 (struct mlx5_flow_dv_modify_hdr_resource *resource, 958 const struct rte_flow_action *action, 959 struct rte_flow_error *error) 960 { 961 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 962 uint64_t value = rte_be_to_cpu_32(*conf); 963 struct rte_flow_item item; 964 struct rte_flow_item_tcp tcp; 965 struct rte_flow_item_tcp tcp_mask; 966 967 memset(&tcp, 0, sizeof(tcp)); 968 memset(&tcp_mask, 0, sizeof(tcp_mask)); 969 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ) 970 /* 971 * The HW has no decrement operation, only increment operation. 972 * To simulate decrement X from Y using increment operation 973 * we need to add UINT32_MAX X times to Y. 974 * Each adding of UINT32_MAX decrements Y by 1. 975 */ 976 value *= UINT32_MAX; 977 tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value); 978 tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX); 979 item.type = RTE_FLOW_ITEM_TYPE_TCP; 980 item.spec = &tcp; 981 item.mask = &tcp_mask; 982 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 983 MLX5_MODIFICATION_TYPE_ADD, error); 984 } 985 986 /** 987 * Convert modify-header increment/decrement TCP Acknowledgment number 988 * to DV specification. 989 * 990 * @param[in,out] resource 991 * Pointer to the modify-header resource. 992 * @param[in] action 993 * Pointer to action specification. 994 * @param[out] error 995 * Pointer to the error structure. 996 * 997 * @return 998 * 0 on success, a negative errno value otherwise and rte_errno is set. 999 */ 1000 static int 1001 flow_dv_convert_action_modify_tcp_ack 1002 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1003 const struct rte_flow_action *action, 1004 struct rte_flow_error *error) 1005 { 1006 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 1007 uint64_t value = rte_be_to_cpu_32(*conf); 1008 struct rte_flow_item item; 1009 struct rte_flow_item_tcp tcp; 1010 struct rte_flow_item_tcp tcp_mask; 1011 1012 memset(&tcp, 0, sizeof(tcp)); 1013 memset(&tcp_mask, 0, sizeof(tcp_mask)); 1014 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK) 1015 /* 1016 * The HW has no decrement operation, only increment operation. 1017 * To simulate decrement X from Y using increment operation 1018 * we need to add UINT32_MAX X times to Y. 1019 * Each adding of UINT32_MAX decrements Y by 1. 1020 */ 1021 value *= UINT32_MAX; 1022 tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value); 1023 tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX); 1024 item.type = RTE_FLOW_ITEM_TYPE_TCP; 1025 item.spec = &tcp; 1026 item.mask = &tcp_mask; 1027 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 1028 MLX5_MODIFICATION_TYPE_ADD, error); 1029 } 1030 1031 static enum mlx5_modification_field reg_to_field[] = { 1032 [REG_NON] = MLX5_MODI_OUT_NONE, 1033 [REG_A] = MLX5_MODI_META_DATA_REG_A, 1034 [REG_B] = MLX5_MODI_META_DATA_REG_B, 1035 [REG_C_0] = MLX5_MODI_META_REG_C_0, 1036 [REG_C_1] = MLX5_MODI_META_REG_C_1, 1037 [REG_C_2] = MLX5_MODI_META_REG_C_2, 1038 [REG_C_3] = MLX5_MODI_META_REG_C_3, 1039 [REG_C_4] = MLX5_MODI_META_REG_C_4, 1040 [REG_C_5] = MLX5_MODI_META_REG_C_5, 1041 [REG_C_6] = MLX5_MODI_META_REG_C_6, 1042 [REG_C_7] = MLX5_MODI_META_REG_C_7, 1043 }; 1044 1045 /** 1046 * Convert register set to DV specification. 1047 * 1048 * @param[in,out] resource 1049 * Pointer to the modify-header resource. 1050 * @param[in] action 1051 * Pointer to action specification. 1052 * @param[out] error 1053 * Pointer to the error structure. 1054 * 1055 * @return 1056 * 0 on success, a negative errno value otherwise and rte_errno is set. 1057 */ 1058 static int 1059 flow_dv_convert_action_set_reg 1060 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1061 const struct rte_flow_action *action, 1062 struct rte_flow_error *error) 1063 { 1064 const struct mlx5_rte_flow_action_set_tag *conf = action->conf; 1065 struct mlx5_modification_cmd *actions = resource->actions; 1066 uint32_t i = resource->actions_num; 1067 1068 if (i >= MLX5_MAX_MODIFY_NUM) 1069 return rte_flow_error_set(error, EINVAL, 1070 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 1071 "too many items to modify"); 1072 MLX5_ASSERT(conf->id != REG_NON); 1073 MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field)); 1074 actions[i] = (struct mlx5_modification_cmd) { 1075 .action_type = MLX5_MODIFICATION_TYPE_SET, 1076 .field = reg_to_field[conf->id], 1077 .offset = conf->offset, 1078 .length = conf->length, 1079 }; 1080 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 1081 actions[i].data1 = rte_cpu_to_be_32(conf->data); 1082 ++i; 1083 resource->actions_num = i; 1084 return 0; 1085 } 1086 1087 /** 1088 * Convert SET_TAG action to DV specification. 1089 * 1090 * @param[in] dev 1091 * Pointer to the rte_eth_dev structure. 1092 * @param[in,out] resource 1093 * Pointer to the modify-header resource. 1094 * @param[in] conf 1095 * Pointer to action specification. 1096 * @param[out] error 1097 * Pointer to the error structure. 1098 * 1099 * @return 1100 * 0 on success, a negative errno value otherwise and rte_errno is set. 1101 */ 1102 static int 1103 flow_dv_convert_action_set_tag 1104 (struct rte_eth_dev *dev, 1105 struct mlx5_flow_dv_modify_hdr_resource *resource, 1106 const struct rte_flow_action_set_tag *conf, 1107 struct rte_flow_error *error) 1108 { 1109 rte_be32_t data = rte_cpu_to_be_32(conf->data); 1110 rte_be32_t mask = rte_cpu_to_be_32(conf->mask); 1111 struct rte_flow_item item = { 1112 .spec = &data, 1113 .mask = &mask, 1114 }; 1115 struct field_modify_info reg_c_x[] = { 1116 [1] = {0, 0, 0}, 1117 }; 1118 enum mlx5_modification_field reg_type; 1119 int ret; 1120 1121 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 1122 if (ret < 0) 1123 return ret; 1124 MLX5_ASSERT(ret != REG_NON); 1125 MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field)); 1126 reg_type = reg_to_field[ret]; 1127 MLX5_ASSERT(reg_type > 0); 1128 reg_c_x[0] = (struct field_modify_info){4, 0, reg_type}; 1129 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1130 MLX5_MODIFICATION_TYPE_SET, error); 1131 } 1132 1133 /** 1134 * Convert internal COPY_REG action to DV specification. 1135 * 1136 * @param[in] dev 1137 * Pointer to the rte_eth_dev structure. 1138 * @param[in,out] res 1139 * Pointer to the modify-header resource. 1140 * @param[in] action 1141 * Pointer to action specification. 1142 * @param[out] error 1143 * Pointer to the error structure. 1144 * 1145 * @return 1146 * 0 on success, a negative errno value otherwise and rte_errno is set. 1147 */ 1148 static int 1149 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev, 1150 struct mlx5_flow_dv_modify_hdr_resource *res, 1151 const struct rte_flow_action *action, 1152 struct rte_flow_error *error) 1153 { 1154 const struct mlx5_flow_action_copy_mreg *conf = action->conf; 1155 rte_be32_t mask = RTE_BE32(UINT32_MAX); 1156 struct rte_flow_item item = { 1157 .spec = NULL, 1158 .mask = &mask, 1159 }; 1160 struct field_modify_info reg_src[] = { 1161 {4, 0, reg_to_field[conf->src]}, 1162 {0, 0, 0}, 1163 }; 1164 struct field_modify_info reg_dst = { 1165 .offset = 0, 1166 .id = reg_to_field[conf->dst], 1167 }; 1168 /* Adjust reg_c[0] usage according to reported mask. */ 1169 if (conf->dst == REG_C_0 || conf->src == REG_C_0) { 1170 struct mlx5_priv *priv = dev->data->dev_private; 1171 uint32_t reg_c0 = priv->sh->dv_regc0_mask; 1172 1173 MLX5_ASSERT(reg_c0); 1174 MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY); 1175 if (conf->dst == REG_C_0) { 1176 /* Copy to reg_c[0], within mask only. */ 1177 reg_dst.offset = rte_bsf32(reg_c0); 1178 mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset); 1179 } else { 1180 reg_dst.offset = 0; 1181 mask = rte_cpu_to_be_32(reg_c0); 1182 } 1183 } 1184 return flow_dv_convert_modify_action(&item, 1185 reg_src, ®_dst, res, 1186 MLX5_MODIFICATION_TYPE_COPY, 1187 error); 1188 } 1189 1190 /** 1191 * Convert MARK action to DV specification. This routine is used 1192 * in extensive metadata only and requires metadata register to be 1193 * handled. In legacy mode hardware tag resource is engaged. 1194 * 1195 * @param[in] dev 1196 * Pointer to the rte_eth_dev structure. 1197 * @param[in] conf 1198 * Pointer to MARK action specification. 1199 * @param[in,out] resource 1200 * Pointer to the modify-header resource. 1201 * @param[out] error 1202 * Pointer to the error structure. 1203 * 1204 * @return 1205 * 0 on success, a negative errno value otherwise and rte_errno is set. 1206 */ 1207 static int 1208 flow_dv_convert_action_mark(struct rte_eth_dev *dev, 1209 const struct rte_flow_action_mark *conf, 1210 struct mlx5_flow_dv_modify_hdr_resource *resource, 1211 struct rte_flow_error *error) 1212 { 1213 struct mlx5_priv *priv = dev->data->dev_private; 1214 rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK & 1215 priv->sh->dv_mark_mask); 1216 rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask; 1217 struct rte_flow_item item = { 1218 .spec = &data, 1219 .mask = &mask, 1220 }; 1221 struct field_modify_info reg_c_x[] = { 1222 [1] = {0, 0, 0}, 1223 }; 1224 int reg; 1225 1226 if (!mask) 1227 return rte_flow_error_set(error, EINVAL, 1228 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1229 NULL, "zero mark action mask"); 1230 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1231 if (reg < 0) 1232 return reg; 1233 MLX5_ASSERT(reg > 0); 1234 if (reg == REG_C_0) { 1235 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1236 uint32_t shl_c0 = rte_bsf32(msk_c0); 1237 1238 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1239 mask = rte_cpu_to_be_32(mask) & msk_c0; 1240 mask = rte_cpu_to_be_32(mask << shl_c0); 1241 } 1242 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1243 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1244 MLX5_MODIFICATION_TYPE_SET, error); 1245 } 1246 1247 /** 1248 * Get metadata register index for specified steering domain. 1249 * 1250 * @param[in] dev 1251 * Pointer to the rte_eth_dev structure. 1252 * @param[in] attr 1253 * Attributes of flow to determine steering domain. 1254 * @param[out] error 1255 * Pointer to the error structure. 1256 * 1257 * @return 1258 * positive index on success, a negative errno value otherwise 1259 * and rte_errno is set. 1260 */ 1261 static enum modify_reg 1262 flow_dv_get_metadata_reg(struct rte_eth_dev *dev, 1263 const struct rte_flow_attr *attr, 1264 struct rte_flow_error *error) 1265 { 1266 int reg = 1267 mlx5_flow_get_reg_id(dev, attr->transfer ? 1268 MLX5_METADATA_FDB : 1269 attr->egress ? 1270 MLX5_METADATA_TX : 1271 MLX5_METADATA_RX, 0, error); 1272 if (reg < 0) 1273 return rte_flow_error_set(error, 1274 ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, 1275 NULL, "unavailable " 1276 "metadata register"); 1277 return reg; 1278 } 1279 1280 /** 1281 * Convert SET_META action to DV specification. 1282 * 1283 * @param[in] dev 1284 * Pointer to the rte_eth_dev structure. 1285 * @param[in,out] resource 1286 * Pointer to the modify-header resource. 1287 * @param[in] attr 1288 * Attributes of flow that includes this item. 1289 * @param[in] conf 1290 * Pointer to action specification. 1291 * @param[out] error 1292 * Pointer to the error structure. 1293 * 1294 * @return 1295 * 0 on success, a negative errno value otherwise and rte_errno is set. 1296 */ 1297 static int 1298 flow_dv_convert_action_set_meta 1299 (struct rte_eth_dev *dev, 1300 struct mlx5_flow_dv_modify_hdr_resource *resource, 1301 const struct rte_flow_attr *attr, 1302 const struct rte_flow_action_set_meta *conf, 1303 struct rte_flow_error *error) 1304 { 1305 uint32_t mask = rte_cpu_to_be_32(conf->mask); 1306 uint32_t data = rte_cpu_to_be_32(conf->data) & mask; 1307 struct rte_flow_item item = { 1308 .spec = &data, 1309 .mask = &mask, 1310 }; 1311 struct field_modify_info reg_c_x[] = { 1312 [1] = {0, 0, 0}, 1313 }; 1314 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1315 1316 if (reg < 0) 1317 return reg; 1318 MLX5_ASSERT(reg != REG_NON); 1319 if (reg == REG_C_0) { 1320 struct mlx5_priv *priv = dev->data->dev_private; 1321 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1322 uint32_t shl_c0 = rte_bsf32(msk_c0); 1323 1324 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1325 mask = rte_cpu_to_be_32(mask) & msk_c0; 1326 mask = rte_cpu_to_be_32(mask << shl_c0); 1327 } 1328 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1329 /* The routine expects parameters in memory as big-endian ones. */ 1330 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1331 MLX5_MODIFICATION_TYPE_SET, error); 1332 } 1333 1334 /** 1335 * Convert modify-header set IPv4 DSCP action to DV specification. 1336 * 1337 * @param[in,out] resource 1338 * Pointer to the modify-header resource. 1339 * @param[in] action 1340 * Pointer to action specification. 1341 * @param[out] error 1342 * Pointer to the error structure. 1343 * 1344 * @return 1345 * 0 on success, a negative errno value otherwise and rte_errno is set. 1346 */ 1347 static int 1348 flow_dv_convert_action_modify_ipv4_dscp 1349 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1350 const struct rte_flow_action *action, 1351 struct rte_flow_error *error) 1352 { 1353 const struct rte_flow_action_set_dscp *conf = 1354 (const struct rte_flow_action_set_dscp *)(action->conf); 1355 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 1356 struct rte_flow_item_ipv4 ipv4; 1357 struct rte_flow_item_ipv4 ipv4_mask; 1358 1359 memset(&ipv4, 0, sizeof(ipv4)); 1360 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 1361 ipv4.hdr.type_of_service = conf->dscp; 1362 ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2; 1363 item.spec = &ipv4; 1364 item.mask = &ipv4_mask; 1365 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 1366 MLX5_MODIFICATION_TYPE_SET, error); 1367 } 1368 1369 /** 1370 * Convert modify-header set IPv6 DSCP action to DV specification. 1371 * 1372 * @param[in,out] resource 1373 * Pointer to the modify-header resource. 1374 * @param[in] action 1375 * Pointer to action specification. 1376 * @param[out] error 1377 * Pointer to the error structure. 1378 * 1379 * @return 1380 * 0 on success, a negative errno value otherwise and rte_errno is set. 1381 */ 1382 static int 1383 flow_dv_convert_action_modify_ipv6_dscp 1384 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1385 const struct rte_flow_action *action, 1386 struct rte_flow_error *error) 1387 { 1388 const struct rte_flow_action_set_dscp *conf = 1389 (const struct rte_flow_action_set_dscp *)(action->conf); 1390 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 1391 struct rte_flow_item_ipv6 ipv6; 1392 struct rte_flow_item_ipv6 ipv6_mask; 1393 1394 memset(&ipv6, 0, sizeof(ipv6)); 1395 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 1396 /* 1397 * Even though the DSCP bits offset of IPv6 is not byte aligned, 1398 * rdma-core only accept the DSCP bits byte aligned start from 1399 * bit 0 to 5 as to be compatible with IPv4. No need to shift the 1400 * bits in IPv6 case as rdma-core requires byte aligned value. 1401 */ 1402 ipv6.hdr.vtc_flow = conf->dscp; 1403 ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22; 1404 item.spec = &ipv6; 1405 item.mask = &ipv6_mask; 1406 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 1407 MLX5_MODIFICATION_TYPE_SET, error); 1408 } 1409 1410 static int 1411 mlx5_flow_item_field_width(struct mlx5_priv *priv, 1412 enum rte_flow_field_id field, int inherit) 1413 { 1414 switch (field) { 1415 case RTE_FLOW_FIELD_START: 1416 return 32; 1417 case RTE_FLOW_FIELD_MAC_DST: 1418 case RTE_FLOW_FIELD_MAC_SRC: 1419 return 48; 1420 case RTE_FLOW_FIELD_VLAN_TYPE: 1421 return 16; 1422 case RTE_FLOW_FIELD_VLAN_ID: 1423 return 12; 1424 case RTE_FLOW_FIELD_MAC_TYPE: 1425 return 16; 1426 case RTE_FLOW_FIELD_IPV4_DSCP: 1427 return 6; 1428 case RTE_FLOW_FIELD_IPV4_TTL: 1429 return 8; 1430 case RTE_FLOW_FIELD_IPV4_SRC: 1431 case RTE_FLOW_FIELD_IPV4_DST: 1432 return 32; 1433 case RTE_FLOW_FIELD_IPV6_DSCP: 1434 return 6; 1435 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1436 return 8; 1437 case RTE_FLOW_FIELD_IPV6_SRC: 1438 case RTE_FLOW_FIELD_IPV6_DST: 1439 return 128; 1440 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1441 case RTE_FLOW_FIELD_TCP_PORT_DST: 1442 return 16; 1443 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1444 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1445 return 32; 1446 case RTE_FLOW_FIELD_TCP_FLAGS: 1447 return 9; 1448 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1449 case RTE_FLOW_FIELD_UDP_PORT_DST: 1450 return 16; 1451 case RTE_FLOW_FIELD_VXLAN_VNI: 1452 case RTE_FLOW_FIELD_GENEVE_VNI: 1453 return 24; 1454 case RTE_FLOW_FIELD_GTP_TEID: 1455 case RTE_FLOW_FIELD_TAG: 1456 return 32; 1457 case RTE_FLOW_FIELD_MARK: 1458 return __builtin_popcount(priv->sh->dv_mark_mask); 1459 case RTE_FLOW_FIELD_META: 1460 return __builtin_popcount(priv->sh->dv_meta_mask); 1461 case RTE_FLOW_FIELD_POINTER: 1462 case RTE_FLOW_FIELD_VALUE: 1463 return inherit < 0 ? 0 : inherit; 1464 default: 1465 MLX5_ASSERT(false); 1466 } 1467 return 0; 1468 } 1469 1470 static void 1471 mlx5_flow_field_id_to_modify_info 1472 (const struct rte_flow_action_modify_data *data, 1473 struct field_modify_info *info, uint32_t *mask, 1474 uint32_t width, uint32_t *shift, struct rte_eth_dev *dev, 1475 const struct rte_flow_attr *attr, struct rte_flow_error *error) 1476 { 1477 struct mlx5_priv *priv = dev->data->dev_private; 1478 uint32_t idx = 0; 1479 uint32_t off = 0; 1480 1481 switch (data->field) { 1482 case RTE_FLOW_FIELD_START: 1483 /* not supported yet */ 1484 MLX5_ASSERT(false); 1485 break; 1486 case RTE_FLOW_FIELD_MAC_DST: 1487 off = data->offset > 16 ? data->offset - 16 : 0; 1488 if (mask) { 1489 if (data->offset < 16) { 1490 info[idx] = (struct field_modify_info){2, 4, 1491 MLX5_MODI_OUT_DMAC_15_0}; 1492 if (width < 16) { 1493 mask[idx] = rte_cpu_to_be_16(0xffff >> 1494 (16 - width)); 1495 width = 0; 1496 } else { 1497 mask[idx] = RTE_BE16(0xffff); 1498 width -= 16; 1499 } 1500 if (!width) 1501 break; 1502 ++idx; 1503 } 1504 info[idx] = (struct field_modify_info){4, 0, 1505 MLX5_MODI_OUT_DMAC_47_16}; 1506 mask[idx] = rte_cpu_to_be_32((0xffffffff >> 1507 (32 - width)) << off); 1508 } else { 1509 if (data->offset < 16) 1510 info[idx++] = (struct field_modify_info){2, 4, 1511 MLX5_MODI_OUT_DMAC_15_0}; 1512 info[idx] = (struct field_modify_info){4, 0, 1513 MLX5_MODI_OUT_DMAC_47_16}; 1514 } 1515 break; 1516 case RTE_FLOW_FIELD_MAC_SRC: 1517 off = data->offset > 16 ? data->offset - 16 : 0; 1518 if (mask) { 1519 if (data->offset < 16) { 1520 info[idx] = (struct field_modify_info){2, 4, 1521 MLX5_MODI_OUT_SMAC_15_0}; 1522 if (width < 16) { 1523 mask[idx] = rte_cpu_to_be_16(0xffff >> 1524 (16 - width)); 1525 width = 0; 1526 } else { 1527 mask[idx] = RTE_BE16(0xffff); 1528 width -= 16; 1529 } 1530 if (!width) 1531 break; 1532 ++idx; 1533 } 1534 info[idx] = (struct field_modify_info){4, 0, 1535 MLX5_MODI_OUT_SMAC_47_16}; 1536 mask[idx] = rte_cpu_to_be_32((0xffffffff >> 1537 (32 - width)) << off); 1538 } else { 1539 if (data->offset < 16) 1540 info[idx++] = (struct field_modify_info){2, 4, 1541 MLX5_MODI_OUT_SMAC_15_0}; 1542 info[idx] = (struct field_modify_info){4, 0, 1543 MLX5_MODI_OUT_SMAC_47_16}; 1544 } 1545 break; 1546 case RTE_FLOW_FIELD_VLAN_TYPE: 1547 /* not supported yet */ 1548 break; 1549 case RTE_FLOW_FIELD_VLAN_ID: 1550 info[idx] = (struct field_modify_info){2, 0, 1551 MLX5_MODI_OUT_FIRST_VID}; 1552 if (mask) 1553 mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width)); 1554 break; 1555 case RTE_FLOW_FIELD_MAC_TYPE: 1556 info[idx] = (struct field_modify_info){2, 0, 1557 MLX5_MODI_OUT_ETHERTYPE}; 1558 if (mask) 1559 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1560 break; 1561 case RTE_FLOW_FIELD_IPV4_DSCP: 1562 info[idx] = (struct field_modify_info){1, 0, 1563 MLX5_MODI_OUT_IP_DSCP}; 1564 if (mask) 1565 mask[idx] = 0x3f >> (6 - width); 1566 break; 1567 case RTE_FLOW_FIELD_IPV4_TTL: 1568 info[idx] = (struct field_modify_info){1, 0, 1569 MLX5_MODI_OUT_IPV4_TTL}; 1570 if (mask) 1571 mask[idx] = 0xff >> (8 - width); 1572 break; 1573 case RTE_FLOW_FIELD_IPV4_SRC: 1574 info[idx] = (struct field_modify_info){4, 0, 1575 MLX5_MODI_OUT_SIPV4}; 1576 if (mask) 1577 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1578 (32 - width)); 1579 break; 1580 case RTE_FLOW_FIELD_IPV4_DST: 1581 info[idx] = (struct field_modify_info){4, 0, 1582 MLX5_MODI_OUT_DIPV4}; 1583 if (mask) 1584 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1585 (32 - width)); 1586 break; 1587 case RTE_FLOW_FIELD_IPV6_DSCP: 1588 info[idx] = (struct field_modify_info){1, 0, 1589 MLX5_MODI_OUT_IP_DSCP}; 1590 if (mask) 1591 mask[idx] = 0x3f >> (6 - width); 1592 break; 1593 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1594 info[idx] = (struct field_modify_info){1, 0, 1595 MLX5_MODI_OUT_IPV6_HOPLIMIT}; 1596 if (mask) 1597 mask[idx] = 0xff >> (8 - width); 1598 break; 1599 case RTE_FLOW_FIELD_IPV6_SRC: 1600 if (mask) { 1601 if (data->offset < 32) { 1602 info[idx] = (struct field_modify_info){4, 12, 1603 MLX5_MODI_OUT_SIPV6_31_0}; 1604 if (width < 32) { 1605 mask[idx] = 1606 rte_cpu_to_be_32(0xffffffff >> 1607 (32 - width)); 1608 width = 0; 1609 } else { 1610 mask[idx] = RTE_BE32(0xffffffff); 1611 width -= 32; 1612 } 1613 if (!width) 1614 break; 1615 ++idx; 1616 } 1617 if (data->offset < 64) { 1618 info[idx] = (struct field_modify_info){4, 8, 1619 MLX5_MODI_OUT_SIPV6_63_32}; 1620 if (width < 32) { 1621 mask[idx] = 1622 rte_cpu_to_be_32(0xffffffff >> 1623 (32 - width)); 1624 width = 0; 1625 } else { 1626 mask[idx] = RTE_BE32(0xffffffff); 1627 width -= 32; 1628 } 1629 if (!width) 1630 break; 1631 ++idx; 1632 } 1633 if (data->offset < 96) { 1634 info[idx] = (struct field_modify_info){4, 4, 1635 MLX5_MODI_OUT_SIPV6_95_64}; 1636 if (width < 32) { 1637 mask[idx] = 1638 rte_cpu_to_be_32(0xffffffff >> 1639 (32 - width)); 1640 width = 0; 1641 } else { 1642 mask[idx] = RTE_BE32(0xffffffff); 1643 width -= 32; 1644 } 1645 if (!width) 1646 break; 1647 ++idx; 1648 } 1649 info[idx] = (struct field_modify_info){4, 0, 1650 MLX5_MODI_OUT_SIPV6_127_96}; 1651 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1652 (32 - width)); 1653 } else { 1654 if (data->offset < 32) 1655 info[idx++] = (struct field_modify_info){4, 12, 1656 MLX5_MODI_OUT_SIPV6_31_0}; 1657 if (data->offset < 64) 1658 info[idx++] = (struct field_modify_info){4, 8, 1659 MLX5_MODI_OUT_SIPV6_63_32}; 1660 if (data->offset < 96) 1661 info[idx++] = (struct field_modify_info){4, 4, 1662 MLX5_MODI_OUT_SIPV6_95_64}; 1663 if (data->offset < 128) 1664 info[idx++] = (struct field_modify_info){4, 0, 1665 MLX5_MODI_OUT_SIPV6_127_96}; 1666 } 1667 break; 1668 case RTE_FLOW_FIELD_IPV6_DST: 1669 if (mask) { 1670 if (data->offset < 32) { 1671 info[idx] = (struct field_modify_info){4, 12, 1672 MLX5_MODI_OUT_DIPV6_31_0}; 1673 if (width < 32) { 1674 mask[idx] = 1675 rte_cpu_to_be_32(0xffffffff >> 1676 (32 - width)); 1677 width = 0; 1678 } else { 1679 mask[idx] = RTE_BE32(0xffffffff); 1680 width -= 32; 1681 } 1682 if (!width) 1683 break; 1684 ++idx; 1685 } 1686 if (data->offset < 64) { 1687 info[idx] = (struct field_modify_info){4, 8, 1688 MLX5_MODI_OUT_DIPV6_63_32}; 1689 if (width < 32) { 1690 mask[idx] = 1691 rte_cpu_to_be_32(0xffffffff >> 1692 (32 - width)); 1693 width = 0; 1694 } else { 1695 mask[idx] = RTE_BE32(0xffffffff); 1696 width -= 32; 1697 } 1698 if (!width) 1699 break; 1700 ++idx; 1701 } 1702 if (data->offset < 96) { 1703 info[idx] = (struct field_modify_info){4, 4, 1704 MLX5_MODI_OUT_DIPV6_95_64}; 1705 if (width < 32) { 1706 mask[idx] = 1707 rte_cpu_to_be_32(0xffffffff >> 1708 (32 - width)); 1709 width = 0; 1710 } else { 1711 mask[idx] = RTE_BE32(0xffffffff); 1712 width -= 32; 1713 } 1714 if (!width) 1715 break; 1716 ++idx; 1717 } 1718 info[idx] = (struct field_modify_info){4, 0, 1719 MLX5_MODI_OUT_DIPV6_127_96}; 1720 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1721 (32 - width)); 1722 } else { 1723 if (data->offset < 32) 1724 info[idx++] = (struct field_modify_info){4, 12, 1725 MLX5_MODI_OUT_DIPV6_31_0}; 1726 if (data->offset < 64) 1727 info[idx++] = (struct field_modify_info){4, 8, 1728 MLX5_MODI_OUT_DIPV6_63_32}; 1729 if (data->offset < 96) 1730 info[idx++] = (struct field_modify_info){4, 4, 1731 MLX5_MODI_OUT_DIPV6_95_64}; 1732 if (data->offset < 128) 1733 info[idx++] = (struct field_modify_info){4, 0, 1734 MLX5_MODI_OUT_DIPV6_127_96}; 1735 } 1736 break; 1737 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1738 info[idx] = (struct field_modify_info){2, 0, 1739 MLX5_MODI_OUT_TCP_SPORT}; 1740 if (mask) 1741 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1742 break; 1743 case RTE_FLOW_FIELD_TCP_PORT_DST: 1744 info[idx] = (struct field_modify_info){2, 0, 1745 MLX5_MODI_OUT_TCP_DPORT}; 1746 if (mask) 1747 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1748 break; 1749 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1750 info[idx] = (struct field_modify_info){4, 0, 1751 MLX5_MODI_OUT_TCP_SEQ_NUM}; 1752 if (mask) 1753 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1754 (32 - width)); 1755 break; 1756 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1757 info[idx] = (struct field_modify_info){4, 0, 1758 MLX5_MODI_OUT_TCP_ACK_NUM}; 1759 if (mask) 1760 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1761 (32 - width)); 1762 break; 1763 case RTE_FLOW_FIELD_TCP_FLAGS: 1764 info[idx] = (struct field_modify_info){2, 0, 1765 MLX5_MODI_OUT_TCP_FLAGS}; 1766 if (mask) 1767 mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width)); 1768 break; 1769 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1770 info[idx] = (struct field_modify_info){2, 0, 1771 MLX5_MODI_OUT_UDP_SPORT}; 1772 if (mask) 1773 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1774 break; 1775 case RTE_FLOW_FIELD_UDP_PORT_DST: 1776 info[idx] = (struct field_modify_info){2, 0, 1777 MLX5_MODI_OUT_UDP_DPORT}; 1778 if (mask) 1779 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1780 break; 1781 case RTE_FLOW_FIELD_VXLAN_VNI: 1782 /* not supported yet */ 1783 break; 1784 case RTE_FLOW_FIELD_GENEVE_VNI: 1785 /* not supported yet*/ 1786 break; 1787 case RTE_FLOW_FIELD_GTP_TEID: 1788 info[idx] = (struct field_modify_info){4, 0, 1789 MLX5_MODI_GTP_TEID}; 1790 if (mask) 1791 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1792 (32 - width)); 1793 break; 1794 case RTE_FLOW_FIELD_TAG: 1795 { 1796 int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 1797 data->level, error); 1798 if (reg < 0) 1799 return; 1800 MLX5_ASSERT(reg != REG_NON); 1801 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1802 info[idx] = (struct field_modify_info){4, 0, 1803 reg_to_field[reg]}; 1804 if (mask) 1805 mask[idx] = 1806 rte_cpu_to_be_32(0xffffffff >> 1807 (32 - width)); 1808 } 1809 break; 1810 case RTE_FLOW_FIELD_MARK: 1811 { 1812 uint32_t mark_mask = priv->sh->dv_mark_mask; 1813 uint32_t mark_count = __builtin_popcount(mark_mask); 1814 int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 1815 0, error); 1816 if (reg < 0) 1817 return; 1818 MLX5_ASSERT(reg != REG_NON); 1819 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1820 info[idx] = (struct field_modify_info){4, 0, 1821 reg_to_field[reg]}; 1822 if (mask) 1823 mask[idx] = rte_cpu_to_be_32((mark_mask >> 1824 (mark_count - width)) & mark_mask); 1825 } 1826 break; 1827 case RTE_FLOW_FIELD_META: 1828 { 1829 uint32_t meta_mask = priv->sh->dv_meta_mask; 1830 uint32_t meta_count = __builtin_popcount(meta_mask); 1831 uint32_t msk_c0 = 1832 rte_cpu_to_be_32(priv->sh->dv_regc0_mask); 1833 uint32_t shl_c0 = rte_bsf32(msk_c0); 1834 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1835 if (reg < 0) 1836 return; 1837 MLX5_ASSERT(reg != REG_NON); 1838 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1839 if (reg == REG_C_0) 1840 *shift = shl_c0; 1841 info[idx] = (struct field_modify_info){4, 0, 1842 reg_to_field[reg]}; 1843 if (mask) 1844 mask[idx] = rte_cpu_to_be_32((meta_mask >> 1845 (meta_count - width)) & meta_mask); 1846 } 1847 break; 1848 case RTE_FLOW_FIELD_POINTER: 1849 case RTE_FLOW_FIELD_VALUE: 1850 default: 1851 MLX5_ASSERT(false); 1852 break; 1853 } 1854 } 1855 1856 /** 1857 * Convert modify_field action to DV specification. 1858 * 1859 * @param[in] dev 1860 * Pointer to the rte_eth_dev structure. 1861 * @param[in,out] resource 1862 * Pointer to the modify-header resource. 1863 * @param[in] action 1864 * Pointer to action specification. 1865 * @param[in] attr 1866 * Attributes of flow that includes this item. 1867 * @param[out] error 1868 * Pointer to the error structure. 1869 * 1870 * @return 1871 * 0 on success, a negative errno value otherwise and rte_errno is set. 1872 */ 1873 static int 1874 flow_dv_convert_action_modify_field 1875 (struct rte_eth_dev *dev, 1876 struct mlx5_flow_dv_modify_hdr_resource *resource, 1877 const struct rte_flow_action *action, 1878 const struct rte_flow_attr *attr, 1879 struct rte_flow_error *error) 1880 { 1881 const struct rte_flow_action_modify_field *conf = 1882 (const struct rte_flow_action_modify_field *)(action->conf); 1883 struct rte_flow_item item = { 1884 .spec = NULL, 1885 .mask = NULL 1886 }; 1887 struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = { 1888 {0, 0, 0} }; 1889 struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = { 1890 {0, 0, 0} }; 1891 uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0}; 1892 uint32_t type; 1893 uint32_t shift = 0; 1894 1895 if (conf->src.field == RTE_FLOW_FIELD_POINTER || 1896 conf->src.field == RTE_FLOW_FIELD_VALUE) { 1897 type = MLX5_MODIFICATION_TYPE_SET; 1898 /** For SET fill the destination field (field) first. */ 1899 mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, 1900 conf->width, &shift, dev, 1901 attr, error); 1902 item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? 1903 (void *)(uintptr_t)conf->src.pvalue : 1904 (void *)(uintptr_t)&conf->src.value; 1905 } else { 1906 type = MLX5_MODIFICATION_TYPE_COPY; 1907 /** For COPY fill the destination field (dcopy) without mask. */ 1908 mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL, 1909 conf->width, &shift, dev, 1910 attr, error); 1911 /** Then construct the source field (field) with mask. */ 1912 mlx5_flow_field_id_to_modify_info(&conf->src, field, mask, 1913 conf->width, &shift, 1914 dev, attr, error); 1915 } 1916 item.mask = &mask; 1917 return flow_dv_convert_modify_action(&item, 1918 field, dcopy, resource, type, error); 1919 } 1920 1921 /** 1922 * Validate MARK item. 1923 * 1924 * @param[in] dev 1925 * Pointer to the rte_eth_dev structure. 1926 * @param[in] item 1927 * Item specification. 1928 * @param[in] attr 1929 * Attributes of flow that includes this item. 1930 * @param[out] error 1931 * Pointer to error structure. 1932 * 1933 * @return 1934 * 0 on success, a negative errno value otherwise and rte_errno is set. 1935 */ 1936 static int 1937 flow_dv_validate_item_mark(struct rte_eth_dev *dev, 1938 const struct rte_flow_item *item, 1939 const struct rte_flow_attr *attr __rte_unused, 1940 struct rte_flow_error *error) 1941 { 1942 struct mlx5_priv *priv = dev->data->dev_private; 1943 struct mlx5_dev_config *config = &priv->config; 1944 const struct rte_flow_item_mark *spec = item->spec; 1945 const struct rte_flow_item_mark *mask = item->mask; 1946 const struct rte_flow_item_mark nic_mask = { 1947 .id = priv->sh->dv_mark_mask, 1948 }; 1949 int ret; 1950 1951 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 1952 return rte_flow_error_set(error, ENOTSUP, 1953 RTE_FLOW_ERROR_TYPE_ITEM, item, 1954 "extended metadata feature" 1955 " isn't enabled"); 1956 if (!mlx5_flow_ext_mreg_supported(dev)) 1957 return rte_flow_error_set(error, ENOTSUP, 1958 RTE_FLOW_ERROR_TYPE_ITEM, item, 1959 "extended metadata register" 1960 " isn't supported"); 1961 if (!nic_mask.id) 1962 return rte_flow_error_set(error, ENOTSUP, 1963 RTE_FLOW_ERROR_TYPE_ITEM, item, 1964 "extended metadata register" 1965 " isn't available"); 1966 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1967 if (ret < 0) 1968 return ret; 1969 if (!spec) 1970 return rte_flow_error_set(error, EINVAL, 1971 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 1972 item->spec, 1973 "data cannot be empty"); 1974 if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id)) 1975 return rte_flow_error_set(error, EINVAL, 1976 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1977 &spec->id, 1978 "mark id exceeds the limit"); 1979 if (!mask) 1980 mask = &nic_mask; 1981 if (!mask->id) 1982 return rte_flow_error_set(error, EINVAL, 1983 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 1984 "mask cannot be zero"); 1985 1986 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 1987 (const uint8_t *)&nic_mask, 1988 sizeof(struct rte_flow_item_mark), 1989 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 1990 if (ret < 0) 1991 return ret; 1992 return 0; 1993 } 1994 1995 /** 1996 * Validate META item. 1997 * 1998 * @param[in] dev 1999 * Pointer to the rte_eth_dev structure. 2000 * @param[in] item 2001 * Item specification. 2002 * @param[in] attr 2003 * Attributes of flow that includes this item. 2004 * @param[out] error 2005 * Pointer to error structure. 2006 * 2007 * @return 2008 * 0 on success, a negative errno value otherwise and rte_errno is set. 2009 */ 2010 static int 2011 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused, 2012 const struct rte_flow_item *item, 2013 const struct rte_flow_attr *attr, 2014 struct rte_flow_error *error) 2015 { 2016 struct mlx5_priv *priv = dev->data->dev_private; 2017 struct mlx5_dev_config *config = &priv->config; 2018 const struct rte_flow_item_meta *spec = item->spec; 2019 const struct rte_flow_item_meta *mask = item->mask; 2020 struct rte_flow_item_meta nic_mask = { 2021 .data = UINT32_MAX 2022 }; 2023 int reg; 2024 int ret; 2025 2026 if (!spec) 2027 return rte_flow_error_set(error, EINVAL, 2028 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2029 item->spec, 2030 "data cannot be empty"); 2031 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 2032 if (!mlx5_flow_ext_mreg_supported(dev)) 2033 return rte_flow_error_set(error, ENOTSUP, 2034 RTE_FLOW_ERROR_TYPE_ITEM, item, 2035 "extended metadata register" 2036 " isn't supported"); 2037 reg = flow_dv_get_metadata_reg(dev, attr, error); 2038 if (reg < 0) 2039 return reg; 2040 if (reg == REG_NON) 2041 return rte_flow_error_set(error, ENOTSUP, 2042 RTE_FLOW_ERROR_TYPE_ITEM, item, 2043 "unavalable extended metadata register"); 2044 if (reg == REG_B) 2045 return rte_flow_error_set(error, ENOTSUP, 2046 RTE_FLOW_ERROR_TYPE_ITEM, item, 2047 "match on reg_b " 2048 "isn't supported"); 2049 if (reg != REG_A) 2050 nic_mask.data = priv->sh->dv_meta_mask; 2051 } else { 2052 if (attr->transfer) 2053 return rte_flow_error_set(error, ENOTSUP, 2054 RTE_FLOW_ERROR_TYPE_ITEM, item, 2055 "extended metadata feature " 2056 "should be enabled when " 2057 "meta item is requested " 2058 "with e-switch mode "); 2059 if (attr->ingress) 2060 return rte_flow_error_set(error, ENOTSUP, 2061 RTE_FLOW_ERROR_TYPE_ITEM, item, 2062 "match on metadata for ingress " 2063 "is not supported in legacy " 2064 "metadata mode"); 2065 } 2066 if (!mask) 2067 mask = &rte_flow_item_meta_mask; 2068 if (!mask->data) 2069 return rte_flow_error_set(error, EINVAL, 2070 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2071 "mask cannot be zero"); 2072 2073 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2074 (const uint8_t *)&nic_mask, 2075 sizeof(struct rte_flow_item_meta), 2076 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2077 return ret; 2078 } 2079 2080 /** 2081 * Validate TAG item. 2082 * 2083 * @param[in] dev 2084 * Pointer to the rte_eth_dev structure. 2085 * @param[in] item 2086 * Item specification. 2087 * @param[in] attr 2088 * Attributes of flow that includes this item. 2089 * @param[out] error 2090 * Pointer to error structure. 2091 * 2092 * @return 2093 * 0 on success, a negative errno value otherwise and rte_errno is set. 2094 */ 2095 static int 2096 flow_dv_validate_item_tag(struct rte_eth_dev *dev, 2097 const struct rte_flow_item *item, 2098 const struct rte_flow_attr *attr __rte_unused, 2099 struct rte_flow_error *error) 2100 { 2101 const struct rte_flow_item_tag *spec = item->spec; 2102 const struct rte_flow_item_tag *mask = item->mask; 2103 const struct rte_flow_item_tag nic_mask = { 2104 .data = RTE_BE32(UINT32_MAX), 2105 .index = 0xff, 2106 }; 2107 int ret; 2108 2109 if (!mlx5_flow_ext_mreg_supported(dev)) 2110 return rte_flow_error_set(error, ENOTSUP, 2111 RTE_FLOW_ERROR_TYPE_ITEM, item, 2112 "extensive metadata register" 2113 " isn't supported"); 2114 if (!spec) 2115 return rte_flow_error_set(error, EINVAL, 2116 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2117 item->spec, 2118 "data cannot be empty"); 2119 if (!mask) 2120 mask = &rte_flow_item_tag_mask; 2121 if (!mask->data) 2122 return rte_flow_error_set(error, EINVAL, 2123 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2124 "mask cannot be zero"); 2125 2126 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2127 (const uint8_t *)&nic_mask, 2128 sizeof(struct rte_flow_item_tag), 2129 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2130 if (ret < 0) 2131 return ret; 2132 if (mask->index != 0xff) 2133 return rte_flow_error_set(error, EINVAL, 2134 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2135 "partial mask for tag index" 2136 " is not supported"); 2137 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error); 2138 if (ret < 0) 2139 return ret; 2140 MLX5_ASSERT(ret != REG_NON); 2141 return 0; 2142 } 2143 2144 /** 2145 * Validate vport item. 2146 * 2147 * @param[in] dev 2148 * Pointer to the rte_eth_dev structure. 2149 * @param[in] item 2150 * Item specification. 2151 * @param[in] attr 2152 * Attributes of flow that includes this item. 2153 * @param[in] item_flags 2154 * Bit-fields that holds the items detected until now. 2155 * @param[out] error 2156 * Pointer to error structure. 2157 * 2158 * @return 2159 * 0 on success, a negative errno value otherwise and rte_errno is set. 2160 */ 2161 static int 2162 flow_dv_validate_item_port_id(struct rte_eth_dev *dev, 2163 const struct rte_flow_item *item, 2164 const struct rte_flow_attr *attr, 2165 uint64_t item_flags, 2166 struct rte_flow_error *error) 2167 { 2168 const struct rte_flow_item_port_id *spec = item->spec; 2169 const struct rte_flow_item_port_id *mask = item->mask; 2170 const struct rte_flow_item_port_id switch_mask = { 2171 .id = 0xffffffff, 2172 }; 2173 struct mlx5_priv *esw_priv; 2174 struct mlx5_priv *dev_priv; 2175 int ret; 2176 2177 if (!attr->transfer) 2178 return rte_flow_error_set(error, EINVAL, 2179 RTE_FLOW_ERROR_TYPE_ITEM, 2180 NULL, 2181 "match on port id is valid only" 2182 " when transfer flag is enabled"); 2183 if (item_flags & MLX5_FLOW_ITEM_PORT_ID) 2184 return rte_flow_error_set(error, ENOTSUP, 2185 RTE_FLOW_ERROR_TYPE_ITEM, item, 2186 "multiple source ports are not" 2187 " supported"); 2188 if (!mask) 2189 mask = &switch_mask; 2190 if (mask->id != 0xffffffff) 2191 return rte_flow_error_set(error, ENOTSUP, 2192 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2193 mask, 2194 "no support for partial mask on" 2195 " \"id\" field"); 2196 ret = mlx5_flow_item_acceptable 2197 (item, (const uint8_t *)mask, 2198 (const uint8_t *)&rte_flow_item_port_id_mask, 2199 sizeof(struct rte_flow_item_port_id), 2200 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2201 if (ret) 2202 return ret; 2203 if (!spec) 2204 return 0; 2205 if (spec->id == MLX5_PORT_ESW_MGR) 2206 return 0; 2207 esw_priv = mlx5_port_to_eswitch_info(spec->id, false); 2208 if (!esw_priv) 2209 return rte_flow_error_set(error, rte_errno, 2210 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2211 "failed to obtain E-Switch info for" 2212 " port"); 2213 dev_priv = mlx5_dev_to_eswitch_info(dev); 2214 if (!dev_priv) 2215 return rte_flow_error_set(error, rte_errno, 2216 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2217 NULL, 2218 "failed to obtain E-Switch info"); 2219 if (esw_priv->domain_id != dev_priv->domain_id) 2220 return rte_flow_error_set(error, EINVAL, 2221 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2222 "cannot match on a port from a" 2223 " different E-Switch"); 2224 return 0; 2225 } 2226 2227 /** 2228 * Validate VLAN item. 2229 * 2230 * @param[in] item 2231 * Item specification. 2232 * @param[in] item_flags 2233 * Bit-fields that holds the items detected until now. 2234 * @param[in] dev 2235 * Ethernet device flow is being created on. 2236 * @param[out] error 2237 * Pointer to error structure. 2238 * 2239 * @return 2240 * 0 on success, a negative errno value otherwise and rte_errno is set. 2241 */ 2242 static int 2243 flow_dv_validate_item_vlan(const struct rte_flow_item *item, 2244 uint64_t item_flags, 2245 struct rte_eth_dev *dev, 2246 struct rte_flow_error *error) 2247 { 2248 const struct rte_flow_item_vlan *mask = item->mask; 2249 const struct rte_flow_item_vlan nic_mask = { 2250 .tci = RTE_BE16(UINT16_MAX), 2251 .inner_type = RTE_BE16(UINT16_MAX), 2252 .has_more_vlan = 1, 2253 }; 2254 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2255 int ret; 2256 const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 | 2257 MLX5_FLOW_LAYER_INNER_L4) : 2258 (MLX5_FLOW_LAYER_OUTER_L3 | 2259 MLX5_FLOW_LAYER_OUTER_L4); 2260 const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 2261 MLX5_FLOW_LAYER_OUTER_VLAN; 2262 2263 if (item_flags & vlanm) 2264 return rte_flow_error_set(error, EINVAL, 2265 RTE_FLOW_ERROR_TYPE_ITEM, item, 2266 "multiple VLAN layers not supported"); 2267 else if ((item_flags & l34m) != 0) 2268 return rte_flow_error_set(error, EINVAL, 2269 RTE_FLOW_ERROR_TYPE_ITEM, item, 2270 "VLAN cannot follow L3/L4 layer"); 2271 if (!mask) 2272 mask = &rte_flow_item_vlan_mask; 2273 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2274 (const uint8_t *)&nic_mask, 2275 sizeof(struct rte_flow_item_vlan), 2276 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2277 if (ret) 2278 return ret; 2279 if (!tunnel && mask->tci != RTE_BE16(0x0fff)) { 2280 struct mlx5_priv *priv = dev->data->dev_private; 2281 2282 if (priv->vmwa_context) { 2283 /* 2284 * Non-NULL context means we have a virtual machine 2285 * and SR-IOV enabled, we have to create VLAN interface 2286 * to make hypervisor to setup E-Switch vport 2287 * context correctly. We avoid creating the multiple 2288 * VLAN interfaces, so we cannot support VLAN tag mask. 2289 */ 2290 return rte_flow_error_set(error, EINVAL, 2291 RTE_FLOW_ERROR_TYPE_ITEM, 2292 item, 2293 "VLAN tag mask is not" 2294 " supported in virtual" 2295 " environment"); 2296 } 2297 } 2298 return 0; 2299 } 2300 2301 /* 2302 * GTP flags are contained in 1 byte of the format: 2303 * ------------------------------------------- 2304 * | bit | 0 - 2 | 3 | 4 | 5 | 6 | 7 | 2305 * |-----------------------------------------| 2306 * | value | Version | PT | Res | E | S | PN | 2307 * ------------------------------------------- 2308 * 2309 * Matching is supported only for GTP flags E, S, PN. 2310 */ 2311 #define MLX5_GTP_FLAGS_MASK 0x07 2312 2313 /** 2314 * Validate GTP item. 2315 * 2316 * @param[in] dev 2317 * Pointer to the rte_eth_dev structure. 2318 * @param[in] item 2319 * Item specification. 2320 * @param[in] item_flags 2321 * Bit-fields that holds the items detected until now. 2322 * @param[out] error 2323 * Pointer to error structure. 2324 * 2325 * @return 2326 * 0 on success, a negative errno value otherwise and rte_errno is set. 2327 */ 2328 static int 2329 flow_dv_validate_item_gtp(struct rte_eth_dev *dev, 2330 const struct rte_flow_item *item, 2331 uint64_t item_flags, 2332 struct rte_flow_error *error) 2333 { 2334 struct mlx5_priv *priv = dev->data->dev_private; 2335 const struct rte_flow_item_gtp *spec = item->spec; 2336 const struct rte_flow_item_gtp *mask = item->mask; 2337 const struct rte_flow_item_gtp nic_mask = { 2338 .v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK, 2339 .msg_type = 0xff, 2340 .teid = RTE_BE32(0xffffffff), 2341 }; 2342 2343 if (!priv->config.hca_attr.tunnel_stateless_gtp) 2344 return rte_flow_error_set(error, ENOTSUP, 2345 RTE_FLOW_ERROR_TYPE_ITEM, item, 2346 "GTP support is not enabled"); 2347 if (item_flags & MLX5_FLOW_LAYER_TUNNEL) 2348 return rte_flow_error_set(error, ENOTSUP, 2349 RTE_FLOW_ERROR_TYPE_ITEM, item, 2350 "multiple tunnel layers not" 2351 " supported"); 2352 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP)) 2353 return rte_flow_error_set(error, EINVAL, 2354 RTE_FLOW_ERROR_TYPE_ITEM, item, 2355 "no outer UDP layer found"); 2356 if (!mask) 2357 mask = &rte_flow_item_gtp_mask; 2358 if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK) 2359 return rte_flow_error_set(error, ENOTSUP, 2360 RTE_FLOW_ERROR_TYPE_ITEM, item, 2361 "Match is supported for GTP" 2362 " flags only"); 2363 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2364 (const uint8_t *)&nic_mask, 2365 sizeof(struct rte_flow_item_gtp), 2366 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2367 } 2368 2369 /** 2370 * Validate GTP PSC item. 2371 * 2372 * @param[in] item 2373 * Item specification. 2374 * @param[in] last_item 2375 * Previous validated item in the pattern items. 2376 * @param[in] gtp_item 2377 * Previous GTP item specification. 2378 * @param[in] attr 2379 * Pointer to flow attributes. 2380 * @param[out] error 2381 * Pointer to error structure. 2382 * 2383 * @return 2384 * 0 on success, a negative errno value otherwise and rte_errno is set. 2385 */ 2386 static int 2387 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, 2388 uint64_t last_item, 2389 const struct rte_flow_item *gtp_item, 2390 const struct rte_flow_attr *attr, 2391 struct rte_flow_error *error) 2392 { 2393 const struct rte_flow_item_gtp *gtp_spec; 2394 const struct rte_flow_item_gtp *gtp_mask; 2395 const struct rte_flow_item_gtp_psc *mask; 2396 const struct rte_flow_item_gtp_psc nic_mask = { 2397 .hdr.type = 0xF, 2398 .hdr.qfi = 0x3F, 2399 }; 2400 2401 if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP)) 2402 return rte_flow_error_set 2403 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2404 "GTP PSC item must be preceded with GTP item"); 2405 gtp_spec = gtp_item->spec; 2406 gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask; 2407 /* GTP spec and E flag is requested to match zero. */ 2408 if (gtp_spec && 2409 (gtp_mask->v_pt_rsv_flags & 2410 ~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG)) 2411 return rte_flow_error_set 2412 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2413 "GTP E flag must be 1 to match GTP PSC"); 2414 /* Check the flow is not created in group zero. */ 2415 if (!attr->transfer && !attr->group) 2416 return rte_flow_error_set 2417 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2418 "GTP PSC is not supported for group 0"); 2419 /* GTP spec is here and E flag is requested to match zero. */ 2420 if (!item->spec) 2421 return 0; 2422 mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask; 2423 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2424 (const uint8_t *)&nic_mask, 2425 sizeof(struct rte_flow_item_gtp_psc), 2426 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2427 } 2428 2429 /** 2430 * Validate IPV4 item. 2431 * Use existing validation function mlx5_flow_validate_item_ipv4(), and 2432 * add specific validation of fragment_offset field, 2433 * 2434 * @param[in] item 2435 * Item specification. 2436 * @param[in] item_flags 2437 * Bit-fields that holds the items detected until now. 2438 * @param[out] error 2439 * Pointer to error structure. 2440 * 2441 * @return 2442 * 0 on success, a negative errno value otherwise and rte_errno is set. 2443 */ 2444 static int 2445 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev, 2446 const struct rte_flow_item *item, 2447 uint64_t item_flags, uint64_t last_item, 2448 uint16_t ether_type, struct rte_flow_error *error) 2449 { 2450 int ret; 2451 struct mlx5_priv *priv = dev->data->dev_private; 2452 const struct rte_flow_item_ipv4 *spec = item->spec; 2453 const struct rte_flow_item_ipv4 *last = item->last; 2454 const struct rte_flow_item_ipv4 *mask = item->mask; 2455 rte_be16_t fragment_offset_spec = 0; 2456 rte_be16_t fragment_offset_last = 0; 2457 struct rte_flow_item_ipv4 nic_ipv4_mask = { 2458 .hdr = { 2459 .src_addr = RTE_BE32(0xffffffff), 2460 .dst_addr = RTE_BE32(0xffffffff), 2461 .type_of_service = 0xff, 2462 .fragment_offset = RTE_BE16(0xffff), 2463 .next_proto_id = 0xff, 2464 .time_to_live = 0xff, 2465 }, 2466 }; 2467 2468 if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) { 2469 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2470 bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl : 2471 priv->config.hca_attr.inner_ipv4_ihl; 2472 if (!ihl_cap) 2473 return rte_flow_error_set(error, ENOTSUP, 2474 RTE_FLOW_ERROR_TYPE_ITEM, 2475 item, 2476 "IPV4 ihl offload not supported"); 2477 nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl; 2478 } 2479 ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item, 2480 ether_type, &nic_ipv4_mask, 2481 MLX5_ITEM_RANGE_ACCEPTED, error); 2482 if (ret < 0) 2483 return ret; 2484 if (spec && mask) 2485 fragment_offset_spec = spec->hdr.fragment_offset & 2486 mask->hdr.fragment_offset; 2487 if (!fragment_offset_spec) 2488 return 0; 2489 /* 2490 * spec and mask are valid, enforce using full mask to make sure the 2491 * complete value is used correctly. 2492 */ 2493 if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2494 != RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2495 return rte_flow_error_set(error, EINVAL, 2496 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2497 item, "must use full mask for" 2498 " fragment_offset"); 2499 /* 2500 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0, 2501 * indicating this is 1st fragment of fragmented packet. 2502 * This is not yet supported in MLX5, return appropriate error message. 2503 */ 2504 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG)) 2505 return rte_flow_error_set(error, ENOTSUP, 2506 RTE_FLOW_ERROR_TYPE_ITEM, item, 2507 "match on first fragment not " 2508 "supported"); 2509 if (fragment_offset_spec && !last) 2510 return rte_flow_error_set(error, ENOTSUP, 2511 RTE_FLOW_ERROR_TYPE_ITEM, item, 2512 "specified value not supported"); 2513 /* spec and last are valid, validate the specified range. */ 2514 fragment_offset_last = last->hdr.fragment_offset & 2515 mask->hdr.fragment_offset; 2516 /* 2517 * Match on fragment_offset spec 0x2001 and last 0x3fff 2518 * means MF is 1 and frag-offset is > 0. 2519 * This packet is fragment 2nd and onward, excluding last. 2520 * This is not yet supported in MLX5, return appropriate 2521 * error message. 2522 */ 2523 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) && 2524 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2525 return rte_flow_error_set(error, ENOTSUP, 2526 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2527 last, "match on following " 2528 "fragments not supported"); 2529 /* 2530 * Match on fragment_offset spec 0x0001 and last 0x1fff 2531 * means MF is 0 and frag-offset is > 0. 2532 * This packet is last fragment of fragmented packet. 2533 * This is not yet supported in MLX5, return appropriate 2534 * error message. 2535 */ 2536 if (fragment_offset_spec == RTE_BE16(1) && 2537 fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK)) 2538 return rte_flow_error_set(error, ENOTSUP, 2539 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2540 last, "match on last " 2541 "fragment not supported"); 2542 /* 2543 * Match on fragment_offset spec 0x0001 and last 0x3fff 2544 * means MF and/or frag-offset is not 0. 2545 * This is a fragmented packet. 2546 * Other range values are invalid and rejected. 2547 */ 2548 if (!(fragment_offset_spec == RTE_BE16(1) && 2549 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))) 2550 return rte_flow_error_set(error, ENOTSUP, 2551 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2552 "specified range not supported"); 2553 return 0; 2554 } 2555 2556 /** 2557 * Validate IPV6 fragment extension item. 2558 * 2559 * @param[in] item 2560 * Item specification. 2561 * @param[in] item_flags 2562 * Bit-fields that holds the items detected until now. 2563 * @param[out] error 2564 * Pointer to error structure. 2565 * 2566 * @return 2567 * 0 on success, a negative errno value otherwise and rte_errno is set. 2568 */ 2569 static int 2570 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item, 2571 uint64_t item_flags, 2572 struct rte_flow_error *error) 2573 { 2574 const struct rte_flow_item_ipv6_frag_ext *spec = item->spec; 2575 const struct rte_flow_item_ipv6_frag_ext *last = item->last; 2576 const struct rte_flow_item_ipv6_frag_ext *mask = item->mask; 2577 rte_be16_t frag_data_spec = 0; 2578 rte_be16_t frag_data_last = 0; 2579 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2580 const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 : 2581 MLX5_FLOW_LAYER_OUTER_L4; 2582 int ret = 0; 2583 struct rte_flow_item_ipv6_frag_ext nic_mask = { 2584 .hdr = { 2585 .next_header = 0xff, 2586 .frag_data = RTE_BE16(0xffff), 2587 }, 2588 }; 2589 2590 if (item_flags & l4m) 2591 return rte_flow_error_set(error, EINVAL, 2592 RTE_FLOW_ERROR_TYPE_ITEM, item, 2593 "ipv6 fragment extension item cannot " 2594 "follow L4 item."); 2595 if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 2596 (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) 2597 return rte_flow_error_set(error, EINVAL, 2598 RTE_FLOW_ERROR_TYPE_ITEM, item, 2599 "ipv6 fragment extension item must " 2600 "follow ipv6 item"); 2601 if (spec && mask) 2602 frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data; 2603 if (!frag_data_spec) 2604 return 0; 2605 /* 2606 * spec and mask are valid, enforce using full mask to make sure the 2607 * complete value is used correctly. 2608 */ 2609 if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) != 2610 RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2611 return rte_flow_error_set(error, EINVAL, 2612 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2613 item, "must use full mask for" 2614 " frag_data"); 2615 /* 2616 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0. 2617 * This is 1st fragment of fragmented packet. 2618 */ 2619 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK)) 2620 return rte_flow_error_set(error, ENOTSUP, 2621 RTE_FLOW_ERROR_TYPE_ITEM, item, 2622 "match on first fragment not " 2623 "supported"); 2624 if (frag_data_spec && !last) 2625 return rte_flow_error_set(error, EINVAL, 2626 RTE_FLOW_ERROR_TYPE_ITEM, item, 2627 "specified value not supported"); 2628 ret = mlx5_flow_item_acceptable 2629 (item, (const uint8_t *)mask, 2630 (const uint8_t *)&nic_mask, 2631 sizeof(struct rte_flow_item_ipv6_frag_ext), 2632 MLX5_ITEM_RANGE_ACCEPTED, error); 2633 if (ret) 2634 return ret; 2635 /* spec and last are valid, validate the specified range. */ 2636 frag_data_last = last->hdr.frag_data & mask->hdr.frag_data; 2637 /* 2638 * Match on frag_data spec 0x0009 and last 0xfff9 2639 * means M is 1 and frag-offset is > 0. 2640 * This packet is fragment 2nd and onward, excluding last. 2641 * This is not yet supported in MLX5, return appropriate 2642 * error message. 2643 */ 2644 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN | 2645 RTE_IPV6_EHDR_MF_MASK) && 2646 frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2647 return rte_flow_error_set(error, ENOTSUP, 2648 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2649 last, "match on following " 2650 "fragments not supported"); 2651 /* 2652 * Match on frag_data spec 0x0008 and last 0xfff8 2653 * means M is 0 and frag-offset is > 0. 2654 * This packet is last fragment of fragmented packet. 2655 * This is not yet supported in MLX5, return appropriate 2656 * error message. 2657 */ 2658 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) && 2659 frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK)) 2660 return rte_flow_error_set(error, ENOTSUP, 2661 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2662 last, "match on last " 2663 "fragment not supported"); 2664 /* Other range values are invalid and rejected. */ 2665 return rte_flow_error_set(error, EINVAL, 2666 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2667 "specified range not supported"); 2668 } 2669 2670 /* 2671 * Validate ASO CT item. 2672 * 2673 * @param[in] dev 2674 * Pointer to the rte_eth_dev structure. 2675 * @param[in] item 2676 * Item specification. 2677 * @param[in] item_flags 2678 * Pointer to bit-fields that holds the items detected until now. 2679 * @param[out] error 2680 * Pointer to error structure. 2681 * 2682 * @return 2683 * 0 on success, a negative errno value otherwise and rte_errno is set. 2684 */ 2685 static int 2686 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev, 2687 const struct rte_flow_item *item, 2688 uint64_t *item_flags, 2689 struct rte_flow_error *error) 2690 { 2691 const struct rte_flow_item_conntrack *spec = item->spec; 2692 const struct rte_flow_item_conntrack *mask = item->mask; 2693 RTE_SET_USED(dev); 2694 uint32_t flags; 2695 2696 if (*item_flags & MLX5_FLOW_LAYER_ASO_CT) 2697 return rte_flow_error_set(error, EINVAL, 2698 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2699 "Only one CT is supported"); 2700 if (!mask) 2701 mask = &rte_flow_item_conntrack_mask; 2702 flags = spec->flags & mask->flags; 2703 if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) && 2704 ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) || 2705 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) || 2706 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))) 2707 return rte_flow_error_set(error, EINVAL, 2708 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2709 "Conflict status bits"); 2710 /* State change also needs to be considered. */ 2711 *item_flags |= MLX5_FLOW_LAYER_ASO_CT; 2712 return 0; 2713 } 2714 2715 /** 2716 * Validate the pop VLAN action. 2717 * 2718 * @param[in] dev 2719 * Pointer to the rte_eth_dev structure. 2720 * @param[in] action_flags 2721 * Holds the actions detected until now. 2722 * @param[in] action 2723 * Pointer to the pop vlan action. 2724 * @param[in] item_flags 2725 * The items found in this flow rule. 2726 * @param[in] attr 2727 * Pointer to flow attributes. 2728 * @param[out] error 2729 * Pointer to error structure. 2730 * 2731 * @return 2732 * 0 on success, a negative errno value otherwise and rte_errno is set. 2733 */ 2734 static int 2735 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev, 2736 uint64_t action_flags, 2737 const struct rte_flow_action *action, 2738 uint64_t item_flags, 2739 const struct rte_flow_attr *attr, 2740 struct rte_flow_error *error) 2741 { 2742 const struct mlx5_priv *priv = dev->data->dev_private; 2743 struct mlx5_dev_ctx_shared *sh = priv->sh; 2744 bool direction_error = false; 2745 2746 if (!priv->sh->pop_vlan_action) 2747 return rte_flow_error_set(error, ENOTSUP, 2748 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2749 NULL, 2750 "pop vlan action is not supported"); 2751 /* Pop VLAN is not supported in egress except for CX6 FDB mode. */ 2752 if (attr->transfer) { 2753 bool fdb_tx = priv->representor_id != UINT16_MAX; 2754 bool is_cx5 = sh->steering_format_version == 2755 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2756 2757 if (fdb_tx && is_cx5) 2758 direction_error = true; 2759 } else if (attr->egress) { 2760 direction_error = true; 2761 } 2762 if (direction_error) 2763 return rte_flow_error_set(error, ENOTSUP, 2764 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 2765 NULL, 2766 "pop vlan action not supported for egress"); 2767 if (action_flags & MLX5_FLOW_VLAN_ACTIONS) 2768 return rte_flow_error_set(error, ENOTSUP, 2769 RTE_FLOW_ERROR_TYPE_ACTION, action, 2770 "no support for multiple VLAN " 2771 "actions"); 2772 /* Pop VLAN with preceding Decap requires inner header with VLAN. */ 2773 if ((action_flags & MLX5_FLOW_ACTION_DECAP) && 2774 !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN)) 2775 return rte_flow_error_set(error, ENOTSUP, 2776 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2777 NULL, 2778 "cannot pop vlan after decap without " 2779 "match on inner vlan in the flow"); 2780 /* Pop VLAN without preceding Decap requires outer header with VLAN. */ 2781 if (!(action_flags & MLX5_FLOW_ACTION_DECAP) && 2782 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 2783 return rte_flow_error_set(error, ENOTSUP, 2784 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2785 NULL, 2786 "cannot pop vlan without a " 2787 "match on (outer) vlan in the flow"); 2788 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2789 return rte_flow_error_set(error, EINVAL, 2790 RTE_FLOW_ERROR_TYPE_ACTION, action, 2791 "wrong action order, port_id should " 2792 "be after pop VLAN action"); 2793 if (!attr->transfer && priv->representor) 2794 return rte_flow_error_set(error, ENOTSUP, 2795 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2796 "pop vlan action for VF representor " 2797 "not supported on NIC table"); 2798 return 0; 2799 } 2800 2801 /** 2802 * Get VLAN default info from vlan match info. 2803 * 2804 * @param[in] items 2805 * the list of item specifications. 2806 * @param[out] vlan 2807 * pointer VLAN info to fill to. 2808 * 2809 * @return 2810 * 0 on success, a negative errno value otherwise and rte_errno is set. 2811 */ 2812 static void 2813 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items, 2814 struct rte_vlan_hdr *vlan) 2815 { 2816 const struct rte_flow_item_vlan nic_mask = { 2817 .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK | 2818 MLX5DV_FLOW_VLAN_VID_MASK), 2819 .inner_type = RTE_BE16(0xffff), 2820 }; 2821 2822 if (items == NULL) 2823 return; 2824 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 2825 int type = items->type; 2826 2827 if (type == RTE_FLOW_ITEM_TYPE_VLAN || 2828 type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN) 2829 break; 2830 } 2831 if (items->type != RTE_FLOW_ITEM_TYPE_END) { 2832 const struct rte_flow_item_vlan *vlan_m = items->mask; 2833 const struct rte_flow_item_vlan *vlan_v = items->spec; 2834 2835 /* If VLAN item in pattern doesn't contain data, return here. */ 2836 if (!vlan_v) 2837 return; 2838 if (!vlan_m) 2839 vlan_m = &nic_mask; 2840 /* Only full match values are accepted */ 2841 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) == 2842 MLX5DV_FLOW_VLAN_PCP_MASK_BE) { 2843 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 2844 vlan->vlan_tci |= 2845 rte_be_to_cpu_16(vlan_v->tci & 2846 MLX5DV_FLOW_VLAN_PCP_MASK_BE); 2847 } 2848 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) == 2849 MLX5DV_FLOW_VLAN_VID_MASK_BE) { 2850 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 2851 vlan->vlan_tci |= 2852 rte_be_to_cpu_16(vlan_v->tci & 2853 MLX5DV_FLOW_VLAN_VID_MASK_BE); 2854 } 2855 if (vlan_m->inner_type == nic_mask.inner_type) 2856 vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type & 2857 vlan_m->inner_type); 2858 } 2859 } 2860 2861 /** 2862 * Validate the push VLAN action. 2863 * 2864 * @param[in] dev 2865 * Pointer to the rte_eth_dev structure. 2866 * @param[in] action_flags 2867 * Holds the actions detected until now. 2868 * @param[in] item_flags 2869 * The items found in this flow rule. 2870 * @param[in] action 2871 * Pointer to the action structure. 2872 * @param[in] attr 2873 * Pointer to flow attributes 2874 * @param[out] error 2875 * Pointer to error structure. 2876 * 2877 * @return 2878 * 0 on success, a negative errno value otherwise and rte_errno is set. 2879 */ 2880 static int 2881 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev, 2882 uint64_t action_flags, 2883 const struct rte_flow_item_vlan *vlan_m, 2884 const struct rte_flow_action *action, 2885 const struct rte_flow_attr *attr, 2886 struct rte_flow_error *error) 2887 { 2888 const struct rte_flow_action_of_push_vlan *push_vlan = action->conf; 2889 const struct mlx5_priv *priv = dev->data->dev_private; 2890 struct mlx5_dev_ctx_shared *sh = priv->sh; 2891 bool direction_error = false; 2892 2893 if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && 2894 push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) 2895 return rte_flow_error_set(error, EINVAL, 2896 RTE_FLOW_ERROR_TYPE_ACTION, action, 2897 "invalid vlan ethertype"); 2898 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2899 return rte_flow_error_set(error, EINVAL, 2900 RTE_FLOW_ERROR_TYPE_ACTION, action, 2901 "wrong action order, port_id should " 2902 "be after push VLAN"); 2903 /* Push VLAN is not supported in ingress except for CX6 FDB mode. */ 2904 if (attr->transfer) { 2905 bool fdb_tx = priv->representor_id != UINT16_MAX; 2906 bool is_cx5 = sh->steering_format_version == 2907 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2908 2909 if (!fdb_tx && is_cx5) 2910 direction_error = true; 2911 } else if (attr->ingress) { 2912 direction_error = true; 2913 } 2914 if (direction_error) 2915 return rte_flow_error_set(error, ENOTSUP, 2916 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 2917 NULL, 2918 "push vlan action not supported for ingress"); 2919 if (!attr->transfer && priv->representor) 2920 return rte_flow_error_set(error, ENOTSUP, 2921 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2922 "push vlan action for VF representor " 2923 "not supported on NIC table"); 2924 if (vlan_m && 2925 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) && 2926 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) != 2927 MLX5DV_FLOW_VLAN_PCP_MASK_BE && 2928 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) && 2929 !(mlx5_flow_find_action 2930 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP))) 2931 return rte_flow_error_set(error, EINVAL, 2932 RTE_FLOW_ERROR_TYPE_ACTION, action, 2933 "not full match mask on VLAN PCP and " 2934 "there is no of_set_vlan_pcp action, " 2935 "push VLAN action cannot figure out " 2936 "PCP value"); 2937 if (vlan_m && 2938 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) && 2939 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) != 2940 MLX5DV_FLOW_VLAN_VID_MASK_BE && 2941 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) && 2942 !(mlx5_flow_find_action 2943 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))) 2944 return rte_flow_error_set(error, EINVAL, 2945 RTE_FLOW_ERROR_TYPE_ACTION, action, 2946 "not full match mask on VLAN VID and " 2947 "there is no of_set_vlan_vid action, " 2948 "push VLAN action cannot figure out " 2949 "VID value"); 2950 (void)attr; 2951 return 0; 2952 } 2953 2954 /** 2955 * Validate the set VLAN PCP. 2956 * 2957 * @param[in] action_flags 2958 * Holds the actions detected until now. 2959 * @param[in] actions 2960 * Pointer to the list of actions remaining in the flow rule. 2961 * @param[out] error 2962 * Pointer to error structure. 2963 * 2964 * @return 2965 * 0 on success, a negative errno value otherwise and rte_errno is set. 2966 */ 2967 static int 2968 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags, 2969 const struct rte_flow_action actions[], 2970 struct rte_flow_error *error) 2971 { 2972 const struct rte_flow_action *action = actions; 2973 const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf; 2974 2975 if (conf->vlan_pcp > 7) 2976 return rte_flow_error_set(error, EINVAL, 2977 RTE_FLOW_ERROR_TYPE_ACTION, action, 2978 "VLAN PCP value is too big"); 2979 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)) 2980 return rte_flow_error_set(error, ENOTSUP, 2981 RTE_FLOW_ERROR_TYPE_ACTION, action, 2982 "set VLAN PCP action must follow " 2983 "the push VLAN action"); 2984 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) 2985 return rte_flow_error_set(error, ENOTSUP, 2986 RTE_FLOW_ERROR_TYPE_ACTION, action, 2987 "Multiple VLAN PCP modification are " 2988 "not supported"); 2989 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2990 return rte_flow_error_set(error, EINVAL, 2991 RTE_FLOW_ERROR_TYPE_ACTION, action, 2992 "wrong action order, port_id should " 2993 "be after set VLAN PCP"); 2994 return 0; 2995 } 2996 2997 /** 2998 * Validate the set VLAN VID. 2999 * 3000 * @param[in] item_flags 3001 * Holds the items detected in this rule. 3002 * @param[in] action_flags 3003 * Holds the actions detected until now. 3004 * @param[in] actions 3005 * Pointer to the list of actions remaining in the flow rule. 3006 * @param[out] error 3007 * Pointer to error structure. 3008 * 3009 * @return 3010 * 0 on success, a negative errno value otherwise and rte_errno is set. 3011 */ 3012 static int 3013 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags, 3014 uint64_t action_flags, 3015 const struct rte_flow_action actions[], 3016 struct rte_flow_error *error) 3017 { 3018 const struct rte_flow_action *action = actions; 3019 const struct rte_flow_action_of_set_vlan_vid *conf = action->conf; 3020 3021 if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE) 3022 return rte_flow_error_set(error, EINVAL, 3023 RTE_FLOW_ERROR_TYPE_ACTION, action, 3024 "VLAN VID value is too big"); 3025 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) && 3026 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 3027 return rte_flow_error_set(error, ENOTSUP, 3028 RTE_FLOW_ERROR_TYPE_ACTION, action, 3029 "set VLAN VID action must follow push" 3030 " VLAN action or match on VLAN item"); 3031 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) 3032 return rte_flow_error_set(error, ENOTSUP, 3033 RTE_FLOW_ERROR_TYPE_ACTION, action, 3034 "Multiple VLAN VID modifications are " 3035 "not supported"); 3036 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3037 return rte_flow_error_set(error, EINVAL, 3038 RTE_FLOW_ERROR_TYPE_ACTION, action, 3039 "wrong action order, port_id should " 3040 "be after set VLAN VID"); 3041 return 0; 3042 } 3043 3044 /* 3045 * Validate the FLAG action. 3046 * 3047 * @param[in] dev 3048 * Pointer to the rte_eth_dev structure. 3049 * @param[in] action_flags 3050 * Holds the actions detected until now. 3051 * @param[in] attr 3052 * Pointer to flow attributes 3053 * @param[out] error 3054 * Pointer to error structure. 3055 * 3056 * @return 3057 * 0 on success, a negative errno value otherwise and rte_errno is set. 3058 */ 3059 static int 3060 flow_dv_validate_action_flag(struct rte_eth_dev *dev, 3061 uint64_t action_flags, 3062 const struct rte_flow_attr *attr, 3063 struct rte_flow_error *error) 3064 { 3065 struct mlx5_priv *priv = dev->data->dev_private; 3066 struct mlx5_dev_config *config = &priv->config; 3067 int ret; 3068 3069 /* Fall back if no extended metadata register support. */ 3070 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3071 return mlx5_flow_validate_action_flag(action_flags, attr, 3072 error); 3073 /* Extensive metadata mode requires registers. */ 3074 if (!mlx5_flow_ext_mreg_supported(dev)) 3075 return rte_flow_error_set(error, ENOTSUP, 3076 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3077 "no metadata registers " 3078 "to support flag action"); 3079 if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT)) 3080 return rte_flow_error_set(error, ENOTSUP, 3081 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3082 "extended metadata register" 3083 " isn't available"); 3084 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3085 if (ret < 0) 3086 return ret; 3087 MLX5_ASSERT(ret > 0); 3088 if (action_flags & MLX5_FLOW_ACTION_MARK) 3089 return rte_flow_error_set(error, EINVAL, 3090 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3091 "can't mark and flag in same flow"); 3092 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3093 return rte_flow_error_set(error, EINVAL, 3094 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3095 "can't have 2 flag" 3096 " actions in same flow"); 3097 return 0; 3098 } 3099 3100 /** 3101 * Validate MARK action. 3102 * 3103 * @param[in] dev 3104 * Pointer to the rte_eth_dev structure. 3105 * @param[in] action 3106 * Pointer to action. 3107 * @param[in] action_flags 3108 * Holds the actions detected until now. 3109 * @param[in] attr 3110 * Pointer to flow attributes 3111 * @param[out] error 3112 * Pointer to error structure. 3113 * 3114 * @return 3115 * 0 on success, a negative errno value otherwise and rte_errno is set. 3116 */ 3117 static int 3118 flow_dv_validate_action_mark(struct rte_eth_dev *dev, 3119 const struct rte_flow_action *action, 3120 uint64_t action_flags, 3121 const struct rte_flow_attr *attr, 3122 struct rte_flow_error *error) 3123 { 3124 struct mlx5_priv *priv = dev->data->dev_private; 3125 struct mlx5_dev_config *config = &priv->config; 3126 const struct rte_flow_action_mark *mark = action->conf; 3127 int ret; 3128 3129 if (is_tunnel_offload_active(dev)) 3130 return rte_flow_error_set(error, ENOTSUP, 3131 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3132 "no mark action " 3133 "if tunnel offload active"); 3134 /* Fall back if no extended metadata register support. */ 3135 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3136 return mlx5_flow_validate_action_mark(action, action_flags, 3137 attr, error); 3138 /* Extensive metadata mode requires registers. */ 3139 if (!mlx5_flow_ext_mreg_supported(dev)) 3140 return rte_flow_error_set(error, ENOTSUP, 3141 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3142 "no metadata registers " 3143 "to support mark action"); 3144 if (!priv->sh->dv_mark_mask) 3145 return rte_flow_error_set(error, ENOTSUP, 3146 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3147 "extended metadata register" 3148 " isn't available"); 3149 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3150 if (ret < 0) 3151 return ret; 3152 MLX5_ASSERT(ret > 0); 3153 if (!mark) 3154 return rte_flow_error_set(error, EINVAL, 3155 RTE_FLOW_ERROR_TYPE_ACTION, action, 3156 "configuration cannot be null"); 3157 if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask)) 3158 return rte_flow_error_set(error, EINVAL, 3159 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 3160 &mark->id, 3161 "mark id exceeds the limit"); 3162 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3163 return rte_flow_error_set(error, EINVAL, 3164 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3165 "can't flag and mark in same flow"); 3166 if (action_flags & MLX5_FLOW_ACTION_MARK) 3167 return rte_flow_error_set(error, EINVAL, 3168 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3169 "can't have 2 mark actions in same" 3170 " flow"); 3171 return 0; 3172 } 3173 3174 /** 3175 * Validate SET_META action. 3176 * 3177 * @param[in] dev 3178 * Pointer to the rte_eth_dev structure. 3179 * @param[in] action 3180 * Pointer to the action structure. 3181 * @param[in] action_flags 3182 * Holds the actions detected until now. 3183 * @param[in] attr 3184 * Pointer to flow attributes 3185 * @param[out] error 3186 * Pointer to error structure. 3187 * 3188 * @return 3189 * 0 on success, a negative errno value otherwise and rte_errno is set. 3190 */ 3191 static int 3192 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev, 3193 const struct rte_flow_action *action, 3194 uint64_t action_flags __rte_unused, 3195 const struct rte_flow_attr *attr, 3196 struct rte_flow_error *error) 3197 { 3198 const struct rte_flow_action_set_meta *conf; 3199 uint32_t nic_mask = UINT32_MAX; 3200 int reg; 3201 3202 if (!mlx5_flow_ext_mreg_supported(dev)) 3203 return rte_flow_error_set(error, ENOTSUP, 3204 RTE_FLOW_ERROR_TYPE_ACTION, action, 3205 "extended metadata register" 3206 " isn't supported"); 3207 reg = flow_dv_get_metadata_reg(dev, attr, error); 3208 if (reg < 0) 3209 return reg; 3210 if (reg == REG_NON) 3211 return rte_flow_error_set(error, ENOTSUP, 3212 RTE_FLOW_ERROR_TYPE_ACTION, action, 3213 "unavalable extended metadata register"); 3214 if (reg != REG_A && reg != REG_B) { 3215 struct mlx5_priv *priv = dev->data->dev_private; 3216 3217 nic_mask = priv->sh->dv_meta_mask; 3218 } 3219 if (!(action->conf)) 3220 return rte_flow_error_set(error, EINVAL, 3221 RTE_FLOW_ERROR_TYPE_ACTION, action, 3222 "configuration cannot be null"); 3223 conf = (const struct rte_flow_action_set_meta *)action->conf; 3224 if (!conf->mask) 3225 return rte_flow_error_set(error, EINVAL, 3226 RTE_FLOW_ERROR_TYPE_ACTION, action, 3227 "zero mask doesn't have any effect"); 3228 if (conf->mask & ~nic_mask) 3229 return rte_flow_error_set(error, EINVAL, 3230 RTE_FLOW_ERROR_TYPE_ACTION, action, 3231 "meta data must be within reg C0"); 3232 return 0; 3233 } 3234 3235 /** 3236 * Validate SET_TAG action. 3237 * 3238 * @param[in] dev 3239 * Pointer to the rte_eth_dev structure. 3240 * @param[in] action 3241 * Pointer to the action structure. 3242 * @param[in] action_flags 3243 * Holds the actions detected until now. 3244 * @param[in] attr 3245 * Pointer to flow attributes 3246 * @param[out] error 3247 * Pointer to error structure. 3248 * 3249 * @return 3250 * 0 on success, a negative errno value otherwise and rte_errno is set. 3251 */ 3252 static int 3253 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, 3254 const struct rte_flow_action *action, 3255 uint64_t action_flags, 3256 const struct rte_flow_attr *attr, 3257 struct rte_flow_error *error) 3258 { 3259 const struct rte_flow_action_set_tag *conf; 3260 const uint64_t terminal_action_flags = 3261 MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | 3262 MLX5_FLOW_ACTION_RSS; 3263 int ret; 3264 3265 if (!mlx5_flow_ext_mreg_supported(dev)) 3266 return rte_flow_error_set(error, ENOTSUP, 3267 RTE_FLOW_ERROR_TYPE_ACTION, action, 3268 "extensive metadata register" 3269 " isn't supported"); 3270 if (!(action->conf)) 3271 return rte_flow_error_set(error, EINVAL, 3272 RTE_FLOW_ERROR_TYPE_ACTION, action, 3273 "configuration cannot be null"); 3274 conf = (const struct rte_flow_action_set_tag *)action->conf; 3275 if (!conf->mask) 3276 return rte_flow_error_set(error, EINVAL, 3277 RTE_FLOW_ERROR_TYPE_ACTION, action, 3278 "zero mask doesn't have any effect"); 3279 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 3280 if (ret < 0) 3281 return ret; 3282 if (!attr->transfer && attr->ingress && 3283 (action_flags & terminal_action_flags)) 3284 return rte_flow_error_set(error, EINVAL, 3285 RTE_FLOW_ERROR_TYPE_ACTION, action, 3286 "set_tag has no effect" 3287 " with terminal actions"); 3288 return 0; 3289 } 3290 3291 /** 3292 * Validate count action. 3293 * 3294 * @param[in] dev 3295 * Pointer to rte_eth_dev structure. 3296 * @param[in] shared 3297 * Indicator if action is shared. 3298 * @param[in] action_flags 3299 * Holds the actions detected until now. 3300 * @param[out] error 3301 * Pointer to error structure. 3302 * 3303 * @return 3304 * 0 on success, a negative errno value otherwise and rte_errno is set. 3305 */ 3306 static int 3307 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared, 3308 uint64_t action_flags, 3309 struct rte_flow_error *error) 3310 { 3311 struct mlx5_priv *priv = dev->data->dev_private; 3312 3313 if (!priv->sh->devx) 3314 goto notsup_err; 3315 if (action_flags & MLX5_FLOW_ACTION_COUNT) 3316 return rte_flow_error_set(error, EINVAL, 3317 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3318 "duplicate count actions set"); 3319 if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) && 3320 !priv->sh->flow_hit_aso_en) 3321 return rte_flow_error_set(error, EINVAL, 3322 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3323 "old age and shared count combination is not supported"); 3324 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 3325 return 0; 3326 #endif 3327 notsup_err: 3328 return rte_flow_error_set 3329 (error, ENOTSUP, 3330 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3331 NULL, 3332 "count action not supported"); 3333 } 3334 3335 /** 3336 * Validate the L2 encap action. 3337 * 3338 * @param[in] dev 3339 * Pointer to the rte_eth_dev structure. 3340 * @param[in] action_flags 3341 * Holds the actions detected until now. 3342 * @param[in] action 3343 * Pointer to the action structure. 3344 * @param[in] attr 3345 * Pointer to flow attributes. 3346 * @param[out] error 3347 * Pointer to error structure. 3348 * 3349 * @return 3350 * 0 on success, a negative errno value otherwise and rte_errno is set. 3351 */ 3352 static int 3353 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev, 3354 uint64_t action_flags, 3355 const struct rte_flow_action *action, 3356 const struct rte_flow_attr *attr, 3357 struct rte_flow_error *error) 3358 { 3359 const struct mlx5_priv *priv = dev->data->dev_private; 3360 3361 if (!(action->conf)) 3362 return rte_flow_error_set(error, EINVAL, 3363 RTE_FLOW_ERROR_TYPE_ACTION, action, 3364 "configuration cannot be null"); 3365 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3366 return rte_flow_error_set(error, EINVAL, 3367 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3368 "can only have a single encap action " 3369 "in a flow"); 3370 if (!attr->transfer && priv->representor) 3371 return rte_flow_error_set(error, ENOTSUP, 3372 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3373 "encap action for VF representor " 3374 "not supported on NIC table"); 3375 return 0; 3376 } 3377 3378 /** 3379 * Validate a decap action. 3380 * 3381 * @param[in] dev 3382 * Pointer to the rte_eth_dev structure. 3383 * @param[in] action_flags 3384 * Holds the actions detected until now. 3385 * @param[in] action 3386 * Pointer to the action structure. 3387 * @param[in] item_flags 3388 * Holds the items detected. 3389 * @param[in] attr 3390 * Pointer to flow attributes 3391 * @param[out] error 3392 * Pointer to error structure. 3393 * 3394 * @return 3395 * 0 on success, a negative errno value otherwise and rte_errno is set. 3396 */ 3397 static int 3398 flow_dv_validate_action_decap(struct rte_eth_dev *dev, 3399 uint64_t action_flags, 3400 const struct rte_flow_action *action, 3401 const uint64_t item_flags, 3402 const struct rte_flow_attr *attr, 3403 struct rte_flow_error *error) 3404 { 3405 const struct mlx5_priv *priv = dev->data->dev_private; 3406 3407 if (priv->config.hca_attr.scatter_fcs_w_decap_disable && 3408 !priv->config.decap_en) 3409 return rte_flow_error_set(error, ENOTSUP, 3410 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3411 "decap is not enabled"); 3412 if (action_flags & MLX5_FLOW_XCAP_ACTIONS) 3413 return rte_flow_error_set(error, ENOTSUP, 3414 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3415 action_flags & 3416 MLX5_FLOW_ACTION_DECAP ? "can only " 3417 "have a single decap action" : "decap " 3418 "after encap is not supported"); 3419 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 3420 return rte_flow_error_set(error, EINVAL, 3421 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3422 "can't have decap action after" 3423 " modify action"); 3424 if (attr->egress) 3425 return rte_flow_error_set(error, ENOTSUP, 3426 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 3427 NULL, 3428 "decap action not supported for " 3429 "egress"); 3430 if (!attr->transfer && priv->representor) 3431 return rte_flow_error_set(error, ENOTSUP, 3432 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3433 "decap action for VF representor " 3434 "not supported on NIC table"); 3435 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP && 3436 !(item_flags & MLX5_FLOW_LAYER_VXLAN)) 3437 return rte_flow_error_set(error, ENOTSUP, 3438 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3439 "VXLAN item should be present for VXLAN decap"); 3440 return 0; 3441 } 3442 3443 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,}; 3444 3445 /** 3446 * Validate the raw encap and decap actions. 3447 * 3448 * @param[in] dev 3449 * Pointer to the rte_eth_dev structure. 3450 * @param[in] decap 3451 * Pointer to the decap action. 3452 * @param[in] encap 3453 * Pointer to the encap action. 3454 * @param[in] attr 3455 * Pointer to flow attributes 3456 * @param[in/out] action_flags 3457 * Holds the actions detected until now. 3458 * @param[out] actions_n 3459 * pointer to the number of actions counter. 3460 * @param[in] action 3461 * Pointer to the action structure. 3462 * @param[in] item_flags 3463 * Holds the items detected. 3464 * @param[out] error 3465 * Pointer to error structure. 3466 * 3467 * @return 3468 * 0 on success, a negative errno value otherwise and rte_errno is set. 3469 */ 3470 static int 3471 flow_dv_validate_action_raw_encap_decap 3472 (struct rte_eth_dev *dev, 3473 const struct rte_flow_action_raw_decap *decap, 3474 const struct rte_flow_action_raw_encap *encap, 3475 const struct rte_flow_attr *attr, uint64_t *action_flags, 3476 int *actions_n, const struct rte_flow_action *action, 3477 uint64_t item_flags, struct rte_flow_error *error) 3478 { 3479 const struct mlx5_priv *priv = dev->data->dev_private; 3480 int ret; 3481 3482 if (encap && (!encap->size || !encap->data)) 3483 return rte_flow_error_set(error, EINVAL, 3484 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3485 "raw encap data cannot be empty"); 3486 if (decap && encap) { 3487 if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE && 3488 encap->size > MLX5_ENCAPSULATION_DECISION_SIZE) 3489 /* L3 encap. */ 3490 decap = NULL; 3491 else if (encap->size <= 3492 MLX5_ENCAPSULATION_DECISION_SIZE && 3493 decap->size > 3494 MLX5_ENCAPSULATION_DECISION_SIZE) 3495 /* L3 decap. */ 3496 encap = NULL; 3497 else if (encap->size > 3498 MLX5_ENCAPSULATION_DECISION_SIZE && 3499 decap->size > 3500 MLX5_ENCAPSULATION_DECISION_SIZE) 3501 /* 2 L2 actions: encap and decap. */ 3502 ; 3503 else 3504 return rte_flow_error_set(error, 3505 ENOTSUP, 3506 RTE_FLOW_ERROR_TYPE_ACTION, 3507 NULL, "unsupported too small " 3508 "raw decap and too small raw " 3509 "encap combination"); 3510 } 3511 if (decap) { 3512 ret = flow_dv_validate_action_decap(dev, *action_flags, action, 3513 item_flags, attr, error); 3514 if (ret < 0) 3515 return ret; 3516 *action_flags |= MLX5_FLOW_ACTION_DECAP; 3517 ++(*actions_n); 3518 } 3519 if (encap) { 3520 if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE) 3521 return rte_flow_error_set(error, ENOTSUP, 3522 RTE_FLOW_ERROR_TYPE_ACTION, 3523 NULL, 3524 "small raw encap size"); 3525 if (*action_flags & MLX5_FLOW_ACTION_ENCAP) 3526 return rte_flow_error_set(error, EINVAL, 3527 RTE_FLOW_ERROR_TYPE_ACTION, 3528 NULL, 3529 "more than one encap action"); 3530 if (!attr->transfer && priv->representor) 3531 return rte_flow_error_set 3532 (error, ENOTSUP, 3533 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3534 "encap action for VF representor " 3535 "not supported on NIC table"); 3536 *action_flags |= MLX5_FLOW_ACTION_ENCAP; 3537 ++(*actions_n); 3538 } 3539 return 0; 3540 } 3541 3542 /* 3543 * Validate the ASO CT action. 3544 * 3545 * @param[in] dev 3546 * Pointer to the rte_eth_dev structure. 3547 * @param[in] action_flags 3548 * Holds the actions detected until now. 3549 * @param[in] item_flags 3550 * The items found in this flow rule. 3551 * @param[in] attr 3552 * Pointer to flow attributes. 3553 * @param[out] error 3554 * Pointer to error structure. 3555 * 3556 * @return 3557 * 0 on success, a negative errno value otherwise and rte_errno is set. 3558 */ 3559 static int 3560 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, 3561 uint64_t action_flags, 3562 uint64_t item_flags, 3563 const struct rte_flow_attr *attr, 3564 struct rte_flow_error *error) 3565 { 3566 RTE_SET_USED(dev); 3567 3568 if (attr->group == 0 && !attr->transfer) 3569 return rte_flow_error_set(error, ENOTSUP, 3570 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3571 NULL, 3572 "Only support non-root table"); 3573 if (action_flags & MLX5_FLOW_FATE_ACTIONS) 3574 return rte_flow_error_set(error, ENOTSUP, 3575 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3576 "CT cannot follow a fate action"); 3577 if ((action_flags & MLX5_FLOW_ACTION_METER) || 3578 (action_flags & MLX5_FLOW_ACTION_AGE)) 3579 return rte_flow_error_set(error, EINVAL, 3580 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3581 "Only one ASO action is supported"); 3582 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3583 return rte_flow_error_set(error, EINVAL, 3584 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3585 "Encap cannot exist before CT"); 3586 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP)) 3587 return rte_flow_error_set(error, EINVAL, 3588 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3589 "Not a outer TCP packet"); 3590 return 0; 3591 } 3592 3593 int 3594 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused, 3595 struct mlx5_list_entry *entry, void *cb_ctx) 3596 { 3597 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3598 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3599 struct mlx5_flow_dv_encap_decap_resource *resource; 3600 3601 resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource, 3602 entry); 3603 if (resource->reformat_type == ctx_resource->reformat_type && 3604 resource->ft_type == ctx_resource->ft_type && 3605 resource->flags == ctx_resource->flags && 3606 resource->size == ctx_resource->size && 3607 !memcmp((const void *)resource->buf, 3608 (const void *)ctx_resource->buf, 3609 resource->size)) 3610 return 0; 3611 return -1; 3612 } 3613 3614 struct mlx5_list_entry * 3615 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx) 3616 { 3617 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3618 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3619 struct mlx5dv_dr_domain *domain; 3620 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3621 struct mlx5_flow_dv_encap_decap_resource *resource; 3622 uint32_t idx; 3623 int ret; 3624 3625 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3626 domain = sh->fdb_domain; 3627 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3628 domain = sh->rx_domain; 3629 else 3630 domain = sh->tx_domain; 3631 /* Register new encap/decap resource. */ 3632 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx); 3633 if (!resource) { 3634 rte_flow_error_set(ctx->error, ENOMEM, 3635 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3636 "cannot allocate resource memory"); 3637 return NULL; 3638 } 3639 *resource = *ctx_resource; 3640 resource->idx = idx; 3641 ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx, 3642 domain, resource, 3643 &resource->action); 3644 if (ret) { 3645 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx); 3646 rte_flow_error_set(ctx->error, ENOMEM, 3647 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3648 NULL, "cannot create action"); 3649 return NULL; 3650 } 3651 3652 return &resource->entry; 3653 } 3654 3655 struct mlx5_list_entry * 3656 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 3657 void *cb_ctx) 3658 { 3659 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3660 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3661 struct mlx5_flow_dv_encap_decap_resource *cache_resource; 3662 uint32_t idx; 3663 3664 cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 3665 &idx); 3666 if (!cache_resource) { 3667 rte_flow_error_set(ctx->error, ENOMEM, 3668 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3669 "cannot allocate resource memory"); 3670 return NULL; 3671 } 3672 memcpy(cache_resource, oentry, sizeof(*cache_resource)); 3673 cache_resource->idx = idx; 3674 return &cache_resource->entry; 3675 } 3676 3677 void 3678 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3679 { 3680 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3681 struct mlx5_flow_dv_encap_decap_resource *res = 3682 container_of(entry, typeof(*res), entry); 3683 3684 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 3685 } 3686 3687 /** 3688 * Find existing encap/decap resource or create and register a new one. 3689 * 3690 * @param[in, out] dev 3691 * Pointer to rte_eth_dev structure. 3692 * @param[in, out] resource 3693 * Pointer to encap/decap resource. 3694 * @parm[in, out] dev_flow 3695 * Pointer to the dev_flow. 3696 * @param[out] error 3697 * pointer to error structure. 3698 * 3699 * @return 3700 * 0 on success otherwise -errno and errno is set. 3701 */ 3702 static int 3703 flow_dv_encap_decap_resource_register 3704 (struct rte_eth_dev *dev, 3705 struct mlx5_flow_dv_encap_decap_resource *resource, 3706 struct mlx5_flow *dev_flow, 3707 struct rte_flow_error *error) 3708 { 3709 struct mlx5_priv *priv = dev->data->dev_private; 3710 struct mlx5_dev_ctx_shared *sh = priv->sh; 3711 struct mlx5_list_entry *entry; 3712 union { 3713 struct { 3714 uint32_t ft_type:8; 3715 uint32_t refmt_type:8; 3716 /* 3717 * Header reformat actions can be shared between 3718 * non-root tables. One bit to indicate non-root 3719 * table or not. 3720 */ 3721 uint32_t is_root:1; 3722 uint32_t reserve:15; 3723 }; 3724 uint32_t v32; 3725 } encap_decap_key = { 3726 { 3727 .ft_type = resource->ft_type, 3728 .refmt_type = resource->reformat_type, 3729 .is_root = !!dev_flow->dv.group, 3730 .reserve = 0, 3731 } 3732 }; 3733 struct mlx5_flow_cb_ctx ctx = { 3734 .error = error, 3735 .data = resource, 3736 }; 3737 struct mlx5_hlist *encaps_decaps; 3738 uint64_t key64; 3739 3740 encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps, 3741 "encaps_decaps", 3742 MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ, 3743 true, true, sh, 3744 flow_dv_encap_decap_create_cb, 3745 flow_dv_encap_decap_match_cb, 3746 flow_dv_encap_decap_remove_cb, 3747 flow_dv_encap_decap_clone_cb, 3748 flow_dv_encap_decap_clone_free_cb); 3749 if (unlikely(!encaps_decaps)) 3750 return -rte_errno; 3751 resource->flags = dev_flow->dv.group ? 0 : 1; 3752 key64 = __rte_raw_cksum(&encap_decap_key.v32, 3753 sizeof(encap_decap_key.v32), 0); 3754 if (resource->reformat_type != 3755 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 && 3756 resource->size) 3757 key64 = __rte_raw_cksum(resource->buf, resource->size, key64); 3758 entry = mlx5_hlist_register(encaps_decaps, key64, &ctx); 3759 if (!entry) 3760 return -rte_errno; 3761 resource = container_of(entry, typeof(*resource), entry); 3762 dev_flow->dv.encap_decap = resource; 3763 dev_flow->handle->dvh.rix_encap_decap = resource->idx; 3764 return 0; 3765 } 3766 3767 /** 3768 * Find existing table jump resource or create and register a new one. 3769 * 3770 * @param[in, out] dev 3771 * Pointer to rte_eth_dev structure. 3772 * @param[in, out] tbl 3773 * Pointer to flow table resource. 3774 * @parm[in, out] dev_flow 3775 * Pointer to the dev_flow. 3776 * @param[out] error 3777 * pointer to error structure. 3778 * 3779 * @return 3780 * 0 on success otherwise -errno and errno is set. 3781 */ 3782 static int 3783 flow_dv_jump_tbl_resource_register 3784 (struct rte_eth_dev *dev __rte_unused, 3785 struct mlx5_flow_tbl_resource *tbl, 3786 struct mlx5_flow *dev_flow, 3787 struct rte_flow_error *error __rte_unused) 3788 { 3789 struct mlx5_flow_tbl_data_entry *tbl_data = 3790 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 3791 3792 MLX5_ASSERT(tbl); 3793 MLX5_ASSERT(tbl_data->jump.action); 3794 dev_flow->handle->rix_jump = tbl_data->idx; 3795 dev_flow->dv.jump = &tbl_data->jump; 3796 return 0; 3797 } 3798 3799 int 3800 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused, 3801 struct mlx5_list_entry *entry, void *cb_ctx) 3802 { 3803 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3804 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3805 struct mlx5_flow_dv_port_id_action_resource *res = 3806 container_of(entry, typeof(*res), entry); 3807 3808 return ref->port_id != res->port_id; 3809 } 3810 3811 struct mlx5_list_entry * 3812 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx) 3813 { 3814 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3815 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3816 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3817 struct mlx5_flow_dv_port_id_action_resource *resource; 3818 uint32_t idx; 3819 int ret; 3820 3821 /* Register new port id action resource. */ 3822 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3823 if (!resource) { 3824 rte_flow_error_set(ctx->error, ENOMEM, 3825 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3826 "cannot allocate port_id action memory"); 3827 return NULL; 3828 } 3829 *resource = *ref; 3830 ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain, 3831 ref->port_id, 3832 &resource->action); 3833 if (ret) { 3834 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx); 3835 rte_flow_error_set(ctx->error, ENOMEM, 3836 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3837 "cannot create action"); 3838 return NULL; 3839 } 3840 resource->idx = idx; 3841 return &resource->entry; 3842 } 3843 3844 struct mlx5_list_entry * 3845 flow_dv_port_id_clone_cb(void *tool_ctx, 3846 struct mlx5_list_entry *entry __rte_unused, 3847 void *cb_ctx) 3848 { 3849 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3850 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3851 struct mlx5_flow_dv_port_id_action_resource *resource; 3852 uint32_t idx; 3853 3854 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3855 if (!resource) { 3856 rte_flow_error_set(ctx->error, ENOMEM, 3857 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3858 "cannot allocate port_id action memory"); 3859 return NULL; 3860 } 3861 memcpy(resource, entry, sizeof(*resource)); 3862 resource->idx = idx; 3863 return &resource->entry; 3864 } 3865 3866 void 3867 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3868 { 3869 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3870 struct mlx5_flow_dv_port_id_action_resource *resource = 3871 container_of(entry, typeof(*resource), entry); 3872 3873 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 3874 } 3875 3876 /** 3877 * Find existing table port ID resource or create and register a new one. 3878 * 3879 * @param[in, out] dev 3880 * Pointer to rte_eth_dev structure. 3881 * @param[in, out] ref 3882 * Pointer to port ID action resource reference. 3883 * @parm[in, out] dev_flow 3884 * Pointer to the dev_flow. 3885 * @param[out] error 3886 * pointer to error structure. 3887 * 3888 * @return 3889 * 0 on success otherwise -errno and errno is set. 3890 */ 3891 static int 3892 flow_dv_port_id_action_resource_register 3893 (struct rte_eth_dev *dev, 3894 struct mlx5_flow_dv_port_id_action_resource *ref, 3895 struct mlx5_flow *dev_flow, 3896 struct rte_flow_error *error) 3897 { 3898 struct mlx5_priv *priv = dev->data->dev_private; 3899 struct mlx5_list_entry *entry; 3900 struct mlx5_flow_dv_port_id_action_resource *resource; 3901 struct mlx5_flow_cb_ctx ctx = { 3902 .error = error, 3903 .data = ref, 3904 }; 3905 3906 entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx); 3907 if (!entry) 3908 return -rte_errno; 3909 resource = container_of(entry, typeof(*resource), entry); 3910 dev_flow->dv.port_id_action = resource; 3911 dev_flow->handle->rix_port_id_action = resource->idx; 3912 return 0; 3913 } 3914 3915 int 3916 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused, 3917 struct mlx5_list_entry *entry, void *cb_ctx) 3918 { 3919 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3920 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3921 struct mlx5_flow_dv_push_vlan_action_resource *res = 3922 container_of(entry, typeof(*res), entry); 3923 3924 return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type; 3925 } 3926 3927 struct mlx5_list_entry * 3928 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx) 3929 { 3930 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3931 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3932 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3933 struct mlx5_flow_dv_push_vlan_action_resource *resource; 3934 struct mlx5dv_dr_domain *domain; 3935 uint32_t idx; 3936 int ret; 3937 3938 /* Register new port id action resource. */ 3939 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 3940 if (!resource) { 3941 rte_flow_error_set(ctx->error, ENOMEM, 3942 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3943 "cannot allocate push_vlan action memory"); 3944 return NULL; 3945 } 3946 *resource = *ref; 3947 if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3948 domain = sh->fdb_domain; 3949 else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3950 domain = sh->rx_domain; 3951 else 3952 domain = sh->tx_domain; 3953 ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag, 3954 &resource->action); 3955 if (ret) { 3956 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 3957 rte_flow_error_set(ctx->error, ENOMEM, 3958 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3959 "cannot create push vlan action"); 3960 return NULL; 3961 } 3962 resource->idx = idx; 3963 return &resource->entry; 3964 } 3965 3966 struct mlx5_list_entry * 3967 flow_dv_push_vlan_clone_cb(void *tool_ctx, 3968 struct mlx5_list_entry *entry __rte_unused, 3969 void *cb_ctx) 3970 { 3971 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3972 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3973 struct mlx5_flow_dv_push_vlan_action_resource *resource; 3974 uint32_t idx; 3975 3976 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 3977 if (!resource) { 3978 rte_flow_error_set(ctx->error, ENOMEM, 3979 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3980 "cannot allocate push_vlan action memory"); 3981 return NULL; 3982 } 3983 memcpy(resource, entry, sizeof(*resource)); 3984 resource->idx = idx; 3985 return &resource->entry; 3986 } 3987 3988 void 3989 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3990 { 3991 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3992 struct mlx5_flow_dv_push_vlan_action_resource *resource = 3993 container_of(entry, typeof(*resource), entry); 3994 3995 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 3996 } 3997 3998 /** 3999 * Find existing push vlan resource or create and register a new one. 4000 * 4001 * @param [in, out] dev 4002 * Pointer to rte_eth_dev structure. 4003 * @param[in, out] ref 4004 * Pointer to port ID action resource reference. 4005 * @parm[in, out] dev_flow 4006 * Pointer to the dev_flow. 4007 * @param[out] error 4008 * pointer to error structure. 4009 * 4010 * @return 4011 * 0 on success otherwise -errno and errno is set. 4012 */ 4013 static int 4014 flow_dv_push_vlan_action_resource_register 4015 (struct rte_eth_dev *dev, 4016 struct mlx5_flow_dv_push_vlan_action_resource *ref, 4017 struct mlx5_flow *dev_flow, 4018 struct rte_flow_error *error) 4019 { 4020 struct mlx5_priv *priv = dev->data->dev_private; 4021 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4022 struct mlx5_list_entry *entry; 4023 struct mlx5_flow_cb_ctx ctx = { 4024 .error = error, 4025 .data = ref, 4026 }; 4027 4028 entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx); 4029 if (!entry) 4030 return -rte_errno; 4031 resource = container_of(entry, typeof(*resource), entry); 4032 4033 dev_flow->handle->dvh.rix_push_vlan = resource->idx; 4034 dev_flow->dv.push_vlan_res = resource; 4035 return 0; 4036 } 4037 4038 /** 4039 * Get the size of specific rte_flow_item_type hdr size 4040 * 4041 * @param[in] item_type 4042 * Tested rte_flow_item_type. 4043 * 4044 * @return 4045 * sizeof struct item_type, 0 if void or irrelevant. 4046 */ 4047 static size_t 4048 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type) 4049 { 4050 size_t retval; 4051 4052 switch (item_type) { 4053 case RTE_FLOW_ITEM_TYPE_ETH: 4054 retval = sizeof(struct rte_ether_hdr); 4055 break; 4056 case RTE_FLOW_ITEM_TYPE_VLAN: 4057 retval = sizeof(struct rte_vlan_hdr); 4058 break; 4059 case RTE_FLOW_ITEM_TYPE_IPV4: 4060 retval = sizeof(struct rte_ipv4_hdr); 4061 break; 4062 case RTE_FLOW_ITEM_TYPE_IPV6: 4063 retval = sizeof(struct rte_ipv6_hdr); 4064 break; 4065 case RTE_FLOW_ITEM_TYPE_UDP: 4066 retval = sizeof(struct rte_udp_hdr); 4067 break; 4068 case RTE_FLOW_ITEM_TYPE_TCP: 4069 retval = sizeof(struct rte_tcp_hdr); 4070 break; 4071 case RTE_FLOW_ITEM_TYPE_VXLAN: 4072 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4073 retval = sizeof(struct rte_vxlan_hdr); 4074 break; 4075 case RTE_FLOW_ITEM_TYPE_GRE: 4076 case RTE_FLOW_ITEM_TYPE_NVGRE: 4077 retval = sizeof(struct rte_gre_hdr); 4078 break; 4079 case RTE_FLOW_ITEM_TYPE_MPLS: 4080 retval = sizeof(struct rte_mpls_hdr); 4081 break; 4082 case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */ 4083 default: 4084 retval = 0; 4085 break; 4086 } 4087 return retval; 4088 } 4089 4090 #define MLX5_ENCAP_IPV4_VERSION 0x40 4091 #define MLX5_ENCAP_IPV4_IHL_MIN 0x05 4092 #define MLX5_ENCAP_IPV4_TTL_DEF 0x40 4093 #define MLX5_ENCAP_IPV6_VTC_FLOW 0x60000000 4094 #define MLX5_ENCAP_IPV6_HOP_LIMIT 0xff 4095 #define MLX5_ENCAP_VXLAN_FLAGS 0x08000000 4096 #define MLX5_ENCAP_VXLAN_GPE_FLAGS 0x04 4097 4098 /** 4099 * Convert the encap action data from list of rte_flow_item to raw buffer 4100 * 4101 * @param[in] items 4102 * Pointer to rte_flow_item objects list. 4103 * @param[out] buf 4104 * Pointer to the output buffer. 4105 * @param[out] size 4106 * Pointer to the output buffer size. 4107 * @param[out] error 4108 * Pointer to the error structure. 4109 * 4110 * @return 4111 * 0 on success, a negative errno value otherwise and rte_errno is set. 4112 */ 4113 static int 4114 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf, 4115 size_t *size, struct rte_flow_error *error) 4116 { 4117 struct rte_ether_hdr *eth = NULL; 4118 struct rte_vlan_hdr *vlan = NULL; 4119 struct rte_ipv4_hdr *ipv4 = NULL; 4120 struct rte_ipv6_hdr *ipv6 = NULL; 4121 struct rte_udp_hdr *udp = NULL; 4122 struct rte_vxlan_hdr *vxlan = NULL; 4123 struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL; 4124 struct rte_gre_hdr *gre = NULL; 4125 size_t len; 4126 size_t temp_size = 0; 4127 4128 if (!items) 4129 return rte_flow_error_set(error, EINVAL, 4130 RTE_FLOW_ERROR_TYPE_ACTION, 4131 NULL, "invalid empty data"); 4132 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 4133 len = flow_dv_get_item_hdr_len(items->type); 4134 if (len + temp_size > MLX5_ENCAP_MAX_LEN) 4135 return rte_flow_error_set(error, EINVAL, 4136 RTE_FLOW_ERROR_TYPE_ACTION, 4137 (void *)items->type, 4138 "items total size is too big" 4139 " for encap action"); 4140 rte_memcpy((void *)&buf[temp_size], items->spec, len); 4141 switch (items->type) { 4142 case RTE_FLOW_ITEM_TYPE_ETH: 4143 eth = (struct rte_ether_hdr *)&buf[temp_size]; 4144 break; 4145 case RTE_FLOW_ITEM_TYPE_VLAN: 4146 vlan = (struct rte_vlan_hdr *)&buf[temp_size]; 4147 if (!eth) 4148 return rte_flow_error_set(error, EINVAL, 4149 RTE_FLOW_ERROR_TYPE_ACTION, 4150 (void *)items->type, 4151 "eth header not found"); 4152 if (!eth->ether_type) 4153 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN); 4154 break; 4155 case RTE_FLOW_ITEM_TYPE_IPV4: 4156 ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size]; 4157 if (!vlan && !eth) 4158 return rte_flow_error_set(error, EINVAL, 4159 RTE_FLOW_ERROR_TYPE_ACTION, 4160 (void *)items->type, 4161 "neither eth nor vlan" 4162 " header found"); 4163 if (vlan && !vlan->eth_proto) 4164 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4165 else if (eth && !eth->ether_type) 4166 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4167 if (!ipv4->version_ihl) 4168 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION | 4169 MLX5_ENCAP_IPV4_IHL_MIN; 4170 if (!ipv4->time_to_live) 4171 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF; 4172 break; 4173 case RTE_FLOW_ITEM_TYPE_IPV6: 4174 ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size]; 4175 if (!vlan && !eth) 4176 return rte_flow_error_set(error, EINVAL, 4177 RTE_FLOW_ERROR_TYPE_ACTION, 4178 (void *)items->type, 4179 "neither eth nor vlan" 4180 " header found"); 4181 if (vlan && !vlan->eth_proto) 4182 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4183 else if (eth && !eth->ether_type) 4184 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4185 if (!ipv6->vtc_flow) 4186 ipv6->vtc_flow = 4187 RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW); 4188 if (!ipv6->hop_limits) 4189 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT; 4190 break; 4191 case RTE_FLOW_ITEM_TYPE_UDP: 4192 udp = (struct rte_udp_hdr *)&buf[temp_size]; 4193 if (!ipv4 && !ipv6) 4194 return rte_flow_error_set(error, EINVAL, 4195 RTE_FLOW_ERROR_TYPE_ACTION, 4196 (void *)items->type, 4197 "ip header not found"); 4198 if (ipv4 && !ipv4->next_proto_id) 4199 ipv4->next_proto_id = IPPROTO_UDP; 4200 else if (ipv6 && !ipv6->proto) 4201 ipv6->proto = IPPROTO_UDP; 4202 break; 4203 case RTE_FLOW_ITEM_TYPE_VXLAN: 4204 vxlan = (struct rte_vxlan_hdr *)&buf[temp_size]; 4205 if (!udp) 4206 return rte_flow_error_set(error, EINVAL, 4207 RTE_FLOW_ERROR_TYPE_ACTION, 4208 (void *)items->type, 4209 "udp header not found"); 4210 if (!udp->dst_port) 4211 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN); 4212 if (!vxlan->vx_flags) 4213 vxlan->vx_flags = 4214 RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS); 4215 break; 4216 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4217 vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size]; 4218 if (!udp) 4219 return rte_flow_error_set(error, EINVAL, 4220 RTE_FLOW_ERROR_TYPE_ACTION, 4221 (void *)items->type, 4222 "udp header not found"); 4223 if (!vxlan_gpe->proto) 4224 return rte_flow_error_set(error, EINVAL, 4225 RTE_FLOW_ERROR_TYPE_ACTION, 4226 (void *)items->type, 4227 "next protocol not found"); 4228 if (!udp->dst_port) 4229 udp->dst_port = 4230 RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE); 4231 if (!vxlan_gpe->vx_flags) 4232 vxlan_gpe->vx_flags = 4233 MLX5_ENCAP_VXLAN_GPE_FLAGS; 4234 break; 4235 case RTE_FLOW_ITEM_TYPE_GRE: 4236 case RTE_FLOW_ITEM_TYPE_NVGRE: 4237 gre = (struct rte_gre_hdr *)&buf[temp_size]; 4238 if (!gre->proto) 4239 return rte_flow_error_set(error, EINVAL, 4240 RTE_FLOW_ERROR_TYPE_ACTION, 4241 (void *)items->type, 4242 "next protocol not found"); 4243 if (!ipv4 && !ipv6) 4244 return rte_flow_error_set(error, EINVAL, 4245 RTE_FLOW_ERROR_TYPE_ACTION, 4246 (void *)items->type, 4247 "ip header not found"); 4248 if (ipv4 && !ipv4->next_proto_id) 4249 ipv4->next_proto_id = IPPROTO_GRE; 4250 else if (ipv6 && !ipv6->proto) 4251 ipv6->proto = IPPROTO_GRE; 4252 break; 4253 case RTE_FLOW_ITEM_TYPE_VOID: 4254 break; 4255 default: 4256 return rte_flow_error_set(error, EINVAL, 4257 RTE_FLOW_ERROR_TYPE_ACTION, 4258 (void *)items->type, 4259 "unsupported item type"); 4260 break; 4261 } 4262 temp_size += len; 4263 } 4264 *size = temp_size; 4265 return 0; 4266 } 4267 4268 static int 4269 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error) 4270 { 4271 struct rte_ether_hdr *eth = NULL; 4272 struct rte_vlan_hdr *vlan = NULL; 4273 struct rte_ipv6_hdr *ipv6 = NULL; 4274 struct rte_udp_hdr *udp = NULL; 4275 char *next_hdr; 4276 uint16_t proto; 4277 4278 eth = (struct rte_ether_hdr *)data; 4279 next_hdr = (char *)(eth + 1); 4280 proto = RTE_BE16(eth->ether_type); 4281 4282 /* VLAN skipping */ 4283 while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) { 4284 vlan = (struct rte_vlan_hdr *)next_hdr; 4285 proto = RTE_BE16(vlan->eth_proto); 4286 next_hdr += sizeof(struct rte_vlan_hdr); 4287 } 4288 4289 /* HW calculates IPv4 csum. no need to proceed */ 4290 if (proto == RTE_ETHER_TYPE_IPV4) 4291 return 0; 4292 4293 /* non IPv4/IPv6 header. not supported */ 4294 if (proto != RTE_ETHER_TYPE_IPV6) { 4295 return rte_flow_error_set(error, ENOTSUP, 4296 RTE_FLOW_ERROR_TYPE_ACTION, 4297 NULL, "Cannot offload non IPv4/IPv6"); 4298 } 4299 4300 ipv6 = (struct rte_ipv6_hdr *)next_hdr; 4301 4302 /* ignore non UDP */ 4303 if (ipv6->proto != IPPROTO_UDP) 4304 return 0; 4305 4306 udp = (struct rte_udp_hdr *)(ipv6 + 1); 4307 udp->dgram_cksum = 0; 4308 4309 return 0; 4310 } 4311 4312 /** 4313 * Convert L2 encap action to DV specification. 4314 * 4315 * @param[in] dev 4316 * Pointer to rte_eth_dev structure. 4317 * @param[in] action 4318 * Pointer to action structure. 4319 * @param[in, out] dev_flow 4320 * Pointer to the mlx5_flow. 4321 * @param[in] transfer 4322 * Mark if the flow is E-Switch flow. 4323 * @param[out] error 4324 * Pointer to the error structure. 4325 * 4326 * @return 4327 * 0 on success, a negative errno value otherwise and rte_errno is set. 4328 */ 4329 static int 4330 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev, 4331 const struct rte_flow_action *action, 4332 struct mlx5_flow *dev_flow, 4333 uint8_t transfer, 4334 struct rte_flow_error *error) 4335 { 4336 const struct rte_flow_item *encap_data; 4337 const struct rte_flow_action_raw_encap *raw_encap_data; 4338 struct mlx5_flow_dv_encap_decap_resource res = { 4339 .reformat_type = 4340 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL, 4341 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4342 MLX5DV_FLOW_TABLE_TYPE_NIC_TX, 4343 }; 4344 4345 if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 4346 raw_encap_data = 4347 (const struct rte_flow_action_raw_encap *)action->conf; 4348 res.size = raw_encap_data->size; 4349 memcpy(res.buf, raw_encap_data->data, res.size); 4350 } else { 4351 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) 4352 encap_data = 4353 ((const struct rte_flow_action_vxlan_encap *) 4354 action->conf)->definition; 4355 else 4356 encap_data = 4357 ((const struct rte_flow_action_nvgre_encap *) 4358 action->conf)->definition; 4359 if (flow_dv_convert_encap_data(encap_data, res.buf, 4360 &res.size, error)) 4361 return -rte_errno; 4362 } 4363 if (flow_dv_zero_encap_udp_csum(res.buf, error)) 4364 return -rte_errno; 4365 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4366 return rte_flow_error_set(error, EINVAL, 4367 RTE_FLOW_ERROR_TYPE_ACTION, 4368 NULL, "can't create L2 encap action"); 4369 return 0; 4370 } 4371 4372 /** 4373 * Convert L2 decap action to DV specification. 4374 * 4375 * @param[in] dev 4376 * Pointer to rte_eth_dev structure. 4377 * @param[in, out] dev_flow 4378 * Pointer to the mlx5_flow. 4379 * @param[in] transfer 4380 * Mark if the flow is E-Switch flow. 4381 * @param[out] error 4382 * Pointer to the error structure. 4383 * 4384 * @return 4385 * 0 on success, a negative errno value otherwise and rte_errno is set. 4386 */ 4387 static int 4388 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev, 4389 struct mlx5_flow *dev_flow, 4390 uint8_t transfer, 4391 struct rte_flow_error *error) 4392 { 4393 struct mlx5_flow_dv_encap_decap_resource res = { 4394 .size = 0, 4395 .reformat_type = 4396 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2, 4397 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4398 MLX5DV_FLOW_TABLE_TYPE_NIC_RX, 4399 }; 4400 4401 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4402 return rte_flow_error_set(error, EINVAL, 4403 RTE_FLOW_ERROR_TYPE_ACTION, 4404 NULL, "can't create L2 decap action"); 4405 return 0; 4406 } 4407 4408 /** 4409 * Convert raw decap/encap (L3 tunnel) action to DV specification. 4410 * 4411 * @param[in] dev 4412 * Pointer to rte_eth_dev structure. 4413 * @param[in] action 4414 * Pointer to action structure. 4415 * @param[in, out] dev_flow 4416 * Pointer to the mlx5_flow. 4417 * @param[in] attr 4418 * Pointer to the flow attributes. 4419 * @param[out] error 4420 * Pointer to the error structure. 4421 * 4422 * @return 4423 * 0 on success, a negative errno value otherwise and rte_errno is set. 4424 */ 4425 static int 4426 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev, 4427 const struct rte_flow_action *action, 4428 struct mlx5_flow *dev_flow, 4429 const struct rte_flow_attr *attr, 4430 struct rte_flow_error *error) 4431 { 4432 const struct rte_flow_action_raw_encap *encap_data; 4433 struct mlx5_flow_dv_encap_decap_resource res; 4434 4435 memset(&res, 0, sizeof(res)); 4436 encap_data = (const struct rte_flow_action_raw_encap *)action->conf; 4437 res.size = encap_data->size; 4438 memcpy(res.buf, encap_data->data, res.size); 4439 res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ? 4440 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 : 4441 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 4442 if (attr->transfer) 4443 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4444 else 4445 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4446 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4447 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4448 return rte_flow_error_set(error, EINVAL, 4449 RTE_FLOW_ERROR_TYPE_ACTION, 4450 NULL, "can't create encap action"); 4451 return 0; 4452 } 4453 4454 /** 4455 * Create action push VLAN. 4456 * 4457 * @param[in] dev 4458 * Pointer to rte_eth_dev structure. 4459 * @param[in] attr 4460 * Pointer to the flow attributes. 4461 * @param[in] vlan 4462 * Pointer to the vlan to push to the Ethernet header. 4463 * @param[in, out] dev_flow 4464 * Pointer to the mlx5_flow. 4465 * @param[out] error 4466 * Pointer to the error structure. 4467 * 4468 * @return 4469 * 0 on success, a negative errno value otherwise and rte_errno is set. 4470 */ 4471 static int 4472 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, 4473 const struct rte_flow_attr *attr, 4474 const struct rte_vlan_hdr *vlan, 4475 struct mlx5_flow *dev_flow, 4476 struct rte_flow_error *error) 4477 { 4478 struct mlx5_flow_dv_push_vlan_action_resource res; 4479 4480 memset(&res, 0, sizeof(res)); 4481 res.vlan_tag = 4482 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 | 4483 vlan->vlan_tci); 4484 if (attr->transfer) 4485 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4486 else 4487 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4488 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4489 return flow_dv_push_vlan_action_resource_register 4490 (dev, &res, dev_flow, error); 4491 } 4492 4493 /** 4494 * Validate the modify-header actions. 4495 * 4496 * @param[in] action_flags 4497 * Holds the actions detected until now. 4498 * @param[in] action 4499 * Pointer to the modify action. 4500 * @param[out] error 4501 * Pointer to error structure. 4502 * 4503 * @return 4504 * 0 on success, a negative errno value otherwise and rte_errno is set. 4505 */ 4506 static int 4507 flow_dv_validate_action_modify_hdr(const uint64_t action_flags, 4508 const struct rte_flow_action *action, 4509 struct rte_flow_error *error) 4510 { 4511 if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf) 4512 return rte_flow_error_set(error, EINVAL, 4513 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4514 NULL, "action configuration not set"); 4515 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 4516 return rte_flow_error_set(error, EINVAL, 4517 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4518 "can't have encap action before" 4519 " modify action"); 4520 return 0; 4521 } 4522 4523 /** 4524 * Validate the modify-header MAC address actions. 4525 * 4526 * @param[in] action_flags 4527 * Holds the actions detected until now. 4528 * @param[in] action 4529 * Pointer to the modify action. 4530 * @param[in] item_flags 4531 * Holds the items detected. 4532 * @param[out] error 4533 * Pointer to error structure. 4534 * 4535 * @return 4536 * 0 on success, a negative errno value otherwise and rte_errno is set. 4537 */ 4538 static int 4539 flow_dv_validate_action_modify_mac(const uint64_t action_flags, 4540 const struct rte_flow_action *action, 4541 const uint64_t item_flags, 4542 struct rte_flow_error *error) 4543 { 4544 int ret = 0; 4545 4546 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4547 if (!ret) { 4548 if (!(item_flags & MLX5_FLOW_LAYER_L2)) 4549 return rte_flow_error_set(error, EINVAL, 4550 RTE_FLOW_ERROR_TYPE_ACTION, 4551 NULL, 4552 "no L2 item in pattern"); 4553 } 4554 return ret; 4555 } 4556 4557 /** 4558 * Validate the modify-header IPv4 address actions. 4559 * 4560 * @param[in] action_flags 4561 * Holds the actions detected until now. 4562 * @param[in] action 4563 * Pointer to the modify action. 4564 * @param[in] item_flags 4565 * Holds the items detected. 4566 * @param[out] error 4567 * Pointer to error structure. 4568 * 4569 * @return 4570 * 0 on success, a negative errno value otherwise and rte_errno is set. 4571 */ 4572 static int 4573 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags, 4574 const struct rte_flow_action *action, 4575 const uint64_t item_flags, 4576 struct rte_flow_error *error) 4577 { 4578 int ret = 0; 4579 uint64_t layer; 4580 4581 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4582 if (!ret) { 4583 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4584 MLX5_FLOW_LAYER_INNER_L3_IPV4 : 4585 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 4586 if (!(item_flags & layer)) 4587 return rte_flow_error_set(error, EINVAL, 4588 RTE_FLOW_ERROR_TYPE_ACTION, 4589 NULL, 4590 "no ipv4 item in pattern"); 4591 } 4592 return ret; 4593 } 4594 4595 /** 4596 * Validate the modify-header IPv6 address actions. 4597 * 4598 * @param[in] action_flags 4599 * Holds the actions detected until now. 4600 * @param[in] action 4601 * Pointer to the modify action. 4602 * @param[in] item_flags 4603 * Holds the items detected. 4604 * @param[out] error 4605 * Pointer to error structure. 4606 * 4607 * @return 4608 * 0 on success, a negative errno value otherwise and rte_errno is set. 4609 */ 4610 static int 4611 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags, 4612 const struct rte_flow_action *action, 4613 const uint64_t item_flags, 4614 struct rte_flow_error *error) 4615 { 4616 int ret = 0; 4617 uint64_t layer; 4618 4619 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4620 if (!ret) { 4621 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4622 MLX5_FLOW_LAYER_INNER_L3_IPV6 : 4623 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 4624 if (!(item_flags & layer)) 4625 return rte_flow_error_set(error, EINVAL, 4626 RTE_FLOW_ERROR_TYPE_ACTION, 4627 NULL, 4628 "no ipv6 item in pattern"); 4629 } 4630 return ret; 4631 } 4632 4633 /** 4634 * Validate the modify-header TP actions. 4635 * 4636 * @param[in] action_flags 4637 * Holds the actions detected until now. 4638 * @param[in] action 4639 * Pointer to the modify action. 4640 * @param[in] item_flags 4641 * Holds the items detected. 4642 * @param[out] error 4643 * Pointer to error structure. 4644 * 4645 * @return 4646 * 0 on success, a negative errno value otherwise and rte_errno is set. 4647 */ 4648 static int 4649 flow_dv_validate_action_modify_tp(const uint64_t action_flags, 4650 const struct rte_flow_action *action, 4651 const uint64_t item_flags, 4652 struct rte_flow_error *error) 4653 { 4654 int ret = 0; 4655 uint64_t layer; 4656 4657 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4658 if (!ret) { 4659 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4660 MLX5_FLOW_LAYER_INNER_L4 : 4661 MLX5_FLOW_LAYER_OUTER_L4; 4662 if (!(item_flags & layer)) 4663 return rte_flow_error_set(error, EINVAL, 4664 RTE_FLOW_ERROR_TYPE_ACTION, 4665 NULL, "no transport layer " 4666 "in pattern"); 4667 } 4668 return ret; 4669 } 4670 4671 /** 4672 * Validate the modify-header actions of increment/decrement 4673 * TCP Sequence-number. 4674 * 4675 * @param[in] action_flags 4676 * Holds the actions detected until now. 4677 * @param[in] action 4678 * Pointer to the modify action. 4679 * @param[in] item_flags 4680 * Holds the items detected. 4681 * @param[out] error 4682 * Pointer to error structure. 4683 * 4684 * @return 4685 * 0 on success, a negative errno value otherwise and rte_errno is set. 4686 */ 4687 static int 4688 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags, 4689 const struct rte_flow_action *action, 4690 const uint64_t item_flags, 4691 struct rte_flow_error *error) 4692 { 4693 int ret = 0; 4694 uint64_t layer; 4695 4696 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4697 if (!ret) { 4698 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4699 MLX5_FLOW_LAYER_INNER_L4_TCP : 4700 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4701 if (!(item_flags & layer)) 4702 return rte_flow_error_set(error, EINVAL, 4703 RTE_FLOW_ERROR_TYPE_ACTION, 4704 NULL, "no TCP item in" 4705 " pattern"); 4706 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ && 4707 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) || 4708 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ && 4709 (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ))) 4710 return rte_flow_error_set(error, EINVAL, 4711 RTE_FLOW_ERROR_TYPE_ACTION, 4712 NULL, 4713 "cannot decrease and increase" 4714 " TCP sequence number" 4715 " at the same time"); 4716 } 4717 return ret; 4718 } 4719 4720 /** 4721 * Validate the modify-header actions of increment/decrement 4722 * TCP Acknowledgment number. 4723 * 4724 * @param[in] action_flags 4725 * Holds the actions detected until now. 4726 * @param[in] action 4727 * Pointer to the modify action. 4728 * @param[in] item_flags 4729 * Holds the items detected. 4730 * @param[out] error 4731 * Pointer to error structure. 4732 * 4733 * @return 4734 * 0 on success, a negative errno value otherwise and rte_errno is set. 4735 */ 4736 static int 4737 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags, 4738 const struct rte_flow_action *action, 4739 const uint64_t item_flags, 4740 struct rte_flow_error *error) 4741 { 4742 int ret = 0; 4743 uint64_t layer; 4744 4745 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4746 if (!ret) { 4747 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4748 MLX5_FLOW_LAYER_INNER_L4_TCP : 4749 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4750 if (!(item_flags & layer)) 4751 return rte_flow_error_set(error, EINVAL, 4752 RTE_FLOW_ERROR_TYPE_ACTION, 4753 NULL, "no TCP item in" 4754 " pattern"); 4755 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK && 4756 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) || 4757 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK && 4758 (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK))) 4759 return rte_flow_error_set(error, EINVAL, 4760 RTE_FLOW_ERROR_TYPE_ACTION, 4761 NULL, 4762 "cannot decrease and increase" 4763 " TCP acknowledgment number" 4764 " at the same time"); 4765 } 4766 return ret; 4767 } 4768 4769 /** 4770 * Validate the modify-header TTL actions. 4771 * 4772 * @param[in] action_flags 4773 * Holds the actions detected until now. 4774 * @param[in] action 4775 * Pointer to the modify action. 4776 * @param[in] item_flags 4777 * Holds the items detected. 4778 * @param[out] error 4779 * Pointer to error structure. 4780 * 4781 * @return 4782 * 0 on success, a negative errno value otherwise and rte_errno is set. 4783 */ 4784 static int 4785 flow_dv_validate_action_modify_ttl(const uint64_t action_flags, 4786 const struct rte_flow_action *action, 4787 const uint64_t item_flags, 4788 struct rte_flow_error *error) 4789 { 4790 int ret = 0; 4791 uint64_t layer; 4792 4793 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4794 if (!ret) { 4795 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4796 MLX5_FLOW_LAYER_INNER_L3 : 4797 MLX5_FLOW_LAYER_OUTER_L3; 4798 if (!(item_flags & layer)) 4799 return rte_flow_error_set(error, EINVAL, 4800 RTE_FLOW_ERROR_TYPE_ACTION, 4801 NULL, 4802 "no IP protocol in pattern"); 4803 } 4804 return ret; 4805 } 4806 4807 /** 4808 * Validate the generic modify field actions. 4809 * @param[in] dev 4810 * Pointer to the rte_eth_dev structure. 4811 * @param[in] action_flags 4812 * Holds the actions detected until now. 4813 * @param[in] action 4814 * Pointer to the modify action. 4815 * @param[in] attr 4816 * Pointer to the flow attributes. 4817 * @param[out] error 4818 * Pointer to error structure. 4819 * 4820 * @return 4821 * Number of header fields to modify (0 or more) on success, 4822 * a negative errno value otherwise and rte_errno is set. 4823 */ 4824 static int 4825 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, 4826 const uint64_t action_flags, 4827 const struct rte_flow_action *action, 4828 const struct rte_flow_attr *attr, 4829 struct rte_flow_error *error) 4830 { 4831 int ret = 0; 4832 struct mlx5_priv *priv = dev->data->dev_private; 4833 struct mlx5_dev_config *config = &priv->config; 4834 const struct rte_flow_action_modify_field *action_modify_field = 4835 action->conf; 4836 uint32_t dst_width = mlx5_flow_item_field_width(priv, 4837 action_modify_field->dst.field, -1); 4838 uint32_t src_width = mlx5_flow_item_field_width(priv, 4839 action_modify_field->src.field, dst_width); 4840 4841 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4842 if (ret) 4843 return ret; 4844 4845 if (action_modify_field->width == 0) 4846 return rte_flow_error_set(error, EINVAL, 4847 RTE_FLOW_ERROR_TYPE_ACTION, action, 4848 "no bits are requested to be modified"); 4849 else if (action_modify_field->width > dst_width || 4850 action_modify_field->width > src_width) 4851 return rte_flow_error_set(error, EINVAL, 4852 RTE_FLOW_ERROR_TYPE_ACTION, action, 4853 "cannot modify more bits than" 4854 " the width of a field"); 4855 if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE && 4856 action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) { 4857 if ((action_modify_field->dst.offset + 4858 action_modify_field->width > dst_width) || 4859 (action_modify_field->dst.offset % 32)) 4860 return rte_flow_error_set(error, EINVAL, 4861 RTE_FLOW_ERROR_TYPE_ACTION, action, 4862 "destination offset is too big" 4863 " or not aligned to 4 bytes"); 4864 if (action_modify_field->dst.level && 4865 action_modify_field->dst.field != RTE_FLOW_FIELD_TAG) 4866 return rte_flow_error_set(error, ENOTSUP, 4867 RTE_FLOW_ERROR_TYPE_ACTION, action, 4868 "inner header fields modification" 4869 " is not supported"); 4870 } 4871 if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE && 4872 action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) { 4873 if (!attr->transfer && !attr->group) 4874 return rte_flow_error_set(error, ENOTSUP, 4875 RTE_FLOW_ERROR_TYPE_ACTION, action, 4876 "modify field action is not" 4877 " supported for group 0"); 4878 if ((action_modify_field->src.offset + 4879 action_modify_field->width > src_width) || 4880 (action_modify_field->src.offset % 32)) 4881 return rte_flow_error_set(error, EINVAL, 4882 RTE_FLOW_ERROR_TYPE_ACTION, action, 4883 "source offset is too big" 4884 " or not aligned to 4 bytes"); 4885 if (action_modify_field->src.level && 4886 action_modify_field->src.field != RTE_FLOW_FIELD_TAG) 4887 return rte_flow_error_set(error, ENOTSUP, 4888 RTE_FLOW_ERROR_TYPE_ACTION, action, 4889 "inner header fields modification" 4890 " is not supported"); 4891 } 4892 if ((action_modify_field->dst.field == 4893 action_modify_field->src.field) && 4894 (action_modify_field->dst.level == 4895 action_modify_field->src.level)) 4896 return rte_flow_error_set(error, EINVAL, 4897 RTE_FLOW_ERROR_TYPE_ACTION, action, 4898 "source and destination fields" 4899 " cannot be the same"); 4900 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE || 4901 action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER || 4902 action_modify_field->dst.field == RTE_FLOW_FIELD_MARK) 4903 return rte_flow_error_set(error, EINVAL, 4904 RTE_FLOW_ERROR_TYPE_ACTION, action, 4905 "mark, immediate value or a pointer to it" 4906 " cannot be used as a destination"); 4907 if (action_modify_field->dst.field == RTE_FLOW_FIELD_START || 4908 action_modify_field->src.field == RTE_FLOW_FIELD_START) 4909 return rte_flow_error_set(error, ENOTSUP, 4910 RTE_FLOW_ERROR_TYPE_ACTION, action, 4911 "modifications of an arbitrary" 4912 " place in a packet is not supported"); 4913 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE || 4914 action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE) 4915 return rte_flow_error_set(error, ENOTSUP, 4916 RTE_FLOW_ERROR_TYPE_ACTION, action, 4917 "modifications of the 802.1Q Tag" 4918 " Identifier is not supported"); 4919 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI || 4920 action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI) 4921 return rte_flow_error_set(error, ENOTSUP, 4922 RTE_FLOW_ERROR_TYPE_ACTION, action, 4923 "modifications of the VXLAN Network" 4924 " Identifier is not supported"); 4925 if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI || 4926 action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI) 4927 return rte_flow_error_set(error, ENOTSUP, 4928 RTE_FLOW_ERROR_TYPE_ACTION, action, 4929 "modifications of the GENEVE Network" 4930 " Identifier is not supported"); 4931 if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK || 4932 action_modify_field->src.field == RTE_FLOW_FIELD_MARK || 4933 action_modify_field->dst.field == RTE_FLOW_FIELD_META || 4934 action_modify_field->src.field == RTE_FLOW_FIELD_META) { 4935 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY || 4936 !mlx5_flow_ext_mreg_supported(dev)) 4937 return rte_flow_error_set(error, ENOTSUP, 4938 RTE_FLOW_ERROR_TYPE_ACTION, action, 4939 "cannot modify mark or metadata without" 4940 " extended metadata register support"); 4941 } 4942 if (action_modify_field->operation != RTE_FLOW_MODIFY_SET) 4943 return rte_flow_error_set(error, ENOTSUP, 4944 RTE_FLOW_ERROR_TYPE_ACTION, action, 4945 "add and sub operations" 4946 " are not supported"); 4947 return (action_modify_field->width / 32) + 4948 !!(action_modify_field->width % 32); 4949 } 4950 4951 /** 4952 * Validate jump action. 4953 * 4954 * @param[in] action 4955 * Pointer to the jump action. 4956 * @param[in] action_flags 4957 * Holds the actions detected until now. 4958 * @param[in] attributes 4959 * Pointer to flow attributes 4960 * @param[in] external 4961 * Action belongs to flow rule created by request external to PMD. 4962 * @param[out] error 4963 * Pointer to error structure. 4964 * 4965 * @return 4966 * 0 on success, a negative errno value otherwise and rte_errno is set. 4967 */ 4968 static int 4969 flow_dv_validate_action_jump(struct rte_eth_dev *dev, 4970 const struct mlx5_flow_tunnel *tunnel, 4971 const struct rte_flow_action *action, 4972 uint64_t action_flags, 4973 const struct rte_flow_attr *attributes, 4974 bool external, struct rte_flow_error *error) 4975 { 4976 uint32_t target_group, table; 4977 int ret = 0; 4978 struct flow_grp_info grp_info = { 4979 .external = !!external, 4980 .transfer = !!attributes->transfer, 4981 .fdb_def_rule = 1, 4982 .std_tbl_fix = 0 4983 }; 4984 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 4985 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 4986 return rte_flow_error_set(error, EINVAL, 4987 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4988 "can't have 2 fate actions in" 4989 " same flow"); 4990 if (!action->conf) 4991 return rte_flow_error_set(error, EINVAL, 4992 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4993 NULL, "action configuration not set"); 4994 target_group = 4995 ((const struct rte_flow_action_jump *)action->conf)->group; 4996 ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table, 4997 &grp_info, error); 4998 if (ret) 4999 return ret; 5000 if (attributes->group == target_group && 5001 !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET | 5002 MLX5_FLOW_ACTION_TUNNEL_MATCH))) 5003 return rte_flow_error_set(error, EINVAL, 5004 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5005 "target group must be other than" 5006 " the current flow group"); 5007 return 0; 5008 } 5009 5010 /* 5011 * Validate action PORT_ID / REPRESENTED_PORT. 5012 * 5013 * @param[in] dev 5014 * Pointer to rte_eth_dev structure. 5015 * @param[in] action_flags 5016 * Bit-fields that holds the actions detected until now. 5017 * @param[in] action 5018 * PORT_ID / REPRESENTED_PORT action structure. 5019 * @param[in] attr 5020 * Attributes of flow that includes this action. 5021 * @param[out] error 5022 * Pointer to error structure. 5023 * 5024 * @return 5025 * 0 on success, a negative errno value otherwise and rte_errno is set. 5026 */ 5027 static int 5028 flow_dv_validate_action_port_id(struct rte_eth_dev *dev, 5029 uint64_t action_flags, 5030 const struct rte_flow_action *action, 5031 const struct rte_flow_attr *attr, 5032 struct rte_flow_error *error) 5033 { 5034 const struct rte_flow_action_port_id *port_id; 5035 const struct rte_flow_action_ethdev *ethdev; 5036 struct mlx5_priv *act_priv; 5037 struct mlx5_priv *dev_priv; 5038 uint16_t port; 5039 5040 if (!attr->transfer) 5041 return rte_flow_error_set(error, ENOTSUP, 5042 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5043 NULL, 5044 "port action is valid in transfer" 5045 " mode only"); 5046 if (!action || !action->conf) 5047 return rte_flow_error_set(error, ENOTSUP, 5048 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5049 NULL, 5050 "port action parameters must be" 5051 " specified"); 5052 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5053 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5054 return rte_flow_error_set(error, EINVAL, 5055 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5056 "can have only one fate actions in" 5057 " a flow"); 5058 dev_priv = mlx5_dev_to_eswitch_info(dev); 5059 if (!dev_priv) 5060 return rte_flow_error_set(error, rte_errno, 5061 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5062 NULL, 5063 "failed to obtain E-Switch info"); 5064 switch (action->type) { 5065 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5066 port_id = action->conf; 5067 port = port_id->original ? dev->data->port_id : port_id->id; 5068 break; 5069 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5070 ethdev = action->conf; 5071 port = ethdev->port_id; 5072 break; 5073 default: 5074 MLX5_ASSERT(false); 5075 return rte_flow_error_set 5076 (error, EINVAL, 5077 RTE_FLOW_ERROR_TYPE_ACTION, action, 5078 "unknown E-Switch action"); 5079 } 5080 act_priv = mlx5_port_to_eswitch_info(port, false); 5081 if (!act_priv) 5082 return rte_flow_error_set 5083 (error, rte_errno, 5084 RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf, 5085 "failed to obtain E-Switch port id for port"); 5086 if (act_priv->domain_id != dev_priv->domain_id) 5087 return rte_flow_error_set 5088 (error, EINVAL, 5089 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5090 "port does not belong to" 5091 " E-Switch being configured"); 5092 return 0; 5093 } 5094 5095 /** 5096 * Get the maximum number of modify header actions. 5097 * 5098 * @param dev 5099 * Pointer to rte_eth_dev structure. 5100 * @param root 5101 * Whether action is on root table. 5102 * 5103 * @return 5104 * Max number of modify header actions device can support. 5105 */ 5106 static inline unsigned int 5107 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused, 5108 bool root) 5109 { 5110 /* 5111 * There's no way to directly query the max capacity from FW. 5112 * The maximal value on root table should be assumed to be supported. 5113 */ 5114 if (!root) 5115 return MLX5_MAX_MODIFY_NUM; 5116 else 5117 return MLX5_ROOT_TBL_MODIFY_NUM; 5118 } 5119 5120 /** 5121 * Validate the meter action. 5122 * 5123 * @param[in] dev 5124 * Pointer to rte_eth_dev structure. 5125 * @param[in] action_flags 5126 * Bit-fields that holds the actions detected until now. 5127 * @param[in] action 5128 * Pointer to the meter action. 5129 * @param[in] attr 5130 * Attributes of flow that includes this action. 5131 * @param[in] port_id_item 5132 * Pointer to item indicating port id. 5133 * @param[out] error 5134 * Pointer to error structure. 5135 * 5136 * @return 5137 * 0 on success, a negative errno value otherwise and rte_ernno is set. 5138 */ 5139 static int 5140 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev, 5141 uint64_t action_flags, 5142 const struct rte_flow_action *action, 5143 const struct rte_flow_attr *attr, 5144 const struct rte_flow_item *port_id_item, 5145 bool *def_policy, 5146 struct rte_flow_error *error) 5147 { 5148 struct mlx5_priv *priv = dev->data->dev_private; 5149 const struct rte_flow_action_meter *am = action->conf; 5150 struct mlx5_flow_meter_info *fm; 5151 struct mlx5_flow_meter_policy *mtr_policy; 5152 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 5153 5154 if (!am) 5155 return rte_flow_error_set(error, EINVAL, 5156 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5157 "meter action conf is NULL"); 5158 5159 if (action_flags & MLX5_FLOW_ACTION_METER) 5160 return rte_flow_error_set(error, ENOTSUP, 5161 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5162 "meter chaining not support"); 5163 if (action_flags & MLX5_FLOW_ACTION_JUMP) 5164 return rte_flow_error_set(error, ENOTSUP, 5165 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5166 "meter with jump not support"); 5167 if (!priv->mtr_en) 5168 return rte_flow_error_set(error, ENOTSUP, 5169 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5170 NULL, 5171 "meter action not supported"); 5172 fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL); 5173 if (!fm) 5174 return rte_flow_error_set(error, EINVAL, 5175 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5176 "Meter not found"); 5177 /* aso meter can always be shared by different domains */ 5178 if (fm->ref_cnt && !priv->sh->meter_aso_en && 5179 !(fm->transfer == attr->transfer || 5180 (!fm->ingress && !attr->ingress && attr->egress) || 5181 (!fm->egress && !attr->egress && attr->ingress))) 5182 return rte_flow_error_set(error, EINVAL, 5183 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5184 "Flow attributes domain are either invalid " 5185 "or have a domain conflict with current " 5186 "meter attributes"); 5187 if (fm->def_policy) { 5188 if (!((attr->transfer && 5189 mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) || 5190 (attr->egress && 5191 mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) || 5192 (attr->ingress && 5193 mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS]))) 5194 return rte_flow_error_set(error, EINVAL, 5195 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5196 "Flow attributes domain " 5197 "have a conflict with current " 5198 "meter domain attributes"); 5199 *def_policy = true; 5200 } else { 5201 mtr_policy = mlx5_flow_meter_policy_find(dev, 5202 fm->policy_id, NULL); 5203 if (!mtr_policy) 5204 return rte_flow_error_set(error, EINVAL, 5205 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5206 "Invalid policy id for meter "); 5207 if (!((attr->transfer && mtr_policy->transfer) || 5208 (attr->egress && mtr_policy->egress) || 5209 (attr->ingress && mtr_policy->ingress))) 5210 return rte_flow_error_set(error, EINVAL, 5211 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5212 "Flow attributes domain " 5213 "have a conflict with current " 5214 "meter domain attributes"); 5215 if (attr->transfer && mtr_policy->dev) { 5216 /** 5217 * When policy has fate action of port_id, 5218 * the flow should have the same src port as policy. 5219 */ 5220 struct mlx5_priv *policy_port_priv = 5221 mtr_policy->dev->data->dev_private; 5222 int32_t flow_src_port = priv->representor_id; 5223 5224 if (port_id_item) { 5225 const struct rte_flow_item_port_id *spec = 5226 port_id_item->spec; 5227 struct mlx5_priv *port_priv = 5228 mlx5_port_to_eswitch_info(spec->id, 5229 false); 5230 if (!port_priv) 5231 return rte_flow_error_set(error, 5232 rte_errno, 5233 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5234 spec, 5235 "Failed to get port info."); 5236 flow_src_port = port_priv->representor_id; 5237 } 5238 if (flow_src_port != policy_port_priv->representor_id) 5239 return rte_flow_error_set(error, 5240 rte_errno, 5241 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5242 NULL, 5243 "Flow and meter policy " 5244 "have different src port."); 5245 } 5246 *def_policy = false; 5247 } 5248 return 0; 5249 } 5250 5251 /** 5252 * Validate the age action. 5253 * 5254 * @param[in] action_flags 5255 * Holds the actions detected until now. 5256 * @param[in] action 5257 * Pointer to the age action. 5258 * @param[in] dev 5259 * Pointer to the Ethernet device structure. 5260 * @param[out] error 5261 * Pointer to error structure. 5262 * 5263 * @return 5264 * 0 on success, a negative errno value otherwise and rte_errno is set. 5265 */ 5266 static int 5267 flow_dv_validate_action_age(uint64_t action_flags, 5268 const struct rte_flow_action *action, 5269 struct rte_eth_dev *dev, 5270 struct rte_flow_error *error) 5271 { 5272 struct mlx5_priv *priv = dev->data->dev_private; 5273 const struct rte_flow_action_age *age = action->conf; 5274 5275 if (!priv->sh->devx || (priv->sh->cmng.counter_fallback && 5276 !priv->sh->aso_age_mng)) 5277 return rte_flow_error_set(error, ENOTSUP, 5278 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5279 NULL, 5280 "age action not supported"); 5281 if (!(action->conf)) 5282 return rte_flow_error_set(error, EINVAL, 5283 RTE_FLOW_ERROR_TYPE_ACTION, action, 5284 "configuration cannot be null"); 5285 if (!(age->timeout)) 5286 return rte_flow_error_set(error, EINVAL, 5287 RTE_FLOW_ERROR_TYPE_ACTION, action, 5288 "invalid timeout value 0"); 5289 if (action_flags & MLX5_FLOW_ACTION_AGE) 5290 return rte_flow_error_set(error, EINVAL, 5291 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5292 "duplicate age actions set"); 5293 return 0; 5294 } 5295 5296 /** 5297 * Validate the modify-header IPv4 DSCP actions. 5298 * 5299 * @param[in] action_flags 5300 * Holds the actions detected until now. 5301 * @param[in] action 5302 * Pointer to the modify action. 5303 * @param[in] item_flags 5304 * Holds the items detected. 5305 * @param[out] error 5306 * Pointer to error structure. 5307 * 5308 * @return 5309 * 0 on success, a negative errno value otherwise and rte_errno is set. 5310 */ 5311 static int 5312 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags, 5313 const struct rte_flow_action *action, 5314 const uint64_t item_flags, 5315 struct rte_flow_error *error) 5316 { 5317 int ret = 0; 5318 5319 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5320 if (!ret) { 5321 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4)) 5322 return rte_flow_error_set(error, EINVAL, 5323 RTE_FLOW_ERROR_TYPE_ACTION, 5324 NULL, 5325 "no ipv4 item in pattern"); 5326 } 5327 return ret; 5328 } 5329 5330 /** 5331 * Validate the modify-header IPv6 DSCP actions. 5332 * 5333 * @param[in] action_flags 5334 * Holds the actions detected until now. 5335 * @param[in] action 5336 * Pointer to the modify action. 5337 * @param[in] item_flags 5338 * Holds the items detected. 5339 * @param[out] error 5340 * Pointer to error structure. 5341 * 5342 * @return 5343 * 0 on success, a negative errno value otherwise and rte_errno is set. 5344 */ 5345 static int 5346 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags, 5347 const struct rte_flow_action *action, 5348 const uint64_t item_flags, 5349 struct rte_flow_error *error) 5350 { 5351 int ret = 0; 5352 5353 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5354 if (!ret) { 5355 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6)) 5356 return rte_flow_error_set(error, EINVAL, 5357 RTE_FLOW_ERROR_TYPE_ACTION, 5358 NULL, 5359 "no ipv6 item in pattern"); 5360 } 5361 return ret; 5362 } 5363 5364 int 5365 flow_dv_modify_match_cb(void *tool_ctx __rte_unused, 5366 struct mlx5_list_entry *entry, void *cb_ctx) 5367 { 5368 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5369 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5370 struct mlx5_flow_dv_modify_hdr_resource *resource = 5371 container_of(entry, typeof(*resource), entry); 5372 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5373 5374 key_len += ref->actions_num * sizeof(ref->actions[0]); 5375 return ref->actions_num != resource->actions_num || 5376 memcmp(&ref->ft_type, &resource->ft_type, key_len); 5377 } 5378 5379 static struct mlx5_indexed_pool * 5380 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index) 5381 { 5382 struct mlx5_indexed_pool *ipool = __atomic_load_n 5383 (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST); 5384 5385 if (!ipool) { 5386 struct mlx5_indexed_pool *expected = NULL; 5387 struct mlx5_indexed_pool_config cfg = 5388 (struct mlx5_indexed_pool_config) { 5389 .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 5390 (index + 1) * 5391 sizeof(struct mlx5_modification_cmd), 5392 .trunk_size = 64, 5393 .grow_trunk = 3, 5394 .grow_shift = 2, 5395 .need_lock = 1, 5396 .release_mem_en = !!sh->reclaim_mode, 5397 .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16), 5398 .malloc = mlx5_malloc, 5399 .free = mlx5_free, 5400 .type = "mlx5_modify_action_resource", 5401 }; 5402 5403 cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool)); 5404 ipool = mlx5_ipool_create(&cfg); 5405 if (!ipool) 5406 return NULL; 5407 if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index], 5408 &expected, ipool, false, 5409 __ATOMIC_SEQ_CST, 5410 __ATOMIC_SEQ_CST)) { 5411 mlx5_ipool_destroy(ipool); 5412 ipool = __atomic_load_n(&sh->mdh_ipools[index], 5413 __ATOMIC_SEQ_CST); 5414 } 5415 } 5416 return ipool; 5417 } 5418 5419 struct mlx5_list_entry * 5420 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx) 5421 { 5422 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5423 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5424 struct mlx5dv_dr_domain *ns; 5425 struct mlx5_flow_dv_modify_hdr_resource *entry; 5426 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5427 struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh, 5428 ref->actions_num - 1); 5429 int ret; 5430 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5431 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5432 uint32_t idx; 5433 5434 if (unlikely(!ipool)) { 5435 rte_flow_error_set(ctx->error, ENOMEM, 5436 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5437 NULL, "cannot allocate modify ipool"); 5438 return NULL; 5439 } 5440 entry = mlx5_ipool_zmalloc(ipool, &idx); 5441 if (!entry) { 5442 rte_flow_error_set(ctx->error, ENOMEM, 5443 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5444 "cannot allocate resource memory"); 5445 return NULL; 5446 } 5447 rte_memcpy(&entry->ft_type, 5448 RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)), 5449 key_len + data_len); 5450 if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 5451 ns = sh->fdb_domain; 5452 else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 5453 ns = sh->tx_domain; 5454 else 5455 ns = sh->rx_domain; 5456 ret = mlx5_flow_os_create_flow_action_modify_header 5457 (sh->cdev->ctx, ns, entry, 5458 data_len, &entry->action); 5459 if (ret) { 5460 mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx); 5461 rte_flow_error_set(ctx->error, ENOMEM, 5462 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5463 NULL, "cannot create modification action"); 5464 return NULL; 5465 } 5466 entry->idx = idx; 5467 return &entry->entry; 5468 } 5469 5470 struct mlx5_list_entry * 5471 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 5472 void *cb_ctx) 5473 { 5474 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5475 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5476 struct mlx5_flow_dv_modify_hdr_resource *entry; 5477 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5478 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5479 uint32_t idx; 5480 5481 entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1], 5482 &idx); 5483 if (!entry) { 5484 rte_flow_error_set(ctx->error, ENOMEM, 5485 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5486 "cannot allocate resource memory"); 5487 return NULL; 5488 } 5489 memcpy(entry, oentry, sizeof(*entry) + data_len); 5490 entry->idx = idx; 5491 return &entry->entry; 5492 } 5493 5494 void 5495 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 5496 { 5497 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5498 struct mlx5_flow_dv_modify_hdr_resource *res = 5499 container_of(entry, typeof(*res), entry); 5500 5501 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 5502 } 5503 5504 /** 5505 * Validate the sample action. 5506 * 5507 * @param[in, out] action_flags 5508 * Holds the actions detected until now. 5509 * @param[in] action 5510 * Pointer to the sample action. 5511 * @param[in] dev 5512 * Pointer to the Ethernet device structure. 5513 * @param[in] attr 5514 * Attributes of flow that includes this action. 5515 * @param[in] item_flags 5516 * Holds the items detected. 5517 * @param[in] rss 5518 * Pointer to the RSS action. 5519 * @param[out] sample_rss 5520 * Pointer to the RSS action in sample action list. 5521 * @param[out] count 5522 * Pointer to the COUNT action in sample action list. 5523 * @param[out] fdb_mirror_limit 5524 * Pointer to the FDB mirror limitation flag. 5525 * @param[out] error 5526 * Pointer to error structure. 5527 * 5528 * @return 5529 * 0 on success, a negative errno value otherwise and rte_errno is set. 5530 */ 5531 static int 5532 flow_dv_validate_action_sample(uint64_t *action_flags, 5533 const struct rte_flow_action *action, 5534 struct rte_eth_dev *dev, 5535 const struct rte_flow_attr *attr, 5536 uint64_t item_flags, 5537 const struct rte_flow_action_rss *rss, 5538 const struct rte_flow_action_rss **sample_rss, 5539 const struct rte_flow_action_count **count, 5540 int *fdb_mirror_limit, 5541 struct rte_flow_error *error) 5542 { 5543 struct mlx5_priv *priv = dev->data->dev_private; 5544 struct mlx5_dev_config *dev_conf = &priv->config; 5545 const struct rte_flow_action_sample *sample = action->conf; 5546 const struct rte_flow_action *act; 5547 uint64_t sub_action_flags = 0; 5548 uint16_t queue_index = 0xFFFF; 5549 int actions_n = 0; 5550 int ret; 5551 5552 if (!sample) 5553 return rte_flow_error_set(error, EINVAL, 5554 RTE_FLOW_ERROR_TYPE_ACTION, action, 5555 "configuration cannot be NULL"); 5556 if (sample->ratio == 0) 5557 return rte_flow_error_set(error, EINVAL, 5558 RTE_FLOW_ERROR_TYPE_ACTION, action, 5559 "ratio value starts from 1"); 5560 if (!priv->sh->devx || (sample->ratio > 0 && !priv->sampler_en)) 5561 return rte_flow_error_set(error, ENOTSUP, 5562 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5563 NULL, 5564 "sample action not supported"); 5565 if (*action_flags & MLX5_FLOW_ACTION_SAMPLE) 5566 return rte_flow_error_set(error, EINVAL, 5567 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5568 "Multiple sample actions not " 5569 "supported"); 5570 if (*action_flags & MLX5_FLOW_ACTION_METER) 5571 return rte_flow_error_set(error, EINVAL, 5572 RTE_FLOW_ERROR_TYPE_ACTION, action, 5573 "wrong action order, meter should " 5574 "be after sample action"); 5575 if (*action_flags & MLX5_FLOW_ACTION_JUMP) 5576 return rte_flow_error_set(error, EINVAL, 5577 RTE_FLOW_ERROR_TYPE_ACTION, action, 5578 "wrong action order, jump should " 5579 "be after sample action"); 5580 act = sample->actions; 5581 for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 5582 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 5583 return rte_flow_error_set(error, ENOTSUP, 5584 RTE_FLOW_ERROR_TYPE_ACTION, 5585 act, "too many actions"); 5586 switch (act->type) { 5587 case RTE_FLOW_ACTION_TYPE_QUEUE: 5588 ret = mlx5_flow_validate_action_queue(act, 5589 sub_action_flags, 5590 dev, 5591 attr, error); 5592 if (ret < 0) 5593 return ret; 5594 queue_index = ((const struct rte_flow_action_queue *) 5595 (act->conf))->index; 5596 sub_action_flags |= MLX5_FLOW_ACTION_QUEUE; 5597 ++actions_n; 5598 break; 5599 case RTE_FLOW_ACTION_TYPE_RSS: 5600 *sample_rss = act->conf; 5601 ret = mlx5_flow_validate_action_rss(act, 5602 sub_action_flags, 5603 dev, attr, 5604 item_flags, 5605 error); 5606 if (ret < 0) 5607 return ret; 5608 if (rss && *sample_rss && 5609 ((*sample_rss)->level != rss->level || 5610 (*sample_rss)->types != rss->types)) 5611 return rte_flow_error_set(error, ENOTSUP, 5612 RTE_FLOW_ERROR_TYPE_ACTION, 5613 NULL, 5614 "Can't use the different RSS types " 5615 "or level in the same flow"); 5616 if (*sample_rss != NULL && (*sample_rss)->queue_num) 5617 queue_index = (*sample_rss)->queue[0]; 5618 sub_action_flags |= MLX5_FLOW_ACTION_RSS; 5619 ++actions_n; 5620 break; 5621 case RTE_FLOW_ACTION_TYPE_MARK: 5622 ret = flow_dv_validate_action_mark(dev, act, 5623 sub_action_flags, 5624 attr, error); 5625 if (ret < 0) 5626 return ret; 5627 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) 5628 sub_action_flags |= MLX5_FLOW_ACTION_MARK | 5629 MLX5_FLOW_ACTION_MARK_EXT; 5630 else 5631 sub_action_flags |= MLX5_FLOW_ACTION_MARK; 5632 ++actions_n; 5633 break; 5634 case RTE_FLOW_ACTION_TYPE_COUNT: 5635 ret = flow_dv_validate_action_count 5636 (dev, false, *action_flags | sub_action_flags, 5637 error); 5638 if (ret < 0) 5639 return ret; 5640 *count = act->conf; 5641 sub_action_flags |= MLX5_FLOW_ACTION_COUNT; 5642 *action_flags |= MLX5_FLOW_ACTION_COUNT; 5643 ++actions_n; 5644 break; 5645 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5646 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5647 ret = flow_dv_validate_action_port_id(dev, 5648 sub_action_flags, 5649 act, 5650 attr, 5651 error); 5652 if (ret) 5653 return ret; 5654 sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID; 5655 ++actions_n; 5656 break; 5657 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 5658 ret = flow_dv_validate_action_raw_encap_decap 5659 (dev, NULL, act->conf, attr, &sub_action_flags, 5660 &actions_n, action, item_flags, error); 5661 if (ret < 0) 5662 return ret; 5663 ++actions_n; 5664 break; 5665 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 5666 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 5667 ret = flow_dv_validate_action_l2_encap(dev, 5668 sub_action_flags, 5669 act, attr, 5670 error); 5671 if (ret < 0) 5672 return ret; 5673 sub_action_flags |= MLX5_FLOW_ACTION_ENCAP; 5674 ++actions_n; 5675 break; 5676 default: 5677 return rte_flow_error_set(error, ENOTSUP, 5678 RTE_FLOW_ERROR_TYPE_ACTION, 5679 NULL, 5680 "Doesn't support optional " 5681 "action"); 5682 } 5683 } 5684 if (attr->ingress && !attr->transfer) { 5685 if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE | 5686 MLX5_FLOW_ACTION_RSS))) 5687 return rte_flow_error_set(error, EINVAL, 5688 RTE_FLOW_ERROR_TYPE_ACTION, 5689 NULL, 5690 "Ingress must has a dest " 5691 "QUEUE for Sample"); 5692 } else if (attr->egress && !attr->transfer) { 5693 return rte_flow_error_set(error, ENOTSUP, 5694 RTE_FLOW_ERROR_TYPE_ACTION, 5695 NULL, 5696 "Sample Only support Ingress " 5697 "or E-Switch"); 5698 } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) { 5699 MLX5_ASSERT(attr->transfer); 5700 if (sample->ratio > 1) 5701 return rte_flow_error_set(error, ENOTSUP, 5702 RTE_FLOW_ERROR_TYPE_ACTION, 5703 NULL, 5704 "E-Switch doesn't support " 5705 "any optional action " 5706 "for sampling"); 5707 if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) 5708 return rte_flow_error_set(error, ENOTSUP, 5709 RTE_FLOW_ERROR_TYPE_ACTION, 5710 NULL, 5711 "unsupported action QUEUE"); 5712 if (sub_action_flags & MLX5_FLOW_ACTION_RSS) 5713 return rte_flow_error_set(error, ENOTSUP, 5714 RTE_FLOW_ERROR_TYPE_ACTION, 5715 NULL, 5716 "unsupported action QUEUE"); 5717 if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID)) 5718 return rte_flow_error_set(error, EINVAL, 5719 RTE_FLOW_ERROR_TYPE_ACTION, 5720 NULL, 5721 "E-Switch must has a dest " 5722 "port for mirroring"); 5723 if (!priv->config.hca_attr.reg_c_preserve && 5724 priv->representor_id != UINT16_MAX) 5725 *fdb_mirror_limit = 1; 5726 } 5727 /* Continue validation for Xcap actions.*/ 5728 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) && 5729 (queue_index == 0xFFFF || 5730 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) { 5731 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) == 5732 MLX5_FLOW_XCAP_ACTIONS) 5733 return rte_flow_error_set(error, ENOTSUP, 5734 RTE_FLOW_ERROR_TYPE_ACTION, 5735 NULL, "encap and decap " 5736 "combination aren't " 5737 "supported"); 5738 if (!attr->transfer && attr->ingress && (sub_action_flags & 5739 MLX5_FLOW_ACTION_ENCAP)) 5740 return rte_flow_error_set(error, ENOTSUP, 5741 RTE_FLOW_ERROR_TYPE_ACTION, 5742 NULL, "encap is not supported" 5743 " for ingress traffic"); 5744 } 5745 return 0; 5746 } 5747 5748 /** 5749 * Find existing modify-header resource or create and register a new one. 5750 * 5751 * @param dev[in, out] 5752 * Pointer to rte_eth_dev structure. 5753 * @param[in, out] resource 5754 * Pointer to modify-header resource. 5755 * @parm[in, out] dev_flow 5756 * Pointer to the dev_flow. 5757 * @param[out] error 5758 * pointer to error structure. 5759 * 5760 * @return 5761 * 0 on success otherwise -errno and errno is set. 5762 */ 5763 static int 5764 flow_dv_modify_hdr_resource_register 5765 (struct rte_eth_dev *dev, 5766 struct mlx5_flow_dv_modify_hdr_resource *resource, 5767 struct mlx5_flow *dev_flow, 5768 struct rte_flow_error *error) 5769 { 5770 struct mlx5_priv *priv = dev->data->dev_private; 5771 struct mlx5_dev_ctx_shared *sh = priv->sh; 5772 uint32_t key_len = sizeof(*resource) - 5773 offsetof(typeof(*resource), ft_type) + 5774 resource->actions_num * sizeof(resource->actions[0]); 5775 struct mlx5_list_entry *entry; 5776 struct mlx5_flow_cb_ctx ctx = { 5777 .error = error, 5778 .data = resource, 5779 }; 5780 struct mlx5_hlist *modify_cmds; 5781 uint64_t key64; 5782 5783 modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds, 5784 "hdr_modify", 5785 MLX5_FLOW_HDR_MODIFY_HTABLE_SZ, 5786 true, false, sh, 5787 flow_dv_modify_create_cb, 5788 flow_dv_modify_match_cb, 5789 flow_dv_modify_remove_cb, 5790 flow_dv_modify_clone_cb, 5791 flow_dv_modify_clone_free_cb); 5792 if (unlikely(!modify_cmds)) 5793 return -rte_errno; 5794 resource->root = !dev_flow->dv.group; 5795 if (resource->actions_num > flow_dv_modify_hdr_action_max(dev, 5796 resource->root)) 5797 return rte_flow_error_set(error, EOVERFLOW, 5798 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5799 "too many modify header items"); 5800 key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0); 5801 entry = mlx5_hlist_register(modify_cmds, key64, &ctx); 5802 if (!entry) 5803 return -rte_errno; 5804 resource = container_of(entry, typeof(*resource), entry); 5805 dev_flow->handle->dvh.modify_hdr = resource; 5806 return 0; 5807 } 5808 5809 /** 5810 * Get DV flow counter by index. 5811 * 5812 * @param[in] dev 5813 * Pointer to the Ethernet device structure. 5814 * @param[in] idx 5815 * mlx5 flow counter index in the container. 5816 * @param[out] ppool 5817 * mlx5 flow counter pool in the container. 5818 * 5819 * @return 5820 * Pointer to the counter, NULL otherwise. 5821 */ 5822 static struct mlx5_flow_counter * 5823 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev, 5824 uint32_t idx, 5825 struct mlx5_flow_counter_pool **ppool) 5826 { 5827 struct mlx5_priv *priv = dev->data->dev_private; 5828 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5829 struct mlx5_flow_counter_pool *pool; 5830 5831 /* Decrease to original index and clear shared bit. */ 5832 idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1); 5833 MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n); 5834 pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL]; 5835 MLX5_ASSERT(pool); 5836 if (ppool) 5837 *ppool = pool; 5838 return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL); 5839 } 5840 5841 /** 5842 * Check the devx counter belongs to the pool. 5843 * 5844 * @param[in] pool 5845 * Pointer to the counter pool. 5846 * @param[in] id 5847 * The counter devx ID. 5848 * 5849 * @return 5850 * True if counter belongs to the pool, false otherwise. 5851 */ 5852 static bool 5853 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id) 5854 { 5855 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) * 5856 MLX5_COUNTERS_PER_POOL; 5857 5858 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL) 5859 return true; 5860 return false; 5861 } 5862 5863 /** 5864 * Get a pool by devx counter ID. 5865 * 5866 * @param[in] cmng 5867 * Pointer to the counter management. 5868 * @param[in] id 5869 * The counter devx ID. 5870 * 5871 * @return 5872 * The counter pool pointer if exists, NULL otherwise, 5873 */ 5874 static struct mlx5_flow_counter_pool * 5875 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id) 5876 { 5877 uint32_t i; 5878 struct mlx5_flow_counter_pool *pool = NULL; 5879 5880 rte_spinlock_lock(&cmng->pool_update_sl); 5881 /* Check last used pool. */ 5882 if (cmng->last_pool_idx != POOL_IDX_INVALID && 5883 flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) { 5884 pool = cmng->pools[cmng->last_pool_idx]; 5885 goto out; 5886 } 5887 /* ID out of range means no suitable pool in the container. */ 5888 if (id > cmng->max_id || id < cmng->min_id) 5889 goto out; 5890 /* 5891 * Find the pool from the end of the container, since mostly counter 5892 * ID is sequence increasing, and the last pool should be the needed 5893 * one. 5894 */ 5895 i = cmng->n_valid; 5896 while (i--) { 5897 struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i]; 5898 5899 if (flow_dv_is_counter_in_pool(pool_tmp, id)) { 5900 pool = pool_tmp; 5901 break; 5902 } 5903 } 5904 out: 5905 rte_spinlock_unlock(&cmng->pool_update_sl); 5906 return pool; 5907 } 5908 5909 /** 5910 * Resize a counter container. 5911 * 5912 * @param[in] dev 5913 * Pointer to the Ethernet device structure. 5914 * 5915 * @return 5916 * 0 on success, otherwise negative errno value and rte_errno is set. 5917 */ 5918 static int 5919 flow_dv_container_resize(struct rte_eth_dev *dev) 5920 { 5921 struct mlx5_priv *priv = dev->data->dev_private; 5922 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5923 void *old_pools = cmng->pools; 5924 uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE; 5925 uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize; 5926 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 5927 5928 if (!pools) { 5929 rte_errno = ENOMEM; 5930 return -ENOMEM; 5931 } 5932 if (old_pools) 5933 memcpy(pools, old_pools, cmng->n * 5934 sizeof(struct mlx5_flow_counter_pool *)); 5935 cmng->n = resize; 5936 cmng->pools = pools; 5937 if (old_pools) 5938 mlx5_free(old_pools); 5939 return 0; 5940 } 5941 5942 /** 5943 * Query a devx flow counter. 5944 * 5945 * @param[in] dev 5946 * Pointer to the Ethernet device structure. 5947 * @param[in] counter 5948 * Index to the flow counter. 5949 * @param[out] pkts 5950 * The statistics value of packets. 5951 * @param[out] bytes 5952 * The statistics value of bytes. 5953 * 5954 * @return 5955 * 0 on success, otherwise a negative errno value and rte_errno is set. 5956 */ 5957 static inline int 5958 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts, 5959 uint64_t *bytes) 5960 { 5961 struct mlx5_priv *priv = dev->data->dev_private; 5962 struct mlx5_flow_counter_pool *pool = NULL; 5963 struct mlx5_flow_counter *cnt; 5964 int offset; 5965 5966 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 5967 MLX5_ASSERT(pool); 5968 if (priv->sh->cmng.counter_fallback) 5969 return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0, 5970 0, pkts, bytes, 0, NULL, NULL, 0); 5971 rte_spinlock_lock(&pool->sl); 5972 if (!pool->raw) { 5973 *pkts = 0; 5974 *bytes = 0; 5975 } else { 5976 offset = MLX5_CNT_ARRAY_IDX(pool, cnt); 5977 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits); 5978 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes); 5979 } 5980 rte_spinlock_unlock(&pool->sl); 5981 return 0; 5982 } 5983 5984 /** 5985 * Create and initialize a new counter pool. 5986 * 5987 * @param[in] dev 5988 * Pointer to the Ethernet device structure. 5989 * @param[out] dcs 5990 * The devX counter handle. 5991 * @param[in] age 5992 * Whether the pool is for counter that was allocated for aging. 5993 * @param[in/out] cont_cur 5994 * Pointer to the container pointer, it will be update in pool resize. 5995 * 5996 * @return 5997 * The pool container pointer on success, NULL otherwise and rte_errno is set. 5998 */ 5999 static struct mlx5_flow_counter_pool * 6000 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs, 6001 uint32_t age) 6002 { 6003 struct mlx5_priv *priv = dev->data->dev_private; 6004 struct mlx5_flow_counter_pool *pool; 6005 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6006 bool fallback = priv->sh->cmng.counter_fallback; 6007 uint32_t size = sizeof(*pool); 6008 6009 size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE; 6010 size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE); 6011 pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY); 6012 if (!pool) { 6013 rte_errno = ENOMEM; 6014 return NULL; 6015 } 6016 pool->raw = NULL; 6017 pool->is_aged = !!age; 6018 pool->query_gen = 0; 6019 pool->min_dcs = dcs; 6020 rte_spinlock_init(&pool->sl); 6021 rte_spinlock_init(&pool->csl); 6022 TAILQ_INIT(&pool->counters[0]); 6023 TAILQ_INIT(&pool->counters[1]); 6024 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 6025 rte_spinlock_lock(&cmng->pool_update_sl); 6026 pool->index = cmng->n_valid; 6027 if (pool->index == cmng->n && flow_dv_container_resize(dev)) { 6028 mlx5_free(pool); 6029 rte_spinlock_unlock(&cmng->pool_update_sl); 6030 return NULL; 6031 } 6032 cmng->pools[pool->index] = pool; 6033 cmng->n_valid++; 6034 if (unlikely(fallback)) { 6035 int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL); 6036 6037 if (base < cmng->min_id) 6038 cmng->min_id = base; 6039 if (base > cmng->max_id) 6040 cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1; 6041 cmng->last_pool_idx = pool->index; 6042 } 6043 rte_spinlock_unlock(&cmng->pool_update_sl); 6044 return pool; 6045 } 6046 6047 /** 6048 * Prepare a new counter and/or a new counter pool. 6049 * 6050 * @param[in] dev 6051 * Pointer to the Ethernet device structure. 6052 * @param[out] cnt_free 6053 * Where to put the pointer of a new counter. 6054 * @param[in] age 6055 * Whether the pool is for counter that was allocated for aging. 6056 * 6057 * @return 6058 * The counter pool pointer and @p cnt_free is set on success, 6059 * NULL otherwise and rte_errno is set. 6060 */ 6061 static struct mlx5_flow_counter_pool * 6062 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev, 6063 struct mlx5_flow_counter **cnt_free, 6064 uint32_t age) 6065 { 6066 struct mlx5_priv *priv = dev->data->dev_private; 6067 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6068 struct mlx5_flow_counter_pool *pool; 6069 struct mlx5_counters tmp_tq; 6070 struct mlx5_devx_obj *dcs = NULL; 6071 struct mlx5_flow_counter *cnt; 6072 enum mlx5_counter_type cnt_type = 6073 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6074 bool fallback = priv->sh->cmng.counter_fallback; 6075 uint32_t i; 6076 6077 if (fallback) { 6078 /* bulk_bitmap must be 0 for single counter allocation. */ 6079 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0); 6080 if (!dcs) 6081 return NULL; 6082 pool = flow_dv_find_pool_by_id(cmng, dcs->id); 6083 if (!pool) { 6084 pool = flow_dv_pool_create(dev, dcs, age); 6085 if (!pool) { 6086 mlx5_devx_cmd_destroy(dcs); 6087 return NULL; 6088 } 6089 } 6090 i = dcs->id % MLX5_COUNTERS_PER_POOL; 6091 cnt = MLX5_POOL_GET_CNT(pool, i); 6092 cnt->pool = pool; 6093 cnt->dcs_when_free = dcs; 6094 *cnt_free = cnt; 6095 return pool; 6096 } 6097 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 6098 if (!dcs) { 6099 rte_errno = ENODATA; 6100 return NULL; 6101 } 6102 pool = flow_dv_pool_create(dev, dcs, age); 6103 if (!pool) { 6104 mlx5_devx_cmd_destroy(dcs); 6105 return NULL; 6106 } 6107 TAILQ_INIT(&tmp_tq); 6108 for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) { 6109 cnt = MLX5_POOL_GET_CNT(pool, i); 6110 cnt->pool = pool; 6111 TAILQ_INSERT_HEAD(&tmp_tq, cnt, next); 6112 } 6113 rte_spinlock_lock(&cmng->csl[cnt_type]); 6114 TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next); 6115 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6116 *cnt_free = MLX5_POOL_GET_CNT(pool, 0); 6117 (*cnt_free)->pool = pool; 6118 return pool; 6119 } 6120 6121 /** 6122 * Allocate a flow counter. 6123 * 6124 * @param[in] dev 6125 * Pointer to the Ethernet device structure. 6126 * @param[in] age 6127 * Whether the counter was allocated for aging. 6128 * 6129 * @return 6130 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6131 */ 6132 static uint32_t 6133 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) 6134 { 6135 struct mlx5_priv *priv = dev->data->dev_private; 6136 struct mlx5_flow_counter_pool *pool = NULL; 6137 struct mlx5_flow_counter *cnt_free = NULL; 6138 bool fallback = priv->sh->cmng.counter_fallback; 6139 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6140 enum mlx5_counter_type cnt_type = 6141 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6142 uint32_t cnt_idx; 6143 6144 if (!priv->sh->devx) { 6145 rte_errno = ENOTSUP; 6146 return 0; 6147 } 6148 /* Get free counters from container. */ 6149 rte_spinlock_lock(&cmng->csl[cnt_type]); 6150 cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]); 6151 if (cnt_free) 6152 TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next); 6153 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6154 if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age)) 6155 goto err; 6156 pool = cnt_free->pool; 6157 if (fallback) 6158 cnt_free->dcs_when_active = cnt_free->dcs_when_free; 6159 /* Create a DV counter action only in the first time usage. */ 6160 if (!cnt_free->action) { 6161 uint16_t offset; 6162 struct mlx5_devx_obj *dcs; 6163 int ret; 6164 6165 if (!fallback) { 6166 offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free); 6167 dcs = pool->min_dcs; 6168 } else { 6169 offset = 0; 6170 dcs = cnt_free->dcs_when_free; 6171 } 6172 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset, 6173 &cnt_free->action); 6174 if (ret) { 6175 rte_errno = errno; 6176 goto err; 6177 } 6178 } 6179 cnt_idx = MLX5_MAKE_CNT_IDX(pool->index, 6180 MLX5_CNT_ARRAY_IDX(pool, cnt_free)); 6181 /* Update the counter reset values. */ 6182 if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits, 6183 &cnt_free->bytes)) 6184 goto err; 6185 if (!fallback && !priv->sh->cmng.query_thread_on) 6186 /* Start the asynchronous batch query by the host thread. */ 6187 mlx5_set_query_alarm(priv->sh); 6188 /* 6189 * When the count action isn't shared (by ID), shared_info field is 6190 * used for indirect action API's refcnt. 6191 * When the counter action is not shared neither by ID nor by indirect 6192 * action API, shared info must be 1. 6193 */ 6194 cnt_free->shared_info.refcnt = 1; 6195 return cnt_idx; 6196 err: 6197 if (cnt_free) { 6198 cnt_free->pool = pool; 6199 if (fallback) 6200 cnt_free->dcs_when_free = cnt_free->dcs_when_active; 6201 rte_spinlock_lock(&cmng->csl[cnt_type]); 6202 TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next); 6203 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6204 } 6205 return 0; 6206 } 6207 6208 /** 6209 * Get age param from counter index. 6210 * 6211 * @param[in] dev 6212 * Pointer to the Ethernet device structure. 6213 * @param[in] counter 6214 * Index to the counter handler. 6215 * 6216 * @return 6217 * The aging parameter specified for the counter index. 6218 */ 6219 static struct mlx5_age_param* 6220 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev, 6221 uint32_t counter) 6222 { 6223 struct mlx5_flow_counter *cnt; 6224 struct mlx5_flow_counter_pool *pool = NULL; 6225 6226 flow_dv_counter_get_by_idx(dev, counter, &pool); 6227 counter = (counter - 1) % MLX5_COUNTERS_PER_POOL; 6228 cnt = MLX5_POOL_GET_CNT(pool, counter); 6229 return MLX5_CNT_TO_AGE(cnt); 6230 } 6231 6232 /** 6233 * Remove a flow counter from aged counter list. 6234 * 6235 * @param[in] dev 6236 * Pointer to the Ethernet device structure. 6237 * @param[in] counter 6238 * Index to the counter handler. 6239 * @param[in] cnt 6240 * Pointer to the counter handler. 6241 */ 6242 static void 6243 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev, 6244 uint32_t counter, struct mlx5_flow_counter *cnt) 6245 { 6246 struct mlx5_age_info *age_info; 6247 struct mlx5_age_param *age_param; 6248 struct mlx5_priv *priv = dev->data->dev_private; 6249 uint16_t expected = AGE_CANDIDATE; 6250 6251 age_info = GET_PORT_AGE_INFO(priv); 6252 age_param = flow_dv_counter_idx_get_age(dev, counter); 6253 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 6254 AGE_FREE, false, __ATOMIC_RELAXED, 6255 __ATOMIC_RELAXED)) { 6256 /** 6257 * We need the lock even it is age timeout, 6258 * since counter may still in process. 6259 */ 6260 rte_spinlock_lock(&age_info->aged_sl); 6261 TAILQ_REMOVE(&age_info->aged_counters, cnt, next); 6262 rte_spinlock_unlock(&age_info->aged_sl); 6263 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 6264 } 6265 } 6266 6267 /** 6268 * Release a flow counter. 6269 * 6270 * @param[in] dev 6271 * Pointer to the Ethernet device structure. 6272 * @param[in] counter 6273 * Index to the counter handler. 6274 */ 6275 static void 6276 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) 6277 { 6278 struct mlx5_priv *priv = dev->data->dev_private; 6279 struct mlx5_flow_counter_pool *pool = NULL; 6280 struct mlx5_flow_counter *cnt; 6281 enum mlx5_counter_type cnt_type; 6282 6283 if (!counter) 6284 return; 6285 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 6286 MLX5_ASSERT(pool); 6287 if (pool->is_aged) { 6288 flow_dv_counter_remove_from_age(dev, counter, cnt); 6289 } else { 6290 /* 6291 * If the counter action is shared by indirect action API, 6292 * the atomic function reduces its references counter. 6293 * If after the reduction the action is still referenced, the 6294 * function returns here and does not release it. 6295 * When the counter action is not shared by 6296 * indirect action API, shared info is 1 before the reduction, 6297 * so this condition is failed and function doesn't return here. 6298 */ 6299 if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1, 6300 __ATOMIC_RELAXED)) 6301 return; 6302 } 6303 cnt->pool = pool; 6304 /* 6305 * Put the counter back to list to be updated in none fallback mode. 6306 * Currently, we are using two list alternately, while one is in query, 6307 * add the freed counter to the other list based on the pool query_gen 6308 * value. After query finishes, add counter the list to the global 6309 * container counter list. The list changes while query starts. In 6310 * this case, lock will not be needed as query callback and release 6311 * function both operate with the different list. 6312 */ 6313 if (!priv->sh->cmng.counter_fallback) { 6314 rte_spinlock_lock(&pool->csl); 6315 TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); 6316 rte_spinlock_unlock(&pool->csl); 6317 } else { 6318 cnt->dcs_when_free = cnt->dcs_when_active; 6319 cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : 6320 MLX5_COUNTER_TYPE_ORIGIN; 6321 rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]); 6322 TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type], 6323 cnt, next); 6324 rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]); 6325 } 6326 } 6327 6328 /** 6329 * Resize a meter id container. 6330 * 6331 * @param[in] dev 6332 * Pointer to the Ethernet device structure. 6333 * 6334 * @return 6335 * 0 on success, otherwise negative errno value and rte_errno is set. 6336 */ 6337 static int 6338 flow_dv_mtr_container_resize(struct rte_eth_dev *dev) 6339 { 6340 struct mlx5_priv *priv = dev->data->dev_private; 6341 struct mlx5_aso_mtr_pools_mng *pools_mng = 6342 &priv->sh->mtrmng->pools_mng; 6343 void *old_pools = pools_mng->pools; 6344 uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE; 6345 uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize; 6346 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 6347 6348 if (!pools) { 6349 rte_errno = ENOMEM; 6350 return -ENOMEM; 6351 } 6352 if (!pools_mng->n) 6353 if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { 6354 mlx5_free(pools); 6355 return -ENOMEM; 6356 } 6357 if (old_pools) 6358 memcpy(pools, old_pools, pools_mng->n * 6359 sizeof(struct mlx5_aso_mtr_pool *)); 6360 pools_mng->n = resize; 6361 pools_mng->pools = pools; 6362 if (old_pools) 6363 mlx5_free(old_pools); 6364 return 0; 6365 } 6366 6367 /** 6368 * Prepare a new meter and/or a new meter pool. 6369 * 6370 * @param[in] dev 6371 * Pointer to the Ethernet device structure. 6372 * @param[out] mtr_free 6373 * Where to put the pointer of a new meter.g. 6374 * 6375 * @return 6376 * The meter pool pointer and @mtr_free is set on success, 6377 * NULL otherwise and rte_errno is set. 6378 */ 6379 static struct mlx5_aso_mtr_pool * 6380 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free) 6381 { 6382 struct mlx5_priv *priv = dev->data->dev_private; 6383 struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng; 6384 struct mlx5_aso_mtr_pool *pool = NULL; 6385 struct mlx5_devx_obj *dcs = NULL; 6386 uint32_t i; 6387 uint32_t log_obj_size; 6388 6389 log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1); 6390 dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx, 6391 priv->sh->cdev->pdn, 6392 log_obj_size); 6393 if (!dcs) { 6394 rte_errno = ENODATA; 6395 return NULL; 6396 } 6397 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 6398 if (!pool) { 6399 rte_errno = ENOMEM; 6400 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6401 return NULL; 6402 } 6403 pool->devx_obj = dcs; 6404 pool->index = pools_mng->n_valid; 6405 if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) { 6406 mlx5_free(pool); 6407 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6408 return NULL; 6409 } 6410 pools_mng->pools[pool->index] = pool; 6411 pools_mng->n_valid++; 6412 for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) { 6413 pool->mtrs[i].offset = i; 6414 LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next); 6415 } 6416 pool->mtrs[0].offset = 0; 6417 *mtr_free = &pool->mtrs[0]; 6418 return pool; 6419 } 6420 6421 /** 6422 * Release a flow meter into pool. 6423 * 6424 * @param[in] dev 6425 * Pointer to the Ethernet device structure. 6426 * @param[in] mtr_idx 6427 * Index to aso flow meter. 6428 */ 6429 static void 6430 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx) 6431 { 6432 struct mlx5_priv *priv = dev->data->dev_private; 6433 struct mlx5_aso_mtr_pools_mng *pools_mng = 6434 &priv->sh->mtrmng->pools_mng; 6435 struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 6436 6437 MLX5_ASSERT(aso_mtr); 6438 rte_spinlock_lock(&pools_mng->mtrsl); 6439 memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info)); 6440 aso_mtr->state = ASO_METER_FREE; 6441 LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next); 6442 rte_spinlock_unlock(&pools_mng->mtrsl); 6443 } 6444 6445 /** 6446 * Allocate a aso flow meter. 6447 * 6448 * @param[in] dev 6449 * Pointer to the Ethernet device structure. 6450 * 6451 * @return 6452 * Index to aso flow meter on success, 0 otherwise and rte_errno is set. 6453 */ 6454 static uint32_t 6455 flow_dv_mtr_alloc(struct rte_eth_dev *dev) 6456 { 6457 struct mlx5_priv *priv = dev->data->dev_private; 6458 struct mlx5_aso_mtr *mtr_free = NULL; 6459 struct mlx5_aso_mtr_pools_mng *pools_mng = 6460 &priv->sh->mtrmng->pools_mng; 6461 struct mlx5_aso_mtr_pool *pool; 6462 uint32_t mtr_idx = 0; 6463 6464 if (!priv->sh->devx) { 6465 rte_errno = ENOTSUP; 6466 return 0; 6467 } 6468 /* Allocate the flow meter memory. */ 6469 /* Get free meters from management. */ 6470 rte_spinlock_lock(&pools_mng->mtrsl); 6471 mtr_free = LIST_FIRST(&pools_mng->meters); 6472 if (mtr_free) 6473 LIST_REMOVE(mtr_free, next); 6474 if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) { 6475 rte_spinlock_unlock(&pools_mng->mtrsl); 6476 return 0; 6477 } 6478 mtr_free->state = ASO_METER_WAIT; 6479 rte_spinlock_unlock(&pools_mng->mtrsl); 6480 pool = container_of(mtr_free, 6481 struct mlx5_aso_mtr_pool, 6482 mtrs[mtr_free->offset]); 6483 mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset); 6484 if (!mtr_free->fm.meter_action) { 6485 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 6486 struct rte_flow_error error; 6487 uint8_t reg_id; 6488 6489 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error); 6490 mtr_free->fm.meter_action = 6491 mlx5_glue->dv_create_flow_action_aso 6492 (priv->sh->rx_domain, 6493 pool->devx_obj->obj, 6494 mtr_free->offset, 6495 (1 << MLX5_FLOW_COLOR_GREEN), 6496 reg_id - REG_C_0); 6497 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 6498 if (!mtr_free->fm.meter_action) { 6499 flow_dv_aso_mtr_release_to_pool(dev, mtr_idx); 6500 return 0; 6501 } 6502 } 6503 return mtr_idx; 6504 } 6505 6506 /** 6507 * Verify the @p attributes will be correctly understood by the NIC and store 6508 * them in the @p flow if everything is correct. 6509 * 6510 * @param[in] dev 6511 * Pointer to dev struct. 6512 * @param[in] attributes 6513 * Pointer to flow attributes 6514 * @param[in] external 6515 * This flow rule is created by request external to PMD. 6516 * @param[out] error 6517 * Pointer to error structure. 6518 * 6519 * @return 6520 * - 0 on success and non root table. 6521 * - 1 on success and root table. 6522 * - a negative errno value otherwise and rte_errno is set. 6523 */ 6524 static int 6525 flow_dv_validate_attributes(struct rte_eth_dev *dev, 6526 const struct mlx5_flow_tunnel *tunnel, 6527 const struct rte_flow_attr *attributes, 6528 const struct flow_grp_info *grp_info, 6529 struct rte_flow_error *error) 6530 { 6531 struct mlx5_priv *priv = dev->data->dev_private; 6532 uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes); 6533 int ret = 0; 6534 6535 #ifndef HAVE_MLX5DV_DR 6536 RTE_SET_USED(tunnel); 6537 RTE_SET_USED(grp_info); 6538 if (attributes->group) 6539 return rte_flow_error_set(error, ENOTSUP, 6540 RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 6541 NULL, 6542 "groups are not supported"); 6543 #else 6544 uint32_t table = 0; 6545 6546 ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table, 6547 grp_info, error); 6548 if (ret) 6549 return ret; 6550 if (!table) 6551 ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL; 6552 #endif 6553 if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR && 6554 attributes->priority > lowest_priority) 6555 return rte_flow_error_set(error, ENOTSUP, 6556 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 6557 NULL, 6558 "priority out of range"); 6559 if (attributes->transfer) { 6560 if (!priv->config.dv_esw_en) 6561 return rte_flow_error_set 6562 (error, ENOTSUP, 6563 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 6564 "E-Switch dr is not supported"); 6565 if (!(priv->representor || priv->master)) 6566 return rte_flow_error_set 6567 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6568 NULL, "E-Switch configuration can only be" 6569 " done by a master or a representor device"); 6570 if (attributes->egress) 6571 return rte_flow_error_set 6572 (error, ENOTSUP, 6573 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes, 6574 "egress is not supported"); 6575 } 6576 if (!(attributes->egress ^ attributes->ingress)) 6577 return rte_flow_error_set(error, ENOTSUP, 6578 RTE_FLOW_ERROR_TYPE_ATTR, NULL, 6579 "must specify exactly one of " 6580 "ingress or egress"); 6581 return ret; 6582 } 6583 6584 static uint16_t 6585 mlx5_flow_locate_proto_l3(const struct rte_flow_item **head, 6586 const struct rte_flow_item *end) 6587 { 6588 const struct rte_flow_item *item = *head; 6589 uint16_t l3_protocol; 6590 6591 for (; item != end; item++) { 6592 switch (item->type) { 6593 default: 6594 break; 6595 case RTE_FLOW_ITEM_TYPE_IPV4: 6596 l3_protocol = RTE_ETHER_TYPE_IPV4; 6597 goto l3_ok; 6598 case RTE_FLOW_ITEM_TYPE_IPV6: 6599 l3_protocol = RTE_ETHER_TYPE_IPV6; 6600 goto l3_ok; 6601 case RTE_FLOW_ITEM_TYPE_ETH: 6602 if (item->mask && item->spec) { 6603 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_eth, 6604 type, item, 6605 l3_protocol); 6606 if (l3_protocol == RTE_ETHER_TYPE_IPV4 || 6607 l3_protocol == RTE_ETHER_TYPE_IPV6) 6608 goto l3_ok; 6609 } 6610 break; 6611 case RTE_FLOW_ITEM_TYPE_VLAN: 6612 if (item->mask && item->spec) { 6613 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_vlan, 6614 inner_type, item, 6615 l3_protocol); 6616 if (l3_protocol == RTE_ETHER_TYPE_IPV4 || 6617 l3_protocol == RTE_ETHER_TYPE_IPV6) 6618 goto l3_ok; 6619 } 6620 break; 6621 } 6622 } 6623 return 0; 6624 l3_ok: 6625 *head = item; 6626 return l3_protocol; 6627 } 6628 6629 static uint8_t 6630 mlx5_flow_locate_proto_l4(const struct rte_flow_item **head, 6631 const struct rte_flow_item *end) 6632 { 6633 const struct rte_flow_item *item = *head; 6634 uint8_t l4_protocol; 6635 6636 for (; item != end; item++) { 6637 switch (item->type) { 6638 default: 6639 break; 6640 case RTE_FLOW_ITEM_TYPE_TCP: 6641 l4_protocol = IPPROTO_TCP; 6642 goto l4_ok; 6643 case RTE_FLOW_ITEM_TYPE_UDP: 6644 l4_protocol = IPPROTO_UDP; 6645 goto l4_ok; 6646 case RTE_FLOW_ITEM_TYPE_IPV4: 6647 if (item->mask && item->spec) { 6648 const struct rte_flow_item_ipv4 *mask, *spec; 6649 6650 mask = (typeof(mask))item->mask; 6651 spec = (typeof(spec))item->spec; 6652 l4_protocol = mask->hdr.next_proto_id & 6653 spec->hdr.next_proto_id; 6654 if (l4_protocol == IPPROTO_TCP || 6655 l4_protocol == IPPROTO_UDP) 6656 goto l4_ok; 6657 } 6658 break; 6659 case RTE_FLOW_ITEM_TYPE_IPV6: 6660 if (item->mask && item->spec) { 6661 const struct rte_flow_item_ipv6 *mask, *spec; 6662 mask = (typeof(mask))item->mask; 6663 spec = (typeof(spec))item->spec; 6664 l4_protocol = mask->hdr.proto & spec->hdr.proto; 6665 if (l4_protocol == IPPROTO_TCP || 6666 l4_protocol == IPPROTO_UDP) 6667 goto l4_ok; 6668 } 6669 break; 6670 } 6671 } 6672 return 0; 6673 l4_ok: 6674 *head = item; 6675 return l4_protocol; 6676 } 6677 6678 static int 6679 flow_dv_validate_item_integrity(struct rte_eth_dev *dev, 6680 const struct rte_flow_item *rule_items, 6681 const struct rte_flow_item *integrity_item, 6682 struct rte_flow_error *error) 6683 { 6684 struct mlx5_priv *priv = dev->data->dev_private; 6685 const struct rte_flow_item *tunnel_item, *end_item, *item = rule_items; 6686 const struct rte_flow_item_integrity *mask = (typeof(mask)) 6687 integrity_item->mask; 6688 const struct rte_flow_item_integrity *spec = (typeof(spec)) 6689 integrity_item->spec; 6690 uint32_t protocol; 6691 6692 if (!priv->config.hca_attr.pkt_integrity_match) 6693 return rte_flow_error_set(error, ENOTSUP, 6694 RTE_FLOW_ERROR_TYPE_ITEM, 6695 integrity_item, 6696 "packet integrity integrity_item not supported"); 6697 if (!mask) 6698 mask = &rte_flow_item_integrity_mask; 6699 if (!mlx5_validate_integrity_item(mask)) 6700 return rte_flow_error_set(error, ENOTSUP, 6701 RTE_FLOW_ERROR_TYPE_ITEM, 6702 integrity_item, 6703 "unsupported integrity filter"); 6704 tunnel_item = mlx5_flow_find_tunnel_item(rule_items); 6705 if (spec->level > 1) { 6706 if (!tunnel_item) 6707 return rte_flow_error_set(error, ENOTSUP, 6708 RTE_FLOW_ERROR_TYPE_ITEM, 6709 integrity_item, 6710 "missing tunnel item"); 6711 item = tunnel_item; 6712 end_item = mlx5_find_end_item(tunnel_item); 6713 } else { 6714 end_item = tunnel_item ? tunnel_item : 6715 mlx5_find_end_item(integrity_item); 6716 } 6717 if (mask->l3_ok || mask->ipv4_csum_ok) { 6718 protocol = mlx5_flow_locate_proto_l3(&item, end_item); 6719 if (!protocol) 6720 return rte_flow_error_set(error, EINVAL, 6721 RTE_FLOW_ERROR_TYPE_ITEM, 6722 integrity_item, 6723 "missing L3 protocol"); 6724 } 6725 if (mask->l4_ok || mask->l4_csum_ok) { 6726 protocol = mlx5_flow_locate_proto_l4(&item, end_item); 6727 if (!protocol) 6728 return rte_flow_error_set(error, EINVAL, 6729 RTE_FLOW_ERROR_TYPE_ITEM, 6730 integrity_item, 6731 "missing L4 protocol"); 6732 } 6733 return 0; 6734 } 6735 6736 /** 6737 * Internal validation function. For validating both actions and items. 6738 * 6739 * @param[in] dev 6740 * Pointer to the rte_eth_dev structure. 6741 * @param[in] attr 6742 * Pointer to the flow attributes. 6743 * @param[in] items 6744 * Pointer to the list of items. 6745 * @param[in] actions 6746 * Pointer to the list of actions. 6747 * @param[in] external 6748 * This flow rule is created by request external to PMD. 6749 * @param[in] hairpin 6750 * Number of hairpin TX actions, 0 means classic flow. 6751 * @param[out] error 6752 * Pointer to the error structure. 6753 * 6754 * @return 6755 * 0 on success, a negative errno value otherwise and rte_errno is set. 6756 */ 6757 static int 6758 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, 6759 const struct rte_flow_item items[], 6760 const struct rte_flow_action actions[], 6761 bool external, int hairpin, struct rte_flow_error *error) 6762 { 6763 int ret; 6764 uint64_t action_flags = 0; 6765 uint64_t item_flags = 0; 6766 uint64_t last_item = 0; 6767 uint8_t next_protocol = 0xff; 6768 uint16_t ether_type = 0; 6769 int actions_n = 0; 6770 uint8_t item_ipv6_proto = 0; 6771 int fdb_mirror_limit = 0; 6772 int modify_after_mirror = 0; 6773 const struct rte_flow_item *geneve_item = NULL; 6774 const struct rte_flow_item *gre_item = NULL; 6775 const struct rte_flow_item *gtp_item = NULL; 6776 const struct rte_flow_action_raw_decap *decap; 6777 const struct rte_flow_action_raw_encap *encap; 6778 const struct rte_flow_action_rss *rss = NULL; 6779 const struct rte_flow_action_rss *sample_rss = NULL; 6780 const struct rte_flow_action_count *sample_count = NULL; 6781 const struct rte_flow_item_tcp nic_tcp_mask = { 6782 .hdr = { 6783 .tcp_flags = 0xFF, 6784 .src_port = RTE_BE16(UINT16_MAX), 6785 .dst_port = RTE_BE16(UINT16_MAX), 6786 } 6787 }; 6788 const struct rte_flow_item_ipv6 nic_ipv6_mask = { 6789 .hdr = { 6790 .src_addr = 6791 "\xff\xff\xff\xff\xff\xff\xff\xff" 6792 "\xff\xff\xff\xff\xff\xff\xff\xff", 6793 .dst_addr = 6794 "\xff\xff\xff\xff\xff\xff\xff\xff" 6795 "\xff\xff\xff\xff\xff\xff\xff\xff", 6796 .vtc_flow = RTE_BE32(0xffffffff), 6797 .proto = 0xff, 6798 .hop_limits = 0xff, 6799 }, 6800 .has_frag_ext = 1, 6801 }; 6802 const struct rte_flow_item_ecpri nic_ecpri_mask = { 6803 .hdr = { 6804 .common = { 6805 .u32 = 6806 RTE_BE32(((const struct rte_ecpri_common_hdr) { 6807 .type = 0xFF, 6808 }).u32), 6809 }, 6810 .dummy[0] = 0xffffffff, 6811 }, 6812 }; 6813 struct mlx5_priv *priv = dev->data->dev_private; 6814 struct mlx5_dev_config *dev_conf = &priv->config; 6815 uint16_t queue_index = 0xFFFF; 6816 const struct rte_flow_item_vlan *vlan_m = NULL; 6817 uint32_t rw_act_num = 0; 6818 uint64_t is_root; 6819 const struct mlx5_flow_tunnel *tunnel; 6820 enum mlx5_tof_rule_type tof_rule_type; 6821 struct flow_grp_info grp_info = { 6822 .external = !!external, 6823 .transfer = !!attr->transfer, 6824 .fdb_def_rule = !!priv->fdb_def_rule, 6825 .std_tbl_fix = true, 6826 }; 6827 const struct rte_eth_hairpin_conf *conf; 6828 const struct rte_flow_item *rule_items = items; 6829 const struct rte_flow_item *port_id_item = NULL; 6830 bool def_policy = false; 6831 uint16_t udp_dport = 0; 6832 6833 if (items == NULL) 6834 return -1; 6835 tunnel = is_tunnel_offload_active(dev) ? 6836 mlx5_get_tof(items, actions, &tof_rule_type) : NULL; 6837 if (tunnel) { 6838 if (priv->representor) 6839 return rte_flow_error_set 6840 (error, ENOTSUP, 6841 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6842 NULL, "decap not supported for VF representor"); 6843 if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE) 6844 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 6845 else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE) 6846 action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH | 6847 MLX5_FLOW_ACTION_DECAP; 6848 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 6849 (dev, attr, tunnel, tof_rule_type); 6850 } 6851 ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error); 6852 if (ret < 0) 6853 return ret; 6854 is_root = (uint64_t)ret; 6855 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 6856 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 6857 int type = items->type; 6858 6859 if (!mlx5_flow_os_item_supported(type)) 6860 return rte_flow_error_set(error, ENOTSUP, 6861 RTE_FLOW_ERROR_TYPE_ITEM, 6862 NULL, "item not supported"); 6863 switch (type) { 6864 case RTE_FLOW_ITEM_TYPE_VOID: 6865 break; 6866 case RTE_FLOW_ITEM_TYPE_PORT_ID: 6867 ret = flow_dv_validate_item_port_id 6868 (dev, items, attr, item_flags, error); 6869 if (ret < 0) 6870 return ret; 6871 last_item = MLX5_FLOW_ITEM_PORT_ID; 6872 port_id_item = items; 6873 break; 6874 case RTE_FLOW_ITEM_TYPE_ETH: 6875 ret = mlx5_flow_validate_item_eth(items, item_flags, 6876 true, error); 6877 if (ret < 0) 6878 return ret; 6879 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 6880 MLX5_FLOW_LAYER_OUTER_L2; 6881 if (items->mask != NULL && items->spec != NULL) { 6882 ether_type = 6883 ((const struct rte_flow_item_eth *) 6884 items->spec)->type; 6885 ether_type &= 6886 ((const struct rte_flow_item_eth *) 6887 items->mask)->type; 6888 ether_type = rte_be_to_cpu_16(ether_type); 6889 } else { 6890 ether_type = 0; 6891 } 6892 break; 6893 case RTE_FLOW_ITEM_TYPE_VLAN: 6894 ret = flow_dv_validate_item_vlan(items, item_flags, 6895 dev, error); 6896 if (ret < 0) 6897 return ret; 6898 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 6899 MLX5_FLOW_LAYER_OUTER_VLAN; 6900 if (items->mask != NULL && items->spec != NULL) { 6901 ether_type = 6902 ((const struct rte_flow_item_vlan *) 6903 items->spec)->inner_type; 6904 ether_type &= 6905 ((const struct rte_flow_item_vlan *) 6906 items->mask)->inner_type; 6907 ether_type = rte_be_to_cpu_16(ether_type); 6908 } else { 6909 ether_type = 0; 6910 } 6911 /* Store outer VLAN mask for of_push_vlan action. */ 6912 if (!tunnel) 6913 vlan_m = items->mask; 6914 break; 6915 case RTE_FLOW_ITEM_TYPE_IPV4: 6916 mlx5_flow_tunnel_ip_check(items, next_protocol, 6917 &item_flags, &tunnel); 6918 ret = flow_dv_validate_item_ipv4(dev, items, item_flags, 6919 last_item, ether_type, 6920 error); 6921 if (ret < 0) 6922 return ret; 6923 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 6924 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 6925 if (items->mask != NULL && 6926 ((const struct rte_flow_item_ipv4 *) 6927 items->mask)->hdr.next_proto_id) { 6928 next_protocol = 6929 ((const struct rte_flow_item_ipv4 *) 6930 (items->spec))->hdr.next_proto_id; 6931 next_protocol &= 6932 ((const struct rte_flow_item_ipv4 *) 6933 (items->mask))->hdr.next_proto_id; 6934 } else { 6935 /* Reset for inner layer. */ 6936 next_protocol = 0xff; 6937 } 6938 break; 6939 case RTE_FLOW_ITEM_TYPE_IPV6: 6940 mlx5_flow_tunnel_ip_check(items, next_protocol, 6941 &item_flags, &tunnel); 6942 ret = mlx5_flow_validate_item_ipv6(items, item_flags, 6943 last_item, 6944 ether_type, 6945 &nic_ipv6_mask, 6946 error); 6947 if (ret < 0) 6948 return ret; 6949 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 6950 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 6951 if (items->mask != NULL && 6952 ((const struct rte_flow_item_ipv6 *) 6953 items->mask)->hdr.proto) { 6954 item_ipv6_proto = 6955 ((const struct rte_flow_item_ipv6 *) 6956 items->spec)->hdr.proto; 6957 next_protocol = 6958 ((const struct rte_flow_item_ipv6 *) 6959 items->spec)->hdr.proto; 6960 next_protocol &= 6961 ((const struct rte_flow_item_ipv6 *) 6962 items->mask)->hdr.proto; 6963 } else { 6964 /* Reset for inner layer. */ 6965 next_protocol = 0xff; 6966 } 6967 break; 6968 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 6969 ret = flow_dv_validate_item_ipv6_frag_ext(items, 6970 item_flags, 6971 error); 6972 if (ret < 0) 6973 return ret; 6974 last_item = tunnel ? 6975 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 6976 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 6977 if (items->mask != NULL && 6978 ((const struct rte_flow_item_ipv6_frag_ext *) 6979 items->mask)->hdr.next_header) { 6980 next_protocol = 6981 ((const struct rte_flow_item_ipv6_frag_ext *) 6982 items->spec)->hdr.next_header; 6983 next_protocol &= 6984 ((const struct rte_flow_item_ipv6_frag_ext *) 6985 items->mask)->hdr.next_header; 6986 } else { 6987 /* Reset for inner layer. */ 6988 next_protocol = 0xff; 6989 } 6990 break; 6991 case RTE_FLOW_ITEM_TYPE_TCP: 6992 ret = mlx5_flow_validate_item_tcp 6993 (items, item_flags, 6994 next_protocol, 6995 &nic_tcp_mask, 6996 error); 6997 if (ret < 0) 6998 return ret; 6999 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 7000 MLX5_FLOW_LAYER_OUTER_L4_TCP; 7001 break; 7002 case RTE_FLOW_ITEM_TYPE_UDP: 7003 ret = mlx5_flow_validate_item_udp(items, item_flags, 7004 next_protocol, 7005 error); 7006 const struct rte_flow_item_udp *spec = items->spec; 7007 const struct rte_flow_item_udp *mask = items->mask; 7008 if (!mask) 7009 mask = &rte_flow_item_udp_mask; 7010 if (spec != NULL) 7011 udp_dport = rte_be_to_cpu_16 7012 (spec->hdr.dst_port & 7013 mask->hdr.dst_port); 7014 if (ret < 0) 7015 return ret; 7016 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 7017 MLX5_FLOW_LAYER_OUTER_L4_UDP; 7018 break; 7019 case RTE_FLOW_ITEM_TYPE_GRE: 7020 ret = mlx5_flow_validate_item_gre(items, item_flags, 7021 next_protocol, error); 7022 if (ret < 0) 7023 return ret; 7024 gre_item = items; 7025 last_item = MLX5_FLOW_LAYER_GRE; 7026 break; 7027 case RTE_FLOW_ITEM_TYPE_NVGRE: 7028 ret = mlx5_flow_validate_item_nvgre(items, item_flags, 7029 next_protocol, 7030 error); 7031 if (ret < 0) 7032 return ret; 7033 last_item = MLX5_FLOW_LAYER_NVGRE; 7034 break; 7035 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 7036 ret = mlx5_flow_validate_item_gre_key 7037 (items, item_flags, gre_item, error); 7038 if (ret < 0) 7039 return ret; 7040 last_item = MLX5_FLOW_LAYER_GRE_KEY; 7041 break; 7042 case RTE_FLOW_ITEM_TYPE_VXLAN: 7043 ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, 7044 items, item_flags, 7045 attr, error); 7046 if (ret < 0) 7047 return ret; 7048 last_item = MLX5_FLOW_LAYER_VXLAN; 7049 break; 7050 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 7051 ret = mlx5_flow_validate_item_vxlan_gpe(items, 7052 item_flags, dev, 7053 error); 7054 if (ret < 0) 7055 return ret; 7056 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 7057 break; 7058 case RTE_FLOW_ITEM_TYPE_GENEVE: 7059 ret = mlx5_flow_validate_item_geneve(items, 7060 item_flags, dev, 7061 error); 7062 if (ret < 0) 7063 return ret; 7064 geneve_item = items; 7065 last_item = MLX5_FLOW_LAYER_GENEVE; 7066 break; 7067 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 7068 ret = mlx5_flow_validate_item_geneve_opt(items, 7069 last_item, 7070 geneve_item, 7071 dev, 7072 error); 7073 if (ret < 0) 7074 return ret; 7075 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 7076 break; 7077 case RTE_FLOW_ITEM_TYPE_MPLS: 7078 ret = mlx5_flow_validate_item_mpls(dev, items, 7079 item_flags, 7080 last_item, error); 7081 if (ret < 0) 7082 return ret; 7083 last_item = MLX5_FLOW_LAYER_MPLS; 7084 break; 7085 7086 case RTE_FLOW_ITEM_TYPE_MARK: 7087 ret = flow_dv_validate_item_mark(dev, items, attr, 7088 error); 7089 if (ret < 0) 7090 return ret; 7091 last_item = MLX5_FLOW_ITEM_MARK; 7092 break; 7093 case RTE_FLOW_ITEM_TYPE_META: 7094 ret = flow_dv_validate_item_meta(dev, items, attr, 7095 error); 7096 if (ret < 0) 7097 return ret; 7098 last_item = MLX5_FLOW_ITEM_METADATA; 7099 break; 7100 case RTE_FLOW_ITEM_TYPE_ICMP: 7101 ret = mlx5_flow_validate_item_icmp(items, item_flags, 7102 next_protocol, 7103 error); 7104 if (ret < 0) 7105 return ret; 7106 last_item = MLX5_FLOW_LAYER_ICMP; 7107 break; 7108 case RTE_FLOW_ITEM_TYPE_ICMP6: 7109 ret = mlx5_flow_validate_item_icmp6(items, item_flags, 7110 next_protocol, 7111 error); 7112 if (ret < 0) 7113 return ret; 7114 item_ipv6_proto = IPPROTO_ICMPV6; 7115 last_item = MLX5_FLOW_LAYER_ICMP6; 7116 break; 7117 case RTE_FLOW_ITEM_TYPE_TAG: 7118 ret = flow_dv_validate_item_tag(dev, items, 7119 attr, error); 7120 if (ret < 0) 7121 return ret; 7122 last_item = MLX5_FLOW_ITEM_TAG; 7123 break; 7124 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 7125 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 7126 break; 7127 case RTE_FLOW_ITEM_TYPE_GTP: 7128 ret = flow_dv_validate_item_gtp(dev, items, item_flags, 7129 error); 7130 if (ret < 0) 7131 return ret; 7132 gtp_item = items; 7133 last_item = MLX5_FLOW_LAYER_GTP; 7134 break; 7135 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 7136 ret = flow_dv_validate_item_gtp_psc(items, last_item, 7137 gtp_item, attr, 7138 error); 7139 if (ret < 0) 7140 return ret; 7141 last_item = MLX5_FLOW_LAYER_GTP_PSC; 7142 break; 7143 case RTE_FLOW_ITEM_TYPE_ECPRI: 7144 /* Capacity will be checked in the translate stage. */ 7145 ret = mlx5_flow_validate_item_ecpri(items, item_flags, 7146 last_item, 7147 ether_type, 7148 &nic_ecpri_mask, 7149 error); 7150 if (ret < 0) 7151 return ret; 7152 last_item = MLX5_FLOW_LAYER_ECPRI; 7153 break; 7154 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 7155 if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) 7156 return rte_flow_error_set 7157 (error, ENOTSUP, 7158 RTE_FLOW_ERROR_TYPE_ITEM, 7159 NULL, "multiple integrity items not supported"); 7160 ret = flow_dv_validate_item_integrity(dev, rule_items, 7161 items, error); 7162 if (ret < 0) 7163 return ret; 7164 last_item = MLX5_FLOW_ITEM_INTEGRITY; 7165 break; 7166 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 7167 ret = flow_dv_validate_item_aso_ct(dev, items, 7168 &item_flags, error); 7169 if (ret < 0) 7170 return ret; 7171 break; 7172 case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL: 7173 /* tunnel offload item was processed before 7174 * list it here as a supported type 7175 */ 7176 break; 7177 default: 7178 return rte_flow_error_set(error, ENOTSUP, 7179 RTE_FLOW_ERROR_TYPE_ITEM, 7180 NULL, "item not supported"); 7181 } 7182 item_flags |= last_item; 7183 } 7184 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 7185 int type = actions->type; 7186 bool shared_count = false; 7187 7188 if (!mlx5_flow_os_action_supported(type)) 7189 return rte_flow_error_set(error, ENOTSUP, 7190 RTE_FLOW_ERROR_TYPE_ACTION, 7191 actions, 7192 "action not supported"); 7193 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 7194 return rte_flow_error_set(error, ENOTSUP, 7195 RTE_FLOW_ERROR_TYPE_ACTION, 7196 actions, "too many actions"); 7197 if (action_flags & 7198 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 7199 return rte_flow_error_set(error, ENOTSUP, 7200 RTE_FLOW_ERROR_TYPE_ACTION, 7201 NULL, "meter action with policy " 7202 "must be the last action"); 7203 switch (type) { 7204 case RTE_FLOW_ACTION_TYPE_VOID: 7205 break; 7206 case RTE_FLOW_ACTION_TYPE_PORT_ID: 7207 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 7208 ret = flow_dv_validate_action_port_id(dev, 7209 action_flags, 7210 actions, 7211 attr, 7212 error); 7213 if (ret) 7214 return ret; 7215 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 7216 ++actions_n; 7217 break; 7218 case RTE_FLOW_ACTION_TYPE_FLAG: 7219 ret = flow_dv_validate_action_flag(dev, action_flags, 7220 attr, error); 7221 if (ret < 0) 7222 return ret; 7223 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7224 /* Count all modify-header actions as one. */ 7225 if (!(action_flags & 7226 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7227 ++actions_n; 7228 action_flags |= MLX5_FLOW_ACTION_FLAG | 7229 MLX5_FLOW_ACTION_MARK_EXT; 7230 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7231 modify_after_mirror = 1; 7232 7233 } else { 7234 action_flags |= MLX5_FLOW_ACTION_FLAG; 7235 ++actions_n; 7236 } 7237 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7238 break; 7239 case RTE_FLOW_ACTION_TYPE_MARK: 7240 ret = flow_dv_validate_action_mark(dev, actions, 7241 action_flags, 7242 attr, error); 7243 if (ret < 0) 7244 return ret; 7245 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7246 /* Count all modify-header actions as one. */ 7247 if (!(action_flags & 7248 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7249 ++actions_n; 7250 action_flags |= MLX5_FLOW_ACTION_MARK | 7251 MLX5_FLOW_ACTION_MARK_EXT; 7252 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7253 modify_after_mirror = 1; 7254 } else { 7255 action_flags |= MLX5_FLOW_ACTION_MARK; 7256 ++actions_n; 7257 } 7258 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7259 break; 7260 case RTE_FLOW_ACTION_TYPE_SET_META: 7261 ret = flow_dv_validate_action_set_meta(dev, actions, 7262 action_flags, 7263 attr, error); 7264 if (ret < 0) 7265 return ret; 7266 /* Count all modify-header actions as one action. */ 7267 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7268 ++actions_n; 7269 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7270 modify_after_mirror = 1; 7271 action_flags |= MLX5_FLOW_ACTION_SET_META; 7272 rw_act_num += MLX5_ACT_NUM_SET_META; 7273 break; 7274 case RTE_FLOW_ACTION_TYPE_SET_TAG: 7275 ret = flow_dv_validate_action_set_tag(dev, actions, 7276 action_flags, 7277 attr, error); 7278 if (ret < 0) 7279 return ret; 7280 /* Count all modify-header actions as one action. */ 7281 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7282 ++actions_n; 7283 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7284 modify_after_mirror = 1; 7285 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 7286 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7287 break; 7288 case RTE_FLOW_ACTION_TYPE_DROP: 7289 ret = mlx5_flow_validate_action_drop(action_flags, 7290 attr, error); 7291 if (ret < 0) 7292 return ret; 7293 action_flags |= MLX5_FLOW_ACTION_DROP; 7294 ++actions_n; 7295 break; 7296 case RTE_FLOW_ACTION_TYPE_QUEUE: 7297 ret = mlx5_flow_validate_action_queue(actions, 7298 action_flags, dev, 7299 attr, error); 7300 if (ret < 0) 7301 return ret; 7302 queue_index = ((const struct rte_flow_action_queue *) 7303 (actions->conf))->index; 7304 action_flags |= MLX5_FLOW_ACTION_QUEUE; 7305 ++actions_n; 7306 break; 7307 case RTE_FLOW_ACTION_TYPE_RSS: 7308 rss = actions->conf; 7309 ret = mlx5_flow_validate_action_rss(actions, 7310 action_flags, dev, 7311 attr, item_flags, 7312 error); 7313 if (ret < 0) 7314 return ret; 7315 if (rss && sample_rss && 7316 (sample_rss->level != rss->level || 7317 sample_rss->types != rss->types)) 7318 return rte_flow_error_set(error, ENOTSUP, 7319 RTE_FLOW_ERROR_TYPE_ACTION, 7320 NULL, 7321 "Can't use the different RSS types " 7322 "or level in the same flow"); 7323 if (rss != NULL && rss->queue_num) 7324 queue_index = rss->queue[0]; 7325 action_flags |= MLX5_FLOW_ACTION_RSS; 7326 ++actions_n; 7327 break; 7328 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 7329 ret = 7330 mlx5_flow_validate_action_default_miss(action_flags, 7331 attr, error); 7332 if (ret < 0) 7333 return ret; 7334 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 7335 ++actions_n; 7336 break; 7337 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 7338 shared_count = true; 7339 /* fall-through. */ 7340 case RTE_FLOW_ACTION_TYPE_COUNT: 7341 ret = flow_dv_validate_action_count(dev, shared_count, 7342 action_flags, 7343 error); 7344 if (ret < 0) 7345 return ret; 7346 action_flags |= MLX5_FLOW_ACTION_COUNT; 7347 ++actions_n; 7348 break; 7349 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 7350 if (flow_dv_validate_action_pop_vlan(dev, 7351 action_flags, 7352 actions, 7353 item_flags, attr, 7354 error)) 7355 return -rte_errno; 7356 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7357 modify_after_mirror = 1; 7358 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 7359 ++actions_n; 7360 break; 7361 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 7362 ret = flow_dv_validate_action_push_vlan(dev, 7363 action_flags, 7364 vlan_m, 7365 actions, attr, 7366 error); 7367 if (ret < 0) 7368 return ret; 7369 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7370 modify_after_mirror = 1; 7371 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 7372 ++actions_n; 7373 break; 7374 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 7375 ret = flow_dv_validate_action_set_vlan_pcp 7376 (action_flags, actions, error); 7377 if (ret < 0) 7378 return ret; 7379 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7380 modify_after_mirror = 1; 7381 /* Count PCP with push_vlan command. */ 7382 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; 7383 break; 7384 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 7385 ret = flow_dv_validate_action_set_vlan_vid 7386 (item_flags, action_flags, 7387 actions, error); 7388 if (ret < 0) 7389 return ret; 7390 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7391 modify_after_mirror = 1; 7392 /* Count VID with push_vlan command. */ 7393 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 7394 rw_act_num += MLX5_ACT_NUM_MDF_VID; 7395 break; 7396 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 7397 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 7398 ret = flow_dv_validate_action_l2_encap(dev, 7399 action_flags, 7400 actions, attr, 7401 error); 7402 if (ret < 0) 7403 return ret; 7404 action_flags |= MLX5_FLOW_ACTION_ENCAP; 7405 ++actions_n; 7406 break; 7407 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 7408 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 7409 ret = flow_dv_validate_action_decap(dev, action_flags, 7410 actions, item_flags, 7411 attr, error); 7412 if (ret < 0) 7413 return ret; 7414 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7415 modify_after_mirror = 1; 7416 action_flags |= MLX5_FLOW_ACTION_DECAP; 7417 ++actions_n; 7418 break; 7419 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 7420 ret = flow_dv_validate_action_raw_encap_decap 7421 (dev, NULL, actions->conf, attr, &action_flags, 7422 &actions_n, actions, item_flags, error); 7423 if (ret < 0) 7424 return ret; 7425 break; 7426 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 7427 decap = actions->conf; 7428 while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID) 7429 ; 7430 if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 7431 encap = NULL; 7432 actions--; 7433 } else { 7434 encap = actions->conf; 7435 } 7436 ret = flow_dv_validate_action_raw_encap_decap 7437 (dev, 7438 decap ? decap : &empty_decap, encap, 7439 attr, &action_flags, &actions_n, 7440 actions, item_flags, error); 7441 if (ret < 0) 7442 return ret; 7443 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7444 (action_flags & MLX5_FLOW_ACTION_DECAP)) 7445 modify_after_mirror = 1; 7446 break; 7447 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 7448 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 7449 ret = flow_dv_validate_action_modify_mac(action_flags, 7450 actions, 7451 item_flags, 7452 error); 7453 if (ret < 0) 7454 return ret; 7455 /* Count all modify-header actions as one action. */ 7456 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7457 ++actions_n; 7458 action_flags |= actions->type == 7459 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 7460 MLX5_FLOW_ACTION_SET_MAC_SRC : 7461 MLX5_FLOW_ACTION_SET_MAC_DST; 7462 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7463 modify_after_mirror = 1; 7464 /* 7465 * Even if the source and destination MAC addresses have 7466 * overlap in the header with 4B alignment, the convert 7467 * function will handle them separately and 4 SW actions 7468 * will be created. And 2 actions will be added each 7469 * time no matter how many bytes of address will be set. 7470 */ 7471 rw_act_num += MLX5_ACT_NUM_MDF_MAC; 7472 break; 7473 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 7474 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 7475 ret = flow_dv_validate_action_modify_ipv4(action_flags, 7476 actions, 7477 item_flags, 7478 error); 7479 if (ret < 0) 7480 return ret; 7481 /* Count all modify-header actions as one action. */ 7482 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7483 ++actions_n; 7484 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7485 modify_after_mirror = 1; 7486 action_flags |= actions->type == 7487 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 7488 MLX5_FLOW_ACTION_SET_IPV4_SRC : 7489 MLX5_FLOW_ACTION_SET_IPV4_DST; 7490 rw_act_num += MLX5_ACT_NUM_MDF_IPV4; 7491 break; 7492 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 7493 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 7494 ret = flow_dv_validate_action_modify_ipv6(action_flags, 7495 actions, 7496 item_flags, 7497 error); 7498 if (ret < 0) 7499 return ret; 7500 if (item_ipv6_proto == IPPROTO_ICMPV6) 7501 return rte_flow_error_set(error, ENOTSUP, 7502 RTE_FLOW_ERROR_TYPE_ACTION, 7503 actions, 7504 "Can't change header " 7505 "with ICMPv6 proto"); 7506 /* Count all modify-header actions as one action. */ 7507 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7508 ++actions_n; 7509 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7510 modify_after_mirror = 1; 7511 action_flags |= actions->type == 7512 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 7513 MLX5_FLOW_ACTION_SET_IPV6_SRC : 7514 MLX5_FLOW_ACTION_SET_IPV6_DST; 7515 rw_act_num += MLX5_ACT_NUM_MDF_IPV6; 7516 break; 7517 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 7518 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 7519 ret = flow_dv_validate_action_modify_tp(action_flags, 7520 actions, 7521 item_flags, 7522 error); 7523 if (ret < 0) 7524 return ret; 7525 /* Count all modify-header actions as one action. */ 7526 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7527 ++actions_n; 7528 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7529 modify_after_mirror = 1; 7530 action_flags |= actions->type == 7531 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 7532 MLX5_FLOW_ACTION_SET_TP_SRC : 7533 MLX5_FLOW_ACTION_SET_TP_DST; 7534 rw_act_num += MLX5_ACT_NUM_MDF_PORT; 7535 break; 7536 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 7537 case RTE_FLOW_ACTION_TYPE_SET_TTL: 7538 ret = flow_dv_validate_action_modify_ttl(action_flags, 7539 actions, 7540 item_flags, 7541 error); 7542 if (ret < 0) 7543 return ret; 7544 /* Count all modify-header actions as one action. */ 7545 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7546 ++actions_n; 7547 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7548 modify_after_mirror = 1; 7549 action_flags |= actions->type == 7550 RTE_FLOW_ACTION_TYPE_SET_TTL ? 7551 MLX5_FLOW_ACTION_SET_TTL : 7552 MLX5_FLOW_ACTION_DEC_TTL; 7553 rw_act_num += MLX5_ACT_NUM_MDF_TTL; 7554 break; 7555 case RTE_FLOW_ACTION_TYPE_JUMP: 7556 ret = flow_dv_validate_action_jump(dev, tunnel, actions, 7557 action_flags, 7558 attr, external, 7559 error); 7560 if (ret) 7561 return ret; 7562 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7563 fdb_mirror_limit) 7564 return rte_flow_error_set(error, EINVAL, 7565 RTE_FLOW_ERROR_TYPE_ACTION, 7566 NULL, 7567 "sample and jump action combination is not supported"); 7568 ++actions_n; 7569 action_flags |= MLX5_FLOW_ACTION_JUMP; 7570 break; 7571 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 7572 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 7573 ret = flow_dv_validate_action_modify_tcp_seq 7574 (action_flags, 7575 actions, 7576 item_flags, 7577 error); 7578 if (ret < 0) 7579 return ret; 7580 /* Count all modify-header actions as one action. */ 7581 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7582 ++actions_n; 7583 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7584 modify_after_mirror = 1; 7585 action_flags |= actions->type == 7586 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 7587 MLX5_FLOW_ACTION_INC_TCP_SEQ : 7588 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 7589 rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ; 7590 break; 7591 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 7592 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 7593 ret = flow_dv_validate_action_modify_tcp_ack 7594 (action_flags, 7595 actions, 7596 item_flags, 7597 error); 7598 if (ret < 0) 7599 return ret; 7600 /* Count all modify-header actions as one action. */ 7601 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7602 ++actions_n; 7603 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7604 modify_after_mirror = 1; 7605 action_flags |= actions->type == 7606 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 7607 MLX5_FLOW_ACTION_INC_TCP_ACK : 7608 MLX5_FLOW_ACTION_DEC_TCP_ACK; 7609 rw_act_num += MLX5_ACT_NUM_MDF_TCPACK; 7610 break; 7611 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 7612 break; 7613 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 7614 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 7615 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7616 break; 7617 case RTE_FLOW_ACTION_TYPE_METER: 7618 ret = mlx5_flow_validate_action_meter(dev, 7619 action_flags, 7620 actions, attr, 7621 port_id_item, 7622 &def_policy, 7623 error); 7624 if (ret < 0) 7625 return ret; 7626 action_flags |= MLX5_FLOW_ACTION_METER; 7627 if (!def_policy) 7628 action_flags |= 7629 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 7630 ++actions_n; 7631 /* Meter action will add one more TAG action. */ 7632 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7633 break; 7634 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 7635 if (!attr->transfer && !attr->group) 7636 return rte_flow_error_set(error, ENOTSUP, 7637 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7638 NULL, 7639 "Shared ASO age action is not supported for group 0"); 7640 if (action_flags & MLX5_FLOW_ACTION_AGE) 7641 return rte_flow_error_set 7642 (error, EINVAL, 7643 RTE_FLOW_ERROR_TYPE_ACTION, 7644 NULL, 7645 "duplicate age actions set"); 7646 action_flags |= MLX5_FLOW_ACTION_AGE; 7647 ++actions_n; 7648 break; 7649 case RTE_FLOW_ACTION_TYPE_AGE: 7650 ret = flow_dv_validate_action_age(action_flags, 7651 actions, dev, 7652 error); 7653 if (ret < 0) 7654 return ret; 7655 /* 7656 * Validate the regular AGE action (using counter) 7657 * mutual exclusion with share counter actions. 7658 */ 7659 if (!priv->sh->flow_hit_aso_en) { 7660 if (shared_count) 7661 return rte_flow_error_set 7662 (error, EINVAL, 7663 RTE_FLOW_ERROR_TYPE_ACTION, 7664 NULL, 7665 "old age and shared count combination is not supported"); 7666 if (sample_count) 7667 return rte_flow_error_set 7668 (error, EINVAL, 7669 RTE_FLOW_ERROR_TYPE_ACTION, 7670 NULL, 7671 "old age action and count must be in the same sub flow"); 7672 } 7673 action_flags |= MLX5_FLOW_ACTION_AGE; 7674 ++actions_n; 7675 break; 7676 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 7677 ret = flow_dv_validate_action_modify_ipv4_dscp 7678 (action_flags, 7679 actions, 7680 item_flags, 7681 error); 7682 if (ret < 0) 7683 return ret; 7684 /* Count all modify-header actions as one action. */ 7685 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7686 ++actions_n; 7687 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7688 modify_after_mirror = 1; 7689 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 7690 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7691 break; 7692 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 7693 ret = flow_dv_validate_action_modify_ipv6_dscp 7694 (action_flags, 7695 actions, 7696 item_flags, 7697 error); 7698 if (ret < 0) 7699 return ret; 7700 /* Count all modify-header actions as one action. */ 7701 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7702 ++actions_n; 7703 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7704 modify_after_mirror = 1; 7705 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 7706 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7707 break; 7708 case RTE_FLOW_ACTION_TYPE_SAMPLE: 7709 ret = flow_dv_validate_action_sample(&action_flags, 7710 actions, dev, 7711 attr, item_flags, 7712 rss, &sample_rss, 7713 &sample_count, 7714 &fdb_mirror_limit, 7715 error); 7716 if (ret < 0) 7717 return ret; 7718 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 7719 ++actions_n; 7720 break; 7721 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 7722 ret = flow_dv_validate_action_modify_field(dev, 7723 action_flags, 7724 actions, 7725 attr, 7726 error); 7727 if (ret < 0) 7728 return ret; 7729 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7730 modify_after_mirror = 1; 7731 /* Count all modify-header actions as one action. */ 7732 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7733 ++actions_n; 7734 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 7735 rw_act_num += ret; 7736 break; 7737 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 7738 ret = flow_dv_validate_action_aso_ct(dev, action_flags, 7739 item_flags, attr, 7740 error); 7741 if (ret < 0) 7742 return ret; 7743 action_flags |= MLX5_FLOW_ACTION_CT; 7744 break; 7745 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 7746 /* tunnel offload action was processed before 7747 * list it here as a supported type 7748 */ 7749 break; 7750 default: 7751 return rte_flow_error_set(error, ENOTSUP, 7752 RTE_FLOW_ERROR_TYPE_ACTION, 7753 actions, 7754 "action not supported"); 7755 } 7756 } 7757 /* 7758 * Validate actions in flow rules 7759 * - Explicit decap action is prohibited by the tunnel offload API. 7760 * - Drop action in tunnel steer rule is prohibited by the API. 7761 * - Application cannot use MARK action because it's value can mask 7762 * tunnel default miss nitification. 7763 * - JUMP in tunnel match rule has no support in current PMD 7764 * implementation. 7765 * - TAG & META are reserved for future uses. 7766 */ 7767 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) { 7768 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP | 7769 MLX5_FLOW_ACTION_MARK | 7770 MLX5_FLOW_ACTION_SET_TAG | 7771 MLX5_FLOW_ACTION_SET_META | 7772 MLX5_FLOW_ACTION_DROP; 7773 7774 if (action_flags & bad_actions_mask) 7775 return rte_flow_error_set 7776 (error, EINVAL, 7777 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7778 "Invalid RTE action in tunnel " 7779 "set decap rule"); 7780 if (!(action_flags & MLX5_FLOW_ACTION_JUMP)) 7781 return rte_flow_error_set 7782 (error, EINVAL, 7783 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7784 "tunnel set decap rule must terminate " 7785 "with JUMP"); 7786 if (!attr->ingress) 7787 return rte_flow_error_set 7788 (error, EINVAL, 7789 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7790 "tunnel flows for ingress traffic only"); 7791 } 7792 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) { 7793 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP | 7794 MLX5_FLOW_ACTION_MARK | 7795 MLX5_FLOW_ACTION_SET_TAG | 7796 MLX5_FLOW_ACTION_SET_META; 7797 7798 if (action_flags & bad_actions_mask) 7799 return rte_flow_error_set 7800 (error, EINVAL, 7801 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7802 "Invalid RTE action in tunnel " 7803 "set match rule"); 7804 } 7805 /* 7806 * Validate the drop action mutual exclusion with other actions. 7807 * Drop action is mutually-exclusive with any other action, except for 7808 * Count action. 7809 * Drop action compatibility with tunnel offload was already validated. 7810 */ 7811 if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH | 7812 MLX5_FLOW_ACTION_TUNNEL_MATCH)); 7813 else if ((action_flags & MLX5_FLOW_ACTION_DROP) && 7814 (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT))) 7815 return rte_flow_error_set(error, EINVAL, 7816 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7817 "Drop action is mutually-exclusive " 7818 "with any other action, except for " 7819 "Count action"); 7820 /* Eswitch has few restrictions on using items and actions */ 7821 if (attr->transfer) { 7822 if (!mlx5_flow_ext_mreg_supported(dev) && 7823 action_flags & MLX5_FLOW_ACTION_FLAG) 7824 return rte_flow_error_set(error, ENOTSUP, 7825 RTE_FLOW_ERROR_TYPE_ACTION, 7826 NULL, 7827 "unsupported action FLAG"); 7828 if (!mlx5_flow_ext_mreg_supported(dev) && 7829 action_flags & MLX5_FLOW_ACTION_MARK) 7830 return rte_flow_error_set(error, ENOTSUP, 7831 RTE_FLOW_ERROR_TYPE_ACTION, 7832 NULL, 7833 "unsupported action MARK"); 7834 if (action_flags & MLX5_FLOW_ACTION_QUEUE) 7835 return rte_flow_error_set(error, ENOTSUP, 7836 RTE_FLOW_ERROR_TYPE_ACTION, 7837 NULL, 7838 "unsupported action QUEUE"); 7839 if (action_flags & MLX5_FLOW_ACTION_RSS) 7840 return rte_flow_error_set(error, ENOTSUP, 7841 RTE_FLOW_ERROR_TYPE_ACTION, 7842 NULL, 7843 "unsupported action RSS"); 7844 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 7845 return rte_flow_error_set(error, EINVAL, 7846 RTE_FLOW_ERROR_TYPE_ACTION, 7847 actions, 7848 "no fate action is found"); 7849 } else { 7850 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) 7851 return rte_flow_error_set(error, EINVAL, 7852 RTE_FLOW_ERROR_TYPE_ACTION, 7853 actions, 7854 "no fate action is found"); 7855 } 7856 /* 7857 * Continue validation for Xcap and VLAN actions. 7858 * If hairpin is working in explicit TX rule mode, there is no actions 7859 * splitting and the validation of hairpin ingress flow should be the 7860 * same as other standard flows. 7861 */ 7862 if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS | 7863 MLX5_FLOW_VLAN_ACTIONS)) && 7864 (queue_index == 0xFFFF || 7865 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN || 7866 ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL && 7867 conf->tx_explicit != 0))) { 7868 if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) == 7869 MLX5_FLOW_XCAP_ACTIONS) 7870 return rte_flow_error_set(error, ENOTSUP, 7871 RTE_FLOW_ERROR_TYPE_ACTION, 7872 NULL, "encap and decap " 7873 "combination aren't supported"); 7874 if (!attr->transfer && attr->ingress) { 7875 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 7876 return rte_flow_error_set 7877 (error, ENOTSUP, 7878 RTE_FLOW_ERROR_TYPE_ACTION, 7879 NULL, "encap is not supported" 7880 " for ingress traffic"); 7881 else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 7882 return rte_flow_error_set 7883 (error, ENOTSUP, 7884 RTE_FLOW_ERROR_TYPE_ACTION, 7885 NULL, "push VLAN action not " 7886 "supported for ingress"); 7887 else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) == 7888 MLX5_FLOW_VLAN_ACTIONS) 7889 return rte_flow_error_set 7890 (error, ENOTSUP, 7891 RTE_FLOW_ERROR_TYPE_ACTION, 7892 NULL, "no support for " 7893 "multiple VLAN actions"); 7894 } 7895 } 7896 if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) { 7897 if ((action_flags & (MLX5_FLOW_FATE_ACTIONS & 7898 ~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) && 7899 attr->ingress) 7900 return rte_flow_error_set 7901 (error, ENOTSUP, 7902 RTE_FLOW_ERROR_TYPE_ACTION, 7903 NULL, "fate action not supported for " 7904 "meter with policy"); 7905 if (attr->egress) { 7906 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 7907 return rte_flow_error_set 7908 (error, ENOTSUP, 7909 RTE_FLOW_ERROR_TYPE_ACTION, 7910 NULL, "modify header action in egress " 7911 "cannot be done before meter action"); 7912 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 7913 return rte_flow_error_set 7914 (error, ENOTSUP, 7915 RTE_FLOW_ERROR_TYPE_ACTION, 7916 NULL, "encap action in egress " 7917 "cannot be done before meter action"); 7918 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 7919 return rte_flow_error_set 7920 (error, ENOTSUP, 7921 RTE_FLOW_ERROR_TYPE_ACTION, 7922 NULL, "push vlan action in egress " 7923 "cannot be done before meter action"); 7924 } 7925 } 7926 /* 7927 * Hairpin flow will add one more TAG action in TX implicit mode. 7928 * In TX explicit mode, there will be no hairpin flow ID. 7929 */ 7930 if (hairpin > 0) 7931 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7932 /* extra metadata enabled: one more TAG action will be add. */ 7933 if (dev_conf->dv_flow_en && 7934 dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 7935 mlx5_flow_ext_mreg_supported(dev)) 7936 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7937 if (rw_act_num > 7938 flow_dv_modify_hdr_action_max(dev, is_root)) { 7939 return rte_flow_error_set(error, ENOTSUP, 7940 RTE_FLOW_ERROR_TYPE_ACTION, 7941 NULL, "too many header modify" 7942 " actions to support"); 7943 } 7944 /* Eswitch egress mirror and modify flow has limitation on CX5 */ 7945 if (fdb_mirror_limit && modify_after_mirror) 7946 return rte_flow_error_set(error, EINVAL, 7947 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7948 "sample before modify action is not supported"); 7949 return 0; 7950 } 7951 7952 /** 7953 * Internal preparation function. Allocates the DV flow size, 7954 * this size is constant. 7955 * 7956 * @param[in] dev 7957 * Pointer to the rte_eth_dev structure. 7958 * @param[in] attr 7959 * Pointer to the flow attributes. 7960 * @param[in] items 7961 * Pointer to the list of items. 7962 * @param[in] actions 7963 * Pointer to the list of actions. 7964 * @param[out] error 7965 * Pointer to the error structure. 7966 * 7967 * @return 7968 * Pointer to mlx5_flow object on success, 7969 * otherwise NULL and rte_errno is set. 7970 */ 7971 static struct mlx5_flow * 7972 flow_dv_prepare(struct rte_eth_dev *dev, 7973 const struct rte_flow_attr *attr __rte_unused, 7974 const struct rte_flow_item items[] __rte_unused, 7975 const struct rte_flow_action actions[] __rte_unused, 7976 struct rte_flow_error *error) 7977 { 7978 uint32_t handle_idx = 0; 7979 struct mlx5_flow *dev_flow; 7980 struct mlx5_flow_handle *dev_handle; 7981 struct mlx5_priv *priv = dev->data->dev_private; 7982 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 7983 7984 MLX5_ASSERT(wks); 7985 wks->skip_matcher_reg = 0; 7986 wks->policy = NULL; 7987 wks->final_policy = NULL; 7988 /* In case of corrupting the memory. */ 7989 if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) { 7990 rte_flow_error_set(error, ENOSPC, 7991 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 7992 "not free temporary device flow"); 7993 return NULL; 7994 } 7995 dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 7996 &handle_idx); 7997 if (!dev_handle) { 7998 rte_flow_error_set(error, ENOMEM, 7999 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8000 "not enough memory to create flow handle"); 8001 return NULL; 8002 } 8003 MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows)); 8004 dev_flow = &wks->flows[wks->flow_idx++]; 8005 memset(dev_flow, 0, sizeof(*dev_flow)); 8006 dev_flow->handle = dev_handle; 8007 dev_flow->handle_idx = handle_idx; 8008 dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 8009 dev_flow->ingress = attr->ingress; 8010 dev_flow->dv.transfer = attr->transfer; 8011 return dev_flow; 8012 } 8013 8014 #ifdef RTE_LIBRTE_MLX5_DEBUG 8015 /** 8016 * Sanity check for match mask and value. Similar to check_valid_spec() in 8017 * kernel driver. If unmasked bit is present in value, it returns failure. 8018 * 8019 * @param match_mask 8020 * pointer to match mask buffer. 8021 * @param match_value 8022 * pointer to match value buffer. 8023 * 8024 * @return 8025 * 0 if valid, -EINVAL otherwise. 8026 */ 8027 static int 8028 flow_dv_check_valid_spec(void *match_mask, void *match_value) 8029 { 8030 uint8_t *m = match_mask; 8031 uint8_t *v = match_value; 8032 unsigned int i; 8033 8034 for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) { 8035 if (v[i] & ~m[i]) { 8036 DRV_LOG(ERR, 8037 "match_value differs from match_criteria" 8038 " %p[%u] != %p[%u]", 8039 match_value, i, match_mask, i); 8040 return -EINVAL; 8041 } 8042 } 8043 return 0; 8044 } 8045 #endif 8046 8047 /** 8048 * Add match of ip_version. 8049 * 8050 * @param[in] group 8051 * Flow group. 8052 * @param[in] headers_v 8053 * Values header pointer. 8054 * @param[in] headers_m 8055 * Masks header pointer. 8056 * @param[in] ip_version 8057 * The IP version to set. 8058 */ 8059 static inline void 8060 flow_dv_set_match_ip_version(uint32_t group, 8061 void *headers_v, 8062 void *headers_m, 8063 uint8_t ip_version) 8064 { 8065 if (group == 0) 8066 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf); 8067 else 8068 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 8069 ip_version); 8070 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version); 8071 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0); 8072 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0); 8073 } 8074 8075 /** 8076 * Add Ethernet item to matcher and to the value. 8077 * 8078 * @param[in, out] matcher 8079 * Flow matcher. 8080 * @param[in, out] key 8081 * Flow matcher value. 8082 * @param[in] item 8083 * Flow pattern to translate. 8084 * @param[in] inner 8085 * Item is inner pattern. 8086 */ 8087 static void 8088 flow_dv_translate_item_eth(void *matcher, void *key, 8089 const struct rte_flow_item *item, int inner, 8090 uint32_t group) 8091 { 8092 const struct rte_flow_item_eth *eth_m = item->mask; 8093 const struct rte_flow_item_eth *eth_v = item->spec; 8094 const struct rte_flow_item_eth nic_mask = { 8095 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8096 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8097 .type = RTE_BE16(0xffff), 8098 .has_vlan = 0, 8099 }; 8100 void *hdrs_m; 8101 void *hdrs_v; 8102 char *l24_v; 8103 unsigned int i; 8104 8105 if (!eth_v) 8106 return; 8107 if (!eth_m) 8108 eth_m = &nic_mask; 8109 if (inner) { 8110 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8111 inner_headers); 8112 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8113 } else { 8114 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8115 outer_headers); 8116 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8117 } 8118 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16), 8119 ð_m->dst, sizeof(eth_m->dst)); 8120 /* The value must be in the range of the mask. */ 8121 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16); 8122 for (i = 0; i < sizeof(eth_m->dst); ++i) 8123 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i]; 8124 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16), 8125 ð_m->src, sizeof(eth_m->src)); 8126 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16); 8127 /* The value must be in the range of the mask. */ 8128 for (i = 0; i < sizeof(eth_m->dst); ++i) 8129 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i]; 8130 /* 8131 * HW supports match on one Ethertype, the Ethertype following the last 8132 * VLAN tag of the packet (see PRM). 8133 * Set match on ethertype only if ETH header is not followed by VLAN. 8134 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8135 * ethertype, and use ip_version field instead. 8136 * eCPRI over Ether layer will use type value 0xAEFE. 8137 */ 8138 if (eth_m->type == 0xFFFF) { 8139 /* Set cvlan_tag mask for any single\multi\un-tagged case. */ 8140 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8141 switch (eth_v->type) { 8142 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8143 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8144 return; 8145 case RTE_BE16(RTE_ETHER_TYPE_QINQ): 8146 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8147 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8148 return; 8149 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8150 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8151 return; 8152 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8153 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8154 return; 8155 default: 8156 break; 8157 } 8158 } 8159 if (eth_m->has_vlan) { 8160 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8161 if (eth_v->has_vlan) { 8162 /* 8163 * Here, when also has_more_vlan field in VLAN item is 8164 * not set, only single-tagged packets will be matched. 8165 */ 8166 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8167 return; 8168 } 8169 } 8170 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8171 rte_be_to_cpu_16(eth_m->type)); 8172 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 8173 *(uint16_t *)(l24_v) = eth_m->type & eth_v->type; 8174 } 8175 8176 /** 8177 * Add VLAN item to matcher and to the value. 8178 * 8179 * @param[in, out] dev_flow 8180 * Flow descriptor. 8181 * @param[in, out] matcher 8182 * Flow matcher. 8183 * @param[in, out] key 8184 * Flow matcher value. 8185 * @param[in] item 8186 * Flow pattern to translate. 8187 * @param[in] inner 8188 * Item is inner pattern. 8189 */ 8190 static void 8191 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow, 8192 void *matcher, void *key, 8193 const struct rte_flow_item *item, 8194 int inner, uint32_t group) 8195 { 8196 const struct rte_flow_item_vlan *vlan_m = item->mask; 8197 const struct rte_flow_item_vlan *vlan_v = item->spec; 8198 void *hdrs_m; 8199 void *hdrs_v; 8200 uint16_t tci_m; 8201 uint16_t tci_v; 8202 8203 if (inner) { 8204 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8205 inner_headers); 8206 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8207 } else { 8208 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8209 outer_headers); 8210 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8211 /* 8212 * This is workaround, masks are not supported, 8213 * and pre-validated. 8214 */ 8215 if (vlan_v) 8216 dev_flow->handle->vf_vlan.tag = 8217 rte_be_to_cpu_16(vlan_v->tci) & 0x0fff; 8218 } 8219 /* 8220 * When VLAN item exists in flow, mark packet as tagged, 8221 * even if TCI is not specified. 8222 */ 8223 if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) { 8224 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8225 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8226 } 8227 if (!vlan_v) 8228 return; 8229 if (!vlan_m) 8230 vlan_m = &rte_flow_item_vlan_mask; 8231 tci_m = rte_be_to_cpu_16(vlan_m->tci); 8232 tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci); 8233 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m); 8234 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v); 8235 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12); 8236 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12); 8237 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13); 8238 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13); 8239 /* 8240 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8241 * ethertype, and use ip_version field instead. 8242 */ 8243 if (vlan_m->inner_type == 0xFFFF) { 8244 switch (vlan_v->inner_type) { 8245 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8246 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8247 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8248 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8249 return; 8250 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8251 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8252 return; 8253 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8254 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8255 return; 8256 default: 8257 break; 8258 } 8259 } 8260 if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) { 8261 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8262 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8263 /* Only one vlan_tag bit can be set. */ 8264 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8265 return; 8266 } 8267 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8268 rte_be_to_cpu_16(vlan_m->inner_type)); 8269 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype, 8270 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type)); 8271 } 8272 8273 /** 8274 * Add IPV4 item to matcher and to the value. 8275 * 8276 * @param[in, out] matcher 8277 * Flow matcher. 8278 * @param[in, out] key 8279 * Flow matcher value. 8280 * @param[in] item 8281 * Flow pattern to translate. 8282 * @param[in] inner 8283 * Item is inner pattern. 8284 * @param[in] group 8285 * The group to insert the rule. 8286 */ 8287 static void 8288 flow_dv_translate_item_ipv4(void *matcher, void *key, 8289 const struct rte_flow_item *item, 8290 int inner, uint32_t group) 8291 { 8292 const struct rte_flow_item_ipv4 *ipv4_m = item->mask; 8293 const struct rte_flow_item_ipv4 *ipv4_v = item->spec; 8294 const struct rte_flow_item_ipv4 nic_mask = { 8295 .hdr = { 8296 .src_addr = RTE_BE32(0xffffffff), 8297 .dst_addr = RTE_BE32(0xffffffff), 8298 .type_of_service = 0xff, 8299 .next_proto_id = 0xff, 8300 .time_to_live = 0xff, 8301 }, 8302 }; 8303 void *headers_m; 8304 void *headers_v; 8305 char *l24_m; 8306 char *l24_v; 8307 uint8_t tos, ihl_m, ihl_v; 8308 8309 if (inner) { 8310 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8311 inner_headers); 8312 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8313 } else { 8314 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8315 outer_headers); 8316 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8317 } 8318 flow_dv_set_match_ip_version(group, headers_v, headers_m, 4); 8319 if (!ipv4_v) 8320 return; 8321 if (!ipv4_m) 8322 ipv4_m = &nic_mask; 8323 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8324 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8325 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8326 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8327 *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr; 8328 *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr; 8329 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8330 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8331 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8332 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8333 *(uint32_t *)l24_m = ipv4_m->hdr.src_addr; 8334 *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr; 8335 tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service; 8336 ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8337 ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8338 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m); 8339 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v); 8340 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, 8341 ipv4_m->hdr.type_of_service); 8342 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos); 8343 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, 8344 ipv4_m->hdr.type_of_service >> 2); 8345 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2); 8346 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8347 ipv4_m->hdr.next_proto_id); 8348 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8349 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id); 8350 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8351 ipv4_m->hdr.time_to_live); 8352 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8353 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live); 8354 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8355 !!(ipv4_m->hdr.fragment_offset)); 8356 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8357 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset)); 8358 } 8359 8360 /** 8361 * Add IPV6 item to matcher and to the value. 8362 * 8363 * @param[in, out] matcher 8364 * Flow matcher. 8365 * @param[in, out] key 8366 * Flow matcher value. 8367 * @param[in] item 8368 * Flow pattern to translate. 8369 * @param[in] inner 8370 * Item is inner pattern. 8371 * @param[in] group 8372 * The group to insert the rule. 8373 */ 8374 static void 8375 flow_dv_translate_item_ipv6(void *matcher, void *key, 8376 const struct rte_flow_item *item, 8377 int inner, uint32_t group) 8378 { 8379 const struct rte_flow_item_ipv6 *ipv6_m = item->mask; 8380 const struct rte_flow_item_ipv6 *ipv6_v = item->spec; 8381 const struct rte_flow_item_ipv6 nic_mask = { 8382 .hdr = { 8383 .src_addr = 8384 "\xff\xff\xff\xff\xff\xff\xff\xff" 8385 "\xff\xff\xff\xff\xff\xff\xff\xff", 8386 .dst_addr = 8387 "\xff\xff\xff\xff\xff\xff\xff\xff" 8388 "\xff\xff\xff\xff\xff\xff\xff\xff", 8389 .vtc_flow = RTE_BE32(0xffffffff), 8390 .proto = 0xff, 8391 .hop_limits = 0xff, 8392 }, 8393 }; 8394 void *headers_m; 8395 void *headers_v; 8396 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8397 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8398 char *l24_m; 8399 char *l24_v; 8400 uint32_t vtc_m; 8401 uint32_t vtc_v; 8402 int i; 8403 int size; 8404 8405 if (inner) { 8406 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8407 inner_headers); 8408 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8409 } else { 8410 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8411 outer_headers); 8412 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8413 } 8414 flow_dv_set_match_ip_version(group, headers_v, headers_m, 6); 8415 if (!ipv6_v) 8416 return; 8417 if (!ipv6_m) 8418 ipv6_m = &nic_mask; 8419 size = sizeof(ipv6_m->hdr.dst_addr); 8420 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8421 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8422 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8423 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8424 memcpy(l24_m, ipv6_m->hdr.dst_addr, size); 8425 for (i = 0; i < size; ++i) 8426 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i]; 8427 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8428 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8429 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8430 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8431 memcpy(l24_m, ipv6_m->hdr.src_addr, size); 8432 for (i = 0; i < size; ++i) 8433 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i]; 8434 /* TOS. */ 8435 vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow); 8436 vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow); 8437 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20); 8438 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20); 8439 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22); 8440 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22); 8441 /* Label. */ 8442 if (inner) { 8443 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label, 8444 vtc_m); 8445 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label, 8446 vtc_v); 8447 } else { 8448 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label, 8449 vtc_m); 8450 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label, 8451 vtc_v); 8452 } 8453 /* Protocol. */ 8454 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8455 ipv6_m->hdr.proto); 8456 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8457 ipv6_v->hdr.proto & ipv6_m->hdr.proto); 8458 /* Hop limit. */ 8459 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8460 ipv6_m->hdr.hop_limits); 8461 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8462 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits); 8463 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8464 !!(ipv6_m->has_frag_ext)); 8465 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8466 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext)); 8467 } 8468 8469 /** 8470 * Add IPV6 fragment extension item to matcher and to the value. 8471 * 8472 * @param[in, out] matcher 8473 * Flow matcher. 8474 * @param[in, out] key 8475 * Flow matcher value. 8476 * @param[in] item 8477 * Flow pattern to translate. 8478 * @param[in] inner 8479 * Item is inner pattern. 8480 */ 8481 static void 8482 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key, 8483 const struct rte_flow_item *item, 8484 int inner) 8485 { 8486 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask; 8487 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec; 8488 const struct rte_flow_item_ipv6_frag_ext nic_mask = { 8489 .hdr = { 8490 .next_header = 0xff, 8491 .frag_data = RTE_BE16(0xffff), 8492 }, 8493 }; 8494 void *headers_m; 8495 void *headers_v; 8496 8497 if (inner) { 8498 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8499 inner_headers); 8500 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8501 } else { 8502 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8503 outer_headers); 8504 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8505 } 8506 /* IPv6 fragment extension item exists, so packet is IP fragment. */ 8507 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1); 8508 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1); 8509 if (!ipv6_frag_ext_v) 8510 return; 8511 if (!ipv6_frag_ext_m) 8512 ipv6_frag_ext_m = &nic_mask; 8513 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8514 ipv6_frag_ext_m->hdr.next_header); 8515 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8516 ipv6_frag_ext_v->hdr.next_header & 8517 ipv6_frag_ext_m->hdr.next_header); 8518 } 8519 8520 /** 8521 * Add TCP item to matcher and to the value. 8522 * 8523 * @param[in, out] matcher 8524 * Flow matcher. 8525 * @param[in, out] key 8526 * Flow matcher value. 8527 * @param[in] item 8528 * Flow pattern to translate. 8529 * @param[in] inner 8530 * Item is inner pattern. 8531 */ 8532 static void 8533 flow_dv_translate_item_tcp(void *matcher, void *key, 8534 const struct rte_flow_item *item, 8535 int inner) 8536 { 8537 const struct rte_flow_item_tcp *tcp_m = item->mask; 8538 const struct rte_flow_item_tcp *tcp_v = item->spec; 8539 void *headers_m; 8540 void *headers_v; 8541 8542 if (inner) { 8543 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8544 inner_headers); 8545 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8546 } else { 8547 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8548 outer_headers); 8549 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8550 } 8551 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8552 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP); 8553 if (!tcp_v) 8554 return; 8555 if (!tcp_m) 8556 tcp_m = &rte_flow_item_tcp_mask; 8557 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport, 8558 rte_be_to_cpu_16(tcp_m->hdr.src_port)); 8559 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, 8560 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port)); 8561 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport, 8562 rte_be_to_cpu_16(tcp_m->hdr.dst_port)); 8563 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, 8564 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port)); 8565 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags, 8566 tcp_m->hdr.tcp_flags); 8567 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, 8568 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags)); 8569 } 8570 8571 /** 8572 * Add UDP item to matcher and to the value. 8573 * 8574 * @param[in, out] matcher 8575 * Flow matcher. 8576 * @param[in, out] key 8577 * Flow matcher value. 8578 * @param[in] item 8579 * Flow pattern to translate. 8580 * @param[in] inner 8581 * Item is inner pattern. 8582 */ 8583 static void 8584 flow_dv_translate_item_udp(void *matcher, void *key, 8585 const struct rte_flow_item *item, 8586 int inner) 8587 { 8588 const struct rte_flow_item_udp *udp_m = item->mask; 8589 const struct rte_flow_item_udp *udp_v = item->spec; 8590 void *headers_m; 8591 void *headers_v; 8592 8593 if (inner) { 8594 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8595 inner_headers); 8596 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8597 } else { 8598 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8599 outer_headers); 8600 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8601 } 8602 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8603 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 8604 if (!udp_v) 8605 return; 8606 if (!udp_m) 8607 udp_m = &rte_flow_item_udp_mask; 8608 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport, 8609 rte_be_to_cpu_16(udp_m->hdr.src_port)); 8610 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, 8611 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port)); 8612 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 8613 rte_be_to_cpu_16(udp_m->hdr.dst_port)); 8614 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 8615 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port)); 8616 } 8617 8618 /** 8619 * Add GRE optional Key item to matcher and to the value. 8620 * 8621 * @param[in, out] matcher 8622 * Flow matcher. 8623 * @param[in, out] key 8624 * Flow matcher value. 8625 * @param[in] item 8626 * Flow pattern to translate. 8627 * @param[in] inner 8628 * Item is inner pattern. 8629 */ 8630 static void 8631 flow_dv_translate_item_gre_key(void *matcher, void *key, 8632 const struct rte_flow_item *item) 8633 { 8634 const rte_be32_t *key_m = item->mask; 8635 const rte_be32_t *key_v = item->spec; 8636 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8637 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8638 rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX); 8639 8640 /* GRE K bit must be on and should already be validated */ 8641 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1); 8642 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1); 8643 if (!key_v) 8644 return; 8645 if (!key_m) 8646 key_m = &gre_key_default_mask; 8647 MLX5_SET(fte_match_set_misc, misc_m, gre_key_h, 8648 rte_be_to_cpu_32(*key_m) >> 8); 8649 MLX5_SET(fte_match_set_misc, misc_v, gre_key_h, 8650 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8); 8651 MLX5_SET(fte_match_set_misc, misc_m, gre_key_l, 8652 rte_be_to_cpu_32(*key_m) & 0xFF); 8653 MLX5_SET(fte_match_set_misc, misc_v, gre_key_l, 8654 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF); 8655 } 8656 8657 /** 8658 * Add GRE item to matcher and to the value. 8659 * 8660 * @param[in, out] matcher 8661 * Flow matcher. 8662 * @param[in, out] key 8663 * Flow matcher value. 8664 * @param[in] item 8665 * Flow pattern to translate. 8666 * @param[in] inner 8667 * Item is inner pattern. 8668 */ 8669 static void 8670 flow_dv_translate_item_gre(void *matcher, void *key, 8671 const struct rte_flow_item *item, 8672 int inner) 8673 { 8674 const struct rte_flow_item_gre *gre_m = item->mask; 8675 const struct rte_flow_item_gre *gre_v = item->spec; 8676 void *headers_m; 8677 void *headers_v; 8678 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8679 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8680 struct { 8681 union { 8682 __extension__ 8683 struct { 8684 uint16_t version:3; 8685 uint16_t rsvd0:9; 8686 uint16_t s_present:1; 8687 uint16_t k_present:1; 8688 uint16_t rsvd_bit1:1; 8689 uint16_t c_present:1; 8690 }; 8691 uint16_t value; 8692 }; 8693 } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v; 8694 8695 if (inner) { 8696 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8697 inner_headers); 8698 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8699 } else { 8700 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8701 outer_headers); 8702 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8703 } 8704 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8705 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE); 8706 if (!gre_v) 8707 return; 8708 if (!gre_m) 8709 gre_m = &rte_flow_item_gre_mask; 8710 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 8711 rte_be_to_cpu_16(gre_m->protocol)); 8712 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 8713 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol)); 8714 gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver); 8715 gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver); 8716 MLX5_SET(fte_match_set_misc, misc_m, gre_c_present, 8717 gre_crks_rsvd0_ver_m.c_present); 8718 MLX5_SET(fte_match_set_misc, misc_v, gre_c_present, 8719 gre_crks_rsvd0_ver_v.c_present & 8720 gre_crks_rsvd0_ver_m.c_present); 8721 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 8722 gre_crks_rsvd0_ver_m.k_present); 8723 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 8724 gre_crks_rsvd0_ver_v.k_present & 8725 gre_crks_rsvd0_ver_m.k_present); 8726 MLX5_SET(fte_match_set_misc, misc_m, gre_s_present, 8727 gre_crks_rsvd0_ver_m.s_present); 8728 MLX5_SET(fte_match_set_misc, misc_v, gre_s_present, 8729 gre_crks_rsvd0_ver_v.s_present & 8730 gre_crks_rsvd0_ver_m.s_present); 8731 } 8732 8733 /** 8734 * Add NVGRE item to matcher and to the value. 8735 * 8736 * @param[in, out] matcher 8737 * Flow matcher. 8738 * @param[in, out] key 8739 * Flow matcher value. 8740 * @param[in] item 8741 * Flow pattern to translate. 8742 * @param[in] inner 8743 * Item is inner pattern. 8744 */ 8745 static void 8746 flow_dv_translate_item_nvgre(void *matcher, void *key, 8747 const struct rte_flow_item *item, 8748 int inner) 8749 { 8750 const struct rte_flow_item_nvgre *nvgre_m = item->mask; 8751 const struct rte_flow_item_nvgre *nvgre_v = item->spec; 8752 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8753 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8754 const char *tni_flow_id_m; 8755 const char *tni_flow_id_v; 8756 char *gre_key_m; 8757 char *gre_key_v; 8758 int size; 8759 int i; 8760 8761 /* For NVGRE, GRE header fields must be set with defined values. */ 8762 const struct rte_flow_item_gre gre_spec = { 8763 .c_rsvd0_ver = RTE_BE16(0x2000), 8764 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB) 8765 }; 8766 const struct rte_flow_item_gre gre_mask = { 8767 .c_rsvd0_ver = RTE_BE16(0xB000), 8768 .protocol = RTE_BE16(UINT16_MAX), 8769 }; 8770 const struct rte_flow_item gre_item = { 8771 .spec = &gre_spec, 8772 .mask = &gre_mask, 8773 .last = NULL, 8774 }; 8775 flow_dv_translate_item_gre(matcher, key, &gre_item, inner); 8776 if (!nvgre_v) 8777 return; 8778 if (!nvgre_m) 8779 nvgre_m = &rte_flow_item_nvgre_mask; 8780 tni_flow_id_m = (const char *)nvgre_m->tni; 8781 tni_flow_id_v = (const char *)nvgre_v->tni; 8782 size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id); 8783 gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h); 8784 gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h); 8785 memcpy(gre_key_m, tni_flow_id_m, size); 8786 for (i = 0; i < size; ++i) 8787 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i]; 8788 } 8789 8790 /** 8791 * Add VXLAN item to matcher and to the value. 8792 * 8793 * @param[in] dev 8794 * Pointer to the Ethernet device structure. 8795 * @param[in] attr 8796 * Flow rule attributes. 8797 * @param[in, out] matcher 8798 * Flow matcher. 8799 * @param[in, out] key 8800 * Flow matcher value. 8801 * @param[in] item 8802 * Flow pattern to translate. 8803 * @param[in] inner 8804 * Item is inner pattern. 8805 */ 8806 static void 8807 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, 8808 const struct rte_flow_attr *attr, 8809 void *matcher, void *key, 8810 const struct rte_flow_item *item, 8811 int inner) 8812 { 8813 const struct rte_flow_item_vxlan *vxlan_m = item->mask; 8814 const struct rte_flow_item_vxlan *vxlan_v = item->spec; 8815 void *headers_m; 8816 void *headers_v; 8817 void *misc5_m; 8818 void *misc5_v; 8819 uint32_t *tunnel_header_v; 8820 uint32_t *tunnel_header_m; 8821 uint16_t dport; 8822 struct mlx5_priv *priv = dev->data->dev_private; 8823 const struct rte_flow_item_vxlan nic_mask = { 8824 .vni = "\xff\xff\xff", 8825 .rsvd1 = 0xff, 8826 }; 8827 8828 if (inner) { 8829 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8830 inner_headers); 8831 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8832 } else { 8833 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8834 outer_headers); 8835 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8836 } 8837 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 8838 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 8839 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 8840 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 8841 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 8842 } 8843 dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport); 8844 if (!vxlan_v) 8845 return; 8846 if (!vxlan_m) { 8847 if ((!attr->group && !priv->sh->tunnel_header_0_1) || 8848 (attr->group && !priv->sh->misc5_cap)) 8849 vxlan_m = &rte_flow_item_vxlan_mask; 8850 else 8851 vxlan_m = &nic_mask; 8852 } 8853 if ((priv->sh->steering_format_version == 8854 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && 8855 dport != MLX5_UDP_PORT_VXLAN) || 8856 (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) || 8857 ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) { 8858 void *misc_m; 8859 void *misc_v; 8860 char *vni_m; 8861 char *vni_v; 8862 int size; 8863 int i; 8864 misc_m = MLX5_ADDR_OF(fte_match_param, 8865 matcher, misc_parameters); 8866 misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8867 size = sizeof(vxlan_m->vni); 8868 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni); 8869 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni); 8870 memcpy(vni_m, vxlan_m->vni, size); 8871 for (i = 0; i < size; ++i) 8872 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 8873 return; 8874 } 8875 misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5); 8876 misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5); 8877 tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8878 misc5_v, 8879 tunnel_header_1); 8880 tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8881 misc5_m, 8882 tunnel_header_1); 8883 *tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) | 8884 (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 | 8885 (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16; 8886 if (*tunnel_header_v) 8887 *tunnel_header_m = vxlan_m->vni[0] | 8888 vxlan_m->vni[1] << 8 | 8889 vxlan_m->vni[2] << 16; 8890 else 8891 *tunnel_header_m = 0x0; 8892 *tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24; 8893 if (vxlan_v->rsvd1 & vxlan_m->rsvd1) 8894 *tunnel_header_m |= vxlan_m->rsvd1 << 24; 8895 } 8896 8897 /** 8898 * Add VXLAN-GPE item to matcher and to the value. 8899 * 8900 * @param[in, out] matcher 8901 * Flow matcher. 8902 * @param[in, out] key 8903 * Flow matcher value. 8904 * @param[in] item 8905 * Flow pattern to translate. 8906 * @param[in] inner 8907 * Item is inner pattern. 8908 */ 8909 8910 static void 8911 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key, 8912 const struct rte_flow_item *item, int inner) 8913 { 8914 const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask; 8915 const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec; 8916 void *headers_m; 8917 void *headers_v; 8918 void *misc_m = 8919 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3); 8920 void *misc_v = 8921 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 8922 char *vni_m; 8923 char *vni_v; 8924 uint16_t dport; 8925 int size; 8926 int i; 8927 uint8_t flags_m = 0xff; 8928 uint8_t flags_v = 0xc; 8929 8930 if (inner) { 8931 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8932 inner_headers); 8933 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8934 } else { 8935 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8936 outer_headers); 8937 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8938 } 8939 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 8940 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 8941 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 8942 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 8943 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 8944 } 8945 if (!vxlan_v) 8946 return; 8947 if (!vxlan_m) 8948 vxlan_m = &rte_flow_item_vxlan_gpe_mask; 8949 size = sizeof(vxlan_m->vni); 8950 vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni); 8951 vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni); 8952 memcpy(vni_m, vxlan_m->vni, size); 8953 for (i = 0; i < size; ++i) 8954 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 8955 if (vxlan_m->flags) { 8956 flags_m = vxlan_m->flags; 8957 flags_v = vxlan_v->flags; 8958 } 8959 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m); 8960 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v); 8961 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol, 8962 vxlan_m->protocol); 8963 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol, 8964 vxlan_v->protocol); 8965 } 8966 8967 /** 8968 * Add Geneve item to matcher and to the value. 8969 * 8970 * @param[in, out] matcher 8971 * Flow matcher. 8972 * @param[in, out] key 8973 * Flow matcher value. 8974 * @param[in] item 8975 * Flow pattern to translate. 8976 * @param[in] inner 8977 * Item is inner pattern. 8978 */ 8979 8980 static void 8981 flow_dv_translate_item_geneve(void *matcher, void *key, 8982 const struct rte_flow_item *item, int inner) 8983 { 8984 const struct rte_flow_item_geneve *geneve_m = item->mask; 8985 const struct rte_flow_item_geneve *geneve_v = item->spec; 8986 void *headers_m; 8987 void *headers_v; 8988 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8989 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8990 uint16_t dport; 8991 uint16_t gbhdr_m; 8992 uint16_t gbhdr_v; 8993 char *vni_m; 8994 char *vni_v; 8995 size_t size, i; 8996 8997 if (inner) { 8998 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8999 inner_headers); 9000 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9001 } else { 9002 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9003 outer_headers); 9004 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9005 } 9006 dport = MLX5_UDP_PORT_GENEVE; 9007 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9008 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9009 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9010 } 9011 if (!geneve_v) 9012 return; 9013 if (!geneve_m) 9014 geneve_m = &rte_flow_item_geneve_mask; 9015 size = sizeof(geneve_m->vni); 9016 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni); 9017 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni); 9018 memcpy(vni_m, geneve_m->vni, size); 9019 for (i = 0; i < size; ++i) 9020 vni_v[i] = vni_m[i] & geneve_v->vni[i]; 9021 MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type, 9022 rte_be_to_cpu_16(geneve_m->protocol)); 9023 MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type, 9024 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol)); 9025 gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0); 9026 gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0); 9027 MLX5_SET(fte_match_set_misc, misc_m, geneve_oam, 9028 MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9029 MLX5_SET(fte_match_set_misc, misc_v, geneve_oam, 9030 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9031 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9032 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9033 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9034 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) & 9035 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9036 } 9037 9038 /** 9039 * Create Geneve TLV option resource. 9040 * 9041 * @param dev[in, out] 9042 * Pointer to rte_eth_dev structure. 9043 * @param[in, out] tag_be24 9044 * Tag value in big endian then R-shift 8. 9045 * @parm[in, out] dev_flow 9046 * Pointer to the dev_flow. 9047 * @param[out] error 9048 * pointer to error structure. 9049 * 9050 * @return 9051 * 0 on success otherwise -errno and errno is set. 9052 */ 9053 9054 int 9055 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev, 9056 const struct rte_flow_item *item, 9057 struct rte_flow_error *error) 9058 { 9059 struct mlx5_priv *priv = dev->data->dev_private; 9060 struct mlx5_dev_ctx_shared *sh = priv->sh; 9061 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 9062 sh->geneve_tlv_option_resource; 9063 struct mlx5_devx_obj *obj; 9064 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9065 int ret = 0; 9066 9067 if (!geneve_opt_v) 9068 return -1; 9069 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 9070 if (geneve_opt_resource != NULL) { 9071 if (geneve_opt_resource->option_class == 9072 geneve_opt_v->option_class && 9073 geneve_opt_resource->option_type == 9074 geneve_opt_v->option_type && 9075 geneve_opt_resource->length == 9076 geneve_opt_v->option_len) { 9077 /* We already have GENVE TLV option obj allocated. */ 9078 __atomic_fetch_add(&geneve_opt_resource->refcnt, 1, 9079 __ATOMIC_RELAXED); 9080 } else { 9081 ret = rte_flow_error_set(error, ENOMEM, 9082 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9083 "Only one GENEVE TLV option supported"); 9084 goto exit; 9085 } 9086 } else { 9087 /* Create a GENEVE TLV object and resource. */ 9088 obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx, 9089 geneve_opt_v->option_class, 9090 geneve_opt_v->option_type, 9091 geneve_opt_v->option_len); 9092 if (!obj) { 9093 ret = rte_flow_error_set(error, ENODATA, 9094 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9095 "Failed to create GENEVE TLV Devx object"); 9096 goto exit; 9097 } 9098 sh->geneve_tlv_option_resource = 9099 mlx5_malloc(MLX5_MEM_ZERO, 9100 sizeof(*geneve_opt_resource), 9101 0, SOCKET_ID_ANY); 9102 if (!sh->geneve_tlv_option_resource) { 9103 claim_zero(mlx5_devx_cmd_destroy(obj)); 9104 ret = rte_flow_error_set(error, ENOMEM, 9105 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9106 "GENEVE TLV object memory allocation failed"); 9107 goto exit; 9108 } 9109 geneve_opt_resource = sh->geneve_tlv_option_resource; 9110 geneve_opt_resource->obj = obj; 9111 geneve_opt_resource->option_class = geneve_opt_v->option_class; 9112 geneve_opt_resource->option_type = geneve_opt_v->option_type; 9113 geneve_opt_resource->length = geneve_opt_v->option_len; 9114 __atomic_store_n(&geneve_opt_resource->refcnt, 1, 9115 __ATOMIC_RELAXED); 9116 } 9117 exit: 9118 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 9119 return ret; 9120 } 9121 9122 /** 9123 * Add Geneve TLV option item to matcher. 9124 * 9125 * @param[in, out] dev 9126 * Pointer to rte_eth_dev structure. 9127 * @param[in, out] matcher 9128 * Flow matcher. 9129 * @param[in, out] key 9130 * Flow matcher value. 9131 * @param[in] item 9132 * Flow pattern to translate. 9133 * @param[out] error 9134 * Pointer to error structure. 9135 */ 9136 static int 9137 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher, 9138 void *key, const struct rte_flow_item *item, 9139 struct rte_flow_error *error) 9140 { 9141 const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask; 9142 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9143 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9144 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9145 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9146 misc_parameters_3); 9147 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9148 rte_be32_t opt_data_key = 0, opt_data_mask = 0; 9149 int ret = 0; 9150 9151 if (!geneve_opt_v) 9152 return -1; 9153 if (!geneve_opt_m) 9154 geneve_opt_m = &rte_flow_item_geneve_opt_mask; 9155 ret = flow_dev_geneve_tlv_option_resource_register(dev, item, 9156 error); 9157 if (ret) { 9158 DRV_LOG(ERR, "Failed to create geneve_tlv_obj"); 9159 return ret; 9160 } 9161 /* 9162 * Set the option length in GENEVE header if not requested. 9163 * The GENEVE TLV option length is expressed by the option length field 9164 * in the GENEVE header. 9165 * If the option length was not requested but the GENEVE TLV option item 9166 * is present we set the option length field implicitly. 9167 */ 9168 if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) { 9169 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9170 MLX5_GENEVE_OPTLEN_MASK); 9171 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9172 geneve_opt_v->option_len + 1); 9173 } 9174 MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1); 9175 MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1); 9176 /* Set the data. */ 9177 if (geneve_opt_v->data) { 9178 memcpy(&opt_data_key, geneve_opt_v->data, 9179 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9180 sizeof(opt_data_key))); 9181 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9182 sizeof(opt_data_key)); 9183 memcpy(&opt_data_mask, geneve_opt_m->data, 9184 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9185 sizeof(opt_data_mask))); 9186 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9187 sizeof(opt_data_mask)); 9188 MLX5_SET(fte_match_set_misc3, misc3_m, 9189 geneve_tlv_option_0_data, 9190 rte_be_to_cpu_32(opt_data_mask)); 9191 MLX5_SET(fte_match_set_misc3, misc3_v, 9192 geneve_tlv_option_0_data, 9193 rte_be_to_cpu_32(opt_data_key & opt_data_mask)); 9194 } 9195 return ret; 9196 } 9197 9198 /** 9199 * Add MPLS item to matcher and to the value. 9200 * 9201 * @param[in, out] matcher 9202 * Flow matcher. 9203 * @param[in, out] key 9204 * Flow matcher value. 9205 * @param[in] item 9206 * Flow pattern to translate. 9207 * @param[in] prev_layer 9208 * The protocol layer indicated in previous item. 9209 * @param[in] inner 9210 * Item is inner pattern. 9211 */ 9212 static void 9213 flow_dv_translate_item_mpls(void *matcher, void *key, 9214 const struct rte_flow_item *item, 9215 uint64_t prev_layer, 9216 int inner) 9217 { 9218 const uint32_t *in_mpls_m = item->mask; 9219 const uint32_t *in_mpls_v = item->spec; 9220 uint32_t *out_mpls_m = 0; 9221 uint32_t *out_mpls_v = 0; 9222 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9223 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9224 void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher, 9225 misc_parameters_2); 9226 void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9227 void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 9228 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9229 9230 switch (prev_layer) { 9231 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9232 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff); 9233 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9234 MLX5_UDP_PORT_MPLS); 9235 break; 9236 case MLX5_FLOW_LAYER_GRE: 9237 /* Fall-through. */ 9238 case MLX5_FLOW_LAYER_GRE_KEY: 9239 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff); 9240 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 9241 RTE_ETHER_TYPE_MPLS); 9242 break; 9243 default: 9244 break; 9245 } 9246 if (!in_mpls_v) 9247 return; 9248 if (!in_mpls_m) 9249 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask; 9250 switch (prev_layer) { 9251 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9252 out_mpls_m = 9253 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9254 outer_first_mpls_over_udp); 9255 out_mpls_v = 9256 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9257 outer_first_mpls_over_udp); 9258 break; 9259 case MLX5_FLOW_LAYER_GRE: 9260 out_mpls_m = 9261 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9262 outer_first_mpls_over_gre); 9263 out_mpls_v = 9264 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9265 outer_first_mpls_over_gre); 9266 break; 9267 default: 9268 /* Inner MPLS not over GRE is not supported. */ 9269 if (!inner) { 9270 out_mpls_m = 9271 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9272 misc2_m, 9273 outer_first_mpls); 9274 out_mpls_v = 9275 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9276 misc2_v, 9277 outer_first_mpls); 9278 } 9279 break; 9280 } 9281 if (out_mpls_m && out_mpls_v) { 9282 *out_mpls_m = *in_mpls_m; 9283 *out_mpls_v = *in_mpls_v & *in_mpls_m; 9284 } 9285 } 9286 9287 /** 9288 * Add metadata register item to matcher 9289 * 9290 * @param[in, out] matcher 9291 * Flow matcher. 9292 * @param[in, out] key 9293 * Flow matcher value. 9294 * @param[in] reg_type 9295 * Type of device metadata register 9296 * @param[in] value 9297 * Register value 9298 * @param[in] mask 9299 * Register mask 9300 */ 9301 static void 9302 flow_dv_match_meta_reg(void *matcher, void *key, 9303 enum modify_reg reg_type, 9304 uint32_t data, uint32_t mask) 9305 { 9306 void *misc2_m = 9307 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2); 9308 void *misc2_v = 9309 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9310 uint32_t temp; 9311 9312 data &= mask; 9313 switch (reg_type) { 9314 case REG_A: 9315 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask); 9316 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data); 9317 break; 9318 case REG_B: 9319 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask); 9320 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data); 9321 break; 9322 case REG_C_0: 9323 /* 9324 * The metadata register C0 field might be divided into 9325 * source vport index and META item value, we should set 9326 * this field according to specified mask, not as whole one. 9327 */ 9328 temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0); 9329 temp |= mask; 9330 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp); 9331 temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0); 9332 temp &= ~mask; 9333 temp |= data; 9334 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp); 9335 break; 9336 case REG_C_1: 9337 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask); 9338 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data); 9339 break; 9340 case REG_C_2: 9341 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask); 9342 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data); 9343 break; 9344 case REG_C_3: 9345 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask); 9346 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data); 9347 break; 9348 case REG_C_4: 9349 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask); 9350 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data); 9351 break; 9352 case REG_C_5: 9353 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask); 9354 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data); 9355 break; 9356 case REG_C_6: 9357 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask); 9358 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data); 9359 break; 9360 case REG_C_7: 9361 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask); 9362 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data); 9363 break; 9364 default: 9365 MLX5_ASSERT(false); 9366 break; 9367 } 9368 } 9369 9370 /** 9371 * Add MARK item to matcher 9372 * 9373 * @param[in] dev 9374 * The device to configure through. 9375 * @param[in, out] matcher 9376 * Flow matcher. 9377 * @param[in, out] key 9378 * Flow matcher value. 9379 * @param[in] item 9380 * Flow pattern to translate. 9381 */ 9382 static void 9383 flow_dv_translate_item_mark(struct rte_eth_dev *dev, 9384 void *matcher, void *key, 9385 const struct rte_flow_item *item) 9386 { 9387 struct mlx5_priv *priv = dev->data->dev_private; 9388 const struct rte_flow_item_mark *mark; 9389 uint32_t value; 9390 uint32_t mask; 9391 9392 mark = item->mask ? (const void *)item->mask : 9393 &rte_flow_item_mark_mask; 9394 mask = mark->id & priv->sh->dv_mark_mask; 9395 mark = (const void *)item->spec; 9396 MLX5_ASSERT(mark); 9397 value = mark->id & priv->sh->dv_mark_mask & mask; 9398 if (mask) { 9399 enum modify_reg reg; 9400 9401 /* Get the metadata register index for the mark. */ 9402 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL); 9403 MLX5_ASSERT(reg > 0); 9404 if (reg == REG_C_0) { 9405 struct mlx5_priv *priv = dev->data->dev_private; 9406 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9407 uint32_t shl_c0 = rte_bsf32(msk_c0); 9408 9409 mask &= msk_c0; 9410 mask <<= shl_c0; 9411 value <<= shl_c0; 9412 } 9413 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9414 } 9415 } 9416 9417 /** 9418 * Add META item to matcher 9419 * 9420 * @param[in] dev 9421 * The devich to configure through. 9422 * @param[in, out] matcher 9423 * Flow matcher. 9424 * @param[in, out] key 9425 * Flow matcher value. 9426 * @param[in] attr 9427 * Attributes of flow that includes this item. 9428 * @param[in] item 9429 * Flow pattern to translate. 9430 */ 9431 static void 9432 flow_dv_translate_item_meta(struct rte_eth_dev *dev, 9433 void *matcher, void *key, 9434 const struct rte_flow_attr *attr, 9435 const struct rte_flow_item *item) 9436 { 9437 const struct rte_flow_item_meta *meta_m; 9438 const struct rte_flow_item_meta *meta_v; 9439 9440 meta_m = (const void *)item->mask; 9441 if (!meta_m) 9442 meta_m = &rte_flow_item_meta_mask; 9443 meta_v = (const void *)item->spec; 9444 if (meta_v) { 9445 int reg; 9446 uint32_t value = meta_v->data; 9447 uint32_t mask = meta_m->data; 9448 9449 reg = flow_dv_get_metadata_reg(dev, attr, NULL); 9450 if (reg < 0) 9451 return; 9452 MLX5_ASSERT(reg != REG_NON); 9453 if (reg == REG_C_0) { 9454 struct mlx5_priv *priv = dev->data->dev_private; 9455 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9456 uint32_t shl_c0 = rte_bsf32(msk_c0); 9457 9458 mask &= msk_c0; 9459 mask <<= shl_c0; 9460 value <<= shl_c0; 9461 } 9462 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9463 } 9464 } 9465 9466 /** 9467 * Add vport metadata Reg C0 item to matcher 9468 * 9469 * @param[in, out] matcher 9470 * Flow matcher. 9471 * @param[in, out] key 9472 * Flow matcher value. 9473 * @param[in] reg 9474 * Flow pattern to translate. 9475 */ 9476 static void 9477 flow_dv_translate_item_meta_vport(void *matcher, void *key, 9478 uint32_t value, uint32_t mask) 9479 { 9480 flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask); 9481 } 9482 9483 /** 9484 * Add tag item to matcher 9485 * 9486 * @param[in] dev 9487 * The devich to configure through. 9488 * @param[in, out] matcher 9489 * Flow matcher. 9490 * @param[in, out] key 9491 * Flow matcher value. 9492 * @param[in] item 9493 * Flow pattern to translate. 9494 */ 9495 static void 9496 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev, 9497 void *matcher, void *key, 9498 const struct rte_flow_item *item) 9499 { 9500 const struct mlx5_rte_flow_item_tag *tag_v = item->spec; 9501 const struct mlx5_rte_flow_item_tag *tag_m = item->mask; 9502 uint32_t mask, value; 9503 9504 MLX5_ASSERT(tag_v); 9505 value = tag_v->data; 9506 mask = tag_m ? tag_m->data : UINT32_MAX; 9507 if (tag_v->id == REG_C_0) { 9508 struct mlx5_priv *priv = dev->data->dev_private; 9509 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9510 uint32_t shl_c0 = rte_bsf32(msk_c0); 9511 9512 mask &= msk_c0; 9513 mask <<= shl_c0; 9514 value <<= shl_c0; 9515 } 9516 flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask); 9517 } 9518 9519 /** 9520 * Add TAG item to matcher 9521 * 9522 * @param[in] dev 9523 * The devich to configure through. 9524 * @param[in, out] matcher 9525 * Flow matcher. 9526 * @param[in, out] key 9527 * Flow matcher value. 9528 * @param[in] item 9529 * Flow pattern to translate. 9530 */ 9531 static void 9532 flow_dv_translate_item_tag(struct rte_eth_dev *dev, 9533 void *matcher, void *key, 9534 const struct rte_flow_item *item) 9535 { 9536 const struct rte_flow_item_tag *tag_v = item->spec; 9537 const struct rte_flow_item_tag *tag_m = item->mask; 9538 enum modify_reg reg; 9539 9540 MLX5_ASSERT(tag_v); 9541 tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask; 9542 /* Get the metadata register index for the tag. */ 9543 reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL); 9544 MLX5_ASSERT(reg > 0); 9545 flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data); 9546 } 9547 9548 /** 9549 * Add source vport match to the specified matcher. 9550 * 9551 * @param[in, out] matcher 9552 * Flow matcher. 9553 * @param[in, out] key 9554 * Flow matcher value. 9555 * @param[in] port 9556 * Source vport value to match 9557 * @param[in] mask 9558 * Mask 9559 */ 9560 static void 9561 flow_dv_translate_item_source_vport(void *matcher, void *key, 9562 int16_t port, uint16_t mask) 9563 { 9564 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9565 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9566 9567 MLX5_SET(fte_match_set_misc, misc_m, source_port, mask); 9568 MLX5_SET(fte_match_set_misc, misc_v, source_port, port); 9569 } 9570 9571 /** 9572 * Translate port-id item to eswitch match on port-id. 9573 * 9574 * @param[in] dev 9575 * The devich to configure through. 9576 * @param[in, out] matcher 9577 * Flow matcher. 9578 * @param[in, out] key 9579 * Flow matcher value. 9580 * @param[in] item 9581 * Flow pattern to translate. 9582 * @param[in] 9583 * Flow attributes. 9584 * 9585 * @return 9586 * 0 on success, a negative errno value otherwise. 9587 */ 9588 static int 9589 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher, 9590 void *key, const struct rte_flow_item *item, 9591 const struct rte_flow_attr *attr) 9592 { 9593 const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL; 9594 const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL; 9595 struct mlx5_priv *priv; 9596 uint16_t mask, id; 9597 9598 if (pid_v && pid_v->id == MLX5_PORT_ESW_MGR) { 9599 flow_dv_translate_item_source_vport(matcher, key, 9600 flow_dv_get_esw_manager_vport_id(dev), 0xffff); 9601 return 0; 9602 } 9603 mask = pid_m ? pid_m->id : 0xffff; 9604 id = pid_v ? pid_v->id : dev->data->port_id; 9605 priv = mlx5_port_to_eswitch_info(id, item == NULL); 9606 if (!priv) 9607 return -rte_errno; 9608 /* 9609 * Translate to vport field or to metadata, depending on mode. 9610 * Kernel can use either misc.source_port or half of C0 metadata 9611 * register. 9612 */ 9613 if (priv->vport_meta_mask) { 9614 /* 9615 * Provide the hint for SW steering library 9616 * to insert the flow into ingress domain and 9617 * save the extra vport match. 9618 */ 9619 if (mask == 0xffff && priv->vport_id == 0xffff && 9620 priv->pf_bond < 0 && attr->transfer) 9621 flow_dv_translate_item_source_vport 9622 (matcher, key, priv->vport_id, mask); 9623 /* 9624 * We should always set the vport metadata register, 9625 * otherwise the SW steering library can drop 9626 * the rule if wire vport metadata value is not zero, 9627 * it depends on kernel configuration. 9628 */ 9629 flow_dv_translate_item_meta_vport(matcher, key, 9630 priv->vport_meta_tag, 9631 priv->vport_meta_mask); 9632 } else { 9633 flow_dv_translate_item_source_vport(matcher, key, 9634 priv->vport_id, mask); 9635 } 9636 return 0; 9637 } 9638 9639 /** 9640 * Add ICMP6 item to matcher and to the value. 9641 * 9642 * @param[in, out] matcher 9643 * Flow matcher. 9644 * @param[in, out] key 9645 * Flow matcher value. 9646 * @param[in] item 9647 * Flow pattern to translate. 9648 * @param[in] inner 9649 * Item is inner pattern. 9650 */ 9651 static void 9652 flow_dv_translate_item_icmp6(void *matcher, void *key, 9653 const struct rte_flow_item *item, 9654 int inner) 9655 { 9656 const struct rte_flow_item_icmp6 *icmp6_m = item->mask; 9657 const struct rte_flow_item_icmp6 *icmp6_v = item->spec; 9658 void *headers_m; 9659 void *headers_v; 9660 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9661 misc_parameters_3); 9662 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9663 if (inner) { 9664 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9665 inner_headers); 9666 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9667 } else { 9668 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9669 outer_headers); 9670 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9671 } 9672 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9673 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6); 9674 if (!icmp6_v) 9675 return; 9676 if (!icmp6_m) 9677 icmp6_m = &rte_flow_item_icmp6_mask; 9678 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type); 9679 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type, 9680 icmp6_v->type & icmp6_m->type); 9681 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code); 9682 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code, 9683 icmp6_v->code & icmp6_m->code); 9684 } 9685 9686 /** 9687 * Add ICMP item to matcher and to the value. 9688 * 9689 * @param[in, out] matcher 9690 * Flow matcher. 9691 * @param[in, out] key 9692 * Flow matcher value. 9693 * @param[in] item 9694 * Flow pattern to translate. 9695 * @param[in] inner 9696 * Item is inner pattern. 9697 */ 9698 static void 9699 flow_dv_translate_item_icmp(void *matcher, void *key, 9700 const struct rte_flow_item *item, 9701 int inner) 9702 { 9703 const struct rte_flow_item_icmp *icmp_m = item->mask; 9704 const struct rte_flow_item_icmp *icmp_v = item->spec; 9705 uint32_t icmp_header_data_m = 0; 9706 uint32_t icmp_header_data_v = 0; 9707 void *headers_m; 9708 void *headers_v; 9709 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9710 misc_parameters_3); 9711 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9712 if (inner) { 9713 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9714 inner_headers); 9715 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9716 } else { 9717 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9718 outer_headers); 9719 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9720 } 9721 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9722 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP); 9723 if (!icmp_v) 9724 return; 9725 if (!icmp_m) 9726 icmp_m = &rte_flow_item_icmp_mask; 9727 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type, 9728 icmp_m->hdr.icmp_type); 9729 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type, 9730 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type); 9731 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code, 9732 icmp_m->hdr.icmp_code); 9733 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code, 9734 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code); 9735 icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb); 9736 icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16; 9737 if (icmp_header_data_m) { 9738 icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb); 9739 icmp_header_data_v |= 9740 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16; 9741 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data, 9742 icmp_header_data_m); 9743 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data, 9744 icmp_header_data_v & icmp_header_data_m); 9745 } 9746 } 9747 9748 /** 9749 * Add GTP item to matcher and to the value. 9750 * 9751 * @param[in, out] matcher 9752 * Flow matcher. 9753 * @param[in, out] key 9754 * Flow matcher value. 9755 * @param[in] item 9756 * Flow pattern to translate. 9757 * @param[in] inner 9758 * Item is inner pattern. 9759 */ 9760 static void 9761 flow_dv_translate_item_gtp(void *matcher, void *key, 9762 const struct rte_flow_item *item, int inner) 9763 { 9764 const struct rte_flow_item_gtp *gtp_m = item->mask; 9765 const struct rte_flow_item_gtp *gtp_v = item->spec; 9766 void *headers_m; 9767 void *headers_v; 9768 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9769 misc_parameters_3); 9770 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9771 uint16_t dport = RTE_GTPU_UDP_PORT; 9772 9773 if (inner) { 9774 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9775 inner_headers); 9776 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9777 } else { 9778 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9779 outer_headers); 9780 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9781 } 9782 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9783 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9784 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9785 } 9786 if (!gtp_v) 9787 return; 9788 if (!gtp_m) 9789 gtp_m = &rte_flow_item_gtp_mask; 9790 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, 9791 gtp_m->v_pt_rsv_flags); 9792 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, 9793 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags); 9794 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type); 9795 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type, 9796 gtp_v->msg_type & gtp_m->msg_type); 9797 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid, 9798 rte_be_to_cpu_32(gtp_m->teid)); 9799 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid, 9800 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid)); 9801 } 9802 9803 /** 9804 * Add GTP PSC item to matcher. 9805 * 9806 * @param[in, out] matcher 9807 * Flow matcher. 9808 * @param[in, out] key 9809 * Flow matcher value. 9810 * @param[in] item 9811 * Flow pattern to translate. 9812 */ 9813 static int 9814 flow_dv_translate_item_gtp_psc(void *matcher, void *key, 9815 const struct rte_flow_item *item) 9816 { 9817 const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask; 9818 const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec; 9819 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9820 misc_parameters_3); 9821 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9822 union { 9823 uint32_t w32; 9824 struct { 9825 uint16_t seq_num; 9826 uint8_t npdu_num; 9827 uint8_t next_ext_header_type; 9828 }; 9829 } dw_2; 9830 uint8_t gtp_flags; 9831 9832 /* Always set E-flag match on one, regardless of GTP item settings. */ 9833 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags); 9834 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9835 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags); 9836 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags); 9837 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9838 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags); 9839 /*Set next extension header type. */ 9840 dw_2.seq_num = 0; 9841 dw_2.npdu_num = 0; 9842 dw_2.next_ext_header_type = 0xff; 9843 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2, 9844 rte_cpu_to_be_32(dw_2.w32)); 9845 dw_2.seq_num = 0; 9846 dw_2.npdu_num = 0; 9847 dw_2.next_ext_header_type = 0x85; 9848 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2, 9849 rte_cpu_to_be_32(dw_2.w32)); 9850 if (gtp_psc_v) { 9851 union { 9852 uint32_t w32; 9853 struct { 9854 uint8_t len; 9855 uint8_t type_flags; 9856 uint8_t qfi; 9857 uint8_t reserved; 9858 }; 9859 } dw_0; 9860 9861 /*Set extension header PDU type and Qos. */ 9862 if (!gtp_psc_m) 9863 gtp_psc_m = &rte_flow_item_gtp_psc_mask; 9864 dw_0.w32 = 0; 9865 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type); 9866 dw_0.qfi = gtp_psc_m->hdr.qfi; 9867 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0, 9868 rte_cpu_to_be_32(dw_0.w32)); 9869 dw_0.w32 = 0; 9870 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type & 9871 gtp_psc_m->hdr.type); 9872 dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi; 9873 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0, 9874 rte_cpu_to_be_32(dw_0.w32)); 9875 } 9876 return 0; 9877 } 9878 9879 /** 9880 * Add eCPRI item to matcher and to the value. 9881 * 9882 * @param[in] dev 9883 * The devich to configure through. 9884 * @param[in, out] matcher 9885 * Flow matcher. 9886 * @param[in, out] key 9887 * Flow matcher value. 9888 * @param[in] item 9889 * Flow pattern to translate. 9890 * @param[in] last_item 9891 * Last item flags. 9892 */ 9893 static void 9894 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher, 9895 void *key, const struct rte_flow_item *item, 9896 uint64_t last_item) 9897 { 9898 struct mlx5_priv *priv = dev->data->dev_private; 9899 const struct rte_flow_item_ecpri *ecpri_m = item->mask; 9900 const struct rte_flow_item_ecpri *ecpri_v = item->spec; 9901 struct rte_ecpri_common_hdr common; 9902 void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher, 9903 misc_parameters_4); 9904 void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4); 9905 uint32_t *samples; 9906 void *dw_m; 9907 void *dw_v; 9908 9909 /* 9910 * In case of eCPRI over Ethernet, if EtherType is not specified, 9911 * match on eCPRI EtherType implicitly. 9912 */ 9913 if (last_item & MLX5_FLOW_LAYER_OUTER_L2) { 9914 void *hdrs_m, *hdrs_v, *l2m, *l2v; 9915 9916 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 9917 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9918 l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype); 9919 l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 9920 if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) { 9921 *(uint16_t *)l2m = UINT16_MAX; 9922 *(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI); 9923 } 9924 } 9925 if (!ecpri_v) 9926 return; 9927 if (!ecpri_m) 9928 ecpri_m = &rte_flow_item_ecpri_mask; 9929 /* 9930 * Maximal four DW samples are supported in a single matching now. 9931 * Two are used now for a eCPRI matching: 9932 * 1. Type: one byte, mask should be 0x00ff0000 in network order 9933 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000 9934 * if any. 9935 */ 9936 if (!ecpri_m->hdr.common.u32) 9937 return; 9938 samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids; 9939 /* Need to take the whole DW as the mask to fill the entry. */ 9940 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 9941 prog_sample_field_value_0); 9942 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 9943 prog_sample_field_value_0); 9944 /* Already big endian (network order) in the header. */ 9945 *(uint32_t *)dw_m = ecpri_m->hdr.common.u32; 9946 *(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32; 9947 /* Sample#0, used for matching type, offset 0. */ 9948 MLX5_SET(fte_match_set_misc4, misc4_m, 9949 prog_sample_field_id_0, samples[0]); 9950 /* It makes no sense to set the sample ID in the mask field. */ 9951 MLX5_SET(fte_match_set_misc4, misc4_v, 9952 prog_sample_field_id_0, samples[0]); 9953 /* 9954 * Checking if message body part needs to be matched. 9955 * Some wildcard rules only matching type field should be supported. 9956 */ 9957 if (ecpri_m->hdr.dummy[0]) { 9958 common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32); 9959 switch (common.type) { 9960 case RTE_ECPRI_MSG_TYPE_IQ_DATA: 9961 case RTE_ECPRI_MSG_TYPE_RTC_CTRL: 9962 case RTE_ECPRI_MSG_TYPE_DLY_MSR: 9963 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 9964 prog_sample_field_value_1); 9965 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 9966 prog_sample_field_value_1); 9967 *(uint32_t *)dw_m = ecpri_m->hdr.dummy[0]; 9968 *(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] & 9969 ecpri_m->hdr.dummy[0]; 9970 /* Sample#1, to match message body, offset 4. */ 9971 MLX5_SET(fte_match_set_misc4, misc4_m, 9972 prog_sample_field_id_1, samples[1]); 9973 MLX5_SET(fte_match_set_misc4, misc4_v, 9974 prog_sample_field_id_1, samples[1]); 9975 break; 9976 default: 9977 /* Others, do not match any sample ID. */ 9978 break; 9979 } 9980 } 9981 } 9982 9983 /* 9984 * Add connection tracking status item to matcher 9985 * 9986 * @param[in] dev 9987 * The devich to configure through. 9988 * @param[in, out] matcher 9989 * Flow matcher. 9990 * @param[in, out] key 9991 * Flow matcher value. 9992 * @param[in] item 9993 * Flow pattern to translate. 9994 */ 9995 static void 9996 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev, 9997 void *matcher, void *key, 9998 const struct rte_flow_item *item) 9999 { 10000 uint32_t reg_value = 0; 10001 int reg_id; 10002 /* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */ 10003 uint32_t reg_mask = 0; 10004 const struct rte_flow_item_conntrack *spec = item->spec; 10005 const struct rte_flow_item_conntrack *mask = item->mask; 10006 uint32_t flags; 10007 struct rte_flow_error error; 10008 10009 if (!mask) 10010 mask = &rte_flow_item_conntrack_mask; 10011 if (!spec || !mask->flags) 10012 return; 10013 flags = spec->flags & mask->flags; 10014 /* The conflict should be checked in the validation. */ 10015 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) 10016 reg_value |= MLX5_CT_SYNDROME_VALID; 10017 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10018 reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE; 10019 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) 10020 reg_value |= MLX5_CT_SYNDROME_INVALID; 10021 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED) 10022 reg_value |= MLX5_CT_SYNDROME_TRAP; 10023 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10024 reg_value |= MLX5_CT_SYNDROME_BAD_PACKET; 10025 if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID | 10026 RTE_FLOW_CONNTRACK_PKT_STATE_INVALID | 10027 RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)) 10028 reg_mask |= 0xc0; 10029 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10030 reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE; 10031 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10032 reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET; 10033 /* The REG_C_x value could be saved during startup. */ 10034 reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error); 10035 if (reg_id == REG_NON) 10036 return; 10037 flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id, 10038 reg_value, reg_mask); 10039 } 10040 10041 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 }; 10042 10043 #define HEADER_IS_ZERO(match_criteria, headers) \ 10044 !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \ 10045 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \ 10046 10047 /** 10048 * Calculate flow matcher enable bitmap. 10049 * 10050 * @param match_criteria 10051 * Pointer to flow matcher criteria. 10052 * 10053 * @return 10054 * Bitmap of enabled fields. 10055 */ 10056 static uint8_t 10057 flow_dv_matcher_enable(uint32_t *match_criteria) 10058 { 10059 uint8_t match_criteria_enable; 10060 10061 match_criteria_enable = 10062 (!HEADER_IS_ZERO(match_criteria, outer_headers)) << 10063 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT; 10064 match_criteria_enable |= 10065 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) << 10066 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT; 10067 match_criteria_enable |= 10068 (!HEADER_IS_ZERO(match_criteria, inner_headers)) << 10069 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT; 10070 match_criteria_enable |= 10071 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) << 10072 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT; 10073 match_criteria_enable |= 10074 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) << 10075 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT; 10076 match_criteria_enable |= 10077 (!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) << 10078 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT; 10079 match_criteria_enable |= 10080 (!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) << 10081 MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT; 10082 return match_criteria_enable; 10083 } 10084 10085 static void 10086 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria) 10087 { 10088 /* 10089 * Check flow matching criteria first, subtract misc5/4 length if flow 10090 * doesn't own misc5/4 parameters. In some old rdma-core releases, 10091 * misc5/4 are not supported, and matcher creation failure is expected 10092 * w/o subtration. If misc5 is provided, misc4 must be counted in since 10093 * misc5 is right after misc4. 10094 */ 10095 if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) { 10096 *size = MLX5_ST_SZ_BYTES(fte_match_param) - 10097 MLX5_ST_SZ_BYTES(fte_match_set_misc5); 10098 if (!(match_criteria & (1 << 10099 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) { 10100 *size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4); 10101 } 10102 } 10103 } 10104 10105 static struct mlx5_list_entry * 10106 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused, 10107 struct mlx5_list_entry *entry, void *cb_ctx) 10108 { 10109 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10110 struct mlx5_flow_dv_matcher *ref = ctx->data; 10111 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10112 typeof(*tbl), tbl); 10113 struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY, 10114 sizeof(*resource), 10115 0, SOCKET_ID_ANY); 10116 10117 if (!resource) { 10118 rte_flow_error_set(ctx->error, ENOMEM, 10119 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10120 "cannot create matcher"); 10121 return NULL; 10122 } 10123 memcpy(resource, entry, sizeof(*resource)); 10124 resource->tbl = &tbl->tbl; 10125 return &resource->entry; 10126 } 10127 10128 static void 10129 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused, 10130 struct mlx5_list_entry *entry) 10131 { 10132 mlx5_free(entry); 10133 } 10134 10135 struct mlx5_list_entry * 10136 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx) 10137 { 10138 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10139 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10140 struct rte_eth_dev *dev = ctx->dev; 10141 struct mlx5_flow_tbl_data_entry *tbl_data; 10142 struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2; 10143 struct rte_flow_error *error = ctx->error; 10144 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10145 struct mlx5_flow_tbl_resource *tbl; 10146 void *domain; 10147 uint32_t idx = 0; 10148 int ret; 10149 10150 tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10151 if (!tbl_data) { 10152 rte_flow_error_set(error, ENOMEM, 10153 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10154 NULL, 10155 "cannot allocate flow table data entry"); 10156 return NULL; 10157 } 10158 tbl_data->idx = idx; 10159 tbl_data->tunnel = tt_prm->tunnel; 10160 tbl_data->group_id = tt_prm->group_id; 10161 tbl_data->external = !!tt_prm->external; 10162 tbl_data->tunnel_offload = is_tunnel_offload_active(dev); 10163 tbl_data->is_egress = !!key.is_egress; 10164 tbl_data->is_transfer = !!key.is_fdb; 10165 tbl_data->dummy = !!key.dummy; 10166 tbl_data->level = key.level; 10167 tbl_data->id = key.id; 10168 tbl = &tbl_data->tbl; 10169 if (key.dummy) 10170 return &tbl_data->entry; 10171 if (key.is_fdb) 10172 domain = sh->fdb_domain; 10173 else if (key.is_egress) 10174 domain = sh->tx_domain; 10175 else 10176 domain = sh->rx_domain; 10177 ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj); 10178 if (ret) { 10179 rte_flow_error_set(error, ENOMEM, 10180 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10181 NULL, "cannot create flow table object"); 10182 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10183 return NULL; 10184 } 10185 if (key.level != 0) { 10186 ret = mlx5_flow_os_create_flow_action_dest_flow_tbl 10187 (tbl->obj, &tbl_data->jump.action); 10188 if (ret) { 10189 rte_flow_error_set(error, ENOMEM, 10190 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10191 NULL, 10192 "cannot create flow jump action"); 10193 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10194 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10195 return NULL; 10196 } 10197 } 10198 MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list", 10199 key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress", 10200 key.level, key.id); 10201 tbl_data->matchers = mlx5_list_create(matcher_name, sh, true, 10202 flow_dv_matcher_create_cb, 10203 flow_dv_matcher_match_cb, 10204 flow_dv_matcher_remove_cb, 10205 flow_dv_matcher_clone_cb, 10206 flow_dv_matcher_clone_free_cb); 10207 if (!tbl_data->matchers) { 10208 rte_flow_error_set(error, ENOMEM, 10209 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10210 NULL, 10211 "cannot create tbl matcher list"); 10212 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10213 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10214 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10215 return NULL; 10216 } 10217 return &tbl_data->entry; 10218 } 10219 10220 int 10221 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10222 void *cb_ctx) 10223 { 10224 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10225 struct mlx5_flow_tbl_data_entry *tbl_data = 10226 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10227 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10228 10229 return tbl_data->level != key.level || 10230 tbl_data->id != key.id || 10231 tbl_data->dummy != key.dummy || 10232 tbl_data->is_transfer != !!key.is_fdb || 10233 tbl_data->is_egress != !!key.is_egress; 10234 } 10235 10236 struct mlx5_list_entry * 10237 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10238 void *cb_ctx) 10239 { 10240 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10241 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10242 struct mlx5_flow_tbl_data_entry *tbl_data; 10243 struct rte_flow_error *error = ctx->error; 10244 uint32_t idx = 0; 10245 10246 tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10247 if (!tbl_data) { 10248 rte_flow_error_set(error, ENOMEM, 10249 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10250 NULL, 10251 "cannot allocate flow table data entry"); 10252 return NULL; 10253 } 10254 memcpy(tbl_data, oentry, sizeof(*tbl_data)); 10255 tbl_data->idx = idx; 10256 return &tbl_data->entry; 10257 } 10258 10259 void 10260 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10261 { 10262 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10263 struct mlx5_flow_tbl_data_entry *tbl_data = 10264 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10265 10266 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10267 } 10268 10269 /** 10270 * Get a flow table. 10271 * 10272 * @param[in, out] dev 10273 * Pointer to rte_eth_dev structure. 10274 * @param[in] table_level 10275 * Table level to use. 10276 * @param[in] egress 10277 * Direction of the table. 10278 * @param[in] transfer 10279 * E-Switch or NIC flow. 10280 * @param[in] dummy 10281 * Dummy entry for dv API. 10282 * @param[in] table_id 10283 * Table id to use. 10284 * @param[out] error 10285 * pointer to error structure. 10286 * 10287 * @return 10288 * Returns tables resource based on the index, NULL in case of failed. 10289 */ 10290 struct mlx5_flow_tbl_resource * 10291 flow_dv_tbl_resource_get(struct rte_eth_dev *dev, 10292 uint32_t table_level, uint8_t egress, 10293 uint8_t transfer, 10294 bool external, 10295 const struct mlx5_flow_tunnel *tunnel, 10296 uint32_t group_id, uint8_t dummy, 10297 uint32_t table_id, 10298 struct rte_flow_error *error) 10299 { 10300 struct mlx5_priv *priv = dev->data->dev_private; 10301 union mlx5_flow_tbl_key table_key = { 10302 { 10303 .level = table_level, 10304 .id = table_id, 10305 .reserved = 0, 10306 .dummy = !!dummy, 10307 .is_fdb = !!transfer, 10308 .is_egress = !!egress, 10309 } 10310 }; 10311 struct mlx5_flow_tbl_tunnel_prm tt_prm = { 10312 .tunnel = tunnel, 10313 .group_id = group_id, 10314 .external = external, 10315 }; 10316 struct mlx5_flow_cb_ctx ctx = { 10317 .dev = dev, 10318 .error = error, 10319 .data = &table_key.v64, 10320 .data2 = &tt_prm, 10321 }; 10322 struct mlx5_list_entry *entry; 10323 struct mlx5_flow_tbl_data_entry *tbl_data; 10324 10325 entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx); 10326 if (!entry) { 10327 rte_flow_error_set(error, ENOMEM, 10328 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10329 "cannot get table"); 10330 return NULL; 10331 } 10332 DRV_LOG(DEBUG, "table_level %u table_id %u " 10333 "tunnel %u group %u registered.", 10334 table_level, table_id, 10335 tunnel ? tunnel->tunnel_id : 0, group_id); 10336 tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10337 return &tbl_data->tbl; 10338 } 10339 10340 void 10341 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10342 { 10343 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10344 struct mlx5_flow_tbl_data_entry *tbl_data = 10345 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10346 10347 MLX5_ASSERT(entry && sh); 10348 if (tbl_data->jump.action) 10349 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10350 if (tbl_data->tbl.obj) 10351 mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj); 10352 if (tbl_data->tunnel_offload && tbl_data->external) { 10353 struct mlx5_list_entry *he; 10354 struct mlx5_hlist *tunnel_grp_hash; 10355 struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub; 10356 union tunnel_tbl_key tunnel_key = { 10357 .tunnel_id = tbl_data->tunnel ? 10358 tbl_data->tunnel->tunnel_id : 0, 10359 .group = tbl_data->group_id 10360 }; 10361 uint32_t table_level = tbl_data->level; 10362 struct mlx5_flow_cb_ctx ctx = { 10363 .data = (void *)&tunnel_key.val, 10364 }; 10365 10366 tunnel_grp_hash = tbl_data->tunnel ? 10367 tbl_data->tunnel->groups : 10368 thub->groups; 10369 he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx); 10370 if (he) 10371 mlx5_hlist_unregister(tunnel_grp_hash, he); 10372 DRV_LOG(DEBUG, 10373 "table_level %u id %u tunnel %u group %u released.", 10374 table_level, 10375 tbl_data->id, 10376 tbl_data->tunnel ? 10377 tbl_data->tunnel->tunnel_id : 0, 10378 tbl_data->group_id); 10379 } 10380 mlx5_list_destroy(tbl_data->matchers); 10381 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10382 } 10383 10384 /** 10385 * Release a flow table. 10386 * 10387 * @param[in] sh 10388 * Pointer to device shared structure. 10389 * @param[in] tbl 10390 * Table resource to be released. 10391 * 10392 * @return 10393 * Returns 0 if table was released, else return 1; 10394 */ 10395 static int 10396 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 10397 struct mlx5_flow_tbl_resource *tbl) 10398 { 10399 struct mlx5_flow_tbl_data_entry *tbl_data = 10400 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10401 10402 if (!tbl) 10403 return 0; 10404 return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry); 10405 } 10406 10407 int 10408 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused, 10409 struct mlx5_list_entry *entry, void *cb_ctx) 10410 { 10411 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10412 struct mlx5_flow_dv_matcher *ref = ctx->data; 10413 struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur), 10414 entry); 10415 10416 return cur->crc != ref->crc || 10417 cur->priority != ref->priority || 10418 memcmp((const void *)cur->mask.buf, 10419 (const void *)ref->mask.buf, ref->mask.size); 10420 } 10421 10422 struct mlx5_list_entry * 10423 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx) 10424 { 10425 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10426 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10427 struct mlx5_flow_dv_matcher *ref = ctx->data; 10428 struct mlx5_flow_dv_matcher *resource; 10429 struct mlx5dv_flow_matcher_attr dv_attr = { 10430 .type = IBV_FLOW_ATTR_NORMAL, 10431 .match_mask = (void *)&ref->mask, 10432 }; 10433 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10434 typeof(*tbl), tbl); 10435 int ret; 10436 10437 resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0, 10438 SOCKET_ID_ANY); 10439 if (!resource) { 10440 rte_flow_error_set(ctx->error, ENOMEM, 10441 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10442 "cannot create matcher"); 10443 return NULL; 10444 } 10445 *resource = *ref; 10446 dv_attr.match_criteria_enable = 10447 flow_dv_matcher_enable(resource->mask.buf); 10448 __flow_dv_adjust_buf_size(&ref->mask.size, 10449 dv_attr.match_criteria_enable); 10450 dv_attr.priority = ref->priority; 10451 if (tbl->is_egress) 10452 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS; 10453 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 10454 tbl->tbl.obj, 10455 &resource->matcher_object); 10456 if (ret) { 10457 mlx5_free(resource); 10458 rte_flow_error_set(ctx->error, ENOMEM, 10459 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10460 "cannot create matcher"); 10461 return NULL; 10462 } 10463 return &resource->entry; 10464 } 10465 10466 /** 10467 * Register the flow matcher. 10468 * 10469 * @param[in, out] dev 10470 * Pointer to rte_eth_dev structure. 10471 * @param[in, out] matcher 10472 * Pointer to flow matcher. 10473 * @param[in, out] key 10474 * Pointer to flow table key. 10475 * @parm[in, out] dev_flow 10476 * Pointer to the dev_flow. 10477 * @param[out] error 10478 * pointer to error structure. 10479 * 10480 * @return 10481 * 0 on success otherwise -errno and errno is set. 10482 */ 10483 static int 10484 flow_dv_matcher_register(struct rte_eth_dev *dev, 10485 struct mlx5_flow_dv_matcher *ref, 10486 union mlx5_flow_tbl_key *key, 10487 struct mlx5_flow *dev_flow, 10488 const struct mlx5_flow_tunnel *tunnel, 10489 uint32_t group_id, 10490 struct rte_flow_error *error) 10491 { 10492 struct mlx5_list_entry *entry; 10493 struct mlx5_flow_dv_matcher *resource; 10494 struct mlx5_flow_tbl_resource *tbl; 10495 struct mlx5_flow_tbl_data_entry *tbl_data; 10496 struct mlx5_flow_cb_ctx ctx = { 10497 .error = error, 10498 .data = ref, 10499 }; 10500 /** 10501 * tunnel offload API requires this registration for cases when 10502 * tunnel match rule was inserted before tunnel set rule. 10503 */ 10504 tbl = flow_dv_tbl_resource_get(dev, key->level, 10505 key->is_egress, key->is_fdb, 10506 dev_flow->external, tunnel, 10507 group_id, 0, key->id, error); 10508 if (!tbl) 10509 return -rte_errno; /* No need to refill the error info */ 10510 tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10511 ref->tbl = tbl; 10512 entry = mlx5_list_register(tbl_data->matchers, &ctx); 10513 if (!entry) { 10514 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 10515 return rte_flow_error_set(error, ENOMEM, 10516 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10517 "cannot allocate ref memory"); 10518 } 10519 resource = container_of(entry, typeof(*resource), entry); 10520 dev_flow->handle->dvh.matcher = resource; 10521 return 0; 10522 } 10523 10524 struct mlx5_list_entry * 10525 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx) 10526 { 10527 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10528 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10529 struct mlx5_flow_dv_tag_resource *entry; 10530 uint32_t idx = 0; 10531 int ret; 10532 10533 entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10534 if (!entry) { 10535 rte_flow_error_set(ctx->error, ENOMEM, 10536 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10537 "cannot allocate resource memory"); 10538 return NULL; 10539 } 10540 entry->idx = idx; 10541 entry->tag_id = *(uint32_t *)(ctx->data); 10542 ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id, 10543 &entry->action); 10544 if (ret) { 10545 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx); 10546 rte_flow_error_set(ctx->error, ENOMEM, 10547 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10548 NULL, "cannot create action"); 10549 return NULL; 10550 } 10551 return &entry->entry; 10552 } 10553 10554 int 10555 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10556 void *cb_ctx) 10557 { 10558 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10559 struct mlx5_flow_dv_tag_resource *tag = 10560 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10561 10562 return *(uint32_t *)(ctx->data) != tag->tag_id; 10563 } 10564 10565 struct mlx5_list_entry * 10566 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10567 void *cb_ctx) 10568 { 10569 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10570 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10571 struct mlx5_flow_dv_tag_resource *entry; 10572 uint32_t idx = 0; 10573 10574 entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10575 if (!entry) { 10576 rte_flow_error_set(ctx->error, ENOMEM, 10577 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10578 "cannot allocate tag resource memory"); 10579 return NULL; 10580 } 10581 memcpy(entry, oentry, sizeof(*entry)); 10582 entry->idx = idx; 10583 return &entry->entry; 10584 } 10585 10586 void 10587 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10588 { 10589 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10590 struct mlx5_flow_dv_tag_resource *tag = 10591 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10592 10593 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10594 } 10595 10596 /** 10597 * Find existing tag resource or create and register a new one. 10598 * 10599 * @param dev[in, out] 10600 * Pointer to rte_eth_dev structure. 10601 * @param[in, out] tag_be24 10602 * Tag value in big endian then R-shift 8. 10603 * @parm[in, out] dev_flow 10604 * Pointer to the dev_flow. 10605 * @param[out] error 10606 * pointer to error structure. 10607 * 10608 * @return 10609 * 0 on success otherwise -errno and errno is set. 10610 */ 10611 static int 10612 flow_dv_tag_resource_register 10613 (struct rte_eth_dev *dev, 10614 uint32_t tag_be24, 10615 struct mlx5_flow *dev_flow, 10616 struct rte_flow_error *error) 10617 { 10618 struct mlx5_priv *priv = dev->data->dev_private; 10619 struct mlx5_flow_dv_tag_resource *resource; 10620 struct mlx5_list_entry *entry; 10621 struct mlx5_flow_cb_ctx ctx = { 10622 .error = error, 10623 .data = &tag_be24, 10624 }; 10625 struct mlx5_hlist *tag_table; 10626 10627 tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table, 10628 "tags", 10629 MLX5_TAGS_HLIST_ARRAY_SIZE, 10630 false, false, priv->sh, 10631 flow_dv_tag_create_cb, 10632 flow_dv_tag_match_cb, 10633 flow_dv_tag_remove_cb, 10634 flow_dv_tag_clone_cb, 10635 flow_dv_tag_clone_free_cb); 10636 if (unlikely(!tag_table)) 10637 return -rte_errno; 10638 entry = mlx5_hlist_register(tag_table, tag_be24, &ctx); 10639 if (entry) { 10640 resource = container_of(entry, struct mlx5_flow_dv_tag_resource, 10641 entry); 10642 dev_flow->handle->dvh.rix_tag = resource->idx; 10643 dev_flow->dv.tag_resource = resource; 10644 return 0; 10645 } 10646 return -rte_errno; 10647 } 10648 10649 void 10650 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10651 { 10652 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10653 struct mlx5_flow_dv_tag_resource *tag = 10654 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10655 10656 MLX5_ASSERT(tag && sh && tag->action); 10657 claim_zero(mlx5_flow_os_destroy_flow_action(tag->action)); 10658 DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag); 10659 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10660 } 10661 10662 /** 10663 * Release the tag. 10664 * 10665 * @param dev 10666 * Pointer to Ethernet device. 10667 * @param tag_idx 10668 * Tag index. 10669 * 10670 * @return 10671 * 1 while a reference on it exists, 0 when freed. 10672 */ 10673 static int 10674 flow_dv_tag_release(struct rte_eth_dev *dev, 10675 uint32_t tag_idx) 10676 { 10677 struct mlx5_priv *priv = dev->data->dev_private; 10678 struct mlx5_flow_dv_tag_resource *tag; 10679 10680 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx); 10681 if (!tag) 10682 return 0; 10683 DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--", 10684 dev->data->port_id, (void *)tag, tag->entry.ref_cnt); 10685 return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry); 10686 } 10687 10688 /** 10689 * Translate action PORT_ID / REPRESENTED_PORT to vport. 10690 * 10691 * @param[in] dev 10692 * Pointer to rte_eth_dev structure. 10693 * @param[in] action 10694 * Pointer to action PORT_ID / REPRESENTED_PORT. 10695 * @param[out] dst_port_id 10696 * The target port ID. 10697 * @param[out] error 10698 * Pointer to the error structure. 10699 * 10700 * @return 10701 * 0 on success, a negative errno value otherwise and rte_errno is set. 10702 */ 10703 static int 10704 flow_dv_translate_action_port_id(struct rte_eth_dev *dev, 10705 const struct rte_flow_action *action, 10706 uint32_t *dst_port_id, 10707 struct rte_flow_error *error) 10708 { 10709 uint32_t port; 10710 struct mlx5_priv *priv; 10711 10712 switch (action->type) { 10713 case RTE_FLOW_ACTION_TYPE_PORT_ID: { 10714 const struct rte_flow_action_port_id *conf; 10715 10716 conf = (const struct rte_flow_action_port_id *)action->conf; 10717 port = conf->original ? dev->data->port_id : conf->id; 10718 break; 10719 } 10720 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { 10721 const struct rte_flow_action_ethdev *ethdev; 10722 10723 ethdev = (const struct rte_flow_action_ethdev *)action->conf; 10724 port = ethdev->port_id; 10725 break; 10726 } 10727 default: 10728 MLX5_ASSERT(false); 10729 return rte_flow_error_set(error, EINVAL, 10730 RTE_FLOW_ERROR_TYPE_ACTION, action, 10731 "unknown E-Switch action"); 10732 } 10733 10734 priv = mlx5_port_to_eswitch_info(port, false); 10735 if (!priv) 10736 return rte_flow_error_set(error, -rte_errno, 10737 RTE_FLOW_ERROR_TYPE_ACTION, 10738 NULL, 10739 "No eswitch info was found for port"); 10740 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT 10741 /* 10742 * This parameter is transferred to 10743 * mlx5dv_dr_action_create_dest_ib_port(). 10744 */ 10745 *dst_port_id = priv->dev_port; 10746 #else 10747 /* 10748 * Legacy mode, no LAG configurations is supported. 10749 * This parameter is transferred to 10750 * mlx5dv_dr_action_create_dest_vport(). 10751 */ 10752 *dst_port_id = priv->vport_id; 10753 #endif 10754 return 0; 10755 } 10756 10757 /** 10758 * Create a counter with aging configuration. 10759 * 10760 * @param[in] dev 10761 * Pointer to rte_eth_dev structure. 10762 * @param[in] dev_flow 10763 * Pointer to the mlx5_flow. 10764 * @param[out] count 10765 * Pointer to the counter action configuration. 10766 * @param[in] age 10767 * Pointer to the aging action configuration. 10768 * 10769 * @return 10770 * Index to flow counter on success, 0 otherwise. 10771 */ 10772 static uint32_t 10773 flow_dv_translate_create_counter(struct rte_eth_dev *dev, 10774 struct mlx5_flow *dev_flow, 10775 const struct rte_flow_action_count *count 10776 __rte_unused, 10777 const struct rte_flow_action_age *age) 10778 { 10779 uint32_t counter; 10780 struct mlx5_age_param *age_param; 10781 10782 counter = flow_dv_counter_alloc(dev, !!age); 10783 if (!counter || age == NULL) 10784 return counter; 10785 age_param = flow_dv_counter_idx_get_age(dev, counter); 10786 age_param->context = age->context ? age->context : 10787 (void *)(uintptr_t)(dev_flow->flow_idx); 10788 age_param->timeout = age->timeout; 10789 age_param->port_id = dev->data->port_id; 10790 __atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED); 10791 __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED); 10792 return counter; 10793 } 10794 10795 /** 10796 * Add Tx queue matcher 10797 * 10798 * @param[in] dev 10799 * Pointer to the dev struct. 10800 * @param[in, out] matcher 10801 * Flow matcher. 10802 * @param[in, out] key 10803 * Flow matcher value. 10804 * @param[in] item 10805 * Flow pattern to translate. 10806 * @param[in] inner 10807 * Item is inner pattern. 10808 */ 10809 static void 10810 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev, 10811 void *matcher, void *key, 10812 const struct rte_flow_item *item) 10813 { 10814 const struct mlx5_rte_flow_item_tx_queue *queue_m; 10815 const struct mlx5_rte_flow_item_tx_queue *queue_v; 10816 void *misc_m = 10817 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 10818 void *misc_v = 10819 MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 10820 struct mlx5_txq_ctrl *txq; 10821 uint32_t queue, mask; 10822 10823 queue_m = (const void *)item->mask; 10824 queue_v = (const void *)item->spec; 10825 if (!queue_v) 10826 return; 10827 txq = mlx5_txq_get(dev, queue_v->queue); 10828 if (!txq) 10829 return; 10830 if (txq->type == MLX5_TXQ_TYPE_HAIRPIN) 10831 queue = txq->obj->sq->id; 10832 else 10833 queue = txq->obj->sq_obj.sq->id; 10834 mask = queue_m == NULL ? UINT32_MAX : queue_m->queue; 10835 MLX5_SET(fte_match_set_misc, misc_m, source_sqn, mask); 10836 MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue & mask); 10837 mlx5_txq_release(dev, queue_v->queue); 10838 } 10839 10840 /** 10841 * Set the hash fields according to the @p flow information. 10842 * 10843 * @param[in] dev_flow 10844 * Pointer to the mlx5_flow. 10845 * @param[in] rss_desc 10846 * Pointer to the mlx5_flow_rss_desc. 10847 */ 10848 static void 10849 flow_dv_hashfields_set(struct mlx5_flow *dev_flow, 10850 struct mlx5_flow_rss_desc *rss_desc) 10851 { 10852 uint64_t items = dev_flow->handle->layers; 10853 int rss_inner = 0; 10854 uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types); 10855 10856 dev_flow->hash_fields = 0; 10857 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT 10858 if (rss_desc->level >= 2) 10859 rss_inner = 1; 10860 #endif 10861 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || 10862 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { 10863 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 10864 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 10865 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4; 10866 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 10867 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4; 10868 else 10869 dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH; 10870 } 10871 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 10872 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) { 10873 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 10874 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 10875 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6; 10876 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 10877 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6; 10878 else 10879 dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH; 10880 } 10881 } 10882 if (dev_flow->hash_fields == 0) 10883 /* 10884 * There is no match between the RSS types and the 10885 * L3 protocol (IPv4/IPv6) defined in the flow rule. 10886 */ 10887 return; 10888 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || 10889 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { 10890 if (rss_types & RTE_ETH_RSS_UDP) { 10891 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 10892 dev_flow->hash_fields |= 10893 IBV_RX_HASH_SRC_PORT_UDP; 10894 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 10895 dev_flow->hash_fields |= 10896 IBV_RX_HASH_DST_PORT_UDP; 10897 else 10898 dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH; 10899 } 10900 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) || 10901 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) { 10902 if (rss_types & RTE_ETH_RSS_TCP) { 10903 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 10904 dev_flow->hash_fields |= 10905 IBV_RX_HASH_SRC_PORT_TCP; 10906 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 10907 dev_flow->hash_fields |= 10908 IBV_RX_HASH_DST_PORT_TCP; 10909 else 10910 dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH; 10911 } 10912 } 10913 if (rss_inner) 10914 dev_flow->hash_fields |= IBV_RX_HASH_INNER; 10915 } 10916 10917 /** 10918 * Prepare an Rx Hash queue. 10919 * 10920 * @param dev 10921 * Pointer to Ethernet device. 10922 * @param[in] dev_flow 10923 * Pointer to the mlx5_flow. 10924 * @param[in] rss_desc 10925 * Pointer to the mlx5_flow_rss_desc. 10926 * @param[out] hrxq_idx 10927 * Hash Rx queue index. 10928 * 10929 * @return 10930 * The Verbs/DevX object initialised, NULL otherwise and rte_errno is set. 10931 */ 10932 static struct mlx5_hrxq * 10933 flow_dv_hrxq_prepare(struct rte_eth_dev *dev, 10934 struct mlx5_flow *dev_flow, 10935 struct mlx5_flow_rss_desc *rss_desc, 10936 uint32_t *hrxq_idx) 10937 { 10938 struct mlx5_priv *priv = dev->data->dev_private; 10939 struct mlx5_flow_handle *dh = dev_flow->handle; 10940 struct mlx5_hrxq *hrxq; 10941 10942 MLX5_ASSERT(rss_desc->queue_num); 10943 rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN; 10944 rss_desc->hash_fields = dev_flow->hash_fields; 10945 rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL); 10946 rss_desc->shared_rss = 0; 10947 if (rss_desc->hash_fields == 0) 10948 rss_desc->queue_num = 1; 10949 *hrxq_idx = mlx5_hrxq_get(dev, rss_desc); 10950 if (!*hrxq_idx) 10951 return NULL; 10952 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 10953 *hrxq_idx); 10954 return hrxq; 10955 } 10956 10957 /** 10958 * Release sample sub action resource. 10959 * 10960 * @param[in, out] dev 10961 * Pointer to rte_eth_dev structure. 10962 * @param[in] act_res 10963 * Pointer to sample sub action resource. 10964 */ 10965 static void 10966 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev, 10967 struct mlx5_flow_sub_actions_idx *act_res) 10968 { 10969 if (act_res->rix_hrxq) { 10970 mlx5_hrxq_release(dev, act_res->rix_hrxq); 10971 act_res->rix_hrxq = 0; 10972 } 10973 if (act_res->rix_encap_decap) { 10974 flow_dv_encap_decap_resource_release(dev, 10975 act_res->rix_encap_decap); 10976 act_res->rix_encap_decap = 0; 10977 } 10978 if (act_res->rix_port_id_action) { 10979 flow_dv_port_id_action_resource_release(dev, 10980 act_res->rix_port_id_action); 10981 act_res->rix_port_id_action = 0; 10982 } 10983 if (act_res->rix_tag) { 10984 flow_dv_tag_release(dev, act_res->rix_tag); 10985 act_res->rix_tag = 0; 10986 } 10987 if (act_res->rix_jump) { 10988 flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump); 10989 act_res->rix_jump = 0; 10990 } 10991 } 10992 10993 int 10994 flow_dv_sample_match_cb(void *tool_ctx __rte_unused, 10995 struct mlx5_list_entry *entry, void *cb_ctx) 10996 { 10997 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10998 struct rte_eth_dev *dev = ctx->dev; 10999 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11000 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 11001 typeof(*resource), 11002 entry); 11003 11004 if (ctx_resource->ratio == resource->ratio && 11005 ctx_resource->ft_type == resource->ft_type && 11006 ctx_resource->ft_id == resource->ft_id && 11007 ctx_resource->set_action == resource->set_action && 11008 !memcmp((void *)&ctx_resource->sample_act, 11009 (void *)&resource->sample_act, 11010 sizeof(struct mlx5_flow_sub_actions_list))) { 11011 /* 11012 * Existing sample action should release the prepared 11013 * sub-actions reference counter. 11014 */ 11015 flow_dv_sample_sub_actions_release(dev, 11016 &ctx_resource->sample_idx); 11017 return 0; 11018 } 11019 return 1; 11020 } 11021 11022 struct mlx5_list_entry * 11023 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11024 { 11025 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11026 struct rte_eth_dev *dev = ctx->dev; 11027 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11028 void **sample_dv_actions = ctx_resource->sub_actions; 11029 struct mlx5_flow_dv_sample_resource *resource; 11030 struct mlx5dv_dr_flow_sampler_attr sampler_attr; 11031 struct mlx5_priv *priv = dev->data->dev_private; 11032 struct mlx5_dev_ctx_shared *sh = priv->sh; 11033 struct mlx5_flow_tbl_resource *tbl; 11034 uint32_t idx = 0; 11035 const uint32_t next_ft_step = 1; 11036 uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step; 11037 uint8_t is_egress = 0; 11038 uint8_t is_transfer = 0; 11039 struct rte_flow_error *error = ctx->error; 11040 11041 /* Register new sample resource. */ 11042 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11043 if (!resource) { 11044 rte_flow_error_set(error, ENOMEM, 11045 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11046 NULL, 11047 "cannot allocate resource memory"); 11048 return NULL; 11049 } 11050 *resource = *ctx_resource; 11051 /* Create normal path table level */ 11052 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11053 is_transfer = 1; 11054 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 11055 is_egress = 1; 11056 tbl = flow_dv_tbl_resource_get(dev, next_ft_id, 11057 is_egress, is_transfer, 11058 true, NULL, 0, 0, 0, error); 11059 if (!tbl) { 11060 rte_flow_error_set(error, ENOMEM, 11061 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11062 NULL, 11063 "fail to create normal path table " 11064 "for sample"); 11065 goto error; 11066 } 11067 resource->normal_path_tbl = tbl; 11068 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) { 11069 if (!sh->default_miss_action) { 11070 rte_flow_error_set(error, ENOMEM, 11071 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11072 NULL, 11073 "default miss action was not " 11074 "created"); 11075 goto error; 11076 } 11077 sample_dv_actions[ctx_resource->sample_act.actions_num++] = 11078 sh->default_miss_action; 11079 } 11080 /* Create a DR sample action */ 11081 sampler_attr.sample_ratio = resource->ratio; 11082 sampler_attr.default_next_table = tbl->obj; 11083 sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num; 11084 sampler_attr.sample_actions = (struct mlx5dv_dr_action **) 11085 &sample_dv_actions[0]; 11086 sampler_attr.action = resource->set_action; 11087 if (mlx5_os_flow_dr_create_flow_action_sampler 11088 (&sampler_attr, &resource->verbs_action)) { 11089 rte_flow_error_set(error, ENOMEM, 11090 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11091 NULL, "cannot create sample action"); 11092 goto error; 11093 } 11094 resource->idx = idx; 11095 resource->dev = dev; 11096 return &resource->entry; 11097 error: 11098 if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB) 11099 flow_dv_sample_sub_actions_release(dev, 11100 &resource->sample_idx); 11101 if (resource->normal_path_tbl) 11102 flow_dv_tbl_resource_release(MLX5_SH(dev), 11103 resource->normal_path_tbl); 11104 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx); 11105 return NULL; 11106 11107 } 11108 11109 struct mlx5_list_entry * 11110 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused, 11111 struct mlx5_list_entry *entry __rte_unused, 11112 void *cb_ctx) 11113 { 11114 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11115 struct rte_eth_dev *dev = ctx->dev; 11116 struct mlx5_flow_dv_sample_resource *resource; 11117 struct mlx5_priv *priv = dev->data->dev_private; 11118 struct mlx5_dev_ctx_shared *sh = priv->sh; 11119 uint32_t idx = 0; 11120 11121 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11122 if (!resource) { 11123 rte_flow_error_set(ctx->error, ENOMEM, 11124 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11125 NULL, 11126 "cannot allocate resource memory"); 11127 return NULL; 11128 } 11129 memcpy(resource, entry, sizeof(*resource)); 11130 resource->idx = idx; 11131 resource->dev = dev; 11132 return &resource->entry; 11133 } 11134 11135 void 11136 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused, 11137 struct mlx5_list_entry *entry) 11138 { 11139 struct mlx5_flow_dv_sample_resource *resource = 11140 container_of(entry, typeof(*resource), entry); 11141 struct rte_eth_dev *dev = resource->dev; 11142 struct mlx5_priv *priv = dev->data->dev_private; 11143 11144 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 11145 } 11146 11147 /** 11148 * Find existing sample resource or create and register a new one. 11149 * 11150 * @param[in, out] dev 11151 * Pointer to rte_eth_dev structure. 11152 * @param[in] ref 11153 * Pointer to sample resource reference. 11154 * @parm[in, out] dev_flow 11155 * Pointer to the dev_flow. 11156 * @param[out] error 11157 * pointer to error structure. 11158 * 11159 * @return 11160 * 0 on success otherwise -errno and errno is set. 11161 */ 11162 static int 11163 flow_dv_sample_resource_register(struct rte_eth_dev *dev, 11164 struct mlx5_flow_dv_sample_resource *ref, 11165 struct mlx5_flow *dev_flow, 11166 struct rte_flow_error *error) 11167 { 11168 struct mlx5_flow_dv_sample_resource *resource; 11169 struct mlx5_list_entry *entry; 11170 struct mlx5_priv *priv = dev->data->dev_private; 11171 struct mlx5_flow_cb_ctx ctx = { 11172 .dev = dev, 11173 .error = error, 11174 .data = ref, 11175 }; 11176 11177 entry = mlx5_list_register(priv->sh->sample_action_list, &ctx); 11178 if (!entry) 11179 return -rte_errno; 11180 resource = container_of(entry, typeof(*resource), entry); 11181 dev_flow->handle->dvh.rix_sample = resource->idx; 11182 dev_flow->dv.sample_res = resource; 11183 return 0; 11184 } 11185 11186 int 11187 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused, 11188 struct mlx5_list_entry *entry, void *cb_ctx) 11189 { 11190 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11191 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11192 struct rte_eth_dev *dev = ctx->dev; 11193 struct mlx5_flow_dv_dest_array_resource *resource = 11194 container_of(entry, typeof(*resource), entry); 11195 uint32_t idx = 0; 11196 11197 if (ctx_resource->num_of_dest == resource->num_of_dest && 11198 ctx_resource->ft_type == resource->ft_type && 11199 !memcmp((void *)resource->sample_act, 11200 (void *)ctx_resource->sample_act, 11201 (ctx_resource->num_of_dest * 11202 sizeof(struct mlx5_flow_sub_actions_list)))) { 11203 /* 11204 * Existing sample action should release the prepared 11205 * sub-actions reference counter. 11206 */ 11207 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11208 flow_dv_sample_sub_actions_release(dev, 11209 &ctx_resource->sample_idx[idx]); 11210 return 0; 11211 } 11212 return 1; 11213 } 11214 11215 struct mlx5_list_entry * 11216 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11217 { 11218 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11219 struct rte_eth_dev *dev = ctx->dev; 11220 struct mlx5_flow_dv_dest_array_resource *resource; 11221 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11222 struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 }; 11223 struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM]; 11224 struct mlx5_priv *priv = dev->data->dev_private; 11225 struct mlx5_dev_ctx_shared *sh = priv->sh; 11226 struct mlx5_flow_sub_actions_list *sample_act; 11227 struct mlx5dv_dr_domain *domain; 11228 uint32_t idx = 0, res_idx = 0; 11229 struct rte_flow_error *error = ctx->error; 11230 uint64_t action_flags; 11231 int ret; 11232 11233 /* Register new destination array resource. */ 11234 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11235 &res_idx); 11236 if (!resource) { 11237 rte_flow_error_set(error, ENOMEM, 11238 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11239 NULL, 11240 "cannot allocate resource memory"); 11241 return NULL; 11242 } 11243 *resource = *ctx_resource; 11244 if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11245 domain = sh->fdb_domain; 11246 else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 11247 domain = sh->rx_domain; 11248 else 11249 domain = sh->tx_domain; 11250 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11251 dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *) 11252 mlx5_malloc(MLX5_MEM_ZERO, 11253 sizeof(struct mlx5dv_dr_action_dest_attr), 11254 0, SOCKET_ID_ANY); 11255 if (!dest_attr[idx]) { 11256 rte_flow_error_set(error, ENOMEM, 11257 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11258 NULL, 11259 "cannot allocate resource memory"); 11260 goto error; 11261 } 11262 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST; 11263 sample_act = &ctx_resource->sample_act[idx]; 11264 action_flags = sample_act->action_flags; 11265 switch (action_flags) { 11266 case MLX5_FLOW_ACTION_QUEUE: 11267 dest_attr[idx]->dest = sample_act->dr_queue_action; 11268 break; 11269 case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP): 11270 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT; 11271 dest_attr[idx]->dest_reformat = &dest_reformat[idx]; 11272 dest_attr[idx]->dest_reformat->reformat = 11273 sample_act->dr_encap_action; 11274 dest_attr[idx]->dest_reformat->dest = 11275 sample_act->dr_port_id_action; 11276 break; 11277 case MLX5_FLOW_ACTION_PORT_ID: 11278 dest_attr[idx]->dest = sample_act->dr_port_id_action; 11279 break; 11280 case MLX5_FLOW_ACTION_JUMP: 11281 dest_attr[idx]->dest = sample_act->dr_jump_action; 11282 break; 11283 default: 11284 rte_flow_error_set(error, EINVAL, 11285 RTE_FLOW_ERROR_TYPE_ACTION, 11286 NULL, 11287 "unsupported actions type"); 11288 goto error; 11289 } 11290 } 11291 /* create a dest array actioin */ 11292 ret = mlx5_os_flow_dr_create_flow_action_dest_array 11293 (domain, 11294 resource->num_of_dest, 11295 dest_attr, 11296 &resource->action); 11297 if (ret) { 11298 rte_flow_error_set(error, ENOMEM, 11299 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11300 NULL, 11301 "cannot create destination array action"); 11302 goto error; 11303 } 11304 resource->idx = res_idx; 11305 resource->dev = dev; 11306 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11307 mlx5_free(dest_attr[idx]); 11308 return &resource->entry; 11309 error: 11310 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11311 flow_dv_sample_sub_actions_release(dev, 11312 &resource->sample_idx[idx]); 11313 if (dest_attr[idx]) 11314 mlx5_free(dest_attr[idx]); 11315 } 11316 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx); 11317 return NULL; 11318 } 11319 11320 struct mlx5_list_entry * 11321 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused, 11322 struct mlx5_list_entry *entry __rte_unused, 11323 void *cb_ctx) 11324 { 11325 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11326 struct rte_eth_dev *dev = ctx->dev; 11327 struct mlx5_flow_dv_dest_array_resource *resource; 11328 struct mlx5_priv *priv = dev->data->dev_private; 11329 struct mlx5_dev_ctx_shared *sh = priv->sh; 11330 uint32_t res_idx = 0; 11331 struct rte_flow_error *error = ctx->error; 11332 11333 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11334 &res_idx); 11335 if (!resource) { 11336 rte_flow_error_set(error, ENOMEM, 11337 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11338 NULL, 11339 "cannot allocate dest-array memory"); 11340 return NULL; 11341 } 11342 memcpy(resource, entry, sizeof(*resource)); 11343 resource->idx = res_idx; 11344 resource->dev = dev; 11345 return &resource->entry; 11346 } 11347 11348 void 11349 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused, 11350 struct mlx5_list_entry *entry) 11351 { 11352 struct mlx5_flow_dv_dest_array_resource *resource = 11353 container_of(entry, typeof(*resource), entry); 11354 struct rte_eth_dev *dev = resource->dev; 11355 struct mlx5_priv *priv = dev->data->dev_private; 11356 11357 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 11358 } 11359 11360 /** 11361 * Find existing destination array resource or create and register a new one. 11362 * 11363 * @param[in, out] dev 11364 * Pointer to rte_eth_dev structure. 11365 * @param[in] ref 11366 * Pointer to destination array resource reference. 11367 * @parm[in, out] dev_flow 11368 * Pointer to the dev_flow. 11369 * @param[out] error 11370 * pointer to error structure. 11371 * 11372 * @return 11373 * 0 on success otherwise -errno and errno is set. 11374 */ 11375 static int 11376 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev, 11377 struct mlx5_flow_dv_dest_array_resource *ref, 11378 struct mlx5_flow *dev_flow, 11379 struct rte_flow_error *error) 11380 { 11381 struct mlx5_flow_dv_dest_array_resource *resource; 11382 struct mlx5_priv *priv = dev->data->dev_private; 11383 struct mlx5_list_entry *entry; 11384 struct mlx5_flow_cb_ctx ctx = { 11385 .dev = dev, 11386 .error = error, 11387 .data = ref, 11388 }; 11389 11390 entry = mlx5_list_register(priv->sh->dest_array_list, &ctx); 11391 if (!entry) 11392 return -rte_errno; 11393 resource = container_of(entry, typeof(*resource), entry); 11394 dev_flow->handle->dvh.rix_dest_array = resource->idx; 11395 dev_flow->dv.dest_array_res = resource; 11396 return 0; 11397 } 11398 11399 /** 11400 * Convert Sample action to DV specification. 11401 * 11402 * @param[in] dev 11403 * Pointer to rte_eth_dev structure. 11404 * @param[in] action 11405 * Pointer to sample action structure. 11406 * @param[in, out] dev_flow 11407 * Pointer to the mlx5_flow. 11408 * @param[in] attr 11409 * Pointer to the flow attributes. 11410 * @param[in, out] num_of_dest 11411 * Pointer to the num of destination. 11412 * @param[in, out] sample_actions 11413 * Pointer to sample actions list. 11414 * @param[in, out] res 11415 * Pointer to sample resource. 11416 * @param[out] error 11417 * Pointer to the error structure. 11418 * 11419 * @return 11420 * 0 on success, a negative errno value otherwise and rte_errno is set. 11421 */ 11422 static int 11423 flow_dv_translate_action_sample(struct rte_eth_dev *dev, 11424 const struct rte_flow_action_sample *action, 11425 struct mlx5_flow *dev_flow, 11426 const struct rte_flow_attr *attr, 11427 uint32_t *num_of_dest, 11428 void **sample_actions, 11429 struct mlx5_flow_dv_sample_resource *res, 11430 struct rte_flow_error *error) 11431 { 11432 struct mlx5_priv *priv = dev->data->dev_private; 11433 const struct rte_flow_action *sub_actions; 11434 struct mlx5_flow_sub_actions_list *sample_act; 11435 struct mlx5_flow_sub_actions_idx *sample_idx; 11436 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11437 struct rte_flow *flow = dev_flow->flow; 11438 struct mlx5_flow_rss_desc *rss_desc; 11439 uint64_t action_flags = 0; 11440 11441 MLX5_ASSERT(wks); 11442 rss_desc = &wks->rss_desc; 11443 sample_act = &res->sample_act; 11444 sample_idx = &res->sample_idx; 11445 res->ratio = action->ratio; 11446 sub_actions = action->actions; 11447 for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) { 11448 int type = sub_actions->type; 11449 uint32_t pre_rix = 0; 11450 void *pre_r; 11451 switch (type) { 11452 case RTE_FLOW_ACTION_TYPE_QUEUE: 11453 { 11454 const struct rte_flow_action_queue *queue; 11455 struct mlx5_hrxq *hrxq; 11456 uint32_t hrxq_idx; 11457 11458 queue = sub_actions->conf; 11459 rss_desc->queue_num = 1; 11460 rss_desc->queue[0] = queue->index; 11461 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11462 rss_desc, &hrxq_idx); 11463 if (!hrxq) 11464 return rte_flow_error_set 11465 (error, rte_errno, 11466 RTE_FLOW_ERROR_TYPE_ACTION, 11467 NULL, 11468 "cannot create fate queue"); 11469 sample_act->dr_queue_action = hrxq->action; 11470 sample_idx->rix_hrxq = hrxq_idx; 11471 sample_actions[sample_act->actions_num++] = 11472 hrxq->action; 11473 (*num_of_dest)++; 11474 action_flags |= MLX5_FLOW_ACTION_QUEUE; 11475 if (action_flags & MLX5_FLOW_ACTION_MARK) 11476 dev_flow->handle->rix_hrxq = hrxq_idx; 11477 dev_flow->handle->fate_action = 11478 MLX5_FLOW_FATE_QUEUE; 11479 break; 11480 } 11481 case RTE_FLOW_ACTION_TYPE_RSS: 11482 { 11483 struct mlx5_hrxq *hrxq; 11484 uint32_t hrxq_idx; 11485 const struct rte_flow_action_rss *rss; 11486 const uint8_t *rss_key; 11487 11488 rss = sub_actions->conf; 11489 memcpy(rss_desc->queue, rss->queue, 11490 rss->queue_num * sizeof(uint16_t)); 11491 rss_desc->queue_num = rss->queue_num; 11492 /* NULL RSS key indicates default RSS key. */ 11493 rss_key = !rss->key ? rss_hash_default_key : rss->key; 11494 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 11495 /* 11496 * rss->level and rss.types should be set in advance 11497 * when expanding items for RSS. 11498 */ 11499 flow_dv_hashfields_set(dev_flow, rss_desc); 11500 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11501 rss_desc, &hrxq_idx); 11502 if (!hrxq) 11503 return rte_flow_error_set 11504 (error, rte_errno, 11505 RTE_FLOW_ERROR_TYPE_ACTION, 11506 NULL, 11507 "cannot create fate queue"); 11508 sample_act->dr_queue_action = hrxq->action; 11509 sample_idx->rix_hrxq = hrxq_idx; 11510 sample_actions[sample_act->actions_num++] = 11511 hrxq->action; 11512 (*num_of_dest)++; 11513 action_flags |= MLX5_FLOW_ACTION_RSS; 11514 if (action_flags & MLX5_FLOW_ACTION_MARK) 11515 dev_flow->handle->rix_hrxq = hrxq_idx; 11516 dev_flow->handle->fate_action = 11517 MLX5_FLOW_FATE_QUEUE; 11518 break; 11519 } 11520 case RTE_FLOW_ACTION_TYPE_MARK: 11521 { 11522 uint32_t tag_be = mlx5_flow_mark_set 11523 (((const struct rte_flow_action_mark *) 11524 (sub_actions->conf))->id); 11525 11526 dev_flow->handle->mark = 1; 11527 pre_rix = dev_flow->handle->dvh.rix_tag; 11528 /* Save the mark resource before sample */ 11529 pre_r = dev_flow->dv.tag_resource; 11530 if (flow_dv_tag_resource_register(dev, tag_be, 11531 dev_flow, error)) 11532 return -rte_errno; 11533 MLX5_ASSERT(dev_flow->dv.tag_resource); 11534 sample_act->dr_tag_action = 11535 dev_flow->dv.tag_resource->action; 11536 sample_idx->rix_tag = 11537 dev_flow->handle->dvh.rix_tag; 11538 sample_actions[sample_act->actions_num++] = 11539 sample_act->dr_tag_action; 11540 /* Recover the mark resource after sample */ 11541 dev_flow->dv.tag_resource = pre_r; 11542 dev_flow->handle->dvh.rix_tag = pre_rix; 11543 action_flags |= MLX5_FLOW_ACTION_MARK; 11544 break; 11545 } 11546 case RTE_FLOW_ACTION_TYPE_COUNT: 11547 { 11548 if (!flow->counter) { 11549 flow->counter = 11550 flow_dv_translate_create_counter(dev, 11551 dev_flow, sub_actions->conf, 11552 0); 11553 if (!flow->counter) 11554 return rte_flow_error_set 11555 (error, rte_errno, 11556 RTE_FLOW_ERROR_TYPE_ACTION, 11557 NULL, 11558 "cannot create counter" 11559 " object."); 11560 } 11561 sample_act->dr_cnt_action = 11562 (flow_dv_counter_get_by_idx(dev, 11563 flow->counter, NULL))->action; 11564 sample_actions[sample_act->actions_num++] = 11565 sample_act->dr_cnt_action; 11566 action_flags |= MLX5_FLOW_ACTION_COUNT; 11567 break; 11568 } 11569 case RTE_FLOW_ACTION_TYPE_PORT_ID: 11570 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 11571 { 11572 struct mlx5_flow_dv_port_id_action_resource 11573 port_id_resource; 11574 uint32_t port_id = 0; 11575 11576 memset(&port_id_resource, 0, sizeof(port_id_resource)); 11577 /* Save the port id resource before sample */ 11578 pre_rix = dev_flow->handle->rix_port_id_action; 11579 pre_r = dev_flow->dv.port_id_action; 11580 if (flow_dv_translate_action_port_id(dev, sub_actions, 11581 &port_id, error)) 11582 return -rte_errno; 11583 port_id_resource.port_id = port_id; 11584 if (flow_dv_port_id_action_resource_register 11585 (dev, &port_id_resource, dev_flow, error)) 11586 return -rte_errno; 11587 sample_act->dr_port_id_action = 11588 dev_flow->dv.port_id_action->action; 11589 sample_idx->rix_port_id_action = 11590 dev_flow->handle->rix_port_id_action; 11591 sample_actions[sample_act->actions_num++] = 11592 sample_act->dr_port_id_action; 11593 /* Recover the port id resource after sample */ 11594 dev_flow->dv.port_id_action = pre_r; 11595 dev_flow->handle->rix_port_id_action = pre_rix; 11596 (*num_of_dest)++; 11597 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 11598 break; 11599 } 11600 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 11601 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 11602 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 11603 /* Save the encap resource before sample */ 11604 pre_rix = dev_flow->handle->dvh.rix_encap_decap; 11605 pre_r = dev_flow->dv.encap_decap; 11606 if (flow_dv_create_action_l2_encap(dev, sub_actions, 11607 dev_flow, 11608 attr->transfer, 11609 error)) 11610 return -rte_errno; 11611 sample_act->dr_encap_action = 11612 dev_flow->dv.encap_decap->action; 11613 sample_idx->rix_encap_decap = 11614 dev_flow->handle->dvh.rix_encap_decap; 11615 sample_actions[sample_act->actions_num++] = 11616 sample_act->dr_encap_action; 11617 /* Recover the encap resource after sample */ 11618 dev_flow->dv.encap_decap = pre_r; 11619 dev_flow->handle->dvh.rix_encap_decap = pre_rix; 11620 action_flags |= MLX5_FLOW_ACTION_ENCAP; 11621 break; 11622 default: 11623 return rte_flow_error_set(error, EINVAL, 11624 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11625 NULL, 11626 "Not support for sampler action"); 11627 } 11628 } 11629 sample_act->action_flags = action_flags; 11630 res->ft_id = dev_flow->dv.group; 11631 if (attr->transfer) { 11632 union { 11633 uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)]; 11634 uint64_t set_action; 11635 } action_ctx = { .set_action = 0 }; 11636 11637 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 11638 MLX5_SET(set_action_in, action_ctx.action_in, action_type, 11639 MLX5_MODIFICATION_TYPE_SET); 11640 MLX5_SET(set_action_in, action_ctx.action_in, field, 11641 MLX5_MODI_META_REG_C_0); 11642 MLX5_SET(set_action_in, action_ctx.action_in, data, 11643 priv->vport_meta_tag); 11644 res->set_action = action_ctx.set_action; 11645 } else if (attr->ingress) { 11646 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 11647 } else { 11648 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 11649 } 11650 return 0; 11651 } 11652 11653 /** 11654 * Convert Sample action to DV specification. 11655 * 11656 * @param[in] dev 11657 * Pointer to rte_eth_dev structure. 11658 * @param[in, out] dev_flow 11659 * Pointer to the mlx5_flow. 11660 * @param[in] num_of_dest 11661 * The num of destination. 11662 * @param[in, out] res 11663 * Pointer to sample resource. 11664 * @param[in, out] mdest_res 11665 * Pointer to destination array resource. 11666 * @param[in] sample_actions 11667 * Pointer to sample path actions list. 11668 * @param[in] action_flags 11669 * Holds the actions detected until now. 11670 * @param[out] error 11671 * Pointer to the error structure. 11672 * 11673 * @return 11674 * 0 on success, a negative errno value otherwise and rte_errno is set. 11675 */ 11676 static int 11677 flow_dv_create_action_sample(struct rte_eth_dev *dev, 11678 struct mlx5_flow *dev_flow, 11679 uint32_t num_of_dest, 11680 struct mlx5_flow_dv_sample_resource *res, 11681 struct mlx5_flow_dv_dest_array_resource *mdest_res, 11682 void **sample_actions, 11683 uint64_t action_flags, 11684 struct rte_flow_error *error) 11685 { 11686 /* update normal path action resource into last index of array */ 11687 uint32_t dest_index = MLX5_MAX_DEST_NUM - 1; 11688 struct mlx5_flow_sub_actions_list *sample_act = 11689 &mdest_res->sample_act[dest_index]; 11690 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11691 struct mlx5_flow_rss_desc *rss_desc; 11692 uint32_t normal_idx = 0; 11693 struct mlx5_hrxq *hrxq; 11694 uint32_t hrxq_idx; 11695 11696 MLX5_ASSERT(wks); 11697 rss_desc = &wks->rss_desc; 11698 if (num_of_dest > 1) { 11699 if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) { 11700 /* Handle QP action for mirroring */ 11701 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11702 rss_desc, &hrxq_idx); 11703 if (!hrxq) 11704 return rte_flow_error_set 11705 (error, rte_errno, 11706 RTE_FLOW_ERROR_TYPE_ACTION, 11707 NULL, 11708 "cannot create rx queue"); 11709 normal_idx++; 11710 mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx; 11711 sample_act->dr_queue_action = hrxq->action; 11712 if (action_flags & MLX5_FLOW_ACTION_MARK) 11713 dev_flow->handle->rix_hrxq = hrxq_idx; 11714 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 11715 } 11716 if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) { 11717 normal_idx++; 11718 mdest_res->sample_idx[dest_index].rix_encap_decap = 11719 dev_flow->handle->dvh.rix_encap_decap; 11720 sample_act->dr_encap_action = 11721 dev_flow->dv.encap_decap->action; 11722 dev_flow->handle->dvh.rix_encap_decap = 0; 11723 } 11724 if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) { 11725 normal_idx++; 11726 mdest_res->sample_idx[dest_index].rix_port_id_action = 11727 dev_flow->handle->rix_port_id_action; 11728 sample_act->dr_port_id_action = 11729 dev_flow->dv.port_id_action->action; 11730 dev_flow->handle->rix_port_id_action = 0; 11731 } 11732 if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) { 11733 normal_idx++; 11734 mdest_res->sample_idx[dest_index].rix_jump = 11735 dev_flow->handle->rix_jump; 11736 sample_act->dr_jump_action = 11737 dev_flow->dv.jump->action; 11738 dev_flow->handle->rix_jump = 0; 11739 } 11740 sample_act->actions_num = normal_idx; 11741 /* update sample action resource into first index of array */ 11742 mdest_res->ft_type = res->ft_type; 11743 memcpy(&mdest_res->sample_idx[0], &res->sample_idx, 11744 sizeof(struct mlx5_flow_sub_actions_idx)); 11745 memcpy(&mdest_res->sample_act[0], &res->sample_act, 11746 sizeof(struct mlx5_flow_sub_actions_list)); 11747 mdest_res->num_of_dest = num_of_dest; 11748 if (flow_dv_dest_array_resource_register(dev, mdest_res, 11749 dev_flow, error)) 11750 return rte_flow_error_set(error, EINVAL, 11751 RTE_FLOW_ERROR_TYPE_ACTION, 11752 NULL, "can't create sample " 11753 "action"); 11754 } else { 11755 res->sub_actions = sample_actions; 11756 if (flow_dv_sample_resource_register(dev, res, dev_flow, error)) 11757 return rte_flow_error_set(error, EINVAL, 11758 RTE_FLOW_ERROR_TYPE_ACTION, 11759 NULL, 11760 "can't create sample action"); 11761 } 11762 return 0; 11763 } 11764 11765 /** 11766 * Remove an ASO age action from age actions list. 11767 * 11768 * @param[in] dev 11769 * Pointer to the Ethernet device structure. 11770 * @param[in] age 11771 * Pointer to the aso age action handler. 11772 */ 11773 static void 11774 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev, 11775 struct mlx5_aso_age_action *age) 11776 { 11777 struct mlx5_age_info *age_info; 11778 struct mlx5_age_param *age_param = &age->age_params; 11779 struct mlx5_priv *priv = dev->data->dev_private; 11780 uint16_t expected = AGE_CANDIDATE; 11781 11782 age_info = GET_PORT_AGE_INFO(priv); 11783 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 11784 AGE_FREE, false, __ATOMIC_RELAXED, 11785 __ATOMIC_RELAXED)) { 11786 /** 11787 * We need the lock even it is age timeout, 11788 * since age action may still in process. 11789 */ 11790 rte_spinlock_lock(&age_info->aged_sl); 11791 LIST_REMOVE(age, next); 11792 rte_spinlock_unlock(&age_info->aged_sl); 11793 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 11794 } 11795 } 11796 11797 /** 11798 * Release an ASO age action. 11799 * 11800 * @param[in] dev 11801 * Pointer to the Ethernet device structure. 11802 * @param[in] age_idx 11803 * Index of ASO age action to release. 11804 * @param[in] flow 11805 * True if the release operation is during flow destroy operation. 11806 * False if the release operation is during action destroy operation. 11807 * 11808 * @return 11809 * 0 when age action was removed, otherwise the number of references. 11810 */ 11811 static int 11812 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx) 11813 { 11814 struct mlx5_priv *priv = dev->data->dev_private; 11815 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11816 struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx); 11817 uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED); 11818 11819 if (!ret) { 11820 flow_dv_aso_age_remove_from_age(dev, age); 11821 rte_spinlock_lock(&mng->free_sl); 11822 LIST_INSERT_HEAD(&mng->free, age, next); 11823 rte_spinlock_unlock(&mng->free_sl); 11824 } 11825 return ret; 11826 } 11827 11828 /** 11829 * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools. 11830 * 11831 * @param[in] dev 11832 * Pointer to the Ethernet device structure. 11833 * 11834 * @return 11835 * 0 on success, otherwise negative errno value and rte_errno is set. 11836 */ 11837 static int 11838 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev) 11839 { 11840 struct mlx5_priv *priv = dev->data->dev_private; 11841 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11842 void *old_pools = mng->pools; 11843 uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE; 11844 uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize; 11845 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 11846 11847 if (!pools) { 11848 rte_errno = ENOMEM; 11849 return -ENOMEM; 11850 } 11851 if (old_pools) { 11852 memcpy(pools, old_pools, 11853 mng->n * sizeof(struct mlx5_flow_counter_pool *)); 11854 mlx5_free(old_pools); 11855 } else { 11856 /* First ASO flow hit allocation - starting ASO data-path. */ 11857 int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh); 11858 11859 if (ret) { 11860 mlx5_free(pools); 11861 return ret; 11862 } 11863 } 11864 mng->n = resize; 11865 mng->pools = pools; 11866 return 0; 11867 } 11868 11869 /** 11870 * Create and initialize a new ASO aging pool. 11871 * 11872 * @param[in] dev 11873 * Pointer to the Ethernet device structure. 11874 * @param[out] age_free 11875 * Where to put the pointer of a new age action. 11876 * 11877 * @return 11878 * The age actions pool pointer and @p age_free is set on success, 11879 * NULL otherwise and rte_errno is set. 11880 */ 11881 static struct mlx5_aso_age_pool * 11882 flow_dv_age_pool_create(struct rte_eth_dev *dev, 11883 struct mlx5_aso_age_action **age_free) 11884 { 11885 struct mlx5_priv *priv = dev->data->dev_private; 11886 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11887 struct mlx5_aso_age_pool *pool = NULL; 11888 struct mlx5_devx_obj *obj = NULL; 11889 uint32_t i; 11890 11891 obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx, 11892 priv->sh->cdev->pdn); 11893 if (!obj) { 11894 rte_errno = ENODATA; 11895 DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX."); 11896 return NULL; 11897 } 11898 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 11899 if (!pool) { 11900 claim_zero(mlx5_devx_cmd_destroy(obj)); 11901 rte_errno = ENOMEM; 11902 return NULL; 11903 } 11904 pool->flow_hit_aso_obj = obj; 11905 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 11906 rte_spinlock_lock(&mng->resize_sl); 11907 pool->index = mng->next; 11908 /* Resize pools array if there is no room for the new pool in it. */ 11909 if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) { 11910 claim_zero(mlx5_devx_cmd_destroy(obj)); 11911 mlx5_free(pool); 11912 rte_spinlock_unlock(&mng->resize_sl); 11913 return NULL; 11914 } 11915 mng->pools[pool->index] = pool; 11916 mng->next++; 11917 rte_spinlock_unlock(&mng->resize_sl); 11918 /* Assign the first action in the new pool, the rest go to free list. */ 11919 *age_free = &pool->actions[0]; 11920 for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) { 11921 pool->actions[i].offset = i; 11922 LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next); 11923 } 11924 return pool; 11925 } 11926 11927 /** 11928 * Allocate a ASO aging bit. 11929 * 11930 * @param[in] dev 11931 * Pointer to the Ethernet device structure. 11932 * @param[out] error 11933 * Pointer to the error structure. 11934 * 11935 * @return 11936 * Index to ASO age action on success, 0 otherwise and rte_errno is set. 11937 */ 11938 static uint32_t 11939 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 11940 { 11941 struct mlx5_priv *priv = dev->data->dev_private; 11942 const struct mlx5_aso_age_pool *pool; 11943 struct mlx5_aso_age_action *age_free = NULL; 11944 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11945 11946 MLX5_ASSERT(mng); 11947 /* Try to get the next free age action bit. */ 11948 rte_spinlock_lock(&mng->free_sl); 11949 age_free = LIST_FIRST(&mng->free); 11950 if (age_free) { 11951 LIST_REMOVE(age_free, next); 11952 } else if (!flow_dv_age_pool_create(dev, &age_free)) { 11953 rte_spinlock_unlock(&mng->free_sl); 11954 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 11955 NULL, "failed to create ASO age pool"); 11956 return 0; /* 0 is an error. */ 11957 } 11958 rte_spinlock_unlock(&mng->free_sl); 11959 pool = container_of 11960 ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL]) 11961 (age_free - age_free->offset), const struct mlx5_aso_age_pool, 11962 actions); 11963 if (!age_free->dr_action) { 11964 int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0, 11965 error); 11966 11967 if (reg_c < 0) { 11968 rte_flow_error_set(error, rte_errno, 11969 RTE_FLOW_ERROR_TYPE_ACTION, 11970 NULL, "failed to get reg_c " 11971 "for ASO flow hit"); 11972 return 0; /* 0 is an error. */ 11973 } 11974 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 11975 age_free->dr_action = mlx5_glue->dv_create_flow_action_aso 11976 (priv->sh->rx_domain, 11977 pool->flow_hit_aso_obj->obj, age_free->offset, 11978 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET, 11979 (reg_c - REG_C_0)); 11980 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 11981 if (!age_free->dr_action) { 11982 rte_errno = errno; 11983 rte_spinlock_lock(&mng->free_sl); 11984 LIST_INSERT_HEAD(&mng->free, age_free, next); 11985 rte_spinlock_unlock(&mng->free_sl); 11986 rte_flow_error_set(error, rte_errno, 11987 RTE_FLOW_ERROR_TYPE_ACTION, 11988 NULL, "failed to create ASO " 11989 "flow hit action"); 11990 return 0; /* 0 is an error. */ 11991 } 11992 } 11993 __atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED); 11994 return pool->index | ((age_free->offset + 1) << 16); 11995 } 11996 11997 /** 11998 * Initialize flow ASO age parameters. 11999 * 12000 * @param[in] dev 12001 * Pointer to rte_eth_dev structure. 12002 * @param[in] age_idx 12003 * Index of ASO age action. 12004 * @param[in] context 12005 * Pointer to flow counter age context. 12006 * @param[in] timeout 12007 * Aging timeout in seconds. 12008 * 12009 */ 12010 static void 12011 flow_dv_aso_age_params_init(struct rte_eth_dev *dev, 12012 uint32_t age_idx, 12013 void *context, 12014 uint32_t timeout) 12015 { 12016 struct mlx5_aso_age_action *aso_age; 12017 12018 aso_age = flow_aso_age_get_by_idx(dev, age_idx); 12019 MLX5_ASSERT(aso_age); 12020 aso_age->age_params.context = context; 12021 aso_age->age_params.timeout = timeout; 12022 aso_age->age_params.port_id = dev->data->port_id; 12023 __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0, 12024 __ATOMIC_RELAXED); 12025 __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE, 12026 __ATOMIC_RELAXED); 12027 } 12028 12029 static void 12030 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask, 12031 const struct rte_flow_item_integrity *value, 12032 void *headers_m, void *headers_v) 12033 { 12034 if (mask->l4_ok) { 12035 /* application l4_ok filter aggregates all hardware l4 filters 12036 * therefore hw l4_checksum_ok must be implicitly added here. 12037 */ 12038 struct rte_flow_item_integrity local_item; 12039 12040 local_item.l4_csum_ok = 1; 12041 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 12042 local_item.l4_csum_ok); 12043 if (value->l4_ok) { 12044 /* application l4_ok = 1 matches sets both hw flags 12045 * l4_ok and l4_checksum_ok flags to 1. 12046 */ 12047 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12048 l4_checksum_ok, local_item.l4_csum_ok); 12049 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok, 12050 mask->l4_ok); 12051 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok, 12052 value->l4_ok); 12053 } else { 12054 /* application l4_ok = 0 matches on hw flag 12055 * l4_checksum_ok = 0 only. 12056 */ 12057 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12058 l4_checksum_ok, 0); 12059 } 12060 } else if (mask->l4_csum_ok) { 12061 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 12062 mask->l4_csum_ok); 12063 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, 12064 value->l4_csum_ok); 12065 } 12066 } 12067 12068 static void 12069 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask, 12070 const struct rte_flow_item_integrity *value, 12071 void *headers_m, void *headers_v, 12072 bool is_ipv4) 12073 { 12074 if (mask->l3_ok) { 12075 /* application l3_ok filter aggregates all hardware l3 filters 12076 * therefore hw ipv4_checksum_ok must be implicitly added here. 12077 */ 12078 struct rte_flow_item_integrity local_item; 12079 12080 local_item.ipv4_csum_ok = !!is_ipv4; 12081 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 12082 local_item.ipv4_csum_ok); 12083 if (value->l3_ok) { 12084 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12085 ipv4_checksum_ok, local_item.ipv4_csum_ok); 12086 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok, 12087 mask->l3_ok); 12088 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok, 12089 value->l3_ok); 12090 } else { 12091 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12092 ipv4_checksum_ok, 0); 12093 } 12094 } else if (mask->ipv4_csum_ok) { 12095 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 12096 mask->ipv4_csum_ok); 12097 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok, 12098 value->ipv4_csum_ok); 12099 } 12100 } 12101 12102 static void 12103 flow_dv_translate_item_integrity(void *matcher, void *key, 12104 const struct rte_flow_item *head_item, 12105 const struct rte_flow_item *integrity_item) 12106 { 12107 const struct rte_flow_item_integrity *mask = integrity_item->mask; 12108 const struct rte_flow_item_integrity *value = integrity_item->spec; 12109 const struct rte_flow_item *tunnel_item, *end_item, *item; 12110 void *headers_m; 12111 void *headers_v; 12112 uint32_t l3_protocol; 12113 12114 if (!value) 12115 return; 12116 if (!mask) 12117 mask = &rte_flow_item_integrity_mask; 12118 if (value->level > 1) { 12119 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12120 inner_headers); 12121 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 12122 } else { 12123 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12124 outer_headers); 12125 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 12126 } 12127 tunnel_item = mlx5_flow_find_tunnel_item(head_item); 12128 if (value->level > 1) { 12129 /* tunnel item was verified during the item validation */ 12130 item = tunnel_item; 12131 end_item = mlx5_find_end_item(tunnel_item); 12132 } else { 12133 item = head_item; 12134 end_item = tunnel_item ? tunnel_item : 12135 mlx5_find_end_item(integrity_item); 12136 } 12137 l3_protocol = mask->l3_ok ? 12138 mlx5_flow_locate_proto_l3(&item, end_item) : 0; 12139 flow_dv_translate_integrity_l3(mask, value, headers_m, headers_v, 12140 l3_protocol == RTE_ETHER_TYPE_IPV4); 12141 flow_dv_translate_integrity_l4(mask, value, headers_m, headers_v); 12142 } 12143 12144 /** 12145 * Prepares DV flow counter with aging configuration. 12146 * Gets it by index when exists, creates a new one when doesn't. 12147 * 12148 * @param[in] dev 12149 * Pointer to rte_eth_dev structure. 12150 * @param[in] dev_flow 12151 * Pointer to the mlx5_flow. 12152 * @param[in, out] flow 12153 * Pointer to the sub flow. 12154 * @param[in] count 12155 * Pointer to the counter action configuration. 12156 * @param[in] age 12157 * Pointer to the aging action configuration. 12158 * @param[out] error 12159 * Pointer to the error structure. 12160 * 12161 * @return 12162 * Pointer to the counter, NULL otherwise. 12163 */ 12164 static struct mlx5_flow_counter * 12165 flow_dv_prepare_counter(struct rte_eth_dev *dev, 12166 struct mlx5_flow *dev_flow, 12167 struct rte_flow *flow, 12168 const struct rte_flow_action_count *count, 12169 const struct rte_flow_action_age *age, 12170 struct rte_flow_error *error) 12171 { 12172 if (!flow->counter) { 12173 flow->counter = flow_dv_translate_create_counter(dev, dev_flow, 12174 count, age); 12175 if (!flow->counter) { 12176 rte_flow_error_set(error, rte_errno, 12177 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12178 "cannot create counter object."); 12179 return NULL; 12180 } 12181 } 12182 return flow_dv_counter_get_by_idx(dev, flow->counter, NULL); 12183 } 12184 12185 /* 12186 * Release an ASO CT action by its own device. 12187 * 12188 * @param[in] dev 12189 * Pointer to the Ethernet device structure. 12190 * @param[in] idx 12191 * Index of ASO CT action to release. 12192 * 12193 * @return 12194 * 0 when CT action was removed, otherwise the number of references. 12195 */ 12196 static inline int 12197 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx) 12198 { 12199 struct mlx5_priv *priv = dev->data->dev_private; 12200 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12201 uint32_t ret; 12202 struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12203 enum mlx5_aso_ct_state state = 12204 __atomic_load_n(&ct->state, __ATOMIC_RELAXED); 12205 12206 /* Cannot release when CT is in the ASO SQ. */ 12207 if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY) 12208 return -1; 12209 ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED); 12210 if (!ret) { 12211 if (ct->dr_action_orig) { 12212 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12213 claim_zero(mlx5_glue->destroy_flow_action 12214 (ct->dr_action_orig)); 12215 #endif 12216 ct->dr_action_orig = NULL; 12217 } 12218 if (ct->dr_action_rply) { 12219 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12220 claim_zero(mlx5_glue->destroy_flow_action 12221 (ct->dr_action_rply)); 12222 #endif 12223 ct->dr_action_rply = NULL; 12224 } 12225 /* Clear the state to free, no need in 1st allocation. */ 12226 MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE); 12227 rte_spinlock_lock(&mng->ct_sl); 12228 LIST_INSERT_HEAD(&mng->free_cts, ct, next); 12229 rte_spinlock_unlock(&mng->ct_sl); 12230 } 12231 return (int)ret; 12232 } 12233 12234 static inline int 12235 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx, 12236 struct rte_flow_error *error) 12237 { 12238 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx); 12239 uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx); 12240 struct rte_eth_dev *owndev = &rte_eth_devices[owner]; 12241 int ret; 12242 12243 MLX5_ASSERT(owner < RTE_MAX_ETHPORTS); 12244 if (dev->data->dev_started != 1) 12245 return rte_flow_error_set(error, EAGAIN, 12246 RTE_FLOW_ERROR_TYPE_ACTION, 12247 NULL, 12248 "Indirect CT action cannot be destroyed when the port is stopped"); 12249 ret = flow_dv_aso_ct_dev_release(owndev, idx); 12250 if (ret < 0) 12251 return rte_flow_error_set(error, EAGAIN, 12252 RTE_FLOW_ERROR_TYPE_ACTION, 12253 NULL, 12254 "Current state prevents indirect CT action from being destroyed"); 12255 return ret; 12256 } 12257 12258 /* 12259 * Resize the ASO CT pools array by 64 pools. 12260 * 12261 * @param[in] dev 12262 * Pointer to the Ethernet device structure. 12263 * 12264 * @return 12265 * 0 on success, otherwise negative errno value and rte_errno is set. 12266 */ 12267 static int 12268 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev) 12269 { 12270 struct mlx5_priv *priv = dev->data->dev_private; 12271 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12272 void *old_pools = mng->pools; 12273 /* Magic number now, need a macro. */ 12274 uint32_t resize = mng->n + 64; 12275 uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize; 12276 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12277 12278 if (!pools) { 12279 rte_errno = ENOMEM; 12280 return -rte_errno; 12281 } 12282 rte_rwlock_write_lock(&mng->resize_rwl); 12283 /* ASO SQ/QP was already initialized in the startup. */ 12284 if (old_pools) { 12285 /* Realloc could be an alternative choice. */ 12286 rte_memcpy(pools, old_pools, 12287 mng->n * sizeof(struct mlx5_aso_ct_pool *)); 12288 mlx5_free(old_pools); 12289 } 12290 mng->n = resize; 12291 mng->pools = pools; 12292 rte_rwlock_write_unlock(&mng->resize_rwl); 12293 return 0; 12294 } 12295 12296 /* 12297 * Create and initialize a new ASO CT pool. 12298 * 12299 * @param[in] dev 12300 * Pointer to the Ethernet device structure. 12301 * @param[out] ct_free 12302 * Where to put the pointer of a new CT action. 12303 * 12304 * @return 12305 * The CT actions pool pointer and @p ct_free is set on success, 12306 * NULL otherwise and rte_errno is set. 12307 */ 12308 static struct mlx5_aso_ct_pool * 12309 flow_dv_ct_pool_create(struct rte_eth_dev *dev, 12310 struct mlx5_aso_ct_action **ct_free) 12311 { 12312 struct mlx5_priv *priv = dev->data->dev_private; 12313 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12314 struct mlx5_aso_ct_pool *pool = NULL; 12315 struct mlx5_devx_obj *obj = NULL; 12316 uint32_t i; 12317 uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL); 12318 12319 obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx, 12320 priv->sh->cdev->pdn, 12321 log_obj_size); 12322 if (!obj) { 12323 rte_errno = ENODATA; 12324 DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); 12325 return NULL; 12326 } 12327 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 12328 if (!pool) { 12329 rte_errno = ENOMEM; 12330 claim_zero(mlx5_devx_cmd_destroy(obj)); 12331 return NULL; 12332 } 12333 pool->devx_obj = obj; 12334 pool->index = mng->next; 12335 /* Resize pools array if there is no room for the new pool in it. */ 12336 if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) { 12337 claim_zero(mlx5_devx_cmd_destroy(obj)); 12338 mlx5_free(pool); 12339 return NULL; 12340 } 12341 mng->pools[pool->index] = pool; 12342 mng->next++; 12343 /* Assign the first action in the new pool, the rest go to free list. */ 12344 *ct_free = &pool->actions[0]; 12345 /* Lock outside, the list operation is safe here. */ 12346 for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) { 12347 /* refcnt is 0 when allocating the memory. */ 12348 pool->actions[i].offset = i; 12349 LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next); 12350 } 12351 return pool; 12352 } 12353 12354 /* 12355 * Allocate a ASO CT action from free list. 12356 * 12357 * @param[in] dev 12358 * Pointer to the Ethernet device structure. 12359 * @param[out] error 12360 * Pointer to the error structure. 12361 * 12362 * @return 12363 * Index to ASO CT action on success, 0 otherwise and rte_errno is set. 12364 */ 12365 static uint32_t 12366 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12367 { 12368 struct mlx5_priv *priv = dev->data->dev_private; 12369 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12370 struct mlx5_aso_ct_action *ct = NULL; 12371 struct mlx5_aso_ct_pool *pool; 12372 uint8_t reg_c; 12373 uint32_t ct_idx; 12374 12375 MLX5_ASSERT(mng); 12376 if (!priv->sh->devx) { 12377 rte_errno = ENOTSUP; 12378 return 0; 12379 } 12380 /* Get a free CT action, if no, a new pool will be created. */ 12381 rte_spinlock_lock(&mng->ct_sl); 12382 ct = LIST_FIRST(&mng->free_cts); 12383 if (ct) { 12384 LIST_REMOVE(ct, next); 12385 } else if (!flow_dv_ct_pool_create(dev, &ct)) { 12386 rte_spinlock_unlock(&mng->ct_sl); 12387 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12388 NULL, "failed to create ASO CT pool"); 12389 return 0; 12390 } 12391 rte_spinlock_unlock(&mng->ct_sl); 12392 pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); 12393 ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset); 12394 /* 0: inactive, 1: created, 2+: used by flows. */ 12395 __atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED); 12396 reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error); 12397 if (!ct->dr_action_orig) { 12398 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12399 ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso 12400 (priv->sh->rx_domain, pool->devx_obj->obj, 12401 ct->offset, 12402 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR, 12403 reg_c - REG_C_0); 12404 #else 12405 RTE_SET_USED(reg_c); 12406 #endif 12407 if (!ct->dr_action_orig) { 12408 flow_dv_aso_ct_dev_release(dev, ct_idx); 12409 rte_flow_error_set(error, rte_errno, 12410 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12411 "failed to create ASO CT action"); 12412 return 0; 12413 } 12414 } 12415 if (!ct->dr_action_rply) { 12416 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12417 ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso 12418 (priv->sh->rx_domain, pool->devx_obj->obj, 12419 ct->offset, 12420 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER, 12421 reg_c - REG_C_0); 12422 #endif 12423 if (!ct->dr_action_rply) { 12424 flow_dv_aso_ct_dev_release(dev, ct_idx); 12425 rte_flow_error_set(error, rte_errno, 12426 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12427 "failed to create ASO CT action"); 12428 return 0; 12429 } 12430 } 12431 return ct_idx; 12432 } 12433 12434 /* 12435 * Create a conntrack object with context and actions by using ASO mechanism. 12436 * 12437 * @param[in] dev 12438 * Pointer to rte_eth_dev structure. 12439 * @param[in] pro 12440 * Pointer to conntrack information profile. 12441 * @param[out] error 12442 * Pointer to the error structure. 12443 * 12444 * @return 12445 * Index to conntrack object on success, 0 otherwise. 12446 */ 12447 static uint32_t 12448 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, 12449 const struct rte_flow_action_conntrack *pro, 12450 struct rte_flow_error *error) 12451 { 12452 struct mlx5_priv *priv = dev->data->dev_private; 12453 struct mlx5_dev_ctx_shared *sh = priv->sh; 12454 struct mlx5_aso_ct_action *ct; 12455 uint32_t idx; 12456 12457 if (!sh->ct_aso_en) 12458 return rte_flow_error_set(error, ENOTSUP, 12459 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12460 "Connection is not supported"); 12461 idx = flow_dv_aso_ct_alloc(dev, error); 12462 if (!idx) 12463 return rte_flow_error_set(error, rte_errno, 12464 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12465 "Failed to allocate CT object"); 12466 ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12467 if (mlx5_aso_ct_update_by_wqe(sh, ct, pro)) 12468 return rte_flow_error_set(error, EBUSY, 12469 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12470 "Failed to update CT"); 12471 ct->is_original = !!pro->is_original_dir; 12472 ct->peer = pro->peer_port; 12473 return idx; 12474 } 12475 12476 /** 12477 * Fill the flow with DV spec, lock free 12478 * (mutex should be acquired by caller). 12479 * 12480 * @param[in] dev 12481 * Pointer to rte_eth_dev structure. 12482 * @param[in, out] dev_flow 12483 * Pointer to the sub flow. 12484 * @param[in] attr 12485 * Pointer to the flow attributes. 12486 * @param[in] items 12487 * Pointer to the list of items. 12488 * @param[in] actions 12489 * Pointer to the list of actions. 12490 * @param[out] error 12491 * Pointer to the error structure. 12492 * 12493 * @return 12494 * 0 on success, a negative errno value otherwise and rte_errno is set. 12495 */ 12496 static int 12497 flow_dv_translate(struct rte_eth_dev *dev, 12498 struct mlx5_flow *dev_flow, 12499 const struct rte_flow_attr *attr, 12500 const struct rte_flow_item items[], 12501 const struct rte_flow_action actions[], 12502 struct rte_flow_error *error) 12503 { 12504 struct mlx5_priv *priv = dev->data->dev_private; 12505 struct mlx5_dev_config *dev_conf = &priv->config; 12506 struct rte_flow *flow = dev_flow->flow; 12507 struct mlx5_flow_handle *handle = dev_flow->handle; 12508 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 12509 struct mlx5_flow_rss_desc *rss_desc; 12510 uint64_t item_flags = 0; 12511 uint64_t last_item = 0; 12512 uint64_t action_flags = 0; 12513 struct mlx5_flow_dv_matcher matcher = { 12514 .mask = { 12515 .size = sizeof(matcher.mask.buf), 12516 }, 12517 }; 12518 int actions_n = 0; 12519 bool actions_end = false; 12520 union { 12521 struct mlx5_flow_dv_modify_hdr_resource res; 12522 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 12523 sizeof(struct mlx5_modification_cmd) * 12524 (MLX5_MAX_MODIFY_NUM + 1)]; 12525 } mhdr_dummy; 12526 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 12527 const struct rte_flow_action_count *count = NULL; 12528 const struct rte_flow_action_age *non_shared_age = NULL; 12529 union flow_dv_attr flow_attr = { .attr = 0 }; 12530 uint32_t tag_be; 12531 union mlx5_flow_tbl_key tbl_key; 12532 uint32_t modify_action_position = UINT32_MAX; 12533 void *match_mask = matcher.mask.buf; 12534 void *match_value = dev_flow->dv.value.buf; 12535 uint8_t next_protocol = 0xff; 12536 struct rte_vlan_hdr vlan = { 0 }; 12537 struct mlx5_flow_dv_dest_array_resource mdest_res; 12538 struct mlx5_flow_dv_sample_resource sample_res; 12539 void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 12540 const struct rte_flow_action_sample *sample = NULL; 12541 struct mlx5_flow_sub_actions_list *sample_act; 12542 uint32_t sample_act_pos = UINT32_MAX; 12543 uint32_t age_act_pos = UINT32_MAX; 12544 uint32_t num_of_dest = 0; 12545 int tmp_actions_n = 0; 12546 uint32_t table; 12547 int ret = 0; 12548 const struct mlx5_flow_tunnel *tunnel = NULL; 12549 struct flow_grp_info grp_info = { 12550 .external = !!dev_flow->external, 12551 .transfer = !!attr->transfer, 12552 .fdb_def_rule = !!priv->fdb_def_rule, 12553 .skip_scale = dev_flow->skip_scale & 12554 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 12555 .std_tbl_fix = true, 12556 }; 12557 const struct rte_flow_item *head_item = items; 12558 12559 if (!wks) 12560 return rte_flow_error_set(error, ENOMEM, 12561 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12562 NULL, 12563 "failed to push flow workspace"); 12564 rss_desc = &wks->rss_desc; 12565 memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource)); 12566 memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource)); 12567 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12568 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12569 /* update normal path action resource into last index of array */ 12570 sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1]; 12571 if (is_tunnel_offload_active(dev)) { 12572 if (dev_flow->tunnel) { 12573 RTE_VERIFY(dev_flow->tof_type == 12574 MLX5_TUNNEL_OFFLOAD_MISS_RULE); 12575 tunnel = dev_flow->tunnel; 12576 } else { 12577 tunnel = mlx5_get_tof(items, actions, 12578 &dev_flow->tof_type); 12579 dev_flow->tunnel = tunnel; 12580 } 12581 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 12582 (dev, attr, tunnel, dev_flow->tof_type); 12583 } 12584 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12585 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12586 ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table, 12587 &grp_info, error); 12588 if (ret) 12589 return ret; 12590 dev_flow->dv.group = table; 12591 if (attr->transfer) 12592 mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 12593 /* number of actions must be set to 0 in case of dirty stack. */ 12594 mhdr_res->actions_num = 0; 12595 if (is_flow_tunnel_match_rule(dev_flow->tof_type)) { 12596 /* 12597 * do not add decap action if match rule drops packet 12598 * HW rejects rules with decap & drop 12599 * 12600 * if tunnel match rule was inserted before matching tunnel set 12601 * rule flow table used in the match rule must be registered. 12602 * current implementation handles that in the 12603 * flow_dv_match_register() at the function end. 12604 */ 12605 bool add_decap = true; 12606 const struct rte_flow_action *ptr = actions; 12607 12608 for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) { 12609 if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) { 12610 add_decap = false; 12611 break; 12612 } 12613 } 12614 if (add_decap) { 12615 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12616 attr->transfer, 12617 error)) 12618 return -rte_errno; 12619 dev_flow->dv.actions[actions_n++] = 12620 dev_flow->dv.encap_decap->action; 12621 action_flags |= MLX5_FLOW_ACTION_DECAP; 12622 } 12623 } 12624 for (; !actions_end ; actions++) { 12625 const struct rte_flow_action_queue *queue; 12626 const struct rte_flow_action_rss *rss; 12627 const struct rte_flow_action *action = actions; 12628 const uint8_t *rss_key; 12629 struct mlx5_flow_tbl_resource *tbl; 12630 struct mlx5_aso_age_action *age_act; 12631 struct mlx5_flow_counter *cnt_act; 12632 uint32_t port_id = 0; 12633 struct mlx5_flow_dv_port_id_action_resource port_id_resource; 12634 int action_type = actions->type; 12635 const struct rte_flow_action *found_action = NULL; 12636 uint32_t jump_group = 0; 12637 uint32_t owner_idx; 12638 struct mlx5_aso_ct_action *ct; 12639 12640 if (!mlx5_flow_os_action_supported(action_type)) 12641 return rte_flow_error_set(error, ENOTSUP, 12642 RTE_FLOW_ERROR_TYPE_ACTION, 12643 actions, 12644 "action not supported"); 12645 switch (action_type) { 12646 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 12647 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 12648 break; 12649 case RTE_FLOW_ACTION_TYPE_VOID: 12650 break; 12651 case RTE_FLOW_ACTION_TYPE_PORT_ID: 12652 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 12653 if (flow_dv_translate_action_port_id(dev, action, 12654 &port_id, error)) 12655 return -rte_errno; 12656 port_id_resource.port_id = port_id; 12657 MLX5_ASSERT(!handle->rix_port_id_action); 12658 if (flow_dv_port_id_action_resource_register 12659 (dev, &port_id_resource, dev_flow, error)) 12660 return -rte_errno; 12661 dev_flow->dv.actions[actions_n++] = 12662 dev_flow->dv.port_id_action->action; 12663 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12664 dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID; 12665 sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12666 num_of_dest++; 12667 break; 12668 case RTE_FLOW_ACTION_TYPE_FLAG: 12669 action_flags |= MLX5_FLOW_ACTION_FLAG; 12670 dev_flow->handle->mark = 1; 12671 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12672 struct rte_flow_action_mark mark = { 12673 .id = MLX5_FLOW_MARK_DEFAULT, 12674 }; 12675 12676 if (flow_dv_convert_action_mark(dev, &mark, 12677 mhdr_res, 12678 error)) 12679 return -rte_errno; 12680 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12681 break; 12682 } 12683 tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT); 12684 /* 12685 * Only one FLAG or MARK is supported per device flow 12686 * right now. So the pointer to the tag resource must be 12687 * zero before the register process. 12688 */ 12689 MLX5_ASSERT(!handle->dvh.rix_tag); 12690 if (flow_dv_tag_resource_register(dev, tag_be, 12691 dev_flow, error)) 12692 return -rte_errno; 12693 MLX5_ASSERT(dev_flow->dv.tag_resource); 12694 dev_flow->dv.actions[actions_n++] = 12695 dev_flow->dv.tag_resource->action; 12696 break; 12697 case RTE_FLOW_ACTION_TYPE_MARK: 12698 action_flags |= MLX5_FLOW_ACTION_MARK; 12699 dev_flow->handle->mark = 1; 12700 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12701 const struct rte_flow_action_mark *mark = 12702 (const struct rte_flow_action_mark *) 12703 actions->conf; 12704 12705 if (flow_dv_convert_action_mark(dev, mark, 12706 mhdr_res, 12707 error)) 12708 return -rte_errno; 12709 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12710 break; 12711 } 12712 /* Fall-through */ 12713 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 12714 /* Legacy (non-extensive) MARK action. */ 12715 tag_be = mlx5_flow_mark_set 12716 (((const struct rte_flow_action_mark *) 12717 (actions->conf))->id); 12718 MLX5_ASSERT(!handle->dvh.rix_tag); 12719 if (flow_dv_tag_resource_register(dev, tag_be, 12720 dev_flow, error)) 12721 return -rte_errno; 12722 MLX5_ASSERT(dev_flow->dv.tag_resource); 12723 dev_flow->dv.actions[actions_n++] = 12724 dev_flow->dv.tag_resource->action; 12725 break; 12726 case RTE_FLOW_ACTION_TYPE_SET_META: 12727 if (flow_dv_convert_action_set_meta 12728 (dev, mhdr_res, attr, 12729 (const struct rte_flow_action_set_meta *) 12730 actions->conf, error)) 12731 return -rte_errno; 12732 action_flags |= MLX5_FLOW_ACTION_SET_META; 12733 break; 12734 case RTE_FLOW_ACTION_TYPE_SET_TAG: 12735 if (flow_dv_convert_action_set_tag 12736 (dev, mhdr_res, 12737 (const struct rte_flow_action_set_tag *) 12738 actions->conf, error)) 12739 return -rte_errno; 12740 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 12741 break; 12742 case RTE_FLOW_ACTION_TYPE_DROP: 12743 action_flags |= MLX5_FLOW_ACTION_DROP; 12744 dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP; 12745 break; 12746 case RTE_FLOW_ACTION_TYPE_QUEUE: 12747 queue = actions->conf; 12748 rss_desc->queue_num = 1; 12749 rss_desc->queue[0] = queue->index; 12750 action_flags |= MLX5_FLOW_ACTION_QUEUE; 12751 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 12752 sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE; 12753 num_of_dest++; 12754 break; 12755 case RTE_FLOW_ACTION_TYPE_RSS: 12756 rss = actions->conf; 12757 memcpy(rss_desc->queue, rss->queue, 12758 rss->queue_num * sizeof(uint16_t)); 12759 rss_desc->queue_num = rss->queue_num; 12760 /* NULL RSS key indicates default RSS key. */ 12761 rss_key = !rss->key ? rss_hash_default_key : rss->key; 12762 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 12763 /* 12764 * rss->level and rss.types should be set in advance 12765 * when expanding items for RSS. 12766 */ 12767 action_flags |= MLX5_FLOW_ACTION_RSS; 12768 dev_flow->handle->fate_action = rss_desc->shared_rss ? 12769 MLX5_FLOW_FATE_SHARED_RSS : 12770 MLX5_FLOW_FATE_QUEUE; 12771 break; 12772 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 12773 owner_idx = (uint32_t)(uintptr_t)action->conf; 12774 age_act = flow_aso_age_get_by_idx(dev, owner_idx); 12775 if (flow->age == 0) { 12776 flow->age = owner_idx; 12777 __atomic_fetch_add(&age_act->refcnt, 1, 12778 __ATOMIC_RELAXED); 12779 } 12780 age_act_pos = actions_n++; 12781 action_flags |= MLX5_FLOW_ACTION_AGE; 12782 break; 12783 case RTE_FLOW_ACTION_TYPE_AGE: 12784 non_shared_age = action->conf; 12785 age_act_pos = actions_n++; 12786 action_flags |= MLX5_FLOW_ACTION_AGE; 12787 break; 12788 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 12789 owner_idx = (uint32_t)(uintptr_t)action->conf; 12790 cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx, 12791 NULL); 12792 MLX5_ASSERT(cnt_act != NULL); 12793 /** 12794 * When creating meter drop flow in drop table, the 12795 * counter should not overwrite the rte flow counter. 12796 */ 12797 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 12798 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) { 12799 dev_flow->dv.actions[actions_n++] = 12800 cnt_act->action; 12801 } else { 12802 if (flow->counter == 0) { 12803 flow->counter = owner_idx; 12804 __atomic_fetch_add 12805 (&cnt_act->shared_info.refcnt, 12806 1, __ATOMIC_RELAXED); 12807 } 12808 /* Save information first, will apply later. */ 12809 action_flags |= MLX5_FLOW_ACTION_COUNT; 12810 } 12811 break; 12812 case RTE_FLOW_ACTION_TYPE_COUNT: 12813 if (!priv->sh->devx) { 12814 return rte_flow_error_set 12815 (error, ENOTSUP, 12816 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12817 NULL, 12818 "count action not supported"); 12819 } 12820 /* Save information first, will apply later. */ 12821 count = action->conf; 12822 action_flags |= MLX5_FLOW_ACTION_COUNT; 12823 break; 12824 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 12825 dev_flow->dv.actions[actions_n++] = 12826 priv->sh->pop_vlan_action; 12827 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 12828 break; 12829 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 12830 if (!(action_flags & 12831 MLX5_FLOW_ACTION_OF_SET_VLAN_VID)) 12832 flow_dev_get_vlan_info_from_items(items, &vlan); 12833 vlan.eth_proto = rte_be_to_cpu_16 12834 ((((const struct rte_flow_action_of_push_vlan *) 12835 actions->conf)->ethertype)); 12836 found_action = mlx5_flow_find_action 12837 (actions + 1, 12838 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID); 12839 if (found_action) 12840 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12841 found_action = mlx5_flow_find_action 12842 (actions + 1, 12843 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP); 12844 if (found_action) 12845 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12846 if (flow_dv_create_action_push_vlan 12847 (dev, attr, &vlan, dev_flow, error)) 12848 return -rte_errno; 12849 dev_flow->dv.actions[actions_n++] = 12850 dev_flow->dv.push_vlan_res->action; 12851 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 12852 break; 12853 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 12854 /* of_vlan_push action handled this action */ 12855 MLX5_ASSERT(action_flags & 12856 MLX5_FLOW_ACTION_OF_PUSH_VLAN); 12857 break; 12858 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 12859 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 12860 break; 12861 flow_dev_get_vlan_info_from_items(items, &vlan); 12862 mlx5_update_vlan_vid_pcp(actions, &vlan); 12863 /* If no VLAN push - this is a modify header action */ 12864 if (flow_dv_convert_action_modify_vlan_vid 12865 (mhdr_res, actions, error)) 12866 return -rte_errno; 12867 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 12868 break; 12869 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 12870 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 12871 if (flow_dv_create_action_l2_encap(dev, actions, 12872 dev_flow, 12873 attr->transfer, 12874 error)) 12875 return -rte_errno; 12876 dev_flow->dv.actions[actions_n++] = 12877 dev_flow->dv.encap_decap->action; 12878 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12879 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 12880 sample_act->action_flags |= 12881 MLX5_FLOW_ACTION_ENCAP; 12882 break; 12883 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 12884 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 12885 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12886 attr->transfer, 12887 error)) 12888 return -rte_errno; 12889 dev_flow->dv.actions[actions_n++] = 12890 dev_flow->dv.encap_decap->action; 12891 action_flags |= MLX5_FLOW_ACTION_DECAP; 12892 break; 12893 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 12894 /* Handle encap with preceding decap. */ 12895 if (action_flags & MLX5_FLOW_ACTION_DECAP) { 12896 if (flow_dv_create_action_raw_encap 12897 (dev, actions, dev_flow, attr, error)) 12898 return -rte_errno; 12899 dev_flow->dv.actions[actions_n++] = 12900 dev_flow->dv.encap_decap->action; 12901 } else { 12902 /* Handle encap without preceding decap. */ 12903 if (flow_dv_create_action_l2_encap 12904 (dev, actions, dev_flow, attr->transfer, 12905 error)) 12906 return -rte_errno; 12907 dev_flow->dv.actions[actions_n++] = 12908 dev_flow->dv.encap_decap->action; 12909 } 12910 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12911 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 12912 sample_act->action_flags |= 12913 MLX5_FLOW_ACTION_ENCAP; 12914 break; 12915 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 12916 while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID) 12917 ; 12918 if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 12919 if (flow_dv_create_action_l2_decap 12920 (dev, dev_flow, attr->transfer, error)) 12921 return -rte_errno; 12922 dev_flow->dv.actions[actions_n++] = 12923 dev_flow->dv.encap_decap->action; 12924 } 12925 /* If decap is followed by encap, handle it at encap. */ 12926 action_flags |= MLX5_FLOW_ACTION_DECAP; 12927 break; 12928 case MLX5_RTE_FLOW_ACTION_TYPE_JUMP: 12929 dev_flow->dv.actions[actions_n++] = 12930 (void *)(uintptr_t)action->conf; 12931 action_flags |= MLX5_FLOW_ACTION_JUMP; 12932 break; 12933 case RTE_FLOW_ACTION_TYPE_JUMP: 12934 jump_group = ((const struct rte_flow_action_jump *) 12935 action->conf)->group; 12936 grp_info.std_tbl_fix = 0; 12937 if (dev_flow->skip_scale & 12938 (1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT)) 12939 grp_info.skip_scale = 1; 12940 else 12941 grp_info.skip_scale = 0; 12942 ret = mlx5_flow_group_to_table(dev, tunnel, 12943 jump_group, 12944 &table, 12945 &grp_info, error); 12946 if (ret) 12947 return ret; 12948 tbl = flow_dv_tbl_resource_get(dev, table, attr->egress, 12949 attr->transfer, 12950 !!dev_flow->external, 12951 tunnel, jump_group, 0, 12952 0, error); 12953 if (!tbl) 12954 return rte_flow_error_set 12955 (error, errno, 12956 RTE_FLOW_ERROR_TYPE_ACTION, 12957 NULL, 12958 "cannot create jump action."); 12959 if (flow_dv_jump_tbl_resource_register 12960 (dev, tbl, dev_flow, error)) { 12961 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 12962 return rte_flow_error_set 12963 (error, errno, 12964 RTE_FLOW_ERROR_TYPE_ACTION, 12965 NULL, 12966 "cannot create jump action."); 12967 } 12968 dev_flow->dv.actions[actions_n++] = 12969 dev_flow->dv.jump->action; 12970 action_flags |= MLX5_FLOW_ACTION_JUMP; 12971 dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP; 12972 sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP; 12973 num_of_dest++; 12974 break; 12975 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 12976 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 12977 if (flow_dv_convert_action_modify_mac 12978 (mhdr_res, actions, error)) 12979 return -rte_errno; 12980 action_flags |= actions->type == 12981 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 12982 MLX5_FLOW_ACTION_SET_MAC_SRC : 12983 MLX5_FLOW_ACTION_SET_MAC_DST; 12984 break; 12985 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 12986 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 12987 if (flow_dv_convert_action_modify_ipv4 12988 (mhdr_res, actions, error)) 12989 return -rte_errno; 12990 action_flags |= actions->type == 12991 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 12992 MLX5_FLOW_ACTION_SET_IPV4_SRC : 12993 MLX5_FLOW_ACTION_SET_IPV4_DST; 12994 break; 12995 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 12996 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 12997 if (flow_dv_convert_action_modify_ipv6 12998 (mhdr_res, actions, error)) 12999 return -rte_errno; 13000 action_flags |= actions->type == 13001 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 13002 MLX5_FLOW_ACTION_SET_IPV6_SRC : 13003 MLX5_FLOW_ACTION_SET_IPV6_DST; 13004 break; 13005 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 13006 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 13007 if (flow_dv_convert_action_modify_tp 13008 (mhdr_res, actions, items, 13009 &flow_attr, dev_flow, !!(action_flags & 13010 MLX5_FLOW_ACTION_DECAP), error)) 13011 return -rte_errno; 13012 action_flags |= actions->type == 13013 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 13014 MLX5_FLOW_ACTION_SET_TP_SRC : 13015 MLX5_FLOW_ACTION_SET_TP_DST; 13016 break; 13017 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 13018 if (flow_dv_convert_action_modify_dec_ttl 13019 (mhdr_res, items, &flow_attr, dev_flow, 13020 !!(action_flags & 13021 MLX5_FLOW_ACTION_DECAP), error)) 13022 return -rte_errno; 13023 action_flags |= MLX5_FLOW_ACTION_DEC_TTL; 13024 break; 13025 case RTE_FLOW_ACTION_TYPE_SET_TTL: 13026 if (flow_dv_convert_action_modify_ttl 13027 (mhdr_res, actions, items, &flow_attr, 13028 dev_flow, !!(action_flags & 13029 MLX5_FLOW_ACTION_DECAP), error)) 13030 return -rte_errno; 13031 action_flags |= MLX5_FLOW_ACTION_SET_TTL; 13032 break; 13033 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 13034 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 13035 if (flow_dv_convert_action_modify_tcp_seq 13036 (mhdr_res, actions, error)) 13037 return -rte_errno; 13038 action_flags |= actions->type == 13039 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 13040 MLX5_FLOW_ACTION_INC_TCP_SEQ : 13041 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 13042 break; 13043 13044 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 13045 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 13046 if (flow_dv_convert_action_modify_tcp_ack 13047 (mhdr_res, actions, error)) 13048 return -rte_errno; 13049 action_flags |= actions->type == 13050 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 13051 MLX5_FLOW_ACTION_INC_TCP_ACK : 13052 MLX5_FLOW_ACTION_DEC_TCP_ACK; 13053 break; 13054 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 13055 if (flow_dv_convert_action_set_reg 13056 (mhdr_res, actions, error)) 13057 return -rte_errno; 13058 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13059 break; 13060 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 13061 if (flow_dv_convert_action_copy_mreg 13062 (dev, mhdr_res, actions, error)) 13063 return -rte_errno; 13064 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13065 break; 13066 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 13067 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 13068 dev_flow->handle->fate_action = 13069 MLX5_FLOW_FATE_DEFAULT_MISS; 13070 break; 13071 case RTE_FLOW_ACTION_TYPE_METER: 13072 if (!wks->fm) 13073 return rte_flow_error_set(error, rte_errno, 13074 RTE_FLOW_ERROR_TYPE_ACTION, 13075 NULL, "Failed to get meter in flow."); 13076 /* Set the meter action. */ 13077 dev_flow->dv.actions[actions_n++] = 13078 wks->fm->meter_action; 13079 action_flags |= MLX5_FLOW_ACTION_METER; 13080 break; 13081 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 13082 if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res, 13083 actions, error)) 13084 return -rte_errno; 13085 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 13086 break; 13087 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 13088 if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res, 13089 actions, error)) 13090 return -rte_errno; 13091 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 13092 break; 13093 case RTE_FLOW_ACTION_TYPE_SAMPLE: 13094 sample_act_pos = actions_n; 13095 sample = (const struct rte_flow_action_sample *) 13096 action->conf; 13097 actions_n++; 13098 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 13099 /* put encap action into group if work with port id */ 13100 if ((action_flags & MLX5_FLOW_ACTION_ENCAP) && 13101 (action_flags & MLX5_FLOW_ACTION_PORT_ID)) 13102 sample_act->action_flags |= 13103 MLX5_FLOW_ACTION_ENCAP; 13104 break; 13105 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 13106 if (flow_dv_convert_action_modify_field 13107 (dev, mhdr_res, actions, attr, error)) 13108 return -rte_errno; 13109 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 13110 break; 13111 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 13112 owner_idx = (uint32_t)(uintptr_t)action->conf; 13113 ct = flow_aso_ct_get_by_idx(dev, owner_idx); 13114 if (!ct) 13115 return rte_flow_error_set(error, EINVAL, 13116 RTE_FLOW_ERROR_TYPE_ACTION, 13117 NULL, 13118 "Failed to get CT object."); 13119 if (mlx5_aso_ct_available(priv->sh, ct)) 13120 return rte_flow_error_set(error, rte_errno, 13121 RTE_FLOW_ERROR_TYPE_ACTION, 13122 NULL, 13123 "CT is unavailable."); 13124 if (ct->is_original) 13125 dev_flow->dv.actions[actions_n] = 13126 ct->dr_action_orig; 13127 else 13128 dev_flow->dv.actions[actions_n] = 13129 ct->dr_action_rply; 13130 if (flow->ct == 0) { 13131 flow->indirect_type = 13132 MLX5_INDIRECT_ACTION_TYPE_CT; 13133 flow->ct = owner_idx; 13134 __atomic_fetch_add(&ct->refcnt, 1, 13135 __ATOMIC_RELAXED); 13136 } 13137 actions_n++; 13138 action_flags |= MLX5_FLOW_ACTION_CT; 13139 break; 13140 case RTE_FLOW_ACTION_TYPE_END: 13141 actions_end = true; 13142 if (mhdr_res->actions_num) { 13143 /* create modify action if needed. */ 13144 if (flow_dv_modify_hdr_resource_register 13145 (dev, mhdr_res, dev_flow, error)) 13146 return -rte_errno; 13147 dev_flow->dv.actions[modify_action_position] = 13148 handle->dvh.modify_hdr->action; 13149 } 13150 /* 13151 * Handle AGE and COUNT action by single HW counter 13152 * when they are not shared. 13153 */ 13154 if (action_flags & MLX5_FLOW_ACTION_AGE) { 13155 if ((non_shared_age && count) || 13156 !(priv->sh->flow_hit_aso_en && 13157 (attr->group || attr->transfer))) { 13158 /* Creates age by counters. */ 13159 cnt_act = flow_dv_prepare_counter 13160 (dev, dev_flow, 13161 flow, count, 13162 non_shared_age, 13163 error); 13164 if (!cnt_act) 13165 return -rte_errno; 13166 dev_flow->dv.actions[age_act_pos] = 13167 cnt_act->action; 13168 break; 13169 } 13170 if (!flow->age && non_shared_age) { 13171 flow->age = flow_dv_aso_age_alloc 13172 (dev, error); 13173 if (!flow->age) 13174 return -rte_errno; 13175 flow_dv_aso_age_params_init 13176 (dev, flow->age, 13177 non_shared_age->context ? 13178 non_shared_age->context : 13179 (void *)(uintptr_t) 13180 (dev_flow->flow_idx), 13181 non_shared_age->timeout); 13182 } 13183 age_act = flow_aso_age_get_by_idx(dev, 13184 flow->age); 13185 dev_flow->dv.actions[age_act_pos] = 13186 age_act->dr_action; 13187 } 13188 if (action_flags & MLX5_FLOW_ACTION_COUNT) { 13189 /* 13190 * Create one count action, to be used 13191 * by all sub-flows. 13192 */ 13193 cnt_act = flow_dv_prepare_counter(dev, dev_flow, 13194 flow, count, 13195 NULL, error); 13196 if (!cnt_act) 13197 return -rte_errno; 13198 dev_flow->dv.actions[actions_n++] = 13199 cnt_act->action; 13200 } 13201 default: 13202 break; 13203 } 13204 if (mhdr_res->actions_num && 13205 modify_action_position == UINT32_MAX) 13206 modify_action_position = actions_n++; 13207 } 13208 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 13209 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 13210 int item_type = items->type; 13211 13212 if (!mlx5_flow_os_item_supported(item_type)) 13213 return rte_flow_error_set(error, ENOTSUP, 13214 RTE_FLOW_ERROR_TYPE_ITEM, 13215 NULL, "item not supported"); 13216 switch (item_type) { 13217 case RTE_FLOW_ITEM_TYPE_PORT_ID: 13218 flow_dv_translate_item_port_id 13219 (dev, match_mask, match_value, items, attr); 13220 last_item = MLX5_FLOW_ITEM_PORT_ID; 13221 break; 13222 case RTE_FLOW_ITEM_TYPE_ETH: 13223 flow_dv_translate_item_eth(match_mask, match_value, 13224 items, tunnel, 13225 dev_flow->dv.group); 13226 matcher.priority = action_flags & 13227 MLX5_FLOW_ACTION_DEFAULT_MISS && 13228 !dev_flow->external ? 13229 MLX5_PRIORITY_MAP_L3 : 13230 MLX5_PRIORITY_MAP_L2; 13231 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 13232 MLX5_FLOW_LAYER_OUTER_L2; 13233 break; 13234 case RTE_FLOW_ITEM_TYPE_VLAN: 13235 flow_dv_translate_item_vlan(dev_flow, 13236 match_mask, match_value, 13237 items, tunnel, 13238 dev_flow->dv.group); 13239 matcher.priority = MLX5_PRIORITY_MAP_L2; 13240 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 13241 MLX5_FLOW_LAYER_INNER_VLAN) : 13242 (MLX5_FLOW_LAYER_OUTER_L2 | 13243 MLX5_FLOW_LAYER_OUTER_VLAN); 13244 break; 13245 case RTE_FLOW_ITEM_TYPE_IPV4: 13246 mlx5_flow_tunnel_ip_check(items, next_protocol, 13247 &item_flags, &tunnel); 13248 flow_dv_translate_item_ipv4(match_mask, match_value, 13249 items, tunnel, 13250 dev_flow->dv.group); 13251 matcher.priority = MLX5_PRIORITY_MAP_L3; 13252 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 13253 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 13254 if (items->mask != NULL && 13255 ((const struct rte_flow_item_ipv4 *) 13256 items->mask)->hdr.next_proto_id) { 13257 next_protocol = 13258 ((const struct rte_flow_item_ipv4 *) 13259 (items->spec))->hdr.next_proto_id; 13260 next_protocol &= 13261 ((const struct rte_flow_item_ipv4 *) 13262 (items->mask))->hdr.next_proto_id; 13263 } else { 13264 /* Reset for inner layer. */ 13265 next_protocol = 0xff; 13266 } 13267 break; 13268 case RTE_FLOW_ITEM_TYPE_IPV6: 13269 mlx5_flow_tunnel_ip_check(items, next_protocol, 13270 &item_flags, &tunnel); 13271 flow_dv_translate_item_ipv6(match_mask, match_value, 13272 items, tunnel, 13273 dev_flow->dv.group); 13274 matcher.priority = MLX5_PRIORITY_MAP_L3; 13275 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 13276 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 13277 if (items->mask != NULL && 13278 ((const struct rte_flow_item_ipv6 *) 13279 items->mask)->hdr.proto) { 13280 next_protocol = 13281 ((const struct rte_flow_item_ipv6 *) 13282 items->spec)->hdr.proto; 13283 next_protocol &= 13284 ((const struct rte_flow_item_ipv6 *) 13285 items->mask)->hdr.proto; 13286 } else { 13287 /* Reset for inner layer. */ 13288 next_protocol = 0xff; 13289 } 13290 break; 13291 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 13292 flow_dv_translate_item_ipv6_frag_ext(match_mask, 13293 match_value, 13294 items, tunnel); 13295 last_item = tunnel ? 13296 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 13297 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 13298 if (items->mask != NULL && 13299 ((const struct rte_flow_item_ipv6_frag_ext *) 13300 items->mask)->hdr.next_header) { 13301 next_protocol = 13302 ((const struct rte_flow_item_ipv6_frag_ext *) 13303 items->spec)->hdr.next_header; 13304 next_protocol &= 13305 ((const struct rte_flow_item_ipv6_frag_ext *) 13306 items->mask)->hdr.next_header; 13307 } else { 13308 /* Reset for inner layer. */ 13309 next_protocol = 0xff; 13310 } 13311 break; 13312 case RTE_FLOW_ITEM_TYPE_TCP: 13313 flow_dv_translate_item_tcp(match_mask, match_value, 13314 items, tunnel); 13315 matcher.priority = MLX5_PRIORITY_MAP_L4; 13316 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 13317 MLX5_FLOW_LAYER_OUTER_L4_TCP; 13318 break; 13319 case RTE_FLOW_ITEM_TYPE_UDP: 13320 flow_dv_translate_item_udp(match_mask, match_value, 13321 items, tunnel); 13322 matcher.priority = MLX5_PRIORITY_MAP_L4; 13323 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 13324 MLX5_FLOW_LAYER_OUTER_L4_UDP; 13325 break; 13326 case RTE_FLOW_ITEM_TYPE_GRE: 13327 flow_dv_translate_item_gre(match_mask, match_value, 13328 items, tunnel); 13329 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13330 last_item = MLX5_FLOW_LAYER_GRE; 13331 break; 13332 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 13333 flow_dv_translate_item_gre_key(match_mask, 13334 match_value, items); 13335 last_item = MLX5_FLOW_LAYER_GRE_KEY; 13336 break; 13337 case RTE_FLOW_ITEM_TYPE_NVGRE: 13338 flow_dv_translate_item_nvgre(match_mask, match_value, 13339 items, tunnel); 13340 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13341 last_item = MLX5_FLOW_LAYER_GRE; 13342 break; 13343 case RTE_FLOW_ITEM_TYPE_VXLAN: 13344 flow_dv_translate_item_vxlan(dev, attr, 13345 match_mask, match_value, 13346 items, tunnel); 13347 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13348 last_item = MLX5_FLOW_LAYER_VXLAN; 13349 break; 13350 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 13351 flow_dv_translate_item_vxlan_gpe(match_mask, 13352 match_value, items, 13353 tunnel); 13354 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13355 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 13356 break; 13357 case RTE_FLOW_ITEM_TYPE_GENEVE: 13358 flow_dv_translate_item_geneve(match_mask, match_value, 13359 items, tunnel); 13360 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13361 last_item = MLX5_FLOW_LAYER_GENEVE; 13362 break; 13363 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 13364 ret = flow_dv_translate_item_geneve_opt(dev, match_mask, 13365 match_value, 13366 items, error); 13367 if (ret) 13368 return rte_flow_error_set(error, -ret, 13369 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13370 "cannot create GENEVE TLV option"); 13371 flow->geneve_tlv_option = 1; 13372 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 13373 break; 13374 case RTE_FLOW_ITEM_TYPE_MPLS: 13375 flow_dv_translate_item_mpls(match_mask, match_value, 13376 items, last_item, tunnel); 13377 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13378 last_item = MLX5_FLOW_LAYER_MPLS; 13379 break; 13380 case RTE_FLOW_ITEM_TYPE_MARK: 13381 flow_dv_translate_item_mark(dev, match_mask, 13382 match_value, items); 13383 last_item = MLX5_FLOW_ITEM_MARK; 13384 break; 13385 case RTE_FLOW_ITEM_TYPE_META: 13386 flow_dv_translate_item_meta(dev, match_mask, 13387 match_value, attr, items); 13388 last_item = MLX5_FLOW_ITEM_METADATA; 13389 break; 13390 case RTE_FLOW_ITEM_TYPE_ICMP: 13391 flow_dv_translate_item_icmp(match_mask, match_value, 13392 items, tunnel); 13393 last_item = MLX5_FLOW_LAYER_ICMP; 13394 break; 13395 case RTE_FLOW_ITEM_TYPE_ICMP6: 13396 flow_dv_translate_item_icmp6(match_mask, match_value, 13397 items, tunnel); 13398 last_item = MLX5_FLOW_LAYER_ICMP6; 13399 break; 13400 case RTE_FLOW_ITEM_TYPE_TAG: 13401 flow_dv_translate_item_tag(dev, match_mask, 13402 match_value, items); 13403 last_item = MLX5_FLOW_ITEM_TAG; 13404 break; 13405 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 13406 flow_dv_translate_mlx5_item_tag(dev, match_mask, 13407 match_value, items); 13408 last_item = MLX5_FLOW_ITEM_TAG; 13409 break; 13410 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 13411 flow_dv_translate_item_tx_queue(dev, match_mask, 13412 match_value, 13413 items); 13414 last_item = MLX5_FLOW_ITEM_TX_QUEUE; 13415 break; 13416 case RTE_FLOW_ITEM_TYPE_GTP: 13417 flow_dv_translate_item_gtp(match_mask, match_value, 13418 items, tunnel); 13419 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13420 last_item = MLX5_FLOW_LAYER_GTP; 13421 break; 13422 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 13423 ret = flow_dv_translate_item_gtp_psc(match_mask, 13424 match_value, 13425 items); 13426 if (ret) 13427 return rte_flow_error_set(error, -ret, 13428 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13429 "cannot create GTP PSC item"); 13430 last_item = MLX5_FLOW_LAYER_GTP_PSC; 13431 break; 13432 case RTE_FLOW_ITEM_TYPE_ECPRI: 13433 if (!mlx5_flex_parser_ecpri_exist(dev)) { 13434 /* Create it only the first time to be used. */ 13435 ret = mlx5_flex_parser_ecpri_alloc(dev); 13436 if (ret) 13437 return rte_flow_error_set 13438 (error, -ret, 13439 RTE_FLOW_ERROR_TYPE_ITEM, 13440 NULL, 13441 "cannot create eCPRI parser"); 13442 } 13443 flow_dv_translate_item_ecpri(dev, match_mask, 13444 match_value, items, 13445 last_item); 13446 /* No other protocol should follow eCPRI layer. */ 13447 last_item = MLX5_FLOW_LAYER_ECPRI; 13448 break; 13449 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 13450 flow_dv_translate_item_integrity(match_mask, 13451 match_value, 13452 head_item, items); 13453 break; 13454 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 13455 flow_dv_translate_item_aso_ct(dev, match_mask, 13456 match_value, items); 13457 break; 13458 default: 13459 break; 13460 } 13461 item_flags |= last_item; 13462 } 13463 /* 13464 * When E-Switch mode is enabled, we have two cases where we need to 13465 * set the source port manually. 13466 * The first one, is in case of Nic steering rule, and the second is 13467 * E-Switch rule where no port_id item was found. In both cases 13468 * the source port is set according the current port in use. 13469 */ 13470 if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) && 13471 (priv->representor || priv->master)) { 13472 if (flow_dv_translate_item_port_id(dev, match_mask, 13473 match_value, NULL, attr)) 13474 return -rte_errno; 13475 } 13476 #ifdef RTE_LIBRTE_MLX5_DEBUG 13477 MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf, 13478 dev_flow->dv.value.buf)); 13479 #endif 13480 /* 13481 * Layers may be already initialized from prefix flow if this dev_flow 13482 * is the suffix flow. 13483 */ 13484 handle->layers |= item_flags; 13485 if (action_flags & MLX5_FLOW_ACTION_RSS) 13486 flow_dv_hashfields_set(dev_flow, rss_desc); 13487 /* If has RSS action in the sample action, the Sample/Mirror resource 13488 * should be registered after the hash filed be update. 13489 */ 13490 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) { 13491 ret = flow_dv_translate_action_sample(dev, 13492 sample, 13493 dev_flow, attr, 13494 &num_of_dest, 13495 sample_actions, 13496 &sample_res, 13497 error); 13498 if (ret < 0) 13499 return ret; 13500 ret = flow_dv_create_action_sample(dev, 13501 dev_flow, 13502 num_of_dest, 13503 &sample_res, 13504 &mdest_res, 13505 sample_actions, 13506 action_flags, 13507 error); 13508 if (ret < 0) 13509 return rte_flow_error_set 13510 (error, rte_errno, 13511 RTE_FLOW_ERROR_TYPE_ACTION, 13512 NULL, 13513 "cannot create sample action"); 13514 if (num_of_dest > 1) { 13515 dev_flow->dv.actions[sample_act_pos] = 13516 dev_flow->dv.dest_array_res->action; 13517 } else { 13518 dev_flow->dv.actions[sample_act_pos] = 13519 dev_flow->dv.sample_res->verbs_action; 13520 } 13521 } 13522 /* 13523 * For multiple destination (sample action with ratio=1), the encap 13524 * action and port id action will be combined into group action. 13525 * So need remove the original these actions in the flow and only 13526 * use the sample action instead of. 13527 */ 13528 if (num_of_dest > 1 && 13529 (sample_act->dr_port_id_action || sample_act->dr_jump_action)) { 13530 int i; 13531 void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 13532 13533 for (i = 0; i < actions_n; i++) { 13534 if ((sample_act->dr_encap_action && 13535 sample_act->dr_encap_action == 13536 dev_flow->dv.actions[i]) || 13537 (sample_act->dr_port_id_action && 13538 sample_act->dr_port_id_action == 13539 dev_flow->dv.actions[i]) || 13540 (sample_act->dr_jump_action && 13541 sample_act->dr_jump_action == 13542 dev_flow->dv.actions[i])) 13543 continue; 13544 temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i]; 13545 } 13546 memcpy((void *)dev_flow->dv.actions, 13547 (void *)temp_actions, 13548 tmp_actions_n * sizeof(void *)); 13549 actions_n = tmp_actions_n; 13550 } 13551 dev_flow->dv.actions_n = actions_n; 13552 dev_flow->act_flags = action_flags; 13553 if (wks->skip_matcher_reg) 13554 return 0; 13555 /* Register matcher. */ 13556 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 13557 matcher.mask.size); 13558 matcher.priority = mlx5_get_matcher_priority(dev, attr, 13559 matcher.priority, 13560 dev_flow->external); 13561 /** 13562 * When creating meter drop flow in drop table, using original 13563 * 5-tuple match, the matcher priority should be lower than 13564 * mtr_id matcher. 13565 */ 13566 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 13567 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP && 13568 matcher.priority <= MLX5_REG_BITS) 13569 matcher.priority += MLX5_REG_BITS; 13570 /* reserved field no needs to be set to 0 here. */ 13571 tbl_key.is_fdb = attr->transfer; 13572 tbl_key.is_egress = attr->egress; 13573 tbl_key.level = dev_flow->dv.group; 13574 tbl_key.id = dev_flow->dv.table_id; 13575 if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow, 13576 tunnel, attr->group, error)) 13577 return -rte_errno; 13578 return 0; 13579 } 13580 13581 /** 13582 * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13583 * and tunnel. 13584 * 13585 * @param[in, out] action 13586 * Shred RSS action holding hash RX queue objects. 13587 * @param[in] hash_fields 13588 * Defines combination of packet fields to participate in RX hash. 13589 * @param[in] tunnel 13590 * Tunnel type 13591 * @param[in] hrxq_idx 13592 * Hash RX queue index to set. 13593 * 13594 * @return 13595 * 0 on success, otherwise negative errno value. 13596 */ 13597 static int 13598 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action, 13599 const uint64_t hash_fields, 13600 uint32_t hrxq_idx) 13601 { 13602 uint32_t *hrxqs = action->hrxq; 13603 13604 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13605 case MLX5_RSS_HASH_IPV4: 13606 /* fall-through. */ 13607 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13608 /* fall-through. */ 13609 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13610 hrxqs[0] = hrxq_idx; 13611 return 0; 13612 case MLX5_RSS_HASH_IPV4_TCP: 13613 /* fall-through. */ 13614 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13615 /* fall-through. */ 13616 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13617 hrxqs[1] = hrxq_idx; 13618 return 0; 13619 case MLX5_RSS_HASH_IPV4_UDP: 13620 /* fall-through. */ 13621 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13622 /* fall-through. */ 13623 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13624 hrxqs[2] = hrxq_idx; 13625 return 0; 13626 case MLX5_RSS_HASH_IPV6: 13627 /* fall-through. */ 13628 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13629 /* fall-through. */ 13630 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13631 hrxqs[3] = hrxq_idx; 13632 return 0; 13633 case MLX5_RSS_HASH_IPV6_TCP: 13634 /* fall-through. */ 13635 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13636 /* fall-through. */ 13637 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13638 hrxqs[4] = hrxq_idx; 13639 return 0; 13640 case MLX5_RSS_HASH_IPV6_UDP: 13641 /* fall-through. */ 13642 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13643 /* fall-through. */ 13644 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13645 hrxqs[5] = hrxq_idx; 13646 return 0; 13647 case MLX5_RSS_HASH_NONE: 13648 hrxqs[6] = hrxq_idx; 13649 return 0; 13650 default: 13651 return -1; 13652 } 13653 } 13654 13655 /** 13656 * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13657 * and tunnel. 13658 * 13659 * @param[in] dev 13660 * Pointer to the Ethernet device structure. 13661 * @param[in] idx 13662 * Shared RSS action ID holding hash RX queue objects. 13663 * @param[in] hash_fields 13664 * Defines combination of packet fields to participate in RX hash. 13665 * @param[in] tunnel 13666 * Tunnel type 13667 * 13668 * @return 13669 * Valid hash RX queue index, otherwise 0. 13670 */ 13671 static uint32_t 13672 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx, 13673 const uint64_t hash_fields) 13674 { 13675 struct mlx5_priv *priv = dev->data->dev_private; 13676 struct mlx5_shared_action_rss *shared_rss = 13677 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 13678 const uint32_t *hrxqs = shared_rss->hrxq; 13679 13680 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13681 case MLX5_RSS_HASH_IPV4: 13682 /* fall-through. */ 13683 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13684 /* fall-through. */ 13685 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13686 return hrxqs[0]; 13687 case MLX5_RSS_HASH_IPV4_TCP: 13688 /* fall-through. */ 13689 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13690 /* fall-through. */ 13691 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13692 return hrxqs[1]; 13693 case MLX5_RSS_HASH_IPV4_UDP: 13694 /* fall-through. */ 13695 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13696 /* fall-through. */ 13697 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13698 return hrxqs[2]; 13699 case MLX5_RSS_HASH_IPV6: 13700 /* fall-through. */ 13701 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13702 /* fall-through. */ 13703 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13704 return hrxqs[3]; 13705 case MLX5_RSS_HASH_IPV6_TCP: 13706 /* fall-through. */ 13707 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13708 /* fall-through. */ 13709 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13710 return hrxqs[4]; 13711 case MLX5_RSS_HASH_IPV6_UDP: 13712 /* fall-through. */ 13713 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13714 /* fall-through. */ 13715 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13716 return hrxqs[5]; 13717 case MLX5_RSS_HASH_NONE: 13718 return hrxqs[6]; 13719 default: 13720 return 0; 13721 } 13722 13723 } 13724 13725 /** 13726 * Apply the flow to the NIC, lock free, 13727 * (mutex should be acquired by caller). 13728 * 13729 * @param[in] dev 13730 * Pointer to the Ethernet device structure. 13731 * @param[in, out] flow 13732 * Pointer to flow structure. 13733 * @param[out] error 13734 * Pointer to error structure. 13735 * 13736 * @return 13737 * 0 on success, a negative errno value otherwise and rte_errno is set. 13738 */ 13739 static int 13740 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, 13741 struct rte_flow_error *error) 13742 { 13743 struct mlx5_flow_dv_workspace *dv; 13744 struct mlx5_flow_handle *dh; 13745 struct mlx5_flow_handle_dv *dv_h; 13746 struct mlx5_flow *dev_flow; 13747 struct mlx5_priv *priv = dev->data->dev_private; 13748 uint32_t handle_idx; 13749 int n; 13750 int err; 13751 int idx; 13752 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 13753 struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc; 13754 uint8_t misc_mask; 13755 13756 MLX5_ASSERT(wks); 13757 for (idx = wks->flow_idx - 1; idx >= 0; idx--) { 13758 dev_flow = &wks->flows[idx]; 13759 dv = &dev_flow->dv; 13760 dh = dev_flow->handle; 13761 dv_h = &dh->dvh; 13762 n = dv->actions_n; 13763 if (dh->fate_action == MLX5_FLOW_FATE_DROP) { 13764 if (dv->transfer) { 13765 MLX5_ASSERT(priv->sh->dr_drop_action); 13766 dv->actions[n++] = priv->sh->dr_drop_action; 13767 } else { 13768 #ifdef HAVE_MLX5DV_DR 13769 /* DR supports drop action placeholder. */ 13770 MLX5_ASSERT(priv->sh->dr_drop_action); 13771 dv->actions[n++] = dv->group ? 13772 priv->sh->dr_drop_action : 13773 priv->root_drop_action; 13774 #else 13775 /* For DV we use the explicit drop queue. */ 13776 MLX5_ASSERT(priv->drop_queue.hrxq); 13777 dv->actions[n++] = 13778 priv->drop_queue.hrxq->action; 13779 #endif 13780 } 13781 } else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE && 13782 !dv_h->rix_sample && !dv_h->rix_dest_array)) { 13783 struct mlx5_hrxq *hrxq; 13784 uint32_t hrxq_idx; 13785 13786 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc, 13787 &hrxq_idx); 13788 if (!hrxq) { 13789 rte_flow_error_set 13790 (error, rte_errno, 13791 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13792 "cannot get hash queue"); 13793 goto error; 13794 } 13795 dh->rix_hrxq = hrxq_idx; 13796 dv->actions[n++] = hrxq->action; 13797 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13798 struct mlx5_hrxq *hrxq = NULL; 13799 uint32_t hrxq_idx; 13800 13801 hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev, 13802 rss_desc->shared_rss, 13803 dev_flow->hash_fields); 13804 if (hrxq_idx) 13805 hrxq = mlx5_ipool_get 13806 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 13807 hrxq_idx); 13808 if (!hrxq) { 13809 rte_flow_error_set 13810 (error, rte_errno, 13811 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13812 "cannot get hash queue"); 13813 goto error; 13814 } 13815 dh->rix_srss = rss_desc->shared_rss; 13816 dv->actions[n++] = hrxq->action; 13817 } else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) { 13818 if (!priv->sh->default_miss_action) { 13819 rte_flow_error_set 13820 (error, rte_errno, 13821 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13822 "default miss action not be created."); 13823 goto error; 13824 } 13825 dv->actions[n++] = priv->sh->default_miss_action; 13826 } 13827 misc_mask = flow_dv_matcher_enable(dv->value.buf); 13828 __flow_dv_adjust_buf_size(&dv->value.size, misc_mask); 13829 err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object, 13830 (void *)&dv->value, n, 13831 dv->actions, &dh->drv_flow); 13832 if (err) { 13833 rte_flow_error_set 13834 (error, errno, 13835 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 13836 NULL, 13837 (!priv->config.allow_duplicate_pattern && 13838 errno == EEXIST) ? 13839 "duplicating pattern is not allowed" : 13840 "hardware refuses to create flow"); 13841 goto error; 13842 } 13843 if (priv->vmwa_context && 13844 dh->vf_vlan.tag && !dh->vf_vlan.created) { 13845 /* 13846 * The rule contains the VLAN pattern. 13847 * For VF we are going to create VLAN 13848 * interface to make hypervisor set correct 13849 * e-Switch vport context. 13850 */ 13851 mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan); 13852 } 13853 } 13854 return 0; 13855 error: 13856 err = rte_errno; /* Save rte_errno before cleanup. */ 13857 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles, 13858 handle_idx, dh, next) { 13859 /* hrxq is union, don't clear it if the flag is not set. */ 13860 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) { 13861 mlx5_hrxq_release(dev, dh->rix_hrxq); 13862 dh->rix_hrxq = 0; 13863 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13864 dh->rix_srss = 0; 13865 } 13866 if (dh->vf_vlan.tag && dh->vf_vlan.created) 13867 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 13868 } 13869 rte_errno = err; /* Restore rte_errno. */ 13870 return -rte_errno; 13871 } 13872 13873 void 13874 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused, 13875 struct mlx5_list_entry *entry) 13876 { 13877 struct mlx5_flow_dv_matcher *resource = container_of(entry, 13878 typeof(*resource), 13879 entry); 13880 13881 claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object)); 13882 mlx5_free(resource); 13883 } 13884 13885 /** 13886 * Release the flow matcher. 13887 * 13888 * @param dev 13889 * Pointer to Ethernet device. 13890 * @param port_id 13891 * Index to port ID action resource. 13892 * 13893 * @return 13894 * 1 while a reference on it exists, 0 when freed. 13895 */ 13896 static int 13897 flow_dv_matcher_release(struct rte_eth_dev *dev, 13898 struct mlx5_flow_handle *handle) 13899 { 13900 struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher; 13901 struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl, 13902 typeof(*tbl), tbl); 13903 int ret; 13904 13905 MLX5_ASSERT(matcher->matcher_object); 13906 ret = mlx5_list_unregister(tbl->matchers, &matcher->entry); 13907 flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl); 13908 return ret; 13909 } 13910 13911 void 13912 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 13913 { 13914 struct mlx5_dev_ctx_shared *sh = tool_ctx; 13915 struct mlx5_flow_dv_encap_decap_resource *res = 13916 container_of(entry, typeof(*res), entry); 13917 13918 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 13919 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 13920 } 13921 13922 /** 13923 * Release an encap/decap resource. 13924 * 13925 * @param dev 13926 * Pointer to Ethernet device. 13927 * @param encap_decap_idx 13928 * Index of encap decap resource. 13929 * 13930 * @return 13931 * 1 while a reference on it exists, 0 when freed. 13932 */ 13933 static int 13934 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 13935 uint32_t encap_decap_idx) 13936 { 13937 struct mlx5_priv *priv = dev->data->dev_private; 13938 struct mlx5_flow_dv_encap_decap_resource *resource; 13939 13940 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 13941 encap_decap_idx); 13942 if (!resource) 13943 return 0; 13944 MLX5_ASSERT(resource->action); 13945 return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry); 13946 } 13947 13948 /** 13949 * Release an jump to table action resource. 13950 * 13951 * @param dev 13952 * Pointer to Ethernet device. 13953 * @param rix_jump 13954 * Index to the jump action resource. 13955 * 13956 * @return 13957 * 1 while a reference on it exists, 0 when freed. 13958 */ 13959 static int 13960 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 13961 uint32_t rix_jump) 13962 { 13963 struct mlx5_priv *priv = dev->data->dev_private; 13964 struct mlx5_flow_tbl_data_entry *tbl_data; 13965 13966 tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP], 13967 rix_jump); 13968 if (!tbl_data) 13969 return 0; 13970 return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl); 13971 } 13972 13973 void 13974 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 13975 { 13976 struct mlx5_flow_dv_modify_hdr_resource *res = 13977 container_of(entry, typeof(*res), entry); 13978 struct mlx5_dev_ctx_shared *sh = tool_ctx; 13979 13980 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 13981 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 13982 } 13983 13984 /** 13985 * Release a modify-header resource. 13986 * 13987 * @param dev 13988 * Pointer to Ethernet device. 13989 * @param handle 13990 * Pointer to mlx5_flow_handle. 13991 * 13992 * @return 13993 * 1 while a reference on it exists, 0 when freed. 13994 */ 13995 static int 13996 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev, 13997 struct mlx5_flow_handle *handle) 13998 { 13999 struct mlx5_priv *priv = dev->data->dev_private; 14000 struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr; 14001 14002 MLX5_ASSERT(entry->action); 14003 return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry); 14004 } 14005 14006 void 14007 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14008 { 14009 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14010 struct mlx5_flow_dv_port_id_action_resource *resource = 14011 container_of(entry, typeof(*resource), entry); 14012 14013 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14014 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 14015 } 14016 14017 /** 14018 * Release port ID action resource. 14019 * 14020 * @param dev 14021 * Pointer to Ethernet device. 14022 * @param handle 14023 * Pointer to mlx5_flow_handle. 14024 * 14025 * @return 14026 * 1 while a reference on it exists, 0 when freed. 14027 */ 14028 static int 14029 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 14030 uint32_t port_id) 14031 { 14032 struct mlx5_priv *priv = dev->data->dev_private; 14033 struct mlx5_flow_dv_port_id_action_resource *resource; 14034 14035 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id); 14036 if (!resource) 14037 return 0; 14038 MLX5_ASSERT(resource->action); 14039 return mlx5_list_unregister(priv->sh->port_id_action_list, 14040 &resource->entry); 14041 } 14042 14043 /** 14044 * Release shared RSS action resource. 14045 * 14046 * @param dev 14047 * Pointer to Ethernet device. 14048 * @param srss 14049 * Shared RSS action index. 14050 */ 14051 static void 14052 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss) 14053 { 14054 struct mlx5_priv *priv = dev->data->dev_private; 14055 struct mlx5_shared_action_rss *shared_rss; 14056 14057 shared_rss = mlx5_ipool_get 14058 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss); 14059 __atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14060 } 14061 14062 void 14063 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14064 { 14065 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14066 struct mlx5_flow_dv_push_vlan_action_resource *resource = 14067 container_of(entry, typeof(*resource), entry); 14068 14069 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14070 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 14071 } 14072 14073 /** 14074 * Release push vlan action resource. 14075 * 14076 * @param dev 14077 * Pointer to Ethernet device. 14078 * @param handle 14079 * Pointer to mlx5_flow_handle. 14080 * 14081 * @return 14082 * 1 while a reference on it exists, 0 when freed. 14083 */ 14084 static int 14085 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev, 14086 struct mlx5_flow_handle *handle) 14087 { 14088 struct mlx5_priv *priv = dev->data->dev_private; 14089 struct mlx5_flow_dv_push_vlan_action_resource *resource; 14090 uint32_t idx = handle->dvh.rix_push_vlan; 14091 14092 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 14093 if (!resource) 14094 return 0; 14095 MLX5_ASSERT(resource->action); 14096 return mlx5_list_unregister(priv->sh->push_vlan_action_list, 14097 &resource->entry); 14098 } 14099 14100 /** 14101 * Release the fate resource. 14102 * 14103 * @param dev 14104 * Pointer to Ethernet device. 14105 * @param handle 14106 * Pointer to mlx5_flow_handle. 14107 */ 14108 static void 14109 flow_dv_fate_resource_release(struct rte_eth_dev *dev, 14110 struct mlx5_flow_handle *handle) 14111 { 14112 if (!handle->rix_fate) 14113 return; 14114 switch (handle->fate_action) { 14115 case MLX5_FLOW_FATE_QUEUE: 14116 if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array) 14117 mlx5_hrxq_release(dev, handle->rix_hrxq); 14118 break; 14119 case MLX5_FLOW_FATE_JUMP: 14120 flow_dv_jump_tbl_resource_release(dev, handle->rix_jump); 14121 break; 14122 case MLX5_FLOW_FATE_PORT_ID: 14123 flow_dv_port_id_action_resource_release(dev, 14124 handle->rix_port_id_action); 14125 break; 14126 default: 14127 DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action); 14128 break; 14129 } 14130 handle->rix_fate = 0; 14131 } 14132 14133 void 14134 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused, 14135 struct mlx5_list_entry *entry) 14136 { 14137 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 14138 typeof(*resource), 14139 entry); 14140 struct rte_eth_dev *dev = resource->dev; 14141 struct mlx5_priv *priv = dev->data->dev_private; 14142 14143 if (resource->verbs_action) 14144 claim_zero(mlx5_flow_os_destroy_flow_action 14145 (resource->verbs_action)); 14146 if (resource->normal_path_tbl) 14147 flow_dv_tbl_resource_release(MLX5_SH(dev), 14148 resource->normal_path_tbl); 14149 flow_dv_sample_sub_actions_release(dev, &resource->sample_idx); 14150 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 14151 DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource); 14152 } 14153 14154 /** 14155 * Release an sample resource. 14156 * 14157 * @param dev 14158 * Pointer to Ethernet device. 14159 * @param handle 14160 * Pointer to mlx5_flow_handle. 14161 * 14162 * @return 14163 * 1 while a reference on it exists, 0 when freed. 14164 */ 14165 static int 14166 flow_dv_sample_resource_release(struct rte_eth_dev *dev, 14167 struct mlx5_flow_handle *handle) 14168 { 14169 struct mlx5_priv *priv = dev->data->dev_private; 14170 struct mlx5_flow_dv_sample_resource *resource; 14171 14172 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE], 14173 handle->dvh.rix_sample); 14174 if (!resource) 14175 return 0; 14176 MLX5_ASSERT(resource->verbs_action); 14177 return mlx5_list_unregister(priv->sh->sample_action_list, 14178 &resource->entry); 14179 } 14180 14181 void 14182 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused, 14183 struct mlx5_list_entry *entry) 14184 { 14185 struct mlx5_flow_dv_dest_array_resource *resource = 14186 container_of(entry, typeof(*resource), entry); 14187 struct rte_eth_dev *dev = resource->dev; 14188 struct mlx5_priv *priv = dev->data->dev_private; 14189 uint32_t i = 0; 14190 14191 MLX5_ASSERT(resource->action); 14192 if (resource->action) 14193 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14194 for (; i < resource->num_of_dest; i++) 14195 flow_dv_sample_sub_actions_release(dev, 14196 &resource->sample_idx[i]); 14197 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 14198 DRV_LOG(DEBUG, "destination array resource %p: removed", 14199 (void *)resource); 14200 } 14201 14202 /** 14203 * Release an destination array resource. 14204 * 14205 * @param dev 14206 * Pointer to Ethernet device. 14207 * @param handle 14208 * Pointer to mlx5_flow_handle. 14209 * 14210 * @return 14211 * 1 while a reference on it exists, 0 when freed. 14212 */ 14213 static int 14214 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev, 14215 struct mlx5_flow_handle *handle) 14216 { 14217 struct mlx5_priv *priv = dev->data->dev_private; 14218 struct mlx5_flow_dv_dest_array_resource *resource; 14219 14220 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], 14221 handle->dvh.rix_dest_array); 14222 if (!resource) 14223 return 0; 14224 MLX5_ASSERT(resource->action); 14225 return mlx5_list_unregister(priv->sh->dest_array_list, 14226 &resource->entry); 14227 } 14228 14229 static void 14230 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev) 14231 { 14232 struct mlx5_priv *priv = dev->data->dev_private; 14233 struct mlx5_dev_ctx_shared *sh = priv->sh; 14234 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 14235 sh->geneve_tlv_option_resource; 14236 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 14237 if (geneve_opt_resource) { 14238 if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1, 14239 __ATOMIC_RELAXED))) { 14240 claim_zero(mlx5_devx_cmd_destroy 14241 (geneve_opt_resource->obj)); 14242 mlx5_free(sh->geneve_tlv_option_resource); 14243 sh->geneve_tlv_option_resource = NULL; 14244 } 14245 } 14246 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 14247 } 14248 14249 /** 14250 * Remove the flow from the NIC but keeps it in memory. 14251 * Lock free, (mutex should be acquired by caller). 14252 * 14253 * @param[in] dev 14254 * Pointer to Ethernet device. 14255 * @param[in, out] flow 14256 * Pointer to flow structure. 14257 */ 14258 static void 14259 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow) 14260 { 14261 struct mlx5_flow_handle *dh; 14262 uint32_t handle_idx; 14263 struct mlx5_priv *priv = dev->data->dev_private; 14264 14265 if (!flow) 14266 return; 14267 handle_idx = flow->dev_handles; 14268 while (handle_idx) { 14269 dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14270 handle_idx); 14271 if (!dh) 14272 return; 14273 if (dh->drv_flow) { 14274 claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow)); 14275 dh->drv_flow = NULL; 14276 } 14277 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) 14278 flow_dv_fate_resource_release(dev, dh); 14279 if (dh->vf_vlan.tag && dh->vf_vlan.created) 14280 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 14281 handle_idx = dh->next.next; 14282 } 14283 } 14284 14285 /** 14286 * Remove the flow from the NIC and the memory. 14287 * Lock free, (mutex should be acquired by caller). 14288 * 14289 * @param[in] dev 14290 * Pointer to the Ethernet device structure. 14291 * @param[in, out] flow 14292 * Pointer to flow structure. 14293 */ 14294 static void 14295 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) 14296 { 14297 struct mlx5_flow_handle *dev_handle; 14298 struct mlx5_priv *priv = dev->data->dev_private; 14299 struct mlx5_flow_meter_info *fm = NULL; 14300 uint32_t srss = 0; 14301 14302 if (!flow) 14303 return; 14304 flow_dv_remove(dev, flow); 14305 if (flow->counter) { 14306 flow_dv_counter_free(dev, flow->counter); 14307 flow->counter = 0; 14308 } 14309 if (flow->meter) { 14310 fm = flow_dv_meter_find_by_idx(priv, flow->meter); 14311 if (fm) 14312 mlx5_flow_meter_detach(priv, fm); 14313 flow->meter = 0; 14314 } 14315 /* Keep the current age handling by default. */ 14316 if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct) 14317 flow_dv_aso_ct_release(dev, flow->ct, NULL); 14318 else if (flow->age) 14319 flow_dv_aso_age_release(dev, flow->age); 14320 if (flow->geneve_tlv_option) { 14321 flow_dv_geneve_tlv_option_resource_release(dev); 14322 flow->geneve_tlv_option = 0; 14323 } 14324 while (flow->dev_handles) { 14325 uint32_t tmp_idx = flow->dev_handles; 14326 14327 dev_handle = mlx5_ipool_get(priv->sh->ipool 14328 [MLX5_IPOOL_MLX5_FLOW], tmp_idx); 14329 if (!dev_handle) 14330 return; 14331 flow->dev_handles = dev_handle->next.next; 14332 if (dev_handle->dvh.matcher) 14333 flow_dv_matcher_release(dev, dev_handle); 14334 if (dev_handle->dvh.rix_sample) 14335 flow_dv_sample_resource_release(dev, dev_handle); 14336 if (dev_handle->dvh.rix_dest_array) 14337 flow_dv_dest_array_resource_release(dev, dev_handle); 14338 if (dev_handle->dvh.rix_encap_decap) 14339 flow_dv_encap_decap_resource_release(dev, 14340 dev_handle->dvh.rix_encap_decap); 14341 if (dev_handle->dvh.modify_hdr) 14342 flow_dv_modify_hdr_resource_release(dev, dev_handle); 14343 if (dev_handle->dvh.rix_push_vlan) 14344 flow_dv_push_vlan_action_resource_release(dev, 14345 dev_handle); 14346 if (dev_handle->dvh.rix_tag) 14347 flow_dv_tag_release(dev, 14348 dev_handle->dvh.rix_tag); 14349 if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS) 14350 flow_dv_fate_resource_release(dev, dev_handle); 14351 else if (!srss) 14352 srss = dev_handle->rix_srss; 14353 if (fm && dev_handle->is_meter_flow_id && 14354 dev_handle->split_flow_id) 14355 mlx5_ipool_free(fm->flow_ipool, 14356 dev_handle->split_flow_id); 14357 else if (dev_handle->split_flow_id && 14358 !dev_handle->is_meter_flow_id) 14359 mlx5_ipool_free(priv->sh->ipool 14360 [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], 14361 dev_handle->split_flow_id); 14362 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14363 tmp_idx); 14364 } 14365 if (srss) 14366 flow_dv_shared_rss_action_release(dev, srss); 14367 } 14368 14369 /** 14370 * Release array of hash RX queue objects. 14371 * Helper function. 14372 * 14373 * @param[in] dev 14374 * Pointer to the Ethernet device structure. 14375 * @param[in, out] hrxqs 14376 * Array of hash RX queue objects. 14377 * 14378 * @return 14379 * Total number of references to hash RX queue objects in *hrxqs* array 14380 * after this operation. 14381 */ 14382 static int 14383 __flow_dv_hrxqs_release(struct rte_eth_dev *dev, 14384 uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN]) 14385 { 14386 size_t i; 14387 int remaining = 0; 14388 14389 for (i = 0; i < RTE_DIM(*hrxqs); i++) { 14390 int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]); 14391 14392 if (!ret) 14393 (*hrxqs)[i] = 0; 14394 remaining += ret; 14395 } 14396 return remaining; 14397 } 14398 14399 /** 14400 * Release all hash RX queue objects representing shared RSS action. 14401 * 14402 * @param[in] dev 14403 * Pointer to the Ethernet device structure. 14404 * @param[in, out] action 14405 * Shared RSS action to remove hash RX queue objects from. 14406 * 14407 * @return 14408 * Total number of references to hash RX queue objects stored in *action* 14409 * after this operation. 14410 * Expected to be 0 if no external references held. 14411 */ 14412 static int 14413 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev, 14414 struct mlx5_shared_action_rss *shared_rss) 14415 { 14416 return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq); 14417 } 14418 14419 /** 14420 * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to 14421 * user input. 14422 * 14423 * Only one hash value is available for one L3+L4 combination: 14424 * for example: 14425 * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and 14426 * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share 14427 * same slot in mlx5_rss_hash_fields. 14428 * 14429 * @param[in] rss 14430 * Pointer to the shared action RSS conf. 14431 * @param[in, out] hash_field 14432 * hash_field variable needed to be adjusted. 14433 * 14434 * @return 14435 * void 14436 */ 14437 static void 14438 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss, 14439 uint64_t *hash_field) 14440 { 14441 uint64_t rss_types = rss->origin.types; 14442 14443 switch (*hash_field & ~IBV_RX_HASH_INNER) { 14444 case MLX5_RSS_HASH_IPV4: 14445 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 14446 *hash_field &= ~MLX5_RSS_HASH_IPV4; 14447 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 14448 *hash_field |= IBV_RX_HASH_DST_IPV4; 14449 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 14450 *hash_field |= IBV_RX_HASH_SRC_IPV4; 14451 else 14452 *hash_field |= MLX5_RSS_HASH_IPV4; 14453 } 14454 return; 14455 case MLX5_RSS_HASH_IPV6: 14456 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 14457 *hash_field &= ~MLX5_RSS_HASH_IPV6; 14458 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 14459 *hash_field |= IBV_RX_HASH_DST_IPV6; 14460 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 14461 *hash_field |= IBV_RX_HASH_SRC_IPV6; 14462 else 14463 *hash_field |= MLX5_RSS_HASH_IPV6; 14464 } 14465 return; 14466 case MLX5_RSS_HASH_IPV4_UDP: 14467 /* fall-through. */ 14468 case MLX5_RSS_HASH_IPV6_UDP: 14469 if (rss_types & RTE_ETH_RSS_UDP) { 14470 *hash_field &= ~MLX5_UDP_IBV_RX_HASH; 14471 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 14472 *hash_field |= IBV_RX_HASH_DST_PORT_UDP; 14473 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 14474 *hash_field |= IBV_RX_HASH_SRC_PORT_UDP; 14475 else 14476 *hash_field |= MLX5_UDP_IBV_RX_HASH; 14477 } 14478 return; 14479 case MLX5_RSS_HASH_IPV4_TCP: 14480 /* fall-through. */ 14481 case MLX5_RSS_HASH_IPV6_TCP: 14482 if (rss_types & RTE_ETH_RSS_TCP) { 14483 *hash_field &= ~MLX5_TCP_IBV_RX_HASH; 14484 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 14485 *hash_field |= IBV_RX_HASH_DST_PORT_TCP; 14486 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 14487 *hash_field |= IBV_RX_HASH_SRC_PORT_TCP; 14488 else 14489 *hash_field |= MLX5_TCP_IBV_RX_HASH; 14490 } 14491 return; 14492 default: 14493 return; 14494 } 14495 } 14496 14497 /** 14498 * Setup shared RSS action. 14499 * Prepare set of hash RX queue objects sufficient to handle all valid 14500 * hash_fields combinations (see enum ibv_rx_hash_fields). 14501 * 14502 * @param[in] dev 14503 * Pointer to the Ethernet device structure. 14504 * @param[in] action_idx 14505 * Shared RSS action ipool index. 14506 * @param[in, out] action 14507 * Partially initialized shared RSS action. 14508 * @param[out] error 14509 * Perform verbose error reporting if not NULL. Initialized in case of 14510 * error only. 14511 * 14512 * @return 14513 * 0 on success, otherwise negative errno value. 14514 */ 14515 static int 14516 __flow_dv_action_rss_setup(struct rte_eth_dev *dev, 14517 uint32_t action_idx, 14518 struct mlx5_shared_action_rss *shared_rss, 14519 struct rte_flow_error *error) 14520 { 14521 struct mlx5_flow_rss_desc rss_desc = { 0 }; 14522 size_t i; 14523 int err; 14524 14525 if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) { 14526 return rte_flow_error_set(error, rte_errno, 14527 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14528 "cannot setup indirection table"); 14529 } 14530 memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN); 14531 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN; 14532 rss_desc.const_q = shared_rss->origin.queue; 14533 rss_desc.queue_num = shared_rss->origin.queue_num; 14534 /* Set non-zero value to indicate a shared RSS. */ 14535 rss_desc.shared_rss = action_idx; 14536 rss_desc.ind_tbl = shared_rss->ind_tbl; 14537 for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) { 14538 uint32_t hrxq_idx; 14539 uint64_t hash_fields = mlx5_rss_hash_fields[i]; 14540 int tunnel = 0; 14541 14542 __flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields); 14543 if (shared_rss->origin.level > 1) { 14544 hash_fields |= IBV_RX_HASH_INNER; 14545 tunnel = 1; 14546 } 14547 rss_desc.tunnel = tunnel; 14548 rss_desc.hash_fields = hash_fields; 14549 hrxq_idx = mlx5_hrxq_get(dev, &rss_desc); 14550 if (!hrxq_idx) { 14551 rte_flow_error_set 14552 (error, rte_errno, 14553 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14554 "cannot get hash queue"); 14555 goto error_hrxq_new; 14556 } 14557 err = __flow_dv_action_rss_hrxq_set 14558 (shared_rss, hash_fields, hrxq_idx); 14559 MLX5_ASSERT(!err); 14560 } 14561 return 0; 14562 error_hrxq_new: 14563 err = rte_errno; 14564 __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14565 if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true)) 14566 shared_rss->ind_tbl = NULL; 14567 rte_errno = err; 14568 return -rte_errno; 14569 } 14570 14571 /** 14572 * Create shared RSS action. 14573 * 14574 * @param[in] dev 14575 * Pointer to the Ethernet device structure. 14576 * @param[in] conf 14577 * Shared action configuration. 14578 * @param[in] rss 14579 * RSS action specification used to create shared action. 14580 * @param[out] error 14581 * Perform verbose error reporting if not NULL. Initialized in case of 14582 * error only. 14583 * 14584 * @return 14585 * A valid shared action ID in case of success, 0 otherwise and 14586 * rte_errno is set. 14587 */ 14588 static uint32_t 14589 __flow_dv_action_rss_create(struct rte_eth_dev *dev, 14590 const struct rte_flow_indir_action_conf *conf, 14591 const struct rte_flow_action_rss *rss, 14592 struct rte_flow_error *error) 14593 { 14594 struct mlx5_priv *priv = dev->data->dev_private; 14595 struct mlx5_shared_action_rss *shared_rss = NULL; 14596 void *queue = NULL; 14597 struct rte_flow_action_rss *origin; 14598 const uint8_t *rss_key; 14599 uint32_t queue_size = rss->queue_num * sizeof(uint16_t); 14600 uint32_t idx; 14601 14602 RTE_SET_USED(conf); 14603 queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 14604 0, SOCKET_ID_ANY); 14605 shared_rss = mlx5_ipool_zmalloc 14606 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx); 14607 if (!shared_rss || !queue) { 14608 rte_flow_error_set(error, ENOMEM, 14609 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14610 "cannot allocate resource memory"); 14611 goto error_rss_init; 14612 } 14613 if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) { 14614 rte_flow_error_set(error, E2BIG, 14615 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14616 "rss action number out of range"); 14617 goto error_rss_init; 14618 } 14619 shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO, 14620 sizeof(*shared_rss->ind_tbl), 14621 0, SOCKET_ID_ANY); 14622 if (!shared_rss->ind_tbl) { 14623 rte_flow_error_set(error, ENOMEM, 14624 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14625 "cannot allocate resource memory"); 14626 goto error_rss_init; 14627 } 14628 memcpy(queue, rss->queue, queue_size); 14629 shared_rss->ind_tbl->queues = queue; 14630 shared_rss->ind_tbl->queues_n = rss->queue_num; 14631 origin = &shared_rss->origin; 14632 origin->func = rss->func; 14633 origin->level = rss->level; 14634 /* RSS type 0 indicates default RSS type (RTE_ETH_RSS_IP). */ 14635 origin->types = !rss->types ? RTE_ETH_RSS_IP : rss->types; 14636 /* NULL RSS key indicates default RSS key. */ 14637 rss_key = !rss->key ? rss_hash_default_key : rss->key; 14638 memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 14639 origin->key = &shared_rss->key[0]; 14640 origin->key_len = MLX5_RSS_HASH_KEY_LEN; 14641 origin->queue = queue; 14642 origin->queue_num = rss->queue_num; 14643 if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error)) 14644 goto error_rss_init; 14645 rte_spinlock_init(&shared_rss->action_rss_sl); 14646 __atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14647 rte_spinlock_lock(&priv->shared_act_sl); 14648 ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14649 &priv->rss_shared_actions, idx, shared_rss, next); 14650 rte_spinlock_unlock(&priv->shared_act_sl); 14651 return idx; 14652 error_rss_init: 14653 if (shared_rss) { 14654 if (shared_rss->ind_tbl) 14655 mlx5_free(shared_rss->ind_tbl); 14656 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14657 idx); 14658 } 14659 if (queue) 14660 mlx5_free(queue); 14661 return 0; 14662 } 14663 14664 /** 14665 * Destroy the shared RSS action. 14666 * Release related hash RX queue objects. 14667 * 14668 * @param[in] dev 14669 * Pointer to the Ethernet device structure. 14670 * @param[in] idx 14671 * The shared RSS action object ID to be removed. 14672 * @param[out] error 14673 * Perform verbose error reporting if not NULL. Initialized in case of 14674 * error only. 14675 * 14676 * @return 14677 * 0 on success, otherwise negative errno value. 14678 */ 14679 static int 14680 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, 14681 struct rte_flow_error *error) 14682 { 14683 struct mlx5_priv *priv = dev->data->dev_private; 14684 struct mlx5_shared_action_rss *shared_rss = 14685 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14686 uint32_t old_refcnt = 1; 14687 int remaining; 14688 uint16_t *queue = NULL; 14689 14690 if (!shared_rss) 14691 return rte_flow_error_set(error, EINVAL, 14692 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14693 "invalid shared action"); 14694 if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt, 14695 0, 0, __ATOMIC_ACQUIRE, 14696 __ATOMIC_RELAXED)) 14697 return rte_flow_error_set(error, EBUSY, 14698 RTE_FLOW_ERROR_TYPE_ACTION, 14699 NULL, 14700 "shared rss has references"); 14701 remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14702 if (remaining) 14703 return rte_flow_error_set(error, EBUSY, 14704 RTE_FLOW_ERROR_TYPE_ACTION, 14705 NULL, 14706 "shared rss hrxq has references"); 14707 queue = shared_rss->ind_tbl->queues; 14708 remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true); 14709 if (remaining) 14710 return rte_flow_error_set(error, EBUSY, 14711 RTE_FLOW_ERROR_TYPE_ACTION, 14712 NULL, 14713 "shared rss indirection table has" 14714 " references"); 14715 mlx5_free(queue); 14716 rte_spinlock_lock(&priv->shared_act_sl); 14717 ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14718 &priv->rss_shared_actions, idx, shared_rss, next); 14719 rte_spinlock_unlock(&priv->shared_act_sl); 14720 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14721 idx); 14722 return 0; 14723 } 14724 14725 /** 14726 * Create indirect action, lock free, 14727 * (mutex should be acquired by caller). 14728 * Dispatcher for action type specific call. 14729 * 14730 * @param[in] dev 14731 * Pointer to the Ethernet device structure. 14732 * @param[in] conf 14733 * Shared action configuration. 14734 * @param[in] action 14735 * Action specification used to create indirect action. 14736 * @param[out] error 14737 * Perform verbose error reporting if not NULL. Initialized in case of 14738 * error only. 14739 * 14740 * @return 14741 * A valid shared action handle in case of success, NULL otherwise and 14742 * rte_errno is set. 14743 */ 14744 static struct rte_flow_action_handle * 14745 flow_dv_action_create(struct rte_eth_dev *dev, 14746 const struct rte_flow_indir_action_conf *conf, 14747 const struct rte_flow_action *action, 14748 struct rte_flow_error *err) 14749 { 14750 struct mlx5_priv *priv = dev->data->dev_private; 14751 uint32_t age_idx = 0; 14752 uint32_t idx = 0; 14753 uint32_t ret = 0; 14754 14755 switch (action->type) { 14756 case RTE_FLOW_ACTION_TYPE_RSS: 14757 ret = __flow_dv_action_rss_create(dev, conf, action->conf, err); 14758 idx = (MLX5_INDIRECT_ACTION_TYPE_RSS << 14759 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14760 break; 14761 case RTE_FLOW_ACTION_TYPE_AGE: 14762 age_idx = flow_dv_aso_age_alloc(dev, err); 14763 if (!age_idx) { 14764 ret = -rte_errno; 14765 break; 14766 } 14767 idx = (MLX5_INDIRECT_ACTION_TYPE_AGE << 14768 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx; 14769 flow_dv_aso_age_params_init(dev, age_idx, 14770 ((const struct rte_flow_action_age *) 14771 action->conf)->context ? 14772 ((const struct rte_flow_action_age *) 14773 action->conf)->context : 14774 (void *)(uintptr_t)idx, 14775 ((const struct rte_flow_action_age *) 14776 action->conf)->timeout); 14777 ret = age_idx; 14778 break; 14779 case RTE_FLOW_ACTION_TYPE_COUNT: 14780 ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL); 14781 idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT << 14782 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14783 break; 14784 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 14785 ret = flow_dv_translate_create_conntrack(dev, action->conf, 14786 err); 14787 idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret); 14788 break; 14789 default: 14790 rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, 14791 NULL, "action type not supported"); 14792 break; 14793 } 14794 return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL; 14795 } 14796 14797 /** 14798 * Destroy the indirect action. 14799 * Release action related resources on the NIC and the memory. 14800 * Lock free, (mutex should be acquired by caller). 14801 * Dispatcher for action type specific call. 14802 * 14803 * @param[in] dev 14804 * Pointer to the Ethernet device structure. 14805 * @param[in] handle 14806 * The indirect action object handle to be removed. 14807 * @param[out] error 14808 * Perform verbose error reporting if not NULL. Initialized in case of 14809 * error only. 14810 * 14811 * @return 14812 * 0 on success, otherwise negative errno value. 14813 */ 14814 static int 14815 flow_dv_action_destroy(struct rte_eth_dev *dev, 14816 struct rte_flow_action_handle *handle, 14817 struct rte_flow_error *error) 14818 { 14819 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 14820 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 14821 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 14822 struct mlx5_flow_counter *cnt; 14823 uint32_t no_flow_refcnt = 1; 14824 int ret; 14825 14826 switch (type) { 14827 case MLX5_INDIRECT_ACTION_TYPE_RSS: 14828 return __flow_dv_action_rss_release(dev, idx, error); 14829 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 14830 cnt = flow_dv_counter_get_by_idx(dev, idx, NULL); 14831 if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt, 14832 &no_flow_refcnt, 1, false, 14833 __ATOMIC_ACQUIRE, 14834 __ATOMIC_RELAXED)) 14835 return rte_flow_error_set(error, EBUSY, 14836 RTE_FLOW_ERROR_TYPE_ACTION, 14837 NULL, 14838 "Indirect count action has references"); 14839 flow_dv_counter_free(dev, idx); 14840 return 0; 14841 case MLX5_INDIRECT_ACTION_TYPE_AGE: 14842 ret = flow_dv_aso_age_release(dev, idx); 14843 if (ret) 14844 /* 14845 * In this case, the last flow has a reference will 14846 * actually release the age action. 14847 */ 14848 DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was" 14849 " released with references %d.", idx, ret); 14850 return 0; 14851 case MLX5_INDIRECT_ACTION_TYPE_CT: 14852 ret = flow_dv_aso_ct_release(dev, idx, error); 14853 if (ret < 0) 14854 return ret; 14855 if (ret > 0) 14856 DRV_LOG(DEBUG, "Connection tracking object %u still " 14857 "has references %d.", idx, ret); 14858 return 0; 14859 default: 14860 return rte_flow_error_set(error, ENOTSUP, 14861 RTE_FLOW_ERROR_TYPE_ACTION, 14862 NULL, 14863 "action type not supported"); 14864 } 14865 } 14866 14867 /** 14868 * Updates in place shared RSS action configuration. 14869 * 14870 * @param[in] dev 14871 * Pointer to the Ethernet device structure. 14872 * @param[in] idx 14873 * The shared RSS action object ID to be updated. 14874 * @param[in] action_conf 14875 * RSS action specification used to modify *shared_rss*. 14876 * @param[out] error 14877 * Perform verbose error reporting if not NULL. Initialized in case of 14878 * error only. 14879 * 14880 * @return 14881 * 0 on success, otherwise negative errno value. 14882 * @note: currently only support update of RSS queues. 14883 */ 14884 static int 14885 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx, 14886 const struct rte_flow_action_rss *action_conf, 14887 struct rte_flow_error *error) 14888 { 14889 struct mlx5_priv *priv = dev->data->dev_private; 14890 struct mlx5_shared_action_rss *shared_rss = 14891 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14892 int ret = 0; 14893 void *queue = NULL; 14894 uint16_t *queue_old = NULL; 14895 uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t); 14896 14897 if (!shared_rss) 14898 return rte_flow_error_set(error, EINVAL, 14899 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14900 "invalid shared action to update"); 14901 if (priv->obj_ops.ind_table_modify == NULL) 14902 return rte_flow_error_set(error, ENOTSUP, 14903 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14904 "cannot modify indirection table"); 14905 queue = mlx5_malloc(MLX5_MEM_ZERO, 14906 RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 14907 0, SOCKET_ID_ANY); 14908 if (!queue) 14909 return rte_flow_error_set(error, ENOMEM, 14910 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14911 NULL, 14912 "cannot allocate resource memory"); 14913 memcpy(queue, action_conf->queue, queue_size); 14914 MLX5_ASSERT(shared_rss->ind_tbl); 14915 rte_spinlock_lock(&shared_rss->action_rss_sl); 14916 queue_old = shared_rss->ind_tbl->queues; 14917 ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl, 14918 queue, action_conf->queue_num, true); 14919 if (ret) { 14920 mlx5_free(queue); 14921 ret = rte_flow_error_set(error, rte_errno, 14922 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14923 "cannot update indirection table"); 14924 } else { 14925 mlx5_free(queue_old); 14926 shared_rss->origin.queue = queue; 14927 shared_rss->origin.queue_num = action_conf->queue_num; 14928 } 14929 rte_spinlock_unlock(&shared_rss->action_rss_sl); 14930 return ret; 14931 } 14932 14933 /* 14934 * Updates in place conntrack context or direction. 14935 * Context update should be synchronized. 14936 * 14937 * @param[in] dev 14938 * Pointer to the Ethernet device structure. 14939 * @param[in] idx 14940 * The conntrack object ID to be updated. 14941 * @param[in] update 14942 * Pointer to the structure of information to update. 14943 * @param[out] error 14944 * Perform verbose error reporting if not NULL. Initialized in case of 14945 * error only. 14946 * 14947 * @return 14948 * 0 on success, otherwise negative errno value. 14949 */ 14950 static int 14951 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, 14952 const struct rte_flow_modify_conntrack *update, 14953 struct rte_flow_error *error) 14954 { 14955 struct mlx5_priv *priv = dev->data->dev_private; 14956 struct mlx5_aso_ct_action *ct; 14957 const struct rte_flow_action_conntrack *new_prf; 14958 int ret = 0; 14959 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 14960 uint32_t dev_idx; 14961 14962 if (PORT_ID(priv) != owner) 14963 return rte_flow_error_set(error, EACCES, 14964 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14965 NULL, 14966 "CT object owned by another port"); 14967 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 14968 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 14969 if (!ct->refcnt) 14970 return rte_flow_error_set(error, ENOMEM, 14971 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14972 NULL, 14973 "CT object is inactive"); 14974 new_prf = &update->new_ct; 14975 if (update->direction) 14976 ct->is_original = !!new_prf->is_original_dir; 14977 if (update->state) { 14978 /* Only validate the profile when it needs to be updated. */ 14979 ret = mlx5_validate_action_ct(dev, new_prf, error); 14980 if (ret) 14981 return ret; 14982 ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf); 14983 if (ret) 14984 return rte_flow_error_set(error, EIO, 14985 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14986 NULL, 14987 "Failed to send CT context update WQE"); 14988 /* Block until ready or a failure. */ 14989 ret = mlx5_aso_ct_available(priv->sh, ct); 14990 if (ret) 14991 rte_flow_error_set(error, rte_errno, 14992 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14993 NULL, 14994 "Timeout to get the CT update"); 14995 } 14996 return ret; 14997 } 14998 14999 /** 15000 * Updates in place shared action configuration, lock free, 15001 * (mutex should be acquired by caller). 15002 * 15003 * @param[in] dev 15004 * Pointer to the Ethernet device structure. 15005 * @param[in] handle 15006 * The indirect action object handle to be updated. 15007 * @param[in] update 15008 * Action specification used to modify the action pointed by *handle*. 15009 * *update* could be of same type with the action pointed by the *handle* 15010 * handle argument, or some other structures like a wrapper, depending on 15011 * the indirect action type. 15012 * @param[out] error 15013 * Perform verbose error reporting if not NULL. Initialized in case of 15014 * error only. 15015 * 15016 * @return 15017 * 0 on success, otherwise negative errno value. 15018 */ 15019 static int 15020 flow_dv_action_update(struct rte_eth_dev *dev, 15021 struct rte_flow_action_handle *handle, 15022 const void *update, 15023 struct rte_flow_error *err) 15024 { 15025 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15026 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15027 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15028 const void *action_conf; 15029 15030 switch (type) { 15031 case MLX5_INDIRECT_ACTION_TYPE_RSS: 15032 action_conf = ((const struct rte_flow_action *)update)->conf; 15033 return __flow_dv_action_rss_update(dev, idx, action_conf, err); 15034 case MLX5_INDIRECT_ACTION_TYPE_CT: 15035 return __flow_dv_action_ct_update(dev, idx, update, err); 15036 default: 15037 return rte_flow_error_set(err, ENOTSUP, 15038 RTE_FLOW_ERROR_TYPE_ACTION, 15039 NULL, 15040 "action type update not supported"); 15041 } 15042 } 15043 15044 /** 15045 * Destroy the meter sub policy table rules. 15046 * Lock free, (mutex should be acquired by caller). 15047 * 15048 * @param[in] dev 15049 * Pointer to Ethernet device. 15050 * @param[in] sub_policy 15051 * Pointer to meter sub policy table. 15052 */ 15053 static void 15054 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, 15055 struct mlx5_flow_meter_sub_policy *sub_policy) 15056 { 15057 struct mlx5_priv *priv = dev->data->dev_private; 15058 struct mlx5_flow_tbl_data_entry *tbl; 15059 struct mlx5_flow_meter_policy *policy = sub_policy->main_policy; 15060 struct mlx5_flow_meter_info *next_fm; 15061 struct mlx5_sub_policy_color_rule *color_rule; 15062 void *tmp; 15063 uint32_t i; 15064 15065 for (i = 0; i < RTE_COLORS; i++) { 15066 next_fm = NULL; 15067 if (i == RTE_COLOR_GREEN && policy && 15068 policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) 15069 next_fm = mlx5_flow_meter_find(priv, 15070 policy->act_cnt[i].next_mtr_id, NULL); 15071 RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], 15072 next_port, tmp) { 15073 claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule)); 15074 tbl = container_of(color_rule->matcher->tbl, 15075 typeof(*tbl), tbl); 15076 mlx5_list_unregister(tbl->matchers, 15077 &color_rule->matcher->entry); 15078 TAILQ_REMOVE(&sub_policy->color_rules[i], 15079 color_rule, next_port); 15080 mlx5_free(color_rule); 15081 if (next_fm) 15082 mlx5_flow_meter_detach(priv, next_fm); 15083 } 15084 } 15085 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15086 if (sub_policy->rix_hrxq[i]) { 15087 if (policy && !policy->is_hierarchy) 15088 mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]); 15089 sub_policy->rix_hrxq[i] = 0; 15090 } 15091 if (sub_policy->jump_tbl[i]) { 15092 flow_dv_tbl_resource_release(MLX5_SH(dev), 15093 sub_policy->jump_tbl[i]); 15094 sub_policy->jump_tbl[i] = NULL; 15095 } 15096 } 15097 if (sub_policy->tbl_rsc) { 15098 flow_dv_tbl_resource_release(MLX5_SH(dev), 15099 sub_policy->tbl_rsc); 15100 sub_policy->tbl_rsc = NULL; 15101 } 15102 } 15103 15104 /** 15105 * Destroy policy rules, lock free, 15106 * (mutex should be acquired by caller). 15107 * Dispatcher for action type specific call. 15108 * 15109 * @param[in] dev 15110 * Pointer to the Ethernet device structure. 15111 * @param[in] mtr_policy 15112 * Meter policy struct. 15113 */ 15114 static void 15115 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, 15116 struct mlx5_flow_meter_policy *mtr_policy) 15117 { 15118 uint32_t i, j; 15119 struct mlx5_flow_meter_sub_policy *sub_policy; 15120 uint16_t sub_policy_num; 15121 15122 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15123 sub_policy_num = (mtr_policy->sub_policy_num >> 15124 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15125 MLX5_MTR_SUB_POLICY_NUM_MASK; 15126 for (j = 0; j < sub_policy_num; j++) { 15127 sub_policy = mtr_policy->sub_policys[i][j]; 15128 if (sub_policy) 15129 __flow_dv_destroy_sub_policy_rules(dev, 15130 sub_policy); 15131 } 15132 } 15133 } 15134 15135 /** 15136 * Destroy policy action, lock free, 15137 * (mutex should be acquired by caller). 15138 * Dispatcher for action type specific call. 15139 * 15140 * @param[in] dev 15141 * Pointer to the Ethernet device structure. 15142 * @param[in] mtr_policy 15143 * Meter policy struct. 15144 */ 15145 static void 15146 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev, 15147 struct mlx5_flow_meter_policy *mtr_policy) 15148 { 15149 struct rte_flow_action *rss_action; 15150 struct mlx5_flow_handle dev_handle; 15151 uint32_t i, j; 15152 15153 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15154 if (mtr_policy->act_cnt[i].rix_mark) { 15155 flow_dv_tag_release(dev, 15156 mtr_policy->act_cnt[i].rix_mark); 15157 mtr_policy->act_cnt[i].rix_mark = 0; 15158 } 15159 if (mtr_policy->act_cnt[i].modify_hdr) { 15160 dev_handle.dvh.modify_hdr = 15161 mtr_policy->act_cnt[i].modify_hdr; 15162 flow_dv_modify_hdr_resource_release(dev, &dev_handle); 15163 } 15164 switch (mtr_policy->act_cnt[i].fate_action) { 15165 case MLX5_FLOW_FATE_SHARED_RSS: 15166 rss_action = mtr_policy->act_cnt[i].rss; 15167 mlx5_free(rss_action); 15168 break; 15169 case MLX5_FLOW_FATE_PORT_ID: 15170 if (mtr_policy->act_cnt[i].rix_port_id_action) { 15171 flow_dv_port_id_action_resource_release(dev, 15172 mtr_policy->act_cnt[i].rix_port_id_action); 15173 mtr_policy->act_cnt[i].rix_port_id_action = 0; 15174 } 15175 break; 15176 case MLX5_FLOW_FATE_DROP: 15177 case MLX5_FLOW_FATE_JUMP: 15178 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15179 mtr_policy->act_cnt[i].dr_jump_action[j] = 15180 NULL; 15181 break; 15182 default: 15183 /*Queue action do nothing*/ 15184 break; 15185 } 15186 } 15187 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15188 mtr_policy->dr_drop_action[j] = NULL; 15189 } 15190 15191 /** 15192 * Create policy action per domain, lock free, 15193 * (mutex should be acquired by caller). 15194 * Dispatcher for action type specific call. 15195 * 15196 * @param[in] dev 15197 * Pointer to the Ethernet device structure. 15198 * @param[in] mtr_policy 15199 * Meter policy struct. 15200 * @param[in] action 15201 * Action specification used to create meter actions. 15202 * @param[out] error 15203 * Perform verbose error reporting if not NULL. Initialized in case of 15204 * error only. 15205 * 15206 * @return 15207 * 0 on success, otherwise negative errno value. 15208 */ 15209 static int 15210 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, 15211 struct mlx5_flow_meter_policy *mtr_policy, 15212 const struct rte_flow_action *actions[RTE_COLORS], 15213 enum mlx5_meter_domain domain, 15214 struct rte_mtr_error *error) 15215 { 15216 struct mlx5_priv *priv = dev->data->dev_private; 15217 struct rte_flow_error flow_err; 15218 const struct rte_flow_action *act; 15219 uint64_t action_flags; 15220 struct mlx5_flow_handle dh; 15221 struct mlx5_flow dev_flow; 15222 struct mlx5_flow_dv_port_id_action_resource port_id_action; 15223 int i, ret; 15224 uint8_t egress, transfer; 15225 struct mlx5_meter_policy_action_container *act_cnt = NULL; 15226 union { 15227 struct mlx5_flow_dv_modify_hdr_resource res; 15228 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 15229 sizeof(struct mlx5_modification_cmd) * 15230 (MLX5_MAX_MODIFY_NUM + 1)]; 15231 } mhdr_dummy; 15232 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 15233 15234 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 15235 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 15236 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 15237 memset(&dev_flow, 0, sizeof(struct mlx5_flow)); 15238 memset(&port_id_action, 0, 15239 sizeof(struct mlx5_flow_dv_port_id_action_resource)); 15240 memset(mhdr_res, 0, sizeof(*mhdr_res)); 15241 mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 15242 (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 15243 MLX5DV_FLOW_TABLE_TYPE_NIC_RX); 15244 dev_flow.handle = &dh; 15245 dev_flow.dv.port_id_action = &port_id_action; 15246 dev_flow.external = true; 15247 for (i = 0; i < RTE_COLORS; i++) { 15248 if (i < MLX5_MTR_RTE_COLORS) 15249 act_cnt = &mtr_policy->act_cnt[i]; 15250 /* Skip the color policy actions creation. */ 15251 if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) || 15252 (i == RTE_COLOR_GREEN && mtr_policy->skip_g)) 15253 continue; 15254 action_flags = 0; 15255 for (act = actions[i]; 15256 act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 15257 switch (act->type) { 15258 case RTE_FLOW_ACTION_TYPE_MARK: 15259 { 15260 uint32_t tag_be = mlx5_flow_mark_set 15261 (((const struct rte_flow_action_mark *) 15262 (act->conf))->id); 15263 15264 if (i >= MLX5_MTR_RTE_COLORS) 15265 return -rte_mtr_error_set(error, 15266 ENOTSUP, 15267 RTE_MTR_ERROR_TYPE_METER_POLICY, 15268 NULL, 15269 "cannot create policy " 15270 "mark action for this color"); 15271 dev_flow.handle->mark = 1; 15272 if (flow_dv_tag_resource_register(dev, tag_be, 15273 &dev_flow, &flow_err)) 15274 return -rte_mtr_error_set(error, 15275 ENOTSUP, 15276 RTE_MTR_ERROR_TYPE_METER_POLICY, 15277 NULL, 15278 "cannot setup policy mark action"); 15279 MLX5_ASSERT(dev_flow.dv.tag_resource); 15280 act_cnt->rix_mark = 15281 dev_flow.handle->dvh.rix_tag; 15282 action_flags |= MLX5_FLOW_ACTION_MARK; 15283 break; 15284 } 15285 case RTE_FLOW_ACTION_TYPE_SET_TAG: 15286 if (i >= MLX5_MTR_RTE_COLORS) 15287 return -rte_mtr_error_set(error, 15288 ENOTSUP, 15289 RTE_MTR_ERROR_TYPE_METER_POLICY, 15290 NULL, 15291 "cannot create policy " 15292 "set tag action for this color"); 15293 if (flow_dv_convert_action_set_tag 15294 (dev, mhdr_res, 15295 (const struct rte_flow_action_set_tag *) 15296 act->conf, &flow_err)) 15297 return -rte_mtr_error_set(error, 15298 ENOTSUP, 15299 RTE_MTR_ERROR_TYPE_METER_POLICY, 15300 NULL, "cannot convert policy " 15301 "set tag action"); 15302 if (!mhdr_res->actions_num) 15303 return -rte_mtr_error_set(error, 15304 ENOTSUP, 15305 RTE_MTR_ERROR_TYPE_METER_POLICY, 15306 NULL, "cannot find policy " 15307 "set tag action"); 15308 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 15309 break; 15310 case RTE_FLOW_ACTION_TYPE_DROP: 15311 { 15312 struct mlx5_flow_mtr_mng *mtrmng = 15313 priv->sh->mtrmng; 15314 struct mlx5_flow_tbl_data_entry *tbl_data; 15315 15316 /* 15317 * Create the drop table with 15318 * METER DROP level. 15319 */ 15320 if (!mtrmng->drop_tbl[domain]) { 15321 mtrmng->drop_tbl[domain] = 15322 flow_dv_tbl_resource_get(dev, 15323 MLX5_FLOW_TABLE_LEVEL_METER, 15324 egress, transfer, false, NULL, 0, 15325 0, MLX5_MTR_TABLE_ID_DROP, &flow_err); 15326 if (!mtrmng->drop_tbl[domain]) 15327 return -rte_mtr_error_set 15328 (error, ENOTSUP, 15329 RTE_MTR_ERROR_TYPE_METER_POLICY, 15330 NULL, 15331 "Failed to create meter drop table"); 15332 } 15333 tbl_data = container_of 15334 (mtrmng->drop_tbl[domain], 15335 struct mlx5_flow_tbl_data_entry, tbl); 15336 if (i < MLX5_MTR_RTE_COLORS) { 15337 act_cnt->dr_jump_action[domain] = 15338 tbl_data->jump.action; 15339 act_cnt->fate_action = 15340 MLX5_FLOW_FATE_DROP; 15341 } 15342 if (i == RTE_COLOR_RED) 15343 mtr_policy->dr_drop_action[domain] = 15344 tbl_data->jump.action; 15345 action_flags |= MLX5_FLOW_ACTION_DROP; 15346 break; 15347 } 15348 case RTE_FLOW_ACTION_TYPE_QUEUE: 15349 { 15350 if (i >= MLX5_MTR_RTE_COLORS) 15351 return -rte_mtr_error_set(error, 15352 ENOTSUP, 15353 RTE_MTR_ERROR_TYPE_METER_POLICY, 15354 NULL, "cannot create policy " 15355 "fate queue for this color"); 15356 act_cnt->queue = 15357 ((const struct rte_flow_action_queue *) 15358 (act->conf))->index; 15359 act_cnt->fate_action = 15360 MLX5_FLOW_FATE_QUEUE; 15361 dev_flow.handle->fate_action = 15362 MLX5_FLOW_FATE_QUEUE; 15363 mtr_policy->is_queue = 1; 15364 action_flags |= MLX5_FLOW_ACTION_QUEUE; 15365 break; 15366 } 15367 case RTE_FLOW_ACTION_TYPE_RSS: 15368 { 15369 int rss_size; 15370 15371 if (i >= MLX5_MTR_RTE_COLORS) 15372 return -rte_mtr_error_set(error, 15373 ENOTSUP, 15374 RTE_MTR_ERROR_TYPE_METER_POLICY, 15375 NULL, 15376 "cannot create policy " 15377 "rss action for this color"); 15378 /* 15379 * Save RSS conf into policy struct 15380 * for translate stage. 15381 */ 15382 rss_size = (int)rte_flow_conv 15383 (RTE_FLOW_CONV_OP_ACTION, 15384 NULL, 0, act, &flow_err); 15385 if (rss_size <= 0) 15386 return -rte_mtr_error_set(error, 15387 ENOTSUP, 15388 RTE_MTR_ERROR_TYPE_METER_POLICY, 15389 NULL, "Get the wrong " 15390 "rss action struct size"); 15391 act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO, 15392 rss_size, 0, SOCKET_ID_ANY); 15393 if (!act_cnt->rss) 15394 return -rte_mtr_error_set(error, 15395 ENOTSUP, 15396 RTE_MTR_ERROR_TYPE_METER_POLICY, 15397 NULL, 15398 "Fail to malloc rss action memory"); 15399 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION, 15400 act_cnt->rss, rss_size, 15401 act, &flow_err); 15402 if (ret < 0) 15403 return -rte_mtr_error_set(error, 15404 ENOTSUP, 15405 RTE_MTR_ERROR_TYPE_METER_POLICY, 15406 NULL, "Fail to save " 15407 "rss action into policy struct"); 15408 act_cnt->fate_action = 15409 MLX5_FLOW_FATE_SHARED_RSS; 15410 action_flags |= MLX5_FLOW_ACTION_RSS; 15411 break; 15412 } 15413 case RTE_FLOW_ACTION_TYPE_PORT_ID: 15414 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 15415 { 15416 struct mlx5_flow_dv_port_id_action_resource 15417 port_id_resource; 15418 uint32_t port_id = 0; 15419 15420 if (i >= MLX5_MTR_RTE_COLORS) 15421 return -rte_mtr_error_set(error, 15422 ENOTSUP, 15423 RTE_MTR_ERROR_TYPE_METER_POLICY, 15424 NULL, "cannot create policy " 15425 "port action for this color"); 15426 memset(&port_id_resource, 0, 15427 sizeof(port_id_resource)); 15428 if (flow_dv_translate_action_port_id(dev, act, 15429 &port_id, &flow_err)) 15430 return -rte_mtr_error_set(error, 15431 ENOTSUP, 15432 RTE_MTR_ERROR_TYPE_METER_POLICY, 15433 NULL, "cannot translate " 15434 "policy port action"); 15435 port_id_resource.port_id = port_id; 15436 if (flow_dv_port_id_action_resource_register 15437 (dev, &port_id_resource, 15438 &dev_flow, &flow_err)) 15439 return -rte_mtr_error_set(error, 15440 ENOTSUP, 15441 RTE_MTR_ERROR_TYPE_METER_POLICY, 15442 NULL, "cannot setup " 15443 "policy port action"); 15444 act_cnt->rix_port_id_action = 15445 dev_flow.handle->rix_port_id_action; 15446 act_cnt->fate_action = 15447 MLX5_FLOW_FATE_PORT_ID; 15448 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 15449 break; 15450 } 15451 case RTE_FLOW_ACTION_TYPE_JUMP: 15452 { 15453 uint32_t jump_group = 0; 15454 uint32_t table = 0; 15455 struct mlx5_flow_tbl_data_entry *tbl_data; 15456 struct flow_grp_info grp_info = { 15457 .external = !!dev_flow.external, 15458 .transfer = !!transfer, 15459 .fdb_def_rule = !!priv->fdb_def_rule, 15460 .std_tbl_fix = 0, 15461 .skip_scale = dev_flow.skip_scale & 15462 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 15463 }; 15464 struct mlx5_flow_meter_sub_policy *sub_policy = 15465 mtr_policy->sub_policys[domain][0]; 15466 15467 if (i >= MLX5_MTR_RTE_COLORS) 15468 return -rte_mtr_error_set(error, 15469 ENOTSUP, 15470 RTE_MTR_ERROR_TYPE_METER_POLICY, 15471 NULL, 15472 "cannot create policy " 15473 "jump action for this color"); 15474 jump_group = 15475 ((const struct rte_flow_action_jump *) 15476 act->conf)->group; 15477 if (mlx5_flow_group_to_table(dev, NULL, 15478 jump_group, 15479 &table, 15480 &grp_info, &flow_err)) 15481 return -rte_mtr_error_set(error, 15482 ENOTSUP, 15483 RTE_MTR_ERROR_TYPE_METER_POLICY, 15484 NULL, "cannot setup " 15485 "policy jump action"); 15486 sub_policy->jump_tbl[i] = 15487 flow_dv_tbl_resource_get(dev, 15488 table, egress, 15489 transfer, 15490 !!dev_flow.external, 15491 NULL, jump_group, 0, 15492 0, &flow_err); 15493 if 15494 (!sub_policy->jump_tbl[i]) 15495 return -rte_mtr_error_set(error, 15496 ENOTSUP, 15497 RTE_MTR_ERROR_TYPE_METER_POLICY, 15498 NULL, "cannot create jump action."); 15499 tbl_data = container_of 15500 (sub_policy->jump_tbl[i], 15501 struct mlx5_flow_tbl_data_entry, tbl); 15502 act_cnt->dr_jump_action[domain] = 15503 tbl_data->jump.action; 15504 act_cnt->fate_action = 15505 MLX5_FLOW_FATE_JUMP; 15506 action_flags |= MLX5_FLOW_ACTION_JUMP; 15507 break; 15508 } 15509 /* 15510 * No need to check meter hierarchy for Y or R colors 15511 * here since it is done in the validation stage. 15512 */ 15513 case RTE_FLOW_ACTION_TYPE_METER: 15514 { 15515 const struct rte_flow_action_meter *mtr; 15516 struct mlx5_flow_meter_info *next_fm; 15517 struct mlx5_flow_meter_policy *next_policy; 15518 struct rte_flow_action tag_action; 15519 struct mlx5_rte_flow_action_set_tag set_tag; 15520 uint32_t next_mtr_idx = 0; 15521 15522 mtr = act->conf; 15523 next_fm = mlx5_flow_meter_find(priv, 15524 mtr->mtr_id, 15525 &next_mtr_idx); 15526 if (!next_fm) 15527 return -rte_mtr_error_set(error, EINVAL, 15528 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15529 "Fail to find next meter."); 15530 if (next_fm->def_policy) 15531 return -rte_mtr_error_set(error, EINVAL, 15532 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15533 "Hierarchy only supports termination meter."); 15534 next_policy = mlx5_flow_meter_policy_find(dev, 15535 next_fm->policy_id, NULL); 15536 MLX5_ASSERT(next_policy); 15537 if (next_fm->drop_cnt) { 15538 set_tag.id = 15539 (enum modify_reg) 15540 mlx5_flow_get_reg_id(dev, 15541 MLX5_MTR_ID, 15542 0, 15543 (struct rte_flow_error *)error); 15544 set_tag.offset = (priv->mtr_reg_share ? 15545 MLX5_MTR_COLOR_BITS : 0); 15546 set_tag.length = (priv->mtr_reg_share ? 15547 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : 15548 MLX5_REG_BITS); 15549 set_tag.data = next_mtr_idx; 15550 tag_action.type = 15551 (enum rte_flow_action_type) 15552 MLX5_RTE_FLOW_ACTION_TYPE_TAG; 15553 tag_action.conf = &set_tag; 15554 if (flow_dv_convert_action_set_reg 15555 (mhdr_res, &tag_action, 15556 (struct rte_flow_error *)error)) 15557 return -rte_errno; 15558 action_flags |= 15559 MLX5_FLOW_ACTION_SET_TAG; 15560 } 15561 act_cnt->fate_action = MLX5_FLOW_FATE_MTR; 15562 act_cnt->next_mtr_id = next_fm->meter_id; 15563 act_cnt->next_sub_policy = NULL; 15564 mtr_policy->is_hierarchy = 1; 15565 mtr_policy->dev = next_policy->dev; 15566 action_flags |= 15567 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 15568 break; 15569 } 15570 default: 15571 return -rte_mtr_error_set(error, ENOTSUP, 15572 RTE_MTR_ERROR_TYPE_METER_POLICY, 15573 NULL, "action type not supported"); 15574 } 15575 if (action_flags & MLX5_FLOW_ACTION_SET_TAG) { 15576 /* create modify action if needed. */ 15577 dev_flow.dv.group = 1; 15578 if (flow_dv_modify_hdr_resource_register 15579 (dev, mhdr_res, &dev_flow, &flow_err)) 15580 return -rte_mtr_error_set(error, 15581 ENOTSUP, 15582 RTE_MTR_ERROR_TYPE_METER_POLICY, 15583 NULL, "cannot register policy " 15584 "set tag action"); 15585 act_cnt->modify_hdr = 15586 dev_flow.handle->dvh.modify_hdr; 15587 } 15588 } 15589 } 15590 return 0; 15591 } 15592 15593 /** 15594 * Create policy action per domain, lock free, 15595 * (mutex should be acquired by caller). 15596 * Dispatcher for action type specific call. 15597 * 15598 * @param[in] dev 15599 * Pointer to the Ethernet device structure. 15600 * @param[in] mtr_policy 15601 * Meter policy struct. 15602 * @param[in] action 15603 * Action specification used to create meter actions. 15604 * @param[out] error 15605 * Perform verbose error reporting if not NULL. Initialized in case of 15606 * error only. 15607 * 15608 * @return 15609 * 0 on success, otherwise negative errno value. 15610 */ 15611 static int 15612 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev, 15613 struct mlx5_flow_meter_policy *mtr_policy, 15614 const struct rte_flow_action *actions[RTE_COLORS], 15615 struct rte_mtr_error *error) 15616 { 15617 int ret, i; 15618 uint16_t sub_policy_num; 15619 15620 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15621 sub_policy_num = (mtr_policy->sub_policy_num >> 15622 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15623 MLX5_MTR_SUB_POLICY_NUM_MASK; 15624 if (sub_policy_num) { 15625 ret = __flow_dv_create_domain_policy_acts(dev, 15626 mtr_policy, actions, 15627 (enum mlx5_meter_domain)i, error); 15628 /* Cleaning resource is done in the caller level. */ 15629 if (ret) 15630 return ret; 15631 } 15632 } 15633 return 0; 15634 } 15635 15636 /** 15637 * Query a DV flow rule for its statistics via DevX. 15638 * 15639 * @param[in] dev 15640 * Pointer to Ethernet device. 15641 * @param[in] cnt_idx 15642 * Index to the flow counter. 15643 * @param[out] data 15644 * Data retrieved by the query. 15645 * @param[out] error 15646 * Perform verbose error reporting if not NULL. 15647 * 15648 * @return 15649 * 0 on success, a negative errno value otherwise and rte_errno is set. 15650 */ 15651 static int 15652 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data, 15653 struct rte_flow_error *error) 15654 { 15655 struct mlx5_priv *priv = dev->data->dev_private; 15656 struct rte_flow_query_count *qc = data; 15657 15658 if (!priv->sh->devx) 15659 return rte_flow_error_set(error, ENOTSUP, 15660 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15661 NULL, 15662 "counters are not supported"); 15663 if (cnt_idx) { 15664 uint64_t pkts, bytes; 15665 struct mlx5_flow_counter *cnt; 15666 int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes); 15667 15668 if (err) 15669 return rte_flow_error_set(error, -err, 15670 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15671 NULL, "cannot read counters"); 15672 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL); 15673 qc->hits_set = 1; 15674 qc->bytes_set = 1; 15675 qc->hits = pkts - cnt->hits; 15676 qc->bytes = bytes - cnt->bytes; 15677 if (qc->reset) { 15678 cnt->hits = pkts; 15679 cnt->bytes = bytes; 15680 } 15681 return 0; 15682 } 15683 return rte_flow_error_set(error, EINVAL, 15684 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15685 NULL, 15686 "counters are not available"); 15687 } 15688 15689 static int 15690 flow_dv_action_query(struct rte_eth_dev *dev, 15691 const struct rte_flow_action_handle *handle, void *data, 15692 struct rte_flow_error *error) 15693 { 15694 struct mlx5_age_param *age_param; 15695 struct rte_flow_query_age *resp; 15696 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15697 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15698 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15699 struct mlx5_priv *priv = dev->data->dev_private; 15700 struct mlx5_aso_ct_action *ct; 15701 uint16_t owner; 15702 uint32_t dev_idx; 15703 15704 switch (type) { 15705 case MLX5_INDIRECT_ACTION_TYPE_AGE: 15706 age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params; 15707 resp = data; 15708 resp->aged = __atomic_load_n(&age_param->state, 15709 __ATOMIC_RELAXED) == AGE_TMOUT ? 15710 1 : 0; 15711 resp->sec_since_last_hit_valid = !resp->aged; 15712 if (resp->sec_since_last_hit_valid) 15713 resp->sec_since_last_hit = __atomic_load_n 15714 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15715 return 0; 15716 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 15717 return flow_dv_query_count(dev, idx, data, error); 15718 case MLX5_INDIRECT_ACTION_TYPE_CT: 15719 owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15720 if (owner != PORT_ID(priv)) 15721 return rte_flow_error_set(error, EACCES, 15722 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15723 NULL, 15724 "CT object owned by another port"); 15725 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15726 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15727 MLX5_ASSERT(ct); 15728 if (!ct->refcnt) 15729 return rte_flow_error_set(error, EFAULT, 15730 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15731 NULL, 15732 "CT object is inactive"); 15733 ((struct rte_flow_action_conntrack *)data)->peer_port = 15734 ct->peer; 15735 ((struct rte_flow_action_conntrack *)data)->is_original_dir = 15736 ct->is_original; 15737 if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data)) 15738 return rte_flow_error_set(error, EIO, 15739 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15740 NULL, 15741 "Failed to query CT context"); 15742 return 0; 15743 default: 15744 return rte_flow_error_set(error, ENOTSUP, 15745 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15746 "action type query not supported"); 15747 } 15748 } 15749 15750 /** 15751 * Query a flow rule AGE action for aging information. 15752 * 15753 * @param[in] dev 15754 * Pointer to Ethernet device. 15755 * @param[in] flow 15756 * Pointer to the sub flow. 15757 * @param[out] data 15758 * data retrieved by the query. 15759 * @param[out] error 15760 * Perform verbose error reporting if not NULL. 15761 * 15762 * @return 15763 * 0 on success, a negative errno value otherwise and rte_errno is set. 15764 */ 15765 static int 15766 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow, 15767 void *data, struct rte_flow_error *error) 15768 { 15769 struct rte_flow_query_age *resp = data; 15770 struct mlx5_age_param *age_param; 15771 15772 if (flow->age) { 15773 struct mlx5_aso_age_action *act = 15774 flow_aso_age_get_by_idx(dev, flow->age); 15775 15776 age_param = &act->age_params; 15777 } else if (flow->counter) { 15778 age_param = flow_dv_counter_idx_get_age(dev, flow->counter); 15779 15780 if (!age_param || !age_param->timeout) 15781 return rte_flow_error_set 15782 (error, EINVAL, 15783 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15784 NULL, "cannot read age data"); 15785 } else { 15786 return rte_flow_error_set(error, EINVAL, 15787 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15788 NULL, "age data not available"); 15789 } 15790 resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) == 15791 AGE_TMOUT ? 1 : 0; 15792 resp->sec_since_last_hit_valid = !resp->aged; 15793 if (resp->sec_since_last_hit_valid) 15794 resp->sec_since_last_hit = __atomic_load_n 15795 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15796 return 0; 15797 } 15798 15799 /** 15800 * Query a flow. 15801 * 15802 * @see rte_flow_query() 15803 * @see rte_flow_ops 15804 */ 15805 static int 15806 flow_dv_query(struct rte_eth_dev *dev, 15807 struct rte_flow *flow __rte_unused, 15808 const struct rte_flow_action *actions __rte_unused, 15809 void *data __rte_unused, 15810 struct rte_flow_error *error __rte_unused) 15811 { 15812 int ret = -EINVAL; 15813 15814 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 15815 switch (actions->type) { 15816 case RTE_FLOW_ACTION_TYPE_VOID: 15817 break; 15818 case RTE_FLOW_ACTION_TYPE_COUNT: 15819 ret = flow_dv_query_count(dev, flow->counter, data, 15820 error); 15821 break; 15822 case RTE_FLOW_ACTION_TYPE_AGE: 15823 ret = flow_dv_query_age(dev, flow, data, error); 15824 break; 15825 default: 15826 return rte_flow_error_set(error, ENOTSUP, 15827 RTE_FLOW_ERROR_TYPE_ACTION, 15828 actions, 15829 "action not supported"); 15830 } 15831 } 15832 return ret; 15833 } 15834 15835 /** 15836 * Destroy the meter table set. 15837 * Lock free, (mutex should be acquired by caller). 15838 * 15839 * @param[in] dev 15840 * Pointer to Ethernet device. 15841 * @param[in] fm 15842 * Meter information table. 15843 */ 15844 static void 15845 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev, 15846 struct mlx5_flow_meter_info *fm) 15847 { 15848 struct mlx5_priv *priv = dev->data->dev_private; 15849 int i; 15850 15851 if (!fm || !priv->config.dv_flow_en) 15852 return; 15853 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15854 if (fm->drop_rule[i]) { 15855 claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i])); 15856 fm->drop_rule[i] = NULL; 15857 } 15858 } 15859 } 15860 15861 static void 15862 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev) 15863 { 15864 struct mlx5_priv *priv = dev->data->dev_private; 15865 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 15866 struct mlx5_flow_tbl_data_entry *tbl; 15867 int i, j; 15868 15869 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15870 if (mtrmng->def_rule[i]) { 15871 claim_zero(mlx5_flow_os_destroy_flow 15872 (mtrmng->def_rule[i])); 15873 mtrmng->def_rule[i] = NULL; 15874 } 15875 if (mtrmng->def_matcher[i]) { 15876 tbl = container_of(mtrmng->def_matcher[i]->tbl, 15877 struct mlx5_flow_tbl_data_entry, tbl); 15878 mlx5_list_unregister(tbl->matchers, 15879 &mtrmng->def_matcher[i]->entry); 15880 mtrmng->def_matcher[i] = NULL; 15881 } 15882 for (j = 0; j < MLX5_REG_BITS; j++) { 15883 if (mtrmng->drop_matcher[i][j]) { 15884 tbl = 15885 container_of(mtrmng->drop_matcher[i][j]->tbl, 15886 struct mlx5_flow_tbl_data_entry, 15887 tbl); 15888 mlx5_list_unregister(tbl->matchers, 15889 &mtrmng->drop_matcher[i][j]->entry); 15890 mtrmng->drop_matcher[i][j] = NULL; 15891 } 15892 } 15893 if (mtrmng->drop_tbl[i]) { 15894 flow_dv_tbl_resource_release(MLX5_SH(dev), 15895 mtrmng->drop_tbl[i]); 15896 mtrmng->drop_tbl[i] = NULL; 15897 } 15898 } 15899 } 15900 15901 /* Number of meter flow actions, count and jump or count and drop. */ 15902 #define METER_ACTIONS 2 15903 15904 static void 15905 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev, 15906 enum mlx5_meter_domain domain) 15907 { 15908 struct mlx5_priv *priv = dev->data->dev_private; 15909 struct mlx5_flow_meter_def_policy *def_policy = 15910 priv->sh->mtrmng->def_policy[domain]; 15911 15912 __flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy); 15913 mlx5_free(def_policy); 15914 priv->sh->mtrmng->def_policy[domain] = NULL; 15915 } 15916 15917 /** 15918 * Destroy the default policy table set. 15919 * 15920 * @param[in] dev 15921 * Pointer to Ethernet device. 15922 */ 15923 static void 15924 flow_dv_destroy_def_policy(struct rte_eth_dev *dev) 15925 { 15926 struct mlx5_priv *priv = dev->data->dev_private; 15927 int i; 15928 15929 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) 15930 if (priv->sh->mtrmng->def_policy[i]) 15931 __flow_dv_destroy_domain_def_policy(dev, 15932 (enum mlx5_meter_domain)i); 15933 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID; 15934 } 15935 15936 static int 15937 __flow_dv_create_policy_flow(struct rte_eth_dev *dev, 15938 uint32_t color_reg_c_idx, 15939 enum rte_color color, void *matcher_object, 15940 int actions_n, void *actions, 15941 bool match_src_port, const struct rte_flow_item *item, 15942 void **rule, const struct rte_flow_attr *attr) 15943 { 15944 int ret; 15945 struct mlx5_flow_dv_match_params value = { 15946 .size = sizeof(value.buf), 15947 }; 15948 struct mlx5_flow_dv_match_params matcher = { 15949 .size = sizeof(matcher.buf), 15950 }; 15951 struct mlx5_priv *priv = dev->data->dev_private; 15952 uint8_t misc_mask; 15953 15954 if (match_src_port && (priv->representor || priv->master)) { 15955 if (flow_dv_translate_item_port_id(dev, matcher.buf, 15956 value.buf, item, attr)) { 15957 DRV_LOG(ERR, "Failed to create meter policy%d flow's" 15958 " value with port.", color); 15959 return -1; 15960 } 15961 } 15962 flow_dv_match_meta_reg(matcher.buf, value.buf, 15963 (enum modify_reg)color_reg_c_idx, 15964 rte_col_2_mlx5_col(color), UINT32_MAX); 15965 misc_mask = flow_dv_matcher_enable(value.buf); 15966 __flow_dv_adjust_buf_size(&value.size, misc_mask); 15967 ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value, 15968 actions_n, actions, rule); 15969 if (ret) { 15970 DRV_LOG(ERR, "Failed to create meter policy%d flow.", color); 15971 return -1; 15972 } 15973 return 0; 15974 } 15975 15976 static int 15977 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev, 15978 uint32_t color_reg_c_idx, 15979 uint16_t priority, 15980 struct mlx5_flow_meter_sub_policy *sub_policy, 15981 const struct rte_flow_attr *attr, 15982 bool match_src_port, 15983 const struct rte_flow_item *item, 15984 struct mlx5_flow_dv_matcher **policy_matcher, 15985 struct rte_flow_error *error) 15986 { 15987 struct mlx5_list_entry *entry; 15988 struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc; 15989 struct mlx5_flow_dv_matcher matcher = { 15990 .mask = { 15991 .size = sizeof(matcher.mask.buf), 15992 }, 15993 .tbl = tbl_rsc, 15994 }; 15995 struct mlx5_flow_dv_match_params value = { 15996 .size = sizeof(value.buf), 15997 }; 15998 struct mlx5_flow_cb_ctx ctx = { 15999 .error = error, 16000 .data = &matcher, 16001 }; 16002 struct mlx5_flow_tbl_data_entry *tbl_data; 16003 struct mlx5_priv *priv = dev->data->dev_private; 16004 const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 16005 16006 if (match_src_port && (priv->representor || priv->master)) { 16007 if (flow_dv_translate_item_port_id(dev, matcher.mask.buf, 16008 value.buf, item, attr)) { 16009 DRV_LOG(ERR, "Failed to register meter policy%d matcher" 16010 " with port.", priority); 16011 return -1; 16012 } 16013 } 16014 tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl); 16015 if (priority < RTE_COLOR_RED) 16016 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16017 (enum modify_reg)color_reg_c_idx, 0, color_mask); 16018 matcher.priority = priority; 16019 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 16020 matcher.mask.size); 16021 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16022 if (!entry) { 16023 DRV_LOG(ERR, "Failed to register meter drop matcher."); 16024 return -1; 16025 } 16026 *policy_matcher = 16027 container_of(entry, struct mlx5_flow_dv_matcher, entry); 16028 return 0; 16029 } 16030 16031 /** 16032 * Create the policy rules per domain. 16033 * 16034 * @param[in] dev 16035 * Pointer to Ethernet device. 16036 * @param[in] sub_policy 16037 * Pointer to sub policy table.. 16038 * @param[in] egress 16039 * Direction of the table. 16040 * @param[in] transfer 16041 * E-Switch or NIC flow. 16042 * @param[in] acts 16043 * Pointer to policy action list per color. 16044 * 16045 * @return 16046 * 0 on success, -1 otherwise. 16047 */ 16048 static int 16049 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev, 16050 struct mlx5_flow_meter_sub_policy *sub_policy, 16051 uint8_t egress, uint8_t transfer, bool match_src_port, 16052 struct mlx5_meter_policy_acts acts[RTE_COLORS]) 16053 { 16054 struct mlx5_priv *priv = dev->data->dev_private; 16055 struct rte_flow_error flow_err; 16056 uint32_t color_reg_c_idx; 16057 struct rte_flow_attr attr = { 16058 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 16059 .priority = 0, 16060 .ingress = 0, 16061 .egress = !!egress, 16062 .transfer = !!transfer, 16063 .reserved = 0, 16064 }; 16065 int i; 16066 int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err); 16067 struct mlx5_sub_policy_color_rule *color_rule; 16068 bool svport_match; 16069 struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL}; 16070 16071 if (ret < 0) 16072 return -1; 16073 /* Create policy table with POLICY level. */ 16074 if (!sub_policy->tbl_rsc) 16075 sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev, 16076 MLX5_FLOW_TABLE_LEVEL_POLICY, 16077 egress, transfer, false, NULL, 0, 0, 16078 sub_policy->idx, &flow_err); 16079 if (!sub_policy->tbl_rsc) { 16080 DRV_LOG(ERR, 16081 "Failed to create meter sub policy table."); 16082 return -1; 16083 } 16084 /* Prepare matchers. */ 16085 color_reg_c_idx = ret; 16086 for (i = 0; i < RTE_COLORS; i++) { 16087 TAILQ_INIT(&sub_policy->color_rules[i]); 16088 if (!acts[i].actions_n) 16089 continue; 16090 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 16091 sizeof(struct mlx5_sub_policy_color_rule), 16092 0, SOCKET_ID_ANY); 16093 if (!color_rule) { 16094 DRV_LOG(ERR, "No memory to create color rule."); 16095 goto err_exit; 16096 } 16097 tmp_rules[i] = color_rule; 16098 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 16099 color_rule, next_port); 16100 color_rule->src_port = priv->representor_id; 16101 /* No use. */ 16102 attr.priority = i; 16103 /* Create matchers for colors. */ 16104 svport_match = (i != RTE_COLOR_RED) ? match_src_port : false; 16105 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 16106 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 16107 &attr, svport_match, NULL, 16108 &color_rule->matcher, &flow_err)) { 16109 DRV_LOG(ERR, "Failed to create color%u matcher.", i); 16110 goto err_exit; 16111 } 16112 /* Create flow, matching color. */ 16113 if (__flow_dv_create_policy_flow(dev, 16114 color_reg_c_idx, (enum rte_color)i, 16115 color_rule->matcher->matcher_object, 16116 acts[i].actions_n, acts[i].dv_actions, 16117 svport_match, NULL, &color_rule->rule, 16118 &attr)) { 16119 DRV_LOG(ERR, "Failed to create color%u rule.", i); 16120 goto err_exit; 16121 } 16122 } 16123 return 0; 16124 err_exit: 16125 /* All the policy rules will be cleared. */ 16126 do { 16127 color_rule = tmp_rules[i]; 16128 if (color_rule) { 16129 if (color_rule->rule) 16130 mlx5_flow_os_destroy_flow(color_rule->rule); 16131 if (color_rule->matcher) { 16132 struct mlx5_flow_tbl_data_entry *tbl = 16133 container_of(color_rule->matcher->tbl, 16134 typeof(*tbl), tbl); 16135 mlx5_list_unregister(tbl->matchers, 16136 &color_rule->matcher->entry); 16137 } 16138 TAILQ_REMOVE(&sub_policy->color_rules[i], 16139 color_rule, next_port); 16140 mlx5_free(color_rule); 16141 } 16142 } while (i--); 16143 return -1; 16144 } 16145 16146 static int 16147 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev, 16148 struct mlx5_flow_meter_policy *mtr_policy, 16149 struct mlx5_flow_meter_sub_policy *sub_policy, 16150 uint32_t domain) 16151 { 16152 struct mlx5_priv *priv = dev->data->dev_private; 16153 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16154 struct mlx5_flow_dv_tag_resource *tag; 16155 struct mlx5_flow_dv_port_id_action_resource *port_action; 16156 struct mlx5_hrxq *hrxq; 16157 struct mlx5_flow_meter_info *next_fm = NULL; 16158 struct mlx5_flow_meter_policy *next_policy; 16159 struct mlx5_flow_meter_sub_policy *next_sub_policy; 16160 struct mlx5_flow_tbl_data_entry *tbl_data; 16161 struct rte_flow_error error; 16162 uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16163 uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16164 bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX); 16165 bool match_src_port = false; 16166 int i; 16167 16168 /* If RSS or Queue, no previous actions / rules is created. */ 16169 for (i = 0; i < RTE_COLORS; i++) { 16170 acts[i].actions_n = 0; 16171 if (i == RTE_COLOR_RED) { 16172 /* Only support drop on red. */ 16173 acts[i].dv_actions[0] = 16174 mtr_policy->dr_drop_action[domain]; 16175 acts[i].actions_n = 1; 16176 continue; 16177 } 16178 if (i == RTE_COLOR_GREEN && 16179 mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) { 16180 struct rte_flow_attr attr = { 16181 .transfer = transfer 16182 }; 16183 16184 next_fm = mlx5_flow_meter_find(priv, 16185 mtr_policy->act_cnt[i].next_mtr_id, 16186 NULL); 16187 if (!next_fm) { 16188 DRV_LOG(ERR, 16189 "Failed to get next hierarchy meter."); 16190 goto err_exit; 16191 } 16192 if (mlx5_flow_meter_attach(priv, next_fm, 16193 &attr, &error)) { 16194 DRV_LOG(ERR, "%s", error.message); 16195 next_fm = NULL; 16196 goto err_exit; 16197 } 16198 /* Meter action must be the first for TX. */ 16199 if (mtr_first) { 16200 acts[i].dv_actions[acts[i].actions_n] = 16201 next_fm->meter_action; 16202 acts[i].actions_n++; 16203 } 16204 } 16205 if (mtr_policy->act_cnt[i].rix_mark) { 16206 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], 16207 mtr_policy->act_cnt[i].rix_mark); 16208 if (!tag) { 16209 DRV_LOG(ERR, "Failed to find " 16210 "mark action for policy."); 16211 goto err_exit; 16212 } 16213 acts[i].dv_actions[acts[i].actions_n] = tag->action; 16214 acts[i].actions_n++; 16215 } 16216 if (mtr_policy->act_cnt[i].modify_hdr) { 16217 acts[i].dv_actions[acts[i].actions_n] = 16218 mtr_policy->act_cnt[i].modify_hdr->action; 16219 acts[i].actions_n++; 16220 } 16221 if (mtr_policy->act_cnt[i].fate_action) { 16222 switch (mtr_policy->act_cnt[i].fate_action) { 16223 case MLX5_FLOW_FATE_PORT_ID: 16224 port_action = mlx5_ipool_get 16225 (priv->sh->ipool[MLX5_IPOOL_PORT_ID], 16226 mtr_policy->act_cnt[i].rix_port_id_action); 16227 if (!port_action) { 16228 DRV_LOG(ERR, "Failed to find " 16229 "port action for policy."); 16230 goto err_exit; 16231 } 16232 acts[i].dv_actions[acts[i].actions_n] = 16233 port_action->action; 16234 acts[i].actions_n++; 16235 mtr_policy->dev = dev; 16236 match_src_port = true; 16237 break; 16238 case MLX5_FLOW_FATE_DROP: 16239 case MLX5_FLOW_FATE_JUMP: 16240 acts[i].dv_actions[acts[i].actions_n] = 16241 mtr_policy->act_cnt[i].dr_jump_action[domain]; 16242 acts[i].actions_n++; 16243 break; 16244 case MLX5_FLOW_FATE_SHARED_RSS: 16245 case MLX5_FLOW_FATE_QUEUE: 16246 hrxq = mlx5_ipool_get 16247 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 16248 sub_policy->rix_hrxq[i]); 16249 if (!hrxq) { 16250 DRV_LOG(ERR, "Failed to find " 16251 "queue action for policy."); 16252 goto err_exit; 16253 } 16254 acts[i].dv_actions[acts[i].actions_n] = 16255 hrxq->action; 16256 acts[i].actions_n++; 16257 break; 16258 case MLX5_FLOW_FATE_MTR: 16259 if (!next_fm) { 16260 DRV_LOG(ERR, 16261 "No next hierarchy meter."); 16262 goto err_exit; 16263 } 16264 if (!mtr_first) { 16265 acts[i].dv_actions[acts[i].actions_n] = 16266 next_fm->meter_action; 16267 acts[i].actions_n++; 16268 } 16269 if (mtr_policy->act_cnt[i].next_sub_policy) { 16270 next_sub_policy = 16271 mtr_policy->act_cnt[i].next_sub_policy; 16272 } else { 16273 next_policy = 16274 mlx5_flow_meter_policy_find(dev, 16275 next_fm->policy_id, NULL); 16276 MLX5_ASSERT(next_policy); 16277 next_sub_policy = 16278 next_policy->sub_policys[domain][0]; 16279 } 16280 tbl_data = 16281 container_of(next_sub_policy->tbl_rsc, 16282 struct mlx5_flow_tbl_data_entry, tbl); 16283 acts[i].dv_actions[acts[i].actions_n++] = 16284 tbl_data->jump.action; 16285 if (mtr_policy->act_cnt[i].modify_hdr) 16286 match_src_port = !!transfer; 16287 break; 16288 default: 16289 /*Queue action do nothing*/ 16290 break; 16291 } 16292 } 16293 } 16294 if (__flow_dv_create_domain_policy_rules(dev, sub_policy, 16295 egress, transfer, match_src_port, acts)) { 16296 DRV_LOG(ERR, 16297 "Failed to create policy rules per domain."); 16298 goto err_exit; 16299 } 16300 return 0; 16301 err_exit: 16302 if (next_fm) 16303 mlx5_flow_meter_detach(priv, next_fm); 16304 return -1; 16305 } 16306 16307 /** 16308 * Create the policy rules. 16309 * 16310 * @param[in] dev 16311 * Pointer to Ethernet device. 16312 * @param[in,out] mtr_policy 16313 * Pointer to meter policy table. 16314 * 16315 * @return 16316 * 0 on success, -1 otherwise. 16317 */ 16318 static int 16319 flow_dv_create_policy_rules(struct rte_eth_dev *dev, 16320 struct mlx5_flow_meter_policy *mtr_policy) 16321 { 16322 int i; 16323 uint16_t sub_policy_num; 16324 16325 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16326 sub_policy_num = (mtr_policy->sub_policy_num >> 16327 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 16328 MLX5_MTR_SUB_POLICY_NUM_MASK; 16329 if (!sub_policy_num) 16330 continue; 16331 /* Prepare actions list and create policy rules. */ 16332 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16333 mtr_policy->sub_policys[i][0], i)) { 16334 DRV_LOG(ERR, "Failed to create policy action " 16335 "list per domain."); 16336 return -1; 16337 } 16338 } 16339 return 0; 16340 } 16341 16342 static int 16343 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain) 16344 { 16345 struct mlx5_priv *priv = dev->data->dev_private; 16346 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16347 struct mlx5_flow_meter_def_policy *def_policy; 16348 struct mlx5_flow_tbl_resource *jump_tbl; 16349 struct mlx5_flow_tbl_data_entry *tbl_data; 16350 uint8_t egress, transfer; 16351 struct rte_flow_error error; 16352 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16353 int ret; 16354 16355 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16356 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16357 def_policy = mtrmng->def_policy[domain]; 16358 if (!def_policy) { 16359 def_policy = mlx5_malloc(MLX5_MEM_ZERO, 16360 sizeof(struct mlx5_flow_meter_def_policy), 16361 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 16362 if (!def_policy) { 16363 DRV_LOG(ERR, "Failed to alloc default policy table."); 16364 goto def_policy_error; 16365 } 16366 mtrmng->def_policy[domain] = def_policy; 16367 /* Create the meter suffix table with SUFFIX level. */ 16368 jump_tbl = flow_dv_tbl_resource_get(dev, 16369 MLX5_FLOW_TABLE_LEVEL_METER, 16370 egress, transfer, false, NULL, 0, 16371 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16372 if (!jump_tbl) { 16373 DRV_LOG(ERR, 16374 "Failed to create meter suffix table."); 16375 goto def_policy_error; 16376 } 16377 def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl; 16378 tbl_data = container_of(jump_tbl, 16379 struct mlx5_flow_tbl_data_entry, tbl); 16380 def_policy->dr_jump_action[RTE_COLOR_GREEN] = 16381 tbl_data->jump.action; 16382 acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action; 16383 acts[RTE_COLOR_GREEN].actions_n = 1; 16384 /* 16385 * YELLOW has the same default policy as GREEN does. 16386 * G & Y share the same table and action. The 2nd time of table 16387 * resource getting is just to update the reference count for 16388 * the releasing stage. 16389 */ 16390 jump_tbl = flow_dv_tbl_resource_get(dev, 16391 MLX5_FLOW_TABLE_LEVEL_METER, 16392 egress, transfer, false, NULL, 0, 16393 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16394 if (!jump_tbl) { 16395 DRV_LOG(ERR, 16396 "Failed to get meter suffix table."); 16397 goto def_policy_error; 16398 } 16399 def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl; 16400 tbl_data = container_of(jump_tbl, 16401 struct mlx5_flow_tbl_data_entry, tbl); 16402 def_policy->dr_jump_action[RTE_COLOR_YELLOW] = 16403 tbl_data->jump.action; 16404 acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action; 16405 acts[RTE_COLOR_YELLOW].actions_n = 1; 16406 /* Create jump action to the drop table. */ 16407 if (!mtrmng->drop_tbl[domain]) { 16408 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get 16409 (dev, MLX5_FLOW_TABLE_LEVEL_METER, 16410 egress, transfer, false, NULL, 0, 16411 0, MLX5_MTR_TABLE_ID_DROP, &error); 16412 if (!mtrmng->drop_tbl[domain]) { 16413 DRV_LOG(ERR, "Failed to create meter " 16414 "drop table for default policy."); 16415 goto def_policy_error; 16416 } 16417 } 16418 /* all RED: unique Drop table for jump action. */ 16419 tbl_data = container_of(mtrmng->drop_tbl[domain], 16420 struct mlx5_flow_tbl_data_entry, tbl); 16421 def_policy->dr_jump_action[RTE_COLOR_RED] = 16422 tbl_data->jump.action; 16423 acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action; 16424 acts[RTE_COLOR_RED].actions_n = 1; 16425 /* Create default policy rules. */ 16426 ret = __flow_dv_create_domain_policy_rules(dev, 16427 &def_policy->sub_policy, 16428 egress, transfer, false, acts); 16429 if (ret) { 16430 DRV_LOG(ERR, "Failed to create default policy rules."); 16431 goto def_policy_error; 16432 } 16433 } 16434 return 0; 16435 def_policy_error: 16436 __flow_dv_destroy_domain_def_policy(dev, 16437 (enum mlx5_meter_domain)domain); 16438 return -1; 16439 } 16440 16441 /** 16442 * Create the default policy table set. 16443 * 16444 * @param[in] dev 16445 * Pointer to Ethernet device. 16446 * @return 16447 * 0 on success, -1 otherwise. 16448 */ 16449 static int 16450 flow_dv_create_def_policy(struct rte_eth_dev *dev) 16451 { 16452 struct mlx5_priv *priv = dev->data->dev_private; 16453 int i; 16454 16455 /* Non-termination policy table. */ 16456 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16457 if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER) 16458 continue; 16459 if (__flow_dv_create_domain_def_policy(dev, i)) { 16460 DRV_LOG(ERR, "Failed to create default policy"); 16461 /* Rollback the created default policies for others. */ 16462 flow_dv_destroy_def_policy(dev); 16463 return -1; 16464 } 16465 } 16466 return 0; 16467 } 16468 16469 /** 16470 * Create the needed meter tables. 16471 * Lock free, (mutex should be acquired by caller). 16472 * 16473 * @param[in] dev 16474 * Pointer to Ethernet device. 16475 * @param[in] fm 16476 * Meter information table. 16477 * @param[in] mtr_idx 16478 * Meter index. 16479 * @param[in] domain_bitmap 16480 * Domain bitmap. 16481 * @return 16482 * 0 on success, -1 otherwise. 16483 */ 16484 static int 16485 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev, 16486 struct mlx5_flow_meter_info *fm, 16487 uint32_t mtr_idx, 16488 uint8_t domain_bitmap) 16489 { 16490 struct mlx5_priv *priv = dev->data->dev_private; 16491 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16492 struct rte_flow_error error; 16493 struct mlx5_flow_tbl_data_entry *tbl_data; 16494 uint8_t egress, transfer; 16495 void *actions[METER_ACTIONS]; 16496 int domain, ret, i; 16497 struct mlx5_flow_counter *cnt; 16498 struct mlx5_flow_dv_match_params value = { 16499 .size = sizeof(value.buf), 16500 }; 16501 struct mlx5_flow_dv_match_params matcher_para = { 16502 .size = sizeof(matcher_para.buf), 16503 }; 16504 int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID, 16505 0, &error); 16506 uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1; 16507 uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0; 16508 struct mlx5_list_entry *entry; 16509 struct mlx5_flow_dv_matcher matcher = { 16510 .mask = { 16511 .size = sizeof(matcher.mask.buf), 16512 }, 16513 }; 16514 struct mlx5_flow_dv_matcher *drop_matcher; 16515 struct mlx5_flow_cb_ctx ctx = { 16516 .error = &error, 16517 .data = &matcher, 16518 }; 16519 uint8_t misc_mask; 16520 16521 if (!priv->mtr_en || mtr_id_reg_c < 0) { 16522 rte_errno = ENOTSUP; 16523 return -1; 16524 } 16525 for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) { 16526 if (!(domain_bitmap & (1 << domain)) || 16527 (mtrmng->def_rule[domain] && !fm->drop_cnt)) 16528 continue; 16529 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16530 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16531 /* Create the drop table with METER DROP level. */ 16532 if (!mtrmng->drop_tbl[domain]) { 16533 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev, 16534 MLX5_FLOW_TABLE_LEVEL_METER, 16535 egress, transfer, false, NULL, 0, 16536 0, MLX5_MTR_TABLE_ID_DROP, &error); 16537 if (!mtrmng->drop_tbl[domain]) { 16538 DRV_LOG(ERR, "Failed to create meter drop table."); 16539 goto policy_error; 16540 } 16541 } 16542 /* Create default matcher in drop table. */ 16543 matcher.tbl = mtrmng->drop_tbl[domain], 16544 tbl_data = container_of(mtrmng->drop_tbl[domain], 16545 struct mlx5_flow_tbl_data_entry, tbl); 16546 if (!mtrmng->def_matcher[domain]) { 16547 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16548 (enum modify_reg)mtr_id_reg_c, 16549 0, 0); 16550 matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY; 16551 matcher.crc = rte_raw_cksum 16552 ((const void *)matcher.mask.buf, 16553 matcher.mask.size); 16554 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16555 if (!entry) { 16556 DRV_LOG(ERR, "Failed to register meter " 16557 "drop default matcher."); 16558 goto policy_error; 16559 } 16560 mtrmng->def_matcher[domain] = container_of(entry, 16561 struct mlx5_flow_dv_matcher, entry); 16562 } 16563 /* Create default rule in drop table. */ 16564 if (!mtrmng->def_rule[domain]) { 16565 i = 0; 16566 actions[i++] = priv->sh->dr_drop_action; 16567 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16568 (enum modify_reg)mtr_id_reg_c, 0, 0); 16569 misc_mask = flow_dv_matcher_enable(value.buf); 16570 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16571 ret = mlx5_flow_os_create_flow 16572 (mtrmng->def_matcher[domain]->matcher_object, 16573 (void *)&value, i, actions, 16574 &mtrmng->def_rule[domain]); 16575 if (ret) { 16576 DRV_LOG(ERR, "Failed to create meter " 16577 "default drop rule for drop table."); 16578 goto policy_error; 16579 } 16580 } 16581 if (!fm->drop_cnt) 16582 continue; 16583 MLX5_ASSERT(mtrmng->max_mtr_bits); 16584 if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) { 16585 /* Create matchers for Drop. */ 16586 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16587 (enum modify_reg)mtr_id_reg_c, 0, 16588 (mtr_id_mask << mtr_id_offset)); 16589 matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits; 16590 matcher.crc = rte_raw_cksum 16591 ((const void *)matcher.mask.buf, 16592 matcher.mask.size); 16593 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16594 if (!entry) { 16595 DRV_LOG(ERR, 16596 "Failed to register meter drop matcher."); 16597 goto policy_error; 16598 } 16599 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] = 16600 container_of(entry, struct mlx5_flow_dv_matcher, 16601 entry); 16602 } 16603 drop_matcher = 16604 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]; 16605 /* Create drop rule, matching meter_id only. */ 16606 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16607 (enum modify_reg)mtr_id_reg_c, 16608 (mtr_idx << mtr_id_offset), UINT32_MAX); 16609 i = 0; 16610 cnt = flow_dv_counter_get_by_idx(dev, 16611 fm->drop_cnt, NULL); 16612 actions[i++] = cnt->action; 16613 actions[i++] = priv->sh->dr_drop_action; 16614 misc_mask = flow_dv_matcher_enable(value.buf); 16615 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16616 ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object, 16617 (void *)&value, i, actions, 16618 &fm->drop_rule[domain]); 16619 if (ret) { 16620 DRV_LOG(ERR, "Failed to create meter " 16621 "drop rule for drop table."); 16622 goto policy_error; 16623 } 16624 } 16625 return 0; 16626 policy_error: 16627 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16628 if (fm->drop_rule[i]) { 16629 claim_zero(mlx5_flow_os_destroy_flow 16630 (fm->drop_rule[i])); 16631 fm->drop_rule[i] = NULL; 16632 } 16633 } 16634 return -1; 16635 } 16636 16637 static struct mlx5_flow_meter_sub_policy * 16638 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, 16639 struct mlx5_flow_meter_policy *mtr_policy, 16640 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS], 16641 struct mlx5_flow_meter_sub_policy *next_sub_policy, 16642 bool *is_reuse) 16643 { 16644 struct mlx5_priv *priv = dev->data->dev_private; 16645 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16646 uint32_t sub_policy_idx = 0; 16647 uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0}; 16648 uint32_t i, j; 16649 struct mlx5_hrxq *hrxq; 16650 struct mlx5_flow_handle dh; 16651 struct mlx5_meter_policy_action_container *act_cnt; 16652 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16653 uint16_t sub_policy_num; 16654 16655 rte_spinlock_lock(&mtr_policy->sl); 16656 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16657 if (!rss_desc[i]) 16658 continue; 16659 hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]); 16660 if (!hrxq_idx[i]) { 16661 rte_spinlock_unlock(&mtr_policy->sl); 16662 return NULL; 16663 } 16664 } 16665 sub_policy_num = (mtr_policy->sub_policy_num >> 16666 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16667 MLX5_MTR_SUB_POLICY_NUM_MASK; 16668 for (j = 0; j < sub_policy_num; j++) { 16669 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16670 if (rss_desc[i] && 16671 hrxq_idx[i] != 16672 mtr_policy->sub_policys[domain][j]->rix_hrxq[i]) 16673 break; 16674 } 16675 if (i >= MLX5_MTR_RTE_COLORS) { 16676 /* 16677 * Found the sub policy table with 16678 * the same queue per color. 16679 */ 16680 rte_spinlock_unlock(&mtr_policy->sl); 16681 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16682 mlx5_hrxq_release(dev, hrxq_idx[i]); 16683 *is_reuse = true; 16684 return mtr_policy->sub_policys[domain][j]; 16685 } 16686 } 16687 /* Create sub policy. */ 16688 if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) { 16689 /* Reuse the first pre-allocated sub_policy. */ 16690 sub_policy = mtr_policy->sub_policys[domain][0]; 16691 sub_policy_idx = sub_policy->idx; 16692 } else { 16693 sub_policy = mlx5_ipool_zmalloc 16694 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16695 &sub_policy_idx); 16696 if (!sub_policy || 16697 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { 16698 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16699 mlx5_hrxq_release(dev, hrxq_idx[i]); 16700 goto rss_sub_policy_error; 16701 } 16702 sub_policy->idx = sub_policy_idx; 16703 sub_policy->main_policy = mtr_policy; 16704 } 16705 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16706 if (!rss_desc[i]) 16707 continue; 16708 sub_policy->rix_hrxq[i] = hrxq_idx[i]; 16709 if (mtr_policy->is_hierarchy) { 16710 act_cnt = &mtr_policy->act_cnt[i]; 16711 act_cnt->next_sub_policy = next_sub_policy; 16712 mlx5_hrxq_release(dev, hrxq_idx[i]); 16713 } else { 16714 /* 16715 * Overwrite the last action from 16716 * RSS action to Queue action. 16717 */ 16718 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 16719 hrxq_idx[i]); 16720 if (!hrxq) { 16721 DRV_LOG(ERR, "Failed to get policy hrxq"); 16722 goto rss_sub_policy_error; 16723 } 16724 act_cnt = &mtr_policy->act_cnt[i]; 16725 if (act_cnt->rix_mark || act_cnt->modify_hdr) { 16726 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 16727 if (act_cnt->rix_mark) 16728 dh.mark = 1; 16729 dh.fate_action = MLX5_FLOW_FATE_QUEUE; 16730 dh.rix_hrxq = hrxq_idx[i]; 16731 flow_drv_rxq_flags_set(dev, &dh); 16732 } 16733 } 16734 } 16735 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16736 sub_policy, domain)) { 16737 DRV_LOG(ERR, "Failed to create policy " 16738 "rules for ingress domain."); 16739 goto rss_sub_policy_error; 16740 } 16741 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16742 i = (mtr_policy->sub_policy_num >> 16743 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16744 MLX5_MTR_SUB_POLICY_NUM_MASK; 16745 if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) { 16746 DRV_LOG(ERR, "No free sub-policy slot."); 16747 goto rss_sub_policy_error; 16748 } 16749 mtr_policy->sub_policys[domain][i] = sub_policy; 16750 i++; 16751 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 16752 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 16753 mtr_policy->sub_policy_num |= 16754 (i & MLX5_MTR_SUB_POLICY_NUM_MASK) << 16755 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 16756 } 16757 rte_spinlock_unlock(&mtr_policy->sl); 16758 *is_reuse = false; 16759 return sub_policy; 16760 rss_sub_policy_error: 16761 if (sub_policy) { 16762 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 16763 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16764 i = (mtr_policy->sub_policy_num >> 16765 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16766 MLX5_MTR_SUB_POLICY_NUM_MASK; 16767 mtr_policy->sub_policys[domain][i] = NULL; 16768 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16769 sub_policy->idx); 16770 } 16771 } 16772 rte_spinlock_unlock(&mtr_policy->sl); 16773 return NULL; 16774 } 16775 16776 /** 16777 * Find the policy table for prefix table with RSS. 16778 * 16779 * @param[in] dev 16780 * Pointer to Ethernet device. 16781 * @param[in] mtr_policy 16782 * Pointer to meter policy table. 16783 * @param[in] rss_desc 16784 * Pointer to rss_desc 16785 * @return 16786 * Pointer to table set on success, NULL otherwise and rte_errno is set. 16787 */ 16788 static struct mlx5_flow_meter_sub_policy * 16789 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev, 16790 struct mlx5_flow_meter_policy *mtr_policy, 16791 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]) 16792 { 16793 struct mlx5_priv *priv = dev->data->dev_private; 16794 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16795 struct mlx5_flow_meter_info *next_fm; 16796 struct mlx5_flow_meter_policy *next_policy; 16797 struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL; 16798 struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM]; 16799 struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM]; 16800 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16801 bool reuse_sub_policy; 16802 uint32_t i = 0; 16803 uint32_t j = 0; 16804 16805 while (true) { 16806 /* Iterate hierarchy to get all policies in this hierarchy. */ 16807 policies[i++] = mtr_policy; 16808 if (!mtr_policy->is_hierarchy) 16809 break; 16810 if (i >= MLX5_MTR_CHAIN_MAX_NUM) { 16811 DRV_LOG(ERR, "Exceed max meter number in hierarchy."); 16812 return NULL; 16813 } 16814 next_fm = mlx5_flow_meter_find(priv, 16815 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 16816 if (!next_fm) { 16817 DRV_LOG(ERR, "Failed to get next meter in hierarchy."); 16818 return NULL; 16819 } 16820 next_policy = 16821 mlx5_flow_meter_policy_find(dev, next_fm->policy_id, 16822 NULL); 16823 MLX5_ASSERT(next_policy); 16824 mtr_policy = next_policy; 16825 } 16826 while (i) { 16827 /** 16828 * From last policy to the first one in hierarchy, 16829 * create / get the sub policy for each of them. 16830 */ 16831 sub_policy = __flow_dv_meter_get_rss_sub_policy(dev, 16832 policies[--i], 16833 rss_desc, 16834 next_sub_policy, 16835 &reuse_sub_policy); 16836 if (!sub_policy) { 16837 DRV_LOG(ERR, "Failed to get the sub policy."); 16838 goto err_exit; 16839 } 16840 if (!reuse_sub_policy) 16841 sub_policies[j++] = sub_policy; 16842 next_sub_policy = sub_policy; 16843 } 16844 return sub_policy; 16845 err_exit: 16846 while (j) { 16847 uint16_t sub_policy_num; 16848 16849 sub_policy = sub_policies[--j]; 16850 mtr_policy = sub_policy->main_policy; 16851 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 16852 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16853 sub_policy_num = (mtr_policy->sub_policy_num >> 16854 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16855 MLX5_MTR_SUB_POLICY_NUM_MASK; 16856 mtr_policy->sub_policys[domain][sub_policy_num - 1] = 16857 NULL; 16858 sub_policy_num--; 16859 mtr_policy->sub_policy_num &= 16860 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 16861 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)); 16862 mtr_policy->sub_policy_num |= 16863 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) << 16864 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i); 16865 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16866 sub_policy->idx); 16867 } 16868 } 16869 return NULL; 16870 } 16871 16872 /** 16873 * Create the sub policy tag rule for all meters in hierarchy. 16874 * 16875 * @param[in] dev 16876 * Pointer to Ethernet device. 16877 * @param[in] fm 16878 * Meter information table. 16879 * @param[in] src_port 16880 * The src port this extra rule should use. 16881 * @param[in] item 16882 * The src port match item. 16883 * @param[out] error 16884 * Perform verbose error reporting if not NULL. 16885 * @return 16886 * 0 on success, a negative errno value otherwise and rte_errno is set. 16887 */ 16888 static int 16889 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev, 16890 struct mlx5_flow_meter_info *fm, 16891 int32_t src_port, 16892 const struct rte_flow_item *item, 16893 struct rte_flow_error *error) 16894 { 16895 struct mlx5_priv *priv = dev->data->dev_private; 16896 struct mlx5_flow_meter_policy *mtr_policy; 16897 struct mlx5_flow_meter_sub_policy *sub_policy; 16898 struct mlx5_flow_meter_info *next_fm = NULL; 16899 struct mlx5_flow_meter_policy *next_policy; 16900 struct mlx5_flow_meter_sub_policy *next_sub_policy; 16901 struct mlx5_flow_tbl_data_entry *tbl_data; 16902 struct mlx5_sub_policy_color_rule *color_rule; 16903 struct mlx5_meter_policy_acts acts; 16904 uint32_t color_reg_c_idx; 16905 bool mtr_first = (src_port != UINT16_MAX) ? true : false; 16906 struct rte_flow_attr attr = { 16907 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 16908 .priority = 0, 16909 .ingress = 0, 16910 .egress = 0, 16911 .transfer = 1, 16912 .reserved = 0, 16913 }; 16914 uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER; 16915 int i; 16916 16917 mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 16918 MLX5_ASSERT(mtr_policy); 16919 if (!mtr_policy->is_hierarchy) 16920 return 0; 16921 next_fm = mlx5_flow_meter_find(priv, 16922 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 16923 if (!next_fm) { 16924 return rte_flow_error_set(error, EINVAL, 16925 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 16926 "Failed to find next meter in hierarchy."); 16927 } 16928 if (!next_fm->drop_cnt) 16929 goto exit; 16930 color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); 16931 sub_policy = mtr_policy->sub_policys[domain][0]; 16932 for (i = 0; i < RTE_COLORS; i++) { 16933 bool rule_exist = false; 16934 struct mlx5_meter_policy_action_container *act_cnt; 16935 16936 if (i >= RTE_COLOR_YELLOW) 16937 break; 16938 TAILQ_FOREACH(color_rule, 16939 &sub_policy->color_rules[i], next_port) 16940 if (color_rule->src_port == src_port) { 16941 rule_exist = true; 16942 break; 16943 } 16944 if (rule_exist) 16945 continue; 16946 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 16947 sizeof(struct mlx5_sub_policy_color_rule), 16948 0, SOCKET_ID_ANY); 16949 if (!color_rule) 16950 return rte_flow_error_set(error, ENOMEM, 16951 RTE_FLOW_ERROR_TYPE_ACTION, 16952 NULL, "No memory to create tag color rule."); 16953 color_rule->src_port = src_port; 16954 attr.priority = i; 16955 next_policy = mlx5_flow_meter_policy_find(dev, 16956 next_fm->policy_id, NULL); 16957 MLX5_ASSERT(next_policy); 16958 next_sub_policy = next_policy->sub_policys[domain][0]; 16959 tbl_data = container_of(next_sub_policy->tbl_rsc, 16960 struct mlx5_flow_tbl_data_entry, tbl); 16961 act_cnt = &mtr_policy->act_cnt[i]; 16962 if (mtr_first) { 16963 acts.dv_actions[0] = next_fm->meter_action; 16964 acts.dv_actions[1] = act_cnt->modify_hdr->action; 16965 } else { 16966 acts.dv_actions[0] = act_cnt->modify_hdr->action; 16967 acts.dv_actions[1] = next_fm->meter_action; 16968 } 16969 acts.dv_actions[2] = tbl_data->jump.action; 16970 acts.actions_n = 3; 16971 if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) { 16972 next_fm = NULL; 16973 goto err_exit; 16974 } 16975 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 16976 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 16977 &attr, true, item, 16978 &color_rule->matcher, error)) { 16979 rte_flow_error_set(error, errno, 16980 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 16981 "Failed to create hierarchy meter matcher."); 16982 goto err_exit; 16983 } 16984 if (__flow_dv_create_policy_flow(dev, color_reg_c_idx, 16985 (enum rte_color)i, 16986 color_rule->matcher->matcher_object, 16987 acts.actions_n, acts.dv_actions, 16988 true, item, 16989 &color_rule->rule, &attr)) { 16990 rte_flow_error_set(error, errno, 16991 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 16992 "Failed to create hierarchy meter rule."); 16993 goto err_exit; 16994 } 16995 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 16996 color_rule, next_port); 16997 } 16998 exit: 16999 /** 17000 * Recursive call to iterate all meters in hierarchy and 17001 * create needed rules. 17002 */ 17003 return flow_dv_meter_hierarchy_rule_create(dev, next_fm, 17004 src_port, item, error); 17005 err_exit: 17006 if (color_rule) { 17007 if (color_rule->rule) 17008 mlx5_flow_os_destroy_flow(color_rule->rule); 17009 if (color_rule->matcher) { 17010 struct mlx5_flow_tbl_data_entry *tbl = 17011 container_of(color_rule->matcher->tbl, 17012 typeof(*tbl), tbl); 17013 mlx5_list_unregister(tbl->matchers, 17014 &color_rule->matcher->entry); 17015 } 17016 mlx5_free(color_rule); 17017 } 17018 if (next_fm) 17019 mlx5_flow_meter_detach(priv, next_fm); 17020 return -rte_errno; 17021 } 17022 17023 /** 17024 * Destroy the sub policy table with RX queue. 17025 * 17026 * @param[in] dev 17027 * Pointer to Ethernet device. 17028 * @param[in] mtr_policy 17029 * Pointer to meter policy table. 17030 */ 17031 static void 17032 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, 17033 struct mlx5_flow_meter_policy *mtr_policy) 17034 { 17035 struct mlx5_priv *priv = dev->data->dev_private; 17036 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 17037 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 17038 uint32_t i, j; 17039 uint16_t sub_policy_num, new_policy_num; 17040 17041 rte_spinlock_lock(&mtr_policy->sl); 17042 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17043 switch (mtr_policy->act_cnt[i].fate_action) { 17044 case MLX5_FLOW_FATE_SHARED_RSS: 17045 sub_policy_num = (mtr_policy->sub_policy_num >> 17046 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17047 MLX5_MTR_SUB_POLICY_NUM_MASK; 17048 new_policy_num = sub_policy_num; 17049 for (j = 0; j < sub_policy_num; j++) { 17050 sub_policy = 17051 mtr_policy->sub_policys[domain][j]; 17052 if (sub_policy) { 17053 __flow_dv_destroy_sub_policy_rules(dev, 17054 sub_policy); 17055 if (sub_policy != 17056 mtr_policy->sub_policys[domain][0]) { 17057 mtr_policy->sub_policys[domain][j] = 17058 NULL; 17059 mlx5_ipool_free 17060 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17061 sub_policy->idx); 17062 new_policy_num--; 17063 } 17064 } 17065 } 17066 if (new_policy_num != sub_policy_num) { 17067 mtr_policy->sub_policy_num &= 17068 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17069 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 17070 mtr_policy->sub_policy_num |= 17071 (new_policy_num & 17072 MLX5_MTR_SUB_POLICY_NUM_MASK) << 17073 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 17074 } 17075 break; 17076 case MLX5_FLOW_FATE_QUEUE: 17077 sub_policy = mtr_policy->sub_policys[domain][0]; 17078 __flow_dv_destroy_sub_policy_rules(dev, 17079 sub_policy); 17080 break; 17081 default: 17082 /*Other actions without queue and do nothing*/ 17083 break; 17084 } 17085 } 17086 rte_spinlock_unlock(&mtr_policy->sl); 17087 } 17088 /** 17089 * Check whether the DR drop action is supported on the root table or not. 17090 * 17091 * Create a simple flow with DR drop action on root table to validate 17092 * if DR drop action on root table is supported or not. 17093 * 17094 * @param[in] dev 17095 * Pointer to rte_eth_dev structure. 17096 * 17097 * @return 17098 * 0 on success, a negative errno value otherwise and rte_errno is set. 17099 */ 17100 int 17101 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev) 17102 { 17103 struct mlx5_priv *priv = dev->data->dev_private; 17104 struct mlx5_dev_ctx_shared *sh = priv->sh; 17105 struct mlx5_flow_dv_match_params mask = { 17106 .size = sizeof(mask.buf), 17107 }; 17108 struct mlx5_flow_dv_match_params value = { 17109 .size = sizeof(value.buf), 17110 }; 17111 struct mlx5dv_flow_matcher_attr dv_attr = { 17112 .type = IBV_FLOW_ATTR_NORMAL, 17113 .priority = 0, 17114 .match_criteria_enable = 0, 17115 .match_mask = (void *)&mask, 17116 }; 17117 struct mlx5_flow_tbl_resource *tbl = NULL; 17118 void *matcher = NULL; 17119 void *flow = NULL; 17120 int ret = -1; 17121 17122 tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 17123 0, 0, 0, NULL); 17124 if (!tbl) 17125 goto err; 17126 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17127 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17128 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 17129 tbl->obj, &matcher); 17130 if (ret) 17131 goto err; 17132 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17133 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17134 &sh->dr_drop_action, &flow); 17135 err: 17136 /* 17137 * If DR drop action is not supported on root table, flow create will 17138 * be failed with EOPNOTSUPP or EPROTONOSUPPORT. 17139 */ 17140 if (!flow) { 17141 if (matcher && 17142 (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP)) 17143 DRV_LOG(INFO, "DR drop action is not supported in root table."); 17144 else 17145 DRV_LOG(ERR, "Unexpected error in DR drop action support detection"); 17146 ret = -1; 17147 } else { 17148 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17149 } 17150 if (matcher) 17151 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17152 if (tbl) 17153 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17154 return ret; 17155 } 17156 17157 /** 17158 * Validate the batch counter support in root table. 17159 * 17160 * Create a simple flow with invalid counter and drop action on root table to 17161 * validate if batch counter with offset on root table is supported or not. 17162 * 17163 * @param[in] dev 17164 * Pointer to rte_eth_dev structure. 17165 * 17166 * @return 17167 * 0 on success, a negative errno value otherwise and rte_errno is set. 17168 */ 17169 int 17170 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev) 17171 { 17172 struct mlx5_priv *priv = dev->data->dev_private; 17173 struct mlx5_dev_ctx_shared *sh = priv->sh; 17174 struct mlx5_flow_dv_match_params mask = { 17175 .size = sizeof(mask.buf), 17176 }; 17177 struct mlx5_flow_dv_match_params value = { 17178 .size = sizeof(value.buf), 17179 }; 17180 struct mlx5dv_flow_matcher_attr dv_attr = { 17181 .type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS, 17182 .priority = 0, 17183 .match_criteria_enable = 0, 17184 .match_mask = (void *)&mask, 17185 }; 17186 void *actions[2] = { 0 }; 17187 struct mlx5_flow_tbl_resource *tbl = NULL; 17188 struct mlx5_devx_obj *dcs = NULL; 17189 void *matcher = NULL; 17190 void *flow = NULL; 17191 int ret = -1; 17192 17193 tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL, 17194 0, 0, 0, NULL); 17195 if (!tbl) 17196 goto err; 17197 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 17198 if (!dcs) 17199 goto err; 17200 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX, 17201 &actions[0]); 17202 if (ret) 17203 goto err; 17204 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17205 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17206 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 17207 tbl->obj, &matcher); 17208 if (ret) 17209 goto err; 17210 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17211 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17212 actions, &flow); 17213 err: 17214 /* 17215 * If batch counter with offset is not supported, the driver will not 17216 * validate the invalid offset value, flow create should success. 17217 * In this case, it means batch counter is not supported in root table. 17218 * 17219 * Otherwise, if flow create is failed, counter offset is supported. 17220 */ 17221 if (flow) { 17222 DRV_LOG(INFO, "Batch counter is not supported in root " 17223 "table. Switch to fallback mode."); 17224 rte_errno = ENOTSUP; 17225 ret = -rte_errno; 17226 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17227 } else { 17228 /* Check matcher to make sure validate fail at flow create. */ 17229 if (!matcher || (matcher && errno != EINVAL)) 17230 DRV_LOG(ERR, "Unexpected error in counter offset " 17231 "support detection"); 17232 ret = 0; 17233 } 17234 if (actions[0]) 17235 claim_zero(mlx5_flow_os_destroy_flow_action(actions[0])); 17236 if (matcher) 17237 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17238 if (tbl) 17239 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17240 if (dcs) 17241 claim_zero(mlx5_devx_cmd_destroy(dcs)); 17242 return ret; 17243 } 17244 17245 /** 17246 * Query a devx counter. 17247 * 17248 * @param[in] dev 17249 * Pointer to the Ethernet device structure. 17250 * @param[in] cnt 17251 * Index to the flow counter. 17252 * @param[in] clear 17253 * Set to clear the counter statistics. 17254 * @param[out] pkts 17255 * The statistics value of packets. 17256 * @param[out] bytes 17257 * The statistics value of bytes. 17258 * 17259 * @return 17260 * 0 on success, otherwise return -1. 17261 */ 17262 static int 17263 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear, 17264 uint64_t *pkts, uint64_t *bytes) 17265 { 17266 struct mlx5_priv *priv = dev->data->dev_private; 17267 struct mlx5_flow_counter *cnt; 17268 uint64_t inn_pkts, inn_bytes; 17269 int ret; 17270 17271 if (!priv->sh->devx) 17272 return -1; 17273 17274 ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes); 17275 if (ret) 17276 return -1; 17277 cnt = flow_dv_counter_get_by_idx(dev, counter, NULL); 17278 *pkts = inn_pkts - cnt->hits; 17279 *bytes = inn_bytes - cnt->bytes; 17280 if (clear) { 17281 cnt->hits = inn_pkts; 17282 cnt->bytes = inn_bytes; 17283 } 17284 return 0; 17285 } 17286 17287 /** 17288 * Get aged-out flows. 17289 * 17290 * @param[in] dev 17291 * Pointer to the Ethernet device structure. 17292 * @param[in] context 17293 * The address of an array of pointers to the aged-out flows contexts. 17294 * @param[in] nb_contexts 17295 * The length of context array pointers. 17296 * @param[out] error 17297 * Perform verbose error reporting if not NULL. Initialized in case of 17298 * error only. 17299 * 17300 * @return 17301 * how many contexts get in success, otherwise negative errno value. 17302 * if nb_contexts is 0, return the amount of all aged contexts. 17303 * if nb_contexts is not 0 , return the amount of aged flows reported 17304 * in the context array. 17305 * @note: only stub for now 17306 */ 17307 static int 17308 flow_dv_get_aged_flows(struct rte_eth_dev *dev, 17309 void **context, 17310 uint32_t nb_contexts, 17311 struct rte_flow_error *error) 17312 { 17313 struct mlx5_priv *priv = dev->data->dev_private; 17314 struct mlx5_age_info *age_info; 17315 struct mlx5_age_param *age_param; 17316 struct mlx5_flow_counter *counter; 17317 struct mlx5_aso_age_action *act; 17318 int nb_flows = 0; 17319 17320 if (nb_contexts && !context) 17321 return rte_flow_error_set(error, EINVAL, 17322 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17323 NULL, "empty context"); 17324 age_info = GET_PORT_AGE_INFO(priv); 17325 rte_spinlock_lock(&age_info->aged_sl); 17326 LIST_FOREACH(act, &age_info->aged_aso, next) { 17327 nb_flows++; 17328 if (nb_contexts) { 17329 context[nb_flows - 1] = 17330 act->age_params.context; 17331 if (!(--nb_contexts)) 17332 break; 17333 } 17334 } 17335 TAILQ_FOREACH(counter, &age_info->aged_counters, next) { 17336 nb_flows++; 17337 if (nb_contexts) { 17338 age_param = MLX5_CNT_TO_AGE(counter); 17339 context[nb_flows - 1] = age_param->context; 17340 if (!(--nb_contexts)) 17341 break; 17342 } 17343 } 17344 rte_spinlock_unlock(&age_info->aged_sl); 17345 MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); 17346 return nb_flows; 17347 } 17348 17349 /* 17350 * Mutex-protected thunk to lock-free flow_dv_counter_alloc(). 17351 */ 17352 static uint32_t 17353 flow_dv_counter_allocate(struct rte_eth_dev *dev) 17354 { 17355 return flow_dv_counter_alloc(dev, 0); 17356 } 17357 17358 /** 17359 * Validate indirect action. 17360 * Dispatcher for action type specific validation. 17361 * 17362 * @param[in] dev 17363 * Pointer to the Ethernet device structure. 17364 * @param[in] conf 17365 * Indirect action configuration. 17366 * @param[in] action 17367 * The indirect action object to validate. 17368 * @param[out] error 17369 * Perform verbose error reporting if not NULL. Initialized in case of 17370 * error only. 17371 * 17372 * @return 17373 * 0 on success, otherwise negative errno value. 17374 */ 17375 static int 17376 flow_dv_action_validate(struct rte_eth_dev *dev, 17377 const struct rte_flow_indir_action_conf *conf, 17378 const struct rte_flow_action *action, 17379 struct rte_flow_error *err) 17380 { 17381 struct mlx5_priv *priv = dev->data->dev_private; 17382 17383 RTE_SET_USED(conf); 17384 switch (action->type) { 17385 case RTE_FLOW_ACTION_TYPE_RSS: 17386 /* 17387 * priv->obj_ops is set according to driver capabilities. 17388 * When DevX capabilities are 17389 * sufficient, it is set to devx_obj_ops. 17390 * Otherwise, it is set to ibv_obj_ops. 17391 * ibv_obj_ops doesn't support ind_table_modify operation. 17392 * In this case the indirect RSS action can't be used. 17393 */ 17394 if (priv->obj_ops.ind_table_modify == NULL) 17395 return rte_flow_error_set 17396 (err, ENOTSUP, 17397 RTE_FLOW_ERROR_TYPE_ACTION, 17398 NULL, 17399 "Indirect RSS action not supported"); 17400 return mlx5_validate_action_rss(dev, action, err); 17401 case RTE_FLOW_ACTION_TYPE_AGE: 17402 if (!priv->sh->aso_age_mng) 17403 return rte_flow_error_set(err, ENOTSUP, 17404 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17405 NULL, 17406 "Indirect age action not supported"); 17407 return flow_dv_validate_action_age(0, action, dev, err); 17408 case RTE_FLOW_ACTION_TYPE_COUNT: 17409 return flow_dv_validate_action_count(dev, true, 0, err); 17410 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 17411 if (!priv->sh->ct_aso_en) 17412 return rte_flow_error_set(err, ENOTSUP, 17413 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17414 "ASO CT is not supported"); 17415 return mlx5_validate_action_ct(dev, action->conf, err); 17416 default: 17417 return rte_flow_error_set(err, ENOTSUP, 17418 RTE_FLOW_ERROR_TYPE_ACTION, 17419 NULL, 17420 "action type not supported"); 17421 } 17422 } 17423 17424 /* 17425 * Check if the RSS configurations for colors of a meter policy match 17426 * each other, except the queues. 17427 * 17428 * @param[in] r1 17429 * Pointer to the first RSS flow action. 17430 * @param[in] r2 17431 * Pointer to the second RSS flow action. 17432 * 17433 * @return 17434 * 0 on match, 1 on conflict. 17435 */ 17436 static inline int 17437 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1, 17438 const struct rte_flow_action_rss *r2) 17439 { 17440 if (!r1 || !r2) 17441 return 0; 17442 if (r1->func != r2->func || r1->level != r2->level || 17443 r1->types != r2->types || r1->key_len != r2->key_len || 17444 memcmp(r1->key, r2->key, r1->key_len)) 17445 return 1; 17446 return 0; 17447 } 17448 17449 /** 17450 * Validate the meter hierarchy chain for meter policy. 17451 * 17452 * @param[in] dev 17453 * Pointer to the Ethernet device structure. 17454 * @param[in] meter_id 17455 * Meter id. 17456 * @param[in] action_flags 17457 * Holds the actions detected until now. 17458 * @param[out] is_rss 17459 * Is RSS or not. 17460 * @param[out] hierarchy_domain 17461 * The domain bitmap for hierarchy policy. 17462 * @param[out] error 17463 * Perform verbose error reporting if not NULL. Initialized in case of 17464 * error only. 17465 * 17466 * @return 17467 * 0 on success, otherwise negative errno value with error set. 17468 */ 17469 static int 17470 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, 17471 uint32_t meter_id, 17472 uint64_t action_flags, 17473 bool *is_rss, 17474 uint8_t *hierarchy_domain, 17475 struct rte_mtr_error *error) 17476 { 17477 struct mlx5_priv *priv = dev->data->dev_private; 17478 struct mlx5_flow_meter_info *fm; 17479 struct mlx5_flow_meter_policy *policy; 17480 uint8_t cnt = 1; 17481 17482 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 17483 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17484 return -rte_mtr_error_set(error, EINVAL, 17485 RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, 17486 NULL, 17487 "Multiple fate actions not supported."); 17488 *hierarchy_domain = 0; 17489 while (true) { 17490 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 17491 if (!fm) 17492 return -rte_mtr_error_set(error, EINVAL, 17493 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17494 "Meter not found in meter hierarchy."); 17495 if (fm->def_policy) 17496 return -rte_mtr_error_set(error, EINVAL, 17497 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17498 "Non termination meter not supported in hierarchy."); 17499 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 17500 MLX5_ASSERT(policy); 17501 /** 17502 * Only inherit the supported domains of the first meter in 17503 * hierarchy. 17504 * One meter supports at least one domain. 17505 */ 17506 if (!*hierarchy_domain) { 17507 if (policy->transfer) 17508 *hierarchy_domain |= 17509 MLX5_MTR_DOMAIN_TRANSFER_BIT; 17510 if (policy->ingress) 17511 *hierarchy_domain |= 17512 MLX5_MTR_DOMAIN_INGRESS_BIT; 17513 if (policy->egress) 17514 *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT; 17515 } 17516 if (!policy->is_hierarchy) { 17517 *is_rss = policy->is_rss; 17518 break; 17519 } 17520 meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id; 17521 if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM) 17522 return -rte_mtr_error_set(error, EINVAL, 17523 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 17524 "Exceed max hierarchy meter number."); 17525 } 17526 return 0; 17527 } 17528 17529 /** 17530 * Validate meter policy actions. 17531 * Dispatcher for action type specific validation. 17532 * 17533 * @param[in] dev 17534 * Pointer to the Ethernet device structure. 17535 * @param[in] action 17536 * The meter policy action object to validate. 17537 * @param[in] attr 17538 * Attributes of flow to determine steering domain. 17539 * @param[out] error 17540 * Perform verbose error reporting if not NULL. Initialized in case of 17541 * error only. 17542 * 17543 * @return 17544 * 0 on success, otherwise negative errno value. 17545 */ 17546 static int 17547 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, 17548 const struct rte_flow_action *actions[RTE_COLORS], 17549 struct rte_flow_attr *attr, 17550 bool *is_rss, 17551 uint8_t *domain_bitmap, 17552 uint8_t *policy_mode, 17553 struct rte_mtr_error *error) 17554 { 17555 struct mlx5_priv *priv = dev->data->dev_private; 17556 struct mlx5_dev_config *dev_conf = &priv->config; 17557 const struct rte_flow_action *act; 17558 uint64_t action_flags[RTE_COLORS] = {0}; 17559 int actions_n; 17560 int i, ret; 17561 struct rte_flow_error flow_err; 17562 uint8_t domain_color[RTE_COLORS] = {0}; 17563 uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT; 17564 uint8_t hierarchy_domain = 0; 17565 const struct rte_flow_action_meter *mtr; 17566 bool def_green = false; 17567 bool def_yellow = false; 17568 const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; 17569 17570 if (!priv->config.dv_esw_en) 17571 def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 17572 *domain_bitmap = def_domain; 17573 /* Red color could only support DROP action. */ 17574 if (!actions[RTE_COLOR_RED] || 17575 actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) 17576 return -rte_mtr_error_set(error, ENOTSUP, 17577 RTE_MTR_ERROR_TYPE_METER_POLICY, 17578 NULL, "Red color only supports drop action."); 17579 /* 17580 * Check default policy actions: 17581 * Green / Yellow: no action, Red: drop action 17582 * Either G or Y will trigger default policy actions to be created. 17583 */ 17584 if (!actions[RTE_COLOR_GREEN] || 17585 actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) 17586 def_green = true; 17587 if (!actions[RTE_COLOR_YELLOW] || 17588 actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) 17589 def_yellow = true; 17590 if (def_green && def_yellow) { 17591 *policy_mode = MLX5_MTR_POLICY_MODE_DEF; 17592 return 0; 17593 } else if (!def_green && def_yellow) { 17594 *policy_mode = MLX5_MTR_POLICY_MODE_OG; 17595 } else if (def_green && !def_yellow) { 17596 *policy_mode = MLX5_MTR_POLICY_MODE_OY; 17597 } 17598 /* Set to empty string in case of NULL pointer access by user. */ 17599 flow_err.message = ""; 17600 for (i = 0; i < RTE_COLORS; i++) { 17601 act = actions[i]; 17602 for (action_flags[i] = 0, actions_n = 0; 17603 act && act->type != RTE_FLOW_ACTION_TYPE_END; 17604 act++) { 17605 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 17606 return -rte_mtr_error_set(error, ENOTSUP, 17607 RTE_MTR_ERROR_TYPE_METER_POLICY, 17608 NULL, "too many actions"); 17609 switch (act->type) { 17610 case RTE_FLOW_ACTION_TYPE_PORT_ID: 17611 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 17612 if (!priv->config.dv_esw_en) 17613 return -rte_mtr_error_set(error, 17614 ENOTSUP, 17615 RTE_MTR_ERROR_TYPE_METER_POLICY, 17616 NULL, "PORT action validate check" 17617 " fail for ESW disable"); 17618 ret = flow_dv_validate_action_port_id(dev, 17619 action_flags[i], 17620 act, attr, &flow_err); 17621 if (ret) 17622 return -rte_mtr_error_set(error, 17623 ENOTSUP, 17624 RTE_MTR_ERROR_TYPE_METER_POLICY, 17625 NULL, flow_err.message ? 17626 flow_err.message : 17627 "PORT action validate check fail"); 17628 ++actions_n; 17629 action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID; 17630 break; 17631 case RTE_FLOW_ACTION_TYPE_MARK: 17632 ret = flow_dv_validate_action_mark(dev, act, 17633 action_flags[i], 17634 attr, &flow_err); 17635 if (ret < 0) 17636 return -rte_mtr_error_set(error, 17637 ENOTSUP, 17638 RTE_MTR_ERROR_TYPE_METER_POLICY, 17639 NULL, flow_err.message ? 17640 flow_err.message : 17641 "Mark action validate check fail"); 17642 if (dev_conf->dv_xmeta_en != 17643 MLX5_XMETA_MODE_LEGACY) 17644 return -rte_mtr_error_set(error, 17645 ENOTSUP, 17646 RTE_MTR_ERROR_TYPE_METER_POLICY, 17647 NULL, "Extend MARK action is " 17648 "not supported. Please try use " 17649 "default policy for meter."); 17650 action_flags[i] |= MLX5_FLOW_ACTION_MARK; 17651 ++actions_n; 17652 break; 17653 case RTE_FLOW_ACTION_TYPE_SET_TAG: 17654 ret = flow_dv_validate_action_set_tag(dev, 17655 act, action_flags[i], 17656 attr, &flow_err); 17657 if (ret) 17658 return -rte_mtr_error_set(error, 17659 ENOTSUP, 17660 RTE_MTR_ERROR_TYPE_METER_POLICY, 17661 NULL, flow_err.message ? 17662 flow_err.message : 17663 "Set tag action validate check fail"); 17664 action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG; 17665 ++actions_n; 17666 break; 17667 case RTE_FLOW_ACTION_TYPE_DROP: 17668 ret = mlx5_flow_validate_action_drop 17669 (action_flags[i], attr, &flow_err); 17670 if (ret < 0) 17671 return -rte_mtr_error_set(error, 17672 ENOTSUP, 17673 RTE_MTR_ERROR_TYPE_METER_POLICY, 17674 NULL, flow_err.message ? 17675 flow_err.message : 17676 "Drop action validate check fail"); 17677 action_flags[i] |= MLX5_FLOW_ACTION_DROP; 17678 ++actions_n; 17679 break; 17680 case RTE_FLOW_ACTION_TYPE_QUEUE: 17681 /* 17682 * Check whether extensive 17683 * metadata feature is engaged. 17684 */ 17685 if (dev_conf->dv_flow_en && 17686 (dev_conf->dv_xmeta_en != 17687 MLX5_XMETA_MODE_LEGACY) && 17688 mlx5_flow_ext_mreg_supported(dev)) 17689 return -rte_mtr_error_set(error, 17690 ENOTSUP, 17691 RTE_MTR_ERROR_TYPE_METER_POLICY, 17692 NULL, "Queue action with meta " 17693 "is not supported. Please try use " 17694 "default policy for meter."); 17695 ret = mlx5_flow_validate_action_queue(act, 17696 action_flags[i], dev, 17697 attr, &flow_err); 17698 if (ret < 0) 17699 return -rte_mtr_error_set(error, 17700 ENOTSUP, 17701 RTE_MTR_ERROR_TYPE_METER_POLICY, 17702 NULL, flow_err.message ? 17703 flow_err.message : 17704 "Queue action validate check fail"); 17705 action_flags[i] |= MLX5_FLOW_ACTION_QUEUE; 17706 ++actions_n; 17707 break; 17708 case RTE_FLOW_ACTION_TYPE_RSS: 17709 if (dev_conf->dv_flow_en && 17710 (dev_conf->dv_xmeta_en != 17711 MLX5_XMETA_MODE_LEGACY) && 17712 mlx5_flow_ext_mreg_supported(dev)) 17713 return -rte_mtr_error_set(error, 17714 ENOTSUP, 17715 RTE_MTR_ERROR_TYPE_METER_POLICY, 17716 NULL, "RSS action with meta " 17717 "is not supported. Please try use " 17718 "default policy for meter."); 17719 ret = mlx5_validate_action_rss(dev, act, 17720 &flow_err); 17721 if (ret < 0) 17722 return -rte_mtr_error_set(error, 17723 ENOTSUP, 17724 RTE_MTR_ERROR_TYPE_METER_POLICY, 17725 NULL, flow_err.message ? 17726 flow_err.message : 17727 "RSS action validate check fail"); 17728 action_flags[i] |= MLX5_FLOW_ACTION_RSS; 17729 ++actions_n; 17730 /* Either G or Y will set the RSS. */ 17731 rss_color[i] = act->conf; 17732 break; 17733 case RTE_FLOW_ACTION_TYPE_JUMP: 17734 ret = flow_dv_validate_action_jump(dev, 17735 NULL, act, action_flags[i], 17736 attr, true, &flow_err); 17737 if (ret) 17738 return -rte_mtr_error_set(error, 17739 ENOTSUP, 17740 RTE_MTR_ERROR_TYPE_METER_POLICY, 17741 NULL, flow_err.message ? 17742 flow_err.message : 17743 "Jump action validate check fail"); 17744 ++actions_n; 17745 action_flags[i] |= MLX5_FLOW_ACTION_JUMP; 17746 break; 17747 /* 17748 * Only the last meter in the hierarchy will support 17749 * the YELLOW color steering. Then in the meter policy 17750 * actions list, there should be no other meter inside. 17751 */ 17752 case RTE_FLOW_ACTION_TYPE_METER: 17753 if (i != RTE_COLOR_GREEN) 17754 return -rte_mtr_error_set(error, 17755 ENOTSUP, 17756 RTE_MTR_ERROR_TYPE_METER_POLICY, 17757 NULL, 17758 "Meter hierarchy only supports GREEN color."); 17759 if (*policy_mode != MLX5_MTR_POLICY_MODE_OG) 17760 return -rte_mtr_error_set(error, 17761 ENOTSUP, 17762 RTE_MTR_ERROR_TYPE_METER_POLICY, 17763 NULL, 17764 "No yellow policy should be provided in meter hierarchy."); 17765 mtr = act->conf; 17766 ret = flow_dv_validate_policy_mtr_hierarchy(dev, 17767 mtr->mtr_id, 17768 action_flags[i], 17769 is_rss, 17770 &hierarchy_domain, 17771 error); 17772 if (ret) 17773 return ret; 17774 ++actions_n; 17775 action_flags[i] |= 17776 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 17777 break; 17778 default: 17779 return -rte_mtr_error_set(error, ENOTSUP, 17780 RTE_MTR_ERROR_TYPE_METER_POLICY, 17781 NULL, 17782 "Doesn't support optional action"); 17783 } 17784 } 17785 if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) { 17786 domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT; 17787 } else if ((action_flags[i] & 17788 (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || 17789 (action_flags[i] & MLX5_FLOW_ACTION_MARK)) { 17790 /* 17791 * Only support MLX5_XMETA_MODE_LEGACY 17792 * so MARK action is only in ingress domain. 17793 */ 17794 domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT; 17795 } else { 17796 domain_color[i] = def_domain; 17797 if (action_flags[i] && 17798 !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17799 domain_color[i] &= 17800 ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 17801 } 17802 if (action_flags[i] & 17803 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 17804 domain_color[i] &= hierarchy_domain; 17805 /* 17806 * Non-termination actions only support NIC Tx domain. 17807 * The adjustion should be skipped when there is no 17808 * action or only END is provided. The default domains 17809 * bit-mask is set to find the MIN intersection. 17810 * The action flags checking should also be skipped. 17811 */ 17812 if ((def_green && i == RTE_COLOR_GREEN) || 17813 (def_yellow && i == RTE_COLOR_YELLOW)) 17814 continue; 17815 /* 17816 * Validate the drop action mutual exclusion 17817 * with other actions. Drop action is mutually-exclusive 17818 * with any other action, except for Count action. 17819 */ 17820 if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) && 17821 (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) { 17822 return -rte_mtr_error_set(error, ENOTSUP, 17823 RTE_MTR_ERROR_TYPE_METER_POLICY, 17824 NULL, "Drop action is mutually-exclusive " 17825 "with any other action"); 17826 } 17827 /* Eswitch has few restrictions on using items and actions */ 17828 if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) { 17829 if (!mlx5_flow_ext_mreg_supported(dev) && 17830 action_flags[i] & MLX5_FLOW_ACTION_MARK) 17831 return -rte_mtr_error_set(error, ENOTSUP, 17832 RTE_MTR_ERROR_TYPE_METER_POLICY, 17833 NULL, "unsupported action MARK"); 17834 if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE) 17835 return -rte_mtr_error_set(error, ENOTSUP, 17836 RTE_MTR_ERROR_TYPE_METER_POLICY, 17837 NULL, "unsupported action QUEUE"); 17838 if (action_flags[i] & MLX5_FLOW_ACTION_RSS) 17839 return -rte_mtr_error_set(error, ENOTSUP, 17840 RTE_MTR_ERROR_TYPE_METER_POLICY, 17841 NULL, "unsupported action RSS"); 17842 if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17843 return -rte_mtr_error_set(error, ENOTSUP, 17844 RTE_MTR_ERROR_TYPE_METER_POLICY, 17845 NULL, "no fate action is found"); 17846 } else { 17847 if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) && 17848 (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) { 17849 if ((domain_color[i] & 17850 MLX5_MTR_DOMAIN_EGRESS_BIT)) 17851 domain_color[i] = 17852 MLX5_MTR_DOMAIN_EGRESS_BIT; 17853 else 17854 return -rte_mtr_error_set(error, 17855 ENOTSUP, 17856 RTE_MTR_ERROR_TYPE_METER_POLICY, 17857 NULL, 17858 "no fate action is found"); 17859 } 17860 } 17861 } 17862 /* If both colors have RSS, the attributes should be the same. */ 17863 if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN], 17864 rss_color[RTE_COLOR_YELLOW])) 17865 return -rte_mtr_error_set(error, EINVAL, 17866 RTE_MTR_ERROR_TYPE_METER_POLICY, 17867 NULL, "policy RSS attr conflict"); 17868 if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW]) 17869 *is_rss = true; 17870 /* "domain_color[C]" is non-zero for each color, default is ALL. */ 17871 if (!def_green && !def_yellow && 17872 domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] && 17873 !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) && 17874 !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP)) 17875 return -rte_mtr_error_set(error, EINVAL, 17876 RTE_MTR_ERROR_TYPE_METER_POLICY, 17877 NULL, "policy domains conflict"); 17878 /* 17879 * At least one color policy is listed in the actions, the domains 17880 * to be supported should be the intersection. 17881 */ 17882 *domain_bitmap = domain_color[RTE_COLOR_GREEN] & 17883 domain_color[RTE_COLOR_YELLOW]; 17884 return 0; 17885 } 17886 17887 static int 17888 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags) 17889 { 17890 struct mlx5_priv *priv = dev->data->dev_private; 17891 int ret = 0; 17892 17893 if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) { 17894 ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain, 17895 flags); 17896 if (ret != 0) 17897 return ret; 17898 } 17899 if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) { 17900 ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags); 17901 if (ret != 0) 17902 return ret; 17903 } 17904 if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) { 17905 ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags); 17906 if (ret != 0) 17907 return ret; 17908 } 17909 return 0; 17910 } 17911 17912 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { 17913 .validate = flow_dv_validate, 17914 .prepare = flow_dv_prepare, 17915 .translate = flow_dv_translate, 17916 .apply = flow_dv_apply, 17917 .remove = flow_dv_remove, 17918 .destroy = flow_dv_destroy, 17919 .query = flow_dv_query, 17920 .create_mtr_tbls = flow_dv_create_mtr_tbls, 17921 .destroy_mtr_tbls = flow_dv_destroy_mtr_tbls, 17922 .destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls, 17923 .create_meter = flow_dv_mtr_alloc, 17924 .free_meter = flow_dv_aso_mtr_release_to_pool, 17925 .validate_mtr_acts = flow_dv_validate_mtr_policy_acts, 17926 .create_mtr_acts = flow_dv_create_mtr_policy_acts, 17927 .destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts, 17928 .create_policy_rules = flow_dv_create_policy_rules, 17929 .destroy_policy_rules = flow_dv_destroy_policy_rules, 17930 .create_def_policy = flow_dv_create_def_policy, 17931 .destroy_def_policy = flow_dv_destroy_def_policy, 17932 .meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare, 17933 .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create, 17934 .destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq, 17935 .counter_alloc = flow_dv_counter_allocate, 17936 .counter_free = flow_dv_counter_free, 17937 .counter_query = flow_dv_counter_query, 17938 .get_aged_flows = flow_dv_get_aged_flows, 17939 .action_validate = flow_dv_action_validate, 17940 .action_create = flow_dv_action_create, 17941 .action_destroy = flow_dv_action_destroy, 17942 .action_update = flow_dv_action_update, 17943 .action_query = flow_dv_action_query, 17944 .sync_domain = flow_dv_sync_domain, 17945 }; 17946 17947 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ 17948 17949