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_ip.h> 19 #include <rte_gre.h> 20 #include <rte_vxlan.h> 21 #include <rte_gtp.h> 22 #include <rte_eal_paging.h> 23 #include <rte_mpls.h> 24 #include <rte_mtr.h> 25 #include <rte_mtr_driver.h> 26 #include <rte_tailq.h> 27 28 #include <mlx5_glue.h> 29 #include <mlx5_devx_cmds.h> 30 #include <mlx5_prm.h> 31 #include <mlx5_malloc.h> 32 33 #include "mlx5_defs.h" 34 #include "mlx5.h" 35 #include "mlx5_common_os.h" 36 #include "mlx5_flow.h" 37 #include "mlx5_flow_os.h" 38 #include "mlx5_rx.h" 39 #include "mlx5_tx.h" 40 #include "rte_pmd_mlx5.h" 41 42 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) 43 44 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS 45 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0 46 #endif 47 48 #ifndef HAVE_MLX5DV_DR_ESWITCH 49 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB 50 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0 51 #endif 52 #endif 53 54 #ifndef HAVE_MLX5DV_DR 55 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1 56 #endif 57 58 /* VLAN header definitions */ 59 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13 60 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT) 61 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff 62 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK) 63 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK) 64 65 union flow_dv_attr { 66 struct { 67 uint32_t valid:1; 68 uint32_t ipv4:1; 69 uint32_t ipv6:1; 70 uint32_t tcp:1; 71 uint32_t udp:1; 72 uint32_t reserved:27; 73 }; 74 uint32_t attr; 75 }; 76 77 static int 78 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 79 struct mlx5_flow_tbl_resource *tbl); 80 81 static int 82 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 83 uint32_t encap_decap_idx); 84 85 static int 86 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 87 uint32_t port_id); 88 static void 89 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss); 90 91 static int 92 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 93 uint32_t rix_jump); 94 95 /** 96 * Initialize flow attributes structure according to flow items' types. 97 * 98 * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel 99 * mode. For tunnel mode, the items to be modified are the outermost ones. 100 * 101 * @param[in] item 102 * Pointer to item specification. 103 * @param[out] attr 104 * Pointer to flow attributes structure. 105 * @param[in] dev_flow 106 * Pointer to the sub flow. 107 * @param[in] tunnel_decap 108 * Whether action is after tunnel decapsulation. 109 */ 110 static void 111 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr, 112 struct mlx5_flow *dev_flow, bool tunnel_decap) 113 { 114 uint64_t layers = dev_flow->handle->layers; 115 116 /* 117 * If layers is already initialized, it means this dev_flow is the 118 * suffix flow, the layers flags is set by the prefix flow. Need to 119 * use the layer flags from prefix flow as the suffix flow may not 120 * have the user defined items as the flow is split. 121 */ 122 if (layers) { 123 if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4) 124 attr->ipv4 = 1; 125 else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6) 126 attr->ipv6 = 1; 127 if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP) 128 attr->tcp = 1; 129 else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP) 130 attr->udp = 1; 131 attr->valid = 1; 132 return; 133 } 134 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 135 uint8_t next_protocol = 0xff; 136 switch (item->type) { 137 case RTE_FLOW_ITEM_TYPE_GRE: 138 case RTE_FLOW_ITEM_TYPE_NVGRE: 139 case RTE_FLOW_ITEM_TYPE_VXLAN: 140 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 141 case RTE_FLOW_ITEM_TYPE_GENEVE: 142 case RTE_FLOW_ITEM_TYPE_MPLS: 143 if (tunnel_decap) 144 attr->attr = 0; 145 break; 146 case RTE_FLOW_ITEM_TYPE_IPV4: 147 if (!attr->ipv6) 148 attr->ipv4 = 1; 149 if (item->mask != NULL && 150 ((const struct rte_flow_item_ipv4 *) 151 item->mask)->hdr.next_proto_id) 152 next_protocol = 153 ((const struct rte_flow_item_ipv4 *) 154 (item->spec))->hdr.next_proto_id & 155 ((const struct rte_flow_item_ipv4 *) 156 (item->mask))->hdr.next_proto_id; 157 if ((next_protocol == IPPROTO_IPIP || 158 next_protocol == IPPROTO_IPV6) && tunnel_decap) 159 attr->attr = 0; 160 break; 161 case RTE_FLOW_ITEM_TYPE_IPV6: 162 if (!attr->ipv4) 163 attr->ipv6 = 1; 164 if (item->mask != NULL && 165 ((const struct rte_flow_item_ipv6 *) 166 item->mask)->hdr.proto) 167 next_protocol = 168 ((const struct rte_flow_item_ipv6 *) 169 (item->spec))->hdr.proto & 170 ((const struct rte_flow_item_ipv6 *) 171 (item->mask))->hdr.proto; 172 if ((next_protocol == IPPROTO_IPIP || 173 next_protocol == IPPROTO_IPV6) && tunnel_decap) 174 attr->attr = 0; 175 break; 176 case RTE_FLOW_ITEM_TYPE_UDP: 177 if (!attr->tcp) 178 attr->udp = 1; 179 break; 180 case RTE_FLOW_ITEM_TYPE_TCP: 181 if (!attr->udp) 182 attr->tcp = 1; 183 break; 184 default: 185 break; 186 } 187 } 188 attr->valid = 1; 189 } 190 191 /* 192 * Convert rte_mtr_color to mlx5 color. 193 * 194 * @param[in] rcol 195 * rte_mtr_color. 196 * 197 * @return 198 * mlx5 color. 199 */ 200 static inline int 201 rte_col_2_mlx5_col(enum rte_color rcol) 202 { 203 switch (rcol) { 204 case RTE_COLOR_GREEN: 205 return MLX5_FLOW_COLOR_GREEN; 206 case RTE_COLOR_YELLOW: 207 return MLX5_FLOW_COLOR_YELLOW; 208 case RTE_COLOR_RED: 209 return MLX5_FLOW_COLOR_RED; 210 default: 211 break; 212 } 213 return MLX5_FLOW_COLOR_UNDEFINED; 214 } 215 216 struct field_modify_info { 217 uint32_t size; /* Size of field in protocol header, in bytes. */ 218 uint32_t offset; /* Offset of field in protocol header, in bytes. */ 219 enum mlx5_modification_field id; 220 }; 221 222 struct field_modify_info modify_eth[] = { 223 {4, 0, MLX5_MODI_OUT_DMAC_47_16}, 224 {2, 4, MLX5_MODI_OUT_DMAC_15_0}, 225 {4, 6, MLX5_MODI_OUT_SMAC_47_16}, 226 {2, 10, MLX5_MODI_OUT_SMAC_15_0}, 227 {0, 0, 0}, 228 }; 229 230 struct field_modify_info modify_vlan_out_first_vid[] = { 231 /* Size in bits !!! */ 232 {12, 0, MLX5_MODI_OUT_FIRST_VID}, 233 {0, 0, 0}, 234 }; 235 236 struct field_modify_info modify_ipv4[] = { 237 {1, 1, MLX5_MODI_OUT_IP_DSCP}, 238 {1, 8, MLX5_MODI_OUT_IPV4_TTL}, 239 {4, 12, MLX5_MODI_OUT_SIPV4}, 240 {4, 16, MLX5_MODI_OUT_DIPV4}, 241 {0, 0, 0}, 242 }; 243 244 struct field_modify_info modify_ipv6[] = { 245 {1, 0, MLX5_MODI_OUT_IP_DSCP}, 246 {1, 7, MLX5_MODI_OUT_IPV6_HOPLIMIT}, 247 {4, 8, MLX5_MODI_OUT_SIPV6_127_96}, 248 {4, 12, MLX5_MODI_OUT_SIPV6_95_64}, 249 {4, 16, MLX5_MODI_OUT_SIPV6_63_32}, 250 {4, 20, MLX5_MODI_OUT_SIPV6_31_0}, 251 {4, 24, MLX5_MODI_OUT_DIPV6_127_96}, 252 {4, 28, MLX5_MODI_OUT_DIPV6_95_64}, 253 {4, 32, MLX5_MODI_OUT_DIPV6_63_32}, 254 {4, 36, MLX5_MODI_OUT_DIPV6_31_0}, 255 {0, 0, 0}, 256 }; 257 258 struct field_modify_info modify_udp[] = { 259 {2, 0, MLX5_MODI_OUT_UDP_SPORT}, 260 {2, 2, MLX5_MODI_OUT_UDP_DPORT}, 261 {0, 0, 0}, 262 }; 263 264 struct field_modify_info modify_tcp[] = { 265 {2, 0, MLX5_MODI_OUT_TCP_SPORT}, 266 {2, 2, MLX5_MODI_OUT_TCP_DPORT}, 267 {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM}, 268 {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM}, 269 {0, 0, 0}, 270 }; 271 272 static const struct rte_flow_item * 273 mlx5_flow_find_tunnel_item(const struct rte_flow_item *item) 274 { 275 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 276 switch (item->type) { 277 default: 278 break; 279 case RTE_FLOW_ITEM_TYPE_VXLAN: 280 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 281 case RTE_FLOW_ITEM_TYPE_GRE: 282 case RTE_FLOW_ITEM_TYPE_MPLS: 283 case RTE_FLOW_ITEM_TYPE_NVGRE: 284 case RTE_FLOW_ITEM_TYPE_GENEVE: 285 return item; 286 case RTE_FLOW_ITEM_TYPE_IPV4: 287 case RTE_FLOW_ITEM_TYPE_IPV6: 288 if (item[1].type == RTE_FLOW_ITEM_TYPE_IPV4 || 289 item[1].type == RTE_FLOW_ITEM_TYPE_IPV6) 290 return item; 291 break; 292 } 293 } 294 return NULL; 295 } 296 297 static void 298 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused, 299 uint8_t next_protocol, uint64_t *item_flags, 300 int *tunnel) 301 { 302 MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 || 303 item->type == RTE_FLOW_ITEM_TYPE_IPV6); 304 if (next_protocol == IPPROTO_IPIP) { 305 *item_flags |= MLX5_FLOW_LAYER_IPIP; 306 *tunnel = 1; 307 } 308 if (next_protocol == IPPROTO_IPV6) { 309 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP; 310 *tunnel = 1; 311 } 312 } 313 314 static inline struct mlx5_hlist * 315 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl, 316 const char *name, uint32_t size, bool direct_key, 317 bool lcores_share, void *ctx, 318 mlx5_list_create_cb cb_create, 319 mlx5_list_match_cb cb_match, 320 mlx5_list_remove_cb cb_remove, 321 mlx5_list_clone_cb cb_clone, 322 mlx5_list_clone_free_cb cb_clone_free) 323 { 324 struct mlx5_hlist *hl; 325 struct mlx5_hlist *expected = NULL; 326 char s[MLX5_NAME_SIZE]; 327 328 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 329 if (likely(hl)) 330 return hl; 331 snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name); 332 hl = mlx5_hlist_create(s, size, direct_key, lcores_share, 333 ctx, cb_create, cb_match, cb_remove, cb_clone, 334 cb_clone_free); 335 if (!hl) { 336 DRV_LOG(ERR, "%s hash creation failed", name); 337 rte_errno = ENOMEM; 338 return NULL; 339 } 340 if (!__atomic_compare_exchange_n(phl, &expected, hl, false, 341 __ATOMIC_SEQ_CST, 342 __ATOMIC_SEQ_CST)) { 343 mlx5_hlist_destroy(hl); 344 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 345 } 346 return hl; 347 } 348 349 /* Update VLAN's VID/PCP based on input rte_flow_action. 350 * 351 * @param[in] action 352 * Pointer to struct rte_flow_action. 353 * @param[out] vlan 354 * Pointer to struct rte_vlan_hdr. 355 */ 356 static void 357 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, 358 struct rte_vlan_hdr *vlan) 359 { 360 uint16_t vlan_tci; 361 if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) { 362 vlan_tci = 363 ((const struct rte_flow_action_of_set_vlan_pcp *) 364 action->conf)->vlan_pcp; 365 vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT; 366 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 367 vlan->vlan_tci |= vlan_tci; 368 } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) { 369 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 370 vlan->vlan_tci |= rte_be_to_cpu_16 371 (((const struct rte_flow_action_of_set_vlan_vid *) 372 action->conf)->vlan_vid); 373 } 374 } 375 376 /** 377 * Fetch 1, 2, 3 or 4 byte field from the byte array 378 * and return as unsigned integer in host-endian format. 379 * 380 * @param[in] data 381 * Pointer to data array. 382 * @param[in] size 383 * Size of field to extract. 384 * 385 * @return 386 * converted field in host endian format. 387 */ 388 static inline uint32_t 389 flow_dv_fetch_field(const uint8_t *data, uint32_t size) 390 { 391 uint32_t ret; 392 393 switch (size) { 394 case 1: 395 ret = *data; 396 break; 397 case 2: 398 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 399 break; 400 case 3: 401 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 402 ret = (ret << 8) | *(data + sizeof(uint16_t)); 403 break; 404 case 4: 405 ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); 406 break; 407 default: 408 MLX5_ASSERT(false); 409 ret = 0; 410 break; 411 } 412 return ret; 413 } 414 415 /** 416 * Convert modify-header action to DV specification. 417 * 418 * Data length of each action is determined by provided field description 419 * and the item mask. Data bit offset and width of each action is determined 420 * by provided item mask. 421 * 422 * @param[in] item 423 * Pointer to item specification. 424 * @param[in] field 425 * Pointer to field modification information. 426 * For MLX5_MODIFICATION_TYPE_SET specifies destination field. 427 * For MLX5_MODIFICATION_TYPE_ADD specifies destination field. 428 * For MLX5_MODIFICATION_TYPE_COPY specifies source field. 429 * @param[in] dcopy 430 * Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type. 431 * Negative offset value sets the same offset as source offset. 432 * size field is ignored, value is taken from source field. 433 * @param[in,out] resource 434 * Pointer to the modify-header resource. 435 * @param[in] type 436 * Type of modification. 437 * @param[out] error 438 * Pointer to the error structure. 439 * 440 * @return 441 * 0 on success, a negative errno value otherwise and rte_errno is set. 442 */ 443 static int 444 flow_dv_convert_modify_action(struct rte_flow_item *item, 445 struct field_modify_info *field, 446 struct field_modify_info *dcopy, 447 struct mlx5_flow_dv_modify_hdr_resource *resource, 448 uint32_t type, struct rte_flow_error *error) 449 { 450 uint32_t i = resource->actions_num; 451 struct mlx5_modification_cmd *actions = resource->actions; 452 uint32_t carry_b = 0; 453 454 /* 455 * The item and mask are provided in big-endian format. 456 * The fields should be presented as in big-endian format either. 457 * Mask must be always present, it defines the actual field width. 458 */ 459 MLX5_ASSERT(item->mask); 460 MLX5_ASSERT(field->size); 461 do { 462 uint32_t size_b; 463 uint32_t off_b; 464 uint32_t mask; 465 uint32_t data; 466 bool next_field = true; 467 bool next_dcopy = true; 468 469 if (i >= MLX5_MAX_MODIFY_NUM) 470 return rte_flow_error_set(error, EINVAL, 471 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 472 "too many items to modify"); 473 /* Fetch variable byte size mask from the array. */ 474 mask = flow_dv_fetch_field((const uint8_t *)item->mask + 475 field->offset, field->size); 476 if (!mask) { 477 ++field; 478 continue; 479 } 480 /* Deduce actual data width in bits from mask value. */ 481 off_b = rte_bsf32(mask) + carry_b; 482 size_b = sizeof(uint32_t) * CHAR_BIT - 483 off_b - __builtin_clz(mask); 484 MLX5_ASSERT(size_b); 485 actions[i] = (struct mlx5_modification_cmd) { 486 .action_type = type, 487 .field = field->id, 488 .offset = off_b, 489 .length = (size_b == sizeof(uint32_t) * CHAR_BIT) ? 490 0 : size_b, 491 }; 492 if (type == MLX5_MODIFICATION_TYPE_COPY) { 493 MLX5_ASSERT(dcopy); 494 actions[i].dst_field = dcopy->id; 495 actions[i].dst_offset = 496 (int)dcopy->offset < 0 ? off_b : dcopy->offset; 497 /* Convert entire record to big-endian format. */ 498 actions[i].data1 = rte_cpu_to_be_32(actions[i].data1); 499 /* 500 * Destination field overflow. Copy leftovers of 501 * a source field to the next destination field. 502 */ 503 carry_b = 0; 504 if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) && 505 dcopy->size != 0) { 506 actions[i].length = 507 dcopy->size * CHAR_BIT - dcopy->offset; 508 carry_b = actions[i].length; 509 next_field = false; 510 } 511 /* 512 * Not enough bits in a source filed to fill a 513 * destination field. Switch to the next source. 514 */ 515 if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) && 516 (size_b == field->size * CHAR_BIT - off_b)) { 517 actions[i].length = 518 field->size * CHAR_BIT - off_b; 519 dcopy->offset += actions[i].length; 520 next_dcopy = false; 521 } 522 if (next_dcopy) 523 ++dcopy; 524 } else { 525 MLX5_ASSERT(item->spec); 526 data = flow_dv_fetch_field((const uint8_t *)item->spec + 527 field->offset, field->size); 528 /* Shift out the trailing masked bits from data. */ 529 data = (data & mask) >> off_b; 530 actions[i].data1 = rte_cpu_to_be_32(data); 531 } 532 /* Convert entire record to expected big-endian format. */ 533 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 534 if (next_field) 535 ++field; 536 ++i; 537 } while (field->size); 538 if (resource->actions_num == i) 539 return rte_flow_error_set(error, EINVAL, 540 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 541 "invalid modification flow item"); 542 resource->actions_num = i; 543 return 0; 544 } 545 546 /** 547 * Convert modify-header set IPv4 address action to DV specification. 548 * 549 * @param[in,out] resource 550 * Pointer to the modify-header resource. 551 * @param[in] action 552 * Pointer to action specification. 553 * @param[out] error 554 * Pointer to the error structure. 555 * 556 * @return 557 * 0 on success, a negative errno value otherwise and rte_errno is set. 558 */ 559 static int 560 flow_dv_convert_action_modify_ipv4 561 (struct mlx5_flow_dv_modify_hdr_resource *resource, 562 const struct rte_flow_action *action, 563 struct rte_flow_error *error) 564 { 565 const struct rte_flow_action_set_ipv4 *conf = 566 (const struct rte_flow_action_set_ipv4 *)(action->conf); 567 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 568 struct rte_flow_item_ipv4 ipv4; 569 struct rte_flow_item_ipv4 ipv4_mask; 570 571 memset(&ipv4, 0, sizeof(ipv4)); 572 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 573 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) { 574 ipv4.hdr.src_addr = conf->ipv4_addr; 575 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr; 576 } else { 577 ipv4.hdr.dst_addr = conf->ipv4_addr; 578 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr; 579 } 580 item.spec = &ipv4; 581 item.mask = &ipv4_mask; 582 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 583 MLX5_MODIFICATION_TYPE_SET, error); 584 } 585 586 /** 587 * Convert modify-header set IPv6 address action to DV specification. 588 * 589 * @param[in,out] resource 590 * Pointer to the modify-header resource. 591 * @param[in] action 592 * Pointer to action specification. 593 * @param[out] error 594 * Pointer to the error structure. 595 * 596 * @return 597 * 0 on success, a negative errno value otherwise and rte_errno is set. 598 */ 599 static int 600 flow_dv_convert_action_modify_ipv6 601 (struct mlx5_flow_dv_modify_hdr_resource *resource, 602 const struct rte_flow_action *action, 603 struct rte_flow_error *error) 604 { 605 const struct rte_flow_action_set_ipv6 *conf = 606 (const struct rte_flow_action_set_ipv6 *)(action->conf); 607 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 608 struct rte_flow_item_ipv6 ipv6; 609 struct rte_flow_item_ipv6 ipv6_mask; 610 611 memset(&ipv6, 0, sizeof(ipv6)); 612 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 613 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) { 614 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr, 615 sizeof(ipv6.hdr.src_addr)); 616 memcpy(&ipv6_mask.hdr.src_addr, 617 &rte_flow_item_ipv6_mask.hdr.src_addr, 618 sizeof(ipv6.hdr.src_addr)); 619 } else { 620 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr, 621 sizeof(ipv6.hdr.dst_addr)); 622 memcpy(&ipv6_mask.hdr.dst_addr, 623 &rte_flow_item_ipv6_mask.hdr.dst_addr, 624 sizeof(ipv6.hdr.dst_addr)); 625 } 626 item.spec = &ipv6; 627 item.mask = &ipv6_mask; 628 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 629 MLX5_MODIFICATION_TYPE_SET, error); 630 } 631 632 /** 633 * Convert modify-header set MAC address action to DV specification. 634 * 635 * @param[in,out] resource 636 * Pointer to the modify-header resource. 637 * @param[in] action 638 * Pointer to action specification. 639 * @param[out] error 640 * Pointer to the error structure. 641 * 642 * @return 643 * 0 on success, a negative errno value otherwise and rte_errno is set. 644 */ 645 static int 646 flow_dv_convert_action_modify_mac 647 (struct mlx5_flow_dv_modify_hdr_resource *resource, 648 const struct rte_flow_action *action, 649 struct rte_flow_error *error) 650 { 651 const struct rte_flow_action_set_mac *conf = 652 (const struct rte_flow_action_set_mac *)(action->conf); 653 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH }; 654 struct rte_flow_item_eth eth; 655 struct rte_flow_item_eth eth_mask; 656 657 memset(ð, 0, sizeof(eth)); 658 memset(ð_mask, 0, sizeof(eth_mask)); 659 if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) { 660 memcpy(ð.src.addr_bytes, &conf->mac_addr, 661 sizeof(eth.src.addr_bytes)); 662 memcpy(ð_mask.src.addr_bytes, 663 &rte_flow_item_eth_mask.src.addr_bytes, 664 sizeof(eth_mask.src.addr_bytes)); 665 } else { 666 memcpy(ð.dst.addr_bytes, &conf->mac_addr, 667 sizeof(eth.dst.addr_bytes)); 668 memcpy(ð_mask.dst.addr_bytes, 669 &rte_flow_item_eth_mask.dst.addr_bytes, 670 sizeof(eth_mask.dst.addr_bytes)); 671 } 672 item.spec = ð 673 item.mask = ð_mask; 674 return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource, 675 MLX5_MODIFICATION_TYPE_SET, error); 676 } 677 678 /** 679 * Convert modify-header set VLAN VID action to DV specification. 680 * 681 * @param[in,out] resource 682 * Pointer to the modify-header resource. 683 * @param[in] action 684 * Pointer to action specification. 685 * @param[out] error 686 * Pointer to the error structure. 687 * 688 * @return 689 * 0 on success, a negative errno value otherwise and rte_errno is set. 690 */ 691 static int 692 flow_dv_convert_action_modify_vlan_vid 693 (struct mlx5_flow_dv_modify_hdr_resource *resource, 694 const struct rte_flow_action *action, 695 struct rte_flow_error *error) 696 { 697 const struct rte_flow_action_of_set_vlan_vid *conf = 698 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf); 699 int i = resource->actions_num; 700 struct mlx5_modification_cmd *actions = resource->actions; 701 struct field_modify_info *field = modify_vlan_out_first_vid; 702 703 if (i >= MLX5_MAX_MODIFY_NUM) 704 return rte_flow_error_set(error, EINVAL, 705 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 706 "too many items to modify"); 707 actions[i] = (struct mlx5_modification_cmd) { 708 .action_type = MLX5_MODIFICATION_TYPE_SET, 709 .field = field->id, 710 .length = field->size, 711 .offset = field->offset, 712 }; 713 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 714 actions[i].data1 = conf->vlan_vid; 715 actions[i].data1 = actions[i].data1 << 16; 716 resource->actions_num = ++i; 717 return 0; 718 } 719 720 /** 721 * Convert modify-header set TP action to DV specification. 722 * 723 * @param[in,out] resource 724 * Pointer to the modify-header resource. 725 * @param[in] action 726 * Pointer to action specification. 727 * @param[in] items 728 * Pointer to rte_flow_item objects list. 729 * @param[in] attr 730 * Pointer to flow attributes structure. 731 * @param[in] dev_flow 732 * Pointer to the sub flow. 733 * @param[in] tunnel_decap 734 * Whether action is after tunnel decapsulation. 735 * @param[out] error 736 * Pointer to the error structure. 737 * 738 * @return 739 * 0 on success, a negative errno value otherwise and rte_errno is set. 740 */ 741 static int 742 flow_dv_convert_action_modify_tp 743 (struct mlx5_flow_dv_modify_hdr_resource *resource, 744 const struct rte_flow_action *action, 745 const struct rte_flow_item *items, 746 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 747 bool tunnel_decap, struct rte_flow_error *error) 748 { 749 const struct rte_flow_action_set_tp *conf = 750 (const struct rte_flow_action_set_tp *)(action->conf); 751 struct rte_flow_item item; 752 struct rte_flow_item_udp udp; 753 struct rte_flow_item_udp udp_mask; 754 struct rte_flow_item_tcp tcp; 755 struct rte_flow_item_tcp tcp_mask; 756 struct field_modify_info *field; 757 758 if (!attr->valid) 759 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 760 if (attr->udp) { 761 memset(&udp, 0, sizeof(udp)); 762 memset(&udp_mask, 0, sizeof(udp_mask)); 763 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 764 udp.hdr.src_port = conf->port; 765 udp_mask.hdr.src_port = 766 rte_flow_item_udp_mask.hdr.src_port; 767 } else { 768 udp.hdr.dst_port = conf->port; 769 udp_mask.hdr.dst_port = 770 rte_flow_item_udp_mask.hdr.dst_port; 771 } 772 item.type = RTE_FLOW_ITEM_TYPE_UDP; 773 item.spec = &udp; 774 item.mask = &udp_mask; 775 field = modify_udp; 776 } else { 777 MLX5_ASSERT(attr->tcp); 778 memset(&tcp, 0, sizeof(tcp)); 779 memset(&tcp_mask, 0, sizeof(tcp_mask)); 780 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 781 tcp.hdr.src_port = conf->port; 782 tcp_mask.hdr.src_port = 783 rte_flow_item_tcp_mask.hdr.src_port; 784 } else { 785 tcp.hdr.dst_port = conf->port; 786 tcp_mask.hdr.dst_port = 787 rte_flow_item_tcp_mask.hdr.dst_port; 788 } 789 item.type = RTE_FLOW_ITEM_TYPE_TCP; 790 item.spec = &tcp; 791 item.mask = &tcp_mask; 792 field = modify_tcp; 793 } 794 return flow_dv_convert_modify_action(&item, field, NULL, resource, 795 MLX5_MODIFICATION_TYPE_SET, error); 796 } 797 798 /** 799 * Convert modify-header set TTL action to DV specification. 800 * 801 * @param[in,out] resource 802 * Pointer to the modify-header resource. 803 * @param[in] action 804 * Pointer to action specification. 805 * @param[in] items 806 * Pointer to rte_flow_item objects list. 807 * @param[in] attr 808 * Pointer to flow attributes structure. 809 * @param[in] dev_flow 810 * Pointer to the sub flow. 811 * @param[in] tunnel_decap 812 * Whether action is after tunnel decapsulation. 813 * @param[out] error 814 * Pointer to the error structure. 815 * 816 * @return 817 * 0 on success, a negative errno value otherwise and rte_errno is set. 818 */ 819 static int 820 flow_dv_convert_action_modify_ttl 821 (struct mlx5_flow_dv_modify_hdr_resource *resource, 822 const struct rte_flow_action *action, 823 const struct rte_flow_item *items, 824 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 825 bool tunnel_decap, struct rte_flow_error *error) 826 { 827 const struct rte_flow_action_set_ttl *conf = 828 (const struct rte_flow_action_set_ttl *)(action->conf); 829 struct rte_flow_item item; 830 struct rte_flow_item_ipv4 ipv4; 831 struct rte_flow_item_ipv4 ipv4_mask; 832 struct rte_flow_item_ipv6 ipv6; 833 struct rte_flow_item_ipv6 ipv6_mask; 834 struct field_modify_info *field; 835 836 if (!attr->valid) 837 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 838 if (attr->ipv4) { 839 memset(&ipv4, 0, sizeof(ipv4)); 840 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 841 ipv4.hdr.time_to_live = conf->ttl_value; 842 ipv4_mask.hdr.time_to_live = 0xFF; 843 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 844 item.spec = &ipv4; 845 item.mask = &ipv4_mask; 846 field = modify_ipv4; 847 } else { 848 MLX5_ASSERT(attr->ipv6); 849 memset(&ipv6, 0, sizeof(ipv6)); 850 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 851 ipv6.hdr.hop_limits = conf->ttl_value; 852 ipv6_mask.hdr.hop_limits = 0xFF; 853 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 854 item.spec = &ipv6; 855 item.mask = &ipv6_mask; 856 field = modify_ipv6; 857 } 858 return flow_dv_convert_modify_action(&item, field, NULL, resource, 859 MLX5_MODIFICATION_TYPE_SET, error); 860 } 861 862 /** 863 * Convert modify-header decrement TTL action to DV specification. 864 * 865 * @param[in,out] resource 866 * Pointer to the modify-header resource. 867 * @param[in] action 868 * Pointer to action specification. 869 * @param[in] items 870 * Pointer to rte_flow_item objects list. 871 * @param[in] attr 872 * Pointer to flow attributes structure. 873 * @param[in] dev_flow 874 * Pointer to the sub flow. 875 * @param[in] tunnel_decap 876 * Whether action is after tunnel decapsulation. 877 * @param[out] error 878 * Pointer to the error structure. 879 * 880 * @return 881 * 0 on success, a negative errno value otherwise and rte_errno is set. 882 */ 883 static int 884 flow_dv_convert_action_modify_dec_ttl 885 (struct mlx5_flow_dv_modify_hdr_resource *resource, 886 const struct rte_flow_item *items, 887 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 888 bool tunnel_decap, struct rte_flow_error *error) 889 { 890 struct rte_flow_item item; 891 struct rte_flow_item_ipv4 ipv4; 892 struct rte_flow_item_ipv4 ipv4_mask; 893 struct rte_flow_item_ipv6 ipv6; 894 struct rte_flow_item_ipv6 ipv6_mask; 895 struct field_modify_info *field; 896 897 if (!attr->valid) 898 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 899 if (attr->ipv4) { 900 memset(&ipv4, 0, sizeof(ipv4)); 901 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 902 ipv4.hdr.time_to_live = 0xFF; 903 ipv4_mask.hdr.time_to_live = 0xFF; 904 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 905 item.spec = &ipv4; 906 item.mask = &ipv4_mask; 907 field = modify_ipv4; 908 } else { 909 MLX5_ASSERT(attr->ipv6); 910 memset(&ipv6, 0, sizeof(ipv6)); 911 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 912 ipv6.hdr.hop_limits = 0xFF; 913 ipv6_mask.hdr.hop_limits = 0xFF; 914 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 915 item.spec = &ipv6; 916 item.mask = &ipv6_mask; 917 field = modify_ipv6; 918 } 919 return flow_dv_convert_modify_action(&item, field, NULL, resource, 920 MLX5_MODIFICATION_TYPE_ADD, error); 921 } 922 923 /** 924 * Convert modify-header increment/decrement TCP Sequence number 925 * to DV specification. 926 * 927 * @param[in,out] resource 928 * Pointer to the modify-header resource. 929 * @param[in] action 930 * Pointer to action specification. 931 * @param[out] error 932 * Pointer to the error structure. 933 * 934 * @return 935 * 0 on success, a negative errno value otherwise and rte_errno is set. 936 */ 937 static int 938 flow_dv_convert_action_modify_tcp_seq 939 (struct mlx5_flow_dv_modify_hdr_resource *resource, 940 const struct rte_flow_action *action, 941 struct rte_flow_error *error) 942 { 943 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 944 uint64_t value = rte_be_to_cpu_32(*conf); 945 struct rte_flow_item item; 946 struct rte_flow_item_tcp tcp; 947 struct rte_flow_item_tcp tcp_mask; 948 949 memset(&tcp, 0, sizeof(tcp)); 950 memset(&tcp_mask, 0, sizeof(tcp_mask)); 951 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ) 952 /* 953 * The HW has no decrement operation, only increment operation. 954 * To simulate decrement X from Y using increment operation 955 * we need to add UINT32_MAX X times to Y. 956 * Each adding of UINT32_MAX decrements Y by 1. 957 */ 958 value *= UINT32_MAX; 959 tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value); 960 tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX); 961 item.type = RTE_FLOW_ITEM_TYPE_TCP; 962 item.spec = &tcp; 963 item.mask = &tcp_mask; 964 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 965 MLX5_MODIFICATION_TYPE_ADD, error); 966 } 967 968 /** 969 * Convert modify-header increment/decrement TCP Acknowledgment number 970 * to DV specification. 971 * 972 * @param[in,out] resource 973 * Pointer to the modify-header resource. 974 * @param[in] action 975 * Pointer to action specification. 976 * @param[out] error 977 * Pointer to the error structure. 978 * 979 * @return 980 * 0 on success, a negative errno value otherwise and rte_errno is set. 981 */ 982 static int 983 flow_dv_convert_action_modify_tcp_ack 984 (struct mlx5_flow_dv_modify_hdr_resource *resource, 985 const struct rte_flow_action *action, 986 struct rte_flow_error *error) 987 { 988 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 989 uint64_t value = rte_be_to_cpu_32(*conf); 990 struct rte_flow_item item; 991 struct rte_flow_item_tcp tcp; 992 struct rte_flow_item_tcp tcp_mask; 993 994 memset(&tcp, 0, sizeof(tcp)); 995 memset(&tcp_mask, 0, sizeof(tcp_mask)); 996 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK) 997 /* 998 * The HW has no decrement operation, only increment operation. 999 * To simulate decrement X from Y using increment operation 1000 * we need to add UINT32_MAX X times to Y. 1001 * Each adding of UINT32_MAX decrements Y by 1. 1002 */ 1003 value *= UINT32_MAX; 1004 tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value); 1005 tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX); 1006 item.type = RTE_FLOW_ITEM_TYPE_TCP; 1007 item.spec = &tcp; 1008 item.mask = &tcp_mask; 1009 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 1010 MLX5_MODIFICATION_TYPE_ADD, error); 1011 } 1012 1013 static enum mlx5_modification_field reg_to_field[] = { 1014 [REG_NON] = MLX5_MODI_OUT_NONE, 1015 [REG_A] = MLX5_MODI_META_DATA_REG_A, 1016 [REG_B] = MLX5_MODI_META_DATA_REG_B, 1017 [REG_C_0] = MLX5_MODI_META_REG_C_0, 1018 [REG_C_1] = MLX5_MODI_META_REG_C_1, 1019 [REG_C_2] = MLX5_MODI_META_REG_C_2, 1020 [REG_C_3] = MLX5_MODI_META_REG_C_3, 1021 [REG_C_4] = MLX5_MODI_META_REG_C_4, 1022 [REG_C_5] = MLX5_MODI_META_REG_C_5, 1023 [REG_C_6] = MLX5_MODI_META_REG_C_6, 1024 [REG_C_7] = MLX5_MODI_META_REG_C_7, 1025 }; 1026 1027 /** 1028 * Convert register set to DV specification. 1029 * 1030 * @param[in,out] resource 1031 * Pointer to the modify-header resource. 1032 * @param[in] action 1033 * Pointer to action specification. 1034 * @param[out] error 1035 * Pointer to the error structure. 1036 * 1037 * @return 1038 * 0 on success, a negative errno value otherwise and rte_errno is set. 1039 */ 1040 static int 1041 flow_dv_convert_action_set_reg 1042 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1043 const struct rte_flow_action *action, 1044 struct rte_flow_error *error) 1045 { 1046 const struct mlx5_rte_flow_action_set_tag *conf = action->conf; 1047 struct mlx5_modification_cmd *actions = resource->actions; 1048 uint32_t i = resource->actions_num; 1049 1050 if (i >= MLX5_MAX_MODIFY_NUM) 1051 return rte_flow_error_set(error, EINVAL, 1052 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 1053 "too many items to modify"); 1054 MLX5_ASSERT(conf->id != REG_NON); 1055 MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field)); 1056 actions[i] = (struct mlx5_modification_cmd) { 1057 .action_type = MLX5_MODIFICATION_TYPE_SET, 1058 .field = reg_to_field[conf->id], 1059 .offset = conf->offset, 1060 .length = conf->length, 1061 }; 1062 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 1063 actions[i].data1 = rte_cpu_to_be_32(conf->data); 1064 ++i; 1065 resource->actions_num = i; 1066 return 0; 1067 } 1068 1069 /** 1070 * Convert SET_TAG action to DV specification. 1071 * 1072 * @param[in] dev 1073 * Pointer to the rte_eth_dev structure. 1074 * @param[in,out] resource 1075 * Pointer to the modify-header resource. 1076 * @param[in] conf 1077 * Pointer to action specification. 1078 * @param[out] error 1079 * Pointer to the error structure. 1080 * 1081 * @return 1082 * 0 on success, a negative errno value otherwise and rte_errno is set. 1083 */ 1084 static int 1085 flow_dv_convert_action_set_tag 1086 (struct rte_eth_dev *dev, 1087 struct mlx5_flow_dv_modify_hdr_resource *resource, 1088 const struct rte_flow_action_set_tag *conf, 1089 struct rte_flow_error *error) 1090 { 1091 rte_be32_t data = rte_cpu_to_be_32(conf->data); 1092 rte_be32_t mask = rte_cpu_to_be_32(conf->mask); 1093 struct rte_flow_item item = { 1094 .spec = &data, 1095 .mask = &mask, 1096 }; 1097 struct field_modify_info reg_c_x[] = { 1098 [1] = {0, 0, 0}, 1099 }; 1100 enum mlx5_modification_field reg_type; 1101 int ret; 1102 1103 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 1104 if (ret < 0) 1105 return ret; 1106 MLX5_ASSERT(ret != REG_NON); 1107 MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field)); 1108 reg_type = reg_to_field[ret]; 1109 MLX5_ASSERT(reg_type > 0); 1110 reg_c_x[0] = (struct field_modify_info){4, 0, reg_type}; 1111 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1112 MLX5_MODIFICATION_TYPE_SET, error); 1113 } 1114 1115 /** 1116 * Convert internal COPY_REG action to DV specification. 1117 * 1118 * @param[in] dev 1119 * Pointer to the rte_eth_dev structure. 1120 * @param[in,out] res 1121 * Pointer to the modify-header resource. 1122 * @param[in] action 1123 * Pointer to action specification. 1124 * @param[out] error 1125 * Pointer to the error structure. 1126 * 1127 * @return 1128 * 0 on success, a negative errno value otherwise and rte_errno is set. 1129 */ 1130 static int 1131 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev, 1132 struct mlx5_flow_dv_modify_hdr_resource *res, 1133 const struct rte_flow_action *action, 1134 struct rte_flow_error *error) 1135 { 1136 const struct mlx5_flow_action_copy_mreg *conf = action->conf; 1137 rte_be32_t mask = RTE_BE32(UINT32_MAX); 1138 struct rte_flow_item item = { 1139 .spec = NULL, 1140 .mask = &mask, 1141 }; 1142 struct field_modify_info reg_src[] = { 1143 {4, 0, reg_to_field[conf->src]}, 1144 {0, 0, 0}, 1145 }; 1146 struct field_modify_info reg_dst = { 1147 .offset = 0, 1148 .id = reg_to_field[conf->dst], 1149 }; 1150 /* Adjust reg_c[0] usage according to reported mask. */ 1151 if (conf->dst == REG_C_0 || conf->src == REG_C_0) { 1152 struct mlx5_priv *priv = dev->data->dev_private; 1153 uint32_t reg_c0 = priv->sh->dv_regc0_mask; 1154 1155 MLX5_ASSERT(reg_c0); 1156 MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY); 1157 if (conf->dst == REG_C_0) { 1158 /* Copy to reg_c[0], within mask only. */ 1159 reg_dst.offset = rte_bsf32(reg_c0); 1160 mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset); 1161 } else { 1162 reg_dst.offset = 0; 1163 mask = rte_cpu_to_be_32(reg_c0); 1164 } 1165 } 1166 return flow_dv_convert_modify_action(&item, 1167 reg_src, ®_dst, res, 1168 MLX5_MODIFICATION_TYPE_COPY, 1169 error); 1170 } 1171 1172 /** 1173 * Convert MARK action to DV specification. This routine is used 1174 * in extensive metadata only and requires metadata register to be 1175 * handled. In legacy mode hardware tag resource is engaged. 1176 * 1177 * @param[in] dev 1178 * Pointer to the rte_eth_dev structure. 1179 * @param[in] conf 1180 * Pointer to MARK action specification. 1181 * @param[in,out] resource 1182 * Pointer to the modify-header resource. 1183 * @param[out] error 1184 * Pointer to the error structure. 1185 * 1186 * @return 1187 * 0 on success, a negative errno value otherwise and rte_errno is set. 1188 */ 1189 static int 1190 flow_dv_convert_action_mark(struct rte_eth_dev *dev, 1191 const struct rte_flow_action_mark *conf, 1192 struct mlx5_flow_dv_modify_hdr_resource *resource, 1193 struct rte_flow_error *error) 1194 { 1195 struct mlx5_priv *priv = dev->data->dev_private; 1196 rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK & 1197 priv->sh->dv_mark_mask); 1198 rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask; 1199 struct rte_flow_item item = { 1200 .spec = &data, 1201 .mask = &mask, 1202 }; 1203 struct field_modify_info reg_c_x[] = { 1204 [1] = {0, 0, 0}, 1205 }; 1206 int reg; 1207 1208 if (!mask) 1209 return rte_flow_error_set(error, EINVAL, 1210 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1211 NULL, "zero mark action mask"); 1212 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1213 if (reg < 0) 1214 return reg; 1215 MLX5_ASSERT(reg > 0); 1216 if (reg == REG_C_0) { 1217 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1218 uint32_t shl_c0 = rte_bsf32(msk_c0); 1219 1220 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1221 mask = rte_cpu_to_be_32(mask) & msk_c0; 1222 mask = rte_cpu_to_be_32(mask << shl_c0); 1223 } 1224 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1225 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1226 MLX5_MODIFICATION_TYPE_SET, error); 1227 } 1228 1229 /** 1230 * Get metadata register index for specified steering domain. 1231 * 1232 * @param[in] dev 1233 * Pointer to the rte_eth_dev structure. 1234 * @param[in] attr 1235 * Attributes of flow to determine steering domain. 1236 * @param[out] error 1237 * Pointer to the error structure. 1238 * 1239 * @return 1240 * positive index on success, a negative errno value otherwise 1241 * and rte_errno is set. 1242 */ 1243 static enum modify_reg 1244 flow_dv_get_metadata_reg(struct rte_eth_dev *dev, 1245 const struct rte_flow_attr *attr, 1246 struct rte_flow_error *error) 1247 { 1248 int reg = 1249 mlx5_flow_get_reg_id(dev, attr->transfer ? 1250 MLX5_METADATA_FDB : 1251 attr->egress ? 1252 MLX5_METADATA_TX : 1253 MLX5_METADATA_RX, 0, error); 1254 if (reg < 0) 1255 return rte_flow_error_set(error, 1256 ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, 1257 NULL, "unavailable " 1258 "metadata register"); 1259 return reg; 1260 } 1261 1262 /** 1263 * Convert SET_META action to DV specification. 1264 * 1265 * @param[in] dev 1266 * Pointer to the rte_eth_dev structure. 1267 * @param[in,out] resource 1268 * Pointer to the modify-header resource. 1269 * @param[in] attr 1270 * Attributes of flow that includes this item. 1271 * @param[in] conf 1272 * Pointer to action specification. 1273 * @param[out] error 1274 * Pointer to the error structure. 1275 * 1276 * @return 1277 * 0 on success, a negative errno value otherwise and rte_errno is set. 1278 */ 1279 static int 1280 flow_dv_convert_action_set_meta 1281 (struct rte_eth_dev *dev, 1282 struct mlx5_flow_dv_modify_hdr_resource *resource, 1283 const struct rte_flow_attr *attr, 1284 const struct rte_flow_action_set_meta *conf, 1285 struct rte_flow_error *error) 1286 { 1287 uint32_t mask = rte_cpu_to_be_32(conf->mask); 1288 uint32_t data = rte_cpu_to_be_32(conf->data) & mask; 1289 struct rte_flow_item item = { 1290 .spec = &data, 1291 .mask = &mask, 1292 }; 1293 struct field_modify_info reg_c_x[] = { 1294 [1] = {0, 0, 0}, 1295 }; 1296 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1297 1298 if (reg < 0) 1299 return reg; 1300 MLX5_ASSERT(reg != REG_NON); 1301 if (reg == REG_C_0) { 1302 struct mlx5_priv *priv = dev->data->dev_private; 1303 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1304 uint32_t shl_c0 = rte_bsf32(msk_c0); 1305 1306 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1307 mask = rte_cpu_to_be_32(mask) & msk_c0; 1308 mask = rte_cpu_to_be_32(mask << shl_c0); 1309 } 1310 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1311 /* The routine expects parameters in memory as big-endian ones. */ 1312 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1313 MLX5_MODIFICATION_TYPE_SET, error); 1314 } 1315 1316 /** 1317 * Convert modify-header set IPv4 DSCP action to DV specification. 1318 * 1319 * @param[in,out] resource 1320 * Pointer to the modify-header resource. 1321 * @param[in] action 1322 * Pointer to action specification. 1323 * @param[out] error 1324 * Pointer to the error structure. 1325 * 1326 * @return 1327 * 0 on success, a negative errno value otherwise and rte_errno is set. 1328 */ 1329 static int 1330 flow_dv_convert_action_modify_ipv4_dscp 1331 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1332 const struct rte_flow_action *action, 1333 struct rte_flow_error *error) 1334 { 1335 const struct rte_flow_action_set_dscp *conf = 1336 (const struct rte_flow_action_set_dscp *)(action->conf); 1337 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 1338 struct rte_flow_item_ipv4 ipv4; 1339 struct rte_flow_item_ipv4 ipv4_mask; 1340 1341 memset(&ipv4, 0, sizeof(ipv4)); 1342 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 1343 ipv4.hdr.type_of_service = conf->dscp; 1344 ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2; 1345 item.spec = &ipv4; 1346 item.mask = &ipv4_mask; 1347 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 1348 MLX5_MODIFICATION_TYPE_SET, error); 1349 } 1350 1351 /** 1352 * Convert modify-header set IPv6 DSCP action to DV specification. 1353 * 1354 * @param[in,out] resource 1355 * Pointer to the modify-header resource. 1356 * @param[in] action 1357 * Pointer to action specification. 1358 * @param[out] error 1359 * Pointer to the error structure. 1360 * 1361 * @return 1362 * 0 on success, a negative errno value otherwise and rte_errno is set. 1363 */ 1364 static int 1365 flow_dv_convert_action_modify_ipv6_dscp 1366 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1367 const struct rte_flow_action *action, 1368 struct rte_flow_error *error) 1369 { 1370 const struct rte_flow_action_set_dscp *conf = 1371 (const struct rte_flow_action_set_dscp *)(action->conf); 1372 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 1373 struct rte_flow_item_ipv6 ipv6; 1374 struct rte_flow_item_ipv6 ipv6_mask; 1375 1376 memset(&ipv6, 0, sizeof(ipv6)); 1377 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 1378 /* 1379 * Even though the DSCP bits offset of IPv6 is not byte aligned, 1380 * rdma-core only accept the DSCP bits byte aligned start from 1381 * bit 0 to 5 as to be compatible with IPv4. No need to shift the 1382 * bits in IPv6 case as rdma-core requires byte aligned value. 1383 */ 1384 ipv6.hdr.vtc_flow = conf->dscp; 1385 ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22; 1386 item.spec = &ipv6; 1387 item.mask = &ipv6_mask; 1388 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 1389 MLX5_MODIFICATION_TYPE_SET, error); 1390 } 1391 1392 static int 1393 mlx5_flow_item_field_width(struct mlx5_priv *priv, 1394 enum rte_flow_field_id field) 1395 { 1396 switch (field) { 1397 case RTE_FLOW_FIELD_START: 1398 return 32; 1399 case RTE_FLOW_FIELD_MAC_DST: 1400 case RTE_FLOW_FIELD_MAC_SRC: 1401 return 48; 1402 case RTE_FLOW_FIELD_VLAN_TYPE: 1403 return 16; 1404 case RTE_FLOW_FIELD_VLAN_ID: 1405 return 12; 1406 case RTE_FLOW_FIELD_MAC_TYPE: 1407 return 16; 1408 case RTE_FLOW_FIELD_IPV4_DSCP: 1409 return 6; 1410 case RTE_FLOW_FIELD_IPV4_TTL: 1411 return 8; 1412 case RTE_FLOW_FIELD_IPV4_SRC: 1413 case RTE_FLOW_FIELD_IPV4_DST: 1414 return 32; 1415 case RTE_FLOW_FIELD_IPV6_DSCP: 1416 return 6; 1417 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1418 return 8; 1419 case RTE_FLOW_FIELD_IPV6_SRC: 1420 case RTE_FLOW_FIELD_IPV6_DST: 1421 return 128; 1422 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1423 case RTE_FLOW_FIELD_TCP_PORT_DST: 1424 return 16; 1425 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1426 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1427 return 32; 1428 case RTE_FLOW_FIELD_TCP_FLAGS: 1429 return 9; 1430 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1431 case RTE_FLOW_FIELD_UDP_PORT_DST: 1432 return 16; 1433 case RTE_FLOW_FIELD_VXLAN_VNI: 1434 case RTE_FLOW_FIELD_GENEVE_VNI: 1435 return 24; 1436 case RTE_FLOW_FIELD_GTP_TEID: 1437 case RTE_FLOW_FIELD_TAG: 1438 return 32; 1439 case RTE_FLOW_FIELD_MARK: 1440 return __builtin_popcount(priv->sh->dv_mark_mask); 1441 case RTE_FLOW_FIELD_META: 1442 return __builtin_popcount(priv->sh->dv_meta_mask); 1443 case RTE_FLOW_FIELD_POINTER: 1444 case RTE_FLOW_FIELD_VALUE: 1445 return 64; 1446 default: 1447 MLX5_ASSERT(false); 1448 } 1449 return 0; 1450 } 1451 1452 static void 1453 mlx5_flow_field_id_to_modify_info 1454 (const struct rte_flow_action_modify_data *data, 1455 struct field_modify_info *info, 1456 uint32_t *mask, uint32_t *value, 1457 uint32_t width, uint32_t dst_width, 1458 uint32_t *shift, struct rte_eth_dev *dev, 1459 const struct rte_flow_attr *attr, 1460 struct rte_flow_error *error) 1461 { 1462 struct mlx5_priv *priv = dev->data->dev_private; 1463 uint32_t idx = 0; 1464 uint32_t off = 0; 1465 uint64_t val = 0; 1466 switch (data->field) { 1467 case RTE_FLOW_FIELD_START: 1468 /* not supported yet */ 1469 MLX5_ASSERT(false); 1470 break; 1471 case RTE_FLOW_FIELD_MAC_DST: 1472 off = data->offset > 16 ? data->offset - 16 : 0; 1473 if (mask) { 1474 if (data->offset < 16) { 1475 info[idx] = (struct field_modify_info){2, 0, 1476 MLX5_MODI_OUT_DMAC_15_0}; 1477 if (width < 16) { 1478 mask[idx] = rte_cpu_to_be_16(0xffff >> 1479 (16 - width)); 1480 width = 0; 1481 } else { 1482 mask[idx] = RTE_BE16(0xffff); 1483 width -= 16; 1484 } 1485 if (!width) 1486 break; 1487 ++idx; 1488 } 1489 info[idx] = (struct field_modify_info){4, 4 * idx, 1490 MLX5_MODI_OUT_DMAC_47_16}; 1491 mask[idx] = rte_cpu_to_be_32((0xffffffff >> 1492 (32 - width)) << off); 1493 } else { 1494 if (data->offset < 16) 1495 info[idx++] = (struct field_modify_info){2, 0, 1496 MLX5_MODI_OUT_DMAC_15_0}; 1497 info[idx] = (struct field_modify_info){4, off, 1498 MLX5_MODI_OUT_DMAC_47_16}; 1499 } 1500 break; 1501 case RTE_FLOW_FIELD_MAC_SRC: 1502 off = data->offset > 16 ? data->offset - 16 : 0; 1503 if (mask) { 1504 if (data->offset < 16) { 1505 info[idx] = (struct field_modify_info){2, 0, 1506 MLX5_MODI_OUT_SMAC_15_0}; 1507 if (width < 16) { 1508 mask[idx] = rte_cpu_to_be_16(0xffff >> 1509 (16 - width)); 1510 width = 0; 1511 } else { 1512 mask[idx] = RTE_BE16(0xffff); 1513 width -= 16; 1514 } 1515 if (!width) 1516 break; 1517 ++idx; 1518 } 1519 info[idx] = (struct field_modify_info){4, 4 * idx, 1520 MLX5_MODI_OUT_SMAC_47_16}; 1521 mask[idx] = rte_cpu_to_be_32((0xffffffff >> 1522 (32 - width)) << off); 1523 } else { 1524 if (data->offset < 16) 1525 info[idx++] = (struct field_modify_info){2, 0, 1526 MLX5_MODI_OUT_SMAC_15_0}; 1527 info[idx] = (struct field_modify_info){4, off, 1528 MLX5_MODI_OUT_SMAC_47_16}; 1529 } 1530 break; 1531 case RTE_FLOW_FIELD_VLAN_TYPE: 1532 /* not supported yet */ 1533 break; 1534 case RTE_FLOW_FIELD_VLAN_ID: 1535 info[idx] = (struct field_modify_info){2, 0, 1536 MLX5_MODI_OUT_FIRST_VID}; 1537 if (mask) 1538 mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width)); 1539 break; 1540 case RTE_FLOW_FIELD_MAC_TYPE: 1541 info[idx] = (struct field_modify_info){2, 0, 1542 MLX5_MODI_OUT_ETHERTYPE}; 1543 if (mask) 1544 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1545 break; 1546 case RTE_FLOW_FIELD_IPV4_DSCP: 1547 info[idx] = (struct field_modify_info){1, 0, 1548 MLX5_MODI_OUT_IP_DSCP}; 1549 if (mask) 1550 mask[idx] = 0x3f >> (6 - width); 1551 break; 1552 case RTE_FLOW_FIELD_IPV4_TTL: 1553 info[idx] = (struct field_modify_info){1, 0, 1554 MLX5_MODI_OUT_IPV4_TTL}; 1555 if (mask) 1556 mask[idx] = 0xff >> (8 - width); 1557 break; 1558 case RTE_FLOW_FIELD_IPV4_SRC: 1559 info[idx] = (struct field_modify_info){4, 0, 1560 MLX5_MODI_OUT_SIPV4}; 1561 if (mask) 1562 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1563 (32 - width)); 1564 break; 1565 case RTE_FLOW_FIELD_IPV4_DST: 1566 info[idx] = (struct field_modify_info){4, 0, 1567 MLX5_MODI_OUT_DIPV4}; 1568 if (mask) 1569 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1570 (32 - width)); 1571 break; 1572 case RTE_FLOW_FIELD_IPV6_DSCP: 1573 info[idx] = (struct field_modify_info){1, 0, 1574 MLX5_MODI_OUT_IP_DSCP}; 1575 if (mask) 1576 mask[idx] = 0x3f >> (6 - width); 1577 break; 1578 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1579 info[idx] = (struct field_modify_info){1, 0, 1580 MLX5_MODI_OUT_IPV6_HOPLIMIT}; 1581 if (mask) 1582 mask[idx] = 0xff >> (8 - width); 1583 break; 1584 case RTE_FLOW_FIELD_IPV6_SRC: 1585 if (mask) { 1586 if (data->offset < 32) { 1587 info[idx] = (struct field_modify_info){4, 1588 4 * idx, 1589 MLX5_MODI_OUT_SIPV6_31_0}; 1590 if (width < 32) { 1591 mask[idx] = 1592 rte_cpu_to_be_32(0xffffffff >> 1593 (32 - width)); 1594 width = 0; 1595 } else { 1596 mask[idx] = RTE_BE32(0xffffffff); 1597 width -= 32; 1598 } 1599 if (!width) 1600 break; 1601 ++idx; 1602 } 1603 if (data->offset < 64) { 1604 info[idx] = (struct field_modify_info){4, 1605 4 * idx, 1606 MLX5_MODI_OUT_SIPV6_63_32}; 1607 if (width < 32) { 1608 mask[idx] = 1609 rte_cpu_to_be_32(0xffffffff >> 1610 (32 - width)); 1611 width = 0; 1612 } else { 1613 mask[idx] = RTE_BE32(0xffffffff); 1614 width -= 32; 1615 } 1616 if (!width) 1617 break; 1618 ++idx; 1619 } 1620 if (data->offset < 96) { 1621 info[idx] = (struct field_modify_info){4, 1622 4 * idx, 1623 MLX5_MODI_OUT_SIPV6_95_64}; 1624 if (width < 32) { 1625 mask[idx] = 1626 rte_cpu_to_be_32(0xffffffff >> 1627 (32 - width)); 1628 width = 0; 1629 } else { 1630 mask[idx] = RTE_BE32(0xffffffff); 1631 width -= 32; 1632 } 1633 if (!width) 1634 break; 1635 ++idx; 1636 } 1637 info[idx] = (struct field_modify_info){4, 4 * idx, 1638 MLX5_MODI_OUT_SIPV6_127_96}; 1639 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1640 (32 - width)); 1641 } else { 1642 if (data->offset < 32) 1643 info[idx++] = (struct field_modify_info){4, 0, 1644 MLX5_MODI_OUT_SIPV6_31_0}; 1645 if (data->offset < 64) 1646 info[idx++] = (struct field_modify_info){4, 0, 1647 MLX5_MODI_OUT_SIPV6_63_32}; 1648 if (data->offset < 96) 1649 info[idx++] = (struct field_modify_info){4, 0, 1650 MLX5_MODI_OUT_SIPV6_95_64}; 1651 if (data->offset < 128) 1652 info[idx++] = (struct field_modify_info){4, 0, 1653 MLX5_MODI_OUT_SIPV6_127_96}; 1654 } 1655 break; 1656 case RTE_FLOW_FIELD_IPV6_DST: 1657 if (mask) { 1658 if (data->offset < 32) { 1659 info[idx] = (struct field_modify_info){4, 1660 4 * idx, 1661 MLX5_MODI_OUT_DIPV6_31_0}; 1662 if (width < 32) { 1663 mask[idx] = 1664 rte_cpu_to_be_32(0xffffffff >> 1665 (32 - width)); 1666 width = 0; 1667 } else { 1668 mask[idx] = RTE_BE32(0xffffffff); 1669 width -= 32; 1670 } 1671 if (!width) 1672 break; 1673 ++idx; 1674 } 1675 if (data->offset < 64) { 1676 info[idx] = (struct field_modify_info){4, 1677 4 * idx, 1678 MLX5_MODI_OUT_DIPV6_63_32}; 1679 if (width < 32) { 1680 mask[idx] = 1681 rte_cpu_to_be_32(0xffffffff >> 1682 (32 - width)); 1683 width = 0; 1684 } else { 1685 mask[idx] = RTE_BE32(0xffffffff); 1686 width -= 32; 1687 } 1688 if (!width) 1689 break; 1690 ++idx; 1691 } 1692 if (data->offset < 96) { 1693 info[idx] = (struct field_modify_info){4, 1694 4 * idx, 1695 MLX5_MODI_OUT_DIPV6_95_64}; 1696 if (width < 32) { 1697 mask[idx] = 1698 rte_cpu_to_be_32(0xffffffff >> 1699 (32 - width)); 1700 width = 0; 1701 } else { 1702 mask[idx] = RTE_BE32(0xffffffff); 1703 width -= 32; 1704 } 1705 if (!width) 1706 break; 1707 ++idx; 1708 } 1709 info[idx] = (struct field_modify_info){4, 4 * idx, 1710 MLX5_MODI_OUT_DIPV6_127_96}; 1711 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1712 (32 - width)); 1713 } else { 1714 if (data->offset < 32) 1715 info[idx++] = (struct field_modify_info){4, 0, 1716 MLX5_MODI_OUT_DIPV6_31_0}; 1717 if (data->offset < 64) 1718 info[idx++] = (struct field_modify_info){4, 0, 1719 MLX5_MODI_OUT_DIPV6_63_32}; 1720 if (data->offset < 96) 1721 info[idx++] = (struct field_modify_info){4, 0, 1722 MLX5_MODI_OUT_DIPV6_95_64}; 1723 if (data->offset < 128) 1724 info[idx++] = (struct field_modify_info){4, 0, 1725 MLX5_MODI_OUT_DIPV6_127_96}; 1726 } 1727 break; 1728 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1729 info[idx] = (struct field_modify_info){2, 0, 1730 MLX5_MODI_OUT_TCP_SPORT}; 1731 if (mask) 1732 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1733 break; 1734 case RTE_FLOW_FIELD_TCP_PORT_DST: 1735 info[idx] = (struct field_modify_info){2, 0, 1736 MLX5_MODI_OUT_TCP_DPORT}; 1737 if (mask) 1738 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1739 break; 1740 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1741 info[idx] = (struct field_modify_info){4, 0, 1742 MLX5_MODI_OUT_TCP_SEQ_NUM}; 1743 if (mask) 1744 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1745 (32 - width)); 1746 break; 1747 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1748 info[idx] = (struct field_modify_info){4, 0, 1749 MLX5_MODI_OUT_TCP_ACK_NUM}; 1750 if (mask) 1751 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1752 (32 - width)); 1753 break; 1754 case RTE_FLOW_FIELD_TCP_FLAGS: 1755 info[idx] = (struct field_modify_info){2, 0, 1756 MLX5_MODI_OUT_TCP_FLAGS}; 1757 if (mask) 1758 mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width)); 1759 break; 1760 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1761 info[idx] = (struct field_modify_info){2, 0, 1762 MLX5_MODI_OUT_UDP_SPORT}; 1763 if (mask) 1764 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1765 break; 1766 case RTE_FLOW_FIELD_UDP_PORT_DST: 1767 info[idx] = (struct field_modify_info){2, 0, 1768 MLX5_MODI_OUT_UDP_DPORT}; 1769 if (mask) 1770 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1771 break; 1772 case RTE_FLOW_FIELD_VXLAN_VNI: 1773 /* not supported yet */ 1774 break; 1775 case RTE_FLOW_FIELD_GENEVE_VNI: 1776 /* not supported yet*/ 1777 break; 1778 case RTE_FLOW_FIELD_GTP_TEID: 1779 info[idx] = (struct field_modify_info){4, 0, 1780 MLX5_MODI_GTP_TEID}; 1781 if (mask) 1782 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1783 (32 - width)); 1784 break; 1785 case RTE_FLOW_FIELD_TAG: 1786 { 1787 int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 1788 data->level, error); 1789 if (reg < 0) 1790 return; 1791 MLX5_ASSERT(reg != REG_NON); 1792 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1793 info[idx] = (struct field_modify_info){4, 0, 1794 reg_to_field[reg]}; 1795 if (mask) 1796 mask[idx] = 1797 rte_cpu_to_be_32(0xffffffff >> 1798 (32 - width)); 1799 } 1800 break; 1801 case RTE_FLOW_FIELD_MARK: 1802 { 1803 uint32_t mark_mask = priv->sh->dv_mark_mask; 1804 uint32_t mark_count = __builtin_popcount(mark_mask); 1805 int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 1806 0, error); 1807 if (reg < 0) 1808 return; 1809 MLX5_ASSERT(reg != REG_NON); 1810 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1811 info[idx] = (struct field_modify_info){4, 0, 1812 reg_to_field[reg]}; 1813 if (mask) 1814 mask[idx] = rte_cpu_to_be_32((mark_mask >> 1815 (mark_count - width)) & mark_mask); 1816 } 1817 break; 1818 case RTE_FLOW_FIELD_META: 1819 { 1820 uint32_t meta_mask = priv->sh->dv_meta_mask; 1821 uint32_t meta_count = __builtin_popcount(meta_mask); 1822 uint32_t msk_c0 = 1823 rte_cpu_to_be_32(priv->sh->dv_regc0_mask); 1824 uint32_t shl_c0 = rte_bsf32(msk_c0); 1825 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1826 if (reg < 0) 1827 return; 1828 MLX5_ASSERT(reg != REG_NON); 1829 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1830 if (reg == REG_C_0) 1831 *shift = shl_c0; 1832 info[idx] = (struct field_modify_info){4, 0, 1833 reg_to_field[reg]}; 1834 if (mask) 1835 mask[idx] = rte_cpu_to_be_32((meta_mask >> 1836 (meta_count - width)) & meta_mask); 1837 } 1838 break; 1839 case RTE_FLOW_FIELD_POINTER: 1840 case RTE_FLOW_FIELD_VALUE: 1841 if (data->field == RTE_FLOW_FIELD_POINTER) 1842 memcpy(&val, (void *)(uintptr_t)data->value, 1843 sizeof(uint64_t)); 1844 else 1845 val = data->value; 1846 for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) { 1847 if (mask[idx]) { 1848 if (dst_width == 48) { 1849 /*special case for MAC addresses */ 1850 value[idx] = rte_cpu_to_be_16(val); 1851 val >>= 16; 1852 dst_width -= 16; 1853 } else if (dst_width > 16) { 1854 value[idx] = rte_cpu_to_be_32(val); 1855 val >>= 32; 1856 } else if (dst_width > 8) { 1857 value[idx] = rte_cpu_to_be_16(val); 1858 val >>= 16; 1859 } else { 1860 value[idx] = (uint8_t)val; 1861 val >>= 8; 1862 } 1863 if (*shift) 1864 value[idx] <<= *shift; 1865 if (!val) 1866 break; 1867 } 1868 } 1869 break; 1870 default: 1871 MLX5_ASSERT(false); 1872 break; 1873 } 1874 } 1875 1876 /** 1877 * Convert modify_field action to DV specification. 1878 * 1879 * @param[in] dev 1880 * Pointer to the rte_eth_dev structure. 1881 * @param[in,out] resource 1882 * Pointer to the modify-header resource. 1883 * @param[in] action 1884 * Pointer to action specification. 1885 * @param[in] attr 1886 * Attributes of flow that includes this item. 1887 * @param[out] error 1888 * Pointer to the error structure. 1889 * 1890 * @return 1891 * 0 on success, a negative errno value otherwise and rte_errno is set. 1892 */ 1893 static int 1894 flow_dv_convert_action_modify_field 1895 (struct rte_eth_dev *dev, 1896 struct mlx5_flow_dv_modify_hdr_resource *resource, 1897 const struct rte_flow_action *action, 1898 const struct rte_flow_attr *attr, 1899 struct rte_flow_error *error) 1900 { 1901 struct mlx5_priv *priv = dev->data->dev_private; 1902 const struct rte_flow_action_modify_field *conf = 1903 (const struct rte_flow_action_modify_field *)(action->conf); 1904 struct rte_flow_item item; 1905 struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = { 1906 {0, 0, 0} }; 1907 struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = { 1908 {0, 0, 0} }; 1909 uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0}; 1910 uint32_t value[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0}; 1911 uint32_t type; 1912 uint32_t shift = 0; 1913 uint32_t dst_width = mlx5_flow_item_field_width(priv, conf->dst.field); 1914 1915 if (conf->src.field == RTE_FLOW_FIELD_POINTER || 1916 conf->src.field == RTE_FLOW_FIELD_VALUE) { 1917 type = MLX5_MODIFICATION_TYPE_SET; 1918 /** For SET fill the destination field (field) first. */ 1919 mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, 1920 value, conf->width, dst_width, 1921 &shift, dev, attr, error); 1922 /** Then copy immediate value from source as per mask. */ 1923 mlx5_flow_field_id_to_modify_info(&conf->src, dcopy, mask, 1924 value, conf->width, dst_width, 1925 &shift, dev, attr, error); 1926 item.spec = &value; 1927 } else { 1928 type = MLX5_MODIFICATION_TYPE_COPY; 1929 /** For COPY fill the destination field (dcopy) without mask. */ 1930 mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL, 1931 value, conf->width, dst_width, 1932 &shift, dev, attr, error); 1933 /** Then construct the source field (field) with mask. */ 1934 mlx5_flow_field_id_to_modify_info(&conf->src, field, mask, 1935 value, conf->width, dst_width, 1936 &shift, dev, attr, error); 1937 } 1938 item.mask = &mask; 1939 return flow_dv_convert_modify_action(&item, 1940 field, dcopy, resource, type, error); 1941 } 1942 1943 /** 1944 * Validate MARK item. 1945 * 1946 * @param[in] dev 1947 * Pointer to the rte_eth_dev structure. 1948 * @param[in] item 1949 * Item specification. 1950 * @param[in] attr 1951 * Attributes of flow that includes this item. 1952 * @param[out] error 1953 * Pointer to error structure. 1954 * 1955 * @return 1956 * 0 on success, a negative errno value otherwise and rte_errno is set. 1957 */ 1958 static int 1959 flow_dv_validate_item_mark(struct rte_eth_dev *dev, 1960 const struct rte_flow_item *item, 1961 const struct rte_flow_attr *attr __rte_unused, 1962 struct rte_flow_error *error) 1963 { 1964 struct mlx5_priv *priv = dev->data->dev_private; 1965 struct mlx5_dev_config *config = &priv->config; 1966 const struct rte_flow_item_mark *spec = item->spec; 1967 const struct rte_flow_item_mark *mask = item->mask; 1968 const struct rte_flow_item_mark nic_mask = { 1969 .id = priv->sh->dv_mark_mask, 1970 }; 1971 int ret; 1972 1973 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 1974 return rte_flow_error_set(error, ENOTSUP, 1975 RTE_FLOW_ERROR_TYPE_ITEM, item, 1976 "extended metadata feature" 1977 " isn't enabled"); 1978 if (!mlx5_flow_ext_mreg_supported(dev)) 1979 return rte_flow_error_set(error, ENOTSUP, 1980 RTE_FLOW_ERROR_TYPE_ITEM, item, 1981 "extended metadata register" 1982 " isn't supported"); 1983 if (!nic_mask.id) 1984 return rte_flow_error_set(error, ENOTSUP, 1985 RTE_FLOW_ERROR_TYPE_ITEM, item, 1986 "extended metadata register" 1987 " isn't available"); 1988 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1989 if (ret < 0) 1990 return ret; 1991 if (!spec) 1992 return rte_flow_error_set(error, EINVAL, 1993 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 1994 item->spec, 1995 "data cannot be empty"); 1996 if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id)) 1997 return rte_flow_error_set(error, EINVAL, 1998 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1999 &spec->id, 2000 "mark id exceeds the limit"); 2001 if (!mask) 2002 mask = &nic_mask; 2003 if (!mask->id) 2004 return rte_flow_error_set(error, EINVAL, 2005 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2006 "mask cannot be zero"); 2007 2008 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2009 (const uint8_t *)&nic_mask, 2010 sizeof(struct rte_flow_item_mark), 2011 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2012 if (ret < 0) 2013 return ret; 2014 return 0; 2015 } 2016 2017 /** 2018 * Validate META item. 2019 * 2020 * @param[in] dev 2021 * Pointer to the rte_eth_dev structure. 2022 * @param[in] item 2023 * Item specification. 2024 * @param[in] attr 2025 * Attributes of flow that includes this item. 2026 * @param[out] error 2027 * Pointer to error structure. 2028 * 2029 * @return 2030 * 0 on success, a negative errno value otherwise and rte_errno is set. 2031 */ 2032 static int 2033 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused, 2034 const struct rte_flow_item *item, 2035 const struct rte_flow_attr *attr, 2036 struct rte_flow_error *error) 2037 { 2038 struct mlx5_priv *priv = dev->data->dev_private; 2039 struct mlx5_dev_config *config = &priv->config; 2040 const struct rte_flow_item_meta *spec = item->spec; 2041 const struct rte_flow_item_meta *mask = item->mask; 2042 struct rte_flow_item_meta nic_mask = { 2043 .data = UINT32_MAX 2044 }; 2045 int reg; 2046 int ret; 2047 2048 if (!spec) 2049 return rte_flow_error_set(error, EINVAL, 2050 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2051 item->spec, 2052 "data cannot be empty"); 2053 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 2054 if (!mlx5_flow_ext_mreg_supported(dev)) 2055 return rte_flow_error_set(error, ENOTSUP, 2056 RTE_FLOW_ERROR_TYPE_ITEM, item, 2057 "extended metadata register" 2058 " isn't supported"); 2059 reg = flow_dv_get_metadata_reg(dev, attr, error); 2060 if (reg < 0) 2061 return reg; 2062 if (reg == REG_NON) 2063 return rte_flow_error_set(error, ENOTSUP, 2064 RTE_FLOW_ERROR_TYPE_ITEM, item, 2065 "unavalable extended metadata register"); 2066 if (reg == REG_B) 2067 return rte_flow_error_set(error, ENOTSUP, 2068 RTE_FLOW_ERROR_TYPE_ITEM, item, 2069 "match on reg_b " 2070 "isn't supported"); 2071 if (reg != REG_A) 2072 nic_mask.data = priv->sh->dv_meta_mask; 2073 } else { 2074 if (attr->transfer) 2075 return rte_flow_error_set(error, ENOTSUP, 2076 RTE_FLOW_ERROR_TYPE_ITEM, item, 2077 "extended metadata feature " 2078 "should be enabled when " 2079 "meta item is requested " 2080 "with e-switch mode "); 2081 if (attr->ingress) 2082 return rte_flow_error_set(error, ENOTSUP, 2083 RTE_FLOW_ERROR_TYPE_ITEM, item, 2084 "match on metadata for ingress " 2085 "is not supported in legacy " 2086 "metadata mode"); 2087 } 2088 if (!mask) 2089 mask = &rte_flow_item_meta_mask; 2090 if (!mask->data) 2091 return rte_flow_error_set(error, EINVAL, 2092 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2093 "mask cannot be zero"); 2094 2095 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2096 (const uint8_t *)&nic_mask, 2097 sizeof(struct rte_flow_item_meta), 2098 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2099 return ret; 2100 } 2101 2102 /** 2103 * Validate TAG item. 2104 * 2105 * @param[in] dev 2106 * Pointer to the rte_eth_dev structure. 2107 * @param[in] item 2108 * Item specification. 2109 * @param[in] attr 2110 * Attributes of flow that includes this item. 2111 * @param[out] error 2112 * Pointer to error structure. 2113 * 2114 * @return 2115 * 0 on success, a negative errno value otherwise and rte_errno is set. 2116 */ 2117 static int 2118 flow_dv_validate_item_tag(struct rte_eth_dev *dev, 2119 const struct rte_flow_item *item, 2120 const struct rte_flow_attr *attr __rte_unused, 2121 struct rte_flow_error *error) 2122 { 2123 const struct rte_flow_item_tag *spec = item->spec; 2124 const struct rte_flow_item_tag *mask = item->mask; 2125 const struct rte_flow_item_tag nic_mask = { 2126 .data = RTE_BE32(UINT32_MAX), 2127 .index = 0xff, 2128 }; 2129 int ret; 2130 2131 if (!mlx5_flow_ext_mreg_supported(dev)) 2132 return rte_flow_error_set(error, ENOTSUP, 2133 RTE_FLOW_ERROR_TYPE_ITEM, item, 2134 "extensive metadata register" 2135 " isn't supported"); 2136 if (!spec) 2137 return rte_flow_error_set(error, EINVAL, 2138 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2139 item->spec, 2140 "data cannot be empty"); 2141 if (!mask) 2142 mask = &rte_flow_item_tag_mask; 2143 if (!mask->data) 2144 return rte_flow_error_set(error, EINVAL, 2145 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2146 "mask cannot be zero"); 2147 2148 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2149 (const uint8_t *)&nic_mask, 2150 sizeof(struct rte_flow_item_tag), 2151 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2152 if (ret < 0) 2153 return ret; 2154 if (mask->index != 0xff) 2155 return rte_flow_error_set(error, EINVAL, 2156 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2157 "partial mask for tag index" 2158 " is not supported"); 2159 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error); 2160 if (ret < 0) 2161 return ret; 2162 MLX5_ASSERT(ret != REG_NON); 2163 return 0; 2164 } 2165 2166 /** 2167 * Validate vport item. 2168 * 2169 * @param[in] dev 2170 * Pointer to the rte_eth_dev structure. 2171 * @param[in] item 2172 * Item specification. 2173 * @param[in] attr 2174 * Attributes of flow that includes this item. 2175 * @param[in] item_flags 2176 * Bit-fields that holds the items detected until now. 2177 * @param[out] error 2178 * Pointer to error structure. 2179 * 2180 * @return 2181 * 0 on success, a negative errno value otherwise and rte_errno is set. 2182 */ 2183 static int 2184 flow_dv_validate_item_port_id(struct rte_eth_dev *dev, 2185 const struct rte_flow_item *item, 2186 const struct rte_flow_attr *attr, 2187 uint64_t item_flags, 2188 struct rte_flow_error *error) 2189 { 2190 const struct rte_flow_item_port_id *spec = item->spec; 2191 const struct rte_flow_item_port_id *mask = item->mask; 2192 const struct rte_flow_item_port_id switch_mask = { 2193 .id = 0xffffffff, 2194 }; 2195 struct mlx5_priv *esw_priv; 2196 struct mlx5_priv *dev_priv; 2197 int ret; 2198 2199 if (!attr->transfer) 2200 return rte_flow_error_set(error, EINVAL, 2201 RTE_FLOW_ERROR_TYPE_ITEM, 2202 NULL, 2203 "match on port id is valid only" 2204 " when transfer flag is enabled"); 2205 if (item_flags & MLX5_FLOW_ITEM_PORT_ID) 2206 return rte_flow_error_set(error, ENOTSUP, 2207 RTE_FLOW_ERROR_TYPE_ITEM, item, 2208 "multiple source ports are not" 2209 " supported"); 2210 if (!mask) 2211 mask = &switch_mask; 2212 if (mask->id != 0xffffffff) 2213 return rte_flow_error_set(error, ENOTSUP, 2214 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2215 mask, 2216 "no support for partial mask on" 2217 " \"id\" field"); 2218 ret = mlx5_flow_item_acceptable 2219 (item, (const uint8_t *)mask, 2220 (const uint8_t *)&rte_flow_item_port_id_mask, 2221 sizeof(struct rte_flow_item_port_id), 2222 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2223 if (ret) 2224 return ret; 2225 if (!spec) 2226 return 0; 2227 esw_priv = mlx5_port_to_eswitch_info(spec->id, false); 2228 if (!esw_priv) 2229 return rte_flow_error_set(error, rte_errno, 2230 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2231 "failed to obtain E-Switch info for" 2232 " port"); 2233 dev_priv = mlx5_dev_to_eswitch_info(dev); 2234 if (!dev_priv) 2235 return rte_flow_error_set(error, rte_errno, 2236 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2237 NULL, 2238 "failed to obtain E-Switch info"); 2239 if (esw_priv->domain_id != dev_priv->domain_id) 2240 return rte_flow_error_set(error, EINVAL, 2241 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2242 "cannot match on a port from a" 2243 " different E-Switch"); 2244 return 0; 2245 } 2246 2247 /** 2248 * Validate VLAN item. 2249 * 2250 * @param[in] item 2251 * Item specification. 2252 * @param[in] item_flags 2253 * Bit-fields that holds the items detected until now. 2254 * @param[in] dev 2255 * Ethernet device flow is being created on. 2256 * @param[out] error 2257 * Pointer to error structure. 2258 * 2259 * @return 2260 * 0 on success, a negative errno value otherwise and rte_errno is set. 2261 */ 2262 static int 2263 flow_dv_validate_item_vlan(const struct rte_flow_item *item, 2264 uint64_t item_flags, 2265 struct rte_eth_dev *dev, 2266 struct rte_flow_error *error) 2267 { 2268 const struct rte_flow_item_vlan *mask = item->mask; 2269 const struct rte_flow_item_vlan nic_mask = { 2270 .tci = RTE_BE16(UINT16_MAX), 2271 .inner_type = RTE_BE16(UINT16_MAX), 2272 .has_more_vlan = 1, 2273 }; 2274 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2275 int ret; 2276 const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 | 2277 MLX5_FLOW_LAYER_INNER_L4) : 2278 (MLX5_FLOW_LAYER_OUTER_L3 | 2279 MLX5_FLOW_LAYER_OUTER_L4); 2280 const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 2281 MLX5_FLOW_LAYER_OUTER_VLAN; 2282 2283 if (item_flags & vlanm) 2284 return rte_flow_error_set(error, EINVAL, 2285 RTE_FLOW_ERROR_TYPE_ITEM, item, 2286 "multiple VLAN layers not supported"); 2287 else if ((item_flags & l34m) != 0) 2288 return rte_flow_error_set(error, EINVAL, 2289 RTE_FLOW_ERROR_TYPE_ITEM, item, 2290 "VLAN cannot follow L3/L4 layer"); 2291 if (!mask) 2292 mask = &rte_flow_item_vlan_mask; 2293 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2294 (const uint8_t *)&nic_mask, 2295 sizeof(struct rte_flow_item_vlan), 2296 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2297 if (ret) 2298 return ret; 2299 if (!tunnel && mask->tci != RTE_BE16(0x0fff)) { 2300 struct mlx5_priv *priv = dev->data->dev_private; 2301 2302 if (priv->vmwa_context) { 2303 /* 2304 * Non-NULL context means we have a virtual machine 2305 * and SR-IOV enabled, we have to create VLAN interface 2306 * to make hypervisor to setup E-Switch vport 2307 * context correctly. We avoid creating the multiple 2308 * VLAN interfaces, so we cannot support VLAN tag mask. 2309 */ 2310 return rte_flow_error_set(error, EINVAL, 2311 RTE_FLOW_ERROR_TYPE_ITEM, 2312 item, 2313 "VLAN tag mask is not" 2314 " supported in virtual" 2315 " environment"); 2316 } 2317 } 2318 return 0; 2319 } 2320 2321 /* 2322 * GTP flags are contained in 1 byte of the format: 2323 * ------------------------------------------- 2324 * | bit | 0 - 2 | 3 | 4 | 5 | 6 | 7 | 2325 * |-----------------------------------------| 2326 * | value | Version | PT | Res | E | S | PN | 2327 * ------------------------------------------- 2328 * 2329 * Matching is supported only for GTP flags E, S, PN. 2330 */ 2331 #define MLX5_GTP_FLAGS_MASK 0x07 2332 2333 /** 2334 * Validate GTP item. 2335 * 2336 * @param[in] dev 2337 * Pointer to the rte_eth_dev structure. 2338 * @param[in] item 2339 * Item specification. 2340 * @param[in] item_flags 2341 * Bit-fields that holds the items detected until now. 2342 * @param[out] error 2343 * Pointer to error structure. 2344 * 2345 * @return 2346 * 0 on success, a negative errno value otherwise and rte_errno is set. 2347 */ 2348 static int 2349 flow_dv_validate_item_gtp(struct rte_eth_dev *dev, 2350 const struct rte_flow_item *item, 2351 uint64_t item_flags, 2352 struct rte_flow_error *error) 2353 { 2354 struct mlx5_priv *priv = dev->data->dev_private; 2355 const struct rte_flow_item_gtp *spec = item->spec; 2356 const struct rte_flow_item_gtp *mask = item->mask; 2357 const struct rte_flow_item_gtp nic_mask = { 2358 .v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK, 2359 .msg_type = 0xff, 2360 .teid = RTE_BE32(0xffffffff), 2361 }; 2362 2363 if (!priv->config.hca_attr.tunnel_stateless_gtp) 2364 return rte_flow_error_set(error, ENOTSUP, 2365 RTE_FLOW_ERROR_TYPE_ITEM, item, 2366 "GTP support is not enabled"); 2367 if (item_flags & MLX5_FLOW_LAYER_TUNNEL) 2368 return rte_flow_error_set(error, ENOTSUP, 2369 RTE_FLOW_ERROR_TYPE_ITEM, item, 2370 "multiple tunnel layers not" 2371 " supported"); 2372 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP)) 2373 return rte_flow_error_set(error, EINVAL, 2374 RTE_FLOW_ERROR_TYPE_ITEM, item, 2375 "no outer UDP layer found"); 2376 if (!mask) 2377 mask = &rte_flow_item_gtp_mask; 2378 if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK) 2379 return rte_flow_error_set(error, ENOTSUP, 2380 RTE_FLOW_ERROR_TYPE_ITEM, item, 2381 "Match is supported for GTP" 2382 " flags only"); 2383 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2384 (const uint8_t *)&nic_mask, 2385 sizeof(struct rte_flow_item_gtp), 2386 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2387 } 2388 2389 /** 2390 * Validate GTP PSC item. 2391 * 2392 * @param[in] item 2393 * Item specification. 2394 * @param[in] last_item 2395 * Previous validated item in the pattern items. 2396 * @param[in] gtp_item 2397 * Previous GTP item specification. 2398 * @param[in] attr 2399 * Pointer to flow attributes. 2400 * @param[out] error 2401 * Pointer to error structure. 2402 * 2403 * @return 2404 * 0 on success, a negative errno value otherwise and rte_errno is set. 2405 */ 2406 static int 2407 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, 2408 uint64_t last_item, 2409 const struct rte_flow_item *gtp_item, 2410 const struct rte_flow_attr *attr, 2411 struct rte_flow_error *error) 2412 { 2413 const struct rte_flow_item_gtp *gtp_spec; 2414 const struct rte_flow_item_gtp *gtp_mask; 2415 const struct rte_flow_item_gtp_psc *spec; 2416 const struct rte_flow_item_gtp_psc *mask; 2417 const struct rte_flow_item_gtp_psc nic_mask = { 2418 .pdu_type = 0xFF, 2419 .qfi = 0xFF, 2420 }; 2421 2422 if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP)) 2423 return rte_flow_error_set 2424 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2425 "GTP PSC item must be preceded with GTP item"); 2426 gtp_spec = gtp_item->spec; 2427 gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask; 2428 /* GTP spec and E flag is requested to match zero. */ 2429 if (gtp_spec && 2430 (gtp_mask->v_pt_rsv_flags & 2431 ~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG)) 2432 return rte_flow_error_set 2433 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2434 "GTP E flag must be 1 to match GTP PSC"); 2435 /* Check the flow is not created in group zero. */ 2436 if (!attr->transfer && !attr->group) 2437 return rte_flow_error_set 2438 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2439 "GTP PSC is not supported for group 0"); 2440 /* GTP spec is here and E flag is requested to match zero. */ 2441 if (!item->spec) 2442 return 0; 2443 spec = item->spec; 2444 mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask; 2445 if (spec->pdu_type > MLX5_GTP_EXT_MAX_PDU_TYPE) 2446 return rte_flow_error_set 2447 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2448 "PDU type should be smaller than 16"); 2449 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2450 (const uint8_t *)&nic_mask, 2451 sizeof(struct rte_flow_item_gtp_psc), 2452 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2453 } 2454 2455 /** 2456 * Validate IPV4 item. 2457 * Use existing validation function mlx5_flow_validate_item_ipv4(), and 2458 * add specific validation of fragment_offset field, 2459 * 2460 * @param[in] item 2461 * Item specification. 2462 * @param[in] item_flags 2463 * Bit-fields that holds the items detected until now. 2464 * @param[out] error 2465 * Pointer to error structure. 2466 * 2467 * @return 2468 * 0 on success, a negative errno value otherwise and rte_errno is set. 2469 */ 2470 static int 2471 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev, 2472 const struct rte_flow_item *item, 2473 uint64_t item_flags, uint64_t last_item, 2474 uint16_t ether_type, struct rte_flow_error *error) 2475 { 2476 int ret; 2477 struct mlx5_priv *priv = dev->data->dev_private; 2478 const struct rte_flow_item_ipv4 *spec = item->spec; 2479 const struct rte_flow_item_ipv4 *last = item->last; 2480 const struct rte_flow_item_ipv4 *mask = item->mask; 2481 rte_be16_t fragment_offset_spec = 0; 2482 rte_be16_t fragment_offset_last = 0; 2483 struct rte_flow_item_ipv4 nic_ipv4_mask = { 2484 .hdr = { 2485 .src_addr = RTE_BE32(0xffffffff), 2486 .dst_addr = RTE_BE32(0xffffffff), 2487 .type_of_service = 0xff, 2488 .fragment_offset = RTE_BE16(0xffff), 2489 .next_proto_id = 0xff, 2490 .time_to_live = 0xff, 2491 }, 2492 }; 2493 2494 if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) { 2495 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2496 bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl : 2497 priv->config.hca_attr.inner_ipv4_ihl; 2498 if (!ihl_cap) 2499 return rte_flow_error_set(error, ENOTSUP, 2500 RTE_FLOW_ERROR_TYPE_ITEM, 2501 item, 2502 "IPV4 ihl offload not supported"); 2503 nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl; 2504 } 2505 ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item, 2506 ether_type, &nic_ipv4_mask, 2507 MLX5_ITEM_RANGE_ACCEPTED, error); 2508 if (ret < 0) 2509 return ret; 2510 if (spec && mask) 2511 fragment_offset_spec = spec->hdr.fragment_offset & 2512 mask->hdr.fragment_offset; 2513 if (!fragment_offset_spec) 2514 return 0; 2515 /* 2516 * spec and mask are valid, enforce using full mask to make sure the 2517 * complete value is used correctly. 2518 */ 2519 if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2520 != RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2521 return rte_flow_error_set(error, EINVAL, 2522 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2523 item, "must use full mask for" 2524 " fragment_offset"); 2525 /* 2526 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0, 2527 * indicating this is 1st fragment of fragmented packet. 2528 * This is not yet supported in MLX5, return appropriate error message. 2529 */ 2530 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG)) 2531 return rte_flow_error_set(error, ENOTSUP, 2532 RTE_FLOW_ERROR_TYPE_ITEM, item, 2533 "match on first fragment not " 2534 "supported"); 2535 if (fragment_offset_spec && !last) 2536 return rte_flow_error_set(error, ENOTSUP, 2537 RTE_FLOW_ERROR_TYPE_ITEM, item, 2538 "specified value not supported"); 2539 /* spec and last are valid, validate the specified range. */ 2540 fragment_offset_last = last->hdr.fragment_offset & 2541 mask->hdr.fragment_offset; 2542 /* 2543 * Match on fragment_offset spec 0x2001 and last 0x3fff 2544 * means MF is 1 and frag-offset is > 0. 2545 * This packet is fragment 2nd and onward, excluding last. 2546 * This is not yet supported in MLX5, return appropriate 2547 * error message. 2548 */ 2549 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) && 2550 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2551 return rte_flow_error_set(error, ENOTSUP, 2552 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2553 last, "match on following " 2554 "fragments not supported"); 2555 /* 2556 * Match on fragment_offset spec 0x0001 and last 0x1fff 2557 * means MF is 0 and frag-offset is > 0. 2558 * This packet is last fragment of fragmented packet. 2559 * This is not yet supported in MLX5, return appropriate 2560 * error message. 2561 */ 2562 if (fragment_offset_spec == RTE_BE16(1) && 2563 fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK)) 2564 return rte_flow_error_set(error, ENOTSUP, 2565 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2566 last, "match on last " 2567 "fragment not supported"); 2568 /* 2569 * Match on fragment_offset spec 0x0001 and last 0x3fff 2570 * means MF and/or frag-offset is not 0. 2571 * This is a fragmented packet. 2572 * Other range values are invalid and rejected. 2573 */ 2574 if (!(fragment_offset_spec == RTE_BE16(1) && 2575 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))) 2576 return rte_flow_error_set(error, ENOTSUP, 2577 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2578 "specified range not supported"); 2579 return 0; 2580 } 2581 2582 /** 2583 * Validate IPV6 fragment extension item. 2584 * 2585 * @param[in] item 2586 * Item specification. 2587 * @param[in] item_flags 2588 * Bit-fields that holds the items detected until now. 2589 * @param[out] error 2590 * Pointer to error structure. 2591 * 2592 * @return 2593 * 0 on success, a negative errno value otherwise and rte_errno is set. 2594 */ 2595 static int 2596 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item, 2597 uint64_t item_flags, 2598 struct rte_flow_error *error) 2599 { 2600 const struct rte_flow_item_ipv6_frag_ext *spec = item->spec; 2601 const struct rte_flow_item_ipv6_frag_ext *last = item->last; 2602 const struct rte_flow_item_ipv6_frag_ext *mask = item->mask; 2603 rte_be16_t frag_data_spec = 0; 2604 rte_be16_t frag_data_last = 0; 2605 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2606 const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 : 2607 MLX5_FLOW_LAYER_OUTER_L4; 2608 int ret = 0; 2609 struct rte_flow_item_ipv6_frag_ext nic_mask = { 2610 .hdr = { 2611 .next_header = 0xff, 2612 .frag_data = RTE_BE16(0xffff), 2613 }, 2614 }; 2615 2616 if (item_flags & l4m) 2617 return rte_flow_error_set(error, EINVAL, 2618 RTE_FLOW_ERROR_TYPE_ITEM, item, 2619 "ipv6 fragment extension item cannot " 2620 "follow L4 item."); 2621 if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 2622 (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) 2623 return rte_flow_error_set(error, EINVAL, 2624 RTE_FLOW_ERROR_TYPE_ITEM, item, 2625 "ipv6 fragment extension item must " 2626 "follow ipv6 item"); 2627 if (spec && mask) 2628 frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data; 2629 if (!frag_data_spec) 2630 return 0; 2631 /* 2632 * spec and mask are valid, enforce using full mask to make sure the 2633 * complete value is used correctly. 2634 */ 2635 if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) != 2636 RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2637 return rte_flow_error_set(error, EINVAL, 2638 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2639 item, "must use full mask for" 2640 " frag_data"); 2641 /* 2642 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0. 2643 * This is 1st fragment of fragmented packet. 2644 */ 2645 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK)) 2646 return rte_flow_error_set(error, ENOTSUP, 2647 RTE_FLOW_ERROR_TYPE_ITEM, item, 2648 "match on first fragment not " 2649 "supported"); 2650 if (frag_data_spec && !last) 2651 return rte_flow_error_set(error, EINVAL, 2652 RTE_FLOW_ERROR_TYPE_ITEM, item, 2653 "specified value not supported"); 2654 ret = mlx5_flow_item_acceptable 2655 (item, (const uint8_t *)mask, 2656 (const uint8_t *)&nic_mask, 2657 sizeof(struct rte_flow_item_ipv6_frag_ext), 2658 MLX5_ITEM_RANGE_ACCEPTED, error); 2659 if (ret) 2660 return ret; 2661 /* spec and last are valid, validate the specified range. */ 2662 frag_data_last = last->hdr.frag_data & mask->hdr.frag_data; 2663 /* 2664 * Match on frag_data spec 0x0009 and last 0xfff9 2665 * means M is 1 and frag-offset is > 0. 2666 * This packet is fragment 2nd and onward, excluding last. 2667 * This is not yet supported in MLX5, return appropriate 2668 * error message. 2669 */ 2670 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN | 2671 RTE_IPV6_EHDR_MF_MASK) && 2672 frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2673 return rte_flow_error_set(error, ENOTSUP, 2674 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2675 last, "match on following " 2676 "fragments not supported"); 2677 /* 2678 * Match on frag_data spec 0x0008 and last 0xfff8 2679 * means M is 0 and frag-offset is > 0. 2680 * This packet is last fragment of fragmented packet. 2681 * This is not yet supported in MLX5, return appropriate 2682 * error message. 2683 */ 2684 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) && 2685 frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK)) 2686 return rte_flow_error_set(error, ENOTSUP, 2687 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2688 last, "match on last " 2689 "fragment not supported"); 2690 /* Other range values are invalid and rejected. */ 2691 return rte_flow_error_set(error, EINVAL, 2692 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2693 "specified range not supported"); 2694 } 2695 2696 /* 2697 * Validate ASO CT item. 2698 * 2699 * @param[in] dev 2700 * Pointer to the rte_eth_dev structure. 2701 * @param[in] item 2702 * Item specification. 2703 * @param[in] item_flags 2704 * Pointer to bit-fields that holds the items detected until now. 2705 * @param[out] error 2706 * Pointer to error structure. 2707 * 2708 * @return 2709 * 0 on success, a negative errno value otherwise and rte_errno is set. 2710 */ 2711 static int 2712 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev, 2713 const struct rte_flow_item *item, 2714 uint64_t *item_flags, 2715 struct rte_flow_error *error) 2716 { 2717 const struct rte_flow_item_conntrack *spec = item->spec; 2718 const struct rte_flow_item_conntrack *mask = item->mask; 2719 RTE_SET_USED(dev); 2720 uint32_t flags; 2721 2722 if (*item_flags & MLX5_FLOW_LAYER_ASO_CT) 2723 return rte_flow_error_set(error, EINVAL, 2724 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2725 "Only one CT is supported"); 2726 if (!mask) 2727 mask = &rte_flow_item_conntrack_mask; 2728 flags = spec->flags & mask->flags; 2729 if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) && 2730 ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) || 2731 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) || 2732 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))) 2733 return rte_flow_error_set(error, EINVAL, 2734 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2735 "Conflict status bits"); 2736 /* State change also needs to be considered. */ 2737 *item_flags |= MLX5_FLOW_LAYER_ASO_CT; 2738 return 0; 2739 } 2740 2741 /** 2742 * Validate the pop VLAN action. 2743 * 2744 * @param[in] dev 2745 * Pointer to the rte_eth_dev structure. 2746 * @param[in] action_flags 2747 * Holds the actions detected until now. 2748 * @param[in] action 2749 * Pointer to the pop vlan action. 2750 * @param[in] item_flags 2751 * The items found in this flow rule. 2752 * @param[in] attr 2753 * Pointer to flow attributes. 2754 * @param[out] error 2755 * Pointer to error structure. 2756 * 2757 * @return 2758 * 0 on success, a negative errno value otherwise and rte_errno is set. 2759 */ 2760 static int 2761 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev, 2762 uint64_t action_flags, 2763 const struct rte_flow_action *action, 2764 uint64_t item_flags, 2765 const struct rte_flow_attr *attr, 2766 struct rte_flow_error *error) 2767 { 2768 const struct mlx5_priv *priv = dev->data->dev_private; 2769 struct mlx5_dev_ctx_shared *sh = priv->sh; 2770 bool direction_error = false; 2771 2772 if (!priv->sh->pop_vlan_action) 2773 return rte_flow_error_set(error, ENOTSUP, 2774 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2775 NULL, 2776 "pop vlan action is not supported"); 2777 /* Pop VLAN is not supported in egress except for CX6 FDB mode. */ 2778 if (attr->transfer) { 2779 bool fdb_tx = priv->representor_id != UINT16_MAX; 2780 bool is_cx5 = sh->steering_format_version == 2781 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2782 2783 if (fdb_tx && is_cx5) 2784 direction_error = true; 2785 } else if (attr->egress) { 2786 direction_error = true; 2787 } 2788 if (direction_error) 2789 return rte_flow_error_set(error, ENOTSUP, 2790 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 2791 NULL, 2792 "pop vlan action not supported for egress"); 2793 if (action_flags & MLX5_FLOW_VLAN_ACTIONS) 2794 return rte_flow_error_set(error, ENOTSUP, 2795 RTE_FLOW_ERROR_TYPE_ACTION, action, 2796 "no support for multiple VLAN " 2797 "actions"); 2798 /* Pop VLAN with preceding Decap requires inner header with VLAN. */ 2799 if ((action_flags & MLX5_FLOW_ACTION_DECAP) && 2800 !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN)) 2801 return rte_flow_error_set(error, ENOTSUP, 2802 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2803 NULL, 2804 "cannot pop vlan after decap without " 2805 "match on inner vlan in the flow"); 2806 /* Pop VLAN without preceding Decap requires outer header with VLAN. */ 2807 if (!(action_flags & MLX5_FLOW_ACTION_DECAP) && 2808 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 2809 return rte_flow_error_set(error, ENOTSUP, 2810 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2811 NULL, 2812 "cannot pop vlan without a " 2813 "match on (outer) vlan in the flow"); 2814 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2815 return rte_flow_error_set(error, EINVAL, 2816 RTE_FLOW_ERROR_TYPE_ACTION, action, 2817 "wrong action order, port_id should " 2818 "be after pop VLAN action"); 2819 if (!attr->transfer && priv->representor) 2820 return rte_flow_error_set(error, ENOTSUP, 2821 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2822 "pop vlan action for VF representor " 2823 "not supported on NIC table"); 2824 return 0; 2825 } 2826 2827 /** 2828 * Get VLAN default info from vlan match info. 2829 * 2830 * @param[in] items 2831 * the list of item specifications. 2832 * @param[out] vlan 2833 * pointer VLAN info to fill to. 2834 * 2835 * @return 2836 * 0 on success, a negative errno value otherwise and rte_errno is set. 2837 */ 2838 static void 2839 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items, 2840 struct rte_vlan_hdr *vlan) 2841 { 2842 const struct rte_flow_item_vlan nic_mask = { 2843 .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK | 2844 MLX5DV_FLOW_VLAN_VID_MASK), 2845 .inner_type = RTE_BE16(0xffff), 2846 }; 2847 2848 if (items == NULL) 2849 return; 2850 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 2851 int type = items->type; 2852 2853 if (type == RTE_FLOW_ITEM_TYPE_VLAN || 2854 type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN) 2855 break; 2856 } 2857 if (items->type != RTE_FLOW_ITEM_TYPE_END) { 2858 const struct rte_flow_item_vlan *vlan_m = items->mask; 2859 const struct rte_flow_item_vlan *vlan_v = items->spec; 2860 2861 /* If VLAN item in pattern doesn't contain data, return here. */ 2862 if (!vlan_v) 2863 return; 2864 if (!vlan_m) 2865 vlan_m = &nic_mask; 2866 /* Only full match values are accepted */ 2867 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) == 2868 MLX5DV_FLOW_VLAN_PCP_MASK_BE) { 2869 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 2870 vlan->vlan_tci |= 2871 rte_be_to_cpu_16(vlan_v->tci & 2872 MLX5DV_FLOW_VLAN_PCP_MASK_BE); 2873 } 2874 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) == 2875 MLX5DV_FLOW_VLAN_VID_MASK_BE) { 2876 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 2877 vlan->vlan_tci |= 2878 rte_be_to_cpu_16(vlan_v->tci & 2879 MLX5DV_FLOW_VLAN_VID_MASK_BE); 2880 } 2881 if (vlan_m->inner_type == nic_mask.inner_type) 2882 vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type & 2883 vlan_m->inner_type); 2884 } 2885 } 2886 2887 /** 2888 * Validate the push VLAN action. 2889 * 2890 * @param[in] dev 2891 * Pointer to the rte_eth_dev structure. 2892 * @param[in] action_flags 2893 * Holds the actions detected until now. 2894 * @param[in] item_flags 2895 * The items found in this flow rule. 2896 * @param[in] action 2897 * Pointer to the action structure. 2898 * @param[in] attr 2899 * Pointer to flow attributes 2900 * @param[out] error 2901 * Pointer to error structure. 2902 * 2903 * @return 2904 * 0 on success, a negative errno value otherwise and rte_errno is set. 2905 */ 2906 static int 2907 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev, 2908 uint64_t action_flags, 2909 const struct rte_flow_item_vlan *vlan_m, 2910 const struct rte_flow_action *action, 2911 const struct rte_flow_attr *attr, 2912 struct rte_flow_error *error) 2913 { 2914 const struct rte_flow_action_of_push_vlan *push_vlan = action->conf; 2915 const struct mlx5_priv *priv = dev->data->dev_private; 2916 struct mlx5_dev_ctx_shared *sh = priv->sh; 2917 bool direction_error = false; 2918 2919 if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && 2920 push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) 2921 return rte_flow_error_set(error, EINVAL, 2922 RTE_FLOW_ERROR_TYPE_ACTION, action, 2923 "invalid vlan ethertype"); 2924 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2925 return rte_flow_error_set(error, EINVAL, 2926 RTE_FLOW_ERROR_TYPE_ACTION, action, 2927 "wrong action order, port_id should " 2928 "be after push VLAN"); 2929 /* Push VLAN is not supported in ingress except for CX6 FDB mode. */ 2930 if (attr->transfer) { 2931 bool fdb_tx = priv->representor_id != UINT16_MAX; 2932 bool is_cx5 = sh->steering_format_version == 2933 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2934 2935 if (!fdb_tx && is_cx5) 2936 direction_error = true; 2937 } else if (attr->ingress) { 2938 direction_error = true; 2939 } 2940 if (direction_error) 2941 return rte_flow_error_set(error, ENOTSUP, 2942 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 2943 NULL, 2944 "push vlan action not supported for ingress"); 2945 if (!attr->transfer && priv->representor) 2946 return rte_flow_error_set(error, ENOTSUP, 2947 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2948 "push vlan action for VF representor " 2949 "not supported on NIC table"); 2950 if (vlan_m && 2951 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) && 2952 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) != 2953 MLX5DV_FLOW_VLAN_PCP_MASK_BE && 2954 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) && 2955 !(mlx5_flow_find_action 2956 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP))) 2957 return rte_flow_error_set(error, EINVAL, 2958 RTE_FLOW_ERROR_TYPE_ACTION, action, 2959 "not full match mask on VLAN PCP and " 2960 "there is no of_set_vlan_pcp action, " 2961 "push VLAN action cannot figure out " 2962 "PCP value"); 2963 if (vlan_m && 2964 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) && 2965 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) != 2966 MLX5DV_FLOW_VLAN_VID_MASK_BE && 2967 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) && 2968 !(mlx5_flow_find_action 2969 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))) 2970 return rte_flow_error_set(error, EINVAL, 2971 RTE_FLOW_ERROR_TYPE_ACTION, action, 2972 "not full match mask on VLAN VID and " 2973 "there is no of_set_vlan_vid action, " 2974 "push VLAN action cannot figure out " 2975 "VID value"); 2976 (void)attr; 2977 return 0; 2978 } 2979 2980 /** 2981 * Validate the set VLAN PCP. 2982 * 2983 * @param[in] action_flags 2984 * Holds the actions detected until now. 2985 * @param[in] actions 2986 * Pointer to the list of actions remaining in the flow rule. 2987 * @param[out] error 2988 * Pointer to error structure. 2989 * 2990 * @return 2991 * 0 on success, a negative errno value otherwise and rte_errno is set. 2992 */ 2993 static int 2994 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags, 2995 const struct rte_flow_action actions[], 2996 struct rte_flow_error *error) 2997 { 2998 const struct rte_flow_action *action = actions; 2999 const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf; 3000 3001 if (conf->vlan_pcp > 7) 3002 return rte_flow_error_set(error, EINVAL, 3003 RTE_FLOW_ERROR_TYPE_ACTION, action, 3004 "VLAN PCP value is too big"); 3005 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)) 3006 return rte_flow_error_set(error, ENOTSUP, 3007 RTE_FLOW_ERROR_TYPE_ACTION, action, 3008 "set VLAN PCP action must follow " 3009 "the push VLAN action"); 3010 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) 3011 return rte_flow_error_set(error, ENOTSUP, 3012 RTE_FLOW_ERROR_TYPE_ACTION, action, 3013 "Multiple VLAN PCP modification are " 3014 "not supported"); 3015 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3016 return rte_flow_error_set(error, EINVAL, 3017 RTE_FLOW_ERROR_TYPE_ACTION, action, 3018 "wrong action order, port_id should " 3019 "be after set VLAN PCP"); 3020 return 0; 3021 } 3022 3023 /** 3024 * Validate the set VLAN VID. 3025 * 3026 * @param[in] item_flags 3027 * Holds the items detected in this rule. 3028 * @param[in] action_flags 3029 * Holds the actions detected until now. 3030 * @param[in] actions 3031 * Pointer to the list of actions remaining in the flow rule. 3032 * @param[out] error 3033 * Pointer to error structure. 3034 * 3035 * @return 3036 * 0 on success, a negative errno value otherwise and rte_errno is set. 3037 */ 3038 static int 3039 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags, 3040 uint64_t action_flags, 3041 const struct rte_flow_action actions[], 3042 struct rte_flow_error *error) 3043 { 3044 const struct rte_flow_action *action = actions; 3045 const struct rte_flow_action_of_set_vlan_vid *conf = action->conf; 3046 3047 if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE) 3048 return rte_flow_error_set(error, EINVAL, 3049 RTE_FLOW_ERROR_TYPE_ACTION, action, 3050 "VLAN VID value is too big"); 3051 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) && 3052 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 3053 return rte_flow_error_set(error, ENOTSUP, 3054 RTE_FLOW_ERROR_TYPE_ACTION, action, 3055 "set VLAN VID action must follow push" 3056 " VLAN action or match on VLAN item"); 3057 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) 3058 return rte_flow_error_set(error, ENOTSUP, 3059 RTE_FLOW_ERROR_TYPE_ACTION, action, 3060 "Multiple VLAN VID modifications are " 3061 "not supported"); 3062 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3063 return rte_flow_error_set(error, EINVAL, 3064 RTE_FLOW_ERROR_TYPE_ACTION, action, 3065 "wrong action order, port_id should " 3066 "be after set VLAN VID"); 3067 return 0; 3068 } 3069 3070 /* 3071 * Validate the FLAG action. 3072 * 3073 * @param[in] dev 3074 * Pointer to the rte_eth_dev structure. 3075 * @param[in] action_flags 3076 * Holds the actions detected until now. 3077 * @param[in] attr 3078 * Pointer to flow attributes 3079 * @param[out] error 3080 * Pointer to error structure. 3081 * 3082 * @return 3083 * 0 on success, a negative errno value otherwise and rte_errno is set. 3084 */ 3085 static int 3086 flow_dv_validate_action_flag(struct rte_eth_dev *dev, 3087 uint64_t action_flags, 3088 const struct rte_flow_attr *attr, 3089 struct rte_flow_error *error) 3090 { 3091 struct mlx5_priv *priv = dev->data->dev_private; 3092 struct mlx5_dev_config *config = &priv->config; 3093 int ret; 3094 3095 /* Fall back if no extended metadata register support. */ 3096 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3097 return mlx5_flow_validate_action_flag(action_flags, attr, 3098 error); 3099 /* Extensive metadata mode requires registers. */ 3100 if (!mlx5_flow_ext_mreg_supported(dev)) 3101 return rte_flow_error_set(error, ENOTSUP, 3102 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3103 "no metadata registers " 3104 "to support flag action"); 3105 if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT)) 3106 return rte_flow_error_set(error, ENOTSUP, 3107 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3108 "extended metadata register" 3109 " isn't available"); 3110 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3111 if (ret < 0) 3112 return ret; 3113 MLX5_ASSERT(ret > 0); 3114 if (action_flags & MLX5_FLOW_ACTION_MARK) 3115 return rte_flow_error_set(error, EINVAL, 3116 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3117 "can't mark and flag in same flow"); 3118 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3119 return rte_flow_error_set(error, EINVAL, 3120 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3121 "can't have 2 flag" 3122 " actions in same flow"); 3123 return 0; 3124 } 3125 3126 /** 3127 * Validate MARK action. 3128 * 3129 * @param[in] dev 3130 * Pointer to the rte_eth_dev structure. 3131 * @param[in] action 3132 * Pointer to action. 3133 * @param[in] action_flags 3134 * Holds the actions detected until now. 3135 * @param[in] attr 3136 * Pointer to flow attributes 3137 * @param[out] error 3138 * Pointer to error structure. 3139 * 3140 * @return 3141 * 0 on success, a negative errno value otherwise and rte_errno is set. 3142 */ 3143 static int 3144 flow_dv_validate_action_mark(struct rte_eth_dev *dev, 3145 const struct rte_flow_action *action, 3146 uint64_t action_flags, 3147 const struct rte_flow_attr *attr, 3148 struct rte_flow_error *error) 3149 { 3150 struct mlx5_priv *priv = dev->data->dev_private; 3151 struct mlx5_dev_config *config = &priv->config; 3152 const struct rte_flow_action_mark *mark = action->conf; 3153 int ret; 3154 3155 if (is_tunnel_offload_active(dev)) 3156 return rte_flow_error_set(error, ENOTSUP, 3157 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3158 "no mark action " 3159 "if tunnel offload active"); 3160 /* Fall back if no extended metadata register support. */ 3161 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3162 return mlx5_flow_validate_action_mark(action, action_flags, 3163 attr, error); 3164 /* Extensive metadata mode requires registers. */ 3165 if (!mlx5_flow_ext_mreg_supported(dev)) 3166 return rte_flow_error_set(error, ENOTSUP, 3167 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3168 "no metadata registers " 3169 "to support mark action"); 3170 if (!priv->sh->dv_mark_mask) 3171 return rte_flow_error_set(error, ENOTSUP, 3172 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3173 "extended metadata register" 3174 " isn't available"); 3175 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3176 if (ret < 0) 3177 return ret; 3178 MLX5_ASSERT(ret > 0); 3179 if (!mark) 3180 return rte_flow_error_set(error, EINVAL, 3181 RTE_FLOW_ERROR_TYPE_ACTION, action, 3182 "configuration cannot be null"); 3183 if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask)) 3184 return rte_flow_error_set(error, EINVAL, 3185 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 3186 &mark->id, 3187 "mark id exceeds the limit"); 3188 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3189 return rte_flow_error_set(error, EINVAL, 3190 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3191 "can't flag and mark in same flow"); 3192 if (action_flags & MLX5_FLOW_ACTION_MARK) 3193 return rte_flow_error_set(error, EINVAL, 3194 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3195 "can't have 2 mark actions in same" 3196 " flow"); 3197 return 0; 3198 } 3199 3200 /** 3201 * Validate SET_META action. 3202 * 3203 * @param[in] dev 3204 * Pointer to the rte_eth_dev structure. 3205 * @param[in] action 3206 * Pointer to the action structure. 3207 * @param[in] action_flags 3208 * Holds the actions detected until now. 3209 * @param[in] attr 3210 * Pointer to flow attributes 3211 * @param[out] error 3212 * Pointer to error structure. 3213 * 3214 * @return 3215 * 0 on success, a negative errno value otherwise and rte_errno is set. 3216 */ 3217 static int 3218 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev, 3219 const struct rte_flow_action *action, 3220 uint64_t action_flags __rte_unused, 3221 const struct rte_flow_attr *attr, 3222 struct rte_flow_error *error) 3223 { 3224 const struct rte_flow_action_set_meta *conf; 3225 uint32_t nic_mask = UINT32_MAX; 3226 int reg; 3227 3228 if (!mlx5_flow_ext_mreg_supported(dev)) 3229 return rte_flow_error_set(error, ENOTSUP, 3230 RTE_FLOW_ERROR_TYPE_ACTION, action, 3231 "extended metadata register" 3232 " isn't supported"); 3233 reg = flow_dv_get_metadata_reg(dev, attr, error); 3234 if (reg < 0) 3235 return reg; 3236 if (reg == REG_NON) 3237 return rte_flow_error_set(error, ENOTSUP, 3238 RTE_FLOW_ERROR_TYPE_ACTION, action, 3239 "unavalable extended metadata register"); 3240 if (reg != REG_A && reg != REG_B) { 3241 struct mlx5_priv *priv = dev->data->dev_private; 3242 3243 nic_mask = priv->sh->dv_meta_mask; 3244 } 3245 if (!(action->conf)) 3246 return rte_flow_error_set(error, EINVAL, 3247 RTE_FLOW_ERROR_TYPE_ACTION, action, 3248 "configuration cannot be null"); 3249 conf = (const struct rte_flow_action_set_meta *)action->conf; 3250 if (!conf->mask) 3251 return rte_flow_error_set(error, EINVAL, 3252 RTE_FLOW_ERROR_TYPE_ACTION, action, 3253 "zero mask doesn't have any effect"); 3254 if (conf->mask & ~nic_mask) 3255 return rte_flow_error_set(error, EINVAL, 3256 RTE_FLOW_ERROR_TYPE_ACTION, action, 3257 "meta data must be within reg C0"); 3258 return 0; 3259 } 3260 3261 /** 3262 * Validate SET_TAG action. 3263 * 3264 * @param[in] dev 3265 * Pointer to the rte_eth_dev structure. 3266 * @param[in] action 3267 * Pointer to the action structure. 3268 * @param[in] action_flags 3269 * Holds the actions detected until now. 3270 * @param[in] attr 3271 * Pointer to flow attributes 3272 * @param[out] error 3273 * Pointer to error structure. 3274 * 3275 * @return 3276 * 0 on success, a negative errno value otherwise and rte_errno is set. 3277 */ 3278 static int 3279 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, 3280 const struct rte_flow_action *action, 3281 uint64_t action_flags, 3282 const struct rte_flow_attr *attr, 3283 struct rte_flow_error *error) 3284 { 3285 const struct rte_flow_action_set_tag *conf; 3286 const uint64_t terminal_action_flags = 3287 MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | 3288 MLX5_FLOW_ACTION_RSS; 3289 int ret; 3290 3291 if (!mlx5_flow_ext_mreg_supported(dev)) 3292 return rte_flow_error_set(error, ENOTSUP, 3293 RTE_FLOW_ERROR_TYPE_ACTION, action, 3294 "extensive metadata register" 3295 " isn't supported"); 3296 if (!(action->conf)) 3297 return rte_flow_error_set(error, EINVAL, 3298 RTE_FLOW_ERROR_TYPE_ACTION, action, 3299 "configuration cannot be null"); 3300 conf = (const struct rte_flow_action_set_tag *)action->conf; 3301 if (!conf->mask) 3302 return rte_flow_error_set(error, EINVAL, 3303 RTE_FLOW_ERROR_TYPE_ACTION, action, 3304 "zero mask doesn't have any effect"); 3305 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 3306 if (ret < 0) 3307 return ret; 3308 if (!attr->transfer && attr->ingress && 3309 (action_flags & terminal_action_flags)) 3310 return rte_flow_error_set(error, EINVAL, 3311 RTE_FLOW_ERROR_TYPE_ACTION, action, 3312 "set_tag has no effect" 3313 " with terminal actions"); 3314 return 0; 3315 } 3316 3317 /** 3318 * Check if action counter is shared by either old or new mechanism. 3319 * 3320 * @param[in] action 3321 * Pointer to the action structure. 3322 * 3323 * @return 3324 * True when counter is shared, false otherwise. 3325 */ 3326 static inline bool 3327 is_shared_action_count(const struct rte_flow_action *action) 3328 { 3329 const struct rte_flow_action_count *count = 3330 (const struct rte_flow_action_count *)action->conf; 3331 3332 if ((int)action->type == MLX5_RTE_FLOW_ACTION_TYPE_COUNT) 3333 return true; 3334 return !!(count && count->shared); 3335 } 3336 3337 /** 3338 * Validate count action. 3339 * 3340 * @param[in] dev 3341 * Pointer to rte_eth_dev structure. 3342 * @param[in] shared 3343 * Indicator if action is shared. 3344 * @param[in] action_flags 3345 * Holds the actions detected until now. 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_count(struct rte_eth_dev *dev, bool shared, 3354 uint64_t action_flags, 3355 struct rte_flow_error *error) 3356 { 3357 struct mlx5_priv *priv = dev->data->dev_private; 3358 3359 if (!priv->config.devx) 3360 goto notsup_err; 3361 if (action_flags & MLX5_FLOW_ACTION_COUNT) 3362 return rte_flow_error_set(error, EINVAL, 3363 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3364 "duplicate count actions set"); 3365 if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) && 3366 !priv->sh->flow_hit_aso_en) 3367 return rte_flow_error_set(error, EINVAL, 3368 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3369 "old age and shared count combination is not supported"); 3370 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 3371 return 0; 3372 #endif 3373 notsup_err: 3374 return rte_flow_error_set 3375 (error, ENOTSUP, 3376 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3377 NULL, 3378 "count action not supported"); 3379 } 3380 3381 /** 3382 * Validate the L2 encap action. 3383 * 3384 * @param[in] dev 3385 * Pointer to the rte_eth_dev structure. 3386 * @param[in] action_flags 3387 * Holds the actions detected until now. 3388 * @param[in] action 3389 * Pointer to the action structure. 3390 * @param[in] attr 3391 * Pointer to flow attributes. 3392 * @param[out] error 3393 * Pointer to error structure. 3394 * 3395 * @return 3396 * 0 on success, a negative errno value otherwise and rte_errno is set. 3397 */ 3398 static int 3399 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev, 3400 uint64_t action_flags, 3401 const struct rte_flow_action *action, 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 (!(action->conf)) 3408 return rte_flow_error_set(error, EINVAL, 3409 RTE_FLOW_ERROR_TYPE_ACTION, action, 3410 "configuration cannot be null"); 3411 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3412 return rte_flow_error_set(error, EINVAL, 3413 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3414 "can only have a single encap action " 3415 "in a flow"); 3416 if (!attr->transfer && priv->representor) 3417 return rte_flow_error_set(error, ENOTSUP, 3418 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3419 "encap action for VF representor " 3420 "not supported on NIC table"); 3421 return 0; 3422 } 3423 3424 /** 3425 * Validate a decap action. 3426 * 3427 * @param[in] dev 3428 * Pointer to the rte_eth_dev structure. 3429 * @param[in] action_flags 3430 * Holds the actions detected until now. 3431 * @param[in] action 3432 * Pointer to the action structure. 3433 * @param[in] item_flags 3434 * Holds the items detected. 3435 * @param[in] attr 3436 * Pointer to flow attributes 3437 * @param[out] error 3438 * Pointer to error structure. 3439 * 3440 * @return 3441 * 0 on success, a negative errno value otherwise and rte_errno is set. 3442 */ 3443 static int 3444 flow_dv_validate_action_decap(struct rte_eth_dev *dev, 3445 uint64_t action_flags, 3446 const struct rte_flow_action *action, 3447 const uint64_t item_flags, 3448 const struct rte_flow_attr *attr, 3449 struct rte_flow_error *error) 3450 { 3451 const struct mlx5_priv *priv = dev->data->dev_private; 3452 3453 if (priv->config.hca_attr.scatter_fcs_w_decap_disable && 3454 !priv->config.decap_en) 3455 return rte_flow_error_set(error, ENOTSUP, 3456 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3457 "decap is not enabled"); 3458 if (action_flags & MLX5_FLOW_XCAP_ACTIONS) 3459 return rte_flow_error_set(error, ENOTSUP, 3460 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3461 action_flags & 3462 MLX5_FLOW_ACTION_DECAP ? "can only " 3463 "have a single decap action" : "decap " 3464 "after encap is not supported"); 3465 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 3466 return rte_flow_error_set(error, EINVAL, 3467 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3468 "can't have decap action after" 3469 " modify action"); 3470 if (attr->egress) 3471 return rte_flow_error_set(error, ENOTSUP, 3472 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 3473 NULL, 3474 "decap action not supported for " 3475 "egress"); 3476 if (!attr->transfer && priv->representor) 3477 return rte_flow_error_set(error, ENOTSUP, 3478 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3479 "decap action for VF representor " 3480 "not supported on NIC table"); 3481 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP && 3482 !(item_flags & MLX5_FLOW_LAYER_VXLAN)) 3483 return rte_flow_error_set(error, ENOTSUP, 3484 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3485 "VXLAN item should be present for VXLAN decap"); 3486 return 0; 3487 } 3488 3489 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,}; 3490 3491 /** 3492 * Validate the raw encap and decap actions. 3493 * 3494 * @param[in] dev 3495 * Pointer to the rte_eth_dev structure. 3496 * @param[in] decap 3497 * Pointer to the decap action. 3498 * @param[in] encap 3499 * Pointer to the encap action. 3500 * @param[in] attr 3501 * Pointer to flow attributes 3502 * @param[in/out] action_flags 3503 * Holds the actions detected until now. 3504 * @param[out] actions_n 3505 * pointer to the number of actions counter. 3506 * @param[in] action 3507 * Pointer to the action structure. 3508 * @param[in] item_flags 3509 * Holds the items detected. 3510 * @param[out] error 3511 * Pointer to error structure. 3512 * 3513 * @return 3514 * 0 on success, a negative errno value otherwise and rte_errno is set. 3515 */ 3516 static int 3517 flow_dv_validate_action_raw_encap_decap 3518 (struct rte_eth_dev *dev, 3519 const struct rte_flow_action_raw_decap *decap, 3520 const struct rte_flow_action_raw_encap *encap, 3521 const struct rte_flow_attr *attr, uint64_t *action_flags, 3522 int *actions_n, const struct rte_flow_action *action, 3523 uint64_t item_flags, struct rte_flow_error *error) 3524 { 3525 const struct mlx5_priv *priv = dev->data->dev_private; 3526 int ret; 3527 3528 if (encap && (!encap->size || !encap->data)) 3529 return rte_flow_error_set(error, EINVAL, 3530 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3531 "raw encap data cannot be empty"); 3532 if (decap && encap) { 3533 if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE && 3534 encap->size > MLX5_ENCAPSULATION_DECISION_SIZE) 3535 /* L3 encap. */ 3536 decap = NULL; 3537 else if (encap->size <= 3538 MLX5_ENCAPSULATION_DECISION_SIZE && 3539 decap->size > 3540 MLX5_ENCAPSULATION_DECISION_SIZE) 3541 /* L3 decap. */ 3542 encap = NULL; 3543 else if (encap->size > 3544 MLX5_ENCAPSULATION_DECISION_SIZE && 3545 decap->size > 3546 MLX5_ENCAPSULATION_DECISION_SIZE) 3547 /* 2 L2 actions: encap and decap. */ 3548 ; 3549 else 3550 return rte_flow_error_set(error, 3551 ENOTSUP, 3552 RTE_FLOW_ERROR_TYPE_ACTION, 3553 NULL, "unsupported too small " 3554 "raw decap and too small raw " 3555 "encap combination"); 3556 } 3557 if (decap) { 3558 ret = flow_dv_validate_action_decap(dev, *action_flags, action, 3559 item_flags, attr, error); 3560 if (ret < 0) 3561 return ret; 3562 *action_flags |= MLX5_FLOW_ACTION_DECAP; 3563 ++(*actions_n); 3564 } 3565 if (encap) { 3566 if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE) 3567 return rte_flow_error_set(error, ENOTSUP, 3568 RTE_FLOW_ERROR_TYPE_ACTION, 3569 NULL, 3570 "small raw encap size"); 3571 if (*action_flags & MLX5_FLOW_ACTION_ENCAP) 3572 return rte_flow_error_set(error, EINVAL, 3573 RTE_FLOW_ERROR_TYPE_ACTION, 3574 NULL, 3575 "more than one encap action"); 3576 if (!attr->transfer && priv->representor) 3577 return rte_flow_error_set 3578 (error, ENOTSUP, 3579 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3580 "encap action for VF representor " 3581 "not supported on NIC table"); 3582 *action_flags |= MLX5_FLOW_ACTION_ENCAP; 3583 ++(*actions_n); 3584 } 3585 return 0; 3586 } 3587 3588 /* 3589 * Validate the ASO CT action. 3590 * 3591 * @param[in] dev 3592 * Pointer to the rte_eth_dev structure. 3593 * @param[in] action_flags 3594 * Holds the actions detected until now. 3595 * @param[in] item_flags 3596 * The items found in this flow rule. 3597 * @param[in] attr 3598 * Pointer to flow attributes. 3599 * @param[out] error 3600 * Pointer to error structure. 3601 * 3602 * @return 3603 * 0 on success, a negative errno value otherwise and rte_errno is set. 3604 */ 3605 static int 3606 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, 3607 uint64_t action_flags, 3608 uint64_t item_flags, 3609 const struct rte_flow_attr *attr, 3610 struct rte_flow_error *error) 3611 { 3612 RTE_SET_USED(dev); 3613 3614 if (attr->group == 0 && !attr->transfer) 3615 return rte_flow_error_set(error, ENOTSUP, 3616 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3617 NULL, 3618 "Only support non-root table"); 3619 if (action_flags & MLX5_FLOW_FATE_ACTIONS) 3620 return rte_flow_error_set(error, ENOTSUP, 3621 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3622 "CT cannot follow a fate action"); 3623 if ((action_flags & MLX5_FLOW_ACTION_METER) || 3624 (action_flags & MLX5_FLOW_ACTION_AGE)) 3625 return rte_flow_error_set(error, EINVAL, 3626 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3627 "Only one ASO action is supported"); 3628 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3629 return rte_flow_error_set(error, EINVAL, 3630 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3631 "Encap cannot exist before CT"); 3632 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP)) 3633 return rte_flow_error_set(error, EINVAL, 3634 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3635 "Not a outer TCP packet"); 3636 return 0; 3637 } 3638 3639 int 3640 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused, 3641 struct mlx5_list_entry *entry, void *cb_ctx) 3642 { 3643 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3644 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3645 struct mlx5_flow_dv_encap_decap_resource *resource; 3646 3647 resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource, 3648 entry); 3649 if (resource->reformat_type == ctx_resource->reformat_type && 3650 resource->ft_type == ctx_resource->ft_type && 3651 resource->flags == ctx_resource->flags && 3652 resource->size == ctx_resource->size && 3653 !memcmp((const void *)resource->buf, 3654 (const void *)ctx_resource->buf, 3655 resource->size)) 3656 return 0; 3657 return -1; 3658 } 3659 3660 struct mlx5_list_entry * 3661 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx) 3662 { 3663 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3664 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3665 struct mlx5dv_dr_domain *domain; 3666 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3667 struct mlx5_flow_dv_encap_decap_resource *resource; 3668 uint32_t idx; 3669 int ret; 3670 3671 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3672 domain = sh->fdb_domain; 3673 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3674 domain = sh->rx_domain; 3675 else 3676 domain = sh->tx_domain; 3677 /* Register new encap/decap resource. */ 3678 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx); 3679 if (!resource) { 3680 rte_flow_error_set(ctx->error, ENOMEM, 3681 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3682 "cannot allocate resource memory"); 3683 return NULL; 3684 } 3685 *resource = *ctx_resource; 3686 resource->idx = idx; 3687 ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->ctx, domain, 3688 resource, 3689 &resource->action); 3690 if (ret) { 3691 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx); 3692 rte_flow_error_set(ctx->error, ENOMEM, 3693 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3694 NULL, "cannot create action"); 3695 return NULL; 3696 } 3697 3698 return &resource->entry; 3699 } 3700 3701 struct mlx5_list_entry * 3702 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 3703 void *cb_ctx) 3704 { 3705 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3706 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3707 struct mlx5_flow_dv_encap_decap_resource *cache_resource; 3708 uint32_t idx; 3709 3710 cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 3711 &idx); 3712 if (!cache_resource) { 3713 rte_flow_error_set(ctx->error, ENOMEM, 3714 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3715 "cannot allocate resource memory"); 3716 return NULL; 3717 } 3718 memcpy(cache_resource, oentry, sizeof(*cache_resource)); 3719 cache_resource->idx = idx; 3720 return &cache_resource->entry; 3721 } 3722 3723 void 3724 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3725 { 3726 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3727 struct mlx5_flow_dv_encap_decap_resource *res = 3728 container_of(entry, typeof(*res), entry); 3729 3730 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 3731 } 3732 3733 /** 3734 * Find existing encap/decap resource or create and register a new one. 3735 * 3736 * @param[in, out] dev 3737 * Pointer to rte_eth_dev structure. 3738 * @param[in, out] resource 3739 * Pointer to encap/decap resource. 3740 * @parm[in, out] dev_flow 3741 * Pointer to the dev_flow. 3742 * @param[out] error 3743 * pointer to error structure. 3744 * 3745 * @return 3746 * 0 on success otherwise -errno and errno is set. 3747 */ 3748 static int 3749 flow_dv_encap_decap_resource_register 3750 (struct rte_eth_dev *dev, 3751 struct mlx5_flow_dv_encap_decap_resource *resource, 3752 struct mlx5_flow *dev_flow, 3753 struct rte_flow_error *error) 3754 { 3755 struct mlx5_priv *priv = dev->data->dev_private; 3756 struct mlx5_dev_ctx_shared *sh = priv->sh; 3757 struct mlx5_list_entry *entry; 3758 union { 3759 struct { 3760 uint32_t ft_type:8; 3761 uint32_t refmt_type:8; 3762 /* 3763 * Header reformat actions can be shared between 3764 * non-root tables. One bit to indicate non-root 3765 * table or not. 3766 */ 3767 uint32_t is_root:1; 3768 uint32_t reserve:15; 3769 }; 3770 uint32_t v32; 3771 } encap_decap_key = { 3772 { 3773 .ft_type = resource->ft_type, 3774 .refmt_type = resource->reformat_type, 3775 .is_root = !!dev_flow->dv.group, 3776 .reserve = 0, 3777 } 3778 }; 3779 struct mlx5_flow_cb_ctx ctx = { 3780 .error = error, 3781 .data = resource, 3782 }; 3783 struct mlx5_hlist *encaps_decaps; 3784 uint64_t key64; 3785 3786 encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps, 3787 "encaps_decaps", 3788 MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ, 3789 true, true, sh, 3790 flow_dv_encap_decap_create_cb, 3791 flow_dv_encap_decap_match_cb, 3792 flow_dv_encap_decap_remove_cb, 3793 flow_dv_encap_decap_clone_cb, 3794 flow_dv_encap_decap_clone_free_cb); 3795 if (unlikely(!encaps_decaps)) 3796 return -rte_errno; 3797 resource->flags = dev_flow->dv.group ? 0 : 1; 3798 key64 = __rte_raw_cksum(&encap_decap_key.v32, 3799 sizeof(encap_decap_key.v32), 0); 3800 if (resource->reformat_type != 3801 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 && 3802 resource->size) 3803 key64 = __rte_raw_cksum(resource->buf, resource->size, key64); 3804 entry = mlx5_hlist_register(encaps_decaps, key64, &ctx); 3805 if (!entry) 3806 return -rte_errno; 3807 resource = container_of(entry, typeof(*resource), entry); 3808 dev_flow->dv.encap_decap = resource; 3809 dev_flow->handle->dvh.rix_encap_decap = resource->idx; 3810 return 0; 3811 } 3812 3813 /** 3814 * Find existing table jump resource or create and register a new one. 3815 * 3816 * @param[in, out] dev 3817 * Pointer to rte_eth_dev structure. 3818 * @param[in, out] tbl 3819 * Pointer to flow table resource. 3820 * @parm[in, out] dev_flow 3821 * Pointer to the dev_flow. 3822 * @param[out] error 3823 * pointer to error structure. 3824 * 3825 * @return 3826 * 0 on success otherwise -errno and errno is set. 3827 */ 3828 static int 3829 flow_dv_jump_tbl_resource_register 3830 (struct rte_eth_dev *dev __rte_unused, 3831 struct mlx5_flow_tbl_resource *tbl, 3832 struct mlx5_flow *dev_flow, 3833 struct rte_flow_error *error __rte_unused) 3834 { 3835 struct mlx5_flow_tbl_data_entry *tbl_data = 3836 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 3837 3838 MLX5_ASSERT(tbl); 3839 MLX5_ASSERT(tbl_data->jump.action); 3840 dev_flow->handle->rix_jump = tbl_data->idx; 3841 dev_flow->dv.jump = &tbl_data->jump; 3842 return 0; 3843 } 3844 3845 int 3846 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused, 3847 struct mlx5_list_entry *entry, void *cb_ctx) 3848 { 3849 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3850 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3851 struct mlx5_flow_dv_port_id_action_resource *res = 3852 container_of(entry, typeof(*res), entry); 3853 3854 return ref->port_id != res->port_id; 3855 } 3856 3857 struct mlx5_list_entry * 3858 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx) 3859 { 3860 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3861 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3862 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3863 struct mlx5_flow_dv_port_id_action_resource *resource; 3864 uint32_t idx; 3865 int ret; 3866 3867 /* Register new port id action resource. */ 3868 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3869 if (!resource) { 3870 rte_flow_error_set(ctx->error, ENOMEM, 3871 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3872 "cannot allocate port_id action memory"); 3873 return NULL; 3874 } 3875 *resource = *ref; 3876 ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain, 3877 ref->port_id, 3878 &resource->action); 3879 if (ret) { 3880 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx); 3881 rte_flow_error_set(ctx->error, ENOMEM, 3882 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3883 "cannot create action"); 3884 return NULL; 3885 } 3886 resource->idx = idx; 3887 return &resource->entry; 3888 } 3889 3890 struct mlx5_list_entry * 3891 flow_dv_port_id_clone_cb(void *tool_ctx, 3892 struct mlx5_list_entry *entry __rte_unused, 3893 void *cb_ctx) 3894 { 3895 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3896 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3897 struct mlx5_flow_dv_port_id_action_resource *resource; 3898 uint32_t idx; 3899 3900 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3901 if (!resource) { 3902 rte_flow_error_set(ctx->error, ENOMEM, 3903 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3904 "cannot allocate port_id action memory"); 3905 return NULL; 3906 } 3907 memcpy(resource, entry, sizeof(*resource)); 3908 resource->idx = idx; 3909 return &resource->entry; 3910 } 3911 3912 void 3913 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3914 { 3915 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3916 struct mlx5_flow_dv_port_id_action_resource *resource = 3917 container_of(entry, typeof(*resource), entry); 3918 3919 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 3920 } 3921 3922 /** 3923 * Find existing table port ID resource or create and register a new one. 3924 * 3925 * @param[in, out] dev 3926 * Pointer to rte_eth_dev structure. 3927 * @param[in, out] ref 3928 * Pointer to port ID action resource reference. 3929 * @parm[in, out] dev_flow 3930 * Pointer to the dev_flow. 3931 * @param[out] error 3932 * pointer to error structure. 3933 * 3934 * @return 3935 * 0 on success otherwise -errno and errno is set. 3936 */ 3937 static int 3938 flow_dv_port_id_action_resource_register 3939 (struct rte_eth_dev *dev, 3940 struct mlx5_flow_dv_port_id_action_resource *ref, 3941 struct mlx5_flow *dev_flow, 3942 struct rte_flow_error *error) 3943 { 3944 struct mlx5_priv *priv = dev->data->dev_private; 3945 struct mlx5_list_entry *entry; 3946 struct mlx5_flow_dv_port_id_action_resource *resource; 3947 struct mlx5_flow_cb_ctx ctx = { 3948 .error = error, 3949 .data = ref, 3950 }; 3951 3952 entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx); 3953 if (!entry) 3954 return -rte_errno; 3955 resource = container_of(entry, typeof(*resource), entry); 3956 dev_flow->dv.port_id_action = resource; 3957 dev_flow->handle->rix_port_id_action = resource->idx; 3958 return 0; 3959 } 3960 3961 int 3962 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused, 3963 struct mlx5_list_entry *entry, void *cb_ctx) 3964 { 3965 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3966 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3967 struct mlx5_flow_dv_push_vlan_action_resource *res = 3968 container_of(entry, typeof(*res), entry); 3969 3970 return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type; 3971 } 3972 3973 struct mlx5_list_entry * 3974 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx) 3975 { 3976 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3977 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3978 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3979 struct mlx5_flow_dv_push_vlan_action_resource *resource; 3980 struct mlx5dv_dr_domain *domain; 3981 uint32_t idx; 3982 int ret; 3983 3984 /* Register new port id action resource. */ 3985 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 3986 if (!resource) { 3987 rte_flow_error_set(ctx->error, ENOMEM, 3988 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3989 "cannot allocate push_vlan action memory"); 3990 return NULL; 3991 } 3992 *resource = *ref; 3993 if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3994 domain = sh->fdb_domain; 3995 else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3996 domain = sh->rx_domain; 3997 else 3998 domain = sh->tx_domain; 3999 ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag, 4000 &resource->action); 4001 if (ret) { 4002 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 4003 rte_flow_error_set(ctx->error, ENOMEM, 4004 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4005 "cannot create push vlan action"); 4006 return NULL; 4007 } 4008 resource->idx = idx; 4009 return &resource->entry; 4010 } 4011 4012 struct mlx5_list_entry * 4013 flow_dv_push_vlan_clone_cb(void *tool_ctx, 4014 struct mlx5_list_entry *entry __rte_unused, 4015 void *cb_ctx) 4016 { 4017 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4018 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 4019 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4020 uint32_t idx; 4021 4022 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 4023 if (!resource) { 4024 rte_flow_error_set(ctx->error, ENOMEM, 4025 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4026 "cannot allocate push_vlan action memory"); 4027 return NULL; 4028 } 4029 memcpy(resource, entry, sizeof(*resource)); 4030 resource->idx = idx; 4031 return &resource->entry; 4032 } 4033 4034 void 4035 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 4036 { 4037 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4038 struct mlx5_flow_dv_push_vlan_action_resource *resource = 4039 container_of(entry, typeof(*resource), entry); 4040 4041 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 4042 } 4043 4044 /** 4045 * Find existing push vlan resource or create and register a new one. 4046 * 4047 * @param [in, out] dev 4048 * Pointer to rte_eth_dev structure. 4049 * @param[in, out] ref 4050 * Pointer to port ID action resource reference. 4051 * @parm[in, out] dev_flow 4052 * Pointer to the dev_flow. 4053 * @param[out] error 4054 * pointer to error structure. 4055 * 4056 * @return 4057 * 0 on success otherwise -errno and errno is set. 4058 */ 4059 static int 4060 flow_dv_push_vlan_action_resource_register 4061 (struct rte_eth_dev *dev, 4062 struct mlx5_flow_dv_push_vlan_action_resource *ref, 4063 struct mlx5_flow *dev_flow, 4064 struct rte_flow_error *error) 4065 { 4066 struct mlx5_priv *priv = dev->data->dev_private; 4067 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4068 struct mlx5_list_entry *entry; 4069 struct mlx5_flow_cb_ctx ctx = { 4070 .error = error, 4071 .data = ref, 4072 }; 4073 4074 entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx); 4075 if (!entry) 4076 return -rte_errno; 4077 resource = container_of(entry, typeof(*resource), entry); 4078 4079 dev_flow->handle->dvh.rix_push_vlan = resource->idx; 4080 dev_flow->dv.push_vlan_res = resource; 4081 return 0; 4082 } 4083 4084 /** 4085 * Get the size of specific rte_flow_item_type hdr size 4086 * 4087 * @param[in] item_type 4088 * Tested rte_flow_item_type. 4089 * 4090 * @return 4091 * sizeof struct item_type, 0 if void or irrelevant. 4092 */ 4093 static size_t 4094 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type) 4095 { 4096 size_t retval; 4097 4098 switch (item_type) { 4099 case RTE_FLOW_ITEM_TYPE_ETH: 4100 retval = sizeof(struct rte_ether_hdr); 4101 break; 4102 case RTE_FLOW_ITEM_TYPE_VLAN: 4103 retval = sizeof(struct rte_vlan_hdr); 4104 break; 4105 case RTE_FLOW_ITEM_TYPE_IPV4: 4106 retval = sizeof(struct rte_ipv4_hdr); 4107 break; 4108 case RTE_FLOW_ITEM_TYPE_IPV6: 4109 retval = sizeof(struct rte_ipv6_hdr); 4110 break; 4111 case RTE_FLOW_ITEM_TYPE_UDP: 4112 retval = sizeof(struct rte_udp_hdr); 4113 break; 4114 case RTE_FLOW_ITEM_TYPE_TCP: 4115 retval = sizeof(struct rte_tcp_hdr); 4116 break; 4117 case RTE_FLOW_ITEM_TYPE_VXLAN: 4118 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4119 retval = sizeof(struct rte_vxlan_hdr); 4120 break; 4121 case RTE_FLOW_ITEM_TYPE_GRE: 4122 case RTE_FLOW_ITEM_TYPE_NVGRE: 4123 retval = sizeof(struct rte_gre_hdr); 4124 break; 4125 case RTE_FLOW_ITEM_TYPE_MPLS: 4126 retval = sizeof(struct rte_mpls_hdr); 4127 break; 4128 case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */ 4129 default: 4130 retval = 0; 4131 break; 4132 } 4133 return retval; 4134 } 4135 4136 #define MLX5_ENCAP_IPV4_VERSION 0x40 4137 #define MLX5_ENCAP_IPV4_IHL_MIN 0x05 4138 #define MLX5_ENCAP_IPV4_TTL_DEF 0x40 4139 #define MLX5_ENCAP_IPV6_VTC_FLOW 0x60000000 4140 #define MLX5_ENCAP_IPV6_HOP_LIMIT 0xff 4141 #define MLX5_ENCAP_VXLAN_FLAGS 0x08000000 4142 #define MLX5_ENCAP_VXLAN_GPE_FLAGS 0x04 4143 4144 /** 4145 * Convert the encap action data from list of rte_flow_item to raw buffer 4146 * 4147 * @param[in] items 4148 * Pointer to rte_flow_item objects list. 4149 * @param[out] buf 4150 * Pointer to the output buffer. 4151 * @param[out] size 4152 * Pointer to the output buffer size. 4153 * @param[out] error 4154 * Pointer to the error structure. 4155 * 4156 * @return 4157 * 0 on success, a negative errno value otherwise and rte_errno is set. 4158 */ 4159 static int 4160 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf, 4161 size_t *size, struct rte_flow_error *error) 4162 { 4163 struct rte_ether_hdr *eth = NULL; 4164 struct rte_vlan_hdr *vlan = NULL; 4165 struct rte_ipv4_hdr *ipv4 = NULL; 4166 struct rte_ipv6_hdr *ipv6 = NULL; 4167 struct rte_udp_hdr *udp = NULL; 4168 struct rte_vxlan_hdr *vxlan = NULL; 4169 struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL; 4170 struct rte_gre_hdr *gre = NULL; 4171 size_t len; 4172 size_t temp_size = 0; 4173 4174 if (!items) 4175 return rte_flow_error_set(error, EINVAL, 4176 RTE_FLOW_ERROR_TYPE_ACTION, 4177 NULL, "invalid empty data"); 4178 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 4179 len = flow_dv_get_item_hdr_len(items->type); 4180 if (len + temp_size > MLX5_ENCAP_MAX_LEN) 4181 return rte_flow_error_set(error, EINVAL, 4182 RTE_FLOW_ERROR_TYPE_ACTION, 4183 (void *)items->type, 4184 "items total size is too big" 4185 " for encap action"); 4186 rte_memcpy((void *)&buf[temp_size], items->spec, len); 4187 switch (items->type) { 4188 case RTE_FLOW_ITEM_TYPE_ETH: 4189 eth = (struct rte_ether_hdr *)&buf[temp_size]; 4190 break; 4191 case RTE_FLOW_ITEM_TYPE_VLAN: 4192 vlan = (struct rte_vlan_hdr *)&buf[temp_size]; 4193 if (!eth) 4194 return rte_flow_error_set(error, EINVAL, 4195 RTE_FLOW_ERROR_TYPE_ACTION, 4196 (void *)items->type, 4197 "eth header not found"); 4198 if (!eth->ether_type) 4199 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN); 4200 break; 4201 case RTE_FLOW_ITEM_TYPE_IPV4: 4202 ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size]; 4203 if (!vlan && !eth) 4204 return rte_flow_error_set(error, EINVAL, 4205 RTE_FLOW_ERROR_TYPE_ACTION, 4206 (void *)items->type, 4207 "neither eth nor vlan" 4208 " header found"); 4209 if (vlan && !vlan->eth_proto) 4210 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4211 else if (eth && !eth->ether_type) 4212 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4213 if (!ipv4->version_ihl) 4214 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION | 4215 MLX5_ENCAP_IPV4_IHL_MIN; 4216 if (!ipv4->time_to_live) 4217 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF; 4218 break; 4219 case RTE_FLOW_ITEM_TYPE_IPV6: 4220 ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size]; 4221 if (!vlan && !eth) 4222 return rte_flow_error_set(error, EINVAL, 4223 RTE_FLOW_ERROR_TYPE_ACTION, 4224 (void *)items->type, 4225 "neither eth nor vlan" 4226 " header found"); 4227 if (vlan && !vlan->eth_proto) 4228 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4229 else if (eth && !eth->ether_type) 4230 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4231 if (!ipv6->vtc_flow) 4232 ipv6->vtc_flow = 4233 RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW); 4234 if (!ipv6->hop_limits) 4235 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT; 4236 break; 4237 case RTE_FLOW_ITEM_TYPE_UDP: 4238 udp = (struct rte_udp_hdr *)&buf[temp_size]; 4239 if (!ipv4 && !ipv6) 4240 return rte_flow_error_set(error, EINVAL, 4241 RTE_FLOW_ERROR_TYPE_ACTION, 4242 (void *)items->type, 4243 "ip header not found"); 4244 if (ipv4 && !ipv4->next_proto_id) 4245 ipv4->next_proto_id = IPPROTO_UDP; 4246 else if (ipv6 && !ipv6->proto) 4247 ipv6->proto = IPPROTO_UDP; 4248 break; 4249 case RTE_FLOW_ITEM_TYPE_VXLAN: 4250 vxlan = (struct rte_vxlan_hdr *)&buf[temp_size]; 4251 if (!udp) 4252 return rte_flow_error_set(error, EINVAL, 4253 RTE_FLOW_ERROR_TYPE_ACTION, 4254 (void *)items->type, 4255 "udp header not found"); 4256 if (!udp->dst_port) 4257 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN); 4258 if (!vxlan->vx_flags) 4259 vxlan->vx_flags = 4260 RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS); 4261 break; 4262 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4263 vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size]; 4264 if (!udp) 4265 return rte_flow_error_set(error, EINVAL, 4266 RTE_FLOW_ERROR_TYPE_ACTION, 4267 (void *)items->type, 4268 "udp header not found"); 4269 if (!vxlan_gpe->proto) 4270 return rte_flow_error_set(error, EINVAL, 4271 RTE_FLOW_ERROR_TYPE_ACTION, 4272 (void *)items->type, 4273 "next protocol not found"); 4274 if (!udp->dst_port) 4275 udp->dst_port = 4276 RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE); 4277 if (!vxlan_gpe->vx_flags) 4278 vxlan_gpe->vx_flags = 4279 MLX5_ENCAP_VXLAN_GPE_FLAGS; 4280 break; 4281 case RTE_FLOW_ITEM_TYPE_GRE: 4282 case RTE_FLOW_ITEM_TYPE_NVGRE: 4283 gre = (struct rte_gre_hdr *)&buf[temp_size]; 4284 if (!gre->proto) 4285 return rte_flow_error_set(error, EINVAL, 4286 RTE_FLOW_ERROR_TYPE_ACTION, 4287 (void *)items->type, 4288 "next protocol not found"); 4289 if (!ipv4 && !ipv6) 4290 return rte_flow_error_set(error, EINVAL, 4291 RTE_FLOW_ERROR_TYPE_ACTION, 4292 (void *)items->type, 4293 "ip header not found"); 4294 if (ipv4 && !ipv4->next_proto_id) 4295 ipv4->next_proto_id = IPPROTO_GRE; 4296 else if (ipv6 && !ipv6->proto) 4297 ipv6->proto = IPPROTO_GRE; 4298 break; 4299 case RTE_FLOW_ITEM_TYPE_VOID: 4300 break; 4301 default: 4302 return rte_flow_error_set(error, EINVAL, 4303 RTE_FLOW_ERROR_TYPE_ACTION, 4304 (void *)items->type, 4305 "unsupported item type"); 4306 break; 4307 } 4308 temp_size += len; 4309 } 4310 *size = temp_size; 4311 return 0; 4312 } 4313 4314 static int 4315 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error) 4316 { 4317 struct rte_ether_hdr *eth = NULL; 4318 struct rte_vlan_hdr *vlan = NULL; 4319 struct rte_ipv6_hdr *ipv6 = NULL; 4320 struct rte_udp_hdr *udp = NULL; 4321 char *next_hdr; 4322 uint16_t proto; 4323 4324 eth = (struct rte_ether_hdr *)data; 4325 next_hdr = (char *)(eth + 1); 4326 proto = RTE_BE16(eth->ether_type); 4327 4328 /* VLAN skipping */ 4329 while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) { 4330 vlan = (struct rte_vlan_hdr *)next_hdr; 4331 proto = RTE_BE16(vlan->eth_proto); 4332 next_hdr += sizeof(struct rte_vlan_hdr); 4333 } 4334 4335 /* HW calculates IPv4 csum. no need to proceed */ 4336 if (proto == RTE_ETHER_TYPE_IPV4) 4337 return 0; 4338 4339 /* non IPv4/IPv6 header. not supported */ 4340 if (proto != RTE_ETHER_TYPE_IPV6) { 4341 return rte_flow_error_set(error, ENOTSUP, 4342 RTE_FLOW_ERROR_TYPE_ACTION, 4343 NULL, "Cannot offload non IPv4/IPv6"); 4344 } 4345 4346 ipv6 = (struct rte_ipv6_hdr *)next_hdr; 4347 4348 /* ignore non UDP */ 4349 if (ipv6->proto != IPPROTO_UDP) 4350 return 0; 4351 4352 udp = (struct rte_udp_hdr *)(ipv6 + 1); 4353 udp->dgram_cksum = 0; 4354 4355 return 0; 4356 } 4357 4358 /** 4359 * Convert L2 encap action to DV specification. 4360 * 4361 * @param[in] dev 4362 * Pointer to rte_eth_dev structure. 4363 * @param[in] action 4364 * Pointer to action structure. 4365 * @param[in, out] dev_flow 4366 * Pointer to the mlx5_flow. 4367 * @param[in] transfer 4368 * Mark if the flow is E-Switch flow. 4369 * @param[out] error 4370 * Pointer to the error structure. 4371 * 4372 * @return 4373 * 0 on success, a negative errno value otherwise and rte_errno is set. 4374 */ 4375 static int 4376 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev, 4377 const struct rte_flow_action *action, 4378 struct mlx5_flow *dev_flow, 4379 uint8_t transfer, 4380 struct rte_flow_error *error) 4381 { 4382 const struct rte_flow_item *encap_data; 4383 const struct rte_flow_action_raw_encap *raw_encap_data; 4384 struct mlx5_flow_dv_encap_decap_resource res = { 4385 .reformat_type = 4386 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL, 4387 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4388 MLX5DV_FLOW_TABLE_TYPE_NIC_TX, 4389 }; 4390 4391 if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 4392 raw_encap_data = 4393 (const struct rte_flow_action_raw_encap *)action->conf; 4394 res.size = raw_encap_data->size; 4395 memcpy(res.buf, raw_encap_data->data, res.size); 4396 } else { 4397 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) 4398 encap_data = 4399 ((const struct rte_flow_action_vxlan_encap *) 4400 action->conf)->definition; 4401 else 4402 encap_data = 4403 ((const struct rte_flow_action_nvgre_encap *) 4404 action->conf)->definition; 4405 if (flow_dv_convert_encap_data(encap_data, res.buf, 4406 &res.size, error)) 4407 return -rte_errno; 4408 } 4409 if (flow_dv_zero_encap_udp_csum(res.buf, error)) 4410 return -rte_errno; 4411 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4412 return rte_flow_error_set(error, EINVAL, 4413 RTE_FLOW_ERROR_TYPE_ACTION, 4414 NULL, "can't create L2 encap action"); 4415 return 0; 4416 } 4417 4418 /** 4419 * Convert L2 decap action to DV specification. 4420 * 4421 * @param[in] dev 4422 * Pointer to rte_eth_dev structure. 4423 * @param[in, out] dev_flow 4424 * Pointer to the mlx5_flow. 4425 * @param[in] transfer 4426 * Mark if the flow is E-Switch flow. 4427 * @param[out] error 4428 * Pointer to the error structure. 4429 * 4430 * @return 4431 * 0 on success, a negative errno value otherwise and rte_errno is set. 4432 */ 4433 static int 4434 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev, 4435 struct mlx5_flow *dev_flow, 4436 uint8_t transfer, 4437 struct rte_flow_error *error) 4438 { 4439 struct mlx5_flow_dv_encap_decap_resource res = { 4440 .size = 0, 4441 .reformat_type = 4442 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2, 4443 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4444 MLX5DV_FLOW_TABLE_TYPE_NIC_RX, 4445 }; 4446 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 L2 decap action"); 4451 return 0; 4452 } 4453 4454 /** 4455 * Convert raw decap/encap (L3 tunnel) action to DV specification. 4456 * 4457 * @param[in] dev 4458 * Pointer to rte_eth_dev structure. 4459 * @param[in] action 4460 * Pointer to action structure. 4461 * @param[in, out] dev_flow 4462 * Pointer to the mlx5_flow. 4463 * @param[in] attr 4464 * Pointer to the flow attributes. 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_raw_encap(struct rte_eth_dev *dev, 4473 const struct rte_flow_action *action, 4474 struct mlx5_flow *dev_flow, 4475 const struct rte_flow_attr *attr, 4476 struct rte_flow_error *error) 4477 { 4478 const struct rte_flow_action_raw_encap *encap_data; 4479 struct mlx5_flow_dv_encap_decap_resource res; 4480 4481 memset(&res, 0, sizeof(res)); 4482 encap_data = (const struct rte_flow_action_raw_encap *)action->conf; 4483 res.size = encap_data->size; 4484 memcpy(res.buf, encap_data->data, res.size); 4485 res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ? 4486 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 : 4487 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 4488 if (attr->transfer) 4489 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4490 else 4491 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4492 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4493 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4494 return rte_flow_error_set(error, EINVAL, 4495 RTE_FLOW_ERROR_TYPE_ACTION, 4496 NULL, "can't create encap action"); 4497 return 0; 4498 } 4499 4500 /** 4501 * Create action push VLAN. 4502 * 4503 * @param[in] dev 4504 * Pointer to rte_eth_dev structure. 4505 * @param[in] attr 4506 * Pointer to the flow attributes. 4507 * @param[in] vlan 4508 * Pointer to the vlan to push to the Ethernet header. 4509 * @param[in, out] dev_flow 4510 * Pointer to the mlx5_flow. 4511 * @param[out] error 4512 * Pointer to the error structure. 4513 * 4514 * @return 4515 * 0 on success, a negative errno value otherwise and rte_errno is set. 4516 */ 4517 static int 4518 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, 4519 const struct rte_flow_attr *attr, 4520 const struct rte_vlan_hdr *vlan, 4521 struct mlx5_flow *dev_flow, 4522 struct rte_flow_error *error) 4523 { 4524 struct mlx5_flow_dv_push_vlan_action_resource res; 4525 4526 memset(&res, 0, sizeof(res)); 4527 res.vlan_tag = 4528 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 | 4529 vlan->vlan_tci); 4530 if (attr->transfer) 4531 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4532 else 4533 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4534 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4535 return flow_dv_push_vlan_action_resource_register 4536 (dev, &res, dev_flow, error); 4537 } 4538 4539 /** 4540 * Validate the modify-header actions. 4541 * 4542 * @param[in] action_flags 4543 * Holds the actions detected until now. 4544 * @param[in] action 4545 * Pointer to the modify action. 4546 * @param[out] error 4547 * Pointer to error structure. 4548 * 4549 * @return 4550 * 0 on success, a negative errno value otherwise and rte_errno is set. 4551 */ 4552 static int 4553 flow_dv_validate_action_modify_hdr(const uint64_t action_flags, 4554 const struct rte_flow_action *action, 4555 struct rte_flow_error *error) 4556 { 4557 if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf) 4558 return rte_flow_error_set(error, EINVAL, 4559 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4560 NULL, "action configuration not set"); 4561 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 4562 return rte_flow_error_set(error, EINVAL, 4563 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4564 "can't have encap action before" 4565 " modify action"); 4566 return 0; 4567 } 4568 4569 /** 4570 * Validate the modify-header MAC address actions. 4571 * 4572 * @param[in] action_flags 4573 * Holds the actions detected until now. 4574 * @param[in] action 4575 * Pointer to the modify action. 4576 * @param[in] item_flags 4577 * Holds the items detected. 4578 * @param[out] error 4579 * Pointer to error structure. 4580 * 4581 * @return 4582 * 0 on success, a negative errno value otherwise and rte_errno is set. 4583 */ 4584 static int 4585 flow_dv_validate_action_modify_mac(const uint64_t action_flags, 4586 const struct rte_flow_action *action, 4587 const uint64_t item_flags, 4588 struct rte_flow_error *error) 4589 { 4590 int ret = 0; 4591 4592 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4593 if (!ret) { 4594 if (!(item_flags & MLX5_FLOW_LAYER_L2)) 4595 return rte_flow_error_set(error, EINVAL, 4596 RTE_FLOW_ERROR_TYPE_ACTION, 4597 NULL, 4598 "no L2 item in pattern"); 4599 } 4600 return ret; 4601 } 4602 4603 /** 4604 * Validate the modify-header IPv4 address actions. 4605 * 4606 * @param[in] action_flags 4607 * Holds the actions detected until now. 4608 * @param[in] action 4609 * Pointer to the modify action. 4610 * @param[in] item_flags 4611 * Holds the items detected. 4612 * @param[out] error 4613 * Pointer to error structure. 4614 * 4615 * @return 4616 * 0 on success, a negative errno value otherwise and rte_errno is set. 4617 */ 4618 static int 4619 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags, 4620 const struct rte_flow_action *action, 4621 const uint64_t item_flags, 4622 struct rte_flow_error *error) 4623 { 4624 int ret = 0; 4625 uint64_t layer; 4626 4627 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4628 if (!ret) { 4629 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4630 MLX5_FLOW_LAYER_INNER_L3_IPV4 : 4631 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 4632 if (!(item_flags & layer)) 4633 return rte_flow_error_set(error, EINVAL, 4634 RTE_FLOW_ERROR_TYPE_ACTION, 4635 NULL, 4636 "no ipv4 item in pattern"); 4637 } 4638 return ret; 4639 } 4640 4641 /** 4642 * Validate the modify-header IPv6 address actions. 4643 * 4644 * @param[in] action_flags 4645 * Holds the actions detected until now. 4646 * @param[in] action 4647 * Pointer to the modify action. 4648 * @param[in] item_flags 4649 * Holds the items detected. 4650 * @param[out] error 4651 * Pointer to error structure. 4652 * 4653 * @return 4654 * 0 on success, a negative errno value otherwise and rte_errno is set. 4655 */ 4656 static int 4657 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags, 4658 const struct rte_flow_action *action, 4659 const uint64_t item_flags, 4660 struct rte_flow_error *error) 4661 { 4662 int ret = 0; 4663 uint64_t layer; 4664 4665 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4666 if (!ret) { 4667 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4668 MLX5_FLOW_LAYER_INNER_L3_IPV6 : 4669 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 4670 if (!(item_flags & layer)) 4671 return rte_flow_error_set(error, EINVAL, 4672 RTE_FLOW_ERROR_TYPE_ACTION, 4673 NULL, 4674 "no ipv6 item in pattern"); 4675 } 4676 return ret; 4677 } 4678 4679 /** 4680 * Validate the modify-header TP actions. 4681 * 4682 * @param[in] action_flags 4683 * Holds the actions detected until now. 4684 * @param[in] action 4685 * Pointer to the modify action. 4686 * @param[in] item_flags 4687 * Holds the items detected. 4688 * @param[out] error 4689 * Pointer to error structure. 4690 * 4691 * @return 4692 * 0 on success, a negative errno value otherwise and rte_errno is set. 4693 */ 4694 static int 4695 flow_dv_validate_action_modify_tp(const uint64_t action_flags, 4696 const struct rte_flow_action *action, 4697 const uint64_t item_flags, 4698 struct rte_flow_error *error) 4699 { 4700 int ret = 0; 4701 uint64_t layer; 4702 4703 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4704 if (!ret) { 4705 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4706 MLX5_FLOW_LAYER_INNER_L4 : 4707 MLX5_FLOW_LAYER_OUTER_L4; 4708 if (!(item_flags & layer)) 4709 return rte_flow_error_set(error, EINVAL, 4710 RTE_FLOW_ERROR_TYPE_ACTION, 4711 NULL, "no transport layer " 4712 "in pattern"); 4713 } 4714 return ret; 4715 } 4716 4717 /** 4718 * Validate the modify-header actions of increment/decrement 4719 * TCP Sequence-number. 4720 * 4721 * @param[in] action_flags 4722 * Holds the actions detected until now. 4723 * @param[in] action 4724 * Pointer to the modify action. 4725 * @param[in] item_flags 4726 * Holds the items detected. 4727 * @param[out] error 4728 * Pointer to error structure. 4729 * 4730 * @return 4731 * 0 on success, a negative errno value otherwise and rte_errno is set. 4732 */ 4733 static int 4734 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags, 4735 const struct rte_flow_action *action, 4736 const uint64_t item_flags, 4737 struct rte_flow_error *error) 4738 { 4739 int ret = 0; 4740 uint64_t layer; 4741 4742 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4743 if (!ret) { 4744 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4745 MLX5_FLOW_LAYER_INNER_L4_TCP : 4746 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4747 if (!(item_flags & layer)) 4748 return rte_flow_error_set(error, EINVAL, 4749 RTE_FLOW_ERROR_TYPE_ACTION, 4750 NULL, "no TCP item in" 4751 " pattern"); 4752 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ && 4753 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) || 4754 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ && 4755 (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ))) 4756 return rte_flow_error_set(error, EINVAL, 4757 RTE_FLOW_ERROR_TYPE_ACTION, 4758 NULL, 4759 "cannot decrease and increase" 4760 " TCP sequence number" 4761 " at the same time"); 4762 } 4763 return ret; 4764 } 4765 4766 /** 4767 * Validate the modify-header actions of increment/decrement 4768 * TCP Acknowledgment number. 4769 * 4770 * @param[in] action_flags 4771 * Holds the actions detected until now. 4772 * @param[in] action 4773 * Pointer to the modify action. 4774 * @param[in] item_flags 4775 * Holds the items detected. 4776 * @param[out] error 4777 * Pointer to error structure. 4778 * 4779 * @return 4780 * 0 on success, a negative errno value otherwise and rte_errno is set. 4781 */ 4782 static int 4783 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags, 4784 const struct rte_flow_action *action, 4785 const uint64_t item_flags, 4786 struct rte_flow_error *error) 4787 { 4788 int ret = 0; 4789 uint64_t layer; 4790 4791 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4792 if (!ret) { 4793 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4794 MLX5_FLOW_LAYER_INNER_L4_TCP : 4795 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4796 if (!(item_flags & layer)) 4797 return rte_flow_error_set(error, EINVAL, 4798 RTE_FLOW_ERROR_TYPE_ACTION, 4799 NULL, "no TCP item in" 4800 " pattern"); 4801 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK && 4802 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) || 4803 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK && 4804 (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK))) 4805 return rte_flow_error_set(error, EINVAL, 4806 RTE_FLOW_ERROR_TYPE_ACTION, 4807 NULL, 4808 "cannot decrease and increase" 4809 " TCP acknowledgment number" 4810 " at the same time"); 4811 } 4812 return ret; 4813 } 4814 4815 /** 4816 * Validate the modify-header TTL actions. 4817 * 4818 * @param[in] action_flags 4819 * Holds the actions detected until now. 4820 * @param[in] action 4821 * Pointer to the modify action. 4822 * @param[in] item_flags 4823 * Holds the items detected. 4824 * @param[out] error 4825 * Pointer to error structure. 4826 * 4827 * @return 4828 * 0 on success, a negative errno value otherwise and rte_errno is set. 4829 */ 4830 static int 4831 flow_dv_validate_action_modify_ttl(const uint64_t action_flags, 4832 const struct rte_flow_action *action, 4833 const uint64_t item_flags, 4834 struct rte_flow_error *error) 4835 { 4836 int ret = 0; 4837 uint64_t layer; 4838 4839 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4840 if (!ret) { 4841 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4842 MLX5_FLOW_LAYER_INNER_L3 : 4843 MLX5_FLOW_LAYER_OUTER_L3; 4844 if (!(item_flags & layer)) 4845 return rte_flow_error_set(error, EINVAL, 4846 RTE_FLOW_ERROR_TYPE_ACTION, 4847 NULL, 4848 "no IP protocol in pattern"); 4849 } 4850 return ret; 4851 } 4852 4853 /** 4854 * Validate the generic modify field actions. 4855 * @param[in] dev 4856 * Pointer to the rte_eth_dev structure. 4857 * @param[in] action_flags 4858 * Holds the actions detected until now. 4859 * @param[in] action 4860 * Pointer to the modify action. 4861 * @param[in] attr 4862 * Pointer to the flow attributes. 4863 * @param[out] error 4864 * Pointer to error structure. 4865 * 4866 * @return 4867 * Number of header fields to modify (0 or more) on success, 4868 * a negative errno value otherwise and rte_errno is set. 4869 */ 4870 static int 4871 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, 4872 const uint64_t action_flags, 4873 const struct rte_flow_action *action, 4874 const struct rte_flow_attr *attr, 4875 struct rte_flow_error *error) 4876 { 4877 int ret = 0; 4878 struct mlx5_priv *priv = dev->data->dev_private; 4879 struct mlx5_dev_config *config = &priv->config; 4880 const struct rte_flow_action_modify_field *action_modify_field = 4881 action->conf; 4882 uint32_t dst_width = mlx5_flow_item_field_width(priv, 4883 action_modify_field->dst.field); 4884 uint32_t src_width = mlx5_flow_item_field_width(priv, 4885 action_modify_field->src.field); 4886 4887 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4888 if (ret) 4889 return ret; 4890 4891 if (action_modify_field->width == 0) 4892 return rte_flow_error_set(error, EINVAL, 4893 RTE_FLOW_ERROR_TYPE_ACTION, action, 4894 "no bits are requested to be modified"); 4895 else if (action_modify_field->width > dst_width || 4896 action_modify_field->width > src_width) 4897 return rte_flow_error_set(error, EINVAL, 4898 RTE_FLOW_ERROR_TYPE_ACTION, action, 4899 "cannot modify more bits than" 4900 " the width of a field"); 4901 if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE && 4902 action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) { 4903 if ((action_modify_field->dst.offset + 4904 action_modify_field->width > dst_width) || 4905 (action_modify_field->dst.offset % 32)) 4906 return rte_flow_error_set(error, EINVAL, 4907 RTE_FLOW_ERROR_TYPE_ACTION, action, 4908 "destination offset is too big" 4909 " or not aligned to 4 bytes"); 4910 if (action_modify_field->dst.level && 4911 action_modify_field->dst.field != RTE_FLOW_FIELD_TAG) 4912 return rte_flow_error_set(error, ENOTSUP, 4913 RTE_FLOW_ERROR_TYPE_ACTION, action, 4914 "inner header fields modification" 4915 " is not supported"); 4916 } 4917 if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE && 4918 action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) { 4919 if (!attr->transfer && !attr->group) 4920 return rte_flow_error_set(error, ENOTSUP, 4921 RTE_FLOW_ERROR_TYPE_ACTION, action, 4922 "modify field action is not" 4923 " supported for group 0"); 4924 if ((action_modify_field->src.offset + 4925 action_modify_field->width > src_width) || 4926 (action_modify_field->src.offset % 32)) 4927 return rte_flow_error_set(error, EINVAL, 4928 RTE_FLOW_ERROR_TYPE_ACTION, action, 4929 "source offset is too big" 4930 " or not aligned to 4 bytes"); 4931 if (action_modify_field->src.level && 4932 action_modify_field->src.field != RTE_FLOW_FIELD_TAG) 4933 return rte_flow_error_set(error, ENOTSUP, 4934 RTE_FLOW_ERROR_TYPE_ACTION, action, 4935 "inner header fields modification" 4936 " is not supported"); 4937 } 4938 if ((action_modify_field->dst.field == 4939 action_modify_field->src.field) && 4940 (action_modify_field->dst.level == 4941 action_modify_field->src.level)) 4942 return rte_flow_error_set(error, EINVAL, 4943 RTE_FLOW_ERROR_TYPE_ACTION, action, 4944 "source and destination fields" 4945 " cannot be the same"); 4946 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE || 4947 action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER || 4948 action_modify_field->dst.field == RTE_FLOW_FIELD_MARK) 4949 return rte_flow_error_set(error, EINVAL, 4950 RTE_FLOW_ERROR_TYPE_ACTION, action, 4951 "mark, immediate value or a pointer to it" 4952 " cannot be used as a destination"); 4953 if (action_modify_field->dst.field == RTE_FLOW_FIELD_START || 4954 action_modify_field->src.field == RTE_FLOW_FIELD_START) 4955 return rte_flow_error_set(error, ENOTSUP, 4956 RTE_FLOW_ERROR_TYPE_ACTION, action, 4957 "modifications of an arbitrary" 4958 " place in a packet is not supported"); 4959 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE || 4960 action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE) 4961 return rte_flow_error_set(error, ENOTSUP, 4962 RTE_FLOW_ERROR_TYPE_ACTION, action, 4963 "modifications of the 802.1Q Tag" 4964 " Identifier is not supported"); 4965 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI || 4966 action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI) 4967 return rte_flow_error_set(error, ENOTSUP, 4968 RTE_FLOW_ERROR_TYPE_ACTION, action, 4969 "modifications of the VXLAN Network" 4970 " Identifier is not supported"); 4971 if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI || 4972 action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI) 4973 return rte_flow_error_set(error, ENOTSUP, 4974 RTE_FLOW_ERROR_TYPE_ACTION, action, 4975 "modifications of the GENEVE Network" 4976 " Identifier is not supported"); 4977 if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK || 4978 action_modify_field->src.field == RTE_FLOW_FIELD_MARK || 4979 action_modify_field->dst.field == RTE_FLOW_FIELD_META || 4980 action_modify_field->src.field == RTE_FLOW_FIELD_META) { 4981 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY || 4982 !mlx5_flow_ext_mreg_supported(dev)) 4983 return rte_flow_error_set(error, ENOTSUP, 4984 RTE_FLOW_ERROR_TYPE_ACTION, action, 4985 "cannot modify mark or metadata without" 4986 " extended metadata register support"); 4987 } 4988 if (action_modify_field->operation != RTE_FLOW_MODIFY_SET) 4989 return rte_flow_error_set(error, ENOTSUP, 4990 RTE_FLOW_ERROR_TYPE_ACTION, action, 4991 "add and sub operations" 4992 " are not supported"); 4993 return (action_modify_field->width / 32) + 4994 !!(action_modify_field->width % 32); 4995 } 4996 4997 /** 4998 * Validate jump action. 4999 * 5000 * @param[in] action 5001 * Pointer to the jump action. 5002 * @param[in] action_flags 5003 * Holds the actions detected until now. 5004 * @param[in] attributes 5005 * Pointer to flow attributes 5006 * @param[in] external 5007 * Action belongs to flow rule created by request external to PMD. 5008 * @param[out] error 5009 * Pointer to error structure. 5010 * 5011 * @return 5012 * 0 on success, a negative errno value otherwise and rte_errno is set. 5013 */ 5014 static int 5015 flow_dv_validate_action_jump(struct rte_eth_dev *dev, 5016 const struct mlx5_flow_tunnel *tunnel, 5017 const struct rte_flow_action *action, 5018 uint64_t action_flags, 5019 const struct rte_flow_attr *attributes, 5020 bool external, struct rte_flow_error *error) 5021 { 5022 uint32_t target_group, table; 5023 int ret = 0; 5024 struct flow_grp_info grp_info = { 5025 .external = !!external, 5026 .transfer = !!attributes->transfer, 5027 .fdb_def_rule = 1, 5028 .std_tbl_fix = 0 5029 }; 5030 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5031 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5032 return rte_flow_error_set(error, EINVAL, 5033 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5034 "can't have 2 fate actions in" 5035 " same flow"); 5036 if (!action->conf) 5037 return rte_flow_error_set(error, EINVAL, 5038 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5039 NULL, "action configuration not set"); 5040 target_group = 5041 ((const struct rte_flow_action_jump *)action->conf)->group; 5042 ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table, 5043 &grp_info, error); 5044 if (ret) 5045 return ret; 5046 if (attributes->group == target_group && 5047 !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET | 5048 MLX5_FLOW_ACTION_TUNNEL_MATCH))) 5049 return rte_flow_error_set(error, EINVAL, 5050 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5051 "target group must be other than" 5052 " the current flow group"); 5053 return 0; 5054 } 5055 5056 /* 5057 * Validate the port_id action. 5058 * 5059 * @param[in] dev 5060 * Pointer to rte_eth_dev structure. 5061 * @param[in] action_flags 5062 * Bit-fields that holds the actions detected until now. 5063 * @param[in] action 5064 * Port_id RTE action structure. 5065 * @param[in] attr 5066 * Attributes of flow that includes this action. 5067 * @param[out] error 5068 * Pointer to error structure. 5069 * 5070 * @return 5071 * 0 on success, a negative errno value otherwise and rte_errno is set. 5072 */ 5073 static int 5074 flow_dv_validate_action_port_id(struct rte_eth_dev *dev, 5075 uint64_t action_flags, 5076 const struct rte_flow_action *action, 5077 const struct rte_flow_attr *attr, 5078 struct rte_flow_error *error) 5079 { 5080 const struct rte_flow_action_port_id *port_id; 5081 struct mlx5_priv *act_priv; 5082 struct mlx5_priv *dev_priv; 5083 uint16_t port; 5084 5085 if (!attr->transfer) 5086 return rte_flow_error_set(error, ENOTSUP, 5087 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5088 NULL, 5089 "port id action is valid in transfer" 5090 " mode only"); 5091 if (!action || !action->conf) 5092 return rte_flow_error_set(error, ENOTSUP, 5093 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5094 NULL, 5095 "port id action parameters must be" 5096 " specified"); 5097 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5098 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5099 return rte_flow_error_set(error, EINVAL, 5100 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5101 "can have only one fate actions in" 5102 " a flow"); 5103 dev_priv = mlx5_dev_to_eswitch_info(dev); 5104 if (!dev_priv) 5105 return rte_flow_error_set(error, rte_errno, 5106 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5107 NULL, 5108 "failed to obtain E-Switch info"); 5109 port_id = action->conf; 5110 port = port_id->original ? dev->data->port_id : port_id->id; 5111 act_priv = mlx5_port_to_eswitch_info(port, false); 5112 if (!act_priv) 5113 return rte_flow_error_set 5114 (error, rte_errno, 5115 RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id, 5116 "failed to obtain E-Switch port id for port"); 5117 if (act_priv->domain_id != dev_priv->domain_id) 5118 return rte_flow_error_set 5119 (error, EINVAL, 5120 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5121 "port does not belong to" 5122 " E-Switch being configured"); 5123 return 0; 5124 } 5125 5126 /** 5127 * Get the maximum number of modify header actions. 5128 * 5129 * @param dev 5130 * Pointer to rte_eth_dev structure. 5131 * @param root 5132 * Whether action is on root table. 5133 * 5134 * @return 5135 * Max number of modify header actions device can support. 5136 */ 5137 static inline unsigned int 5138 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused, 5139 bool root) 5140 { 5141 /* 5142 * There's no way to directly query the max capacity from FW. 5143 * The maximal value on root table should be assumed to be supported. 5144 */ 5145 if (!root) 5146 return MLX5_MAX_MODIFY_NUM; 5147 else 5148 return MLX5_ROOT_TBL_MODIFY_NUM; 5149 } 5150 5151 /** 5152 * Validate the meter action. 5153 * 5154 * @param[in] dev 5155 * Pointer to rte_eth_dev structure. 5156 * @param[in] action_flags 5157 * Bit-fields that holds the actions detected until now. 5158 * @param[in] action 5159 * Pointer to the meter action. 5160 * @param[in] attr 5161 * Attributes of flow that includes this action. 5162 * @param[in] port_id_item 5163 * Pointer to item indicating port id. 5164 * @param[out] error 5165 * Pointer to error structure. 5166 * 5167 * @return 5168 * 0 on success, a negative errno value otherwise and rte_ernno is set. 5169 */ 5170 static int 5171 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev, 5172 uint64_t action_flags, 5173 const struct rte_flow_action *action, 5174 const struct rte_flow_attr *attr, 5175 const struct rte_flow_item *port_id_item, 5176 bool *def_policy, 5177 struct rte_flow_error *error) 5178 { 5179 struct mlx5_priv *priv = dev->data->dev_private; 5180 const struct rte_flow_action_meter *am = action->conf; 5181 struct mlx5_flow_meter_info *fm; 5182 struct mlx5_flow_meter_policy *mtr_policy; 5183 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 5184 5185 if (!am) 5186 return rte_flow_error_set(error, EINVAL, 5187 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5188 "meter action conf is NULL"); 5189 5190 if (action_flags & MLX5_FLOW_ACTION_METER) 5191 return rte_flow_error_set(error, ENOTSUP, 5192 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5193 "meter chaining not support"); 5194 if (action_flags & MLX5_FLOW_ACTION_JUMP) 5195 return rte_flow_error_set(error, ENOTSUP, 5196 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5197 "meter with jump not support"); 5198 if (!priv->mtr_en) 5199 return rte_flow_error_set(error, ENOTSUP, 5200 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5201 NULL, 5202 "meter action not supported"); 5203 fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL); 5204 if (!fm) 5205 return rte_flow_error_set(error, EINVAL, 5206 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5207 "Meter not found"); 5208 /* aso meter can always be shared by different domains */ 5209 if (fm->ref_cnt && !priv->sh->meter_aso_en && 5210 !(fm->transfer == attr->transfer || 5211 (!fm->ingress && !attr->ingress && attr->egress) || 5212 (!fm->egress && !attr->egress && attr->ingress))) 5213 return rte_flow_error_set(error, EINVAL, 5214 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5215 "Flow attributes domain are either invalid " 5216 "or have a domain conflict with current " 5217 "meter attributes"); 5218 if (fm->def_policy) { 5219 if (!((attr->transfer && 5220 mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) || 5221 (attr->egress && 5222 mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) || 5223 (attr->ingress && 5224 mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS]))) 5225 return rte_flow_error_set(error, EINVAL, 5226 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5227 "Flow attributes domain " 5228 "have a conflict with current " 5229 "meter domain attributes"); 5230 *def_policy = true; 5231 } else { 5232 mtr_policy = mlx5_flow_meter_policy_find(dev, 5233 fm->policy_id, NULL); 5234 if (!mtr_policy) 5235 return rte_flow_error_set(error, EINVAL, 5236 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5237 "Invalid policy id for meter "); 5238 if (!((attr->transfer && mtr_policy->transfer) || 5239 (attr->egress && mtr_policy->egress) || 5240 (attr->ingress && mtr_policy->ingress))) 5241 return rte_flow_error_set(error, EINVAL, 5242 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5243 "Flow attributes domain " 5244 "have a conflict with current " 5245 "meter domain attributes"); 5246 if (attr->transfer && mtr_policy->dev) { 5247 /** 5248 * When policy has fate action of port_id, 5249 * the flow should have the same src port as policy. 5250 */ 5251 struct mlx5_priv *policy_port_priv = 5252 mtr_policy->dev->data->dev_private; 5253 int32_t flow_src_port = priv->representor_id; 5254 5255 if (port_id_item) { 5256 const struct rte_flow_item_port_id *spec = 5257 port_id_item->spec; 5258 struct mlx5_priv *port_priv = 5259 mlx5_port_to_eswitch_info(spec->id, 5260 false); 5261 if (!port_priv) 5262 return rte_flow_error_set(error, 5263 rte_errno, 5264 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5265 spec, 5266 "Failed to get port info."); 5267 flow_src_port = port_priv->representor_id; 5268 } 5269 if (flow_src_port != policy_port_priv->representor_id) 5270 return rte_flow_error_set(error, 5271 rte_errno, 5272 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5273 NULL, 5274 "Flow and meter policy " 5275 "have different src port."); 5276 } 5277 *def_policy = false; 5278 } 5279 return 0; 5280 } 5281 5282 /** 5283 * Validate the age action. 5284 * 5285 * @param[in] action_flags 5286 * Holds the actions detected until now. 5287 * @param[in] action 5288 * Pointer to the age action. 5289 * @param[in] dev 5290 * Pointer to the Ethernet device structure. 5291 * @param[out] error 5292 * Pointer to error structure. 5293 * 5294 * @return 5295 * 0 on success, a negative errno value otherwise and rte_errno is set. 5296 */ 5297 static int 5298 flow_dv_validate_action_age(uint64_t action_flags, 5299 const struct rte_flow_action *action, 5300 struct rte_eth_dev *dev, 5301 struct rte_flow_error *error) 5302 { 5303 struct mlx5_priv *priv = dev->data->dev_private; 5304 const struct rte_flow_action_age *age = action->conf; 5305 5306 if (!priv->config.devx || (priv->sh->cmng.counter_fallback && 5307 !priv->sh->aso_age_mng)) 5308 return rte_flow_error_set(error, ENOTSUP, 5309 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5310 NULL, 5311 "age action not supported"); 5312 if (!(action->conf)) 5313 return rte_flow_error_set(error, EINVAL, 5314 RTE_FLOW_ERROR_TYPE_ACTION, action, 5315 "configuration cannot be null"); 5316 if (!(age->timeout)) 5317 return rte_flow_error_set(error, EINVAL, 5318 RTE_FLOW_ERROR_TYPE_ACTION, action, 5319 "invalid timeout value 0"); 5320 if (action_flags & MLX5_FLOW_ACTION_AGE) 5321 return rte_flow_error_set(error, EINVAL, 5322 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5323 "duplicate age actions set"); 5324 return 0; 5325 } 5326 5327 /** 5328 * Validate the modify-header IPv4 DSCP actions. 5329 * 5330 * @param[in] action_flags 5331 * Holds the actions detected until now. 5332 * @param[in] action 5333 * Pointer to the modify action. 5334 * @param[in] item_flags 5335 * Holds the items detected. 5336 * @param[out] error 5337 * Pointer to error structure. 5338 * 5339 * @return 5340 * 0 on success, a negative errno value otherwise and rte_errno is set. 5341 */ 5342 static int 5343 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags, 5344 const struct rte_flow_action *action, 5345 const uint64_t item_flags, 5346 struct rte_flow_error *error) 5347 { 5348 int ret = 0; 5349 5350 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5351 if (!ret) { 5352 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4)) 5353 return rte_flow_error_set(error, EINVAL, 5354 RTE_FLOW_ERROR_TYPE_ACTION, 5355 NULL, 5356 "no ipv4 item in pattern"); 5357 } 5358 return ret; 5359 } 5360 5361 /** 5362 * Validate the modify-header IPv6 DSCP actions. 5363 * 5364 * @param[in] action_flags 5365 * Holds the actions detected until now. 5366 * @param[in] action 5367 * Pointer to the modify action. 5368 * @param[in] item_flags 5369 * Holds the items detected. 5370 * @param[out] error 5371 * Pointer to error structure. 5372 * 5373 * @return 5374 * 0 on success, a negative errno value otherwise and rte_errno is set. 5375 */ 5376 static int 5377 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags, 5378 const struct rte_flow_action *action, 5379 const uint64_t item_flags, 5380 struct rte_flow_error *error) 5381 { 5382 int ret = 0; 5383 5384 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5385 if (!ret) { 5386 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6)) 5387 return rte_flow_error_set(error, EINVAL, 5388 RTE_FLOW_ERROR_TYPE_ACTION, 5389 NULL, 5390 "no ipv6 item in pattern"); 5391 } 5392 return ret; 5393 } 5394 5395 int 5396 flow_dv_modify_match_cb(void *tool_ctx __rte_unused, 5397 struct mlx5_list_entry *entry, void *cb_ctx) 5398 { 5399 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5400 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5401 struct mlx5_flow_dv_modify_hdr_resource *resource = 5402 container_of(entry, typeof(*resource), entry); 5403 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5404 5405 key_len += ref->actions_num * sizeof(ref->actions[0]); 5406 return ref->actions_num != resource->actions_num || 5407 memcmp(&ref->ft_type, &resource->ft_type, key_len); 5408 } 5409 5410 static struct mlx5_indexed_pool * 5411 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index) 5412 { 5413 struct mlx5_indexed_pool *ipool = __atomic_load_n 5414 (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST); 5415 5416 if (!ipool) { 5417 struct mlx5_indexed_pool *expected = NULL; 5418 struct mlx5_indexed_pool_config cfg = 5419 (struct mlx5_indexed_pool_config) { 5420 .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 5421 (index + 1) * 5422 sizeof(struct mlx5_modification_cmd), 5423 .trunk_size = 64, 5424 .grow_trunk = 3, 5425 .grow_shift = 2, 5426 .need_lock = 1, 5427 .release_mem_en = !!sh->reclaim_mode, 5428 .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16), 5429 .malloc = mlx5_malloc, 5430 .free = mlx5_free, 5431 .type = "mlx5_modify_action_resource", 5432 }; 5433 5434 cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool)); 5435 ipool = mlx5_ipool_create(&cfg); 5436 if (!ipool) 5437 return NULL; 5438 if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index], 5439 &expected, ipool, false, 5440 __ATOMIC_SEQ_CST, 5441 __ATOMIC_SEQ_CST)) { 5442 mlx5_ipool_destroy(ipool); 5443 ipool = __atomic_load_n(&sh->mdh_ipools[index], 5444 __ATOMIC_SEQ_CST); 5445 } 5446 } 5447 return ipool; 5448 } 5449 5450 struct mlx5_list_entry * 5451 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx) 5452 { 5453 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5454 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5455 struct mlx5dv_dr_domain *ns; 5456 struct mlx5_flow_dv_modify_hdr_resource *entry; 5457 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5458 struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh, 5459 ref->actions_num - 1); 5460 int ret; 5461 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5462 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5463 uint32_t idx; 5464 5465 if (unlikely(!ipool)) { 5466 rte_flow_error_set(ctx->error, ENOMEM, 5467 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5468 NULL, "cannot allocate modify ipool"); 5469 return NULL; 5470 } 5471 entry = mlx5_ipool_zmalloc(ipool, &idx); 5472 if (!entry) { 5473 rte_flow_error_set(ctx->error, ENOMEM, 5474 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5475 "cannot allocate resource memory"); 5476 return NULL; 5477 } 5478 rte_memcpy(&entry->ft_type, 5479 RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)), 5480 key_len + data_len); 5481 if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 5482 ns = sh->fdb_domain; 5483 else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 5484 ns = sh->tx_domain; 5485 else 5486 ns = sh->rx_domain; 5487 ret = mlx5_flow_os_create_flow_action_modify_header 5488 (sh->ctx, ns, entry, 5489 data_len, &entry->action); 5490 if (ret) { 5491 mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx); 5492 rte_flow_error_set(ctx->error, ENOMEM, 5493 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5494 NULL, "cannot create modification action"); 5495 return NULL; 5496 } 5497 entry->idx = idx; 5498 return &entry->entry; 5499 } 5500 5501 struct mlx5_list_entry * 5502 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 5503 void *cb_ctx) 5504 { 5505 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5506 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5507 struct mlx5_flow_dv_modify_hdr_resource *entry; 5508 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5509 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5510 uint32_t idx; 5511 5512 entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1], 5513 &idx); 5514 if (!entry) { 5515 rte_flow_error_set(ctx->error, ENOMEM, 5516 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5517 "cannot allocate resource memory"); 5518 return NULL; 5519 } 5520 memcpy(entry, oentry, sizeof(*entry) + data_len); 5521 entry->idx = idx; 5522 return &entry->entry; 5523 } 5524 5525 void 5526 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 5527 { 5528 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5529 struct mlx5_flow_dv_modify_hdr_resource *res = 5530 container_of(entry, typeof(*res), entry); 5531 5532 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 5533 } 5534 5535 /** 5536 * Validate the sample action. 5537 * 5538 * @param[in, out] action_flags 5539 * Holds the actions detected until now. 5540 * @param[in] action 5541 * Pointer to the sample action. 5542 * @param[in] dev 5543 * Pointer to the Ethernet device structure. 5544 * @param[in] attr 5545 * Attributes of flow that includes this action. 5546 * @param[in] item_flags 5547 * Holds the items detected. 5548 * @param[in] rss 5549 * Pointer to the RSS action. 5550 * @param[out] sample_rss 5551 * Pointer to the RSS action in sample action list. 5552 * @param[out] count 5553 * Pointer to the COUNT action in sample action list. 5554 * @param[out] fdb_mirror_limit 5555 * Pointer to the FDB mirror limitation flag. 5556 * @param[out] error 5557 * Pointer to error structure. 5558 * 5559 * @return 5560 * 0 on success, a negative errno value otherwise and rte_errno is set. 5561 */ 5562 static int 5563 flow_dv_validate_action_sample(uint64_t *action_flags, 5564 const struct rte_flow_action *action, 5565 struct rte_eth_dev *dev, 5566 const struct rte_flow_attr *attr, 5567 uint64_t item_flags, 5568 const struct rte_flow_action_rss *rss, 5569 const struct rte_flow_action_rss **sample_rss, 5570 const struct rte_flow_action_count **count, 5571 int *fdb_mirror_limit, 5572 struct rte_flow_error *error) 5573 { 5574 struct mlx5_priv *priv = dev->data->dev_private; 5575 struct mlx5_dev_config *dev_conf = &priv->config; 5576 const struct rte_flow_action_sample *sample = action->conf; 5577 const struct rte_flow_action *act; 5578 uint64_t sub_action_flags = 0; 5579 uint16_t queue_index = 0xFFFF; 5580 int actions_n = 0; 5581 int ret; 5582 5583 if (!sample) 5584 return rte_flow_error_set(error, EINVAL, 5585 RTE_FLOW_ERROR_TYPE_ACTION, action, 5586 "configuration cannot be NULL"); 5587 if (sample->ratio == 0) 5588 return rte_flow_error_set(error, EINVAL, 5589 RTE_FLOW_ERROR_TYPE_ACTION, action, 5590 "ratio value starts from 1"); 5591 if (!priv->config.devx || (sample->ratio > 0 && !priv->sampler_en)) 5592 return rte_flow_error_set(error, ENOTSUP, 5593 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5594 NULL, 5595 "sample action not supported"); 5596 if (*action_flags & MLX5_FLOW_ACTION_SAMPLE) 5597 return rte_flow_error_set(error, EINVAL, 5598 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5599 "Multiple sample actions not " 5600 "supported"); 5601 if (*action_flags & MLX5_FLOW_ACTION_METER) 5602 return rte_flow_error_set(error, EINVAL, 5603 RTE_FLOW_ERROR_TYPE_ACTION, action, 5604 "wrong action order, meter should " 5605 "be after sample action"); 5606 if (*action_flags & MLX5_FLOW_ACTION_JUMP) 5607 return rte_flow_error_set(error, EINVAL, 5608 RTE_FLOW_ERROR_TYPE_ACTION, action, 5609 "wrong action order, jump should " 5610 "be after sample action"); 5611 act = sample->actions; 5612 for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 5613 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 5614 return rte_flow_error_set(error, ENOTSUP, 5615 RTE_FLOW_ERROR_TYPE_ACTION, 5616 act, "too many actions"); 5617 switch (act->type) { 5618 case RTE_FLOW_ACTION_TYPE_QUEUE: 5619 ret = mlx5_flow_validate_action_queue(act, 5620 sub_action_flags, 5621 dev, 5622 attr, error); 5623 if (ret < 0) 5624 return ret; 5625 queue_index = ((const struct rte_flow_action_queue *) 5626 (act->conf))->index; 5627 sub_action_flags |= MLX5_FLOW_ACTION_QUEUE; 5628 ++actions_n; 5629 break; 5630 case RTE_FLOW_ACTION_TYPE_RSS: 5631 *sample_rss = act->conf; 5632 ret = mlx5_flow_validate_action_rss(act, 5633 sub_action_flags, 5634 dev, attr, 5635 item_flags, 5636 error); 5637 if (ret < 0) 5638 return ret; 5639 if (rss && *sample_rss && 5640 ((*sample_rss)->level != rss->level || 5641 (*sample_rss)->types != rss->types)) 5642 return rte_flow_error_set(error, ENOTSUP, 5643 RTE_FLOW_ERROR_TYPE_ACTION, 5644 NULL, 5645 "Can't use the different RSS types " 5646 "or level in the same flow"); 5647 if (*sample_rss != NULL && (*sample_rss)->queue_num) 5648 queue_index = (*sample_rss)->queue[0]; 5649 sub_action_flags |= MLX5_FLOW_ACTION_RSS; 5650 ++actions_n; 5651 break; 5652 case RTE_FLOW_ACTION_TYPE_MARK: 5653 ret = flow_dv_validate_action_mark(dev, act, 5654 sub_action_flags, 5655 attr, error); 5656 if (ret < 0) 5657 return ret; 5658 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) 5659 sub_action_flags |= MLX5_FLOW_ACTION_MARK | 5660 MLX5_FLOW_ACTION_MARK_EXT; 5661 else 5662 sub_action_flags |= MLX5_FLOW_ACTION_MARK; 5663 ++actions_n; 5664 break; 5665 case RTE_FLOW_ACTION_TYPE_COUNT: 5666 ret = flow_dv_validate_action_count 5667 (dev, is_shared_action_count(act), 5668 *action_flags | sub_action_flags, 5669 error); 5670 if (ret < 0) 5671 return ret; 5672 *count = act->conf; 5673 sub_action_flags |= MLX5_FLOW_ACTION_COUNT; 5674 *action_flags |= MLX5_FLOW_ACTION_COUNT; 5675 ++actions_n; 5676 break; 5677 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5678 ret = flow_dv_validate_action_port_id(dev, 5679 sub_action_flags, 5680 act, 5681 attr, 5682 error); 5683 if (ret) 5684 return ret; 5685 sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID; 5686 ++actions_n; 5687 break; 5688 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 5689 ret = flow_dv_validate_action_raw_encap_decap 5690 (dev, NULL, act->conf, attr, &sub_action_flags, 5691 &actions_n, action, item_flags, error); 5692 if (ret < 0) 5693 return ret; 5694 ++actions_n; 5695 break; 5696 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 5697 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 5698 ret = flow_dv_validate_action_l2_encap(dev, 5699 sub_action_flags, 5700 act, attr, 5701 error); 5702 if (ret < 0) 5703 return ret; 5704 sub_action_flags |= MLX5_FLOW_ACTION_ENCAP; 5705 ++actions_n; 5706 break; 5707 default: 5708 return rte_flow_error_set(error, ENOTSUP, 5709 RTE_FLOW_ERROR_TYPE_ACTION, 5710 NULL, 5711 "Doesn't support optional " 5712 "action"); 5713 } 5714 } 5715 if (attr->ingress && !attr->transfer) { 5716 if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE | 5717 MLX5_FLOW_ACTION_RSS))) 5718 return rte_flow_error_set(error, EINVAL, 5719 RTE_FLOW_ERROR_TYPE_ACTION, 5720 NULL, 5721 "Ingress must has a dest " 5722 "QUEUE for Sample"); 5723 } else if (attr->egress && !attr->transfer) { 5724 return rte_flow_error_set(error, ENOTSUP, 5725 RTE_FLOW_ERROR_TYPE_ACTION, 5726 NULL, 5727 "Sample Only support Ingress " 5728 "or E-Switch"); 5729 } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) { 5730 MLX5_ASSERT(attr->transfer); 5731 if (sample->ratio > 1) 5732 return rte_flow_error_set(error, ENOTSUP, 5733 RTE_FLOW_ERROR_TYPE_ACTION, 5734 NULL, 5735 "E-Switch doesn't support " 5736 "any optional action " 5737 "for sampling"); 5738 if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) 5739 return rte_flow_error_set(error, ENOTSUP, 5740 RTE_FLOW_ERROR_TYPE_ACTION, 5741 NULL, 5742 "unsupported action QUEUE"); 5743 if (sub_action_flags & MLX5_FLOW_ACTION_RSS) 5744 return rte_flow_error_set(error, ENOTSUP, 5745 RTE_FLOW_ERROR_TYPE_ACTION, 5746 NULL, 5747 "unsupported action QUEUE"); 5748 if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID)) 5749 return rte_flow_error_set(error, EINVAL, 5750 RTE_FLOW_ERROR_TYPE_ACTION, 5751 NULL, 5752 "E-Switch must has a dest " 5753 "port for mirroring"); 5754 if (!priv->config.hca_attr.reg_c_preserve && 5755 priv->representor_id != UINT16_MAX) 5756 *fdb_mirror_limit = 1; 5757 } 5758 /* Continue validation for Xcap actions.*/ 5759 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) && 5760 (queue_index == 0xFFFF || 5761 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) { 5762 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) == 5763 MLX5_FLOW_XCAP_ACTIONS) 5764 return rte_flow_error_set(error, ENOTSUP, 5765 RTE_FLOW_ERROR_TYPE_ACTION, 5766 NULL, "encap and decap " 5767 "combination aren't " 5768 "supported"); 5769 if (!attr->transfer && attr->ingress && (sub_action_flags & 5770 MLX5_FLOW_ACTION_ENCAP)) 5771 return rte_flow_error_set(error, ENOTSUP, 5772 RTE_FLOW_ERROR_TYPE_ACTION, 5773 NULL, "encap is not supported" 5774 " for ingress traffic"); 5775 } 5776 return 0; 5777 } 5778 5779 /** 5780 * Find existing modify-header resource or create and register a new one. 5781 * 5782 * @param dev[in, out] 5783 * Pointer to rte_eth_dev structure. 5784 * @param[in, out] resource 5785 * Pointer to modify-header resource. 5786 * @parm[in, out] dev_flow 5787 * Pointer to the dev_flow. 5788 * @param[out] error 5789 * pointer to error structure. 5790 * 5791 * @return 5792 * 0 on success otherwise -errno and errno is set. 5793 */ 5794 static int 5795 flow_dv_modify_hdr_resource_register 5796 (struct rte_eth_dev *dev, 5797 struct mlx5_flow_dv_modify_hdr_resource *resource, 5798 struct mlx5_flow *dev_flow, 5799 struct rte_flow_error *error) 5800 { 5801 struct mlx5_priv *priv = dev->data->dev_private; 5802 struct mlx5_dev_ctx_shared *sh = priv->sh; 5803 uint32_t key_len = sizeof(*resource) - 5804 offsetof(typeof(*resource), ft_type) + 5805 resource->actions_num * sizeof(resource->actions[0]); 5806 struct mlx5_list_entry *entry; 5807 struct mlx5_flow_cb_ctx ctx = { 5808 .error = error, 5809 .data = resource, 5810 }; 5811 struct mlx5_hlist *modify_cmds; 5812 uint64_t key64; 5813 5814 modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds, 5815 "hdr_modify", 5816 MLX5_FLOW_HDR_MODIFY_HTABLE_SZ, 5817 true, false, sh, 5818 flow_dv_modify_create_cb, 5819 flow_dv_modify_match_cb, 5820 flow_dv_modify_remove_cb, 5821 flow_dv_modify_clone_cb, 5822 flow_dv_modify_clone_free_cb); 5823 if (unlikely(!modify_cmds)) 5824 return -rte_errno; 5825 resource->root = !dev_flow->dv.group; 5826 if (resource->actions_num > flow_dv_modify_hdr_action_max(dev, 5827 resource->root)) 5828 return rte_flow_error_set(error, EOVERFLOW, 5829 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5830 "too many modify header items"); 5831 key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0); 5832 entry = mlx5_hlist_register(modify_cmds, key64, &ctx); 5833 if (!entry) 5834 return -rte_errno; 5835 resource = container_of(entry, typeof(*resource), entry); 5836 dev_flow->handle->dvh.modify_hdr = resource; 5837 return 0; 5838 } 5839 5840 /** 5841 * Get DV flow counter by index. 5842 * 5843 * @param[in] dev 5844 * Pointer to the Ethernet device structure. 5845 * @param[in] idx 5846 * mlx5 flow counter index in the container. 5847 * @param[out] ppool 5848 * mlx5 flow counter pool in the container. 5849 * 5850 * @return 5851 * Pointer to the counter, NULL otherwise. 5852 */ 5853 static struct mlx5_flow_counter * 5854 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev, 5855 uint32_t idx, 5856 struct mlx5_flow_counter_pool **ppool) 5857 { 5858 struct mlx5_priv *priv = dev->data->dev_private; 5859 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5860 struct mlx5_flow_counter_pool *pool; 5861 5862 /* Decrease to original index and clear shared bit. */ 5863 idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1); 5864 MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n); 5865 pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL]; 5866 MLX5_ASSERT(pool); 5867 if (ppool) 5868 *ppool = pool; 5869 return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL); 5870 } 5871 5872 /** 5873 * Check the devx counter belongs to the pool. 5874 * 5875 * @param[in] pool 5876 * Pointer to the counter pool. 5877 * @param[in] id 5878 * The counter devx ID. 5879 * 5880 * @return 5881 * True if counter belongs to the pool, false otherwise. 5882 */ 5883 static bool 5884 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id) 5885 { 5886 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) * 5887 MLX5_COUNTERS_PER_POOL; 5888 5889 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL) 5890 return true; 5891 return false; 5892 } 5893 5894 /** 5895 * Get a pool by devx counter ID. 5896 * 5897 * @param[in] cmng 5898 * Pointer to the counter management. 5899 * @param[in] id 5900 * The counter devx ID. 5901 * 5902 * @return 5903 * The counter pool pointer if exists, NULL otherwise, 5904 */ 5905 static struct mlx5_flow_counter_pool * 5906 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id) 5907 { 5908 uint32_t i; 5909 struct mlx5_flow_counter_pool *pool = NULL; 5910 5911 rte_spinlock_lock(&cmng->pool_update_sl); 5912 /* Check last used pool. */ 5913 if (cmng->last_pool_idx != POOL_IDX_INVALID && 5914 flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) { 5915 pool = cmng->pools[cmng->last_pool_idx]; 5916 goto out; 5917 } 5918 /* ID out of range means no suitable pool in the container. */ 5919 if (id > cmng->max_id || id < cmng->min_id) 5920 goto out; 5921 /* 5922 * Find the pool from the end of the container, since mostly counter 5923 * ID is sequence increasing, and the last pool should be the needed 5924 * one. 5925 */ 5926 i = cmng->n_valid; 5927 while (i--) { 5928 struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i]; 5929 5930 if (flow_dv_is_counter_in_pool(pool_tmp, id)) { 5931 pool = pool_tmp; 5932 break; 5933 } 5934 } 5935 out: 5936 rte_spinlock_unlock(&cmng->pool_update_sl); 5937 return pool; 5938 } 5939 5940 /** 5941 * Resize a counter container. 5942 * 5943 * @param[in] dev 5944 * Pointer to the Ethernet device structure. 5945 * 5946 * @return 5947 * 0 on success, otherwise negative errno value and rte_errno is set. 5948 */ 5949 static int 5950 flow_dv_container_resize(struct rte_eth_dev *dev) 5951 { 5952 struct mlx5_priv *priv = dev->data->dev_private; 5953 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5954 void *old_pools = cmng->pools; 5955 uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE; 5956 uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize; 5957 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 5958 5959 if (!pools) { 5960 rte_errno = ENOMEM; 5961 return -ENOMEM; 5962 } 5963 if (old_pools) 5964 memcpy(pools, old_pools, cmng->n * 5965 sizeof(struct mlx5_flow_counter_pool *)); 5966 cmng->n = resize; 5967 cmng->pools = pools; 5968 if (old_pools) 5969 mlx5_free(old_pools); 5970 return 0; 5971 } 5972 5973 /** 5974 * Query a devx flow counter. 5975 * 5976 * @param[in] dev 5977 * Pointer to the Ethernet device structure. 5978 * @param[in] counter 5979 * Index to the flow counter. 5980 * @param[out] pkts 5981 * The statistics value of packets. 5982 * @param[out] bytes 5983 * The statistics value of bytes. 5984 * 5985 * @return 5986 * 0 on success, otherwise a negative errno value and rte_errno is set. 5987 */ 5988 static inline int 5989 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts, 5990 uint64_t *bytes) 5991 { 5992 struct mlx5_priv *priv = dev->data->dev_private; 5993 struct mlx5_flow_counter_pool *pool = NULL; 5994 struct mlx5_flow_counter *cnt; 5995 int offset; 5996 5997 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 5998 MLX5_ASSERT(pool); 5999 if (priv->sh->cmng.counter_fallback) 6000 return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0, 6001 0, pkts, bytes, 0, NULL, NULL, 0); 6002 rte_spinlock_lock(&pool->sl); 6003 if (!pool->raw) { 6004 *pkts = 0; 6005 *bytes = 0; 6006 } else { 6007 offset = MLX5_CNT_ARRAY_IDX(pool, cnt); 6008 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits); 6009 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes); 6010 } 6011 rte_spinlock_unlock(&pool->sl); 6012 return 0; 6013 } 6014 6015 /** 6016 * Create and initialize a new counter pool. 6017 * 6018 * @param[in] dev 6019 * Pointer to the Ethernet device structure. 6020 * @param[out] dcs 6021 * The devX counter handle. 6022 * @param[in] age 6023 * Whether the pool is for counter that was allocated for aging. 6024 * @param[in/out] cont_cur 6025 * Pointer to the container pointer, it will be update in pool resize. 6026 * 6027 * @return 6028 * The pool container pointer on success, NULL otherwise and rte_errno is set. 6029 */ 6030 static struct mlx5_flow_counter_pool * 6031 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs, 6032 uint32_t age) 6033 { 6034 struct mlx5_priv *priv = dev->data->dev_private; 6035 struct mlx5_flow_counter_pool *pool; 6036 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6037 bool fallback = priv->sh->cmng.counter_fallback; 6038 uint32_t size = sizeof(*pool); 6039 6040 size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE; 6041 size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE); 6042 pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY); 6043 if (!pool) { 6044 rte_errno = ENOMEM; 6045 return NULL; 6046 } 6047 pool->raw = NULL; 6048 pool->is_aged = !!age; 6049 pool->query_gen = 0; 6050 pool->min_dcs = dcs; 6051 rte_spinlock_init(&pool->sl); 6052 rte_spinlock_init(&pool->csl); 6053 TAILQ_INIT(&pool->counters[0]); 6054 TAILQ_INIT(&pool->counters[1]); 6055 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 6056 rte_spinlock_lock(&cmng->pool_update_sl); 6057 pool->index = cmng->n_valid; 6058 if (pool->index == cmng->n && flow_dv_container_resize(dev)) { 6059 mlx5_free(pool); 6060 rte_spinlock_unlock(&cmng->pool_update_sl); 6061 return NULL; 6062 } 6063 cmng->pools[pool->index] = pool; 6064 cmng->n_valid++; 6065 if (unlikely(fallback)) { 6066 int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL); 6067 6068 if (base < cmng->min_id) 6069 cmng->min_id = base; 6070 if (base > cmng->max_id) 6071 cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1; 6072 cmng->last_pool_idx = pool->index; 6073 } 6074 rte_spinlock_unlock(&cmng->pool_update_sl); 6075 return pool; 6076 } 6077 6078 /** 6079 * Prepare a new counter and/or a new counter pool. 6080 * 6081 * @param[in] dev 6082 * Pointer to the Ethernet device structure. 6083 * @param[out] cnt_free 6084 * Where to put the pointer of a new counter. 6085 * @param[in] age 6086 * Whether the pool is for counter that was allocated for aging. 6087 * 6088 * @return 6089 * The counter pool pointer and @p cnt_free is set on success, 6090 * NULL otherwise and rte_errno is set. 6091 */ 6092 static struct mlx5_flow_counter_pool * 6093 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev, 6094 struct mlx5_flow_counter **cnt_free, 6095 uint32_t age) 6096 { 6097 struct mlx5_priv *priv = dev->data->dev_private; 6098 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6099 struct mlx5_flow_counter_pool *pool; 6100 struct mlx5_counters tmp_tq; 6101 struct mlx5_devx_obj *dcs = NULL; 6102 struct mlx5_flow_counter *cnt; 6103 enum mlx5_counter_type cnt_type = 6104 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6105 bool fallback = priv->sh->cmng.counter_fallback; 6106 uint32_t i; 6107 6108 if (fallback) { 6109 /* bulk_bitmap must be 0 for single counter allocation. */ 6110 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0); 6111 if (!dcs) 6112 return NULL; 6113 pool = flow_dv_find_pool_by_id(cmng, dcs->id); 6114 if (!pool) { 6115 pool = flow_dv_pool_create(dev, dcs, age); 6116 if (!pool) { 6117 mlx5_devx_cmd_destroy(dcs); 6118 return NULL; 6119 } 6120 } 6121 i = dcs->id % MLX5_COUNTERS_PER_POOL; 6122 cnt = MLX5_POOL_GET_CNT(pool, i); 6123 cnt->pool = pool; 6124 cnt->dcs_when_free = dcs; 6125 *cnt_free = cnt; 6126 return pool; 6127 } 6128 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4); 6129 if (!dcs) { 6130 rte_errno = ENODATA; 6131 return NULL; 6132 } 6133 pool = flow_dv_pool_create(dev, dcs, age); 6134 if (!pool) { 6135 mlx5_devx_cmd_destroy(dcs); 6136 return NULL; 6137 } 6138 TAILQ_INIT(&tmp_tq); 6139 for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) { 6140 cnt = MLX5_POOL_GET_CNT(pool, i); 6141 cnt->pool = pool; 6142 TAILQ_INSERT_HEAD(&tmp_tq, cnt, next); 6143 } 6144 rte_spinlock_lock(&cmng->csl[cnt_type]); 6145 TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next); 6146 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6147 *cnt_free = MLX5_POOL_GET_CNT(pool, 0); 6148 (*cnt_free)->pool = pool; 6149 return pool; 6150 } 6151 6152 /** 6153 * Allocate a flow counter. 6154 * 6155 * @param[in] dev 6156 * Pointer to the Ethernet device structure. 6157 * @param[in] age 6158 * Whether the counter was allocated for aging. 6159 * 6160 * @return 6161 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6162 */ 6163 static uint32_t 6164 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) 6165 { 6166 struct mlx5_priv *priv = dev->data->dev_private; 6167 struct mlx5_flow_counter_pool *pool = NULL; 6168 struct mlx5_flow_counter *cnt_free = NULL; 6169 bool fallback = priv->sh->cmng.counter_fallback; 6170 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6171 enum mlx5_counter_type cnt_type = 6172 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6173 uint32_t cnt_idx; 6174 6175 if (!priv->config.devx) { 6176 rte_errno = ENOTSUP; 6177 return 0; 6178 } 6179 /* Get free counters from container. */ 6180 rte_spinlock_lock(&cmng->csl[cnt_type]); 6181 cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]); 6182 if (cnt_free) 6183 TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next); 6184 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6185 if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age)) 6186 goto err; 6187 pool = cnt_free->pool; 6188 if (fallback) 6189 cnt_free->dcs_when_active = cnt_free->dcs_when_free; 6190 /* Create a DV counter action only in the first time usage. */ 6191 if (!cnt_free->action) { 6192 uint16_t offset; 6193 struct mlx5_devx_obj *dcs; 6194 int ret; 6195 6196 if (!fallback) { 6197 offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free); 6198 dcs = pool->min_dcs; 6199 } else { 6200 offset = 0; 6201 dcs = cnt_free->dcs_when_free; 6202 } 6203 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset, 6204 &cnt_free->action); 6205 if (ret) { 6206 rte_errno = errno; 6207 goto err; 6208 } 6209 } 6210 cnt_idx = MLX5_MAKE_CNT_IDX(pool->index, 6211 MLX5_CNT_ARRAY_IDX(pool, cnt_free)); 6212 /* Update the counter reset values. */ 6213 if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits, 6214 &cnt_free->bytes)) 6215 goto err; 6216 if (!fallback && !priv->sh->cmng.query_thread_on) 6217 /* Start the asynchronous batch query by the host thread. */ 6218 mlx5_set_query_alarm(priv->sh); 6219 /* 6220 * When the count action isn't shared (by ID), shared_info field is 6221 * used for indirect action API's refcnt. 6222 * When the counter action is not shared neither by ID nor by indirect 6223 * action API, shared info must be 1. 6224 */ 6225 cnt_free->shared_info.refcnt = 1; 6226 return cnt_idx; 6227 err: 6228 if (cnt_free) { 6229 cnt_free->pool = pool; 6230 if (fallback) 6231 cnt_free->dcs_when_free = cnt_free->dcs_when_active; 6232 rte_spinlock_lock(&cmng->csl[cnt_type]); 6233 TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next); 6234 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6235 } 6236 return 0; 6237 } 6238 6239 /** 6240 * Allocate a shared flow counter. 6241 * 6242 * @param[in] ctx 6243 * Pointer to the shared counter configuration. 6244 * @param[in] data 6245 * Pointer to save the allocated counter index. 6246 * 6247 * @return 6248 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6249 */ 6250 6251 static int32_t 6252 flow_dv_counter_alloc_shared_cb(void *ctx, union mlx5_l3t_data *data) 6253 { 6254 struct mlx5_shared_counter_conf *conf = ctx; 6255 struct rte_eth_dev *dev = conf->dev; 6256 struct mlx5_flow_counter *cnt; 6257 6258 data->dword = flow_dv_counter_alloc(dev, 0); 6259 data->dword |= MLX5_CNT_SHARED_OFFSET; 6260 cnt = flow_dv_counter_get_by_idx(dev, data->dword, NULL); 6261 cnt->shared_info.id = conf->id; 6262 return 0; 6263 } 6264 6265 /** 6266 * Get a shared flow counter. 6267 * 6268 * @param[in] dev 6269 * Pointer to the Ethernet device structure. 6270 * @param[in] id 6271 * Counter identifier. 6272 * 6273 * @return 6274 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6275 */ 6276 static uint32_t 6277 flow_dv_counter_get_shared(struct rte_eth_dev *dev, uint32_t id) 6278 { 6279 struct mlx5_priv *priv = dev->data->dev_private; 6280 struct mlx5_shared_counter_conf conf = { 6281 .dev = dev, 6282 .id = id, 6283 }; 6284 union mlx5_l3t_data data = { 6285 .dword = 0, 6286 }; 6287 6288 mlx5_l3t_prepare_entry(priv->sh->cnt_id_tbl, id, &data, 6289 flow_dv_counter_alloc_shared_cb, &conf); 6290 return data.dword; 6291 } 6292 6293 /** 6294 * Get age param from counter index. 6295 * 6296 * @param[in] dev 6297 * Pointer to the Ethernet device structure. 6298 * @param[in] counter 6299 * Index to the counter handler. 6300 * 6301 * @return 6302 * The aging parameter specified for the counter index. 6303 */ 6304 static struct mlx5_age_param* 6305 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev, 6306 uint32_t counter) 6307 { 6308 struct mlx5_flow_counter *cnt; 6309 struct mlx5_flow_counter_pool *pool = NULL; 6310 6311 flow_dv_counter_get_by_idx(dev, counter, &pool); 6312 counter = (counter - 1) % MLX5_COUNTERS_PER_POOL; 6313 cnt = MLX5_POOL_GET_CNT(pool, counter); 6314 return MLX5_CNT_TO_AGE(cnt); 6315 } 6316 6317 /** 6318 * Remove a flow counter from aged counter list. 6319 * 6320 * @param[in] dev 6321 * Pointer to the Ethernet device structure. 6322 * @param[in] counter 6323 * Index to the counter handler. 6324 * @param[in] cnt 6325 * Pointer to the counter handler. 6326 */ 6327 static void 6328 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev, 6329 uint32_t counter, struct mlx5_flow_counter *cnt) 6330 { 6331 struct mlx5_age_info *age_info; 6332 struct mlx5_age_param *age_param; 6333 struct mlx5_priv *priv = dev->data->dev_private; 6334 uint16_t expected = AGE_CANDIDATE; 6335 6336 age_info = GET_PORT_AGE_INFO(priv); 6337 age_param = flow_dv_counter_idx_get_age(dev, counter); 6338 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 6339 AGE_FREE, false, __ATOMIC_RELAXED, 6340 __ATOMIC_RELAXED)) { 6341 /** 6342 * We need the lock even it is age timeout, 6343 * since counter may still in process. 6344 */ 6345 rte_spinlock_lock(&age_info->aged_sl); 6346 TAILQ_REMOVE(&age_info->aged_counters, cnt, next); 6347 rte_spinlock_unlock(&age_info->aged_sl); 6348 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 6349 } 6350 } 6351 6352 /** 6353 * Release a flow counter. 6354 * 6355 * @param[in] dev 6356 * Pointer to the Ethernet device structure. 6357 * @param[in] counter 6358 * Index to the counter handler. 6359 */ 6360 static void 6361 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) 6362 { 6363 struct mlx5_priv *priv = dev->data->dev_private; 6364 struct mlx5_flow_counter_pool *pool = NULL; 6365 struct mlx5_flow_counter *cnt; 6366 enum mlx5_counter_type cnt_type; 6367 6368 if (!counter) 6369 return; 6370 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 6371 MLX5_ASSERT(pool); 6372 if (pool->is_aged) { 6373 flow_dv_counter_remove_from_age(dev, counter, cnt); 6374 } else { 6375 /* 6376 * If the counter action is shared by ID, the l3t_clear_entry 6377 * function reduces its references counter. If after the 6378 * reduction the action is still referenced, the function 6379 * returns here and does not release it. 6380 */ 6381 if (IS_LEGACY_SHARED_CNT(counter) && 6382 mlx5_l3t_clear_entry(priv->sh->cnt_id_tbl, 6383 cnt->shared_info.id)) 6384 return; 6385 /* 6386 * If the counter action is shared by indirect action API, 6387 * the atomic function reduces its references counter. 6388 * If after the reduction the action is still referenced, the 6389 * function returns here and does not release it. 6390 * When the counter action is not shared neither by ID nor by 6391 * indirect action API, shared info is 1 before the reduction, 6392 * so this condition is failed and function doesn't return here. 6393 */ 6394 if (!IS_LEGACY_SHARED_CNT(counter) && 6395 __atomic_sub_fetch(&cnt->shared_info.refcnt, 1, 6396 __ATOMIC_RELAXED)) 6397 return; 6398 } 6399 cnt->pool = pool; 6400 /* 6401 * Put the counter back to list to be updated in none fallback mode. 6402 * Currently, we are using two list alternately, while one is in query, 6403 * add the freed counter to the other list based on the pool query_gen 6404 * value. After query finishes, add counter the list to the global 6405 * container counter list. The list changes while query starts. In 6406 * this case, lock will not be needed as query callback and release 6407 * function both operate with the different list. 6408 */ 6409 if (!priv->sh->cmng.counter_fallback) { 6410 rte_spinlock_lock(&pool->csl); 6411 TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); 6412 rte_spinlock_unlock(&pool->csl); 6413 } else { 6414 cnt->dcs_when_free = cnt->dcs_when_active; 6415 cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : 6416 MLX5_COUNTER_TYPE_ORIGIN; 6417 rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]); 6418 TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type], 6419 cnt, next); 6420 rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]); 6421 } 6422 } 6423 6424 /** 6425 * Resize a meter id container. 6426 * 6427 * @param[in] dev 6428 * Pointer to the Ethernet device structure. 6429 * 6430 * @return 6431 * 0 on success, otherwise negative errno value and rte_errno is set. 6432 */ 6433 static int 6434 flow_dv_mtr_container_resize(struct rte_eth_dev *dev) 6435 { 6436 struct mlx5_priv *priv = dev->data->dev_private; 6437 struct mlx5_aso_mtr_pools_mng *pools_mng = 6438 &priv->sh->mtrmng->pools_mng; 6439 void *old_pools = pools_mng->pools; 6440 uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE; 6441 uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize; 6442 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 6443 6444 if (!pools) { 6445 rte_errno = ENOMEM; 6446 return -ENOMEM; 6447 } 6448 if (!pools_mng->n) 6449 if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { 6450 mlx5_free(pools); 6451 return -ENOMEM; 6452 } 6453 if (old_pools) 6454 memcpy(pools, old_pools, pools_mng->n * 6455 sizeof(struct mlx5_aso_mtr_pool *)); 6456 pools_mng->n = resize; 6457 pools_mng->pools = pools; 6458 if (old_pools) 6459 mlx5_free(old_pools); 6460 return 0; 6461 } 6462 6463 /** 6464 * Prepare a new meter and/or a new meter pool. 6465 * 6466 * @param[in] dev 6467 * Pointer to the Ethernet device structure. 6468 * @param[out] mtr_free 6469 * Where to put the pointer of a new meter.g. 6470 * 6471 * @return 6472 * The meter pool pointer and @mtr_free is set on success, 6473 * NULL otherwise and rte_errno is set. 6474 */ 6475 static struct mlx5_aso_mtr_pool * 6476 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, 6477 struct mlx5_aso_mtr **mtr_free) 6478 { 6479 struct mlx5_priv *priv = dev->data->dev_private; 6480 struct mlx5_aso_mtr_pools_mng *pools_mng = 6481 &priv->sh->mtrmng->pools_mng; 6482 struct mlx5_aso_mtr_pool *pool = NULL; 6483 struct mlx5_devx_obj *dcs = NULL; 6484 uint32_t i; 6485 uint32_t log_obj_size; 6486 6487 log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1); 6488 dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->ctx, 6489 priv->sh->pdn, log_obj_size); 6490 if (!dcs) { 6491 rte_errno = ENODATA; 6492 return NULL; 6493 } 6494 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 6495 if (!pool) { 6496 rte_errno = ENOMEM; 6497 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6498 return NULL; 6499 } 6500 pool->devx_obj = dcs; 6501 pool->index = pools_mng->n_valid; 6502 if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) { 6503 mlx5_free(pool); 6504 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6505 return NULL; 6506 } 6507 pools_mng->pools[pool->index] = pool; 6508 pools_mng->n_valid++; 6509 for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) { 6510 pool->mtrs[i].offset = i; 6511 LIST_INSERT_HEAD(&pools_mng->meters, 6512 &pool->mtrs[i], next); 6513 } 6514 pool->mtrs[0].offset = 0; 6515 *mtr_free = &pool->mtrs[0]; 6516 return pool; 6517 } 6518 6519 /** 6520 * Release a flow meter into pool. 6521 * 6522 * @param[in] dev 6523 * Pointer to the Ethernet device structure. 6524 * @param[in] mtr_idx 6525 * Index to aso flow meter. 6526 */ 6527 static void 6528 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx) 6529 { 6530 struct mlx5_priv *priv = dev->data->dev_private; 6531 struct mlx5_aso_mtr_pools_mng *pools_mng = 6532 &priv->sh->mtrmng->pools_mng; 6533 struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 6534 6535 MLX5_ASSERT(aso_mtr); 6536 rte_spinlock_lock(&pools_mng->mtrsl); 6537 memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info)); 6538 aso_mtr->state = ASO_METER_FREE; 6539 LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next); 6540 rte_spinlock_unlock(&pools_mng->mtrsl); 6541 } 6542 6543 /** 6544 * Allocate a aso flow meter. 6545 * 6546 * @param[in] dev 6547 * Pointer to the Ethernet device structure. 6548 * 6549 * @return 6550 * Index to aso flow meter on success, 0 otherwise and rte_errno is set. 6551 */ 6552 static uint32_t 6553 flow_dv_mtr_alloc(struct rte_eth_dev *dev) 6554 { 6555 struct mlx5_priv *priv = dev->data->dev_private; 6556 struct mlx5_aso_mtr *mtr_free = NULL; 6557 struct mlx5_aso_mtr_pools_mng *pools_mng = 6558 &priv->sh->mtrmng->pools_mng; 6559 struct mlx5_aso_mtr_pool *pool; 6560 uint32_t mtr_idx = 0; 6561 6562 if (!priv->config.devx) { 6563 rte_errno = ENOTSUP; 6564 return 0; 6565 } 6566 /* Allocate the flow meter memory. */ 6567 /* Get free meters from management. */ 6568 rte_spinlock_lock(&pools_mng->mtrsl); 6569 mtr_free = LIST_FIRST(&pools_mng->meters); 6570 if (mtr_free) 6571 LIST_REMOVE(mtr_free, next); 6572 if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) { 6573 rte_spinlock_unlock(&pools_mng->mtrsl); 6574 return 0; 6575 } 6576 mtr_free->state = ASO_METER_WAIT; 6577 rte_spinlock_unlock(&pools_mng->mtrsl); 6578 pool = container_of(mtr_free, 6579 struct mlx5_aso_mtr_pool, 6580 mtrs[mtr_free->offset]); 6581 mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset); 6582 if (!mtr_free->fm.meter_action) { 6583 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 6584 struct rte_flow_error error; 6585 uint8_t reg_id; 6586 6587 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error); 6588 mtr_free->fm.meter_action = 6589 mlx5_glue->dv_create_flow_action_aso 6590 (priv->sh->rx_domain, 6591 pool->devx_obj->obj, 6592 mtr_free->offset, 6593 (1 << MLX5_FLOW_COLOR_GREEN), 6594 reg_id - REG_C_0); 6595 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 6596 if (!mtr_free->fm.meter_action) { 6597 flow_dv_aso_mtr_release_to_pool(dev, mtr_idx); 6598 return 0; 6599 } 6600 } 6601 return mtr_idx; 6602 } 6603 6604 /** 6605 * Verify the @p attributes will be correctly understood by the NIC and store 6606 * them in the @p flow if everything is correct. 6607 * 6608 * @param[in] dev 6609 * Pointer to dev struct. 6610 * @param[in] attributes 6611 * Pointer to flow attributes 6612 * @param[in] external 6613 * This flow rule is created by request external to PMD. 6614 * @param[out] error 6615 * Pointer to error structure. 6616 * 6617 * @return 6618 * - 0 on success and non root table. 6619 * - 1 on success and root table. 6620 * - a negative errno value otherwise and rte_errno is set. 6621 */ 6622 static int 6623 flow_dv_validate_attributes(struct rte_eth_dev *dev, 6624 const struct mlx5_flow_tunnel *tunnel, 6625 const struct rte_flow_attr *attributes, 6626 const struct flow_grp_info *grp_info, 6627 struct rte_flow_error *error) 6628 { 6629 struct mlx5_priv *priv = dev->data->dev_private; 6630 uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes); 6631 int ret = 0; 6632 6633 #ifndef HAVE_MLX5DV_DR 6634 RTE_SET_USED(tunnel); 6635 RTE_SET_USED(grp_info); 6636 if (attributes->group) 6637 return rte_flow_error_set(error, ENOTSUP, 6638 RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 6639 NULL, 6640 "groups are not supported"); 6641 #else 6642 uint32_t table = 0; 6643 6644 ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table, 6645 grp_info, error); 6646 if (ret) 6647 return ret; 6648 if (!table) 6649 ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL; 6650 #endif 6651 if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR && 6652 attributes->priority > lowest_priority) 6653 return rte_flow_error_set(error, ENOTSUP, 6654 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 6655 NULL, 6656 "priority out of range"); 6657 if (attributes->transfer) { 6658 if (!priv->config.dv_esw_en) 6659 return rte_flow_error_set 6660 (error, ENOTSUP, 6661 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 6662 "E-Switch dr is not supported"); 6663 if (!(priv->representor || priv->master)) 6664 return rte_flow_error_set 6665 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6666 NULL, "E-Switch configuration can only be" 6667 " done by a master or a representor device"); 6668 if (attributes->egress) 6669 return rte_flow_error_set 6670 (error, ENOTSUP, 6671 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes, 6672 "egress is not supported"); 6673 } 6674 if (!(attributes->egress ^ attributes->ingress)) 6675 return rte_flow_error_set(error, ENOTSUP, 6676 RTE_FLOW_ERROR_TYPE_ATTR, NULL, 6677 "must specify exactly one of " 6678 "ingress or egress"); 6679 return ret; 6680 } 6681 6682 static uint16_t 6683 mlx5_flow_locate_proto_l3(const struct rte_flow_item **head, 6684 const struct rte_flow_item *end) 6685 { 6686 const struct rte_flow_item *item = *head; 6687 uint16_t l3_protocol; 6688 6689 for (; item != end; item++) { 6690 switch (item->type) { 6691 default: 6692 break; 6693 case RTE_FLOW_ITEM_TYPE_IPV4: 6694 l3_protocol = RTE_ETHER_TYPE_IPV4; 6695 goto l3_ok; 6696 case RTE_FLOW_ITEM_TYPE_IPV6: 6697 l3_protocol = RTE_ETHER_TYPE_IPV6; 6698 goto l3_ok; 6699 case RTE_FLOW_ITEM_TYPE_ETH: 6700 if (item->mask && item->spec) { 6701 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_eth, 6702 type, item, 6703 l3_protocol); 6704 if (l3_protocol == RTE_ETHER_TYPE_IPV4 || 6705 l3_protocol == RTE_ETHER_TYPE_IPV6) 6706 goto l3_ok; 6707 } 6708 break; 6709 case RTE_FLOW_ITEM_TYPE_VLAN: 6710 if (item->mask && item->spec) { 6711 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_vlan, 6712 inner_type, item, 6713 l3_protocol); 6714 if (l3_protocol == RTE_ETHER_TYPE_IPV4 || 6715 l3_protocol == RTE_ETHER_TYPE_IPV6) 6716 goto l3_ok; 6717 } 6718 break; 6719 } 6720 } 6721 return 0; 6722 l3_ok: 6723 *head = item; 6724 return l3_protocol; 6725 } 6726 6727 static uint8_t 6728 mlx5_flow_locate_proto_l4(const struct rte_flow_item **head, 6729 const struct rte_flow_item *end) 6730 { 6731 const struct rte_flow_item *item = *head; 6732 uint8_t l4_protocol; 6733 6734 for (; item != end; item++) { 6735 switch (item->type) { 6736 default: 6737 break; 6738 case RTE_FLOW_ITEM_TYPE_TCP: 6739 l4_protocol = IPPROTO_TCP; 6740 goto l4_ok; 6741 case RTE_FLOW_ITEM_TYPE_UDP: 6742 l4_protocol = IPPROTO_UDP; 6743 goto l4_ok; 6744 case RTE_FLOW_ITEM_TYPE_IPV4: 6745 if (item->mask && item->spec) { 6746 const struct rte_flow_item_ipv4 *mask, *spec; 6747 6748 mask = (typeof(mask))item->mask; 6749 spec = (typeof(spec))item->spec; 6750 l4_protocol = mask->hdr.next_proto_id & 6751 spec->hdr.next_proto_id; 6752 if (l4_protocol == IPPROTO_TCP || 6753 l4_protocol == IPPROTO_UDP) 6754 goto l4_ok; 6755 } 6756 break; 6757 case RTE_FLOW_ITEM_TYPE_IPV6: 6758 if (item->mask && item->spec) { 6759 const struct rte_flow_item_ipv6 *mask, *spec; 6760 mask = (typeof(mask))item->mask; 6761 spec = (typeof(spec))item->spec; 6762 l4_protocol = mask->hdr.proto & spec->hdr.proto; 6763 if (l4_protocol == IPPROTO_TCP || 6764 l4_protocol == IPPROTO_UDP) 6765 goto l4_ok; 6766 } 6767 break; 6768 } 6769 } 6770 return 0; 6771 l4_ok: 6772 *head = item; 6773 return l4_protocol; 6774 } 6775 6776 static int 6777 flow_dv_validate_item_integrity(struct rte_eth_dev *dev, 6778 const struct rte_flow_item *rule_items, 6779 const struct rte_flow_item *integrity_item, 6780 struct rte_flow_error *error) 6781 { 6782 struct mlx5_priv *priv = dev->data->dev_private; 6783 const struct rte_flow_item *tunnel_item, *end_item, *item = rule_items; 6784 const struct rte_flow_item_integrity *mask = (typeof(mask)) 6785 integrity_item->mask; 6786 const struct rte_flow_item_integrity *spec = (typeof(spec)) 6787 integrity_item->spec; 6788 uint32_t protocol; 6789 6790 if (!priv->config.hca_attr.pkt_integrity_match) 6791 return rte_flow_error_set(error, ENOTSUP, 6792 RTE_FLOW_ERROR_TYPE_ITEM, 6793 integrity_item, 6794 "packet integrity integrity_item not supported"); 6795 if (!mask) 6796 mask = &rte_flow_item_integrity_mask; 6797 if (!mlx5_validate_integrity_item(mask)) 6798 return rte_flow_error_set(error, ENOTSUP, 6799 RTE_FLOW_ERROR_TYPE_ITEM, 6800 integrity_item, 6801 "unsupported integrity filter"); 6802 tunnel_item = mlx5_flow_find_tunnel_item(rule_items); 6803 if (spec->level > 1) { 6804 if (!tunnel_item) 6805 return rte_flow_error_set(error, ENOTSUP, 6806 RTE_FLOW_ERROR_TYPE_ITEM, 6807 integrity_item, 6808 "missing tunnel item"); 6809 item = tunnel_item; 6810 end_item = mlx5_find_end_item(tunnel_item); 6811 } else { 6812 end_item = tunnel_item ? tunnel_item : 6813 mlx5_find_end_item(integrity_item); 6814 } 6815 if (mask->l3_ok || mask->ipv4_csum_ok) { 6816 protocol = mlx5_flow_locate_proto_l3(&item, end_item); 6817 if (!protocol) 6818 return rte_flow_error_set(error, EINVAL, 6819 RTE_FLOW_ERROR_TYPE_ITEM, 6820 integrity_item, 6821 "missing L3 protocol"); 6822 } 6823 if (mask->l4_ok || mask->l4_csum_ok) { 6824 protocol = mlx5_flow_locate_proto_l4(&item, end_item); 6825 if (!protocol) 6826 return rte_flow_error_set(error, EINVAL, 6827 RTE_FLOW_ERROR_TYPE_ITEM, 6828 integrity_item, 6829 "missing L4 protocol"); 6830 } 6831 return 0; 6832 } 6833 6834 /** 6835 * Internal validation function. For validating both actions and items. 6836 * 6837 * @param[in] dev 6838 * Pointer to the rte_eth_dev structure. 6839 * @param[in] attr 6840 * Pointer to the flow attributes. 6841 * @param[in] items 6842 * Pointer to the list of items. 6843 * @param[in] actions 6844 * Pointer to the list of actions. 6845 * @param[in] external 6846 * This flow rule is created by request external to PMD. 6847 * @param[in] hairpin 6848 * Number of hairpin TX actions, 0 means classic flow. 6849 * @param[out] error 6850 * Pointer to the error structure. 6851 * 6852 * @return 6853 * 0 on success, a negative errno value otherwise and rte_errno is set. 6854 */ 6855 static int 6856 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, 6857 const struct rte_flow_item items[], 6858 const struct rte_flow_action actions[], 6859 bool external, int hairpin, struct rte_flow_error *error) 6860 { 6861 int ret; 6862 uint64_t action_flags = 0; 6863 uint64_t item_flags = 0; 6864 uint64_t last_item = 0; 6865 uint8_t next_protocol = 0xff; 6866 uint16_t ether_type = 0; 6867 int actions_n = 0; 6868 uint8_t item_ipv6_proto = 0; 6869 int fdb_mirror_limit = 0; 6870 int modify_after_mirror = 0; 6871 const struct rte_flow_item *geneve_item = NULL; 6872 const struct rte_flow_item *gre_item = NULL; 6873 const struct rte_flow_item *gtp_item = NULL; 6874 const struct rte_flow_action_raw_decap *decap; 6875 const struct rte_flow_action_raw_encap *encap; 6876 const struct rte_flow_action_rss *rss = NULL; 6877 const struct rte_flow_action_rss *sample_rss = NULL; 6878 const struct rte_flow_action_count *sample_count = NULL; 6879 const struct rte_flow_item_tcp nic_tcp_mask = { 6880 .hdr = { 6881 .tcp_flags = 0xFF, 6882 .src_port = RTE_BE16(UINT16_MAX), 6883 .dst_port = RTE_BE16(UINT16_MAX), 6884 } 6885 }; 6886 const struct rte_flow_item_ipv6 nic_ipv6_mask = { 6887 .hdr = { 6888 .src_addr = 6889 "\xff\xff\xff\xff\xff\xff\xff\xff" 6890 "\xff\xff\xff\xff\xff\xff\xff\xff", 6891 .dst_addr = 6892 "\xff\xff\xff\xff\xff\xff\xff\xff" 6893 "\xff\xff\xff\xff\xff\xff\xff\xff", 6894 .vtc_flow = RTE_BE32(0xffffffff), 6895 .proto = 0xff, 6896 .hop_limits = 0xff, 6897 }, 6898 .has_frag_ext = 1, 6899 }; 6900 const struct rte_flow_item_ecpri nic_ecpri_mask = { 6901 .hdr = { 6902 .common = { 6903 .u32 = 6904 RTE_BE32(((const struct rte_ecpri_common_hdr) { 6905 .type = 0xFF, 6906 }).u32), 6907 }, 6908 .dummy[0] = 0xffffffff, 6909 }, 6910 }; 6911 struct mlx5_priv *priv = dev->data->dev_private; 6912 struct mlx5_dev_config *dev_conf = &priv->config; 6913 uint16_t queue_index = 0xFFFF; 6914 const struct rte_flow_item_vlan *vlan_m = NULL; 6915 uint32_t rw_act_num = 0; 6916 uint64_t is_root; 6917 const struct mlx5_flow_tunnel *tunnel; 6918 enum mlx5_tof_rule_type tof_rule_type; 6919 struct flow_grp_info grp_info = { 6920 .external = !!external, 6921 .transfer = !!attr->transfer, 6922 .fdb_def_rule = !!priv->fdb_def_rule, 6923 .std_tbl_fix = true, 6924 }; 6925 const struct rte_eth_hairpin_conf *conf; 6926 const struct rte_flow_item *rule_items = items; 6927 const struct rte_flow_item *port_id_item = NULL; 6928 bool def_policy = false; 6929 uint16_t udp_dport = 0; 6930 6931 if (items == NULL) 6932 return -1; 6933 tunnel = is_tunnel_offload_active(dev) ? 6934 mlx5_get_tof(items, actions, &tof_rule_type) : NULL; 6935 if (tunnel) { 6936 if (priv->representor) 6937 return rte_flow_error_set 6938 (error, ENOTSUP, 6939 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6940 NULL, "decap not supported for VF representor"); 6941 if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE) 6942 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 6943 else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE) 6944 action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH | 6945 MLX5_FLOW_ACTION_DECAP; 6946 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 6947 (dev, attr, tunnel, tof_rule_type); 6948 } 6949 ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error); 6950 if (ret < 0) 6951 return ret; 6952 is_root = (uint64_t)ret; 6953 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 6954 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 6955 int type = items->type; 6956 6957 if (!mlx5_flow_os_item_supported(type)) 6958 return rte_flow_error_set(error, ENOTSUP, 6959 RTE_FLOW_ERROR_TYPE_ITEM, 6960 NULL, "item not supported"); 6961 switch (type) { 6962 case RTE_FLOW_ITEM_TYPE_VOID: 6963 break; 6964 case RTE_FLOW_ITEM_TYPE_PORT_ID: 6965 ret = flow_dv_validate_item_port_id 6966 (dev, items, attr, item_flags, error); 6967 if (ret < 0) 6968 return ret; 6969 last_item = MLX5_FLOW_ITEM_PORT_ID; 6970 port_id_item = items; 6971 break; 6972 case RTE_FLOW_ITEM_TYPE_ETH: 6973 ret = mlx5_flow_validate_item_eth(items, item_flags, 6974 true, error); 6975 if (ret < 0) 6976 return ret; 6977 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 6978 MLX5_FLOW_LAYER_OUTER_L2; 6979 if (items->mask != NULL && items->spec != NULL) { 6980 ether_type = 6981 ((const struct rte_flow_item_eth *) 6982 items->spec)->type; 6983 ether_type &= 6984 ((const struct rte_flow_item_eth *) 6985 items->mask)->type; 6986 ether_type = rte_be_to_cpu_16(ether_type); 6987 } else { 6988 ether_type = 0; 6989 } 6990 break; 6991 case RTE_FLOW_ITEM_TYPE_VLAN: 6992 ret = flow_dv_validate_item_vlan(items, item_flags, 6993 dev, error); 6994 if (ret < 0) 6995 return ret; 6996 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 6997 MLX5_FLOW_LAYER_OUTER_VLAN; 6998 if (items->mask != NULL && items->spec != NULL) { 6999 ether_type = 7000 ((const struct rte_flow_item_vlan *) 7001 items->spec)->inner_type; 7002 ether_type &= 7003 ((const struct rte_flow_item_vlan *) 7004 items->mask)->inner_type; 7005 ether_type = rte_be_to_cpu_16(ether_type); 7006 } else { 7007 ether_type = 0; 7008 } 7009 /* Store outer VLAN mask for of_push_vlan action. */ 7010 if (!tunnel) 7011 vlan_m = items->mask; 7012 break; 7013 case RTE_FLOW_ITEM_TYPE_IPV4: 7014 mlx5_flow_tunnel_ip_check(items, next_protocol, 7015 &item_flags, &tunnel); 7016 ret = flow_dv_validate_item_ipv4(dev, items, item_flags, 7017 last_item, ether_type, 7018 error); 7019 if (ret < 0) 7020 return ret; 7021 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 7022 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 7023 if (items->mask != NULL && 7024 ((const struct rte_flow_item_ipv4 *) 7025 items->mask)->hdr.next_proto_id) { 7026 next_protocol = 7027 ((const struct rte_flow_item_ipv4 *) 7028 (items->spec))->hdr.next_proto_id; 7029 next_protocol &= 7030 ((const struct rte_flow_item_ipv4 *) 7031 (items->mask))->hdr.next_proto_id; 7032 } else { 7033 /* Reset for inner layer. */ 7034 next_protocol = 0xff; 7035 } 7036 break; 7037 case RTE_FLOW_ITEM_TYPE_IPV6: 7038 mlx5_flow_tunnel_ip_check(items, next_protocol, 7039 &item_flags, &tunnel); 7040 ret = mlx5_flow_validate_item_ipv6(items, item_flags, 7041 last_item, 7042 ether_type, 7043 &nic_ipv6_mask, 7044 error); 7045 if (ret < 0) 7046 return ret; 7047 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 7048 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 7049 if (items->mask != NULL && 7050 ((const struct rte_flow_item_ipv6 *) 7051 items->mask)->hdr.proto) { 7052 item_ipv6_proto = 7053 ((const struct rte_flow_item_ipv6 *) 7054 items->spec)->hdr.proto; 7055 next_protocol = 7056 ((const struct rte_flow_item_ipv6 *) 7057 items->spec)->hdr.proto; 7058 next_protocol &= 7059 ((const struct rte_flow_item_ipv6 *) 7060 items->mask)->hdr.proto; 7061 } else { 7062 /* Reset for inner layer. */ 7063 next_protocol = 0xff; 7064 } 7065 break; 7066 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 7067 ret = flow_dv_validate_item_ipv6_frag_ext(items, 7068 item_flags, 7069 error); 7070 if (ret < 0) 7071 return ret; 7072 last_item = tunnel ? 7073 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 7074 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 7075 if (items->mask != NULL && 7076 ((const struct rte_flow_item_ipv6_frag_ext *) 7077 items->mask)->hdr.next_header) { 7078 next_protocol = 7079 ((const struct rte_flow_item_ipv6_frag_ext *) 7080 items->spec)->hdr.next_header; 7081 next_protocol &= 7082 ((const struct rte_flow_item_ipv6_frag_ext *) 7083 items->mask)->hdr.next_header; 7084 } else { 7085 /* Reset for inner layer. */ 7086 next_protocol = 0xff; 7087 } 7088 break; 7089 case RTE_FLOW_ITEM_TYPE_TCP: 7090 ret = mlx5_flow_validate_item_tcp 7091 (items, item_flags, 7092 next_protocol, 7093 &nic_tcp_mask, 7094 error); 7095 if (ret < 0) 7096 return ret; 7097 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 7098 MLX5_FLOW_LAYER_OUTER_L4_TCP; 7099 break; 7100 case RTE_FLOW_ITEM_TYPE_UDP: 7101 ret = mlx5_flow_validate_item_udp(items, item_flags, 7102 next_protocol, 7103 error); 7104 const struct rte_flow_item_udp *spec = items->spec; 7105 const struct rte_flow_item_udp *mask = items->mask; 7106 if (!mask) 7107 mask = &rte_flow_item_udp_mask; 7108 if (spec != NULL) 7109 udp_dport = rte_be_to_cpu_16 7110 (spec->hdr.dst_port & 7111 mask->hdr.dst_port); 7112 if (ret < 0) 7113 return ret; 7114 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 7115 MLX5_FLOW_LAYER_OUTER_L4_UDP; 7116 break; 7117 case RTE_FLOW_ITEM_TYPE_GRE: 7118 ret = mlx5_flow_validate_item_gre(items, item_flags, 7119 next_protocol, error); 7120 if (ret < 0) 7121 return ret; 7122 gre_item = items; 7123 last_item = MLX5_FLOW_LAYER_GRE; 7124 break; 7125 case RTE_FLOW_ITEM_TYPE_NVGRE: 7126 ret = mlx5_flow_validate_item_nvgre(items, item_flags, 7127 next_protocol, 7128 error); 7129 if (ret < 0) 7130 return ret; 7131 last_item = MLX5_FLOW_LAYER_NVGRE; 7132 break; 7133 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 7134 ret = mlx5_flow_validate_item_gre_key 7135 (items, item_flags, gre_item, error); 7136 if (ret < 0) 7137 return ret; 7138 last_item = MLX5_FLOW_LAYER_GRE_KEY; 7139 break; 7140 case RTE_FLOW_ITEM_TYPE_VXLAN: 7141 ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, 7142 items, item_flags, 7143 attr, error); 7144 if (ret < 0) 7145 return ret; 7146 last_item = MLX5_FLOW_LAYER_VXLAN; 7147 break; 7148 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 7149 ret = mlx5_flow_validate_item_vxlan_gpe(items, 7150 item_flags, dev, 7151 error); 7152 if (ret < 0) 7153 return ret; 7154 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 7155 break; 7156 case RTE_FLOW_ITEM_TYPE_GENEVE: 7157 ret = mlx5_flow_validate_item_geneve(items, 7158 item_flags, dev, 7159 error); 7160 if (ret < 0) 7161 return ret; 7162 geneve_item = items; 7163 last_item = MLX5_FLOW_LAYER_GENEVE; 7164 break; 7165 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 7166 ret = mlx5_flow_validate_item_geneve_opt(items, 7167 last_item, 7168 geneve_item, 7169 dev, 7170 error); 7171 if (ret < 0) 7172 return ret; 7173 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 7174 break; 7175 case RTE_FLOW_ITEM_TYPE_MPLS: 7176 ret = mlx5_flow_validate_item_mpls(dev, items, 7177 item_flags, 7178 last_item, error); 7179 if (ret < 0) 7180 return ret; 7181 last_item = MLX5_FLOW_LAYER_MPLS; 7182 break; 7183 7184 case RTE_FLOW_ITEM_TYPE_MARK: 7185 ret = flow_dv_validate_item_mark(dev, items, attr, 7186 error); 7187 if (ret < 0) 7188 return ret; 7189 last_item = MLX5_FLOW_ITEM_MARK; 7190 break; 7191 case RTE_FLOW_ITEM_TYPE_META: 7192 ret = flow_dv_validate_item_meta(dev, items, attr, 7193 error); 7194 if (ret < 0) 7195 return ret; 7196 last_item = MLX5_FLOW_ITEM_METADATA; 7197 break; 7198 case RTE_FLOW_ITEM_TYPE_ICMP: 7199 ret = mlx5_flow_validate_item_icmp(items, item_flags, 7200 next_protocol, 7201 error); 7202 if (ret < 0) 7203 return ret; 7204 last_item = MLX5_FLOW_LAYER_ICMP; 7205 break; 7206 case RTE_FLOW_ITEM_TYPE_ICMP6: 7207 ret = mlx5_flow_validate_item_icmp6(items, item_flags, 7208 next_protocol, 7209 error); 7210 if (ret < 0) 7211 return ret; 7212 item_ipv6_proto = IPPROTO_ICMPV6; 7213 last_item = MLX5_FLOW_LAYER_ICMP6; 7214 break; 7215 case RTE_FLOW_ITEM_TYPE_TAG: 7216 ret = flow_dv_validate_item_tag(dev, items, 7217 attr, error); 7218 if (ret < 0) 7219 return ret; 7220 last_item = MLX5_FLOW_ITEM_TAG; 7221 break; 7222 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 7223 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 7224 break; 7225 case RTE_FLOW_ITEM_TYPE_GTP: 7226 ret = flow_dv_validate_item_gtp(dev, items, item_flags, 7227 error); 7228 if (ret < 0) 7229 return ret; 7230 gtp_item = items; 7231 last_item = MLX5_FLOW_LAYER_GTP; 7232 break; 7233 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 7234 ret = flow_dv_validate_item_gtp_psc(items, last_item, 7235 gtp_item, attr, 7236 error); 7237 if (ret < 0) 7238 return ret; 7239 last_item = MLX5_FLOW_LAYER_GTP_PSC; 7240 break; 7241 case RTE_FLOW_ITEM_TYPE_ECPRI: 7242 /* Capacity will be checked in the translate stage. */ 7243 ret = mlx5_flow_validate_item_ecpri(items, item_flags, 7244 last_item, 7245 ether_type, 7246 &nic_ecpri_mask, 7247 error); 7248 if (ret < 0) 7249 return ret; 7250 last_item = MLX5_FLOW_LAYER_ECPRI; 7251 break; 7252 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 7253 if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) 7254 return rte_flow_error_set 7255 (error, ENOTSUP, 7256 RTE_FLOW_ERROR_TYPE_ITEM, 7257 NULL, "multiple integrity items not supported"); 7258 ret = flow_dv_validate_item_integrity(dev, rule_items, 7259 items, error); 7260 if (ret < 0) 7261 return ret; 7262 last_item = MLX5_FLOW_ITEM_INTEGRITY; 7263 break; 7264 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 7265 ret = flow_dv_validate_item_aso_ct(dev, items, 7266 &item_flags, error); 7267 if (ret < 0) 7268 return ret; 7269 break; 7270 case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL: 7271 /* tunnel offload item was processed before 7272 * list it here as a supported type 7273 */ 7274 break; 7275 default: 7276 return rte_flow_error_set(error, ENOTSUP, 7277 RTE_FLOW_ERROR_TYPE_ITEM, 7278 NULL, "item not supported"); 7279 } 7280 item_flags |= last_item; 7281 } 7282 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 7283 int type = actions->type; 7284 bool shared_count = false; 7285 7286 if (!mlx5_flow_os_action_supported(type)) 7287 return rte_flow_error_set(error, ENOTSUP, 7288 RTE_FLOW_ERROR_TYPE_ACTION, 7289 actions, 7290 "action not supported"); 7291 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 7292 return rte_flow_error_set(error, ENOTSUP, 7293 RTE_FLOW_ERROR_TYPE_ACTION, 7294 actions, "too many actions"); 7295 if (action_flags & 7296 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 7297 return rte_flow_error_set(error, ENOTSUP, 7298 RTE_FLOW_ERROR_TYPE_ACTION, 7299 NULL, "meter action with policy " 7300 "must be the last action"); 7301 switch (type) { 7302 case RTE_FLOW_ACTION_TYPE_VOID: 7303 break; 7304 case RTE_FLOW_ACTION_TYPE_PORT_ID: 7305 ret = flow_dv_validate_action_port_id(dev, 7306 action_flags, 7307 actions, 7308 attr, 7309 error); 7310 if (ret) 7311 return ret; 7312 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 7313 ++actions_n; 7314 break; 7315 case RTE_FLOW_ACTION_TYPE_FLAG: 7316 ret = flow_dv_validate_action_flag(dev, action_flags, 7317 attr, error); 7318 if (ret < 0) 7319 return ret; 7320 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7321 /* Count all modify-header actions as one. */ 7322 if (!(action_flags & 7323 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7324 ++actions_n; 7325 action_flags |= MLX5_FLOW_ACTION_FLAG | 7326 MLX5_FLOW_ACTION_MARK_EXT; 7327 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7328 modify_after_mirror = 1; 7329 7330 } else { 7331 action_flags |= MLX5_FLOW_ACTION_FLAG; 7332 ++actions_n; 7333 } 7334 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7335 break; 7336 case RTE_FLOW_ACTION_TYPE_MARK: 7337 ret = flow_dv_validate_action_mark(dev, actions, 7338 action_flags, 7339 attr, error); 7340 if (ret < 0) 7341 return ret; 7342 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7343 /* Count all modify-header actions as one. */ 7344 if (!(action_flags & 7345 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7346 ++actions_n; 7347 action_flags |= MLX5_FLOW_ACTION_MARK | 7348 MLX5_FLOW_ACTION_MARK_EXT; 7349 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7350 modify_after_mirror = 1; 7351 } else { 7352 action_flags |= MLX5_FLOW_ACTION_MARK; 7353 ++actions_n; 7354 } 7355 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7356 break; 7357 case RTE_FLOW_ACTION_TYPE_SET_META: 7358 ret = flow_dv_validate_action_set_meta(dev, actions, 7359 action_flags, 7360 attr, error); 7361 if (ret < 0) 7362 return ret; 7363 /* Count all modify-header actions as one action. */ 7364 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7365 ++actions_n; 7366 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7367 modify_after_mirror = 1; 7368 action_flags |= MLX5_FLOW_ACTION_SET_META; 7369 rw_act_num += MLX5_ACT_NUM_SET_META; 7370 break; 7371 case RTE_FLOW_ACTION_TYPE_SET_TAG: 7372 ret = flow_dv_validate_action_set_tag(dev, actions, 7373 action_flags, 7374 attr, error); 7375 if (ret < 0) 7376 return ret; 7377 /* Count all modify-header actions as one action. */ 7378 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7379 ++actions_n; 7380 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7381 modify_after_mirror = 1; 7382 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 7383 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7384 break; 7385 case RTE_FLOW_ACTION_TYPE_DROP: 7386 ret = mlx5_flow_validate_action_drop(action_flags, 7387 attr, error); 7388 if (ret < 0) 7389 return ret; 7390 action_flags |= MLX5_FLOW_ACTION_DROP; 7391 ++actions_n; 7392 break; 7393 case RTE_FLOW_ACTION_TYPE_QUEUE: 7394 ret = mlx5_flow_validate_action_queue(actions, 7395 action_flags, dev, 7396 attr, error); 7397 if (ret < 0) 7398 return ret; 7399 queue_index = ((const struct rte_flow_action_queue *) 7400 (actions->conf))->index; 7401 action_flags |= MLX5_FLOW_ACTION_QUEUE; 7402 ++actions_n; 7403 break; 7404 case RTE_FLOW_ACTION_TYPE_RSS: 7405 rss = actions->conf; 7406 ret = mlx5_flow_validate_action_rss(actions, 7407 action_flags, dev, 7408 attr, item_flags, 7409 error); 7410 if (ret < 0) 7411 return ret; 7412 if (rss && sample_rss && 7413 (sample_rss->level != rss->level || 7414 sample_rss->types != rss->types)) 7415 return rte_flow_error_set(error, ENOTSUP, 7416 RTE_FLOW_ERROR_TYPE_ACTION, 7417 NULL, 7418 "Can't use the different RSS types " 7419 "or level in the same flow"); 7420 if (rss != NULL && rss->queue_num) 7421 queue_index = rss->queue[0]; 7422 action_flags |= MLX5_FLOW_ACTION_RSS; 7423 ++actions_n; 7424 break; 7425 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 7426 ret = 7427 mlx5_flow_validate_action_default_miss(action_flags, 7428 attr, error); 7429 if (ret < 0) 7430 return ret; 7431 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 7432 ++actions_n; 7433 break; 7434 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 7435 case RTE_FLOW_ACTION_TYPE_COUNT: 7436 shared_count = is_shared_action_count(actions); 7437 ret = flow_dv_validate_action_count(dev, shared_count, 7438 action_flags, 7439 error); 7440 if (ret < 0) 7441 return ret; 7442 action_flags |= MLX5_FLOW_ACTION_COUNT; 7443 ++actions_n; 7444 break; 7445 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 7446 if (flow_dv_validate_action_pop_vlan(dev, 7447 action_flags, 7448 actions, 7449 item_flags, attr, 7450 error)) 7451 return -rte_errno; 7452 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7453 modify_after_mirror = 1; 7454 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 7455 ++actions_n; 7456 break; 7457 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 7458 ret = flow_dv_validate_action_push_vlan(dev, 7459 action_flags, 7460 vlan_m, 7461 actions, attr, 7462 error); 7463 if (ret < 0) 7464 return ret; 7465 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7466 modify_after_mirror = 1; 7467 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 7468 ++actions_n; 7469 break; 7470 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 7471 ret = flow_dv_validate_action_set_vlan_pcp 7472 (action_flags, actions, error); 7473 if (ret < 0) 7474 return ret; 7475 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7476 modify_after_mirror = 1; 7477 /* Count PCP with push_vlan command. */ 7478 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; 7479 break; 7480 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 7481 ret = flow_dv_validate_action_set_vlan_vid 7482 (item_flags, action_flags, 7483 actions, error); 7484 if (ret < 0) 7485 return ret; 7486 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7487 modify_after_mirror = 1; 7488 /* Count VID with push_vlan command. */ 7489 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 7490 rw_act_num += MLX5_ACT_NUM_MDF_VID; 7491 break; 7492 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 7493 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 7494 ret = flow_dv_validate_action_l2_encap(dev, 7495 action_flags, 7496 actions, attr, 7497 error); 7498 if (ret < 0) 7499 return ret; 7500 action_flags |= MLX5_FLOW_ACTION_ENCAP; 7501 ++actions_n; 7502 break; 7503 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 7504 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 7505 ret = flow_dv_validate_action_decap(dev, action_flags, 7506 actions, item_flags, 7507 attr, error); 7508 if (ret < 0) 7509 return ret; 7510 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7511 modify_after_mirror = 1; 7512 action_flags |= MLX5_FLOW_ACTION_DECAP; 7513 ++actions_n; 7514 break; 7515 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 7516 ret = flow_dv_validate_action_raw_encap_decap 7517 (dev, NULL, actions->conf, attr, &action_flags, 7518 &actions_n, actions, item_flags, error); 7519 if (ret < 0) 7520 return ret; 7521 break; 7522 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 7523 decap = actions->conf; 7524 while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID) 7525 ; 7526 if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 7527 encap = NULL; 7528 actions--; 7529 } else { 7530 encap = actions->conf; 7531 } 7532 ret = flow_dv_validate_action_raw_encap_decap 7533 (dev, 7534 decap ? decap : &empty_decap, encap, 7535 attr, &action_flags, &actions_n, 7536 actions, item_flags, error); 7537 if (ret < 0) 7538 return ret; 7539 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7540 (action_flags & MLX5_FLOW_ACTION_DECAP)) 7541 modify_after_mirror = 1; 7542 break; 7543 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 7544 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 7545 ret = flow_dv_validate_action_modify_mac(action_flags, 7546 actions, 7547 item_flags, 7548 error); 7549 if (ret < 0) 7550 return ret; 7551 /* Count all modify-header actions as one action. */ 7552 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7553 ++actions_n; 7554 action_flags |= actions->type == 7555 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 7556 MLX5_FLOW_ACTION_SET_MAC_SRC : 7557 MLX5_FLOW_ACTION_SET_MAC_DST; 7558 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7559 modify_after_mirror = 1; 7560 /* 7561 * Even if the source and destination MAC addresses have 7562 * overlap in the header with 4B alignment, the convert 7563 * function will handle them separately and 4 SW actions 7564 * will be created. And 2 actions will be added each 7565 * time no matter how many bytes of address will be set. 7566 */ 7567 rw_act_num += MLX5_ACT_NUM_MDF_MAC; 7568 break; 7569 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 7570 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 7571 ret = flow_dv_validate_action_modify_ipv4(action_flags, 7572 actions, 7573 item_flags, 7574 error); 7575 if (ret < 0) 7576 return ret; 7577 /* Count all modify-header actions as one action. */ 7578 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7579 ++actions_n; 7580 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7581 modify_after_mirror = 1; 7582 action_flags |= actions->type == 7583 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 7584 MLX5_FLOW_ACTION_SET_IPV4_SRC : 7585 MLX5_FLOW_ACTION_SET_IPV4_DST; 7586 rw_act_num += MLX5_ACT_NUM_MDF_IPV4; 7587 break; 7588 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 7589 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 7590 ret = flow_dv_validate_action_modify_ipv6(action_flags, 7591 actions, 7592 item_flags, 7593 error); 7594 if (ret < 0) 7595 return ret; 7596 if (item_ipv6_proto == IPPROTO_ICMPV6) 7597 return rte_flow_error_set(error, ENOTSUP, 7598 RTE_FLOW_ERROR_TYPE_ACTION, 7599 actions, 7600 "Can't change header " 7601 "with ICMPv6 proto"); 7602 /* Count all modify-header actions as one action. */ 7603 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7604 ++actions_n; 7605 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7606 modify_after_mirror = 1; 7607 action_flags |= actions->type == 7608 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 7609 MLX5_FLOW_ACTION_SET_IPV6_SRC : 7610 MLX5_FLOW_ACTION_SET_IPV6_DST; 7611 rw_act_num += MLX5_ACT_NUM_MDF_IPV6; 7612 break; 7613 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 7614 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 7615 ret = flow_dv_validate_action_modify_tp(action_flags, 7616 actions, 7617 item_flags, 7618 error); 7619 if (ret < 0) 7620 return ret; 7621 /* Count all modify-header actions as one action. */ 7622 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7623 ++actions_n; 7624 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7625 modify_after_mirror = 1; 7626 action_flags |= actions->type == 7627 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 7628 MLX5_FLOW_ACTION_SET_TP_SRC : 7629 MLX5_FLOW_ACTION_SET_TP_DST; 7630 rw_act_num += MLX5_ACT_NUM_MDF_PORT; 7631 break; 7632 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 7633 case RTE_FLOW_ACTION_TYPE_SET_TTL: 7634 ret = flow_dv_validate_action_modify_ttl(action_flags, 7635 actions, 7636 item_flags, 7637 error); 7638 if (ret < 0) 7639 return ret; 7640 /* Count all modify-header actions as one action. */ 7641 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7642 ++actions_n; 7643 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7644 modify_after_mirror = 1; 7645 action_flags |= actions->type == 7646 RTE_FLOW_ACTION_TYPE_SET_TTL ? 7647 MLX5_FLOW_ACTION_SET_TTL : 7648 MLX5_FLOW_ACTION_DEC_TTL; 7649 rw_act_num += MLX5_ACT_NUM_MDF_TTL; 7650 break; 7651 case RTE_FLOW_ACTION_TYPE_JUMP: 7652 ret = flow_dv_validate_action_jump(dev, tunnel, actions, 7653 action_flags, 7654 attr, external, 7655 error); 7656 if (ret) 7657 return ret; 7658 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7659 fdb_mirror_limit) 7660 return rte_flow_error_set(error, EINVAL, 7661 RTE_FLOW_ERROR_TYPE_ACTION, 7662 NULL, 7663 "sample and jump action combination is not supported"); 7664 ++actions_n; 7665 action_flags |= MLX5_FLOW_ACTION_JUMP; 7666 break; 7667 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 7668 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 7669 ret = flow_dv_validate_action_modify_tcp_seq 7670 (action_flags, 7671 actions, 7672 item_flags, 7673 error); 7674 if (ret < 0) 7675 return ret; 7676 /* Count all modify-header actions as one action. */ 7677 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7678 ++actions_n; 7679 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7680 modify_after_mirror = 1; 7681 action_flags |= actions->type == 7682 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 7683 MLX5_FLOW_ACTION_INC_TCP_SEQ : 7684 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 7685 rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ; 7686 break; 7687 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 7688 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 7689 ret = flow_dv_validate_action_modify_tcp_ack 7690 (action_flags, 7691 actions, 7692 item_flags, 7693 error); 7694 if (ret < 0) 7695 return ret; 7696 /* Count all modify-header actions as one action. */ 7697 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7698 ++actions_n; 7699 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7700 modify_after_mirror = 1; 7701 action_flags |= actions->type == 7702 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 7703 MLX5_FLOW_ACTION_INC_TCP_ACK : 7704 MLX5_FLOW_ACTION_DEC_TCP_ACK; 7705 rw_act_num += MLX5_ACT_NUM_MDF_TCPACK; 7706 break; 7707 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 7708 break; 7709 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 7710 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 7711 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7712 break; 7713 case RTE_FLOW_ACTION_TYPE_METER: 7714 ret = mlx5_flow_validate_action_meter(dev, 7715 action_flags, 7716 actions, attr, 7717 port_id_item, 7718 &def_policy, 7719 error); 7720 if (ret < 0) 7721 return ret; 7722 action_flags |= MLX5_FLOW_ACTION_METER; 7723 if (!def_policy) 7724 action_flags |= 7725 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 7726 ++actions_n; 7727 /* Meter action will add one more TAG action. */ 7728 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7729 break; 7730 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 7731 if (!attr->transfer && !attr->group) 7732 return rte_flow_error_set(error, ENOTSUP, 7733 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7734 NULL, 7735 "Shared ASO age action is not supported for group 0"); 7736 if (action_flags & MLX5_FLOW_ACTION_AGE) 7737 return rte_flow_error_set 7738 (error, EINVAL, 7739 RTE_FLOW_ERROR_TYPE_ACTION, 7740 NULL, 7741 "duplicate age actions set"); 7742 action_flags |= MLX5_FLOW_ACTION_AGE; 7743 ++actions_n; 7744 break; 7745 case RTE_FLOW_ACTION_TYPE_AGE: 7746 ret = flow_dv_validate_action_age(action_flags, 7747 actions, dev, 7748 error); 7749 if (ret < 0) 7750 return ret; 7751 /* 7752 * Validate the regular AGE action (using counter) 7753 * mutual exclusion with share counter actions. 7754 */ 7755 if (!priv->sh->flow_hit_aso_en) { 7756 if (shared_count) 7757 return rte_flow_error_set 7758 (error, EINVAL, 7759 RTE_FLOW_ERROR_TYPE_ACTION, 7760 NULL, 7761 "old age and shared count combination is not supported"); 7762 if (sample_count) 7763 return rte_flow_error_set 7764 (error, EINVAL, 7765 RTE_FLOW_ERROR_TYPE_ACTION, 7766 NULL, 7767 "old age action and count must be in the same sub flow"); 7768 } 7769 action_flags |= MLX5_FLOW_ACTION_AGE; 7770 ++actions_n; 7771 break; 7772 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 7773 ret = flow_dv_validate_action_modify_ipv4_dscp 7774 (action_flags, 7775 actions, 7776 item_flags, 7777 error); 7778 if (ret < 0) 7779 return ret; 7780 /* Count all modify-header actions as one action. */ 7781 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7782 ++actions_n; 7783 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7784 modify_after_mirror = 1; 7785 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 7786 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7787 break; 7788 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 7789 ret = flow_dv_validate_action_modify_ipv6_dscp 7790 (action_flags, 7791 actions, 7792 item_flags, 7793 error); 7794 if (ret < 0) 7795 return ret; 7796 /* Count all modify-header actions as one action. */ 7797 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7798 ++actions_n; 7799 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7800 modify_after_mirror = 1; 7801 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 7802 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7803 break; 7804 case RTE_FLOW_ACTION_TYPE_SAMPLE: 7805 ret = flow_dv_validate_action_sample(&action_flags, 7806 actions, dev, 7807 attr, item_flags, 7808 rss, &sample_rss, 7809 &sample_count, 7810 &fdb_mirror_limit, 7811 error); 7812 if (ret < 0) 7813 return ret; 7814 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 7815 ++actions_n; 7816 break; 7817 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 7818 ret = flow_dv_validate_action_modify_field(dev, 7819 action_flags, 7820 actions, 7821 attr, 7822 error); 7823 if (ret < 0) 7824 return ret; 7825 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7826 modify_after_mirror = 1; 7827 /* Count all modify-header actions as one action. */ 7828 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7829 ++actions_n; 7830 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 7831 rw_act_num += ret; 7832 break; 7833 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 7834 ret = flow_dv_validate_action_aso_ct(dev, action_flags, 7835 item_flags, attr, 7836 error); 7837 if (ret < 0) 7838 return ret; 7839 action_flags |= MLX5_FLOW_ACTION_CT; 7840 break; 7841 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 7842 /* tunnel offload action was processed before 7843 * list it here as a supported type 7844 */ 7845 break; 7846 default: 7847 return rte_flow_error_set(error, ENOTSUP, 7848 RTE_FLOW_ERROR_TYPE_ACTION, 7849 actions, 7850 "action not supported"); 7851 } 7852 } 7853 /* 7854 * Validate actions in flow rules 7855 * - Explicit decap action is prohibited by the tunnel offload API. 7856 * - Drop action in tunnel steer rule is prohibited by the API. 7857 * - Application cannot use MARK action because it's value can mask 7858 * tunnel default miss nitification. 7859 * - JUMP in tunnel match rule has no support in current PMD 7860 * implementation. 7861 * - TAG & META are reserved for future uses. 7862 */ 7863 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) { 7864 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP | 7865 MLX5_FLOW_ACTION_MARK | 7866 MLX5_FLOW_ACTION_SET_TAG | 7867 MLX5_FLOW_ACTION_SET_META | 7868 MLX5_FLOW_ACTION_DROP; 7869 7870 if (action_flags & bad_actions_mask) 7871 return rte_flow_error_set 7872 (error, EINVAL, 7873 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7874 "Invalid RTE action in tunnel " 7875 "set decap rule"); 7876 if (!(action_flags & MLX5_FLOW_ACTION_JUMP)) 7877 return rte_flow_error_set 7878 (error, EINVAL, 7879 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7880 "tunnel set decap rule must terminate " 7881 "with JUMP"); 7882 if (!attr->ingress) 7883 return rte_flow_error_set 7884 (error, EINVAL, 7885 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7886 "tunnel flows for ingress traffic only"); 7887 } 7888 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) { 7889 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP | 7890 MLX5_FLOW_ACTION_MARK | 7891 MLX5_FLOW_ACTION_SET_TAG | 7892 MLX5_FLOW_ACTION_SET_META; 7893 7894 if (action_flags & bad_actions_mask) 7895 return rte_flow_error_set 7896 (error, EINVAL, 7897 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7898 "Invalid RTE action in tunnel " 7899 "set match rule"); 7900 } 7901 /* 7902 * Validate the drop action mutual exclusion with other actions. 7903 * Drop action is mutually-exclusive with any other action, except for 7904 * Count action. 7905 * Drop action compatibility with tunnel offload was already validated. 7906 */ 7907 if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH | 7908 MLX5_FLOW_ACTION_TUNNEL_MATCH)); 7909 else if ((action_flags & MLX5_FLOW_ACTION_DROP) && 7910 (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT))) 7911 return rte_flow_error_set(error, EINVAL, 7912 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7913 "Drop action is mutually-exclusive " 7914 "with any other action, except for " 7915 "Count action"); 7916 /* Eswitch has few restrictions on using items and actions */ 7917 if (attr->transfer) { 7918 if (!mlx5_flow_ext_mreg_supported(dev) && 7919 action_flags & MLX5_FLOW_ACTION_FLAG) 7920 return rte_flow_error_set(error, ENOTSUP, 7921 RTE_FLOW_ERROR_TYPE_ACTION, 7922 NULL, 7923 "unsupported action FLAG"); 7924 if (!mlx5_flow_ext_mreg_supported(dev) && 7925 action_flags & MLX5_FLOW_ACTION_MARK) 7926 return rte_flow_error_set(error, ENOTSUP, 7927 RTE_FLOW_ERROR_TYPE_ACTION, 7928 NULL, 7929 "unsupported action MARK"); 7930 if (action_flags & MLX5_FLOW_ACTION_QUEUE) 7931 return rte_flow_error_set(error, ENOTSUP, 7932 RTE_FLOW_ERROR_TYPE_ACTION, 7933 NULL, 7934 "unsupported action QUEUE"); 7935 if (action_flags & MLX5_FLOW_ACTION_RSS) 7936 return rte_flow_error_set(error, ENOTSUP, 7937 RTE_FLOW_ERROR_TYPE_ACTION, 7938 NULL, 7939 "unsupported action RSS"); 7940 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 7941 return rte_flow_error_set(error, EINVAL, 7942 RTE_FLOW_ERROR_TYPE_ACTION, 7943 actions, 7944 "no fate action is found"); 7945 } else { 7946 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) 7947 return rte_flow_error_set(error, EINVAL, 7948 RTE_FLOW_ERROR_TYPE_ACTION, 7949 actions, 7950 "no fate action is found"); 7951 } 7952 /* 7953 * Continue validation for Xcap and VLAN actions. 7954 * If hairpin is working in explicit TX rule mode, there is no actions 7955 * splitting and the validation of hairpin ingress flow should be the 7956 * same as other standard flows. 7957 */ 7958 if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS | 7959 MLX5_FLOW_VLAN_ACTIONS)) && 7960 (queue_index == 0xFFFF || 7961 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN || 7962 ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL && 7963 conf->tx_explicit != 0))) { 7964 if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) == 7965 MLX5_FLOW_XCAP_ACTIONS) 7966 return rte_flow_error_set(error, ENOTSUP, 7967 RTE_FLOW_ERROR_TYPE_ACTION, 7968 NULL, "encap and decap " 7969 "combination aren't supported"); 7970 if (!attr->transfer && attr->ingress) { 7971 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 7972 return rte_flow_error_set 7973 (error, ENOTSUP, 7974 RTE_FLOW_ERROR_TYPE_ACTION, 7975 NULL, "encap is not supported" 7976 " for ingress traffic"); 7977 else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 7978 return rte_flow_error_set 7979 (error, ENOTSUP, 7980 RTE_FLOW_ERROR_TYPE_ACTION, 7981 NULL, "push VLAN action not " 7982 "supported for ingress"); 7983 else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) == 7984 MLX5_FLOW_VLAN_ACTIONS) 7985 return rte_flow_error_set 7986 (error, ENOTSUP, 7987 RTE_FLOW_ERROR_TYPE_ACTION, 7988 NULL, "no support for " 7989 "multiple VLAN actions"); 7990 } 7991 } 7992 if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) { 7993 if ((action_flags & (MLX5_FLOW_FATE_ACTIONS & 7994 ~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) && 7995 attr->ingress) 7996 return rte_flow_error_set 7997 (error, ENOTSUP, 7998 RTE_FLOW_ERROR_TYPE_ACTION, 7999 NULL, "fate action not supported for " 8000 "meter with policy"); 8001 if (attr->egress) { 8002 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 8003 return rte_flow_error_set 8004 (error, ENOTSUP, 8005 RTE_FLOW_ERROR_TYPE_ACTION, 8006 NULL, "modify header action in egress " 8007 "cannot be done before meter action"); 8008 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 8009 return rte_flow_error_set 8010 (error, ENOTSUP, 8011 RTE_FLOW_ERROR_TYPE_ACTION, 8012 NULL, "encap action in egress " 8013 "cannot be done before meter action"); 8014 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 8015 return rte_flow_error_set 8016 (error, ENOTSUP, 8017 RTE_FLOW_ERROR_TYPE_ACTION, 8018 NULL, "push vlan action in egress " 8019 "cannot be done before meter action"); 8020 } 8021 } 8022 /* 8023 * Hairpin flow will add one more TAG action in TX implicit mode. 8024 * In TX explicit mode, there will be no hairpin flow ID. 8025 */ 8026 if (hairpin > 0) 8027 rw_act_num += MLX5_ACT_NUM_SET_TAG; 8028 /* extra metadata enabled: one more TAG action will be add. */ 8029 if (dev_conf->dv_flow_en && 8030 dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 8031 mlx5_flow_ext_mreg_supported(dev)) 8032 rw_act_num += MLX5_ACT_NUM_SET_TAG; 8033 if (rw_act_num > 8034 flow_dv_modify_hdr_action_max(dev, is_root)) { 8035 return rte_flow_error_set(error, ENOTSUP, 8036 RTE_FLOW_ERROR_TYPE_ACTION, 8037 NULL, "too many header modify" 8038 " actions to support"); 8039 } 8040 /* Eswitch egress mirror and modify flow has limitation on CX5 */ 8041 if (fdb_mirror_limit && modify_after_mirror) 8042 return rte_flow_error_set(error, EINVAL, 8043 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8044 "sample before modify action is not supported"); 8045 return 0; 8046 } 8047 8048 /** 8049 * Internal preparation function. Allocates the DV flow size, 8050 * this size is constant. 8051 * 8052 * @param[in] dev 8053 * Pointer to the rte_eth_dev structure. 8054 * @param[in] attr 8055 * Pointer to the flow attributes. 8056 * @param[in] items 8057 * Pointer to the list of items. 8058 * @param[in] actions 8059 * Pointer to the list of actions. 8060 * @param[out] error 8061 * Pointer to the error structure. 8062 * 8063 * @return 8064 * Pointer to mlx5_flow object on success, 8065 * otherwise NULL and rte_errno is set. 8066 */ 8067 static struct mlx5_flow * 8068 flow_dv_prepare(struct rte_eth_dev *dev, 8069 const struct rte_flow_attr *attr __rte_unused, 8070 const struct rte_flow_item items[] __rte_unused, 8071 const struct rte_flow_action actions[] __rte_unused, 8072 struct rte_flow_error *error) 8073 { 8074 uint32_t handle_idx = 0; 8075 struct mlx5_flow *dev_flow; 8076 struct mlx5_flow_handle *dev_handle; 8077 struct mlx5_priv *priv = dev->data->dev_private; 8078 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 8079 8080 MLX5_ASSERT(wks); 8081 wks->skip_matcher_reg = 0; 8082 wks->policy = NULL; 8083 wks->final_policy = NULL; 8084 /* In case of corrupting the memory. */ 8085 if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) { 8086 rte_flow_error_set(error, ENOSPC, 8087 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8088 "not free temporary device flow"); 8089 return NULL; 8090 } 8091 dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 8092 &handle_idx); 8093 if (!dev_handle) { 8094 rte_flow_error_set(error, ENOMEM, 8095 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8096 "not enough memory to create flow handle"); 8097 return NULL; 8098 } 8099 MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows)); 8100 dev_flow = &wks->flows[wks->flow_idx++]; 8101 memset(dev_flow, 0, sizeof(*dev_flow)); 8102 dev_flow->handle = dev_handle; 8103 dev_flow->handle_idx = handle_idx; 8104 dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 8105 dev_flow->ingress = attr->ingress; 8106 dev_flow->dv.transfer = attr->transfer; 8107 return dev_flow; 8108 } 8109 8110 #ifdef RTE_LIBRTE_MLX5_DEBUG 8111 /** 8112 * Sanity check for match mask and value. Similar to check_valid_spec() in 8113 * kernel driver. If unmasked bit is present in value, it returns failure. 8114 * 8115 * @param match_mask 8116 * pointer to match mask buffer. 8117 * @param match_value 8118 * pointer to match value buffer. 8119 * 8120 * @return 8121 * 0 if valid, -EINVAL otherwise. 8122 */ 8123 static int 8124 flow_dv_check_valid_spec(void *match_mask, void *match_value) 8125 { 8126 uint8_t *m = match_mask; 8127 uint8_t *v = match_value; 8128 unsigned int i; 8129 8130 for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) { 8131 if (v[i] & ~m[i]) { 8132 DRV_LOG(ERR, 8133 "match_value differs from match_criteria" 8134 " %p[%u] != %p[%u]", 8135 match_value, i, match_mask, i); 8136 return -EINVAL; 8137 } 8138 } 8139 return 0; 8140 } 8141 #endif 8142 8143 /** 8144 * Add match of ip_version. 8145 * 8146 * @param[in] group 8147 * Flow group. 8148 * @param[in] headers_v 8149 * Values header pointer. 8150 * @param[in] headers_m 8151 * Masks header pointer. 8152 * @param[in] ip_version 8153 * The IP version to set. 8154 */ 8155 static inline void 8156 flow_dv_set_match_ip_version(uint32_t group, 8157 void *headers_v, 8158 void *headers_m, 8159 uint8_t ip_version) 8160 { 8161 if (group == 0) 8162 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf); 8163 else 8164 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 8165 ip_version); 8166 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version); 8167 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0); 8168 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0); 8169 } 8170 8171 /** 8172 * Add Ethernet item to matcher and to the value. 8173 * 8174 * @param[in, out] matcher 8175 * Flow matcher. 8176 * @param[in, out] key 8177 * Flow matcher value. 8178 * @param[in] item 8179 * Flow pattern to translate. 8180 * @param[in] inner 8181 * Item is inner pattern. 8182 */ 8183 static void 8184 flow_dv_translate_item_eth(void *matcher, void *key, 8185 const struct rte_flow_item *item, int inner, 8186 uint32_t group) 8187 { 8188 const struct rte_flow_item_eth *eth_m = item->mask; 8189 const struct rte_flow_item_eth *eth_v = item->spec; 8190 const struct rte_flow_item_eth nic_mask = { 8191 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8192 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8193 .type = RTE_BE16(0xffff), 8194 .has_vlan = 0, 8195 }; 8196 void *hdrs_m; 8197 void *hdrs_v; 8198 char *l24_v; 8199 unsigned int i; 8200 8201 if (!eth_v) 8202 return; 8203 if (!eth_m) 8204 eth_m = &nic_mask; 8205 if (inner) { 8206 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8207 inner_headers); 8208 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8209 } else { 8210 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8211 outer_headers); 8212 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8213 } 8214 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16), 8215 ð_m->dst, sizeof(eth_m->dst)); 8216 /* The value must be in the range of the mask. */ 8217 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16); 8218 for (i = 0; i < sizeof(eth_m->dst); ++i) 8219 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i]; 8220 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16), 8221 ð_m->src, sizeof(eth_m->src)); 8222 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16); 8223 /* The value must be in the range of the mask. */ 8224 for (i = 0; i < sizeof(eth_m->dst); ++i) 8225 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i]; 8226 /* 8227 * HW supports match on one Ethertype, the Ethertype following the last 8228 * VLAN tag of the packet (see PRM). 8229 * Set match on ethertype only if ETH header is not followed by VLAN. 8230 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8231 * ethertype, and use ip_version field instead. 8232 * eCPRI over Ether layer will use type value 0xAEFE. 8233 */ 8234 if (eth_m->type == 0xFFFF) { 8235 /* Set cvlan_tag mask for any single\multi\un-tagged case. */ 8236 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8237 switch (eth_v->type) { 8238 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8239 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8240 return; 8241 case RTE_BE16(RTE_ETHER_TYPE_QINQ): 8242 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8243 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8244 return; 8245 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8246 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8247 return; 8248 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8249 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8250 return; 8251 default: 8252 break; 8253 } 8254 } 8255 if (eth_m->has_vlan) { 8256 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8257 if (eth_v->has_vlan) { 8258 /* 8259 * Here, when also has_more_vlan field in VLAN item is 8260 * not set, only single-tagged packets will be matched. 8261 */ 8262 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8263 return; 8264 } 8265 } 8266 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8267 rte_be_to_cpu_16(eth_m->type)); 8268 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 8269 *(uint16_t *)(l24_v) = eth_m->type & eth_v->type; 8270 } 8271 8272 /** 8273 * Add VLAN item to matcher and to the value. 8274 * 8275 * @param[in, out] dev_flow 8276 * Flow descriptor. 8277 * @param[in, out] matcher 8278 * Flow matcher. 8279 * @param[in, out] key 8280 * Flow matcher value. 8281 * @param[in] item 8282 * Flow pattern to translate. 8283 * @param[in] inner 8284 * Item is inner pattern. 8285 */ 8286 static void 8287 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow, 8288 void *matcher, void *key, 8289 const struct rte_flow_item *item, 8290 int inner, uint32_t group) 8291 { 8292 const struct rte_flow_item_vlan *vlan_m = item->mask; 8293 const struct rte_flow_item_vlan *vlan_v = item->spec; 8294 void *hdrs_m; 8295 void *hdrs_v; 8296 uint16_t tci_m; 8297 uint16_t tci_v; 8298 8299 if (inner) { 8300 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8301 inner_headers); 8302 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8303 } else { 8304 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8305 outer_headers); 8306 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8307 /* 8308 * This is workaround, masks are not supported, 8309 * and pre-validated. 8310 */ 8311 if (vlan_v) 8312 dev_flow->handle->vf_vlan.tag = 8313 rte_be_to_cpu_16(vlan_v->tci) & 0x0fff; 8314 } 8315 /* 8316 * When VLAN item exists in flow, mark packet as tagged, 8317 * even if TCI is not specified. 8318 */ 8319 if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) { 8320 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8321 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8322 } 8323 if (!vlan_v) 8324 return; 8325 if (!vlan_m) 8326 vlan_m = &rte_flow_item_vlan_mask; 8327 tci_m = rte_be_to_cpu_16(vlan_m->tci); 8328 tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci); 8329 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m); 8330 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v); 8331 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12); 8332 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12); 8333 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13); 8334 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13); 8335 /* 8336 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8337 * ethertype, and use ip_version field instead. 8338 */ 8339 if (vlan_m->inner_type == 0xFFFF) { 8340 switch (vlan_v->inner_type) { 8341 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8342 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8343 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8344 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8345 return; 8346 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8347 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8348 return; 8349 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8350 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8351 return; 8352 default: 8353 break; 8354 } 8355 } 8356 if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) { 8357 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8358 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8359 /* Only one vlan_tag bit can be set. */ 8360 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8361 return; 8362 } 8363 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8364 rte_be_to_cpu_16(vlan_m->inner_type)); 8365 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype, 8366 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type)); 8367 } 8368 8369 /** 8370 * Add IPV4 item to matcher and to the value. 8371 * 8372 * @param[in, out] matcher 8373 * Flow matcher. 8374 * @param[in, out] key 8375 * Flow matcher value. 8376 * @param[in] item 8377 * Flow pattern to translate. 8378 * @param[in] inner 8379 * Item is inner pattern. 8380 * @param[in] group 8381 * The group to insert the rule. 8382 */ 8383 static void 8384 flow_dv_translate_item_ipv4(void *matcher, void *key, 8385 const struct rte_flow_item *item, 8386 int inner, uint32_t group) 8387 { 8388 const struct rte_flow_item_ipv4 *ipv4_m = item->mask; 8389 const struct rte_flow_item_ipv4 *ipv4_v = item->spec; 8390 const struct rte_flow_item_ipv4 nic_mask = { 8391 .hdr = { 8392 .src_addr = RTE_BE32(0xffffffff), 8393 .dst_addr = RTE_BE32(0xffffffff), 8394 .type_of_service = 0xff, 8395 .next_proto_id = 0xff, 8396 .time_to_live = 0xff, 8397 }, 8398 }; 8399 void *headers_m; 8400 void *headers_v; 8401 char *l24_m; 8402 char *l24_v; 8403 uint8_t tos, ihl_m, ihl_v; 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, 4); 8415 if (!ipv4_v) 8416 return; 8417 if (!ipv4_m) 8418 ipv4_m = &nic_mask; 8419 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8420 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8421 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8422 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8423 *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr; 8424 *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr; 8425 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8426 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8427 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8428 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8429 *(uint32_t *)l24_m = ipv4_m->hdr.src_addr; 8430 *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr; 8431 tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service; 8432 ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8433 ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8434 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m); 8435 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v); 8436 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, 8437 ipv4_m->hdr.type_of_service); 8438 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos); 8439 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, 8440 ipv4_m->hdr.type_of_service >> 2); 8441 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2); 8442 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8443 ipv4_m->hdr.next_proto_id); 8444 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8445 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id); 8446 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8447 ipv4_m->hdr.time_to_live); 8448 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8449 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live); 8450 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8451 !!(ipv4_m->hdr.fragment_offset)); 8452 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8453 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset)); 8454 } 8455 8456 /** 8457 * Add IPV6 item to matcher and to the value. 8458 * 8459 * @param[in, out] matcher 8460 * Flow matcher. 8461 * @param[in, out] key 8462 * Flow matcher value. 8463 * @param[in] item 8464 * Flow pattern to translate. 8465 * @param[in] inner 8466 * Item is inner pattern. 8467 * @param[in] group 8468 * The group to insert the rule. 8469 */ 8470 static void 8471 flow_dv_translate_item_ipv6(void *matcher, void *key, 8472 const struct rte_flow_item *item, 8473 int inner, uint32_t group) 8474 { 8475 const struct rte_flow_item_ipv6 *ipv6_m = item->mask; 8476 const struct rte_flow_item_ipv6 *ipv6_v = item->spec; 8477 const struct rte_flow_item_ipv6 nic_mask = { 8478 .hdr = { 8479 .src_addr = 8480 "\xff\xff\xff\xff\xff\xff\xff\xff" 8481 "\xff\xff\xff\xff\xff\xff\xff\xff", 8482 .dst_addr = 8483 "\xff\xff\xff\xff\xff\xff\xff\xff" 8484 "\xff\xff\xff\xff\xff\xff\xff\xff", 8485 .vtc_flow = RTE_BE32(0xffffffff), 8486 .proto = 0xff, 8487 .hop_limits = 0xff, 8488 }, 8489 }; 8490 void *headers_m; 8491 void *headers_v; 8492 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8493 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8494 char *l24_m; 8495 char *l24_v; 8496 uint32_t vtc_m; 8497 uint32_t vtc_v; 8498 int i; 8499 int size; 8500 8501 if (inner) { 8502 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8503 inner_headers); 8504 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8505 } else { 8506 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8507 outer_headers); 8508 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8509 } 8510 flow_dv_set_match_ip_version(group, headers_v, headers_m, 6); 8511 if (!ipv6_v) 8512 return; 8513 if (!ipv6_m) 8514 ipv6_m = &nic_mask; 8515 size = sizeof(ipv6_m->hdr.dst_addr); 8516 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8517 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8518 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8519 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8520 memcpy(l24_m, ipv6_m->hdr.dst_addr, size); 8521 for (i = 0; i < size; ++i) 8522 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i]; 8523 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8524 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8525 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8526 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8527 memcpy(l24_m, ipv6_m->hdr.src_addr, size); 8528 for (i = 0; i < size; ++i) 8529 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i]; 8530 /* TOS. */ 8531 vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow); 8532 vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow); 8533 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20); 8534 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20); 8535 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22); 8536 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22); 8537 /* Label. */ 8538 if (inner) { 8539 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label, 8540 vtc_m); 8541 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label, 8542 vtc_v); 8543 } else { 8544 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label, 8545 vtc_m); 8546 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label, 8547 vtc_v); 8548 } 8549 /* Protocol. */ 8550 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8551 ipv6_m->hdr.proto); 8552 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8553 ipv6_v->hdr.proto & ipv6_m->hdr.proto); 8554 /* Hop limit. */ 8555 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8556 ipv6_m->hdr.hop_limits); 8557 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8558 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits); 8559 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8560 !!(ipv6_m->has_frag_ext)); 8561 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8562 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext)); 8563 } 8564 8565 /** 8566 * Add IPV6 fragment extension item to matcher and to the value. 8567 * 8568 * @param[in, out] matcher 8569 * Flow matcher. 8570 * @param[in, out] key 8571 * Flow matcher value. 8572 * @param[in] item 8573 * Flow pattern to translate. 8574 * @param[in] inner 8575 * Item is inner pattern. 8576 */ 8577 static void 8578 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key, 8579 const struct rte_flow_item *item, 8580 int inner) 8581 { 8582 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask; 8583 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec; 8584 const struct rte_flow_item_ipv6_frag_ext nic_mask = { 8585 .hdr = { 8586 .next_header = 0xff, 8587 .frag_data = RTE_BE16(0xffff), 8588 }, 8589 }; 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 /* IPv6 fragment extension item exists, so packet is IP fragment. */ 8603 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1); 8604 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1); 8605 if (!ipv6_frag_ext_v) 8606 return; 8607 if (!ipv6_frag_ext_m) 8608 ipv6_frag_ext_m = &nic_mask; 8609 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8610 ipv6_frag_ext_m->hdr.next_header); 8611 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8612 ipv6_frag_ext_v->hdr.next_header & 8613 ipv6_frag_ext_m->hdr.next_header); 8614 } 8615 8616 /** 8617 * Add TCP item to matcher and to the value. 8618 * 8619 * @param[in, out] matcher 8620 * Flow matcher. 8621 * @param[in, out] key 8622 * Flow matcher value. 8623 * @param[in] item 8624 * Flow pattern to translate. 8625 * @param[in] inner 8626 * Item is inner pattern. 8627 */ 8628 static void 8629 flow_dv_translate_item_tcp(void *matcher, void *key, 8630 const struct rte_flow_item *item, 8631 int inner) 8632 { 8633 const struct rte_flow_item_tcp *tcp_m = item->mask; 8634 const struct rte_flow_item_tcp *tcp_v = item->spec; 8635 void *headers_m; 8636 void *headers_v; 8637 8638 if (inner) { 8639 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8640 inner_headers); 8641 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8642 } else { 8643 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8644 outer_headers); 8645 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8646 } 8647 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8648 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP); 8649 if (!tcp_v) 8650 return; 8651 if (!tcp_m) 8652 tcp_m = &rte_flow_item_tcp_mask; 8653 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport, 8654 rte_be_to_cpu_16(tcp_m->hdr.src_port)); 8655 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, 8656 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port)); 8657 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport, 8658 rte_be_to_cpu_16(tcp_m->hdr.dst_port)); 8659 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, 8660 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port)); 8661 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags, 8662 tcp_m->hdr.tcp_flags); 8663 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, 8664 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags)); 8665 } 8666 8667 /** 8668 * Add UDP item to matcher and to the value. 8669 * 8670 * @param[in, out] matcher 8671 * Flow matcher. 8672 * @param[in, out] key 8673 * Flow matcher value. 8674 * @param[in] item 8675 * Flow pattern to translate. 8676 * @param[in] inner 8677 * Item is inner pattern. 8678 */ 8679 static void 8680 flow_dv_translate_item_udp(void *matcher, void *key, 8681 const struct rte_flow_item *item, 8682 int inner) 8683 { 8684 const struct rte_flow_item_udp *udp_m = item->mask; 8685 const struct rte_flow_item_udp *udp_v = item->spec; 8686 void *headers_m; 8687 void *headers_v; 8688 8689 if (inner) { 8690 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8691 inner_headers); 8692 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8693 } else { 8694 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8695 outer_headers); 8696 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8697 } 8698 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8699 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 8700 if (!udp_v) 8701 return; 8702 if (!udp_m) 8703 udp_m = &rte_flow_item_udp_mask; 8704 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport, 8705 rte_be_to_cpu_16(udp_m->hdr.src_port)); 8706 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, 8707 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port)); 8708 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 8709 rte_be_to_cpu_16(udp_m->hdr.dst_port)); 8710 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 8711 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port)); 8712 } 8713 8714 /** 8715 * Add GRE optional Key item to matcher and to the value. 8716 * 8717 * @param[in, out] matcher 8718 * Flow matcher. 8719 * @param[in, out] key 8720 * Flow matcher value. 8721 * @param[in] item 8722 * Flow pattern to translate. 8723 * @param[in] inner 8724 * Item is inner pattern. 8725 */ 8726 static void 8727 flow_dv_translate_item_gre_key(void *matcher, void *key, 8728 const struct rte_flow_item *item) 8729 { 8730 const rte_be32_t *key_m = item->mask; 8731 const rte_be32_t *key_v = item->spec; 8732 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8733 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8734 rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX); 8735 8736 /* GRE K bit must be on and should already be validated */ 8737 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1); 8738 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1); 8739 if (!key_v) 8740 return; 8741 if (!key_m) 8742 key_m = &gre_key_default_mask; 8743 MLX5_SET(fte_match_set_misc, misc_m, gre_key_h, 8744 rte_be_to_cpu_32(*key_m) >> 8); 8745 MLX5_SET(fte_match_set_misc, misc_v, gre_key_h, 8746 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8); 8747 MLX5_SET(fte_match_set_misc, misc_m, gre_key_l, 8748 rte_be_to_cpu_32(*key_m) & 0xFF); 8749 MLX5_SET(fte_match_set_misc, misc_v, gre_key_l, 8750 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF); 8751 } 8752 8753 /** 8754 * Add GRE item to matcher and to the value. 8755 * 8756 * @param[in, out] matcher 8757 * Flow matcher. 8758 * @param[in, out] key 8759 * Flow matcher value. 8760 * @param[in] item 8761 * Flow pattern to translate. 8762 * @param[in] inner 8763 * Item is inner pattern. 8764 */ 8765 static void 8766 flow_dv_translate_item_gre(void *matcher, void *key, 8767 const struct rte_flow_item *item, 8768 int inner) 8769 { 8770 const struct rte_flow_item_gre *gre_m = item->mask; 8771 const struct rte_flow_item_gre *gre_v = item->spec; 8772 void *headers_m; 8773 void *headers_v; 8774 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8775 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8776 struct { 8777 union { 8778 __extension__ 8779 struct { 8780 uint16_t version:3; 8781 uint16_t rsvd0:9; 8782 uint16_t s_present:1; 8783 uint16_t k_present:1; 8784 uint16_t rsvd_bit1:1; 8785 uint16_t c_present:1; 8786 }; 8787 uint16_t value; 8788 }; 8789 } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v; 8790 8791 if (inner) { 8792 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8793 inner_headers); 8794 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8795 } else { 8796 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8797 outer_headers); 8798 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8799 } 8800 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8801 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE); 8802 if (!gre_v) 8803 return; 8804 if (!gre_m) 8805 gre_m = &rte_flow_item_gre_mask; 8806 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 8807 rte_be_to_cpu_16(gre_m->protocol)); 8808 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 8809 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol)); 8810 gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver); 8811 gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver); 8812 MLX5_SET(fte_match_set_misc, misc_m, gre_c_present, 8813 gre_crks_rsvd0_ver_m.c_present); 8814 MLX5_SET(fte_match_set_misc, misc_v, gre_c_present, 8815 gre_crks_rsvd0_ver_v.c_present & 8816 gre_crks_rsvd0_ver_m.c_present); 8817 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 8818 gre_crks_rsvd0_ver_m.k_present); 8819 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 8820 gre_crks_rsvd0_ver_v.k_present & 8821 gre_crks_rsvd0_ver_m.k_present); 8822 MLX5_SET(fte_match_set_misc, misc_m, gre_s_present, 8823 gre_crks_rsvd0_ver_m.s_present); 8824 MLX5_SET(fte_match_set_misc, misc_v, gre_s_present, 8825 gre_crks_rsvd0_ver_v.s_present & 8826 gre_crks_rsvd0_ver_m.s_present); 8827 } 8828 8829 /** 8830 * Add NVGRE item to matcher and to the value. 8831 * 8832 * @param[in, out] matcher 8833 * Flow matcher. 8834 * @param[in, out] key 8835 * Flow matcher value. 8836 * @param[in] item 8837 * Flow pattern to translate. 8838 * @param[in] inner 8839 * Item is inner pattern. 8840 */ 8841 static void 8842 flow_dv_translate_item_nvgre(void *matcher, void *key, 8843 const struct rte_flow_item *item, 8844 int inner) 8845 { 8846 const struct rte_flow_item_nvgre *nvgre_m = item->mask; 8847 const struct rte_flow_item_nvgre *nvgre_v = item->spec; 8848 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8849 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8850 const char *tni_flow_id_m; 8851 const char *tni_flow_id_v; 8852 char *gre_key_m; 8853 char *gre_key_v; 8854 int size; 8855 int i; 8856 8857 /* For NVGRE, GRE header fields must be set with defined values. */ 8858 const struct rte_flow_item_gre gre_spec = { 8859 .c_rsvd0_ver = RTE_BE16(0x2000), 8860 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB) 8861 }; 8862 const struct rte_flow_item_gre gre_mask = { 8863 .c_rsvd0_ver = RTE_BE16(0xB000), 8864 .protocol = RTE_BE16(UINT16_MAX), 8865 }; 8866 const struct rte_flow_item gre_item = { 8867 .spec = &gre_spec, 8868 .mask = &gre_mask, 8869 .last = NULL, 8870 }; 8871 flow_dv_translate_item_gre(matcher, key, &gre_item, inner); 8872 if (!nvgre_v) 8873 return; 8874 if (!nvgre_m) 8875 nvgre_m = &rte_flow_item_nvgre_mask; 8876 tni_flow_id_m = (const char *)nvgre_m->tni; 8877 tni_flow_id_v = (const char *)nvgre_v->tni; 8878 size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id); 8879 gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h); 8880 gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h); 8881 memcpy(gre_key_m, tni_flow_id_m, size); 8882 for (i = 0; i < size; ++i) 8883 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i]; 8884 } 8885 8886 /** 8887 * Add VXLAN item to matcher and to the value. 8888 * 8889 * @param[in] dev 8890 * Pointer to the Ethernet device structure. 8891 * @param[in] attr 8892 * Flow rule attributes. 8893 * @param[in, out] matcher 8894 * Flow matcher. 8895 * @param[in, out] key 8896 * Flow matcher value. 8897 * @param[in] item 8898 * Flow pattern to translate. 8899 * @param[in] inner 8900 * Item is inner pattern. 8901 */ 8902 static void 8903 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, 8904 const struct rte_flow_attr *attr, 8905 void *matcher, void *key, 8906 const struct rte_flow_item *item, 8907 int inner) 8908 { 8909 const struct rte_flow_item_vxlan *vxlan_m = item->mask; 8910 const struct rte_flow_item_vxlan *vxlan_v = item->spec; 8911 void *headers_m; 8912 void *headers_v; 8913 void *misc5_m; 8914 void *misc5_v; 8915 uint32_t *tunnel_header_v; 8916 uint32_t *tunnel_header_m; 8917 uint16_t dport; 8918 struct mlx5_priv *priv = dev->data->dev_private; 8919 const struct rte_flow_item_vxlan nic_mask = { 8920 .vni = "\xff\xff\xff", 8921 .rsvd1 = 0xff, 8922 }; 8923 8924 if (inner) { 8925 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8926 inner_headers); 8927 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8928 } else { 8929 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8930 outer_headers); 8931 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8932 } 8933 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 8934 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 8935 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 8936 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 8937 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 8938 } 8939 dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport); 8940 if (!vxlan_v) 8941 return; 8942 if (!vxlan_m) { 8943 if ((!attr->group && !priv->sh->tunnel_header_0_1) || 8944 (attr->group && !priv->sh->misc5_cap)) 8945 vxlan_m = &rte_flow_item_vxlan_mask; 8946 else 8947 vxlan_m = &nic_mask; 8948 } 8949 if ((priv->sh->steering_format_version == 8950 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && 8951 dport != MLX5_UDP_PORT_VXLAN) || 8952 (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) || 8953 ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) { 8954 void *misc_m; 8955 void *misc_v; 8956 char *vni_m; 8957 char *vni_v; 8958 int size; 8959 int i; 8960 misc_m = MLX5_ADDR_OF(fte_match_param, 8961 matcher, misc_parameters); 8962 misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8963 size = sizeof(vxlan_m->vni); 8964 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni); 8965 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni); 8966 memcpy(vni_m, vxlan_m->vni, size); 8967 for (i = 0; i < size; ++i) 8968 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 8969 return; 8970 } 8971 misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5); 8972 misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5); 8973 tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8974 misc5_v, 8975 tunnel_header_1); 8976 tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8977 misc5_m, 8978 tunnel_header_1); 8979 *tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) | 8980 (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 | 8981 (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16; 8982 if (*tunnel_header_v) 8983 *tunnel_header_m = vxlan_m->vni[0] | 8984 vxlan_m->vni[1] << 8 | 8985 vxlan_m->vni[2] << 16; 8986 else 8987 *tunnel_header_m = 0x0; 8988 *tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24; 8989 if (vxlan_v->rsvd1 & vxlan_m->rsvd1) 8990 *tunnel_header_m |= vxlan_m->rsvd1 << 24; 8991 } 8992 8993 /** 8994 * Add VXLAN-GPE item to matcher and to the value. 8995 * 8996 * @param[in, out] matcher 8997 * Flow matcher. 8998 * @param[in, out] key 8999 * Flow matcher value. 9000 * @param[in] item 9001 * Flow pattern to translate. 9002 * @param[in] inner 9003 * Item is inner pattern. 9004 */ 9005 9006 static void 9007 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key, 9008 const struct rte_flow_item *item, int inner) 9009 { 9010 const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask; 9011 const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec; 9012 void *headers_m; 9013 void *headers_v; 9014 void *misc_m = 9015 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3); 9016 void *misc_v = 9017 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9018 char *vni_m; 9019 char *vni_v; 9020 uint16_t dport; 9021 int size; 9022 int i; 9023 uint8_t flags_m = 0xff; 9024 uint8_t flags_v = 0xc; 9025 9026 if (inner) { 9027 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9028 inner_headers); 9029 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9030 } else { 9031 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9032 outer_headers); 9033 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9034 } 9035 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 9036 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 9037 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9038 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9039 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9040 } 9041 if (!vxlan_v) 9042 return; 9043 if (!vxlan_m) 9044 vxlan_m = &rte_flow_item_vxlan_gpe_mask; 9045 size = sizeof(vxlan_m->vni); 9046 vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni); 9047 vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni); 9048 memcpy(vni_m, vxlan_m->vni, size); 9049 for (i = 0; i < size; ++i) 9050 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 9051 if (vxlan_m->flags) { 9052 flags_m = vxlan_m->flags; 9053 flags_v = vxlan_v->flags; 9054 } 9055 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m); 9056 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v); 9057 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol, 9058 vxlan_m->protocol); 9059 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol, 9060 vxlan_v->protocol); 9061 } 9062 9063 /** 9064 * Add Geneve item to matcher and to the value. 9065 * 9066 * @param[in, out] matcher 9067 * Flow matcher. 9068 * @param[in, out] key 9069 * Flow matcher value. 9070 * @param[in] item 9071 * Flow pattern to translate. 9072 * @param[in] inner 9073 * Item is inner pattern. 9074 */ 9075 9076 static void 9077 flow_dv_translate_item_geneve(void *matcher, void *key, 9078 const struct rte_flow_item *item, int inner) 9079 { 9080 const struct rte_flow_item_geneve *geneve_m = item->mask; 9081 const struct rte_flow_item_geneve *geneve_v = item->spec; 9082 void *headers_m; 9083 void *headers_v; 9084 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9085 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9086 uint16_t dport; 9087 uint16_t gbhdr_m; 9088 uint16_t gbhdr_v; 9089 char *vni_m; 9090 char *vni_v; 9091 size_t size, i; 9092 9093 if (inner) { 9094 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9095 inner_headers); 9096 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9097 } else { 9098 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9099 outer_headers); 9100 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9101 } 9102 dport = MLX5_UDP_PORT_GENEVE; 9103 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9104 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9105 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9106 } 9107 if (!geneve_v) 9108 return; 9109 if (!geneve_m) 9110 geneve_m = &rte_flow_item_geneve_mask; 9111 size = sizeof(geneve_m->vni); 9112 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni); 9113 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni); 9114 memcpy(vni_m, geneve_m->vni, size); 9115 for (i = 0; i < size; ++i) 9116 vni_v[i] = vni_m[i] & geneve_v->vni[i]; 9117 MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type, 9118 rte_be_to_cpu_16(geneve_m->protocol)); 9119 MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type, 9120 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol)); 9121 gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0); 9122 gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0); 9123 MLX5_SET(fte_match_set_misc, misc_m, geneve_oam, 9124 MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9125 MLX5_SET(fte_match_set_misc, misc_v, geneve_oam, 9126 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9127 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9128 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9129 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9130 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) & 9131 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9132 } 9133 9134 /** 9135 * Create Geneve TLV option resource. 9136 * 9137 * @param dev[in, out] 9138 * Pointer to rte_eth_dev structure. 9139 * @param[in, out] tag_be24 9140 * Tag value in big endian then R-shift 8. 9141 * @parm[in, out] dev_flow 9142 * Pointer to the dev_flow. 9143 * @param[out] error 9144 * pointer to error structure. 9145 * 9146 * @return 9147 * 0 on success otherwise -errno and errno is set. 9148 */ 9149 9150 int 9151 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev, 9152 const struct rte_flow_item *item, 9153 struct rte_flow_error *error) 9154 { 9155 struct mlx5_priv *priv = dev->data->dev_private; 9156 struct mlx5_dev_ctx_shared *sh = priv->sh; 9157 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 9158 sh->geneve_tlv_option_resource; 9159 struct mlx5_devx_obj *obj; 9160 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9161 int ret = 0; 9162 9163 if (!geneve_opt_v) 9164 return -1; 9165 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 9166 if (geneve_opt_resource != NULL) { 9167 if (geneve_opt_resource->option_class == 9168 geneve_opt_v->option_class && 9169 geneve_opt_resource->option_type == 9170 geneve_opt_v->option_type && 9171 geneve_opt_resource->length == 9172 geneve_opt_v->option_len) { 9173 /* We already have GENVE TLV option obj allocated. */ 9174 __atomic_fetch_add(&geneve_opt_resource->refcnt, 1, 9175 __ATOMIC_RELAXED); 9176 } else { 9177 ret = rte_flow_error_set(error, ENOMEM, 9178 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9179 "Only one GENEVE TLV option supported"); 9180 goto exit; 9181 } 9182 } else { 9183 /* Create a GENEVE TLV object and resource. */ 9184 obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->ctx, 9185 geneve_opt_v->option_class, 9186 geneve_opt_v->option_type, 9187 geneve_opt_v->option_len); 9188 if (!obj) { 9189 ret = rte_flow_error_set(error, ENODATA, 9190 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9191 "Failed to create GENEVE TLV Devx object"); 9192 goto exit; 9193 } 9194 sh->geneve_tlv_option_resource = 9195 mlx5_malloc(MLX5_MEM_ZERO, 9196 sizeof(*geneve_opt_resource), 9197 0, SOCKET_ID_ANY); 9198 if (!sh->geneve_tlv_option_resource) { 9199 claim_zero(mlx5_devx_cmd_destroy(obj)); 9200 ret = rte_flow_error_set(error, ENOMEM, 9201 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9202 "GENEVE TLV object memory allocation failed"); 9203 goto exit; 9204 } 9205 geneve_opt_resource = sh->geneve_tlv_option_resource; 9206 geneve_opt_resource->obj = obj; 9207 geneve_opt_resource->option_class = geneve_opt_v->option_class; 9208 geneve_opt_resource->option_type = geneve_opt_v->option_type; 9209 geneve_opt_resource->length = geneve_opt_v->option_len; 9210 __atomic_store_n(&geneve_opt_resource->refcnt, 1, 9211 __ATOMIC_RELAXED); 9212 } 9213 exit: 9214 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 9215 return ret; 9216 } 9217 9218 /** 9219 * Add Geneve TLV option item to matcher. 9220 * 9221 * @param[in, out] dev 9222 * Pointer to rte_eth_dev structure. 9223 * @param[in, out] matcher 9224 * Flow matcher. 9225 * @param[in, out] key 9226 * Flow matcher value. 9227 * @param[in] item 9228 * Flow pattern to translate. 9229 * @param[out] error 9230 * Pointer to error structure. 9231 */ 9232 static int 9233 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher, 9234 void *key, const struct rte_flow_item *item, 9235 struct rte_flow_error *error) 9236 { 9237 const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask; 9238 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9239 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9240 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9241 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9242 misc_parameters_3); 9243 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9244 rte_be32_t opt_data_key = 0, opt_data_mask = 0; 9245 int ret = 0; 9246 9247 if (!geneve_opt_v) 9248 return -1; 9249 if (!geneve_opt_m) 9250 geneve_opt_m = &rte_flow_item_geneve_opt_mask; 9251 ret = flow_dev_geneve_tlv_option_resource_register(dev, item, 9252 error); 9253 if (ret) { 9254 DRV_LOG(ERR, "Failed to create geneve_tlv_obj"); 9255 return ret; 9256 } 9257 /* 9258 * Set the option length in GENEVE header if not requested. 9259 * The GENEVE TLV option length is expressed by the option length field 9260 * in the GENEVE header. 9261 * If the option length was not requested but the GENEVE TLV option item 9262 * is present we set the option length field implicitly. 9263 */ 9264 if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) { 9265 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9266 MLX5_GENEVE_OPTLEN_MASK); 9267 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9268 geneve_opt_v->option_len + 1); 9269 } 9270 MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1); 9271 MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1); 9272 /* Set the data. */ 9273 if (geneve_opt_v->data) { 9274 memcpy(&opt_data_key, geneve_opt_v->data, 9275 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9276 sizeof(opt_data_key))); 9277 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9278 sizeof(opt_data_key)); 9279 memcpy(&opt_data_mask, geneve_opt_m->data, 9280 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9281 sizeof(opt_data_mask))); 9282 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9283 sizeof(opt_data_mask)); 9284 MLX5_SET(fte_match_set_misc3, misc3_m, 9285 geneve_tlv_option_0_data, 9286 rte_be_to_cpu_32(opt_data_mask)); 9287 MLX5_SET(fte_match_set_misc3, misc3_v, 9288 geneve_tlv_option_0_data, 9289 rte_be_to_cpu_32(opt_data_key & opt_data_mask)); 9290 } 9291 return ret; 9292 } 9293 9294 /** 9295 * Add MPLS item to matcher and to the value. 9296 * 9297 * @param[in, out] matcher 9298 * Flow matcher. 9299 * @param[in, out] key 9300 * Flow matcher value. 9301 * @param[in] item 9302 * Flow pattern to translate. 9303 * @param[in] prev_layer 9304 * The protocol layer indicated in previous item. 9305 * @param[in] inner 9306 * Item is inner pattern. 9307 */ 9308 static void 9309 flow_dv_translate_item_mpls(void *matcher, void *key, 9310 const struct rte_flow_item *item, 9311 uint64_t prev_layer, 9312 int inner) 9313 { 9314 const uint32_t *in_mpls_m = item->mask; 9315 const uint32_t *in_mpls_v = item->spec; 9316 uint32_t *out_mpls_m = 0; 9317 uint32_t *out_mpls_v = 0; 9318 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9319 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9320 void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher, 9321 misc_parameters_2); 9322 void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9323 void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 9324 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9325 9326 switch (prev_layer) { 9327 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9328 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff); 9329 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9330 MLX5_UDP_PORT_MPLS); 9331 break; 9332 case MLX5_FLOW_LAYER_GRE: 9333 /* Fall-through. */ 9334 case MLX5_FLOW_LAYER_GRE_KEY: 9335 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff); 9336 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 9337 RTE_ETHER_TYPE_MPLS); 9338 break; 9339 default: 9340 break; 9341 } 9342 if (!in_mpls_v) 9343 return; 9344 if (!in_mpls_m) 9345 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask; 9346 switch (prev_layer) { 9347 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9348 out_mpls_m = 9349 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9350 outer_first_mpls_over_udp); 9351 out_mpls_v = 9352 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9353 outer_first_mpls_over_udp); 9354 break; 9355 case MLX5_FLOW_LAYER_GRE: 9356 out_mpls_m = 9357 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9358 outer_first_mpls_over_gre); 9359 out_mpls_v = 9360 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9361 outer_first_mpls_over_gre); 9362 break; 9363 default: 9364 /* Inner MPLS not over GRE is not supported. */ 9365 if (!inner) { 9366 out_mpls_m = 9367 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9368 misc2_m, 9369 outer_first_mpls); 9370 out_mpls_v = 9371 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9372 misc2_v, 9373 outer_first_mpls); 9374 } 9375 break; 9376 } 9377 if (out_mpls_m && out_mpls_v) { 9378 *out_mpls_m = *in_mpls_m; 9379 *out_mpls_v = *in_mpls_v & *in_mpls_m; 9380 } 9381 } 9382 9383 /** 9384 * Add metadata register item to matcher 9385 * 9386 * @param[in, out] matcher 9387 * Flow matcher. 9388 * @param[in, out] key 9389 * Flow matcher value. 9390 * @param[in] reg_type 9391 * Type of device metadata register 9392 * @param[in] value 9393 * Register value 9394 * @param[in] mask 9395 * Register mask 9396 */ 9397 static void 9398 flow_dv_match_meta_reg(void *matcher, void *key, 9399 enum modify_reg reg_type, 9400 uint32_t data, uint32_t mask) 9401 { 9402 void *misc2_m = 9403 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2); 9404 void *misc2_v = 9405 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9406 uint32_t temp; 9407 9408 data &= mask; 9409 switch (reg_type) { 9410 case REG_A: 9411 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask); 9412 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data); 9413 break; 9414 case REG_B: 9415 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask); 9416 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data); 9417 break; 9418 case REG_C_0: 9419 /* 9420 * The metadata register C0 field might be divided into 9421 * source vport index and META item value, we should set 9422 * this field according to specified mask, not as whole one. 9423 */ 9424 temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0); 9425 temp |= mask; 9426 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp); 9427 temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0); 9428 temp &= ~mask; 9429 temp |= data; 9430 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp); 9431 break; 9432 case REG_C_1: 9433 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask); 9434 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data); 9435 break; 9436 case REG_C_2: 9437 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask); 9438 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data); 9439 break; 9440 case REG_C_3: 9441 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask); 9442 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data); 9443 break; 9444 case REG_C_4: 9445 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask); 9446 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data); 9447 break; 9448 case REG_C_5: 9449 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask); 9450 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data); 9451 break; 9452 case REG_C_6: 9453 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask); 9454 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data); 9455 break; 9456 case REG_C_7: 9457 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask); 9458 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data); 9459 break; 9460 default: 9461 MLX5_ASSERT(false); 9462 break; 9463 } 9464 } 9465 9466 /** 9467 * Add MARK item to matcher 9468 * 9469 * @param[in] dev 9470 * The device to configure through. 9471 * @param[in, out] matcher 9472 * Flow matcher. 9473 * @param[in, out] key 9474 * Flow matcher value. 9475 * @param[in] item 9476 * Flow pattern to translate. 9477 */ 9478 static void 9479 flow_dv_translate_item_mark(struct rte_eth_dev *dev, 9480 void *matcher, void *key, 9481 const struct rte_flow_item *item) 9482 { 9483 struct mlx5_priv *priv = dev->data->dev_private; 9484 const struct rte_flow_item_mark *mark; 9485 uint32_t value; 9486 uint32_t mask; 9487 9488 mark = item->mask ? (const void *)item->mask : 9489 &rte_flow_item_mark_mask; 9490 mask = mark->id & priv->sh->dv_mark_mask; 9491 mark = (const void *)item->spec; 9492 MLX5_ASSERT(mark); 9493 value = mark->id & priv->sh->dv_mark_mask & mask; 9494 if (mask) { 9495 enum modify_reg reg; 9496 9497 /* Get the metadata register index for the mark. */ 9498 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL); 9499 MLX5_ASSERT(reg > 0); 9500 if (reg == REG_C_0) { 9501 struct mlx5_priv *priv = dev->data->dev_private; 9502 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9503 uint32_t shl_c0 = rte_bsf32(msk_c0); 9504 9505 mask &= msk_c0; 9506 mask <<= shl_c0; 9507 value <<= shl_c0; 9508 } 9509 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9510 } 9511 } 9512 9513 /** 9514 * Add META item to matcher 9515 * 9516 * @param[in] dev 9517 * The devich to configure through. 9518 * @param[in, out] matcher 9519 * Flow matcher. 9520 * @param[in, out] key 9521 * Flow matcher value. 9522 * @param[in] attr 9523 * Attributes of flow that includes this item. 9524 * @param[in] item 9525 * Flow pattern to translate. 9526 */ 9527 static void 9528 flow_dv_translate_item_meta(struct rte_eth_dev *dev, 9529 void *matcher, void *key, 9530 const struct rte_flow_attr *attr, 9531 const struct rte_flow_item *item) 9532 { 9533 const struct rte_flow_item_meta *meta_m; 9534 const struct rte_flow_item_meta *meta_v; 9535 9536 meta_m = (const void *)item->mask; 9537 if (!meta_m) 9538 meta_m = &rte_flow_item_meta_mask; 9539 meta_v = (const void *)item->spec; 9540 if (meta_v) { 9541 int reg; 9542 uint32_t value = meta_v->data; 9543 uint32_t mask = meta_m->data; 9544 9545 reg = flow_dv_get_metadata_reg(dev, attr, NULL); 9546 if (reg < 0) 9547 return; 9548 MLX5_ASSERT(reg != REG_NON); 9549 if (reg == REG_C_0) { 9550 struct mlx5_priv *priv = dev->data->dev_private; 9551 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9552 uint32_t shl_c0 = rte_bsf32(msk_c0); 9553 9554 mask &= msk_c0; 9555 mask <<= shl_c0; 9556 value <<= shl_c0; 9557 } 9558 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9559 } 9560 } 9561 9562 /** 9563 * Add vport metadata Reg C0 item to matcher 9564 * 9565 * @param[in, out] matcher 9566 * Flow matcher. 9567 * @param[in, out] key 9568 * Flow matcher value. 9569 * @param[in] reg 9570 * Flow pattern to translate. 9571 */ 9572 static void 9573 flow_dv_translate_item_meta_vport(void *matcher, void *key, 9574 uint32_t value, uint32_t mask) 9575 { 9576 flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask); 9577 } 9578 9579 /** 9580 * Add tag item to matcher 9581 * 9582 * @param[in] dev 9583 * The devich to configure through. 9584 * @param[in, out] matcher 9585 * Flow matcher. 9586 * @param[in, out] key 9587 * Flow matcher value. 9588 * @param[in] item 9589 * Flow pattern to translate. 9590 */ 9591 static void 9592 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev, 9593 void *matcher, void *key, 9594 const struct rte_flow_item *item) 9595 { 9596 const struct mlx5_rte_flow_item_tag *tag_v = item->spec; 9597 const struct mlx5_rte_flow_item_tag *tag_m = item->mask; 9598 uint32_t mask, value; 9599 9600 MLX5_ASSERT(tag_v); 9601 value = tag_v->data; 9602 mask = tag_m ? tag_m->data : UINT32_MAX; 9603 if (tag_v->id == REG_C_0) { 9604 struct mlx5_priv *priv = dev->data->dev_private; 9605 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9606 uint32_t shl_c0 = rte_bsf32(msk_c0); 9607 9608 mask &= msk_c0; 9609 mask <<= shl_c0; 9610 value <<= shl_c0; 9611 } 9612 flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask); 9613 } 9614 9615 /** 9616 * Add TAG item to matcher 9617 * 9618 * @param[in] dev 9619 * The devich to configure through. 9620 * @param[in, out] matcher 9621 * Flow matcher. 9622 * @param[in, out] key 9623 * Flow matcher value. 9624 * @param[in] item 9625 * Flow pattern to translate. 9626 */ 9627 static void 9628 flow_dv_translate_item_tag(struct rte_eth_dev *dev, 9629 void *matcher, void *key, 9630 const struct rte_flow_item *item) 9631 { 9632 const struct rte_flow_item_tag *tag_v = item->spec; 9633 const struct rte_flow_item_tag *tag_m = item->mask; 9634 enum modify_reg reg; 9635 9636 MLX5_ASSERT(tag_v); 9637 tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask; 9638 /* Get the metadata register index for the tag. */ 9639 reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL); 9640 MLX5_ASSERT(reg > 0); 9641 flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data); 9642 } 9643 9644 /** 9645 * Add source vport match to the specified matcher. 9646 * 9647 * @param[in, out] matcher 9648 * Flow matcher. 9649 * @param[in, out] key 9650 * Flow matcher value. 9651 * @param[in] port 9652 * Source vport value to match 9653 * @param[in] mask 9654 * Mask 9655 */ 9656 static void 9657 flow_dv_translate_item_source_vport(void *matcher, void *key, 9658 int16_t port, uint16_t mask) 9659 { 9660 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9661 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9662 9663 MLX5_SET(fte_match_set_misc, misc_m, source_port, mask); 9664 MLX5_SET(fte_match_set_misc, misc_v, source_port, port); 9665 } 9666 9667 /** 9668 * Translate port-id item to eswitch match on port-id. 9669 * 9670 * @param[in] dev 9671 * The devich to configure through. 9672 * @param[in, out] matcher 9673 * Flow matcher. 9674 * @param[in, out] key 9675 * Flow matcher value. 9676 * @param[in] item 9677 * Flow pattern to translate. 9678 * @param[in] 9679 * Flow attributes. 9680 * 9681 * @return 9682 * 0 on success, a negative errno value otherwise. 9683 */ 9684 static int 9685 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher, 9686 void *key, const struct rte_flow_item *item, 9687 const struct rte_flow_attr *attr) 9688 { 9689 const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL; 9690 const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL; 9691 struct mlx5_priv *priv; 9692 uint16_t mask, id; 9693 9694 mask = pid_m ? pid_m->id : 0xffff; 9695 id = pid_v ? pid_v->id : dev->data->port_id; 9696 priv = mlx5_port_to_eswitch_info(id, item == NULL); 9697 if (!priv) 9698 return -rte_errno; 9699 /* 9700 * Translate to vport field or to metadata, depending on mode. 9701 * Kernel can use either misc.source_port or half of C0 metadata 9702 * register. 9703 */ 9704 if (priv->vport_meta_mask) { 9705 /* 9706 * Provide the hint for SW steering library 9707 * to insert the flow into ingress domain and 9708 * save the extra vport match. 9709 */ 9710 if (mask == 0xffff && priv->vport_id == 0xffff && 9711 priv->pf_bond < 0 && attr->transfer) 9712 flow_dv_translate_item_source_vport 9713 (matcher, key, priv->vport_id, mask); 9714 /* 9715 * We should always set the vport metadata register, 9716 * otherwise the SW steering library can drop 9717 * the rule if wire vport metadata value is not zero, 9718 * it depends on kernel configuration. 9719 */ 9720 flow_dv_translate_item_meta_vport(matcher, key, 9721 priv->vport_meta_tag, 9722 priv->vport_meta_mask); 9723 } else { 9724 flow_dv_translate_item_source_vport(matcher, key, 9725 priv->vport_id, mask); 9726 } 9727 return 0; 9728 } 9729 9730 /** 9731 * Add ICMP6 item to matcher and to the value. 9732 * 9733 * @param[in, out] matcher 9734 * Flow matcher. 9735 * @param[in, out] key 9736 * Flow matcher value. 9737 * @param[in] item 9738 * Flow pattern to translate. 9739 * @param[in] inner 9740 * Item is inner pattern. 9741 */ 9742 static void 9743 flow_dv_translate_item_icmp6(void *matcher, void *key, 9744 const struct rte_flow_item *item, 9745 int inner) 9746 { 9747 const struct rte_flow_item_icmp6 *icmp6_m = item->mask; 9748 const struct rte_flow_item_icmp6 *icmp6_v = item->spec; 9749 void *headers_m; 9750 void *headers_v; 9751 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9752 misc_parameters_3); 9753 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9754 if (inner) { 9755 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9756 inner_headers); 9757 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9758 } else { 9759 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9760 outer_headers); 9761 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9762 } 9763 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9764 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6); 9765 if (!icmp6_v) 9766 return; 9767 if (!icmp6_m) 9768 icmp6_m = &rte_flow_item_icmp6_mask; 9769 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type); 9770 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type, 9771 icmp6_v->type & icmp6_m->type); 9772 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code); 9773 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code, 9774 icmp6_v->code & icmp6_m->code); 9775 } 9776 9777 /** 9778 * Add ICMP item to matcher and to the value. 9779 * 9780 * @param[in, out] matcher 9781 * Flow matcher. 9782 * @param[in, out] key 9783 * Flow matcher value. 9784 * @param[in] item 9785 * Flow pattern to translate. 9786 * @param[in] inner 9787 * Item is inner pattern. 9788 */ 9789 static void 9790 flow_dv_translate_item_icmp(void *matcher, void *key, 9791 const struct rte_flow_item *item, 9792 int inner) 9793 { 9794 const struct rte_flow_item_icmp *icmp_m = item->mask; 9795 const struct rte_flow_item_icmp *icmp_v = item->spec; 9796 uint32_t icmp_header_data_m = 0; 9797 uint32_t icmp_header_data_v = 0; 9798 void *headers_m; 9799 void *headers_v; 9800 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9801 misc_parameters_3); 9802 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9803 if (inner) { 9804 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9805 inner_headers); 9806 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9807 } else { 9808 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9809 outer_headers); 9810 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9811 } 9812 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9813 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP); 9814 if (!icmp_v) 9815 return; 9816 if (!icmp_m) 9817 icmp_m = &rte_flow_item_icmp_mask; 9818 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type, 9819 icmp_m->hdr.icmp_type); 9820 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type, 9821 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type); 9822 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code, 9823 icmp_m->hdr.icmp_code); 9824 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code, 9825 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code); 9826 icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb); 9827 icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16; 9828 if (icmp_header_data_m) { 9829 icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb); 9830 icmp_header_data_v |= 9831 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16; 9832 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data, 9833 icmp_header_data_m); 9834 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data, 9835 icmp_header_data_v & icmp_header_data_m); 9836 } 9837 } 9838 9839 /** 9840 * Add GTP item to matcher and to the value. 9841 * 9842 * @param[in, out] matcher 9843 * Flow matcher. 9844 * @param[in, out] key 9845 * Flow matcher value. 9846 * @param[in] item 9847 * Flow pattern to translate. 9848 * @param[in] inner 9849 * Item is inner pattern. 9850 */ 9851 static void 9852 flow_dv_translate_item_gtp(void *matcher, void *key, 9853 const struct rte_flow_item *item, int inner) 9854 { 9855 const struct rte_flow_item_gtp *gtp_m = item->mask; 9856 const struct rte_flow_item_gtp *gtp_v = item->spec; 9857 void *headers_m; 9858 void *headers_v; 9859 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9860 misc_parameters_3); 9861 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9862 uint16_t dport = RTE_GTPU_UDP_PORT; 9863 9864 if (inner) { 9865 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9866 inner_headers); 9867 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9868 } else { 9869 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9870 outer_headers); 9871 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9872 } 9873 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9874 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9875 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9876 } 9877 if (!gtp_v) 9878 return; 9879 if (!gtp_m) 9880 gtp_m = &rte_flow_item_gtp_mask; 9881 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, 9882 gtp_m->v_pt_rsv_flags); 9883 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, 9884 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags); 9885 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type); 9886 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type, 9887 gtp_v->msg_type & gtp_m->msg_type); 9888 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid, 9889 rte_be_to_cpu_32(gtp_m->teid)); 9890 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid, 9891 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid)); 9892 } 9893 9894 /** 9895 * Add GTP PSC item to matcher. 9896 * 9897 * @param[in, out] matcher 9898 * Flow matcher. 9899 * @param[in, out] key 9900 * Flow matcher value. 9901 * @param[in] item 9902 * Flow pattern to translate. 9903 */ 9904 static int 9905 flow_dv_translate_item_gtp_psc(void *matcher, void *key, 9906 const struct rte_flow_item *item) 9907 { 9908 const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask; 9909 const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec; 9910 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9911 misc_parameters_3); 9912 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9913 union { 9914 uint32_t w32; 9915 struct { 9916 uint16_t seq_num; 9917 uint8_t npdu_num; 9918 uint8_t next_ext_header_type; 9919 }; 9920 } dw_2; 9921 uint8_t gtp_flags; 9922 9923 /* Always set E-flag match on one, regardless of GTP item settings. */ 9924 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags); 9925 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9926 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags); 9927 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags); 9928 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9929 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags); 9930 /*Set next extension header type. */ 9931 dw_2.seq_num = 0; 9932 dw_2.npdu_num = 0; 9933 dw_2.next_ext_header_type = 0xff; 9934 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2, 9935 rte_cpu_to_be_32(dw_2.w32)); 9936 dw_2.seq_num = 0; 9937 dw_2.npdu_num = 0; 9938 dw_2.next_ext_header_type = 0x85; 9939 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2, 9940 rte_cpu_to_be_32(dw_2.w32)); 9941 if (gtp_psc_v) { 9942 union { 9943 uint32_t w32; 9944 struct { 9945 uint8_t len; 9946 uint8_t type_flags; 9947 uint8_t qfi; 9948 uint8_t reserved; 9949 }; 9950 } dw_0; 9951 9952 /*Set extension header PDU type and Qos. */ 9953 if (!gtp_psc_m) 9954 gtp_psc_m = &rte_flow_item_gtp_psc_mask; 9955 dw_0.w32 = 0; 9956 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->pdu_type); 9957 dw_0.qfi = gtp_psc_m->qfi; 9958 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0, 9959 rte_cpu_to_be_32(dw_0.w32)); 9960 dw_0.w32 = 0; 9961 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->pdu_type & 9962 gtp_psc_m->pdu_type); 9963 dw_0.qfi = gtp_psc_v->qfi & gtp_psc_m->qfi; 9964 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0, 9965 rte_cpu_to_be_32(dw_0.w32)); 9966 } 9967 return 0; 9968 } 9969 9970 /** 9971 * Add eCPRI item to matcher and to the value. 9972 * 9973 * @param[in] dev 9974 * The devich to configure through. 9975 * @param[in, out] matcher 9976 * Flow matcher. 9977 * @param[in, out] key 9978 * Flow matcher value. 9979 * @param[in] item 9980 * Flow pattern to translate. 9981 * @param[in] last_item 9982 * Last item flags. 9983 */ 9984 static void 9985 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher, 9986 void *key, const struct rte_flow_item *item, 9987 uint64_t last_item) 9988 { 9989 struct mlx5_priv *priv = dev->data->dev_private; 9990 const struct rte_flow_item_ecpri *ecpri_m = item->mask; 9991 const struct rte_flow_item_ecpri *ecpri_v = item->spec; 9992 struct rte_ecpri_common_hdr common; 9993 void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher, 9994 misc_parameters_4); 9995 void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4); 9996 uint32_t *samples; 9997 void *dw_m; 9998 void *dw_v; 9999 10000 /* 10001 * In case of eCPRI over Ethernet, if EtherType is not specified, 10002 * match on eCPRI EtherType implicitly. 10003 */ 10004 if (last_item & MLX5_FLOW_LAYER_OUTER_L2) { 10005 void *hdrs_m, *hdrs_v, *l2m, *l2v; 10006 10007 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 10008 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 10009 l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype); 10010 l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 10011 if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) { 10012 *(uint16_t *)l2m = UINT16_MAX; 10013 *(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI); 10014 } 10015 } 10016 if (!ecpri_v) 10017 return; 10018 if (!ecpri_m) 10019 ecpri_m = &rte_flow_item_ecpri_mask; 10020 /* 10021 * Maximal four DW samples are supported in a single matching now. 10022 * Two are used now for a eCPRI matching: 10023 * 1. Type: one byte, mask should be 0x00ff0000 in network order 10024 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000 10025 * if any. 10026 */ 10027 if (!ecpri_m->hdr.common.u32) 10028 return; 10029 samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids; 10030 /* Need to take the whole DW as the mask to fill the entry. */ 10031 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 10032 prog_sample_field_value_0); 10033 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 10034 prog_sample_field_value_0); 10035 /* Already big endian (network order) in the header. */ 10036 *(uint32_t *)dw_m = ecpri_m->hdr.common.u32; 10037 *(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32; 10038 /* Sample#0, used for matching type, offset 0. */ 10039 MLX5_SET(fte_match_set_misc4, misc4_m, 10040 prog_sample_field_id_0, samples[0]); 10041 /* It makes no sense to set the sample ID in the mask field. */ 10042 MLX5_SET(fte_match_set_misc4, misc4_v, 10043 prog_sample_field_id_0, samples[0]); 10044 /* 10045 * Checking if message body part needs to be matched. 10046 * Some wildcard rules only matching type field should be supported. 10047 */ 10048 if (ecpri_m->hdr.dummy[0]) { 10049 common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32); 10050 switch (common.type) { 10051 case RTE_ECPRI_MSG_TYPE_IQ_DATA: 10052 case RTE_ECPRI_MSG_TYPE_RTC_CTRL: 10053 case RTE_ECPRI_MSG_TYPE_DLY_MSR: 10054 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 10055 prog_sample_field_value_1); 10056 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 10057 prog_sample_field_value_1); 10058 *(uint32_t *)dw_m = ecpri_m->hdr.dummy[0]; 10059 *(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] & 10060 ecpri_m->hdr.dummy[0]; 10061 /* Sample#1, to match message body, offset 4. */ 10062 MLX5_SET(fte_match_set_misc4, misc4_m, 10063 prog_sample_field_id_1, samples[1]); 10064 MLX5_SET(fte_match_set_misc4, misc4_v, 10065 prog_sample_field_id_1, samples[1]); 10066 break; 10067 default: 10068 /* Others, do not match any sample ID. */ 10069 break; 10070 } 10071 } 10072 } 10073 10074 /* 10075 * Add connection tracking status item to matcher 10076 * 10077 * @param[in] dev 10078 * The devich to configure through. 10079 * @param[in, out] matcher 10080 * Flow matcher. 10081 * @param[in, out] key 10082 * Flow matcher value. 10083 * @param[in] item 10084 * Flow pattern to translate. 10085 */ 10086 static void 10087 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev, 10088 void *matcher, void *key, 10089 const struct rte_flow_item *item) 10090 { 10091 uint32_t reg_value = 0; 10092 int reg_id; 10093 /* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */ 10094 uint32_t reg_mask = 0; 10095 const struct rte_flow_item_conntrack *spec = item->spec; 10096 const struct rte_flow_item_conntrack *mask = item->mask; 10097 uint32_t flags; 10098 struct rte_flow_error error; 10099 10100 if (!mask) 10101 mask = &rte_flow_item_conntrack_mask; 10102 if (!spec || !mask->flags) 10103 return; 10104 flags = spec->flags & mask->flags; 10105 /* The conflict should be checked in the validation. */ 10106 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) 10107 reg_value |= MLX5_CT_SYNDROME_VALID; 10108 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10109 reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE; 10110 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) 10111 reg_value |= MLX5_CT_SYNDROME_INVALID; 10112 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED) 10113 reg_value |= MLX5_CT_SYNDROME_TRAP; 10114 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10115 reg_value |= MLX5_CT_SYNDROME_BAD_PACKET; 10116 if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID | 10117 RTE_FLOW_CONNTRACK_PKT_STATE_INVALID | 10118 RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)) 10119 reg_mask |= 0xc0; 10120 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10121 reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE; 10122 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10123 reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET; 10124 /* The REG_C_x value could be saved during startup. */ 10125 reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error); 10126 if (reg_id == REG_NON) 10127 return; 10128 flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id, 10129 reg_value, reg_mask); 10130 } 10131 10132 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 }; 10133 10134 #define HEADER_IS_ZERO(match_criteria, headers) \ 10135 !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \ 10136 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \ 10137 10138 /** 10139 * Calculate flow matcher enable bitmap. 10140 * 10141 * @param match_criteria 10142 * Pointer to flow matcher criteria. 10143 * 10144 * @return 10145 * Bitmap of enabled fields. 10146 */ 10147 static uint8_t 10148 flow_dv_matcher_enable(uint32_t *match_criteria) 10149 { 10150 uint8_t match_criteria_enable; 10151 10152 match_criteria_enable = 10153 (!HEADER_IS_ZERO(match_criteria, outer_headers)) << 10154 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT; 10155 match_criteria_enable |= 10156 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) << 10157 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT; 10158 match_criteria_enable |= 10159 (!HEADER_IS_ZERO(match_criteria, inner_headers)) << 10160 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT; 10161 match_criteria_enable |= 10162 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) << 10163 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT; 10164 match_criteria_enable |= 10165 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) << 10166 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT; 10167 match_criteria_enable |= 10168 (!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) << 10169 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT; 10170 match_criteria_enable |= 10171 (!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) << 10172 MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT; 10173 return match_criteria_enable; 10174 } 10175 10176 static void 10177 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria) 10178 { 10179 /* 10180 * Check flow matching criteria first, subtract misc5/4 length if flow 10181 * doesn't own misc5/4 parameters. In some old rdma-core releases, 10182 * misc5/4 are not supported, and matcher creation failure is expected 10183 * w/o subtration. If misc5 is provided, misc4 must be counted in since 10184 * misc5 is right after misc4. 10185 */ 10186 if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) { 10187 *size = MLX5_ST_SZ_BYTES(fte_match_param) - 10188 MLX5_ST_SZ_BYTES(fte_match_set_misc5); 10189 if (!(match_criteria & (1 << 10190 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) { 10191 *size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4); 10192 } 10193 } 10194 } 10195 10196 static struct mlx5_list_entry * 10197 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused, 10198 struct mlx5_list_entry *entry, void *cb_ctx) 10199 { 10200 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10201 struct mlx5_flow_dv_matcher *ref = ctx->data; 10202 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10203 typeof(*tbl), tbl); 10204 struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY, 10205 sizeof(*resource), 10206 0, SOCKET_ID_ANY); 10207 10208 if (!resource) { 10209 rte_flow_error_set(ctx->error, ENOMEM, 10210 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10211 "cannot create matcher"); 10212 return NULL; 10213 } 10214 memcpy(resource, entry, sizeof(*resource)); 10215 resource->tbl = &tbl->tbl; 10216 return &resource->entry; 10217 } 10218 10219 static void 10220 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused, 10221 struct mlx5_list_entry *entry) 10222 { 10223 mlx5_free(entry); 10224 } 10225 10226 struct mlx5_list_entry * 10227 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx) 10228 { 10229 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10230 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10231 struct rte_eth_dev *dev = ctx->dev; 10232 struct mlx5_flow_tbl_data_entry *tbl_data; 10233 struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2; 10234 struct rte_flow_error *error = ctx->error; 10235 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10236 struct mlx5_flow_tbl_resource *tbl; 10237 void *domain; 10238 uint32_t idx = 0; 10239 int ret; 10240 10241 tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10242 if (!tbl_data) { 10243 rte_flow_error_set(error, ENOMEM, 10244 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10245 NULL, 10246 "cannot allocate flow table data entry"); 10247 return NULL; 10248 } 10249 tbl_data->idx = idx; 10250 tbl_data->tunnel = tt_prm->tunnel; 10251 tbl_data->group_id = tt_prm->group_id; 10252 tbl_data->external = !!tt_prm->external; 10253 tbl_data->tunnel_offload = is_tunnel_offload_active(dev); 10254 tbl_data->is_egress = !!key.is_egress; 10255 tbl_data->is_transfer = !!key.is_fdb; 10256 tbl_data->dummy = !!key.dummy; 10257 tbl_data->level = key.level; 10258 tbl_data->id = key.id; 10259 tbl = &tbl_data->tbl; 10260 if (key.dummy) 10261 return &tbl_data->entry; 10262 if (key.is_fdb) 10263 domain = sh->fdb_domain; 10264 else if (key.is_egress) 10265 domain = sh->tx_domain; 10266 else 10267 domain = sh->rx_domain; 10268 ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj); 10269 if (ret) { 10270 rte_flow_error_set(error, ENOMEM, 10271 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10272 NULL, "cannot create flow table object"); 10273 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10274 return NULL; 10275 } 10276 if (key.level != 0) { 10277 ret = mlx5_flow_os_create_flow_action_dest_flow_tbl 10278 (tbl->obj, &tbl_data->jump.action); 10279 if (ret) { 10280 rte_flow_error_set(error, ENOMEM, 10281 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10282 NULL, 10283 "cannot create flow jump action"); 10284 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10285 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10286 return NULL; 10287 } 10288 } 10289 MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list", 10290 key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress", 10291 key.level, key.id); 10292 tbl_data->matchers = mlx5_list_create(matcher_name, sh, true, 10293 flow_dv_matcher_create_cb, 10294 flow_dv_matcher_match_cb, 10295 flow_dv_matcher_remove_cb, 10296 flow_dv_matcher_clone_cb, 10297 flow_dv_matcher_clone_free_cb); 10298 if (!tbl_data->matchers) { 10299 rte_flow_error_set(error, ENOMEM, 10300 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10301 NULL, 10302 "cannot create tbl matcher list"); 10303 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10304 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10305 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10306 return NULL; 10307 } 10308 return &tbl_data->entry; 10309 } 10310 10311 int 10312 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10313 void *cb_ctx) 10314 { 10315 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10316 struct mlx5_flow_tbl_data_entry *tbl_data = 10317 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10318 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10319 10320 return tbl_data->level != key.level || 10321 tbl_data->id != key.id || 10322 tbl_data->dummy != key.dummy || 10323 tbl_data->is_transfer != !!key.is_fdb || 10324 tbl_data->is_egress != !!key.is_egress; 10325 } 10326 10327 struct mlx5_list_entry * 10328 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10329 void *cb_ctx) 10330 { 10331 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10332 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10333 struct mlx5_flow_tbl_data_entry *tbl_data; 10334 struct rte_flow_error *error = ctx->error; 10335 uint32_t idx = 0; 10336 10337 tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10338 if (!tbl_data) { 10339 rte_flow_error_set(error, ENOMEM, 10340 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10341 NULL, 10342 "cannot allocate flow table data entry"); 10343 return NULL; 10344 } 10345 memcpy(tbl_data, oentry, sizeof(*tbl_data)); 10346 tbl_data->idx = idx; 10347 return &tbl_data->entry; 10348 } 10349 10350 void 10351 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10352 { 10353 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10354 struct mlx5_flow_tbl_data_entry *tbl_data = 10355 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10356 10357 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10358 } 10359 10360 /** 10361 * Get a flow table. 10362 * 10363 * @param[in, out] dev 10364 * Pointer to rte_eth_dev structure. 10365 * @param[in] table_level 10366 * Table level to use. 10367 * @param[in] egress 10368 * Direction of the table. 10369 * @param[in] transfer 10370 * E-Switch or NIC flow. 10371 * @param[in] dummy 10372 * Dummy entry for dv API. 10373 * @param[in] table_id 10374 * Table id to use. 10375 * @param[out] error 10376 * pointer to error structure. 10377 * 10378 * @return 10379 * Returns tables resource based on the index, NULL in case of failed. 10380 */ 10381 struct mlx5_flow_tbl_resource * 10382 flow_dv_tbl_resource_get(struct rte_eth_dev *dev, 10383 uint32_t table_level, uint8_t egress, 10384 uint8_t transfer, 10385 bool external, 10386 const struct mlx5_flow_tunnel *tunnel, 10387 uint32_t group_id, uint8_t dummy, 10388 uint32_t table_id, 10389 struct rte_flow_error *error) 10390 { 10391 struct mlx5_priv *priv = dev->data->dev_private; 10392 union mlx5_flow_tbl_key table_key = { 10393 { 10394 .level = table_level, 10395 .id = table_id, 10396 .reserved = 0, 10397 .dummy = !!dummy, 10398 .is_fdb = !!transfer, 10399 .is_egress = !!egress, 10400 } 10401 }; 10402 struct mlx5_flow_tbl_tunnel_prm tt_prm = { 10403 .tunnel = tunnel, 10404 .group_id = group_id, 10405 .external = external, 10406 }; 10407 struct mlx5_flow_cb_ctx ctx = { 10408 .dev = dev, 10409 .error = error, 10410 .data = &table_key.v64, 10411 .data2 = &tt_prm, 10412 }; 10413 struct mlx5_list_entry *entry; 10414 struct mlx5_flow_tbl_data_entry *tbl_data; 10415 10416 entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx); 10417 if (!entry) { 10418 rte_flow_error_set(error, ENOMEM, 10419 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10420 "cannot get table"); 10421 return NULL; 10422 } 10423 DRV_LOG(DEBUG, "table_level %u table_id %u " 10424 "tunnel %u group %u registered.", 10425 table_level, table_id, 10426 tunnel ? tunnel->tunnel_id : 0, group_id); 10427 tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10428 return &tbl_data->tbl; 10429 } 10430 10431 void 10432 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10433 { 10434 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10435 struct mlx5_flow_tbl_data_entry *tbl_data = 10436 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10437 10438 MLX5_ASSERT(entry && sh); 10439 if (tbl_data->jump.action) 10440 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10441 if (tbl_data->tbl.obj) 10442 mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj); 10443 if (tbl_data->tunnel_offload && tbl_data->external) { 10444 struct mlx5_list_entry *he; 10445 struct mlx5_hlist *tunnel_grp_hash; 10446 struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub; 10447 union tunnel_tbl_key tunnel_key = { 10448 .tunnel_id = tbl_data->tunnel ? 10449 tbl_data->tunnel->tunnel_id : 0, 10450 .group = tbl_data->group_id 10451 }; 10452 uint32_t table_level = tbl_data->level; 10453 struct mlx5_flow_cb_ctx ctx = { 10454 .data = (void *)&tunnel_key.val, 10455 }; 10456 10457 tunnel_grp_hash = tbl_data->tunnel ? 10458 tbl_data->tunnel->groups : 10459 thub->groups; 10460 he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx); 10461 if (he) 10462 mlx5_hlist_unregister(tunnel_grp_hash, he); 10463 DRV_LOG(DEBUG, 10464 "table_level %u id %u tunnel %u group %u released.", 10465 table_level, 10466 tbl_data->id, 10467 tbl_data->tunnel ? 10468 tbl_data->tunnel->tunnel_id : 0, 10469 tbl_data->group_id); 10470 } 10471 mlx5_list_destroy(tbl_data->matchers); 10472 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10473 } 10474 10475 /** 10476 * Release a flow table. 10477 * 10478 * @param[in] sh 10479 * Pointer to device shared structure. 10480 * @param[in] tbl 10481 * Table resource to be released. 10482 * 10483 * @return 10484 * Returns 0 if table was released, else return 1; 10485 */ 10486 static int 10487 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 10488 struct mlx5_flow_tbl_resource *tbl) 10489 { 10490 struct mlx5_flow_tbl_data_entry *tbl_data = 10491 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10492 10493 if (!tbl) 10494 return 0; 10495 return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry); 10496 } 10497 10498 int 10499 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused, 10500 struct mlx5_list_entry *entry, void *cb_ctx) 10501 { 10502 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10503 struct mlx5_flow_dv_matcher *ref = ctx->data; 10504 struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur), 10505 entry); 10506 10507 return cur->crc != ref->crc || 10508 cur->priority != ref->priority || 10509 memcmp((const void *)cur->mask.buf, 10510 (const void *)ref->mask.buf, ref->mask.size); 10511 } 10512 10513 struct mlx5_list_entry * 10514 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx) 10515 { 10516 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10517 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10518 struct mlx5_flow_dv_matcher *ref = ctx->data; 10519 struct mlx5_flow_dv_matcher *resource; 10520 struct mlx5dv_flow_matcher_attr dv_attr = { 10521 .type = IBV_FLOW_ATTR_NORMAL, 10522 .match_mask = (void *)&ref->mask, 10523 }; 10524 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10525 typeof(*tbl), tbl); 10526 int ret; 10527 10528 resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0, 10529 SOCKET_ID_ANY); 10530 if (!resource) { 10531 rte_flow_error_set(ctx->error, ENOMEM, 10532 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10533 "cannot create matcher"); 10534 return NULL; 10535 } 10536 *resource = *ref; 10537 dv_attr.match_criteria_enable = 10538 flow_dv_matcher_enable(resource->mask.buf); 10539 __flow_dv_adjust_buf_size(&ref->mask.size, 10540 dv_attr.match_criteria_enable); 10541 dv_attr.priority = ref->priority; 10542 if (tbl->is_egress) 10543 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS; 10544 ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->tbl.obj, 10545 &resource->matcher_object); 10546 if (ret) { 10547 mlx5_free(resource); 10548 rte_flow_error_set(ctx->error, ENOMEM, 10549 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10550 "cannot create matcher"); 10551 return NULL; 10552 } 10553 return &resource->entry; 10554 } 10555 10556 /** 10557 * Register the flow matcher. 10558 * 10559 * @param[in, out] dev 10560 * Pointer to rte_eth_dev structure. 10561 * @param[in, out] matcher 10562 * Pointer to flow matcher. 10563 * @param[in, out] key 10564 * Pointer to flow table key. 10565 * @parm[in, out] dev_flow 10566 * Pointer to the dev_flow. 10567 * @param[out] error 10568 * pointer to error structure. 10569 * 10570 * @return 10571 * 0 on success otherwise -errno and errno is set. 10572 */ 10573 static int 10574 flow_dv_matcher_register(struct rte_eth_dev *dev, 10575 struct mlx5_flow_dv_matcher *ref, 10576 union mlx5_flow_tbl_key *key, 10577 struct mlx5_flow *dev_flow, 10578 const struct mlx5_flow_tunnel *tunnel, 10579 uint32_t group_id, 10580 struct rte_flow_error *error) 10581 { 10582 struct mlx5_list_entry *entry; 10583 struct mlx5_flow_dv_matcher *resource; 10584 struct mlx5_flow_tbl_resource *tbl; 10585 struct mlx5_flow_tbl_data_entry *tbl_data; 10586 struct mlx5_flow_cb_ctx ctx = { 10587 .error = error, 10588 .data = ref, 10589 }; 10590 /** 10591 * tunnel offload API requires this registration for cases when 10592 * tunnel match rule was inserted before tunnel set rule. 10593 */ 10594 tbl = flow_dv_tbl_resource_get(dev, key->level, 10595 key->is_egress, key->is_fdb, 10596 dev_flow->external, tunnel, 10597 group_id, 0, key->id, error); 10598 if (!tbl) 10599 return -rte_errno; /* No need to refill the error info */ 10600 tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10601 ref->tbl = tbl; 10602 entry = mlx5_list_register(tbl_data->matchers, &ctx); 10603 if (!entry) { 10604 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 10605 return rte_flow_error_set(error, ENOMEM, 10606 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10607 "cannot allocate ref memory"); 10608 } 10609 resource = container_of(entry, typeof(*resource), entry); 10610 dev_flow->handle->dvh.matcher = resource; 10611 return 0; 10612 } 10613 10614 struct mlx5_list_entry * 10615 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx) 10616 { 10617 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10618 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10619 struct mlx5_flow_dv_tag_resource *entry; 10620 uint32_t idx = 0; 10621 int ret; 10622 10623 entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10624 if (!entry) { 10625 rte_flow_error_set(ctx->error, ENOMEM, 10626 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10627 "cannot allocate resource memory"); 10628 return NULL; 10629 } 10630 entry->idx = idx; 10631 entry->tag_id = *(uint32_t *)(ctx->data); 10632 ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id, 10633 &entry->action); 10634 if (ret) { 10635 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx); 10636 rte_flow_error_set(ctx->error, ENOMEM, 10637 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10638 NULL, "cannot create action"); 10639 return NULL; 10640 } 10641 return &entry->entry; 10642 } 10643 10644 int 10645 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10646 void *cb_ctx) 10647 { 10648 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10649 struct mlx5_flow_dv_tag_resource *tag = 10650 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10651 10652 return *(uint32_t *)(ctx->data) != tag->tag_id; 10653 } 10654 10655 struct mlx5_list_entry * 10656 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10657 void *cb_ctx) 10658 { 10659 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10660 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10661 struct mlx5_flow_dv_tag_resource *entry; 10662 uint32_t idx = 0; 10663 10664 entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10665 if (!entry) { 10666 rte_flow_error_set(ctx->error, ENOMEM, 10667 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10668 "cannot allocate tag resource memory"); 10669 return NULL; 10670 } 10671 memcpy(entry, oentry, sizeof(*entry)); 10672 entry->idx = idx; 10673 return &entry->entry; 10674 } 10675 10676 void 10677 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10678 { 10679 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10680 struct mlx5_flow_dv_tag_resource *tag = 10681 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10682 10683 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10684 } 10685 10686 /** 10687 * Find existing tag resource or create and register a new one. 10688 * 10689 * @param dev[in, out] 10690 * Pointer to rte_eth_dev structure. 10691 * @param[in, out] tag_be24 10692 * Tag value in big endian then R-shift 8. 10693 * @parm[in, out] dev_flow 10694 * Pointer to the dev_flow. 10695 * @param[out] error 10696 * pointer to error structure. 10697 * 10698 * @return 10699 * 0 on success otherwise -errno and errno is set. 10700 */ 10701 static int 10702 flow_dv_tag_resource_register 10703 (struct rte_eth_dev *dev, 10704 uint32_t tag_be24, 10705 struct mlx5_flow *dev_flow, 10706 struct rte_flow_error *error) 10707 { 10708 struct mlx5_priv *priv = dev->data->dev_private; 10709 struct mlx5_flow_dv_tag_resource *resource; 10710 struct mlx5_list_entry *entry; 10711 struct mlx5_flow_cb_ctx ctx = { 10712 .error = error, 10713 .data = &tag_be24, 10714 }; 10715 struct mlx5_hlist *tag_table; 10716 10717 tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table, 10718 "tags", 10719 MLX5_TAGS_HLIST_ARRAY_SIZE, 10720 false, false, priv->sh, 10721 flow_dv_tag_create_cb, 10722 flow_dv_tag_match_cb, 10723 flow_dv_tag_remove_cb, 10724 flow_dv_tag_clone_cb, 10725 flow_dv_tag_clone_free_cb); 10726 if (unlikely(!tag_table)) 10727 return -rte_errno; 10728 entry = mlx5_hlist_register(tag_table, tag_be24, &ctx); 10729 if (entry) { 10730 resource = container_of(entry, struct mlx5_flow_dv_tag_resource, 10731 entry); 10732 dev_flow->handle->dvh.rix_tag = resource->idx; 10733 dev_flow->dv.tag_resource = resource; 10734 return 0; 10735 } 10736 return -rte_errno; 10737 } 10738 10739 void 10740 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10741 { 10742 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10743 struct mlx5_flow_dv_tag_resource *tag = 10744 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10745 10746 MLX5_ASSERT(tag && sh && tag->action); 10747 claim_zero(mlx5_flow_os_destroy_flow_action(tag->action)); 10748 DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag); 10749 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10750 } 10751 10752 /** 10753 * Release the tag. 10754 * 10755 * @param dev 10756 * Pointer to Ethernet device. 10757 * @param tag_idx 10758 * Tag index. 10759 * 10760 * @return 10761 * 1 while a reference on it exists, 0 when freed. 10762 */ 10763 static int 10764 flow_dv_tag_release(struct rte_eth_dev *dev, 10765 uint32_t tag_idx) 10766 { 10767 struct mlx5_priv *priv = dev->data->dev_private; 10768 struct mlx5_flow_dv_tag_resource *tag; 10769 10770 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx); 10771 if (!tag) 10772 return 0; 10773 DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--", 10774 dev->data->port_id, (void *)tag, tag->entry.ref_cnt); 10775 return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry); 10776 } 10777 10778 /** 10779 * Translate port ID action to vport. 10780 * 10781 * @param[in] dev 10782 * Pointer to rte_eth_dev structure. 10783 * @param[in] action 10784 * Pointer to the port ID action. 10785 * @param[out] dst_port_id 10786 * The target port ID. 10787 * @param[out] error 10788 * Pointer to the error structure. 10789 * 10790 * @return 10791 * 0 on success, a negative errno value otherwise and rte_errno is set. 10792 */ 10793 static int 10794 flow_dv_translate_action_port_id(struct rte_eth_dev *dev, 10795 const struct rte_flow_action *action, 10796 uint32_t *dst_port_id, 10797 struct rte_flow_error *error) 10798 { 10799 uint32_t port; 10800 struct mlx5_priv *priv; 10801 const struct rte_flow_action_port_id *conf = 10802 (const struct rte_flow_action_port_id *)action->conf; 10803 10804 port = conf->original ? dev->data->port_id : conf->id; 10805 priv = mlx5_port_to_eswitch_info(port, false); 10806 if (!priv) 10807 return rte_flow_error_set(error, -rte_errno, 10808 RTE_FLOW_ERROR_TYPE_ACTION, 10809 NULL, 10810 "No eswitch info was found for port"); 10811 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT 10812 /* 10813 * This parameter is transferred to 10814 * mlx5dv_dr_action_create_dest_ib_port(). 10815 */ 10816 *dst_port_id = priv->dev_port; 10817 #else 10818 /* 10819 * Legacy mode, no LAG configurations is supported. 10820 * This parameter is transferred to 10821 * mlx5dv_dr_action_create_dest_vport(). 10822 */ 10823 *dst_port_id = priv->vport_id; 10824 #endif 10825 return 0; 10826 } 10827 10828 /** 10829 * Create a counter with aging configuration. 10830 * 10831 * @param[in] dev 10832 * Pointer to rte_eth_dev structure. 10833 * @param[in] dev_flow 10834 * Pointer to the mlx5_flow. 10835 * @param[out] count 10836 * Pointer to the counter action configuration. 10837 * @param[in] age 10838 * Pointer to the aging action configuration. 10839 * 10840 * @return 10841 * Index to flow counter on success, 0 otherwise. 10842 */ 10843 static uint32_t 10844 flow_dv_translate_create_counter(struct rte_eth_dev *dev, 10845 struct mlx5_flow *dev_flow, 10846 const struct rte_flow_action_count *count, 10847 const struct rte_flow_action_age *age) 10848 { 10849 uint32_t counter; 10850 struct mlx5_age_param *age_param; 10851 10852 if (count && count->shared) 10853 counter = flow_dv_counter_get_shared(dev, count->id); 10854 else 10855 counter = flow_dv_counter_alloc(dev, !!age); 10856 if (!counter || age == NULL) 10857 return counter; 10858 age_param = flow_dv_counter_idx_get_age(dev, counter); 10859 age_param->context = age->context ? age->context : 10860 (void *)(uintptr_t)(dev_flow->flow_idx); 10861 age_param->timeout = age->timeout; 10862 age_param->port_id = dev->data->port_id; 10863 __atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED); 10864 __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED); 10865 return counter; 10866 } 10867 10868 /** 10869 * Add Tx queue matcher 10870 * 10871 * @param[in] dev 10872 * Pointer to the dev struct. 10873 * @param[in, out] matcher 10874 * Flow matcher. 10875 * @param[in, out] key 10876 * Flow matcher value. 10877 * @param[in] item 10878 * Flow pattern to translate. 10879 * @param[in] inner 10880 * Item is inner pattern. 10881 */ 10882 static void 10883 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev, 10884 void *matcher, void *key, 10885 const struct rte_flow_item *item) 10886 { 10887 const struct mlx5_rte_flow_item_tx_queue *queue_m; 10888 const struct mlx5_rte_flow_item_tx_queue *queue_v; 10889 void *misc_m = 10890 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 10891 void *misc_v = 10892 MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 10893 struct mlx5_txq_ctrl *txq; 10894 uint32_t queue; 10895 10896 10897 queue_m = (const void *)item->mask; 10898 if (!queue_m) 10899 return; 10900 queue_v = (const void *)item->spec; 10901 if (!queue_v) 10902 return; 10903 txq = mlx5_txq_get(dev, queue_v->queue); 10904 if (!txq) 10905 return; 10906 queue = txq->obj->sq->id; 10907 MLX5_SET(fte_match_set_misc, misc_m, source_sqn, queue_m->queue); 10908 MLX5_SET(fte_match_set_misc, misc_v, source_sqn, 10909 queue & queue_m->queue); 10910 mlx5_txq_release(dev, queue_v->queue); 10911 } 10912 10913 /** 10914 * Set the hash fields according to the @p flow information. 10915 * 10916 * @param[in] dev_flow 10917 * Pointer to the mlx5_flow. 10918 * @param[in] rss_desc 10919 * Pointer to the mlx5_flow_rss_desc. 10920 */ 10921 static void 10922 flow_dv_hashfields_set(struct mlx5_flow *dev_flow, 10923 struct mlx5_flow_rss_desc *rss_desc) 10924 { 10925 uint64_t items = dev_flow->handle->layers; 10926 int rss_inner = 0; 10927 uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types); 10928 10929 dev_flow->hash_fields = 0; 10930 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT 10931 if (rss_desc->level >= 2) 10932 rss_inner = 1; 10933 #endif 10934 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || 10935 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { 10936 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 10937 if (rss_types & ETH_RSS_L3_SRC_ONLY) 10938 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4; 10939 else if (rss_types & ETH_RSS_L3_DST_ONLY) 10940 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4; 10941 else 10942 dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH; 10943 } 10944 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 10945 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) { 10946 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 10947 if (rss_types & ETH_RSS_L3_SRC_ONLY) 10948 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6; 10949 else if (rss_types & ETH_RSS_L3_DST_ONLY) 10950 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6; 10951 else 10952 dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH; 10953 } 10954 } 10955 if (dev_flow->hash_fields == 0) 10956 /* 10957 * There is no match between the RSS types and the 10958 * L3 protocol (IPv4/IPv6) defined in the flow rule. 10959 */ 10960 return; 10961 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || 10962 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { 10963 if (rss_types & ETH_RSS_UDP) { 10964 if (rss_types & ETH_RSS_L4_SRC_ONLY) 10965 dev_flow->hash_fields |= 10966 IBV_RX_HASH_SRC_PORT_UDP; 10967 else if (rss_types & ETH_RSS_L4_DST_ONLY) 10968 dev_flow->hash_fields |= 10969 IBV_RX_HASH_DST_PORT_UDP; 10970 else 10971 dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH; 10972 } 10973 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) || 10974 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) { 10975 if (rss_types & ETH_RSS_TCP) { 10976 if (rss_types & ETH_RSS_L4_SRC_ONLY) 10977 dev_flow->hash_fields |= 10978 IBV_RX_HASH_SRC_PORT_TCP; 10979 else if (rss_types & ETH_RSS_L4_DST_ONLY) 10980 dev_flow->hash_fields |= 10981 IBV_RX_HASH_DST_PORT_TCP; 10982 else 10983 dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH; 10984 } 10985 } 10986 if (rss_inner) 10987 dev_flow->hash_fields |= IBV_RX_HASH_INNER; 10988 } 10989 10990 /** 10991 * Prepare an Rx Hash queue. 10992 * 10993 * @param dev 10994 * Pointer to Ethernet device. 10995 * @param[in] dev_flow 10996 * Pointer to the mlx5_flow. 10997 * @param[in] rss_desc 10998 * Pointer to the mlx5_flow_rss_desc. 10999 * @param[out] hrxq_idx 11000 * Hash Rx queue index. 11001 * 11002 * @return 11003 * The Verbs/DevX object initialised, NULL otherwise and rte_errno is set. 11004 */ 11005 static struct mlx5_hrxq * 11006 flow_dv_hrxq_prepare(struct rte_eth_dev *dev, 11007 struct mlx5_flow *dev_flow, 11008 struct mlx5_flow_rss_desc *rss_desc, 11009 uint32_t *hrxq_idx) 11010 { 11011 struct mlx5_priv *priv = dev->data->dev_private; 11012 struct mlx5_flow_handle *dh = dev_flow->handle; 11013 struct mlx5_hrxq *hrxq; 11014 11015 MLX5_ASSERT(rss_desc->queue_num); 11016 rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN; 11017 rss_desc->hash_fields = dev_flow->hash_fields; 11018 rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL); 11019 rss_desc->shared_rss = 0; 11020 if (rss_desc->hash_fields == 0) 11021 rss_desc->queue_num = 1; 11022 *hrxq_idx = mlx5_hrxq_get(dev, rss_desc); 11023 if (!*hrxq_idx) 11024 return NULL; 11025 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 11026 *hrxq_idx); 11027 return hrxq; 11028 } 11029 11030 /** 11031 * Release sample sub action resource. 11032 * 11033 * @param[in, out] dev 11034 * Pointer to rte_eth_dev structure. 11035 * @param[in] act_res 11036 * Pointer to sample sub action resource. 11037 */ 11038 static void 11039 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev, 11040 struct mlx5_flow_sub_actions_idx *act_res) 11041 { 11042 if (act_res->rix_hrxq) { 11043 mlx5_hrxq_release(dev, act_res->rix_hrxq); 11044 act_res->rix_hrxq = 0; 11045 } 11046 if (act_res->rix_encap_decap) { 11047 flow_dv_encap_decap_resource_release(dev, 11048 act_res->rix_encap_decap); 11049 act_res->rix_encap_decap = 0; 11050 } 11051 if (act_res->rix_port_id_action) { 11052 flow_dv_port_id_action_resource_release(dev, 11053 act_res->rix_port_id_action); 11054 act_res->rix_port_id_action = 0; 11055 } 11056 if (act_res->rix_tag) { 11057 flow_dv_tag_release(dev, act_res->rix_tag); 11058 act_res->rix_tag = 0; 11059 } 11060 if (act_res->rix_jump) { 11061 flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump); 11062 act_res->rix_jump = 0; 11063 } 11064 } 11065 11066 int 11067 flow_dv_sample_match_cb(void *tool_ctx __rte_unused, 11068 struct mlx5_list_entry *entry, void *cb_ctx) 11069 { 11070 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11071 struct rte_eth_dev *dev = ctx->dev; 11072 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11073 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 11074 typeof(*resource), 11075 entry); 11076 11077 if (ctx_resource->ratio == resource->ratio && 11078 ctx_resource->ft_type == resource->ft_type && 11079 ctx_resource->ft_id == resource->ft_id && 11080 ctx_resource->set_action == resource->set_action && 11081 !memcmp((void *)&ctx_resource->sample_act, 11082 (void *)&resource->sample_act, 11083 sizeof(struct mlx5_flow_sub_actions_list))) { 11084 /* 11085 * Existing sample action should release the prepared 11086 * sub-actions reference counter. 11087 */ 11088 flow_dv_sample_sub_actions_release(dev, 11089 &ctx_resource->sample_idx); 11090 return 0; 11091 } 11092 return 1; 11093 } 11094 11095 struct mlx5_list_entry * 11096 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11097 { 11098 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11099 struct rte_eth_dev *dev = ctx->dev; 11100 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11101 void **sample_dv_actions = ctx_resource->sub_actions; 11102 struct mlx5_flow_dv_sample_resource *resource; 11103 struct mlx5dv_dr_flow_sampler_attr sampler_attr; 11104 struct mlx5_priv *priv = dev->data->dev_private; 11105 struct mlx5_dev_ctx_shared *sh = priv->sh; 11106 struct mlx5_flow_tbl_resource *tbl; 11107 uint32_t idx = 0; 11108 const uint32_t next_ft_step = 1; 11109 uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step; 11110 uint8_t is_egress = 0; 11111 uint8_t is_transfer = 0; 11112 struct rte_flow_error *error = ctx->error; 11113 11114 /* Register new sample resource. */ 11115 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11116 if (!resource) { 11117 rte_flow_error_set(error, ENOMEM, 11118 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11119 NULL, 11120 "cannot allocate resource memory"); 11121 return NULL; 11122 } 11123 *resource = *ctx_resource; 11124 /* Create normal path table level */ 11125 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11126 is_transfer = 1; 11127 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 11128 is_egress = 1; 11129 tbl = flow_dv_tbl_resource_get(dev, next_ft_id, 11130 is_egress, is_transfer, 11131 true, NULL, 0, 0, 0, error); 11132 if (!tbl) { 11133 rte_flow_error_set(error, ENOMEM, 11134 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11135 NULL, 11136 "fail to create normal path table " 11137 "for sample"); 11138 goto error; 11139 } 11140 resource->normal_path_tbl = tbl; 11141 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) { 11142 if (!sh->default_miss_action) { 11143 rte_flow_error_set(error, ENOMEM, 11144 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11145 NULL, 11146 "default miss action was not " 11147 "created"); 11148 goto error; 11149 } 11150 sample_dv_actions[ctx_resource->sample_act.actions_num++] = 11151 sh->default_miss_action; 11152 } 11153 /* Create a DR sample action */ 11154 sampler_attr.sample_ratio = resource->ratio; 11155 sampler_attr.default_next_table = tbl->obj; 11156 sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num; 11157 sampler_attr.sample_actions = (struct mlx5dv_dr_action **) 11158 &sample_dv_actions[0]; 11159 sampler_attr.action = resource->set_action; 11160 if (mlx5_os_flow_dr_create_flow_action_sampler 11161 (&sampler_attr, &resource->verbs_action)) { 11162 rte_flow_error_set(error, ENOMEM, 11163 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11164 NULL, "cannot create sample action"); 11165 goto error; 11166 } 11167 resource->idx = idx; 11168 resource->dev = dev; 11169 return &resource->entry; 11170 error: 11171 if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB) 11172 flow_dv_sample_sub_actions_release(dev, 11173 &resource->sample_idx); 11174 if (resource->normal_path_tbl) 11175 flow_dv_tbl_resource_release(MLX5_SH(dev), 11176 resource->normal_path_tbl); 11177 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx); 11178 return NULL; 11179 11180 } 11181 11182 struct mlx5_list_entry * 11183 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused, 11184 struct mlx5_list_entry *entry __rte_unused, 11185 void *cb_ctx) 11186 { 11187 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11188 struct rte_eth_dev *dev = ctx->dev; 11189 struct mlx5_flow_dv_sample_resource *resource; 11190 struct mlx5_priv *priv = dev->data->dev_private; 11191 struct mlx5_dev_ctx_shared *sh = priv->sh; 11192 uint32_t idx = 0; 11193 11194 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11195 if (!resource) { 11196 rte_flow_error_set(ctx->error, ENOMEM, 11197 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11198 NULL, 11199 "cannot allocate resource memory"); 11200 return NULL; 11201 } 11202 memcpy(resource, entry, sizeof(*resource)); 11203 resource->idx = idx; 11204 resource->dev = dev; 11205 return &resource->entry; 11206 } 11207 11208 void 11209 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused, 11210 struct mlx5_list_entry *entry) 11211 { 11212 struct mlx5_flow_dv_sample_resource *resource = 11213 container_of(entry, typeof(*resource), entry); 11214 struct rte_eth_dev *dev = resource->dev; 11215 struct mlx5_priv *priv = dev->data->dev_private; 11216 11217 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 11218 } 11219 11220 /** 11221 * Find existing sample resource or create and register a new one. 11222 * 11223 * @param[in, out] dev 11224 * Pointer to rte_eth_dev structure. 11225 * @param[in] ref 11226 * Pointer to sample resource reference. 11227 * @parm[in, out] dev_flow 11228 * Pointer to the dev_flow. 11229 * @param[out] error 11230 * pointer to error structure. 11231 * 11232 * @return 11233 * 0 on success otherwise -errno and errno is set. 11234 */ 11235 static int 11236 flow_dv_sample_resource_register(struct rte_eth_dev *dev, 11237 struct mlx5_flow_dv_sample_resource *ref, 11238 struct mlx5_flow *dev_flow, 11239 struct rte_flow_error *error) 11240 { 11241 struct mlx5_flow_dv_sample_resource *resource; 11242 struct mlx5_list_entry *entry; 11243 struct mlx5_priv *priv = dev->data->dev_private; 11244 struct mlx5_flow_cb_ctx ctx = { 11245 .dev = dev, 11246 .error = error, 11247 .data = ref, 11248 }; 11249 11250 entry = mlx5_list_register(priv->sh->sample_action_list, &ctx); 11251 if (!entry) 11252 return -rte_errno; 11253 resource = container_of(entry, typeof(*resource), entry); 11254 dev_flow->handle->dvh.rix_sample = resource->idx; 11255 dev_flow->dv.sample_res = resource; 11256 return 0; 11257 } 11258 11259 int 11260 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused, 11261 struct mlx5_list_entry *entry, void *cb_ctx) 11262 { 11263 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11264 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11265 struct rte_eth_dev *dev = ctx->dev; 11266 struct mlx5_flow_dv_dest_array_resource *resource = 11267 container_of(entry, typeof(*resource), entry); 11268 uint32_t idx = 0; 11269 11270 if (ctx_resource->num_of_dest == resource->num_of_dest && 11271 ctx_resource->ft_type == resource->ft_type && 11272 !memcmp((void *)resource->sample_act, 11273 (void *)ctx_resource->sample_act, 11274 (ctx_resource->num_of_dest * 11275 sizeof(struct mlx5_flow_sub_actions_list)))) { 11276 /* 11277 * Existing sample action should release the prepared 11278 * sub-actions reference counter. 11279 */ 11280 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11281 flow_dv_sample_sub_actions_release(dev, 11282 &ctx_resource->sample_idx[idx]); 11283 return 0; 11284 } 11285 return 1; 11286 } 11287 11288 struct mlx5_list_entry * 11289 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11290 { 11291 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11292 struct rte_eth_dev *dev = ctx->dev; 11293 struct mlx5_flow_dv_dest_array_resource *resource; 11294 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11295 struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 }; 11296 struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM]; 11297 struct mlx5_priv *priv = dev->data->dev_private; 11298 struct mlx5_dev_ctx_shared *sh = priv->sh; 11299 struct mlx5_flow_sub_actions_list *sample_act; 11300 struct mlx5dv_dr_domain *domain; 11301 uint32_t idx = 0, res_idx = 0; 11302 struct rte_flow_error *error = ctx->error; 11303 uint64_t action_flags; 11304 int ret; 11305 11306 /* Register new destination array resource. */ 11307 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11308 &res_idx); 11309 if (!resource) { 11310 rte_flow_error_set(error, ENOMEM, 11311 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11312 NULL, 11313 "cannot allocate resource memory"); 11314 return NULL; 11315 } 11316 *resource = *ctx_resource; 11317 if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11318 domain = sh->fdb_domain; 11319 else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 11320 domain = sh->rx_domain; 11321 else 11322 domain = sh->tx_domain; 11323 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11324 dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *) 11325 mlx5_malloc(MLX5_MEM_ZERO, 11326 sizeof(struct mlx5dv_dr_action_dest_attr), 11327 0, SOCKET_ID_ANY); 11328 if (!dest_attr[idx]) { 11329 rte_flow_error_set(error, ENOMEM, 11330 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11331 NULL, 11332 "cannot allocate resource memory"); 11333 goto error; 11334 } 11335 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST; 11336 sample_act = &ctx_resource->sample_act[idx]; 11337 action_flags = sample_act->action_flags; 11338 switch (action_flags) { 11339 case MLX5_FLOW_ACTION_QUEUE: 11340 dest_attr[idx]->dest = sample_act->dr_queue_action; 11341 break; 11342 case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP): 11343 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT; 11344 dest_attr[idx]->dest_reformat = &dest_reformat[idx]; 11345 dest_attr[idx]->dest_reformat->reformat = 11346 sample_act->dr_encap_action; 11347 dest_attr[idx]->dest_reformat->dest = 11348 sample_act->dr_port_id_action; 11349 break; 11350 case MLX5_FLOW_ACTION_PORT_ID: 11351 dest_attr[idx]->dest = sample_act->dr_port_id_action; 11352 break; 11353 case MLX5_FLOW_ACTION_JUMP: 11354 dest_attr[idx]->dest = sample_act->dr_jump_action; 11355 break; 11356 default: 11357 rte_flow_error_set(error, EINVAL, 11358 RTE_FLOW_ERROR_TYPE_ACTION, 11359 NULL, 11360 "unsupported actions type"); 11361 goto error; 11362 } 11363 } 11364 /* create a dest array actioin */ 11365 ret = mlx5_os_flow_dr_create_flow_action_dest_array 11366 (domain, 11367 resource->num_of_dest, 11368 dest_attr, 11369 &resource->action); 11370 if (ret) { 11371 rte_flow_error_set(error, ENOMEM, 11372 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11373 NULL, 11374 "cannot create destination array action"); 11375 goto error; 11376 } 11377 resource->idx = res_idx; 11378 resource->dev = dev; 11379 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11380 mlx5_free(dest_attr[idx]); 11381 return &resource->entry; 11382 error: 11383 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11384 flow_dv_sample_sub_actions_release(dev, 11385 &resource->sample_idx[idx]); 11386 if (dest_attr[idx]) 11387 mlx5_free(dest_attr[idx]); 11388 } 11389 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx); 11390 return NULL; 11391 } 11392 11393 struct mlx5_list_entry * 11394 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused, 11395 struct mlx5_list_entry *entry __rte_unused, 11396 void *cb_ctx) 11397 { 11398 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11399 struct rte_eth_dev *dev = ctx->dev; 11400 struct mlx5_flow_dv_dest_array_resource *resource; 11401 struct mlx5_priv *priv = dev->data->dev_private; 11402 struct mlx5_dev_ctx_shared *sh = priv->sh; 11403 uint32_t res_idx = 0; 11404 struct rte_flow_error *error = ctx->error; 11405 11406 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11407 &res_idx); 11408 if (!resource) { 11409 rte_flow_error_set(error, ENOMEM, 11410 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11411 NULL, 11412 "cannot allocate dest-array memory"); 11413 return NULL; 11414 } 11415 memcpy(resource, entry, sizeof(*resource)); 11416 resource->idx = res_idx; 11417 resource->dev = dev; 11418 return &resource->entry; 11419 } 11420 11421 void 11422 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused, 11423 struct mlx5_list_entry *entry) 11424 { 11425 struct mlx5_flow_dv_dest_array_resource *resource = 11426 container_of(entry, typeof(*resource), entry); 11427 struct rte_eth_dev *dev = resource->dev; 11428 struct mlx5_priv *priv = dev->data->dev_private; 11429 11430 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 11431 } 11432 11433 /** 11434 * Find existing destination array resource or create and register a new one. 11435 * 11436 * @param[in, out] dev 11437 * Pointer to rte_eth_dev structure. 11438 * @param[in] ref 11439 * Pointer to destination array resource reference. 11440 * @parm[in, out] dev_flow 11441 * Pointer to the dev_flow. 11442 * @param[out] error 11443 * pointer to error structure. 11444 * 11445 * @return 11446 * 0 on success otherwise -errno and errno is set. 11447 */ 11448 static int 11449 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev, 11450 struct mlx5_flow_dv_dest_array_resource *ref, 11451 struct mlx5_flow *dev_flow, 11452 struct rte_flow_error *error) 11453 { 11454 struct mlx5_flow_dv_dest_array_resource *resource; 11455 struct mlx5_priv *priv = dev->data->dev_private; 11456 struct mlx5_list_entry *entry; 11457 struct mlx5_flow_cb_ctx ctx = { 11458 .dev = dev, 11459 .error = error, 11460 .data = ref, 11461 }; 11462 11463 entry = mlx5_list_register(priv->sh->dest_array_list, &ctx); 11464 if (!entry) 11465 return -rte_errno; 11466 resource = container_of(entry, typeof(*resource), entry); 11467 dev_flow->handle->dvh.rix_dest_array = resource->idx; 11468 dev_flow->dv.dest_array_res = resource; 11469 return 0; 11470 } 11471 11472 /** 11473 * Convert Sample action to DV specification. 11474 * 11475 * @param[in] dev 11476 * Pointer to rte_eth_dev structure. 11477 * @param[in] action 11478 * Pointer to sample action structure. 11479 * @param[in, out] dev_flow 11480 * Pointer to the mlx5_flow. 11481 * @param[in] attr 11482 * Pointer to the flow attributes. 11483 * @param[in, out] num_of_dest 11484 * Pointer to the num of destination. 11485 * @param[in, out] sample_actions 11486 * Pointer to sample actions list. 11487 * @param[in, out] res 11488 * Pointer to sample resource. 11489 * @param[out] error 11490 * Pointer to the error structure. 11491 * 11492 * @return 11493 * 0 on success, a negative errno value otherwise and rte_errno is set. 11494 */ 11495 static int 11496 flow_dv_translate_action_sample(struct rte_eth_dev *dev, 11497 const struct rte_flow_action_sample *action, 11498 struct mlx5_flow *dev_flow, 11499 const struct rte_flow_attr *attr, 11500 uint32_t *num_of_dest, 11501 void **sample_actions, 11502 struct mlx5_flow_dv_sample_resource *res, 11503 struct rte_flow_error *error) 11504 { 11505 struct mlx5_priv *priv = dev->data->dev_private; 11506 const struct rte_flow_action *sub_actions; 11507 struct mlx5_flow_sub_actions_list *sample_act; 11508 struct mlx5_flow_sub_actions_idx *sample_idx; 11509 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11510 struct rte_flow *flow = dev_flow->flow; 11511 struct mlx5_flow_rss_desc *rss_desc; 11512 uint64_t action_flags = 0; 11513 11514 MLX5_ASSERT(wks); 11515 rss_desc = &wks->rss_desc; 11516 sample_act = &res->sample_act; 11517 sample_idx = &res->sample_idx; 11518 res->ratio = action->ratio; 11519 sub_actions = action->actions; 11520 for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) { 11521 int type = sub_actions->type; 11522 uint32_t pre_rix = 0; 11523 void *pre_r; 11524 switch (type) { 11525 case RTE_FLOW_ACTION_TYPE_QUEUE: 11526 { 11527 const struct rte_flow_action_queue *queue; 11528 struct mlx5_hrxq *hrxq; 11529 uint32_t hrxq_idx; 11530 11531 queue = sub_actions->conf; 11532 rss_desc->queue_num = 1; 11533 rss_desc->queue[0] = queue->index; 11534 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11535 rss_desc, &hrxq_idx); 11536 if (!hrxq) 11537 return rte_flow_error_set 11538 (error, rte_errno, 11539 RTE_FLOW_ERROR_TYPE_ACTION, 11540 NULL, 11541 "cannot create fate queue"); 11542 sample_act->dr_queue_action = hrxq->action; 11543 sample_idx->rix_hrxq = hrxq_idx; 11544 sample_actions[sample_act->actions_num++] = 11545 hrxq->action; 11546 (*num_of_dest)++; 11547 action_flags |= MLX5_FLOW_ACTION_QUEUE; 11548 if (action_flags & MLX5_FLOW_ACTION_MARK) 11549 dev_flow->handle->rix_hrxq = hrxq_idx; 11550 dev_flow->handle->fate_action = 11551 MLX5_FLOW_FATE_QUEUE; 11552 break; 11553 } 11554 case RTE_FLOW_ACTION_TYPE_RSS: 11555 { 11556 struct mlx5_hrxq *hrxq; 11557 uint32_t hrxq_idx; 11558 const struct rte_flow_action_rss *rss; 11559 const uint8_t *rss_key; 11560 11561 rss = sub_actions->conf; 11562 memcpy(rss_desc->queue, rss->queue, 11563 rss->queue_num * sizeof(uint16_t)); 11564 rss_desc->queue_num = rss->queue_num; 11565 /* NULL RSS key indicates default RSS key. */ 11566 rss_key = !rss->key ? rss_hash_default_key : rss->key; 11567 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 11568 /* 11569 * rss->level and rss.types should be set in advance 11570 * when expanding items for RSS. 11571 */ 11572 flow_dv_hashfields_set(dev_flow, rss_desc); 11573 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11574 rss_desc, &hrxq_idx); 11575 if (!hrxq) 11576 return rte_flow_error_set 11577 (error, rte_errno, 11578 RTE_FLOW_ERROR_TYPE_ACTION, 11579 NULL, 11580 "cannot create fate queue"); 11581 sample_act->dr_queue_action = hrxq->action; 11582 sample_idx->rix_hrxq = hrxq_idx; 11583 sample_actions[sample_act->actions_num++] = 11584 hrxq->action; 11585 (*num_of_dest)++; 11586 action_flags |= MLX5_FLOW_ACTION_RSS; 11587 if (action_flags & MLX5_FLOW_ACTION_MARK) 11588 dev_flow->handle->rix_hrxq = hrxq_idx; 11589 dev_flow->handle->fate_action = 11590 MLX5_FLOW_FATE_QUEUE; 11591 break; 11592 } 11593 case RTE_FLOW_ACTION_TYPE_MARK: 11594 { 11595 uint32_t tag_be = mlx5_flow_mark_set 11596 (((const struct rte_flow_action_mark *) 11597 (sub_actions->conf))->id); 11598 11599 dev_flow->handle->mark = 1; 11600 pre_rix = dev_flow->handle->dvh.rix_tag; 11601 /* Save the mark resource before sample */ 11602 pre_r = dev_flow->dv.tag_resource; 11603 if (flow_dv_tag_resource_register(dev, tag_be, 11604 dev_flow, error)) 11605 return -rte_errno; 11606 MLX5_ASSERT(dev_flow->dv.tag_resource); 11607 sample_act->dr_tag_action = 11608 dev_flow->dv.tag_resource->action; 11609 sample_idx->rix_tag = 11610 dev_flow->handle->dvh.rix_tag; 11611 sample_actions[sample_act->actions_num++] = 11612 sample_act->dr_tag_action; 11613 /* Recover the mark resource after sample */ 11614 dev_flow->dv.tag_resource = pre_r; 11615 dev_flow->handle->dvh.rix_tag = pre_rix; 11616 action_flags |= MLX5_FLOW_ACTION_MARK; 11617 break; 11618 } 11619 case RTE_FLOW_ACTION_TYPE_COUNT: 11620 { 11621 if (!flow->counter) { 11622 flow->counter = 11623 flow_dv_translate_create_counter(dev, 11624 dev_flow, sub_actions->conf, 11625 0); 11626 if (!flow->counter) 11627 return rte_flow_error_set 11628 (error, rte_errno, 11629 RTE_FLOW_ERROR_TYPE_ACTION, 11630 NULL, 11631 "cannot create counter" 11632 " object."); 11633 } 11634 sample_act->dr_cnt_action = 11635 (flow_dv_counter_get_by_idx(dev, 11636 flow->counter, NULL))->action; 11637 sample_actions[sample_act->actions_num++] = 11638 sample_act->dr_cnt_action; 11639 action_flags |= MLX5_FLOW_ACTION_COUNT; 11640 break; 11641 } 11642 case RTE_FLOW_ACTION_TYPE_PORT_ID: 11643 { 11644 struct mlx5_flow_dv_port_id_action_resource 11645 port_id_resource; 11646 uint32_t port_id = 0; 11647 11648 memset(&port_id_resource, 0, sizeof(port_id_resource)); 11649 /* Save the port id resource before sample */ 11650 pre_rix = dev_flow->handle->rix_port_id_action; 11651 pre_r = dev_flow->dv.port_id_action; 11652 if (flow_dv_translate_action_port_id(dev, sub_actions, 11653 &port_id, error)) 11654 return -rte_errno; 11655 port_id_resource.port_id = port_id; 11656 if (flow_dv_port_id_action_resource_register 11657 (dev, &port_id_resource, dev_flow, error)) 11658 return -rte_errno; 11659 sample_act->dr_port_id_action = 11660 dev_flow->dv.port_id_action->action; 11661 sample_idx->rix_port_id_action = 11662 dev_flow->handle->rix_port_id_action; 11663 sample_actions[sample_act->actions_num++] = 11664 sample_act->dr_port_id_action; 11665 /* Recover the port id resource after sample */ 11666 dev_flow->dv.port_id_action = pre_r; 11667 dev_flow->handle->rix_port_id_action = pre_rix; 11668 (*num_of_dest)++; 11669 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 11670 break; 11671 } 11672 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 11673 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 11674 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 11675 /* Save the encap resource before sample */ 11676 pre_rix = dev_flow->handle->dvh.rix_encap_decap; 11677 pre_r = dev_flow->dv.encap_decap; 11678 if (flow_dv_create_action_l2_encap(dev, sub_actions, 11679 dev_flow, 11680 attr->transfer, 11681 error)) 11682 return -rte_errno; 11683 sample_act->dr_encap_action = 11684 dev_flow->dv.encap_decap->action; 11685 sample_idx->rix_encap_decap = 11686 dev_flow->handle->dvh.rix_encap_decap; 11687 sample_actions[sample_act->actions_num++] = 11688 sample_act->dr_encap_action; 11689 /* Recover the encap resource after sample */ 11690 dev_flow->dv.encap_decap = pre_r; 11691 dev_flow->handle->dvh.rix_encap_decap = pre_rix; 11692 action_flags |= MLX5_FLOW_ACTION_ENCAP; 11693 break; 11694 default: 11695 return rte_flow_error_set(error, EINVAL, 11696 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11697 NULL, 11698 "Not support for sampler action"); 11699 } 11700 } 11701 sample_act->action_flags = action_flags; 11702 res->ft_id = dev_flow->dv.group; 11703 if (attr->transfer) { 11704 union { 11705 uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)]; 11706 uint64_t set_action; 11707 } action_ctx = { .set_action = 0 }; 11708 11709 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 11710 MLX5_SET(set_action_in, action_ctx.action_in, action_type, 11711 MLX5_MODIFICATION_TYPE_SET); 11712 MLX5_SET(set_action_in, action_ctx.action_in, field, 11713 MLX5_MODI_META_REG_C_0); 11714 MLX5_SET(set_action_in, action_ctx.action_in, data, 11715 priv->vport_meta_tag); 11716 res->set_action = action_ctx.set_action; 11717 } else if (attr->ingress) { 11718 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 11719 } else { 11720 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 11721 } 11722 return 0; 11723 } 11724 11725 /** 11726 * Convert Sample action to DV specification. 11727 * 11728 * @param[in] dev 11729 * Pointer to rte_eth_dev structure. 11730 * @param[in, out] dev_flow 11731 * Pointer to the mlx5_flow. 11732 * @param[in] num_of_dest 11733 * The num of destination. 11734 * @param[in, out] res 11735 * Pointer to sample resource. 11736 * @param[in, out] mdest_res 11737 * Pointer to destination array resource. 11738 * @param[in] sample_actions 11739 * Pointer to sample path actions list. 11740 * @param[in] action_flags 11741 * Holds the actions detected until now. 11742 * @param[out] error 11743 * Pointer to the error structure. 11744 * 11745 * @return 11746 * 0 on success, a negative errno value otherwise and rte_errno is set. 11747 */ 11748 static int 11749 flow_dv_create_action_sample(struct rte_eth_dev *dev, 11750 struct mlx5_flow *dev_flow, 11751 uint32_t num_of_dest, 11752 struct mlx5_flow_dv_sample_resource *res, 11753 struct mlx5_flow_dv_dest_array_resource *mdest_res, 11754 void **sample_actions, 11755 uint64_t action_flags, 11756 struct rte_flow_error *error) 11757 { 11758 /* update normal path action resource into last index of array */ 11759 uint32_t dest_index = MLX5_MAX_DEST_NUM - 1; 11760 struct mlx5_flow_sub_actions_list *sample_act = 11761 &mdest_res->sample_act[dest_index]; 11762 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11763 struct mlx5_flow_rss_desc *rss_desc; 11764 uint32_t normal_idx = 0; 11765 struct mlx5_hrxq *hrxq; 11766 uint32_t hrxq_idx; 11767 11768 MLX5_ASSERT(wks); 11769 rss_desc = &wks->rss_desc; 11770 if (num_of_dest > 1) { 11771 if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) { 11772 /* Handle QP action for mirroring */ 11773 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11774 rss_desc, &hrxq_idx); 11775 if (!hrxq) 11776 return rte_flow_error_set 11777 (error, rte_errno, 11778 RTE_FLOW_ERROR_TYPE_ACTION, 11779 NULL, 11780 "cannot create rx queue"); 11781 normal_idx++; 11782 mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx; 11783 sample_act->dr_queue_action = hrxq->action; 11784 if (action_flags & MLX5_FLOW_ACTION_MARK) 11785 dev_flow->handle->rix_hrxq = hrxq_idx; 11786 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 11787 } 11788 if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) { 11789 normal_idx++; 11790 mdest_res->sample_idx[dest_index].rix_encap_decap = 11791 dev_flow->handle->dvh.rix_encap_decap; 11792 sample_act->dr_encap_action = 11793 dev_flow->dv.encap_decap->action; 11794 dev_flow->handle->dvh.rix_encap_decap = 0; 11795 } 11796 if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) { 11797 normal_idx++; 11798 mdest_res->sample_idx[dest_index].rix_port_id_action = 11799 dev_flow->handle->rix_port_id_action; 11800 sample_act->dr_port_id_action = 11801 dev_flow->dv.port_id_action->action; 11802 dev_flow->handle->rix_port_id_action = 0; 11803 } 11804 if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) { 11805 normal_idx++; 11806 mdest_res->sample_idx[dest_index].rix_jump = 11807 dev_flow->handle->rix_jump; 11808 sample_act->dr_jump_action = 11809 dev_flow->dv.jump->action; 11810 dev_flow->handle->rix_jump = 0; 11811 } 11812 sample_act->actions_num = normal_idx; 11813 /* update sample action resource into first index of array */ 11814 mdest_res->ft_type = res->ft_type; 11815 memcpy(&mdest_res->sample_idx[0], &res->sample_idx, 11816 sizeof(struct mlx5_flow_sub_actions_idx)); 11817 memcpy(&mdest_res->sample_act[0], &res->sample_act, 11818 sizeof(struct mlx5_flow_sub_actions_list)); 11819 mdest_res->num_of_dest = num_of_dest; 11820 if (flow_dv_dest_array_resource_register(dev, mdest_res, 11821 dev_flow, error)) 11822 return rte_flow_error_set(error, EINVAL, 11823 RTE_FLOW_ERROR_TYPE_ACTION, 11824 NULL, "can't create sample " 11825 "action"); 11826 } else { 11827 res->sub_actions = sample_actions; 11828 if (flow_dv_sample_resource_register(dev, res, dev_flow, error)) 11829 return rte_flow_error_set(error, EINVAL, 11830 RTE_FLOW_ERROR_TYPE_ACTION, 11831 NULL, 11832 "can't create sample action"); 11833 } 11834 return 0; 11835 } 11836 11837 /** 11838 * Remove an ASO age action from age actions list. 11839 * 11840 * @param[in] dev 11841 * Pointer to the Ethernet device structure. 11842 * @param[in] age 11843 * Pointer to the aso age action handler. 11844 */ 11845 static void 11846 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev, 11847 struct mlx5_aso_age_action *age) 11848 { 11849 struct mlx5_age_info *age_info; 11850 struct mlx5_age_param *age_param = &age->age_params; 11851 struct mlx5_priv *priv = dev->data->dev_private; 11852 uint16_t expected = AGE_CANDIDATE; 11853 11854 age_info = GET_PORT_AGE_INFO(priv); 11855 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 11856 AGE_FREE, false, __ATOMIC_RELAXED, 11857 __ATOMIC_RELAXED)) { 11858 /** 11859 * We need the lock even it is age timeout, 11860 * since age action may still in process. 11861 */ 11862 rte_spinlock_lock(&age_info->aged_sl); 11863 LIST_REMOVE(age, next); 11864 rte_spinlock_unlock(&age_info->aged_sl); 11865 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 11866 } 11867 } 11868 11869 /** 11870 * Release an ASO age action. 11871 * 11872 * @param[in] dev 11873 * Pointer to the Ethernet device structure. 11874 * @param[in] age_idx 11875 * Index of ASO age action to release. 11876 * @param[in] flow 11877 * True if the release operation is during flow destroy operation. 11878 * False if the release operation is during action destroy operation. 11879 * 11880 * @return 11881 * 0 when age action was removed, otherwise the number of references. 11882 */ 11883 static int 11884 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx) 11885 { 11886 struct mlx5_priv *priv = dev->data->dev_private; 11887 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11888 struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx); 11889 uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED); 11890 11891 if (!ret) { 11892 flow_dv_aso_age_remove_from_age(dev, age); 11893 rte_spinlock_lock(&mng->free_sl); 11894 LIST_INSERT_HEAD(&mng->free, age, next); 11895 rte_spinlock_unlock(&mng->free_sl); 11896 } 11897 return ret; 11898 } 11899 11900 /** 11901 * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools. 11902 * 11903 * @param[in] dev 11904 * Pointer to the Ethernet device structure. 11905 * 11906 * @return 11907 * 0 on success, otherwise negative errno value and rte_errno is set. 11908 */ 11909 static int 11910 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev) 11911 { 11912 struct mlx5_priv *priv = dev->data->dev_private; 11913 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11914 void *old_pools = mng->pools; 11915 uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE; 11916 uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize; 11917 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 11918 11919 if (!pools) { 11920 rte_errno = ENOMEM; 11921 return -ENOMEM; 11922 } 11923 if (old_pools) { 11924 memcpy(pools, old_pools, 11925 mng->n * sizeof(struct mlx5_flow_counter_pool *)); 11926 mlx5_free(old_pools); 11927 } else { 11928 /* First ASO flow hit allocation - starting ASO data-path. */ 11929 int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh); 11930 11931 if (ret) { 11932 mlx5_free(pools); 11933 return ret; 11934 } 11935 } 11936 mng->n = resize; 11937 mng->pools = pools; 11938 return 0; 11939 } 11940 11941 /** 11942 * Create and initialize a new ASO aging pool. 11943 * 11944 * @param[in] dev 11945 * Pointer to the Ethernet device structure. 11946 * @param[out] age_free 11947 * Where to put the pointer of a new age action. 11948 * 11949 * @return 11950 * The age actions pool pointer and @p age_free is set on success, 11951 * NULL otherwise and rte_errno is set. 11952 */ 11953 static struct mlx5_aso_age_pool * 11954 flow_dv_age_pool_create(struct rte_eth_dev *dev, 11955 struct mlx5_aso_age_action **age_free) 11956 { 11957 struct mlx5_priv *priv = dev->data->dev_private; 11958 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11959 struct mlx5_aso_age_pool *pool = NULL; 11960 struct mlx5_devx_obj *obj = NULL; 11961 uint32_t i; 11962 11963 obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->ctx, 11964 priv->sh->pdn); 11965 if (!obj) { 11966 rte_errno = ENODATA; 11967 DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX."); 11968 return NULL; 11969 } 11970 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 11971 if (!pool) { 11972 claim_zero(mlx5_devx_cmd_destroy(obj)); 11973 rte_errno = ENOMEM; 11974 return NULL; 11975 } 11976 pool->flow_hit_aso_obj = obj; 11977 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 11978 rte_spinlock_lock(&mng->resize_sl); 11979 pool->index = mng->next; 11980 /* Resize pools array if there is no room for the new pool in it. */ 11981 if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) { 11982 claim_zero(mlx5_devx_cmd_destroy(obj)); 11983 mlx5_free(pool); 11984 rte_spinlock_unlock(&mng->resize_sl); 11985 return NULL; 11986 } 11987 mng->pools[pool->index] = pool; 11988 mng->next++; 11989 rte_spinlock_unlock(&mng->resize_sl); 11990 /* Assign the first action in the new pool, the rest go to free list. */ 11991 *age_free = &pool->actions[0]; 11992 for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) { 11993 pool->actions[i].offset = i; 11994 LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next); 11995 } 11996 return pool; 11997 } 11998 11999 /** 12000 * Allocate a ASO aging bit. 12001 * 12002 * @param[in] dev 12003 * Pointer to the Ethernet device structure. 12004 * @param[out] error 12005 * Pointer to the error structure. 12006 * 12007 * @return 12008 * Index to ASO age action on success, 0 otherwise and rte_errno is set. 12009 */ 12010 static uint32_t 12011 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12012 { 12013 struct mlx5_priv *priv = dev->data->dev_private; 12014 const struct mlx5_aso_age_pool *pool; 12015 struct mlx5_aso_age_action *age_free = NULL; 12016 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12017 12018 MLX5_ASSERT(mng); 12019 /* Try to get the next free age action bit. */ 12020 rte_spinlock_lock(&mng->free_sl); 12021 age_free = LIST_FIRST(&mng->free); 12022 if (age_free) { 12023 LIST_REMOVE(age_free, next); 12024 } else if (!flow_dv_age_pool_create(dev, &age_free)) { 12025 rte_spinlock_unlock(&mng->free_sl); 12026 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12027 NULL, "failed to create ASO age pool"); 12028 return 0; /* 0 is an error. */ 12029 } 12030 rte_spinlock_unlock(&mng->free_sl); 12031 pool = container_of 12032 ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL]) 12033 (age_free - age_free->offset), const struct mlx5_aso_age_pool, 12034 actions); 12035 if (!age_free->dr_action) { 12036 int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0, 12037 error); 12038 12039 if (reg_c < 0) { 12040 rte_flow_error_set(error, rte_errno, 12041 RTE_FLOW_ERROR_TYPE_ACTION, 12042 NULL, "failed to get reg_c " 12043 "for ASO flow hit"); 12044 return 0; /* 0 is an error. */ 12045 } 12046 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 12047 age_free->dr_action = mlx5_glue->dv_create_flow_action_aso 12048 (priv->sh->rx_domain, 12049 pool->flow_hit_aso_obj->obj, age_free->offset, 12050 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET, 12051 (reg_c - REG_C_0)); 12052 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 12053 if (!age_free->dr_action) { 12054 rte_errno = errno; 12055 rte_spinlock_lock(&mng->free_sl); 12056 LIST_INSERT_HEAD(&mng->free, age_free, next); 12057 rte_spinlock_unlock(&mng->free_sl); 12058 rte_flow_error_set(error, rte_errno, 12059 RTE_FLOW_ERROR_TYPE_ACTION, 12060 NULL, "failed to create ASO " 12061 "flow hit action"); 12062 return 0; /* 0 is an error. */ 12063 } 12064 } 12065 __atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED); 12066 return pool->index | ((age_free->offset + 1) << 16); 12067 } 12068 12069 /** 12070 * Initialize flow ASO age parameters. 12071 * 12072 * @param[in] dev 12073 * Pointer to rte_eth_dev structure. 12074 * @param[in] age_idx 12075 * Index of ASO age action. 12076 * @param[in] context 12077 * Pointer to flow counter age context. 12078 * @param[in] timeout 12079 * Aging timeout in seconds. 12080 * 12081 */ 12082 static void 12083 flow_dv_aso_age_params_init(struct rte_eth_dev *dev, 12084 uint32_t age_idx, 12085 void *context, 12086 uint32_t timeout) 12087 { 12088 struct mlx5_aso_age_action *aso_age; 12089 12090 aso_age = flow_aso_age_get_by_idx(dev, age_idx); 12091 MLX5_ASSERT(aso_age); 12092 aso_age->age_params.context = context; 12093 aso_age->age_params.timeout = timeout; 12094 aso_age->age_params.port_id = dev->data->port_id; 12095 __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0, 12096 __ATOMIC_RELAXED); 12097 __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE, 12098 __ATOMIC_RELAXED); 12099 } 12100 12101 static void 12102 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask, 12103 const struct rte_flow_item_integrity *value, 12104 void *headers_m, void *headers_v) 12105 { 12106 if (mask->l4_ok) { 12107 /* application l4_ok filter aggregates all hardware l4 filters 12108 * therefore hw l4_checksum_ok must be implicitly added here. 12109 */ 12110 struct rte_flow_item_integrity local_item; 12111 12112 local_item.l4_csum_ok = 1; 12113 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 12114 local_item.l4_csum_ok); 12115 if (value->l4_ok) { 12116 /* application l4_ok = 1 matches sets both hw flags 12117 * l4_ok and l4_checksum_ok flags to 1. 12118 */ 12119 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12120 l4_checksum_ok, local_item.l4_csum_ok); 12121 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok, 12122 mask->l4_ok); 12123 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok, 12124 value->l4_ok); 12125 } else { 12126 /* application l4_ok = 0 matches on hw flag 12127 * l4_checksum_ok = 0 only. 12128 */ 12129 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12130 l4_checksum_ok, 0); 12131 } 12132 } else if (mask->l4_csum_ok) { 12133 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 12134 mask->l4_csum_ok); 12135 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, 12136 value->l4_csum_ok); 12137 } 12138 } 12139 12140 static void 12141 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask, 12142 const struct rte_flow_item_integrity *value, 12143 void *headers_m, void *headers_v, 12144 bool is_ipv4) 12145 { 12146 if (mask->l3_ok) { 12147 /* application l3_ok filter aggregates all hardware l3 filters 12148 * therefore hw ipv4_checksum_ok must be implicitly added here. 12149 */ 12150 struct rte_flow_item_integrity local_item; 12151 12152 local_item.ipv4_csum_ok = !!is_ipv4; 12153 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 12154 local_item.ipv4_csum_ok); 12155 if (value->l3_ok) { 12156 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12157 ipv4_checksum_ok, local_item.ipv4_csum_ok); 12158 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok, 12159 mask->l3_ok); 12160 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok, 12161 value->l3_ok); 12162 } else { 12163 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12164 ipv4_checksum_ok, 0); 12165 } 12166 } else if (mask->ipv4_csum_ok) { 12167 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 12168 mask->ipv4_csum_ok); 12169 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok, 12170 value->ipv4_csum_ok); 12171 } 12172 } 12173 12174 static void 12175 flow_dv_translate_item_integrity(void *matcher, void *key, 12176 const struct rte_flow_item *head_item, 12177 const struct rte_flow_item *integrity_item) 12178 { 12179 const struct rte_flow_item_integrity *mask = integrity_item->mask; 12180 const struct rte_flow_item_integrity *value = integrity_item->spec; 12181 const struct rte_flow_item *tunnel_item, *end_item, *item; 12182 void *headers_m; 12183 void *headers_v; 12184 uint32_t l3_protocol; 12185 12186 if (!value) 12187 return; 12188 if (!mask) 12189 mask = &rte_flow_item_integrity_mask; 12190 if (value->level > 1) { 12191 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12192 inner_headers); 12193 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 12194 } else { 12195 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12196 outer_headers); 12197 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 12198 } 12199 tunnel_item = mlx5_flow_find_tunnel_item(head_item); 12200 if (value->level > 1) { 12201 /* tunnel item was verified during the item validation */ 12202 item = tunnel_item; 12203 end_item = mlx5_find_end_item(tunnel_item); 12204 } else { 12205 item = head_item; 12206 end_item = tunnel_item ? tunnel_item : 12207 mlx5_find_end_item(integrity_item); 12208 } 12209 l3_protocol = mask->l3_ok ? 12210 mlx5_flow_locate_proto_l3(&item, end_item) : 0; 12211 flow_dv_translate_integrity_l3(mask, value, headers_m, headers_v, 12212 l3_protocol == RTE_ETHER_TYPE_IPV4); 12213 flow_dv_translate_integrity_l4(mask, value, headers_m, headers_v); 12214 } 12215 12216 /** 12217 * Prepares DV flow counter with aging configuration. 12218 * Gets it by index when exists, creates a new one when doesn't. 12219 * 12220 * @param[in] dev 12221 * Pointer to rte_eth_dev structure. 12222 * @param[in] dev_flow 12223 * Pointer to the mlx5_flow. 12224 * @param[in, out] flow 12225 * Pointer to the sub flow. 12226 * @param[in] count 12227 * Pointer to the counter action configuration. 12228 * @param[in] age 12229 * Pointer to the aging action configuration. 12230 * @param[out] error 12231 * Pointer to the error structure. 12232 * 12233 * @return 12234 * Pointer to the counter, NULL otherwise. 12235 */ 12236 static struct mlx5_flow_counter * 12237 flow_dv_prepare_counter(struct rte_eth_dev *dev, 12238 struct mlx5_flow *dev_flow, 12239 struct rte_flow *flow, 12240 const struct rte_flow_action_count *count, 12241 const struct rte_flow_action_age *age, 12242 struct rte_flow_error *error) 12243 { 12244 if (!flow->counter) { 12245 flow->counter = flow_dv_translate_create_counter(dev, dev_flow, 12246 count, age); 12247 if (!flow->counter) { 12248 rte_flow_error_set(error, rte_errno, 12249 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12250 "cannot create counter object."); 12251 return NULL; 12252 } 12253 } 12254 return flow_dv_counter_get_by_idx(dev, flow->counter, NULL); 12255 } 12256 12257 /* 12258 * Release an ASO CT action by its own device. 12259 * 12260 * @param[in] dev 12261 * Pointer to the Ethernet device structure. 12262 * @param[in] idx 12263 * Index of ASO CT action to release. 12264 * 12265 * @return 12266 * 0 when CT action was removed, otherwise the number of references. 12267 */ 12268 static inline int 12269 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx) 12270 { 12271 struct mlx5_priv *priv = dev->data->dev_private; 12272 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12273 uint32_t ret; 12274 struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12275 enum mlx5_aso_ct_state state = 12276 __atomic_load_n(&ct->state, __ATOMIC_RELAXED); 12277 12278 /* Cannot release when CT is in the ASO SQ. */ 12279 if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY) 12280 return -1; 12281 ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED); 12282 if (!ret) { 12283 if (ct->dr_action_orig) { 12284 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12285 claim_zero(mlx5_glue->destroy_flow_action 12286 (ct->dr_action_orig)); 12287 #endif 12288 ct->dr_action_orig = NULL; 12289 } 12290 if (ct->dr_action_rply) { 12291 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12292 claim_zero(mlx5_glue->destroy_flow_action 12293 (ct->dr_action_rply)); 12294 #endif 12295 ct->dr_action_rply = NULL; 12296 } 12297 /* Clear the state to free, no need in 1st allocation. */ 12298 MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE); 12299 rte_spinlock_lock(&mng->ct_sl); 12300 LIST_INSERT_HEAD(&mng->free_cts, ct, next); 12301 rte_spinlock_unlock(&mng->ct_sl); 12302 } 12303 return (int)ret; 12304 } 12305 12306 static inline int 12307 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx) 12308 { 12309 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx); 12310 uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx); 12311 struct rte_eth_dev *owndev = &rte_eth_devices[owner]; 12312 RTE_SET_USED(dev); 12313 12314 MLX5_ASSERT(owner < RTE_MAX_ETHPORTS); 12315 if (dev->data->dev_started != 1) 12316 return -1; 12317 return flow_dv_aso_ct_dev_release(owndev, idx); 12318 } 12319 12320 /* 12321 * Resize the ASO CT pools array by 64 pools. 12322 * 12323 * @param[in] dev 12324 * Pointer to the Ethernet device structure. 12325 * 12326 * @return 12327 * 0 on success, otherwise negative errno value and rte_errno is set. 12328 */ 12329 static int 12330 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev) 12331 { 12332 struct mlx5_priv *priv = dev->data->dev_private; 12333 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12334 void *old_pools = mng->pools; 12335 /* Magic number now, need a macro. */ 12336 uint32_t resize = mng->n + 64; 12337 uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize; 12338 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12339 12340 if (!pools) { 12341 rte_errno = ENOMEM; 12342 return -rte_errno; 12343 } 12344 rte_rwlock_write_lock(&mng->resize_rwl); 12345 /* ASO SQ/QP was already initialized in the startup. */ 12346 if (old_pools) { 12347 /* Realloc could be an alternative choice. */ 12348 rte_memcpy(pools, old_pools, 12349 mng->n * sizeof(struct mlx5_aso_ct_pool *)); 12350 mlx5_free(old_pools); 12351 } 12352 mng->n = resize; 12353 mng->pools = pools; 12354 rte_rwlock_write_unlock(&mng->resize_rwl); 12355 return 0; 12356 } 12357 12358 /* 12359 * Create and initialize a new ASO CT pool. 12360 * 12361 * @param[in] dev 12362 * Pointer to the Ethernet device structure. 12363 * @param[out] ct_free 12364 * Where to put the pointer of a new CT action. 12365 * 12366 * @return 12367 * The CT actions pool pointer and @p ct_free is set on success, 12368 * NULL otherwise and rte_errno is set. 12369 */ 12370 static struct mlx5_aso_ct_pool * 12371 flow_dv_ct_pool_create(struct rte_eth_dev *dev, 12372 struct mlx5_aso_ct_action **ct_free) 12373 { 12374 struct mlx5_priv *priv = dev->data->dev_private; 12375 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12376 struct mlx5_aso_ct_pool *pool = NULL; 12377 struct mlx5_devx_obj *obj = NULL; 12378 uint32_t i; 12379 uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL); 12380 12381 obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->ctx, 12382 priv->sh->pdn, log_obj_size); 12383 if (!obj) { 12384 rte_errno = ENODATA; 12385 DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); 12386 return NULL; 12387 } 12388 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 12389 if (!pool) { 12390 rte_errno = ENOMEM; 12391 claim_zero(mlx5_devx_cmd_destroy(obj)); 12392 return NULL; 12393 } 12394 pool->devx_obj = obj; 12395 pool->index = mng->next; 12396 /* Resize pools array if there is no room for the new pool in it. */ 12397 if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) { 12398 claim_zero(mlx5_devx_cmd_destroy(obj)); 12399 mlx5_free(pool); 12400 return NULL; 12401 } 12402 mng->pools[pool->index] = pool; 12403 mng->next++; 12404 /* Assign the first action in the new pool, the rest go to free list. */ 12405 *ct_free = &pool->actions[0]; 12406 /* Lock outside, the list operation is safe here. */ 12407 for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) { 12408 /* refcnt is 0 when allocating the memory. */ 12409 pool->actions[i].offset = i; 12410 LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next); 12411 } 12412 return pool; 12413 } 12414 12415 /* 12416 * Allocate a ASO CT action from free list. 12417 * 12418 * @param[in] dev 12419 * Pointer to the Ethernet device structure. 12420 * @param[out] error 12421 * Pointer to the error structure. 12422 * 12423 * @return 12424 * Index to ASO CT action on success, 0 otherwise and rte_errno is set. 12425 */ 12426 static uint32_t 12427 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12428 { 12429 struct mlx5_priv *priv = dev->data->dev_private; 12430 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12431 struct mlx5_aso_ct_action *ct = NULL; 12432 struct mlx5_aso_ct_pool *pool; 12433 uint8_t reg_c; 12434 uint32_t ct_idx; 12435 12436 MLX5_ASSERT(mng); 12437 if (!priv->config.devx) { 12438 rte_errno = ENOTSUP; 12439 return 0; 12440 } 12441 /* Get a free CT action, if no, a new pool will be created. */ 12442 rte_spinlock_lock(&mng->ct_sl); 12443 ct = LIST_FIRST(&mng->free_cts); 12444 if (ct) { 12445 LIST_REMOVE(ct, next); 12446 } else if (!flow_dv_ct_pool_create(dev, &ct)) { 12447 rte_spinlock_unlock(&mng->ct_sl); 12448 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12449 NULL, "failed to create ASO CT pool"); 12450 return 0; 12451 } 12452 rte_spinlock_unlock(&mng->ct_sl); 12453 pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); 12454 ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset); 12455 /* 0: inactive, 1: created, 2+: used by flows. */ 12456 __atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED); 12457 reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error); 12458 if (!ct->dr_action_orig) { 12459 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12460 ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso 12461 (priv->sh->rx_domain, pool->devx_obj->obj, 12462 ct->offset, 12463 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR, 12464 reg_c - REG_C_0); 12465 #else 12466 RTE_SET_USED(reg_c); 12467 #endif 12468 if (!ct->dr_action_orig) { 12469 flow_dv_aso_ct_dev_release(dev, ct_idx); 12470 rte_flow_error_set(error, rte_errno, 12471 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12472 "failed to create ASO CT action"); 12473 return 0; 12474 } 12475 } 12476 if (!ct->dr_action_rply) { 12477 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12478 ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso 12479 (priv->sh->rx_domain, pool->devx_obj->obj, 12480 ct->offset, 12481 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER, 12482 reg_c - REG_C_0); 12483 #endif 12484 if (!ct->dr_action_rply) { 12485 flow_dv_aso_ct_dev_release(dev, ct_idx); 12486 rte_flow_error_set(error, rte_errno, 12487 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12488 "failed to create ASO CT action"); 12489 return 0; 12490 } 12491 } 12492 return ct_idx; 12493 } 12494 12495 /* 12496 * Create a conntrack object with context and actions by using ASO mechanism. 12497 * 12498 * @param[in] dev 12499 * Pointer to rte_eth_dev structure. 12500 * @param[in] pro 12501 * Pointer to conntrack information profile. 12502 * @param[out] error 12503 * Pointer to the error structure. 12504 * 12505 * @return 12506 * Index to conntrack object on success, 0 otherwise. 12507 */ 12508 static uint32_t 12509 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, 12510 const struct rte_flow_action_conntrack *pro, 12511 struct rte_flow_error *error) 12512 { 12513 struct mlx5_priv *priv = dev->data->dev_private; 12514 struct mlx5_dev_ctx_shared *sh = priv->sh; 12515 struct mlx5_aso_ct_action *ct; 12516 uint32_t idx; 12517 12518 if (!sh->ct_aso_en) 12519 return rte_flow_error_set(error, ENOTSUP, 12520 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12521 "Connection is not supported"); 12522 idx = flow_dv_aso_ct_alloc(dev, error); 12523 if (!idx) 12524 return rte_flow_error_set(error, rte_errno, 12525 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12526 "Failed to allocate CT object"); 12527 ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12528 if (mlx5_aso_ct_update_by_wqe(sh, ct, pro)) 12529 return rte_flow_error_set(error, EBUSY, 12530 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12531 "Failed to update CT"); 12532 ct->is_original = !!pro->is_original_dir; 12533 ct->peer = pro->peer_port; 12534 return idx; 12535 } 12536 12537 /** 12538 * Fill the flow with DV spec, lock free 12539 * (mutex should be acquired by caller). 12540 * 12541 * @param[in] dev 12542 * Pointer to rte_eth_dev structure. 12543 * @param[in, out] dev_flow 12544 * Pointer to the sub flow. 12545 * @param[in] attr 12546 * Pointer to the flow attributes. 12547 * @param[in] items 12548 * Pointer to the list of items. 12549 * @param[in] actions 12550 * Pointer to the list of actions. 12551 * @param[out] error 12552 * Pointer to the error structure. 12553 * 12554 * @return 12555 * 0 on success, a negative errno value otherwise and rte_errno is set. 12556 */ 12557 static int 12558 flow_dv_translate(struct rte_eth_dev *dev, 12559 struct mlx5_flow *dev_flow, 12560 const struct rte_flow_attr *attr, 12561 const struct rte_flow_item items[], 12562 const struct rte_flow_action actions[], 12563 struct rte_flow_error *error) 12564 { 12565 struct mlx5_priv *priv = dev->data->dev_private; 12566 struct mlx5_dev_config *dev_conf = &priv->config; 12567 struct rte_flow *flow = dev_flow->flow; 12568 struct mlx5_flow_handle *handle = dev_flow->handle; 12569 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 12570 struct mlx5_flow_rss_desc *rss_desc; 12571 uint64_t item_flags = 0; 12572 uint64_t last_item = 0; 12573 uint64_t action_flags = 0; 12574 struct mlx5_flow_dv_matcher matcher = { 12575 .mask = { 12576 .size = sizeof(matcher.mask.buf), 12577 }, 12578 }; 12579 int actions_n = 0; 12580 bool actions_end = false; 12581 union { 12582 struct mlx5_flow_dv_modify_hdr_resource res; 12583 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 12584 sizeof(struct mlx5_modification_cmd) * 12585 (MLX5_MAX_MODIFY_NUM + 1)]; 12586 } mhdr_dummy; 12587 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 12588 const struct rte_flow_action_count *count = NULL; 12589 const struct rte_flow_action_age *non_shared_age = NULL; 12590 union flow_dv_attr flow_attr = { .attr = 0 }; 12591 uint32_t tag_be; 12592 union mlx5_flow_tbl_key tbl_key; 12593 uint32_t modify_action_position = UINT32_MAX; 12594 void *match_mask = matcher.mask.buf; 12595 void *match_value = dev_flow->dv.value.buf; 12596 uint8_t next_protocol = 0xff; 12597 struct rte_vlan_hdr vlan = { 0 }; 12598 struct mlx5_flow_dv_dest_array_resource mdest_res; 12599 struct mlx5_flow_dv_sample_resource sample_res; 12600 void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 12601 const struct rte_flow_action_sample *sample = NULL; 12602 struct mlx5_flow_sub_actions_list *sample_act; 12603 uint32_t sample_act_pos = UINT32_MAX; 12604 uint32_t age_act_pos = UINT32_MAX; 12605 uint32_t num_of_dest = 0; 12606 int tmp_actions_n = 0; 12607 uint32_t table; 12608 int ret = 0; 12609 const struct mlx5_flow_tunnel *tunnel = NULL; 12610 struct flow_grp_info grp_info = { 12611 .external = !!dev_flow->external, 12612 .transfer = !!attr->transfer, 12613 .fdb_def_rule = !!priv->fdb_def_rule, 12614 .skip_scale = dev_flow->skip_scale & 12615 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 12616 .std_tbl_fix = true, 12617 }; 12618 const struct rte_flow_item *head_item = items; 12619 12620 if (!wks) 12621 return rte_flow_error_set(error, ENOMEM, 12622 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12623 NULL, 12624 "failed to push flow workspace"); 12625 rss_desc = &wks->rss_desc; 12626 memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource)); 12627 memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource)); 12628 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12629 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12630 /* update normal path action resource into last index of array */ 12631 sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1]; 12632 if (is_tunnel_offload_active(dev)) { 12633 if (dev_flow->tunnel) { 12634 RTE_VERIFY(dev_flow->tof_type == 12635 MLX5_TUNNEL_OFFLOAD_MISS_RULE); 12636 tunnel = dev_flow->tunnel; 12637 } else { 12638 tunnel = mlx5_get_tof(items, actions, 12639 &dev_flow->tof_type); 12640 dev_flow->tunnel = tunnel; 12641 } 12642 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 12643 (dev, attr, tunnel, dev_flow->tof_type); 12644 } 12645 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12646 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12647 ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table, 12648 &grp_info, error); 12649 if (ret) 12650 return ret; 12651 dev_flow->dv.group = table; 12652 if (attr->transfer) 12653 mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 12654 /* number of actions must be set to 0 in case of dirty stack. */ 12655 mhdr_res->actions_num = 0; 12656 if (is_flow_tunnel_match_rule(dev_flow->tof_type)) { 12657 /* 12658 * do not add decap action if match rule drops packet 12659 * HW rejects rules with decap & drop 12660 * 12661 * if tunnel match rule was inserted before matching tunnel set 12662 * rule flow table used in the match rule must be registered. 12663 * current implementation handles that in the 12664 * flow_dv_match_register() at the function end. 12665 */ 12666 bool add_decap = true; 12667 const struct rte_flow_action *ptr = actions; 12668 12669 for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) { 12670 if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) { 12671 add_decap = false; 12672 break; 12673 } 12674 } 12675 if (add_decap) { 12676 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12677 attr->transfer, 12678 error)) 12679 return -rte_errno; 12680 dev_flow->dv.actions[actions_n++] = 12681 dev_flow->dv.encap_decap->action; 12682 action_flags |= MLX5_FLOW_ACTION_DECAP; 12683 } 12684 } 12685 for (; !actions_end ; actions++) { 12686 const struct rte_flow_action_queue *queue; 12687 const struct rte_flow_action_rss *rss; 12688 const struct rte_flow_action *action = actions; 12689 const uint8_t *rss_key; 12690 struct mlx5_flow_tbl_resource *tbl; 12691 struct mlx5_aso_age_action *age_act; 12692 struct mlx5_flow_counter *cnt_act; 12693 uint32_t port_id = 0; 12694 struct mlx5_flow_dv_port_id_action_resource port_id_resource; 12695 int action_type = actions->type; 12696 const struct rte_flow_action *found_action = NULL; 12697 uint32_t jump_group = 0; 12698 uint32_t owner_idx; 12699 struct mlx5_aso_ct_action *ct; 12700 12701 if (!mlx5_flow_os_action_supported(action_type)) 12702 return rte_flow_error_set(error, ENOTSUP, 12703 RTE_FLOW_ERROR_TYPE_ACTION, 12704 actions, 12705 "action not supported"); 12706 switch (action_type) { 12707 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 12708 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 12709 break; 12710 case RTE_FLOW_ACTION_TYPE_VOID: 12711 break; 12712 case RTE_FLOW_ACTION_TYPE_PORT_ID: 12713 if (flow_dv_translate_action_port_id(dev, action, 12714 &port_id, error)) 12715 return -rte_errno; 12716 port_id_resource.port_id = port_id; 12717 MLX5_ASSERT(!handle->rix_port_id_action); 12718 if (flow_dv_port_id_action_resource_register 12719 (dev, &port_id_resource, dev_flow, error)) 12720 return -rte_errno; 12721 dev_flow->dv.actions[actions_n++] = 12722 dev_flow->dv.port_id_action->action; 12723 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12724 dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID; 12725 sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12726 num_of_dest++; 12727 break; 12728 case RTE_FLOW_ACTION_TYPE_FLAG: 12729 action_flags |= MLX5_FLOW_ACTION_FLAG; 12730 dev_flow->handle->mark = 1; 12731 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12732 struct rte_flow_action_mark mark = { 12733 .id = MLX5_FLOW_MARK_DEFAULT, 12734 }; 12735 12736 if (flow_dv_convert_action_mark(dev, &mark, 12737 mhdr_res, 12738 error)) 12739 return -rte_errno; 12740 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12741 break; 12742 } 12743 tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT); 12744 /* 12745 * Only one FLAG or MARK is supported per device flow 12746 * right now. So the pointer to the tag resource must be 12747 * zero before the register process. 12748 */ 12749 MLX5_ASSERT(!handle->dvh.rix_tag); 12750 if (flow_dv_tag_resource_register(dev, tag_be, 12751 dev_flow, error)) 12752 return -rte_errno; 12753 MLX5_ASSERT(dev_flow->dv.tag_resource); 12754 dev_flow->dv.actions[actions_n++] = 12755 dev_flow->dv.tag_resource->action; 12756 break; 12757 case RTE_FLOW_ACTION_TYPE_MARK: 12758 action_flags |= MLX5_FLOW_ACTION_MARK; 12759 dev_flow->handle->mark = 1; 12760 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12761 const struct rte_flow_action_mark *mark = 12762 (const struct rte_flow_action_mark *) 12763 actions->conf; 12764 12765 if (flow_dv_convert_action_mark(dev, mark, 12766 mhdr_res, 12767 error)) 12768 return -rte_errno; 12769 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12770 break; 12771 } 12772 /* Fall-through */ 12773 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 12774 /* Legacy (non-extensive) MARK action. */ 12775 tag_be = mlx5_flow_mark_set 12776 (((const struct rte_flow_action_mark *) 12777 (actions->conf))->id); 12778 MLX5_ASSERT(!handle->dvh.rix_tag); 12779 if (flow_dv_tag_resource_register(dev, tag_be, 12780 dev_flow, error)) 12781 return -rte_errno; 12782 MLX5_ASSERT(dev_flow->dv.tag_resource); 12783 dev_flow->dv.actions[actions_n++] = 12784 dev_flow->dv.tag_resource->action; 12785 break; 12786 case RTE_FLOW_ACTION_TYPE_SET_META: 12787 if (flow_dv_convert_action_set_meta 12788 (dev, mhdr_res, attr, 12789 (const struct rte_flow_action_set_meta *) 12790 actions->conf, error)) 12791 return -rte_errno; 12792 action_flags |= MLX5_FLOW_ACTION_SET_META; 12793 break; 12794 case RTE_FLOW_ACTION_TYPE_SET_TAG: 12795 if (flow_dv_convert_action_set_tag 12796 (dev, mhdr_res, 12797 (const struct rte_flow_action_set_tag *) 12798 actions->conf, error)) 12799 return -rte_errno; 12800 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 12801 break; 12802 case RTE_FLOW_ACTION_TYPE_DROP: 12803 action_flags |= MLX5_FLOW_ACTION_DROP; 12804 dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP; 12805 break; 12806 case RTE_FLOW_ACTION_TYPE_QUEUE: 12807 queue = actions->conf; 12808 rss_desc->queue_num = 1; 12809 rss_desc->queue[0] = queue->index; 12810 action_flags |= MLX5_FLOW_ACTION_QUEUE; 12811 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 12812 sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE; 12813 num_of_dest++; 12814 break; 12815 case RTE_FLOW_ACTION_TYPE_RSS: 12816 rss = actions->conf; 12817 memcpy(rss_desc->queue, rss->queue, 12818 rss->queue_num * sizeof(uint16_t)); 12819 rss_desc->queue_num = rss->queue_num; 12820 /* NULL RSS key indicates default RSS key. */ 12821 rss_key = !rss->key ? rss_hash_default_key : rss->key; 12822 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 12823 /* 12824 * rss->level and rss.types should be set in advance 12825 * when expanding items for RSS. 12826 */ 12827 action_flags |= MLX5_FLOW_ACTION_RSS; 12828 dev_flow->handle->fate_action = rss_desc->shared_rss ? 12829 MLX5_FLOW_FATE_SHARED_RSS : 12830 MLX5_FLOW_FATE_QUEUE; 12831 break; 12832 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 12833 flow->age = (uint32_t)(uintptr_t)(action->conf); 12834 age_act = flow_aso_age_get_by_idx(dev, flow->age); 12835 __atomic_fetch_add(&age_act->refcnt, 1, 12836 __ATOMIC_RELAXED); 12837 age_act_pos = actions_n++; 12838 action_flags |= MLX5_FLOW_ACTION_AGE; 12839 break; 12840 case RTE_FLOW_ACTION_TYPE_AGE: 12841 non_shared_age = action->conf; 12842 age_act_pos = actions_n++; 12843 action_flags |= MLX5_FLOW_ACTION_AGE; 12844 break; 12845 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 12846 cnt_act = flow_dv_counter_get_by_idx(dev, 12847 (uint32_t)(uintptr_t)action->conf, 12848 NULL); 12849 MLX5_ASSERT(cnt_act != NULL); 12850 /** 12851 * When creating meter drop flow in drop table, the 12852 * counter should not overwrite the rte flow counter. 12853 */ 12854 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 12855 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) { 12856 dev_flow->dv.actions[actions_n++] = 12857 cnt_act->action; 12858 } else { 12859 flow->counter = 12860 (uint32_t)(uintptr_t)(action->conf); 12861 __atomic_fetch_add(&cnt_act->shared_info.refcnt, 12862 1, __ATOMIC_RELAXED); 12863 /* Save information first, will apply later. */ 12864 action_flags |= MLX5_FLOW_ACTION_COUNT; 12865 } 12866 break; 12867 case RTE_FLOW_ACTION_TYPE_COUNT: 12868 if (!dev_conf->devx) { 12869 return rte_flow_error_set 12870 (error, ENOTSUP, 12871 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12872 NULL, 12873 "count action not supported"); 12874 } 12875 /* Save information first, will apply later. */ 12876 count = action->conf; 12877 action_flags |= MLX5_FLOW_ACTION_COUNT; 12878 break; 12879 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 12880 dev_flow->dv.actions[actions_n++] = 12881 priv->sh->pop_vlan_action; 12882 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 12883 break; 12884 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 12885 if (!(action_flags & 12886 MLX5_FLOW_ACTION_OF_SET_VLAN_VID)) 12887 flow_dev_get_vlan_info_from_items(items, &vlan); 12888 vlan.eth_proto = rte_be_to_cpu_16 12889 ((((const struct rte_flow_action_of_push_vlan *) 12890 actions->conf)->ethertype)); 12891 found_action = mlx5_flow_find_action 12892 (actions + 1, 12893 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID); 12894 if (found_action) 12895 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12896 found_action = mlx5_flow_find_action 12897 (actions + 1, 12898 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP); 12899 if (found_action) 12900 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12901 if (flow_dv_create_action_push_vlan 12902 (dev, attr, &vlan, dev_flow, error)) 12903 return -rte_errno; 12904 dev_flow->dv.actions[actions_n++] = 12905 dev_flow->dv.push_vlan_res->action; 12906 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 12907 break; 12908 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 12909 /* of_vlan_push action handled this action */ 12910 MLX5_ASSERT(action_flags & 12911 MLX5_FLOW_ACTION_OF_PUSH_VLAN); 12912 break; 12913 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 12914 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 12915 break; 12916 flow_dev_get_vlan_info_from_items(items, &vlan); 12917 mlx5_update_vlan_vid_pcp(actions, &vlan); 12918 /* If no VLAN push - this is a modify header action */ 12919 if (flow_dv_convert_action_modify_vlan_vid 12920 (mhdr_res, actions, error)) 12921 return -rte_errno; 12922 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 12923 break; 12924 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 12925 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 12926 if (flow_dv_create_action_l2_encap(dev, actions, 12927 dev_flow, 12928 attr->transfer, 12929 error)) 12930 return -rte_errno; 12931 dev_flow->dv.actions[actions_n++] = 12932 dev_flow->dv.encap_decap->action; 12933 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12934 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 12935 sample_act->action_flags |= 12936 MLX5_FLOW_ACTION_ENCAP; 12937 break; 12938 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 12939 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 12940 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12941 attr->transfer, 12942 error)) 12943 return -rte_errno; 12944 dev_flow->dv.actions[actions_n++] = 12945 dev_flow->dv.encap_decap->action; 12946 action_flags |= MLX5_FLOW_ACTION_DECAP; 12947 break; 12948 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 12949 /* Handle encap with preceding decap. */ 12950 if (action_flags & MLX5_FLOW_ACTION_DECAP) { 12951 if (flow_dv_create_action_raw_encap 12952 (dev, actions, dev_flow, attr, error)) 12953 return -rte_errno; 12954 dev_flow->dv.actions[actions_n++] = 12955 dev_flow->dv.encap_decap->action; 12956 } else { 12957 /* Handle encap without preceding decap. */ 12958 if (flow_dv_create_action_l2_encap 12959 (dev, actions, dev_flow, attr->transfer, 12960 error)) 12961 return -rte_errno; 12962 dev_flow->dv.actions[actions_n++] = 12963 dev_flow->dv.encap_decap->action; 12964 } 12965 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12966 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 12967 sample_act->action_flags |= 12968 MLX5_FLOW_ACTION_ENCAP; 12969 break; 12970 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 12971 while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID) 12972 ; 12973 if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 12974 if (flow_dv_create_action_l2_decap 12975 (dev, dev_flow, attr->transfer, error)) 12976 return -rte_errno; 12977 dev_flow->dv.actions[actions_n++] = 12978 dev_flow->dv.encap_decap->action; 12979 } 12980 /* If decap is followed by encap, handle it at encap. */ 12981 action_flags |= MLX5_FLOW_ACTION_DECAP; 12982 break; 12983 case MLX5_RTE_FLOW_ACTION_TYPE_JUMP: 12984 dev_flow->dv.actions[actions_n++] = 12985 (void *)(uintptr_t)action->conf; 12986 action_flags |= MLX5_FLOW_ACTION_JUMP; 12987 break; 12988 case RTE_FLOW_ACTION_TYPE_JUMP: 12989 jump_group = ((const struct rte_flow_action_jump *) 12990 action->conf)->group; 12991 grp_info.std_tbl_fix = 0; 12992 if (dev_flow->skip_scale & 12993 (1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT)) 12994 grp_info.skip_scale = 1; 12995 else 12996 grp_info.skip_scale = 0; 12997 ret = mlx5_flow_group_to_table(dev, tunnel, 12998 jump_group, 12999 &table, 13000 &grp_info, error); 13001 if (ret) 13002 return ret; 13003 tbl = flow_dv_tbl_resource_get(dev, table, attr->egress, 13004 attr->transfer, 13005 !!dev_flow->external, 13006 tunnel, jump_group, 0, 13007 0, error); 13008 if (!tbl) 13009 return rte_flow_error_set 13010 (error, errno, 13011 RTE_FLOW_ERROR_TYPE_ACTION, 13012 NULL, 13013 "cannot create jump action."); 13014 if (flow_dv_jump_tbl_resource_register 13015 (dev, tbl, dev_flow, error)) { 13016 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 13017 return rte_flow_error_set 13018 (error, errno, 13019 RTE_FLOW_ERROR_TYPE_ACTION, 13020 NULL, 13021 "cannot create jump action."); 13022 } 13023 dev_flow->dv.actions[actions_n++] = 13024 dev_flow->dv.jump->action; 13025 action_flags |= MLX5_FLOW_ACTION_JUMP; 13026 dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP; 13027 sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP; 13028 num_of_dest++; 13029 break; 13030 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 13031 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 13032 if (flow_dv_convert_action_modify_mac 13033 (mhdr_res, actions, error)) 13034 return -rte_errno; 13035 action_flags |= actions->type == 13036 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 13037 MLX5_FLOW_ACTION_SET_MAC_SRC : 13038 MLX5_FLOW_ACTION_SET_MAC_DST; 13039 break; 13040 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 13041 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 13042 if (flow_dv_convert_action_modify_ipv4 13043 (mhdr_res, actions, error)) 13044 return -rte_errno; 13045 action_flags |= actions->type == 13046 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 13047 MLX5_FLOW_ACTION_SET_IPV4_SRC : 13048 MLX5_FLOW_ACTION_SET_IPV4_DST; 13049 break; 13050 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 13051 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 13052 if (flow_dv_convert_action_modify_ipv6 13053 (mhdr_res, actions, error)) 13054 return -rte_errno; 13055 action_flags |= actions->type == 13056 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 13057 MLX5_FLOW_ACTION_SET_IPV6_SRC : 13058 MLX5_FLOW_ACTION_SET_IPV6_DST; 13059 break; 13060 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 13061 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 13062 if (flow_dv_convert_action_modify_tp 13063 (mhdr_res, actions, items, 13064 &flow_attr, dev_flow, !!(action_flags & 13065 MLX5_FLOW_ACTION_DECAP), error)) 13066 return -rte_errno; 13067 action_flags |= actions->type == 13068 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 13069 MLX5_FLOW_ACTION_SET_TP_SRC : 13070 MLX5_FLOW_ACTION_SET_TP_DST; 13071 break; 13072 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 13073 if (flow_dv_convert_action_modify_dec_ttl 13074 (mhdr_res, items, &flow_attr, dev_flow, 13075 !!(action_flags & 13076 MLX5_FLOW_ACTION_DECAP), error)) 13077 return -rte_errno; 13078 action_flags |= MLX5_FLOW_ACTION_DEC_TTL; 13079 break; 13080 case RTE_FLOW_ACTION_TYPE_SET_TTL: 13081 if (flow_dv_convert_action_modify_ttl 13082 (mhdr_res, actions, items, &flow_attr, 13083 dev_flow, !!(action_flags & 13084 MLX5_FLOW_ACTION_DECAP), error)) 13085 return -rte_errno; 13086 action_flags |= MLX5_FLOW_ACTION_SET_TTL; 13087 break; 13088 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 13089 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 13090 if (flow_dv_convert_action_modify_tcp_seq 13091 (mhdr_res, actions, error)) 13092 return -rte_errno; 13093 action_flags |= actions->type == 13094 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 13095 MLX5_FLOW_ACTION_INC_TCP_SEQ : 13096 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 13097 break; 13098 13099 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 13100 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 13101 if (flow_dv_convert_action_modify_tcp_ack 13102 (mhdr_res, actions, error)) 13103 return -rte_errno; 13104 action_flags |= actions->type == 13105 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 13106 MLX5_FLOW_ACTION_INC_TCP_ACK : 13107 MLX5_FLOW_ACTION_DEC_TCP_ACK; 13108 break; 13109 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 13110 if (flow_dv_convert_action_set_reg 13111 (mhdr_res, actions, error)) 13112 return -rte_errno; 13113 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13114 break; 13115 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 13116 if (flow_dv_convert_action_copy_mreg 13117 (dev, mhdr_res, actions, error)) 13118 return -rte_errno; 13119 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13120 break; 13121 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 13122 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 13123 dev_flow->handle->fate_action = 13124 MLX5_FLOW_FATE_DEFAULT_MISS; 13125 break; 13126 case RTE_FLOW_ACTION_TYPE_METER: 13127 if (!wks->fm) 13128 return rte_flow_error_set(error, rte_errno, 13129 RTE_FLOW_ERROR_TYPE_ACTION, 13130 NULL, "Failed to get meter in flow."); 13131 /* Set the meter action. */ 13132 dev_flow->dv.actions[actions_n++] = 13133 wks->fm->meter_action; 13134 action_flags |= MLX5_FLOW_ACTION_METER; 13135 break; 13136 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 13137 if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res, 13138 actions, error)) 13139 return -rte_errno; 13140 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 13141 break; 13142 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 13143 if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res, 13144 actions, error)) 13145 return -rte_errno; 13146 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 13147 break; 13148 case RTE_FLOW_ACTION_TYPE_SAMPLE: 13149 sample_act_pos = actions_n; 13150 sample = (const struct rte_flow_action_sample *) 13151 action->conf; 13152 actions_n++; 13153 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 13154 /* put encap action into group if work with port id */ 13155 if ((action_flags & MLX5_FLOW_ACTION_ENCAP) && 13156 (action_flags & MLX5_FLOW_ACTION_PORT_ID)) 13157 sample_act->action_flags |= 13158 MLX5_FLOW_ACTION_ENCAP; 13159 break; 13160 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 13161 if (flow_dv_convert_action_modify_field 13162 (dev, mhdr_res, actions, attr, error)) 13163 return -rte_errno; 13164 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 13165 break; 13166 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 13167 owner_idx = (uint32_t)(uintptr_t)action->conf; 13168 ct = flow_aso_ct_get_by_idx(dev, owner_idx); 13169 if (!ct) 13170 return rte_flow_error_set(error, EINVAL, 13171 RTE_FLOW_ERROR_TYPE_ACTION, 13172 NULL, 13173 "Failed to get CT object."); 13174 if (mlx5_aso_ct_available(priv->sh, ct)) 13175 return rte_flow_error_set(error, rte_errno, 13176 RTE_FLOW_ERROR_TYPE_ACTION, 13177 NULL, 13178 "CT is unavailable."); 13179 if (ct->is_original) 13180 dev_flow->dv.actions[actions_n] = 13181 ct->dr_action_orig; 13182 else 13183 dev_flow->dv.actions[actions_n] = 13184 ct->dr_action_rply; 13185 flow->indirect_type = MLX5_INDIRECT_ACTION_TYPE_CT; 13186 flow->ct = owner_idx; 13187 __atomic_fetch_add(&ct->refcnt, 1, __ATOMIC_RELAXED); 13188 actions_n++; 13189 action_flags |= MLX5_FLOW_ACTION_CT; 13190 break; 13191 case RTE_FLOW_ACTION_TYPE_END: 13192 actions_end = true; 13193 if (mhdr_res->actions_num) { 13194 /* create modify action if needed. */ 13195 if (flow_dv_modify_hdr_resource_register 13196 (dev, mhdr_res, dev_flow, error)) 13197 return -rte_errno; 13198 dev_flow->dv.actions[modify_action_position] = 13199 handle->dvh.modify_hdr->action; 13200 } 13201 /* 13202 * Handle AGE and COUNT action by single HW counter 13203 * when they are not shared. 13204 */ 13205 if (action_flags & MLX5_FLOW_ACTION_AGE) { 13206 if ((non_shared_age && 13207 count && !count->shared) || 13208 !(priv->sh->flow_hit_aso_en && 13209 (attr->group || attr->transfer))) { 13210 /* Creates age by counters. */ 13211 cnt_act = flow_dv_prepare_counter 13212 (dev, dev_flow, 13213 flow, count, 13214 non_shared_age, 13215 error); 13216 if (!cnt_act) 13217 return -rte_errno; 13218 dev_flow->dv.actions[age_act_pos] = 13219 cnt_act->action; 13220 break; 13221 } 13222 if (!flow->age && non_shared_age) { 13223 flow->age = flow_dv_aso_age_alloc 13224 (dev, error); 13225 if (!flow->age) 13226 return -rte_errno; 13227 flow_dv_aso_age_params_init 13228 (dev, flow->age, 13229 non_shared_age->context ? 13230 non_shared_age->context : 13231 (void *)(uintptr_t) 13232 (dev_flow->flow_idx), 13233 non_shared_age->timeout); 13234 } 13235 age_act = flow_aso_age_get_by_idx(dev, 13236 flow->age); 13237 dev_flow->dv.actions[age_act_pos] = 13238 age_act->dr_action; 13239 } 13240 if (action_flags & MLX5_FLOW_ACTION_COUNT) { 13241 /* 13242 * Create one count action, to be used 13243 * by all sub-flows. 13244 */ 13245 cnt_act = flow_dv_prepare_counter(dev, dev_flow, 13246 flow, count, 13247 NULL, error); 13248 if (!cnt_act) 13249 return -rte_errno; 13250 dev_flow->dv.actions[actions_n++] = 13251 cnt_act->action; 13252 } 13253 default: 13254 break; 13255 } 13256 if (mhdr_res->actions_num && 13257 modify_action_position == UINT32_MAX) 13258 modify_action_position = actions_n++; 13259 } 13260 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 13261 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 13262 int item_type = items->type; 13263 13264 if (!mlx5_flow_os_item_supported(item_type)) 13265 return rte_flow_error_set(error, ENOTSUP, 13266 RTE_FLOW_ERROR_TYPE_ITEM, 13267 NULL, "item not supported"); 13268 switch (item_type) { 13269 case RTE_FLOW_ITEM_TYPE_PORT_ID: 13270 flow_dv_translate_item_port_id 13271 (dev, match_mask, match_value, items, attr); 13272 last_item = MLX5_FLOW_ITEM_PORT_ID; 13273 break; 13274 case RTE_FLOW_ITEM_TYPE_ETH: 13275 flow_dv_translate_item_eth(match_mask, match_value, 13276 items, tunnel, 13277 dev_flow->dv.group); 13278 matcher.priority = action_flags & 13279 MLX5_FLOW_ACTION_DEFAULT_MISS && 13280 !dev_flow->external ? 13281 MLX5_PRIORITY_MAP_L3 : 13282 MLX5_PRIORITY_MAP_L2; 13283 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 13284 MLX5_FLOW_LAYER_OUTER_L2; 13285 break; 13286 case RTE_FLOW_ITEM_TYPE_VLAN: 13287 flow_dv_translate_item_vlan(dev_flow, 13288 match_mask, match_value, 13289 items, tunnel, 13290 dev_flow->dv.group); 13291 matcher.priority = MLX5_PRIORITY_MAP_L2; 13292 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 13293 MLX5_FLOW_LAYER_INNER_VLAN) : 13294 (MLX5_FLOW_LAYER_OUTER_L2 | 13295 MLX5_FLOW_LAYER_OUTER_VLAN); 13296 break; 13297 case RTE_FLOW_ITEM_TYPE_IPV4: 13298 mlx5_flow_tunnel_ip_check(items, next_protocol, 13299 &item_flags, &tunnel); 13300 flow_dv_translate_item_ipv4(match_mask, match_value, 13301 items, tunnel, 13302 dev_flow->dv.group); 13303 matcher.priority = MLX5_PRIORITY_MAP_L3; 13304 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 13305 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 13306 if (items->mask != NULL && 13307 ((const struct rte_flow_item_ipv4 *) 13308 items->mask)->hdr.next_proto_id) { 13309 next_protocol = 13310 ((const struct rte_flow_item_ipv4 *) 13311 (items->spec))->hdr.next_proto_id; 13312 next_protocol &= 13313 ((const struct rte_flow_item_ipv4 *) 13314 (items->mask))->hdr.next_proto_id; 13315 } else { 13316 /* Reset for inner layer. */ 13317 next_protocol = 0xff; 13318 } 13319 break; 13320 case RTE_FLOW_ITEM_TYPE_IPV6: 13321 mlx5_flow_tunnel_ip_check(items, next_protocol, 13322 &item_flags, &tunnel); 13323 flow_dv_translate_item_ipv6(match_mask, match_value, 13324 items, tunnel, 13325 dev_flow->dv.group); 13326 matcher.priority = MLX5_PRIORITY_MAP_L3; 13327 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 13328 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 13329 if (items->mask != NULL && 13330 ((const struct rte_flow_item_ipv6 *) 13331 items->mask)->hdr.proto) { 13332 next_protocol = 13333 ((const struct rte_flow_item_ipv6 *) 13334 items->spec)->hdr.proto; 13335 next_protocol &= 13336 ((const struct rte_flow_item_ipv6 *) 13337 items->mask)->hdr.proto; 13338 } else { 13339 /* Reset for inner layer. */ 13340 next_protocol = 0xff; 13341 } 13342 break; 13343 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 13344 flow_dv_translate_item_ipv6_frag_ext(match_mask, 13345 match_value, 13346 items, tunnel); 13347 last_item = tunnel ? 13348 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 13349 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 13350 if (items->mask != NULL && 13351 ((const struct rte_flow_item_ipv6_frag_ext *) 13352 items->mask)->hdr.next_header) { 13353 next_protocol = 13354 ((const struct rte_flow_item_ipv6_frag_ext *) 13355 items->spec)->hdr.next_header; 13356 next_protocol &= 13357 ((const struct rte_flow_item_ipv6_frag_ext *) 13358 items->mask)->hdr.next_header; 13359 } else { 13360 /* Reset for inner layer. */ 13361 next_protocol = 0xff; 13362 } 13363 break; 13364 case RTE_FLOW_ITEM_TYPE_TCP: 13365 flow_dv_translate_item_tcp(match_mask, match_value, 13366 items, tunnel); 13367 matcher.priority = MLX5_PRIORITY_MAP_L4; 13368 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 13369 MLX5_FLOW_LAYER_OUTER_L4_TCP; 13370 break; 13371 case RTE_FLOW_ITEM_TYPE_UDP: 13372 flow_dv_translate_item_udp(match_mask, match_value, 13373 items, tunnel); 13374 matcher.priority = MLX5_PRIORITY_MAP_L4; 13375 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 13376 MLX5_FLOW_LAYER_OUTER_L4_UDP; 13377 break; 13378 case RTE_FLOW_ITEM_TYPE_GRE: 13379 flow_dv_translate_item_gre(match_mask, match_value, 13380 items, tunnel); 13381 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13382 last_item = MLX5_FLOW_LAYER_GRE; 13383 break; 13384 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 13385 flow_dv_translate_item_gre_key(match_mask, 13386 match_value, items); 13387 last_item = MLX5_FLOW_LAYER_GRE_KEY; 13388 break; 13389 case RTE_FLOW_ITEM_TYPE_NVGRE: 13390 flow_dv_translate_item_nvgre(match_mask, match_value, 13391 items, tunnel); 13392 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13393 last_item = MLX5_FLOW_LAYER_GRE; 13394 break; 13395 case RTE_FLOW_ITEM_TYPE_VXLAN: 13396 flow_dv_translate_item_vxlan(dev, attr, 13397 match_mask, match_value, 13398 items, tunnel); 13399 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13400 last_item = MLX5_FLOW_LAYER_VXLAN; 13401 break; 13402 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 13403 flow_dv_translate_item_vxlan_gpe(match_mask, 13404 match_value, items, 13405 tunnel); 13406 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13407 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 13408 break; 13409 case RTE_FLOW_ITEM_TYPE_GENEVE: 13410 flow_dv_translate_item_geneve(match_mask, match_value, 13411 items, tunnel); 13412 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13413 last_item = MLX5_FLOW_LAYER_GENEVE; 13414 break; 13415 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 13416 ret = flow_dv_translate_item_geneve_opt(dev, match_mask, 13417 match_value, 13418 items, error); 13419 if (ret) 13420 return rte_flow_error_set(error, -ret, 13421 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13422 "cannot create GENEVE TLV option"); 13423 flow->geneve_tlv_option = 1; 13424 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 13425 break; 13426 case RTE_FLOW_ITEM_TYPE_MPLS: 13427 flow_dv_translate_item_mpls(match_mask, match_value, 13428 items, last_item, tunnel); 13429 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13430 last_item = MLX5_FLOW_LAYER_MPLS; 13431 break; 13432 case RTE_FLOW_ITEM_TYPE_MARK: 13433 flow_dv_translate_item_mark(dev, match_mask, 13434 match_value, items); 13435 last_item = MLX5_FLOW_ITEM_MARK; 13436 break; 13437 case RTE_FLOW_ITEM_TYPE_META: 13438 flow_dv_translate_item_meta(dev, match_mask, 13439 match_value, attr, items); 13440 last_item = MLX5_FLOW_ITEM_METADATA; 13441 break; 13442 case RTE_FLOW_ITEM_TYPE_ICMP: 13443 flow_dv_translate_item_icmp(match_mask, match_value, 13444 items, tunnel); 13445 last_item = MLX5_FLOW_LAYER_ICMP; 13446 break; 13447 case RTE_FLOW_ITEM_TYPE_ICMP6: 13448 flow_dv_translate_item_icmp6(match_mask, match_value, 13449 items, tunnel); 13450 last_item = MLX5_FLOW_LAYER_ICMP6; 13451 break; 13452 case RTE_FLOW_ITEM_TYPE_TAG: 13453 flow_dv_translate_item_tag(dev, match_mask, 13454 match_value, items); 13455 last_item = MLX5_FLOW_ITEM_TAG; 13456 break; 13457 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 13458 flow_dv_translate_mlx5_item_tag(dev, match_mask, 13459 match_value, items); 13460 last_item = MLX5_FLOW_ITEM_TAG; 13461 break; 13462 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 13463 flow_dv_translate_item_tx_queue(dev, match_mask, 13464 match_value, 13465 items); 13466 last_item = MLX5_FLOW_ITEM_TX_QUEUE; 13467 break; 13468 case RTE_FLOW_ITEM_TYPE_GTP: 13469 flow_dv_translate_item_gtp(match_mask, match_value, 13470 items, tunnel); 13471 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13472 last_item = MLX5_FLOW_LAYER_GTP; 13473 break; 13474 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 13475 ret = flow_dv_translate_item_gtp_psc(match_mask, 13476 match_value, 13477 items); 13478 if (ret) 13479 return rte_flow_error_set(error, -ret, 13480 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13481 "cannot create GTP PSC item"); 13482 last_item = MLX5_FLOW_LAYER_GTP_PSC; 13483 break; 13484 case RTE_FLOW_ITEM_TYPE_ECPRI: 13485 if (!mlx5_flex_parser_ecpri_exist(dev)) { 13486 /* Create it only the first time to be used. */ 13487 ret = mlx5_flex_parser_ecpri_alloc(dev); 13488 if (ret) 13489 return rte_flow_error_set 13490 (error, -ret, 13491 RTE_FLOW_ERROR_TYPE_ITEM, 13492 NULL, 13493 "cannot create eCPRI parser"); 13494 } 13495 flow_dv_translate_item_ecpri(dev, match_mask, 13496 match_value, items, 13497 last_item); 13498 /* No other protocol should follow eCPRI layer. */ 13499 last_item = MLX5_FLOW_LAYER_ECPRI; 13500 break; 13501 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 13502 flow_dv_translate_item_integrity(match_mask, 13503 match_value, 13504 head_item, items); 13505 break; 13506 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 13507 flow_dv_translate_item_aso_ct(dev, match_mask, 13508 match_value, items); 13509 break; 13510 default: 13511 break; 13512 } 13513 item_flags |= last_item; 13514 } 13515 /* 13516 * When E-Switch mode is enabled, we have two cases where we need to 13517 * set the source port manually. 13518 * The first one, is in case of Nic steering rule, and the second is 13519 * E-Switch rule where no port_id item was found. In both cases 13520 * the source port is set according the current port in use. 13521 */ 13522 if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) && 13523 (priv->representor || priv->master)) { 13524 if (flow_dv_translate_item_port_id(dev, match_mask, 13525 match_value, NULL, attr)) 13526 return -rte_errno; 13527 } 13528 #ifdef RTE_LIBRTE_MLX5_DEBUG 13529 MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf, 13530 dev_flow->dv.value.buf)); 13531 #endif 13532 /* 13533 * Layers may be already initialized from prefix flow if this dev_flow 13534 * is the suffix flow. 13535 */ 13536 handle->layers |= item_flags; 13537 if (action_flags & MLX5_FLOW_ACTION_RSS) 13538 flow_dv_hashfields_set(dev_flow, rss_desc); 13539 /* If has RSS action in the sample action, the Sample/Mirror resource 13540 * should be registered after the hash filed be update. 13541 */ 13542 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) { 13543 ret = flow_dv_translate_action_sample(dev, 13544 sample, 13545 dev_flow, attr, 13546 &num_of_dest, 13547 sample_actions, 13548 &sample_res, 13549 error); 13550 if (ret < 0) 13551 return ret; 13552 ret = flow_dv_create_action_sample(dev, 13553 dev_flow, 13554 num_of_dest, 13555 &sample_res, 13556 &mdest_res, 13557 sample_actions, 13558 action_flags, 13559 error); 13560 if (ret < 0) 13561 return rte_flow_error_set 13562 (error, rte_errno, 13563 RTE_FLOW_ERROR_TYPE_ACTION, 13564 NULL, 13565 "cannot create sample action"); 13566 if (num_of_dest > 1) { 13567 dev_flow->dv.actions[sample_act_pos] = 13568 dev_flow->dv.dest_array_res->action; 13569 } else { 13570 dev_flow->dv.actions[sample_act_pos] = 13571 dev_flow->dv.sample_res->verbs_action; 13572 } 13573 } 13574 /* 13575 * For multiple destination (sample action with ratio=1), the encap 13576 * action and port id action will be combined into group action. 13577 * So need remove the original these actions in the flow and only 13578 * use the sample action instead of. 13579 */ 13580 if (num_of_dest > 1 && 13581 (sample_act->dr_port_id_action || sample_act->dr_jump_action)) { 13582 int i; 13583 void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 13584 13585 for (i = 0; i < actions_n; i++) { 13586 if ((sample_act->dr_encap_action && 13587 sample_act->dr_encap_action == 13588 dev_flow->dv.actions[i]) || 13589 (sample_act->dr_port_id_action && 13590 sample_act->dr_port_id_action == 13591 dev_flow->dv.actions[i]) || 13592 (sample_act->dr_jump_action && 13593 sample_act->dr_jump_action == 13594 dev_flow->dv.actions[i])) 13595 continue; 13596 temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i]; 13597 } 13598 memcpy((void *)dev_flow->dv.actions, 13599 (void *)temp_actions, 13600 tmp_actions_n * sizeof(void *)); 13601 actions_n = tmp_actions_n; 13602 } 13603 dev_flow->dv.actions_n = actions_n; 13604 dev_flow->act_flags = action_flags; 13605 if (wks->skip_matcher_reg) 13606 return 0; 13607 /* Register matcher. */ 13608 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 13609 matcher.mask.size); 13610 matcher.priority = mlx5_get_matcher_priority(dev, attr, 13611 matcher.priority); 13612 /** 13613 * When creating meter drop flow in drop table, using original 13614 * 5-tuple match, the matcher priority should be lower than 13615 * mtr_id matcher. 13616 */ 13617 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 13618 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP && 13619 matcher.priority <= MLX5_REG_BITS) 13620 matcher.priority += MLX5_REG_BITS; 13621 /* reserved field no needs to be set to 0 here. */ 13622 tbl_key.is_fdb = attr->transfer; 13623 tbl_key.is_egress = attr->egress; 13624 tbl_key.level = dev_flow->dv.group; 13625 tbl_key.id = dev_flow->dv.table_id; 13626 if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow, 13627 tunnel, attr->group, error)) 13628 return -rte_errno; 13629 return 0; 13630 } 13631 13632 /** 13633 * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13634 * and tunnel. 13635 * 13636 * @param[in, out] action 13637 * Shred RSS action holding hash RX queue objects. 13638 * @param[in] hash_fields 13639 * Defines combination of packet fields to participate in RX hash. 13640 * @param[in] tunnel 13641 * Tunnel type 13642 * @param[in] hrxq_idx 13643 * Hash RX queue index to set. 13644 * 13645 * @return 13646 * 0 on success, otherwise negative errno value. 13647 */ 13648 static int 13649 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action, 13650 const uint64_t hash_fields, 13651 uint32_t hrxq_idx) 13652 { 13653 uint32_t *hrxqs = action->hrxq; 13654 13655 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13656 case MLX5_RSS_HASH_IPV4: 13657 /* fall-through. */ 13658 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13659 /* fall-through. */ 13660 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13661 hrxqs[0] = hrxq_idx; 13662 return 0; 13663 case MLX5_RSS_HASH_IPV4_TCP: 13664 /* fall-through. */ 13665 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13666 /* fall-through. */ 13667 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13668 hrxqs[1] = hrxq_idx; 13669 return 0; 13670 case MLX5_RSS_HASH_IPV4_UDP: 13671 /* fall-through. */ 13672 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13673 /* fall-through. */ 13674 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13675 hrxqs[2] = hrxq_idx; 13676 return 0; 13677 case MLX5_RSS_HASH_IPV6: 13678 /* fall-through. */ 13679 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13680 /* fall-through. */ 13681 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13682 hrxqs[3] = hrxq_idx; 13683 return 0; 13684 case MLX5_RSS_HASH_IPV6_TCP: 13685 /* fall-through. */ 13686 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13687 /* fall-through. */ 13688 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13689 hrxqs[4] = hrxq_idx; 13690 return 0; 13691 case MLX5_RSS_HASH_IPV6_UDP: 13692 /* fall-through. */ 13693 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13694 /* fall-through. */ 13695 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13696 hrxqs[5] = hrxq_idx; 13697 return 0; 13698 case MLX5_RSS_HASH_NONE: 13699 hrxqs[6] = hrxq_idx; 13700 return 0; 13701 default: 13702 return -1; 13703 } 13704 } 13705 13706 /** 13707 * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13708 * and tunnel. 13709 * 13710 * @param[in] dev 13711 * Pointer to the Ethernet device structure. 13712 * @param[in] idx 13713 * Shared RSS action ID holding hash RX queue objects. 13714 * @param[in] hash_fields 13715 * Defines combination of packet fields to participate in RX hash. 13716 * @param[in] tunnel 13717 * Tunnel type 13718 * 13719 * @return 13720 * Valid hash RX queue index, otherwise 0. 13721 */ 13722 static uint32_t 13723 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx, 13724 const uint64_t hash_fields) 13725 { 13726 struct mlx5_priv *priv = dev->data->dev_private; 13727 struct mlx5_shared_action_rss *shared_rss = 13728 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 13729 const uint32_t *hrxqs = shared_rss->hrxq; 13730 13731 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13732 case MLX5_RSS_HASH_IPV4: 13733 /* fall-through. */ 13734 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13735 /* fall-through. */ 13736 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13737 return hrxqs[0]; 13738 case MLX5_RSS_HASH_IPV4_TCP: 13739 /* fall-through. */ 13740 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13741 /* fall-through. */ 13742 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13743 return hrxqs[1]; 13744 case MLX5_RSS_HASH_IPV4_UDP: 13745 /* fall-through. */ 13746 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13747 /* fall-through. */ 13748 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13749 return hrxqs[2]; 13750 case MLX5_RSS_HASH_IPV6: 13751 /* fall-through. */ 13752 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13753 /* fall-through. */ 13754 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13755 return hrxqs[3]; 13756 case MLX5_RSS_HASH_IPV6_TCP: 13757 /* fall-through. */ 13758 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13759 /* fall-through. */ 13760 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13761 return hrxqs[4]; 13762 case MLX5_RSS_HASH_IPV6_UDP: 13763 /* fall-through. */ 13764 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13765 /* fall-through. */ 13766 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13767 return hrxqs[5]; 13768 case MLX5_RSS_HASH_NONE: 13769 return hrxqs[6]; 13770 default: 13771 return 0; 13772 } 13773 13774 } 13775 13776 /** 13777 * Apply the flow to the NIC, lock free, 13778 * (mutex should be acquired by caller). 13779 * 13780 * @param[in] dev 13781 * Pointer to the Ethernet device structure. 13782 * @param[in, out] flow 13783 * Pointer to flow structure. 13784 * @param[out] error 13785 * Pointer to error structure. 13786 * 13787 * @return 13788 * 0 on success, a negative errno value otherwise and rte_errno is set. 13789 */ 13790 static int 13791 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, 13792 struct rte_flow_error *error) 13793 { 13794 struct mlx5_flow_dv_workspace *dv; 13795 struct mlx5_flow_handle *dh; 13796 struct mlx5_flow_handle_dv *dv_h; 13797 struct mlx5_flow *dev_flow; 13798 struct mlx5_priv *priv = dev->data->dev_private; 13799 uint32_t handle_idx; 13800 int n; 13801 int err; 13802 int idx; 13803 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 13804 struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc; 13805 uint8_t misc_mask; 13806 13807 MLX5_ASSERT(wks); 13808 for (idx = wks->flow_idx - 1; idx >= 0; idx--) { 13809 dev_flow = &wks->flows[idx]; 13810 dv = &dev_flow->dv; 13811 dh = dev_flow->handle; 13812 dv_h = &dh->dvh; 13813 n = dv->actions_n; 13814 if (dh->fate_action == MLX5_FLOW_FATE_DROP) { 13815 if (dv->transfer) { 13816 MLX5_ASSERT(priv->sh->dr_drop_action); 13817 dv->actions[n++] = priv->sh->dr_drop_action; 13818 } else { 13819 #ifdef HAVE_MLX5DV_DR 13820 /* DR supports drop action placeholder. */ 13821 MLX5_ASSERT(priv->sh->dr_drop_action); 13822 dv->actions[n++] = dv->group ? 13823 priv->sh->dr_drop_action : 13824 priv->root_drop_action; 13825 #else 13826 /* For DV we use the explicit drop queue. */ 13827 MLX5_ASSERT(priv->drop_queue.hrxq); 13828 dv->actions[n++] = 13829 priv->drop_queue.hrxq->action; 13830 #endif 13831 } 13832 } else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE && 13833 !dv_h->rix_sample && !dv_h->rix_dest_array)) { 13834 struct mlx5_hrxq *hrxq; 13835 uint32_t hrxq_idx; 13836 13837 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc, 13838 &hrxq_idx); 13839 if (!hrxq) { 13840 rte_flow_error_set 13841 (error, rte_errno, 13842 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13843 "cannot get hash queue"); 13844 goto error; 13845 } 13846 dh->rix_hrxq = hrxq_idx; 13847 dv->actions[n++] = hrxq->action; 13848 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13849 struct mlx5_hrxq *hrxq = NULL; 13850 uint32_t hrxq_idx; 13851 13852 hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev, 13853 rss_desc->shared_rss, 13854 dev_flow->hash_fields); 13855 if (hrxq_idx) 13856 hrxq = mlx5_ipool_get 13857 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 13858 hrxq_idx); 13859 if (!hrxq) { 13860 rte_flow_error_set 13861 (error, rte_errno, 13862 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13863 "cannot get hash queue"); 13864 goto error; 13865 } 13866 dh->rix_srss = rss_desc->shared_rss; 13867 dv->actions[n++] = hrxq->action; 13868 } else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) { 13869 if (!priv->sh->default_miss_action) { 13870 rte_flow_error_set 13871 (error, rte_errno, 13872 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13873 "default miss action not be created."); 13874 goto error; 13875 } 13876 dv->actions[n++] = priv->sh->default_miss_action; 13877 } 13878 misc_mask = flow_dv_matcher_enable(dv->value.buf); 13879 __flow_dv_adjust_buf_size(&dv->value.size, misc_mask); 13880 err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object, 13881 (void *)&dv->value, n, 13882 dv->actions, &dh->drv_flow); 13883 if (err) { 13884 rte_flow_error_set 13885 (error, errno, 13886 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 13887 NULL, 13888 (!priv->config.allow_duplicate_pattern && 13889 errno == EEXIST) ? 13890 "duplicating pattern is not allowed" : 13891 "hardware refuses to create flow"); 13892 goto error; 13893 } 13894 if (priv->vmwa_context && 13895 dh->vf_vlan.tag && !dh->vf_vlan.created) { 13896 /* 13897 * The rule contains the VLAN pattern. 13898 * For VF we are going to create VLAN 13899 * interface to make hypervisor set correct 13900 * e-Switch vport context. 13901 */ 13902 mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan); 13903 } 13904 } 13905 return 0; 13906 error: 13907 err = rte_errno; /* Save rte_errno before cleanup. */ 13908 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles, 13909 handle_idx, dh, next) { 13910 /* hrxq is union, don't clear it if the flag is not set. */ 13911 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) { 13912 mlx5_hrxq_release(dev, dh->rix_hrxq); 13913 dh->rix_hrxq = 0; 13914 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13915 dh->rix_srss = 0; 13916 } 13917 if (dh->vf_vlan.tag && dh->vf_vlan.created) 13918 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 13919 } 13920 rte_errno = err; /* Restore rte_errno. */ 13921 return -rte_errno; 13922 } 13923 13924 void 13925 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused, 13926 struct mlx5_list_entry *entry) 13927 { 13928 struct mlx5_flow_dv_matcher *resource = container_of(entry, 13929 typeof(*resource), 13930 entry); 13931 13932 claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object)); 13933 mlx5_free(resource); 13934 } 13935 13936 /** 13937 * Release the flow matcher. 13938 * 13939 * @param dev 13940 * Pointer to Ethernet device. 13941 * @param port_id 13942 * Index to port ID action resource. 13943 * 13944 * @return 13945 * 1 while a reference on it exists, 0 when freed. 13946 */ 13947 static int 13948 flow_dv_matcher_release(struct rte_eth_dev *dev, 13949 struct mlx5_flow_handle *handle) 13950 { 13951 struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher; 13952 struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl, 13953 typeof(*tbl), tbl); 13954 int ret; 13955 13956 MLX5_ASSERT(matcher->matcher_object); 13957 ret = mlx5_list_unregister(tbl->matchers, &matcher->entry); 13958 flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl); 13959 return ret; 13960 } 13961 13962 void 13963 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 13964 { 13965 struct mlx5_dev_ctx_shared *sh = tool_ctx; 13966 struct mlx5_flow_dv_encap_decap_resource *res = 13967 container_of(entry, typeof(*res), entry); 13968 13969 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 13970 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 13971 } 13972 13973 /** 13974 * Release an encap/decap resource. 13975 * 13976 * @param dev 13977 * Pointer to Ethernet device. 13978 * @param encap_decap_idx 13979 * Index of encap decap resource. 13980 * 13981 * @return 13982 * 1 while a reference on it exists, 0 when freed. 13983 */ 13984 static int 13985 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 13986 uint32_t encap_decap_idx) 13987 { 13988 struct mlx5_priv *priv = dev->data->dev_private; 13989 struct mlx5_flow_dv_encap_decap_resource *resource; 13990 13991 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 13992 encap_decap_idx); 13993 if (!resource) 13994 return 0; 13995 MLX5_ASSERT(resource->action); 13996 return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry); 13997 } 13998 13999 /** 14000 * Release an jump to table action resource. 14001 * 14002 * @param dev 14003 * Pointer to Ethernet device. 14004 * @param rix_jump 14005 * Index to the jump action resource. 14006 * 14007 * @return 14008 * 1 while a reference on it exists, 0 when freed. 14009 */ 14010 static int 14011 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 14012 uint32_t rix_jump) 14013 { 14014 struct mlx5_priv *priv = dev->data->dev_private; 14015 struct mlx5_flow_tbl_data_entry *tbl_data; 14016 14017 tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP], 14018 rix_jump); 14019 if (!tbl_data) 14020 return 0; 14021 return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl); 14022 } 14023 14024 void 14025 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14026 { 14027 struct mlx5_flow_dv_modify_hdr_resource *res = 14028 container_of(entry, typeof(*res), entry); 14029 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14030 14031 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 14032 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 14033 } 14034 14035 /** 14036 * Release a modify-header resource. 14037 * 14038 * @param dev 14039 * Pointer to Ethernet device. 14040 * @param handle 14041 * Pointer to mlx5_flow_handle. 14042 * 14043 * @return 14044 * 1 while a reference on it exists, 0 when freed. 14045 */ 14046 static int 14047 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev, 14048 struct mlx5_flow_handle *handle) 14049 { 14050 struct mlx5_priv *priv = dev->data->dev_private; 14051 struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr; 14052 14053 MLX5_ASSERT(entry->action); 14054 return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry); 14055 } 14056 14057 void 14058 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14059 { 14060 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14061 struct mlx5_flow_dv_port_id_action_resource *resource = 14062 container_of(entry, typeof(*resource), entry); 14063 14064 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14065 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 14066 } 14067 14068 /** 14069 * Release port ID action resource. 14070 * 14071 * @param dev 14072 * Pointer to Ethernet device. 14073 * @param handle 14074 * Pointer to mlx5_flow_handle. 14075 * 14076 * @return 14077 * 1 while a reference on it exists, 0 when freed. 14078 */ 14079 static int 14080 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 14081 uint32_t port_id) 14082 { 14083 struct mlx5_priv *priv = dev->data->dev_private; 14084 struct mlx5_flow_dv_port_id_action_resource *resource; 14085 14086 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id); 14087 if (!resource) 14088 return 0; 14089 MLX5_ASSERT(resource->action); 14090 return mlx5_list_unregister(priv->sh->port_id_action_list, 14091 &resource->entry); 14092 } 14093 14094 /** 14095 * Release shared RSS action resource. 14096 * 14097 * @param dev 14098 * Pointer to Ethernet device. 14099 * @param srss 14100 * Shared RSS action index. 14101 */ 14102 static void 14103 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss) 14104 { 14105 struct mlx5_priv *priv = dev->data->dev_private; 14106 struct mlx5_shared_action_rss *shared_rss; 14107 14108 shared_rss = mlx5_ipool_get 14109 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss); 14110 __atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14111 } 14112 14113 void 14114 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14115 { 14116 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14117 struct mlx5_flow_dv_push_vlan_action_resource *resource = 14118 container_of(entry, typeof(*resource), entry); 14119 14120 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14121 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 14122 } 14123 14124 /** 14125 * Release push vlan action resource. 14126 * 14127 * @param dev 14128 * Pointer to Ethernet device. 14129 * @param handle 14130 * Pointer to mlx5_flow_handle. 14131 * 14132 * @return 14133 * 1 while a reference on it exists, 0 when freed. 14134 */ 14135 static int 14136 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev, 14137 struct mlx5_flow_handle *handle) 14138 { 14139 struct mlx5_priv *priv = dev->data->dev_private; 14140 struct mlx5_flow_dv_push_vlan_action_resource *resource; 14141 uint32_t idx = handle->dvh.rix_push_vlan; 14142 14143 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 14144 if (!resource) 14145 return 0; 14146 MLX5_ASSERT(resource->action); 14147 return mlx5_list_unregister(priv->sh->push_vlan_action_list, 14148 &resource->entry); 14149 } 14150 14151 /** 14152 * Release the fate resource. 14153 * 14154 * @param dev 14155 * Pointer to Ethernet device. 14156 * @param handle 14157 * Pointer to mlx5_flow_handle. 14158 */ 14159 static void 14160 flow_dv_fate_resource_release(struct rte_eth_dev *dev, 14161 struct mlx5_flow_handle *handle) 14162 { 14163 if (!handle->rix_fate) 14164 return; 14165 switch (handle->fate_action) { 14166 case MLX5_FLOW_FATE_QUEUE: 14167 if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array) 14168 mlx5_hrxq_release(dev, handle->rix_hrxq); 14169 break; 14170 case MLX5_FLOW_FATE_JUMP: 14171 flow_dv_jump_tbl_resource_release(dev, handle->rix_jump); 14172 break; 14173 case MLX5_FLOW_FATE_PORT_ID: 14174 flow_dv_port_id_action_resource_release(dev, 14175 handle->rix_port_id_action); 14176 break; 14177 default: 14178 DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action); 14179 break; 14180 } 14181 handle->rix_fate = 0; 14182 } 14183 14184 void 14185 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused, 14186 struct mlx5_list_entry *entry) 14187 { 14188 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 14189 typeof(*resource), 14190 entry); 14191 struct rte_eth_dev *dev = resource->dev; 14192 struct mlx5_priv *priv = dev->data->dev_private; 14193 14194 if (resource->verbs_action) 14195 claim_zero(mlx5_flow_os_destroy_flow_action 14196 (resource->verbs_action)); 14197 if (resource->normal_path_tbl) 14198 flow_dv_tbl_resource_release(MLX5_SH(dev), 14199 resource->normal_path_tbl); 14200 flow_dv_sample_sub_actions_release(dev, &resource->sample_idx); 14201 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 14202 DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource); 14203 } 14204 14205 /** 14206 * Release an sample resource. 14207 * 14208 * @param dev 14209 * Pointer to Ethernet device. 14210 * @param handle 14211 * Pointer to mlx5_flow_handle. 14212 * 14213 * @return 14214 * 1 while a reference on it exists, 0 when freed. 14215 */ 14216 static int 14217 flow_dv_sample_resource_release(struct rte_eth_dev *dev, 14218 struct mlx5_flow_handle *handle) 14219 { 14220 struct mlx5_priv *priv = dev->data->dev_private; 14221 struct mlx5_flow_dv_sample_resource *resource; 14222 14223 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE], 14224 handle->dvh.rix_sample); 14225 if (!resource) 14226 return 0; 14227 MLX5_ASSERT(resource->verbs_action); 14228 return mlx5_list_unregister(priv->sh->sample_action_list, 14229 &resource->entry); 14230 } 14231 14232 void 14233 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused, 14234 struct mlx5_list_entry *entry) 14235 { 14236 struct mlx5_flow_dv_dest_array_resource *resource = 14237 container_of(entry, typeof(*resource), entry); 14238 struct rte_eth_dev *dev = resource->dev; 14239 struct mlx5_priv *priv = dev->data->dev_private; 14240 uint32_t i = 0; 14241 14242 MLX5_ASSERT(resource->action); 14243 if (resource->action) 14244 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14245 for (; i < resource->num_of_dest; i++) 14246 flow_dv_sample_sub_actions_release(dev, 14247 &resource->sample_idx[i]); 14248 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 14249 DRV_LOG(DEBUG, "destination array resource %p: removed", 14250 (void *)resource); 14251 } 14252 14253 /** 14254 * Release an destination array resource. 14255 * 14256 * @param dev 14257 * Pointer to Ethernet device. 14258 * @param handle 14259 * Pointer to mlx5_flow_handle. 14260 * 14261 * @return 14262 * 1 while a reference on it exists, 0 when freed. 14263 */ 14264 static int 14265 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev, 14266 struct mlx5_flow_handle *handle) 14267 { 14268 struct mlx5_priv *priv = dev->data->dev_private; 14269 struct mlx5_flow_dv_dest_array_resource *resource; 14270 14271 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], 14272 handle->dvh.rix_dest_array); 14273 if (!resource) 14274 return 0; 14275 MLX5_ASSERT(resource->action); 14276 return mlx5_list_unregister(priv->sh->dest_array_list, 14277 &resource->entry); 14278 } 14279 14280 static void 14281 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev) 14282 { 14283 struct mlx5_priv *priv = dev->data->dev_private; 14284 struct mlx5_dev_ctx_shared *sh = priv->sh; 14285 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 14286 sh->geneve_tlv_option_resource; 14287 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 14288 if (geneve_opt_resource) { 14289 if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1, 14290 __ATOMIC_RELAXED))) { 14291 claim_zero(mlx5_devx_cmd_destroy 14292 (geneve_opt_resource->obj)); 14293 mlx5_free(sh->geneve_tlv_option_resource); 14294 sh->geneve_tlv_option_resource = NULL; 14295 } 14296 } 14297 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 14298 } 14299 14300 /** 14301 * Remove the flow from the NIC but keeps it in memory. 14302 * Lock free, (mutex should be acquired by caller). 14303 * 14304 * @param[in] dev 14305 * Pointer to Ethernet device. 14306 * @param[in, out] flow 14307 * Pointer to flow structure. 14308 */ 14309 static void 14310 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow) 14311 { 14312 struct mlx5_flow_handle *dh; 14313 uint32_t handle_idx; 14314 struct mlx5_priv *priv = dev->data->dev_private; 14315 14316 if (!flow) 14317 return; 14318 handle_idx = flow->dev_handles; 14319 while (handle_idx) { 14320 dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14321 handle_idx); 14322 if (!dh) 14323 return; 14324 if (dh->drv_flow) { 14325 claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow)); 14326 dh->drv_flow = NULL; 14327 } 14328 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) 14329 flow_dv_fate_resource_release(dev, dh); 14330 if (dh->vf_vlan.tag && dh->vf_vlan.created) 14331 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 14332 handle_idx = dh->next.next; 14333 } 14334 } 14335 14336 /** 14337 * Remove the flow from the NIC and the memory. 14338 * Lock free, (mutex should be acquired by caller). 14339 * 14340 * @param[in] dev 14341 * Pointer to the Ethernet device structure. 14342 * @param[in, out] flow 14343 * Pointer to flow structure. 14344 */ 14345 static void 14346 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) 14347 { 14348 struct mlx5_flow_handle *dev_handle; 14349 struct mlx5_priv *priv = dev->data->dev_private; 14350 struct mlx5_flow_meter_info *fm = NULL; 14351 uint32_t srss = 0; 14352 14353 if (!flow) 14354 return; 14355 flow_dv_remove(dev, flow); 14356 if (flow->counter) { 14357 flow_dv_counter_free(dev, flow->counter); 14358 flow->counter = 0; 14359 } 14360 if (flow->meter) { 14361 fm = flow_dv_meter_find_by_idx(priv, flow->meter); 14362 if (fm) 14363 mlx5_flow_meter_detach(priv, fm); 14364 flow->meter = 0; 14365 } 14366 /* Keep the current age handling by default. */ 14367 if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct) 14368 flow_dv_aso_ct_release(dev, flow->ct); 14369 else if (flow->age) 14370 flow_dv_aso_age_release(dev, flow->age); 14371 if (flow->geneve_tlv_option) { 14372 flow_dv_geneve_tlv_option_resource_release(dev); 14373 flow->geneve_tlv_option = 0; 14374 } 14375 while (flow->dev_handles) { 14376 uint32_t tmp_idx = flow->dev_handles; 14377 14378 dev_handle = mlx5_ipool_get(priv->sh->ipool 14379 [MLX5_IPOOL_MLX5_FLOW], tmp_idx); 14380 if (!dev_handle) 14381 return; 14382 flow->dev_handles = dev_handle->next.next; 14383 if (dev_handle->dvh.matcher) 14384 flow_dv_matcher_release(dev, dev_handle); 14385 if (dev_handle->dvh.rix_sample) 14386 flow_dv_sample_resource_release(dev, dev_handle); 14387 if (dev_handle->dvh.rix_dest_array) 14388 flow_dv_dest_array_resource_release(dev, dev_handle); 14389 if (dev_handle->dvh.rix_encap_decap) 14390 flow_dv_encap_decap_resource_release(dev, 14391 dev_handle->dvh.rix_encap_decap); 14392 if (dev_handle->dvh.modify_hdr) 14393 flow_dv_modify_hdr_resource_release(dev, dev_handle); 14394 if (dev_handle->dvh.rix_push_vlan) 14395 flow_dv_push_vlan_action_resource_release(dev, 14396 dev_handle); 14397 if (dev_handle->dvh.rix_tag) 14398 flow_dv_tag_release(dev, 14399 dev_handle->dvh.rix_tag); 14400 if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS) 14401 flow_dv_fate_resource_release(dev, dev_handle); 14402 else if (!srss) 14403 srss = dev_handle->rix_srss; 14404 if (fm && dev_handle->is_meter_flow_id && 14405 dev_handle->split_flow_id) 14406 mlx5_ipool_free(fm->flow_ipool, 14407 dev_handle->split_flow_id); 14408 else if (dev_handle->split_flow_id && 14409 !dev_handle->is_meter_flow_id) 14410 mlx5_ipool_free(priv->sh->ipool 14411 [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], 14412 dev_handle->split_flow_id); 14413 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14414 tmp_idx); 14415 } 14416 if (srss) 14417 flow_dv_shared_rss_action_release(dev, srss); 14418 } 14419 14420 /** 14421 * Release array of hash RX queue objects. 14422 * Helper function. 14423 * 14424 * @param[in] dev 14425 * Pointer to the Ethernet device structure. 14426 * @param[in, out] hrxqs 14427 * Array of hash RX queue objects. 14428 * 14429 * @return 14430 * Total number of references to hash RX queue objects in *hrxqs* array 14431 * after this operation. 14432 */ 14433 static int 14434 __flow_dv_hrxqs_release(struct rte_eth_dev *dev, 14435 uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN]) 14436 { 14437 size_t i; 14438 int remaining = 0; 14439 14440 for (i = 0; i < RTE_DIM(*hrxqs); i++) { 14441 int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]); 14442 14443 if (!ret) 14444 (*hrxqs)[i] = 0; 14445 remaining += ret; 14446 } 14447 return remaining; 14448 } 14449 14450 /** 14451 * Release all hash RX queue objects representing shared RSS action. 14452 * 14453 * @param[in] dev 14454 * Pointer to the Ethernet device structure. 14455 * @param[in, out] action 14456 * Shared RSS action to remove hash RX queue objects from. 14457 * 14458 * @return 14459 * Total number of references to hash RX queue objects stored in *action* 14460 * after this operation. 14461 * Expected to be 0 if no external references held. 14462 */ 14463 static int 14464 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev, 14465 struct mlx5_shared_action_rss *shared_rss) 14466 { 14467 return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq); 14468 } 14469 14470 /** 14471 * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to 14472 * user input. 14473 * 14474 * Only one hash value is available for one L3+L4 combination: 14475 * for example: 14476 * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and 14477 * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share 14478 * same slot in mlx5_rss_hash_fields. 14479 * 14480 * @param[in] rss 14481 * Pointer to the shared action RSS conf. 14482 * @param[in, out] hash_field 14483 * hash_field variable needed to be adjusted. 14484 * 14485 * @return 14486 * void 14487 */ 14488 static void 14489 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss, 14490 uint64_t *hash_field) 14491 { 14492 uint64_t rss_types = rss->origin.types; 14493 14494 switch (*hash_field & ~IBV_RX_HASH_INNER) { 14495 case MLX5_RSS_HASH_IPV4: 14496 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 14497 *hash_field &= ~MLX5_RSS_HASH_IPV4; 14498 if (rss_types & ETH_RSS_L3_DST_ONLY) 14499 *hash_field |= IBV_RX_HASH_DST_IPV4; 14500 else if (rss_types & ETH_RSS_L3_SRC_ONLY) 14501 *hash_field |= IBV_RX_HASH_SRC_IPV4; 14502 else 14503 *hash_field |= MLX5_RSS_HASH_IPV4; 14504 } 14505 return; 14506 case MLX5_RSS_HASH_IPV6: 14507 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 14508 *hash_field &= ~MLX5_RSS_HASH_IPV6; 14509 if (rss_types & ETH_RSS_L3_DST_ONLY) 14510 *hash_field |= IBV_RX_HASH_DST_IPV6; 14511 else if (rss_types & ETH_RSS_L3_SRC_ONLY) 14512 *hash_field |= IBV_RX_HASH_SRC_IPV6; 14513 else 14514 *hash_field |= MLX5_RSS_HASH_IPV6; 14515 } 14516 return; 14517 case MLX5_RSS_HASH_IPV4_UDP: 14518 /* fall-through. */ 14519 case MLX5_RSS_HASH_IPV6_UDP: 14520 if (rss_types & ETH_RSS_UDP) { 14521 *hash_field &= ~MLX5_UDP_IBV_RX_HASH; 14522 if (rss_types & ETH_RSS_L4_DST_ONLY) 14523 *hash_field |= IBV_RX_HASH_DST_PORT_UDP; 14524 else if (rss_types & ETH_RSS_L4_SRC_ONLY) 14525 *hash_field |= IBV_RX_HASH_SRC_PORT_UDP; 14526 else 14527 *hash_field |= MLX5_UDP_IBV_RX_HASH; 14528 } 14529 return; 14530 case MLX5_RSS_HASH_IPV4_TCP: 14531 /* fall-through. */ 14532 case MLX5_RSS_HASH_IPV6_TCP: 14533 if (rss_types & ETH_RSS_TCP) { 14534 *hash_field &= ~MLX5_TCP_IBV_RX_HASH; 14535 if (rss_types & ETH_RSS_L4_DST_ONLY) 14536 *hash_field |= IBV_RX_HASH_DST_PORT_TCP; 14537 else if (rss_types & ETH_RSS_L4_SRC_ONLY) 14538 *hash_field |= IBV_RX_HASH_SRC_PORT_TCP; 14539 else 14540 *hash_field |= MLX5_TCP_IBV_RX_HASH; 14541 } 14542 return; 14543 default: 14544 return; 14545 } 14546 } 14547 14548 /** 14549 * Setup shared RSS action. 14550 * Prepare set of hash RX queue objects sufficient to handle all valid 14551 * hash_fields combinations (see enum ibv_rx_hash_fields). 14552 * 14553 * @param[in] dev 14554 * Pointer to the Ethernet device structure. 14555 * @param[in] action_idx 14556 * Shared RSS action ipool index. 14557 * @param[in, out] action 14558 * Partially initialized shared RSS action. 14559 * @param[out] error 14560 * Perform verbose error reporting if not NULL. Initialized in case of 14561 * error only. 14562 * 14563 * @return 14564 * 0 on success, otherwise negative errno value. 14565 */ 14566 static int 14567 __flow_dv_action_rss_setup(struct rte_eth_dev *dev, 14568 uint32_t action_idx, 14569 struct mlx5_shared_action_rss *shared_rss, 14570 struct rte_flow_error *error) 14571 { 14572 struct mlx5_flow_rss_desc rss_desc = { 0 }; 14573 size_t i; 14574 int err; 14575 14576 if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) { 14577 return rte_flow_error_set(error, rte_errno, 14578 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14579 "cannot setup indirection table"); 14580 } 14581 memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN); 14582 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN; 14583 rss_desc.const_q = shared_rss->origin.queue; 14584 rss_desc.queue_num = shared_rss->origin.queue_num; 14585 /* Set non-zero value to indicate a shared RSS. */ 14586 rss_desc.shared_rss = action_idx; 14587 rss_desc.ind_tbl = shared_rss->ind_tbl; 14588 for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) { 14589 uint32_t hrxq_idx; 14590 uint64_t hash_fields = mlx5_rss_hash_fields[i]; 14591 int tunnel = 0; 14592 14593 __flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields); 14594 if (shared_rss->origin.level > 1) { 14595 hash_fields |= IBV_RX_HASH_INNER; 14596 tunnel = 1; 14597 } 14598 rss_desc.tunnel = tunnel; 14599 rss_desc.hash_fields = hash_fields; 14600 hrxq_idx = mlx5_hrxq_get(dev, &rss_desc); 14601 if (!hrxq_idx) { 14602 rte_flow_error_set 14603 (error, rte_errno, 14604 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14605 "cannot get hash queue"); 14606 goto error_hrxq_new; 14607 } 14608 err = __flow_dv_action_rss_hrxq_set 14609 (shared_rss, hash_fields, hrxq_idx); 14610 MLX5_ASSERT(!err); 14611 } 14612 return 0; 14613 error_hrxq_new: 14614 err = rte_errno; 14615 __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14616 if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true)) 14617 shared_rss->ind_tbl = NULL; 14618 rte_errno = err; 14619 return -rte_errno; 14620 } 14621 14622 /** 14623 * Create shared RSS action. 14624 * 14625 * @param[in] dev 14626 * Pointer to the Ethernet device structure. 14627 * @param[in] conf 14628 * Shared action configuration. 14629 * @param[in] rss 14630 * RSS action specification used to create shared action. 14631 * @param[out] error 14632 * Perform verbose error reporting if not NULL. Initialized in case of 14633 * error only. 14634 * 14635 * @return 14636 * A valid shared action ID in case of success, 0 otherwise and 14637 * rte_errno is set. 14638 */ 14639 static uint32_t 14640 __flow_dv_action_rss_create(struct rte_eth_dev *dev, 14641 const struct rte_flow_indir_action_conf *conf, 14642 const struct rte_flow_action_rss *rss, 14643 struct rte_flow_error *error) 14644 { 14645 struct mlx5_priv *priv = dev->data->dev_private; 14646 struct mlx5_shared_action_rss *shared_rss = NULL; 14647 void *queue = NULL; 14648 struct rte_flow_action_rss *origin; 14649 const uint8_t *rss_key; 14650 uint32_t queue_size = rss->queue_num * sizeof(uint16_t); 14651 uint32_t idx; 14652 14653 RTE_SET_USED(conf); 14654 queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 14655 0, SOCKET_ID_ANY); 14656 shared_rss = mlx5_ipool_zmalloc 14657 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx); 14658 if (!shared_rss || !queue) { 14659 rte_flow_error_set(error, ENOMEM, 14660 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14661 "cannot allocate resource memory"); 14662 goto error_rss_init; 14663 } 14664 if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) { 14665 rte_flow_error_set(error, E2BIG, 14666 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14667 "rss action number out of range"); 14668 goto error_rss_init; 14669 } 14670 shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO, 14671 sizeof(*shared_rss->ind_tbl), 14672 0, SOCKET_ID_ANY); 14673 if (!shared_rss->ind_tbl) { 14674 rte_flow_error_set(error, ENOMEM, 14675 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14676 "cannot allocate resource memory"); 14677 goto error_rss_init; 14678 } 14679 memcpy(queue, rss->queue, queue_size); 14680 shared_rss->ind_tbl->queues = queue; 14681 shared_rss->ind_tbl->queues_n = rss->queue_num; 14682 origin = &shared_rss->origin; 14683 origin->func = rss->func; 14684 origin->level = rss->level; 14685 /* RSS type 0 indicates default RSS type (ETH_RSS_IP). */ 14686 origin->types = !rss->types ? ETH_RSS_IP : rss->types; 14687 /* NULL RSS key indicates default RSS key. */ 14688 rss_key = !rss->key ? rss_hash_default_key : rss->key; 14689 memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 14690 origin->key = &shared_rss->key[0]; 14691 origin->key_len = MLX5_RSS_HASH_KEY_LEN; 14692 origin->queue = queue; 14693 origin->queue_num = rss->queue_num; 14694 if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error)) 14695 goto error_rss_init; 14696 rte_spinlock_init(&shared_rss->action_rss_sl); 14697 __atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14698 rte_spinlock_lock(&priv->shared_act_sl); 14699 ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14700 &priv->rss_shared_actions, idx, shared_rss, next); 14701 rte_spinlock_unlock(&priv->shared_act_sl); 14702 return idx; 14703 error_rss_init: 14704 if (shared_rss) { 14705 if (shared_rss->ind_tbl) 14706 mlx5_free(shared_rss->ind_tbl); 14707 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14708 idx); 14709 } 14710 if (queue) 14711 mlx5_free(queue); 14712 return 0; 14713 } 14714 14715 /** 14716 * Destroy the shared RSS action. 14717 * Release related hash RX queue objects. 14718 * 14719 * @param[in] dev 14720 * Pointer to the Ethernet device structure. 14721 * @param[in] idx 14722 * The shared RSS action object ID to be removed. 14723 * @param[out] error 14724 * Perform verbose error reporting if not NULL. Initialized in case of 14725 * error only. 14726 * 14727 * @return 14728 * 0 on success, otherwise negative errno value. 14729 */ 14730 static int 14731 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, 14732 struct rte_flow_error *error) 14733 { 14734 struct mlx5_priv *priv = dev->data->dev_private; 14735 struct mlx5_shared_action_rss *shared_rss = 14736 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14737 uint32_t old_refcnt = 1; 14738 int remaining; 14739 uint16_t *queue = NULL; 14740 14741 if (!shared_rss) 14742 return rte_flow_error_set(error, EINVAL, 14743 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14744 "invalid shared action"); 14745 remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14746 if (remaining) 14747 return rte_flow_error_set(error, EBUSY, 14748 RTE_FLOW_ERROR_TYPE_ACTION, 14749 NULL, 14750 "shared rss hrxq has references"); 14751 if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt, 14752 0, 0, __ATOMIC_ACQUIRE, 14753 __ATOMIC_RELAXED)) 14754 return rte_flow_error_set(error, EBUSY, 14755 RTE_FLOW_ERROR_TYPE_ACTION, 14756 NULL, 14757 "shared rss has references"); 14758 queue = shared_rss->ind_tbl->queues; 14759 remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true); 14760 if (remaining) 14761 return rte_flow_error_set(error, EBUSY, 14762 RTE_FLOW_ERROR_TYPE_ACTION, 14763 NULL, 14764 "shared rss indirection table has" 14765 " references"); 14766 mlx5_free(queue); 14767 rte_spinlock_lock(&priv->shared_act_sl); 14768 ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14769 &priv->rss_shared_actions, idx, shared_rss, next); 14770 rte_spinlock_unlock(&priv->shared_act_sl); 14771 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14772 idx); 14773 return 0; 14774 } 14775 14776 /** 14777 * Create indirect action, lock free, 14778 * (mutex should be acquired by caller). 14779 * Dispatcher for action type specific call. 14780 * 14781 * @param[in] dev 14782 * Pointer to the Ethernet device structure. 14783 * @param[in] conf 14784 * Shared action configuration. 14785 * @param[in] action 14786 * Action specification used to create indirect action. 14787 * @param[out] error 14788 * Perform verbose error reporting if not NULL. Initialized in case of 14789 * error only. 14790 * 14791 * @return 14792 * A valid shared action handle in case of success, NULL otherwise and 14793 * rte_errno is set. 14794 */ 14795 static struct rte_flow_action_handle * 14796 flow_dv_action_create(struct rte_eth_dev *dev, 14797 const struct rte_flow_indir_action_conf *conf, 14798 const struct rte_flow_action *action, 14799 struct rte_flow_error *err) 14800 { 14801 struct mlx5_priv *priv = dev->data->dev_private; 14802 uint32_t age_idx = 0; 14803 uint32_t idx = 0; 14804 uint32_t ret = 0; 14805 14806 switch (action->type) { 14807 case RTE_FLOW_ACTION_TYPE_RSS: 14808 ret = __flow_dv_action_rss_create(dev, conf, action->conf, err); 14809 idx = (MLX5_INDIRECT_ACTION_TYPE_RSS << 14810 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14811 break; 14812 case RTE_FLOW_ACTION_TYPE_AGE: 14813 age_idx = flow_dv_aso_age_alloc(dev, err); 14814 if (!age_idx) { 14815 ret = -rte_errno; 14816 break; 14817 } 14818 idx = (MLX5_INDIRECT_ACTION_TYPE_AGE << 14819 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx; 14820 flow_dv_aso_age_params_init(dev, age_idx, 14821 ((const struct rte_flow_action_age *) 14822 action->conf)->context ? 14823 ((const struct rte_flow_action_age *) 14824 action->conf)->context : 14825 (void *)(uintptr_t)idx, 14826 ((const struct rte_flow_action_age *) 14827 action->conf)->timeout); 14828 ret = age_idx; 14829 break; 14830 case RTE_FLOW_ACTION_TYPE_COUNT: 14831 ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL); 14832 idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT << 14833 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14834 break; 14835 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 14836 ret = flow_dv_translate_create_conntrack(dev, action->conf, 14837 err); 14838 idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret); 14839 break; 14840 default: 14841 rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, 14842 NULL, "action type not supported"); 14843 break; 14844 } 14845 return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL; 14846 } 14847 14848 /** 14849 * Destroy the indirect action. 14850 * Release action related resources on the NIC and the memory. 14851 * Lock free, (mutex should be acquired by caller). 14852 * Dispatcher for action type specific call. 14853 * 14854 * @param[in] dev 14855 * Pointer to the Ethernet device structure. 14856 * @param[in] handle 14857 * The indirect action object handle to be removed. 14858 * @param[out] error 14859 * Perform verbose error reporting if not NULL. Initialized in case of 14860 * error only. 14861 * 14862 * @return 14863 * 0 on success, otherwise negative errno value. 14864 */ 14865 static int 14866 flow_dv_action_destroy(struct rte_eth_dev *dev, 14867 struct rte_flow_action_handle *handle, 14868 struct rte_flow_error *error) 14869 { 14870 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 14871 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 14872 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 14873 struct mlx5_flow_counter *cnt; 14874 uint32_t no_flow_refcnt = 1; 14875 int ret; 14876 14877 switch (type) { 14878 case MLX5_INDIRECT_ACTION_TYPE_RSS: 14879 return __flow_dv_action_rss_release(dev, idx, error); 14880 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 14881 cnt = flow_dv_counter_get_by_idx(dev, idx, NULL); 14882 if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt, 14883 &no_flow_refcnt, 1, false, 14884 __ATOMIC_ACQUIRE, 14885 __ATOMIC_RELAXED)) 14886 return rte_flow_error_set(error, EBUSY, 14887 RTE_FLOW_ERROR_TYPE_ACTION, 14888 NULL, 14889 "Indirect count action has references"); 14890 flow_dv_counter_free(dev, idx); 14891 return 0; 14892 case MLX5_INDIRECT_ACTION_TYPE_AGE: 14893 ret = flow_dv_aso_age_release(dev, idx); 14894 if (ret) 14895 /* 14896 * In this case, the last flow has a reference will 14897 * actually release the age action. 14898 */ 14899 DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was" 14900 " released with references %d.", idx, ret); 14901 return 0; 14902 case MLX5_INDIRECT_ACTION_TYPE_CT: 14903 ret = flow_dv_aso_ct_release(dev, idx); 14904 if (ret < 0) 14905 return ret; 14906 if (ret > 0) 14907 DRV_LOG(DEBUG, "Connection tracking object %u still " 14908 "has references %d.", idx, ret); 14909 return 0; 14910 default: 14911 return rte_flow_error_set(error, ENOTSUP, 14912 RTE_FLOW_ERROR_TYPE_ACTION, 14913 NULL, 14914 "action type not supported"); 14915 } 14916 } 14917 14918 /** 14919 * Updates in place shared RSS action configuration. 14920 * 14921 * @param[in] dev 14922 * Pointer to the Ethernet device structure. 14923 * @param[in] idx 14924 * The shared RSS action object ID to be updated. 14925 * @param[in] action_conf 14926 * RSS action specification used to modify *shared_rss*. 14927 * @param[out] error 14928 * Perform verbose error reporting if not NULL. Initialized in case of 14929 * error only. 14930 * 14931 * @return 14932 * 0 on success, otherwise negative errno value. 14933 * @note: currently only support update of RSS queues. 14934 */ 14935 static int 14936 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx, 14937 const struct rte_flow_action_rss *action_conf, 14938 struct rte_flow_error *error) 14939 { 14940 struct mlx5_priv *priv = dev->data->dev_private; 14941 struct mlx5_shared_action_rss *shared_rss = 14942 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14943 int ret = 0; 14944 void *queue = NULL; 14945 uint16_t *queue_old = NULL; 14946 uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t); 14947 14948 if (!shared_rss) 14949 return rte_flow_error_set(error, EINVAL, 14950 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14951 "invalid shared action to update"); 14952 if (priv->obj_ops.ind_table_modify == NULL) 14953 return rte_flow_error_set(error, ENOTSUP, 14954 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14955 "cannot modify indirection table"); 14956 queue = mlx5_malloc(MLX5_MEM_ZERO, 14957 RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 14958 0, SOCKET_ID_ANY); 14959 if (!queue) 14960 return rte_flow_error_set(error, ENOMEM, 14961 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14962 NULL, 14963 "cannot allocate resource memory"); 14964 memcpy(queue, action_conf->queue, queue_size); 14965 MLX5_ASSERT(shared_rss->ind_tbl); 14966 rte_spinlock_lock(&shared_rss->action_rss_sl); 14967 queue_old = shared_rss->ind_tbl->queues; 14968 ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl, 14969 queue, action_conf->queue_num, true); 14970 if (ret) { 14971 mlx5_free(queue); 14972 ret = rte_flow_error_set(error, rte_errno, 14973 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14974 "cannot update indirection table"); 14975 } else { 14976 mlx5_free(queue_old); 14977 shared_rss->origin.queue = queue; 14978 shared_rss->origin.queue_num = action_conf->queue_num; 14979 } 14980 rte_spinlock_unlock(&shared_rss->action_rss_sl); 14981 return ret; 14982 } 14983 14984 /* 14985 * Updates in place conntrack context or direction. 14986 * Context update should be synchronized. 14987 * 14988 * @param[in] dev 14989 * Pointer to the Ethernet device structure. 14990 * @param[in] idx 14991 * The conntrack object ID to be updated. 14992 * @param[in] update 14993 * Pointer to the structure of information to update. 14994 * @param[out] error 14995 * Perform verbose error reporting if not NULL. Initialized in case of 14996 * error only. 14997 * 14998 * @return 14999 * 0 on success, otherwise negative errno value. 15000 */ 15001 static int 15002 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, 15003 const struct rte_flow_modify_conntrack *update, 15004 struct rte_flow_error *error) 15005 { 15006 struct mlx5_priv *priv = dev->data->dev_private; 15007 struct mlx5_aso_ct_action *ct; 15008 const struct rte_flow_action_conntrack *new_prf; 15009 int ret = 0; 15010 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15011 uint32_t dev_idx; 15012 15013 if (PORT_ID(priv) != owner) 15014 return rte_flow_error_set(error, EACCES, 15015 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15016 NULL, 15017 "CT object owned by another port"); 15018 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15019 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15020 if (!ct->refcnt) 15021 return rte_flow_error_set(error, ENOMEM, 15022 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15023 NULL, 15024 "CT object is inactive"); 15025 new_prf = &update->new_ct; 15026 if (update->direction) 15027 ct->is_original = !!new_prf->is_original_dir; 15028 if (update->state) { 15029 /* Only validate the profile when it needs to be updated. */ 15030 ret = mlx5_validate_action_ct(dev, new_prf, error); 15031 if (ret) 15032 return ret; 15033 ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf); 15034 if (ret) 15035 return rte_flow_error_set(error, EIO, 15036 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15037 NULL, 15038 "Failed to send CT context update WQE"); 15039 /* Block until ready or a failure. */ 15040 ret = mlx5_aso_ct_available(priv->sh, ct); 15041 if (ret) 15042 rte_flow_error_set(error, rte_errno, 15043 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15044 NULL, 15045 "Timeout to get the CT update"); 15046 } 15047 return ret; 15048 } 15049 15050 /** 15051 * Updates in place shared action configuration, lock free, 15052 * (mutex should be acquired by caller). 15053 * 15054 * @param[in] dev 15055 * Pointer to the Ethernet device structure. 15056 * @param[in] handle 15057 * The indirect action object handle to be updated. 15058 * @param[in] update 15059 * Action specification used to modify the action pointed by *handle*. 15060 * *update* could be of same type with the action pointed by the *handle* 15061 * handle argument, or some other structures like a wrapper, depending on 15062 * the indirect action type. 15063 * @param[out] error 15064 * Perform verbose error reporting if not NULL. Initialized in case of 15065 * error only. 15066 * 15067 * @return 15068 * 0 on success, otherwise negative errno value. 15069 */ 15070 static int 15071 flow_dv_action_update(struct rte_eth_dev *dev, 15072 struct rte_flow_action_handle *handle, 15073 const void *update, 15074 struct rte_flow_error *err) 15075 { 15076 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15077 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15078 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15079 const void *action_conf; 15080 15081 switch (type) { 15082 case MLX5_INDIRECT_ACTION_TYPE_RSS: 15083 action_conf = ((const struct rte_flow_action *)update)->conf; 15084 return __flow_dv_action_rss_update(dev, idx, action_conf, err); 15085 case MLX5_INDIRECT_ACTION_TYPE_CT: 15086 return __flow_dv_action_ct_update(dev, idx, update, err); 15087 default: 15088 return rte_flow_error_set(err, ENOTSUP, 15089 RTE_FLOW_ERROR_TYPE_ACTION, 15090 NULL, 15091 "action type update not supported"); 15092 } 15093 } 15094 15095 /** 15096 * Destroy the meter sub policy table rules. 15097 * Lock free, (mutex should be acquired by caller). 15098 * 15099 * @param[in] dev 15100 * Pointer to Ethernet device. 15101 * @param[in] sub_policy 15102 * Pointer to meter sub policy table. 15103 */ 15104 static void 15105 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, 15106 struct mlx5_flow_meter_sub_policy *sub_policy) 15107 { 15108 struct mlx5_priv *priv = dev->data->dev_private; 15109 struct mlx5_flow_tbl_data_entry *tbl; 15110 struct mlx5_flow_meter_policy *policy = sub_policy->main_policy; 15111 struct mlx5_flow_meter_info *next_fm; 15112 struct mlx5_sub_policy_color_rule *color_rule; 15113 void *tmp; 15114 uint32_t i; 15115 15116 for (i = 0; i < RTE_COLORS; i++) { 15117 next_fm = NULL; 15118 if (i == RTE_COLOR_GREEN && policy && 15119 policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) 15120 next_fm = mlx5_flow_meter_find(priv, 15121 policy->act_cnt[i].next_mtr_id, NULL); 15122 TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], 15123 next_port, tmp) { 15124 claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule)); 15125 tbl = container_of(color_rule->matcher->tbl, 15126 typeof(*tbl), tbl); 15127 mlx5_list_unregister(tbl->matchers, 15128 &color_rule->matcher->entry); 15129 TAILQ_REMOVE(&sub_policy->color_rules[i], 15130 color_rule, next_port); 15131 mlx5_free(color_rule); 15132 if (next_fm) 15133 mlx5_flow_meter_detach(priv, next_fm); 15134 } 15135 } 15136 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15137 if (sub_policy->rix_hrxq[i]) { 15138 if (policy && !policy->is_hierarchy) 15139 mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]); 15140 sub_policy->rix_hrxq[i] = 0; 15141 } 15142 if (sub_policy->jump_tbl[i]) { 15143 flow_dv_tbl_resource_release(MLX5_SH(dev), 15144 sub_policy->jump_tbl[i]); 15145 sub_policy->jump_tbl[i] = NULL; 15146 } 15147 } 15148 if (sub_policy->tbl_rsc) { 15149 flow_dv_tbl_resource_release(MLX5_SH(dev), 15150 sub_policy->tbl_rsc); 15151 sub_policy->tbl_rsc = NULL; 15152 } 15153 } 15154 15155 /** 15156 * Destroy policy rules, lock free, 15157 * (mutex should be acquired by caller). 15158 * Dispatcher for action type specific call. 15159 * 15160 * @param[in] dev 15161 * Pointer to the Ethernet device structure. 15162 * @param[in] mtr_policy 15163 * Meter policy struct. 15164 */ 15165 static void 15166 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, 15167 struct mlx5_flow_meter_policy *mtr_policy) 15168 { 15169 uint32_t i, j; 15170 struct mlx5_flow_meter_sub_policy *sub_policy; 15171 uint16_t sub_policy_num; 15172 15173 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15174 sub_policy_num = (mtr_policy->sub_policy_num >> 15175 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15176 MLX5_MTR_SUB_POLICY_NUM_MASK; 15177 for (j = 0; j < sub_policy_num; j++) { 15178 sub_policy = mtr_policy->sub_policys[i][j]; 15179 if (sub_policy) 15180 __flow_dv_destroy_sub_policy_rules(dev, 15181 sub_policy); 15182 } 15183 } 15184 } 15185 15186 /** 15187 * Destroy policy action, lock free, 15188 * (mutex should be acquired by caller). 15189 * Dispatcher for action type specific call. 15190 * 15191 * @param[in] dev 15192 * Pointer to the Ethernet device structure. 15193 * @param[in] mtr_policy 15194 * Meter policy struct. 15195 */ 15196 static void 15197 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev, 15198 struct mlx5_flow_meter_policy *mtr_policy) 15199 { 15200 struct rte_flow_action *rss_action; 15201 struct mlx5_flow_handle dev_handle; 15202 uint32_t i, j; 15203 15204 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15205 if (mtr_policy->act_cnt[i].rix_mark) { 15206 flow_dv_tag_release(dev, 15207 mtr_policy->act_cnt[i].rix_mark); 15208 mtr_policy->act_cnt[i].rix_mark = 0; 15209 } 15210 if (mtr_policy->act_cnt[i].modify_hdr) { 15211 dev_handle.dvh.modify_hdr = 15212 mtr_policy->act_cnt[i].modify_hdr; 15213 flow_dv_modify_hdr_resource_release(dev, &dev_handle); 15214 } 15215 switch (mtr_policy->act_cnt[i].fate_action) { 15216 case MLX5_FLOW_FATE_SHARED_RSS: 15217 rss_action = mtr_policy->act_cnt[i].rss; 15218 mlx5_free(rss_action); 15219 break; 15220 case MLX5_FLOW_FATE_PORT_ID: 15221 if (mtr_policy->act_cnt[i].rix_port_id_action) { 15222 flow_dv_port_id_action_resource_release(dev, 15223 mtr_policy->act_cnt[i].rix_port_id_action); 15224 mtr_policy->act_cnt[i].rix_port_id_action = 0; 15225 } 15226 break; 15227 case MLX5_FLOW_FATE_DROP: 15228 case MLX5_FLOW_FATE_JUMP: 15229 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15230 mtr_policy->act_cnt[i].dr_jump_action[j] = 15231 NULL; 15232 break; 15233 default: 15234 /*Queue action do nothing*/ 15235 break; 15236 } 15237 } 15238 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15239 mtr_policy->dr_drop_action[j] = NULL; 15240 } 15241 15242 /** 15243 * Create policy action per domain, lock free, 15244 * (mutex should be acquired by caller). 15245 * Dispatcher for action type specific call. 15246 * 15247 * @param[in] dev 15248 * Pointer to the Ethernet device structure. 15249 * @param[in] mtr_policy 15250 * Meter policy struct. 15251 * @param[in] action 15252 * Action specification used to create meter actions. 15253 * @param[out] error 15254 * Perform verbose error reporting if not NULL. Initialized in case of 15255 * error only. 15256 * 15257 * @return 15258 * 0 on success, otherwise negative errno value. 15259 */ 15260 static int 15261 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, 15262 struct mlx5_flow_meter_policy *mtr_policy, 15263 const struct rte_flow_action *actions[RTE_COLORS], 15264 enum mlx5_meter_domain domain, 15265 struct rte_mtr_error *error) 15266 { 15267 struct mlx5_priv *priv = dev->data->dev_private; 15268 struct rte_flow_error flow_err; 15269 const struct rte_flow_action *act; 15270 uint64_t action_flags; 15271 struct mlx5_flow_handle dh; 15272 struct mlx5_flow dev_flow; 15273 struct mlx5_flow_dv_port_id_action_resource port_id_action; 15274 int i, ret; 15275 uint8_t egress, transfer; 15276 struct mlx5_meter_policy_action_container *act_cnt = NULL; 15277 union { 15278 struct mlx5_flow_dv_modify_hdr_resource res; 15279 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 15280 sizeof(struct mlx5_modification_cmd) * 15281 (MLX5_MAX_MODIFY_NUM + 1)]; 15282 } mhdr_dummy; 15283 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 15284 15285 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 15286 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 15287 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 15288 memset(&dev_flow, 0, sizeof(struct mlx5_flow)); 15289 memset(&port_id_action, 0, 15290 sizeof(struct mlx5_flow_dv_port_id_action_resource)); 15291 memset(mhdr_res, 0, sizeof(*mhdr_res)); 15292 mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 15293 (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 15294 MLX5DV_FLOW_TABLE_TYPE_NIC_RX); 15295 dev_flow.handle = &dh; 15296 dev_flow.dv.port_id_action = &port_id_action; 15297 dev_flow.external = true; 15298 for (i = 0; i < RTE_COLORS; i++) { 15299 if (i < MLX5_MTR_RTE_COLORS) 15300 act_cnt = &mtr_policy->act_cnt[i]; 15301 /* Skip the color policy actions creation. */ 15302 if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) || 15303 (i == RTE_COLOR_GREEN && mtr_policy->skip_g)) 15304 continue; 15305 action_flags = 0; 15306 for (act = actions[i]; 15307 act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 15308 switch (act->type) { 15309 case RTE_FLOW_ACTION_TYPE_MARK: 15310 { 15311 uint32_t tag_be = mlx5_flow_mark_set 15312 (((const struct rte_flow_action_mark *) 15313 (act->conf))->id); 15314 15315 if (i >= MLX5_MTR_RTE_COLORS) 15316 return -rte_mtr_error_set(error, 15317 ENOTSUP, 15318 RTE_MTR_ERROR_TYPE_METER_POLICY, 15319 NULL, 15320 "cannot create policy " 15321 "mark action for this color"); 15322 dev_flow.handle->mark = 1; 15323 if (flow_dv_tag_resource_register(dev, tag_be, 15324 &dev_flow, &flow_err)) 15325 return -rte_mtr_error_set(error, 15326 ENOTSUP, 15327 RTE_MTR_ERROR_TYPE_METER_POLICY, 15328 NULL, 15329 "cannot setup policy mark action"); 15330 MLX5_ASSERT(dev_flow.dv.tag_resource); 15331 act_cnt->rix_mark = 15332 dev_flow.handle->dvh.rix_tag; 15333 action_flags |= MLX5_FLOW_ACTION_MARK; 15334 break; 15335 } 15336 case RTE_FLOW_ACTION_TYPE_SET_TAG: 15337 if (i >= MLX5_MTR_RTE_COLORS) 15338 return -rte_mtr_error_set(error, 15339 ENOTSUP, 15340 RTE_MTR_ERROR_TYPE_METER_POLICY, 15341 NULL, 15342 "cannot create policy " 15343 "set tag action for this color"); 15344 if (flow_dv_convert_action_set_tag 15345 (dev, mhdr_res, 15346 (const struct rte_flow_action_set_tag *) 15347 act->conf, &flow_err)) 15348 return -rte_mtr_error_set(error, 15349 ENOTSUP, 15350 RTE_MTR_ERROR_TYPE_METER_POLICY, 15351 NULL, "cannot convert policy " 15352 "set tag action"); 15353 if (!mhdr_res->actions_num) 15354 return -rte_mtr_error_set(error, 15355 ENOTSUP, 15356 RTE_MTR_ERROR_TYPE_METER_POLICY, 15357 NULL, "cannot find policy " 15358 "set tag action"); 15359 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 15360 break; 15361 case RTE_FLOW_ACTION_TYPE_DROP: 15362 { 15363 struct mlx5_flow_mtr_mng *mtrmng = 15364 priv->sh->mtrmng; 15365 struct mlx5_flow_tbl_data_entry *tbl_data; 15366 15367 /* 15368 * Create the drop table with 15369 * METER DROP level. 15370 */ 15371 if (!mtrmng->drop_tbl[domain]) { 15372 mtrmng->drop_tbl[domain] = 15373 flow_dv_tbl_resource_get(dev, 15374 MLX5_FLOW_TABLE_LEVEL_METER, 15375 egress, transfer, false, NULL, 0, 15376 0, MLX5_MTR_TABLE_ID_DROP, &flow_err); 15377 if (!mtrmng->drop_tbl[domain]) 15378 return -rte_mtr_error_set 15379 (error, ENOTSUP, 15380 RTE_MTR_ERROR_TYPE_METER_POLICY, 15381 NULL, 15382 "Failed to create meter drop table"); 15383 } 15384 tbl_data = container_of 15385 (mtrmng->drop_tbl[domain], 15386 struct mlx5_flow_tbl_data_entry, tbl); 15387 if (i < MLX5_MTR_RTE_COLORS) { 15388 act_cnt->dr_jump_action[domain] = 15389 tbl_data->jump.action; 15390 act_cnt->fate_action = 15391 MLX5_FLOW_FATE_DROP; 15392 } 15393 if (i == RTE_COLOR_RED) 15394 mtr_policy->dr_drop_action[domain] = 15395 tbl_data->jump.action; 15396 action_flags |= MLX5_FLOW_ACTION_DROP; 15397 break; 15398 } 15399 case RTE_FLOW_ACTION_TYPE_QUEUE: 15400 { 15401 if (i >= MLX5_MTR_RTE_COLORS) 15402 return -rte_mtr_error_set(error, 15403 ENOTSUP, 15404 RTE_MTR_ERROR_TYPE_METER_POLICY, 15405 NULL, "cannot create policy " 15406 "fate queue for this color"); 15407 act_cnt->queue = 15408 ((const struct rte_flow_action_queue *) 15409 (act->conf))->index; 15410 act_cnt->fate_action = 15411 MLX5_FLOW_FATE_QUEUE; 15412 dev_flow.handle->fate_action = 15413 MLX5_FLOW_FATE_QUEUE; 15414 mtr_policy->is_queue = 1; 15415 action_flags |= MLX5_FLOW_ACTION_QUEUE; 15416 break; 15417 } 15418 case RTE_FLOW_ACTION_TYPE_RSS: 15419 { 15420 int rss_size; 15421 15422 if (i >= MLX5_MTR_RTE_COLORS) 15423 return -rte_mtr_error_set(error, 15424 ENOTSUP, 15425 RTE_MTR_ERROR_TYPE_METER_POLICY, 15426 NULL, 15427 "cannot create policy " 15428 "rss action for this color"); 15429 /* 15430 * Save RSS conf into policy struct 15431 * for translate stage. 15432 */ 15433 rss_size = (int)rte_flow_conv 15434 (RTE_FLOW_CONV_OP_ACTION, 15435 NULL, 0, act, &flow_err); 15436 if (rss_size <= 0) 15437 return -rte_mtr_error_set(error, 15438 ENOTSUP, 15439 RTE_MTR_ERROR_TYPE_METER_POLICY, 15440 NULL, "Get the wrong " 15441 "rss action struct size"); 15442 act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO, 15443 rss_size, 0, SOCKET_ID_ANY); 15444 if (!act_cnt->rss) 15445 return -rte_mtr_error_set(error, 15446 ENOTSUP, 15447 RTE_MTR_ERROR_TYPE_METER_POLICY, 15448 NULL, 15449 "Fail to malloc rss action memory"); 15450 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION, 15451 act_cnt->rss, rss_size, 15452 act, &flow_err); 15453 if (ret < 0) 15454 return -rte_mtr_error_set(error, 15455 ENOTSUP, 15456 RTE_MTR_ERROR_TYPE_METER_POLICY, 15457 NULL, "Fail to save " 15458 "rss action into policy struct"); 15459 act_cnt->fate_action = 15460 MLX5_FLOW_FATE_SHARED_RSS; 15461 action_flags |= MLX5_FLOW_ACTION_RSS; 15462 break; 15463 } 15464 case RTE_FLOW_ACTION_TYPE_PORT_ID: 15465 { 15466 struct mlx5_flow_dv_port_id_action_resource 15467 port_id_resource; 15468 uint32_t port_id = 0; 15469 15470 if (i >= MLX5_MTR_RTE_COLORS) 15471 return -rte_mtr_error_set(error, 15472 ENOTSUP, 15473 RTE_MTR_ERROR_TYPE_METER_POLICY, 15474 NULL, "cannot create policy " 15475 "port action for this color"); 15476 memset(&port_id_resource, 0, 15477 sizeof(port_id_resource)); 15478 if (flow_dv_translate_action_port_id(dev, act, 15479 &port_id, &flow_err)) 15480 return -rte_mtr_error_set(error, 15481 ENOTSUP, 15482 RTE_MTR_ERROR_TYPE_METER_POLICY, 15483 NULL, "cannot translate " 15484 "policy port action"); 15485 port_id_resource.port_id = port_id; 15486 if (flow_dv_port_id_action_resource_register 15487 (dev, &port_id_resource, 15488 &dev_flow, &flow_err)) 15489 return -rte_mtr_error_set(error, 15490 ENOTSUP, 15491 RTE_MTR_ERROR_TYPE_METER_POLICY, 15492 NULL, "cannot setup " 15493 "policy port action"); 15494 act_cnt->rix_port_id_action = 15495 dev_flow.handle->rix_port_id_action; 15496 act_cnt->fate_action = 15497 MLX5_FLOW_FATE_PORT_ID; 15498 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 15499 break; 15500 } 15501 case RTE_FLOW_ACTION_TYPE_JUMP: 15502 { 15503 uint32_t jump_group = 0; 15504 uint32_t table = 0; 15505 struct mlx5_flow_tbl_data_entry *tbl_data; 15506 struct flow_grp_info grp_info = { 15507 .external = !!dev_flow.external, 15508 .transfer = !!transfer, 15509 .fdb_def_rule = !!priv->fdb_def_rule, 15510 .std_tbl_fix = 0, 15511 .skip_scale = dev_flow.skip_scale & 15512 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 15513 }; 15514 struct mlx5_flow_meter_sub_policy *sub_policy = 15515 mtr_policy->sub_policys[domain][0]; 15516 15517 if (i >= MLX5_MTR_RTE_COLORS) 15518 return -rte_mtr_error_set(error, 15519 ENOTSUP, 15520 RTE_MTR_ERROR_TYPE_METER_POLICY, 15521 NULL, 15522 "cannot create policy " 15523 "jump action for this color"); 15524 jump_group = 15525 ((const struct rte_flow_action_jump *) 15526 act->conf)->group; 15527 if (mlx5_flow_group_to_table(dev, NULL, 15528 jump_group, 15529 &table, 15530 &grp_info, &flow_err)) 15531 return -rte_mtr_error_set(error, 15532 ENOTSUP, 15533 RTE_MTR_ERROR_TYPE_METER_POLICY, 15534 NULL, "cannot setup " 15535 "policy jump action"); 15536 sub_policy->jump_tbl[i] = 15537 flow_dv_tbl_resource_get(dev, 15538 table, egress, 15539 transfer, 15540 !!dev_flow.external, 15541 NULL, jump_group, 0, 15542 0, &flow_err); 15543 if 15544 (!sub_policy->jump_tbl[i]) 15545 return -rte_mtr_error_set(error, 15546 ENOTSUP, 15547 RTE_MTR_ERROR_TYPE_METER_POLICY, 15548 NULL, "cannot create jump action."); 15549 tbl_data = container_of 15550 (sub_policy->jump_tbl[i], 15551 struct mlx5_flow_tbl_data_entry, tbl); 15552 act_cnt->dr_jump_action[domain] = 15553 tbl_data->jump.action; 15554 act_cnt->fate_action = 15555 MLX5_FLOW_FATE_JUMP; 15556 action_flags |= MLX5_FLOW_ACTION_JUMP; 15557 break; 15558 } 15559 /* 15560 * No need to check meter hierarchy for Y or R colors 15561 * here since it is done in the validation stage. 15562 */ 15563 case RTE_FLOW_ACTION_TYPE_METER: 15564 { 15565 const struct rte_flow_action_meter *mtr; 15566 struct mlx5_flow_meter_info *next_fm; 15567 struct mlx5_flow_meter_policy *next_policy; 15568 struct rte_flow_action tag_action; 15569 struct mlx5_rte_flow_action_set_tag set_tag; 15570 uint32_t next_mtr_idx = 0; 15571 15572 mtr = act->conf; 15573 next_fm = mlx5_flow_meter_find(priv, 15574 mtr->mtr_id, 15575 &next_mtr_idx); 15576 if (!next_fm) 15577 return -rte_mtr_error_set(error, EINVAL, 15578 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15579 "Fail to find next meter."); 15580 if (next_fm->def_policy) 15581 return -rte_mtr_error_set(error, EINVAL, 15582 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15583 "Hierarchy only supports termination meter."); 15584 next_policy = mlx5_flow_meter_policy_find(dev, 15585 next_fm->policy_id, NULL); 15586 MLX5_ASSERT(next_policy); 15587 if (next_fm->drop_cnt) { 15588 set_tag.id = 15589 (enum modify_reg) 15590 mlx5_flow_get_reg_id(dev, 15591 MLX5_MTR_ID, 15592 0, 15593 (struct rte_flow_error *)error); 15594 set_tag.offset = (priv->mtr_reg_share ? 15595 MLX5_MTR_COLOR_BITS : 0); 15596 set_tag.length = (priv->mtr_reg_share ? 15597 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : 15598 MLX5_REG_BITS); 15599 set_tag.data = next_mtr_idx; 15600 tag_action.type = 15601 (enum rte_flow_action_type) 15602 MLX5_RTE_FLOW_ACTION_TYPE_TAG; 15603 tag_action.conf = &set_tag; 15604 if (flow_dv_convert_action_set_reg 15605 (mhdr_res, &tag_action, 15606 (struct rte_flow_error *)error)) 15607 return -rte_errno; 15608 action_flags |= 15609 MLX5_FLOW_ACTION_SET_TAG; 15610 } 15611 act_cnt->fate_action = MLX5_FLOW_FATE_MTR; 15612 act_cnt->next_mtr_id = next_fm->meter_id; 15613 act_cnt->next_sub_policy = NULL; 15614 mtr_policy->is_hierarchy = 1; 15615 mtr_policy->dev = next_policy->dev; 15616 action_flags |= 15617 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 15618 break; 15619 } 15620 default: 15621 return -rte_mtr_error_set(error, ENOTSUP, 15622 RTE_MTR_ERROR_TYPE_METER_POLICY, 15623 NULL, "action type not supported"); 15624 } 15625 if (action_flags & MLX5_FLOW_ACTION_SET_TAG) { 15626 /* create modify action if needed. */ 15627 dev_flow.dv.group = 1; 15628 if (flow_dv_modify_hdr_resource_register 15629 (dev, mhdr_res, &dev_flow, &flow_err)) 15630 return -rte_mtr_error_set(error, 15631 ENOTSUP, 15632 RTE_MTR_ERROR_TYPE_METER_POLICY, 15633 NULL, "cannot register policy " 15634 "set tag action"); 15635 act_cnt->modify_hdr = 15636 dev_flow.handle->dvh.modify_hdr; 15637 } 15638 } 15639 } 15640 return 0; 15641 } 15642 15643 /** 15644 * Create policy action per domain, lock free, 15645 * (mutex should be acquired by caller). 15646 * Dispatcher for action type specific call. 15647 * 15648 * @param[in] dev 15649 * Pointer to the Ethernet device structure. 15650 * @param[in] mtr_policy 15651 * Meter policy struct. 15652 * @param[in] action 15653 * Action specification used to create meter actions. 15654 * @param[out] error 15655 * Perform verbose error reporting if not NULL. Initialized in case of 15656 * error only. 15657 * 15658 * @return 15659 * 0 on success, otherwise negative errno value. 15660 */ 15661 static int 15662 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev, 15663 struct mlx5_flow_meter_policy *mtr_policy, 15664 const struct rte_flow_action *actions[RTE_COLORS], 15665 struct rte_mtr_error *error) 15666 { 15667 int ret, i; 15668 uint16_t sub_policy_num; 15669 15670 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15671 sub_policy_num = (mtr_policy->sub_policy_num >> 15672 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15673 MLX5_MTR_SUB_POLICY_NUM_MASK; 15674 if (sub_policy_num) { 15675 ret = __flow_dv_create_domain_policy_acts(dev, 15676 mtr_policy, actions, 15677 (enum mlx5_meter_domain)i, error); 15678 /* Cleaning resource is done in the caller level. */ 15679 if (ret) 15680 return ret; 15681 } 15682 } 15683 return 0; 15684 } 15685 15686 /** 15687 * Query a DV flow rule for its statistics via DevX. 15688 * 15689 * @param[in] dev 15690 * Pointer to Ethernet device. 15691 * @param[in] cnt_idx 15692 * Index to the flow counter. 15693 * @param[out] data 15694 * Data retrieved by the query. 15695 * @param[out] error 15696 * Perform verbose error reporting if not NULL. 15697 * 15698 * @return 15699 * 0 on success, a negative errno value otherwise and rte_errno is set. 15700 */ 15701 static int 15702 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data, 15703 struct rte_flow_error *error) 15704 { 15705 struct mlx5_priv *priv = dev->data->dev_private; 15706 struct rte_flow_query_count *qc = data; 15707 15708 if (!priv->config.devx) 15709 return rte_flow_error_set(error, ENOTSUP, 15710 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15711 NULL, 15712 "counters are not supported"); 15713 if (cnt_idx) { 15714 uint64_t pkts, bytes; 15715 struct mlx5_flow_counter *cnt; 15716 int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes); 15717 15718 if (err) 15719 return rte_flow_error_set(error, -err, 15720 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15721 NULL, "cannot read counters"); 15722 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL); 15723 qc->hits_set = 1; 15724 qc->bytes_set = 1; 15725 qc->hits = pkts - cnt->hits; 15726 qc->bytes = bytes - cnt->bytes; 15727 if (qc->reset) { 15728 cnt->hits = pkts; 15729 cnt->bytes = bytes; 15730 } 15731 return 0; 15732 } 15733 return rte_flow_error_set(error, EINVAL, 15734 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15735 NULL, 15736 "counters are not available"); 15737 } 15738 15739 static int 15740 flow_dv_action_query(struct rte_eth_dev *dev, 15741 const struct rte_flow_action_handle *handle, void *data, 15742 struct rte_flow_error *error) 15743 { 15744 struct mlx5_age_param *age_param; 15745 struct rte_flow_query_age *resp; 15746 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15747 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15748 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15749 struct mlx5_priv *priv = dev->data->dev_private; 15750 struct mlx5_aso_ct_action *ct; 15751 uint16_t owner; 15752 uint32_t dev_idx; 15753 15754 switch (type) { 15755 case MLX5_INDIRECT_ACTION_TYPE_AGE: 15756 age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params; 15757 resp = data; 15758 resp->aged = __atomic_load_n(&age_param->state, 15759 __ATOMIC_RELAXED) == AGE_TMOUT ? 15760 1 : 0; 15761 resp->sec_since_last_hit_valid = !resp->aged; 15762 if (resp->sec_since_last_hit_valid) 15763 resp->sec_since_last_hit = __atomic_load_n 15764 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15765 return 0; 15766 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 15767 return flow_dv_query_count(dev, idx, data, error); 15768 case MLX5_INDIRECT_ACTION_TYPE_CT: 15769 owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15770 if (owner != PORT_ID(priv)) 15771 return rte_flow_error_set(error, EACCES, 15772 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15773 NULL, 15774 "CT object owned by another port"); 15775 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15776 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15777 MLX5_ASSERT(ct); 15778 if (!ct->refcnt) 15779 return rte_flow_error_set(error, EFAULT, 15780 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15781 NULL, 15782 "CT object is inactive"); 15783 ((struct rte_flow_action_conntrack *)data)->peer_port = 15784 ct->peer; 15785 ((struct rte_flow_action_conntrack *)data)->is_original_dir = 15786 ct->is_original; 15787 if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data)) 15788 return rte_flow_error_set(error, EIO, 15789 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15790 NULL, 15791 "Failed to query CT context"); 15792 return 0; 15793 default: 15794 return rte_flow_error_set(error, ENOTSUP, 15795 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15796 "action type query not supported"); 15797 } 15798 } 15799 15800 /** 15801 * Query a flow rule AGE action for aging information. 15802 * 15803 * @param[in] dev 15804 * Pointer to Ethernet device. 15805 * @param[in] flow 15806 * Pointer to the sub flow. 15807 * @param[out] data 15808 * data retrieved by the query. 15809 * @param[out] error 15810 * Perform verbose error reporting if not NULL. 15811 * 15812 * @return 15813 * 0 on success, a negative errno value otherwise and rte_errno is set. 15814 */ 15815 static int 15816 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow, 15817 void *data, struct rte_flow_error *error) 15818 { 15819 struct rte_flow_query_age *resp = data; 15820 struct mlx5_age_param *age_param; 15821 15822 if (flow->age) { 15823 struct mlx5_aso_age_action *act = 15824 flow_aso_age_get_by_idx(dev, flow->age); 15825 15826 age_param = &act->age_params; 15827 } else if (flow->counter) { 15828 age_param = flow_dv_counter_idx_get_age(dev, flow->counter); 15829 15830 if (!age_param || !age_param->timeout) 15831 return rte_flow_error_set 15832 (error, EINVAL, 15833 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15834 NULL, "cannot read age data"); 15835 } else { 15836 return rte_flow_error_set(error, EINVAL, 15837 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15838 NULL, "age data not available"); 15839 } 15840 resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) == 15841 AGE_TMOUT ? 1 : 0; 15842 resp->sec_since_last_hit_valid = !resp->aged; 15843 if (resp->sec_since_last_hit_valid) 15844 resp->sec_since_last_hit = __atomic_load_n 15845 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15846 return 0; 15847 } 15848 15849 /** 15850 * Query a flow. 15851 * 15852 * @see rte_flow_query() 15853 * @see rte_flow_ops 15854 */ 15855 static int 15856 flow_dv_query(struct rte_eth_dev *dev, 15857 struct rte_flow *flow __rte_unused, 15858 const struct rte_flow_action *actions __rte_unused, 15859 void *data __rte_unused, 15860 struct rte_flow_error *error __rte_unused) 15861 { 15862 int ret = -EINVAL; 15863 15864 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 15865 switch (actions->type) { 15866 case RTE_FLOW_ACTION_TYPE_VOID: 15867 break; 15868 case RTE_FLOW_ACTION_TYPE_COUNT: 15869 ret = flow_dv_query_count(dev, flow->counter, data, 15870 error); 15871 break; 15872 case RTE_FLOW_ACTION_TYPE_AGE: 15873 ret = flow_dv_query_age(dev, flow, data, error); 15874 break; 15875 default: 15876 return rte_flow_error_set(error, ENOTSUP, 15877 RTE_FLOW_ERROR_TYPE_ACTION, 15878 actions, 15879 "action not supported"); 15880 } 15881 } 15882 return ret; 15883 } 15884 15885 /** 15886 * Destroy the meter table set. 15887 * Lock free, (mutex should be acquired by caller). 15888 * 15889 * @param[in] dev 15890 * Pointer to Ethernet device. 15891 * @param[in] fm 15892 * Meter information table. 15893 */ 15894 static void 15895 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev, 15896 struct mlx5_flow_meter_info *fm) 15897 { 15898 struct mlx5_priv *priv = dev->data->dev_private; 15899 int i; 15900 15901 if (!fm || !priv->config.dv_flow_en) 15902 return; 15903 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15904 if (fm->drop_rule[i]) { 15905 claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i])); 15906 fm->drop_rule[i] = NULL; 15907 } 15908 } 15909 } 15910 15911 static void 15912 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev) 15913 { 15914 struct mlx5_priv *priv = dev->data->dev_private; 15915 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 15916 struct mlx5_flow_tbl_data_entry *tbl; 15917 int i, j; 15918 15919 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15920 if (mtrmng->def_rule[i]) { 15921 claim_zero(mlx5_flow_os_destroy_flow 15922 (mtrmng->def_rule[i])); 15923 mtrmng->def_rule[i] = NULL; 15924 } 15925 if (mtrmng->def_matcher[i]) { 15926 tbl = container_of(mtrmng->def_matcher[i]->tbl, 15927 struct mlx5_flow_tbl_data_entry, tbl); 15928 mlx5_list_unregister(tbl->matchers, 15929 &mtrmng->def_matcher[i]->entry); 15930 mtrmng->def_matcher[i] = NULL; 15931 } 15932 for (j = 0; j < MLX5_REG_BITS; j++) { 15933 if (mtrmng->drop_matcher[i][j]) { 15934 tbl = 15935 container_of(mtrmng->drop_matcher[i][j]->tbl, 15936 struct mlx5_flow_tbl_data_entry, 15937 tbl); 15938 mlx5_list_unregister(tbl->matchers, 15939 &mtrmng->drop_matcher[i][j]->entry); 15940 mtrmng->drop_matcher[i][j] = NULL; 15941 } 15942 } 15943 if (mtrmng->drop_tbl[i]) { 15944 flow_dv_tbl_resource_release(MLX5_SH(dev), 15945 mtrmng->drop_tbl[i]); 15946 mtrmng->drop_tbl[i] = NULL; 15947 } 15948 } 15949 } 15950 15951 /* Number of meter flow actions, count and jump or count and drop. */ 15952 #define METER_ACTIONS 2 15953 15954 static void 15955 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev, 15956 enum mlx5_meter_domain domain) 15957 { 15958 struct mlx5_priv *priv = dev->data->dev_private; 15959 struct mlx5_flow_meter_def_policy *def_policy = 15960 priv->sh->mtrmng->def_policy[domain]; 15961 15962 __flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy); 15963 mlx5_free(def_policy); 15964 priv->sh->mtrmng->def_policy[domain] = NULL; 15965 } 15966 15967 /** 15968 * Destroy the default policy table set. 15969 * 15970 * @param[in] dev 15971 * Pointer to Ethernet device. 15972 */ 15973 static void 15974 flow_dv_destroy_def_policy(struct rte_eth_dev *dev) 15975 { 15976 struct mlx5_priv *priv = dev->data->dev_private; 15977 int i; 15978 15979 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) 15980 if (priv->sh->mtrmng->def_policy[i]) 15981 __flow_dv_destroy_domain_def_policy(dev, 15982 (enum mlx5_meter_domain)i); 15983 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID; 15984 } 15985 15986 static int 15987 __flow_dv_create_policy_flow(struct rte_eth_dev *dev, 15988 uint32_t color_reg_c_idx, 15989 enum rte_color color, void *matcher_object, 15990 int actions_n, void *actions, 15991 bool match_src_port, const struct rte_flow_item *item, 15992 void **rule, const struct rte_flow_attr *attr) 15993 { 15994 int ret; 15995 struct mlx5_flow_dv_match_params value = { 15996 .size = sizeof(value.buf), 15997 }; 15998 struct mlx5_flow_dv_match_params matcher = { 15999 .size = sizeof(matcher.buf), 16000 }; 16001 struct mlx5_priv *priv = dev->data->dev_private; 16002 uint8_t misc_mask; 16003 16004 if (match_src_port && (priv->representor || priv->master)) { 16005 if (flow_dv_translate_item_port_id(dev, matcher.buf, 16006 value.buf, item, attr)) { 16007 DRV_LOG(ERR, "Failed to create meter policy%d flow's" 16008 " value with port.", color); 16009 return -1; 16010 } 16011 } 16012 flow_dv_match_meta_reg(matcher.buf, value.buf, 16013 (enum modify_reg)color_reg_c_idx, 16014 rte_col_2_mlx5_col(color), UINT32_MAX); 16015 misc_mask = flow_dv_matcher_enable(value.buf); 16016 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16017 ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value, 16018 actions_n, actions, rule); 16019 if (ret) { 16020 DRV_LOG(ERR, "Failed to create meter policy%d flow.", color); 16021 return -1; 16022 } 16023 return 0; 16024 } 16025 16026 static int 16027 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev, 16028 uint32_t color_reg_c_idx, 16029 uint16_t priority, 16030 struct mlx5_flow_meter_sub_policy *sub_policy, 16031 const struct rte_flow_attr *attr, 16032 bool match_src_port, 16033 const struct rte_flow_item *item, 16034 struct mlx5_flow_dv_matcher **policy_matcher, 16035 struct rte_flow_error *error) 16036 { 16037 struct mlx5_list_entry *entry; 16038 struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc; 16039 struct mlx5_flow_dv_matcher matcher = { 16040 .mask = { 16041 .size = sizeof(matcher.mask.buf), 16042 }, 16043 .tbl = tbl_rsc, 16044 }; 16045 struct mlx5_flow_dv_match_params value = { 16046 .size = sizeof(value.buf), 16047 }; 16048 struct mlx5_flow_cb_ctx ctx = { 16049 .error = error, 16050 .data = &matcher, 16051 }; 16052 struct mlx5_flow_tbl_data_entry *tbl_data; 16053 struct mlx5_priv *priv = dev->data->dev_private; 16054 const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 16055 16056 if (match_src_port && (priv->representor || priv->master)) { 16057 if (flow_dv_translate_item_port_id(dev, matcher.mask.buf, 16058 value.buf, item, attr)) { 16059 DRV_LOG(ERR, "Failed to register meter policy%d matcher" 16060 " with port.", priority); 16061 return -1; 16062 } 16063 } 16064 tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl); 16065 if (priority < RTE_COLOR_RED) 16066 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16067 (enum modify_reg)color_reg_c_idx, 0, color_mask); 16068 matcher.priority = priority; 16069 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 16070 matcher.mask.size); 16071 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16072 if (!entry) { 16073 DRV_LOG(ERR, "Failed to register meter drop matcher."); 16074 return -1; 16075 } 16076 *policy_matcher = 16077 container_of(entry, struct mlx5_flow_dv_matcher, entry); 16078 return 0; 16079 } 16080 16081 /** 16082 * Create the policy rules per domain. 16083 * 16084 * @param[in] dev 16085 * Pointer to Ethernet device. 16086 * @param[in] sub_policy 16087 * Pointer to sub policy table.. 16088 * @param[in] egress 16089 * Direction of the table. 16090 * @param[in] transfer 16091 * E-Switch or NIC flow. 16092 * @param[in] acts 16093 * Pointer to policy action list per color. 16094 * 16095 * @return 16096 * 0 on success, -1 otherwise. 16097 */ 16098 static int 16099 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev, 16100 struct mlx5_flow_meter_sub_policy *sub_policy, 16101 uint8_t egress, uint8_t transfer, bool match_src_port, 16102 struct mlx5_meter_policy_acts acts[RTE_COLORS]) 16103 { 16104 struct mlx5_priv *priv = dev->data->dev_private; 16105 struct rte_flow_error flow_err; 16106 uint32_t color_reg_c_idx; 16107 struct rte_flow_attr attr = { 16108 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 16109 .priority = 0, 16110 .ingress = 0, 16111 .egress = !!egress, 16112 .transfer = !!transfer, 16113 .reserved = 0, 16114 }; 16115 int i; 16116 int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err); 16117 struct mlx5_sub_policy_color_rule *color_rule; 16118 bool svport_match; 16119 struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL}; 16120 16121 if (ret < 0) 16122 return -1; 16123 /* Create policy table with POLICY level. */ 16124 if (!sub_policy->tbl_rsc) 16125 sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev, 16126 MLX5_FLOW_TABLE_LEVEL_POLICY, 16127 egress, transfer, false, NULL, 0, 0, 16128 sub_policy->idx, &flow_err); 16129 if (!sub_policy->tbl_rsc) { 16130 DRV_LOG(ERR, 16131 "Failed to create meter sub policy table."); 16132 return -1; 16133 } 16134 /* Prepare matchers. */ 16135 color_reg_c_idx = ret; 16136 for (i = 0; i < RTE_COLORS; i++) { 16137 TAILQ_INIT(&sub_policy->color_rules[i]); 16138 if (!acts[i].actions_n) 16139 continue; 16140 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 16141 sizeof(struct mlx5_sub_policy_color_rule), 16142 0, SOCKET_ID_ANY); 16143 if (!color_rule) { 16144 DRV_LOG(ERR, "No memory to create color rule."); 16145 goto err_exit; 16146 } 16147 tmp_rules[i] = color_rule; 16148 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 16149 color_rule, next_port); 16150 color_rule->src_port = priv->representor_id; 16151 /* No use. */ 16152 attr.priority = i; 16153 /* Create matchers for colors. */ 16154 svport_match = (i != RTE_COLOR_RED) ? match_src_port : false; 16155 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 16156 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 16157 &attr, svport_match, NULL, 16158 &color_rule->matcher, &flow_err)) { 16159 DRV_LOG(ERR, "Failed to create color%u matcher.", i); 16160 goto err_exit; 16161 } 16162 /* Create flow, matching color. */ 16163 if (__flow_dv_create_policy_flow(dev, 16164 color_reg_c_idx, (enum rte_color)i, 16165 color_rule->matcher->matcher_object, 16166 acts[i].actions_n, acts[i].dv_actions, 16167 svport_match, NULL, &color_rule->rule, 16168 &attr)) { 16169 DRV_LOG(ERR, "Failed to create color%u rule.", i); 16170 goto err_exit; 16171 } 16172 } 16173 return 0; 16174 err_exit: 16175 /* All the policy rules will be cleared. */ 16176 do { 16177 color_rule = tmp_rules[i]; 16178 if (color_rule) { 16179 if (color_rule->rule) 16180 mlx5_flow_os_destroy_flow(color_rule->rule); 16181 if (color_rule->matcher) { 16182 struct mlx5_flow_tbl_data_entry *tbl = 16183 container_of(color_rule->matcher->tbl, 16184 typeof(*tbl), tbl); 16185 mlx5_list_unregister(tbl->matchers, 16186 &color_rule->matcher->entry); 16187 } 16188 TAILQ_REMOVE(&sub_policy->color_rules[i], 16189 color_rule, next_port); 16190 mlx5_free(color_rule); 16191 } 16192 } while (i--); 16193 return -1; 16194 } 16195 16196 static int 16197 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev, 16198 struct mlx5_flow_meter_policy *mtr_policy, 16199 struct mlx5_flow_meter_sub_policy *sub_policy, 16200 uint32_t domain) 16201 { 16202 struct mlx5_priv *priv = dev->data->dev_private; 16203 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16204 struct mlx5_flow_dv_tag_resource *tag; 16205 struct mlx5_flow_dv_port_id_action_resource *port_action; 16206 struct mlx5_hrxq *hrxq; 16207 struct mlx5_flow_meter_info *next_fm = NULL; 16208 struct mlx5_flow_meter_policy *next_policy; 16209 struct mlx5_flow_meter_sub_policy *next_sub_policy; 16210 struct mlx5_flow_tbl_data_entry *tbl_data; 16211 struct rte_flow_error error; 16212 uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16213 uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16214 bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX); 16215 bool match_src_port = false; 16216 int i; 16217 16218 /* If RSS or Queue, no previous actions / rules is created. */ 16219 for (i = 0; i < RTE_COLORS; i++) { 16220 acts[i].actions_n = 0; 16221 if (i == RTE_COLOR_RED) { 16222 /* Only support drop on red. */ 16223 acts[i].dv_actions[0] = 16224 mtr_policy->dr_drop_action[domain]; 16225 acts[i].actions_n = 1; 16226 continue; 16227 } 16228 if (i == RTE_COLOR_GREEN && 16229 mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) { 16230 struct rte_flow_attr attr = { 16231 .transfer = transfer 16232 }; 16233 16234 next_fm = mlx5_flow_meter_find(priv, 16235 mtr_policy->act_cnt[i].next_mtr_id, 16236 NULL); 16237 if (!next_fm) { 16238 DRV_LOG(ERR, 16239 "Failed to get next hierarchy meter."); 16240 goto err_exit; 16241 } 16242 if (mlx5_flow_meter_attach(priv, next_fm, 16243 &attr, &error)) { 16244 DRV_LOG(ERR, "%s", error.message); 16245 next_fm = NULL; 16246 goto err_exit; 16247 } 16248 /* Meter action must be the first for TX. */ 16249 if (mtr_first) { 16250 acts[i].dv_actions[acts[i].actions_n] = 16251 next_fm->meter_action; 16252 acts[i].actions_n++; 16253 } 16254 } 16255 if (mtr_policy->act_cnt[i].rix_mark) { 16256 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], 16257 mtr_policy->act_cnt[i].rix_mark); 16258 if (!tag) { 16259 DRV_LOG(ERR, "Failed to find " 16260 "mark action for policy."); 16261 goto err_exit; 16262 } 16263 acts[i].dv_actions[acts[i].actions_n] = tag->action; 16264 acts[i].actions_n++; 16265 } 16266 if (mtr_policy->act_cnt[i].modify_hdr) { 16267 acts[i].dv_actions[acts[i].actions_n] = 16268 mtr_policy->act_cnt[i].modify_hdr->action; 16269 acts[i].actions_n++; 16270 } 16271 if (mtr_policy->act_cnt[i].fate_action) { 16272 switch (mtr_policy->act_cnt[i].fate_action) { 16273 case MLX5_FLOW_FATE_PORT_ID: 16274 port_action = mlx5_ipool_get 16275 (priv->sh->ipool[MLX5_IPOOL_PORT_ID], 16276 mtr_policy->act_cnt[i].rix_port_id_action); 16277 if (!port_action) { 16278 DRV_LOG(ERR, "Failed to find " 16279 "port action for policy."); 16280 goto err_exit; 16281 } 16282 acts[i].dv_actions[acts[i].actions_n] = 16283 port_action->action; 16284 acts[i].actions_n++; 16285 mtr_policy->dev = dev; 16286 match_src_port = true; 16287 break; 16288 case MLX5_FLOW_FATE_DROP: 16289 case MLX5_FLOW_FATE_JUMP: 16290 acts[i].dv_actions[acts[i].actions_n] = 16291 mtr_policy->act_cnt[i].dr_jump_action[domain]; 16292 acts[i].actions_n++; 16293 break; 16294 case MLX5_FLOW_FATE_SHARED_RSS: 16295 case MLX5_FLOW_FATE_QUEUE: 16296 hrxq = mlx5_ipool_get 16297 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 16298 sub_policy->rix_hrxq[i]); 16299 if (!hrxq) { 16300 DRV_LOG(ERR, "Failed to find " 16301 "queue action for policy."); 16302 goto err_exit; 16303 } 16304 acts[i].dv_actions[acts[i].actions_n] = 16305 hrxq->action; 16306 acts[i].actions_n++; 16307 break; 16308 case MLX5_FLOW_FATE_MTR: 16309 if (!next_fm) { 16310 DRV_LOG(ERR, 16311 "No next hierarchy meter."); 16312 goto err_exit; 16313 } 16314 if (!mtr_first) { 16315 acts[i].dv_actions[acts[i].actions_n] = 16316 next_fm->meter_action; 16317 acts[i].actions_n++; 16318 } 16319 if (mtr_policy->act_cnt[i].next_sub_policy) { 16320 next_sub_policy = 16321 mtr_policy->act_cnt[i].next_sub_policy; 16322 } else { 16323 next_policy = 16324 mlx5_flow_meter_policy_find(dev, 16325 next_fm->policy_id, NULL); 16326 MLX5_ASSERT(next_policy); 16327 next_sub_policy = 16328 next_policy->sub_policys[domain][0]; 16329 } 16330 tbl_data = 16331 container_of(next_sub_policy->tbl_rsc, 16332 struct mlx5_flow_tbl_data_entry, tbl); 16333 acts[i].dv_actions[acts[i].actions_n++] = 16334 tbl_data->jump.action; 16335 if (mtr_policy->act_cnt[i].modify_hdr) 16336 match_src_port = !!transfer; 16337 break; 16338 default: 16339 /*Queue action do nothing*/ 16340 break; 16341 } 16342 } 16343 } 16344 if (__flow_dv_create_domain_policy_rules(dev, sub_policy, 16345 egress, transfer, match_src_port, acts)) { 16346 DRV_LOG(ERR, 16347 "Failed to create policy rules per domain."); 16348 goto err_exit; 16349 } 16350 return 0; 16351 err_exit: 16352 if (next_fm) 16353 mlx5_flow_meter_detach(priv, next_fm); 16354 return -1; 16355 } 16356 16357 /** 16358 * Create the policy rules. 16359 * 16360 * @param[in] dev 16361 * Pointer to Ethernet device. 16362 * @param[in,out] mtr_policy 16363 * Pointer to meter policy table. 16364 * 16365 * @return 16366 * 0 on success, -1 otherwise. 16367 */ 16368 static int 16369 flow_dv_create_policy_rules(struct rte_eth_dev *dev, 16370 struct mlx5_flow_meter_policy *mtr_policy) 16371 { 16372 int i; 16373 uint16_t sub_policy_num; 16374 16375 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16376 sub_policy_num = (mtr_policy->sub_policy_num >> 16377 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 16378 MLX5_MTR_SUB_POLICY_NUM_MASK; 16379 if (!sub_policy_num) 16380 continue; 16381 /* Prepare actions list and create policy rules. */ 16382 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16383 mtr_policy->sub_policys[i][0], i)) { 16384 DRV_LOG(ERR, "Failed to create policy action " 16385 "list per domain."); 16386 return -1; 16387 } 16388 } 16389 return 0; 16390 } 16391 16392 static int 16393 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain) 16394 { 16395 struct mlx5_priv *priv = dev->data->dev_private; 16396 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16397 struct mlx5_flow_meter_def_policy *def_policy; 16398 struct mlx5_flow_tbl_resource *jump_tbl; 16399 struct mlx5_flow_tbl_data_entry *tbl_data; 16400 uint8_t egress, transfer; 16401 struct rte_flow_error error; 16402 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16403 int ret; 16404 16405 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16406 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16407 def_policy = mtrmng->def_policy[domain]; 16408 if (!def_policy) { 16409 def_policy = mlx5_malloc(MLX5_MEM_ZERO, 16410 sizeof(struct mlx5_flow_meter_def_policy), 16411 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 16412 if (!def_policy) { 16413 DRV_LOG(ERR, "Failed to alloc default policy table."); 16414 goto def_policy_error; 16415 } 16416 mtrmng->def_policy[domain] = def_policy; 16417 /* Create the meter suffix table with SUFFIX level. */ 16418 jump_tbl = flow_dv_tbl_resource_get(dev, 16419 MLX5_FLOW_TABLE_LEVEL_METER, 16420 egress, transfer, false, NULL, 0, 16421 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16422 if (!jump_tbl) { 16423 DRV_LOG(ERR, 16424 "Failed to create meter suffix table."); 16425 goto def_policy_error; 16426 } 16427 def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl; 16428 tbl_data = container_of(jump_tbl, 16429 struct mlx5_flow_tbl_data_entry, tbl); 16430 def_policy->dr_jump_action[RTE_COLOR_GREEN] = 16431 tbl_data->jump.action; 16432 acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action; 16433 acts[RTE_COLOR_GREEN].actions_n = 1; 16434 /* 16435 * YELLOW has the same default policy as GREEN does. 16436 * G & Y share the same table and action. The 2nd time of table 16437 * resource getting is just to update the reference count for 16438 * the releasing stage. 16439 */ 16440 jump_tbl = flow_dv_tbl_resource_get(dev, 16441 MLX5_FLOW_TABLE_LEVEL_METER, 16442 egress, transfer, false, NULL, 0, 16443 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16444 if (!jump_tbl) { 16445 DRV_LOG(ERR, 16446 "Failed to get meter suffix table."); 16447 goto def_policy_error; 16448 } 16449 def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl; 16450 tbl_data = container_of(jump_tbl, 16451 struct mlx5_flow_tbl_data_entry, tbl); 16452 def_policy->dr_jump_action[RTE_COLOR_YELLOW] = 16453 tbl_data->jump.action; 16454 acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action; 16455 acts[RTE_COLOR_YELLOW].actions_n = 1; 16456 /* Create jump action to the drop table. */ 16457 if (!mtrmng->drop_tbl[domain]) { 16458 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get 16459 (dev, MLX5_FLOW_TABLE_LEVEL_METER, 16460 egress, transfer, false, NULL, 0, 16461 0, MLX5_MTR_TABLE_ID_DROP, &error); 16462 if (!mtrmng->drop_tbl[domain]) { 16463 DRV_LOG(ERR, "Failed to create meter " 16464 "drop table for default policy."); 16465 goto def_policy_error; 16466 } 16467 } 16468 /* all RED: unique Drop table for jump action. */ 16469 tbl_data = container_of(mtrmng->drop_tbl[domain], 16470 struct mlx5_flow_tbl_data_entry, tbl); 16471 def_policy->dr_jump_action[RTE_COLOR_RED] = 16472 tbl_data->jump.action; 16473 acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action; 16474 acts[RTE_COLOR_RED].actions_n = 1; 16475 /* Create default policy rules. */ 16476 ret = __flow_dv_create_domain_policy_rules(dev, 16477 &def_policy->sub_policy, 16478 egress, transfer, false, acts); 16479 if (ret) { 16480 DRV_LOG(ERR, "Failed to create default policy rules."); 16481 goto def_policy_error; 16482 } 16483 } 16484 return 0; 16485 def_policy_error: 16486 __flow_dv_destroy_domain_def_policy(dev, 16487 (enum mlx5_meter_domain)domain); 16488 return -1; 16489 } 16490 16491 /** 16492 * Create the default policy table set. 16493 * 16494 * @param[in] dev 16495 * Pointer to Ethernet device. 16496 * @return 16497 * 0 on success, -1 otherwise. 16498 */ 16499 static int 16500 flow_dv_create_def_policy(struct rte_eth_dev *dev) 16501 { 16502 struct mlx5_priv *priv = dev->data->dev_private; 16503 int i; 16504 16505 /* Non-termination policy table. */ 16506 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16507 if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER) 16508 continue; 16509 if (__flow_dv_create_domain_def_policy(dev, i)) { 16510 DRV_LOG(ERR, "Failed to create default policy"); 16511 /* Rollback the created default policies for others. */ 16512 flow_dv_destroy_def_policy(dev); 16513 return -1; 16514 } 16515 } 16516 return 0; 16517 } 16518 16519 /** 16520 * Create the needed meter tables. 16521 * Lock free, (mutex should be acquired by caller). 16522 * 16523 * @param[in] dev 16524 * Pointer to Ethernet device. 16525 * @param[in] fm 16526 * Meter information table. 16527 * @param[in] mtr_idx 16528 * Meter index. 16529 * @param[in] domain_bitmap 16530 * Domain bitmap. 16531 * @return 16532 * 0 on success, -1 otherwise. 16533 */ 16534 static int 16535 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev, 16536 struct mlx5_flow_meter_info *fm, 16537 uint32_t mtr_idx, 16538 uint8_t domain_bitmap) 16539 { 16540 struct mlx5_priv *priv = dev->data->dev_private; 16541 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16542 struct rte_flow_error error; 16543 struct mlx5_flow_tbl_data_entry *tbl_data; 16544 uint8_t egress, transfer; 16545 void *actions[METER_ACTIONS]; 16546 int domain, ret, i; 16547 struct mlx5_flow_counter *cnt; 16548 struct mlx5_flow_dv_match_params value = { 16549 .size = sizeof(value.buf), 16550 }; 16551 struct mlx5_flow_dv_match_params matcher_para = { 16552 .size = sizeof(matcher_para.buf), 16553 }; 16554 int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID, 16555 0, &error); 16556 uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1; 16557 uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0; 16558 struct mlx5_list_entry *entry; 16559 struct mlx5_flow_dv_matcher matcher = { 16560 .mask = { 16561 .size = sizeof(matcher.mask.buf), 16562 }, 16563 }; 16564 struct mlx5_flow_dv_matcher *drop_matcher; 16565 struct mlx5_flow_cb_ctx ctx = { 16566 .error = &error, 16567 .data = &matcher, 16568 }; 16569 uint8_t misc_mask; 16570 16571 if (!priv->mtr_en || mtr_id_reg_c < 0) { 16572 rte_errno = ENOTSUP; 16573 return -1; 16574 } 16575 for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) { 16576 if (!(domain_bitmap & (1 << domain)) || 16577 (mtrmng->def_rule[domain] && !fm->drop_cnt)) 16578 continue; 16579 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16580 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16581 /* Create the drop table with METER DROP level. */ 16582 if (!mtrmng->drop_tbl[domain]) { 16583 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev, 16584 MLX5_FLOW_TABLE_LEVEL_METER, 16585 egress, transfer, false, NULL, 0, 16586 0, MLX5_MTR_TABLE_ID_DROP, &error); 16587 if (!mtrmng->drop_tbl[domain]) { 16588 DRV_LOG(ERR, "Failed to create meter drop table."); 16589 goto policy_error; 16590 } 16591 } 16592 /* Create default matcher in drop table. */ 16593 matcher.tbl = mtrmng->drop_tbl[domain], 16594 tbl_data = container_of(mtrmng->drop_tbl[domain], 16595 struct mlx5_flow_tbl_data_entry, tbl); 16596 if (!mtrmng->def_matcher[domain]) { 16597 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16598 (enum modify_reg)mtr_id_reg_c, 16599 0, 0); 16600 matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY; 16601 matcher.crc = rte_raw_cksum 16602 ((const void *)matcher.mask.buf, 16603 matcher.mask.size); 16604 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16605 if (!entry) { 16606 DRV_LOG(ERR, "Failed to register meter " 16607 "drop default matcher."); 16608 goto policy_error; 16609 } 16610 mtrmng->def_matcher[domain] = container_of(entry, 16611 struct mlx5_flow_dv_matcher, entry); 16612 } 16613 /* Create default rule in drop table. */ 16614 if (!mtrmng->def_rule[domain]) { 16615 i = 0; 16616 actions[i++] = priv->sh->dr_drop_action; 16617 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16618 (enum modify_reg)mtr_id_reg_c, 0, 0); 16619 misc_mask = flow_dv_matcher_enable(value.buf); 16620 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16621 ret = mlx5_flow_os_create_flow 16622 (mtrmng->def_matcher[domain]->matcher_object, 16623 (void *)&value, i, actions, 16624 &mtrmng->def_rule[domain]); 16625 if (ret) { 16626 DRV_LOG(ERR, "Failed to create meter " 16627 "default drop rule for drop table."); 16628 goto policy_error; 16629 } 16630 } 16631 if (!fm->drop_cnt) 16632 continue; 16633 MLX5_ASSERT(mtrmng->max_mtr_bits); 16634 if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) { 16635 /* Create matchers for Drop. */ 16636 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16637 (enum modify_reg)mtr_id_reg_c, 0, 16638 (mtr_id_mask << mtr_id_offset)); 16639 matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits; 16640 matcher.crc = rte_raw_cksum 16641 ((const void *)matcher.mask.buf, 16642 matcher.mask.size); 16643 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16644 if (!entry) { 16645 DRV_LOG(ERR, 16646 "Failed to register meter drop matcher."); 16647 goto policy_error; 16648 } 16649 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] = 16650 container_of(entry, struct mlx5_flow_dv_matcher, 16651 entry); 16652 } 16653 drop_matcher = 16654 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]; 16655 /* Create drop rule, matching meter_id only. */ 16656 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16657 (enum modify_reg)mtr_id_reg_c, 16658 (mtr_idx << mtr_id_offset), UINT32_MAX); 16659 i = 0; 16660 cnt = flow_dv_counter_get_by_idx(dev, 16661 fm->drop_cnt, NULL); 16662 actions[i++] = cnt->action; 16663 actions[i++] = priv->sh->dr_drop_action; 16664 misc_mask = flow_dv_matcher_enable(value.buf); 16665 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16666 ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object, 16667 (void *)&value, i, actions, 16668 &fm->drop_rule[domain]); 16669 if (ret) { 16670 DRV_LOG(ERR, "Failed to create meter " 16671 "drop rule for drop table."); 16672 goto policy_error; 16673 } 16674 } 16675 return 0; 16676 policy_error: 16677 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16678 if (fm->drop_rule[i]) { 16679 claim_zero(mlx5_flow_os_destroy_flow 16680 (fm->drop_rule[i])); 16681 fm->drop_rule[i] = NULL; 16682 } 16683 } 16684 return -1; 16685 } 16686 16687 static struct mlx5_flow_meter_sub_policy * 16688 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, 16689 struct mlx5_flow_meter_policy *mtr_policy, 16690 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS], 16691 struct mlx5_flow_meter_sub_policy *next_sub_policy, 16692 bool *is_reuse) 16693 { 16694 struct mlx5_priv *priv = dev->data->dev_private; 16695 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16696 uint32_t sub_policy_idx = 0; 16697 uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0}; 16698 uint32_t i, j; 16699 struct mlx5_hrxq *hrxq; 16700 struct mlx5_flow_handle dh; 16701 struct mlx5_meter_policy_action_container *act_cnt; 16702 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16703 uint16_t sub_policy_num; 16704 16705 rte_spinlock_lock(&mtr_policy->sl); 16706 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16707 if (!rss_desc[i]) 16708 continue; 16709 hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]); 16710 if (!hrxq_idx[i]) { 16711 rte_spinlock_unlock(&mtr_policy->sl); 16712 return NULL; 16713 } 16714 } 16715 sub_policy_num = (mtr_policy->sub_policy_num >> 16716 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16717 MLX5_MTR_SUB_POLICY_NUM_MASK; 16718 for (j = 0; j < sub_policy_num; j++) { 16719 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16720 if (rss_desc[i] && 16721 hrxq_idx[i] != 16722 mtr_policy->sub_policys[domain][j]->rix_hrxq[i]) 16723 break; 16724 } 16725 if (i >= MLX5_MTR_RTE_COLORS) { 16726 /* 16727 * Found the sub policy table with 16728 * the same queue per color. 16729 */ 16730 rte_spinlock_unlock(&mtr_policy->sl); 16731 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16732 mlx5_hrxq_release(dev, hrxq_idx[i]); 16733 *is_reuse = true; 16734 return mtr_policy->sub_policys[domain][j]; 16735 } 16736 } 16737 /* Create sub policy. */ 16738 if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) { 16739 /* Reuse the first pre-allocated sub_policy. */ 16740 sub_policy = mtr_policy->sub_policys[domain][0]; 16741 sub_policy_idx = sub_policy->idx; 16742 } else { 16743 sub_policy = mlx5_ipool_zmalloc 16744 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16745 &sub_policy_idx); 16746 if (!sub_policy || 16747 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { 16748 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16749 mlx5_hrxq_release(dev, hrxq_idx[i]); 16750 goto rss_sub_policy_error; 16751 } 16752 sub_policy->idx = sub_policy_idx; 16753 sub_policy->main_policy = mtr_policy; 16754 } 16755 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16756 if (!rss_desc[i]) 16757 continue; 16758 sub_policy->rix_hrxq[i] = hrxq_idx[i]; 16759 if (mtr_policy->is_hierarchy) { 16760 act_cnt = &mtr_policy->act_cnt[i]; 16761 act_cnt->next_sub_policy = next_sub_policy; 16762 mlx5_hrxq_release(dev, hrxq_idx[i]); 16763 } else { 16764 /* 16765 * Overwrite the last action from 16766 * RSS action to Queue action. 16767 */ 16768 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 16769 hrxq_idx[i]); 16770 if (!hrxq) { 16771 DRV_LOG(ERR, "Failed to get policy hrxq"); 16772 goto rss_sub_policy_error; 16773 } 16774 act_cnt = &mtr_policy->act_cnt[i]; 16775 if (act_cnt->rix_mark || act_cnt->modify_hdr) { 16776 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 16777 if (act_cnt->rix_mark) 16778 dh.mark = 1; 16779 dh.fate_action = MLX5_FLOW_FATE_QUEUE; 16780 dh.rix_hrxq = hrxq_idx[i]; 16781 flow_drv_rxq_flags_set(dev, &dh); 16782 } 16783 } 16784 } 16785 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16786 sub_policy, domain)) { 16787 DRV_LOG(ERR, "Failed to create policy " 16788 "rules for ingress domain."); 16789 goto rss_sub_policy_error; 16790 } 16791 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16792 i = (mtr_policy->sub_policy_num >> 16793 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16794 MLX5_MTR_SUB_POLICY_NUM_MASK; 16795 if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) { 16796 DRV_LOG(ERR, "No free sub-policy slot."); 16797 goto rss_sub_policy_error; 16798 } 16799 mtr_policy->sub_policys[domain][i] = sub_policy; 16800 i++; 16801 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 16802 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 16803 mtr_policy->sub_policy_num |= 16804 (i & MLX5_MTR_SUB_POLICY_NUM_MASK) << 16805 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 16806 } 16807 rte_spinlock_unlock(&mtr_policy->sl); 16808 *is_reuse = false; 16809 return sub_policy; 16810 rss_sub_policy_error: 16811 if (sub_policy) { 16812 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 16813 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16814 i = (mtr_policy->sub_policy_num >> 16815 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16816 MLX5_MTR_SUB_POLICY_NUM_MASK; 16817 mtr_policy->sub_policys[domain][i] = NULL; 16818 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16819 sub_policy->idx); 16820 } 16821 } 16822 rte_spinlock_unlock(&mtr_policy->sl); 16823 return NULL; 16824 } 16825 16826 /** 16827 * Find the policy table for prefix table with RSS. 16828 * 16829 * @param[in] dev 16830 * Pointer to Ethernet device. 16831 * @param[in] mtr_policy 16832 * Pointer to meter policy table. 16833 * @param[in] rss_desc 16834 * Pointer to rss_desc 16835 * @return 16836 * Pointer to table set on success, NULL otherwise and rte_errno is set. 16837 */ 16838 static struct mlx5_flow_meter_sub_policy * 16839 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev, 16840 struct mlx5_flow_meter_policy *mtr_policy, 16841 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]) 16842 { 16843 struct mlx5_priv *priv = dev->data->dev_private; 16844 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16845 struct mlx5_flow_meter_info *next_fm; 16846 struct mlx5_flow_meter_policy *next_policy; 16847 struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL; 16848 struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM]; 16849 struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM]; 16850 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16851 bool reuse_sub_policy; 16852 uint32_t i = 0; 16853 uint32_t j = 0; 16854 16855 while (true) { 16856 /* Iterate hierarchy to get all policies in this hierarchy. */ 16857 policies[i++] = mtr_policy; 16858 if (!mtr_policy->is_hierarchy) 16859 break; 16860 if (i >= MLX5_MTR_CHAIN_MAX_NUM) { 16861 DRV_LOG(ERR, "Exceed max meter number in hierarchy."); 16862 return NULL; 16863 } 16864 next_fm = mlx5_flow_meter_find(priv, 16865 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 16866 if (!next_fm) { 16867 DRV_LOG(ERR, "Failed to get next meter in hierarchy."); 16868 return NULL; 16869 } 16870 next_policy = 16871 mlx5_flow_meter_policy_find(dev, next_fm->policy_id, 16872 NULL); 16873 MLX5_ASSERT(next_policy); 16874 mtr_policy = next_policy; 16875 } 16876 while (i) { 16877 /** 16878 * From last policy to the first one in hierarchy, 16879 * create / get the sub policy for each of them. 16880 */ 16881 sub_policy = __flow_dv_meter_get_rss_sub_policy(dev, 16882 policies[--i], 16883 rss_desc, 16884 next_sub_policy, 16885 &reuse_sub_policy); 16886 if (!sub_policy) { 16887 DRV_LOG(ERR, "Failed to get the sub policy."); 16888 goto err_exit; 16889 } 16890 if (!reuse_sub_policy) 16891 sub_policies[j++] = sub_policy; 16892 next_sub_policy = sub_policy; 16893 } 16894 return sub_policy; 16895 err_exit: 16896 while (j) { 16897 uint16_t sub_policy_num; 16898 16899 sub_policy = sub_policies[--j]; 16900 mtr_policy = sub_policy->main_policy; 16901 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 16902 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16903 sub_policy_num = (mtr_policy->sub_policy_num >> 16904 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16905 MLX5_MTR_SUB_POLICY_NUM_MASK; 16906 mtr_policy->sub_policys[domain][sub_policy_num - 1] = 16907 NULL; 16908 sub_policy_num--; 16909 mtr_policy->sub_policy_num &= 16910 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 16911 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)); 16912 mtr_policy->sub_policy_num |= 16913 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) << 16914 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i); 16915 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16916 sub_policy->idx); 16917 } 16918 } 16919 return NULL; 16920 } 16921 16922 /** 16923 * Create the sub policy tag rule for all meters in hierarchy. 16924 * 16925 * @param[in] dev 16926 * Pointer to Ethernet device. 16927 * @param[in] fm 16928 * Meter information table. 16929 * @param[in] src_port 16930 * The src port this extra rule should use. 16931 * @param[in] item 16932 * The src port match item. 16933 * @param[out] error 16934 * Perform verbose error reporting if not NULL. 16935 * @return 16936 * 0 on success, a negative errno value otherwise and rte_errno is set. 16937 */ 16938 static int 16939 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev, 16940 struct mlx5_flow_meter_info *fm, 16941 int32_t src_port, 16942 const struct rte_flow_item *item, 16943 struct rte_flow_error *error) 16944 { 16945 struct mlx5_priv *priv = dev->data->dev_private; 16946 struct mlx5_flow_meter_policy *mtr_policy; 16947 struct mlx5_flow_meter_sub_policy *sub_policy; 16948 struct mlx5_flow_meter_info *next_fm = NULL; 16949 struct mlx5_flow_meter_policy *next_policy; 16950 struct mlx5_flow_meter_sub_policy *next_sub_policy; 16951 struct mlx5_flow_tbl_data_entry *tbl_data; 16952 struct mlx5_sub_policy_color_rule *color_rule; 16953 struct mlx5_meter_policy_acts acts; 16954 uint32_t color_reg_c_idx; 16955 bool mtr_first = (src_port != UINT16_MAX) ? true : false; 16956 struct rte_flow_attr attr = { 16957 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 16958 .priority = 0, 16959 .ingress = 0, 16960 .egress = 0, 16961 .transfer = 1, 16962 .reserved = 0, 16963 }; 16964 uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER; 16965 int i; 16966 16967 mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 16968 MLX5_ASSERT(mtr_policy); 16969 if (!mtr_policy->is_hierarchy) 16970 return 0; 16971 next_fm = mlx5_flow_meter_find(priv, 16972 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 16973 if (!next_fm) { 16974 return rte_flow_error_set(error, EINVAL, 16975 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 16976 "Failed to find next meter in hierarchy."); 16977 } 16978 if (!next_fm->drop_cnt) 16979 goto exit; 16980 color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); 16981 sub_policy = mtr_policy->sub_policys[domain][0]; 16982 for (i = 0; i < RTE_COLORS; i++) { 16983 bool rule_exist = false; 16984 struct mlx5_meter_policy_action_container *act_cnt; 16985 16986 if (i >= RTE_COLOR_YELLOW) 16987 break; 16988 TAILQ_FOREACH(color_rule, 16989 &sub_policy->color_rules[i], next_port) 16990 if (color_rule->src_port == src_port) { 16991 rule_exist = true; 16992 break; 16993 } 16994 if (rule_exist) 16995 continue; 16996 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 16997 sizeof(struct mlx5_sub_policy_color_rule), 16998 0, SOCKET_ID_ANY); 16999 if (!color_rule) 17000 return rte_flow_error_set(error, ENOMEM, 17001 RTE_FLOW_ERROR_TYPE_ACTION, 17002 NULL, "No memory to create tag color rule."); 17003 color_rule->src_port = src_port; 17004 attr.priority = i; 17005 next_policy = mlx5_flow_meter_policy_find(dev, 17006 next_fm->policy_id, NULL); 17007 MLX5_ASSERT(next_policy); 17008 next_sub_policy = next_policy->sub_policys[domain][0]; 17009 tbl_data = container_of(next_sub_policy->tbl_rsc, 17010 struct mlx5_flow_tbl_data_entry, tbl); 17011 act_cnt = &mtr_policy->act_cnt[i]; 17012 if (mtr_first) { 17013 acts.dv_actions[0] = next_fm->meter_action; 17014 acts.dv_actions[1] = act_cnt->modify_hdr->action; 17015 } else { 17016 acts.dv_actions[0] = act_cnt->modify_hdr->action; 17017 acts.dv_actions[1] = next_fm->meter_action; 17018 } 17019 acts.dv_actions[2] = tbl_data->jump.action; 17020 acts.actions_n = 3; 17021 if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) { 17022 next_fm = NULL; 17023 goto err_exit; 17024 } 17025 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 17026 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 17027 &attr, true, item, 17028 &color_rule->matcher, error)) { 17029 rte_flow_error_set(error, errno, 17030 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17031 "Failed to create hierarchy meter matcher."); 17032 goto err_exit; 17033 } 17034 if (__flow_dv_create_policy_flow(dev, color_reg_c_idx, 17035 (enum rte_color)i, 17036 color_rule->matcher->matcher_object, 17037 acts.actions_n, acts.dv_actions, 17038 true, item, 17039 &color_rule->rule, &attr)) { 17040 rte_flow_error_set(error, errno, 17041 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17042 "Failed to create hierarchy meter rule."); 17043 goto err_exit; 17044 } 17045 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 17046 color_rule, next_port); 17047 } 17048 exit: 17049 /** 17050 * Recursive call to iterate all meters in hierarchy and 17051 * create needed rules. 17052 */ 17053 return flow_dv_meter_hierarchy_rule_create(dev, next_fm, 17054 src_port, item, error); 17055 err_exit: 17056 if (color_rule) { 17057 if (color_rule->rule) 17058 mlx5_flow_os_destroy_flow(color_rule->rule); 17059 if (color_rule->matcher) { 17060 struct mlx5_flow_tbl_data_entry *tbl = 17061 container_of(color_rule->matcher->tbl, 17062 typeof(*tbl), tbl); 17063 mlx5_list_unregister(tbl->matchers, 17064 &color_rule->matcher->entry); 17065 } 17066 mlx5_free(color_rule); 17067 } 17068 if (next_fm) 17069 mlx5_flow_meter_detach(priv, next_fm); 17070 return -rte_errno; 17071 } 17072 17073 /** 17074 * Destroy the sub policy table with RX queue. 17075 * 17076 * @param[in] dev 17077 * Pointer to Ethernet device. 17078 * @param[in] mtr_policy 17079 * Pointer to meter policy table. 17080 */ 17081 static void 17082 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, 17083 struct mlx5_flow_meter_policy *mtr_policy) 17084 { 17085 struct mlx5_priv *priv = dev->data->dev_private; 17086 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 17087 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 17088 uint32_t i, j; 17089 uint16_t sub_policy_num, new_policy_num; 17090 17091 rte_spinlock_lock(&mtr_policy->sl); 17092 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17093 switch (mtr_policy->act_cnt[i].fate_action) { 17094 case MLX5_FLOW_FATE_SHARED_RSS: 17095 sub_policy_num = (mtr_policy->sub_policy_num >> 17096 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17097 MLX5_MTR_SUB_POLICY_NUM_MASK; 17098 new_policy_num = sub_policy_num; 17099 for (j = 0; j < sub_policy_num; j++) { 17100 sub_policy = 17101 mtr_policy->sub_policys[domain][j]; 17102 if (sub_policy) { 17103 __flow_dv_destroy_sub_policy_rules(dev, 17104 sub_policy); 17105 if (sub_policy != 17106 mtr_policy->sub_policys[domain][0]) { 17107 mtr_policy->sub_policys[domain][j] = 17108 NULL; 17109 mlx5_ipool_free 17110 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17111 sub_policy->idx); 17112 new_policy_num--; 17113 } 17114 } 17115 } 17116 if (new_policy_num != sub_policy_num) { 17117 mtr_policy->sub_policy_num &= 17118 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17119 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 17120 mtr_policy->sub_policy_num |= 17121 (new_policy_num & 17122 MLX5_MTR_SUB_POLICY_NUM_MASK) << 17123 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 17124 } 17125 break; 17126 case MLX5_FLOW_FATE_QUEUE: 17127 sub_policy = mtr_policy->sub_policys[domain][0]; 17128 __flow_dv_destroy_sub_policy_rules(dev, 17129 sub_policy); 17130 break; 17131 default: 17132 /*Other actions without queue and do nothing*/ 17133 break; 17134 } 17135 } 17136 rte_spinlock_unlock(&mtr_policy->sl); 17137 } 17138 /** 17139 * Check whether the DR drop action is supported on the root table or not. 17140 * 17141 * Create a simple flow with DR drop action on root table to validate 17142 * if DR drop action on root table is supported or not. 17143 * 17144 * @param[in] dev 17145 * Pointer to rte_eth_dev structure. 17146 * 17147 * @return 17148 * 0 on success, a negative errno value otherwise and rte_errno is set. 17149 */ 17150 int 17151 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev) 17152 { 17153 struct mlx5_priv *priv = dev->data->dev_private; 17154 struct mlx5_dev_ctx_shared *sh = priv->sh; 17155 struct mlx5_flow_dv_match_params mask = { 17156 .size = sizeof(mask.buf), 17157 }; 17158 struct mlx5_flow_dv_match_params value = { 17159 .size = sizeof(value.buf), 17160 }; 17161 struct mlx5dv_flow_matcher_attr dv_attr = { 17162 .type = IBV_FLOW_ATTR_NORMAL, 17163 .priority = 0, 17164 .match_criteria_enable = 0, 17165 .match_mask = (void *)&mask, 17166 }; 17167 struct mlx5_flow_tbl_resource *tbl = NULL; 17168 void *matcher = NULL; 17169 void *flow = NULL; 17170 int ret = -1; 17171 17172 tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 17173 0, 0, 0, NULL); 17174 if (!tbl) 17175 goto err; 17176 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17177 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17178 ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj, 17179 &matcher); 17180 if (ret) 17181 goto err; 17182 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17183 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17184 &sh->dr_drop_action, &flow); 17185 err: 17186 /* 17187 * If DR drop action is not supported on root table, flow create will 17188 * be failed with EOPNOTSUPP or EPROTONOSUPPORT. 17189 */ 17190 if (!flow) { 17191 if (matcher && 17192 (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP)) 17193 DRV_LOG(INFO, "DR drop action is not supported in root table."); 17194 else 17195 DRV_LOG(ERR, "Unexpected error in DR drop action support detection"); 17196 ret = -1; 17197 } else { 17198 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17199 } 17200 if (matcher) 17201 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17202 if (tbl) 17203 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17204 return ret; 17205 } 17206 17207 /** 17208 * Validate the batch counter support in root table. 17209 * 17210 * Create a simple flow with invalid counter and drop action on root table to 17211 * validate if batch counter with offset on root table is supported or not. 17212 * 17213 * @param[in] dev 17214 * Pointer to rte_eth_dev structure. 17215 * 17216 * @return 17217 * 0 on success, a negative errno value otherwise and rte_errno is set. 17218 */ 17219 int 17220 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev) 17221 { 17222 struct mlx5_priv *priv = dev->data->dev_private; 17223 struct mlx5_dev_ctx_shared *sh = priv->sh; 17224 struct mlx5_flow_dv_match_params mask = { 17225 .size = sizeof(mask.buf), 17226 }; 17227 struct mlx5_flow_dv_match_params value = { 17228 .size = sizeof(value.buf), 17229 }; 17230 struct mlx5dv_flow_matcher_attr dv_attr = { 17231 .type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS, 17232 .priority = 0, 17233 .match_criteria_enable = 0, 17234 .match_mask = (void *)&mask, 17235 }; 17236 void *actions[2] = { 0 }; 17237 struct mlx5_flow_tbl_resource *tbl = NULL; 17238 struct mlx5_devx_obj *dcs = NULL; 17239 void *matcher = NULL; 17240 void *flow = NULL; 17241 int ret = -1; 17242 17243 tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL, 17244 0, 0, 0, NULL); 17245 if (!tbl) 17246 goto err; 17247 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4); 17248 if (!dcs) 17249 goto err; 17250 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX, 17251 &actions[0]); 17252 if (ret) 17253 goto err; 17254 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17255 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17256 ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj, 17257 &matcher); 17258 if (ret) 17259 goto err; 17260 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17261 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17262 actions, &flow); 17263 err: 17264 /* 17265 * If batch counter with offset is not supported, the driver will not 17266 * validate the invalid offset value, flow create should success. 17267 * In this case, it means batch counter is not supported in root table. 17268 * 17269 * Otherwise, if flow create is failed, counter offset is supported. 17270 */ 17271 if (flow) { 17272 DRV_LOG(INFO, "Batch counter is not supported in root " 17273 "table. Switch to fallback mode."); 17274 rte_errno = ENOTSUP; 17275 ret = -rte_errno; 17276 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17277 } else { 17278 /* Check matcher to make sure validate fail at flow create. */ 17279 if (!matcher || (matcher && errno != EINVAL)) 17280 DRV_LOG(ERR, "Unexpected error in counter offset " 17281 "support detection"); 17282 ret = 0; 17283 } 17284 if (actions[0]) 17285 claim_zero(mlx5_flow_os_destroy_flow_action(actions[0])); 17286 if (matcher) 17287 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17288 if (tbl) 17289 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17290 if (dcs) 17291 claim_zero(mlx5_devx_cmd_destroy(dcs)); 17292 return ret; 17293 } 17294 17295 /** 17296 * Query a devx counter. 17297 * 17298 * @param[in] dev 17299 * Pointer to the Ethernet device structure. 17300 * @param[in] cnt 17301 * Index to the flow counter. 17302 * @param[in] clear 17303 * Set to clear the counter statistics. 17304 * @param[out] pkts 17305 * The statistics value of packets. 17306 * @param[out] bytes 17307 * The statistics value of bytes. 17308 * 17309 * @return 17310 * 0 on success, otherwise return -1. 17311 */ 17312 static int 17313 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear, 17314 uint64_t *pkts, uint64_t *bytes) 17315 { 17316 struct mlx5_priv *priv = dev->data->dev_private; 17317 struct mlx5_flow_counter *cnt; 17318 uint64_t inn_pkts, inn_bytes; 17319 int ret; 17320 17321 if (!priv->config.devx) 17322 return -1; 17323 17324 ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes); 17325 if (ret) 17326 return -1; 17327 cnt = flow_dv_counter_get_by_idx(dev, counter, NULL); 17328 *pkts = inn_pkts - cnt->hits; 17329 *bytes = inn_bytes - cnt->bytes; 17330 if (clear) { 17331 cnt->hits = inn_pkts; 17332 cnt->bytes = inn_bytes; 17333 } 17334 return 0; 17335 } 17336 17337 /** 17338 * Get aged-out flows. 17339 * 17340 * @param[in] dev 17341 * Pointer to the Ethernet device structure. 17342 * @param[in] context 17343 * The address of an array of pointers to the aged-out flows contexts. 17344 * @param[in] nb_contexts 17345 * The length of context array pointers. 17346 * @param[out] error 17347 * Perform verbose error reporting if not NULL. Initialized in case of 17348 * error only. 17349 * 17350 * @return 17351 * how many contexts get in success, otherwise negative errno value. 17352 * if nb_contexts is 0, return the amount of all aged contexts. 17353 * if nb_contexts is not 0 , return the amount of aged flows reported 17354 * in the context array. 17355 * @note: only stub for now 17356 */ 17357 static int 17358 flow_dv_get_aged_flows(struct rte_eth_dev *dev, 17359 void **context, 17360 uint32_t nb_contexts, 17361 struct rte_flow_error *error) 17362 { 17363 struct mlx5_priv *priv = dev->data->dev_private; 17364 struct mlx5_age_info *age_info; 17365 struct mlx5_age_param *age_param; 17366 struct mlx5_flow_counter *counter; 17367 struct mlx5_aso_age_action *act; 17368 int nb_flows = 0; 17369 17370 if (nb_contexts && !context) 17371 return rte_flow_error_set(error, EINVAL, 17372 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17373 NULL, "empty context"); 17374 age_info = GET_PORT_AGE_INFO(priv); 17375 rte_spinlock_lock(&age_info->aged_sl); 17376 LIST_FOREACH(act, &age_info->aged_aso, next) { 17377 nb_flows++; 17378 if (nb_contexts) { 17379 context[nb_flows - 1] = 17380 act->age_params.context; 17381 if (!(--nb_contexts)) 17382 break; 17383 } 17384 } 17385 TAILQ_FOREACH(counter, &age_info->aged_counters, next) { 17386 nb_flows++; 17387 if (nb_contexts) { 17388 age_param = MLX5_CNT_TO_AGE(counter); 17389 context[nb_flows - 1] = age_param->context; 17390 if (!(--nb_contexts)) 17391 break; 17392 } 17393 } 17394 rte_spinlock_unlock(&age_info->aged_sl); 17395 MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); 17396 return nb_flows; 17397 } 17398 17399 /* 17400 * Mutex-protected thunk to lock-free flow_dv_counter_alloc(). 17401 */ 17402 static uint32_t 17403 flow_dv_counter_allocate(struct rte_eth_dev *dev) 17404 { 17405 return flow_dv_counter_alloc(dev, 0); 17406 } 17407 17408 /** 17409 * Validate indirect action. 17410 * Dispatcher for action type specific validation. 17411 * 17412 * @param[in] dev 17413 * Pointer to the Ethernet device structure. 17414 * @param[in] conf 17415 * Indirect action configuration. 17416 * @param[in] action 17417 * The indirect action object to validate. 17418 * @param[out] error 17419 * Perform verbose error reporting if not NULL. Initialized in case of 17420 * error only. 17421 * 17422 * @return 17423 * 0 on success, otherwise negative errno value. 17424 */ 17425 static int 17426 flow_dv_action_validate(struct rte_eth_dev *dev, 17427 const struct rte_flow_indir_action_conf *conf, 17428 const struct rte_flow_action *action, 17429 struct rte_flow_error *err) 17430 { 17431 struct mlx5_priv *priv = dev->data->dev_private; 17432 17433 RTE_SET_USED(conf); 17434 switch (action->type) { 17435 case RTE_FLOW_ACTION_TYPE_RSS: 17436 /* 17437 * priv->obj_ops is set according to driver capabilities. 17438 * When DevX capabilities are 17439 * sufficient, it is set to devx_obj_ops. 17440 * Otherwise, it is set to ibv_obj_ops. 17441 * ibv_obj_ops doesn't support ind_table_modify operation. 17442 * In this case the indirect RSS action can't be used. 17443 */ 17444 if (priv->obj_ops.ind_table_modify == NULL) 17445 return rte_flow_error_set 17446 (err, ENOTSUP, 17447 RTE_FLOW_ERROR_TYPE_ACTION, 17448 NULL, 17449 "Indirect RSS action not supported"); 17450 return mlx5_validate_action_rss(dev, action, err); 17451 case RTE_FLOW_ACTION_TYPE_AGE: 17452 if (!priv->sh->aso_age_mng) 17453 return rte_flow_error_set(err, ENOTSUP, 17454 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17455 NULL, 17456 "Indirect age action not supported"); 17457 return flow_dv_validate_action_age(0, action, dev, err); 17458 case RTE_FLOW_ACTION_TYPE_COUNT: 17459 /* 17460 * There are two mechanisms to share the action count. 17461 * The old mechanism uses the shared field to share, while the 17462 * new mechanism uses the indirect action API. 17463 * This validation comes to make sure that the two mechanisms 17464 * are not combined. 17465 */ 17466 if (is_shared_action_count(action)) 17467 return rte_flow_error_set(err, ENOTSUP, 17468 RTE_FLOW_ERROR_TYPE_ACTION, 17469 NULL, 17470 "Mix shared and indirect counter is not supported"); 17471 return flow_dv_validate_action_count(dev, true, 0, err); 17472 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 17473 if (!priv->sh->ct_aso_en) 17474 return rte_flow_error_set(err, ENOTSUP, 17475 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17476 "ASO CT is not supported"); 17477 return mlx5_validate_action_ct(dev, action->conf, err); 17478 default: 17479 return rte_flow_error_set(err, ENOTSUP, 17480 RTE_FLOW_ERROR_TYPE_ACTION, 17481 NULL, 17482 "action type not supported"); 17483 } 17484 } 17485 17486 /* 17487 * Check if the RSS configurations for colors of a meter policy match 17488 * each other, except the queues. 17489 * 17490 * @param[in] r1 17491 * Pointer to the first RSS flow action. 17492 * @param[in] r2 17493 * Pointer to the second RSS flow action. 17494 * 17495 * @return 17496 * 0 on match, 1 on conflict. 17497 */ 17498 static inline int 17499 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1, 17500 const struct rte_flow_action_rss *r2) 17501 { 17502 if (!r1 || !r2) 17503 return 0; 17504 if (r1->func != r2->func || r1->level != r2->level || 17505 r1->types != r2->types || r1->key_len != r2->key_len || 17506 memcmp(r1->key, r2->key, r1->key_len)) 17507 return 1; 17508 return 0; 17509 } 17510 17511 /** 17512 * Validate the meter hierarchy chain for meter policy. 17513 * 17514 * @param[in] dev 17515 * Pointer to the Ethernet device structure. 17516 * @param[in] meter_id 17517 * Meter id. 17518 * @param[in] action_flags 17519 * Holds the actions detected until now. 17520 * @param[out] is_rss 17521 * Is RSS or not. 17522 * @param[out] hierarchy_domain 17523 * The domain bitmap for hierarchy policy. 17524 * @param[out] error 17525 * Perform verbose error reporting if not NULL. Initialized in case of 17526 * error only. 17527 * 17528 * @return 17529 * 0 on success, otherwise negative errno value with error set. 17530 */ 17531 static int 17532 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, 17533 uint32_t meter_id, 17534 uint64_t action_flags, 17535 bool *is_rss, 17536 uint8_t *hierarchy_domain, 17537 struct rte_mtr_error *error) 17538 { 17539 struct mlx5_priv *priv = dev->data->dev_private; 17540 struct mlx5_flow_meter_info *fm; 17541 struct mlx5_flow_meter_policy *policy; 17542 uint8_t cnt = 1; 17543 17544 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 17545 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17546 return -rte_mtr_error_set(error, EINVAL, 17547 RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, 17548 NULL, 17549 "Multiple fate actions not supported."); 17550 *hierarchy_domain = 0; 17551 while (true) { 17552 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 17553 if (!fm) 17554 return -rte_mtr_error_set(error, EINVAL, 17555 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17556 "Meter not found in meter hierarchy."); 17557 if (fm->def_policy) 17558 return -rte_mtr_error_set(error, EINVAL, 17559 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17560 "Non termination meter not supported in hierarchy."); 17561 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 17562 MLX5_ASSERT(policy); 17563 /** 17564 * Only inherit the supported domains of the first meter in 17565 * hierarchy. 17566 * One meter supports at least one domain. 17567 */ 17568 if (!*hierarchy_domain) { 17569 if (policy->transfer) 17570 *hierarchy_domain |= 17571 MLX5_MTR_DOMAIN_TRANSFER_BIT; 17572 if (policy->ingress) 17573 *hierarchy_domain |= 17574 MLX5_MTR_DOMAIN_INGRESS_BIT; 17575 if (policy->egress) 17576 *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT; 17577 } 17578 if (!policy->is_hierarchy) { 17579 *is_rss = policy->is_rss; 17580 break; 17581 } 17582 meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id; 17583 if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM) 17584 return -rte_mtr_error_set(error, EINVAL, 17585 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 17586 "Exceed max hierarchy meter number."); 17587 } 17588 return 0; 17589 } 17590 17591 /** 17592 * Validate meter policy actions. 17593 * Dispatcher for action type specific validation. 17594 * 17595 * @param[in] dev 17596 * Pointer to the Ethernet device structure. 17597 * @param[in] action 17598 * The meter policy action object to validate. 17599 * @param[in] attr 17600 * Attributes of flow to determine steering domain. 17601 * @param[out] error 17602 * Perform verbose error reporting if not NULL. Initialized in case of 17603 * error only. 17604 * 17605 * @return 17606 * 0 on success, otherwise negative errno value. 17607 */ 17608 static int 17609 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, 17610 const struct rte_flow_action *actions[RTE_COLORS], 17611 struct rte_flow_attr *attr, 17612 bool *is_rss, 17613 uint8_t *domain_bitmap, 17614 uint8_t *policy_mode, 17615 struct rte_mtr_error *error) 17616 { 17617 struct mlx5_priv *priv = dev->data->dev_private; 17618 struct mlx5_dev_config *dev_conf = &priv->config; 17619 const struct rte_flow_action *act; 17620 uint64_t action_flags[RTE_COLORS] = {0}; 17621 int actions_n; 17622 int i, ret; 17623 struct rte_flow_error flow_err; 17624 uint8_t domain_color[RTE_COLORS] = {0}; 17625 uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT; 17626 uint8_t hierarchy_domain = 0; 17627 const struct rte_flow_action_meter *mtr; 17628 bool def_green = false; 17629 bool def_yellow = false; 17630 const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; 17631 17632 if (!priv->config.dv_esw_en) 17633 def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 17634 *domain_bitmap = def_domain; 17635 /* Red color could only support DROP action. */ 17636 if (!actions[RTE_COLOR_RED] || 17637 actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) 17638 return -rte_mtr_error_set(error, ENOTSUP, 17639 RTE_MTR_ERROR_TYPE_METER_POLICY, 17640 NULL, "Red color only supports drop action."); 17641 /* 17642 * Check default policy actions: 17643 * Green / Yellow: no action, Red: drop action 17644 * Either G or Y will trigger default policy actions to be created. 17645 */ 17646 if (!actions[RTE_COLOR_GREEN] || 17647 actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) 17648 def_green = true; 17649 if (!actions[RTE_COLOR_YELLOW] || 17650 actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) 17651 def_yellow = true; 17652 if (def_green && def_yellow) { 17653 *policy_mode = MLX5_MTR_POLICY_MODE_DEF; 17654 return 0; 17655 } else if (!def_green && def_yellow) { 17656 *policy_mode = MLX5_MTR_POLICY_MODE_OG; 17657 } else if (def_green && !def_yellow) { 17658 *policy_mode = MLX5_MTR_POLICY_MODE_OY; 17659 } 17660 /* Set to empty string in case of NULL pointer access by user. */ 17661 flow_err.message = ""; 17662 for (i = 0; i < RTE_COLORS; i++) { 17663 act = actions[i]; 17664 for (action_flags[i] = 0, actions_n = 0; 17665 act && act->type != RTE_FLOW_ACTION_TYPE_END; 17666 act++) { 17667 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 17668 return -rte_mtr_error_set(error, ENOTSUP, 17669 RTE_MTR_ERROR_TYPE_METER_POLICY, 17670 NULL, "too many actions"); 17671 switch (act->type) { 17672 case RTE_FLOW_ACTION_TYPE_PORT_ID: 17673 if (!priv->config.dv_esw_en) 17674 return -rte_mtr_error_set(error, 17675 ENOTSUP, 17676 RTE_MTR_ERROR_TYPE_METER_POLICY, 17677 NULL, "PORT action validate check" 17678 " fail for ESW disable"); 17679 ret = flow_dv_validate_action_port_id(dev, 17680 action_flags[i], 17681 act, attr, &flow_err); 17682 if (ret) 17683 return -rte_mtr_error_set(error, 17684 ENOTSUP, 17685 RTE_MTR_ERROR_TYPE_METER_POLICY, 17686 NULL, flow_err.message ? 17687 flow_err.message : 17688 "PORT action validate check fail"); 17689 ++actions_n; 17690 action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID; 17691 break; 17692 case RTE_FLOW_ACTION_TYPE_MARK: 17693 ret = flow_dv_validate_action_mark(dev, act, 17694 action_flags[i], 17695 attr, &flow_err); 17696 if (ret < 0) 17697 return -rte_mtr_error_set(error, 17698 ENOTSUP, 17699 RTE_MTR_ERROR_TYPE_METER_POLICY, 17700 NULL, flow_err.message ? 17701 flow_err.message : 17702 "Mark action validate check fail"); 17703 if (dev_conf->dv_xmeta_en != 17704 MLX5_XMETA_MODE_LEGACY) 17705 return -rte_mtr_error_set(error, 17706 ENOTSUP, 17707 RTE_MTR_ERROR_TYPE_METER_POLICY, 17708 NULL, "Extend MARK action is " 17709 "not supported. Please try use " 17710 "default policy for meter."); 17711 action_flags[i] |= MLX5_FLOW_ACTION_MARK; 17712 ++actions_n; 17713 break; 17714 case RTE_FLOW_ACTION_TYPE_SET_TAG: 17715 ret = flow_dv_validate_action_set_tag(dev, 17716 act, action_flags[i], 17717 attr, &flow_err); 17718 if (ret) 17719 return -rte_mtr_error_set(error, 17720 ENOTSUP, 17721 RTE_MTR_ERROR_TYPE_METER_POLICY, 17722 NULL, flow_err.message ? 17723 flow_err.message : 17724 "Set tag action validate check fail"); 17725 action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG; 17726 ++actions_n; 17727 break; 17728 case RTE_FLOW_ACTION_TYPE_DROP: 17729 ret = mlx5_flow_validate_action_drop 17730 (action_flags[i], attr, &flow_err); 17731 if (ret < 0) 17732 return -rte_mtr_error_set(error, 17733 ENOTSUP, 17734 RTE_MTR_ERROR_TYPE_METER_POLICY, 17735 NULL, flow_err.message ? 17736 flow_err.message : 17737 "Drop action validate check fail"); 17738 action_flags[i] |= MLX5_FLOW_ACTION_DROP; 17739 ++actions_n; 17740 break; 17741 case RTE_FLOW_ACTION_TYPE_QUEUE: 17742 /* 17743 * Check whether extensive 17744 * metadata feature is engaged. 17745 */ 17746 if (dev_conf->dv_flow_en && 17747 (dev_conf->dv_xmeta_en != 17748 MLX5_XMETA_MODE_LEGACY) && 17749 mlx5_flow_ext_mreg_supported(dev)) 17750 return -rte_mtr_error_set(error, 17751 ENOTSUP, 17752 RTE_MTR_ERROR_TYPE_METER_POLICY, 17753 NULL, "Queue action with meta " 17754 "is not supported. Please try use " 17755 "default policy for meter."); 17756 ret = mlx5_flow_validate_action_queue(act, 17757 action_flags[i], dev, 17758 attr, &flow_err); 17759 if (ret < 0) 17760 return -rte_mtr_error_set(error, 17761 ENOTSUP, 17762 RTE_MTR_ERROR_TYPE_METER_POLICY, 17763 NULL, flow_err.message ? 17764 flow_err.message : 17765 "Queue action validate check fail"); 17766 action_flags[i] |= MLX5_FLOW_ACTION_QUEUE; 17767 ++actions_n; 17768 break; 17769 case RTE_FLOW_ACTION_TYPE_RSS: 17770 if (dev_conf->dv_flow_en && 17771 (dev_conf->dv_xmeta_en != 17772 MLX5_XMETA_MODE_LEGACY) && 17773 mlx5_flow_ext_mreg_supported(dev)) 17774 return -rte_mtr_error_set(error, 17775 ENOTSUP, 17776 RTE_MTR_ERROR_TYPE_METER_POLICY, 17777 NULL, "RSS action with meta " 17778 "is not supported. Please try use " 17779 "default policy for meter."); 17780 ret = mlx5_validate_action_rss(dev, act, 17781 &flow_err); 17782 if (ret < 0) 17783 return -rte_mtr_error_set(error, 17784 ENOTSUP, 17785 RTE_MTR_ERROR_TYPE_METER_POLICY, 17786 NULL, flow_err.message ? 17787 flow_err.message : 17788 "RSS action validate check fail"); 17789 action_flags[i] |= MLX5_FLOW_ACTION_RSS; 17790 ++actions_n; 17791 /* Either G or Y will set the RSS. */ 17792 rss_color[i] = act->conf; 17793 break; 17794 case RTE_FLOW_ACTION_TYPE_JUMP: 17795 ret = flow_dv_validate_action_jump(dev, 17796 NULL, act, action_flags[i], 17797 attr, true, &flow_err); 17798 if (ret) 17799 return -rte_mtr_error_set(error, 17800 ENOTSUP, 17801 RTE_MTR_ERROR_TYPE_METER_POLICY, 17802 NULL, flow_err.message ? 17803 flow_err.message : 17804 "Jump action validate check fail"); 17805 ++actions_n; 17806 action_flags[i] |= MLX5_FLOW_ACTION_JUMP; 17807 break; 17808 /* 17809 * Only the last meter in the hierarchy will support 17810 * the YELLOW color steering. Then in the meter policy 17811 * actions list, there should be no other meter inside. 17812 */ 17813 case RTE_FLOW_ACTION_TYPE_METER: 17814 if (i != RTE_COLOR_GREEN) 17815 return -rte_mtr_error_set(error, 17816 ENOTSUP, 17817 RTE_MTR_ERROR_TYPE_METER_POLICY, 17818 NULL, 17819 "Meter hierarchy only supports GREEN color."); 17820 if (*policy_mode != MLX5_MTR_POLICY_MODE_OG) 17821 return -rte_mtr_error_set(error, 17822 ENOTSUP, 17823 RTE_MTR_ERROR_TYPE_METER_POLICY, 17824 NULL, 17825 "No yellow policy should be provided in meter hierarchy."); 17826 mtr = act->conf; 17827 ret = flow_dv_validate_policy_mtr_hierarchy(dev, 17828 mtr->mtr_id, 17829 action_flags[i], 17830 is_rss, 17831 &hierarchy_domain, 17832 error); 17833 if (ret) 17834 return ret; 17835 ++actions_n; 17836 action_flags[i] |= 17837 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 17838 break; 17839 default: 17840 return -rte_mtr_error_set(error, ENOTSUP, 17841 RTE_MTR_ERROR_TYPE_METER_POLICY, 17842 NULL, 17843 "Doesn't support optional action"); 17844 } 17845 } 17846 if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) 17847 domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT; 17848 else if ((action_flags[i] & 17849 (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || 17850 (action_flags[i] & MLX5_FLOW_ACTION_MARK)) 17851 /* 17852 * Only support MLX5_XMETA_MODE_LEGACY 17853 * so MARK action is only in ingress domain. 17854 */ 17855 domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT; 17856 else 17857 domain_color[i] = def_domain; 17858 if (action_flags[i] & 17859 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 17860 domain_color[i] &= hierarchy_domain; 17861 /* 17862 * Non-termination actions only support NIC Tx domain. 17863 * The adjustion should be skipped when there is no 17864 * action or only END is provided. The default domains 17865 * bit-mask is set to find the MIN intersection. 17866 * The action flags checking should also be skipped. 17867 */ 17868 if ((def_green && i == RTE_COLOR_GREEN) || 17869 (def_yellow && i == RTE_COLOR_YELLOW)) 17870 continue; 17871 /* 17872 * Validate the drop action mutual exclusion 17873 * with other actions. Drop action is mutually-exclusive 17874 * with any other action, except for Count action. 17875 */ 17876 if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) && 17877 (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) { 17878 return -rte_mtr_error_set(error, ENOTSUP, 17879 RTE_MTR_ERROR_TYPE_METER_POLICY, 17880 NULL, "Drop action is mutually-exclusive " 17881 "with any other action"); 17882 } 17883 /* Eswitch has few restrictions on using items and actions */ 17884 if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) { 17885 if (!mlx5_flow_ext_mreg_supported(dev) && 17886 action_flags[i] & MLX5_FLOW_ACTION_MARK) 17887 return -rte_mtr_error_set(error, ENOTSUP, 17888 RTE_MTR_ERROR_TYPE_METER_POLICY, 17889 NULL, "unsupported action MARK"); 17890 if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE) 17891 return -rte_mtr_error_set(error, ENOTSUP, 17892 RTE_MTR_ERROR_TYPE_METER_POLICY, 17893 NULL, "unsupported action QUEUE"); 17894 if (action_flags[i] & MLX5_FLOW_ACTION_RSS) 17895 return -rte_mtr_error_set(error, ENOTSUP, 17896 RTE_MTR_ERROR_TYPE_METER_POLICY, 17897 NULL, "unsupported action RSS"); 17898 if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17899 return -rte_mtr_error_set(error, ENOTSUP, 17900 RTE_MTR_ERROR_TYPE_METER_POLICY, 17901 NULL, "no fate action is found"); 17902 } else { 17903 if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) && 17904 (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) { 17905 if ((domain_color[i] & 17906 MLX5_MTR_DOMAIN_EGRESS_BIT)) 17907 domain_color[i] = 17908 MLX5_MTR_DOMAIN_EGRESS_BIT; 17909 else 17910 return -rte_mtr_error_set(error, 17911 ENOTSUP, 17912 RTE_MTR_ERROR_TYPE_METER_POLICY, 17913 NULL, 17914 "no fate action is found"); 17915 } 17916 } 17917 } 17918 /* If both colors have RSS, the attributes should be the same. */ 17919 if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN], 17920 rss_color[RTE_COLOR_YELLOW])) 17921 return -rte_mtr_error_set(error, EINVAL, 17922 RTE_MTR_ERROR_TYPE_METER_POLICY, 17923 NULL, "policy RSS attr conflict"); 17924 if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW]) 17925 *is_rss = true; 17926 /* "domain_color[C]" is non-zero for each color, default is ALL. */ 17927 if (!def_green && !def_yellow && 17928 domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] && 17929 !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) && 17930 !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP)) 17931 return -rte_mtr_error_set(error, EINVAL, 17932 RTE_MTR_ERROR_TYPE_METER_POLICY, 17933 NULL, "policy domains conflict"); 17934 /* 17935 * At least one color policy is listed in the actions, the domains 17936 * to be supported should be the intersection. 17937 */ 17938 *domain_bitmap = domain_color[RTE_COLOR_GREEN] & 17939 domain_color[RTE_COLOR_YELLOW]; 17940 return 0; 17941 } 17942 17943 static int 17944 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags) 17945 { 17946 struct mlx5_priv *priv = dev->data->dev_private; 17947 int ret = 0; 17948 17949 if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) { 17950 ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain, 17951 flags); 17952 if (ret != 0) 17953 return ret; 17954 } 17955 if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) { 17956 ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags); 17957 if (ret != 0) 17958 return ret; 17959 } 17960 if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) { 17961 ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags); 17962 if (ret != 0) 17963 return ret; 17964 } 17965 return 0; 17966 } 17967 17968 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { 17969 .validate = flow_dv_validate, 17970 .prepare = flow_dv_prepare, 17971 .translate = flow_dv_translate, 17972 .apply = flow_dv_apply, 17973 .remove = flow_dv_remove, 17974 .destroy = flow_dv_destroy, 17975 .query = flow_dv_query, 17976 .create_mtr_tbls = flow_dv_create_mtr_tbls, 17977 .destroy_mtr_tbls = flow_dv_destroy_mtr_tbls, 17978 .destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls, 17979 .create_meter = flow_dv_mtr_alloc, 17980 .free_meter = flow_dv_aso_mtr_release_to_pool, 17981 .validate_mtr_acts = flow_dv_validate_mtr_policy_acts, 17982 .create_mtr_acts = flow_dv_create_mtr_policy_acts, 17983 .destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts, 17984 .create_policy_rules = flow_dv_create_policy_rules, 17985 .destroy_policy_rules = flow_dv_destroy_policy_rules, 17986 .create_def_policy = flow_dv_create_def_policy, 17987 .destroy_def_policy = flow_dv_destroy_def_policy, 17988 .meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare, 17989 .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create, 17990 .destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq, 17991 .counter_alloc = flow_dv_counter_allocate, 17992 .counter_free = flow_dv_counter_free, 17993 .counter_query = flow_dv_counter_query, 17994 .get_aged_flows = flow_dv_get_aged_flows, 17995 .action_validate = flow_dv_action_validate, 17996 .action_create = flow_dv_action_create, 17997 .action_destroy = flow_dv_action_destroy, 17998 .action_update = flow_dv_action_update, 17999 .action_query = flow_dv_action_query, 18000 .sync_domain = flow_dv_sync_domain, 18001 }; 18002 18003 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ 18004 18005