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 <bus_pci_driver.h> 19 #include <rte_ip.h> 20 #include <rte_gre.h> 21 #include <rte_vxlan.h> 22 #include <rte_gtp.h> 23 #include <rte_eal_paging.h> 24 #include <rte_mpls.h> 25 #include <rte_mtr.h> 26 #include <rte_mtr_driver.h> 27 #include <rte_tailq.h> 28 29 #include <mlx5_glue.h> 30 #include <mlx5_devx_cmds.h> 31 #include <mlx5_prm.h> 32 #include <mlx5_malloc.h> 33 34 #include "mlx5_defs.h" 35 #include "mlx5.h" 36 #include "mlx5_common_os.h" 37 #include "mlx5_flow.h" 38 #include "mlx5_flow_os.h" 39 #include "mlx5_rx.h" 40 #include "mlx5_tx.h" 41 #include "rte_pmd_mlx5.h" 42 43 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) 44 45 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS 46 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0 47 #endif 48 49 #ifndef HAVE_MLX5DV_DR_ESWITCH 50 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB 51 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0 52 #endif 53 #endif 54 55 #ifndef HAVE_MLX5DV_DR 56 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1 57 #endif 58 59 /* VLAN header definitions */ 60 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13 61 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT) 62 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff 63 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK) 64 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK) 65 66 #define MLX5_ITEM_VALID(item, key_type) \ 67 (((MLX5_SET_MATCHER_SW & (key_type)) && !((item)->spec)) || \ 68 ((MLX5_SET_MATCHER_HS_V == (key_type)) && !((item)->spec)) || \ 69 ((MLX5_SET_MATCHER_HS_M == (key_type)) && !((item)->mask))) 70 71 #define MLX5_ITEM_UPDATE(item, key_type, v, m, gm) \ 72 do { \ 73 if ((key_type) == MLX5_SET_MATCHER_SW_V) { \ 74 v = (item)->spec; \ 75 m = (item)->mask ? (item)->mask : (gm); \ 76 } else if ((key_type) == MLX5_SET_MATCHER_HS_V) { \ 77 v = (item)->spec; \ 78 m = (v); \ 79 } else { \ 80 v = (item)->mask ? (item)->mask : (gm); \ 81 m = (v); \ 82 } \ 83 } while (0) 84 85 union flow_dv_attr { 86 struct { 87 uint32_t valid:1; 88 uint32_t ipv4:1; 89 uint32_t ipv6:1; 90 uint32_t tcp:1; 91 uint32_t udp:1; 92 uint32_t reserved:27; 93 }; 94 uint32_t attr; 95 }; 96 97 static int 98 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 99 uint32_t encap_decap_idx); 100 101 static int 102 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 103 uint32_t port_id); 104 static void 105 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss); 106 107 static int 108 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 109 uint32_t rix_jump); 110 111 /** 112 * Initialize flow attributes structure according to flow items' types. 113 * 114 * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel 115 * mode. For tunnel mode, the items to be modified are the outermost ones. 116 * 117 * @param[in] item 118 * Pointer to item specification. 119 * @param[out] attr 120 * Pointer to flow attributes structure. 121 * @param[in] dev_flow 122 * Pointer to the sub flow. 123 * @param[in] tunnel_decap 124 * Whether action is after tunnel decapsulation. 125 */ 126 static void 127 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr, 128 struct mlx5_flow *dev_flow, bool tunnel_decap) 129 { 130 uint64_t layers = dev_flow->handle->layers; 131 bool tunnel_match = false; 132 133 /* 134 * If layers is already initialized, it means this dev_flow is the 135 * suffix flow, the layers flags is set by the prefix flow. Need to 136 * use the layer flags from prefix flow as the suffix flow may not 137 * have the user defined items as the flow is split. 138 */ 139 if (layers) { 140 if (tunnel_decap) { 141 /* 142 * If decap action before modify, it means the driver 143 * should take the inner as outer for the modify actions. 144 */ 145 layers = ((layers >> 6) & MLX5_FLOW_LAYER_OUTER); 146 } 147 if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4) 148 attr->ipv4 = 1; 149 else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6) 150 attr->ipv6 = 1; 151 if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP) 152 attr->tcp = 1; 153 else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP) 154 attr->udp = 1; 155 attr->valid = 1; 156 return; 157 } 158 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 159 uint8_t next_protocol = 0xff; 160 switch (item->type) { 161 case RTE_FLOW_ITEM_TYPE_GRE: 162 case RTE_FLOW_ITEM_TYPE_NVGRE: 163 case RTE_FLOW_ITEM_TYPE_VXLAN: 164 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 165 case RTE_FLOW_ITEM_TYPE_GENEVE: 166 case RTE_FLOW_ITEM_TYPE_MPLS: 167 case RTE_FLOW_ITEM_TYPE_GTP: 168 if (tunnel_decap) { 169 attr->attr = 0; 170 tunnel_match = true; 171 } 172 break; 173 case RTE_FLOW_ITEM_TYPE_IPV4: 174 if (!attr->ipv6) 175 attr->ipv4 = 1; 176 if (item->mask != NULL && 177 ((const struct rte_flow_item_ipv4 *) 178 item->mask)->hdr.next_proto_id) 179 next_protocol = 180 ((const struct rte_flow_item_ipv4 *) 181 (item->spec))->hdr.next_proto_id & 182 ((const struct rte_flow_item_ipv4 *) 183 (item->mask))->hdr.next_proto_id; 184 if ((next_protocol == IPPROTO_IPIP || 185 next_protocol == IPPROTO_IPV6) && tunnel_decap && 186 !tunnel_match) 187 attr->attr = 0; 188 break; 189 case RTE_FLOW_ITEM_TYPE_IPV6: 190 if (!attr->ipv4) 191 attr->ipv6 = 1; 192 if (item->mask != NULL && 193 ((const struct rte_flow_item_ipv6 *) 194 item->mask)->hdr.proto) 195 next_protocol = 196 ((const struct rte_flow_item_ipv6 *) 197 (item->spec))->hdr.proto & 198 ((const struct rte_flow_item_ipv6 *) 199 (item->mask))->hdr.proto; 200 if ((next_protocol == IPPROTO_IPIP || 201 next_protocol == IPPROTO_IPV6) && tunnel_decap && 202 !tunnel_match) 203 attr->attr = 0; 204 break; 205 case RTE_FLOW_ITEM_TYPE_UDP: 206 if (!attr->tcp) 207 attr->udp = 1; 208 break; 209 case RTE_FLOW_ITEM_TYPE_TCP: 210 if (!attr->udp) 211 attr->tcp = 1; 212 break; 213 default: 214 break; 215 } 216 } 217 attr->valid = 1; 218 } 219 220 struct field_modify_info modify_eth[] = { 221 {4, 0, MLX5_MODI_OUT_DMAC_47_16}, 222 {2, 4, MLX5_MODI_OUT_DMAC_15_0}, 223 {4, 6, MLX5_MODI_OUT_SMAC_47_16}, 224 {2, 10, MLX5_MODI_OUT_SMAC_15_0}, 225 {0, 0, 0}, 226 }; 227 228 struct field_modify_info modify_vlan_out_first_vid[] = { 229 /* Size in bits !!! */ 230 {12, 0, MLX5_MODI_OUT_FIRST_VID}, 231 {0, 0, 0}, 232 }; 233 234 struct field_modify_info modify_ipv4[] = { 235 {1, 1, MLX5_MODI_OUT_IP_DSCP}, 236 {1, 8, MLX5_MODI_OUT_IPV4_TTL}, 237 {4, 12, MLX5_MODI_OUT_SIPV4}, 238 {4, 16, MLX5_MODI_OUT_DIPV4}, 239 {0, 0, 0}, 240 }; 241 242 struct field_modify_info modify_ipv6[] = { 243 {1, 0, MLX5_MODI_OUT_IP_DSCP}, 244 {1, 7, MLX5_MODI_OUT_IPV6_HOPLIMIT}, 245 {4, 8, MLX5_MODI_OUT_SIPV6_127_96}, 246 {4, 12, MLX5_MODI_OUT_SIPV6_95_64}, 247 {4, 16, MLX5_MODI_OUT_SIPV6_63_32}, 248 {4, 20, MLX5_MODI_OUT_SIPV6_31_0}, 249 {4, 24, MLX5_MODI_OUT_DIPV6_127_96}, 250 {4, 28, MLX5_MODI_OUT_DIPV6_95_64}, 251 {4, 32, MLX5_MODI_OUT_DIPV6_63_32}, 252 {4, 36, MLX5_MODI_OUT_DIPV6_31_0}, 253 {0, 0, 0}, 254 }; 255 256 struct field_modify_info modify_udp[] = { 257 {2, 0, MLX5_MODI_OUT_UDP_SPORT}, 258 {2, 2, MLX5_MODI_OUT_UDP_DPORT}, 259 {0, 0, 0}, 260 }; 261 262 struct field_modify_info modify_tcp[] = { 263 {2, 0, MLX5_MODI_OUT_TCP_SPORT}, 264 {2, 2, MLX5_MODI_OUT_TCP_DPORT}, 265 {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM}, 266 {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM}, 267 {0, 0, 0}, 268 }; 269 270 static void 271 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused, 272 uint8_t next_protocol, uint64_t *item_flags, 273 int *tunnel) 274 { 275 MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 || 276 item->type == RTE_FLOW_ITEM_TYPE_IPV6); 277 if (next_protocol == IPPROTO_IPIP) { 278 *item_flags |= MLX5_FLOW_LAYER_IPIP; 279 *tunnel = 1; 280 } 281 if (next_protocol == IPPROTO_IPV6) { 282 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP; 283 *tunnel = 1; 284 } 285 } 286 287 static inline struct mlx5_hlist * 288 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl, 289 const char *name, uint32_t size, bool direct_key, 290 bool lcores_share, void *ctx, 291 mlx5_list_create_cb cb_create, 292 mlx5_list_match_cb cb_match, 293 mlx5_list_remove_cb cb_remove, 294 mlx5_list_clone_cb cb_clone, 295 mlx5_list_clone_free_cb cb_clone_free, 296 struct rte_flow_error *error) 297 { 298 struct mlx5_hlist *hl; 299 struct mlx5_hlist *expected = NULL; 300 char s[MLX5_NAME_SIZE]; 301 302 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 303 if (likely(hl)) 304 return hl; 305 snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name); 306 hl = mlx5_hlist_create(s, size, direct_key, lcores_share, 307 ctx, cb_create, cb_match, cb_remove, cb_clone, 308 cb_clone_free); 309 if (!hl) { 310 DRV_LOG(ERR, "%s hash creation failed", name); 311 rte_flow_error_set(error, ENOMEM, 312 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 313 "cannot allocate resource memory"); 314 return NULL; 315 } 316 if (!__atomic_compare_exchange_n(phl, &expected, hl, false, 317 __ATOMIC_SEQ_CST, 318 __ATOMIC_SEQ_CST)) { 319 mlx5_hlist_destroy(hl); 320 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 321 } 322 return hl; 323 } 324 325 /* Update VLAN's VID/PCP based on input rte_flow_action. 326 * 327 * @param[in] action 328 * Pointer to struct rte_flow_action. 329 * @param[out] vlan 330 * Pointer to struct rte_vlan_hdr. 331 */ 332 static void 333 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, 334 struct rte_vlan_hdr *vlan) 335 { 336 uint16_t vlan_tci; 337 if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) { 338 vlan_tci = 339 ((const struct rte_flow_action_of_set_vlan_pcp *) 340 action->conf)->vlan_pcp; 341 vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT; 342 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 343 vlan->vlan_tci |= vlan_tci; 344 } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) { 345 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 346 vlan->vlan_tci |= rte_be_to_cpu_16 347 (((const struct rte_flow_action_of_set_vlan_vid *) 348 action->conf)->vlan_vid); 349 } 350 } 351 352 /** 353 * Convert modify-header action to DV specification. 354 * 355 * Data length of each action is determined by provided field description 356 * and the item mask. Data bit offset and width of each action is determined 357 * by provided item mask. 358 * 359 * @param[in] item 360 * Pointer to item specification. 361 * @param[in] field 362 * Pointer to field modification information. 363 * For MLX5_MODIFICATION_TYPE_SET specifies destination field. 364 * For MLX5_MODIFICATION_TYPE_ADD specifies destination field. 365 * For MLX5_MODIFICATION_TYPE_COPY specifies source field. 366 * @param[in] dcopy 367 * Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type. 368 * Negative offset value sets the same offset as source offset. 369 * size field is ignored, value is taken from source field. 370 * @param[in,out] resource 371 * Pointer to the modify-header resource. 372 * @param[in] type 373 * Type of modification. 374 * @param[out] error 375 * Pointer to the error structure. 376 * 377 * @return 378 * 0 on success, a negative errno value otherwise and rte_errno is set. 379 */ 380 int 381 flow_dv_convert_modify_action(struct rte_flow_item *item, 382 struct field_modify_info *field, 383 struct field_modify_info *dcopy, 384 struct mlx5_flow_dv_modify_hdr_resource *resource, 385 uint32_t type, struct rte_flow_error *error) 386 { 387 uint32_t i = resource->actions_num; 388 struct mlx5_modification_cmd *actions = resource->actions; 389 uint32_t carry_b = 0; 390 391 /* 392 * The item and mask are provided in big-endian format. 393 * The fields should be presented as in big-endian format either. 394 * Mask must be always present, it defines the actual field width. 395 */ 396 MLX5_ASSERT(item->mask); 397 MLX5_ASSERT(field->size); 398 do { 399 uint32_t size_b; 400 uint32_t off_b; 401 uint32_t mask; 402 uint32_t data; 403 bool next_field = true; 404 bool next_dcopy = true; 405 406 if (i >= MLX5_MAX_MODIFY_NUM) 407 return rte_flow_error_set(error, EINVAL, 408 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 409 "too many items to modify"); 410 /* Fetch variable byte size mask from the array. */ 411 mask = flow_dv_fetch_field((const uint8_t *)item->mask + 412 field->offset, field->size); 413 if (!mask) { 414 ++field; 415 continue; 416 } 417 /* Deduce actual data width in bits from mask value. */ 418 off_b = rte_bsf32(mask) + carry_b; 419 size_b = sizeof(uint32_t) * CHAR_BIT - 420 off_b - __builtin_clz(mask); 421 MLX5_ASSERT(size_b); 422 actions[i] = (struct mlx5_modification_cmd) { 423 .action_type = type, 424 .field = field->id, 425 .offset = off_b, 426 .length = (size_b == sizeof(uint32_t) * CHAR_BIT) ? 427 0 : size_b, 428 }; 429 if (type == MLX5_MODIFICATION_TYPE_COPY) { 430 MLX5_ASSERT(dcopy); 431 actions[i].dst_field = dcopy->id; 432 actions[i].dst_offset = 433 (int)dcopy->offset < 0 ? off_b : dcopy->offset; 434 /* Convert entire record to big-endian format. */ 435 actions[i].data1 = rte_cpu_to_be_32(actions[i].data1); 436 /* 437 * Destination field overflow. Copy leftovers of 438 * a source field to the next destination field. 439 */ 440 carry_b = 0; 441 if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) && 442 dcopy->size != 0) { 443 actions[i].length = 444 dcopy->size * CHAR_BIT - dcopy->offset; 445 carry_b = actions[i].length; 446 next_field = false; 447 } 448 /* 449 * Not enough bits in a source filed to fill a 450 * destination field. Switch to the next source. 451 */ 452 if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) && 453 (size_b == field->size * CHAR_BIT - off_b)) { 454 actions[i].length = 455 field->size * CHAR_BIT - off_b; 456 dcopy->offset += actions[i].length; 457 next_dcopy = false; 458 } 459 if (next_dcopy) 460 ++dcopy; 461 } else { 462 MLX5_ASSERT(item->spec); 463 data = flow_dv_fetch_field((const uint8_t *)item->spec + 464 field->offset, field->size); 465 /* Shift out the trailing masked bits from data. */ 466 data = (data & mask) >> off_b; 467 actions[i].data1 = rte_cpu_to_be_32(data); 468 } 469 /* Convert entire record to expected big-endian format. */ 470 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 471 if (next_field) 472 ++field; 473 ++i; 474 } while (field->size); 475 if (resource->actions_num == i) 476 return rte_flow_error_set(error, EINVAL, 477 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 478 "invalid modification flow item"); 479 resource->actions_num = i; 480 return 0; 481 } 482 483 /** 484 * Convert modify-header set IPv4 address action to DV specification. 485 * 486 * @param[in,out] resource 487 * Pointer to the modify-header resource. 488 * @param[in] action 489 * Pointer to action specification. 490 * @param[out] error 491 * Pointer to the error structure. 492 * 493 * @return 494 * 0 on success, a negative errno value otherwise and rte_errno is set. 495 */ 496 static int 497 flow_dv_convert_action_modify_ipv4 498 (struct mlx5_flow_dv_modify_hdr_resource *resource, 499 const struct rte_flow_action *action, 500 struct rte_flow_error *error) 501 { 502 const struct rte_flow_action_set_ipv4 *conf = 503 (const struct rte_flow_action_set_ipv4 *)(action->conf); 504 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 505 struct rte_flow_item_ipv4 ipv4; 506 struct rte_flow_item_ipv4 ipv4_mask; 507 508 memset(&ipv4, 0, sizeof(ipv4)); 509 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 510 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) { 511 ipv4.hdr.src_addr = conf->ipv4_addr; 512 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr; 513 } else { 514 ipv4.hdr.dst_addr = conf->ipv4_addr; 515 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr; 516 } 517 item.spec = &ipv4; 518 item.mask = &ipv4_mask; 519 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 520 MLX5_MODIFICATION_TYPE_SET, error); 521 } 522 523 /** 524 * Convert modify-header set IPv6 address action to DV specification. 525 * 526 * @param[in,out] resource 527 * Pointer to the modify-header resource. 528 * @param[in] action 529 * Pointer to action specification. 530 * @param[out] error 531 * Pointer to the error structure. 532 * 533 * @return 534 * 0 on success, a negative errno value otherwise and rte_errno is set. 535 */ 536 static int 537 flow_dv_convert_action_modify_ipv6 538 (struct mlx5_flow_dv_modify_hdr_resource *resource, 539 const struct rte_flow_action *action, 540 struct rte_flow_error *error) 541 { 542 const struct rte_flow_action_set_ipv6 *conf = 543 (const struct rte_flow_action_set_ipv6 *)(action->conf); 544 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 545 struct rte_flow_item_ipv6 ipv6; 546 struct rte_flow_item_ipv6 ipv6_mask; 547 548 memset(&ipv6, 0, sizeof(ipv6)); 549 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 550 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) { 551 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr, 552 sizeof(ipv6.hdr.src_addr)); 553 memcpy(&ipv6_mask.hdr.src_addr, 554 &rte_flow_item_ipv6_mask.hdr.src_addr, 555 sizeof(ipv6.hdr.src_addr)); 556 } else { 557 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr, 558 sizeof(ipv6.hdr.dst_addr)); 559 memcpy(&ipv6_mask.hdr.dst_addr, 560 &rte_flow_item_ipv6_mask.hdr.dst_addr, 561 sizeof(ipv6.hdr.dst_addr)); 562 } 563 item.spec = &ipv6; 564 item.mask = &ipv6_mask; 565 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 566 MLX5_MODIFICATION_TYPE_SET, error); 567 } 568 569 /** 570 * Convert modify-header set MAC address action to DV specification. 571 * 572 * @param[in,out] resource 573 * Pointer to the modify-header resource. 574 * @param[in] action 575 * Pointer to action specification. 576 * @param[out] error 577 * Pointer to the error structure. 578 * 579 * @return 580 * 0 on success, a negative errno value otherwise and rte_errno is set. 581 */ 582 static int 583 flow_dv_convert_action_modify_mac 584 (struct mlx5_flow_dv_modify_hdr_resource *resource, 585 const struct rte_flow_action *action, 586 struct rte_flow_error *error) 587 { 588 const struct rte_flow_action_set_mac *conf = 589 (const struct rte_flow_action_set_mac *)(action->conf); 590 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH }; 591 struct rte_flow_item_eth eth; 592 struct rte_flow_item_eth eth_mask; 593 594 memset(ð, 0, sizeof(eth)); 595 memset(ð_mask, 0, sizeof(eth_mask)); 596 if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) { 597 memcpy(ð.hdr.src_addr.addr_bytes, &conf->mac_addr, 598 sizeof(eth.hdr.src_addr.addr_bytes)); 599 memcpy(ð_mask.hdr.src_addr.addr_bytes, 600 &rte_flow_item_eth_mask.hdr.src_addr.addr_bytes, 601 sizeof(eth_mask.hdr.src_addr.addr_bytes)); 602 } else { 603 memcpy(ð.hdr.dst_addr.addr_bytes, &conf->mac_addr, 604 sizeof(eth.hdr.dst_addr.addr_bytes)); 605 memcpy(ð_mask.hdr.dst_addr.addr_bytes, 606 &rte_flow_item_eth_mask.hdr.dst_addr.addr_bytes, 607 sizeof(eth_mask.hdr.dst_addr.addr_bytes)); 608 } 609 item.spec = ð 610 item.mask = ð_mask; 611 return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource, 612 MLX5_MODIFICATION_TYPE_SET, error); 613 } 614 615 /** 616 * Convert modify-header set VLAN VID action to DV specification. 617 * 618 * @param[in,out] resource 619 * Pointer to the modify-header resource. 620 * @param[in] action 621 * Pointer to action specification. 622 * @param[out] error 623 * Pointer to the error structure. 624 * 625 * @return 626 * 0 on success, a negative errno value otherwise and rte_errno is set. 627 */ 628 static int 629 flow_dv_convert_action_modify_vlan_vid 630 (struct mlx5_flow_dv_modify_hdr_resource *resource, 631 const struct rte_flow_action *action, 632 struct rte_flow_error *error) 633 { 634 const struct rte_flow_action_of_set_vlan_vid *conf = 635 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf); 636 int i = resource->actions_num; 637 struct mlx5_modification_cmd *actions = resource->actions; 638 struct field_modify_info *field = modify_vlan_out_first_vid; 639 640 if (i >= MLX5_MAX_MODIFY_NUM) 641 return rte_flow_error_set(error, EINVAL, 642 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 643 "too many items to modify"); 644 actions[i] = (struct mlx5_modification_cmd) { 645 .action_type = MLX5_MODIFICATION_TYPE_SET, 646 .field = field->id, 647 .length = field->size, 648 .offset = field->offset, 649 }; 650 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 651 actions[i].data1 = conf->vlan_vid; 652 actions[i].data1 = actions[i].data1 << 16; 653 resource->actions_num = ++i; 654 return 0; 655 } 656 657 /** 658 * Convert modify-header set TP action to DV specification. 659 * 660 * @param[in,out] resource 661 * Pointer to the modify-header resource. 662 * @param[in] action 663 * Pointer to action specification. 664 * @param[in] items 665 * Pointer to rte_flow_item objects list. 666 * @param[in] attr 667 * Pointer to flow attributes structure. 668 * @param[in] dev_flow 669 * Pointer to the sub flow. 670 * @param[in] tunnel_decap 671 * Whether action is after tunnel decapsulation. 672 * @param[out] error 673 * Pointer to the error structure. 674 * 675 * @return 676 * 0 on success, a negative errno value otherwise and rte_errno is set. 677 */ 678 static int 679 flow_dv_convert_action_modify_tp 680 (struct mlx5_flow_dv_modify_hdr_resource *resource, 681 const struct rte_flow_action *action, 682 const struct rte_flow_item *items, 683 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 684 bool tunnel_decap, struct rte_flow_error *error) 685 { 686 const struct rte_flow_action_set_tp *conf = 687 (const struct rte_flow_action_set_tp *)(action->conf); 688 struct rte_flow_item item; 689 struct rte_flow_item_udp udp; 690 struct rte_flow_item_udp udp_mask; 691 struct rte_flow_item_tcp tcp; 692 struct rte_flow_item_tcp tcp_mask; 693 struct field_modify_info *field; 694 695 if (!attr->valid) 696 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 697 if (attr->udp) { 698 memset(&udp, 0, sizeof(udp)); 699 memset(&udp_mask, 0, sizeof(udp_mask)); 700 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 701 udp.hdr.src_port = conf->port; 702 udp_mask.hdr.src_port = 703 rte_flow_item_udp_mask.hdr.src_port; 704 } else { 705 udp.hdr.dst_port = conf->port; 706 udp_mask.hdr.dst_port = 707 rte_flow_item_udp_mask.hdr.dst_port; 708 } 709 item.type = RTE_FLOW_ITEM_TYPE_UDP; 710 item.spec = &udp; 711 item.mask = &udp_mask; 712 field = modify_udp; 713 } else { 714 MLX5_ASSERT(attr->tcp); 715 memset(&tcp, 0, sizeof(tcp)); 716 memset(&tcp_mask, 0, sizeof(tcp_mask)); 717 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 718 tcp.hdr.src_port = conf->port; 719 tcp_mask.hdr.src_port = 720 rte_flow_item_tcp_mask.hdr.src_port; 721 } else { 722 tcp.hdr.dst_port = conf->port; 723 tcp_mask.hdr.dst_port = 724 rte_flow_item_tcp_mask.hdr.dst_port; 725 } 726 item.type = RTE_FLOW_ITEM_TYPE_TCP; 727 item.spec = &tcp; 728 item.mask = &tcp_mask; 729 field = modify_tcp; 730 } 731 return flow_dv_convert_modify_action(&item, field, NULL, resource, 732 MLX5_MODIFICATION_TYPE_SET, error); 733 } 734 735 /** 736 * Convert modify-header set TTL action to DV specification. 737 * 738 * @param[in,out] resource 739 * Pointer to the modify-header resource. 740 * @param[in] action 741 * Pointer to action specification. 742 * @param[in] items 743 * Pointer to rte_flow_item objects list. 744 * @param[in] attr 745 * Pointer to flow attributes structure. 746 * @param[in] dev_flow 747 * Pointer to the sub flow. 748 * @param[in] tunnel_decap 749 * Whether action is after tunnel decapsulation. 750 * @param[out] error 751 * Pointer to the error structure. 752 * 753 * @return 754 * 0 on success, a negative errno value otherwise and rte_errno is set. 755 */ 756 static int 757 flow_dv_convert_action_modify_ttl 758 (struct mlx5_flow_dv_modify_hdr_resource *resource, 759 const struct rte_flow_action *action, 760 const struct rte_flow_item *items, 761 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 762 bool tunnel_decap, struct rte_flow_error *error) 763 { 764 const struct rte_flow_action_set_ttl *conf = 765 (const struct rte_flow_action_set_ttl *)(action->conf); 766 struct rte_flow_item item; 767 struct rte_flow_item_ipv4 ipv4; 768 struct rte_flow_item_ipv4 ipv4_mask; 769 struct rte_flow_item_ipv6 ipv6; 770 struct rte_flow_item_ipv6 ipv6_mask; 771 struct field_modify_info *field; 772 773 if (!attr->valid) 774 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 775 if (attr->ipv4) { 776 memset(&ipv4, 0, sizeof(ipv4)); 777 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 778 ipv4.hdr.time_to_live = conf->ttl_value; 779 ipv4_mask.hdr.time_to_live = 0xFF; 780 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 781 item.spec = &ipv4; 782 item.mask = &ipv4_mask; 783 field = modify_ipv4; 784 } else { 785 MLX5_ASSERT(attr->ipv6); 786 memset(&ipv6, 0, sizeof(ipv6)); 787 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 788 ipv6.hdr.hop_limits = conf->ttl_value; 789 ipv6_mask.hdr.hop_limits = 0xFF; 790 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 791 item.spec = &ipv6; 792 item.mask = &ipv6_mask; 793 field = modify_ipv6; 794 } 795 return flow_dv_convert_modify_action(&item, field, NULL, resource, 796 MLX5_MODIFICATION_TYPE_SET, error); 797 } 798 799 /** 800 * Convert modify-header decrement TTL action to DV specification. 801 * 802 * @param[in,out] resource 803 * Pointer to the modify-header resource. 804 * @param[in] action 805 * Pointer to action specification. 806 * @param[in] items 807 * Pointer to rte_flow_item objects list. 808 * @param[in] attr 809 * Pointer to flow attributes structure. 810 * @param[in] dev_flow 811 * Pointer to the sub flow. 812 * @param[in] tunnel_decap 813 * Whether action is after tunnel decapsulation. 814 * @param[out] error 815 * Pointer to the error structure. 816 * 817 * @return 818 * 0 on success, a negative errno value otherwise and rte_errno is set. 819 */ 820 static int 821 flow_dv_convert_action_modify_dec_ttl 822 (struct mlx5_flow_dv_modify_hdr_resource *resource, 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 struct rte_flow_item item; 828 struct rte_flow_item_ipv4 ipv4; 829 struct rte_flow_item_ipv4 ipv4_mask; 830 struct rte_flow_item_ipv6 ipv6; 831 struct rte_flow_item_ipv6 ipv6_mask; 832 struct field_modify_info *field; 833 834 if (!attr->valid) 835 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 836 if (attr->ipv4) { 837 memset(&ipv4, 0, sizeof(ipv4)); 838 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 839 ipv4.hdr.time_to_live = 0xFF; 840 ipv4_mask.hdr.time_to_live = 0xFF; 841 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 842 item.spec = &ipv4; 843 item.mask = &ipv4_mask; 844 field = modify_ipv4; 845 } else { 846 MLX5_ASSERT(attr->ipv6); 847 memset(&ipv6, 0, sizeof(ipv6)); 848 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 849 ipv6.hdr.hop_limits = 0xFF; 850 ipv6_mask.hdr.hop_limits = 0xFF; 851 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 852 item.spec = &ipv6; 853 item.mask = &ipv6_mask; 854 field = modify_ipv6; 855 } 856 return flow_dv_convert_modify_action(&item, field, NULL, resource, 857 MLX5_MODIFICATION_TYPE_ADD, error); 858 } 859 860 /** 861 * Convert modify-header increment/decrement TCP Sequence number 862 * to DV specification. 863 * 864 * @param[in,out] resource 865 * Pointer to the modify-header resource. 866 * @param[in] action 867 * Pointer to action specification. 868 * @param[out] error 869 * Pointer to the error structure. 870 * 871 * @return 872 * 0 on success, a negative errno value otherwise and rte_errno is set. 873 */ 874 static int 875 flow_dv_convert_action_modify_tcp_seq 876 (struct mlx5_flow_dv_modify_hdr_resource *resource, 877 const struct rte_flow_action *action, 878 struct rte_flow_error *error) 879 { 880 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 881 uint64_t value = rte_be_to_cpu_32(*conf); 882 struct rte_flow_item item; 883 struct rte_flow_item_tcp tcp; 884 struct rte_flow_item_tcp tcp_mask; 885 886 memset(&tcp, 0, sizeof(tcp)); 887 memset(&tcp_mask, 0, sizeof(tcp_mask)); 888 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ) 889 /* 890 * The HW has no decrement operation, only increment operation. 891 * To simulate decrement X from Y using increment operation 892 * we need to add UINT32_MAX X times to Y. 893 * Each adding of UINT32_MAX decrements Y by 1. 894 */ 895 value *= UINT32_MAX; 896 tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value); 897 tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX); 898 item.type = RTE_FLOW_ITEM_TYPE_TCP; 899 item.spec = &tcp; 900 item.mask = &tcp_mask; 901 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 902 MLX5_MODIFICATION_TYPE_ADD, error); 903 } 904 905 /** 906 * Convert modify-header increment/decrement TCP Acknowledgment number 907 * to DV specification. 908 * 909 * @param[in,out] resource 910 * Pointer to the modify-header resource. 911 * @param[in] action 912 * Pointer to action specification. 913 * @param[out] error 914 * Pointer to the error structure. 915 * 916 * @return 917 * 0 on success, a negative errno value otherwise and rte_errno is set. 918 */ 919 static int 920 flow_dv_convert_action_modify_tcp_ack 921 (struct mlx5_flow_dv_modify_hdr_resource *resource, 922 const struct rte_flow_action *action, 923 struct rte_flow_error *error) 924 { 925 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 926 uint64_t value = rte_be_to_cpu_32(*conf); 927 struct rte_flow_item item; 928 struct rte_flow_item_tcp tcp; 929 struct rte_flow_item_tcp tcp_mask; 930 931 memset(&tcp, 0, sizeof(tcp)); 932 memset(&tcp_mask, 0, sizeof(tcp_mask)); 933 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK) 934 /* 935 * The HW has no decrement operation, only increment operation. 936 * To simulate decrement X from Y using increment operation 937 * we need to add UINT32_MAX X times to Y. 938 * Each adding of UINT32_MAX decrements Y by 1. 939 */ 940 value *= UINT32_MAX; 941 tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value); 942 tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX); 943 item.type = RTE_FLOW_ITEM_TYPE_TCP; 944 item.spec = &tcp; 945 item.mask = &tcp_mask; 946 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 947 MLX5_MODIFICATION_TYPE_ADD, error); 948 } 949 950 static enum mlx5_modification_field reg_to_field[] = { 951 [REG_NON] = MLX5_MODI_OUT_NONE, 952 [REG_A] = MLX5_MODI_META_DATA_REG_A, 953 [REG_B] = MLX5_MODI_META_DATA_REG_B, 954 [REG_C_0] = MLX5_MODI_META_REG_C_0, 955 [REG_C_1] = MLX5_MODI_META_REG_C_1, 956 [REG_C_2] = MLX5_MODI_META_REG_C_2, 957 [REG_C_3] = MLX5_MODI_META_REG_C_3, 958 [REG_C_4] = MLX5_MODI_META_REG_C_4, 959 [REG_C_5] = MLX5_MODI_META_REG_C_5, 960 [REG_C_6] = MLX5_MODI_META_REG_C_6, 961 [REG_C_7] = MLX5_MODI_META_REG_C_7, 962 }; 963 964 /** 965 * Convert register set to DV specification. 966 * 967 * @param[in,out] resource 968 * Pointer to the modify-header resource. 969 * @param[in] action 970 * Pointer to action specification. 971 * @param[out] error 972 * Pointer to the error structure. 973 * 974 * @return 975 * 0 on success, a negative errno value otherwise and rte_errno is set. 976 */ 977 static int 978 flow_dv_convert_action_set_reg 979 (struct mlx5_flow_dv_modify_hdr_resource *resource, 980 const struct rte_flow_action *action, 981 struct rte_flow_error *error) 982 { 983 const struct mlx5_rte_flow_action_set_tag *conf = action->conf; 984 struct mlx5_modification_cmd *actions = resource->actions; 985 uint32_t i = resource->actions_num; 986 987 if (i >= MLX5_MAX_MODIFY_NUM) 988 return rte_flow_error_set(error, EINVAL, 989 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 990 "too many items to modify"); 991 MLX5_ASSERT(conf->id != REG_NON); 992 MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field)); 993 actions[i] = (struct mlx5_modification_cmd) { 994 .action_type = MLX5_MODIFICATION_TYPE_SET, 995 .field = reg_to_field[conf->id], 996 .offset = conf->offset, 997 .length = conf->length, 998 }; 999 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 1000 actions[i].data1 = rte_cpu_to_be_32(conf->data); 1001 ++i; 1002 resource->actions_num = i; 1003 return 0; 1004 } 1005 1006 /** 1007 * Convert SET_TAG action to DV specification. 1008 * 1009 * @param[in] dev 1010 * Pointer to the rte_eth_dev structure. 1011 * @param[in,out] resource 1012 * Pointer to the modify-header resource. 1013 * @param[in] conf 1014 * Pointer to action specification. 1015 * @param[out] error 1016 * Pointer to the error structure. 1017 * 1018 * @return 1019 * 0 on success, a negative errno value otherwise and rte_errno is set. 1020 */ 1021 static int 1022 flow_dv_convert_action_set_tag 1023 (struct rte_eth_dev *dev, 1024 struct mlx5_flow_dv_modify_hdr_resource *resource, 1025 const struct rte_flow_action_set_tag *conf, 1026 struct rte_flow_error *error) 1027 { 1028 rte_be32_t data = rte_cpu_to_be_32(conf->data); 1029 rte_be32_t mask = rte_cpu_to_be_32(conf->mask); 1030 struct rte_flow_item item = { 1031 .spec = &data, 1032 .mask = &mask, 1033 }; 1034 struct field_modify_info reg_c_x[] = { 1035 [1] = {0, 0, 0}, 1036 }; 1037 enum mlx5_modification_field reg_type; 1038 int ret; 1039 1040 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 1041 if (ret < 0) 1042 return ret; 1043 MLX5_ASSERT(ret != REG_NON); 1044 MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field)); 1045 reg_type = reg_to_field[ret]; 1046 MLX5_ASSERT(reg_type > 0); 1047 reg_c_x[0] = (struct field_modify_info){4, 0, reg_type}; 1048 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1049 MLX5_MODIFICATION_TYPE_SET, error); 1050 } 1051 1052 /** 1053 * Convert internal COPY_REG action to DV specification. 1054 * 1055 * @param[in] dev 1056 * Pointer to the rte_eth_dev structure. 1057 * @param[in,out] res 1058 * Pointer to the modify-header resource. 1059 * @param[in] action 1060 * Pointer to action specification. 1061 * @param[out] error 1062 * Pointer to the error structure. 1063 * 1064 * @return 1065 * 0 on success, a negative errno value otherwise and rte_errno is set. 1066 */ 1067 static int 1068 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev, 1069 struct mlx5_flow_dv_modify_hdr_resource *res, 1070 const struct rte_flow_action *action, 1071 struct rte_flow_error *error) 1072 { 1073 const struct mlx5_flow_action_copy_mreg *conf = action->conf; 1074 rte_be32_t mask = RTE_BE32(UINT32_MAX); 1075 struct rte_flow_item item = { 1076 .spec = NULL, 1077 .mask = &mask, 1078 }; 1079 struct field_modify_info reg_src[] = { 1080 {4, 0, reg_to_field[conf->src]}, 1081 {0, 0, 0}, 1082 }; 1083 struct field_modify_info reg_dst = { 1084 .offset = 0, 1085 .id = reg_to_field[conf->dst], 1086 }; 1087 /* Adjust reg_c[0] usage according to reported mask. */ 1088 if (conf->dst == REG_C_0 || conf->src == REG_C_0) { 1089 struct mlx5_priv *priv = dev->data->dev_private; 1090 uint32_t reg_c0 = priv->sh->dv_regc0_mask; 1091 1092 MLX5_ASSERT(reg_c0); 1093 MLX5_ASSERT(priv->sh->config.dv_xmeta_en != 1094 MLX5_XMETA_MODE_LEGACY); 1095 if (conf->dst == REG_C_0) { 1096 /* Copy to reg_c[0], within mask only. */ 1097 reg_dst.offset = rte_bsf32(reg_c0); 1098 mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset); 1099 } else { 1100 reg_dst.offset = 0; 1101 mask = rte_cpu_to_be_32(reg_c0); 1102 } 1103 } 1104 return flow_dv_convert_modify_action(&item, 1105 reg_src, ®_dst, res, 1106 MLX5_MODIFICATION_TYPE_COPY, 1107 error); 1108 } 1109 1110 /** 1111 * Convert MARK action to DV specification. This routine is used 1112 * in extensive metadata only and requires metadata register to be 1113 * handled. In legacy mode hardware tag resource is engaged. 1114 * 1115 * @param[in] dev 1116 * Pointer to the rte_eth_dev structure. 1117 * @param[in] conf 1118 * Pointer to MARK action specification. 1119 * @param[in,out] resource 1120 * Pointer to the modify-header resource. 1121 * @param[out] error 1122 * Pointer to the error structure. 1123 * 1124 * @return 1125 * 0 on success, a negative errno value otherwise and rte_errno is set. 1126 */ 1127 static int 1128 flow_dv_convert_action_mark(struct rte_eth_dev *dev, 1129 const struct rte_flow_action_mark *conf, 1130 struct mlx5_flow_dv_modify_hdr_resource *resource, 1131 struct rte_flow_error *error) 1132 { 1133 struct mlx5_priv *priv = dev->data->dev_private; 1134 rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK & 1135 priv->sh->dv_mark_mask); 1136 rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask; 1137 struct rte_flow_item item = { 1138 .spec = &data, 1139 .mask = &mask, 1140 }; 1141 struct field_modify_info reg_c_x[] = { 1142 [1] = {0, 0, 0}, 1143 }; 1144 int reg; 1145 1146 if (!mask) 1147 return rte_flow_error_set(error, EINVAL, 1148 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1149 NULL, "zero mark action mask"); 1150 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1151 if (reg < 0) 1152 return reg; 1153 MLX5_ASSERT(reg > 0); 1154 if (reg == REG_C_0) { 1155 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1156 uint32_t shl_c0 = rte_bsf32(msk_c0); 1157 1158 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1159 mask = rte_cpu_to_be_32(mask) & msk_c0; 1160 mask = rte_cpu_to_be_32(mask << shl_c0); 1161 } 1162 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1163 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1164 MLX5_MODIFICATION_TYPE_SET, error); 1165 } 1166 1167 /** 1168 * Get metadata register index for specified steering domain. 1169 * 1170 * @param[in] dev 1171 * Pointer to the rte_eth_dev structure. 1172 * @param[in] attr 1173 * Attributes of flow to determine steering domain. 1174 * @param[out] error 1175 * Pointer to the error structure. 1176 * 1177 * @return 1178 * positive index on success, a negative errno value otherwise 1179 * and rte_errno is set. 1180 */ 1181 static enum modify_reg 1182 flow_dv_get_metadata_reg(struct rte_eth_dev *dev, 1183 const struct rte_flow_attr *attr, 1184 struct rte_flow_error *error) 1185 { 1186 int reg = 1187 mlx5_flow_get_reg_id(dev, attr->transfer ? 1188 MLX5_METADATA_FDB : 1189 attr->egress ? 1190 MLX5_METADATA_TX : 1191 MLX5_METADATA_RX, 0, error); 1192 if (reg < 0) 1193 return rte_flow_error_set(error, 1194 ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, 1195 NULL, "unavailable " 1196 "metadata register"); 1197 return reg; 1198 } 1199 1200 /** 1201 * Convert SET_META action to DV specification. 1202 * 1203 * @param[in] dev 1204 * Pointer to the rte_eth_dev structure. 1205 * @param[in,out] resource 1206 * Pointer to the modify-header resource. 1207 * @param[in] attr 1208 * Attributes of flow that includes this item. 1209 * @param[in] conf 1210 * Pointer to action specification. 1211 * @param[out] error 1212 * Pointer to the error structure. 1213 * 1214 * @return 1215 * 0 on success, a negative errno value otherwise and rte_errno is set. 1216 */ 1217 static int 1218 flow_dv_convert_action_set_meta 1219 (struct rte_eth_dev *dev, 1220 struct mlx5_flow_dv_modify_hdr_resource *resource, 1221 const struct rte_flow_attr *attr, 1222 const struct rte_flow_action_set_meta *conf, 1223 struct rte_flow_error *error) 1224 { 1225 uint32_t mask = rte_cpu_to_be_32(conf->mask); 1226 uint32_t data = rte_cpu_to_be_32(conf->data) & mask; 1227 struct rte_flow_item item = { 1228 .spec = &data, 1229 .mask = &mask, 1230 }; 1231 struct field_modify_info reg_c_x[] = { 1232 [1] = {0, 0, 0}, 1233 }; 1234 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1235 1236 if (reg < 0) 1237 return reg; 1238 MLX5_ASSERT(reg != REG_NON); 1239 if (reg == REG_C_0) { 1240 struct mlx5_priv *priv = dev->data->dev_private; 1241 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1242 uint32_t shl_c0 = rte_bsf32(msk_c0); 1243 1244 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1245 mask = rte_cpu_to_be_32(mask) & msk_c0; 1246 mask = rte_cpu_to_be_32(mask << shl_c0); 1247 } 1248 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1249 /* The routine expects parameters in memory as big-endian ones. */ 1250 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1251 MLX5_MODIFICATION_TYPE_SET, error); 1252 } 1253 1254 /** 1255 * Convert modify-header set IPv4 DSCP action to DV specification. 1256 * 1257 * @param[in,out] resource 1258 * Pointer to the modify-header resource. 1259 * @param[in] action 1260 * Pointer to action specification. 1261 * @param[out] error 1262 * Pointer to the error structure. 1263 * 1264 * @return 1265 * 0 on success, a negative errno value otherwise and rte_errno is set. 1266 */ 1267 static int 1268 flow_dv_convert_action_modify_ipv4_dscp 1269 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1270 const struct rte_flow_action *action, 1271 struct rte_flow_error *error) 1272 { 1273 const struct rte_flow_action_set_dscp *conf = 1274 (const struct rte_flow_action_set_dscp *)(action->conf); 1275 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 1276 struct rte_flow_item_ipv4 ipv4; 1277 struct rte_flow_item_ipv4 ipv4_mask; 1278 1279 memset(&ipv4, 0, sizeof(ipv4)); 1280 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 1281 ipv4.hdr.type_of_service = conf->dscp; 1282 ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2; 1283 item.spec = &ipv4; 1284 item.mask = &ipv4_mask; 1285 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 1286 MLX5_MODIFICATION_TYPE_SET, error); 1287 } 1288 1289 /** 1290 * Convert modify-header set IPv6 DSCP action to DV specification. 1291 * 1292 * @param[in,out] resource 1293 * Pointer to the modify-header resource. 1294 * @param[in] action 1295 * Pointer to action specification. 1296 * @param[out] error 1297 * Pointer to the error structure. 1298 * 1299 * @return 1300 * 0 on success, a negative errno value otherwise and rte_errno is set. 1301 */ 1302 static int 1303 flow_dv_convert_action_modify_ipv6_dscp 1304 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1305 const struct rte_flow_action *action, 1306 struct rte_flow_error *error) 1307 { 1308 const struct rte_flow_action_set_dscp *conf = 1309 (const struct rte_flow_action_set_dscp *)(action->conf); 1310 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 1311 struct rte_flow_item_ipv6 ipv6; 1312 struct rte_flow_item_ipv6 ipv6_mask; 1313 1314 memset(&ipv6, 0, sizeof(ipv6)); 1315 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 1316 /* 1317 * Even though the DSCP bits offset of IPv6 is not byte aligned, 1318 * rdma-core only accept the DSCP bits byte aligned start from 1319 * bit 0 to 5 as to be compatible with IPv4. No need to shift the 1320 * bits in IPv6 case as rdma-core requires byte aligned value. 1321 */ 1322 ipv6.hdr.vtc_flow = conf->dscp; 1323 ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22; 1324 item.spec = &ipv6; 1325 item.mask = &ipv6_mask; 1326 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 1327 MLX5_MODIFICATION_TYPE_SET, error); 1328 } 1329 1330 int 1331 mlx5_flow_item_field_width(struct rte_eth_dev *dev, 1332 enum rte_flow_field_id field, int inherit, 1333 const struct rte_flow_attr *attr, 1334 struct rte_flow_error *error) 1335 { 1336 struct mlx5_priv *priv = dev->data->dev_private; 1337 1338 switch (field) { 1339 case RTE_FLOW_FIELD_START: 1340 return 32; 1341 case RTE_FLOW_FIELD_MAC_DST: 1342 case RTE_FLOW_FIELD_MAC_SRC: 1343 return 48; 1344 case RTE_FLOW_FIELD_VLAN_TYPE: 1345 return 16; 1346 case RTE_FLOW_FIELD_VLAN_ID: 1347 return 12; 1348 case RTE_FLOW_FIELD_MAC_TYPE: 1349 return 16; 1350 case RTE_FLOW_FIELD_IPV4_DSCP: 1351 return 6; 1352 case RTE_FLOW_FIELD_IPV4_TTL: 1353 return 8; 1354 case RTE_FLOW_FIELD_IPV4_SRC: 1355 case RTE_FLOW_FIELD_IPV4_DST: 1356 return 32; 1357 case RTE_FLOW_FIELD_IPV6_DSCP: 1358 return 6; 1359 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1360 return 8; 1361 case RTE_FLOW_FIELD_IPV6_SRC: 1362 case RTE_FLOW_FIELD_IPV6_DST: 1363 return 128; 1364 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1365 case RTE_FLOW_FIELD_TCP_PORT_DST: 1366 return 16; 1367 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1368 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1369 return 32; 1370 case RTE_FLOW_FIELD_TCP_FLAGS: 1371 return 9; 1372 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1373 case RTE_FLOW_FIELD_UDP_PORT_DST: 1374 return 16; 1375 case RTE_FLOW_FIELD_VXLAN_VNI: 1376 case RTE_FLOW_FIELD_GENEVE_VNI: 1377 return 24; 1378 case RTE_FLOW_FIELD_GTP_TEID: 1379 case RTE_FLOW_FIELD_TAG: 1380 return 32; 1381 case RTE_FLOW_FIELD_MARK: 1382 return __builtin_popcount(priv->sh->dv_mark_mask); 1383 case RTE_FLOW_FIELD_META: 1384 return (flow_dv_get_metadata_reg(dev, attr, error) == REG_C_0) ? 1385 __builtin_popcount(priv->sh->dv_meta_mask) : 32; 1386 case RTE_FLOW_FIELD_POINTER: 1387 case RTE_FLOW_FIELD_VALUE: 1388 return inherit < 0 ? 0 : inherit; 1389 case RTE_FLOW_FIELD_IPV4_ECN: 1390 case RTE_FLOW_FIELD_IPV6_ECN: 1391 case RTE_FLOW_FIELD_METER_COLOR: 1392 return 2; 1393 default: 1394 MLX5_ASSERT(false); 1395 } 1396 return 0; 1397 } 1398 1399 static __rte_always_inline uint8_t 1400 flow_modify_info_mask_8(uint32_t length, uint32_t off) 1401 { 1402 return (0xffu >> (8 - length)) << off; 1403 } 1404 1405 static __rte_always_inline uint16_t 1406 flow_modify_info_mask_16(uint32_t length, uint32_t off) 1407 { 1408 return rte_cpu_to_be_16((0xffffu >> (16 - length)) << off); 1409 } 1410 1411 static __rte_always_inline uint32_t 1412 flow_modify_info_mask_32(uint32_t length, uint32_t off) 1413 { 1414 return rte_cpu_to_be_32((0xffffffffu >> (32 - length)) << off); 1415 } 1416 1417 static __rte_always_inline uint32_t 1418 flow_modify_info_mask_32_masked(uint32_t length, uint32_t off, uint32_t post_mask) 1419 { 1420 uint32_t mask = (0xffffffffu >> (32 - length)) << off; 1421 return rte_cpu_to_be_32(mask & post_mask); 1422 } 1423 1424 void 1425 mlx5_flow_field_id_to_modify_info 1426 (const struct rte_flow_action_modify_data *data, 1427 struct field_modify_info *info, uint32_t *mask, 1428 uint32_t width, struct rte_eth_dev *dev, 1429 const struct rte_flow_attr *attr, struct rte_flow_error *error) 1430 { 1431 struct mlx5_priv *priv = dev->data->dev_private; 1432 uint32_t idx = 0; 1433 uint32_t off_be = 0; 1434 uint32_t length = 0; 1435 switch ((int)data->field) { 1436 case RTE_FLOW_FIELD_START: 1437 /* not supported yet */ 1438 MLX5_ASSERT(false); 1439 break; 1440 case RTE_FLOW_FIELD_MAC_DST: 1441 MLX5_ASSERT(data->offset + width <= 48); 1442 off_be = 48 - (data->offset + width); 1443 if (off_be < 16) { 1444 info[idx] = (struct field_modify_info){2, 4, 1445 MLX5_MODI_OUT_DMAC_15_0}; 1446 length = off_be + width <= 16 ? width : 16 - off_be; 1447 if (mask) 1448 mask[1] = flow_modify_info_mask_16(length, 1449 off_be); 1450 else 1451 info[idx].offset = off_be; 1452 width -= length; 1453 if (!width) 1454 break; 1455 off_be = 0; 1456 idx++; 1457 } else { 1458 off_be -= 16; 1459 } 1460 info[idx] = (struct field_modify_info){4, 0, 1461 MLX5_MODI_OUT_DMAC_47_16}; 1462 if (mask) 1463 mask[0] = flow_modify_info_mask_32(width, off_be); 1464 else 1465 info[idx].offset = off_be; 1466 break; 1467 case RTE_FLOW_FIELD_MAC_SRC: 1468 MLX5_ASSERT(data->offset + width <= 48); 1469 off_be = 48 - (data->offset + width); 1470 if (off_be < 16) { 1471 info[idx] = (struct field_modify_info){2, 4, 1472 MLX5_MODI_OUT_SMAC_15_0}; 1473 length = off_be + width <= 16 ? width : 16 - off_be; 1474 if (mask) 1475 mask[1] = flow_modify_info_mask_16(length, 1476 off_be); 1477 else 1478 info[idx].offset = off_be; 1479 width -= length; 1480 if (!width) 1481 break; 1482 off_be = 0; 1483 idx++; 1484 } else { 1485 off_be -= 16; 1486 } 1487 info[idx] = (struct field_modify_info){4, 0, 1488 MLX5_MODI_OUT_SMAC_47_16}; 1489 if (mask) 1490 mask[0] = flow_modify_info_mask_32(width, off_be); 1491 else 1492 info[idx].offset = off_be; 1493 break; 1494 case RTE_FLOW_FIELD_VLAN_TYPE: 1495 /* not supported yet */ 1496 break; 1497 case RTE_FLOW_FIELD_VLAN_ID: 1498 MLX5_ASSERT(data->offset + width <= 12); 1499 off_be = 12 - (data->offset + width); 1500 info[idx] = (struct field_modify_info){2, 0, 1501 MLX5_MODI_OUT_FIRST_VID}; 1502 if (mask) 1503 mask[idx] = flow_modify_info_mask_16(width, off_be); 1504 else 1505 info[idx].offset = off_be; 1506 break; 1507 case RTE_FLOW_FIELD_MAC_TYPE: 1508 MLX5_ASSERT(data->offset + width <= 16); 1509 off_be = 16 - (data->offset + width); 1510 info[idx] = (struct field_modify_info){2, 0, 1511 MLX5_MODI_OUT_ETHERTYPE}; 1512 if (mask) 1513 mask[idx] = flow_modify_info_mask_16(width, off_be); 1514 else 1515 info[idx].offset = off_be; 1516 break; 1517 case RTE_FLOW_FIELD_IPV4_DSCP: 1518 MLX5_ASSERT(data->offset + width <= 6); 1519 off_be = 6 - (data->offset + width); 1520 info[idx] = (struct field_modify_info){1, 0, 1521 MLX5_MODI_OUT_IP_DSCP}; 1522 if (mask) 1523 mask[idx] = flow_modify_info_mask_8(width, off_be); 1524 else 1525 info[idx].offset = off_be; 1526 break; 1527 case RTE_FLOW_FIELD_IPV4_TTL: 1528 MLX5_ASSERT(data->offset + width <= 8); 1529 off_be = 8 - (data->offset + width); 1530 info[idx] = (struct field_modify_info){1, 0, 1531 MLX5_MODI_OUT_IPV4_TTL}; 1532 if (mask) 1533 mask[idx] = flow_modify_info_mask_8(width, off_be); 1534 else 1535 info[idx].offset = off_be; 1536 break; 1537 case RTE_FLOW_FIELD_IPV4_SRC: 1538 MLX5_ASSERT(data->offset + width <= 32); 1539 off_be = 32 - (data->offset + width); 1540 info[idx] = (struct field_modify_info){4, 0, 1541 MLX5_MODI_OUT_SIPV4}; 1542 if (mask) 1543 mask[idx] = flow_modify_info_mask_32(width, off_be); 1544 else 1545 info[idx].offset = off_be; 1546 break; 1547 case RTE_FLOW_FIELD_IPV4_DST: 1548 MLX5_ASSERT(data->offset + width <= 32); 1549 off_be = 32 - (data->offset + width); 1550 info[idx] = (struct field_modify_info){4, 0, 1551 MLX5_MODI_OUT_DIPV4}; 1552 if (mask) 1553 mask[idx] = flow_modify_info_mask_32(width, off_be); 1554 else 1555 info[idx].offset = off_be; 1556 break; 1557 case RTE_FLOW_FIELD_IPV6_DSCP: 1558 MLX5_ASSERT(data->offset + width <= 6); 1559 off_be = 6 - (data->offset + width); 1560 info[idx] = (struct field_modify_info){1, 0, 1561 MLX5_MODI_OUT_IP_DSCP}; 1562 if (mask) 1563 mask[idx] = flow_modify_info_mask_8(width, off_be); 1564 else 1565 info[idx].offset = off_be; 1566 break; 1567 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1568 MLX5_ASSERT(data->offset + width <= 8); 1569 off_be = 8 - (data->offset + width); 1570 info[idx] = (struct field_modify_info){1, 0, 1571 MLX5_MODI_OUT_IPV6_HOPLIMIT}; 1572 if (mask) 1573 mask[idx] = flow_modify_info_mask_8(width, off_be); 1574 else 1575 info[idx].offset = off_be; 1576 break; 1577 case RTE_FLOW_FIELD_IPV6_SRC: { 1578 /* 1579 * Fields corresponding to IPv6 source address bytes 1580 * arranged according to network byte ordering. 1581 */ 1582 struct field_modify_info fields[] = { 1583 { 4, 0, MLX5_MODI_OUT_SIPV6_127_96 }, 1584 { 4, 4, MLX5_MODI_OUT_SIPV6_95_64 }, 1585 { 4, 8, MLX5_MODI_OUT_SIPV6_63_32 }, 1586 { 4, 12, MLX5_MODI_OUT_SIPV6_31_0 }, 1587 }; 1588 /* First mask to be modified is the mask of 4th address byte. */ 1589 uint32_t midx = 3; 1590 1591 MLX5_ASSERT(data->offset + width <= 128); 1592 off_be = 128 - (data->offset + width); 1593 while (width > 0 && midx > 0) { 1594 if (off_be < 32) { 1595 info[idx] = fields[midx]; 1596 length = off_be + width <= 32 ? 1597 width : 32 - off_be; 1598 if (mask) 1599 mask[midx] = flow_modify_info_mask_32 1600 (length, off_be); 1601 else 1602 info[idx].offset = off_be; 1603 width -= length; 1604 off_be = 0; 1605 idx++; 1606 } else { 1607 off_be -= 32; 1608 } 1609 midx--; 1610 } 1611 if (!width) 1612 break; 1613 info[idx] = fields[midx]; 1614 if (mask) 1615 mask[midx] = flow_modify_info_mask_32(width, off_be); 1616 else 1617 info[idx].offset = off_be; 1618 break; 1619 } 1620 case RTE_FLOW_FIELD_IPV6_DST: { 1621 /* 1622 * Fields corresponding to IPv6 destination address bytes 1623 * arranged according to network byte ordering. 1624 */ 1625 struct field_modify_info fields[] = { 1626 { 4, 0, MLX5_MODI_OUT_DIPV6_127_96 }, 1627 { 4, 4, MLX5_MODI_OUT_DIPV6_95_64 }, 1628 { 4, 8, MLX5_MODI_OUT_DIPV6_63_32 }, 1629 { 4, 12, MLX5_MODI_OUT_DIPV6_31_0 }, 1630 }; 1631 /* First mask to be modified is the mask of 4th address byte. */ 1632 uint32_t midx = 3; 1633 1634 MLX5_ASSERT(data->offset + width <= 128); 1635 off_be = 128 - (data->offset + width); 1636 while (width > 0 && midx > 0) { 1637 if (off_be < 32) { 1638 info[idx] = fields[midx]; 1639 length = off_be + width <= 32 ? 1640 width : 32 - off_be; 1641 if (mask) 1642 mask[midx] = flow_modify_info_mask_32 1643 (length, off_be); 1644 else 1645 info[idx].offset = off_be; 1646 width -= length; 1647 off_be = 0; 1648 idx++; 1649 } else { 1650 off_be -= 32; 1651 } 1652 midx--; 1653 } 1654 if (!width) 1655 break; 1656 info[idx] = fields[midx]; 1657 if (mask) 1658 mask[midx] = flow_modify_info_mask_32(width, off_be); 1659 else 1660 info[idx].offset = off_be; 1661 break; 1662 } 1663 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1664 MLX5_ASSERT(data->offset + width <= 16); 1665 off_be = 16 - (data->offset + width); 1666 info[idx] = (struct field_modify_info){2, 0, 1667 MLX5_MODI_OUT_TCP_SPORT}; 1668 if (mask) 1669 mask[idx] = flow_modify_info_mask_16(width, off_be); 1670 else 1671 info[idx].offset = off_be; 1672 break; 1673 case RTE_FLOW_FIELD_TCP_PORT_DST: 1674 MLX5_ASSERT(data->offset + width <= 16); 1675 off_be = 16 - (data->offset + width); 1676 info[idx] = (struct field_modify_info){2, 0, 1677 MLX5_MODI_OUT_TCP_DPORT}; 1678 if (mask) 1679 mask[idx] = flow_modify_info_mask_16(width, off_be); 1680 else 1681 info[idx].offset = off_be; 1682 break; 1683 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1684 MLX5_ASSERT(data->offset + width <= 32); 1685 off_be = 32 - (data->offset + width); 1686 info[idx] = (struct field_modify_info){4, 0, 1687 MLX5_MODI_OUT_TCP_SEQ_NUM}; 1688 if (mask) 1689 mask[idx] = flow_modify_info_mask_32(width, off_be); 1690 else 1691 info[idx].offset = off_be; 1692 break; 1693 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1694 MLX5_ASSERT(data->offset + width <= 32); 1695 off_be = 32 - (data->offset + width); 1696 info[idx] = (struct field_modify_info){4, 0, 1697 MLX5_MODI_OUT_TCP_ACK_NUM}; 1698 if (mask) 1699 mask[idx] = flow_modify_info_mask_32(width, off_be); 1700 else 1701 info[idx].offset = off_be; 1702 break; 1703 case RTE_FLOW_FIELD_TCP_FLAGS: 1704 MLX5_ASSERT(data->offset + width <= 9); 1705 off_be = 9 - (data->offset + width); 1706 info[idx] = (struct field_modify_info){2, 0, 1707 MLX5_MODI_OUT_TCP_FLAGS}; 1708 if (mask) 1709 mask[idx] = flow_modify_info_mask_16(width, off_be); 1710 else 1711 info[idx].offset = off_be; 1712 break; 1713 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1714 MLX5_ASSERT(data->offset + width <= 16); 1715 off_be = 16 - (data->offset + width); 1716 info[idx] = (struct field_modify_info){2, 0, 1717 MLX5_MODI_OUT_UDP_SPORT}; 1718 if (mask) 1719 mask[idx] = flow_modify_info_mask_16(width, off_be); 1720 else 1721 info[idx].offset = off_be; 1722 break; 1723 case RTE_FLOW_FIELD_UDP_PORT_DST: 1724 MLX5_ASSERT(data->offset + width <= 16); 1725 off_be = 16 - (data->offset + width); 1726 info[idx] = (struct field_modify_info){2, 0, 1727 MLX5_MODI_OUT_UDP_DPORT}; 1728 if (mask) 1729 mask[idx] = flow_modify_info_mask_16(width, off_be); 1730 else 1731 info[idx].offset = off_be; 1732 break; 1733 case RTE_FLOW_FIELD_VXLAN_VNI: 1734 MLX5_ASSERT(data->offset + width <= 24); 1735 /* VNI is on bits 31-8 of TUNNEL_HDR_DW_1. */ 1736 off_be = 24 - (data->offset + width) + 8; 1737 info[idx] = (struct field_modify_info){4, 0, 1738 MLX5_MODI_TUNNEL_HDR_DW_1}; 1739 if (mask) 1740 mask[idx] = flow_modify_info_mask_32(width, off_be); 1741 else 1742 info[idx].offset = off_be; 1743 break; 1744 case RTE_FLOW_FIELD_GENEVE_VNI: 1745 /* not supported yet*/ 1746 break; 1747 case RTE_FLOW_FIELD_GTP_TEID: 1748 MLX5_ASSERT(data->offset + width <= 32); 1749 off_be = 32 - (data->offset + width); 1750 info[idx] = (struct field_modify_info){4, 0, 1751 MLX5_MODI_GTP_TEID}; 1752 if (mask) 1753 mask[idx] = flow_modify_info_mask_32(width, off_be); 1754 else 1755 info[idx].offset = off_be; 1756 break; 1757 case RTE_FLOW_FIELD_TAG: 1758 { 1759 MLX5_ASSERT(data->offset + width <= 32); 1760 int reg; 1761 1762 if (priv->sh->config.dv_flow_en == 2) 1763 reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, 1764 data->level); 1765 else 1766 reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 1767 data->level, error); 1768 if (reg < 0) 1769 return; 1770 MLX5_ASSERT(reg != REG_NON); 1771 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1772 info[idx] = (struct field_modify_info){4, 0, 1773 reg_to_field[reg]}; 1774 if (mask) 1775 mask[idx] = flow_modify_info_mask_32 1776 (width, data->offset); 1777 else 1778 info[idx].offset = data->offset; 1779 } 1780 break; 1781 case RTE_FLOW_FIELD_MARK: 1782 { 1783 uint32_t mark_mask = priv->sh->dv_mark_mask; 1784 uint32_t mark_count = __builtin_popcount(mark_mask); 1785 RTE_SET_USED(mark_count); 1786 MLX5_ASSERT(data->offset + width <= mark_count); 1787 int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 1788 0, 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] = flow_modify_info_mask_32_masked 1797 (width, data->offset, mark_mask); 1798 else 1799 info[idx].offset = data->offset; 1800 } 1801 break; 1802 case RTE_FLOW_FIELD_META: 1803 { 1804 uint32_t meta_mask = priv->sh->dv_meta_mask; 1805 uint32_t meta_count = __builtin_popcount(meta_mask); 1806 RTE_SET_USED(meta_count); 1807 MLX5_ASSERT(data->offset + width <= meta_count); 1808 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1809 if (reg < 0) 1810 return; 1811 MLX5_ASSERT(reg != REG_NON); 1812 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1813 info[idx] = (struct field_modify_info){4, 0, 1814 reg_to_field[reg]}; 1815 if (mask) 1816 mask[idx] = flow_modify_info_mask_32_masked 1817 (width, data->offset, meta_mask); 1818 else 1819 info[idx].offset = data->offset; 1820 } 1821 break; 1822 case RTE_FLOW_FIELD_IPV4_ECN: 1823 case RTE_FLOW_FIELD_IPV6_ECN: 1824 MLX5_ASSERT(data->offset + width <= 2); 1825 off_be = 2 - (data->offset + width); 1826 info[idx] = (struct field_modify_info){1, 0, 1827 MLX5_MODI_OUT_IP_ECN}; 1828 if (mask) 1829 mask[idx] = flow_modify_info_mask_8(width, off_be); 1830 else 1831 info[idx].offset = off_be; 1832 break; 1833 case RTE_FLOW_FIELD_GTP_PSC_QFI: 1834 MLX5_ASSERT(data->offset + width <= 8); 1835 off_be = data->offset + 8; 1836 info[idx] = (struct field_modify_info){4, 0, 1837 MLX5_MODI_GTPU_FIRST_EXT_DW_0}; 1838 if (mask) 1839 mask[idx] = flow_modify_info_mask_32(width, off_be); 1840 else 1841 info[idx].offset = off_be; 1842 break; 1843 case MLX5_RTE_FLOW_FIELD_META_REG: 1844 { 1845 uint32_t meta_mask = priv->sh->dv_meta_mask; 1846 uint32_t meta_count = __builtin_popcount(meta_mask); 1847 uint32_t reg = data->level; 1848 1849 RTE_SET_USED(meta_count); 1850 MLX5_ASSERT(data->offset + width <= meta_count); 1851 MLX5_ASSERT(reg != REG_NON); 1852 MLX5_ASSERT(reg < RTE_DIM(reg_to_field)); 1853 info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1854 if (mask) 1855 mask[idx] = flow_modify_info_mask_32_masked 1856 (width, data->offset, meta_mask); 1857 else 1858 info[idx].offset = data->offset; 1859 } 1860 break; 1861 case RTE_FLOW_FIELD_METER_COLOR: 1862 { 1863 const uint32_t color_mask = 1864 (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 1865 int reg; 1866 1867 if (priv->sh->config.dv_flow_en == 2) 1868 reg = flow_hw_get_reg_id 1869 (RTE_FLOW_ITEM_TYPE_METER_COLOR, 0); 1870 else 1871 reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 1872 0, error); 1873 if (reg < 0) 1874 return; 1875 MLX5_ASSERT(reg != REG_NON); 1876 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1877 info[idx] = (struct field_modify_info){4, 0, 1878 reg_to_field[reg]}; 1879 if (mask) 1880 mask[idx] = flow_modify_info_mask_32_masked 1881 (width, data->offset, color_mask); 1882 else 1883 info[idx].offset = data->offset; 1884 } 1885 break; 1886 case RTE_FLOW_FIELD_POINTER: 1887 case RTE_FLOW_FIELD_VALUE: 1888 default: 1889 MLX5_ASSERT(false); 1890 break; 1891 } 1892 } 1893 1894 /** 1895 * Convert modify_field action to DV specification. 1896 * 1897 * @param[in] dev 1898 * Pointer to the rte_eth_dev structure. 1899 * @param[in,out] resource 1900 * Pointer to the modify-header resource. 1901 * @param[in] action 1902 * Pointer to action specification. 1903 * @param[in] attr 1904 * Attributes of flow that includes this item. 1905 * @param[out] error 1906 * Pointer to the error structure. 1907 * 1908 * @return 1909 * 0 on success, a negative errno value otherwise and rte_errno is set. 1910 */ 1911 static int 1912 flow_dv_convert_action_modify_field 1913 (struct rte_eth_dev *dev, 1914 struct mlx5_flow_dv_modify_hdr_resource *resource, 1915 const struct rte_flow_action *action, 1916 const struct rte_flow_attr *attr, 1917 struct rte_flow_error *error) 1918 { 1919 const struct rte_flow_action_modify_field *conf = 1920 (const struct rte_flow_action_modify_field *)(action->conf); 1921 struct rte_flow_item item = { 1922 .spec = NULL, 1923 .mask = NULL 1924 }; 1925 struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = { 1926 {0, 0, 0} }; 1927 struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = { 1928 {0, 0, 0} }; 1929 uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0}; 1930 uint32_t type, meta = 0; 1931 1932 if (conf->src.field == RTE_FLOW_FIELD_POINTER || 1933 conf->src.field == RTE_FLOW_FIELD_VALUE) { 1934 type = conf->operation == RTE_FLOW_MODIFY_SET ? 1935 MLX5_MODIFICATION_TYPE_SET : MLX5_MODIFICATION_TYPE_ADD; 1936 /** For SET fill the destination field (field) first. */ 1937 mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, 1938 conf->width, dev, 1939 attr, error); 1940 item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? 1941 (void *)(uintptr_t)conf->src.pvalue : 1942 (void *)(uintptr_t)&conf->src.value; 1943 if (conf->dst.field == RTE_FLOW_FIELD_META || 1944 conf->dst.field == RTE_FLOW_FIELD_TAG || 1945 conf->dst.field == RTE_FLOW_FIELD_METER_COLOR) { 1946 meta = *(const unaligned_uint32_t *)item.spec; 1947 meta = rte_cpu_to_be_32(meta); 1948 item.spec = &meta; 1949 } 1950 } else { 1951 type = MLX5_MODIFICATION_TYPE_COPY; 1952 /** For COPY fill the destination field (dcopy) without mask. */ 1953 mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL, 1954 conf->width, dev, 1955 attr, error); 1956 /** Then construct the source field (field) with mask. */ 1957 mlx5_flow_field_id_to_modify_info(&conf->src, field, mask, 1958 conf->width, dev, 1959 attr, error); 1960 } 1961 item.mask = &mask; 1962 return flow_dv_convert_modify_action(&item, 1963 field, dcopy, resource, type, error); 1964 } 1965 1966 /** 1967 * Validate MARK item. 1968 * 1969 * @param[in] dev 1970 * Pointer to the rte_eth_dev structure. 1971 * @param[in] item 1972 * Item specification. 1973 * @param[in] attr 1974 * Attributes of flow that includes this item. 1975 * @param[out] error 1976 * Pointer to error structure. 1977 * 1978 * @return 1979 * 0 on success, a negative errno value otherwise and rte_errno is set. 1980 */ 1981 static int 1982 flow_dv_validate_item_mark(struct rte_eth_dev *dev, 1983 const struct rte_flow_item *item, 1984 const struct rte_flow_attr *attr __rte_unused, 1985 struct rte_flow_error *error) 1986 { 1987 struct mlx5_priv *priv = dev->data->dev_private; 1988 struct mlx5_sh_config *config = &priv->sh->config; 1989 const struct rte_flow_item_mark *spec = item->spec; 1990 const struct rte_flow_item_mark *mask = item->mask; 1991 const struct rte_flow_item_mark nic_mask = { 1992 .id = priv->sh->dv_mark_mask, 1993 }; 1994 int ret; 1995 1996 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 1997 return rte_flow_error_set(error, ENOTSUP, 1998 RTE_FLOW_ERROR_TYPE_ITEM, item, 1999 "extended metadata feature" 2000 " isn't enabled"); 2001 if (!mlx5_flow_ext_mreg_supported(dev)) 2002 return rte_flow_error_set(error, ENOTSUP, 2003 RTE_FLOW_ERROR_TYPE_ITEM, item, 2004 "extended metadata register" 2005 " isn't supported"); 2006 if (!nic_mask.id) 2007 return rte_flow_error_set(error, ENOTSUP, 2008 RTE_FLOW_ERROR_TYPE_ITEM, item, 2009 "extended metadata register" 2010 " isn't available"); 2011 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 2012 if (ret < 0) 2013 return ret; 2014 if (!spec) 2015 return rte_flow_error_set(error, EINVAL, 2016 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2017 item->spec, 2018 "data cannot be empty"); 2019 if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id)) 2020 return rte_flow_error_set(error, EINVAL, 2021 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 2022 &spec->id, 2023 "mark id exceeds the limit"); 2024 if (!mask) 2025 mask = &nic_mask; 2026 if (!mask->id) 2027 return rte_flow_error_set(error, EINVAL, 2028 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2029 "mask cannot be zero"); 2030 2031 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2032 (const uint8_t *)&nic_mask, 2033 sizeof(struct rte_flow_item_mark), 2034 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2035 if (ret < 0) 2036 return ret; 2037 return 0; 2038 } 2039 2040 /** 2041 * Validate META item. 2042 * 2043 * @param[in] dev 2044 * Pointer to the rte_eth_dev structure. 2045 * @param[in] item 2046 * Item specification. 2047 * @param[in] attr 2048 * Attributes of flow that includes this item. 2049 * @param[out] error 2050 * Pointer to error structure. 2051 * 2052 * @return 2053 * 0 on success, a negative errno value otherwise and rte_errno is set. 2054 */ 2055 static int 2056 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused, 2057 const struct rte_flow_item *item, 2058 const struct rte_flow_attr *attr, 2059 struct rte_flow_error *error) 2060 { 2061 struct mlx5_priv *priv = dev->data->dev_private; 2062 struct mlx5_sh_config *config = &priv->sh->config; 2063 const struct rte_flow_item_meta *spec = item->spec; 2064 const struct rte_flow_item_meta *mask = item->mask; 2065 struct rte_flow_item_meta nic_mask = { 2066 .data = UINT32_MAX 2067 }; 2068 int reg; 2069 int ret; 2070 2071 if (!spec) 2072 return rte_flow_error_set(error, EINVAL, 2073 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2074 item->spec, 2075 "data cannot be empty"); 2076 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 2077 if (!mlx5_flow_ext_mreg_supported(dev)) 2078 return rte_flow_error_set(error, ENOTSUP, 2079 RTE_FLOW_ERROR_TYPE_ITEM, item, 2080 "extended metadata register" 2081 " isn't supported"); 2082 reg = flow_dv_get_metadata_reg(dev, attr, error); 2083 if (reg < 0) 2084 return reg; 2085 if (reg == REG_NON) 2086 return rte_flow_error_set(error, ENOTSUP, 2087 RTE_FLOW_ERROR_TYPE_ITEM, item, 2088 "unavailable extended metadata register"); 2089 if (reg == REG_B) 2090 return rte_flow_error_set(error, ENOTSUP, 2091 RTE_FLOW_ERROR_TYPE_ITEM, item, 2092 "match on reg_b " 2093 "isn't supported"); 2094 if (reg != REG_A) 2095 nic_mask.data = priv->sh->dv_meta_mask; 2096 } else { 2097 if (attr->transfer) 2098 return rte_flow_error_set(error, ENOTSUP, 2099 RTE_FLOW_ERROR_TYPE_ITEM, item, 2100 "extended metadata feature " 2101 "should be enabled when " 2102 "meta item is requested " 2103 "with e-switch mode "); 2104 if (attr->ingress) 2105 return rte_flow_error_set(error, ENOTSUP, 2106 RTE_FLOW_ERROR_TYPE_ITEM, item, 2107 "match on metadata for ingress " 2108 "is not supported in legacy " 2109 "metadata mode"); 2110 } 2111 if (!mask) 2112 mask = &rte_flow_item_meta_mask; 2113 if (!mask->data) 2114 return rte_flow_error_set(error, EINVAL, 2115 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2116 "mask cannot be zero"); 2117 2118 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2119 (const uint8_t *)&nic_mask, 2120 sizeof(struct rte_flow_item_meta), 2121 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2122 return ret; 2123 } 2124 2125 /** 2126 * Validate TAG item. 2127 * 2128 * @param[in] dev 2129 * Pointer to the rte_eth_dev structure. 2130 * @param[in] item 2131 * Item specification. 2132 * @param[in] attr 2133 * Attributes of flow that includes this item. 2134 * @param[out] error 2135 * Pointer to error structure. 2136 * 2137 * @return 2138 * 0 on success, a negative errno value otherwise and rte_errno is set. 2139 */ 2140 static int 2141 flow_dv_validate_item_tag(struct rte_eth_dev *dev, 2142 const struct rte_flow_item *item, 2143 const struct rte_flow_attr *attr __rte_unused, 2144 struct rte_flow_error *error) 2145 { 2146 const struct rte_flow_item_tag *spec = item->spec; 2147 const struct rte_flow_item_tag *mask = item->mask; 2148 const struct rte_flow_item_tag nic_mask = { 2149 .data = RTE_BE32(UINT32_MAX), 2150 .index = 0xff, 2151 }; 2152 int ret; 2153 2154 if (!mlx5_flow_ext_mreg_supported(dev)) 2155 return rte_flow_error_set(error, ENOTSUP, 2156 RTE_FLOW_ERROR_TYPE_ITEM, item, 2157 "extensive metadata register" 2158 " isn't supported"); 2159 if (!spec) 2160 return rte_flow_error_set(error, EINVAL, 2161 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2162 item->spec, 2163 "data cannot be empty"); 2164 if (!mask) 2165 mask = &rte_flow_item_tag_mask; 2166 if (!mask->data) 2167 return rte_flow_error_set(error, EINVAL, 2168 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2169 "mask cannot be zero"); 2170 2171 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2172 (const uint8_t *)&nic_mask, 2173 sizeof(struct rte_flow_item_tag), 2174 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2175 if (ret < 0) 2176 return ret; 2177 if (mask->index != 0xff) 2178 return rte_flow_error_set(error, EINVAL, 2179 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2180 "partial mask for tag index" 2181 " is not supported"); 2182 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error); 2183 if (ret < 0) 2184 return ret; 2185 MLX5_ASSERT(ret != REG_NON); 2186 return 0; 2187 } 2188 2189 /** 2190 * Validate vport item. 2191 * 2192 * @param[in] dev 2193 * Pointer to the rte_eth_dev structure. 2194 * @param[in] item 2195 * Item specification. 2196 * @param[in] attr 2197 * Attributes of flow that includes this item. 2198 * @param[in] item_flags 2199 * Bit-fields that holds the items detected until now. 2200 * @param[out] error 2201 * Pointer to error structure. 2202 * 2203 * @return 2204 * 0 on success, a negative errno value otherwise and rte_errno is set. 2205 */ 2206 static int 2207 flow_dv_validate_item_port_id(struct rte_eth_dev *dev, 2208 const struct rte_flow_item *item, 2209 const struct rte_flow_attr *attr, 2210 uint64_t item_flags, 2211 struct mlx5_priv **act_priv, 2212 struct rte_flow_error *error) 2213 { 2214 const struct rte_flow_item_port_id *spec = item->spec; 2215 const struct rte_flow_item_port_id *mask = item->mask; 2216 const struct rte_flow_item_port_id switch_mask = { 2217 .id = 0xffffffff, 2218 }; 2219 struct mlx5_priv *esw_priv; 2220 struct mlx5_priv *dev_priv; 2221 int ret; 2222 2223 if (!attr->transfer) 2224 return rte_flow_error_set(error, EINVAL, 2225 RTE_FLOW_ERROR_TYPE_ITEM, 2226 NULL, 2227 "match on port id is valid only" 2228 " when transfer flag is enabled"); 2229 if (item_flags & MLX5_FLOW_ITEM_PORT_ID) 2230 return rte_flow_error_set(error, ENOTSUP, 2231 RTE_FLOW_ERROR_TYPE_ITEM, item, 2232 "multiple source ports are not" 2233 " supported"); 2234 if (!mask) 2235 mask = &switch_mask; 2236 if (mask->id != 0xffffffff) 2237 return rte_flow_error_set(error, ENOTSUP, 2238 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2239 mask, 2240 "no support for partial mask on" 2241 " \"id\" field"); 2242 ret = mlx5_flow_item_acceptable 2243 (item, (const uint8_t *)mask, 2244 (const uint8_t *)&rte_flow_item_port_id_mask, 2245 sizeof(struct rte_flow_item_port_id), 2246 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2247 if (ret) 2248 return ret; 2249 if (!spec) 2250 return 0; 2251 if (spec->id == MLX5_PORT_ESW_MGR) 2252 return 0; 2253 esw_priv = mlx5_port_to_eswitch_info(spec->id, false); 2254 if (!esw_priv) 2255 return rte_flow_error_set(error, rte_errno, 2256 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2257 "failed to obtain E-Switch info for" 2258 " port"); 2259 dev_priv = mlx5_dev_to_eswitch_info(dev); 2260 if (!dev_priv) 2261 return rte_flow_error_set(error, rte_errno, 2262 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2263 NULL, 2264 "failed to obtain E-Switch info"); 2265 if (esw_priv->domain_id != dev_priv->domain_id) 2266 return rte_flow_error_set(error, EINVAL, 2267 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2268 "cannot match on a port from a" 2269 " different E-Switch"); 2270 *act_priv = esw_priv; 2271 return 0; 2272 } 2273 2274 /** 2275 * Validate represented port item. 2276 * 2277 * @param[in] dev 2278 * Pointer to the rte_eth_dev structure. 2279 * @param[in] item 2280 * Item specification. 2281 * @param[in] attr 2282 * Attributes of flow that includes this item. 2283 * @param[in] item_flags 2284 * Bit-fields that holds the items detected until now. 2285 * @param[out] error 2286 * Pointer to error structure. 2287 * 2288 * @return 2289 * 0 on success, a negative errno value otherwise and rte_errno is set. 2290 */ 2291 static int 2292 flow_dv_validate_item_represented_port(struct rte_eth_dev *dev, 2293 const struct rte_flow_item *item, 2294 const struct rte_flow_attr *attr, 2295 uint64_t item_flags, 2296 struct mlx5_priv **act_priv, 2297 struct rte_flow_error *error) 2298 { 2299 const struct rte_flow_item_ethdev *spec = item->spec; 2300 const struct rte_flow_item_ethdev *mask = item->mask; 2301 const struct rte_flow_item_ethdev switch_mask = { 2302 .port_id = UINT16_MAX, 2303 }; 2304 struct mlx5_priv *esw_priv; 2305 struct mlx5_priv *dev_priv; 2306 int ret; 2307 2308 if (!attr->transfer) 2309 return rte_flow_error_set(error, EINVAL, 2310 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2311 "match on port id is valid only when transfer flag is enabled"); 2312 if (item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) 2313 return rte_flow_error_set(error, ENOTSUP, 2314 RTE_FLOW_ERROR_TYPE_ITEM, item, 2315 "multiple source ports are not supported"); 2316 if (!mask) 2317 mask = &switch_mask; 2318 if (mask->port_id != UINT16_MAX) 2319 return rte_flow_error_set(error, ENOTSUP, 2320 RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, 2321 "no support for partial mask on \"id\" field"); 2322 ret = mlx5_flow_item_acceptable 2323 (item, (const uint8_t *)mask, 2324 (const uint8_t *)&rte_flow_item_ethdev_mask, 2325 sizeof(struct rte_flow_item_ethdev), 2326 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2327 if (ret) 2328 return ret; 2329 if (!spec || spec->port_id == UINT16_MAX) 2330 return 0; 2331 esw_priv = mlx5_port_to_eswitch_info(spec->port_id, false); 2332 if (!esw_priv) 2333 return rte_flow_error_set(error, rte_errno, 2334 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2335 "failed to obtain E-Switch info for port"); 2336 dev_priv = mlx5_dev_to_eswitch_info(dev); 2337 if (!dev_priv) 2338 return rte_flow_error_set(error, rte_errno, 2339 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2340 NULL, 2341 "failed to obtain E-Switch info"); 2342 if (esw_priv->domain_id != dev_priv->domain_id) 2343 return rte_flow_error_set(error, EINVAL, 2344 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2345 "cannot match on a port from a different E-Switch"); 2346 *act_priv = esw_priv; 2347 return 0; 2348 } 2349 2350 /** 2351 * Validate VLAN item. 2352 * 2353 * @param[in] item 2354 * Item specification. 2355 * @param[in] item_flags 2356 * Bit-fields that holds the items detected until now. 2357 * @param[in] dev 2358 * Ethernet device flow is being created on. 2359 * @param[out] error 2360 * Pointer to error structure. 2361 * 2362 * @return 2363 * 0 on success, a negative errno value otherwise and rte_errno is set. 2364 */ 2365 static int 2366 flow_dv_validate_item_vlan(const struct rte_flow_item *item, 2367 uint64_t item_flags, 2368 struct rte_eth_dev *dev, 2369 struct rte_flow_error *error) 2370 { 2371 const struct rte_flow_item_vlan *mask = item->mask; 2372 const struct rte_flow_item_vlan nic_mask = { 2373 .hdr.vlan_tci = RTE_BE16(UINT16_MAX), 2374 .hdr.eth_proto = RTE_BE16(UINT16_MAX), 2375 .has_more_vlan = 1, 2376 }; 2377 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2378 int ret; 2379 const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 | 2380 MLX5_FLOW_LAYER_INNER_L4) : 2381 (MLX5_FLOW_LAYER_OUTER_L3 | 2382 MLX5_FLOW_LAYER_OUTER_L4); 2383 const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 2384 MLX5_FLOW_LAYER_OUTER_VLAN; 2385 2386 if (item_flags & vlanm) 2387 return rte_flow_error_set(error, EINVAL, 2388 RTE_FLOW_ERROR_TYPE_ITEM, item, 2389 "multiple VLAN layers not supported"); 2390 else if ((item_flags & l34m) != 0) 2391 return rte_flow_error_set(error, EINVAL, 2392 RTE_FLOW_ERROR_TYPE_ITEM, item, 2393 "VLAN cannot follow L3/L4 layer"); 2394 if (!mask) 2395 mask = &rte_flow_item_vlan_mask; 2396 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2397 (const uint8_t *)&nic_mask, 2398 sizeof(struct rte_flow_item_vlan), 2399 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2400 if (ret) 2401 return ret; 2402 if (!tunnel && mask->hdr.vlan_tci != RTE_BE16(0x0fff)) { 2403 struct mlx5_priv *priv = dev->data->dev_private; 2404 2405 if (priv->vmwa_context) { 2406 /* 2407 * Non-NULL context means we have a virtual machine 2408 * and SR-IOV enabled, we have to create VLAN interface 2409 * to make hypervisor to setup E-Switch vport 2410 * context correctly. We avoid creating the multiple 2411 * VLAN interfaces, so we cannot support VLAN tag mask. 2412 */ 2413 return rte_flow_error_set(error, EINVAL, 2414 RTE_FLOW_ERROR_TYPE_ITEM, 2415 item, 2416 "VLAN tag mask is not" 2417 " supported in virtual" 2418 " environment"); 2419 } 2420 } 2421 return 0; 2422 } 2423 2424 /* 2425 * GTP flags are contained in 1 byte of the format: 2426 * ------------------------------------------- 2427 * | bit | 0 - 2 | 3 | 4 | 5 | 6 | 7 | 2428 * |-----------------------------------------| 2429 * | value | Version | PT | Res | E | S | PN | 2430 * ------------------------------------------- 2431 * 2432 * Matching is supported only for GTP flags E, S, PN. 2433 */ 2434 #define MLX5_GTP_FLAGS_MASK 0x07 2435 2436 /** 2437 * Validate GTP item. 2438 * 2439 * @param[in] dev 2440 * Pointer to the rte_eth_dev structure. 2441 * @param[in] item 2442 * Item specification. 2443 * @param[in] item_flags 2444 * Bit-fields that holds the items detected until now. 2445 * @param[out] error 2446 * Pointer to error structure. 2447 * 2448 * @return 2449 * 0 on success, a negative errno value otherwise and rte_errno is set. 2450 */ 2451 static int 2452 flow_dv_validate_item_gtp(struct rte_eth_dev *dev, 2453 const struct rte_flow_item *item, 2454 uint64_t item_flags, 2455 struct rte_flow_error *error) 2456 { 2457 struct mlx5_priv *priv = dev->data->dev_private; 2458 const struct rte_flow_item_gtp *spec = item->spec; 2459 const struct rte_flow_item_gtp *mask = item->mask; 2460 const struct rte_flow_item_gtp nic_mask = { 2461 .hdr.gtp_hdr_info = MLX5_GTP_FLAGS_MASK, 2462 .hdr.msg_type = 0xff, 2463 .hdr.teid = RTE_BE32(0xffffffff), 2464 }; 2465 2466 if (!priv->sh->cdev->config.hca_attr.tunnel_stateless_gtp) 2467 return rte_flow_error_set(error, ENOTSUP, 2468 RTE_FLOW_ERROR_TYPE_ITEM, item, 2469 "GTP support is not enabled"); 2470 if (item_flags & MLX5_FLOW_LAYER_TUNNEL) 2471 return rte_flow_error_set(error, ENOTSUP, 2472 RTE_FLOW_ERROR_TYPE_ITEM, item, 2473 "multiple tunnel layers not" 2474 " supported"); 2475 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP)) 2476 return rte_flow_error_set(error, EINVAL, 2477 RTE_FLOW_ERROR_TYPE_ITEM, item, 2478 "no outer UDP layer found"); 2479 if (!mask) 2480 mask = &rte_flow_item_gtp_mask; 2481 if (spec && spec->hdr.gtp_hdr_info & ~MLX5_GTP_FLAGS_MASK) 2482 return rte_flow_error_set(error, ENOTSUP, 2483 RTE_FLOW_ERROR_TYPE_ITEM, item, 2484 "Match is supported for GTP" 2485 " flags only"); 2486 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2487 (const uint8_t *)&nic_mask, 2488 sizeof(struct rte_flow_item_gtp), 2489 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2490 } 2491 2492 /** 2493 * Validate GTP PSC item. 2494 * 2495 * @param[in] item 2496 * Item specification. 2497 * @param[in] last_item 2498 * Previous validated item in the pattern items. 2499 * @param[in] gtp_item 2500 * Previous GTP item specification. 2501 * @param root 2502 * Whether action is on root table. 2503 * @param[out] error 2504 * Pointer to error structure. 2505 * 2506 * @return 2507 * 0 on success, a negative errno value otherwise and rte_errno is set. 2508 */ 2509 static int 2510 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, 2511 uint64_t last_item, 2512 const struct rte_flow_item *gtp_item, 2513 bool root, 2514 struct rte_flow_error *error) 2515 { 2516 const struct rte_flow_item_gtp *gtp_spec; 2517 const struct rte_flow_item_gtp *gtp_mask; 2518 const struct rte_flow_item_gtp_psc *mask; 2519 const struct rte_flow_item_gtp_psc nic_mask = { 2520 .hdr.type = 0xF, 2521 .hdr.qfi = 0x3F, 2522 }; 2523 2524 if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP)) 2525 return rte_flow_error_set 2526 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2527 "GTP PSC item must be preceded with GTP item"); 2528 gtp_spec = gtp_item->spec; 2529 gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask; 2530 /* GTP spec and E flag is requested to match zero. */ 2531 if (gtp_spec && 2532 (gtp_mask->hdr.gtp_hdr_info & 2533 ~gtp_spec->hdr.gtp_hdr_info & MLX5_GTP_EXT_HEADER_FLAG)) 2534 return rte_flow_error_set 2535 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2536 "GTP E flag must be 1 to match GTP PSC"); 2537 /* Check the flow is not created in group zero. */ 2538 if (root) 2539 return rte_flow_error_set 2540 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2541 "GTP PSC is not supported for group 0"); 2542 /* GTP spec is here and E flag is requested to match zero. */ 2543 if (!item->spec) 2544 return 0; 2545 mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask; 2546 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2547 (const uint8_t *)&nic_mask, 2548 sizeof(struct rte_flow_item_gtp_psc), 2549 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2550 } 2551 2552 /** 2553 * Validate IPV4 item. 2554 * Use existing validation function mlx5_flow_validate_item_ipv4(), and 2555 * add specific validation of fragment_offset field, 2556 * 2557 * @param[in] item 2558 * Item specification. 2559 * @param[in] item_flags 2560 * Bit-fields that holds the items detected until now. 2561 * @param[out] error 2562 * Pointer to error structure. 2563 * 2564 * @return 2565 * 0 on success, a negative errno value otherwise and rte_errno is set. 2566 */ 2567 static int 2568 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev, 2569 const struct rte_flow_item *item, 2570 uint64_t item_flags, uint64_t last_item, 2571 uint16_t ether_type, struct rte_flow_error *error) 2572 { 2573 int ret; 2574 struct mlx5_priv *priv = dev->data->dev_private; 2575 struct mlx5_hca_attr *attr = &priv->sh->cdev->config.hca_attr; 2576 const struct rte_flow_item_ipv4 *spec = item->spec; 2577 const struct rte_flow_item_ipv4 *last = item->last; 2578 const struct rte_flow_item_ipv4 *mask = item->mask; 2579 rte_be16_t fragment_offset_spec = 0; 2580 rte_be16_t fragment_offset_last = 0; 2581 struct rte_flow_item_ipv4 nic_ipv4_mask = { 2582 .hdr = { 2583 .src_addr = RTE_BE32(0xffffffff), 2584 .dst_addr = RTE_BE32(0xffffffff), 2585 .type_of_service = 0xff, 2586 .fragment_offset = RTE_BE16(0xffff), 2587 .next_proto_id = 0xff, 2588 .time_to_live = 0xff, 2589 }, 2590 }; 2591 2592 if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) { 2593 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2594 bool ihl_cap = !tunnel ? 2595 attr->outer_ipv4_ihl : attr->inner_ipv4_ihl; 2596 if (!ihl_cap) 2597 return rte_flow_error_set(error, ENOTSUP, 2598 RTE_FLOW_ERROR_TYPE_ITEM, 2599 item, 2600 "IPV4 ihl offload not supported"); 2601 nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl; 2602 } 2603 ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item, 2604 ether_type, &nic_ipv4_mask, 2605 MLX5_ITEM_RANGE_ACCEPTED, error); 2606 if (ret < 0) 2607 return ret; 2608 if (spec && mask) 2609 fragment_offset_spec = spec->hdr.fragment_offset & 2610 mask->hdr.fragment_offset; 2611 if (!fragment_offset_spec) 2612 return 0; 2613 /* 2614 * spec and mask are valid, enforce using full mask to make sure the 2615 * complete value is used correctly. 2616 */ 2617 if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2618 != RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2619 return rte_flow_error_set(error, EINVAL, 2620 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2621 item, "must use full mask for" 2622 " fragment_offset"); 2623 /* 2624 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0, 2625 * indicating this is 1st fragment of fragmented packet. 2626 * This is not yet supported in MLX5, return appropriate error message. 2627 */ 2628 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG)) 2629 return rte_flow_error_set(error, ENOTSUP, 2630 RTE_FLOW_ERROR_TYPE_ITEM, item, 2631 "match on first fragment not " 2632 "supported"); 2633 if (fragment_offset_spec && !last) 2634 return rte_flow_error_set(error, ENOTSUP, 2635 RTE_FLOW_ERROR_TYPE_ITEM, item, 2636 "specified value not supported"); 2637 /* spec and last are valid, validate the specified range. */ 2638 fragment_offset_last = last->hdr.fragment_offset & 2639 mask->hdr.fragment_offset; 2640 /* 2641 * Match on fragment_offset spec 0x2001 and last 0x3fff 2642 * means MF is 1 and frag-offset is > 0. 2643 * This packet is fragment 2nd and onward, excluding last. 2644 * This is not yet supported in MLX5, return appropriate 2645 * error message. 2646 */ 2647 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) && 2648 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2649 return rte_flow_error_set(error, ENOTSUP, 2650 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2651 last, "match on following " 2652 "fragments not supported"); 2653 /* 2654 * Match on fragment_offset spec 0x0001 and last 0x1fff 2655 * means MF is 0 and frag-offset is > 0. 2656 * This packet is last fragment of fragmented packet. 2657 * This is not yet supported in MLX5, return appropriate 2658 * error message. 2659 */ 2660 if (fragment_offset_spec == RTE_BE16(1) && 2661 fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK)) 2662 return rte_flow_error_set(error, ENOTSUP, 2663 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2664 last, "match on last " 2665 "fragment not supported"); 2666 /* 2667 * Match on fragment_offset spec 0x0001 and last 0x3fff 2668 * means MF and/or frag-offset is not 0. 2669 * This is a fragmented packet. 2670 * Other range values are invalid and rejected. 2671 */ 2672 if (!(fragment_offset_spec == RTE_BE16(1) && 2673 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))) 2674 return rte_flow_error_set(error, ENOTSUP, 2675 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2676 "specified range not supported"); 2677 return 0; 2678 } 2679 2680 /** 2681 * Validate IPV6 fragment extension item. 2682 * 2683 * @param[in] item 2684 * Item specification. 2685 * @param[in] item_flags 2686 * Bit-fields that holds the items detected until now. 2687 * @param[out] error 2688 * Pointer to error structure. 2689 * 2690 * @return 2691 * 0 on success, a negative errno value otherwise and rte_errno is set. 2692 */ 2693 static int 2694 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item, 2695 uint64_t item_flags, 2696 struct rte_flow_error *error) 2697 { 2698 const struct rte_flow_item_ipv6_frag_ext *spec = item->spec; 2699 const struct rte_flow_item_ipv6_frag_ext *last = item->last; 2700 const struct rte_flow_item_ipv6_frag_ext *mask = item->mask; 2701 rte_be16_t frag_data_spec = 0; 2702 rte_be16_t frag_data_last = 0; 2703 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2704 const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 : 2705 MLX5_FLOW_LAYER_OUTER_L4; 2706 int ret = 0; 2707 struct rte_flow_item_ipv6_frag_ext nic_mask = { 2708 .hdr = { 2709 .next_header = 0xff, 2710 .frag_data = RTE_BE16(0xffff), 2711 }, 2712 }; 2713 2714 if (item_flags & l4m) 2715 return rte_flow_error_set(error, EINVAL, 2716 RTE_FLOW_ERROR_TYPE_ITEM, item, 2717 "ipv6 fragment extension item cannot " 2718 "follow L4 item."); 2719 if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 2720 (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) 2721 return rte_flow_error_set(error, EINVAL, 2722 RTE_FLOW_ERROR_TYPE_ITEM, item, 2723 "ipv6 fragment extension item must " 2724 "follow ipv6 item"); 2725 if (spec && mask) 2726 frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data; 2727 if (!frag_data_spec) 2728 return 0; 2729 /* 2730 * spec and mask are valid, enforce using full mask to make sure the 2731 * complete value is used correctly. 2732 */ 2733 if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) != 2734 RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2735 return rte_flow_error_set(error, EINVAL, 2736 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2737 item, "must use full mask for" 2738 " frag_data"); 2739 /* 2740 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0. 2741 * This is 1st fragment of fragmented packet. 2742 */ 2743 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK)) 2744 return rte_flow_error_set(error, ENOTSUP, 2745 RTE_FLOW_ERROR_TYPE_ITEM, item, 2746 "match on first fragment not " 2747 "supported"); 2748 if (frag_data_spec && !last) 2749 return rte_flow_error_set(error, EINVAL, 2750 RTE_FLOW_ERROR_TYPE_ITEM, item, 2751 "specified value not supported"); 2752 ret = mlx5_flow_item_acceptable 2753 (item, (const uint8_t *)mask, 2754 (const uint8_t *)&nic_mask, 2755 sizeof(struct rte_flow_item_ipv6_frag_ext), 2756 MLX5_ITEM_RANGE_ACCEPTED, error); 2757 if (ret) 2758 return ret; 2759 /* spec and last are valid, validate the specified range. */ 2760 frag_data_last = last->hdr.frag_data & mask->hdr.frag_data; 2761 /* 2762 * Match on frag_data spec 0x0009 and last 0xfff9 2763 * means M is 1 and frag-offset is > 0. 2764 * This packet is fragment 2nd and onward, excluding last. 2765 * This is not yet supported in MLX5, return appropriate 2766 * error message. 2767 */ 2768 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN | 2769 RTE_IPV6_EHDR_MF_MASK) && 2770 frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2771 return rte_flow_error_set(error, ENOTSUP, 2772 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2773 last, "match on following " 2774 "fragments not supported"); 2775 /* 2776 * Match on frag_data spec 0x0008 and last 0xfff8 2777 * means M is 0 and frag-offset is > 0. 2778 * This packet is last fragment of fragmented packet. 2779 * This is not yet supported in MLX5, return appropriate 2780 * error message. 2781 */ 2782 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) && 2783 frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK)) 2784 return rte_flow_error_set(error, ENOTSUP, 2785 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2786 last, "match on last " 2787 "fragment not supported"); 2788 /* Other range values are invalid and rejected. */ 2789 return rte_flow_error_set(error, EINVAL, 2790 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2791 "specified range not supported"); 2792 } 2793 2794 /* 2795 * Validate ASO CT item. 2796 * 2797 * @param[in] dev 2798 * Pointer to the rte_eth_dev structure. 2799 * @param[in] item 2800 * Item specification. 2801 * @param[in] item_flags 2802 * Pointer to bit-fields that holds the items detected until now. 2803 * @param[out] error 2804 * Pointer to error structure. 2805 * 2806 * @return 2807 * 0 on success, a negative errno value otherwise and rte_errno is set. 2808 */ 2809 static int 2810 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev, 2811 const struct rte_flow_item *item, 2812 uint64_t *item_flags, 2813 struct rte_flow_error *error) 2814 { 2815 const struct rte_flow_item_conntrack *spec = item->spec; 2816 const struct rte_flow_item_conntrack *mask = item->mask; 2817 RTE_SET_USED(dev); 2818 uint32_t flags; 2819 2820 if (*item_flags & MLX5_FLOW_LAYER_ASO_CT) 2821 return rte_flow_error_set(error, EINVAL, 2822 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2823 "Only one CT is supported"); 2824 if (!mask) 2825 mask = &rte_flow_item_conntrack_mask; 2826 flags = spec->flags & mask->flags; 2827 if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) && 2828 ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) || 2829 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) || 2830 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))) 2831 return rte_flow_error_set(error, EINVAL, 2832 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2833 "Conflict status bits"); 2834 /* State change also needs to be considered. */ 2835 *item_flags |= MLX5_FLOW_LAYER_ASO_CT; 2836 return 0; 2837 } 2838 2839 /** 2840 * Validate the pop VLAN action. 2841 * 2842 * @param[in] dev 2843 * Pointer to the rte_eth_dev structure. 2844 * @param[in] action_flags 2845 * Holds the actions detected until now. 2846 * @param[in] action 2847 * Pointer to the pop vlan action. 2848 * @param[in] item_flags 2849 * The items found in this flow rule. 2850 * @param[in] attr 2851 * Pointer to flow attributes. 2852 * @param[out] error 2853 * Pointer to error structure. 2854 * 2855 * @return 2856 * 0 on success, a negative errno value otherwise and rte_errno is set. 2857 */ 2858 static int 2859 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev, 2860 uint64_t action_flags, 2861 const struct rte_flow_action *action, 2862 uint64_t item_flags, 2863 const struct rte_flow_attr *attr, 2864 struct rte_flow_error *error) 2865 { 2866 const struct mlx5_priv *priv = dev->data->dev_private; 2867 2868 if (!priv->sh->pop_vlan_action) 2869 return rte_flow_error_set(error, ENOTSUP, 2870 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2871 NULL, 2872 "pop vlan action is not supported"); 2873 if (action_flags & MLX5_FLOW_VLAN_ACTIONS) 2874 return rte_flow_error_set(error, ENOTSUP, 2875 RTE_FLOW_ERROR_TYPE_ACTION, action, 2876 "no support for multiple VLAN " 2877 "actions"); 2878 /* Pop VLAN with preceding Decap requires inner header with VLAN. */ 2879 if ((action_flags & MLX5_FLOW_ACTION_DECAP) && 2880 !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN)) 2881 return rte_flow_error_set(error, ENOTSUP, 2882 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2883 NULL, 2884 "cannot pop vlan after decap without " 2885 "match on inner vlan in the flow"); 2886 /* Pop VLAN without preceding Decap requires outer header with VLAN. */ 2887 if (!(action_flags & MLX5_FLOW_ACTION_DECAP) && 2888 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 2889 return rte_flow_error_set(error, ENOTSUP, 2890 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2891 NULL, 2892 "cannot pop vlan without a " 2893 "match on (outer) vlan in the flow"); 2894 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2895 return rte_flow_error_set(error, EINVAL, 2896 RTE_FLOW_ERROR_TYPE_ACTION, action, 2897 "wrong action order, port_id should " 2898 "be after pop VLAN action"); 2899 if (!attr->transfer && priv->representor) 2900 return rte_flow_error_set(error, ENOTSUP, 2901 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2902 "pop vlan action for VF representor " 2903 "not supported on NIC table"); 2904 return 0; 2905 } 2906 2907 /** 2908 * Get VLAN default info from vlan match info. 2909 * 2910 * @param[in] items 2911 * the list of item specifications. 2912 * @param[out] vlan 2913 * pointer VLAN info to fill to. 2914 * 2915 * @return 2916 * 0 on success, a negative errno value otherwise and rte_errno is set. 2917 */ 2918 static void 2919 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items, 2920 struct rte_vlan_hdr *vlan) 2921 { 2922 const struct rte_flow_item_vlan nic_mask = { 2923 .hdr.vlan_tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK | 2924 MLX5DV_FLOW_VLAN_VID_MASK), 2925 .hdr.eth_proto = RTE_BE16(0xffff), 2926 }; 2927 2928 if (items == NULL) 2929 return; 2930 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 2931 int type = items->type; 2932 2933 if (type == RTE_FLOW_ITEM_TYPE_VLAN || 2934 type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN) 2935 break; 2936 } 2937 if (items->type != RTE_FLOW_ITEM_TYPE_END) { 2938 const struct rte_flow_item_vlan *vlan_m = items->mask; 2939 const struct rte_flow_item_vlan *vlan_v = items->spec; 2940 2941 /* If VLAN item in pattern doesn't contain data, return here. */ 2942 if (!vlan_v) 2943 return; 2944 if (!vlan_m) 2945 vlan_m = &nic_mask; 2946 /* Only full match values are accepted */ 2947 if ((vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) == 2948 MLX5DV_FLOW_VLAN_PCP_MASK_BE) { 2949 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 2950 vlan->vlan_tci |= 2951 rte_be_to_cpu_16(vlan_v->hdr.vlan_tci & 2952 MLX5DV_FLOW_VLAN_PCP_MASK_BE); 2953 } 2954 if ((vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) == 2955 MLX5DV_FLOW_VLAN_VID_MASK_BE) { 2956 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 2957 vlan->vlan_tci |= 2958 rte_be_to_cpu_16(vlan_v->hdr.vlan_tci & 2959 MLX5DV_FLOW_VLAN_VID_MASK_BE); 2960 } 2961 if (vlan_m->hdr.eth_proto == nic_mask.hdr.eth_proto) 2962 vlan->eth_proto = rte_be_to_cpu_16(vlan_v->hdr.eth_proto & 2963 vlan_m->hdr.eth_proto); 2964 } 2965 } 2966 2967 /** 2968 * Validate the push VLAN action. 2969 * 2970 * @param[in] dev 2971 * Pointer to the rte_eth_dev structure. 2972 * @param[in] action_flags 2973 * Holds the actions detected until now. 2974 * @param[in] item_flags 2975 * The items found in this flow rule. 2976 * @param[in] action 2977 * Pointer to the action structure. 2978 * @param[in] attr 2979 * Pointer to flow attributes 2980 * @param[out] error 2981 * Pointer to error structure. 2982 * 2983 * @return 2984 * 0 on success, a negative errno value otherwise and rte_errno is set. 2985 */ 2986 static int 2987 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev, 2988 uint64_t action_flags, 2989 const struct rte_flow_item_vlan *vlan_m, 2990 const struct rte_flow_action *action, 2991 const struct rte_flow_attr *attr, 2992 struct rte_flow_error *error) 2993 { 2994 const struct rte_flow_action_of_push_vlan *push_vlan = action->conf; 2995 const struct mlx5_priv *priv = dev->data->dev_private; 2996 2997 if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && 2998 push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) 2999 return rte_flow_error_set(error, EINVAL, 3000 RTE_FLOW_ERROR_TYPE_ACTION, action, 3001 "invalid vlan ethertype"); 3002 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3003 return rte_flow_error_set(error, EINVAL, 3004 RTE_FLOW_ERROR_TYPE_ACTION, action, 3005 "wrong action order, port_id should " 3006 "be after push VLAN"); 3007 if (!attr->transfer && priv->representor) 3008 return rte_flow_error_set(error, ENOTSUP, 3009 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3010 "push vlan action for VF representor " 3011 "not supported on NIC table"); 3012 if (vlan_m && 3013 (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) && 3014 (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) != 3015 MLX5DV_FLOW_VLAN_PCP_MASK_BE && 3016 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) && 3017 !(mlx5_flow_find_action 3018 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP))) 3019 return rte_flow_error_set(error, EINVAL, 3020 RTE_FLOW_ERROR_TYPE_ACTION, action, 3021 "not full match mask on VLAN PCP and " 3022 "there is no of_set_vlan_pcp action, " 3023 "push VLAN action cannot figure out " 3024 "PCP value"); 3025 if (vlan_m && 3026 (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) && 3027 (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) != 3028 MLX5DV_FLOW_VLAN_VID_MASK_BE && 3029 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) && 3030 !(mlx5_flow_find_action 3031 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))) 3032 return rte_flow_error_set(error, EINVAL, 3033 RTE_FLOW_ERROR_TYPE_ACTION, action, 3034 "not full match mask on VLAN VID and " 3035 "there is no of_set_vlan_vid action, " 3036 "push VLAN action cannot figure out " 3037 "VID value"); 3038 (void)attr; 3039 return 0; 3040 } 3041 3042 /** 3043 * Validate the set VLAN PCP. 3044 * 3045 * @param[in] action_flags 3046 * Holds the actions detected until now. 3047 * @param[in] actions 3048 * Pointer to the list of actions remaining in the flow rule. 3049 * @param[out] error 3050 * Pointer to error structure. 3051 * 3052 * @return 3053 * 0 on success, a negative errno value otherwise and rte_errno is set. 3054 */ 3055 static int 3056 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags, 3057 const struct rte_flow_action actions[], 3058 struct rte_flow_error *error) 3059 { 3060 const struct rte_flow_action *action = actions; 3061 const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf; 3062 3063 if (conf->vlan_pcp > 7) 3064 return rte_flow_error_set(error, EINVAL, 3065 RTE_FLOW_ERROR_TYPE_ACTION, action, 3066 "VLAN PCP value is too big"); 3067 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)) 3068 return rte_flow_error_set(error, ENOTSUP, 3069 RTE_FLOW_ERROR_TYPE_ACTION, action, 3070 "set VLAN PCP action must follow " 3071 "the push VLAN action"); 3072 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) 3073 return rte_flow_error_set(error, ENOTSUP, 3074 RTE_FLOW_ERROR_TYPE_ACTION, action, 3075 "Multiple VLAN PCP modification are " 3076 "not supported"); 3077 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3078 return rte_flow_error_set(error, EINVAL, 3079 RTE_FLOW_ERROR_TYPE_ACTION, action, 3080 "wrong action order, port_id should " 3081 "be after set VLAN PCP"); 3082 return 0; 3083 } 3084 3085 /** 3086 * Validate the set VLAN VID. 3087 * 3088 * @param[in] item_flags 3089 * Holds the items detected in this rule. 3090 * @param[in] action_flags 3091 * Holds the actions detected until now. 3092 * @param[in] actions 3093 * Pointer to the list of actions remaining in the flow rule. 3094 * @param[out] error 3095 * Pointer to error structure. 3096 * 3097 * @return 3098 * 0 on success, a negative errno value otherwise and rte_errno is set. 3099 */ 3100 static int 3101 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags, 3102 uint64_t action_flags, 3103 const struct rte_flow_action actions[], 3104 struct rte_flow_error *error) 3105 { 3106 const struct rte_flow_action *action = actions; 3107 const struct rte_flow_action_of_set_vlan_vid *conf = action->conf; 3108 3109 if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE) 3110 return rte_flow_error_set(error, EINVAL, 3111 RTE_FLOW_ERROR_TYPE_ACTION, action, 3112 "VLAN VID value is too big"); 3113 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) && 3114 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 3115 return rte_flow_error_set(error, ENOTSUP, 3116 RTE_FLOW_ERROR_TYPE_ACTION, action, 3117 "set VLAN VID action must follow push" 3118 " VLAN action or match on VLAN item"); 3119 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) 3120 return rte_flow_error_set(error, ENOTSUP, 3121 RTE_FLOW_ERROR_TYPE_ACTION, action, 3122 "Multiple VLAN VID modifications are " 3123 "not supported"); 3124 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3125 return rte_flow_error_set(error, EINVAL, 3126 RTE_FLOW_ERROR_TYPE_ACTION, action, 3127 "wrong action order, port_id should " 3128 "be after set VLAN VID"); 3129 return 0; 3130 } 3131 3132 /* 3133 * Validate the FLAG action. 3134 * 3135 * @param[in] dev 3136 * Pointer to the rte_eth_dev structure. 3137 * @param[in] action_flags 3138 * Holds the actions detected until now. 3139 * @param[in] attr 3140 * Pointer to flow attributes 3141 * @param[out] error 3142 * Pointer to error structure. 3143 * 3144 * @return 3145 * 0 on success, a negative errno value otherwise and rte_errno is set. 3146 */ 3147 static int 3148 flow_dv_validate_action_flag(struct rte_eth_dev *dev, 3149 uint64_t action_flags, 3150 const struct rte_flow_attr *attr, 3151 struct rte_flow_error *error) 3152 { 3153 struct mlx5_priv *priv = dev->data->dev_private; 3154 struct mlx5_sh_config *config = &priv->sh->config; 3155 int ret; 3156 3157 /* Fall back if no extended metadata register support. */ 3158 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3159 return mlx5_flow_validate_action_flag(action_flags, attr, 3160 error); 3161 /* Extensive metadata mode requires registers. */ 3162 if (!mlx5_flow_ext_mreg_supported(dev)) 3163 return rte_flow_error_set(error, ENOTSUP, 3164 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3165 "no metadata registers " 3166 "to support flag action"); 3167 if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT)) 3168 return rte_flow_error_set(error, ENOTSUP, 3169 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3170 "extended metadata register" 3171 " isn't available"); 3172 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3173 if (ret < 0) 3174 return ret; 3175 MLX5_ASSERT(ret > 0); 3176 if (action_flags & MLX5_FLOW_ACTION_MARK) 3177 return rte_flow_error_set(error, EINVAL, 3178 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3179 "can't mark and flag in same flow"); 3180 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3181 return rte_flow_error_set(error, EINVAL, 3182 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3183 "can't have 2 flag" 3184 " actions in same flow"); 3185 return 0; 3186 } 3187 3188 /** 3189 * Validate MARK action. 3190 * 3191 * @param[in] dev 3192 * Pointer to the rte_eth_dev structure. 3193 * @param[in] action 3194 * Pointer to action. 3195 * @param[in] action_flags 3196 * Holds the actions detected until now. 3197 * @param[in] attr 3198 * Pointer to flow attributes 3199 * @param[out] error 3200 * Pointer to error structure. 3201 * 3202 * @return 3203 * 0 on success, a negative errno value otherwise and rte_errno is set. 3204 */ 3205 static int 3206 flow_dv_validate_action_mark(struct rte_eth_dev *dev, 3207 const struct rte_flow_action *action, 3208 uint64_t action_flags, 3209 const struct rte_flow_attr *attr, 3210 struct rte_flow_error *error) 3211 { 3212 struct mlx5_priv *priv = dev->data->dev_private; 3213 struct mlx5_sh_config *config = &priv->sh->config; 3214 const struct rte_flow_action_mark *mark = action->conf; 3215 int ret; 3216 3217 if (is_tunnel_offload_active(dev)) 3218 return rte_flow_error_set(error, ENOTSUP, 3219 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3220 "no mark action " 3221 "if tunnel offload active"); 3222 /* Fall back if no extended metadata register support. */ 3223 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3224 return mlx5_flow_validate_action_mark(action, action_flags, 3225 attr, error); 3226 /* Extensive metadata mode requires registers. */ 3227 if (!mlx5_flow_ext_mreg_supported(dev)) 3228 return rte_flow_error_set(error, ENOTSUP, 3229 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3230 "no metadata registers " 3231 "to support mark action"); 3232 if (!priv->sh->dv_mark_mask) 3233 return rte_flow_error_set(error, ENOTSUP, 3234 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3235 "extended metadata register" 3236 " isn't available"); 3237 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3238 if (ret < 0) 3239 return ret; 3240 MLX5_ASSERT(ret > 0); 3241 if (!mark) 3242 return rte_flow_error_set(error, EINVAL, 3243 RTE_FLOW_ERROR_TYPE_ACTION, action, 3244 "configuration cannot be null"); 3245 if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask)) 3246 return rte_flow_error_set(error, EINVAL, 3247 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 3248 &mark->id, 3249 "mark id exceeds the limit"); 3250 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3251 return rte_flow_error_set(error, EINVAL, 3252 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3253 "can't flag and mark in same flow"); 3254 if (action_flags & MLX5_FLOW_ACTION_MARK) 3255 return rte_flow_error_set(error, EINVAL, 3256 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3257 "can't have 2 mark actions in same" 3258 " flow"); 3259 return 0; 3260 } 3261 3262 /** 3263 * Validate SET_META action. 3264 * 3265 * @param[in] dev 3266 * Pointer to the rte_eth_dev structure. 3267 * @param[in] action 3268 * Pointer to the action structure. 3269 * @param[in] action_flags 3270 * Holds the actions detected until now. 3271 * @param[in] attr 3272 * Pointer to flow attributes 3273 * @param[out] error 3274 * Pointer to error structure. 3275 * 3276 * @return 3277 * 0 on success, a negative errno value otherwise and rte_errno is set. 3278 */ 3279 static int 3280 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev, 3281 const struct rte_flow_action *action, 3282 uint64_t action_flags __rte_unused, 3283 const struct rte_flow_attr *attr, 3284 struct rte_flow_error *error) 3285 { 3286 struct mlx5_priv *priv = dev->data->dev_private; 3287 struct mlx5_sh_config *config = &priv->sh->config; 3288 const struct rte_flow_action_set_meta *conf; 3289 uint32_t nic_mask = UINT32_MAX; 3290 int reg; 3291 3292 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 3293 !mlx5_flow_ext_mreg_supported(dev)) 3294 return rte_flow_error_set(error, ENOTSUP, 3295 RTE_FLOW_ERROR_TYPE_ACTION, action, 3296 "extended metadata register" 3297 " isn't supported"); 3298 reg = flow_dv_get_metadata_reg(dev, attr, error); 3299 if (reg < 0) 3300 return reg; 3301 if (reg == REG_NON) 3302 return rte_flow_error_set(error, ENOTSUP, 3303 RTE_FLOW_ERROR_TYPE_ACTION, action, 3304 "unavailable extended metadata register"); 3305 if (reg != REG_A && reg != REG_B) { 3306 struct mlx5_priv *priv = dev->data->dev_private; 3307 3308 nic_mask = priv->sh->dv_meta_mask; 3309 } 3310 if (!(action->conf)) 3311 return rte_flow_error_set(error, EINVAL, 3312 RTE_FLOW_ERROR_TYPE_ACTION, action, 3313 "configuration cannot be null"); 3314 conf = (const struct rte_flow_action_set_meta *)action->conf; 3315 if (!conf->mask) 3316 return rte_flow_error_set(error, EINVAL, 3317 RTE_FLOW_ERROR_TYPE_ACTION, action, 3318 "zero mask doesn't have any effect"); 3319 if (conf->mask & ~nic_mask) 3320 return rte_flow_error_set(error, EINVAL, 3321 RTE_FLOW_ERROR_TYPE_ACTION, action, 3322 "meta data must be within reg C0"); 3323 return 0; 3324 } 3325 3326 /** 3327 * Validate SET_TAG action. 3328 * 3329 * @param[in] dev 3330 * Pointer to the rte_eth_dev structure. 3331 * @param[in] action 3332 * Pointer to the action structure. 3333 * @param[in] action_flags 3334 * Holds the actions detected until now. 3335 * @param[in] attr 3336 * Pointer to flow attributes 3337 * @param[out] error 3338 * Pointer to error structure. 3339 * 3340 * @return 3341 * 0 on success, a negative errno value otherwise and rte_errno is set. 3342 */ 3343 static int 3344 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, 3345 const struct rte_flow_action *action, 3346 uint64_t action_flags, 3347 const struct rte_flow_attr *attr, 3348 struct rte_flow_error *error) 3349 { 3350 const struct rte_flow_action_set_tag *conf; 3351 const uint64_t terminal_action_flags = 3352 MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | 3353 MLX5_FLOW_ACTION_RSS; 3354 int ret; 3355 3356 if (!mlx5_flow_ext_mreg_supported(dev)) 3357 return rte_flow_error_set(error, ENOTSUP, 3358 RTE_FLOW_ERROR_TYPE_ACTION, action, 3359 "extensive metadata register" 3360 " isn't supported"); 3361 if (!(action->conf)) 3362 return rte_flow_error_set(error, EINVAL, 3363 RTE_FLOW_ERROR_TYPE_ACTION, action, 3364 "configuration cannot be null"); 3365 conf = (const struct rte_flow_action_set_tag *)action->conf; 3366 if (!conf->mask) 3367 return rte_flow_error_set(error, EINVAL, 3368 RTE_FLOW_ERROR_TYPE_ACTION, action, 3369 "zero mask doesn't have any effect"); 3370 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 3371 if (ret < 0) 3372 return ret; 3373 if (attr->ingress && (action_flags & terminal_action_flags)) 3374 return rte_flow_error_set(error, EINVAL, 3375 RTE_FLOW_ERROR_TYPE_ACTION, action, 3376 "set_tag has no effect" 3377 " with terminal actions"); 3378 return 0; 3379 } 3380 3381 /** 3382 * Indicates whether ASO aging is supported. 3383 * 3384 * @param[in] priv 3385 * Pointer to device private context structure. 3386 * @param[in] root 3387 * Whether action is on root table. 3388 * 3389 * @return 3390 * True when ASO aging is supported, false otherwise. 3391 */ 3392 static inline bool 3393 flow_hit_aso_supported(const struct mlx5_priv *priv, bool root) 3394 { 3395 MLX5_ASSERT(priv); 3396 return (priv->sh->flow_hit_aso_en && !root); 3397 } 3398 3399 /** 3400 * Validate count action. 3401 * 3402 * @param[in] dev 3403 * Pointer to rte_eth_dev structure. 3404 * @param[in] shared 3405 * Indicator if action is shared. 3406 * @param[in] action_flags 3407 * Holds the actions detected until now. 3408 * @param[in] root 3409 * Whether action is on root table. 3410 * @param[out] error 3411 * Pointer to error structure. 3412 * 3413 * @return 3414 * 0 on success, a negative errno value otherwise and rte_errno is set. 3415 */ 3416 static int 3417 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared, 3418 uint64_t action_flags, 3419 bool root, 3420 struct rte_flow_error *error) 3421 { 3422 struct mlx5_priv *priv = dev->data->dev_private; 3423 3424 if (!priv->sh->cdev->config.devx) 3425 goto notsup_err; 3426 if (action_flags & MLX5_FLOW_ACTION_COUNT) 3427 return rte_flow_error_set(error, EINVAL, 3428 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3429 "duplicate count actions set"); 3430 if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) && 3431 !flow_hit_aso_supported(priv, root)) 3432 return rte_flow_error_set(error, EINVAL, 3433 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3434 "old age and indirect count combination is not supported"); 3435 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 3436 return 0; 3437 #endif 3438 notsup_err: 3439 return rte_flow_error_set 3440 (error, ENOTSUP, 3441 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3442 NULL, 3443 "count action not supported"); 3444 } 3445 3446 /** 3447 * Validate the L2 encap action. 3448 * 3449 * @param[in] dev 3450 * Pointer to the rte_eth_dev structure. 3451 * @param[in] action_flags 3452 * Holds the actions detected until now. 3453 * @param[in] action 3454 * Pointer to the action structure. 3455 * @param[in] attr 3456 * Pointer to flow attributes. 3457 * @param[out] error 3458 * Pointer to error structure. 3459 * 3460 * @return 3461 * 0 on success, a negative errno value otherwise and rte_errno is set. 3462 */ 3463 static int 3464 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev, 3465 uint64_t action_flags, 3466 const struct rte_flow_action *action, 3467 const struct rte_flow_attr *attr, 3468 struct rte_flow_error *error) 3469 { 3470 const struct mlx5_priv *priv = dev->data->dev_private; 3471 3472 if (!(action->conf)) 3473 return rte_flow_error_set(error, EINVAL, 3474 RTE_FLOW_ERROR_TYPE_ACTION, action, 3475 "configuration cannot be null"); 3476 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3477 return rte_flow_error_set(error, EINVAL, 3478 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3479 "can only have a single encap action " 3480 "in a flow"); 3481 if (!attr->transfer && priv->representor) 3482 return rte_flow_error_set(error, ENOTSUP, 3483 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3484 "encap action for VF representor " 3485 "not supported on NIC table"); 3486 return 0; 3487 } 3488 3489 /** 3490 * Validate a decap action. 3491 * 3492 * @param[in] dev 3493 * Pointer to the rte_eth_dev structure. 3494 * @param[in] action_flags 3495 * Holds the actions detected until now. 3496 * @param[in] action 3497 * Pointer to the action structure. 3498 * @param[in] item_flags 3499 * Holds the items detected. 3500 * @param[in] attr 3501 * Pointer to flow attributes 3502 * @param[out] error 3503 * Pointer to error structure. 3504 * 3505 * @return 3506 * 0 on success, a negative errno value otherwise and rte_errno is set. 3507 */ 3508 static int 3509 flow_dv_validate_action_decap(struct rte_eth_dev *dev, 3510 uint64_t action_flags, 3511 const struct rte_flow_action *action, 3512 const uint64_t item_flags, 3513 const struct rte_flow_attr *attr, 3514 struct rte_flow_error *error) 3515 { 3516 const struct mlx5_priv *priv = dev->data->dev_private; 3517 3518 if (priv->sh->cdev->config.hca_attr.scatter_fcs_w_decap_disable && 3519 !priv->sh->config.decap_en) 3520 return rte_flow_error_set(error, ENOTSUP, 3521 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3522 "decap is not enabled"); 3523 if (action_flags & MLX5_FLOW_XCAP_ACTIONS) 3524 return rte_flow_error_set(error, ENOTSUP, 3525 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3526 action_flags & 3527 MLX5_FLOW_ACTION_DECAP ? "can only " 3528 "have a single decap action" : "decap " 3529 "after encap is not supported"); 3530 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 3531 return rte_flow_error_set(error, EINVAL, 3532 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3533 "can't have decap action after" 3534 " modify action"); 3535 if (attr->egress) 3536 return rte_flow_error_set(error, ENOTSUP, 3537 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 3538 NULL, 3539 "decap action not supported for " 3540 "egress"); 3541 if (!attr->transfer && priv->representor) 3542 return rte_flow_error_set(error, ENOTSUP, 3543 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3544 "decap action for VF representor " 3545 "not supported on NIC table"); 3546 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP && 3547 !(item_flags & MLX5_FLOW_LAYER_VXLAN)) 3548 return rte_flow_error_set(error, ENOTSUP, 3549 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3550 "VXLAN item should be present for VXLAN decap"); 3551 return 0; 3552 } 3553 3554 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,}; 3555 3556 /** 3557 * Validate the raw encap and decap actions. 3558 * 3559 * @param[in] dev 3560 * Pointer to the rte_eth_dev structure. 3561 * @param[in] decap 3562 * Pointer to the decap action. 3563 * @param[in] encap 3564 * Pointer to the encap action. 3565 * @param[in] attr 3566 * Pointer to flow attributes 3567 * @param[in/out] action_flags 3568 * Holds the actions detected until now. 3569 * @param[out] actions_n 3570 * pointer to the number of actions counter. 3571 * @param[in] action 3572 * Pointer to the action structure. 3573 * @param[in] item_flags 3574 * Holds the items detected. 3575 * @param[out] error 3576 * Pointer to error structure. 3577 * 3578 * @return 3579 * 0 on success, a negative errno value otherwise and rte_errno is set. 3580 */ 3581 static int 3582 flow_dv_validate_action_raw_encap_decap 3583 (struct rte_eth_dev *dev, 3584 const struct rte_flow_action_raw_decap *decap, 3585 const struct rte_flow_action_raw_encap *encap, 3586 const struct rte_flow_attr *attr, uint64_t *action_flags, 3587 int *actions_n, const struct rte_flow_action *action, 3588 uint64_t item_flags, struct rte_flow_error *error) 3589 { 3590 const struct mlx5_priv *priv = dev->data->dev_private; 3591 int ret; 3592 3593 if (encap && (!encap->size || !encap->data)) 3594 return rte_flow_error_set(error, EINVAL, 3595 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3596 "raw encap data cannot be empty"); 3597 if (decap && encap) { 3598 if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE && 3599 encap->size > MLX5_ENCAPSULATION_DECISION_SIZE) 3600 /* L3 encap. */ 3601 decap = NULL; 3602 else if (encap->size <= 3603 MLX5_ENCAPSULATION_DECISION_SIZE && 3604 decap->size > 3605 MLX5_ENCAPSULATION_DECISION_SIZE) 3606 /* L3 decap. */ 3607 encap = NULL; 3608 else if (encap->size > 3609 MLX5_ENCAPSULATION_DECISION_SIZE && 3610 decap->size > 3611 MLX5_ENCAPSULATION_DECISION_SIZE) 3612 /* 2 L2 actions: encap and decap. */ 3613 ; 3614 else 3615 return rte_flow_error_set(error, 3616 ENOTSUP, 3617 RTE_FLOW_ERROR_TYPE_ACTION, 3618 NULL, "unsupported too small " 3619 "raw decap and too small raw " 3620 "encap combination"); 3621 } 3622 if (decap) { 3623 ret = flow_dv_validate_action_decap(dev, *action_flags, action, 3624 item_flags, attr, error); 3625 if (ret < 0) 3626 return ret; 3627 *action_flags |= MLX5_FLOW_ACTION_DECAP; 3628 ++(*actions_n); 3629 } 3630 if (encap) { 3631 if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE) 3632 return rte_flow_error_set(error, ENOTSUP, 3633 RTE_FLOW_ERROR_TYPE_ACTION, 3634 NULL, 3635 "small raw encap size"); 3636 if (*action_flags & MLX5_FLOW_ACTION_ENCAP) 3637 return rte_flow_error_set(error, EINVAL, 3638 RTE_FLOW_ERROR_TYPE_ACTION, 3639 NULL, 3640 "more than one encap action"); 3641 if (!attr->transfer && priv->representor) 3642 return rte_flow_error_set 3643 (error, ENOTSUP, 3644 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3645 "encap action for VF representor " 3646 "not supported on NIC table"); 3647 *action_flags |= MLX5_FLOW_ACTION_ENCAP; 3648 ++(*actions_n); 3649 } 3650 return 0; 3651 } 3652 3653 /* 3654 * Validate the ASO CT action. 3655 * 3656 * @param[in] dev 3657 * Pointer to the rte_eth_dev structure. 3658 * @param[in] action_flags 3659 * Holds the actions detected until now. 3660 * @param[in] item_flags 3661 * The items found in this flow rule. 3662 * @param root 3663 * Whether action is on root table. 3664 * @param[out] error 3665 * Pointer to error structure. 3666 * 3667 * @return 3668 * 0 on success, a negative errno value otherwise and rte_errno is set. 3669 */ 3670 static int 3671 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, 3672 uint64_t action_flags, 3673 uint64_t item_flags, 3674 bool root, 3675 struct rte_flow_error *error) 3676 { 3677 RTE_SET_USED(dev); 3678 3679 if (root) 3680 return rte_flow_error_set(error, ENOTSUP, 3681 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3682 NULL, 3683 "Only support non-root table"); 3684 if (action_flags & MLX5_FLOW_FATE_ACTIONS) 3685 return rte_flow_error_set(error, ENOTSUP, 3686 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3687 "CT cannot follow a fate action"); 3688 if ((action_flags & MLX5_FLOW_ACTION_METER) || 3689 (action_flags & MLX5_FLOW_ACTION_AGE)) 3690 return rte_flow_error_set(error, EINVAL, 3691 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3692 "Only one ASO action is supported"); 3693 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3694 return rte_flow_error_set(error, EINVAL, 3695 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3696 "Encap cannot exist before CT"); 3697 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP)) 3698 return rte_flow_error_set(error, EINVAL, 3699 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3700 "Not a outer TCP packet"); 3701 return 0; 3702 } 3703 3704 /** 3705 * Validate METER_COLOR item. 3706 * 3707 * @param[in] dev 3708 * Pointer to the rte_eth_dev structure. 3709 * @param[in] item 3710 * Item specification. 3711 * @param[in] attr 3712 * Attributes of flow that includes this item. 3713 * @param[out] error 3714 * Pointer to error structure. 3715 * 3716 * @return 3717 * 0 on success, a negative errno value otherwise and rte_errno is set. 3718 */ 3719 static int 3720 flow_dv_validate_item_meter_color(struct rte_eth_dev *dev, 3721 const struct rte_flow_item *item, 3722 const struct rte_flow_attr *attr __rte_unused, 3723 struct rte_flow_error *error) 3724 { 3725 struct mlx5_priv *priv = dev->data->dev_private; 3726 const struct rte_flow_item_meter_color *spec = item->spec; 3727 const struct rte_flow_item_meter_color *mask = item->mask; 3728 struct rte_flow_item_meter_color nic_mask = { 3729 .color = RTE_COLORS 3730 }; 3731 int ret; 3732 3733 if (priv->mtr_color_reg == REG_NON) 3734 return rte_flow_error_set(error, ENOTSUP, 3735 RTE_FLOW_ERROR_TYPE_ITEM, item, 3736 "meter color register" 3737 " isn't available"); 3738 ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); 3739 if (ret < 0) 3740 return ret; 3741 if (!spec) 3742 return rte_flow_error_set(error, EINVAL, 3743 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 3744 item->spec, 3745 "data cannot be empty"); 3746 if (spec->color > RTE_COLORS) 3747 return rte_flow_error_set(error, EINVAL, 3748 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 3749 &spec->color, 3750 "meter color is invalid"); 3751 if (!mask) 3752 mask = &rte_flow_item_meter_color_mask; 3753 if (!mask->color) 3754 return rte_flow_error_set(error, EINVAL, 3755 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 3756 "mask cannot be zero"); 3757 3758 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 3759 (const uint8_t *)&nic_mask, 3760 sizeof(struct rte_flow_item_meter_color), 3761 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 3762 if (ret < 0) 3763 return ret; 3764 return 0; 3765 } 3766 3767 int 3768 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused, 3769 struct mlx5_list_entry *entry, void *cb_ctx) 3770 { 3771 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3772 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3773 struct mlx5_flow_dv_encap_decap_resource *resource; 3774 3775 resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource, 3776 entry); 3777 if (resource->reformat_type == ctx_resource->reformat_type && 3778 resource->ft_type == ctx_resource->ft_type && 3779 resource->flags == ctx_resource->flags && 3780 resource->size == ctx_resource->size && 3781 !memcmp((const void *)resource->buf, 3782 (const void *)ctx_resource->buf, 3783 resource->size)) 3784 return 0; 3785 return -1; 3786 } 3787 3788 struct mlx5_list_entry * 3789 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx) 3790 { 3791 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3792 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3793 struct mlx5dv_dr_domain *domain; 3794 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3795 struct mlx5_flow_dv_encap_decap_resource *resource; 3796 uint32_t idx; 3797 int ret; 3798 3799 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3800 domain = sh->fdb_domain; 3801 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3802 domain = sh->rx_domain; 3803 else 3804 domain = sh->tx_domain; 3805 /* Register new encap/decap resource. */ 3806 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx); 3807 if (!resource) { 3808 rte_flow_error_set(ctx->error, ENOMEM, 3809 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3810 "cannot allocate resource memory"); 3811 return NULL; 3812 } 3813 *resource = *ctx_resource; 3814 resource->idx = idx; 3815 ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx, 3816 domain, resource, 3817 &resource->action); 3818 if (ret) { 3819 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx); 3820 rte_flow_error_set(ctx->error, ENOMEM, 3821 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3822 NULL, "cannot create action"); 3823 return NULL; 3824 } 3825 3826 return &resource->entry; 3827 } 3828 3829 struct mlx5_list_entry * 3830 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 3831 void *cb_ctx) 3832 { 3833 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3834 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3835 struct mlx5_flow_dv_encap_decap_resource *cache_resource; 3836 uint32_t idx; 3837 3838 cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 3839 &idx); 3840 if (!cache_resource) { 3841 rte_flow_error_set(ctx->error, ENOMEM, 3842 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3843 "cannot allocate resource memory"); 3844 return NULL; 3845 } 3846 memcpy(cache_resource, oentry, sizeof(*cache_resource)); 3847 cache_resource->idx = idx; 3848 return &cache_resource->entry; 3849 } 3850 3851 void 3852 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3853 { 3854 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3855 struct mlx5_flow_dv_encap_decap_resource *res = 3856 container_of(entry, typeof(*res), entry); 3857 3858 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 3859 } 3860 3861 /** 3862 * Find existing encap/decap resource or create and register a new one. 3863 * 3864 * @param[in, out] dev 3865 * Pointer to rte_eth_dev structure. 3866 * @param[in, out] resource 3867 * Pointer to encap/decap resource. 3868 * @parm[in, out] dev_flow 3869 * Pointer to the dev_flow. 3870 * @param[out] error 3871 * pointer to error structure. 3872 * 3873 * @return 3874 * 0 on success otherwise -errno and errno is set. 3875 */ 3876 static int 3877 flow_dv_encap_decap_resource_register 3878 (struct rte_eth_dev *dev, 3879 struct mlx5_flow_dv_encap_decap_resource *resource, 3880 struct mlx5_flow *dev_flow, 3881 struct rte_flow_error *error) 3882 { 3883 struct mlx5_priv *priv = dev->data->dev_private; 3884 struct mlx5_dev_ctx_shared *sh = priv->sh; 3885 struct mlx5_list_entry *entry; 3886 union { 3887 struct { 3888 uint32_t ft_type:8; 3889 uint32_t refmt_type:8; 3890 /* 3891 * Header reformat actions can be shared between 3892 * non-root tables. One bit to indicate non-root 3893 * table or not. 3894 */ 3895 uint32_t is_root:1; 3896 uint32_t reserve:15; 3897 }; 3898 uint32_t v32; 3899 } encap_decap_key = { 3900 { 3901 .ft_type = resource->ft_type, 3902 .refmt_type = resource->reformat_type, 3903 .is_root = !!dev_flow->dv.group, 3904 .reserve = 0, 3905 } 3906 }; 3907 struct mlx5_flow_cb_ctx ctx = { 3908 .error = error, 3909 .data = resource, 3910 }; 3911 struct mlx5_hlist *encaps_decaps; 3912 uint64_t key64; 3913 3914 encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps, 3915 "encaps_decaps", 3916 MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ, 3917 true, true, sh, 3918 flow_dv_encap_decap_create_cb, 3919 flow_dv_encap_decap_match_cb, 3920 flow_dv_encap_decap_remove_cb, 3921 flow_dv_encap_decap_clone_cb, 3922 flow_dv_encap_decap_clone_free_cb, 3923 error); 3924 if (unlikely(!encaps_decaps)) 3925 return -rte_errno; 3926 resource->flags = dev_flow->dv.group ? 0 : 1; 3927 key64 = __rte_raw_cksum(&encap_decap_key.v32, 3928 sizeof(encap_decap_key.v32), 0); 3929 if (resource->reformat_type != 3930 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 && 3931 resource->size) 3932 key64 = __rte_raw_cksum(resource->buf, resource->size, key64); 3933 entry = mlx5_hlist_register(encaps_decaps, key64, &ctx); 3934 if (!entry) 3935 return -rte_errno; 3936 resource = container_of(entry, typeof(*resource), entry); 3937 dev_flow->dv.encap_decap = resource; 3938 dev_flow->handle->dvh.rix_encap_decap = resource->idx; 3939 return 0; 3940 } 3941 3942 /** 3943 * Find existing table jump resource or create and register a new one. 3944 * 3945 * @param[in, out] dev 3946 * Pointer to rte_eth_dev structure. 3947 * @param[in, out] tbl 3948 * Pointer to flow table resource. 3949 * @parm[in, out] dev_flow 3950 * Pointer to the dev_flow. 3951 * @param[out] error 3952 * pointer to error structure. 3953 * 3954 * @return 3955 * 0 on success otherwise -errno and errno is set. 3956 */ 3957 static int 3958 flow_dv_jump_tbl_resource_register 3959 (struct rte_eth_dev *dev __rte_unused, 3960 struct mlx5_flow_tbl_resource *tbl, 3961 struct mlx5_flow *dev_flow, 3962 struct rte_flow_error *error __rte_unused) 3963 { 3964 struct mlx5_flow_tbl_data_entry *tbl_data = 3965 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 3966 3967 MLX5_ASSERT(tbl); 3968 MLX5_ASSERT(tbl_data->jump.action); 3969 dev_flow->handle->rix_jump = tbl_data->idx; 3970 dev_flow->dv.jump = &tbl_data->jump; 3971 return 0; 3972 } 3973 3974 int 3975 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused, 3976 struct mlx5_list_entry *entry, void *cb_ctx) 3977 { 3978 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3979 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3980 struct mlx5_flow_dv_port_id_action_resource *res = 3981 container_of(entry, typeof(*res), entry); 3982 3983 return ref->port_id != res->port_id; 3984 } 3985 3986 struct mlx5_list_entry * 3987 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx) 3988 { 3989 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3990 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3991 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3992 struct mlx5_flow_dv_port_id_action_resource *resource; 3993 uint32_t idx; 3994 int ret; 3995 3996 /* Register new port id action resource. */ 3997 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3998 if (!resource) { 3999 rte_flow_error_set(ctx->error, ENOMEM, 4000 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4001 "cannot allocate port_id action memory"); 4002 return NULL; 4003 } 4004 *resource = *ref; 4005 ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain, 4006 ref->port_id, 4007 &resource->action); 4008 if (ret) { 4009 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx); 4010 rte_flow_error_set(ctx->error, ENOMEM, 4011 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4012 "cannot create action"); 4013 return NULL; 4014 } 4015 resource->idx = idx; 4016 return &resource->entry; 4017 } 4018 4019 struct mlx5_list_entry * 4020 flow_dv_port_id_clone_cb(void *tool_ctx, 4021 struct mlx5_list_entry *entry __rte_unused, 4022 void *cb_ctx) 4023 { 4024 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4025 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 4026 struct mlx5_flow_dv_port_id_action_resource *resource; 4027 uint32_t idx; 4028 4029 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 4030 if (!resource) { 4031 rte_flow_error_set(ctx->error, ENOMEM, 4032 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4033 "cannot allocate port_id action memory"); 4034 return NULL; 4035 } 4036 memcpy(resource, entry, sizeof(*resource)); 4037 resource->idx = idx; 4038 return &resource->entry; 4039 } 4040 4041 void 4042 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 4043 { 4044 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4045 struct mlx5_flow_dv_port_id_action_resource *resource = 4046 container_of(entry, typeof(*resource), entry); 4047 4048 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 4049 } 4050 4051 /** 4052 * Find existing table port ID resource or create and register a new one. 4053 * 4054 * @param[in, out] dev 4055 * Pointer to rte_eth_dev structure. 4056 * @param[in, out] ref 4057 * Pointer to port ID action resource reference. 4058 * @parm[in, out] dev_flow 4059 * Pointer to the dev_flow. 4060 * @param[out] error 4061 * pointer to error structure. 4062 * 4063 * @return 4064 * 0 on success otherwise -errno and errno is set. 4065 */ 4066 static int 4067 flow_dv_port_id_action_resource_register 4068 (struct rte_eth_dev *dev, 4069 struct mlx5_flow_dv_port_id_action_resource *ref, 4070 struct mlx5_flow *dev_flow, 4071 struct rte_flow_error *error) 4072 { 4073 struct mlx5_priv *priv = dev->data->dev_private; 4074 struct mlx5_list_entry *entry; 4075 struct mlx5_flow_dv_port_id_action_resource *resource; 4076 struct mlx5_flow_cb_ctx ctx = { 4077 .error = error, 4078 .data = ref, 4079 }; 4080 4081 entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx); 4082 if (!entry) 4083 return -rte_errno; 4084 resource = container_of(entry, typeof(*resource), entry); 4085 dev_flow->dv.port_id_action = resource; 4086 dev_flow->handle->rix_port_id_action = resource->idx; 4087 return 0; 4088 } 4089 4090 int 4091 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused, 4092 struct mlx5_list_entry *entry, void *cb_ctx) 4093 { 4094 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 4095 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 4096 struct mlx5_flow_dv_push_vlan_action_resource *res = 4097 container_of(entry, typeof(*res), entry); 4098 4099 return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type; 4100 } 4101 4102 struct mlx5_list_entry * 4103 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx) 4104 { 4105 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4106 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 4107 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 4108 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4109 struct mlx5dv_dr_domain *domain; 4110 uint32_t idx; 4111 int ret; 4112 4113 /* Register new port id action resource. */ 4114 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 4115 if (!resource) { 4116 rte_flow_error_set(ctx->error, ENOMEM, 4117 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4118 "cannot allocate push_vlan action memory"); 4119 return NULL; 4120 } 4121 *resource = *ref; 4122 if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 4123 domain = sh->fdb_domain; 4124 else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 4125 domain = sh->rx_domain; 4126 else 4127 domain = sh->tx_domain; 4128 ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag, 4129 &resource->action); 4130 if (ret) { 4131 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 4132 rte_flow_error_set(ctx->error, ENOMEM, 4133 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4134 "cannot create push vlan action"); 4135 return NULL; 4136 } 4137 resource->idx = idx; 4138 return &resource->entry; 4139 } 4140 4141 struct mlx5_list_entry * 4142 flow_dv_push_vlan_clone_cb(void *tool_ctx, 4143 struct mlx5_list_entry *entry __rte_unused, 4144 void *cb_ctx) 4145 { 4146 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4147 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 4148 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4149 uint32_t idx; 4150 4151 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 4152 if (!resource) { 4153 rte_flow_error_set(ctx->error, ENOMEM, 4154 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 4155 "cannot allocate push_vlan action memory"); 4156 return NULL; 4157 } 4158 memcpy(resource, entry, sizeof(*resource)); 4159 resource->idx = idx; 4160 return &resource->entry; 4161 } 4162 4163 void 4164 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 4165 { 4166 struct mlx5_dev_ctx_shared *sh = tool_ctx; 4167 struct mlx5_flow_dv_push_vlan_action_resource *resource = 4168 container_of(entry, typeof(*resource), entry); 4169 4170 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 4171 } 4172 4173 /** 4174 * Find existing push vlan resource or create and register a new one. 4175 * 4176 * @param [in, out] dev 4177 * Pointer to rte_eth_dev structure. 4178 * @param[in, out] ref 4179 * Pointer to port ID action resource reference. 4180 * @parm[in, out] dev_flow 4181 * Pointer to the dev_flow. 4182 * @param[out] error 4183 * pointer to error structure. 4184 * 4185 * @return 4186 * 0 on success otherwise -errno and errno is set. 4187 */ 4188 static int 4189 flow_dv_push_vlan_action_resource_register 4190 (struct rte_eth_dev *dev, 4191 struct mlx5_flow_dv_push_vlan_action_resource *ref, 4192 struct mlx5_flow *dev_flow, 4193 struct rte_flow_error *error) 4194 { 4195 struct mlx5_priv *priv = dev->data->dev_private; 4196 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4197 struct mlx5_list_entry *entry; 4198 struct mlx5_flow_cb_ctx ctx = { 4199 .error = error, 4200 .data = ref, 4201 }; 4202 4203 entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx); 4204 if (!entry) 4205 return -rte_errno; 4206 resource = container_of(entry, typeof(*resource), entry); 4207 4208 dev_flow->handle->dvh.rix_push_vlan = resource->idx; 4209 dev_flow->dv.push_vlan_res = resource; 4210 return 0; 4211 } 4212 4213 /** 4214 * Get the size of specific rte_flow_item_type hdr size 4215 * 4216 * @param[in] item_type 4217 * Tested rte_flow_item_type. 4218 * 4219 * @return 4220 * sizeof struct item_type, 0 if void or irrelevant. 4221 */ 4222 size_t 4223 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type) 4224 { 4225 size_t retval; 4226 4227 switch (item_type) { 4228 case RTE_FLOW_ITEM_TYPE_ETH: 4229 retval = sizeof(struct rte_ether_hdr); 4230 break; 4231 case RTE_FLOW_ITEM_TYPE_VLAN: 4232 retval = sizeof(struct rte_vlan_hdr); 4233 break; 4234 case RTE_FLOW_ITEM_TYPE_IPV4: 4235 retval = sizeof(struct rte_ipv4_hdr); 4236 break; 4237 case RTE_FLOW_ITEM_TYPE_IPV6: 4238 retval = sizeof(struct rte_ipv6_hdr); 4239 break; 4240 case RTE_FLOW_ITEM_TYPE_UDP: 4241 retval = sizeof(struct rte_udp_hdr); 4242 break; 4243 case RTE_FLOW_ITEM_TYPE_TCP: 4244 retval = sizeof(struct rte_tcp_hdr); 4245 break; 4246 case RTE_FLOW_ITEM_TYPE_VXLAN: 4247 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4248 retval = sizeof(struct rte_vxlan_hdr); 4249 break; 4250 case RTE_FLOW_ITEM_TYPE_GRE: 4251 case RTE_FLOW_ITEM_TYPE_NVGRE: 4252 retval = sizeof(struct rte_gre_hdr); 4253 break; 4254 case RTE_FLOW_ITEM_TYPE_MPLS: 4255 retval = sizeof(struct rte_mpls_hdr); 4256 break; 4257 case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */ 4258 default: 4259 retval = 0; 4260 break; 4261 } 4262 return retval; 4263 } 4264 4265 #define MLX5_ENCAP_IPV4_VERSION 0x40 4266 #define MLX5_ENCAP_IPV4_IHL_MIN 0x05 4267 #define MLX5_ENCAP_IPV4_TTL_DEF 0x40 4268 #define MLX5_ENCAP_IPV6_VTC_FLOW 0x60000000 4269 #define MLX5_ENCAP_IPV6_HOP_LIMIT 0xff 4270 #define MLX5_ENCAP_VXLAN_FLAGS 0x08000000 4271 #define MLX5_ENCAP_VXLAN_GPE_FLAGS 0x04 4272 4273 /** 4274 * Convert the encap action data from list of rte_flow_item to raw buffer 4275 * 4276 * @param[in] items 4277 * Pointer to rte_flow_item objects list. 4278 * @param[out] buf 4279 * Pointer to the output buffer. 4280 * @param[out] size 4281 * Pointer to the output buffer size. 4282 * @param[out] error 4283 * Pointer to the error structure. 4284 * 4285 * @return 4286 * 0 on success, a negative errno value otherwise and rte_errno is set. 4287 */ 4288 int 4289 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf, 4290 size_t *size, struct rte_flow_error *error) 4291 { 4292 struct rte_ether_hdr *eth = NULL; 4293 struct rte_vlan_hdr *vlan = NULL; 4294 struct rte_ipv4_hdr *ipv4 = NULL; 4295 struct rte_ipv6_hdr *ipv6 = NULL; 4296 struct rte_udp_hdr *udp = NULL; 4297 struct rte_vxlan_hdr *vxlan = NULL; 4298 struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL; 4299 struct rte_gre_hdr *gre = NULL; 4300 size_t len; 4301 size_t temp_size = 0; 4302 4303 if (!items) 4304 return rte_flow_error_set(error, EINVAL, 4305 RTE_FLOW_ERROR_TYPE_ACTION, 4306 NULL, "invalid empty data"); 4307 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 4308 len = flow_dv_get_item_hdr_len(items->type); 4309 if (len + temp_size > MLX5_ENCAP_MAX_LEN) 4310 return rte_flow_error_set(error, EINVAL, 4311 RTE_FLOW_ERROR_TYPE_ACTION, 4312 (void *)items->type, 4313 "items total size is too big" 4314 " for encap action"); 4315 rte_memcpy((void *)&buf[temp_size], items->spec, len); 4316 switch (items->type) { 4317 case RTE_FLOW_ITEM_TYPE_ETH: 4318 eth = (struct rte_ether_hdr *)&buf[temp_size]; 4319 break; 4320 case RTE_FLOW_ITEM_TYPE_VLAN: 4321 vlan = (struct rte_vlan_hdr *)&buf[temp_size]; 4322 if (!eth) 4323 return rte_flow_error_set(error, EINVAL, 4324 RTE_FLOW_ERROR_TYPE_ACTION, 4325 (void *)items->type, 4326 "eth header not found"); 4327 if (!eth->ether_type) 4328 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN); 4329 break; 4330 case RTE_FLOW_ITEM_TYPE_IPV4: 4331 ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size]; 4332 if (!vlan && !eth) 4333 return rte_flow_error_set(error, EINVAL, 4334 RTE_FLOW_ERROR_TYPE_ACTION, 4335 (void *)items->type, 4336 "neither eth nor vlan" 4337 " header found"); 4338 if (vlan && !vlan->eth_proto) 4339 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4340 else if (eth && !eth->ether_type) 4341 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4342 if (!ipv4->version_ihl) 4343 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION | 4344 MLX5_ENCAP_IPV4_IHL_MIN; 4345 if (!ipv4->time_to_live) 4346 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF; 4347 break; 4348 case RTE_FLOW_ITEM_TYPE_IPV6: 4349 ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size]; 4350 if (!vlan && !eth) 4351 return rte_flow_error_set(error, EINVAL, 4352 RTE_FLOW_ERROR_TYPE_ACTION, 4353 (void *)items->type, 4354 "neither eth nor vlan" 4355 " header found"); 4356 if (vlan && !vlan->eth_proto) 4357 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4358 else if (eth && !eth->ether_type) 4359 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4360 if (!ipv6->vtc_flow) 4361 ipv6->vtc_flow = 4362 RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW); 4363 if (!ipv6->hop_limits) 4364 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT; 4365 break; 4366 case RTE_FLOW_ITEM_TYPE_UDP: 4367 udp = (struct rte_udp_hdr *)&buf[temp_size]; 4368 if (!ipv4 && !ipv6) 4369 return rte_flow_error_set(error, EINVAL, 4370 RTE_FLOW_ERROR_TYPE_ACTION, 4371 (void *)items->type, 4372 "ip header not found"); 4373 if (ipv4 && !ipv4->next_proto_id) 4374 ipv4->next_proto_id = IPPROTO_UDP; 4375 else if (ipv6 && !ipv6->proto) 4376 ipv6->proto = IPPROTO_UDP; 4377 break; 4378 case RTE_FLOW_ITEM_TYPE_VXLAN: 4379 vxlan = (struct rte_vxlan_hdr *)&buf[temp_size]; 4380 if (!udp) 4381 return rte_flow_error_set(error, EINVAL, 4382 RTE_FLOW_ERROR_TYPE_ACTION, 4383 (void *)items->type, 4384 "udp header not found"); 4385 if (!udp->dst_port) 4386 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN); 4387 if (!vxlan->vx_flags) 4388 vxlan->vx_flags = 4389 RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS); 4390 break; 4391 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4392 vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size]; 4393 if (!udp) 4394 return rte_flow_error_set(error, EINVAL, 4395 RTE_FLOW_ERROR_TYPE_ACTION, 4396 (void *)items->type, 4397 "udp header not found"); 4398 if (!vxlan_gpe->proto) 4399 return rte_flow_error_set(error, EINVAL, 4400 RTE_FLOW_ERROR_TYPE_ACTION, 4401 (void *)items->type, 4402 "next protocol not found"); 4403 if (!udp->dst_port) 4404 udp->dst_port = 4405 RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE); 4406 if (!vxlan_gpe->vx_flags) 4407 vxlan_gpe->vx_flags = 4408 MLX5_ENCAP_VXLAN_GPE_FLAGS; 4409 break; 4410 case RTE_FLOW_ITEM_TYPE_GRE: 4411 case RTE_FLOW_ITEM_TYPE_NVGRE: 4412 gre = (struct rte_gre_hdr *)&buf[temp_size]; 4413 if (!gre->proto) 4414 return rte_flow_error_set(error, EINVAL, 4415 RTE_FLOW_ERROR_TYPE_ACTION, 4416 (void *)items->type, 4417 "next protocol not found"); 4418 if (!ipv4 && !ipv6) 4419 return rte_flow_error_set(error, EINVAL, 4420 RTE_FLOW_ERROR_TYPE_ACTION, 4421 (void *)items->type, 4422 "ip header not found"); 4423 if (ipv4 && !ipv4->next_proto_id) 4424 ipv4->next_proto_id = IPPROTO_GRE; 4425 else if (ipv6 && !ipv6->proto) 4426 ipv6->proto = IPPROTO_GRE; 4427 break; 4428 case RTE_FLOW_ITEM_TYPE_VOID: 4429 break; 4430 default: 4431 return rte_flow_error_set(error, EINVAL, 4432 RTE_FLOW_ERROR_TYPE_ACTION, 4433 (void *)items->type, 4434 "unsupported item type"); 4435 break; 4436 } 4437 temp_size += len; 4438 } 4439 *size = temp_size; 4440 return 0; 4441 } 4442 4443 static int 4444 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error) 4445 { 4446 struct rte_ether_hdr *eth = NULL; 4447 struct rte_vlan_hdr *vlan = NULL; 4448 struct rte_ipv6_hdr *ipv6 = NULL; 4449 struct rte_udp_hdr *udp = NULL; 4450 char *next_hdr; 4451 uint16_t proto; 4452 4453 eth = (struct rte_ether_hdr *)data; 4454 next_hdr = (char *)(eth + 1); 4455 proto = RTE_BE16(eth->ether_type); 4456 4457 /* VLAN skipping */ 4458 while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) { 4459 vlan = (struct rte_vlan_hdr *)next_hdr; 4460 proto = RTE_BE16(vlan->eth_proto); 4461 next_hdr += sizeof(struct rte_vlan_hdr); 4462 } 4463 4464 /* HW calculates IPv4 csum. no need to proceed */ 4465 if (proto == RTE_ETHER_TYPE_IPV4) 4466 return 0; 4467 4468 /* non IPv4/IPv6 header. not supported */ 4469 if (proto != RTE_ETHER_TYPE_IPV6) { 4470 return rte_flow_error_set(error, ENOTSUP, 4471 RTE_FLOW_ERROR_TYPE_ACTION, 4472 NULL, "Cannot offload non IPv4/IPv6"); 4473 } 4474 4475 ipv6 = (struct rte_ipv6_hdr *)next_hdr; 4476 4477 /* ignore non UDP */ 4478 if (ipv6->proto != IPPROTO_UDP) 4479 return 0; 4480 4481 udp = (struct rte_udp_hdr *)(ipv6 + 1); 4482 udp->dgram_cksum = 0; 4483 4484 return 0; 4485 } 4486 4487 /** 4488 * Convert L2 encap action to DV specification. 4489 * 4490 * @param[in] dev 4491 * Pointer to rte_eth_dev structure. 4492 * @param[in] action 4493 * Pointer to action structure. 4494 * @param[in, out] dev_flow 4495 * Pointer to the mlx5_flow. 4496 * @param[in] transfer 4497 * Mark if the flow is E-Switch flow. 4498 * @param[out] error 4499 * Pointer to the error structure. 4500 * 4501 * @return 4502 * 0 on success, a negative errno value otherwise and rte_errno is set. 4503 */ 4504 static int 4505 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev, 4506 const struct rte_flow_action *action, 4507 struct mlx5_flow *dev_flow, 4508 uint8_t transfer, 4509 struct rte_flow_error *error) 4510 { 4511 const struct rte_flow_item *encap_data; 4512 const struct rte_flow_action_raw_encap *raw_encap_data; 4513 struct mlx5_flow_dv_encap_decap_resource res = { 4514 .reformat_type = 4515 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL, 4516 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4517 MLX5DV_FLOW_TABLE_TYPE_NIC_TX, 4518 }; 4519 4520 if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 4521 raw_encap_data = 4522 (const struct rte_flow_action_raw_encap *)action->conf; 4523 res.size = raw_encap_data->size; 4524 memcpy(res.buf, raw_encap_data->data, res.size); 4525 } else { 4526 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) 4527 encap_data = 4528 ((const struct rte_flow_action_vxlan_encap *) 4529 action->conf)->definition; 4530 else 4531 encap_data = 4532 ((const struct rte_flow_action_nvgre_encap *) 4533 action->conf)->definition; 4534 if (flow_dv_convert_encap_data(encap_data, res.buf, 4535 &res.size, error)) 4536 return -rte_errno; 4537 } 4538 if (flow_dv_zero_encap_udp_csum(res.buf, error)) 4539 return -rte_errno; 4540 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4541 return rte_flow_error_set(error, EINVAL, 4542 RTE_FLOW_ERROR_TYPE_ACTION, 4543 NULL, "can't create L2 encap action"); 4544 return 0; 4545 } 4546 4547 /** 4548 * Convert L2 decap action to DV specification. 4549 * 4550 * @param[in] dev 4551 * Pointer to rte_eth_dev structure. 4552 * @param[in, out] dev_flow 4553 * Pointer to the mlx5_flow. 4554 * @param[in] transfer 4555 * Mark if the flow is E-Switch flow. 4556 * @param[out] error 4557 * Pointer to the error structure. 4558 * 4559 * @return 4560 * 0 on success, a negative errno value otherwise and rte_errno is set. 4561 */ 4562 static int 4563 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev, 4564 struct mlx5_flow *dev_flow, 4565 uint8_t transfer, 4566 struct rte_flow_error *error) 4567 { 4568 struct mlx5_flow_dv_encap_decap_resource res = { 4569 .size = 0, 4570 .reformat_type = 4571 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2, 4572 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4573 MLX5DV_FLOW_TABLE_TYPE_NIC_RX, 4574 }; 4575 4576 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4577 return rte_flow_error_set(error, EINVAL, 4578 RTE_FLOW_ERROR_TYPE_ACTION, 4579 NULL, "can't create L2 decap action"); 4580 return 0; 4581 } 4582 4583 /** 4584 * Convert raw decap/encap (L3 tunnel) action to DV specification. 4585 * 4586 * @param[in] dev 4587 * Pointer to rte_eth_dev structure. 4588 * @param[in] action 4589 * Pointer to action structure. 4590 * @param[in, out] dev_flow 4591 * Pointer to the mlx5_flow. 4592 * @param[in] attr 4593 * Pointer to the flow attributes. 4594 * @param[out] error 4595 * Pointer to the error structure. 4596 * 4597 * @return 4598 * 0 on success, a negative errno value otherwise and rte_errno is set. 4599 */ 4600 static int 4601 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev, 4602 const struct rte_flow_action *action, 4603 struct mlx5_flow *dev_flow, 4604 const struct rte_flow_attr *attr, 4605 struct rte_flow_error *error) 4606 { 4607 const struct rte_flow_action_raw_encap *encap_data; 4608 struct mlx5_flow_dv_encap_decap_resource res; 4609 4610 memset(&res, 0, sizeof(res)); 4611 encap_data = (const struct rte_flow_action_raw_encap *)action->conf; 4612 res.size = encap_data->size; 4613 memcpy(res.buf, encap_data->data, res.size); 4614 res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ? 4615 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 : 4616 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 4617 if (attr->transfer) 4618 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4619 else 4620 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4621 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4622 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4623 return rte_flow_error_set(error, EINVAL, 4624 RTE_FLOW_ERROR_TYPE_ACTION, 4625 NULL, "can't create encap action"); 4626 return 0; 4627 } 4628 4629 /** 4630 * Create action push VLAN. 4631 * 4632 * @param[in] dev 4633 * Pointer to rte_eth_dev structure. 4634 * @param[in] attr 4635 * Pointer to the flow attributes. 4636 * @param[in] vlan 4637 * Pointer to the vlan to push to the Ethernet header. 4638 * @param[in, out] dev_flow 4639 * Pointer to the mlx5_flow. 4640 * @param[out] error 4641 * Pointer to the error structure. 4642 * 4643 * @return 4644 * 0 on success, a negative errno value otherwise and rte_errno is set. 4645 */ 4646 static int 4647 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, 4648 const struct rte_flow_attr *attr, 4649 const struct rte_vlan_hdr *vlan, 4650 struct mlx5_flow *dev_flow, 4651 struct rte_flow_error *error) 4652 { 4653 struct mlx5_flow_dv_push_vlan_action_resource res; 4654 4655 memset(&res, 0, sizeof(res)); 4656 res.vlan_tag = 4657 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 | 4658 vlan->vlan_tci); 4659 if (attr->transfer) 4660 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4661 else 4662 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4663 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4664 return flow_dv_push_vlan_action_resource_register 4665 (dev, &res, dev_flow, error); 4666 } 4667 4668 /** 4669 * Validate the modify-header actions. 4670 * 4671 * @param[in] action_flags 4672 * Holds the actions detected until now. 4673 * @param[in] action 4674 * Pointer to the modify action. 4675 * @param[out] error 4676 * Pointer to error structure. 4677 * 4678 * @return 4679 * 0 on success, a negative errno value otherwise and rte_errno is set. 4680 */ 4681 static int 4682 flow_dv_validate_action_modify_hdr(const uint64_t action_flags, 4683 const struct rte_flow_action *action, 4684 struct rte_flow_error *error) 4685 { 4686 if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf) 4687 return rte_flow_error_set(error, EINVAL, 4688 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4689 NULL, "action configuration not set"); 4690 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 4691 return rte_flow_error_set(error, EINVAL, 4692 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4693 "can't have encap action before" 4694 " modify action"); 4695 return 0; 4696 } 4697 4698 /** 4699 * Validate the modify-header MAC address actions. 4700 * 4701 * @param[in] action_flags 4702 * Holds the actions detected until now. 4703 * @param[in] action 4704 * Pointer to the modify action. 4705 * @param[in] item_flags 4706 * Holds the items detected. 4707 * @param[out] error 4708 * Pointer to error structure. 4709 * 4710 * @return 4711 * 0 on success, a negative errno value otherwise and rte_errno is set. 4712 */ 4713 static int 4714 flow_dv_validate_action_modify_mac(const uint64_t action_flags, 4715 const struct rte_flow_action *action, 4716 const uint64_t item_flags, 4717 struct rte_flow_error *error) 4718 { 4719 int ret = 0; 4720 4721 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4722 if (!ret) { 4723 if (!(item_flags & MLX5_FLOW_LAYER_L2)) 4724 return rte_flow_error_set(error, EINVAL, 4725 RTE_FLOW_ERROR_TYPE_ACTION, 4726 NULL, 4727 "no L2 item in pattern"); 4728 } 4729 return ret; 4730 } 4731 4732 /** 4733 * Validate the modify-header IPv4 address actions. 4734 * 4735 * @param[in] action_flags 4736 * Holds the actions detected until now. 4737 * @param[in] action 4738 * Pointer to the modify action. 4739 * @param[in] item_flags 4740 * Holds the items detected. 4741 * @param[out] error 4742 * Pointer to error structure. 4743 * 4744 * @return 4745 * 0 on success, a negative errno value otherwise and rte_errno is set. 4746 */ 4747 static int 4748 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags, 4749 const struct rte_flow_action *action, 4750 const uint64_t item_flags, 4751 struct rte_flow_error *error) 4752 { 4753 int ret = 0; 4754 uint64_t layer; 4755 4756 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4757 if (!ret) { 4758 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4759 MLX5_FLOW_LAYER_INNER_L3_IPV4 : 4760 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 4761 if (!(item_flags & layer)) 4762 return rte_flow_error_set(error, EINVAL, 4763 RTE_FLOW_ERROR_TYPE_ACTION, 4764 NULL, 4765 "no ipv4 item in pattern"); 4766 } 4767 return ret; 4768 } 4769 4770 /** 4771 * Validate the modify-header IPv6 address actions. 4772 * 4773 * @param[in] action_flags 4774 * Holds the actions detected until now. 4775 * @param[in] action 4776 * Pointer to the modify action. 4777 * @param[in] item_flags 4778 * Holds the items detected. 4779 * @param[out] error 4780 * Pointer to error structure. 4781 * 4782 * @return 4783 * 0 on success, a negative errno value otherwise and rte_errno is set. 4784 */ 4785 static int 4786 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags, 4787 const struct rte_flow_action *action, 4788 const uint64_t item_flags, 4789 struct rte_flow_error *error) 4790 { 4791 int ret = 0; 4792 uint64_t layer; 4793 4794 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4795 if (!ret) { 4796 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4797 MLX5_FLOW_LAYER_INNER_L3_IPV6 : 4798 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 4799 if (!(item_flags & layer)) 4800 return rte_flow_error_set(error, EINVAL, 4801 RTE_FLOW_ERROR_TYPE_ACTION, 4802 NULL, 4803 "no ipv6 item in pattern"); 4804 } 4805 return ret; 4806 } 4807 4808 /** 4809 * Validate the modify-header TP actions. 4810 * 4811 * @param[in] action_flags 4812 * Holds the actions detected until now. 4813 * @param[in] action 4814 * Pointer to the modify action. 4815 * @param[in] item_flags 4816 * Holds the items detected. 4817 * @param[out] error 4818 * Pointer to error structure. 4819 * 4820 * @return 4821 * 0 on success, a negative errno value otherwise and rte_errno is set. 4822 */ 4823 static int 4824 flow_dv_validate_action_modify_tp(const uint64_t action_flags, 4825 const struct rte_flow_action *action, 4826 const uint64_t item_flags, 4827 struct rte_flow_error *error) 4828 { 4829 int ret = 0; 4830 uint64_t layer; 4831 4832 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4833 if (!ret) { 4834 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4835 MLX5_FLOW_LAYER_INNER_L4 : 4836 MLX5_FLOW_LAYER_OUTER_L4; 4837 if (!(item_flags & layer)) 4838 return rte_flow_error_set(error, EINVAL, 4839 RTE_FLOW_ERROR_TYPE_ACTION, 4840 NULL, "no transport layer " 4841 "in pattern"); 4842 } 4843 return ret; 4844 } 4845 4846 /** 4847 * Validate the modify-header actions of increment/decrement 4848 * TCP Sequence-number. 4849 * 4850 * @param[in] action_flags 4851 * Holds the actions detected until now. 4852 * @param[in] action 4853 * Pointer to the modify action. 4854 * @param[in] item_flags 4855 * Holds the items detected. 4856 * @param[out] error 4857 * Pointer to error structure. 4858 * 4859 * @return 4860 * 0 on success, a negative errno value otherwise and rte_errno is set. 4861 */ 4862 static int 4863 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags, 4864 const struct rte_flow_action *action, 4865 const uint64_t item_flags, 4866 struct rte_flow_error *error) 4867 { 4868 int ret = 0; 4869 uint64_t layer; 4870 4871 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4872 if (!ret) { 4873 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4874 MLX5_FLOW_LAYER_INNER_L4_TCP : 4875 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4876 if (!(item_flags & layer)) 4877 return rte_flow_error_set(error, EINVAL, 4878 RTE_FLOW_ERROR_TYPE_ACTION, 4879 NULL, "no TCP item in" 4880 " pattern"); 4881 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ && 4882 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) || 4883 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ && 4884 (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ))) 4885 return rte_flow_error_set(error, EINVAL, 4886 RTE_FLOW_ERROR_TYPE_ACTION, 4887 NULL, 4888 "cannot decrease and increase" 4889 " TCP sequence number" 4890 " at the same time"); 4891 } 4892 return ret; 4893 } 4894 4895 /** 4896 * Validate the modify-header actions of increment/decrement 4897 * TCP Acknowledgment number. 4898 * 4899 * @param[in] action_flags 4900 * Holds the actions detected until now. 4901 * @param[in] action 4902 * Pointer to the modify action. 4903 * @param[in] item_flags 4904 * Holds the items detected. 4905 * @param[out] error 4906 * Pointer to error structure. 4907 * 4908 * @return 4909 * 0 on success, a negative errno value otherwise and rte_errno is set. 4910 */ 4911 static int 4912 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags, 4913 const struct rte_flow_action *action, 4914 const uint64_t item_flags, 4915 struct rte_flow_error *error) 4916 { 4917 int ret = 0; 4918 uint64_t layer; 4919 4920 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4921 if (!ret) { 4922 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4923 MLX5_FLOW_LAYER_INNER_L4_TCP : 4924 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4925 if (!(item_flags & layer)) 4926 return rte_flow_error_set(error, EINVAL, 4927 RTE_FLOW_ERROR_TYPE_ACTION, 4928 NULL, "no TCP item in" 4929 " pattern"); 4930 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK && 4931 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) || 4932 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK && 4933 (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK))) 4934 return rte_flow_error_set(error, EINVAL, 4935 RTE_FLOW_ERROR_TYPE_ACTION, 4936 NULL, 4937 "cannot decrease and increase" 4938 " TCP acknowledgment number" 4939 " at the same time"); 4940 } 4941 return ret; 4942 } 4943 4944 /** 4945 * Validate the modify-header TTL actions. 4946 * 4947 * @param[in] action_flags 4948 * Holds the actions detected until now. 4949 * @param[in] action 4950 * Pointer to the modify action. 4951 * @param[in] item_flags 4952 * Holds the items detected. 4953 * @param[out] error 4954 * Pointer to error structure. 4955 * 4956 * @return 4957 * 0 on success, a negative errno value otherwise and rte_errno is set. 4958 */ 4959 static int 4960 flow_dv_validate_action_modify_ttl(const uint64_t action_flags, 4961 const struct rte_flow_action *action, 4962 const uint64_t item_flags, 4963 struct rte_flow_error *error) 4964 { 4965 int ret = 0; 4966 uint64_t layer; 4967 4968 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4969 if (!ret) { 4970 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4971 MLX5_FLOW_LAYER_INNER_L3 : 4972 MLX5_FLOW_LAYER_OUTER_L3; 4973 if (!(item_flags & layer)) 4974 return rte_flow_error_set(error, EINVAL, 4975 RTE_FLOW_ERROR_TYPE_ACTION, 4976 NULL, 4977 "no IP protocol in pattern"); 4978 } 4979 return ret; 4980 } 4981 4982 /** 4983 * Validate the generic modify field actions. 4984 * @param[in] dev 4985 * Pointer to the rte_eth_dev structure. 4986 * @param[in] action_flags 4987 * Holds the actions detected until now. 4988 * @param[in] action 4989 * Pointer to the modify action. 4990 * @param[in] attr 4991 * Pointer to the flow attributes. 4992 * @param root 4993 * Whether action is on root table. 4994 * @param[out] error 4995 * Pointer to error structure. 4996 * 4997 * @return 4998 * Number of header fields to modify (0 or more) on success, 4999 * a negative errno value otherwise and rte_errno is set. 5000 */ 5001 static int 5002 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, 5003 const uint64_t action_flags, 5004 const struct rte_flow_action *action, 5005 const struct rte_flow_attr *attr, 5006 bool root, 5007 struct rte_flow_error *error) 5008 { 5009 int ret = 0; 5010 struct mlx5_priv *priv = dev->data->dev_private; 5011 struct mlx5_sh_config *config = &priv->sh->config; 5012 struct mlx5_hca_attr *hca_attr = &priv->sh->cdev->config.hca_attr; 5013 const struct rte_flow_action_modify_field *action_modify_field = 5014 action->conf; 5015 uint32_t dst_width = mlx5_flow_item_field_width(dev, 5016 action_modify_field->dst.field, 5017 -1, attr, error); 5018 uint32_t src_width = mlx5_flow_item_field_width(dev, 5019 action_modify_field->src.field, 5020 dst_width, attr, error); 5021 5022 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5023 if (ret) 5024 return ret; 5025 5026 if (action_modify_field->width == 0) 5027 return rte_flow_error_set(error, EINVAL, 5028 RTE_FLOW_ERROR_TYPE_ACTION, action, 5029 "no bits are requested to be modified"); 5030 else if (action_modify_field->width > dst_width || 5031 action_modify_field->width > src_width) 5032 return rte_flow_error_set(error, EINVAL, 5033 RTE_FLOW_ERROR_TYPE_ACTION, action, 5034 "cannot modify more bits than" 5035 " the width of a field"); 5036 if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE && 5037 action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) { 5038 if (action_modify_field->dst.offset + 5039 action_modify_field->width > dst_width) 5040 return rte_flow_error_set(error, EINVAL, 5041 RTE_FLOW_ERROR_TYPE_ACTION, action, 5042 "destination offset is too big"); 5043 if (action_modify_field->dst.level && 5044 action_modify_field->dst.field != RTE_FLOW_FIELD_TAG) 5045 return rte_flow_error_set(error, ENOTSUP, 5046 RTE_FLOW_ERROR_TYPE_ACTION, action, 5047 "inner header fields modification" 5048 " is not supported"); 5049 } 5050 if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE && 5051 action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) { 5052 if (root) 5053 return rte_flow_error_set(error, ENOTSUP, 5054 RTE_FLOW_ERROR_TYPE_ACTION, action, 5055 "modify field action is not" 5056 " supported for group 0"); 5057 if (action_modify_field->src.offset + 5058 action_modify_field->width > src_width) 5059 return rte_flow_error_set(error, EINVAL, 5060 RTE_FLOW_ERROR_TYPE_ACTION, action, 5061 "source offset is too big"); 5062 if (action_modify_field->src.level && 5063 action_modify_field->src.field != RTE_FLOW_FIELD_TAG) 5064 return rte_flow_error_set(error, ENOTSUP, 5065 RTE_FLOW_ERROR_TYPE_ACTION, action, 5066 "inner header fields modification" 5067 " is not supported"); 5068 } 5069 if ((action_modify_field->dst.field == 5070 action_modify_field->src.field) && 5071 (action_modify_field->dst.level == 5072 action_modify_field->src.level)) 5073 return rte_flow_error_set(error, EINVAL, 5074 RTE_FLOW_ERROR_TYPE_ACTION, action, 5075 "source and destination fields" 5076 " cannot be the same"); 5077 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE || 5078 action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER || 5079 action_modify_field->dst.field == RTE_FLOW_FIELD_MARK) 5080 return rte_flow_error_set(error, EINVAL, 5081 RTE_FLOW_ERROR_TYPE_ACTION, action, 5082 "mark, immediate value or a pointer to it" 5083 " cannot be used as a destination"); 5084 if (action_modify_field->dst.field == RTE_FLOW_FIELD_START || 5085 action_modify_field->src.field == RTE_FLOW_FIELD_START) 5086 return rte_flow_error_set(error, ENOTSUP, 5087 RTE_FLOW_ERROR_TYPE_ACTION, action, 5088 "modifications of an arbitrary" 5089 " place in a packet is not supported"); 5090 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE || 5091 action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE) 5092 return rte_flow_error_set(error, ENOTSUP, 5093 RTE_FLOW_ERROR_TYPE_ACTION, action, 5094 "modifications of the 802.1Q Tag" 5095 " Identifier is not supported"); 5096 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI || 5097 action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI) 5098 return rte_flow_error_set(error, ENOTSUP, 5099 RTE_FLOW_ERROR_TYPE_ACTION, action, 5100 "modifications of the VXLAN Network" 5101 " Identifier is not supported"); 5102 if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI || 5103 action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI) 5104 return rte_flow_error_set(error, ENOTSUP, 5105 RTE_FLOW_ERROR_TYPE_ACTION, action, 5106 "modifications of the GENEVE Network" 5107 " Identifier is not supported"); 5108 if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK || 5109 action_modify_field->src.field == RTE_FLOW_FIELD_MARK) 5110 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY || 5111 !mlx5_flow_ext_mreg_supported(dev)) 5112 return rte_flow_error_set(error, ENOTSUP, 5113 RTE_FLOW_ERROR_TYPE_ACTION, action, 5114 "cannot modify mark in legacy mode" 5115 " or without extensive registers"); 5116 if (action_modify_field->dst.field == RTE_FLOW_FIELD_META || 5117 action_modify_field->src.field == RTE_FLOW_FIELD_META) { 5118 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 5119 !mlx5_flow_ext_mreg_supported(dev)) 5120 return rte_flow_error_set(error, ENOTSUP, 5121 RTE_FLOW_ERROR_TYPE_ACTION, action, 5122 "cannot modify meta without" 5123 " extensive registers support"); 5124 ret = flow_dv_get_metadata_reg(dev, attr, error); 5125 if (ret < 0 || ret == REG_NON) 5126 return rte_flow_error_set(error, ENOTSUP, 5127 RTE_FLOW_ERROR_TYPE_ACTION, action, 5128 "cannot modify meta without" 5129 " extensive registers available"); 5130 } 5131 if (action_modify_field->operation == RTE_FLOW_MODIFY_SUB) 5132 return rte_flow_error_set(error, ENOTSUP, 5133 RTE_FLOW_ERROR_TYPE_ACTION, action, 5134 "sub operations are not supported"); 5135 if (action_modify_field->dst.field == RTE_FLOW_FIELD_IPV4_ECN || 5136 action_modify_field->src.field == RTE_FLOW_FIELD_IPV4_ECN || 5137 action_modify_field->dst.field == RTE_FLOW_FIELD_IPV6_ECN || 5138 action_modify_field->src.field == RTE_FLOW_FIELD_IPV6_ECN) 5139 if (!hca_attr->modify_outer_ip_ecn && root) 5140 return rte_flow_error_set(error, ENOTSUP, 5141 RTE_FLOW_ERROR_TYPE_ACTION, action, 5142 "modifications of the ECN for current firmware is not supported"); 5143 return (action_modify_field->width / 32) + 5144 !!(action_modify_field->width % 32); 5145 } 5146 5147 /** 5148 * Validate jump action. 5149 * 5150 * @param[in] action 5151 * Pointer to the jump action. 5152 * @param[in] action_flags 5153 * Holds the actions detected until now. 5154 * @param[in] attributes 5155 * Pointer to flow attributes 5156 * @param[in] external 5157 * Action belongs to flow rule created by request external to PMD. 5158 * @param[out] error 5159 * Pointer to error structure. 5160 * 5161 * @return 5162 * 0 on success, a negative errno value otherwise and rte_errno is set. 5163 */ 5164 static int 5165 flow_dv_validate_action_jump(struct rte_eth_dev *dev, 5166 const struct mlx5_flow_tunnel *tunnel, 5167 const struct rte_flow_action *action, 5168 uint64_t action_flags, 5169 const struct rte_flow_attr *attributes, 5170 bool external, struct rte_flow_error *error) 5171 { 5172 uint32_t target_group, table = 0; 5173 struct mlx5_priv *priv = dev->data->dev_private; 5174 int ret = 0; 5175 struct flow_grp_info grp_info = { 5176 .external = !!external, 5177 .transfer = !!attributes->transfer, 5178 .fdb_def_rule = !!priv->fdb_def_rule, 5179 .std_tbl_fix = 0 5180 }; 5181 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5182 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5183 return rte_flow_error_set(error, EINVAL, 5184 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5185 "can't have 2 fate actions in" 5186 " same flow"); 5187 if (!action->conf) 5188 return rte_flow_error_set(error, EINVAL, 5189 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5190 NULL, "action configuration not set"); 5191 target_group = 5192 ((const struct rte_flow_action_jump *)action->conf)->group; 5193 ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table, 5194 &grp_info, error); 5195 if (ret) 5196 return ret; 5197 if (attributes->group == target_group && 5198 !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET | 5199 MLX5_FLOW_ACTION_TUNNEL_MATCH))) 5200 return rte_flow_error_set(error, EINVAL, 5201 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5202 "target group must be other than" 5203 " the current flow group"); 5204 if (table == 0) 5205 return rte_flow_error_set(error, EINVAL, 5206 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5207 NULL, "root table shouldn't be destination"); 5208 return 0; 5209 } 5210 5211 /* 5212 * Validate action PORT_ID / REPRESENTED_PORT. 5213 * 5214 * @param[in] dev 5215 * Pointer to rte_eth_dev structure. 5216 * @param[in] action_flags 5217 * Bit-fields that holds the actions detected until now. 5218 * @param[in] action 5219 * PORT_ID / REPRESENTED_PORT action structure. 5220 * @param[in] attr 5221 * Attributes of flow that includes this action. 5222 * @param[out] error 5223 * Pointer to error structure. 5224 * 5225 * @return 5226 * 0 on success, a negative errno value otherwise and rte_errno is set. 5227 */ 5228 static int 5229 flow_dv_validate_action_port_id(struct rte_eth_dev *dev, 5230 uint64_t action_flags, 5231 const struct rte_flow_action *action, 5232 const struct rte_flow_attr *attr, 5233 struct rte_flow_error *error) 5234 { 5235 const struct rte_flow_action_port_id *port_id; 5236 const struct rte_flow_action_ethdev *ethdev; 5237 struct mlx5_priv *act_priv; 5238 struct mlx5_priv *dev_priv; 5239 uint16_t port; 5240 5241 if (!attr->transfer) 5242 return rte_flow_error_set(error, ENOTSUP, 5243 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5244 NULL, 5245 "port action is valid in transfer" 5246 " mode only"); 5247 if (!action || !action->conf) 5248 return rte_flow_error_set(error, ENOTSUP, 5249 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5250 NULL, 5251 "port action parameters must be" 5252 " specified"); 5253 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5254 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5255 return rte_flow_error_set(error, EINVAL, 5256 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5257 "can have only one fate actions in" 5258 " a flow"); 5259 dev_priv = mlx5_dev_to_eswitch_info(dev); 5260 if (!dev_priv) 5261 return rte_flow_error_set(error, rte_errno, 5262 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5263 NULL, 5264 "failed to obtain E-Switch info"); 5265 switch (action->type) { 5266 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5267 port_id = action->conf; 5268 port = port_id->original ? dev->data->port_id : port_id->id; 5269 break; 5270 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5271 ethdev = action->conf; 5272 port = ethdev->port_id; 5273 break; 5274 default: 5275 MLX5_ASSERT(false); 5276 return rte_flow_error_set 5277 (error, EINVAL, 5278 RTE_FLOW_ERROR_TYPE_ACTION, action, 5279 "unknown E-Switch action"); 5280 } 5281 act_priv = mlx5_port_to_eswitch_info(port, false); 5282 if (!act_priv) 5283 return rte_flow_error_set 5284 (error, rte_errno, 5285 RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf, 5286 "failed to obtain E-Switch port id for port"); 5287 if (act_priv->domain_id != dev_priv->domain_id) 5288 return rte_flow_error_set 5289 (error, EINVAL, 5290 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5291 "port does not belong to" 5292 " E-Switch being configured"); 5293 return 0; 5294 } 5295 5296 /** 5297 * Get the maximum number of modify header actions. 5298 * 5299 * @param dev 5300 * Pointer to rte_eth_dev structure. 5301 * @param root 5302 * Whether action is on root table. 5303 * 5304 * @return 5305 * Max number of modify header actions device can support. 5306 */ 5307 static inline unsigned int 5308 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused, 5309 bool root) 5310 { 5311 /* 5312 * There's no way to directly query the max capacity from FW. 5313 * The maximal value on root table should be assumed to be supported. 5314 */ 5315 if (!root) 5316 return MLX5_MAX_MODIFY_NUM; 5317 else 5318 return MLX5_ROOT_TBL_MODIFY_NUM; 5319 } 5320 5321 /** 5322 * Validate the meter action. 5323 * 5324 * @param[in] dev 5325 * Pointer to rte_eth_dev structure. 5326 * @param[in] action_flags 5327 * Bit-fields that holds the actions detected until now. 5328 * @param[in] item_flags 5329 * Holds the items detected. 5330 * @param[in] action 5331 * Pointer to the meter action. 5332 * @param[in] attr 5333 * Attributes of flow that includes this action. 5334 * @param[in] port_id_item 5335 * Pointer to item indicating port id. 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 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev, 5344 uint64_t action_flags, uint64_t item_flags, 5345 const struct rte_flow_action *action, 5346 const struct rte_flow_attr *attr, 5347 const struct rte_flow_item *port_id_item, 5348 bool *def_policy, 5349 struct rte_flow_error *error) 5350 { 5351 struct mlx5_priv *priv = dev->data->dev_private; 5352 const struct rte_flow_action_meter *am = action->conf; 5353 struct mlx5_flow_meter_info *fm; 5354 struct mlx5_flow_meter_policy *mtr_policy; 5355 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 5356 uint16_t flow_src_port = priv->representor_id; 5357 bool all_ports = false; 5358 5359 if (!am) 5360 return rte_flow_error_set(error, EINVAL, 5361 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5362 "meter action conf is NULL"); 5363 5364 if (action_flags & MLX5_FLOW_ACTION_METER) 5365 return rte_flow_error_set(error, ENOTSUP, 5366 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5367 "meter chaining not support"); 5368 if (action_flags & MLX5_FLOW_ACTION_JUMP) 5369 return rte_flow_error_set(error, ENOTSUP, 5370 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5371 "meter with jump not support"); 5372 if (!priv->mtr_en) 5373 return rte_flow_error_set(error, ENOTSUP, 5374 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5375 NULL, 5376 "meter action not supported"); 5377 fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL); 5378 if (!fm) 5379 return rte_flow_error_set(error, EINVAL, 5380 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5381 "Meter not found"); 5382 /* aso meter can always be shared by different domains */ 5383 if (fm->ref_cnt && !priv->sh->meter_aso_en && 5384 !(fm->transfer == attr->transfer || 5385 (!fm->ingress && !attr->ingress && attr->egress) || 5386 (!fm->egress && !attr->egress && attr->ingress))) 5387 return rte_flow_error_set(error, EINVAL, 5388 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5389 "Flow attributes domain are either invalid " 5390 "or have a domain conflict with current " 5391 "meter attributes"); 5392 if (fm->def_policy) { 5393 if (!((attr->transfer && 5394 mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) || 5395 (attr->egress && 5396 mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) || 5397 (attr->ingress && 5398 mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS]))) 5399 return rte_flow_error_set(error, EINVAL, 5400 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5401 "Flow attributes domain " 5402 "have a conflict with current " 5403 "meter domain attributes"); 5404 *def_policy = true; 5405 } else { 5406 mtr_policy = mlx5_flow_meter_policy_find(dev, 5407 fm->policy_id, NULL); 5408 if (!mtr_policy) 5409 return rte_flow_error_set(error, EINVAL, 5410 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5411 "Invalid policy id for meter "); 5412 if (!((attr->transfer && mtr_policy->transfer) || 5413 (attr->egress && mtr_policy->egress) || 5414 (attr->ingress && mtr_policy->ingress))) 5415 return rte_flow_error_set(error, EINVAL, 5416 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5417 "Flow attributes domain " 5418 "have a conflict with current " 5419 "meter domain attributes"); 5420 if (port_id_item) { 5421 if (mlx5_flow_get_item_vport_id(dev, port_id_item, &flow_src_port, 5422 &all_ports, error)) 5423 return -rte_errno; 5424 } 5425 if (attr->transfer) { 5426 /* When flow matching all src ports, meter should not have drop count. */ 5427 if (all_ports && (fm->drop_cnt || mtr_policy->hierarchy_match_port)) 5428 return rte_flow_error_set(error, EINVAL, 5429 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 5430 "Meter drop count or " 5431 "modify_field/set_tag in meter hierarchy " 5432 "not supported when matching all ports."); 5433 } else if (mtr_policy->is_rss) { 5434 struct mlx5_flow_meter_policy *fp; 5435 struct mlx5_meter_policy_action_container *acg; 5436 struct mlx5_meter_policy_action_container *acy; 5437 const struct rte_flow_action *rss_act; 5438 int ret; 5439 5440 fp = mlx5_flow_meter_hierarchy_get_final_policy(dev, 5441 mtr_policy); 5442 if (fp == NULL) 5443 return rte_flow_error_set(error, EINVAL, 5444 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5445 "Unable to get the final " 5446 "policy in the hierarchy"); 5447 acg = &fp->act_cnt[RTE_COLOR_GREEN]; 5448 acy = &fp->act_cnt[RTE_COLOR_YELLOW]; 5449 MLX5_ASSERT(acg->fate_action == 5450 MLX5_FLOW_FATE_SHARED_RSS || 5451 acy->fate_action == 5452 MLX5_FLOW_FATE_SHARED_RSS); 5453 if (acg->fate_action == MLX5_FLOW_FATE_SHARED_RSS) 5454 rss_act = acg->rss; 5455 else 5456 rss_act = acy->rss; 5457 ret = mlx5_flow_validate_action_rss(rss_act, 5458 action_flags, dev, attr, 5459 item_flags, error); 5460 if (ret) 5461 return ret; 5462 } 5463 *def_policy = false; 5464 } 5465 return 0; 5466 } 5467 5468 /** 5469 * Validate the age action. 5470 * 5471 * @param[in] action_flags 5472 * Holds the actions detected until now. 5473 * @param[in] action 5474 * Pointer to the age action. 5475 * @param[in] dev 5476 * Pointer to the Ethernet device structure. 5477 * @param[out] error 5478 * Pointer to error structure. 5479 * 5480 * @return 5481 * 0 on success, a negative errno value otherwise and rte_errno is set. 5482 */ 5483 static int 5484 flow_dv_validate_action_age(uint64_t action_flags, 5485 const struct rte_flow_action *action, 5486 struct rte_eth_dev *dev, 5487 struct rte_flow_error *error) 5488 { 5489 struct mlx5_priv *priv = dev->data->dev_private; 5490 const struct rte_flow_action_age *age = action->conf; 5491 5492 if (!priv->sh->cdev->config.devx || 5493 (priv->sh->sws_cmng.counter_fallback && !priv->sh->aso_age_mng)) 5494 return rte_flow_error_set(error, ENOTSUP, 5495 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5496 NULL, 5497 "age action not supported"); 5498 if (!(action->conf)) 5499 return rte_flow_error_set(error, EINVAL, 5500 RTE_FLOW_ERROR_TYPE_ACTION, action, 5501 "configuration cannot be null"); 5502 if (!(age->timeout)) 5503 return rte_flow_error_set(error, EINVAL, 5504 RTE_FLOW_ERROR_TYPE_ACTION, action, 5505 "invalid timeout value 0"); 5506 if (action_flags & MLX5_FLOW_ACTION_AGE) 5507 return rte_flow_error_set(error, EINVAL, 5508 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5509 "duplicate age actions set"); 5510 return 0; 5511 } 5512 5513 /** 5514 * Validate the modify-header IPv4 DSCP actions. 5515 * 5516 * @param[in] action_flags 5517 * Holds the actions detected until now. 5518 * @param[in] action 5519 * Pointer to the modify action. 5520 * @param[in] item_flags 5521 * Holds the items detected. 5522 * @param[out] error 5523 * Pointer to error structure. 5524 * 5525 * @return 5526 * 0 on success, a negative errno value otherwise and rte_errno is set. 5527 */ 5528 static int 5529 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags, 5530 const struct rte_flow_action *action, 5531 const uint64_t item_flags, 5532 struct rte_flow_error *error) 5533 { 5534 int ret = 0; 5535 5536 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5537 if (!ret) { 5538 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4)) 5539 return rte_flow_error_set(error, EINVAL, 5540 RTE_FLOW_ERROR_TYPE_ACTION, 5541 NULL, 5542 "no ipv4 item in pattern"); 5543 } 5544 return ret; 5545 } 5546 5547 /** 5548 * Validate the modify-header IPv6 DSCP actions. 5549 * 5550 * @param[in] action_flags 5551 * Holds the actions detected until now. 5552 * @param[in] action 5553 * Pointer to the modify action. 5554 * @param[in] item_flags 5555 * Holds the items detected. 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_modify_ipv6_dscp(const uint64_t action_flags, 5564 const struct rte_flow_action *action, 5565 const uint64_t item_flags, 5566 struct rte_flow_error *error) 5567 { 5568 int ret = 0; 5569 5570 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5571 if (!ret) { 5572 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6)) 5573 return rte_flow_error_set(error, EINVAL, 5574 RTE_FLOW_ERROR_TYPE_ACTION, 5575 NULL, 5576 "no ipv6 item in pattern"); 5577 } 5578 return ret; 5579 } 5580 5581 int 5582 flow_dv_modify_match_cb(void *tool_ctx __rte_unused, 5583 struct mlx5_list_entry *entry, void *cb_ctx) 5584 { 5585 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5586 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5587 struct mlx5_flow_dv_modify_hdr_resource *resource = 5588 container_of(entry, typeof(*resource), entry); 5589 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5590 5591 key_len += ref->actions_num * sizeof(ref->actions[0]); 5592 return ref->actions_num != resource->actions_num || 5593 memcmp(&ref->ft_type, &resource->ft_type, key_len); 5594 } 5595 5596 static struct mlx5_indexed_pool * 5597 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index) 5598 { 5599 struct mlx5_indexed_pool *ipool = __atomic_load_n 5600 (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST); 5601 5602 if (!ipool) { 5603 struct mlx5_indexed_pool *expected = NULL; 5604 struct mlx5_indexed_pool_config cfg = 5605 (struct mlx5_indexed_pool_config) { 5606 .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 5607 (index + 1) * 5608 sizeof(struct mlx5_modification_cmd), 5609 .trunk_size = 64, 5610 .grow_trunk = 3, 5611 .grow_shift = 2, 5612 .need_lock = 1, 5613 .release_mem_en = !!sh->config.reclaim_mode, 5614 .per_core_cache = 5615 sh->config.reclaim_mode ? 0 : (1 << 16), 5616 .malloc = mlx5_malloc, 5617 .free = mlx5_free, 5618 .type = "mlx5_modify_action_resource", 5619 }; 5620 5621 cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool)); 5622 ipool = mlx5_ipool_create(&cfg); 5623 if (!ipool) 5624 return NULL; 5625 if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index], 5626 &expected, ipool, false, 5627 __ATOMIC_SEQ_CST, 5628 __ATOMIC_SEQ_CST)) { 5629 mlx5_ipool_destroy(ipool); 5630 ipool = __atomic_load_n(&sh->mdh_ipools[index], 5631 __ATOMIC_SEQ_CST); 5632 } 5633 } 5634 return ipool; 5635 } 5636 5637 struct mlx5_list_entry * 5638 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx) 5639 { 5640 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5641 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5642 struct mlx5dv_dr_domain *ns; 5643 struct mlx5_flow_dv_modify_hdr_resource *entry; 5644 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5645 struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh, 5646 ref->actions_num - 1); 5647 int ret; 5648 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5649 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5650 uint32_t idx; 5651 5652 if (unlikely(!ipool)) { 5653 rte_flow_error_set(ctx->error, ENOMEM, 5654 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5655 NULL, "cannot allocate modify ipool"); 5656 return NULL; 5657 } 5658 entry = mlx5_ipool_zmalloc(ipool, &idx); 5659 if (!entry) { 5660 rte_flow_error_set(ctx->error, ENOMEM, 5661 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5662 "cannot allocate resource memory"); 5663 return NULL; 5664 } 5665 rte_memcpy(&entry->ft_type, 5666 RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)), 5667 key_len + data_len); 5668 if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 5669 ns = sh->fdb_domain; 5670 else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 5671 ns = sh->tx_domain; 5672 else 5673 ns = sh->rx_domain; 5674 ret = mlx5_flow_os_create_flow_action_modify_header 5675 (sh->cdev->ctx, ns, entry, 5676 data_len, &entry->action); 5677 if (ret) { 5678 mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx); 5679 rte_flow_error_set(ctx->error, ENOMEM, 5680 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5681 NULL, "cannot create modification action"); 5682 return NULL; 5683 } 5684 entry->idx = idx; 5685 return &entry->entry; 5686 } 5687 5688 struct mlx5_list_entry * 5689 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 5690 void *cb_ctx) 5691 { 5692 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5693 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5694 struct mlx5_flow_dv_modify_hdr_resource *entry; 5695 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5696 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5697 uint32_t idx; 5698 5699 entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1], 5700 &idx); 5701 if (!entry) { 5702 rte_flow_error_set(ctx->error, ENOMEM, 5703 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5704 "cannot allocate resource memory"); 5705 return NULL; 5706 } 5707 memcpy(entry, oentry, sizeof(*entry) + data_len); 5708 entry->idx = idx; 5709 return &entry->entry; 5710 } 5711 5712 void 5713 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 5714 { 5715 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5716 struct mlx5_flow_dv_modify_hdr_resource *res = 5717 container_of(entry, typeof(*res), entry); 5718 5719 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 5720 } 5721 5722 /** 5723 * Validate the sample action. 5724 * 5725 * @param[in, out] action_flags 5726 * Holds the actions detected until now. 5727 * @param[in] action 5728 * Pointer to the sample action. 5729 * @param[in] dev 5730 * Pointer to the Ethernet device structure. 5731 * @param[in] attr 5732 * Attributes of flow that includes this action. 5733 * @param[in] item_flags 5734 * Holds the items detected. 5735 * @param[in] rss 5736 * Pointer to the RSS action. 5737 * @param[out] sample_rss 5738 * Pointer to the RSS action in sample action list. 5739 * @param[out] count 5740 * Pointer to the COUNT action in sample action list. 5741 * @param[out] fdb_mirror 5742 * Pointer to the FDB mirror flag. 5743 * @param root 5744 * Whether action is on root table. 5745 * @param[out] error 5746 * Pointer to error structure. 5747 * 5748 * @return 5749 * 0 on success, a negative errno value otherwise and rte_errno is set. 5750 */ 5751 static int 5752 flow_dv_validate_action_sample(uint64_t *action_flags, 5753 const struct rte_flow_action *action, 5754 struct rte_eth_dev *dev, 5755 const struct rte_flow_attr *attr, 5756 uint64_t item_flags, 5757 const struct rte_flow_action_rss *rss, 5758 const struct rte_flow_action_rss **sample_rss, 5759 const struct rte_flow_action_count **count, 5760 int *fdb_mirror, 5761 bool root, 5762 struct rte_flow_error *error) 5763 { 5764 struct mlx5_priv *priv = dev->data->dev_private; 5765 struct mlx5_sh_config *dev_conf = &priv->sh->config; 5766 const struct rte_flow_action_sample *sample = action->conf; 5767 const struct rte_flow_action *act; 5768 uint64_t sub_action_flags = 0; 5769 uint16_t queue_index = 0xFFFF; 5770 int actions_n = 0; 5771 int ret; 5772 5773 if (!sample) 5774 return rte_flow_error_set(error, EINVAL, 5775 RTE_FLOW_ERROR_TYPE_ACTION, action, 5776 "configuration cannot be NULL"); 5777 if (sample->ratio == 0) 5778 return rte_flow_error_set(error, EINVAL, 5779 RTE_FLOW_ERROR_TYPE_ACTION, action, 5780 "ratio value starts from 1"); 5781 if (!priv->sh->cdev->config.devx || 5782 (sample->ratio > 0 && !priv->sampler_en)) 5783 return rte_flow_error_set(error, ENOTSUP, 5784 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5785 NULL, 5786 "sample action not supported"); 5787 if (*action_flags & MLX5_FLOW_ACTION_SAMPLE) 5788 return rte_flow_error_set(error, EINVAL, 5789 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5790 "Multiple sample actions not " 5791 "supported"); 5792 if (*action_flags & MLX5_FLOW_ACTION_METER) 5793 return rte_flow_error_set(error, EINVAL, 5794 RTE_FLOW_ERROR_TYPE_ACTION, action, 5795 "wrong action order, meter should " 5796 "be after sample action"); 5797 if (*action_flags & MLX5_FLOW_ACTION_JUMP) 5798 return rte_flow_error_set(error, EINVAL, 5799 RTE_FLOW_ERROR_TYPE_ACTION, action, 5800 "wrong action order, jump should " 5801 "be after sample action"); 5802 if (*action_flags & MLX5_FLOW_ACTION_CT) 5803 return rte_flow_error_set(error, EINVAL, 5804 RTE_FLOW_ERROR_TYPE_ACTION, action, 5805 "Sample after CT not supported"); 5806 act = sample->actions; 5807 for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 5808 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 5809 return rte_flow_error_set(error, ENOTSUP, 5810 RTE_FLOW_ERROR_TYPE_ACTION, 5811 act, "too many actions"); 5812 switch (act->type) { 5813 case RTE_FLOW_ACTION_TYPE_QUEUE: 5814 ret = mlx5_flow_validate_action_queue(act, 5815 sub_action_flags, 5816 dev, 5817 attr, error); 5818 if (ret < 0) 5819 return ret; 5820 queue_index = ((const struct rte_flow_action_queue *) 5821 (act->conf))->index; 5822 sub_action_flags |= MLX5_FLOW_ACTION_QUEUE; 5823 ++actions_n; 5824 break; 5825 case RTE_FLOW_ACTION_TYPE_RSS: 5826 *sample_rss = act->conf; 5827 ret = mlx5_flow_validate_action_rss(act, 5828 sub_action_flags, 5829 dev, attr, 5830 item_flags, 5831 error); 5832 if (ret < 0) 5833 return ret; 5834 if (rss && *sample_rss && 5835 ((*sample_rss)->level != rss->level || 5836 (*sample_rss)->types != rss->types)) 5837 return rte_flow_error_set(error, ENOTSUP, 5838 RTE_FLOW_ERROR_TYPE_ACTION, 5839 NULL, 5840 "Can't use the different RSS types " 5841 "or level in the same flow"); 5842 if (*sample_rss != NULL && (*sample_rss)->queue_num) 5843 queue_index = (*sample_rss)->queue[0]; 5844 sub_action_flags |= MLX5_FLOW_ACTION_RSS; 5845 ++actions_n; 5846 break; 5847 case RTE_FLOW_ACTION_TYPE_MARK: 5848 ret = flow_dv_validate_action_mark(dev, act, 5849 sub_action_flags, 5850 attr, error); 5851 if (ret < 0) 5852 return ret; 5853 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) 5854 sub_action_flags |= MLX5_FLOW_ACTION_MARK | 5855 MLX5_FLOW_ACTION_MARK_EXT; 5856 else 5857 sub_action_flags |= MLX5_FLOW_ACTION_MARK; 5858 ++actions_n; 5859 break; 5860 case RTE_FLOW_ACTION_TYPE_COUNT: 5861 ret = flow_dv_validate_action_count 5862 (dev, false, *action_flags | sub_action_flags, 5863 root, error); 5864 if (ret < 0) 5865 return ret; 5866 *count = act->conf; 5867 sub_action_flags |= MLX5_FLOW_ACTION_COUNT; 5868 *action_flags |= MLX5_FLOW_ACTION_COUNT; 5869 ++actions_n; 5870 break; 5871 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5872 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5873 ret = flow_dv_validate_action_port_id(dev, 5874 sub_action_flags, 5875 act, 5876 attr, 5877 error); 5878 if (ret) 5879 return ret; 5880 sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID; 5881 ++actions_n; 5882 break; 5883 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 5884 ret = flow_dv_validate_action_raw_encap_decap 5885 (dev, NULL, act->conf, attr, &sub_action_flags, 5886 &actions_n, action, item_flags, error); 5887 if (ret < 0) 5888 return ret; 5889 ++actions_n; 5890 break; 5891 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 5892 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 5893 ret = flow_dv_validate_action_l2_encap(dev, 5894 sub_action_flags, 5895 act, attr, 5896 error); 5897 if (ret < 0) 5898 return ret; 5899 sub_action_flags |= MLX5_FLOW_ACTION_ENCAP; 5900 ++actions_n; 5901 break; 5902 default: 5903 return rte_flow_error_set(error, ENOTSUP, 5904 RTE_FLOW_ERROR_TYPE_ACTION, 5905 NULL, 5906 "Doesn't support optional " 5907 "action"); 5908 } 5909 } 5910 if (attr->ingress) { 5911 if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE | 5912 MLX5_FLOW_ACTION_RSS))) 5913 return rte_flow_error_set(error, EINVAL, 5914 RTE_FLOW_ERROR_TYPE_ACTION, 5915 NULL, 5916 "Ingress must has a dest " 5917 "QUEUE for Sample"); 5918 } else if (attr->egress) { 5919 return rte_flow_error_set(error, ENOTSUP, 5920 RTE_FLOW_ERROR_TYPE_ACTION, 5921 NULL, 5922 "Sample Only support Ingress " 5923 "or E-Switch"); 5924 } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) { 5925 MLX5_ASSERT(attr->transfer); 5926 if (sample->ratio > 1) 5927 return rte_flow_error_set(error, ENOTSUP, 5928 RTE_FLOW_ERROR_TYPE_ACTION, 5929 NULL, 5930 "E-Switch doesn't support " 5931 "any optional action " 5932 "for sampling"); 5933 if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) 5934 return rte_flow_error_set(error, ENOTSUP, 5935 RTE_FLOW_ERROR_TYPE_ACTION, 5936 NULL, 5937 "unsupported action QUEUE"); 5938 if (sub_action_flags & MLX5_FLOW_ACTION_RSS) 5939 return rte_flow_error_set(error, ENOTSUP, 5940 RTE_FLOW_ERROR_TYPE_ACTION, 5941 NULL, 5942 "unsupported action QUEUE"); 5943 if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID)) 5944 return rte_flow_error_set(error, EINVAL, 5945 RTE_FLOW_ERROR_TYPE_ACTION, 5946 NULL, 5947 "E-Switch must has a dest " 5948 "port for mirroring"); 5949 *fdb_mirror = 1; 5950 } 5951 /* Continue validation for Xcap actions.*/ 5952 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) && 5953 (queue_index == 0xFFFF || !mlx5_rxq_is_hairpin(dev, queue_index))) { 5954 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) == 5955 MLX5_FLOW_XCAP_ACTIONS) 5956 return rte_flow_error_set(error, ENOTSUP, 5957 RTE_FLOW_ERROR_TYPE_ACTION, 5958 NULL, "encap and decap " 5959 "combination aren't " 5960 "supported"); 5961 if (attr->ingress && (sub_action_flags & MLX5_FLOW_ACTION_ENCAP)) 5962 return rte_flow_error_set(error, ENOTSUP, 5963 RTE_FLOW_ERROR_TYPE_ACTION, 5964 NULL, "encap is not supported" 5965 " for ingress traffic"); 5966 } 5967 return 0; 5968 } 5969 5970 /** 5971 * Find existing modify-header resource or create and register a new one. 5972 * 5973 * @param dev[in, out] 5974 * Pointer to rte_eth_dev structure. 5975 * @param[in, out] resource 5976 * Pointer to modify-header resource. 5977 * @parm[in, out] dev_flow 5978 * Pointer to the dev_flow. 5979 * @param[out] error 5980 * pointer to error structure. 5981 * 5982 * @return 5983 * 0 on success otherwise -errno and errno is set. 5984 */ 5985 static int 5986 flow_dv_modify_hdr_resource_register 5987 (struct rte_eth_dev *dev, 5988 struct mlx5_flow_dv_modify_hdr_resource *resource, 5989 struct mlx5_flow *dev_flow, 5990 struct rte_flow_error *error) 5991 { 5992 struct mlx5_priv *priv = dev->data->dev_private; 5993 struct mlx5_dev_ctx_shared *sh = priv->sh; 5994 uint32_t key_len = sizeof(*resource) - 5995 offsetof(typeof(*resource), ft_type) + 5996 resource->actions_num * sizeof(resource->actions[0]); 5997 struct mlx5_list_entry *entry; 5998 struct mlx5_flow_cb_ctx ctx = { 5999 .error = error, 6000 .data = resource, 6001 }; 6002 struct mlx5_hlist *modify_cmds; 6003 uint64_t key64; 6004 6005 modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds, 6006 "hdr_modify", 6007 MLX5_FLOW_HDR_MODIFY_HTABLE_SZ, 6008 true, false, sh, 6009 flow_dv_modify_create_cb, 6010 flow_dv_modify_match_cb, 6011 flow_dv_modify_remove_cb, 6012 flow_dv_modify_clone_cb, 6013 flow_dv_modify_clone_free_cb, 6014 error); 6015 if (unlikely(!modify_cmds)) 6016 return -rte_errno; 6017 resource->root = !dev_flow->dv.group; 6018 if (resource->actions_num > flow_dv_modify_hdr_action_max(dev, 6019 resource->root)) 6020 return rte_flow_error_set(error, EOVERFLOW, 6021 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 6022 "too many modify header items"); 6023 key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0); 6024 entry = mlx5_hlist_register(modify_cmds, key64, &ctx); 6025 if (!entry) 6026 return -rte_errno; 6027 resource = container_of(entry, typeof(*resource), entry); 6028 dev_flow->handle->dvh.modify_hdr = resource; 6029 return 0; 6030 } 6031 6032 /** 6033 * Get DV flow counter by index. 6034 * 6035 * @param[in] dev 6036 * Pointer to the Ethernet device structure. 6037 * @param[in] idx 6038 * mlx5 flow counter index in the container. 6039 * @param[out] ppool 6040 * mlx5 flow counter pool in the container. 6041 * 6042 * @return 6043 * Pointer to the counter, NULL otherwise. 6044 */ 6045 static struct mlx5_flow_counter * 6046 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev, 6047 uint32_t idx, 6048 struct mlx5_flow_counter_pool **ppool) 6049 { 6050 struct mlx5_priv *priv = dev->data->dev_private; 6051 struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; 6052 struct mlx5_flow_counter_pool *pool; 6053 6054 /* Decrease to original index and clear shared bit. */ 6055 idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1); 6056 MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < MLX5_COUNTER_POOLS_MAX_NUM); 6057 pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL]; 6058 MLX5_ASSERT(pool); 6059 if (ppool) 6060 *ppool = pool; 6061 return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL); 6062 } 6063 6064 /** 6065 * Check the devx counter belongs to the pool. 6066 * 6067 * @param[in] pool 6068 * Pointer to the counter pool. 6069 * @param[in] id 6070 * The counter devx ID. 6071 * 6072 * @return 6073 * True if counter belongs to the pool, false otherwise. 6074 */ 6075 static bool 6076 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id) 6077 { 6078 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) * 6079 MLX5_COUNTERS_PER_POOL; 6080 6081 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL) 6082 return true; 6083 return false; 6084 } 6085 6086 /** 6087 * Get a pool by devx counter ID. 6088 * 6089 * @param[in] cmng 6090 * Pointer to the counter management. 6091 * @param[in] id 6092 * The counter devx ID. 6093 * 6094 * @return 6095 * The counter pool pointer if exists, NULL otherwise, 6096 */ 6097 static struct mlx5_flow_counter_pool * 6098 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id) 6099 { 6100 uint32_t i; 6101 struct mlx5_flow_counter_pool *pool = NULL; 6102 6103 rte_spinlock_lock(&cmng->pool_update_sl); 6104 /* Check last used pool. */ 6105 if (cmng->last_pool_idx != POOL_IDX_INVALID && 6106 flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) { 6107 pool = cmng->pools[cmng->last_pool_idx]; 6108 goto out; 6109 } 6110 /* ID out of range means no suitable pool in the container. */ 6111 if (id > cmng->max_id || id < cmng->min_id) 6112 goto out; 6113 /* 6114 * Find the pool from the end of the container, since mostly counter 6115 * ID is sequence increasing, and the last pool should be the needed 6116 * one. 6117 */ 6118 i = cmng->n_valid; 6119 while (i--) { 6120 struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i]; 6121 6122 if (flow_dv_is_counter_in_pool(pool_tmp, id)) { 6123 pool = pool_tmp; 6124 break; 6125 } 6126 } 6127 out: 6128 rte_spinlock_unlock(&cmng->pool_update_sl); 6129 return pool; 6130 } 6131 6132 /** 6133 * Query a devx flow counter. 6134 * 6135 * @param[in] dev 6136 * Pointer to the Ethernet device structure. 6137 * @param[in] counter 6138 * Index to the flow counter. 6139 * @param[out] pkts 6140 * The statistics value of packets. 6141 * @param[out] bytes 6142 * The statistics value of bytes. 6143 * 6144 * @return 6145 * 0 on success, otherwise a negative errno value and rte_errno is set. 6146 */ 6147 static inline int 6148 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts, 6149 uint64_t *bytes) 6150 { 6151 struct mlx5_priv *priv = dev->data->dev_private; 6152 struct mlx5_flow_counter_pool *pool = NULL; 6153 struct mlx5_flow_counter *cnt; 6154 int offset; 6155 6156 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 6157 MLX5_ASSERT(pool); 6158 if (priv->sh->sws_cmng.counter_fallback) 6159 return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0, 6160 0, pkts, bytes, 0, NULL, NULL, 0); 6161 rte_spinlock_lock(&pool->sl); 6162 if (!pool->raw) { 6163 *pkts = 0; 6164 *bytes = 0; 6165 } else { 6166 offset = MLX5_CNT_ARRAY_IDX(pool, cnt); 6167 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits); 6168 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes); 6169 } 6170 rte_spinlock_unlock(&pool->sl); 6171 return 0; 6172 } 6173 6174 /** 6175 * Create and initialize a new counter pool. 6176 * 6177 * @param[in] dev 6178 * Pointer to the Ethernet device structure. 6179 * @param[out] dcs 6180 * The devX counter handle. 6181 * @param[in] age 6182 * Whether the pool is for counter that was allocated for aging. 6183 * 6184 * @return 6185 * The pool container pointer on success, NULL otherwise and rte_errno is set. 6186 */ 6187 static struct mlx5_flow_counter_pool * 6188 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs, 6189 uint32_t age) 6190 { 6191 struct mlx5_priv *priv = dev->data->dev_private; 6192 struct mlx5_flow_counter_pool *pool; 6193 struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; 6194 bool fallback = cmng->counter_fallback; 6195 uint32_t size = sizeof(*pool); 6196 6197 if (cmng->n_valid == MLX5_COUNTER_POOLS_MAX_NUM) { 6198 DRV_LOG(ERR, "All counter is in used, try again later."); 6199 rte_errno = EAGAIN; 6200 return NULL; 6201 } 6202 size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE; 6203 size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE); 6204 pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY); 6205 if (!pool) { 6206 rte_errno = ENOMEM; 6207 return NULL; 6208 } 6209 pool->raw = NULL; 6210 pool->is_aged = !!age; 6211 pool->query_gen = 0; 6212 pool->min_dcs = dcs; 6213 rte_spinlock_init(&pool->sl); 6214 rte_spinlock_init(&pool->csl); 6215 TAILQ_INIT(&pool->counters[0]); 6216 TAILQ_INIT(&pool->counters[1]); 6217 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 6218 rte_spinlock_lock(&cmng->pool_update_sl); 6219 pool->index = cmng->n_valid; 6220 cmng->pools[pool->index] = pool; 6221 cmng->n_valid++; 6222 if (unlikely(fallback)) { 6223 int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL); 6224 6225 if (base < cmng->min_id) 6226 cmng->min_id = base; 6227 if (base > cmng->max_id) 6228 cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1; 6229 cmng->last_pool_idx = pool->index; 6230 } 6231 rte_spinlock_unlock(&cmng->pool_update_sl); 6232 return pool; 6233 } 6234 6235 /** 6236 * Prepare a new counter and/or a new counter pool. 6237 * 6238 * @param[in] dev 6239 * Pointer to the Ethernet device structure. 6240 * @param[out] cnt_free 6241 * Where to put the pointer of a new counter. 6242 * @param[in] age 6243 * Whether the pool is for counter that was allocated for aging. 6244 * 6245 * @return 6246 * The counter pool pointer and @p cnt_free is set on success, 6247 * NULL otherwise and rte_errno is set. 6248 */ 6249 static struct mlx5_flow_counter_pool * 6250 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev, 6251 struct mlx5_flow_counter **cnt_free, 6252 uint32_t age) 6253 { 6254 struct mlx5_priv *priv = dev->data->dev_private; 6255 struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; 6256 struct mlx5_flow_counter_pool *pool; 6257 struct mlx5_counters tmp_tq; 6258 struct mlx5_devx_obj *dcs = NULL; 6259 struct mlx5_flow_counter *cnt; 6260 enum mlx5_counter_type cnt_type = 6261 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6262 bool fallback = priv->sh->sws_cmng.counter_fallback; 6263 uint32_t i; 6264 6265 if (fallback) { 6266 /* bulk_bitmap must be 0 for single counter allocation. */ 6267 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0); 6268 if (!dcs) 6269 return NULL; 6270 pool = flow_dv_find_pool_by_id(cmng, dcs->id); 6271 if (!pool) { 6272 pool = flow_dv_pool_create(dev, dcs, age); 6273 if (!pool) { 6274 mlx5_devx_cmd_destroy(dcs); 6275 return NULL; 6276 } 6277 } 6278 i = dcs->id % MLX5_COUNTERS_PER_POOL; 6279 cnt = MLX5_POOL_GET_CNT(pool, i); 6280 cnt->pool = pool; 6281 cnt->dcs_when_free = dcs; 6282 *cnt_free = cnt; 6283 return pool; 6284 } 6285 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 6286 if (!dcs) { 6287 rte_errno = ENODATA; 6288 return NULL; 6289 } 6290 pool = flow_dv_pool_create(dev, dcs, age); 6291 if (!pool) { 6292 mlx5_devx_cmd_destroy(dcs); 6293 return NULL; 6294 } 6295 TAILQ_INIT(&tmp_tq); 6296 for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) { 6297 cnt = MLX5_POOL_GET_CNT(pool, i); 6298 cnt->pool = pool; 6299 TAILQ_INSERT_HEAD(&tmp_tq, cnt, next); 6300 } 6301 rte_spinlock_lock(&cmng->csl[cnt_type]); 6302 TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next); 6303 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6304 *cnt_free = MLX5_POOL_GET_CNT(pool, 0); 6305 (*cnt_free)->pool = pool; 6306 return pool; 6307 } 6308 6309 /** 6310 * Allocate a flow counter. 6311 * 6312 * @param[in] dev 6313 * Pointer to the Ethernet device structure. 6314 * @param[in] age 6315 * Whether the counter was allocated for aging. 6316 * 6317 * @return 6318 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6319 */ 6320 static uint32_t 6321 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) 6322 { 6323 struct mlx5_priv *priv = dev->data->dev_private; 6324 struct mlx5_flow_counter_pool *pool = NULL; 6325 struct mlx5_flow_counter *cnt_free = NULL; 6326 bool fallback = priv->sh->sws_cmng.counter_fallback; 6327 struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; 6328 enum mlx5_counter_type cnt_type = 6329 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6330 uint32_t cnt_idx; 6331 6332 if (!priv->sh->cdev->config.devx) { 6333 rte_errno = ENOTSUP; 6334 return 0; 6335 } 6336 /* Get free counters from container. */ 6337 rte_spinlock_lock(&cmng->csl[cnt_type]); 6338 cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]); 6339 if (cnt_free) 6340 TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next); 6341 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6342 if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age)) 6343 goto err; 6344 pool = cnt_free->pool; 6345 if (fallback) 6346 cnt_free->dcs_when_active = cnt_free->dcs_when_free; 6347 /* Create a DV counter action only in the first time usage. */ 6348 if (!cnt_free->action) { 6349 uint16_t offset; 6350 struct mlx5_devx_obj *dcs; 6351 int ret; 6352 6353 if (!fallback) { 6354 offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free); 6355 dcs = pool->min_dcs; 6356 } else { 6357 offset = 0; 6358 dcs = cnt_free->dcs_when_free; 6359 } 6360 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset, 6361 &cnt_free->action); 6362 if (ret) { 6363 rte_errno = errno; 6364 goto err; 6365 } 6366 } 6367 cnt_idx = MLX5_MAKE_CNT_IDX(pool->index, 6368 MLX5_CNT_ARRAY_IDX(pool, cnt_free)); 6369 /* Update the counter reset values. */ 6370 if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits, 6371 &cnt_free->bytes)) 6372 goto err; 6373 if (!fallback && !priv->sh->sws_cmng.query_thread_on) 6374 /* Start the asynchronous batch query by the host thread. */ 6375 mlx5_set_query_alarm(priv->sh); 6376 /* 6377 * When the count action isn't shared (by ID), shared_info field is 6378 * used for indirect action API's refcnt. 6379 * When the counter action is not shared neither by ID nor by indirect 6380 * action API, shared info must be 1. 6381 */ 6382 cnt_free->shared_info.refcnt = 1; 6383 return cnt_idx; 6384 err: 6385 if (cnt_free) { 6386 cnt_free->pool = pool; 6387 if (fallback) 6388 cnt_free->dcs_when_free = cnt_free->dcs_when_active; 6389 rte_spinlock_lock(&cmng->csl[cnt_type]); 6390 TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next); 6391 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6392 } 6393 return 0; 6394 } 6395 6396 /** 6397 * Get age param from counter index. 6398 * 6399 * @param[in] dev 6400 * Pointer to the Ethernet device structure. 6401 * @param[in] counter 6402 * Index to the counter handler. 6403 * 6404 * @return 6405 * The aging parameter specified for the counter index. 6406 */ 6407 static struct mlx5_age_param* 6408 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev, 6409 uint32_t counter) 6410 { 6411 struct mlx5_flow_counter *cnt; 6412 struct mlx5_flow_counter_pool *pool = NULL; 6413 6414 flow_dv_counter_get_by_idx(dev, counter, &pool); 6415 counter = (counter - 1) % MLX5_COUNTERS_PER_POOL; 6416 cnt = MLX5_POOL_GET_CNT(pool, counter); 6417 return MLX5_CNT_TO_AGE(cnt); 6418 } 6419 6420 /** 6421 * Remove a flow counter from aged counter list. 6422 * 6423 * @param[in] dev 6424 * Pointer to the Ethernet device structure. 6425 * @param[in] counter 6426 * Index to the counter handler. 6427 * @param[in] cnt 6428 * Pointer to the counter handler. 6429 */ 6430 static void 6431 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev, 6432 uint32_t counter, struct mlx5_flow_counter *cnt) 6433 { 6434 struct mlx5_age_info *age_info; 6435 struct mlx5_age_param *age_param; 6436 struct mlx5_priv *priv = dev->data->dev_private; 6437 uint16_t expected = AGE_CANDIDATE; 6438 6439 age_info = GET_PORT_AGE_INFO(priv); 6440 age_param = flow_dv_counter_idx_get_age(dev, counter); 6441 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 6442 AGE_FREE, false, __ATOMIC_RELAXED, 6443 __ATOMIC_RELAXED)) { 6444 /** 6445 * We need the lock even it is age timeout, 6446 * since counter may still in process. 6447 */ 6448 rte_spinlock_lock(&age_info->aged_sl); 6449 TAILQ_REMOVE(&age_info->aged_counters, cnt, next); 6450 rte_spinlock_unlock(&age_info->aged_sl); 6451 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 6452 } 6453 } 6454 6455 /** 6456 * Release a flow counter. 6457 * 6458 * @param[in] dev 6459 * Pointer to the Ethernet device structure. 6460 * @param[in] counter 6461 * Index to the counter handler. 6462 */ 6463 static void 6464 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) 6465 { 6466 struct mlx5_priv *priv = dev->data->dev_private; 6467 struct mlx5_flow_counter_pool *pool = NULL; 6468 struct mlx5_flow_counter *cnt; 6469 enum mlx5_counter_type cnt_type; 6470 6471 if (!counter) 6472 return; 6473 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 6474 MLX5_ASSERT(pool); 6475 if (pool->is_aged) { 6476 flow_dv_counter_remove_from_age(dev, counter, cnt); 6477 } else { 6478 /* 6479 * If the counter action is shared by indirect action API, 6480 * the atomic function reduces its references counter. 6481 * If after the reduction the action is still referenced, the 6482 * function returns here and does not release it. 6483 * When the counter action is not shared by 6484 * indirect action API, shared info is 1 before the reduction, 6485 * so this condition is failed and function doesn't return here. 6486 */ 6487 if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1, 6488 __ATOMIC_RELAXED)) 6489 return; 6490 } 6491 cnt->pool = pool; 6492 /* 6493 * Put the counter back to list to be updated in none fallback mode. 6494 * Currently, we are using two list alternately, while one is in query, 6495 * add the freed counter to the other list based on the pool query_gen 6496 * value. After query finishes, add counter the list to the global 6497 * container counter list. The list changes while query starts. In 6498 * this case, lock will not be needed as query callback and release 6499 * function both operate with the different list. 6500 */ 6501 if (!priv->sh->sws_cmng.counter_fallback) { 6502 rte_spinlock_lock(&pool->csl); 6503 TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); 6504 rte_spinlock_unlock(&pool->csl); 6505 } else { 6506 cnt->dcs_when_free = cnt->dcs_when_active; 6507 cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : 6508 MLX5_COUNTER_TYPE_ORIGIN; 6509 rte_spinlock_lock(&priv->sh->sws_cmng.csl[cnt_type]); 6510 TAILQ_INSERT_TAIL(&priv->sh->sws_cmng.counters[cnt_type], 6511 cnt, next); 6512 rte_spinlock_unlock(&priv->sh->sws_cmng.csl[cnt_type]); 6513 } 6514 } 6515 6516 /** 6517 * Resize a meter id container. 6518 * 6519 * @param[in] dev 6520 * Pointer to the Ethernet device structure. 6521 * 6522 * @return 6523 * 0 on success, otherwise negative errno value and rte_errno is set. 6524 */ 6525 static int 6526 flow_dv_mtr_container_resize(struct rte_eth_dev *dev) 6527 { 6528 struct mlx5_priv *priv = dev->data->dev_private; 6529 struct mlx5_aso_mtr_pools_mng *pools_mng = 6530 &priv->sh->mtrmng->pools_mng; 6531 void *old_pools = pools_mng->pools; 6532 uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE; 6533 uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize; 6534 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 6535 6536 if (!pools) { 6537 rte_errno = ENOMEM; 6538 return -ENOMEM; 6539 } 6540 if (!pools_mng->n) 6541 if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER, 1)) { 6542 mlx5_free(pools); 6543 return -ENOMEM; 6544 } 6545 if (old_pools) 6546 memcpy(pools, old_pools, pools_mng->n * 6547 sizeof(struct mlx5_aso_mtr_pool *)); 6548 pools_mng->n = resize; 6549 pools_mng->pools = pools; 6550 if (old_pools) 6551 mlx5_free(old_pools); 6552 return 0; 6553 } 6554 6555 /** 6556 * Prepare a new meter and/or a new meter pool. 6557 * 6558 * @param[in] dev 6559 * Pointer to the Ethernet device structure. 6560 * @param[out] mtr_free 6561 * Where to put the pointer of a new meter.g. 6562 * 6563 * @return 6564 * The meter pool pointer and @mtr_free is set on success, 6565 * NULL otherwise and rte_errno is set. 6566 */ 6567 static struct mlx5_aso_mtr_pool * 6568 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free) 6569 { 6570 struct mlx5_priv *priv = dev->data->dev_private; 6571 struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng; 6572 struct mlx5_aso_mtr_pool *pool = NULL; 6573 struct mlx5_devx_obj *dcs = NULL; 6574 uint32_t i; 6575 uint32_t log_obj_size; 6576 6577 log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1); 6578 dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx, 6579 priv->sh->cdev->pdn, 6580 log_obj_size); 6581 if (!dcs) { 6582 rte_errno = ENODATA; 6583 return NULL; 6584 } 6585 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 6586 if (!pool) { 6587 rte_errno = ENOMEM; 6588 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6589 return NULL; 6590 } 6591 pool->devx_obj = dcs; 6592 rte_rwlock_write_lock(&pools_mng->resize_mtrwl); 6593 pool->index = pools_mng->n_valid; 6594 if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) { 6595 mlx5_free(pool); 6596 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6597 rte_rwlock_write_unlock(&pools_mng->resize_mtrwl); 6598 return NULL; 6599 } 6600 pools_mng->pools[pool->index] = pool; 6601 pools_mng->n_valid++; 6602 rte_rwlock_write_unlock(&pools_mng->resize_mtrwl); 6603 for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) { 6604 pool->mtrs[i].offset = i; 6605 LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next); 6606 } 6607 pool->mtrs[0].offset = 0; 6608 *mtr_free = &pool->mtrs[0]; 6609 return pool; 6610 } 6611 6612 /** 6613 * Release a flow meter into pool. 6614 * 6615 * @param[in] dev 6616 * Pointer to the Ethernet device structure. 6617 * @param[in] mtr_idx 6618 * Index to aso flow meter. 6619 */ 6620 static void 6621 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx) 6622 { 6623 struct mlx5_priv *priv = dev->data->dev_private; 6624 struct mlx5_aso_mtr_pools_mng *pools_mng = 6625 &priv->sh->mtrmng->pools_mng; 6626 struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 6627 6628 MLX5_ASSERT(aso_mtr); 6629 rte_spinlock_lock(&pools_mng->mtrsl); 6630 memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info)); 6631 aso_mtr->state = ASO_METER_FREE; 6632 LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next); 6633 rte_spinlock_unlock(&pools_mng->mtrsl); 6634 } 6635 6636 /** 6637 * Allocate a aso flow meter. 6638 * 6639 * @param[in] dev 6640 * Pointer to the Ethernet device structure. 6641 * 6642 * @return 6643 * Index to aso flow meter on success, 0 otherwise and rte_errno is set. 6644 */ 6645 static uint32_t 6646 flow_dv_mtr_alloc(struct rte_eth_dev *dev) 6647 { 6648 struct mlx5_priv *priv = dev->data->dev_private; 6649 struct mlx5_aso_mtr *mtr_free = NULL; 6650 struct mlx5_aso_mtr_pools_mng *pools_mng = 6651 &priv->sh->mtrmng->pools_mng; 6652 struct mlx5_aso_mtr_pool *pool; 6653 uint32_t mtr_idx = 0; 6654 6655 if (!priv->sh->cdev->config.devx) { 6656 rte_errno = ENOTSUP; 6657 return 0; 6658 } 6659 /* Allocate the flow meter memory. */ 6660 /* Get free meters from management. */ 6661 rte_spinlock_lock(&pools_mng->mtrsl); 6662 mtr_free = LIST_FIRST(&pools_mng->meters); 6663 if (mtr_free) 6664 LIST_REMOVE(mtr_free, next); 6665 if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) { 6666 rte_spinlock_unlock(&pools_mng->mtrsl); 6667 return 0; 6668 } 6669 mtr_free->state = ASO_METER_WAIT; 6670 rte_spinlock_unlock(&pools_mng->mtrsl); 6671 pool = container_of(mtr_free, 6672 struct mlx5_aso_mtr_pool, 6673 mtrs[mtr_free->offset]); 6674 mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset); 6675 if (!mtr_free->fm.meter_action_g) { 6676 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 6677 struct rte_flow_error error; 6678 uint8_t reg_id; 6679 6680 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error); 6681 mtr_free->fm.meter_action_g = 6682 mlx5_glue->dv_create_flow_action_aso 6683 (priv->sh->rx_domain, 6684 pool->devx_obj->obj, 6685 mtr_free->offset, 6686 (1 << MLX5_FLOW_COLOR_GREEN), 6687 reg_id - REG_C_0); 6688 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 6689 if (!mtr_free->fm.meter_action_g) { 6690 flow_dv_aso_mtr_release_to_pool(dev, mtr_idx); 6691 return 0; 6692 } 6693 } 6694 return mtr_idx; 6695 } 6696 6697 /** 6698 * Verify the @p attributes will be correctly understood by the NIC and store 6699 * them in the @p flow if everything is correct. 6700 * 6701 * @param[in] dev 6702 * Pointer to dev struct. 6703 * @param[in] attributes 6704 * Pointer to flow attributes 6705 * @param[in] external 6706 * This flow rule is created by request external to PMD. 6707 * @param[out] error 6708 * Pointer to error structure. 6709 * 6710 * @return 6711 * - 0 on success and non root table. 6712 * - 1 on success and root table. 6713 * - a negative errno value otherwise and rte_errno is set. 6714 */ 6715 static int 6716 flow_dv_validate_attributes(struct rte_eth_dev *dev, 6717 const struct mlx5_flow_tunnel *tunnel, 6718 const struct rte_flow_attr *attributes, 6719 const struct flow_grp_info *grp_info, 6720 struct rte_flow_error *error) 6721 { 6722 struct mlx5_priv *priv = dev->data->dev_private; 6723 uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes); 6724 int ret = 0; 6725 6726 #ifndef HAVE_MLX5DV_DR 6727 RTE_SET_USED(tunnel); 6728 RTE_SET_USED(grp_info); 6729 if (attributes->group) 6730 return rte_flow_error_set(error, ENOTSUP, 6731 RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 6732 NULL, 6733 "groups are not supported"); 6734 #else 6735 uint32_t table = 0; 6736 6737 ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table, 6738 grp_info, error); 6739 if (ret) 6740 return ret; 6741 if (!table) 6742 ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL; 6743 #endif 6744 if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR && 6745 attributes->priority > lowest_priority) 6746 return rte_flow_error_set(error, ENOTSUP, 6747 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 6748 NULL, 6749 "priority out of range"); 6750 if (attributes->transfer && !priv->sh->config.dv_esw_en) 6751 return rte_flow_error_set(error, ENOTSUP, 6752 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 6753 "E-Switch dr is not supported"); 6754 if (attributes->ingress + attributes->egress + attributes->transfer != 1) { 6755 return rte_flow_error_set(error, EINVAL, 6756 RTE_FLOW_ERROR_TYPE_ATTR, NULL, 6757 "must specify exactly one of " 6758 "ingress, egress or transfer"); 6759 } 6760 return ret; 6761 } 6762 6763 static int 6764 validate_integrity_bits(const struct rte_flow_item_integrity *mask, 6765 int64_t pattern_flags, uint64_t l3_flags, 6766 uint64_t l4_flags, uint64_t ip4_flag, 6767 struct rte_flow_error *error) 6768 { 6769 if (mask->l3_ok && !(pattern_flags & l3_flags)) 6770 return rte_flow_error_set(error, EINVAL, 6771 RTE_FLOW_ERROR_TYPE_ITEM, 6772 NULL, "missing L3 protocol"); 6773 6774 if (mask->ipv4_csum_ok && !(pattern_flags & ip4_flag)) 6775 return rte_flow_error_set(error, EINVAL, 6776 RTE_FLOW_ERROR_TYPE_ITEM, 6777 NULL, "missing IPv4 protocol"); 6778 6779 if ((mask->l4_ok || mask->l4_csum_ok) && !(pattern_flags & l4_flags)) 6780 return rte_flow_error_set(error, EINVAL, 6781 RTE_FLOW_ERROR_TYPE_ITEM, 6782 NULL, "missing L4 protocol"); 6783 6784 return 0; 6785 } 6786 6787 static int 6788 flow_dv_validate_item_integrity_post(const struct 6789 rte_flow_item *integrity_items[2], 6790 int64_t pattern_flags, 6791 struct rte_flow_error *error) 6792 { 6793 const struct rte_flow_item_integrity *mask; 6794 int ret; 6795 6796 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) { 6797 mask = (typeof(mask))integrity_items[0]->mask; 6798 ret = validate_integrity_bits(mask, pattern_flags, 6799 MLX5_FLOW_LAYER_OUTER_L3, 6800 MLX5_FLOW_LAYER_OUTER_L4, 6801 MLX5_FLOW_LAYER_OUTER_L3_IPV4, 6802 error); 6803 if (ret) 6804 return ret; 6805 } 6806 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) { 6807 mask = (typeof(mask))integrity_items[1]->mask; 6808 ret = validate_integrity_bits(mask, pattern_flags, 6809 MLX5_FLOW_LAYER_INNER_L3, 6810 MLX5_FLOW_LAYER_INNER_L4, 6811 MLX5_FLOW_LAYER_INNER_L3_IPV4, 6812 error); 6813 if (ret) 6814 return ret; 6815 } 6816 return 0; 6817 } 6818 6819 static int 6820 flow_dv_validate_item_integrity(struct rte_eth_dev *dev, 6821 const struct rte_flow_item *integrity_item, 6822 uint64_t pattern_flags, uint64_t *last_item, 6823 const struct rte_flow_item *integrity_items[2], 6824 struct rte_flow_error *error) 6825 { 6826 struct mlx5_priv *priv = dev->data->dev_private; 6827 const struct rte_flow_item_integrity *mask = (typeof(mask)) 6828 integrity_item->mask; 6829 const struct rte_flow_item_integrity *spec = (typeof(spec)) 6830 integrity_item->spec; 6831 6832 if (!priv->sh->cdev->config.hca_attr.pkt_integrity_match) 6833 return rte_flow_error_set(error, ENOTSUP, 6834 RTE_FLOW_ERROR_TYPE_ITEM, 6835 integrity_item, 6836 "packet integrity integrity_item not supported"); 6837 if (!spec) 6838 return rte_flow_error_set(error, ENOTSUP, 6839 RTE_FLOW_ERROR_TYPE_ITEM, 6840 integrity_item, 6841 "no spec for integrity item"); 6842 if (!mask) 6843 mask = &rte_flow_item_integrity_mask; 6844 if (!mlx5_validate_integrity_item(mask)) 6845 return rte_flow_error_set(error, ENOTSUP, 6846 RTE_FLOW_ERROR_TYPE_ITEM, 6847 integrity_item, 6848 "unsupported integrity filter"); 6849 if ((mask->l3_ok & !spec->l3_ok) || (mask->l4_ok & !spec->l4_ok) || 6850 (mask->ipv4_csum_ok & !spec->ipv4_csum_ok) || 6851 (mask->l4_csum_ok & !spec->l4_csum_ok)) 6852 return rte_flow_error_set(error, EINVAL, 6853 RTE_FLOW_ERROR_TYPE_ITEM, 6854 NULL, "negative integrity flow is not supported"); 6855 if (spec->level > 1) { 6856 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) 6857 return rte_flow_error_set 6858 (error, ENOTSUP, 6859 RTE_FLOW_ERROR_TYPE_ITEM, 6860 NULL, "multiple inner integrity items not supported"); 6861 integrity_items[1] = integrity_item; 6862 *last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; 6863 } else { 6864 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) 6865 return rte_flow_error_set 6866 (error, ENOTSUP, 6867 RTE_FLOW_ERROR_TYPE_ITEM, 6868 NULL, "multiple outer integrity items not supported"); 6869 integrity_items[0] = integrity_item; 6870 *last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; 6871 } 6872 return 0; 6873 } 6874 6875 static int 6876 flow_dv_validate_item_flex(struct rte_eth_dev *dev, 6877 const struct rte_flow_item *item, 6878 uint64_t item_flags, 6879 uint64_t *last_item, 6880 bool is_inner, 6881 struct rte_flow_error *error) 6882 { 6883 const struct rte_flow_item_flex *flow_spec = item->spec; 6884 const struct rte_flow_item_flex *flow_mask = item->mask; 6885 struct mlx5_flex_item *flex; 6886 6887 if (!flow_spec) 6888 return rte_flow_error_set(error, EINVAL, 6889 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6890 "flex flow item spec cannot be NULL"); 6891 if (!flow_mask) 6892 return rte_flow_error_set(error, EINVAL, 6893 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6894 "flex flow item mask cannot be NULL"); 6895 if (item->last) 6896 return rte_flow_error_set(error, ENOTSUP, 6897 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6898 "flex flow item last not supported"); 6899 if (mlx5_flex_acquire_index(dev, flow_spec->handle, false) < 0) 6900 return rte_flow_error_set(error, EINVAL, 6901 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6902 "invalid flex flow item handle"); 6903 flex = (struct mlx5_flex_item *)flow_spec->handle; 6904 switch (flex->tunnel_mode) { 6905 case FLEX_TUNNEL_MODE_SINGLE: 6906 if (item_flags & 6907 (MLX5_FLOW_ITEM_OUTER_FLEX | MLX5_FLOW_ITEM_INNER_FLEX)) 6908 rte_flow_error_set(error, EINVAL, 6909 RTE_FLOW_ERROR_TYPE_ITEM, 6910 NULL, "multiple flex items not supported"); 6911 break; 6912 case FLEX_TUNNEL_MODE_OUTER: 6913 if (is_inner) 6914 rte_flow_error_set(error, EINVAL, 6915 RTE_FLOW_ERROR_TYPE_ITEM, 6916 NULL, "inner flex item was not configured"); 6917 if (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX) 6918 rte_flow_error_set(error, ENOTSUP, 6919 RTE_FLOW_ERROR_TYPE_ITEM, 6920 NULL, "multiple flex items not supported"); 6921 break; 6922 case FLEX_TUNNEL_MODE_INNER: 6923 if (!is_inner) 6924 rte_flow_error_set(error, EINVAL, 6925 RTE_FLOW_ERROR_TYPE_ITEM, 6926 NULL, "outer flex item was not configured"); 6927 if (item_flags & MLX5_FLOW_ITEM_INNER_FLEX) 6928 rte_flow_error_set(error, EINVAL, 6929 RTE_FLOW_ERROR_TYPE_ITEM, 6930 NULL, "multiple flex items not supported"); 6931 break; 6932 case FLEX_TUNNEL_MODE_MULTI: 6933 if ((is_inner && (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)) || 6934 (!is_inner && (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX))) { 6935 rte_flow_error_set(error, EINVAL, 6936 RTE_FLOW_ERROR_TYPE_ITEM, 6937 NULL, "multiple flex items not supported"); 6938 } 6939 break; 6940 case FLEX_TUNNEL_MODE_TUNNEL: 6941 if (is_inner || (item_flags & MLX5_FLOW_ITEM_FLEX_TUNNEL)) 6942 rte_flow_error_set(error, EINVAL, 6943 RTE_FLOW_ERROR_TYPE_ITEM, 6944 NULL, "multiple flex tunnel items not supported"); 6945 break; 6946 default: 6947 rte_flow_error_set(error, EINVAL, 6948 RTE_FLOW_ERROR_TYPE_ITEM, 6949 NULL, "invalid flex item configuration"); 6950 } 6951 *last_item = flex->tunnel_mode == FLEX_TUNNEL_MODE_TUNNEL ? 6952 MLX5_FLOW_ITEM_FLEX_TUNNEL : is_inner ? 6953 MLX5_FLOW_ITEM_INNER_FLEX : MLX5_FLOW_ITEM_OUTER_FLEX; 6954 return 0; 6955 } 6956 6957 /** 6958 * Internal validation function. For validating both actions and items. 6959 * 6960 * @param[in] dev 6961 * Pointer to the rte_eth_dev structure. 6962 * @param[in] attr 6963 * Pointer to the flow attributes. 6964 * @param[in] items 6965 * Pointer to the list of items. 6966 * @param[in] actions 6967 * Pointer to the list of actions. 6968 * @param[in] external 6969 * This flow rule is created by request external to PMD. 6970 * @param[in] hairpin 6971 * Number of hairpin TX actions, 0 means classic flow. 6972 * @param[out] error 6973 * Pointer to the error structure. 6974 * 6975 * @return 6976 * 0 on success, a negative errno value otherwise and rte_errno is set. 6977 */ 6978 static int 6979 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, 6980 const struct rte_flow_item items[], 6981 const struct rte_flow_action actions[], 6982 bool external, int hairpin, struct rte_flow_error *error) 6983 { 6984 int ret; 6985 uint64_t aso_mask, action_flags = 0; 6986 uint64_t item_flags = 0; 6987 uint64_t last_item = 0; 6988 uint8_t next_protocol = 0xff; 6989 uint16_t ether_type = 0; 6990 int actions_n = 0; 6991 uint8_t item_ipv6_proto = 0; 6992 int fdb_mirror = 0; 6993 int modify_after_mirror = 0; 6994 const struct rte_flow_item *geneve_item = NULL; 6995 const struct rte_flow_item *gre_item = NULL; 6996 const struct rte_flow_item *gtp_item = NULL; 6997 const struct rte_flow_action_raw_decap *decap; 6998 const struct rte_flow_action_raw_encap *encap; 6999 const struct rte_flow_action_rss *rss = NULL; 7000 const struct rte_flow_action_rss *sample_rss = NULL; 7001 const struct rte_flow_action_count *sample_count = NULL; 7002 const struct rte_flow_item_tcp nic_tcp_mask = { 7003 .hdr = { 7004 .tcp_flags = 0xFF, 7005 .src_port = RTE_BE16(UINT16_MAX), 7006 .dst_port = RTE_BE16(UINT16_MAX), 7007 } 7008 }; 7009 const struct rte_flow_item_ipv6 nic_ipv6_mask = { 7010 .hdr = { 7011 .src_addr = 7012 "\xff\xff\xff\xff\xff\xff\xff\xff" 7013 "\xff\xff\xff\xff\xff\xff\xff\xff", 7014 .dst_addr = 7015 "\xff\xff\xff\xff\xff\xff\xff\xff" 7016 "\xff\xff\xff\xff\xff\xff\xff\xff", 7017 .vtc_flow = RTE_BE32(0xffffffff), 7018 .proto = 0xff, 7019 .hop_limits = 0xff, 7020 }, 7021 .has_frag_ext = 1, 7022 }; 7023 const struct rte_flow_item_ecpri nic_ecpri_mask = { 7024 .hdr = { 7025 .common = { 7026 .u32 = 7027 RTE_BE32(((const struct rte_ecpri_common_hdr) { 7028 .type = 0xFF, 7029 }).u32), 7030 }, 7031 .dummy[0] = 0xffffffff, 7032 }, 7033 }; 7034 struct mlx5_priv *priv = dev->data->dev_private; 7035 struct mlx5_sh_config *dev_conf = &priv->sh->config; 7036 uint16_t queue_index = 0xFFFF; 7037 const struct rte_flow_item_vlan *vlan_m = NULL; 7038 uint32_t rw_act_num = 0; 7039 uint64_t is_root; 7040 const struct mlx5_flow_tunnel *tunnel; 7041 enum mlx5_tof_rule_type tof_rule_type; 7042 struct flow_grp_info grp_info = { 7043 .external = !!external, 7044 .transfer = !!attr->transfer, 7045 .fdb_def_rule = !!priv->fdb_def_rule, 7046 .std_tbl_fix = true, 7047 }; 7048 const struct rte_eth_hairpin_conf *conf; 7049 const struct rte_flow_item *integrity_items[2] = {NULL, NULL}; 7050 const struct rte_flow_item *port_id_item = NULL; 7051 bool def_policy = false; 7052 bool shared_count = false; 7053 uint16_t udp_dport = 0; 7054 uint32_t tag_id = 0; 7055 const struct rte_flow_action_age *non_shared_age = NULL; 7056 const struct rte_flow_action_count *count = NULL; 7057 struct mlx5_priv *act_priv = NULL; 7058 int aso_after_sample = 0; 7059 7060 if (items == NULL) 7061 return -1; 7062 tunnel = is_tunnel_offload_active(dev) ? 7063 mlx5_get_tof(items, actions, &tof_rule_type) : NULL; 7064 if (tunnel) { 7065 if (!dev_conf->dv_flow_en) 7066 return rte_flow_error_set 7067 (error, ENOTSUP, 7068 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7069 NULL, "tunnel offload requires DV flow interface"); 7070 if (priv->representor) 7071 return rte_flow_error_set 7072 (error, ENOTSUP, 7073 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7074 NULL, "decap not supported for VF representor"); 7075 if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE) 7076 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 7077 else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE) 7078 action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH | 7079 MLX5_FLOW_ACTION_DECAP; 7080 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 7081 (dev, attr, tunnel, tof_rule_type); 7082 } 7083 ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error); 7084 if (ret < 0) 7085 return ret; 7086 is_root = (uint64_t)ret; 7087 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 7088 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 7089 int type = items->type; 7090 7091 if (!mlx5_flow_os_item_supported(type)) 7092 return rte_flow_error_set(error, ENOTSUP, 7093 RTE_FLOW_ERROR_TYPE_ITEM, 7094 NULL, "item not supported"); 7095 switch (type) { 7096 case RTE_FLOW_ITEM_TYPE_VOID: 7097 break; 7098 case RTE_FLOW_ITEM_TYPE_ESP: 7099 ret = mlx5_flow_os_validate_item_esp(items, item_flags, 7100 next_protocol, 7101 error); 7102 if (ret < 0) 7103 return ret; 7104 last_item = MLX5_FLOW_ITEM_ESP; 7105 break; 7106 case RTE_FLOW_ITEM_TYPE_PORT_ID: 7107 ret = flow_dv_validate_item_port_id 7108 (dev, items, attr, item_flags, &act_priv, error); 7109 if (ret < 0) 7110 return ret; 7111 last_item = MLX5_FLOW_ITEM_PORT_ID; 7112 port_id_item = items; 7113 break; 7114 case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: 7115 case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR: 7116 ret = flow_dv_validate_item_represented_port 7117 (dev, items, attr, item_flags, &act_priv, error); 7118 if (ret < 0) 7119 return ret; 7120 last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT; 7121 port_id_item = items; 7122 break; 7123 case RTE_FLOW_ITEM_TYPE_ETH: 7124 ret = mlx5_flow_validate_item_eth(items, item_flags, 7125 true, error); 7126 if (ret < 0) 7127 return ret; 7128 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 7129 MLX5_FLOW_LAYER_OUTER_L2; 7130 if (items->mask != NULL && items->spec != NULL) { 7131 ether_type = 7132 ((const struct rte_flow_item_eth *) 7133 items->spec)->hdr.ether_type; 7134 ether_type &= 7135 ((const struct rte_flow_item_eth *) 7136 items->mask)->hdr.ether_type; 7137 ether_type = rte_be_to_cpu_16(ether_type); 7138 } else { 7139 ether_type = 0; 7140 } 7141 break; 7142 case RTE_FLOW_ITEM_TYPE_VLAN: 7143 ret = flow_dv_validate_item_vlan(items, item_flags, 7144 dev, error); 7145 if (ret < 0) 7146 return ret; 7147 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 7148 MLX5_FLOW_LAYER_OUTER_VLAN; 7149 if (items->mask != NULL && items->spec != NULL) { 7150 ether_type = 7151 ((const struct rte_flow_item_vlan *) 7152 items->spec)->hdr.eth_proto; 7153 ether_type &= 7154 ((const struct rte_flow_item_vlan *) 7155 items->mask)->hdr.eth_proto; 7156 ether_type = rte_be_to_cpu_16(ether_type); 7157 } else { 7158 ether_type = 0; 7159 } 7160 /* Store outer VLAN mask for of_push_vlan action. */ 7161 if (!tunnel) 7162 vlan_m = items->mask; 7163 break; 7164 case RTE_FLOW_ITEM_TYPE_IPV4: 7165 mlx5_flow_tunnel_ip_check(items, next_protocol, 7166 &item_flags, &tunnel); 7167 ret = flow_dv_validate_item_ipv4(dev, items, item_flags, 7168 last_item, ether_type, 7169 error); 7170 if (ret < 0) 7171 return ret; 7172 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 7173 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 7174 if (items->mask != NULL && 7175 ((const struct rte_flow_item_ipv4 *) 7176 items->mask)->hdr.next_proto_id) { 7177 next_protocol = 7178 ((const struct rte_flow_item_ipv4 *) 7179 (items->spec))->hdr.next_proto_id; 7180 next_protocol &= 7181 ((const struct rte_flow_item_ipv4 *) 7182 (items->mask))->hdr.next_proto_id; 7183 } else { 7184 /* Reset for inner layer. */ 7185 next_protocol = 0xff; 7186 } 7187 break; 7188 case RTE_FLOW_ITEM_TYPE_IPV6: 7189 mlx5_flow_tunnel_ip_check(items, next_protocol, 7190 &item_flags, &tunnel); 7191 ret = mlx5_flow_validate_item_ipv6(items, item_flags, 7192 last_item, 7193 ether_type, 7194 &nic_ipv6_mask, 7195 error); 7196 if (ret < 0) 7197 return ret; 7198 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 7199 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 7200 if (items->mask != NULL && 7201 ((const struct rte_flow_item_ipv6 *) 7202 items->mask)->hdr.proto) { 7203 item_ipv6_proto = 7204 ((const struct rte_flow_item_ipv6 *) 7205 items->spec)->hdr.proto; 7206 next_protocol = 7207 ((const struct rte_flow_item_ipv6 *) 7208 items->spec)->hdr.proto; 7209 next_protocol &= 7210 ((const struct rte_flow_item_ipv6 *) 7211 items->mask)->hdr.proto; 7212 } else { 7213 /* Reset for inner layer. */ 7214 next_protocol = 0xff; 7215 } 7216 break; 7217 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 7218 ret = flow_dv_validate_item_ipv6_frag_ext(items, 7219 item_flags, 7220 error); 7221 if (ret < 0) 7222 return ret; 7223 last_item = tunnel ? 7224 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 7225 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 7226 if (items->mask != NULL && 7227 ((const struct rte_flow_item_ipv6_frag_ext *) 7228 items->mask)->hdr.next_header) { 7229 next_protocol = 7230 ((const struct rte_flow_item_ipv6_frag_ext *) 7231 items->spec)->hdr.next_header; 7232 next_protocol &= 7233 ((const struct rte_flow_item_ipv6_frag_ext *) 7234 items->mask)->hdr.next_header; 7235 } else { 7236 /* Reset for inner layer. */ 7237 next_protocol = 0xff; 7238 } 7239 break; 7240 case RTE_FLOW_ITEM_TYPE_TCP: 7241 ret = mlx5_flow_validate_item_tcp 7242 (items, item_flags, 7243 next_protocol, 7244 &nic_tcp_mask, 7245 error); 7246 if (ret < 0) 7247 return ret; 7248 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 7249 MLX5_FLOW_LAYER_OUTER_L4_TCP; 7250 break; 7251 case RTE_FLOW_ITEM_TYPE_UDP: 7252 ret = mlx5_flow_validate_item_udp(items, item_flags, 7253 next_protocol, 7254 error); 7255 const struct rte_flow_item_udp *spec = items->spec; 7256 const struct rte_flow_item_udp *mask = items->mask; 7257 if (!mask) 7258 mask = &rte_flow_item_udp_mask; 7259 if (spec != NULL) 7260 udp_dport = rte_be_to_cpu_16 7261 (spec->hdr.dst_port & 7262 mask->hdr.dst_port); 7263 if (ret < 0) 7264 return ret; 7265 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 7266 MLX5_FLOW_LAYER_OUTER_L4_UDP; 7267 break; 7268 case RTE_FLOW_ITEM_TYPE_GRE: 7269 ret = mlx5_flow_validate_item_gre(items, item_flags, 7270 next_protocol, error); 7271 if (ret < 0) 7272 return ret; 7273 gre_item = items; 7274 last_item = MLX5_FLOW_LAYER_GRE; 7275 break; 7276 case RTE_FLOW_ITEM_TYPE_GRE_OPTION: 7277 ret = mlx5_flow_validate_item_gre_option(dev, items, item_flags, 7278 attr, gre_item, error); 7279 if (ret < 0) 7280 return ret; 7281 last_item = MLX5_FLOW_LAYER_GRE; 7282 break; 7283 case RTE_FLOW_ITEM_TYPE_NVGRE: 7284 ret = mlx5_flow_validate_item_nvgre(items, item_flags, 7285 next_protocol, 7286 error); 7287 if (ret < 0) 7288 return ret; 7289 last_item = MLX5_FLOW_LAYER_NVGRE; 7290 break; 7291 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 7292 ret = mlx5_flow_validate_item_gre_key 7293 (items, item_flags, gre_item, error); 7294 if (ret < 0) 7295 return ret; 7296 last_item = MLX5_FLOW_LAYER_GRE_KEY; 7297 break; 7298 case RTE_FLOW_ITEM_TYPE_VXLAN: 7299 ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, 7300 items, item_flags, 7301 is_root, error); 7302 if (ret < 0) 7303 return ret; 7304 last_item = MLX5_FLOW_LAYER_VXLAN; 7305 break; 7306 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 7307 ret = mlx5_flow_validate_item_vxlan_gpe(items, 7308 item_flags, dev, 7309 error); 7310 if (ret < 0) 7311 return ret; 7312 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 7313 break; 7314 case RTE_FLOW_ITEM_TYPE_GENEVE: 7315 ret = mlx5_flow_validate_item_geneve(items, 7316 item_flags, dev, 7317 error); 7318 if (ret < 0) 7319 return ret; 7320 geneve_item = items; 7321 last_item = MLX5_FLOW_LAYER_GENEVE; 7322 break; 7323 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 7324 ret = mlx5_flow_validate_item_geneve_opt(items, 7325 last_item, 7326 geneve_item, 7327 dev, 7328 error); 7329 if (ret < 0) 7330 return ret; 7331 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 7332 break; 7333 case RTE_FLOW_ITEM_TYPE_MPLS: 7334 ret = mlx5_flow_validate_item_mpls(dev, items, 7335 item_flags, 7336 last_item, error); 7337 if (ret < 0) 7338 return ret; 7339 last_item = MLX5_FLOW_LAYER_MPLS; 7340 break; 7341 7342 case RTE_FLOW_ITEM_TYPE_MARK: 7343 ret = flow_dv_validate_item_mark(dev, items, attr, 7344 error); 7345 if (ret < 0) 7346 return ret; 7347 last_item = MLX5_FLOW_ITEM_MARK; 7348 break; 7349 case RTE_FLOW_ITEM_TYPE_META: 7350 ret = flow_dv_validate_item_meta(dev, items, attr, 7351 error); 7352 if (ret < 0) 7353 return ret; 7354 last_item = MLX5_FLOW_ITEM_METADATA; 7355 break; 7356 case RTE_FLOW_ITEM_TYPE_ICMP: 7357 ret = mlx5_flow_validate_item_icmp(items, item_flags, 7358 next_protocol, 7359 error); 7360 if (ret < 0) 7361 return ret; 7362 last_item = MLX5_FLOW_LAYER_ICMP; 7363 break; 7364 case RTE_FLOW_ITEM_TYPE_ICMP6: 7365 ret = mlx5_flow_validate_item_icmp6(items, item_flags, 7366 next_protocol, 7367 error); 7368 if (ret < 0) 7369 return ret; 7370 item_ipv6_proto = IPPROTO_ICMPV6; 7371 last_item = MLX5_FLOW_LAYER_ICMP6; 7372 break; 7373 case RTE_FLOW_ITEM_TYPE_TAG: 7374 ret = flow_dv_validate_item_tag(dev, items, 7375 attr, error); 7376 if (ret < 0) 7377 return ret; 7378 last_item = MLX5_FLOW_ITEM_TAG; 7379 break; 7380 case MLX5_RTE_FLOW_ITEM_TYPE_SQ: 7381 last_item = MLX5_FLOW_ITEM_SQ; 7382 break; 7383 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 7384 break; 7385 case RTE_FLOW_ITEM_TYPE_GTP: 7386 ret = flow_dv_validate_item_gtp(dev, items, item_flags, 7387 error); 7388 if (ret < 0) 7389 return ret; 7390 gtp_item = items; 7391 last_item = MLX5_FLOW_LAYER_GTP; 7392 break; 7393 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 7394 ret = flow_dv_validate_item_gtp_psc(items, last_item, 7395 gtp_item, is_root, 7396 error); 7397 if (ret < 0) 7398 return ret; 7399 last_item = MLX5_FLOW_LAYER_GTP_PSC; 7400 break; 7401 case RTE_FLOW_ITEM_TYPE_ECPRI: 7402 /* Capacity will be checked in the translate stage. */ 7403 ret = mlx5_flow_validate_item_ecpri(items, item_flags, 7404 last_item, 7405 ether_type, 7406 &nic_ecpri_mask, 7407 error); 7408 if (ret < 0) 7409 return ret; 7410 last_item = MLX5_FLOW_LAYER_ECPRI; 7411 break; 7412 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 7413 ret = flow_dv_validate_item_integrity(dev, items, 7414 item_flags, 7415 &last_item, 7416 integrity_items, 7417 error); 7418 if (ret < 0) 7419 return ret; 7420 break; 7421 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 7422 ret = flow_dv_validate_item_aso_ct(dev, items, 7423 &item_flags, error); 7424 if (ret < 0) 7425 return ret; 7426 break; 7427 case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL: 7428 /* tunnel offload item was processed before 7429 * list it here as a supported type 7430 */ 7431 break; 7432 case RTE_FLOW_ITEM_TYPE_FLEX: 7433 ret = flow_dv_validate_item_flex(dev, items, item_flags, 7434 &last_item, 7435 tunnel != 0, error); 7436 if (ret < 0) 7437 return ret; 7438 break; 7439 case RTE_FLOW_ITEM_TYPE_METER_COLOR: 7440 ret = flow_dv_validate_item_meter_color(dev, items, 7441 attr, error); 7442 if (ret < 0) 7443 return ret; 7444 last_item = MLX5_FLOW_ITEM_METER_COLOR; 7445 break; 7446 default: 7447 return rte_flow_error_set(error, ENOTSUP, 7448 RTE_FLOW_ERROR_TYPE_ITEM, 7449 NULL, "item not supported"); 7450 } 7451 item_flags |= last_item; 7452 } 7453 if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) { 7454 ret = flow_dv_validate_item_integrity_post(integrity_items, 7455 item_flags, error); 7456 if (ret) 7457 return ret; 7458 } 7459 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 7460 int type = actions->type; 7461 7462 if (!mlx5_flow_os_action_supported(type)) 7463 return rte_flow_error_set(error, ENOTSUP, 7464 RTE_FLOW_ERROR_TYPE_ACTION, 7465 actions, 7466 "action not supported"); 7467 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 7468 return rte_flow_error_set(error, ENOTSUP, 7469 RTE_FLOW_ERROR_TYPE_ACTION, 7470 actions, "too many actions"); 7471 if (action_flags & 7472 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 7473 return rte_flow_error_set(error, ENOTSUP, 7474 RTE_FLOW_ERROR_TYPE_ACTION, 7475 NULL, "meter action with policy " 7476 "must be the last action"); 7477 switch (type) { 7478 case RTE_FLOW_ACTION_TYPE_VOID: 7479 break; 7480 case RTE_FLOW_ACTION_TYPE_PORT_ID: 7481 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 7482 ret = flow_dv_validate_action_port_id(dev, 7483 action_flags, 7484 actions, 7485 attr, 7486 error); 7487 if (ret) 7488 return ret; 7489 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 7490 ++actions_n; 7491 break; 7492 case RTE_FLOW_ACTION_TYPE_FLAG: 7493 ret = flow_dv_validate_action_flag(dev, action_flags, 7494 attr, error); 7495 if (ret < 0) 7496 return ret; 7497 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7498 /* Count all modify-header actions as one. */ 7499 if (!(action_flags & 7500 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7501 ++actions_n; 7502 action_flags |= MLX5_FLOW_ACTION_FLAG | 7503 MLX5_FLOW_ACTION_MARK_EXT; 7504 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7505 modify_after_mirror = 1; 7506 7507 } else { 7508 action_flags |= MLX5_FLOW_ACTION_FLAG; 7509 ++actions_n; 7510 } 7511 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7512 break; 7513 case RTE_FLOW_ACTION_TYPE_MARK: 7514 ret = flow_dv_validate_action_mark(dev, actions, 7515 action_flags, 7516 attr, error); 7517 if (ret < 0) 7518 return ret; 7519 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7520 /* Count all modify-header actions as one. */ 7521 if (!(action_flags & 7522 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7523 ++actions_n; 7524 action_flags |= MLX5_FLOW_ACTION_MARK | 7525 MLX5_FLOW_ACTION_MARK_EXT; 7526 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7527 modify_after_mirror = 1; 7528 } else { 7529 action_flags |= MLX5_FLOW_ACTION_MARK; 7530 ++actions_n; 7531 } 7532 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7533 break; 7534 case RTE_FLOW_ACTION_TYPE_SET_META: 7535 ret = flow_dv_validate_action_set_meta(dev, actions, 7536 action_flags, 7537 attr, error); 7538 if (ret < 0) 7539 return ret; 7540 /* Count all modify-header actions as one action. */ 7541 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7542 ++actions_n; 7543 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7544 modify_after_mirror = 1; 7545 action_flags |= MLX5_FLOW_ACTION_SET_META; 7546 rw_act_num += MLX5_ACT_NUM_SET_META; 7547 break; 7548 case RTE_FLOW_ACTION_TYPE_SET_TAG: 7549 ret = flow_dv_validate_action_set_tag(dev, actions, 7550 action_flags, 7551 attr, error); 7552 if (ret < 0) 7553 return ret; 7554 /* Count all modify-header actions as one action. */ 7555 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7556 ++actions_n; 7557 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7558 modify_after_mirror = 1; 7559 tag_id = ((const struct rte_flow_action_set_tag *) 7560 actions->conf)->index; 7561 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 7562 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7563 break; 7564 case RTE_FLOW_ACTION_TYPE_DROP: 7565 ret = mlx5_flow_validate_action_drop(action_flags, 7566 attr, error); 7567 if (ret < 0) 7568 return ret; 7569 action_flags |= MLX5_FLOW_ACTION_DROP; 7570 ++actions_n; 7571 break; 7572 case RTE_FLOW_ACTION_TYPE_QUEUE: 7573 ret = mlx5_flow_validate_action_queue(actions, 7574 action_flags, dev, 7575 attr, error); 7576 if (ret < 0) 7577 return ret; 7578 queue_index = ((const struct rte_flow_action_queue *) 7579 (actions->conf))->index; 7580 action_flags |= MLX5_FLOW_ACTION_QUEUE; 7581 ++actions_n; 7582 break; 7583 case RTE_FLOW_ACTION_TYPE_RSS: 7584 rss = actions->conf; 7585 ret = mlx5_flow_validate_action_rss(actions, 7586 action_flags, dev, 7587 attr, item_flags, 7588 error); 7589 if (ret < 0) 7590 return ret; 7591 if (rss && sample_rss && 7592 (sample_rss->level != rss->level || 7593 sample_rss->types != rss->types)) 7594 return rte_flow_error_set(error, ENOTSUP, 7595 RTE_FLOW_ERROR_TYPE_ACTION, 7596 NULL, 7597 "Can't use the different RSS types " 7598 "or level in the same flow"); 7599 if (rss != NULL && rss->queue_num) 7600 queue_index = rss->queue[0]; 7601 action_flags |= MLX5_FLOW_ACTION_RSS; 7602 ++actions_n; 7603 break; 7604 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 7605 ret = 7606 mlx5_flow_validate_action_default_miss(action_flags, 7607 attr, error); 7608 if (ret < 0) 7609 return ret; 7610 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 7611 ++actions_n; 7612 break; 7613 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 7614 shared_count = true; 7615 /* fall-through. */ 7616 case RTE_FLOW_ACTION_TYPE_COUNT: 7617 ret = flow_dv_validate_action_count(dev, shared_count, 7618 action_flags, 7619 is_root, error); 7620 if (ret < 0) 7621 return ret; 7622 count = actions->conf; 7623 action_flags |= MLX5_FLOW_ACTION_COUNT; 7624 ++actions_n; 7625 break; 7626 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 7627 if (flow_dv_validate_action_pop_vlan(dev, 7628 action_flags, 7629 actions, 7630 item_flags, attr, 7631 error)) 7632 return -rte_errno; 7633 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7634 modify_after_mirror = 1; 7635 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 7636 ++actions_n; 7637 break; 7638 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 7639 ret = flow_dv_validate_action_push_vlan(dev, 7640 action_flags, 7641 vlan_m, 7642 actions, attr, 7643 error); 7644 if (ret < 0) 7645 return ret; 7646 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7647 modify_after_mirror = 1; 7648 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 7649 ++actions_n; 7650 break; 7651 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 7652 ret = flow_dv_validate_action_set_vlan_pcp 7653 (action_flags, actions, error); 7654 if (ret < 0) 7655 return ret; 7656 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7657 modify_after_mirror = 1; 7658 /* Count PCP with push_vlan command. */ 7659 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; 7660 break; 7661 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 7662 ret = flow_dv_validate_action_set_vlan_vid 7663 (item_flags, action_flags, 7664 actions, error); 7665 if (ret < 0) 7666 return ret; 7667 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7668 modify_after_mirror = 1; 7669 /* Count VID with push_vlan command. */ 7670 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 7671 rw_act_num += MLX5_ACT_NUM_MDF_VID; 7672 break; 7673 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 7674 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 7675 ret = flow_dv_validate_action_l2_encap(dev, 7676 action_flags, 7677 actions, attr, 7678 error); 7679 if (ret < 0) 7680 return ret; 7681 action_flags |= MLX5_FLOW_ACTION_ENCAP; 7682 ++actions_n; 7683 break; 7684 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 7685 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 7686 ret = flow_dv_validate_action_decap(dev, action_flags, 7687 actions, item_flags, 7688 attr, error); 7689 if (ret < 0) 7690 return ret; 7691 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7692 modify_after_mirror = 1; 7693 action_flags |= MLX5_FLOW_ACTION_DECAP; 7694 ++actions_n; 7695 break; 7696 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 7697 ret = flow_dv_validate_action_raw_encap_decap 7698 (dev, NULL, actions->conf, attr, &action_flags, 7699 &actions_n, actions, item_flags, error); 7700 if (ret < 0) 7701 return ret; 7702 break; 7703 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 7704 decap = actions->conf; 7705 while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID) 7706 ; 7707 if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 7708 encap = NULL; 7709 actions--; 7710 } else { 7711 encap = actions->conf; 7712 } 7713 ret = flow_dv_validate_action_raw_encap_decap 7714 (dev, 7715 decap ? decap : &empty_decap, encap, 7716 attr, &action_flags, &actions_n, 7717 actions, item_flags, error); 7718 if (ret < 0) 7719 return ret; 7720 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7721 (action_flags & MLX5_FLOW_ACTION_DECAP)) 7722 modify_after_mirror = 1; 7723 break; 7724 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 7725 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 7726 ret = flow_dv_validate_action_modify_mac(action_flags, 7727 actions, 7728 item_flags, 7729 error); 7730 if (ret < 0) 7731 return ret; 7732 /* Count all modify-header actions as one action. */ 7733 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7734 ++actions_n; 7735 action_flags |= actions->type == 7736 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 7737 MLX5_FLOW_ACTION_SET_MAC_SRC : 7738 MLX5_FLOW_ACTION_SET_MAC_DST; 7739 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7740 modify_after_mirror = 1; 7741 /* 7742 * Even if the source and destination MAC addresses have 7743 * overlap in the header with 4B alignment, the convert 7744 * function will handle them separately and 4 SW actions 7745 * will be created. And 2 actions will be added each 7746 * time no matter how many bytes of address will be set. 7747 */ 7748 rw_act_num += MLX5_ACT_NUM_MDF_MAC; 7749 break; 7750 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 7751 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 7752 ret = flow_dv_validate_action_modify_ipv4(action_flags, 7753 actions, 7754 item_flags, 7755 error); 7756 if (ret < 0) 7757 return ret; 7758 /* Count all modify-header actions as one action. */ 7759 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7760 ++actions_n; 7761 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7762 modify_after_mirror = 1; 7763 action_flags |= actions->type == 7764 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 7765 MLX5_FLOW_ACTION_SET_IPV4_SRC : 7766 MLX5_FLOW_ACTION_SET_IPV4_DST; 7767 rw_act_num += MLX5_ACT_NUM_MDF_IPV4; 7768 break; 7769 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 7770 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 7771 ret = flow_dv_validate_action_modify_ipv6(action_flags, 7772 actions, 7773 item_flags, 7774 error); 7775 if (ret < 0) 7776 return ret; 7777 if (item_ipv6_proto == IPPROTO_ICMPV6) 7778 return rte_flow_error_set(error, ENOTSUP, 7779 RTE_FLOW_ERROR_TYPE_ACTION, 7780 actions, 7781 "Can't change header " 7782 "with ICMPv6 proto"); 7783 /* Count all modify-header actions as one action. */ 7784 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7785 ++actions_n; 7786 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7787 modify_after_mirror = 1; 7788 action_flags |= actions->type == 7789 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 7790 MLX5_FLOW_ACTION_SET_IPV6_SRC : 7791 MLX5_FLOW_ACTION_SET_IPV6_DST; 7792 rw_act_num += MLX5_ACT_NUM_MDF_IPV6; 7793 break; 7794 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 7795 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 7796 ret = flow_dv_validate_action_modify_tp(action_flags, 7797 actions, 7798 item_flags, 7799 error); 7800 if (ret < 0) 7801 return ret; 7802 /* Count all modify-header actions as one action. */ 7803 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7804 ++actions_n; 7805 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7806 modify_after_mirror = 1; 7807 action_flags |= actions->type == 7808 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 7809 MLX5_FLOW_ACTION_SET_TP_SRC : 7810 MLX5_FLOW_ACTION_SET_TP_DST; 7811 rw_act_num += MLX5_ACT_NUM_MDF_PORT; 7812 break; 7813 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 7814 case RTE_FLOW_ACTION_TYPE_SET_TTL: 7815 ret = flow_dv_validate_action_modify_ttl(action_flags, 7816 actions, 7817 item_flags, 7818 error); 7819 if (ret < 0) 7820 return ret; 7821 /* Count all modify-header actions as one action. */ 7822 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7823 ++actions_n; 7824 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7825 modify_after_mirror = 1; 7826 action_flags |= actions->type == 7827 RTE_FLOW_ACTION_TYPE_SET_TTL ? 7828 MLX5_FLOW_ACTION_SET_TTL : 7829 MLX5_FLOW_ACTION_DEC_TTL; 7830 rw_act_num += MLX5_ACT_NUM_MDF_TTL; 7831 break; 7832 case RTE_FLOW_ACTION_TYPE_JUMP: 7833 ret = flow_dv_validate_action_jump(dev, tunnel, actions, 7834 action_flags, 7835 attr, external, 7836 error); 7837 if (ret) 7838 return ret; 7839 ++actions_n; 7840 action_flags |= MLX5_FLOW_ACTION_JUMP; 7841 break; 7842 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 7843 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 7844 ret = flow_dv_validate_action_modify_tcp_seq 7845 (action_flags, 7846 actions, 7847 item_flags, 7848 error); 7849 if (ret < 0) 7850 return ret; 7851 /* Count all modify-header actions as one action. */ 7852 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7853 ++actions_n; 7854 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7855 modify_after_mirror = 1; 7856 action_flags |= actions->type == 7857 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 7858 MLX5_FLOW_ACTION_INC_TCP_SEQ : 7859 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 7860 rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ; 7861 break; 7862 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 7863 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 7864 ret = flow_dv_validate_action_modify_tcp_ack 7865 (action_flags, 7866 actions, 7867 item_flags, 7868 error); 7869 if (ret < 0) 7870 return ret; 7871 /* Count all modify-header actions as one action. */ 7872 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7873 ++actions_n; 7874 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7875 modify_after_mirror = 1; 7876 action_flags |= actions->type == 7877 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 7878 MLX5_FLOW_ACTION_INC_TCP_ACK : 7879 MLX5_FLOW_ACTION_DEC_TCP_ACK; 7880 rw_act_num += MLX5_ACT_NUM_MDF_TCPACK; 7881 break; 7882 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 7883 break; 7884 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 7885 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 7886 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7887 break; 7888 case RTE_FLOW_ACTION_TYPE_METER: 7889 ret = mlx5_flow_validate_action_meter(dev, 7890 action_flags, 7891 item_flags, 7892 actions, attr, 7893 port_id_item, 7894 &def_policy, 7895 error); 7896 if (ret < 0) 7897 return ret; 7898 action_flags |= MLX5_FLOW_ACTION_METER; 7899 if (!def_policy) 7900 action_flags |= 7901 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 7902 ++actions_n; 7903 /* Meter action will add one more TAG action. */ 7904 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7905 break; 7906 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 7907 if (is_root) 7908 return rte_flow_error_set(error, ENOTSUP, 7909 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7910 NULL, 7911 "Shared ASO age action is not supported for group 0"); 7912 if (action_flags & MLX5_FLOW_ACTION_AGE) 7913 return rte_flow_error_set 7914 (error, EINVAL, 7915 RTE_FLOW_ERROR_TYPE_ACTION, 7916 NULL, 7917 "duplicate age actions set"); 7918 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7919 aso_after_sample = 1; 7920 action_flags |= MLX5_FLOW_ACTION_AGE; 7921 ++actions_n; 7922 break; 7923 case RTE_FLOW_ACTION_TYPE_AGE: 7924 non_shared_age = actions->conf; 7925 ret = flow_dv_validate_action_age(action_flags, 7926 actions, dev, 7927 error); 7928 if (ret < 0) 7929 return ret; 7930 /* 7931 * Validate the regular AGE action (using counter) 7932 * mutual exclusion with indirect counter actions. 7933 */ 7934 if (!flow_hit_aso_supported(priv, is_root)) { 7935 if (shared_count) 7936 return rte_flow_error_set 7937 (error, EINVAL, 7938 RTE_FLOW_ERROR_TYPE_ACTION, 7939 NULL, 7940 "old age and indirect count combination is not supported"); 7941 if (sample_count) 7942 return rte_flow_error_set 7943 (error, EINVAL, 7944 RTE_FLOW_ERROR_TYPE_ACTION, 7945 NULL, 7946 "old age action and count must be in the same sub flow"); 7947 } else { 7948 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7949 aso_after_sample = 1; 7950 } 7951 action_flags |= MLX5_FLOW_ACTION_AGE; 7952 ++actions_n; 7953 break; 7954 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 7955 ret = flow_dv_validate_action_modify_ipv4_dscp 7956 (action_flags, 7957 actions, 7958 item_flags, 7959 error); 7960 if (ret < 0) 7961 return ret; 7962 /* Count all modify-header actions as one action. */ 7963 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7964 ++actions_n; 7965 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7966 modify_after_mirror = 1; 7967 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 7968 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7969 break; 7970 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 7971 ret = flow_dv_validate_action_modify_ipv6_dscp 7972 (action_flags, 7973 actions, 7974 item_flags, 7975 error); 7976 if (ret < 0) 7977 return ret; 7978 /* Count all modify-header actions as one action. */ 7979 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7980 ++actions_n; 7981 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7982 modify_after_mirror = 1; 7983 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 7984 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7985 break; 7986 case RTE_FLOW_ACTION_TYPE_SAMPLE: 7987 ret = flow_dv_validate_action_sample(&action_flags, 7988 actions, dev, 7989 attr, item_flags, 7990 rss, &sample_rss, 7991 &sample_count, 7992 &fdb_mirror, 7993 is_root, 7994 error); 7995 if (ret < 0) 7996 return ret; 7997 if ((action_flags & MLX5_FLOW_ACTION_SET_TAG) && 7998 tag_id == 0 && priv->mtr_color_reg == REG_NON) 7999 return rte_flow_error_set(error, EINVAL, 8000 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8001 "sample after tag action causes metadata tag index 0 corruption"); 8002 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 8003 ++actions_n; 8004 break; 8005 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 8006 ret = flow_dv_validate_action_modify_field(dev, 8007 action_flags, 8008 actions, 8009 attr, 8010 is_root, 8011 error); 8012 if (ret < 0) 8013 return ret; 8014 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 8015 modify_after_mirror = 1; 8016 /* Count all modify-header actions as one action. */ 8017 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 8018 ++actions_n; 8019 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 8020 rw_act_num += ret; 8021 break; 8022 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 8023 ret = flow_dv_validate_action_aso_ct(dev, action_flags, 8024 item_flags, 8025 is_root, error); 8026 if (ret < 0) 8027 return ret; 8028 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 8029 aso_after_sample = 1; 8030 action_flags |= MLX5_FLOW_ACTION_CT; 8031 break; 8032 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 8033 /* tunnel offload action was processed before 8034 * list it here as a supported type 8035 */ 8036 break; 8037 #ifdef HAVE_MLX5DV_DR_ACTION_CREATE_DEST_ROOT_TABLE 8038 case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL: 8039 action_flags |= MLX5_FLOW_ACTION_SEND_TO_KERNEL; 8040 ++actions_n; 8041 break; 8042 #endif 8043 default: 8044 return rte_flow_error_set(error, ENOTSUP, 8045 RTE_FLOW_ERROR_TYPE_ACTION, 8046 actions, 8047 "action not supported"); 8048 } 8049 } 8050 /* 8051 * Validate actions in flow rules 8052 * - Explicit decap action is prohibited by the tunnel offload API. 8053 * - Drop action in tunnel steer rule is prohibited by the API. 8054 * - Application cannot use MARK action because it's value can mask 8055 * tunnel default miss notification. 8056 * - JUMP in tunnel match rule has no support in current PMD 8057 * implementation. 8058 * - TAG & META are reserved for future uses. 8059 */ 8060 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) { 8061 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP | 8062 MLX5_FLOW_ACTION_MARK | 8063 MLX5_FLOW_ACTION_SET_TAG | 8064 MLX5_FLOW_ACTION_SET_META | 8065 MLX5_FLOW_ACTION_DROP; 8066 8067 if (action_flags & bad_actions_mask) 8068 return rte_flow_error_set 8069 (error, EINVAL, 8070 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8071 "Invalid RTE action in tunnel " 8072 "set decap rule"); 8073 if (!(action_flags & MLX5_FLOW_ACTION_JUMP)) 8074 return rte_flow_error_set 8075 (error, EINVAL, 8076 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8077 "tunnel set decap rule must terminate " 8078 "with JUMP"); 8079 if (attr->egress) 8080 return rte_flow_error_set 8081 (error, EINVAL, 8082 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8083 "tunnel flows for ingress and transfer traffic only"); 8084 } 8085 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) { 8086 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP | 8087 MLX5_FLOW_ACTION_MARK | 8088 MLX5_FLOW_ACTION_SET_TAG | 8089 MLX5_FLOW_ACTION_SET_META; 8090 8091 if (action_flags & bad_actions_mask) 8092 return rte_flow_error_set 8093 (error, EINVAL, 8094 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8095 "Invalid RTE action in tunnel " 8096 "set match rule"); 8097 } 8098 /* 8099 * Validate the drop action mutual exclusion with other actions. 8100 * Drop action is mutually-exclusive with any other action, except for 8101 * Count/Sample/Age actions. 8102 * Drop action compatibility with tunnel offload was already validated. 8103 */ 8104 if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH | 8105 MLX5_FLOW_ACTION_TUNNEL_MATCH)); 8106 else if ((action_flags & MLX5_FLOW_ACTION_DROP) && 8107 (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_DROP_INCLUSIVE_ACTIONS))) 8108 return rte_flow_error_set(error, EINVAL, 8109 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8110 "Drop action is mutually-exclusive " 8111 "with any other action, except for " 8112 "Count/Sample/Age action"); 8113 /* Eswitch has few restrictions on using items and actions */ 8114 if (attr->transfer) { 8115 if (!mlx5_flow_ext_mreg_supported(dev) && 8116 action_flags & MLX5_FLOW_ACTION_FLAG) 8117 return rte_flow_error_set(error, ENOTSUP, 8118 RTE_FLOW_ERROR_TYPE_ACTION, 8119 NULL, 8120 "unsupported action FLAG"); 8121 if (!mlx5_flow_ext_mreg_supported(dev) && 8122 action_flags & MLX5_FLOW_ACTION_MARK) 8123 return rte_flow_error_set(error, ENOTSUP, 8124 RTE_FLOW_ERROR_TYPE_ACTION, 8125 NULL, 8126 "unsupported action MARK"); 8127 if (action_flags & MLX5_FLOW_ACTION_QUEUE) 8128 return rte_flow_error_set(error, ENOTSUP, 8129 RTE_FLOW_ERROR_TYPE_ACTION, 8130 NULL, 8131 "unsupported action QUEUE"); 8132 if (action_flags & MLX5_FLOW_ACTION_RSS) 8133 return rte_flow_error_set(error, ENOTSUP, 8134 RTE_FLOW_ERROR_TYPE_ACTION, 8135 NULL, 8136 "unsupported action RSS"); 8137 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 8138 return rte_flow_error_set(error, EINVAL, 8139 RTE_FLOW_ERROR_TYPE_ACTION, 8140 actions, 8141 "no fate action is found"); 8142 } else { 8143 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) 8144 return rte_flow_error_set(error, EINVAL, 8145 RTE_FLOW_ERROR_TYPE_ACTION, 8146 actions, 8147 "no fate action is found"); 8148 } 8149 /* 8150 * Continue validation for Xcap and VLAN actions. 8151 * If hairpin is working in explicit TX rule mode, there is no actions 8152 * splitting and the validation of hairpin ingress flow should be the 8153 * same as other standard flows. 8154 */ 8155 if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS | 8156 MLX5_FLOW_VLAN_ACTIONS)) && 8157 (queue_index == 0xFFFF || !mlx5_rxq_is_hairpin(dev, queue_index) || 8158 ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL && 8159 conf->tx_explicit != 0))) { 8160 if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) == 8161 MLX5_FLOW_XCAP_ACTIONS) 8162 return rte_flow_error_set(error, ENOTSUP, 8163 RTE_FLOW_ERROR_TYPE_ACTION, 8164 NULL, "encap and decap " 8165 "combination aren't supported"); 8166 /* Push VLAN is not supported in ingress except for NICs newer than CX5. */ 8167 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) { 8168 struct mlx5_dev_ctx_shared *sh = priv->sh; 8169 bool direction_error = false; 8170 8171 if (attr->transfer) { 8172 bool fdb_tx = flow_source_vport_representor(priv, act_priv); 8173 bool is_cx5 = sh->steering_format_version == 8174 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 8175 8176 if (!fdb_tx && is_cx5) 8177 direction_error = true; 8178 } else if (attr->ingress) { 8179 direction_error = true; 8180 } 8181 if (direction_error) 8182 return rte_flow_error_set(error, ENOTSUP, 8183 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 8184 NULL, 8185 "push VLAN action not supported " 8186 "for ingress"); 8187 } 8188 if (attr->ingress) { 8189 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 8190 return rte_flow_error_set 8191 (error, ENOTSUP, 8192 RTE_FLOW_ERROR_TYPE_ACTION, 8193 NULL, "encap is not supported" 8194 " for ingress traffic"); 8195 else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) == 8196 MLX5_FLOW_VLAN_ACTIONS) 8197 return rte_flow_error_set 8198 (error, ENOTSUP, 8199 RTE_FLOW_ERROR_TYPE_ACTION, 8200 NULL, "no support for " 8201 "multiple VLAN actions"); 8202 } 8203 } 8204 /* Pop VLAN is not supported in egress except for NICs newer than CX5. */ 8205 if (action_flags & MLX5_FLOW_ACTION_OF_POP_VLAN) { 8206 struct mlx5_dev_ctx_shared *sh = priv->sh; 8207 bool direction_error = false; 8208 8209 if (attr->transfer) { 8210 bool fdb_tx = flow_source_vport_representor(priv, act_priv); 8211 bool is_cx5 = sh->steering_format_version == 8212 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 8213 8214 if (fdb_tx && is_cx5) 8215 direction_error = true; 8216 } else if (attr->egress) { 8217 direction_error = true; 8218 } 8219 if (direction_error) 8220 return rte_flow_error_set(error, ENOTSUP, 8221 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 8222 NULL, 8223 "pop vlan action not supported for egress"); 8224 } 8225 if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) { 8226 if ((action_flags & (MLX5_FLOW_FATE_ACTIONS & 8227 ~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) && 8228 attr->ingress) 8229 return rte_flow_error_set 8230 (error, ENOTSUP, 8231 RTE_FLOW_ERROR_TYPE_ACTION, 8232 NULL, "fate action not supported for " 8233 "meter with policy"); 8234 if (attr->egress) { 8235 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 8236 return rte_flow_error_set 8237 (error, ENOTSUP, 8238 RTE_FLOW_ERROR_TYPE_ACTION, 8239 NULL, "modify header action in egress " 8240 "cannot be done before meter action"); 8241 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 8242 return rte_flow_error_set 8243 (error, ENOTSUP, 8244 RTE_FLOW_ERROR_TYPE_ACTION, 8245 NULL, "encap action in egress " 8246 "cannot be done before meter action"); 8247 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 8248 return rte_flow_error_set 8249 (error, ENOTSUP, 8250 RTE_FLOW_ERROR_TYPE_ACTION, 8251 NULL, "push vlan action in egress " 8252 "cannot be done before meter action"); 8253 } 8254 } 8255 /* 8256 * Only support one ASO action in a single flow rule. 8257 * non-shared AGE + counter will fallback to use HW counter, no ASO hit object. 8258 * Group 0 uses HW counter for AGE too even if no counter action. 8259 */ 8260 aso_mask = (action_flags & MLX5_FLOW_ACTION_METER && priv->sh->meter_aso_en) << 2 | 8261 (action_flags & MLX5_FLOW_ACTION_CT && priv->sh->ct_aso_en) << 1 | 8262 (action_flags & MLX5_FLOW_ACTION_AGE && 8263 !(non_shared_age && count) && 8264 (attr->group || (attr->transfer && priv->fdb_def_rule)) && 8265 priv->sh->flow_hit_aso_en); 8266 if (__builtin_popcountl(aso_mask) > 1) 8267 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, 8268 NULL, "unsupported combining AGE, METER, CT ASO actions in a single rule"); 8269 /* 8270 * Hairpin flow will add one more TAG action in TX implicit mode. 8271 * In TX explicit mode, there will be no hairpin flow ID. 8272 */ 8273 if (hairpin > 0) 8274 rw_act_num += MLX5_ACT_NUM_SET_TAG; 8275 /* extra metadata enabled: one more TAG action will be add. */ 8276 if (dev_conf->dv_flow_en && 8277 dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 8278 mlx5_flow_ext_mreg_supported(dev)) 8279 rw_act_num += MLX5_ACT_NUM_SET_TAG; 8280 if (rw_act_num > 8281 flow_dv_modify_hdr_action_max(dev, is_root)) { 8282 return rte_flow_error_set(error, ENOTSUP, 8283 RTE_FLOW_ERROR_TYPE_ACTION, 8284 NULL, "too many header modify" 8285 " actions to support"); 8286 } 8287 if (fdb_mirror) { 8288 if (!priv->sh->cdev->config.hca_attr.reg_c_preserve && 8289 flow_source_vport_representor(priv, act_priv)) { 8290 /* Eswitch egress mirror and modify flow has limitation on CX5 */ 8291 if (modify_after_mirror) 8292 return rte_flow_error_set(error, EINVAL, 8293 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8294 "sample before modify action is not supported"); 8295 if (action_flags & MLX5_FLOW_ACTION_JUMP) 8296 return rte_flow_error_set(error, EINVAL, 8297 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8298 "sample and jump action combination is not supported"); 8299 } 8300 if (aso_mask > 0 && aso_after_sample && fdb_mirror) 8301 return rte_flow_error_set(error, ENOTSUP, 8302 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8303 "sample before ASO action is not supported"); 8304 } 8305 /* 8306 * Validation the NIC Egress flow on representor, except implicit 8307 * hairpin default egress flow with TX_QUEUE item, other flows not 8308 * work due to metadata regC0 mismatch. 8309 */ 8310 if (attr->egress && priv->representor && !(item_flags & MLX5_FLOW_ITEM_SQ)) 8311 return rte_flow_error_set(error, EINVAL, 8312 RTE_FLOW_ERROR_TYPE_ITEM, 8313 NULL, 8314 "NIC egress rules on representors" 8315 " is not supported"); 8316 return 0; 8317 } 8318 8319 /** 8320 * Internal preparation function. Allocates the DV flow size, 8321 * this size is constant. 8322 * 8323 * @param[in] dev 8324 * Pointer to the rte_eth_dev structure. 8325 * @param[in] attr 8326 * Pointer to the flow attributes. 8327 * @param[in] items 8328 * Pointer to the list of items. 8329 * @param[in] actions 8330 * Pointer to the list of actions. 8331 * @param[out] error 8332 * Pointer to the error structure. 8333 * 8334 * @return 8335 * Pointer to mlx5_flow object on success, 8336 * otherwise NULL and rte_errno is set. 8337 */ 8338 static struct mlx5_flow * 8339 flow_dv_prepare(struct rte_eth_dev *dev, 8340 const struct rte_flow_attr *attr __rte_unused, 8341 const struct rte_flow_item items[] __rte_unused, 8342 const struct rte_flow_action actions[] __rte_unused, 8343 struct rte_flow_error *error) 8344 { 8345 uint32_t handle_idx = 0; 8346 struct mlx5_flow *dev_flow; 8347 struct mlx5_flow_handle *dev_handle; 8348 struct mlx5_priv *priv = dev->data->dev_private; 8349 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 8350 8351 MLX5_ASSERT(wks); 8352 wks->skip_matcher_reg = 0; 8353 wks->policy = NULL; 8354 wks->final_policy = NULL; 8355 wks->vport_meta_tag = 0; 8356 /* In case of corrupting the memory. */ 8357 if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) { 8358 rte_flow_error_set(error, ENOSPC, 8359 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8360 "not free temporary device flow"); 8361 return NULL; 8362 } 8363 dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 8364 &handle_idx); 8365 if (!dev_handle) { 8366 rte_flow_error_set(error, ENOMEM, 8367 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8368 "not enough memory to create flow handle"); 8369 return NULL; 8370 } 8371 MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows)); 8372 dev_flow = &wks->flows[wks->flow_idx++]; 8373 memset(dev_flow, 0, sizeof(*dev_flow)); 8374 dev_flow->handle = dev_handle; 8375 dev_flow->handle_idx = handle_idx; 8376 dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 8377 dev_flow->ingress = attr->ingress; 8378 dev_flow->dv.transfer = attr->transfer; 8379 return dev_flow; 8380 } 8381 8382 #ifdef RTE_LIBRTE_MLX5_DEBUG 8383 /** 8384 * Sanity check for match mask and value. Similar to check_valid_spec() in 8385 * kernel driver. If unmasked bit is present in value, it returns failure. 8386 * 8387 * @param match_mask 8388 * pointer to match mask buffer. 8389 * @param match_value 8390 * pointer to match value buffer. 8391 * 8392 * @return 8393 * 0 if valid, -EINVAL otherwise. 8394 */ 8395 static int 8396 flow_dv_check_valid_spec(void *match_mask, void *match_value) 8397 { 8398 uint8_t *m = match_mask; 8399 uint8_t *v = match_value; 8400 unsigned int i; 8401 8402 for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) { 8403 if (v[i] & ~m[i]) { 8404 DRV_LOG(ERR, 8405 "match_value differs from match_criteria" 8406 " %p[%u] != %p[%u]", 8407 match_value, i, match_mask, i); 8408 return -EINVAL; 8409 } 8410 } 8411 return 0; 8412 } 8413 #endif 8414 8415 /** 8416 * Add match of ip_version. 8417 * 8418 * @param[in] group 8419 * Flow group. 8420 * @param[in] headers_v 8421 * Values header pointer. 8422 * @param[in] headers_m 8423 * Masks header pointer. 8424 * @param[in] ip_version 8425 * The IP version to set. 8426 */ 8427 static inline void 8428 flow_dv_set_match_ip_version(uint32_t group, 8429 void *headers_v, 8430 uint32_t key_type, 8431 uint8_t ip_version) 8432 { 8433 if (group == 0 && (key_type & MLX5_SET_MATCHER_M)) 8434 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 0xf); 8435 else 8436 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 8437 ip_version); 8438 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0); 8439 } 8440 8441 /** 8442 * Add Ethernet item to the value. 8443 * 8444 * @param[in, out] key 8445 * Flow matcher value. 8446 * @param[in] item 8447 * Flow pattern to translate. 8448 * @param[in] inner 8449 * Item is inner pattern. 8450 * @param[in] grpup 8451 * Flow matcher group. 8452 * @param[in] key_type 8453 * Set flow matcher mask or value. 8454 */ 8455 static void 8456 flow_dv_translate_item_eth(void *key, const struct rte_flow_item *item, 8457 int inner, uint32_t group, uint32_t key_type) 8458 { 8459 const struct rte_flow_item_eth *eth_vv = item->spec; 8460 const struct rte_flow_item_eth *eth_m; 8461 const struct rte_flow_item_eth *eth_v; 8462 const struct rte_flow_item_eth nic_mask = { 8463 .hdr.dst_addr.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8464 .hdr.src_addr.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8465 .hdr.ether_type = RTE_BE16(0xffff), 8466 .has_vlan = 0, 8467 }; 8468 void *hdrs_v; 8469 char *l24_v; 8470 unsigned int i; 8471 8472 if (MLX5_ITEM_VALID(item, key_type)) 8473 return; 8474 MLX5_ITEM_UPDATE(item, key_type, eth_v, eth_m, &nic_mask); 8475 if (!eth_vv) 8476 eth_vv = eth_v; 8477 if (inner) 8478 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8479 else 8480 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8481 /* The value must be in the range of the mask. */ 8482 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16); 8483 for (i = 0; i < sizeof(eth_m->hdr.dst_addr); ++i) 8484 l24_v[i] = eth_m->hdr.dst_addr.addr_bytes[i] & eth_v->hdr.dst_addr.addr_bytes[i]; 8485 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16); 8486 /* The value must be in the range of the mask. */ 8487 for (i = 0; i < sizeof(eth_m->hdr.dst_addr); ++i) 8488 l24_v[i] = eth_m->hdr.src_addr.addr_bytes[i] & eth_v->hdr.src_addr.addr_bytes[i]; 8489 /* 8490 * HW supports match on one Ethertype, the Ethertype following the last 8491 * VLAN tag of the packet (see PRM). 8492 * Set match on ethertype only if ETH header is not followed by VLAN. 8493 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8494 * ethertype, and use ip_version field instead. 8495 * eCPRI over Ether layer will use type value 0xAEFE. 8496 */ 8497 if (eth_m->hdr.ether_type == 0xFFFF) { 8498 rte_be16_t type = eth_v->hdr.ether_type; 8499 8500 /* 8501 * When set the matcher mask, refer to the original spec 8502 * value. 8503 */ 8504 if (key_type == MLX5_SET_MATCHER_SW_M) { 8505 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8506 type = eth_vv->hdr.ether_type; 8507 } 8508 /* Set cvlan_tag mask for any single\multi\un-tagged case. */ 8509 switch (type) { 8510 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8511 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8512 return; 8513 case RTE_BE16(RTE_ETHER_TYPE_QINQ): 8514 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8515 return; 8516 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8517 flow_dv_set_match_ip_version(group, hdrs_v, key_type, 8518 4); 8519 return; 8520 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8521 flow_dv_set_match_ip_version(group, hdrs_v, key_type, 8522 6); 8523 return; 8524 default: 8525 break; 8526 } 8527 } 8528 /* 8529 * Only SW steering value should refer to the mask value. 8530 * Other cases are using the fake masks, just ignore the mask. 8531 */ 8532 if (eth_v->has_vlan && eth_m->has_vlan) { 8533 /* 8534 * Here, when also has_more_vlan field in VLAN item is 8535 * not set, only single-tagged packets will be matched. 8536 */ 8537 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8538 if (key_type != MLX5_SET_MATCHER_HS_M && eth_vv->has_vlan) 8539 return; 8540 } 8541 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 8542 *(uint16_t *)(l24_v) = eth_m->hdr.ether_type & eth_v->hdr.ether_type; 8543 } 8544 8545 /** 8546 * Add VLAN item to the value. 8547 * 8548 * @param[in, out] key 8549 * Flow matcher value. 8550 * @param[in] item 8551 * Flow pattern to translate. 8552 * @param[in] inner 8553 * Item is inner pattern. 8554 * @param[in] wks 8555 * Item workspace. 8556 * @param[in] key_type 8557 * Set flow matcher mask or value. 8558 */ 8559 static void 8560 flow_dv_translate_item_vlan(void *key, const struct rte_flow_item *item, 8561 int inner, struct mlx5_dv_matcher_workspace *wks, 8562 uint32_t key_type) 8563 { 8564 const struct rte_flow_item_vlan *vlan_m; 8565 const struct rte_flow_item_vlan *vlan_v; 8566 const struct rte_flow_item_vlan *vlan_vv = item->spec; 8567 void *hdrs_v; 8568 uint16_t tci_v; 8569 8570 if (inner) { 8571 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8572 } else { 8573 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8574 /* 8575 * This is workaround, masks are not supported, 8576 * and pre-validated. 8577 */ 8578 if (vlan_vv) 8579 wks->vlan_tag = rte_be_to_cpu_16(vlan_vv->hdr.vlan_tci) & 0x0fff; 8580 } 8581 /* 8582 * When VLAN item exists in flow, mark packet as tagged, 8583 * even if TCI is not specified. 8584 */ 8585 if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) 8586 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8587 if (MLX5_ITEM_VALID(item, key_type)) 8588 return; 8589 MLX5_ITEM_UPDATE(item, key_type, vlan_v, vlan_m, 8590 &rte_flow_item_vlan_mask); 8591 tci_v = rte_be_to_cpu_16(vlan_m->hdr.vlan_tci & vlan_v->hdr.vlan_tci); 8592 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v); 8593 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12); 8594 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13); 8595 /* 8596 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8597 * ethertype, and use ip_version field instead. 8598 */ 8599 if (vlan_m->hdr.eth_proto == 0xFFFF) { 8600 rte_be16_t inner_type = vlan_v->hdr.eth_proto; 8601 8602 /* 8603 * When set the matcher mask, refer to the original spec 8604 * value. 8605 */ 8606 if (key_type == MLX5_SET_MATCHER_SW_M) 8607 inner_type = vlan_vv->hdr.eth_proto; 8608 switch (inner_type) { 8609 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8610 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8611 if (key_type & MLX5_SET_MATCHER_V) 8612 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, 8613 cvlan_tag, 0); 8614 return; 8615 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8616 flow_dv_set_match_ip_version 8617 (wks->group, hdrs_v, key_type, 4); 8618 return; 8619 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8620 flow_dv_set_match_ip_version 8621 (wks->group, hdrs_v, key_type, 6); 8622 return; 8623 default: 8624 break; 8625 } 8626 } 8627 if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) { 8628 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8629 /* Only one vlan_tag bit can be set. */ 8630 if (key_type & MLX5_SET_MATCHER_V) 8631 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8632 return; 8633 } 8634 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype, 8635 rte_be_to_cpu_16(vlan_m->hdr.eth_proto & vlan_v->hdr.eth_proto)); 8636 } 8637 8638 /** 8639 * Add IPV4 item to the value. 8640 * 8641 * @param[in, out] key 8642 * Flow matcher value. 8643 * @param[in] item 8644 * Flow pattern to translate. 8645 * @param[in] inner 8646 * Item is inner pattern. 8647 * @param[in] group 8648 * The group to insert the rule. 8649 * @param[in] key_type 8650 * Set flow matcher mask or value. 8651 */ 8652 static void 8653 flow_dv_translate_item_ipv4(void *key, const struct rte_flow_item *item, 8654 int inner, uint32_t group, uint32_t key_type) 8655 { 8656 const struct rte_flow_item_ipv4 *ipv4_m; 8657 const struct rte_flow_item_ipv4 *ipv4_v; 8658 const struct rte_flow_item_ipv4 nic_mask = { 8659 .hdr = { 8660 .src_addr = RTE_BE32(0xffffffff), 8661 .dst_addr = RTE_BE32(0xffffffff), 8662 .type_of_service = 0xff, 8663 .next_proto_id = 0xff, 8664 .time_to_live = 0xff, 8665 }, 8666 }; 8667 void *headers_v; 8668 char *l24_v; 8669 uint8_t tos; 8670 8671 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8672 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8673 flow_dv_set_match_ip_version(group, headers_v, key_type, 4); 8674 if (MLX5_ITEM_VALID(item, key_type)) 8675 return; 8676 MLX5_ITEM_UPDATE(item, key_type, ipv4_v, ipv4_m, &nic_mask); 8677 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8678 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8679 *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr; 8680 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8681 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8682 *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr; 8683 tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service; 8684 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, 8685 ipv4_v->hdr.ihl & ipv4_m->hdr.ihl); 8686 if (key_type == MLX5_SET_MATCHER_SW_M) 8687 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, 8688 ipv4_v->hdr.type_of_service); 8689 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos); 8690 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2); 8691 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8692 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id); 8693 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8694 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live); 8695 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8696 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset)); 8697 } 8698 8699 /** 8700 * Add IPV6 item to the value. 8701 * 8702 * @param[in, out] key 8703 * Flow matcher value. 8704 * @param[in] item 8705 * Flow pattern to translate. 8706 * @param[in] inner 8707 * Item is inner pattern. 8708 * @param[in] group 8709 * The group to insert the rule. 8710 * @param[in] key_type 8711 * Set flow matcher mask or value. 8712 */ 8713 static void 8714 flow_dv_translate_item_ipv6(void *key, const struct rte_flow_item *item, 8715 int inner, uint32_t group, uint32_t key_type) 8716 { 8717 const struct rte_flow_item_ipv6 *ipv6_m; 8718 const struct rte_flow_item_ipv6 *ipv6_v; 8719 const struct rte_flow_item_ipv6 nic_mask = { 8720 .hdr = { 8721 .src_addr = 8722 "\xff\xff\xff\xff\xff\xff\xff\xff" 8723 "\xff\xff\xff\xff\xff\xff\xff\xff", 8724 .dst_addr = 8725 "\xff\xff\xff\xff\xff\xff\xff\xff" 8726 "\xff\xff\xff\xff\xff\xff\xff\xff", 8727 .vtc_flow = RTE_BE32(0xffffffff), 8728 .proto = 0xff, 8729 .hop_limits = 0xff, 8730 }, 8731 }; 8732 void *headers_v; 8733 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8734 char *l24_v; 8735 uint32_t vtc_v; 8736 int i; 8737 int size; 8738 8739 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8740 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8741 flow_dv_set_match_ip_version(group, headers_v, key_type, 6); 8742 if (MLX5_ITEM_VALID(item, key_type)) 8743 return; 8744 MLX5_ITEM_UPDATE(item, key_type, ipv6_v, ipv6_m, &nic_mask); 8745 size = sizeof(ipv6_m->hdr.dst_addr); 8746 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8747 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8748 for (i = 0; i < size; ++i) 8749 l24_v[i] = ipv6_m->hdr.dst_addr[i] & ipv6_v->hdr.dst_addr[i]; 8750 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8751 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8752 for (i = 0; i < size; ++i) 8753 l24_v[i] = ipv6_m->hdr.src_addr[i] & ipv6_v->hdr.src_addr[i]; 8754 /* TOS. */ 8755 vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow); 8756 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20); 8757 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22); 8758 /* Label. */ 8759 if (inner) 8760 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label, 8761 vtc_v); 8762 else 8763 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label, 8764 vtc_v); 8765 /* Protocol. */ 8766 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8767 ipv6_v->hdr.proto & ipv6_m->hdr.proto); 8768 /* Hop limit. */ 8769 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8770 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits); 8771 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8772 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext)); 8773 } 8774 8775 /** 8776 * Add IPV6 fragment extension item to the value. 8777 * 8778 * @param[in, out] key 8779 * Flow matcher value. 8780 * @param[in] item 8781 * Flow pattern to translate. 8782 * @param[in] inner 8783 * Item is inner pattern. 8784 * @param[in] key_type 8785 * Set flow matcher mask or value. 8786 */ 8787 static void 8788 flow_dv_translate_item_ipv6_frag_ext(void *key, 8789 const struct rte_flow_item *item, 8790 int inner, uint32_t key_type) 8791 { 8792 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m; 8793 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v; 8794 const struct rte_flow_item_ipv6_frag_ext nic_mask = { 8795 .hdr = { 8796 .next_header = 0xff, 8797 .frag_data = RTE_BE16(0xffff), 8798 }, 8799 }; 8800 void *headers_v; 8801 8802 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8803 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8804 /* IPv6 fragment extension item exists, so packet is IP fragment. */ 8805 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1); 8806 if (MLX5_ITEM_VALID(item, key_type)) 8807 return; 8808 MLX5_ITEM_UPDATE(item, key_type, ipv6_frag_ext_v, 8809 ipv6_frag_ext_m, &nic_mask); 8810 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8811 ipv6_frag_ext_v->hdr.next_header & 8812 ipv6_frag_ext_m->hdr.next_header); 8813 } 8814 8815 /** 8816 * Add TCP item to the value. 8817 * 8818 * @param[in, out] key 8819 * Flow matcher value. 8820 * @param[in] item 8821 * Flow pattern to translate. 8822 * @param[in] inner 8823 * Item is inner pattern. 8824 * @param[in] key_type 8825 * Set flow matcher mask or value. 8826 */ 8827 static void 8828 flow_dv_translate_item_tcp(void *key, const struct rte_flow_item *item, 8829 int inner, uint32_t key_type) 8830 { 8831 const struct rte_flow_item_tcp *tcp_m; 8832 const struct rte_flow_item_tcp *tcp_v; 8833 void *headers_v; 8834 8835 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8836 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8837 if (key_type & MLX5_SET_MATCHER_M) 8838 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8839 ip_protocol, 0xff); 8840 else 8841 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8842 ip_protocol, IPPROTO_TCP); 8843 if (MLX5_ITEM_VALID(item, key_type)) 8844 return; 8845 MLX5_ITEM_UPDATE(item, key_type, tcp_v, tcp_m, 8846 &rte_flow_item_tcp_mask); 8847 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, 8848 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port)); 8849 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, 8850 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port)); 8851 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, 8852 tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags); 8853 } 8854 8855 /** 8856 * Add ESP item to the value. 8857 * 8858 * @param[in, out] key 8859 * Flow matcher value. 8860 * @param[in] item 8861 * Flow pattern to translate. 8862 * @param[in] inner 8863 * Item is inner pattern. 8864 * @param[in] key_type 8865 * Set flow matcher mask or value. 8866 */ 8867 static void 8868 flow_dv_translate_item_esp(void *key, const struct rte_flow_item *item, 8869 int inner, uint32_t key_type) 8870 { 8871 const struct rte_flow_item_esp *esp_m; 8872 const struct rte_flow_item_esp *esp_v; 8873 void *headers_v; 8874 char *spi_v; 8875 8876 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8877 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8878 if (key_type & MLX5_SET_MATCHER_M) 8879 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8880 ip_protocol, 0xff); 8881 else 8882 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8883 ip_protocol, IPPROTO_ESP); 8884 if (MLX5_ITEM_VALID(item, key_type)) 8885 return; 8886 MLX5_ITEM_UPDATE(item, key_type, esp_v, esp_m, 8887 &rte_flow_item_esp_mask); 8888 headers_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8889 spi_v = inner ? MLX5_ADDR_OF(fte_match_set_misc, headers_v, 8890 inner_esp_spi) : MLX5_ADDR_OF(fte_match_set_misc 8891 , headers_v, outer_esp_spi); 8892 *(uint32_t *)spi_v = esp_m->hdr.spi & esp_v->hdr.spi; 8893 } 8894 8895 /** 8896 * Add UDP item to the value. 8897 * 8898 * @param[in, out] key 8899 * Flow matcher value. 8900 * @param[in] item 8901 * Flow pattern to translate. 8902 * @param[in] inner 8903 * Item is inner pattern. 8904 * @param[in] key_type 8905 * Set flow matcher mask or value. 8906 */ 8907 static void 8908 flow_dv_translate_item_udp(void *key, const struct rte_flow_item *item, 8909 int inner, struct mlx5_dv_matcher_workspace *wks, 8910 uint32_t key_type) 8911 { 8912 const struct rte_flow_item_udp *udp_m; 8913 const struct rte_flow_item_udp *udp_v; 8914 void *headers_v; 8915 8916 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 8917 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8918 if (key_type & MLX5_SET_MATCHER_M) 8919 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8920 ip_protocol, 0xff); 8921 else 8922 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 8923 ip_protocol, IPPROTO_UDP); 8924 if (MLX5_ITEM_VALID(item, key_type)) 8925 return; 8926 MLX5_ITEM_UPDATE(item, key_type, udp_v, udp_m, 8927 &rte_flow_item_udp_mask); 8928 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, 8929 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port)); 8930 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 8931 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port)); 8932 /* Force get UDP dport in case to be used in VXLAN translate. */ 8933 if (key_type & MLX5_SET_MATCHER_SW) { 8934 udp_v = item->spec; 8935 wks->udp_dport = rte_be_to_cpu_16(udp_v->hdr.dst_port & 8936 udp_m->hdr.dst_port); 8937 } 8938 } 8939 8940 /** 8941 * Add GRE optional Key item to the value. 8942 * 8943 * @param[in, out] key 8944 * Flow matcher value. 8945 * @param[in] item 8946 * Flow pattern to translate. 8947 * @param[in] inner 8948 * Item is inner pattern. 8949 */ 8950 static void 8951 flow_dv_translate_item_gre_key(void *key, const struct rte_flow_item *item, 8952 uint32_t key_type) 8953 { 8954 const rte_be32_t *key_m; 8955 const rte_be32_t *key_v; 8956 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8957 rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX); 8958 8959 /* GRE K bit must be on and should already be validated */ 8960 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1); 8961 if (MLX5_ITEM_VALID(item, key_type)) 8962 return; 8963 MLX5_ITEM_UPDATE(item, key_type, key_v, key_m, 8964 &gre_key_default_mask); 8965 MLX5_SET(fte_match_set_misc, misc_v, gre_key_h, 8966 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8); 8967 MLX5_SET(fte_match_set_misc, misc_v, gre_key_l, 8968 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF); 8969 } 8970 8971 /** 8972 * Add GRE item to the value. 8973 * 8974 * @param[in, out] key 8975 * Flow matcher value. 8976 * @param[in] item 8977 * Flow pattern to translate. 8978 * @param[in] pattern_flags 8979 * Accumulated pattern flags. 8980 * @param[in] key_type 8981 * Set flow matcher mask or value. 8982 */ 8983 static void 8984 flow_dv_translate_item_gre(void *key, const struct rte_flow_item *item, 8985 uint64_t pattern_flags, uint32_t key_type) 8986 { 8987 static const struct rte_flow_item_gre empty_gre = {0,}; 8988 const struct rte_flow_item_gre *gre_m = item->mask; 8989 const struct rte_flow_item_gre *gre_v = item->spec; 8990 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8991 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8992 struct { 8993 union { 8994 __extension__ 8995 struct { 8996 uint16_t version:3; 8997 uint16_t rsvd0:9; 8998 uint16_t s_present:1; 8999 uint16_t k_present:1; 9000 uint16_t rsvd_bit1:1; 9001 uint16_t c_present:1; 9002 }; 9003 uint16_t value; 9004 }; 9005 } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v; 9006 uint16_t protocol_m, protocol_v; 9007 9008 if (key_type & MLX5_SET_MATCHER_M) 9009 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 0xff); 9010 else 9011 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 9012 IPPROTO_GRE); 9013 if (!gre_v) { 9014 gre_v = &empty_gre; 9015 gre_m = &empty_gre; 9016 } else { 9017 if (!gre_m) 9018 gre_m = &rte_flow_item_gre_mask; 9019 } 9020 if (key_type & MLX5_SET_MATCHER_M) 9021 gre_v = gre_m; 9022 else if (key_type == MLX5_SET_MATCHER_HS_V) 9023 gre_m = gre_v; 9024 gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver); 9025 gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver); 9026 MLX5_SET(fte_match_set_misc, misc_v, gre_c_present, 9027 gre_crks_rsvd0_ver_v.c_present & 9028 gre_crks_rsvd0_ver_m.c_present); 9029 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 9030 gre_crks_rsvd0_ver_v.k_present & 9031 gre_crks_rsvd0_ver_m.k_present); 9032 MLX5_SET(fte_match_set_misc, misc_v, gre_s_present, 9033 gre_crks_rsvd0_ver_v.s_present & 9034 gre_crks_rsvd0_ver_m.s_present); 9035 protocol_m = rte_be_to_cpu_16(gre_m->protocol); 9036 protocol_v = rte_be_to_cpu_16(gre_v->protocol); 9037 if (!protocol_m) { 9038 /* Force next protocol to prevent matchers duplication */ 9039 protocol_v = mlx5_translate_tunnel_etypes(pattern_flags); 9040 if (protocol_v) 9041 protocol_m = 0xFFFF; 9042 /* Restore the value to mask in mask case. */ 9043 if (key_type & MLX5_SET_MATCHER_M) 9044 protocol_v = protocol_m; 9045 } 9046 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 9047 protocol_m & protocol_v); 9048 } 9049 9050 /** 9051 * Add GRE optional items to the value. 9052 * 9053 * @param[in, out] key 9054 * Flow matcher value. 9055 * @param[in] item 9056 * Flow pattern to translate. 9057 * @param[in] gre_item 9058 * Pointer to gre_item. 9059 * @param[in] pattern_flags 9060 * Accumulated pattern flags. 9061 * @param[in] key_type 9062 * Set flow matcher mask or value. 9063 */ 9064 static void 9065 flow_dv_translate_item_gre_option(void *key, 9066 const struct rte_flow_item *item, 9067 const struct rte_flow_item *gre_item, 9068 uint64_t pattern_flags, uint32_t key_type) 9069 { 9070 void *misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5); 9071 const struct rte_flow_item_gre_opt *option_m = item->mask; 9072 const struct rte_flow_item_gre_opt *option_v = item->spec; 9073 const struct rte_flow_item_gre *gre_m = gre_item->mask; 9074 const struct rte_flow_item_gre *gre_v = gre_item->spec; 9075 static const struct rte_flow_item_gre empty_gre = {0}; 9076 struct rte_flow_item gre_key_item; 9077 uint16_t c_rsvd0_ver_m, c_rsvd0_ver_v; 9078 uint16_t protocol_m, protocol_v; 9079 9080 /* 9081 * If only match key field, keep using misc for matching. 9082 * If need to match checksum or sequence, using misc5 and do 9083 * not need using misc. 9084 */ 9085 if (!(option_m->sequence.sequence || 9086 option_m->checksum_rsvd.checksum)) { 9087 flow_dv_translate_item_gre(key, gre_item, pattern_flags, key_type); 9088 gre_key_item.spec = &option_v->key.key; 9089 gre_key_item.mask = &option_m->key.key; 9090 flow_dv_translate_item_gre_key(key, &gre_key_item, key_type); 9091 return; 9092 } 9093 if (!gre_v) { 9094 gre_v = &empty_gre; 9095 gre_m = &empty_gre; 9096 } else { 9097 if (!gre_m) 9098 gre_m = &rte_flow_item_gre_mask; 9099 } 9100 protocol_v = gre_v->protocol; 9101 protocol_m = gre_m->protocol; 9102 if (!protocol_m) { 9103 /* Force next protocol to prevent matchers duplication */ 9104 uint16_t ether_type = 9105 mlx5_translate_tunnel_etypes(pattern_flags); 9106 if (ether_type) { 9107 protocol_v = rte_be_to_cpu_16(ether_type); 9108 protocol_m = UINT16_MAX; 9109 } 9110 } 9111 c_rsvd0_ver_v = gre_v->c_rsvd0_ver; 9112 c_rsvd0_ver_m = gre_m->c_rsvd0_ver; 9113 if (option_m->sequence.sequence) { 9114 c_rsvd0_ver_v |= RTE_BE16(0x1000); 9115 c_rsvd0_ver_m |= RTE_BE16(0x1000); 9116 } 9117 if (option_m->key.key) { 9118 c_rsvd0_ver_v |= RTE_BE16(0x2000); 9119 c_rsvd0_ver_m |= RTE_BE16(0x2000); 9120 } 9121 if (option_m->checksum_rsvd.checksum) { 9122 c_rsvd0_ver_v |= RTE_BE16(0x8000); 9123 c_rsvd0_ver_m |= RTE_BE16(0x8000); 9124 } 9125 if (key_type & MLX5_SET_MATCHER_M) { 9126 c_rsvd0_ver_v = c_rsvd0_ver_m; 9127 protocol_v = protocol_m; 9128 option_v = option_m; 9129 } 9130 /* 9131 * Hardware parses GRE optional field into the fixed location, 9132 * do not need to adjust the tunnel dword indices. 9133 */ 9134 MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_0, 9135 rte_be_to_cpu_32((c_rsvd0_ver_v | protocol_v << 16) & 9136 (c_rsvd0_ver_m | protocol_m << 16))); 9137 MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_1, 9138 rte_be_to_cpu_32(option_v->checksum_rsvd.checksum & 9139 option_m->checksum_rsvd.checksum)); 9140 MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_2, 9141 rte_be_to_cpu_32(option_v->key.key & option_m->key.key)); 9142 MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_3, 9143 rte_be_to_cpu_32(option_v->sequence.sequence & 9144 option_m->sequence.sequence)); 9145 } 9146 9147 /** 9148 * Add NVGRE item to matcher and to the value. 9149 * 9150 * @param[in, out] key 9151 * Flow matcher value. 9152 * @param[in] item 9153 * Flow pattern to translate. 9154 * @param[in] pattern_flags 9155 * Accumulated pattern flags. 9156 * @param[in] key_type 9157 * Set flow matcher mask or value. 9158 */ 9159 static void 9160 flow_dv_translate_item_nvgre(void *key, const struct rte_flow_item *item, 9161 unsigned long pattern_flags, uint32_t key_type) 9162 { 9163 const struct rte_flow_item_nvgre *nvgre_m; 9164 const struct rte_flow_item_nvgre *nvgre_v; 9165 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9166 const char *tni_flow_id_m; 9167 const char *tni_flow_id_v; 9168 char *gre_key_v; 9169 int size; 9170 int i; 9171 9172 /* For NVGRE, GRE header fields must be set with defined values. */ 9173 const struct rte_flow_item_gre gre_spec = { 9174 .c_rsvd0_ver = RTE_BE16(0x2000), 9175 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB) 9176 }; 9177 const struct rte_flow_item_gre gre_mask = { 9178 .c_rsvd0_ver = RTE_BE16(0xB000), 9179 .protocol = RTE_BE16(UINT16_MAX), 9180 }; 9181 const struct rte_flow_item gre_item = { 9182 .spec = &gre_spec, 9183 .mask = &gre_mask, 9184 .last = NULL, 9185 }; 9186 flow_dv_translate_item_gre(key, &gre_item, pattern_flags, key_type); 9187 if (MLX5_ITEM_VALID(item, key_type)) 9188 return; 9189 MLX5_ITEM_UPDATE(item, key_type, nvgre_v, nvgre_m, 9190 &rte_flow_item_nvgre_mask); 9191 tni_flow_id_m = (const char *)nvgre_m->tni; 9192 tni_flow_id_v = (const char *)nvgre_v->tni; 9193 size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id); 9194 gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h); 9195 for (i = 0; i < size; ++i) 9196 gre_key_v[i] = tni_flow_id_m[i] & tni_flow_id_v[i]; 9197 } 9198 9199 /** 9200 * Add VXLAN item to the value. 9201 * 9202 * @param[in] dev 9203 * Pointer to the Ethernet device structure. 9204 * @param[in] attr 9205 * Flow rule attributes. 9206 * @param[in, out] key 9207 * Flow matcher value. 9208 * @param[in] item 9209 * Flow pattern to translate. 9210 * @param[in] inner 9211 * Item is inner pattern. 9212 * @param[in] wks 9213 * Matcher workspace. 9214 * @param[in] key_type 9215 * Set flow matcher mask or value. 9216 */ 9217 static void 9218 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, 9219 const struct rte_flow_attr *attr, 9220 void *key, const struct rte_flow_item *item, 9221 int inner, struct mlx5_dv_matcher_workspace *wks, 9222 uint32_t key_type) 9223 { 9224 const struct rte_flow_item_vxlan *vxlan_m; 9225 const struct rte_flow_item_vxlan *vxlan_v; 9226 const struct rte_flow_item_vxlan *vxlan_vv = item->spec; 9227 void *headers_v; 9228 void *misc_v; 9229 void *misc5_v; 9230 uint32_t tunnel_v; 9231 uint32_t *tunnel_header_v; 9232 char *vni_v; 9233 uint16_t dport; 9234 int size; 9235 int i; 9236 struct mlx5_priv *priv = dev->data->dev_private; 9237 const struct rte_flow_item_vxlan nic_mask = { 9238 .hdr.vni = "\xff\xff\xff", 9239 .hdr.rsvd1 = 0xff, 9240 }; 9241 9242 misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5); 9243 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 9244 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9245 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 9246 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 9247 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9248 if (key_type & MLX5_SET_MATCHER_M) 9249 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 9250 udp_dport, 0xFFFF); 9251 else 9252 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 9253 udp_dport, dport); 9254 } 9255 /* 9256 * Read the UDP dport to check if the value satisfies the VXLAN 9257 * matching with MISC5 for CX5. 9258 */ 9259 if (wks->udp_dport) 9260 dport = wks->udp_dport; 9261 if (MLX5_ITEM_VALID(item, key_type)) 9262 return; 9263 MLX5_ITEM_UPDATE(item, key_type, vxlan_v, vxlan_m, &nic_mask); 9264 if ((item->mask == &nic_mask) && 9265 ((!attr->group && !(attr->transfer && priv->fdb_def_rule) && 9266 !priv->sh->tunnel_header_0_1) || 9267 ((attr->group || (attr->transfer && priv->fdb_def_rule)) && 9268 !priv->sh->misc5_cap))) 9269 vxlan_m = &rte_flow_item_vxlan_mask; 9270 if ((priv->sh->steering_format_version == 9271 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && 9272 dport != MLX5_UDP_PORT_VXLAN) || 9273 (!attr->group && !(attr->transfer && priv->fdb_def_rule)) || 9274 ((attr->group || (attr->transfer && priv->fdb_def_rule)) && 9275 !priv->sh->misc5_cap)) { 9276 misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9277 size = sizeof(vxlan_m->hdr.vni); 9278 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni); 9279 for (i = 0; i < size; ++i) 9280 vni_v[i] = vxlan_m->hdr.vni[i] & vxlan_v->hdr.vni[i]; 9281 return; 9282 } 9283 tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 9284 misc5_v, 9285 tunnel_header_1); 9286 tunnel_v = (vxlan_v->hdr.vni[0] & vxlan_m->hdr.vni[0]) | 9287 (vxlan_v->hdr.vni[1] & vxlan_m->hdr.vni[1]) << 8 | 9288 (vxlan_v->hdr.vni[2] & vxlan_m->hdr.vni[2]) << 16; 9289 *tunnel_header_v = tunnel_v; 9290 if (key_type == MLX5_SET_MATCHER_SW_M) { 9291 tunnel_v = (vxlan_vv->hdr.vni[0] & vxlan_m->hdr.vni[0]) | 9292 (vxlan_vv->hdr.vni[1] & vxlan_m->hdr.vni[1]) << 8 | 9293 (vxlan_vv->hdr.vni[2] & vxlan_m->hdr.vni[2]) << 16; 9294 if (!tunnel_v) 9295 *tunnel_header_v = 0x0; 9296 if (vxlan_vv->hdr.rsvd1 & vxlan_m->hdr.rsvd1) 9297 *tunnel_header_v |= vxlan_v->hdr.rsvd1 << 24; 9298 } else { 9299 *tunnel_header_v |= (vxlan_v->hdr.rsvd1 & vxlan_m->hdr.rsvd1) << 24; 9300 } 9301 } 9302 9303 /** 9304 * Add VXLAN-GPE item to the value. 9305 * 9306 * @param[in, out] key 9307 * Flow matcher value. 9308 * @param[in] item 9309 * Flow pattern to translate. 9310 * @param[in] pattern_flags 9311 * Item pattern flags. 9312 * @param[in] key_type 9313 * Set flow matcher mask or value. 9314 */ 9315 9316 static void 9317 flow_dv_translate_item_vxlan_gpe(void *key, const struct rte_flow_item *item, 9318 const uint64_t pattern_flags, 9319 uint32_t key_type) 9320 { 9321 static const struct rte_flow_item_vxlan_gpe dummy_vxlan_gpe_hdr = {{{0}}}; 9322 const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask; 9323 const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec; 9324 /* The item was validated to be on the outer side */ 9325 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9326 void *misc_v = 9327 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9328 char *vni_v = 9329 MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni); 9330 int i, size = sizeof(vxlan_m->hdr.vni); 9331 uint8_t flags_m = 0xff; 9332 uint8_t flags_v = 0xc; 9333 uint8_t m_protocol, v_protocol; 9334 9335 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9336 if (key_type & MLX5_SET_MATCHER_M) 9337 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9338 0xFFFF); 9339 else 9340 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9341 MLX5_UDP_PORT_VXLAN_GPE); 9342 } 9343 if (!vxlan_v) { 9344 vxlan_v = &dummy_vxlan_gpe_hdr; 9345 vxlan_m = &dummy_vxlan_gpe_hdr; 9346 } else { 9347 if (!vxlan_m) 9348 vxlan_m = &rte_flow_item_vxlan_gpe_mask; 9349 } 9350 if (key_type & MLX5_SET_MATCHER_M) 9351 vxlan_v = vxlan_m; 9352 else if (key_type == MLX5_SET_MATCHER_HS_V) 9353 vxlan_m = vxlan_v; 9354 for (i = 0; i < size; ++i) 9355 vni_v[i] = vxlan_m->hdr.vni[i] & vxlan_v->hdr.vni[i]; 9356 if (vxlan_m->hdr.flags) { 9357 flags_m = vxlan_m->hdr.flags; 9358 flags_v = vxlan_v->hdr.flags; 9359 } 9360 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, 9361 flags_m & flags_v); 9362 m_protocol = vxlan_m->hdr.protocol; 9363 v_protocol = vxlan_v->hdr.protocol; 9364 if (!m_protocol) { 9365 /* Force next protocol to ensure next headers parsing. */ 9366 if (pattern_flags & MLX5_FLOW_LAYER_INNER_L2) 9367 v_protocol = RTE_VXLAN_GPE_TYPE_ETH; 9368 else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) 9369 v_protocol = RTE_VXLAN_GPE_TYPE_IPV4; 9370 else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6) 9371 v_protocol = RTE_VXLAN_GPE_TYPE_IPV6; 9372 if (v_protocol) 9373 m_protocol = 0xFF; 9374 /* Restore the value to mask in mask case. */ 9375 if (key_type & MLX5_SET_MATCHER_M) 9376 v_protocol = m_protocol; 9377 } 9378 MLX5_SET(fte_match_set_misc3, misc_v, 9379 outer_vxlan_gpe_next_protocol, m_protocol & v_protocol); 9380 } 9381 9382 /** 9383 * Add Geneve item to the value. 9384 * 9385 * @param[in, out] key 9386 * Flow matcher value. 9387 * @param[in] item 9388 * Flow pattern to translate. 9389 * @param[in] pattern_flags 9390 * Item pattern flags. 9391 * @param[in] key_type 9392 * Set flow matcher mask or value. 9393 */ 9394 9395 static void 9396 flow_dv_translate_item_geneve(void *key, const struct rte_flow_item *item, 9397 uint64_t pattern_flags, uint32_t key_type) 9398 { 9399 static const struct rte_flow_item_geneve empty_geneve = {0,}; 9400 const struct rte_flow_item_geneve *geneve_m = item->mask; 9401 const struct rte_flow_item_geneve *geneve_v = item->spec; 9402 /* GENEVE flow item validation allows single tunnel item */ 9403 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9404 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9405 uint16_t gbhdr_m; 9406 uint16_t gbhdr_v; 9407 char *vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni); 9408 size_t size = sizeof(geneve_m->vni), i; 9409 uint16_t protocol_m, protocol_v; 9410 9411 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9412 if (key_type & MLX5_SET_MATCHER_M) 9413 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9414 0xFFFF); 9415 else 9416 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9417 MLX5_UDP_PORT_GENEVE); 9418 } 9419 if (!geneve_v) { 9420 geneve_v = &empty_geneve; 9421 geneve_m = &empty_geneve; 9422 } else { 9423 if (!geneve_m) 9424 geneve_m = &rte_flow_item_geneve_mask; 9425 } 9426 if (key_type & MLX5_SET_MATCHER_M) 9427 geneve_v = geneve_m; 9428 else if (key_type == MLX5_SET_MATCHER_HS_V) 9429 geneve_m = geneve_v; 9430 for (i = 0; i < size; ++i) 9431 vni_v[i] = geneve_m->vni[i] & geneve_v->vni[i]; 9432 gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0); 9433 gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0); 9434 MLX5_SET(fte_match_set_misc, misc_v, geneve_oam, 9435 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9436 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9437 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) & 9438 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9439 protocol_m = rte_be_to_cpu_16(geneve_m->protocol); 9440 protocol_v = rte_be_to_cpu_16(geneve_v->protocol); 9441 if (!protocol_m) { 9442 /* Force next protocol to prevent matchers duplication */ 9443 protocol_v = mlx5_translate_tunnel_etypes(pattern_flags); 9444 if (protocol_v) 9445 protocol_m = 0xFFFF; 9446 /* Restore the value to mask in mask case. */ 9447 if (key_type & MLX5_SET_MATCHER_M) 9448 protocol_v = protocol_m; 9449 } 9450 MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type, 9451 protocol_m & protocol_v); 9452 } 9453 9454 /** 9455 * Create Geneve TLV option resource. 9456 * 9457 * @param dev[in, out] 9458 * Pointer to rte_eth_dev structure. 9459 * @param[in] item 9460 * Flow pattern to translate. 9461 * @param[out] error 9462 * pointer to error structure. 9463 * 9464 * @return 9465 * 0 on success otherwise -errno and errno is set. 9466 */ 9467 9468 int 9469 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev, 9470 const struct rte_flow_item *item, 9471 struct rte_flow_error *error) 9472 { 9473 struct mlx5_priv *priv = dev->data->dev_private; 9474 struct mlx5_dev_ctx_shared *sh = priv->sh; 9475 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 9476 sh->geneve_tlv_option_resource; 9477 struct mlx5_devx_obj *obj; 9478 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9479 int ret = 0; 9480 9481 if (!geneve_opt_v) 9482 return -1; 9483 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 9484 if (geneve_opt_resource != NULL) { 9485 if (geneve_opt_resource->option_class == 9486 geneve_opt_v->option_class && 9487 geneve_opt_resource->option_type == 9488 geneve_opt_v->option_type && 9489 geneve_opt_resource->length == 9490 geneve_opt_v->option_len) { 9491 /* 9492 * We already have GENEVE TLV option obj allocated. 9493 * Increasing refcnt only in SWS. HWS uses it as global. 9494 */ 9495 if (priv->sh->config.dv_flow_en == 1) 9496 __atomic_fetch_add(&geneve_opt_resource->refcnt, 1, 9497 __ATOMIC_RELAXED); 9498 } else { 9499 ret = rte_flow_error_set(error, ENOMEM, 9500 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9501 "Only one GENEVE TLV option supported"); 9502 goto exit; 9503 } 9504 } else { 9505 /* Create a GENEVE TLV object and resource. */ 9506 obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx, 9507 geneve_opt_v->option_class, 9508 geneve_opt_v->option_type, 9509 geneve_opt_v->option_len); 9510 if (!obj) { 9511 ret = rte_flow_error_set(error, ENODATA, 9512 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9513 "Failed to create GENEVE TLV Devx object"); 9514 goto exit; 9515 } 9516 sh->geneve_tlv_option_resource = 9517 mlx5_malloc(MLX5_MEM_ZERO, 9518 sizeof(*geneve_opt_resource), 9519 0, SOCKET_ID_ANY); 9520 if (!sh->geneve_tlv_option_resource) { 9521 claim_zero(mlx5_devx_cmd_destroy(obj)); 9522 ret = rte_flow_error_set(error, ENOMEM, 9523 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9524 "GENEVE TLV object memory allocation failed"); 9525 goto exit; 9526 } 9527 geneve_opt_resource = sh->geneve_tlv_option_resource; 9528 geneve_opt_resource->obj = obj; 9529 geneve_opt_resource->option_class = geneve_opt_v->option_class; 9530 geneve_opt_resource->option_type = geneve_opt_v->option_type; 9531 geneve_opt_resource->length = geneve_opt_v->option_len; 9532 __atomic_store_n(&geneve_opt_resource->refcnt, 1, 9533 __ATOMIC_RELAXED); 9534 } 9535 exit: 9536 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 9537 return ret; 9538 } 9539 9540 /** 9541 * Add Geneve TLV option item to value. 9542 * 9543 * @param[in, out] dev 9544 * Pointer to rte_eth_dev structure. 9545 * @param[in, out] key 9546 * Flow matcher value. 9547 * @param[in] item 9548 * Flow pattern to translate. 9549 * @param[in] key_type 9550 * Set flow matcher mask or value. 9551 * @param[out] error 9552 * Pointer to error structure. 9553 */ 9554 static int 9555 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *key, 9556 const struct rte_flow_item *item, 9557 uint32_t key_type, 9558 struct rte_flow_error *error) 9559 { 9560 const struct rte_flow_item_geneve_opt *geneve_opt_m; 9561 const struct rte_flow_item_geneve_opt *geneve_opt_v; 9562 const struct rte_flow_item_geneve_opt *geneve_opt_vv = item->spec; 9563 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9564 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9565 rte_be32_t opt_data_key = 0, opt_data_mask = 0; 9566 uint32_t *data; 9567 int ret = 0; 9568 9569 if (MLX5_ITEM_VALID(item, key_type)) 9570 return -1; 9571 MLX5_ITEM_UPDATE(item, key_type, geneve_opt_v, geneve_opt_m, 9572 &rte_flow_item_geneve_opt_mask); 9573 /* Register resource requires item spec. */ 9574 if (key_type & MLX5_SET_MATCHER_V) { 9575 ret = flow_dev_geneve_tlv_option_resource_register(dev, item, 9576 error); 9577 if (ret) { 9578 DRV_LOG(ERR, "Failed to create geneve_tlv_obj"); 9579 return ret; 9580 } 9581 } 9582 /* 9583 * Set the option length in GENEVE header if not requested. 9584 * The GENEVE TLV option length is expressed by the option length field 9585 * in the GENEVE header. 9586 * If the option length was not requested but the GENEVE TLV option item 9587 * is present we set the option length field implicitly. 9588 */ 9589 if (!MLX5_GET16(fte_match_set_misc, misc_v, geneve_opt_len)) { 9590 if (key_type & MLX5_SET_MATCHER_M) 9591 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9592 MLX5_GENEVE_OPTLEN_MASK); 9593 else 9594 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9595 geneve_opt_v->option_len + 1); 9596 } 9597 /* Set the data. */ 9598 if (key_type == MLX5_SET_MATCHER_SW_V) 9599 data = geneve_opt_vv->data; 9600 else 9601 data = geneve_opt_v->data; 9602 if (data) { 9603 memcpy(&opt_data_key, data, 9604 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9605 sizeof(opt_data_key))); 9606 memcpy(&opt_data_mask, geneve_opt_m->data, 9607 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9608 sizeof(opt_data_mask))); 9609 MLX5_SET(fte_match_set_misc3, misc3_v, 9610 geneve_tlv_option_0_data, 9611 rte_be_to_cpu_32(opt_data_key & opt_data_mask)); 9612 } 9613 return ret; 9614 } 9615 9616 /** 9617 * Add MPLS item to the value. 9618 * 9619 * @param[in, out] key 9620 * Flow matcher value. 9621 * @param[in] item 9622 * Flow pattern to translate. 9623 * @param[in] prev_layer 9624 * The protocol layer indicated in previous item. 9625 * @param[in] inner 9626 * Item is inner pattern. 9627 * @param[in] key_type 9628 * Set flow matcher mask or value. 9629 */ 9630 static void 9631 flow_dv_translate_item_mpls(void *key, const struct rte_flow_item *item, 9632 uint64_t prev_layer, int inner, 9633 uint32_t key_type) 9634 { 9635 const uint32_t *in_mpls_m; 9636 const uint32_t *in_mpls_v; 9637 uint32_t *out_mpls_v = 0; 9638 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9639 void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9640 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9641 9642 switch (prev_layer) { 9643 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9644 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9645 if (key_type & MLX5_SET_MATCHER_M) 9646 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 9647 udp_dport, 0xffff); 9648 else 9649 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 9650 udp_dport, MLX5_UDP_PORT_MPLS); 9651 } 9652 break; 9653 case MLX5_FLOW_LAYER_GRE: 9654 /* Fall-through. */ 9655 case MLX5_FLOW_LAYER_GRE_KEY: 9656 if (!MLX5_GET16(fte_match_set_misc, misc_v, gre_protocol)) { 9657 if (key_type & MLX5_SET_MATCHER_M) 9658 MLX5_SET(fte_match_set_misc, misc_v, 9659 gre_protocol, 0xffff); 9660 else 9661 MLX5_SET(fte_match_set_misc, misc_v, 9662 gre_protocol, RTE_ETHER_TYPE_MPLS); 9663 } 9664 break; 9665 default: 9666 break; 9667 } 9668 if (MLX5_ITEM_VALID(item, key_type)) 9669 return; 9670 MLX5_ITEM_UPDATE(item, key_type, in_mpls_v, in_mpls_m, 9671 &rte_flow_item_mpls_mask); 9672 switch (prev_layer) { 9673 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9674 out_mpls_v = 9675 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9676 outer_first_mpls_over_udp); 9677 break; 9678 case MLX5_FLOW_LAYER_GRE: 9679 out_mpls_v = 9680 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9681 outer_first_mpls_over_gre); 9682 break; 9683 default: 9684 /* Inner MPLS not over GRE is not supported. */ 9685 if (!inner) 9686 out_mpls_v = 9687 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9688 misc2_v, 9689 outer_first_mpls); 9690 break; 9691 } 9692 if (out_mpls_v) 9693 *out_mpls_v = *in_mpls_v & *in_mpls_m; 9694 } 9695 9696 /** 9697 * Add metadata register item to matcher 9698 * 9699 * @param[in, out] key 9700 * Flow matcher value. 9701 * @param[in] reg_type 9702 * Type of device metadata register 9703 * @param[in] data 9704 * Register data 9705 * @param[in] mask 9706 * Register mask 9707 */ 9708 static void 9709 flow_dv_match_meta_reg(void *key, enum modify_reg reg_type, 9710 uint32_t data, uint32_t mask) 9711 { 9712 void *misc2_v = 9713 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9714 uint32_t temp; 9715 9716 data &= mask; 9717 switch (reg_type) { 9718 case REG_A: 9719 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data); 9720 break; 9721 case REG_B: 9722 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data); 9723 break; 9724 case REG_C_0: 9725 /* 9726 * The metadata register C0 field might be divided into 9727 * source vport index and META item value, we should set 9728 * this field according to specified mask, not as whole one. 9729 */ 9730 temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0); 9731 if (mask) 9732 temp &= ~mask; 9733 temp |= data; 9734 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp); 9735 break; 9736 case REG_C_1: 9737 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data); 9738 break; 9739 case REG_C_2: 9740 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data); 9741 break; 9742 case REG_C_3: 9743 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data); 9744 break; 9745 case REG_C_4: 9746 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data); 9747 break; 9748 case REG_C_5: 9749 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data); 9750 break; 9751 case REG_C_6: 9752 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data); 9753 break; 9754 case REG_C_7: 9755 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data); 9756 break; 9757 default: 9758 MLX5_ASSERT(false); 9759 break; 9760 } 9761 } 9762 9763 /** 9764 * Add metadata register item to matcher 9765 * 9766 * @param[in, out] matcher 9767 * Flow matcher. 9768 * @param[in, out] key 9769 * Flow matcher value. 9770 * @param[in] reg_type 9771 * Type of device metadata register 9772 * @param[in] value 9773 * Register value 9774 * @param[in] mask 9775 * Register mask 9776 */ 9777 static void 9778 flow_dv_match_meta_reg_all(void *matcher, void *key, enum modify_reg reg_type, 9779 uint32_t data, uint32_t mask) 9780 { 9781 flow_dv_match_meta_reg(key, reg_type, data, mask); 9782 flow_dv_match_meta_reg(matcher, reg_type, mask, mask); 9783 } 9784 9785 /** 9786 * Add MARK item to matcher 9787 * 9788 * @param[in] dev 9789 * The device to configure through. 9790 * @param[in, out] key 9791 * Flow matcher value. 9792 * @param[in] item 9793 * Flow pattern to translate. 9794 * @param[in] key_type 9795 * Set flow matcher mask or value. 9796 */ 9797 static void 9798 flow_dv_translate_item_mark(struct rte_eth_dev *dev, void *key, 9799 const struct rte_flow_item *item, 9800 uint32_t key_type) 9801 { 9802 struct mlx5_priv *priv = dev->data->dev_private; 9803 const struct rte_flow_item_mark *mark; 9804 uint32_t value; 9805 uint32_t mask = 0; 9806 9807 if (key_type & MLX5_SET_MATCHER_SW) { 9808 mark = item->mask ? (const void *)item->mask : 9809 &rte_flow_item_mark_mask; 9810 mask = mark->id; 9811 if (key_type == MLX5_SET_MATCHER_SW_M) { 9812 value = mask; 9813 } else { 9814 mark = (const void *)item->spec; 9815 MLX5_ASSERT(mark); 9816 value = mark->id; 9817 } 9818 } else { 9819 mark = (key_type == MLX5_SET_MATCHER_HS_V) ? 9820 (const void *)item->spec : (const void *)item->mask; 9821 MLX5_ASSERT(mark); 9822 value = mark->id; 9823 if (key_type == MLX5_SET_MATCHER_HS_M) 9824 mask = value; 9825 } 9826 mask &= priv->sh->dv_mark_mask; 9827 value &= mask; 9828 if (mask) { 9829 enum modify_reg reg; 9830 9831 /* Get the metadata register index for the mark. */ 9832 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL); 9833 MLX5_ASSERT(reg > 0); 9834 if (reg == REG_C_0) { 9835 struct mlx5_priv *priv = dev->data->dev_private; 9836 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9837 uint32_t shl_c0 = rte_bsf32(msk_c0); 9838 9839 mask &= msk_c0; 9840 mask <<= shl_c0; 9841 value <<= shl_c0; 9842 } 9843 flow_dv_match_meta_reg(key, reg, value, mask); 9844 } 9845 } 9846 9847 /** 9848 * Add META item to matcher 9849 * 9850 * @param[in] dev 9851 * The devich to configure through. 9852 * @param[in, out] key 9853 * Flow matcher value. 9854 * @param[in] attr 9855 * Attributes of flow that includes this item. 9856 * @param[in] item 9857 * Flow pattern to translate. 9858 * @param[in] key_type 9859 * Set flow matcher mask or value. 9860 */ 9861 static void 9862 flow_dv_translate_item_meta(struct rte_eth_dev *dev, 9863 void *key, 9864 const struct rte_flow_attr *attr, 9865 const struct rte_flow_item *item, 9866 uint32_t key_type) 9867 { 9868 const struct rte_flow_item_meta *meta_m; 9869 const struct rte_flow_item_meta *meta_v; 9870 uint32_t value; 9871 uint32_t mask = 0; 9872 int reg; 9873 9874 if (MLX5_ITEM_VALID(item, key_type)) 9875 return; 9876 MLX5_ITEM_UPDATE(item, key_type, meta_v, meta_m, 9877 &rte_flow_item_meta_mask); 9878 value = meta_v->data; 9879 mask = meta_m->data; 9880 if (key_type == MLX5_SET_MATCHER_HS_M) 9881 mask = value; 9882 /* 9883 * In the current implementation, REG_B cannot be used to match. 9884 * Force to use REG_C_1 in HWS root table as other tables. 9885 * This map may change. 9886 * NIC: modify - REG_B to be present in SW 9887 * match - REG_C_1 when copied from FDB, different from SWS 9888 * FDB: modify - REG_C_1 in Xmeta mode, REG_NON in legacy mode 9889 * match - REG_C_1 in FDB 9890 */ 9891 if (!!(key_type & MLX5_SET_MATCHER_SW)) 9892 reg = flow_dv_get_metadata_reg(dev, attr, NULL); 9893 else 9894 reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_META, 0); 9895 if (reg < 0) 9896 return; 9897 MLX5_ASSERT(reg != REG_NON); 9898 if (reg == REG_C_0) { 9899 struct mlx5_priv *priv = dev->data->dev_private; 9900 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9901 uint32_t shl_c0 = rte_bsf32(msk_c0); 9902 9903 mask &= msk_c0; 9904 mask <<= shl_c0; 9905 value <<= shl_c0; 9906 } 9907 flow_dv_match_meta_reg(key, reg, value, mask); 9908 } 9909 9910 /** 9911 * Add vport metadata Reg C0 item to matcher 9912 * 9913 * @param[in, out] key 9914 * Flow matcher value. 9915 * @param[in] value 9916 * Register value 9917 * @param[in] mask 9918 * Register mask 9919 */ 9920 static void 9921 flow_dv_translate_item_meta_vport(void *key, uint32_t value, uint32_t mask) 9922 { 9923 flow_dv_match_meta_reg(key, REG_C_0, value, mask); 9924 } 9925 9926 /** 9927 * Add tag item to matcher 9928 * 9929 * @param[in] dev 9930 * The devich to configure through. 9931 * @param[in, out] key 9932 * Flow matcher value. 9933 * @param[in] item 9934 * Flow pattern to translate. 9935 * @param[in] key_type 9936 * Set flow matcher mask or value. 9937 */ 9938 static void 9939 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev, void *key, 9940 const struct rte_flow_item *item, 9941 uint32_t key_type) 9942 { 9943 const struct mlx5_rte_flow_item_tag *tag_v = item->spec; 9944 const struct mlx5_rte_flow_item_tag *tag_m = item->mask; 9945 uint32_t mask, value; 9946 9947 MLX5_ASSERT(tag_v); 9948 value = tag_v->data; 9949 mask = tag_m ? tag_m->data : UINT32_MAX; 9950 if (key_type & MLX5_SET_MATCHER_M) 9951 value = mask; 9952 if (tag_v->id == REG_C_0) { 9953 struct mlx5_priv *priv = dev->data->dev_private; 9954 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9955 uint32_t shl_c0 = rte_bsf32(msk_c0); 9956 9957 mask &= msk_c0; 9958 mask <<= shl_c0; 9959 value <<= shl_c0; 9960 } 9961 flow_dv_match_meta_reg(key, tag_v->id, value, mask); 9962 } 9963 9964 /** 9965 * Add TAG item to matcher 9966 * 9967 * @param[in] dev 9968 * The devich to configure through. 9969 * @param[in, out] key 9970 * Flow matcher value. 9971 * @param[in] item 9972 * Flow pattern to translate. 9973 * @param[in] key_type 9974 * Set flow matcher mask or value. 9975 */ 9976 static void 9977 flow_dv_translate_item_tag(struct rte_eth_dev *dev, void *key, 9978 const struct rte_flow_item *item, 9979 uint32_t key_type) 9980 { 9981 const struct rte_flow_item_tag *tag_vv = item->spec; 9982 const struct rte_flow_item_tag *tag_v; 9983 const struct rte_flow_item_tag *tag_m; 9984 enum modify_reg reg; 9985 uint32_t index; 9986 9987 if (MLX5_ITEM_VALID(item, key_type)) 9988 return; 9989 MLX5_ITEM_UPDATE(item, key_type, tag_v, tag_m, 9990 &rte_flow_item_tag_mask); 9991 /* When set mask, the index should be from spec. */ 9992 index = tag_vv ? tag_vv->index : tag_v->index; 9993 /* Get the metadata register index for the tag. */ 9994 if (!!(key_type & MLX5_SET_MATCHER_SW)) 9995 reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, index, NULL); 9996 else 9997 reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, index); 9998 MLX5_ASSERT(reg > 0); 9999 flow_dv_match_meta_reg(key, reg, tag_v->data, tag_m->data); 10000 } 10001 10002 /** 10003 * Add source vport match to the specified matcher. 10004 * 10005 * @param[in, out] key 10006 * Flow matcher value. 10007 * @param[in] port 10008 * Source vport value to match 10009 */ 10010 static void 10011 flow_dv_translate_item_source_vport(void *key, 10012 int16_t port) 10013 { 10014 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 10015 10016 MLX5_SET(fte_match_set_misc, misc_v, source_port, port); 10017 } 10018 10019 /** 10020 * Translate port-id item to eswitch match on port-id. 10021 * 10022 * @param[in] dev 10023 * The devich to configure through. 10024 * @param[in, out] key 10025 * Flow matcher value. 10026 * @param[in] item 10027 * Flow pattern to translate. 10028 * @param[in] attr 10029 * Flow attributes. 10030 * @param[in] key_type 10031 * Set flow matcher mask or value. 10032 * 10033 * @return 10034 * 0 on success, a negative errno value otherwise. 10035 */ 10036 static int 10037 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *key, 10038 const struct rte_flow_item *item, 10039 const struct rte_flow_attr *attr, 10040 uint32_t key_type) 10041 { 10042 const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL; 10043 const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL; 10044 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 10045 struct mlx5_priv *priv; 10046 uint16_t mask, id; 10047 uint32_t vport_meta; 10048 10049 MLX5_ASSERT(wks); 10050 if (pid_v && pid_v->id == MLX5_PORT_ESW_MGR) { 10051 flow_dv_translate_item_source_vport(key, 10052 key_type & MLX5_SET_MATCHER_V ? 10053 mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff); 10054 return 0; 10055 } 10056 mask = pid_m ? pid_m->id : 0xffff; 10057 id = pid_v ? pid_v->id : dev->data->port_id; 10058 priv = mlx5_port_to_eswitch_info(id, item == NULL); 10059 if (!priv) 10060 return -rte_errno; 10061 if (key_type & MLX5_SET_MATCHER_M) { 10062 id = mask; 10063 vport_meta = priv->vport_meta_mask; 10064 } else { 10065 id = priv->vport_id; 10066 vport_meta = priv->vport_meta_tag; 10067 wks->vport_meta_tag = vport_meta; 10068 } 10069 /* 10070 * Translate to vport field or to metadata, depending on mode. 10071 * Kernel can use either misc.source_port or half of C0 metadata 10072 * register. 10073 */ 10074 if (priv->vport_meta_mask) { 10075 /* 10076 * Provide the hint for SW steering library 10077 * to insert the flow into ingress domain and 10078 * save the extra vport match. 10079 */ 10080 if (mask == 0xffff && priv->vport_id == 0xffff && 10081 priv->pf_bond < 0 && attr->transfer) 10082 flow_dv_translate_item_source_vport(key, id); 10083 /* 10084 * We should always set the vport metadata register, 10085 * otherwise the SW steering library can drop 10086 * the rule if wire vport metadata value is not zero, 10087 * it depends on kernel configuration. 10088 */ 10089 flow_dv_translate_item_meta_vport 10090 (key, vport_meta, priv->vport_meta_mask); 10091 } else { 10092 flow_dv_translate_item_source_vport(key, id); 10093 } 10094 return 0; 10095 } 10096 10097 /** 10098 * Translate port representor item to eswitch match on port id. 10099 * 10100 * @param[in] dev 10101 * The devich to configure through. 10102 * @param[in, out] key 10103 * Flow matcher value. 10104 * @param[in] key_type 10105 * Set flow matcher mask or value. 10106 * 10107 * @return 10108 * 0 on success, a negative errno value otherwise. 10109 */ 10110 static int 10111 flow_dv_translate_item_port_representor(struct rte_eth_dev *dev, void *key, 10112 uint32_t key_type) 10113 { 10114 flow_dv_translate_item_source_vport(key, 10115 key_type & MLX5_SET_MATCHER_V ? 10116 mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff); 10117 return 0; 10118 } 10119 10120 /** 10121 * Translate represented port item to eswitch match on port id. 10122 * 10123 * @param[in] dev 10124 * The devich to configure through. 10125 * @param[in, out] key 10126 * Flow matcher value. 10127 * @param[in] item 10128 * Flow pattern to translate. 10129 * @param[in] 10130 * Flow attributes. 10131 * 10132 * @return 10133 * 0 on success, a negative errno value otherwise. 10134 */ 10135 static int 10136 flow_dv_translate_item_represented_port(struct rte_eth_dev *dev, void *key, 10137 const struct rte_flow_item *item, 10138 const struct rte_flow_attr *attr, 10139 uint32_t key_type) 10140 { 10141 const struct rte_flow_item_ethdev *pid_m = item ? item->mask : NULL; 10142 const struct rte_flow_item_ethdev *pid_v = item ? item->spec : NULL; 10143 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 10144 struct mlx5_priv *priv; 10145 uint16_t mask, id; 10146 uint32_t vport_meta; 10147 10148 MLX5_ASSERT(wks); 10149 if (!pid_m && !pid_v) 10150 return 0; 10151 if (pid_v && pid_v->port_id == UINT16_MAX) { 10152 flow_dv_translate_item_source_vport(key, 10153 key_type & MLX5_SET_MATCHER_V ? 10154 mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff); 10155 return 0; 10156 } 10157 mask = pid_m ? pid_m->port_id : UINT16_MAX; 10158 id = pid_v ? pid_v->port_id : dev->data->port_id; 10159 priv = mlx5_port_to_eswitch_info(id, item == NULL); 10160 if (!priv) 10161 return -rte_errno; 10162 if (key_type & MLX5_SET_MATCHER_M) { 10163 id = mask; 10164 vport_meta = priv->vport_meta_mask; 10165 } else { 10166 id = priv->vport_id; 10167 vport_meta = priv->vport_meta_tag; 10168 wks->vport_meta_tag = vport_meta; 10169 } 10170 /* 10171 * Translate to vport field or to metadata, depending on mode. 10172 * Kernel can use either misc.source_port or half of C0 metadata 10173 * register. 10174 */ 10175 if (priv->vport_meta_mask) { 10176 /* 10177 * Provide the hint for SW steering library 10178 * to insert the flow into ingress domain and 10179 * save the extra vport match. 10180 */ 10181 if (mask == UINT16_MAX && priv->vport_id == UINT16_MAX && 10182 priv->pf_bond < 0 && attr->transfer && 10183 priv->sh->config.dv_flow_en != 2) 10184 flow_dv_translate_item_source_vport(key, id); 10185 /* 10186 * We should always set the vport metadata register, 10187 * otherwise the SW steering library can drop 10188 * the rule if wire vport metadata value is not zero, 10189 * it depends on kernel configuration. 10190 */ 10191 flow_dv_translate_item_meta_vport(key, vport_meta, 10192 priv->vport_meta_mask); 10193 } else { 10194 flow_dv_translate_item_source_vport(key, id); 10195 } 10196 return 0; 10197 } 10198 10199 /** 10200 * Translate port-id item to eswitch match on port-id. 10201 * 10202 * @param[in] dev 10203 * The devich to configure through. 10204 * @param[in, out] matcher 10205 * Flow matcher. 10206 * @param[in, out] key 10207 * Flow matcher value. 10208 * @param[in] item 10209 * Flow pattern to translate. 10210 * @param[in] attr 10211 * Flow attributes. 10212 * 10213 * @return 10214 * 0 on success, a negative errno value otherwise. 10215 */ 10216 static int 10217 flow_dv_translate_item_port_id_all(struct rte_eth_dev *dev, 10218 void *matcher, void *key, 10219 const struct rte_flow_item *item, 10220 const struct rte_flow_attr *attr) 10221 { 10222 int ret; 10223 10224 ret = flow_dv_translate_item_port_id 10225 (dev, matcher, item, attr, MLX5_SET_MATCHER_SW_M); 10226 if (ret) 10227 return ret; 10228 ret = flow_dv_translate_item_port_id 10229 (dev, key, item, attr, MLX5_SET_MATCHER_SW_V); 10230 return ret; 10231 } 10232 10233 10234 /** 10235 * Add ICMP6 item to the value. 10236 * 10237 * @param[in, out] key 10238 * Flow matcher value. 10239 * @param[in] item 10240 * Flow pattern to translate. 10241 * @param[in] inner 10242 * Item is inner pattern. 10243 * @param[in] key_type 10244 * Set flow matcher mask or value. 10245 */ 10246 static void 10247 flow_dv_translate_item_icmp6(void *key, const struct rte_flow_item *item, 10248 int inner, uint32_t key_type) 10249 { 10250 const struct rte_flow_item_icmp6 *icmp6_m; 10251 const struct rte_flow_item_icmp6 *icmp6_v; 10252 void *headers_v; 10253 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 10254 10255 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 10256 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 10257 if (key_type & MLX5_SET_MATCHER_M) 10258 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 0xFF); 10259 else 10260 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 10261 IPPROTO_ICMPV6); 10262 if (MLX5_ITEM_VALID(item, key_type)) 10263 return; 10264 MLX5_ITEM_UPDATE(item, key_type, icmp6_v, icmp6_m, 10265 &rte_flow_item_icmp6_mask); 10266 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type, 10267 icmp6_v->type & icmp6_m->type); 10268 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code, 10269 icmp6_v->code & icmp6_m->code); 10270 } 10271 10272 /** 10273 * Add ICMP item to the value. 10274 * 10275 * @param[in, out] key 10276 * Flow matcher value. 10277 * @param[in] item 10278 * Flow pattern to translate. 10279 * @param[in] inner 10280 * Item is inner pattern. 10281 * @param[in] key_type 10282 * Set flow matcher mask or value. 10283 */ 10284 static void 10285 flow_dv_translate_item_icmp(void *key, const struct rte_flow_item *item, 10286 int inner, uint32_t key_type) 10287 { 10288 const struct rte_flow_item_icmp *icmp_m; 10289 const struct rte_flow_item_icmp *icmp_v; 10290 uint32_t icmp_header_data_m = 0; 10291 uint32_t icmp_header_data_v = 0; 10292 void *headers_v; 10293 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 10294 10295 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 10296 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 10297 if (key_type & MLX5_SET_MATCHER_M) 10298 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 10299 ip_protocol, 0xFF); 10300 else 10301 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 10302 ip_protocol, IPPROTO_ICMP); 10303 if (MLX5_ITEM_VALID(item, key_type)) 10304 return; 10305 MLX5_ITEM_UPDATE(item, key_type, icmp_v, icmp_m, 10306 &rte_flow_item_icmp_mask); 10307 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type, 10308 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type); 10309 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code, 10310 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code); 10311 icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb); 10312 icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16; 10313 if (icmp_header_data_m) { 10314 icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb); 10315 icmp_header_data_v |= 10316 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16; 10317 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data, 10318 icmp_header_data_v & icmp_header_data_m); 10319 } 10320 } 10321 10322 /** 10323 * Add GTP item to the value. 10324 * 10325 * @param[in, out] key 10326 * Flow matcher value. 10327 * @param[in] item 10328 * Flow pattern to translate. 10329 * @param[in] inner 10330 * Item is inner pattern. 10331 * @param[in] key_type 10332 * Set flow matcher mask or value. 10333 */ 10334 static void 10335 flow_dv_translate_item_gtp(void *key, const struct rte_flow_item *item, 10336 int inner, uint32_t key_type) 10337 { 10338 const struct rte_flow_item_gtp *gtp_m; 10339 const struct rte_flow_item_gtp *gtp_v; 10340 void *headers_v; 10341 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 10342 uint16_t dport = RTE_GTPU_UDP_PORT; 10343 10344 headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) : 10345 MLX5_ADDR_OF(fte_match_param, key, outer_headers); 10346 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 10347 if (key_type & MLX5_SET_MATCHER_M) 10348 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 10349 udp_dport, 0xFFFF); 10350 else 10351 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 10352 udp_dport, dport); 10353 } 10354 if (MLX5_ITEM_VALID(item, key_type)) 10355 return; 10356 MLX5_ITEM_UPDATE(item, key_type, gtp_v, gtp_m, 10357 &rte_flow_item_gtp_mask); 10358 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, 10359 gtp_v->hdr.gtp_hdr_info & gtp_m->hdr.gtp_hdr_info); 10360 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type, 10361 gtp_v->hdr.msg_type & gtp_m->hdr.msg_type); 10362 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid, 10363 rte_be_to_cpu_32(gtp_v->hdr.teid & gtp_m->hdr.teid)); 10364 } 10365 10366 /** 10367 * Add GTP PSC item to matcher. 10368 * 10369 * @param[in, out] key 10370 * Flow matcher value. 10371 * @param[in] item 10372 * Flow pattern to translate. 10373 * @param[in] key_type 10374 * Set flow matcher mask or value. 10375 */ 10376 static int 10377 flow_dv_translate_item_gtp_psc(void *key, const struct rte_flow_item *item, 10378 uint32_t key_type) 10379 { 10380 const struct rte_flow_item_gtp_psc *gtp_psc_m; 10381 const struct rte_flow_item_gtp_psc *gtp_psc_v; 10382 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 10383 union { 10384 uint32_t w32; 10385 struct { 10386 uint16_t seq_num; 10387 uint8_t npdu_num; 10388 uint8_t next_ext_header_type; 10389 }; 10390 } dw_2; 10391 union { 10392 uint32_t w32; 10393 struct { 10394 uint8_t len; 10395 uint8_t type_flags; 10396 uint8_t qfi; 10397 uint8_t reserved; 10398 }; 10399 } dw_0; 10400 uint8_t gtp_flags; 10401 10402 /* Always set E-flag match on one, regardless of GTP item settings. */ 10403 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags); 10404 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 10405 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags); 10406 /*Set next extension header type. */ 10407 dw_2.seq_num = 0; 10408 dw_2.npdu_num = 0; 10409 if (key_type & MLX5_SET_MATCHER_M) 10410 dw_2.next_ext_header_type = 0xff; 10411 else 10412 dw_2.next_ext_header_type = 0x85; 10413 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2, 10414 rte_cpu_to_be_32(dw_2.w32)); 10415 if (MLX5_ITEM_VALID(item, key_type)) 10416 return 0; 10417 MLX5_ITEM_UPDATE(item, key_type, gtp_psc_v, 10418 gtp_psc_m, &rte_flow_item_gtp_psc_mask); 10419 dw_0.w32 = 0; 10420 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type & 10421 gtp_psc_m->hdr.type); 10422 dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi; 10423 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0, 10424 rte_cpu_to_be_32(dw_0.w32)); 10425 return 0; 10426 } 10427 10428 /** 10429 * Add eCPRI item to matcher and to the value. 10430 * 10431 * @param[in] dev 10432 * The devich to configure through. 10433 * @param[in, out] key 10434 * Flow matcher value. 10435 * @param[in] item 10436 * Flow pattern to translate. 10437 * @param[in] last_item 10438 * Last item flags. 10439 * @param[in] key_type 10440 * Set flow matcher mask or value. 10441 */ 10442 static void 10443 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *key, 10444 const struct rte_flow_item *item, 10445 uint64_t last_item, uint32_t key_type) 10446 { 10447 struct mlx5_priv *priv = dev->data->dev_private; 10448 const struct rte_flow_item_ecpri *ecpri_m; 10449 const struct rte_flow_item_ecpri *ecpri_v; 10450 const struct rte_flow_item_ecpri *ecpri_vv = item->spec; 10451 struct rte_ecpri_common_hdr common; 10452 void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4); 10453 uint32_t *samples; 10454 void *dw_v; 10455 10456 /* 10457 * In case of eCPRI over Ethernet, if EtherType is not specified, 10458 * match on eCPRI EtherType implicitly. 10459 */ 10460 if (last_item & MLX5_FLOW_LAYER_OUTER_L2) { 10461 void *hdrs_v, *l2v; 10462 10463 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 10464 l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 10465 if (*(uint16_t *)l2v == 0) { 10466 if (key_type & MLX5_SET_MATCHER_M) 10467 *(uint16_t *)l2v = UINT16_MAX; 10468 else 10469 *(uint16_t *)l2v = 10470 RTE_BE16(RTE_ETHER_TYPE_ECPRI); 10471 } 10472 } 10473 if (MLX5_ITEM_VALID(item, key_type)) 10474 return; 10475 MLX5_ITEM_UPDATE(item, key_type, ecpri_v, ecpri_m, 10476 &rte_flow_item_ecpri_mask); 10477 /* 10478 * Maximal four DW samples are supported in a single matching now. 10479 * Two are used now for a eCPRI matching: 10480 * 1. Type: one byte, mask should be 0x00ff0000 in network order 10481 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000 10482 * if any. 10483 */ 10484 if (!ecpri_m->hdr.common.u32) 10485 return; 10486 samples = priv->sh->ecpri_parser.ids; 10487 /* Need to take the whole DW as the mask to fill the entry. */ 10488 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 10489 prog_sample_field_value_0); 10490 /* Already big endian (network order) in the header. */ 10491 *(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32; 10492 /* Sample#0, used for matching type, offset 0. */ 10493 /* It makes no sense to set the sample ID in the mask field. */ 10494 MLX5_SET(fte_match_set_misc4, misc4_v, 10495 prog_sample_field_id_0, samples[0]); 10496 /* 10497 * Checking if message body part needs to be matched. 10498 * Some wildcard rules only matching type field should be supported. 10499 */ 10500 if (ecpri_m->hdr.dummy[0]) { 10501 if (key_type == MLX5_SET_MATCHER_SW_M) 10502 common.u32 = rte_be_to_cpu_32(ecpri_vv->hdr.common.u32); 10503 else 10504 common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32); 10505 switch (common.type) { 10506 case RTE_ECPRI_MSG_TYPE_IQ_DATA: 10507 case RTE_ECPRI_MSG_TYPE_RTC_CTRL: 10508 case RTE_ECPRI_MSG_TYPE_DLY_MSR: 10509 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 10510 prog_sample_field_value_1); 10511 *(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] & 10512 ecpri_m->hdr.dummy[0]; 10513 /* Sample#1, to match message body, offset 4. */ 10514 MLX5_SET(fte_match_set_misc4, misc4_v, 10515 prog_sample_field_id_1, samples[1]); 10516 break; 10517 default: 10518 /* Others, do not match any sample ID. */ 10519 break; 10520 } 10521 } 10522 } 10523 10524 /* 10525 * Add connection tracking status item to matcher 10526 * 10527 * @param[in] dev 10528 * The devich to configure through. 10529 * @param[in, out] matcher 10530 * Flow matcher. 10531 * @param[in, out] key 10532 * Flow matcher value. 10533 * @param[in] item 10534 * Flow pattern to translate. 10535 */ 10536 static void 10537 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev, 10538 void *matcher, void *key, 10539 const struct rte_flow_item *item) 10540 { 10541 uint32_t reg_value = 0; 10542 int reg_id; 10543 /* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */ 10544 uint32_t reg_mask = 0; 10545 const struct rte_flow_item_conntrack *spec = item->spec; 10546 const struct rte_flow_item_conntrack *mask = item->mask; 10547 uint32_t flags; 10548 struct rte_flow_error error; 10549 10550 if (!mask) 10551 mask = &rte_flow_item_conntrack_mask; 10552 if (!spec || !mask->flags) 10553 return; 10554 flags = spec->flags & mask->flags; 10555 /* The conflict should be checked in the validation. */ 10556 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) 10557 reg_value |= MLX5_CT_SYNDROME_VALID; 10558 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10559 reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE; 10560 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) 10561 reg_value |= MLX5_CT_SYNDROME_INVALID; 10562 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED) 10563 reg_value |= MLX5_CT_SYNDROME_TRAP; 10564 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10565 reg_value |= MLX5_CT_SYNDROME_BAD_PACKET; 10566 if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID | 10567 RTE_FLOW_CONNTRACK_PKT_STATE_INVALID | 10568 RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)) 10569 reg_mask |= 0xc0; 10570 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10571 reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE; 10572 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10573 reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET; 10574 /* The REG_C_x value could be saved during startup. */ 10575 reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error); 10576 if (reg_id == REG_NON) 10577 return; 10578 flow_dv_match_meta_reg_all(matcher, key, (enum modify_reg)reg_id, 10579 reg_value, reg_mask); 10580 } 10581 10582 static void 10583 flow_dv_translate_item_flex(struct rte_eth_dev *dev, void *matcher, void *key, 10584 const struct rte_flow_item *item, 10585 struct mlx5_flow *dev_flow, bool is_inner) 10586 { 10587 const struct rte_flow_item_flex *spec = 10588 (const struct rte_flow_item_flex *)item->spec; 10589 int index = mlx5_flex_acquire_index(dev, spec->handle, false); 10590 10591 MLX5_ASSERT(index >= 0 && index <= (int)(sizeof(uint32_t) * CHAR_BIT)); 10592 if (index < 0) 10593 return; 10594 if (!(dev_flow->handle->flex_item & RTE_BIT32(index))) { 10595 /* Don't count both inner and outer flex items in one rule. */ 10596 if (mlx5_flex_acquire_index(dev, spec->handle, true) != index) 10597 MLX5_ASSERT(false); 10598 dev_flow->handle->flex_item |= (uint8_t)RTE_BIT32(index); 10599 } 10600 mlx5_flex_flow_translate_item(dev, matcher, key, item, is_inner); 10601 } 10602 10603 /** 10604 * Add METER_COLOR item to matcher 10605 * 10606 * @param[in] dev 10607 * The device to configure through. 10608 * @param[in, out] key 10609 * Flow matcher value. 10610 * @param[in] item 10611 * Flow pattern to translate. 10612 * @param[in] key_type 10613 * Set flow matcher mask or value. 10614 */ 10615 static void 10616 flow_dv_translate_item_meter_color(struct rte_eth_dev *dev, void *key, 10617 const struct rte_flow_item *item, 10618 uint32_t key_type) 10619 { 10620 const struct rte_flow_item_meter_color *color_m = item->mask; 10621 const struct rte_flow_item_meter_color *color_v = item->spec; 10622 uint32_t value, mask; 10623 int reg = REG_NON; 10624 10625 MLX5_ASSERT(color_v); 10626 if (MLX5_ITEM_VALID(item, key_type)) 10627 return; 10628 MLX5_ITEM_UPDATE(item, key_type, color_v, color_m, 10629 &rte_flow_item_meter_color_mask); 10630 value = rte_col_2_mlx5_col(color_v->color); 10631 mask = color_m ? 10632 color_m->color : (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 10633 if (!!(key_type & MLX5_SET_MATCHER_SW)) 10634 reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL); 10635 else 10636 reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_METER_COLOR, 0); 10637 if (reg == REG_NON) 10638 return; 10639 flow_dv_match_meta_reg(key, (enum modify_reg)reg, value, mask); 10640 } 10641 10642 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 }; 10643 10644 #define HEADER_IS_ZERO(match_criteria, headers) \ 10645 !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \ 10646 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \ 10647 10648 /** 10649 * Calculate flow matcher enable bitmap. 10650 * 10651 * @param match_criteria 10652 * Pointer to flow matcher criteria. 10653 * 10654 * @return 10655 * Bitmap of enabled fields. 10656 */ 10657 static uint8_t 10658 flow_dv_matcher_enable(uint32_t *match_criteria) 10659 { 10660 uint8_t match_criteria_enable; 10661 10662 match_criteria_enable = 10663 (!HEADER_IS_ZERO(match_criteria, outer_headers)) << 10664 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT; 10665 match_criteria_enable |= 10666 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) << 10667 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT; 10668 match_criteria_enable |= 10669 (!HEADER_IS_ZERO(match_criteria, inner_headers)) << 10670 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT; 10671 match_criteria_enable |= 10672 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) << 10673 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT; 10674 match_criteria_enable |= 10675 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) << 10676 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT; 10677 match_criteria_enable |= 10678 (!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) << 10679 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT; 10680 match_criteria_enable |= 10681 (!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) << 10682 MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT; 10683 return match_criteria_enable; 10684 } 10685 10686 static void 10687 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria) 10688 { 10689 /* 10690 * Check flow matching criteria first, subtract misc5/4 length if flow 10691 * doesn't own misc5/4 parameters. In some old rdma-core releases, 10692 * misc5/4 are not supported, and matcher creation failure is expected 10693 * w/o subtraction. If misc5 is provided, misc4 must be counted in since 10694 * misc5 is right after misc4. 10695 */ 10696 if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) { 10697 *size = MLX5_ST_SZ_BYTES(fte_match_param) - 10698 MLX5_ST_SZ_BYTES(fte_match_set_misc5); 10699 if (!(match_criteria & (1 << 10700 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) { 10701 *size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4); 10702 } 10703 } 10704 } 10705 10706 static struct mlx5_list_entry * 10707 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused, 10708 struct mlx5_list_entry *entry, void *cb_ctx) 10709 { 10710 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10711 struct mlx5_flow_dv_matcher *ref = ctx->data; 10712 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10713 typeof(*tbl), tbl); 10714 struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY, 10715 sizeof(*resource), 10716 0, SOCKET_ID_ANY); 10717 10718 if (!resource) { 10719 rte_flow_error_set(ctx->error, ENOMEM, 10720 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10721 "cannot create matcher"); 10722 return NULL; 10723 } 10724 memcpy(resource, entry, sizeof(*resource)); 10725 resource->tbl = &tbl->tbl; 10726 return &resource->entry; 10727 } 10728 10729 static void 10730 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused, 10731 struct mlx5_list_entry *entry) 10732 { 10733 mlx5_free(entry); 10734 } 10735 10736 struct mlx5_list_entry * 10737 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx) 10738 { 10739 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10740 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10741 struct rte_eth_dev *dev = ctx->dev; 10742 struct mlx5_flow_tbl_data_entry *tbl_data; 10743 struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2; 10744 struct rte_flow_error *error = ctx->error; 10745 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10746 struct mlx5_flow_tbl_resource *tbl; 10747 void *domain; 10748 uint32_t idx = 0; 10749 int ret; 10750 10751 tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10752 if (!tbl_data) { 10753 rte_flow_error_set(error, ENOMEM, 10754 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10755 NULL, 10756 "cannot allocate flow table data entry"); 10757 return NULL; 10758 } 10759 tbl_data->idx = idx; 10760 tbl_data->tunnel = tt_prm->tunnel; 10761 tbl_data->group_id = tt_prm->group_id; 10762 tbl_data->external = !!tt_prm->external; 10763 tbl_data->tunnel_offload = is_tunnel_offload_active(dev); 10764 tbl_data->is_egress = !!key.is_egress; 10765 tbl_data->is_transfer = !!key.is_fdb; 10766 tbl_data->dummy = !!key.dummy; 10767 tbl_data->level = key.level; 10768 tbl_data->id = key.id; 10769 tbl = &tbl_data->tbl; 10770 if (key.dummy) 10771 return &tbl_data->entry; 10772 if (key.is_fdb) 10773 domain = sh->fdb_domain; 10774 else if (key.is_egress) 10775 domain = sh->tx_domain; 10776 else 10777 domain = sh->rx_domain; 10778 ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj); 10779 if (ret) { 10780 rte_flow_error_set(error, ENOMEM, 10781 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10782 NULL, "cannot create flow table object"); 10783 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10784 return NULL; 10785 } 10786 if (key.level != 0) { 10787 ret = mlx5_flow_os_create_flow_action_dest_flow_tbl 10788 (tbl->obj, &tbl_data->jump.action); 10789 if (ret) { 10790 rte_flow_error_set(error, ENOMEM, 10791 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10792 NULL, 10793 "cannot create flow jump action"); 10794 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10795 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10796 return NULL; 10797 } 10798 } 10799 MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list", 10800 key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress", 10801 key.level, key.id); 10802 tbl_data->matchers = mlx5_list_create(matcher_name, sh, true, 10803 flow_dv_matcher_create_cb, 10804 flow_dv_matcher_match_cb, 10805 flow_dv_matcher_remove_cb, 10806 flow_dv_matcher_clone_cb, 10807 flow_dv_matcher_clone_free_cb); 10808 if (!tbl_data->matchers) { 10809 rte_flow_error_set(error, ENOMEM, 10810 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10811 NULL, 10812 "cannot create tbl matcher list"); 10813 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10814 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10815 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10816 return NULL; 10817 } 10818 return &tbl_data->entry; 10819 } 10820 10821 int 10822 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10823 void *cb_ctx) 10824 { 10825 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10826 struct mlx5_flow_tbl_data_entry *tbl_data = 10827 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10828 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10829 10830 return tbl_data->level != key.level || 10831 tbl_data->id != key.id || 10832 tbl_data->dummy != key.dummy || 10833 tbl_data->is_transfer != !!key.is_fdb || 10834 tbl_data->is_egress != !!key.is_egress; 10835 } 10836 10837 struct mlx5_list_entry * 10838 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10839 void *cb_ctx) 10840 { 10841 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10842 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10843 struct mlx5_flow_tbl_data_entry *tbl_data; 10844 struct rte_flow_error *error = ctx->error; 10845 uint32_t idx = 0; 10846 10847 tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10848 if (!tbl_data) { 10849 rte_flow_error_set(error, ENOMEM, 10850 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10851 NULL, 10852 "cannot allocate flow table data entry"); 10853 return NULL; 10854 } 10855 memcpy(tbl_data, oentry, sizeof(*tbl_data)); 10856 tbl_data->idx = idx; 10857 return &tbl_data->entry; 10858 } 10859 10860 void 10861 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10862 { 10863 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10864 struct mlx5_flow_tbl_data_entry *tbl_data = 10865 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10866 10867 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10868 } 10869 10870 /** 10871 * Get a flow table. 10872 * 10873 * @param[in, out] dev 10874 * Pointer to rte_eth_dev structure. 10875 * @param[in] table_level 10876 * Table level to use. 10877 * @param[in] egress 10878 * Direction of the table. 10879 * @param[in] transfer 10880 * E-Switch or NIC flow. 10881 * @param[in] dummy 10882 * Dummy entry for dv API. 10883 * @param[in] table_id 10884 * Table id to use. 10885 * @param[out] error 10886 * pointer to error structure. 10887 * 10888 * @return 10889 * Returns tables resource based on the index, NULL in case of failed. 10890 */ 10891 struct mlx5_flow_tbl_resource * 10892 flow_dv_tbl_resource_get(struct rte_eth_dev *dev, 10893 uint32_t table_level, uint8_t egress, 10894 uint8_t transfer, 10895 bool external, 10896 const struct mlx5_flow_tunnel *tunnel, 10897 uint32_t group_id, uint8_t dummy, 10898 uint32_t table_id, 10899 struct rte_flow_error *error) 10900 { 10901 struct mlx5_priv *priv = dev->data->dev_private; 10902 union mlx5_flow_tbl_key table_key = { 10903 { 10904 .level = table_level, 10905 .id = table_id, 10906 .reserved = 0, 10907 .dummy = !!dummy, 10908 .is_fdb = !!transfer, 10909 .is_egress = !!egress, 10910 } 10911 }; 10912 struct mlx5_flow_tbl_tunnel_prm tt_prm = { 10913 .tunnel = tunnel, 10914 .group_id = group_id, 10915 .external = external, 10916 }; 10917 struct mlx5_flow_cb_ctx ctx = { 10918 .dev = dev, 10919 .error = error, 10920 .data = &table_key.v64, 10921 .data2 = &tt_prm, 10922 }; 10923 struct mlx5_list_entry *entry; 10924 struct mlx5_flow_tbl_data_entry *tbl_data; 10925 10926 entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx); 10927 if (!entry) { 10928 rte_flow_error_set(error, ENOMEM, 10929 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10930 "cannot get table"); 10931 return NULL; 10932 } 10933 DRV_LOG(DEBUG, "table_level %u table_id %u " 10934 "tunnel %u group %u registered.", 10935 table_level, table_id, 10936 tunnel ? tunnel->tunnel_id : 0, group_id); 10937 tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10938 return &tbl_data->tbl; 10939 } 10940 10941 void 10942 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10943 { 10944 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10945 struct mlx5_flow_tbl_data_entry *tbl_data = 10946 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10947 10948 MLX5_ASSERT(entry && sh); 10949 if (tbl_data->jump.action) 10950 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10951 if (tbl_data->tbl.obj) 10952 mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj); 10953 if (tbl_data->tunnel_offload && tbl_data->external) { 10954 struct mlx5_list_entry *he; 10955 struct mlx5_hlist *tunnel_grp_hash; 10956 struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub; 10957 union tunnel_tbl_key tunnel_key = { 10958 .tunnel_id = tbl_data->tunnel ? 10959 tbl_data->tunnel->tunnel_id : 0, 10960 .group = tbl_data->group_id 10961 }; 10962 uint32_t table_level = tbl_data->level; 10963 struct mlx5_flow_cb_ctx ctx = { 10964 .data = (void *)&tunnel_key.val, 10965 }; 10966 10967 tunnel_grp_hash = tbl_data->tunnel ? 10968 tbl_data->tunnel->groups : 10969 thub->groups; 10970 he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx); 10971 if (he) 10972 mlx5_hlist_unregister(tunnel_grp_hash, he); 10973 DRV_LOG(DEBUG, 10974 "table_level %u id %u tunnel %u group %u released.", 10975 table_level, 10976 tbl_data->id, 10977 tbl_data->tunnel ? 10978 tbl_data->tunnel->tunnel_id : 0, 10979 tbl_data->group_id); 10980 } 10981 if (tbl_data->matchers) 10982 mlx5_list_destroy(tbl_data->matchers); 10983 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10984 } 10985 10986 /** 10987 * Release a flow table. 10988 * 10989 * @param[in] sh 10990 * Pointer to device shared structure. 10991 * @param[in] tbl 10992 * Table resource to be released. 10993 * 10994 * @return 10995 * Returns 0 if table was released, else return 1; 10996 */ 10997 int 10998 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 10999 struct mlx5_flow_tbl_resource *tbl) 11000 { 11001 struct mlx5_flow_tbl_data_entry *tbl_data = 11002 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 11003 11004 if (!tbl) 11005 return 0; 11006 return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry); 11007 } 11008 11009 int 11010 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused, 11011 struct mlx5_list_entry *entry, void *cb_ctx) 11012 { 11013 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11014 struct mlx5_flow_dv_matcher *ref = ctx->data; 11015 struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur), 11016 entry); 11017 11018 return cur->crc != ref->crc || 11019 cur->priority != ref->priority || 11020 memcmp((const void *)cur->mask.buf, 11021 (const void *)ref->mask.buf, ref->mask.size); 11022 } 11023 11024 struct mlx5_list_entry * 11025 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx) 11026 { 11027 struct mlx5_dev_ctx_shared *sh = tool_ctx; 11028 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11029 struct mlx5_flow_dv_matcher *ref = ctx->data; 11030 struct mlx5_flow_dv_matcher *resource; 11031 struct mlx5dv_flow_matcher_attr dv_attr = { 11032 .type = IBV_FLOW_ATTR_NORMAL, 11033 .match_mask = (void *)&ref->mask, 11034 }; 11035 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 11036 typeof(*tbl), tbl); 11037 int ret; 11038 11039 resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0, 11040 SOCKET_ID_ANY); 11041 if (!resource) { 11042 rte_flow_error_set(ctx->error, ENOMEM, 11043 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 11044 "cannot create matcher"); 11045 return NULL; 11046 } 11047 *resource = *ref; 11048 dv_attr.match_criteria_enable = 11049 flow_dv_matcher_enable(resource->mask.buf); 11050 __flow_dv_adjust_buf_size(&ref->mask.size, 11051 dv_attr.match_criteria_enable); 11052 dv_attr.priority = ref->priority; 11053 if (tbl->is_egress) 11054 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS; 11055 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 11056 tbl->tbl.obj, 11057 &resource->matcher_object); 11058 if (ret) { 11059 mlx5_free(resource); 11060 rte_flow_error_set(ctx->error, ENOMEM, 11061 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 11062 "cannot create matcher"); 11063 return NULL; 11064 } 11065 return &resource->entry; 11066 } 11067 11068 /** 11069 * Register the flow matcher. 11070 * 11071 * @param[in, out] dev 11072 * Pointer to rte_eth_dev structure. 11073 * @param[in, out] matcher 11074 * Pointer to flow matcher. 11075 * @param[in, out] key 11076 * Pointer to flow table key. 11077 * @parm[in, out] dev_flow 11078 * Pointer to the dev_flow. 11079 * @param[out] error 11080 * pointer to error structure. 11081 * 11082 * @return 11083 * 0 on success otherwise -errno and errno is set. 11084 */ 11085 static int 11086 flow_dv_matcher_register(struct rte_eth_dev *dev, 11087 struct mlx5_flow_dv_matcher *ref, 11088 union mlx5_flow_tbl_key *key, 11089 struct mlx5_flow *dev_flow, 11090 const struct mlx5_flow_tunnel *tunnel, 11091 uint32_t group_id, 11092 struct rte_flow_error *error) 11093 { 11094 struct mlx5_list_entry *entry; 11095 struct mlx5_flow_dv_matcher *resource; 11096 struct mlx5_flow_tbl_resource *tbl; 11097 struct mlx5_flow_tbl_data_entry *tbl_data; 11098 struct mlx5_flow_cb_ctx ctx = { 11099 .error = error, 11100 .data = ref, 11101 }; 11102 /** 11103 * tunnel offload API requires this registration for cases when 11104 * tunnel match rule was inserted before tunnel set rule. 11105 */ 11106 tbl = flow_dv_tbl_resource_get(dev, key->level, 11107 key->is_egress, key->is_fdb, 11108 dev_flow->external, tunnel, 11109 group_id, 0, key->id, error); 11110 if (!tbl) 11111 return -rte_errno; /* No need to refill the error info */ 11112 tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 11113 ref->tbl = tbl; 11114 entry = mlx5_list_register(tbl_data->matchers, &ctx); 11115 if (!entry) { 11116 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 11117 return rte_flow_error_set(error, ENOMEM, 11118 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 11119 "cannot allocate ref memory"); 11120 } 11121 resource = container_of(entry, typeof(*resource), entry); 11122 dev_flow->handle->dvh.matcher = resource; 11123 return 0; 11124 } 11125 11126 struct mlx5_list_entry * 11127 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx) 11128 { 11129 struct mlx5_dev_ctx_shared *sh = tool_ctx; 11130 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11131 struct mlx5_flow_dv_tag_resource *entry; 11132 uint32_t idx = 0; 11133 int ret; 11134 11135 entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 11136 if (!entry) { 11137 rte_flow_error_set(ctx->error, ENOMEM, 11138 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 11139 "cannot allocate resource memory"); 11140 return NULL; 11141 } 11142 entry->idx = idx; 11143 entry->tag_id = *(uint32_t *)(ctx->data); 11144 ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id, 11145 &entry->action); 11146 if (ret) { 11147 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx); 11148 rte_flow_error_set(ctx->error, ENOMEM, 11149 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11150 NULL, "cannot create action"); 11151 return NULL; 11152 } 11153 return &entry->entry; 11154 } 11155 11156 int 11157 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 11158 void *cb_ctx) 11159 { 11160 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11161 struct mlx5_flow_dv_tag_resource *tag = 11162 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 11163 11164 return *(uint32_t *)(ctx->data) != tag->tag_id; 11165 } 11166 11167 struct mlx5_list_entry * 11168 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 11169 void *cb_ctx) 11170 { 11171 struct mlx5_dev_ctx_shared *sh = tool_ctx; 11172 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11173 struct mlx5_flow_dv_tag_resource *entry; 11174 uint32_t idx = 0; 11175 11176 entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 11177 if (!entry) { 11178 rte_flow_error_set(ctx->error, ENOMEM, 11179 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 11180 "cannot allocate tag resource memory"); 11181 return NULL; 11182 } 11183 memcpy(entry, oentry, sizeof(*entry)); 11184 entry->idx = idx; 11185 return &entry->entry; 11186 } 11187 11188 void 11189 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 11190 { 11191 struct mlx5_dev_ctx_shared *sh = tool_ctx; 11192 struct mlx5_flow_dv_tag_resource *tag = 11193 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 11194 11195 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 11196 } 11197 11198 /** 11199 * Find existing tag resource or create and register a new one. 11200 * 11201 * @param dev[in, out] 11202 * Pointer to rte_eth_dev structure. 11203 * @param[in, out] tag_be24 11204 * Tag value in big endian then R-shift 8. 11205 * @parm[in, out] dev_flow 11206 * Pointer to the dev_flow. 11207 * @param[out] error 11208 * pointer to error structure. 11209 * 11210 * @return 11211 * 0 on success otherwise -errno and errno is set. 11212 */ 11213 static int 11214 flow_dv_tag_resource_register 11215 (struct rte_eth_dev *dev, 11216 uint32_t tag_be24, 11217 struct mlx5_flow *dev_flow, 11218 struct rte_flow_error *error) 11219 { 11220 struct mlx5_priv *priv = dev->data->dev_private; 11221 struct mlx5_flow_dv_tag_resource *resource; 11222 struct mlx5_list_entry *entry; 11223 struct mlx5_flow_cb_ctx ctx = { 11224 .error = error, 11225 .data = &tag_be24, 11226 }; 11227 struct mlx5_hlist *tag_table; 11228 11229 tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table, 11230 "tags", 11231 MLX5_TAGS_HLIST_ARRAY_SIZE, 11232 false, false, priv->sh, 11233 flow_dv_tag_create_cb, 11234 flow_dv_tag_match_cb, 11235 flow_dv_tag_remove_cb, 11236 flow_dv_tag_clone_cb, 11237 flow_dv_tag_clone_free_cb, 11238 error); 11239 if (unlikely(!tag_table)) 11240 return -rte_errno; 11241 entry = mlx5_hlist_register(tag_table, tag_be24, &ctx); 11242 if (entry) { 11243 resource = container_of(entry, struct mlx5_flow_dv_tag_resource, 11244 entry); 11245 dev_flow->handle->dvh.rix_tag = resource->idx; 11246 dev_flow->dv.tag_resource = resource; 11247 return 0; 11248 } 11249 return -rte_errno; 11250 } 11251 11252 void 11253 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 11254 { 11255 struct mlx5_dev_ctx_shared *sh = tool_ctx; 11256 struct mlx5_flow_dv_tag_resource *tag = 11257 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 11258 11259 MLX5_ASSERT(tag && sh && tag->action); 11260 claim_zero(mlx5_flow_os_destroy_flow_action(tag->action)); 11261 DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag); 11262 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 11263 } 11264 11265 /** 11266 * Release the tag. 11267 * 11268 * @param dev 11269 * Pointer to Ethernet device. 11270 * @param tag_idx 11271 * Tag index. 11272 * 11273 * @return 11274 * 1 while a reference on it exists, 0 when freed. 11275 */ 11276 static int 11277 flow_dv_tag_release(struct rte_eth_dev *dev, 11278 uint32_t tag_idx) 11279 { 11280 struct mlx5_priv *priv = dev->data->dev_private; 11281 struct mlx5_flow_dv_tag_resource *tag; 11282 11283 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx); 11284 if (!tag) 11285 return 0; 11286 DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--", 11287 dev->data->port_id, (void *)tag, tag->entry.ref_cnt); 11288 return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry); 11289 } 11290 11291 /** 11292 * Translate action PORT_ID / REPRESENTED_PORT to vport. 11293 * 11294 * @param[in] dev 11295 * Pointer to rte_eth_dev structure. 11296 * @param[in] action 11297 * Pointer to action PORT_ID / REPRESENTED_PORT. 11298 * @param[out] dst_port_id 11299 * The target port ID. 11300 * @param[out] error 11301 * Pointer to the error structure. 11302 * 11303 * @return 11304 * 0 on success, a negative errno value otherwise and rte_errno is set. 11305 */ 11306 static int 11307 flow_dv_translate_action_port_id(struct rte_eth_dev *dev, 11308 const struct rte_flow_action *action, 11309 uint32_t *dst_port_id, 11310 struct rte_flow_error *error) 11311 { 11312 uint32_t port; 11313 struct mlx5_priv *priv; 11314 11315 switch (action->type) { 11316 case RTE_FLOW_ACTION_TYPE_PORT_ID: { 11317 const struct rte_flow_action_port_id *conf; 11318 11319 conf = (const struct rte_flow_action_port_id *)action->conf; 11320 port = conf->original ? dev->data->port_id : conf->id; 11321 break; 11322 } 11323 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { 11324 const struct rte_flow_action_ethdev *ethdev; 11325 11326 ethdev = (const struct rte_flow_action_ethdev *)action->conf; 11327 port = ethdev->port_id; 11328 break; 11329 } 11330 default: 11331 MLX5_ASSERT(false); 11332 return rte_flow_error_set(error, EINVAL, 11333 RTE_FLOW_ERROR_TYPE_ACTION, action, 11334 "unknown E-Switch action"); 11335 } 11336 11337 priv = mlx5_port_to_eswitch_info(port, false); 11338 if (!priv) 11339 return rte_flow_error_set(error, -rte_errno, 11340 RTE_FLOW_ERROR_TYPE_ACTION, 11341 NULL, 11342 "No eswitch info was found for port"); 11343 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT 11344 /* 11345 * This parameter is transferred to 11346 * mlx5dv_dr_action_create_dest_ib_port(). 11347 */ 11348 *dst_port_id = priv->dev_port; 11349 #else 11350 /* 11351 * Legacy mode, no LAG configurations is supported. 11352 * This parameter is transferred to 11353 * mlx5dv_dr_action_create_dest_vport(). 11354 */ 11355 *dst_port_id = priv->vport_id; 11356 #endif 11357 return 0; 11358 } 11359 11360 /** 11361 * Create a counter with aging configuration. 11362 * 11363 * @param[in] dev 11364 * Pointer to rte_eth_dev structure. 11365 * @param[in] dev_flow 11366 * Pointer to the mlx5_flow. 11367 * @param[out] count 11368 * Pointer to the counter action configuration. 11369 * @param[in] age 11370 * Pointer to the aging action configuration. 11371 * 11372 * @return 11373 * Index to flow counter on success, 0 otherwise. 11374 */ 11375 static uint32_t 11376 flow_dv_translate_create_counter(struct rte_eth_dev *dev, 11377 struct mlx5_flow *dev_flow, 11378 const struct rte_flow_action_count *count 11379 __rte_unused, 11380 const struct rte_flow_action_age *age) 11381 { 11382 uint32_t counter; 11383 struct mlx5_age_param *age_param; 11384 11385 counter = flow_dv_counter_alloc(dev, !!age); 11386 if (!counter || age == NULL) 11387 return counter; 11388 age_param = flow_dv_counter_idx_get_age(dev, counter); 11389 age_param->context = age->context ? age->context : 11390 (void *)(uintptr_t)(dev_flow->flow_idx); 11391 age_param->timeout = age->timeout; 11392 age_param->port_id = dev->data->port_id; 11393 __atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED); 11394 __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED); 11395 return counter; 11396 } 11397 11398 /** 11399 * Add SQ matcher 11400 * 11401 * @param[in, out] matcher 11402 * Flow matcher. 11403 * @param[in, out] key 11404 * Flow matcher value. 11405 * @param[in] item 11406 * Flow pattern to translate. 11407 * @param[in] key_type 11408 * Set flow matcher mask or value. 11409 */ 11410 static void 11411 flow_dv_translate_item_sq(void *key, 11412 const struct rte_flow_item *item, 11413 uint32_t key_type) 11414 { 11415 const struct mlx5_rte_flow_item_sq *queue_m; 11416 const struct mlx5_rte_flow_item_sq *queue_v; 11417 const struct mlx5_rte_flow_item_sq queue_mask = { 11418 .queue = UINT32_MAX, 11419 }; 11420 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 11421 uint32_t queue; 11422 11423 MLX5_ITEM_UPDATE(item, key_type, queue_v, queue_m, &queue_mask); 11424 if (!queue_m || !queue_v) 11425 return; 11426 if (key_type & MLX5_SET_MATCHER_V) { 11427 queue = queue_v->queue; 11428 if (key_type == MLX5_SET_MATCHER_SW_V) 11429 queue &= queue_m->queue; 11430 } else { 11431 queue = queue_m->queue; 11432 } 11433 MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue); 11434 } 11435 11436 /** 11437 * Set the hash fields according to the @p flow information. 11438 * 11439 * @param[in] item_flags 11440 * The match pattern item flags. 11441 * @param[in] rss_desc 11442 * Pointer to the mlx5_flow_rss_desc. 11443 * @param[out] hash_fields 11444 * Pointer to the RSS hash fields. 11445 */ 11446 void 11447 flow_dv_hashfields_set(uint64_t item_flags, 11448 struct mlx5_flow_rss_desc *rss_desc, 11449 uint64_t *hash_fields) 11450 { 11451 uint64_t items = item_flags; 11452 uint64_t fields = 0; 11453 int rss_inner = 0; 11454 uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types); 11455 11456 *hash_fields = 0; 11457 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT 11458 if (rss_desc->level >= 2) 11459 rss_inner = 1; 11460 #endif 11461 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || 11462 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { 11463 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 11464 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 11465 fields |= IBV_RX_HASH_SRC_IPV4; 11466 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 11467 fields |= IBV_RX_HASH_DST_IPV4; 11468 else 11469 fields |= MLX5_IPV4_IBV_RX_HASH; 11470 } 11471 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 11472 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) { 11473 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 11474 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 11475 fields |= IBV_RX_HASH_SRC_IPV6; 11476 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 11477 fields |= IBV_RX_HASH_DST_IPV6; 11478 else 11479 fields |= MLX5_IPV6_IBV_RX_HASH; 11480 } 11481 } 11482 if (items & MLX5_FLOW_ITEM_ESP) { 11483 if (rss_types & RTE_ETH_RSS_ESP) 11484 fields |= IBV_RX_HASH_IPSEC_SPI; 11485 } 11486 if ((fields & ~IBV_RX_HASH_IPSEC_SPI) == 0) { 11487 *hash_fields = fields; 11488 /* 11489 * There is no match between the RSS types and the 11490 * L3 protocol (IPv4/IPv6) defined in the flow rule. 11491 */ 11492 return; 11493 } 11494 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || 11495 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { 11496 if (rss_types & RTE_ETH_RSS_UDP) { 11497 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 11498 fields |= IBV_RX_HASH_SRC_PORT_UDP; 11499 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 11500 fields |= IBV_RX_HASH_DST_PORT_UDP; 11501 else 11502 fields |= MLX5_UDP_IBV_RX_HASH; 11503 } 11504 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) || 11505 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) { 11506 if (rss_types & RTE_ETH_RSS_TCP) { 11507 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 11508 fields |= IBV_RX_HASH_SRC_PORT_TCP; 11509 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 11510 fields |= IBV_RX_HASH_DST_PORT_TCP; 11511 else 11512 fields |= MLX5_TCP_IBV_RX_HASH; 11513 } 11514 } 11515 if (rss_inner) 11516 fields |= IBV_RX_HASH_INNER; 11517 *hash_fields = fields; 11518 } 11519 11520 /** 11521 * Prepare an Rx Hash queue. 11522 * 11523 * @param dev 11524 * Pointer to Ethernet device. 11525 * @param[in] dev_flow 11526 * Pointer to the mlx5_flow. 11527 * @param[in] rss_desc 11528 * Pointer to the mlx5_flow_rss_desc. 11529 * @param[out] hrxq_idx 11530 * Hash Rx queue index. 11531 * 11532 * @return 11533 * The Verbs/DevX object initialised, NULL otherwise and rte_errno is set. 11534 */ 11535 static struct mlx5_hrxq * 11536 flow_dv_hrxq_prepare(struct rte_eth_dev *dev, 11537 struct mlx5_flow *dev_flow, 11538 struct mlx5_flow_rss_desc *rss_desc, 11539 uint32_t *hrxq_idx) 11540 { 11541 struct mlx5_flow_handle *dh = dev_flow->handle; 11542 uint32_t shared_rss = rss_desc->shared_rss; 11543 struct mlx5_hrxq *hrxq; 11544 11545 MLX5_ASSERT(rss_desc->queue_num); 11546 rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN; 11547 rss_desc->hash_fields = dev_flow->hash_fields; 11548 rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL); 11549 rss_desc->shared_rss = 0; 11550 if (rss_desc->hash_fields == 0) 11551 rss_desc->queue_num = 1; 11552 hrxq = mlx5_hrxq_get(dev, rss_desc); 11553 *hrxq_idx = hrxq ? hrxq->idx : 0; 11554 rss_desc->shared_rss = shared_rss; 11555 return hrxq; 11556 } 11557 11558 /** 11559 * Release sample sub action resource. 11560 * 11561 * @param[in, out] dev 11562 * Pointer to rte_eth_dev structure. 11563 * @param[in] act_res 11564 * Pointer to sample sub action resource. 11565 */ 11566 static void 11567 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev, 11568 struct mlx5_flow_sub_actions_idx *act_res) 11569 { 11570 if (act_res->rix_hrxq) { 11571 mlx5_hrxq_release(dev, act_res->rix_hrxq); 11572 act_res->rix_hrxq = 0; 11573 } 11574 if (act_res->rix_encap_decap) { 11575 flow_dv_encap_decap_resource_release(dev, 11576 act_res->rix_encap_decap); 11577 act_res->rix_encap_decap = 0; 11578 } 11579 if (act_res->rix_port_id_action) { 11580 flow_dv_port_id_action_resource_release(dev, 11581 act_res->rix_port_id_action); 11582 act_res->rix_port_id_action = 0; 11583 } 11584 if (act_res->rix_tag) { 11585 flow_dv_tag_release(dev, act_res->rix_tag); 11586 act_res->rix_tag = 0; 11587 } 11588 if (act_res->rix_jump) { 11589 flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump); 11590 act_res->rix_jump = 0; 11591 } 11592 } 11593 11594 int 11595 flow_dv_sample_match_cb(void *tool_ctx __rte_unused, 11596 struct mlx5_list_entry *entry, void *cb_ctx) 11597 { 11598 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11599 struct rte_eth_dev *dev = ctx->dev; 11600 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11601 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 11602 typeof(*resource), 11603 entry); 11604 11605 if (ctx_resource->ratio == resource->ratio && 11606 ctx_resource->ft_type == resource->ft_type && 11607 ctx_resource->ft_id == resource->ft_id && 11608 ctx_resource->set_action == resource->set_action && 11609 !memcmp((void *)&ctx_resource->sample_act, 11610 (void *)&resource->sample_act, 11611 sizeof(struct mlx5_flow_sub_actions_list))) { 11612 /* 11613 * Existing sample action should release the prepared 11614 * sub-actions reference counter. 11615 */ 11616 flow_dv_sample_sub_actions_release(dev, 11617 &ctx_resource->sample_idx); 11618 return 0; 11619 } 11620 return 1; 11621 } 11622 11623 struct mlx5_list_entry * 11624 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11625 { 11626 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11627 struct rte_eth_dev *dev = ctx->dev; 11628 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11629 void **sample_dv_actions = ctx_resource->sub_actions; 11630 struct mlx5_flow_dv_sample_resource *resource; 11631 struct mlx5dv_dr_flow_sampler_attr sampler_attr; 11632 struct mlx5_priv *priv = dev->data->dev_private; 11633 struct mlx5_dev_ctx_shared *sh = priv->sh; 11634 struct mlx5_flow_tbl_resource *tbl; 11635 uint32_t idx = 0; 11636 const uint32_t next_ft_step = 1; 11637 uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step; 11638 uint8_t is_egress = 0; 11639 uint8_t is_transfer = 0; 11640 struct rte_flow_error *error = ctx->error; 11641 11642 /* Register new sample resource. */ 11643 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11644 if (!resource) { 11645 rte_flow_error_set(error, ENOMEM, 11646 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11647 NULL, 11648 "cannot allocate resource memory"); 11649 return NULL; 11650 } 11651 *resource = *ctx_resource; 11652 /* Create normal path table level */ 11653 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11654 is_transfer = 1; 11655 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 11656 is_egress = 1; 11657 tbl = flow_dv_tbl_resource_get(dev, next_ft_id, 11658 is_egress, is_transfer, 11659 true, NULL, 0, 0, 0, error); 11660 if (!tbl) { 11661 rte_flow_error_set(error, ENOMEM, 11662 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11663 NULL, 11664 "fail to create normal path table " 11665 "for sample"); 11666 goto error; 11667 } 11668 resource->normal_path_tbl = tbl; 11669 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) { 11670 if (!sh->default_miss_action) { 11671 rte_flow_error_set(error, ENOMEM, 11672 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11673 NULL, 11674 "default miss action was not " 11675 "created"); 11676 goto error; 11677 } 11678 sample_dv_actions[ctx_resource->sample_act.actions_num++] = 11679 sh->default_miss_action; 11680 } 11681 /* Create a DR sample action */ 11682 sampler_attr.sample_ratio = resource->ratio; 11683 sampler_attr.default_next_table = tbl->obj; 11684 sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num; 11685 sampler_attr.sample_actions = (struct mlx5dv_dr_action **) 11686 &sample_dv_actions[0]; 11687 sampler_attr.action = resource->set_action; 11688 if (mlx5_os_flow_dr_create_flow_action_sampler 11689 (&sampler_attr, &resource->verbs_action)) { 11690 rte_flow_error_set(error, ENOMEM, 11691 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11692 NULL, "cannot create sample action"); 11693 goto error; 11694 } 11695 resource->idx = idx; 11696 resource->dev = dev; 11697 return &resource->entry; 11698 error: 11699 if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB) 11700 flow_dv_sample_sub_actions_release(dev, 11701 &resource->sample_idx); 11702 if (resource->normal_path_tbl) 11703 flow_dv_tbl_resource_release(MLX5_SH(dev), 11704 resource->normal_path_tbl); 11705 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx); 11706 return NULL; 11707 11708 } 11709 11710 struct mlx5_list_entry * 11711 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused, 11712 struct mlx5_list_entry *entry __rte_unused, 11713 void *cb_ctx) 11714 { 11715 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11716 struct rte_eth_dev *dev = ctx->dev; 11717 struct mlx5_flow_dv_sample_resource *resource; 11718 struct mlx5_priv *priv = dev->data->dev_private; 11719 struct mlx5_dev_ctx_shared *sh = priv->sh; 11720 uint32_t idx = 0; 11721 11722 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11723 if (!resource) { 11724 rte_flow_error_set(ctx->error, ENOMEM, 11725 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11726 NULL, 11727 "cannot allocate resource memory"); 11728 return NULL; 11729 } 11730 memcpy(resource, entry, sizeof(*resource)); 11731 resource->idx = idx; 11732 resource->dev = dev; 11733 return &resource->entry; 11734 } 11735 11736 void 11737 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused, 11738 struct mlx5_list_entry *entry) 11739 { 11740 struct mlx5_flow_dv_sample_resource *resource = 11741 container_of(entry, typeof(*resource), entry); 11742 struct rte_eth_dev *dev = resource->dev; 11743 struct mlx5_priv *priv = dev->data->dev_private; 11744 11745 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 11746 } 11747 11748 /** 11749 * Find existing sample resource or create and register a new one. 11750 * 11751 * @param[in, out] dev 11752 * Pointer to rte_eth_dev structure. 11753 * @param[in] ref 11754 * Pointer to sample resource reference. 11755 * @parm[in, out] dev_flow 11756 * Pointer to the dev_flow. 11757 * @param[out] error 11758 * pointer to error structure. 11759 * 11760 * @return 11761 * 0 on success otherwise -errno and errno is set. 11762 */ 11763 static int 11764 flow_dv_sample_resource_register(struct rte_eth_dev *dev, 11765 struct mlx5_flow_dv_sample_resource *ref, 11766 struct mlx5_flow *dev_flow, 11767 struct rte_flow_error *error) 11768 { 11769 struct mlx5_flow_dv_sample_resource *resource; 11770 struct mlx5_list_entry *entry; 11771 struct mlx5_priv *priv = dev->data->dev_private; 11772 struct mlx5_flow_cb_ctx ctx = { 11773 .dev = dev, 11774 .error = error, 11775 .data = ref, 11776 }; 11777 11778 entry = mlx5_list_register(priv->sh->sample_action_list, &ctx); 11779 if (!entry) 11780 return -rte_errno; 11781 resource = container_of(entry, typeof(*resource), entry); 11782 dev_flow->handle->dvh.rix_sample = resource->idx; 11783 dev_flow->dv.sample_res = resource; 11784 return 0; 11785 } 11786 11787 int 11788 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused, 11789 struct mlx5_list_entry *entry, void *cb_ctx) 11790 { 11791 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11792 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11793 struct rte_eth_dev *dev = ctx->dev; 11794 struct mlx5_flow_dv_dest_array_resource *resource = 11795 container_of(entry, typeof(*resource), entry); 11796 uint32_t idx = 0; 11797 11798 if (ctx_resource->num_of_dest == resource->num_of_dest && 11799 ctx_resource->ft_type == resource->ft_type && 11800 !memcmp((void *)resource->sample_act, 11801 (void *)ctx_resource->sample_act, 11802 (ctx_resource->num_of_dest * 11803 sizeof(struct mlx5_flow_sub_actions_list)))) { 11804 /* 11805 * Existing sample action should release the prepared 11806 * sub-actions reference counter. 11807 */ 11808 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11809 flow_dv_sample_sub_actions_release(dev, 11810 &ctx_resource->sample_idx[idx]); 11811 return 0; 11812 } 11813 return 1; 11814 } 11815 11816 struct mlx5_list_entry * 11817 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11818 { 11819 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11820 struct rte_eth_dev *dev = ctx->dev; 11821 struct mlx5_flow_dv_dest_array_resource *resource; 11822 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11823 struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 }; 11824 struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM]; 11825 struct mlx5_priv *priv = dev->data->dev_private; 11826 struct mlx5_dev_ctx_shared *sh = priv->sh; 11827 struct mlx5_flow_sub_actions_list *sample_act; 11828 struct mlx5dv_dr_domain *domain; 11829 uint32_t idx = 0, res_idx = 0; 11830 struct rte_flow_error *error = ctx->error; 11831 uint64_t action_flags; 11832 int ret; 11833 11834 /* Register new destination array resource. */ 11835 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11836 &res_idx); 11837 if (!resource) { 11838 rte_flow_error_set(error, ENOMEM, 11839 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11840 NULL, 11841 "cannot allocate resource memory"); 11842 return NULL; 11843 } 11844 *resource = *ctx_resource; 11845 if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11846 domain = sh->fdb_domain; 11847 else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 11848 domain = sh->rx_domain; 11849 else 11850 domain = sh->tx_domain; 11851 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11852 dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *) 11853 mlx5_malloc(MLX5_MEM_ZERO, 11854 sizeof(struct mlx5dv_dr_action_dest_attr), 11855 0, SOCKET_ID_ANY); 11856 if (!dest_attr[idx]) { 11857 rte_flow_error_set(error, ENOMEM, 11858 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11859 NULL, 11860 "cannot allocate resource memory"); 11861 goto error; 11862 } 11863 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST; 11864 sample_act = &ctx_resource->sample_act[idx]; 11865 action_flags = sample_act->action_flags; 11866 switch (action_flags) { 11867 case MLX5_FLOW_ACTION_QUEUE: 11868 dest_attr[idx]->dest = sample_act->dr_queue_action; 11869 break; 11870 case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP): 11871 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT; 11872 dest_attr[idx]->dest_reformat = &dest_reformat[idx]; 11873 dest_attr[idx]->dest_reformat->reformat = 11874 sample_act->dr_encap_action; 11875 dest_attr[idx]->dest_reformat->dest = 11876 sample_act->dr_port_id_action; 11877 break; 11878 case MLX5_FLOW_ACTION_PORT_ID: 11879 dest_attr[idx]->dest = sample_act->dr_port_id_action; 11880 break; 11881 case MLX5_FLOW_ACTION_JUMP: 11882 dest_attr[idx]->dest = sample_act->dr_jump_action; 11883 break; 11884 default: 11885 rte_flow_error_set(error, EINVAL, 11886 RTE_FLOW_ERROR_TYPE_ACTION, 11887 NULL, 11888 "unsupported actions type"); 11889 goto error; 11890 } 11891 } 11892 /* create a dest array action */ 11893 ret = mlx5_os_flow_dr_create_flow_action_dest_array 11894 (domain, 11895 resource->num_of_dest, 11896 dest_attr, 11897 &resource->action); 11898 if (ret) { 11899 rte_flow_error_set(error, ENOMEM, 11900 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11901 NULL, 11902 "cannot create destination array action"); 11903 goto error; 11904 } 11905 resource->idx = res_idx; 11906 resource->dev = dev; 11907 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11908 mlx5_free(dest_attr[idx]); 11909 return &resource->entry; 11910 error: 11911 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11912 flow_dv_sample_sub_actions_release(dev, 11913 &resource->sample_idx[idx]); 11914 if (dest_attr[idx]) 11915 mlx5_free(dest_attr[idx]); 11916 } 11917 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx); 11918 return NULL; 11919 } 11920 11921 struct mlx5_list_entry * 11922 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused, 11923 struct mlx5_list_entry *entry __rte_unused, 11924 void *cb_ctx) 11925 { 11926 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11927 struct rte_eth_dev *dev = ctx->dev; 11928 struct mlx5_flow_dv_dest_array_resource *resource; 11929 struct mlx5_priv *priv = dev->data->dev_private; 11930 struct mlx5_dev_ctx_shared *sh = priv->sh; 11931 uint32_t res_idx = 0; 11932 struct rte_flow_error *error = ctx->error; 11933 11934 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11935 &res_idx); 11936 if (!resource) { 11937 rte_flow_error_set(error, ENOMEM, 11938 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11939 NULL, 11940 "cannot allocate dest-array memory"); 11941 return NULL; 11942 } 11943 memcpy(resource, entry, sizeof(*resource)); 11944 resource->idx = res_idx; 11945 resource->dev = dev; 11946 return &resource->entry; 11947 } 11948 11949 void 11950 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused, 11951 struct mlx5_list_entry *entry) 11952 { 11953 struct mlx5_flow_dv_dest_array_resource *resource = 11954 container_of(entry, typeof(*resource), entry); 11955 struct rte_eth_dev *dev = resource->dev; 11956 struct mlx5_priv *priv = dev->data->dev_private; 11957 11958 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 11959 } 11960 11961 /** 11962 * Find existing destination array resource or create and register a new one. 11963 * 11964 * @param[in, out] dev 11965 * Pointer to rte_eth_dev structure. 11966 * @param[in] ref 11967 * Pointer to destination array resource reference. 11968 * @parm[in, out] dev_flow 11969 * Pointer to the dev_flow. 11970 * @param[out] error 11971 * pointer to error structure. 11972 * 11973 * @return 11974 * 0 on success otherwise -errno and errno is set. 11975 */ 11976 static int 11977 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev, 11978 struct mlx5_flow_dv_dest_array_resource *ref, 11979 struct mlx5_flow *dev_flow, 11980 struct rte_flow_error *error) 11981 { 11982 struct mlx5_flow_dv_dest_array_resource *resource; 11983 struct mlx5_priv *priv = dev->data->dev_private; 11984 struct mlx5_list_entry *entry; 11985 struct mlx5_flow_cb_ctx ctx = { 11986 .dev = dev, 11987 .error = error, 11988 .data = ref, 11989 }; 11990 11991 entry = mlx5_list_register(priv->sh->dest_array_list, &ctx); 11992 if (!entry) 11993 return -rte_errno; 11994 resource = container_of(entry, typeof(*resource), entry); 11995 dev_flow->handle->dvh.rix_dest_array = resource->idx; 11996 dev_flow->dv.dest_array_res = resource; 11997 return 0; 11998 } 11999 12000 /** 12001 * Convert Sample action to DV specification. 12002 * 12003 * @param[in] dev 12004 * Pointer to rte_eth_dev structure. 12005 * @param[in] action 12006 * Pointer to sample action structure. 12007 * @param[in, out] dev_flow 12008 * Pointer to the mlx5_flow. 12009 * @param[in] attr 12010 * Pointer to the flow attributes. 12011 * @param[in, out] num_of_dest 12012 * Pointer to the num of destination. 12013 * @param[in, out] sample_actions 12014 * Pointer to sample actions list. 12015 * @param[in, out] res 12016 * Pointer to sample resource. 12017 * @param[out] error 12018 * Pointer to the error structure. 12019 * 12020 * @return 12021 * 0 on success, a negative errno value otherwise and rte_errno is set. 12022 */ 12023 static int 12024 flow_dv_translate_action_sample(struct rte_eth_dev *dev, 12025 const struct rte_flow_action_sample *action, 12026 struct mlx5_flow *dev_flow, 12027 const struct rte_flow_attr *attr, 12028 uint32_t *num_of_dest, 12029 void **sample_actions, 12030 struct mlx5_flow_dv_sample_resource *res, 12031 struct rte_flow_error *error) 12032 { 12033 struct mlx5_priv *priv = dev->data->dev_private; 12034 const struct rte_flow_action *sub_actions; 12035 struct mlx5_flow_sub_actions_list *sample_act; 12036 struct mlx5_flow_sub_actions_idx *sample_idx; 12037 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 12038 struct rte_flow *flow = dev_flow->flow; 12039 struct mlx5_flow_rss_desc *rss_desc; 12040 uint64_t action_flags = 0; 12041 12042 MLX5_ASSERT(wks); 12043 rss_desc = &wks->rss_desc; 12044 sample_act = &res->sample_act; 12045 sample_idx = &res->sample_idx; 12046 res->ratio = action->ratio; 12047 sub_actions = action->actions; 12048 for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) { 12049 int type = sub_actions->type; 12050 uint32_t pre_rix = 0; 12051 void *pre_r; 12052 switch (type) { 12053 case RTE_FLOW_ACTION_TYPE_QUEUE: 12054 { 12055 const struct rte_flow_action_queue *queue; 12056 struct mlx5_hrxq *hrxq; 12057 uint32_t hrxq_idx; 12058 12059 queue = sub_actions->conf; 12060 rss_desc->queue_num = 1; 12061 rss_desc->queue[0] = queue->index; 12062 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 12063 rss_desc, &hrxq_idx); 12064 if (!hrxq) 12065 return rte_flow_error_set 12066 (error, rte_errno, 12067 RTE_FLOW_ERROR_TYPE_ACTION, 12068 NULL, 12069 "cannot create fate queue"); 12070 sample_act->dr_queue_action = hrxq->action; 12071 sample_idx->rix_hrxq = hrxq_idx; 12072 sample_actions[sample_act->actions_num++] = 12073 hrxq->action; 12074 (*num_of_dest)++; 12075 action_flags |= MLX5_FLOW_ACTION_QUEUE; 12076 if (action_flags & MLX5_FLOW_ACTION_MARK) 12077 dev_flow->handle->rix_hrxq = hrxq_idx; 12078 dev_flow->handle->fate_action = 12079 MLX5_FLOW_FATE_QUEUE; 12080 break; 12081 } 12082 case RTE_FLOW_ACTION_TYPE_RSS: 12083 { 12084 struct mlx5_hrxq *hrxq; 12085 uint32_t hrxq_idx; 12086 const struct rte_flow_action_rss *rss; 12087 const uint8_t *rss_key; 12088 12089 rss = sub_actions->conf; 12090 memcpy(rss_desc->queue, rss->queue, 12091 rss->queue_num * sizeof(uint16_t)); 12092 rss_desc->queue_num = rss->queue_num; 12093 /* NULL RSS key indicates default RSS key. */ 12094 rss_key = !rss->key ? rss_hash_default_key : rss->key; 12095 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 12096 /* 12097 * rss->level and rss.types should be set in advance 12098 * when expanding items for RSS. 12099 */ 12100 flow_dv_hashfields_set(dev_flow->handle->layers, 12101 rss_desc, 12102 &dev_flow->hash_fields); 12103 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 12104 rss_desc, &hrxq_idx); 12105 if (!hrxq) 12106 return rte_flow_error_set 12107 (error, rte_errno, 12108 RTE_FLOW_ERROR_TYPE_ACTION, 12109 NULL, 12110 "cannot create fate queue"); 12111 sample_act->dr_queue_action = hrxq->action; 12112 sample_idx->rix_hrxq = hrxq_idx; 12113 sample_actions[sample_act->actions_num++] = 12114 hrxq->action; 12115 (*num_of_dest)++; 12116 action_flags |= MLX5_FLOW_ACTION_RSS; 12117 if (action_flags & MLX5_FLOW_ACTION_MARK) 12118 dev_flow->handle->rix_hrxq = hrxq_idx; 12119 dev_flow->handle->fate_action = 12120 MLX5_FLOW_FATE_QUEUE; 12121 break; 12122 } 12123 case RTE_FLOW_ACTION_TYPE_MARK: 12124 { 12125 uint32_t tag_be = mlx5_flow_mark_set 12126 (((const struct rte_flow_action_mark *) 12127 (sub_actions->conf))->id); 12128 12129 wks->mark = 1; 12130 pre_rix = dev_flow->handle->dvh.rix_tag; 12131 /* Save the mark resource before sample */ 12132 pre_r = dev_flow->dv.tag_resource; 12133 if (flow_dv_tag_resource_register(dev, tag_be, 12134 dev_flow, error)) 12135 return -rte_errno; 12136 MLX5_ASSERT(dev_flow->dv.tag_resource); 12137 sample_act->dr_tag_action = 12138 dev_flow->dv.tag_resource->action; 12139 sample_idx->rix_tag = 12140 dev_flow->handle->dvh.rix_tag; 12141 sample_actions[sample_act->actions_num++] = 12142 sample_act->dr_tag_action; 12143 /* Recover the mark resource after sample */ 12144 dev_flow->dv.tag_resource = pre_r; 12145 dev_flow->handle->dvh.rix_tag = pre_rix; 12146 action_flags |= MLX5_FLOW_ACTION_MARK; 12147 break; 12148 } 12149 case RTE_FLOW_ACTION_TYPE_COUNT: 12150 { 12151 if (!flow->counter) { 12152 flow->counter = 12153 flow_dv_translate_create_counter(dev, 12154 dev_flow, sub_actions->conf, 12155 0); 12156 if (!flow->counter) 12157 return rte_flow_error_set 12158 (error, rte_errno, 12159 RTE_FLOW_ERROR_TYPE_ACTION, 12160 NULL, 12161 "cannot create counter" 12162 " object."); 12163 } 12164 sample_act->dr_cnt_action = 12165 (flow_dv_counter_get_by_idx(dev, 12166 flow->counter, NULL))->action; 12167 sample_actions[sample_act->actions_num++] = 12168 sample_act->dr_cnt_action; 12169 action_flags |= MLX5_FLOW_ACTION_COUNT; 12170 break; 12171 } 12172 case RTE_FLOW_ACTION_TYPE_PORT_ID: 12173 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 12174 { 12175 struct mlx5_flow_dv_port_id_action_resource 12176 port_id_resource; 12177 uint32_t port_id = 0; 12178 12179 memset(&port_id_resource, 0, sizeof(port_id_resource)); 12180 /* Save the port id resource before sample */ 12181 pre_rix = dev_flow->handle->rix_port_id_action; 12182 pre_r = dev_flow->dv.port_id_action; 12183 if (flow_dv_translate_action_port_id(dev, sub_actions, 12184 &port_id, error)) 12185 return -rte_errno; 12186 port_id_resource.port_id = port_id; 12187 if (flow_dv_port_id_action_resource_register 12188 (dev, &port_id_resource, dev_flow, error)) 12189 return -rte_errno; 12190 sample_act->dr_port_id_action = 12191 dev_flow->dv.port_id_action->action; 12192 sample_idx->rix_port_id_action = 12193 dev_flow->handle->rix_port_id_action; 12194 sample_actions[sample_act->actions_num++] = 12195 sample_act->dr_port_id_action; 12196 /* Recover the port id resource after sample */ 12197 dev_flow->dv.port_id_action = pre_r; 12198 dev_flow->handle->rix_port_id_action = pre_rix; 12199 (*num_of_dest)++; 12200 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12201 break; 12202 } 12203 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 12204 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 12205 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 12206 /* Save the encap resource before sample */ 12207 pre_rix = dev_flow->handle->dvh.rix_encap_decap; 12208 pre_r = dev_flow->dv.encap_decap; 12209 if (flow_dv_create_action_l2_encap(dev, sub_actions, 12210 dev_flow, 12211 attr->transfer, 12212 error)) 12213 return -rte_errno; 12214 sample_act->dr_encap_action = 12215 dev_flow->dv.encap_decap->action; 12216 sample_idx->rix_encap_decap = 12217 dev_flow->handle->dvh.rix_encap_decap; 12218 sample_actions[sample_act->actions_num++] = 12219 sample_act->dr_encap_action; 12220 /* Recover the encap resource after sample */ 12221 dev_flow->dv.encap_decap = pre_r; 12222 dev_flow->handle->dvh.rix_encap_decap = pre_rix; 12223 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12224 break; 12225 default: 12226 return rte_flow_error_set(error, EINVAL, 12227 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12228 NULL, 12229 "Not support for sampler action"); 12230 } 12231 } 12232 sample_act->action_flags = action_flags; 12233 res->ft_id = dev_flow->dv.group; 12234 if (attr->transfer) { 12235 union { 12236 uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)]; 12237 uint64_t set_action; 12238 } action_ctx = { .set_action = 0 }; 12239 uint32_t vport_meta_tag = wks->vport_meta_tag ? 12240 wks->vport_meta_tag : 12241 priv->vport_meta_tag; 12242 12243 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 12244 MLX5_SET(set_action_in, action_ctx.action_in, action_type, 12245 MLX5_MODIFICATION_TYPE_SET); 12246 MLX5_SET(set_action_in, action_ctx.action_in, field, 12247 MLX5_MODI_META_REG_C_0); 12248 MLX5_SET(set_action_in, action_ctx.action_in, data, 12249 vport_meta_tag); 12250 res->set_action = action_ctx.set_action; 12251 } else if (attr->ingress) { 12252 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12253 } else { 12254 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 12255 } 12256 return 0; 12257 } 12258 12259 static void * 12260 flow_dv_translate_action_send_to_kernel(struct rte_eth_dev *dev, 12261 struct rte_flow_error *error) 12262 { 12263 struct mlx5_flow_tbl_resource *tbl; 12264 struct mlx5_dev_ctx_shared *sh; 12265 uint32_t priority; 12266 void *action; 12267 int ret; 12268 12269 sh = MLX5_SH(dev); 12270 if (sh->send_to_kernel_action.action) 12271 return sh->send_to_kernel_action.action; 12272 priority = mlx5_get_send_to_kernel_priority(dev); 12273 if (priority == (uint32_t)-1) { 12274 rte_flow_error_set(error, ENOTSUP, 12275 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 12276 "required priority is not available"); 12277 return NULL; 12278 } 12279 tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 0, 0, 0, 12280 error); 12281 if (!tbl) { 12282 rte_flow_error_set(error, ENODATA, 12283 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 12284 "cannot find destination root table"); 12285 return NULL; 12286 } 12287 ret = mlx5_flow_os_create_flow_action_send_to_kernel(tbl->obj, 12288 priority, &action); 12289 if (ret) { 12290 rte_flow_error_set(error, ENOMEM, 12291 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 12292 "cannot create action"); 12293 goto err; 12294 } 12295 MLX5_ASSERT(action); 12296 sh->send_to_kernel_action.action = action; 12297 sh->send_to_kernel_action.tbl = tbl; 12298 return action; 12299 err: 12300 flow_dv_tbl_resource_release(sh, tbl); 12301 return NULL; 12302 } 12303 12304 /** 12305 * Convert Sample action to DV specification. 12306 * 12307 * @param[in] dev 12308 * Pointer to rte_eth_dev structure. 12309 * @param[in, out] dev_flow 12310 * Pointer to the mlx5_flow. 12311 * @param[in] num_of_dest 12312 * The num of destination. 12313 * @param[in, out] res 12314 * Pointer to sample resource. 12315 * @param[in, out] mdest_res 12316 * Pointer to destination array resource. 12317 * @param[in] sample_actions 12318 * Pointer to sample path actions list. 12319 * @param[in] action_flags 12320 * Holds the actions detected until now. 12321 * @param[out] error 12322 * Pointer to the error structure. 12323 * 12324 * @return 12325 * 0 on success, a negative errno value otherwise and rte_errno is set. 12326 */ 12327 static int 12328 flow_dv_create_action_sample(struct rte_eth_dev *dev, 12329 struct mlx5_flow *dev_flow, 12330 uint32_t num_of_dest, 12331 struct mlx5_flow_dv_sample_resource *res, 12332 struct mlx5_flow_dv_dest_array_resource *mdest_res, 12333 void **sample_actions, 12334 uint64_t action_flags, 12335 struct rte_flow_error *error) 12336 { 12337 /* update normal path action resource into last index of array */ 12338 uint32_t dest_index = MLX5_MAX_DEST_NUM - 1; 12339 struct mlx5_flow_sub_actions_list *sample_act = 12340 &mdest_res->sample_act[dest_index]; 12341 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 12342 struct mlx5_flow_rss_desc *rss_desc; 12343 uint32_t normal_idx = 0; 12344 struct mlx5_hrxq *hrxq; 12345 uint32_t hrxq_idx; 12346 12347 MLX5_ASSERT(wks); 12348 rss_desc = &wks->rss_desc; 12349 if (num_of_dest > 1) { 12350 if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) { 12351 /* Handle QP action for mirroring */ 12352 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 12353 rss_desc, &hrxq_idx); 12354 if (!hrxq) 12355 return rte_flow_error_set 12356 (error, rte_errno, 12357 RTE_FLOW_ERROR_TYPE_ACTION, 12358 NULL, 12359 "cannot create rx queue"); 12360 normal_idx++; 12361 mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx; 12362 sample_act->dr_queue_action = hrxq->action; 12363 if (action_flags & MLX5_FLOW_ACTION_MARK) 12364 dev_flow->handle->rix_hrxq = hrxq_idx; 12365 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 12366 } 12367 if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) { 12368 normal_idx++; 12369 mdest_res->sample_idx[dest_index].rix_encap_decap = 12370 dev_flow->handle->dvh.rix_encap_decap; 12371 sample_act->dr_encap_action = 12372 dev_flow->dv.encap_decap->action; 12373 dev_flow->handle->dvh.rix_encap_decap = 0; 12374 } 12375 if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) { 12376 normal_idx++; 12377 mdest_res->sample_idx[dest_index].rix_port_id_action = 12378 dev_flow->handle->rix_port_id_action; 12379 sample_act->dr_port_id_action = 12380 dev_flow->dv.port_id_action->action; 12381 dev_flow->handle->rix_port_id_action = 0; 12382 } 12383 if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) { 12384 normal_idx++; 12385 mdest_res->sample_idx[dest_index].rix_jump = 12386 dev_flow->handle->rix_jump; 12387 sample_act->dr_jump_action = 12388 dev_flow->dv.jump->action; 12389 dev_flow->handle->rix_jump = 0; 12390 } 12391 sample_act->actions_num = normal_idx; 12392 /* update sample action resource into first index of array */ 12393 mdest_res->ft_type = res->ft_type; 12394 memcpy(&mdest_res->sample_idx[0], &res->sample_idx, 12395 sizeof(struct mlx5_flow_sub_actions_idx)); 12396 memcpy(&mdest_res->sample_act[0], &res->sample_act, 12397 sizeof(struct mlx5_flow_sub_actions_list)); 12398 mdest_res->num_of_dest = num_of_dest; 12399 if (flow_dv_dest_array_resource_register(dev, mdest_res, 12400 dev_flow, error)) 12401 return rte_flow_error_set(error, EINVAL, 12402 RTE_FLOW_ERROR_TYPE_ACTION, 12403 NULL, "can't create sample " 12404 "action"); 12405 } else { 12406 res->sub_actions = sample_actions; 12407 if (flow_dv_sample_resource_register(dev, res, dev_flow, error)) 12408 return rte_flow_error_set(error, EINVAL, 12409 RTE_FLOW_ERROR_TYPE_ACTION, 12410 NULL, 12411 "can't create sample action"); 12412 } 12413 return 0; 12414 } 12415 12416 /** 12417 * Remove an ASO age action from age actions list. 12418 * 12419 * @param[in] dev 12420 * Pointer to the Ethernet device structure. 12421 * @param[in] age 12422 * Pointer to the aso age action handler. 12423 */ 12424 static void 12425 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev, 12426 struct mlx5_aso_age_action *age) 12427 { 12428 struct mlx5_age_info *age_info; 12429 struct mlx5_age_param *age_param = &age->age_params; 12430 struct mlx5_priv *priv = dev->data->dev_private; 12431 uint16_t expected = AGE_CANDIDATE; 12432 12433 age_info = GET_PORT_AGE_INFO(priv); 12434 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 12435 AGE_FREE, false, __ATOMIC_RELAXED, 12436 __ATOMIC_RELAXED)) { 12437 /** 12438 * We need the lock even it is age timeout, 12439 * since age action may still in process. 12440 */ 12441 rte_spinlock_lock(&age_info->aged_sl); 12442 LIST_REMOVE(age, next); 12443 rte_spinlock_unlock(&age_info->aged_sl); 12444 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 12445 } 12446 } 12447 12448 /** 12449 * Release an ASO age action. 12450 * 12451 * @param[in] dev 12452 * Pointer to the Ethernet device structure. 12453 * @param[in] age_idx 12454 * Index of ASO age action to release. 12455 * @param[in] flow 12456 * True if the release operation is during flow destroy operation. 12457 * False if the release operation is during action destroy operation. 12458 * 12459 * @return 12460 * 0 when age action was removed, otherwise the number of references. 12461 */ 12462 static int 12463 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx) 12464 { 12465 struct mlx5_priv *priv = dev->data->dev_private; 12466 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12467 struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx); 12468 uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED); 12469 12470 if (!ret) { 12471 flow_dv_aso_age_remove_from_age(dev, age); 12472 rte_spinlock_lock(&mng->free_sl); 12473 LIST_INSERT_HEAD(&mng->free, age, next); 12474 rte_spinlock_unlock(&mng->free_sl); 12475 } 12476 return ret; 12477 } 12478 12479 /** 12480 * Resize the ASO age pools array by MLX5_ASO_AGE_CONTAINER_RESIZE pools. 12481 * 12482 * @param[in] dev 12483 * Pointer to the Ethernet device structure. 12484 * 12485 * @return 12486 * 0 on success, otherwise negative errno value and rte_errno is set. 12487 */ 12488 static int 12489 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev) 12490 { 12491 struct mlx5_priv *priv = dev->data->dev_private; 12492 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12493 void *old_pools = mng->pools; 12494 uint32_t resize = mng->n + MLX5_ASO_AGE_CONTAINER_RESIZE; 12495 uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize; 12496 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12497 12498 if (!pools) { 12499 rte_errno = ENOMEM; 12500 return -ENOMEM; 12501 } 12502 if (old_pools) { 12503 memcpy(pools, old_pools, 12504 mng->n * sizeof(struct mlx5_flow_counter_pool *)); 12505 mlx5_free(old_pools); 12506 } else { 12507 /* First ASO flow hit allocation - starting ASO data-path. */ 12508 int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh); 12509 12510 if (ret) { 12511 mlx5_free(pools); 12512 return ret; 12513 } 12514 } 12515 mng->n = resize; 12516 mng->pools = pools; 12517 return 0; 12518 } 12519 12520 /** 12521 * Create and initialize a new ASO aging pool. 12522 * 12523 * @param[in] dev 12524 * Pointer to the Ethernet device structure. 12525 * @param[out] age_free 12526 * Where to put the pointer of a new age action. 12527 * 12528 * @return 12529 * The age actions pool pointer and @p age_free is set on success, 12530 * NULL otherwise and rte_errno is set. 12531 */ 12532 static struct mlx5_aso_age_pool * 12533 flow_dv_age_pool_create(struct rte_eth_dev *dev, 12534 struct mlx5_aso_age_action **age_free) 12535 { 12536 struct mlx5_priv *priv = dev->data->dev_private; 12537 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12538 struct mlx5_aso_age_pool *pool = NULL; 12539 struct mlx5_devx_obj *obj = NULL; 12540 uint32_t i; 12541 12542 obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx, 12543 priv->sh->cdev->pdn); 12544 if (!obj) { 12545 rte_errno = ENODATA; 12546 DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX."); 12547 return NULL; 12548 } 12549 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 12550 if (!pool) { 12551 claim_zero(mlx5_devx_cmd_destroy(obj)); 12552 rte_errno = ENOMEM; 12553 return NULL; 12554 } 12555 pool->flow_hit_aso_obj = obj; 12556 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 12557 rte_rwlock_write_lock(&mng->resize_rwl); 12558 pool->index = mng->next; 12559 /* Resize pools array if there is no room for the new pool in it. */ 12560 if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) { 12561 claim_zero(mlx5_devx_cmd_destroy(obj)); 12562 mlx5_free(pool); 12563 rte_rwlock_write_unlock(&mng->resize_rwl); 12564 return NULL; 12565 } 12566 mng->pools[pool->index] = pool; 12567 mng->next++; 12568 rte_rwlock_write_unlock(&mng->resize_rwl); 12569 /* Assign the first action in the new pool, the rest go to free list. */ 12570 *age_free = &pool->actions[0]; 12571 for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) { 12572 pool->actions[i].offset = i; 12573 LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next); 12574 } 12575 return pool; 12576 } 12577 12578 /** 12579 * Allocate a ASO aging bit. 12580 * 12581 * @param[in] dev 12582 * Pointer to the Ethernet device structure. 12583 * @param[out] error 12584 * Pointer to the error structure. 12585 * 12586 * @return 12587 * Index to ASO age action on success, 0 otherwise and rte_errno is set. 12588 */ 12589 static uint32_t 12590 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12591 { 12592 struct mlx5_priv *priv = dev->data->dev_private; 12593 const struct mlx5_aso_age_pool *pool; 12594 struct mlx5_aso_age_action *age_free = NULL; 12595 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12596 12597 MLX5_ASSERT(mng); 12598 /* Try to get the next free age action bit. */ 12599 rte_spinlock_lock(&mng->free_sl); 12600 age_free = LIST_FIRST(&mng->free); 12601 if (age_free) { 12602 LIST_REMOVE(age_free, next); 12603 } else if (!flow_dv_age_pool_create(dev, &age_free)) { 12604 rte_spinlock_unlock(&mng->free_sl); 12605 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12606 NULL, "failed to create ASO age pool"); 12607 return 0; /* 0 is an error. */ 12608 } 12609 rte_spinlock_unlock(&mng->free_sl); 12610 pool = container_of 12611 ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL]) 12612 (age_free - age_free->offset), const struct mlx5_aso_age_pool, 12613 actions); 12614 if (!age_free->dr_action) { 12615 int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0, 12616 error); 12617 12618 if (reg_c < 0) { 12619 rte_flow_error_set(error, rte_errno, 12620 RTE_FLOW_ERROR_TYPE_ACTION, 12621 NULL, "failed to get reg_c " 12622 "for ASO flow hit"); 12623 return 0; /* 0 is an error. */ 12624 } 12625 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 12626 age_free->dr_action = mlx5_glue->dv_create_flow_action_aso 12627 (priv->sh->rx_domain, 12628 pool->flow_hit_aso_obj->obj, age_free->offset, 12629 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET, 12630 (reg_c - REG_C_0)); 12631 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 12632 if (!age_free->dr_action) { 12633 rte_errno = errno; 12634 rte_spinlock_lock(&mng->free_sl); 12635 LIST_INSERT_HEAD(&mng->free, age_free, next); 12636 rte_spinlock_unlock(&mng->free_sl); 12637 rte_flow_error_set(error, rte_errno, 12638 RTE_FLOW_ERROR_TYPE_ACTION, 12639 NULL, "failed to create ASO " 12640 "flow hit action"); 12641 return 0; /* 0 is an error. */ 12642 } 12643 } 12644 __atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED); 12645 return pool->index | ((age_free->offset + 1) << 16); 12646 } 12647 12648 /** 12649 * Initialize flow ASO age parameters. 12650 * 12651 * @param[in] dev 12652 * Pointer to rte_eth_dev structure. 12653 * @param[in] age_idx 12654 * Index of ASO age action. 12655 * @param[in] context 12656 * Pointer to flow counter age context. 12657 * @param[in] timeout 12658 * Aging timeout in seconds. 12659 * 12660 */ 12661 static void 12662 flow_dv_aso_age_params_init(struct rte_eth_dev *dev, 12663 uint32_t age_idx, 12664 void *context, 12665 uint32_t timeout) 12666 { 12667 struct mlx5_aso_age_action *aso_age; 12668 12669 aso_age = flow_aso_age_get_by_idx(dev, age_idx); 12670 MLX5_ASSERT(aso_age); 12671 aso_age->age_params.context = context; 12672 aso_age->age_params.timeout = timeout; 12673 aso_age->age_params.port_id = dev->data->port_id; 12674 __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0, 12675 __ATOMIC_RELAXED); 12676 __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE, 12677 __ATOMIC_RELAXED); 12678 } 12679 12680 static void 12681 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask, 12682 void *headers) 12683 { 12684 /* 12685 * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to 12686 * both mask and value, therefore ether can be used. 12687 * In SWS SW_V mode mask points to item mask and value points to item 12688 * spec. Integrity item value is used only if matching mask is set. 12689 * Use mask reference here to keep SWS functionality. 12690 */ 12691 if (mask->l4_ok) { 12692 /* RTE l4_ok filter aggregates hardware l4_ok and 12693 * l4_checksum_ok filters. 12694 * Positive RTE l4_ok match requires hardware match on both L4 12695 * hardware integrity bits. 12696 * PMD supports positive integrity item semantics only. 12697 */ 12698 MLX5_SET(fte_match_set_lyr_2_4, headers, l4_ok, 1); 12699 MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1); 12700 } else if (mask->l4_csum_ok) { 12701 MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1); 12702 } 12703 } 12704 12705 static void 12706 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask, 12707 void *headers, bool is_ipv4) 12708 { 12709 /* 12710 * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to 12711 * both mask and value, therefore ether can be used. 12712 * In SWS SW_V mode mask points to item mask and value points to item 12713 * spec. Integrity item value used only if matching mask is set. 12714 * Use mask reference here to keep SWS functionality. 12715 */ 12716 if (mask->l3_ok) { 12717 /* RTE l3_ok filter aggregates for IPv4 hardware l3_ok and 12718 * ipv4_csum_ok filters. 12719 * Positive RTE l3_ok match requires hardware match on both L3 12720 * hardware integrity bits. 12721 * PMD supports positive integrity item semantics only. 12722 */ 12723 MLX5_SET(fte_match_set_lyr_2_4, headers, l3_ok, 1); 12724 if (is_ipv4) { 12725 MLX5_SET(fte_match_set_lyr_2_4, headers, 12726 ipv4_checksum_ok, 1); 12727 } 12728 } else if (is_ipv4 && mask->ipv4_csum_ok) { 12729 MLX5_SET(fte_match_set_lyr_2_4, headers, ipv4_checksum_ok, 1); 12730 } 12731 } 12732 12733 static void 12734 set_integrity_bits(void *headers, const struct rte_flow_item *integrity_item, 12735 bool is_l3_ip4, uint32_t key_type) 12736 { 12737 const struct rte_flow_item_integrity *spec; 12738 const struct rte_flow_item_integrity *mask; 12739 12740 /* Integrity bits validation cleared spec pointer */ 12741 if (MLX5_ITEM_VALID(integrity_item, key_type)) 12742 return; 12743 MLX5_ITEM_UPDATE(integrity_item, key_type, spec, mask, 12744 &rte_flow_item_integrity_mask); 12745 flow_dv_translate_integrity_l3(mask, headers, is_l3_ip4); 12746 flow_dv_translate_integrity_l4(mask, headers); 12747 } 12748 12749 static void 12750 flow_dv_translate_item_integrity_post(void *key, 12751 const 12752 struct rte_flow_item *integrity_items[2], 12753 uint64_t pattern_flags, uint32_t key_type) 12754 { 12755 void *headers; 12756 bool is_l3_ip4; 12757 12758 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) { 12759 headers = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 12760 is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) != 12761 0; 12762 set_integrity_bits(headers, integrity_items[1], is_l3_ip4, 12763 key_type); 12764 } 12765 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) { 12766 headers = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 12767 is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) != 12768 0; 12769 set_integrity_bits(headers, integrity_items[0], is_l3_ip4, 12770 key_type); 12771 } 12772 } 12773 12774 static uint64_t 12775 flow_dv_translate_item_integrity(const struct rte_flow_item *item, 12776 struct mlx5_dv_matcher_workspace *wks, 12777 uint64_t key_type) 12778 { 12779 if ((key_type & MLX5_SET_MATCHER_SW) != 0) { 12780 const struct rte_flow_item_integrity 12781 *spec = (typeof(spec))item->spec; 12782 12783 /* SWS integrity bits validation cleared spec pointer */ 12784 if (spec->level > 1) { 12785 wks->integrity_items[1] = item; 12786 wks->last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; 12787 } else { 12788 wks->integrity_items[0] = item; 12789 wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; 12790 } 12791 } else { 12792 /* HWS supports outer integrity only */ 12793 wks->integrity_items[0] = item; 12794 wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; 12795 } 12796 return wks->last_item; 12797 } 12798 12799 /** 12800 * Prepares DV flow counter with aging configuration. 12801 * Gets it by index when exists, creates a new one when doesn't. 12802 * 12803 * @param[in] dev 12804 * Pointer to rte_eth_dev structure. 12805 * @param[in] dev_flow 12806 * Pointer to the mlx5_flow. 12807 * @param[in, out] flow 12808 * Pointer to the sub flow. 12809 * @param[in] count 12810 * Pointer to the counter action configuration. 12811 * @param[in] age 12812 * Pointer to the aging action configuration. 12813 * @param[out] error 12814 * Pointer to the error structure. 12815 * 12816 * @return 12817 * Pointer to the counter, NULL otherwise. 12818 */ 12819 static struct mlx5_flow_counter * 12820 flow_dv_prepare_counter(struct rte_eth_dev *dev, 12821 struct mlx5_flow *dev_flow, 12822 struct rte_flow *flow, 12823 const struct rte_flow_action_count *count, 12824 const struct rte_flow_action_age *age, 12825 struct rte_flow_error *error) 12826 { 12827 if (!flow->counter) { 12828 flow->counter = flow_dv_translate_create_counter(dev, dev_flow, 12829 count, age); 12830 if (!flow->counter) { 12831 rte_flow_error_set(error, rte_errno, 12832 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12833 "cannot create counter object."); 12834 return NULL; 12835 } 12836 } 12837 return flow_dv_counter_get_by_idx(dev, flow->counter, NULL); 12838 } 12839 12840 /* 12841 * Release an ASO CT action by its own device. 12842 * 12843 * @param[in] dev 12844 * Pointer to the Ethernet device structure. 12845 * @param[in] idx 12846 * Index of ASO CT action to release. 12847 * 12848 * @return 12849 * 0 when CT action was removed, otherwise the number of references. 12850 */ 12851 static inline int 12852 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx) 12853 { 12854 struct mlx5_priv *priv = dev->data->dev_private; 12855 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12856 uint32_t ret; 12857 struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12858 enum mlx5_aso_ct_state state = 12859 __atomic_load_n(&ct->state, __ATOMIC_RELAXED); 12860 12861 /* Cannot release when CT is in the ASO SQ. */ 12862 if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY) 12863 return -1; 12864 ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED); 12865 if (!ret) { 12866 if (ct->dr_action_orig) { 12867 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12868 claim_zero(mlx5_glue->destroy_flow_action 12869 (ct->dr_action_orig)); 12870 #endif 12871 ct->dr_action_orig = NULL; 12872 } 12873 if (ct->dr_action_rply) { 12874 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12875 claim_zero(mlx5_glue->destroy_flow_action 12876 (ct->dr_action_rply)); 12877 #endif 12878 ct->dr_action_rply = NULL; 12879 } 12880 /* Clear the state to free, no need in 1st allocation. */ 12881 MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE); 12882 rte_spinlock_lock(&mng->ct_sl); 12883 LIST_INSERT_HEAD(&mng->free_cts, ct, next); 12884 rte_spinlock_unlock(&mng->ct_sl); 12885 } 12886 return (int)ret; 12887 } 12888 12889 static inline int 12890 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx, 12891 struct rte_flow_error *error) 12892 { 12893 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx); 12894 uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx); 12895 struct rte_eth_dev *owndev = &rte_eth_devices[owner]; 12896 int ret; 12897 12898 MLX5_ASSERT(owner < RTE_MAX_ETHPORTS); 12899 if (dev->data->dev_started != 1) 12900 return rte_flow_error_set(error, EAGAIN, 12901 RTE_FLOW_ERROR_TYPE_ACTION, 12902 NULL, 12903 "Indirect CT action cannot be destroyed when the port is stopped"); 12904 ret = flow_dv_aso_ct_dev_release(owndev, idx); 12905 if (ret < 0) 12906 return rte_flow_error_set(error, EAGAIN, 12907 RTE_FLOW_ERROR_TYPE_ACTION, 12908 NULL, 12909 "Current state prevents indirect CT action from being destroyed"); 12910 return ret; 12911 } 12912 12913 /* 12914 * Resize the ASO CT pools array by 64 pools. 12915 * 12916 * @param[in] dev 12917 * Pointer to the Ethernet device structure. 12918 * 12919 * @return 12920 * 0 on success, otherwise negative errno value and rte_errno is set. 12921 */ 12922 static int 12923 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev) 12924 { 12925 struct mlx5_priv *priv = dev->data->dev_private; 12926 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12927 void *old_pools = mng->pools; 12928 /* Magic number now, need a macro. */ 12929 uint32_t resize = mng->n + 64; 12930 uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize; 12931 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12932 12933 if (!pools) { 12934 rte_errno = ENOMEM; 12935 return -rte_errno; 12936 } 12937 rte_rwlock_write_lock(&mng->resize_rwl); 12938 /* ASO SQ/QP was already initialized in the startup. */ 12939 if (old_pools) { 12940 /* Realloc could be an alternative choice. */ 12941 rte_memcpy(pools, old_pools, 12942 mng->n * sizeof(struct mlx5_aso_ct_pool *)); 12943 mlx5_free(old_pools); 12944 } 12945 mng->n = resize; 12946 mng->pools = pools; 12947 rte_rwlock_write_unlock(&mng->resize_rwl); 12948 return 0; 12949 } 12950 12951 /* 12952 * Create and initialize a new ASO CT pool. 12953 * 12954 * @param[in] dev 12955 * Pointer to the Ethernet device structure. 12956 * @param[out] ct_free 12957 * Where to put the pointer of a new CT action. 12958 * 12959 * @return 12960 * The CT actions pool pointer and @p ct_free is set on success, 12961 * NULL otherwise and rte_errno is set. 12962 */ 12963 static struct mlx5_aso_ct_pool * 12964 flow_dv_ct_pool_create(struct rte_eth_dev *dev, 12965 struct mlx5_aso_ct_action **ct_free) 12966 { 12967 struct mlx5_priv *priv = dev->data->dev_private; 12968 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12969 struct mlx5_aso_ct_pool *pool = NULL; 12970 struct mlx5_devx_obj *obj = NULL; 12971 uint32_t i; 12972 uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL); 12973 size_t mem_size; 12974 12975 obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx, 12976 priv->sh->cdev->pdn, 12977 log_obj_size); 12978 if (!obj) { 12979 rte_errno = ENODATA; 12980 DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); 12981 return NULL; 12982 } 12983 mem_size = sizeof(struct mlx5_aso_ct_action) * 12984 MLX5_ASO_CT_ACTIONS_PER_POOL + 12985 sizeof(*pool); 12986 pool = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12987 if (!pool) { 12988 rte_errno = ENOMEM; 12989 claim_zero(mlx5_devx_cmd_destroy(obj)); 12990 return NULL; 12991 } 12992 pool->devx_obj = obj; 12993 pool->index = mng->next; 12994 /* Resize pools array if there is no room for the new pool in it. */ 12995 if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) { 12996 claim_zero(mlx5_devx_cmd_destroy(obj)); 12997 mlx5_free(pool); 12998 return NULL; 12999 } 13000 mng->pools[pool->index] = pool; 13001 mng->next++; 13002 /* Assign the first action in the new pool, the rest go to free list. */ 13003 *ct_free = &pool->actions[0]; 13004 /* Lock outside, the list operation is safe here. */ 13005 for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) { 13006 /* refcnt is 0 when allocating the memory. */ 13007 pool->actions[i].offset = i; 13008 LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next); 13009 } 13010 return pool; 13011 } 13012 13013 /* 13014 * Allocate a ASO CT action from free list. 13015 * 13016 * @param[in] dev 13017 * Pointer to the Ethernet device structure. 13018 * @param[out] error 13019 * Pointer to the error structure. 13020 * 13021 * @return 13022 * Index to ASO CT action on success, 0 otherwise and rte_errno is set. 13023 */ 13024 static uint32_t 13025 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 13026 { 13027 struct mlx5_priv *priv = dev->data->dev_private; 13028 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 13029 struct mlx5_aso_ct_action *ct = NULL; 13030 struct mlx5_aso_ct_pool *pool; 13031 uint8_t reg_c; 13032 uint32_t ct_idx; 13033 13034 MLX5_ASSERT(mng); 13035 if (!priv->sh->cdev->config.devx) { 13036 rte_errno = ENOTSUP; 13037 return 0; 13038 } 13039 /* Get a free CT action, if no, a new pool will be created. */ 13040 rte_spinlock_lock(&mng->ct_sl); 13041 ct = LIST_FIRST(&mng->free_cts); 13042 if (ct) { 13043 LIST_REMOVE(ct, next); 13044 } else if (!flow_dv_ct_pool_create(dev, &ct)) { 13045 rte_spinlock_unlock(&mng->ct_sl); 13046 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 13047 NULL, "failed to create ASO CT pool"); 13048 return 0; 13049 } 13050 rte_spinlock_unlock(&mng->ct_sl); 13051 pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); 13052 ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset); 13053 /* 0: inactive, 1: created, 2+: used by flows. */ 13054 __atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED); 13055 reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error); 13056 if (!ct->dr_action_orig) { 13057 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 13058 ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso 13059 (priv->sh->rx_domain, pool->devx_obj->obj, 13060 ct->offset, 13061 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR, 13062 reg_c - REG_C_0); 13063 #else 13064 RTE_SET_USED(reg_c); 13065 #endif 13066 if (!ct->dr_action_orig) { 13067 flow_dv_aso_ct_dev_release(dev, ct_idx); 13068 rte_flow_error_set(error, rte_errno, 13069 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 13070 "failed to create ASO CT action"); 13071 return 0; 13072 } 13073 } 13074 if (!ct->dr_action_rply) { 13075 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 13076 ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso 13077 (priv->sh->rx_domain, pool->devx_obj->obj, 13078 ct->offset, 13079 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER, 13080 reg_c - REG_C_0); 13081 #endif 13082 if (!ct->dr_action_rply) { 13083 flow_dv_aso_ct_dev_release(dev, ct_idx); 13084 rte_flow_error_set(error, rte_errno, 13085 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 13086 "failed to create ASO CT action"); 13087 return 0; 13088 } 13089 } 13090 return ct_idx; 13091 } 13092 13093 /* 13094 * Create a conntrack object with context and actions by using ASO mechanism. 13095 * 13096 * @param[in] dev 13097 * Pointer to rte_eth_dev structure. 13098 * @param[in] pro 13099 * Pointer to conntrack information profile. 13100 * @param[out] error 13101 * Pointer to the error structure. 13102 * 13103 * @return 13104 * Index to conntrack object on success, 0 otherwise. 13105 */ 13106 static uint32_t 13107 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, 13108 const struct rte_flow_action_conntrack *pro, 13109 struct rte_flow_error *error) 13110 { 13111 struct mlx5_priv *priv = dev->data->dev_private; 13112 struct mlx5_dev_ctx_shared *sh = priv->sh; 13113 struct mlx5_aso_ct_action *ct; 13114 uint32_t idx; 13115 13116 if (!sh->ct_aso_en) 13117 return rte_flow_error_set(error, ENOTSUP, 13118 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 13119 "Connection is not supported"); 13120 idx = flow_dv_aso_ct_alloc(dev, error); 13121 if (!idx) 13122 return rte_flow_error_set(error, rte_errno, 13123 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 13124 "Failed to allocate CT object"); 13125 ct = flow_aso_ct_get_by_dev_idx(dev, idx); 13126 if (mlx5_aso_ct_update_by_wqe(sh, MLX5_HW_INV_QUEUE, ct, pro, NULL, true)) { 13127 flow_dv_aso_ct_dev_release(dev, idx); 13128 rte_flow_error_set(error, EBUSY, 13129 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 13130 "Failed to update CT"); 13131 return 0; 13132 } 13133 ct->is_original = !!pro->is_original_dir; 13134 ct->peer = pro->peer_port; 13135 return idx; 13136 } 13137 13138 /** 13139 * Fill the flow matcher with DV spec. 13140 * 13141 * @param[in] dev 13142 * Pointer to rte_eth_dev structure. 13143 * @param[in] items 13144 * Pointer to the list of items. 13145 * @param[in] wks 13146 * Pointer to the matcher workspace. 13147 * @param[in] key 13148 * Pointer to the flow matcher key. 13149 * @param[in] key_type 13150 * Key type. 13151 * @param[out] error 13152 * Pointer to the error structure. 13153 * 13154 * @return 13155 * 0 on success, a negative errno value otherwise and rte_errno is set. 13156 */ 13157 static int 13158 flow_dv_translate_items(struct rte_eth_dev *dev, 13159 const struct rte_flow_item *items, 13160 struct mlx5_dv_matcher_workspace *wks, 13161 void *key, uint32_t key_type, 13162 struct rte_flow_error *error) 13163 { 13164 struct mlx5_flow_rss_desc *rss_desc = wks->rss_desc; 13165 uint8_t next_protocol = wks->next_protocol; 13166 int tunnel = !!(wks->item_flags & MLX5_FLOW_LAYER_TUNNEL); 13167 int item_type = items->type; 13168 uint64_t last_item = wks->last_item; 13169 int ret; 13170 13171 switch (item_type) { 13172 case RTE_FLOW_ITEM_TYPE_ESP: 13173 flow_dv_translate_item_esp(key, items, tunnel, key_type); 13174 wks->priority = MLX5_PRIORITY_MAP_L4; 13175 last_item = MLX5_FLOW_ITEM_ESP; 13176 break; 13177 case RTE_FLOW_ITEM_TYPE_PORT_ID: 13178 flow_dv_translate_item_port_id 13179 (dev, key, items, wks->attr, key_type); 13180 last_item = MLX5_FLOW_ITEM_PORT_ID; 13181 break; 13182 case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR: 13183 flow_dv_translate_item_port_representor 13184 (dev, key, key_type); 13185 last_item = MLX5_FLOW_ITEM_PORT_REPRESENTOR; 13186 break; 13187 case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: 13188 flow_dv_translate_item_represented_port 13189 (dev, key, items, wks->attr, key_type); 13190 last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT; 13191 break; 13192 case RTE_FLOW_ITEM_TYPE_ETH: 13193 flow_dv_translate_item_eth(key, items, tunnel, 13194 wks->group, key_type); 13195 wks->priority = wks->action_flags & 13196 MLX5_FLOW_ACTION_DEFAULT_MISS && 13197 !wks->external ? 13198 MLX5_PRIORITY_MAP_L3 : 13199 MLX5_PRIORITY_MAP_L2; 13200 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 13201 MLX5_FLOW_LAYER_OUTER_L2; 13202 break; 13203 case RTE_FLOW_ITEM_TYPE_VLAN: 13204 flow_dv_translate_item_vlan(key, items, tunnel, wks, key_type); 13205 wks->priority = MLX5_PRIORITY_MAP_L2; 13206 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 13207 MLX5_FLOW_LAYER_INNER_VLAN) : 13208 (MLX5_FLOW_LAYER_OUTER_L2 | 13209 MLX5_FLOW_LAYER_OUTER_VLAN); 13210 break; 13211 case RTE_FLOW_ITEM_TYPE_IPV4: 13212 mlx5_flow_tunnel_ip_check(items, next_protocol, 13213 &wks->item_flags, &tunnel); 13214 flow_dv_translate_item_ipv4(key, items, tunnel, 13215 wks->group, key_type); 13216 wks->priority = MLX5_PRIORITY_MAP_L3; 13217 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 13218 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 13219 if (items->mask != NULL && 13220 items->spec != NULL && 13221 ((const struct rte_flow_item_ipv4 *) 13222 items->mask)->hdr.next_proto_id) { 13223 next_protocol = 13224 ((const struct rte_flow_item_ipv4 *) 13225 (items->spec))->hdr.next_proto_id; 13226 next_protocol &= 13227 ((const struct rte_flow_item_ipv4 *) 13228 (items->mask))->hdr.next_proto_id; 13229 } else if (key_type == MLX5_SET_MATCHER_HS_M && 13230 items->mask != NULL) { 13231 next_protocol = ((const struct rte_flow_item_ipv4 *) 13232 (items->mask))->hdr.next_proto_id; 13233 } else if (key_type == MLX5_SET_MATCHER_HS_V && 13234 items->spec != NULL) { 13235 next_protocol = ((const struct rte_flow_item_ipv4 *) 13236 (items->spec))->hdr.next_proto_id; 13237 } else { 13238 /* Reset for inner layer. */ 13239 next_protocol = 0xff; 13240 } 13241 break; 13242 case RTE_FLOW_ITEM_TYPE_IPV6: 13243 mlx5_flow_tunnel_ip_check(items, next_protocol, 13244 &wks->item_flags, &tunnel); 13245 flow_dv_translate_item_ipv6(key, items, tunnel, 13246 wks->group, key_type); 13247 wks->priority = MLX5_PRIORITY_MAP_L3; 13248 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 13249 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 13250 if (items->mask != NULL && 13251 items->spec != NULL && 13252 ((const struct rte_flow_item_ipv6 *) 13253 items->mask)->hdr.proto) { 13254 next_protocol = 13255 ((const struct rte_flow_item_ipv6 *) 13256 items->spec)->hdr.proto; 13257 next_protocol &= 13258 ((const struct rte_flow_item_ipv6 *) 13259 items->mask)->hdr.proto; 13260 } else if (key_type == MLX5_SET_MATCHER_HS_M && 13261 items->mask != NULL) { 13262 next_protocol = ((const struct rte_flow_item_ipv6 *) 13263 (items->mask))->hdr.proto; 13264 } else if (key_type == MLX5_SET_MATCHER_HS_V && 13265 items->spec != NULL) { 13266 next_protocol = ((const struct rte_flow_item_ipv6 *) 13267 (items->spec))->hdr.proto; 13268 } else { 13269 /* Reset for inner layer. */ 13270 next_protocol = 0xff; 13271 } 13272 break; 13273 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 13274 flow_dv_translate_item_ipv6_frag_ext 13275 (key, items, tunnel, key_type); 13276 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 13277 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 13278 if (items->mask != NULL && 13279 items->spec != NULL && 13280 ((const struct rte_flow_item_ipv6_frag_ext *) 13281 items->mask)->hdr.next_header) { 13282 next_protocol = 13283 ((const struct rte_flow_item_ipv6_frag_ext *) 13284 items->spec)->hdr.next_header; 13285 next_protocol &= 13286 ((const struct rte_flow_item_ipv6_frag_ext *) 13287 items->mask)->hdr.next_header; 13288 } else if (key_type == MLX5_SET_MATCHER_HS_M && 13289 items->mask != NULL) { 13290 next_protocol = ((const struct rte_flow_item_ipv6_frag_ext *) 13291 (items->mask))->hdr.next_header; 13292 } else if (key_type == MLX5_SET_MATCHER_HS_V && 13293 items->spec != NULL) { 13294 next_protocol = ((const struct rte_flow_item_ipv6_frag_ext *) 13295 (items->spec))->hdr.next_header; 13296 } else { 13297 /* Reset for inner layer. */ 13298 next_protocol = 0xff; 13299 } 13300 break; 13301 case RTE_FLOW_ITEM_TYPE_TCP: 13302 flow_dv_translate_item_tcp(key, items, tunnel, key_type); 13303 wks->priority = MLX5_PRIORITY_MAP_L4; 13304 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 13305 MLX5_FLOW_LAYER_OUTER_L4_TCP; 13306 break; 13307 case RTE_FLOW_ITEM_TYPE_UDP: 13308 flow_dv_translate_item_udp(key, items, tunnel, wks, key_type); 13309 wks->priority = MLX5_PRIORITY_MAP_L4; 13310 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 13311 MLX5_FLOW_LAYER_OUTER_L4_UDP; 13312 break; 13313 case RTE_FLOW_ITEM_TYPE_GRE: 13314 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13315 wks->tunnel_item = items; 13316 wks->gre_item = items; 13317 last_item = MLX5_FLOW_LAYER_GRE; 13318 break; 13319 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 13320 flow_dv_translate_item_gre_key(key, items, key_type); 13321 last_item = MLX5_FLOW_LAYER_GRE_KEY; 13322 break; 13323 case RTE_FLOW_ITEM_TYPE_GRE_OPTION: 13324 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13325 wks->tunnel_item = items; 13326 last_item = MLX5_FLOW_LAYER_GRE; 13327 break; 13328 case RTE_FLOW_ITEM_TYPE_NVGRE: 13329 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13330 wks->tunnel_item = items; 13331 last_item = MLX5_FLOW_LAYER_GRE; 13332 break; 13333 case RTE_FLOW_ITEM_TYPE_VXLAN: 13334 flow_dv_translate_item_vxlan(dev, wks->attr, key, 13335 items, tunnel, wks, key_type); 13336 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13337 last_item = MLX5_FLOW_LAYER_VXLAN; 13338 break; 13339 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 13340 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13341 wks->tunnel_item = items; 13342 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 13343 break; 13344 case RTE_FLOW_ITEM_TYPE_GENEVE: 13345 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13346 wks->tunnel_item = items; 13347 last_item = MLX5_FLOW_LAYER_GENEVE; 13348 break; 13349 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 13350 ret = flow_dv_translate_item_geneve_opt 13351 (dev, key, items, key_type, error); 13352 if (ret) 13353 return rte_flow_error_set(error, -ret, 13354 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13355 "cannot create GENEVE TLV option"); 13356 wks->geneve_tlv_option = 1; 13357 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 13358 break; 13359 case RTE_FLOW_ITEM_TYPE_MPLS: 13360 flow_dv_translate_item_mpls(key, items, last_item, 13361 tunnel, key_type); 13362 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13363 last_item = MLX5_FLOW_LAYER_MPLS; 13364 break; 13365 case RTE_FLOW_ITEM_TYPE_MARK: 13366 flow_dv_translate_item_mark(dev, key, items, key_type); 13367 last_item = MLX5_FLOW_ITEM_MARK; 13368 break; 13369 case RTE_FLOW_ITEM_TYPE_META: 13370 flow_dv_translate_item_meta 13371 (dev, key, wks->attr, items, key_type); 13372 last_item = MLX5_FLOW_ITEM_METADATA; 13373 break; 13374 case RTE_FLOW_ITEM_TYPE_ICMP: 13375 flow_dv_translate_item_icmp(key, items, tunnel, key_type); 13376 wks->priority = MLX5_PRIORITY_MAP_L4; 13377 last_item = MLX5_FLOW_LAYER_ICMP; 13378 break; 13379 case RTE_FLOW_ITEM_TYPE_ICMP6: 13380 flow_dv_translate_item_icmp6(key, items, tunnel, key_type); 13381 wks->priority = MLX5_PRIORITY_MAP_L4; 13382 last_item = MLX5_FLOW_LAYER_ICMP6; 13383 break; 13384 case RTE_FLOW_ITEM_TYPE_TAG: 13385 flow_dv_translate_item_tag(dev, key, items, key_type); 13386 last_item = MLX5_FLOW_ITEM_TAG; 13387 break; 13388 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 13389 flow_dv_translate_mlx5_item_tag(dev, key, items, key_type); 13390 last_item = MLX5_FLOW_ITEM_TAG; 13391 break; 13392 case MLX5_RTE_FLOW_ITEM_TYPE_SQ: 13393 flow_dv_translate_item_sq(key, items, key_type); 13394 last_item = MLX5_FLOW_ITEM_SQ; 13395 break; 13396 case RTE_FLOW_ITEM_TYPE_GTP: 13397 flow_dv_translate_item_gtp(key, items, tunnel, key_type); 13398 wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13399 last_item = MLX5_FLOW_LAYER_GTP; 13400 break; 13401 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 13402 ret = flow_dv_translate_item_gtp_psc(key, items, key_type); 13403 if (ret) 13404 return rte_flow_error_set(error, -ret, 13405 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13406 "cannot create GTP PSC item"); 13407 last_item = MLX5_FLOW_LAYER_GTP_PSC; 13408 break; 13409 case RTE_FLOW_ITEM_TYPE_ECPRI: 13410 if (!mlx5_flex_parser_ecpri_exist(dev)) { 13411 /* Create it only the first time to be used. */ 13412 ret = mlx5_flex_parser_ecpri_alloc(dev); 13413 if (ret) 13414 return rte_flow_error_set 13415 (error, -ret, 13416 RTE_FLOW_ERROR_TYPE_ITEM, 13417 NULL, 13418 "cannot create eCPRI parser"); 13419 } 13420 flow_dv_translate_item_ecpri 13421 (dev, key, items, last_item, key_type); 13422 /* No other protocol should follow eCPRI layer. */ 13423 last_item = MLX5_FLOW_LAYER_ECPRI; 13424 break; 13425 case RTE_FLOW_ITEM_TYPE_METER_COLOR: 13426 flow_dv_translate_item_meter_color(dev, key, items, key_type); 13427 last_item = MLX5_FLOW_ITEM_METER_COLOR; 13428 break; 13429 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 13430 last_item = flow_dv_translate_item_integrity(items, 13431 wks, key_type); 13432 break; 13433 default: 13434 break; 13435 } 13436 wks->item_flags |= last_item; 13437 wks->last_item = last_item; 13438 wks->next_protocol = next_protocol; 13439 return 0; 13440 } 13441 13442 /** 13443 * Fill the HW steering flow with DV spec. 13444 * 13445 * @param[in] items 13446 * Pointer to the list of items. 13447 * @param[in] attr 13448 * Pointer to the flow attributes. 13449 * @param[in] key 13450 * Pointer to the flow matcher key. 13451 * @param[in] key_type 13452 * Key type. 13453 * @param[in, out] item_flags 13454 * Pointer to the flow item flags. 13455 * @param[out] error 13456 * Pointer to the error structure. 13457 * 13458 * @return 13459 * 0 on success, a negative errno value otherwise and rte_errno is set. 13460 */ 13461 int 13462 flow_dv_translate_items_hws(const struct rte_flow_item *items, 13463 struct mlx5_flow_attr *attr, void *key, 13464 uint32_t key_type, uint64_t *item_flags, 13465 uint8_t *match_criteria, 13466 struct rte_flow_error *error) 13467 { 13468 struct mlx5_flow_workspace *flow_wks = mlx5_flow_push_thread_workspace(); 13469 struct mlx5_flow_rss_desc rss_desc = { .level = attr->rss_level }; 13470 struct rte_flow_attr rattr = { 13471 .group = attr->group, 13472 .priority = attr->priority, 13473 .ingress = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_NIC_RX), 13474 .egress = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_NIC_TX), 13475 .transfer = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_FDB), 13476 }; 13477 struct mlx5_dv_matcher_workspace wks = { 13478 .action_flags = attr->act_flags, 13479 .item_flags = item_flags ? *item_flags : 0, 13480 .external = 0, 13481 .next_protocol = 0xff, 13482 .attr = &rattr, 13483 .rss_desc = &rss_desc, 13484 }; 13485 int ret = 0; 13486 13487 RTE_SET_USED(flow_wks); 13488 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 13489 if (!mlx5_flow_os_item_supported(items->type)) { 13490 ret = rte_flow_error_set(error, ENOTSUP, 13491 RTE_FLOW_ERROR_TYPE_ITEM, 13492 NULL, "item not supported"); 13493 goto exit; 13494 } 13495 ret = flow_dv_translate_items(&rte_eth_devices[attr->port_id], 13496 items, &wks, key, key_type, NULL); 13497 if (ret) 13498 goto exit; 13499 } 13500 if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) { 13501 flow_dv_translate_item_integrity_post(key, 13502 wks.integrity_items, 13503 wks.item_flags, 13504 key_type); 13505 } 13506 if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) { 13507 flow_dv_translate_item_vxlan_gpe(key, 13508 wks.tunnel_item, 13509 wks.item_flags, 13510 key_type); 13511 } else if (wks.item_flags & MLX5_FLOW_LAYER_GENEVE) { 13512 flow_dv_translate_item_geneve(key, 13513 wks.tunnel_item, 13514 wks.item_flags, 13515 key_type); 13516 } else if (wks.item_flags & MLX5_FLOW_LAYER_GRE) { 13517 if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE) { 13518 flow_dv_translate_item_gre(key, 13519 wks.tunnel_item, 13520 wks.item_flags, 13521 key_type); 13522 } else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE_OPTION) { 13523 flow_dv_translate_item_gre_option(key, 13524 wks.tunnel_item, 13525 wks.gre_item, 13526 wks.item_flags, 13527 key_type); 13528 } else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_NVGRE) { 13529 flow_dv_translate_item_nvgre(key, 13530 wks.tunnel_item, 13531 wks.item_flags, 13532 key_type); 13533 } else { 13534 MLX5_ASSERT(false); 13535 } 13536 } 13537 13538 if (match_criteria) 13539 *match_criteria = flow_dv_matcher_enable(key); 13540 if (item_flags) 13541 *item_flags = wks.item_flags; 13542 exit: 13543 mlx5_flow_pop_thread_workspace(); 13544 return ret; 13545 } 13546 13547 /** 13548 * Fill the SW steering flow with DV spec. 13549 * 13550 * @param[in] dev 13551 * Pointer to rte_eth_dev structure. 13552 * @param[in, out] dev_flow 13553 * Pointer to the sub flow. 13554 * @param[in] attr 13555 * Pointer to the flow attributes. 13556 * @param[in] items 13557 * Pointer to the list of items. 13558 * @param[in, out] matcher 13559 * Pointer to the flow matcher. 13560 * @param[out] error 13561 * Pointer to the error structure. 13562 * 13563 * @return 13564 * 0 on success, a negative errno value otherwise and rte_errno is set. 13565 */ 13566 static int 13567 flow_dv_translate_items_sws(struct rte_eth_dev *dev, 13568 struct mlx5_flow *dev_flow, 13569 const struct rte_flow_attr *attr, 13570 const struct rte_flow_item *items, 13571 struct mlx5_flow_dv_matcher *matcher, 13572 struct rte_flow_error *error) 13573 { 13574 struct mlx5_priv *priv = dev->data->dev_private; 13575 void *match_mask = matcher->mask.buf; 13576 void *match_value = dev_flow->dv.value.buf; 13577 struct mlx5_dv_matcher_workspace wks = { 13578 .action_flags = dev_flow->act_flags, 13579 .item_flags = 0, 13580 .external = dev_flow->external, 13581 .next_protocol = 0xff, 13582 .group = dev_flow->dv.group, 13583 .attr = attr, 13584 .rss_desc = &((struct mlx5_flow_workspace *) 13585 mlx5_flow_get_thread_workspace())->rss_desc, 13586 }; 13587 struct mlx5_dv_matcher_workspace wks_m = wks; 13588 int item_type; 13589 int ret = 0; 13590 int tunnel; 13591 13592 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 13593 if (!mlx5_flow_os_item_supported(items->type)) 13594 return rte_flow_error_set(error, ENOTSUP, 13595 RTE_FLOW_ERROR_TYPE_ITEM, 13596 NULL, "item not supported"); 13597 tunnel = !!(wks.item_flags & MLX5_FLOW_LAYER_TUNNEL); 13598 item_type = items->type; 13599 switch (item_type) { 13600 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 13601 flow_dv_translate_item_aso_ct(dev, match_mask, 13602 match_value, items); 13603 break; 13604 case RTE_FLOW_ITEM_TYPE_FLEX: 13605 flow_dv_translate_item_flex(dev, match_mask, 13606 match_value, items, 13607 dev_flow, tunnel != 0); 13608 wks.last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX : 13609 MLX5_FLOW_ITEM_OUTER_FLEX; 13610 break; 13611 case MLX5_RTE_FLOW_ITEM_TYPE_SQ: 13612 flow_dv_translate_item_sq(match_value, items, 13613 MLX5_SET_MATCHER_SW_V); 13614 flow_dv_translate_item_sq(match_mask, items, 13615 MLX5_SET_MATCHER_SW_M); 13616 break; 13617 default: 13618 ret = flow_dv_translate_items(dev, items, &wks_m, 13619 match_mask, MLX5_SET_MATCHER_SW_M, error); 13620 if (ret) 13621 return ret; 13622 ret = flow_dv_translate_items(dev, items, &wks, 13623 match_value, MLX5_SET_MATCHER_SW_V, error); 13624 if (ret) 13625 return ret; 13626 break; 13627 } 13628 wks.item_flags |= wks.last_item; 13629 } 13630 /* 13631 * When E-Switch mode is enabled, we have two cases where we need to 13632 * set the source port manually. 13633 * The first one, is in case of NIC ingress steering rule, and the 13634 * second is E-Switch rule where no port_id item was found. 13635 * In both cases the source port is set according the current port 13636 * in use. 13637 */ 13638 if (!(wks.item_flags & MLX5_FLOW_ITEM_PORT_ID) && 13639 !(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && 13640 !(wks.item_flags & MLX5_FLOW_ITEM_PORT_REPRESENTOR) && 13641 priv->sh->esw_mode && 13642 !attr->egress && 13643 attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) { 13644 if (flow_dv_translate_item_port_id_all(dev, match_mask, 13645 match_value, NULL, attr)) 13646 return -rte_errno; 13647 } 13648 if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) { 13649 flow_dv_translate_item_integrity_post(match_mask, 13650 wks_m.integrity_items, 13651 wks_m.item_flags, 13652 MLX5_SET_MATCHER_SW_M); 13653 flow_dv_translate_item_integrity_post(match_value, 13654 wks.integrity_items, 13655 wks.item_flags, 13656 MLX5_SET_MATCHER_SW_V); 13657 } 13658 if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) { 13659 flow_dv_translate_item_vxlan_gpe(match_mask, 13660 wks.tunnel_item, 13661 wks.item_flags, 13662 MLX5_SET_MATCHER_SW_M); 13663 flow_dv_translate_item_vxlan_gpe(match_value, 13664 wks.tunnel_item, 13665 wks.item_flags, 13666 MLX5_SET_MATCHER_SW_V); 13667 } else if (wks.item_flags & MLX5_FLOW_LAYER_GENEVE) { 13668 flow_dv_translate_item_geneve(match_mask, 13669 wks.tunnel_item, 13670 wks.item_flags, 13671 MLX5_SET_MATCHER_SW_M); 13672 flow_dv_translate_item_geneve(match_value, 13673 wks.tunnel_item, 13674 wks.item_flags, 13675 MLX5_SET_MATCHER_SW_V); 13676 } else if (wks.item_flags & MLX5_FLOW_LAYER_GRE) { 13677 if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE) { 13678 flow_dv_translate_item_gre(match_mask, 13679 wks.tunnel_item, 13680 wks.item_flags, 13681 MLX5_SET_MATCHER_SW_M); 13682 flow_dv_translate_item_gre(match_value, 13683 wks.tunnel_item, 13684 wks.item_flags, 13685 MLX5_SET_MATCHER_SW_V); 13686 } else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_NVGRE) { 13687 flow_dv_translate_item_nvgre(match_mask, 13688 wks.tunnel_item, 13689 wks.item_flags, 13690 MLX5_SET_MATCHER_SW_M); 13691 flow_dv_translate_item_nvgre(match_value, 13692 wks.tunnel_item, 13693 wks.item_flags, 13694 MLX5_SET_MATCHER_SW_V); 13695 } else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE_OPTION) { 13696 flow_dv_translate_item_gre_option(match_mask, 13697 wks.tunnel_item, 13698 wks.gre_item, 13699 wks.item_flags, 13700 MLX5_SET_MATCHER_SW_M); 13701 flow_dv_translate_item_gre_option(match_value, 13702 wks.tunnel_item, 13703 wks.gre_item, 13704 wks.item_flags, 13705 MLX5_SET_MATCHER_SW_V); 13706 } else { 13707 MLX5_ASSERT(false); 13708 } 13709 } 13710 dev_flow->handle->vf_vlan.tag = wks.vlan_tag; 13711 matcher->priority = wks.priority; 13712 #ifdef RTE_LIBRTE_MLX5_DEBUG 13713 MLX5_ASSERT(!flow_dv_check_valid_spec(match_mask, match_value)); 13714 #endif 13715 /* 13716 * Layers may be already initialized from prefix flow if this dev_flow 13717 * is the suffix flow. 13718 */ 13719 dev_flow->handle->layers |= wks.item_flags; 13720 dev_flow->flow->geneve_tlv_option = wks.geneve_tlv_option; 13721 return 0; 13722 } 13723 13724 /** 13725 * Fill the flow with DV spec, lock free 13726 * (mutex should be acquired by caller). 13727 * 13728 * @param[in] dev 13729 * Pointer to rte_eth_dev structure. 13730 * @param[in, out] dev_flow 13731 * Pointer to the sub flow. 13732 * @param[in] attr 13733 * Pointer to the flow attributes. 13734 * @param[in] items 13735 * Pointer to the list of items. 13736 * @param[in] actions 13737 * Pointer to the list of actions. 13738 * @param[out] error 13739 * Pointer to the error structure. 13740 * 13741 * @return 13742 * 0 on success, a negative errno value otherwise and rte_errno is set. 13743 */ 13744 static int 13745 flow_dv_translate(struct rte_eth_dev *dev, 13746 struct mlx5_flow *dev_flow, 13747 const struct rte_flow_attr *attr, 13748 const struct rte_flow_item items[], 13749 const struct rte_flow_action actions[], 13750 struct rte_flow_error *error) 13751 { 13752 struct mlx5_priv *priv = dev->data->dev_private; 13753 struct mlx5_sh_config *dev_conf = &priv->sh->config; 13754 struct rte_flow *flow = dev_flow->flow; 13755 struct mlx5_flow_handle *handle = dev_flow->handle; 13756 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 13757 struct mlx5_flow_rss_desc *rss_desc; 13758 uint64_t action_flags = 0; 13759 struct mlx5_flow_dv_matcher matcher = { 13760 .mask = { 13761 .size = sizeof(matcher.mask.buf), 13762 }, 13763 }; 13764 int actions_n = 0; 13765 bool actions_end = false; 13766 union { 13767 struct mlx5_flow_dv_modify_hdr_resource res; 13768 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 13769 sizeof(struct mlx5_modification_cmd) * 13770 (MLX5_MAX_MODIFY_NUM + 1)]; 13771 } mhdr_dummy; 13772 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 13773 const struct rte_flow_action_count *count = NULL; 13774 const struct rte_flow_action_age *non_shared_age = NULL; 13775 union flow_dv_attr flow_attr = { .attr = 0 }; 13776 uint32_t tag_be; 13777 union mlx5_flow_tbl_key tbl_key; 13778 uint32_t modify_action_position = UINT32_MAX; 13779 struct rte_vlan_hdr vlan = { 0 }; 13780 struct mlx5_flow_dv_dest_array_resource mdest_res; 13781 struct mlx5_flow_dv_sample_resource sample_res; 13782 void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 13783 const struct rte_flow_action_sample *sample = NULL; 13784 struct mlx5_flow_sub_actions_list *sample_act; 13785 uint32_t sample_act_pos = UINT32_MAX; 13786 uint32_t age_act_pos = UINT32_MAX; 13787 uint32_t num_of_dest = 0; 13788 int tmp_actions_n = 0; 13789 uint32_t table; 13790 int ret = 0; 13791 const struct mlx5_flow_tunnel *tunnel = NULL; 13792 struct flow_grp_info grp_info = { 13793 .external = !!dev_flow->external, 13794 .transfer = !!attr->transfer, 13795 .fdb_def_rule = !!priv->fdb_def_rule, 13796 .skip_scale = dev_flow->skip_scale & 13797 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 13798 .std_tbl_fix = true, 13799 }; 13800 13801 if (!wks) 13802 return rte_flow_error_set(error, ENOMEM, 13803 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 13804 NULL, 13805 "failed to push flow workspace"); 13806 rss_desc = &wks->rss_desc; 13807 memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource)); 13808 memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource)); 13809 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 13810 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 13811 /* update normal path action resource into last index of array */ 13812 sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1]; 13813 if (is_tunnel_offload_active(dev)) { 13814 if (dev_flow->tunnel) { 13815 RTE_VERIFY(dev_flow->tof_type == 13816 MLX5_TUNNEL_OFFLOAD_MISS_RULE); 13817 tunnel = dev_flow->tunnel; 13818 } else { 13819 tunnel = mlx5_get_tof(items, actions, 13820 &dev_flow->tof_type); 13821 dev_flow->tunnel = tunnel; 13822 } 13823 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 13824 (dev, attr, tunnel, dev_flow->tof_type); 13825 } 13826 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 13827 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 13828 ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table, 13829 &grp_info, error); 13830 if (ret) 13831 return ret; 13832 dev_flow->dv.group = table; 13833 if (attr->transfer) 13834 mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 13835 /* number of actions must be set to 0 in case of dirty stack. */ 13836 mhdr_res->actions_num = 0; 13837 if (is_flow_tunnel_match_rule(dev_flow->tof_type)) { 13838 /* 13839 * do not add decap action if match rule drops packet 13840 * HW rejects rules with decap & drop 13841 * 13842 * if tunnel match rule was inserted before matching tunnel set 13843 * rule flow table used in the match rule must be registered. 13844 * current implementation handles that in the 13845 * flow_dv_match_register() at the function end. 13846 */ 13847 bool add_decap = true; 13848 const struct rte_flow_action *ptr = actions; 13849 13850 for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) { 13851 if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) { 13852 add_decap = false; 13853 break; 13854 } 13855 } 13856 if (add_decap) { 13857 if (flow_dv_create_action_l2_decap(dev, dev_flow, 13858 attr->transfer, 13859 error)) 13860 return -rte_errno; 13861 dev_flow->dv.actions[actions_n++] = 13862 dev_flow->dv.encap_decap->action; 13863 action_flags |= MLX5_FLOW_ACTION_DECAP; 13864 } 13865 } 13866 for (; !actions_end ; actions++) { 13867 const struct rte_flow_action_queue *queue; 13868 const struct rte_flow_action_rss *rss; 13869 const struct rte_flow_action *action = actions; 13870 const uint8_t *rss_key; 13871 struct mlx5_flow_tbl_resource *tbl; 13872 struct mlx5_aso_age_action *age_act; 13873 struct mlx5_flow_counter *cnt_act; 13874 uint32_t port_id = 0; 13875 struct mlx5_flow_dv_port_id_action_resource port_id_resource; 13876 int action_type = actions->type; 13877 const struct rte_flow_action *found_action = NULL; 13878 uint32_t jump_group = 0; 13879 uint32_t owner_idx; 13880 struct mlx5_aso_ct_action *ct; 13881 13882 if (!mlx5_flow_os_action_supported(action_type)) 13883 return rte_flow_error_set(error, ENOTSUP, 13884 RTE_FLOW_ERROR_TYPE_ACTION, 13885 actions, 13886 "action not supported"); 13887 switch (action_type) { 13888 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 13889 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 13890 break; 13891 case RTE_FLOW_ACTION_TYPE_VOID: 13892 break; 13893 case RTE_FLOW_ACTION_TYPE_PORT_ID: 13894 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 13895 if (flow_dv_translate_action_port_id(dev, action, 13896 &port_id, error)) 13897 return -rte_errno; 13898 port_id_resource.port_id = port_id; 13899 MLX5_ASSERT(!handle->rix_port_id_action); 13900 if (flow_dv_port_id_action_resource_register 13901 (dev, &port_id_resource, dev_flow, error)) 13902 return -rte_errno; 13903 dev_flow->dv.actions[actions_n++] = 13904 dev_flow->dv.port_id_action->action; 13905 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 13906 dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID; 13907 sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID; 13908 num_of_dest++; 13909 break; 13910 case RTE_FLOW_ACTION_TYPE_FLAG: 13911 action_flags |= MLX5_FLOW_ACTION_FLAG; 13912 wks->mark = 1; 13913 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 13914 struct rte_flow_action_mark mark = { 13915 .id = MLX5_FLOW_MARK_DEFAULT, 13916 }; 13917 13918 if (flow_dv_convert_action_mark(dev, &mark, 13919 mhdr_res, 13920 error)) 13921 return -rte_errno; 13922 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 13923 break; 13924 } 13925 tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT); 13926 /* 13927 * Only one FLAG or MARK is supported per device flow 13928 * right now. So the pointer to the tag resource must be 13929 * zero before the register process. 13930 */ 13931 MLX5_ASSERT(!handle->dvh.rix_tag); 13932 if (flow_dv_tag_resource_register(dev, tag_be, 13933 dev_flow, error)) 13934 return -rte_errno; 13935 MLX5_ASSERT(dev_flow->dv.tag_resource); 13936 dev_flow->dv.actions[actions_n++] = 13937 dev_flow->dv.tag_resource->action; 13938 break; 13939 case RTE_FLOW_ACTION_TYPE_MARK: 13940 action_flags |= MLX5_FLOW_ACTION_MARK; 13941 wks->mark = 1; 13942 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 13943 const struct rte_flow_action_mark *mark = 13944 (const struct rte_flow_action_mark *) 13945 actions->conf; 13946 13947 if (flow_dv_convert_action_mark(dev, mark, 13948 mhdr_res, 13949 error)) 13950 return -rte_errno; 13951 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 13952 break; 13953 } 13954 /* Fall-through */ 13955 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 13956 /* Legacy (non-extensive) MARK action. */ 13957 tag_be = mlx5_flow_mark_set 13958 (((const struct rte_flow_action_mark *) 13959 (actions->conf))->id); 13960 MLX5_ASSERT(!handle->dvh.rix_tag); 13961 if (flow_dv_tag_resource_register(dev, tag_be, 13962 dev_flow, error)) 13963 return -rte_errno; 13964 MLX5_ASSERT(dev_flow->dv.tag_resource); 13965 dev_flow->dv.actions[actions_n++] = 13966 dev_flow->dv.tag_resource->action; 13967 break; 13968 case RTE_FLOW_ACTION_TYPE_SET_META: 13969 if (flow_dv_convert_action_set_meta 13970 (dev, mhdr_res, attr, 13971 (const struct rte_flow_action_set_meta *) 13972 actions->conf, error)) 13973 return -rte_errno; 13974 action_flags |= MLX5_FLOW_ACTION_SET_META; 13975 break; 13976 case RTE_FLOW_ACTION_TYPE_SET_TAG: 13977 if (flow_dv_convert_action_set_tag 13978 (dev, mhdr_res, 13979 (const struct rte_flow_action_set_tag *) 13980 actions->conf, error)) 13981 return -rte_errno; 13982 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13983 break; 13984 case RTE_FLOW_ACTION_TYPE_DROP: 13985 action_flags |= MLX5_FLOW_ACTION_DROP; 13986 dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP; 13987 break; 13988 case RTE_FLOW_ACTION_TYPE_QUEUE: 13989 queue = actions->conf; 13990 rss_desc->queue_num = 1; 13991 rss_desc->queue[0] = queue->index; 13992 action_flags |= MLX5_FLOW_ACTION_QUEUE; 13993 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 13994 sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE; 13995 num_of_dest++; 13996 break; 13997 case RTE_FLOW_ACTION_TYPE_RSS: 13998 rss = actions->conf; 13999 memcpy(rss_desc->queue, rss->queue, 14000 rss->queue_num * sizeof(uint16_t)); 14001 rss_desc->queue_num = rss->queue_num; 14002 /* NULL RSS key indicates default RSS key. */ 14003 rss_key = !rss->key ? rss_hash_default_key : rss->key; 14004 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 14005 /* 14006 * rss->level and rss.types should be set in advance 14007 * when expanding items for RSS. 14008 */ 14009 action_flags |= MLX5_FLOW_ACTION_RSS; 14010 dev_flow->handle->fate_action = rss_desc->shared_rss ? 14011 MLX5_FLOW_FATE_SHARED_RSS : 14012 MLX5_FLOW_FATE_QUEUE; 14013 break; 14014 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 14015 owner_idx = (uint32_t)(uintptr_t)action->conf; 14016 age_act = flow_aso_age_get_by_idx(dev, owner_idx); 14017 if (flow->age == 0) { 14018 flow->age = owner_idx; 14019 __atomic_fetch_add(&age_act->refcnt, 1, 14020 __ATOMIC_RELAXED); 14021 } 14022 age_act_pos = actions_n++; 14023 action_flags |= MLX5_FLOW_ACTION_AGE; 14024 break; 14025 case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL: 14026 dev_flow->dv.actions[actions_n] = 14027 flow_dv_translate_action_send_to_kernel(dev, 14028 error); 14029 if (!dev_flow->dv.actions[actions_n]) 14030 return -rte_errno; 14031 actions_n++; 14032 action_flags |= MLX5_FLOW_ACTION_SEND_TO_KERNEL; 14033 dev_flow->handle->fate_action = 14034 MLX5_FLOW_FATE_SEND_TO_KERNEL; 14035 break; 14036 case RTE_FLOW_ACTION_TYPE_AGE: 14037 non_shared_age = action->conf; 14038 age_act_pos = actions_n++; 14039 action_flags |= MLX5_FLOW_ACTION_AGE; 14040 break; 14041 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 14042 owner_idx = (uint32_t)(uintptr_t)action->conf; 14043 cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx, 14044 NULL); 14045 MLX5_ASSERT(cnt_act != NULL); 14046 /** 14047 * When creating meter drop flow in drop table, the 14048 * counter should not overwrite the rte flow counter. 14049 */ 14050 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 14051 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) { 14052 dev_flow->dv.actions[actions_n++] = 14053 cnt_act->action; 14054 } else { 14055 if (flow->counter == 0) { 14056 flow->counter = owner_idx; 14057 __atomic_fetch_add 14058 (&cnt_act->shared_info.refcnt, 14059 1, __ATOMIC_RELAXED); 14060 } 14061 /* Save information first, will apply later. */ 14062 action_flags |= MLX5_FLOW_ACTION_COUNT; 14063 } 14064 break; 14065 case RTE_FLOW_ACTION_TYPE_COUNT: 14066 if (!priv->sh->cdev->config.devx) { 14067 return rte_flow_error_set 14068 (error, ENOTSUP, 14069 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14070 NULL, 14071 "count action not supported"); 14072 } 14073 /* Save information first, will apply later. */ 14074 count = action->conf; 14075 action_flags |= MLX5_FLOW_ACTION_COUNT; 14076 break; 14077 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 14078 dev_flow->dv.actions[actions_n++] = 14079 priv->sh->pop_vlan_action; 14080 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 14081 break; 14082 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 14083 if (!(action_flags & 14084 MLX5_FLOW_ACTION_OF_SET_VLAN_VID)) 14085 flow_dev_get_vlan_info_from_items(items, &vlan); 14086 vlan.eth_proto = rte_be_to_cpu_16 14087 ((((const struct rte_flow_action_of_push_vlan *) 14088 actions->conf)->ethertype)); 14089 found_action = mlx5_flow_find_action 14090 (actions + 1, 14091 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID); 14092 if (found_action) 14093 mlx5_update_vlan_vid_pcp(found_action, &vlan); 14094 found_action = mlx5_flow_find_action 14095 (actions + 1, 14096 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP); 14097 if (found_action) 14098 mlx5_update_vlan_vid_pcp(found_action, &vlan); 14099 if (flow_dv_create_action_push_vlan 14100 (dev, attr, &vlan, dev_flow, error)) 14101 return -rte_errno; 14102 dev_flow->dv.actions[actions_n++] = 14103 dev_flow->dv.push_vlan_res->action; 14104 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 14105 break; 14106 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 14107 /* of_vlan_push action handled this action */ 14108 MLX5_ASSERT(action_flags & 14109 MLX5_FLOW_ACTION_OF_PUSH_VLAN); 14110 break; 14111 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 14112 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 14113 break; 14114 flow_dev_get_vlan_info_from_items(items, &vlan); 14115 mlx5_update_vlan_vid_pcp(actions, &vlan); 14116 /* If no VLAN push - this is a modify header action */ 14117 if (flow_dv_convert_action_modify_vlan_vid 14118 (mhdr_res, actions, error)) 14119 return -rte_errno; 14120 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 14121 break; 14122 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 14123 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 14124 if (flow_dv_create_action_l2_encap(dev, actions, 14125 dev_flow, 14126 attr->transfer, 14127 error)) 14128 return -rte_errno; 14129 dev_flow->dv.actions[actions_n++] = 14130 dev_flow->dv.encap_decap->action; 14131 action_flags |= MLX5_FLOW_ACTION_ENCAP; 14132 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 14133 sample_act->action_flags |= 14134 MLX5_FLOW_ACTION_ENCAP; 14135 break; 14136 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 14137 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 14138 if (flow_dv_create_action_l2_decap(dev, dev_flow, 14139 attr->transfer, 14140 error)) 14141 return -rte_errno; 14142 dev_flow->dv.actions[actions_n++] = 14143 dev_flow->dv.encap_decap->action; 14144 action_flags |= MLX5_FLOW_ACTION_DECAP; 14145 break; 14146 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 14147 /* Handle encap with preceding decap. */ 14148 if (action_flags & MLX5_FLOW_ACTION_DECAP) { 14149 if (flow_dv_create_action_raw_encap 14150 (dev, actions, dev_flow, attr, error)) 14151 return -rte_errno; 14152 dev_flow->dv.actions[actions_n++] = 14153 dev_flow->dv.encap_decap->action; 14154 } else { 14155 /* Handle encap without preceding decap. */ 14156 if (flow_dv_create_action_l2_encap 14157 (dev, actions, dev_flow, attr->transfer, 14158 error)) 14159 return -rte_errno; 14160 dev_flow->dv.actions[actions_n++] = 14161 dev_flow->dv.encap_decap->action; 14162 } 14163 action_flags |= MLX5_FLOW_ACTION_ENCAP; 14164 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 14165 sample_act->action_flags |= 14166 MLX5_FLOW_ACTION_ENCAP; 14167 break; 14168 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 14169 while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID) 14170 ; 14171 if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 14172 if (flow_dv_create_action_l2_decap 14173 (dev, dev_flow, attr->transfer, error)) 14174 return -rte_errno; 14175 dev_flow->dv.actions[actions_n++] = 14176 dev_flow->dv.encap_decap->action; 14177 } 14178 /* If decap is followed by encap, handle it at encap. */ 14179 action_flags |= MLX5_FLOW_ACTION_DECAP; 14180 break; 14181 case MLX5_RTE_FLOW_ACTION_TYPE_JUMP: 14182 dev_flow->dv.actions[actions_n++] = 14183 (void *)(uintptr_t)action->conf; 14184 action_flags |= MLX5_FLOW_ACTION_JUMP; 14185 break; 14186 case RTE_FLOW_ACTION_TYPE_JUMP: 14187 jump_group = ((const struct rte_flow_action_jump *) 14188 action->conf)->group; 14189 grp_info.std_tbl_fix = 0; 14190 if (dev_flow->skip_scale & 14191 (1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT)) 14192 grp_info.skip_scale = 1; 14193 else 14194 grp_info.skip_scale = 0; 14195 ret = mlx5_flow_group_to_table(dev, tunnel, 14196 jump_group, 14197 &table, 14198 &grp_info, error); 14199 if (ret) 14200 return ret; 14201 tbl = flow_dv_tbl_resource_get(dev, table, attr->egress, 14202 attr->transfer, 14203 !!dev_flow->external, 14204 tunnel, jump_group, 0, 14205 0, error); 14206 if (!tbl) 14207 return rte_flow_error_set 14208 (error, errno, 14209 RTE_FLOW_ERROR_TYPE_ACTION, 14210 NULL, 14211 "cannot create jump action."); 14212 if (flow_dv_jump_tbl_resource_register 14213 (dev, tbl, dev_flow, error)) { 14214 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 14215 return rte_flow_error_set 14216 (error, errno, 14217 RTE_FLOW_ERROR_TYPE_ACTION, 14218 NULL, 14219 "cannot create jump action."); 14220 } 14221 dev_flow->dv.actions[actions_n++] = 14222 dev_flow->dv.jump->action; 14223 action_flags |= MLX5_FLOW_ACTION_JUMP; 14224 dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP; 14225 sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP; 14226 num_of_dest++; 14227 break; 14228 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 14229 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 14230 if (flow_dv_convert_action_modify_mac 14231 (mhdr_res, actions, error)) 14232 return -rte_errno; 14233 action_flags |= actions->type == 14234 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 14235 MLX5_FLOW_ACTION_SET_MAC_SRC : 14236 MLX5_FLOW_ACTION_SET_MAC_DST; 14237 break; 14238 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 14239 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 14240 if (flow_dv_convert_action_modify_ipv4 14241 (mhdr_res, actions, error)) 14242 return -rte_errno; 14243 action_flags |= actions->type == 14244 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 14245 MLX5_FLOW_ACTION_SET_IPV4_SRC : 14246 MLX5_FLOW_ACTION_SET_IPV4_DST; 14247 break; 14248 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 14249 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 14250 if (flow_dv_convert_action_modify_ipv6 14251 (mhdr_res, actions, error)) 14252 return -rte_errno; 14253 action_flags |= actions->type == 14254 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 14255 MLX5_FLOW_ACTION_SET_IPV6_SRC : 14256 MLX5_FLOW_ACTION_SET_IPV6_DST; 14257 break; 14258 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 14259 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 14260 if (flow_dv_convert_action_modify_tp 14261 (mhdr_res, actions, items, 14262 &flow_attr, dev_flow, !!(action_flags & 14263 MLX5_FLOW_ACTION_DECAP), error)) 14264 return -rte_errno; 14265 action_flags |= actions->type == 14266 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 14267 MLX5_FLOW_ACTION_SET_TP_SRC : 14268 MLX5_FLOW_ACTION_SET_TP_DST; 14269 break; 14270 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 14271 if (flow_dv_convert_action_modify_dec_ttl 14272 (mhdr_res, items, &flow_attr, dev_flow, 14273 !!(action_flags & 14274 MLX5_FLOW_ACTION_DECAP), error)) 14275 return -rte_errno; 14276 action_flags |= MLX5_FLOW_ACTION_DEC_TTL; 14277 break; 14278 case RTE_FLOW_ACTION_TYPE_SET_TTL: 14279 if (flow_dv_convert_action_modify_ttl 14280 (mhdr_res, actions, items, &flow_attr, 14281 dev_flow, !!(action_flags & 14282 MLX5_FLOW_ACTION_DECAP), error)) 14283 return -rte_errno; 14284 action_flags |= MLX5_FLOW_ACTION_SET_TTL; 14285 break; 14286 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 14287 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 14288 if (flow_dv_convert_action_modify_tcp_seq 14289 (mhdr_res, actions, error)) 14290 return -rte_errno; 14291 action_flags |= actions->type == 14292 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 14293 MLX5_FLOW_ACTION_INC_TCP_SEQ : 14294 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 14295 break; 14296 14297 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 14298 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 14299 if (flow_dv_convert_action_modify_tcp_ack 14300 (mhdr_res, actions, error)) 14301 return -rte_errno; 14302 action_flags |= actions->type == 14303 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 14304 MLX5_FLOW_ACTION_INC_TCP_ACK : 14305 MLX5_FLOW_ACTION_DEC_TCP_ACK; 14306 break; 14307 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 14308 if (flow_dv_convert_action_set_reg 14309 (mhdr_res, actions, error)) 14310 return -rte_errno; 14311 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 14312 break; 14313 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 14314 if (flow_dv_convert_action_copy_mreg 14315 (dev, mhdr_res, actions, error)) 14316 return -rte_errno; 14317 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 14318 break; 14319 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 14320 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 14321 dev_flow->handle->fate_action = 14322 MLX5_FLOW_FATE_DEFAULT_MISS; 14323 break; 14324 case RTE_FLOW_ACTION_TYPE_METER: 14325 if (!wks->fm) 14326 return rte_flow_error_set(error, rte_errno, 14327 RTE_FLOW_ERROR_TYPE_ACTION, 14328 NULL, "Failed to get meter in flow."); 14329 /* Set the meter action. */ 14330 dev_flow->dv.actions[actions_n++] = 14331 wks->fm->meter_action_g; 14332 action_flags |= MLX5_FLOW_ACTION_METER; 14333 break; 14334 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 14335 if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res, 14336 actions, error)) 14337 return -rte_errno; 14338 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 14339 break; 14340 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 14341 if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res, 14342 actions, error)) 14343 return -rte_errno; 14344 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 14345 break; 14346 case RTE_FLOW_ACTION_TYPE_SAMPLE: 14347 sample_act_pos = actions_n; 14348 sample = (const struct rte_flow_action_sample *) 14349 action->conf; 14350 actions_n++; 14351 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 14352 /* put encap action into group if work with port id */ 14353 if ((action_flags & MLX5_FLOW_ACTION_ENCAP) && 14354 (action_flags & MLX5_FLOW_ACTION_PORT_ID)) 14355 sample_act->action_flags |= 14356 MLX5_FLOW_ACTION_ENCAP; 14357 break; 14358 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 14359 if (flow_dv_convert_action_modify_field 14360 (dev, mhdr_res, actions, attr, error)) 14361 return -rte_errno; 14362 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 14363 break; 14364 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 14365 owner_idx = (uint32_t)(uintptr_t)action->conf; 14366 ct = flow_aso_ct_get_by_idx(dev, owner_idx); 14367 if (!ct) 14368 return rte_flow_error_set(error, EINVAL, 14369 RTE_FLOW_ERROR_TYPE_ACTION, 14370 NULL, 14371 "Failed to get CT object."); 14372 if (mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct)) 14373 return rte_flow_error_set(error, rte_errno, 14374 RTE_FLOW_ERROR_TYPE_ACTION, 14375 NULL, 14376 "CT is unavailable."); 14377 if (ct->is_original) 14378 dev_flow->dv.actions[actions_n] = 14379 ct->dr_action_orig; 14380 else 14381 dev_flow->dv.actions[actions_n] = 14382 ct->dr_action_rply; 14383 if (flow->ct == 0) { 14384 flow->indirect_type = 14385 MLX5_INDIRECT_ACTION_TYPE_CT; 14386 flow->ct = owner_idx; 14387 __atomic_fetch_add(&ct->refcnt, 1, 14388 __ATOMIC_RELAXED); 14389 } 14390 actions_n++; 14391 action_flags |= MLX5_FLOW_ACTION_CT; 14392 break; 14393 case RTE_FLOW_ACTION_TYPE_END: 14394 actions_end = true; 14395 if (mhdr_res->actions_num) { 14396 /* create modify action if needed. */ 14397 if (flow_dv_modify_hdr_resource_register 14398 (dev, mhdr_res, dev_flow, error)) 14399 return -rte_errno; 14400 dev_flow->dv.actions[modify_action_position] = 14401 handle->dvh.modify_hdr->action; 14402 } 14403 /* 14404 * Handle AGE and COUNT action by single HW counter 14405 * when they are not shared. 14406 */ 14407 if (action_flags & MLX5_FLOW_ACTION_AGE) { 14408 if ((non_shared_age && count) || 14409 !flow_hit_aso_supported(priv, !dev_flow->dv.group)) { 14410 /* Creates age by counters. */ 14411 cnt_act = flow_dv_prepare_counter 14412 (dev, dev_flow, 14413 flow, count, 14414 non_shared_age, 14415 error); 14416 if (!cnt_act) 14417 return -rte_errno; 14418 dev_flow->dv.actions[age_act_pos] = 14419 cnt_act->action; 14420 break; 14421 } 14422 if (!flow->age && non_shared_age) { 14423 flow->age = flow_dv_aso_age_alloc 14424 (dev, error); 14425 if (!flow->age) 14426 return -rte_errno; 14427 flow_dv_aso_age_params_init 14428 (dev, flow->age, 14429 non_shared_age->context ? 14430 non_shared_age->context : 14431 (void *)(uintptr_t) 14432 (dev_flow->flow_idx), 14433 non_shared_age->timeout); 14434 } 14435 age_act = flow_aso_age_get_by_idx(dev, 14436 flow->age); 14437 dev_flow->dv.actions[age_act_pos] = 14438 age_act->dr_action; 14439 } 14440 if (action_flags & MLX5_FLOW_ACTION_COUNT) { 14441 /* 14442 * Create one count action, to be used 14443 * by all sub-flows. 14444 */ 14445 cnt_act = flow_dv_prepare_counter(dev, dev_flow, 14446 flow, count, 14447 NULL, error); 14448 if (!cnt_act) 14449 return -rte_errno; 14450 dev_flow->dv.actions[actions_n++] = 14451 cnt_act->action; 14452 } 14453 default: 14454 break; 14455 } 14456 if (mhdr_res->actions_num && 14457 modify_action_position == UINT32_MAX) 14458 modify_action_position = actions_n++; 14459 } 14460 dev_flow->act_flags = action_flags; 14461 ret = flow_dv_translate_items_sws(dev, dev_flow, attr, items, &matcher, 14462 error); 14463 if (ret) 14464 return -rte_errno; 14465 if (action_flags & MLX5_FLOW_ACTION_RSS) 14466 flow_dv_hashfields_set(dev_flow->handle->layers, 14467 rss_desc, 14468 &dev_flow->hash_fields); 14469 /* If has RSS action in the sample action, the Sample/Mirror resource 14470 * should be registered after the hash filed be update. 14471 */ 14472 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) { 14473 ret = flow_dv_translate_action_sample(dev, 14474 sample, 14475 dev_flow, attr, 14476 &num_of_dest, 14477 sample_actions, 14478 &sample_res, 14479 error); 14480 if (ret < 0) 14481 return ret; 14482 ret = flow_dv_create_action_sample(dev, 14483 dev_flow, 14484 num_of_dest, 14485 &sample_res, 14486 &mdest_res, 14487 sample_actions, 14488 action_flags, 14489 error); 14490 if (ret < 0) 14491 return rte_flow_error_set 14492 (error, rte_errno, 14493 RTE_FLOW_ERROR_TYPE_ACTION, 14494 NULL, 14495 "cannot create sample action"); 14496 if (num_of_dest > 1) { 14497 dev_flow->dv.actions[sample_act_pos] = 14498 dev_flow->dv.dest_array_res->action; 14499 } else { 14500 dev_flow->dv.actions[sample_act_pos] = 14501 dev_flow->dv.sample_res->verbs_action; 14502 } 14503 } 14504 /* 14505 * For multiple destination (sample action with ratio=1), the encap 14506 * action and port id action will be combined into group action. 14507 * So need remove the original these actions in the flow and only 14508 * use the sample action instead of. 14509 */ 14510 if (num_of_dest > 1 && 14511 (sample_act->dr_port_id_action || sample_act->dr_jump_action)) { 14512 int i; 14513 void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 14514 14515 for (i = 0; i < actions_n; i++) { 14516 if ((sample_act->dr_encap_action && 14517 sample_act->dr_encap_action == 14518 dev_flow->dv.actions[i]) || 14519 (sample_act->dr_port_id_action && 14520 sample_act->dr_port_id_action == 14521 dev_flow->dv.actions[i]) || 14522 (sample_act->dr_jump_action && 14523 sample_act->dr_jump_action == 14524 dev_flow->dv.actions[i])) 14525 continue; 14526 temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i]; 14527 } 14528 memcpy((void *)dev_flow->dv.actions, 14529 (void *)temp_actions, 14530 tmp_actions_n * sizeof(void *)); 14531 actions_n = tmp_actions_n; 14532 } 14533 dev_flow->dv.actions_n = actions_n; 14534 if (wks->skip_matcher_reg) 14535 return 0; 14536 /* Register matcher. */ 14537 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 14538 matcher.mask.size); 14539 matcher.priority = mlx5_get_matcher_priority(dev, attr, 14540 matcher.priority, 14541 dev_flow->external); 14542 /** 14543 * When creating meter drop flow in drop table, using original 14544 * 5-tuple match, the matcher priority should be lower than 14545 * mtr_id matcher. 14546 */ 14547 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 14548 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP && 14549 matcher.priority <= MLX5_REG_BITS) 14550 matcher.priority += MLX5_REG_BITS; 14551 /* reserved field no needs to be set to 0 here. */ 14552 tbl_key.is_fdb = attr->transfer; 14553 tbl_key.is_egress = attr->egress; 14554 tbl_key.level = dev_flow->dv.group; 14555 tbl_key.id = dev_flow->dv.table_id; 14556 if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow, 14557 tunnel, attr->group, error)) 14558 return -rte_errno; 14559 return 0; 14560 } 14561 14562 /** 14563 * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields) 14564 * and tunnel. 14565 * 14566 * @param[in, out] action 14567 * Shred RSS action holding hash RX queue objects. 14568 * @param[in] hash_fields 14569 * Defines combination of packet fields to participate in RX hash. 14570 * @param[in] tunnel 14571 * Tunnel type 14572 * @param[in] hrxq_idx 14573 * Hash RX queue index to set. 14574 * 14575 * @return 14576 * 0 on success, otherwise negative errno value. 14577 */ 14578 static int 14579 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action, 14580 const uint64_t hash_fields, 14581 uint32_t hrxq_idx) 14582 { 14583 uint32_t *hrxqs = action->hrxq; 14584 14585 switch (hash_fields & ~IBV_RX_HASH_INNER) { 14586 case MLX5_RSS_HASH_IPV4: 14587 /* fall-through. */ 14588 case MLX5_RSS_HASH_IPV4_DST_ONLY: 14589 /* fall-through. */ 14590 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 14591 hrxqs[0] = hrxq_idx; 14592 return 0; 14593 case MLX5_RSS_HASH_IPV4_TCP: 14594 /* fall-through. */ 14595 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 14596 /* fall-through. */ 14597 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 14598 hrxqs[1] = hrxq_idx; 14599 return 0; 14600 case MLX5_RSS_HASH_IPV4_UDP: 14601 /* fall-through. */ 14602 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 14603 /* fall-through. */ 14604 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 14605 hrxqs[2] = hrxq_idx; 14606 return 0; 14607 case MLX5_RSS_HASH_IPV6: 14608 /* fall-through. */ 14609 case MLX5_RSS_HASH_IPV6_DST_ONLY: 14610 /* fall-through. */ 14611 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 14612 hrxqs[3] = hrxq_idx; 14613 return 0; 14614 case MLX5_RSS_HASH_IPV6_TCP: 14615 /* fall-through. */ 14616 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 14617 /* fall-through. */ 14618 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 14619 hrxqs[4] = hrxq_idx; 14620 return 0; 14621 case MLX5_RSS_HASH_IPV6_UDP: 14622 /* fall-through. */ 14623 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 14624 /* fall-through. */ 14625 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 14626 hrxqs[5] = hrxq_idx; 14627 return 0; 14628 case MLX5_RSS_HASH_NONE: 14629 hrxqs[6] = hrxq_idx; 14630 return 0; 14631 case MLX5_RSS_HASH_IPV4_ESP: 14632 hrxqs[7] = hrxq_idx; 14633 return 0; 14634 case MLX5_RSS_HASH_IPV6_ESP: 14635 hrxqs[8] = hrxq_idx; 14636 return 0; 14637 case MLX5_RSS_HASH_ESP_SPI: 14638 hrxqs[9] = hrxq_idx; 14639 return 0; 14640 default: 14641 return -1; 14642 } 14643 } 14644 14645 /** 14646 * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields) 14647 * and tunnel. 14648 * 14649 * @param[in] dev 14650 * Pointer to the Ethernet device structure. 14651 * @param[in] idx 14652 * Shared RSS action ID holding hash RX queue objects. 14653 * @param[in] hash_fields 14654 * Defines combination of packet fields to participate in RX hash. 14655 * @param[in] tunnel 14656 * Tunnel type 14657 * 14658 * @return 14659 * Valid hash RX queue index, otherwise 0. 14660 */ 14661 uint32_t 14662 flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx, 14663 const uint64_t hash_fields) 14664 { 14665 struct mlx5_priv *priv = dev->data->dev_private; 14666 struct mlx5_shared_action_rss *shared_rss = 14667 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14668 const uint32_t *hrxqs = shared_rss->hrxq; 14669 14670 switch (hash_fields & ~IBV_RX_HASH_INNER) { 14671 case MLX5_RSS_HASH_IPV4: 14672 /* fall-through. */ 14673 case MLX5_RSS_HASH_IPV4_DST_ONLY: 14674 /* fall-through. */ 14675 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 14676 return hrxqs[0]; 14677 case MLX5_RSS_HASH_IPV4_TCP: 14678 /* fall-through. */ 14679 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 14680 /* fall-through. */ 14681 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 14682 return hrxqs[1]; 14683 case MLX5_RSS_HASH_IPV4_UDP: 14684 /* fall-through. */ 14685 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 14686 /* fall-through. */ 14687 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 14688 return hrxqs[2]; 14689 case MLX5_RSS_HASH_IPV6: 14690 /* fall-through. */ 14691 case MLX5_RSS_HASH_IPV6_DST_ONLY: 14692 /* fall-through. */ 14693 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 14694 return hrxqs[3]; 14695 case MLX5_RSS_HASH_IPV6_TCP: 14696 /* fall-through. */ 14697 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 14698 /* fall-through. */ 14699 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 14700 return hrxqs[4]; 14701 case MLX5_RSS_HASH_IPV6_UDP: 14702 /* fall-through. */ 14703 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 14704 /* fall-through. */ 14705 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 14706 return hrxqs[5]; 14707 case MLX5_RSS_HASH_NONE: 14708 return hrxqs[6]; 14709 case MLX5_RSS_HASH_IPV4_ESP: 14710 return hrxqs[7]; 14711 case MLX5_RSS_HASH_IPV6_ESP: 14712 return hrxqs[8]; 14713 case MLX5_RSS_HASH_ESP_SPI: 14714 return hrxqs[9]; 14715 default: 14716 return 0; 14717 } 14718 14719 } 14720 14721 /** 14722 * Apply the flow to the NIC, lock free, 14723 * (mutex should be acquired by caller). 14724 * 14725 * @param[in] dev 14726 * Pointer to the Ethernet device structure. 14727 * @param[in, out] flow 14728 * Pointer to flow structure. 14729 * @param[out] error 14730 * Pointer to error structure. 14731 * 14732 * @return 14733 * 0 on success, a negative errno value otherwise and rte_errno is set. 14734 */ 14735 static int 14736 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, 14737 struct rte_flow_error *error) 14738 { 14739 struct mlx5_flow_dv_workspace *dv; 14740 struct mlx5_flow_handle *dh; 14741 struct mlx5_flow_handle_dv *dv_h; 14742 struct mlx5_flow *dev_flow; 14743 struct mlx5_priv *priv = dev->data->dev_private; 14744 uint32_t handle_idx; 14745 int n; 14746 int err; 14747 int idx; 14748 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 14749 struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc; 14750 uint8_t misc_mask; 14751 14752 MLX5_ASSERT(wks); 14753 for (idx = wks->flow_idx - 1; idx >= 0; idx--) { 14754 dev_flow = &wks->flows[idx]; 14755 dv = &dev_flow->dv; 14756 dh = dev_flow->handle; 14757 dv_h = &dh->dvh; 14758 n = dv->actions_n; 14759 if (dh->fate_action == MLX5_FLOW_FATE_DROP) { 14760 if (dv->transfer) { 14761 MLX5_ASSERT(priv->sh->dr_drop_action); 14762 dv->actions[n++] = priv->sh->dr_drop_action; 14763 } else { 14764 #ifdef HAVE_MLX5DV_DR 14765 /* DR supports drop action placeholder. */ 14766 MLX5_ASSERT(priv->sh->dr_drop_action); 14767 dv->actions[n++] = dv->group ? 14768 priv->sh->dr_drop_action : 14769 priv->root_drop_action; 14770 #else 14771 /* For DV we use the explicit drop queue. */ 14772 MLX5_ASSERT(priv->drop_queue.hrxq); 14773 dv->actions[n++] = 14774 priv->drop_queue.hrxq->action; 14775 #endif 14776 } 14777 } else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE && 14778 !dv_h->rix_sample && !dv_h->rix_dest_array)) { 14779 struct mlx5_hrxq *hrxq; 14780 uint32_t hrxq_idx; 14781 14782 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc, 14783 &hrxq_idx); 14784 if (!hrxq) { 14785 rte_flow_error_set 14786 (error, rte_errno, 14787 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14788 "cannot get hash queue"); 14789 goto error; 14790 } 14791 dh->rix_hrxq = hrxq_idx; 14792 dv->actions[n++] = hrxq->action; 14793 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 14794 struct mlx5_hrxq *hrxq = NULL; 14795 uint32_t hrxq_idx; 14796 14797 hrxq_idx = flow_dv_action_rss_hrxq_lookup(dev, 14798 rss_desc->shared_rss, 14799 dev_flow->hash_fields); 14800 if (hrxq_idx) 14801 hrxq = mlx5_ipool_get 14802 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 14803 hrxq_idx); 14804 if (!hrxq) { 14805 rte_flow_error_set 14806 (error, rte_errno, 14807 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14808 "cannot get hash queue"); 14809 goto error; 14810 } 14811 dh->rix_srss = rss_desc->shared_rss; 14812 dv->actions[n++] = hrxq->action; 14813 } else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) { 14814 if (!priv->sh->default_miss_action) { 14815 rte_flow_error_set 14816 (error, rte_errno, 14817 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14818 "default miss action not be created."); 14819 goto error; 14820 } 14821 dv->actions[n++] = priv->sh->default_miss_action; 14822 } 14823 misc_mask = flow_dv_matcher_enable(dv->value.buf); 14824 __flow_dv_adjust_buf_size(&dv->value.size, misc_mask); 14825 err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object, 14826 (void *)&dv->value, n, 14827 dv->actions, &dh->drv_flow); 14828 if (err) { 14829 rte_flow_error_set 14830 (error, errno, 14831 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 14832 NULL, 14833 (!priv->sh->config.allow_duplicate_pattern && 14834 errno == EEXIST) ? 14835 "duplicating pattern is not allowed" : 14836 "hardware refuses to create flow"); 14837 goto error; 14838 } 14839 if (priv->vmwa_context && 14840 dh->vf_vlan.tag && !dh->vf_vlan.created) { 14841 /* 14842 * The rule contains the VLAN pattern. 14843 * For VF we are going to create VLAN 14844 * interface to make hypervisor set correct 14845 * e-Switch vport context. 14846 */ 14847 mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan); 14848 } 14849 } 14850 return 0; 14851 error: 14852 err = rte_errno; /* Save rte_errno before cleanup. */ 14853 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles, 14854 handle_idx, dh, next) { 14855 /* hrxq is union, don't clear it if the flag is not set. */ 14856 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) { 14857 mlx5_hrxq_release(dev, dh->rix_hrxq); 14858 dh->rix_hrxq = 0; 14859 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 14860 dh->rix_srss = 0; 14861 } 14862 if (dh->vf_vlan.tag && dh->vf_vlan.created) 14863 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 14864 } 14865 rte_errno = err; /* Restore rte_errno. */ 14866 return -rte_errno; 14867 } 14868 14869 void 14870 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused, 14871 struct mlx5_list_entry *entry) 14872 { 14873 struct mlx5_flow_dv_matcher *resource = container_of(entry, 14874 typeof(*resource), 14875 entry); 14876 14877 claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object)); 14878 mlx5_free(resource); 14879 } 14880 14881 /** 14882 * Release the flow matcher. 14883 * 14884 * @param dev 14885 * Pointer to Ethernet device. 14886 * @param port_id 14887 * Index to port ID action resource. 14888 * 14889 * @return 14890 * 1 while a reference on it exists, 0 when freed. 14891 */ 14892 static int 14893 flow_dv_matcher_release(struct rte_eth_dev *dev, 14894 struct mlx5_flow_handle *handle) 14895 { 14896 struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher; 14897 struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl, 14898 typeof(*tbl), tbl); 14899 int ret; 14900 14901 MLX5_ASSERT(matcher->matcher_object); 14902 ret = mlx5_list_unregister(tbl->matchers, &matcher->entry); 14903 flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl); 14904 return ret; 14905 } 14906 14907 void 14908 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14909 { 14910 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14911 struct mlx5_flow_dv_encap_decap_resource *res = 14912 container_of(entry, typeof(*res), entry); 14913 14914 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 14915 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 14916 } 14917 14918 /** 14919 * Release an encap/decap resource. 14920 * 14921 * @param dev 14922 * Pointer to Ethernet device. 14923 * @param encap_decap_idx 14924 * Index of encap decap resource. 14925 * 14926 * @return 14927 * 1 while a reference on it exists, 0 when freed. 14928 */ 14929 static int 14930 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 14931 uint32_t encap_decap_idx) 14932 { 14933 struct mlx5_priv *priv = dev->data->dev_private; 14934 struct mlx5_flow_dv_encap_decap_resource *resource; 14935 14936 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 14937 encap_decap_idx); 14938 if (!resource) 14939 return 0; 14940 MLX5_ASSERT(resource->action); 14941 return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry); 14942 } 14943 14944 /** 14945 * Release an jump to table action resource. 14946 * 14947 * @param dev 14948 * Pointer to Ethernet device. 14949 * @param rix_jump 14950 * Index to the jump action resource. 14951 * 14952 * @return 14953 * 1 while a reference on it exists, 0 when freed. 14954 */ 14955 static int 14956 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 14957 uint32_t rix_jump) 14958 { 14959 struct mlx5_priv *priv = dev->data->dev_private; 14960 struct mlx5_flow_tbl_data_entry *tbl_data; 14961 14962 tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP], 14963 rix_jump); 14964 if (!tbl_data) 14965 return 0; 14966 return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl); 14967 } 14968 14969 void 14970 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14971 { 14972 struct mlx5_flow_dv_modify_hdr_resource *res = 14973 container_of(entry, typeof(*res), entry); 14974 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14975 14976 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 14977 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 14978 } 14979 14980 /** 14981 * Release a modify-header resource. 14982 * 14983 * @param dev 14984 * Pointer to Ethernet device. 14985 * @param handle 14986 * Pointer to mlx5_flow_handle. 14987 * 14988 * @return 14989 * 1 while a reference on it exists, 0 when freed. 14990 */ 14991 static int 14992 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev, 14993 struct mlx5_flow_handle *handle) 14994 { 14995 struct mlx5_priv *priv = dev->data->dev_private; 14996 struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr; 14997 14998 MLX5_ASSERT(entry->action); 14999 return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry); 15000 } 15001 15002 void 15003 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 15004 { 15005 struct mlx5_dev_ctx_shared *sh = tool_ctx; 15006 struct mlx5_flow_dv_port_id_action_resource *resource = 15007 container_of(entry, typeof(*resource), entry); 15008 15009 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 15010 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 15011 } 15012 15013 /** 15014 * Release port ID action resource. 15015 * 15016 * @param dev 15017 * Pointer to Ethernet device. 15018 * @param handle 15019 * Pointer to mlx5_flow_handle. 15020 * 15021 * @return 15022 * 1 while a reference on it exists, 0 when freed. 15023 */ 15024 static int 15025 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 15026 uint32_t port_id) 15027 { 15028 struct mlx5_priv *priv = dev->data->dev_private; 15029 struct mlx5_flow_dv_port_id_action_resource *resource; 15030 15031 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id); 15032 if (!resource) 15033 return 0; 15034 MLX5_ASSERT(resource->action); 15035 return mlx5_list_unregister(priv->sh->port_id_action_list, 15036 &resource->entry); 15037 } 15038 15039 /** 15040 * Release shared RSS action resource. 15041 * 15042 * @param dev 15043 * Pointer to Ethernet device. 15044 * @param srss 15045 * Shared RSS action index. 15046 */ 15047 static void 15048 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss) 15049 { 15050 struct mlx5_priv *priv = dev->data->dev_private; 15051 struct mlx5_shared_action_rss *shared_rss; 15052 15053 shared_rss = mlx5_ipool_get 15054 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss); 15055 __atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 15056 } 15057 15058 void 15059 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 15060 { 15061 struct mlx5_dev_ctx_shared *sh = tool_ctx; 15062 struct mlx5_flow_dv_push_vlan_action_resource *resource = 15063 container_of(entry, typeof(*resource), entry); 15064 15065 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 15066 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 15067 } 15068 15069 /** 15070 * Release push vlan action resource. 15071 * 15072 * @param dev 15073 * Pointer to Ethernet device. 15074 * @param handle 15075 * Pointer to mlx5_flow_handle. 15076 * 15077 * @return 15078 * 1 while a reference on it exists, 0 when freed. 15079 */ 15080 static int 15081 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev, 15082 struct mlx5_flow_handle *handle) 15083 { 15084 struct mlx5_priv *priv = dev->data->dev_private; 15085 struct mlx5_flow_dv_push_vlan_action_resource *resource; 15086 uint32_t idx = handle->dvh.rix_push_vlan; 15087 15088 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 15089 if (!resource) 15090 return 0; 15091 MLX5_ASSERT(resource->action); 15092 return mlx5_list_unregister(priv->sh->push_vlan_action_list, 15093 &resource->entry); 15094 } 15095 15096 /** 15097 * Release the fate resource. 15098 * 15099 * @param dev 15100 * Pointer to Ethernet device. 15101 * @param handle 15102 * Pointer to mlx5_flow_handle. 15103 */ 15104 static void 15105 flow_dv_fate_resource_release(struct rte_eth_dev *dev, 15106 struct mlx5_flow_handle *handle) 15107 { 15108 if (!handle->rix_fate) 15109 return; 15110 switch (handle->fate_action) { 15111 case MLX5_FLOW_FATE_QUEUE: 15112 if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array) 15113 mlx5_hrxq_release(dev, handle->rix_hrxq); 15114 break; 15115 case MLX5_FLOW_FATE_JUMP: 15116 flow_dv_jump_tbl_resource_release(dev, handle->rix_jump); 15117 break; 15118 case MLX5_FLOW_FATE_PORT_ID: 15119 flow_dv_port_id_action_resource_release(dev, 15120 handle->rix_port_id_action); 15121 break; 15122 case MLX5_FLOW_FATE_SEND_TO_KERNEL: 15123 /* In case of send_to_kernel action the actual release of 15124 * resource is done when all shared DR resources are released 15125 * since this resource is created once and always reused. 15126 */ 15127 break; 15128 default: 15129 DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action); 15130 break; 15131 } 15132 handle->rix_fate = 0; 15133 } 15134 15135 void 15136 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused, 15137 struct mlx5_list_entry *entry) 15138 { 15139 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 15140 typeof(*resource), 15141 entry); 15142 struct rte_eth_dev *dev = resource->dev; 15143 struct mlx5_priv *priv = dev->data->dev_private; 15144 15145 if (resource->verbs_action) 15146 claim_zero(mlx5_flow_os_destroy_flow_action 15147 (resource->verbs_action)); 15148 if (resource->normal_path_tbl) 15149 flow_dv_tbl_resource_release(MLX5_SH(dev), 15150 resource->normal_path_tbl); 15151 flow_dv_sample_sub_actions_release(dev, &resource->sample_idx); 15152 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 15153 DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource); 15154 } 15155 15156 /** 15157 * Release an sample resource. 15158 * 15159 * @param dev 15160 * Pointer to Ethernet device. 15161 * @param handle 15162 * Pointer to mlx5_flow_handle. 15163 * 15164 * @return 15165 * 1 while a reference on it exists, 0 when freed. 15166 */ 15167 static int 15168 flow_dv_sample_resource_release(struct rte_eth_dev *dev, 15169 struct mlx5_flow_handle *handle) 15170 { 15171 struct mlx5_priv *priv = dev->data->dev_private; 15172 struct mlx5_flow_dv_sample_resource *resource; 15173 15174 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE], 15175 handle->dvh.rix_sample); 15176 if (!resource) 15177 return 0; 15178 MLX5_ASSERT(resource->verbs_action); 15179 return mlx5_list_unregister(priv->sh->sample_action_list, 15180 &resource->entry); 15181 } 15182 15183 void 15184 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused, 15185 struct mlx5_list_entry *entry) 15186 { 15187 struct mlx5_flow_dv_dest_array_resource *resource = 15188 container_of(entry, typeof(*resource), entry); 15189 struct rte_eth_dev *dev = resource->dev; 15190 struct mlx5_priv *priv = dev->data->dev_private; 15191 uint32_t i = 0; 15192 15193 MLX5_ASSERT(resource->action); 15194 if (resource->action) 15195 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 15196 for (; i < resource->num_of_dest; i++) 15197 flow_dv_sample_sub_actions_release(dev, 15198 &resource->sample_idx[i]); 15199 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 15200 DRV_LOG(DEBUG, "destination array resource %p: removed", 15201 (void *)resource); 15202 } 15203 15204 /** 15205 * Release an destination array resource. 15206 * 15207 * @param dev 15208 * Pointer to Ethernet device. 15209 * @param handle 15210 * Pointer to mlx5_flow_handle. 15211 * 15212 * @return 15213 * 1 while a reference on it exists, 0 when freed. 15214 */ 15215 static int 15216 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev, 15217 struct mlx5_flow_handle *handle) 15218 { 15219 struct mlx5_priv *priv = dev->data->dev_private; 15220 struct mlx5_flow_dv_dest_array_resource *resource; 15221 15222 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], 15223 handle->dvh.rix_dest_array); 15224 if (!resource) 15225 return 0; 15226 MLX5_ASSERT(resource->action); 15227 return mlx5_list_unregister(priv->sh->dest_array_list, 15228 &resource->entry); 15229 } 15230 15231 void 15232 flow_dev_geneve_tlv_option_resource_release(struct mlx5_dev_ctx_shared *sh) 15233 { 15234 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 15235 sh->geneve_tlv_option_resource; 15236 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 15237 if (geneve_opt_resource) { 15238 if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1, 15239 __ATOMIC_RELAXED))) { 15240 claim_zero(mlx5_devx_cmd_destroy 15241 (geneve_opt_resource->obj)); 15242 mlx5_free(sh->geneve_tlv_option_resource); 15243 sh->geneve_tlv_option_resource = NULL; 15244 } 15245 } 15246 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 15247 } 15248 15249 /** 15250 * Remove the flow from the NIC but keeps it in memory. 15251 * Lock free, (mutex should be acquired by caller). 15252 * 15253 * @param[in] dev 15254 * Pointer to Ethernet device. 15255 * @param[in, out] flow 15256 * Pointer to flow structure. 15257 */ 15258 static void 15259 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow) 15260 { 15261 struct mlx5_flow_handle *dh; 15262 uint32_t handle_idx; 15263 struct mlx5_priv *priv = dev->data->dev_private; 15264 15265 if (!flow) 15266 return; 15267 handle_idx = flow->dev_handles; 15268 while (handle_idx) { 15269 dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 15270 handle_idx); 15271 if (!dh) 15272 return; 15273 if (dh->drv_flow) { 15274 claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow)); 15275 dh->drv_flow = NULL; 15276 } 15277 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) 15278 flow_dv_fate_resource_release(dev, dh); 15279 if (dh->vf_vlan.tag && dh->vf_vlan.created) 15280 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 15281 handle_idx = dh->next.next; 15282 } 15283 } 15284 15285 /** 15286 * Remove the flow from the NIC and the memory. 15287 * Lock free, (mutex should be acquired by caller). 15288 * 15289 * @param[in] dev 15290 * Pointer to the Ethernet device structure. 15291 * @param[in, out] flow 15292 * Pointer to flow structure. 15293 */ 15294 static void 15295 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) 15296 { 15297 struct mlx5_flow_handle *dev_handle; 15298 struct mlx5_priv *priv = dev->data->dev_private; 15299 struct mlx5_flow_meter_info *fm = NULL; 15300 uint32_t srss = 0; 15301 15302 if (!flow) 15303 return; 15304 flow_dv_remove(dev, flow); 15305 if (flow->counter) { 15306 flow_dv_counter_free(dev, flow->counter); 15307 flow->counter = 0; 15308 } 15309 if (flow->meter) { 15310 fm = flow_dv_meter_find_by_idx(priv, flow->meter); 15311 if (fm) 15312 mlx5_flow_meter_detach(priv, fm); 15313 flow->meter = 0; 15314 } 15315 /* Keep the current age handling by default. */ 15316 if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct) 15317 flow_dv_aso_ct_release(dev, flow->ct, NULL); 15318 else if (flow->age) 15319 flow_dv_aso_age_release(dev, flow->age); 15320 if (flow->geneve_tlv_option) { 15321 flow_dev_geneve_tlv_option_resource_release(priv->sh); 15322 flow->geneve_tlv_option = 0; 15323 } 15324 while (flow->dev_handles) { 15325 uint32_t tmp_idx = flow->dev_handles; 15326 15327 dev_handle = mlx5_ipool_get(priv->sh->ipool 15328 [MLX5_IPOOL_MLX5_FLOW], tmp_idx); 15329 if (!dev_handle) 15330 return; 15331 flow->dev_handles = dev_handle->next.next; 15332 while (dev_handle->flex_item) { 15333 int index = rte_bsf32(dev_handle->flex_item); 15334 15335 mlx5_flex_release_index(dev, index); 15336 dev_handle->flex_item &= ~(uint8_t)RTE_BIT32(index); 15337 } 15338 if (dev_handle->dvh.matcher) 15339 flow_dv_matcher_release(dev, dev_handle); 15340 if (dev_handle->dvh.rix_sample) 15341 flow_dv_sample_resource_release(dev, dev_handle); 15342 if (dev_handle->dvh.rix_dest_array) 15343 flow_dv_dest_array_resource_release(dev, dev_handle); 15344 if (dev_handle->dvh.rix_encap_decap) 15345 flow_dv_encap_decap_resource_release(dev, 15346 dev_handle->dvh.rix_encap_decap); 15347 if (dev_handle->dvh.modify_hdr) 15348 flow_dv_modify_hdr_resource_release(dev, dev_handle); 15349 if (dev_handle->dvh.rix_push_vlan) 15350 flow_dv_push_vlan_action_resource_release(dev, 15351 dev_handle); 15352 if (dev_handle->dvh.rix_tag) 15353 flow_dv_tag_release(dev, 15354 dev_handle->dvh.rix_tag); 15355 if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS) 15356 flow_dv_fate_resource_release(dev, dev_handle); 15357 else if (!srss) 15358 srss = dev_handle->rix_srss; 15359 if (fm && dev_handle->is_meter_flow_id && 15360 dev_handle->split_flow_id) 15361 mlx5_ipool_free(fm->flow_ipool, 15362 dev_handle->split_flow_id); 15363 else if (dev_handle->split_flow_id && 15364 !dev_handle->is_meter_flow_id) 15365 mlx5_ipool_free(priv->sh->ipool 15366 [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], 15367 dev_handle->split_flow_id); 15368 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 15369 tmp_idx); 15370 } 15371 if (srss) 15372 flow_dv_shared_rss_action_release(dev, srss); 15373 } 15374 15375 /** 15376 * Release array of hash RX queue objects. 15377 * Helper function. 15378 * 15379 * @param[in] dev 15380 * Pointer to the Ethernet device structure. 15381 * @param[in, out] hrxqs 15382 * Array of hash RX queue objects. 15383 * 15384 * @return 15385 * Total number of references to hash RX queue objects in *hrxqs* array 15386 * after this operation. 15387 */ 15388 static int 15389 __flow_dv_hrxqs_release(struct rte_eth_dev *dev, 15390 uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN]) 15391 { 15392 size_t i; 15393 int remaining = 0; 15394 15395 for (i = 0; i < RTE_DIM(*hrxqs); i++) { 15396 int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]); 15397 15398 if (!ret) 15399 (*hrxqs)[i] = 0; 15400 remaining += ret; 15401 } 15402 return remaining; 15403 } 15404 15405 /** 15406 * Release all hash RX queue objects representing shared RSS action. 15407 * 15408 * @param[in] dev 15409 * Pointer to the Ethernet device structure. 15410 * @param[in, out] action 15411 * Shared RSS action to remove hash RX queue objects from. 15412 * 15413 * @return 15414 * Total number of references to hash RX queue objects stored in *action* 15415 * after this operation. 15416 * Expected to be 0 if no external references held. 15417 */ 15418 static int 15419 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev, 15420 struct mlx5_shared_action_rss *shared_rss) 15421 { 15422 return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq); 15423 } 15424 15425 /** 15426 * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to 15427 * user input. 15428 * 15429 * Only one hash value is available for one L3+L4 combination: 15430 * for example: 15431 * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and 15432 * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share 15433 * same slot in mlx5_rss_hash_fields. 15434 * 15435 * @param[in] orig_rss_types 15436 * RSS type as provided in shared RSS action. 15437 * @param[in, out] hash_field 15438 * hash_field variable needed to be adjusted. 15439 * 15440 * @return 15441 * void 15442 */ 15443 void 15444 flow_dv_action_rss_l34_hash_adjust(uint64_t orig_rss_types, 15445 uint64_t *hash_field) 15446 { 15447 uint64_t rss_types = rte_eth_rss_hf_refine(orig_rss_types); 15448 15449 switch (*hash_field & ~IBV_RX_HASH_INNER) { 15450 case MLX5_RSS_HASH_IPV4: 15451 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 15452 *hash_field &= ~MLX5_RSS_HASH_IPV4; 15453 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 15454 *hash_field |= IBV_RX_HASH_DST_IPV4; 15455 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 15456 *hash_field |= IBV_RX_HASH_SRC_IPV4; 15457 else 15458 *hash_field |= MLX5_RSS_HASH_IPV4; 15459 } 15460 return; 15461 case MLX5_RSS_HASH_IPV6: 15462 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 15463 *hash_field &= ~MLX5_RSS_HASH_IPV6; 15464 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 15465 *hash_field |= IBV_RX_HASH_DST_IPV6; 15466 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 15467 *hash_field |= IBV_RX_HASH_SRC_IPV6; 15468 else 15469 *hash_field |= MLX5_RSS_HASH_IPV6; 15470 } 15471 return; 15472 case MLX5_RSS_HASH_IPV4_UDP: 15473 /* fall-through. */ 15474 case MLX5_RSS_HASH_IPV6_UDP: 15475 if (rss_types & RTE_ETH_RSS_UDP) { 15476 *hash_field &= ~MLX5_UDP_IBV_RX_HASH; 15477 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 15478 *hash_field |= IBV_RX_HASH_DST_PORT_UDP; 15479 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 15480 *hash_field |= IBV_RX_HASH_SRC_PORT_UDP; 15481 else 15482 *hash_field |= MLX5_UDP_IBV_RX_HASH; 15483 } 15484 return; 15485 case MLX5_RSS_HASH_IPV4_TCP: 15486 /* fall-through. */ 15487 case MLX5_RSS_HASH_IPV6_TCP: 15488 if (rss_types & RTE_ETH_RSS_TCP) { 15489 *hash_field &= ~MLX5_TCP_IBV_RX_HASH; 15490 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 15491 *hash_field |= IBV_RX_HASH_DST_PORT_TCP; 15492 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 15493 *hash_field |= IBV_RX_HASH_SRC_PORT_TCP; 15494 else 15495 *hash_field |= MLX5_TCP_IBV_RX_HASH; 15496 } 15497 return; 15498 default: 15499 return; 15500 } 15501 } 15502 15503 /** 15504 * Setup shared RSS action. 15505 * Prepare set of hash RX queue objects sufficient to handle all valid 15506 * hash_fields combinations (see enum ibv_rx_hash_fields). 15507 * 15508 * @param[in] dev 15509 * Pointer to the Ethernet device structure. 15510 * @param[in] action_idx 15511 * Shared RSS action ipool index. 15512 * @param[in, out] action 15513 * Partially initialized shared RSS action. 15514 * @param[out] error 15515 * Perform verbose error reporting if not NULL. Initialized in case of 15516 * error only. 15517 * 15518 * @return 15519 * 0 on success, otherwise negative errno value. 15520 */ 15521 static int 15522 __flow_dv_action_rss_setup(struct rte_eth_dev *dev, 15523 uint32_t action_idx, 15524 struct mlx5_shared_action_rss *shared_rss, 15525 struct rte_flow_error *error) 15526 { 15527 struct mlx5_priv *priv = dev->data->dev_private; 15528 struct mlx5_flow_rss_desc rss_desc = { 0 }; 15529 size_t i; 15530 int err; 15531 15532 shared_rss->ind_tbl = mlx5_ind_table_obj_new 15533 (dev, shared_rss->origin.queue, 15534 shared_rss->origin.queue_num, 15535 true, 15536 !!dev->data->dev_started); 15537 if (!shared_rss->ind_tbl) 15538 return rte_flow_error_set(error, rte_errno, 15539 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 15540 "cannot setup indirection table"); 15541 memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN); 15542 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN; 15543 rss_desc.const_q = shared_rss->origin.queue; 15544 rss_desc.queue_num = shared_rss->origin.queue_num; 15545 /* Set non-zero value to indicate a shared RSS. */ 15546 rss_desc.shared_rss = action_idx; 15547 rss_desc.ind_tbl = shared_rss->ind_tbl; 15548 if (priv->sh->config.dv_flow_en == 2) 15549 rss_desc.hws_flags = MLX5DR_ACTION_FLAG_HWS_RX; 15550 for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) { 15551 struct mlx5_hrxq *hrxq; 15552 uint64_t hash_fields = mlx5_rss_hash_fields[i]; 15553 int tunnel = 0; 15554 15555 flow_dv_action_rss_l34_hash_adjust(shared_rss->origin.types, 15556 &hash_fields); 15557 if (shared_rss->origin.level > 1) { 15558 hash_fields |= IBV_RX_HASH_INNER; 15559 tunnel = 1; 15560 } 15561 rss_desc.tunnel = tunnel; 15562 rss_desc.hash_fields = hash_fields; 15563 hrxq = mlx5_hrxq_get(dev, &rss_desc); 15564 if (!hrxq) { 15565 rte_flow_error_set 15566 (error, rte_errno, 15567 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 15568 "cannot get hash queue"); 15569 goto error_hrxq_new; 15570 } 15571 err = __flow_dv_action_rss_hrxq_set 15572 (shared_rss, hash_fields, hrxq->idx); 15573 MLX5_ASSERT(!err); 15574 } 15575 return 0; 15576 error_hrxq_new: 15577 err = rte_errno; 15578 __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 15579 if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true)) 15580 shared_rss->ind_tbl = NULL; 15581 rte_errno = err; 15582 return -rte_errno; 15583 } 15584 15585 /** 15586 * Create shared RSS action. 15587 * 15588 * @param[in] dev 15589 * Pointer to the Ethernet device structure. 15590 * @param[in] conf 15591 * Shared action configuration. 15592 * @param[in] rss 15593 * RSS action specification used to create shared action. 15594 * @param[out] error 15595 * Perform verbose error reporting if not NULL. Initialized in case of 15596 * error only. 15597 * 15598 * @return 15599 * A valid shared action ID in case of success, 0 otherwise and 15600 * rte_errno is set. 15601 */ 15602 static uint32_t 15603 __flow_dv_action_rss_create(struct rte_eth_dev *dev, 15604 const struct rte_flow_indir_action_conf *conf, 15605 const struct rte_flow_action_rss *rss, 15606 struct rte_flow_error *error) 15607 { 15608 struct mlx5_priv *priv = dev->data->dev_private; 15609 struct mlx5_shared_action_rss *shared_rss = NULL; 15610 struct rte_flow_action_rss *origin; 15611 const uint8_t *rss_key; 15612 uint32_t idx; 15613 15614 RTE_SET_USED(conf); 15615 shared_rss = mlx5_ipool_zmalloc 15616 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx); 15617 if (!shared_rss) { 15618 rte_flow_error_set(error, ENOMEM, 15619 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 15620 "cannot allocate resource memory"); 15621 goto error_rss_init; 15622 } 15623 if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) { 15624 rte_flow_error_set(error, E2BIG, 15625 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 15626 "rss action number out of range"); 15627 goto error_rss_init; 15628 } 15629 origin = &shared_rss->origin; 15630 origin->func = rss->func; 15631 origin->level = rss->level; 15632 /* RSS type 0 indicates default RSS type (RTE_ETH_RSS_IP). */ 15633 origin->types = !rss->types ? RTE_ETH_RSS_IP : rss->types; 15634 /* NULL RSS key indicates default RSS key. */ 15635 rss_key = !rss->key ? rss_hash_default_key : rss->key; 15636 memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 15637 origin->key = &shared_rss->key[0]; 15638 origin->key_len = MLX5_RSS_HASH_KEY_LEN; 15639 origin->queue = rss->queue; 15640 origin->queue_num = rss->queue_num; 15641 if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error)) 15642 goto error_rss_init; 15643 /* Update queue with indirect table queue memoyr. */ 15644 origin->queue = shared_rss->ind_tbl->queues; 15645 rte_spinlock_init(&shared_rss->action_rss_sl); 15646 __atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 15647 rte_spinlock_lock(&priv->shared_act_sl); 15648 ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 15649 &priv->rss_shared_actions, idx, shared_rss, next); 15650 rte_spinlock_unlock(&priv->shared_act_sl); 15651 return idx; 15652 error_rss_init: 15653 if (shared_rss) { 15654 if (shared_rss->ind_tbl) 15655 mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, 15656 !!dev->data->dev_started); 15657 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 15658 idx); 15659 } 15660 return 0; 15661 } 15662 15663 /** 15664 * Destroy the shared RSS action. 15665 * Release related hash RX queue objects. 15666 * 15667 * @param[in] dev 15668 * Pointer to the Ethernet device structure. 15669 * @param[in] idx 15670 * The shared RSS action object ID to be removed. 15671 * @param[out] error 15672 * Perform verbose error reporting if not NULL. Initialized in case of 15673 * error only. 15674 * 15675 * @return 15676 * 0 on success, otherwise negative errno value. 15677 */ 15678 static int 15679 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, 15680 struct rte_flow_error *error) 15681 { 15682 struct mlx5_priv *priv = dev->data->dev_private; 15683 struct mlx5_shared_action_rss *shared_rss = 15684 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 15685 uint32_t old_refcnt = 1; 15686 int remaining; 15687 15688 if (!shared_rss) 15689 return rte_flow_error_set(error, EINVAL, 15690 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15691 "invalid shared action"); 15692 if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt, 15693 0, 0, __ATOMIC_ACQUIRE, 15694 __ATOMIC_RELAXED)) 15695 return rte_flow_error_set(error, EBUSY, 15696 RTE_FLOW_ERROR_TYPE_ACTION, 15697 NULL, 15698 "shared rss has references"); 15699 remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 15700 if (remaining) 15701 return rte_flow_error_set(error, EBUSY, 15702 RTE_FLOW_ERROR_TYPE_ACTION, 15703 NULL, 15704 "shared rss hrxq has references"); 15705 remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, 15706 !!dev->data->dev_started); 15707 if (remaining) 15708 return rte_flow_error_set(error, EBUSY, 15709 RTE_FLOW_ERROR_TYPE_ACTION, 15710 NULL, 15711 "shared rss indirection table has" 15712 " references"); 15713 rte_spinlock_lock(&priv->shared_act_sl); 15714 ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 15715 &priv->rss_shared_actions, idx, shared_rss, next); 15716 rte_spinlock_unlock(&priv->shared_act_sl); 15717 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 15718 idx); 15719 return 0; 15720 } 15721 15722 /** 15723 * Create indirect action, lock free, 15724 * (mutex should be acquired by caller). 15725 * Dispatcher for action type specific call. 15726 * 15727 * @param[in] dev 15728 * Pointer to the Ethernet device structure. 15729 * @param[in] conf 15730 * Shared action configuration. 15731 * @param[in] action 15732 * Action specification used to create indirect action. 15733 * @param[out] error 15734 * Perform verbose error reporting if not NULL. Initialized in case of 15735 * error only. 15736 * 15737 * @return 15738 * A valid shared action handle in case of success, NULL otherwise and 15739 * rte_errno is set. 15740 */ 15741 struct rte_flow_action_handle * 15742 flow_dv_action_create(struct rte_eth_dev *dev, 15743 const struct rte_flow_indir_action_conf *conf, 15744 const struct rte_flow_action *action, 15745 struct rte_flow_error *err) 15746 { 15747 struct mlx5_priv *priv = dev->data->dev_private; 15748 uint32_t age_idx = 0; 15749 uint32_t idx = 0; 15750 uint32_t ret = 0; 15751 15752 switch (action->type) { 15753 case RTE_FLOW_ACTION_TYPE_RSS: 15754 ret = __flow_dv_action_rss_create(dev, conf, action->conf, err); 15755 idx = (MLX5_INDIRECT_ACTION_TYPE_RSS << 15756 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 15757 break; 15758 case RTE_FLOW_ACTION_TYPE_AGE: 15759 age_idx = flow_dv_aso_age_alloc(dev, err); 15760 if (!age_idx) { 15761 ret = -rte_errno; 15762 break; 15763 } 15764 idx = (MLX5_INDIRECT_ACTION_TYPE_AGE << 15765 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx; 15766 flow_dv_aso_age_params_init(dev, age_idx, 15767 ((const struct rte_flow_action_age *) 15768 action->conf)->context ? 15769 ((const struct rte_flow_action_age *) 15770 action->conf)->context : 15771 (void *)(uintptr_t)idx, 15772 ((const struct rte_flow_action_age *) 15773 action->conf)->timeout); 15774 ret = age_idx; 15775 break; 15776 case RTE_FLOW_ACTION_TYPE_COUNT: 15777 ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL); 15778 idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT << 15779 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 15780 break; 15781 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 15782 ret = flow_dv_translate_create_conntrack(dev, action->conf, 15783 err); 15784 idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret); 15785 break; 15786 default: 15787 rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, 15788 NULL, "action type not supported"); 15789 break; 15790 } 15791 return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL; 15792 } 15793 15794 /** 15795 * Destroy the indirect action. 15796 * Release action related resources on the NIC and the memory. 15797 * Lock free, (mutex should be acquired by caller). 15798 * Dispatcher for action type specific call. 15799 * 15800 * @param[in] dev 15801 * Pointer to the Ethernet device structure. 15802 * @param[in] handle 15803 * The indirect action object handle to be removed. 15804 * @param[out] error 15805 * Perform verbose error reporting if not NULL. Initialized in case of 15806 * error only. 15807 * 15808 * @return 15809 * 0 on success, otherwise negative errno value. 15810 */ 15811 int 15812 flow_dv_action_destroy(struct rte_eth_dev *dev, 15813 struct rte_flow_action_handle *handle, 15814 struct rte_flow_error *error) 15815 { 15816 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15817 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15818 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15819 struct mlx5_flow_counter *cnt; 15820 uint32_t no_flow_refcnt = 1; 15821 int ret; 15822 15823 switch (type) { 15824 case MLX5_INDIRECT_ACTION_TYPE_RSS: 15825 return __flow_dv_action_rss_release(dev, idx, error); 15826 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 15827 cnt = flow_dv_counter_get_by_idx(dev, idx, NULL); 15828 if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt, 15829 &no_flow_refcnt, 1, false, 15830 __ATOMIC_ACQUIRE, 15831 __ATOMIC_RELAXED)) 15832 return rte_flow_error_set(error, EBUSY, 15833 RTE_FLOW_ERROR_TYPE_ACTION, 15834 NULL, 15835 "Indirect count action has references"); 15836 flow_dv_counter_free(dev, idx); 15837 return 0; 15838 case MLX5_INDIRECT_ACTION_TYPE_AGE: 15839 ret = flow_dv_aso_age_release(dev, idx); 15840 if (ret) 15841 /* 15842 * In this case, the last flow has a reference will 15843 * actually release the age action. 15844 */ 15845 DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was" 15846 " released with references %d.", idx, ret); 15847 return 0; 15848 case MLX5_INDIRECT_ACTION_TYPE_CT: 15849 ret = flow_dv_aso_ct_release(dev, idx, error); 15850 if (ret < 0) 15851 return ret; 15852 if (ret > 0) 15853 DRV_LOG(DEBUG, "Connection tracking object %u still " 15854 "has references %d.", idx, ret); 15855 return 0; 15856 default: 15857 return rte_flow_error_set(error, ENOTSUP, 15858 RTE_FLOW_ERROR_TYPE_ACTION, 15859 NULL, 15860 "action type not supported"); 15861 } 15862 } 15863 15864 /** 15865 * Updates in place shared RSS action configuration. 15866 * 15867 * @param[in] dev 15868 * Pointer to the Ethernet device structure. 15869 * @param[in] idx 15870 * The shared RSS action object ID to be updated. 15871 * @param[in] action_conf 15872 * RSS action specification used to modify *shared_rss*. 15873 * @param[out] error 15874 * Perform verbose error reporting if not NULL. Initialized in case of 15875 * error only. 15876 * 15877 * @return 15878 * 0 on success, otherwise negative errno value. 15879 * @note: currently only support update of RSS queues. 15880 */ 15881 static int 15882 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx, 15883 const struct rte_flow_action_rss *action_conf, 15884 struct rte_flow_error *error) 15885 { 15886 struct mlx5_priv *priv = dev->data->dev_private; 15887 struct mlx5_shared_action_rss *shared_rss = 15888 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 15889 int ret = 0; 15890 void *queue = NULL; 15891 void *queue_i = NULL; 15892 uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t); 15893 bool dev_started = !!dev->data->dev_started; 15894 15895 if (!shared_rss) 15896 return rte_flow_error_set(error, EINVAL, 15897 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15898 "invalid shared action to update"); 15899 if (priv->obj_ops.ind_table_modify == NULL) 15900 return rte_flow_error_set(error, ENOTSUP, 15901 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15902 "cannot modify indirection table"); 15903 queue = mlx5_malloc(MLX5_MEM_ZERO, 15904 RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 15905 0, SOCKET_ID_ANY); 15906 if (!queue) 15907 return rte_flow_error_set(error, ENOMEM, 15908 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15909 NULL, 15910 "cannot allocate resource memory"); 15911 memcpy(queue, action_conf->queue, queue_size); 15912 MLX5_ASSERT(shared_rss->ind_tbl); 15913 rte_spinlock_lock(&shared_rss->action_rss_sl); 15914 queue_i = shared_rss->ind_tbl->queues; 15915 ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl, 15916 queue, action_conf->queue_num, 15917 true /* standalone */, 15918 dev_started /* ref_new_qs */, 15919 dev_started /* deref_old_qs */); 15920 if (ret) { 15921 ret = rte_flow_error_set(error, rte_errno, 15922 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15923 "cannot update indirection table"); 15924 } else { 15925 /* Restore the queue to indirect table internal queue. */ 15926 memcpy(queue_i, queue, queue_size); 15927 shared_rss->ind_tbl->queues = queue_i; 15928 shared_rss->origin.queue_num = action_conf->queue_num; 15929 } 15930 mlx5_free(queue); 15931 rte_spinlock_unlock(&shared_rss->action_rss_sl); 15932 return ret; 15933 } 15934 15935 /* 15936 * Updates in place conntrack context or direction. 15937 * Context update should be synchronized. 15938 * 15939 * @param[in] dev 15940 * Pointer to the Ethernet device structure. 15941 * @param[in] idx 15942 * The conntrack object ID to be updated. 15943 * @param[in] update 15944 * Pointer to the structure of information to update. 15945 * @param[out] error 15946 * Perform verbose error reporting if not NULL. Initialized in case of 15947 * error only. 15948 * 15949 * @return 15950 * 0 on success, otherwise negative errno value. 15951 */ 15952 static int 15953 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, 15954 const struct rte_flow_modify_conntrack *update, 15955 struct rte_flow_error *error) 15956 { 15957 struct mlx5_priv *priv = dev->data->dev_private; 15958 struct mlx5_aso_ct_action *ct; 15959 const struct rte_flow_action_conntrack *new_prf; 15960 int ret = 0; 15961 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15962 uint32_t dev_idx; 15963 15964 if (PORT_ID(priv) != owner) 15965 return rte_flow_error_set(error, EACCES, 15966 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15967 NULL, 15968 "CT object owned by another port"); 15969 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15970 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15971 if (!ct->refcnt) 15972 return rte_flow_error_set(error, ENOMEM, 15973 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15974 NULL, 15975 "CT object is inactive"); 15976 new_prf = &update->new_ct; 15977 if (update->direction) 15978 ct->is_original = !!new_prf->is_original_dir; 15979 if (update->state) { 15980 /* Only validate the profile when it needs to be updated. */ 15981 ret = mlx5_validate_action_ct(dev, new_prf, error); 15982 if (ret) 15983 return ret; 15984 ret = mlx5_aso_ct_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, 15985 ct, new_prf, NULL, true); 15986 if (ret) 15987 return rte_flow_error_set(error, EIO, 15988 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15989 NULL, 15990 "Failed to send CT context update WQE"); 15991 /* Block until ready or a failure, default is asynchronous. */ 15992 ret = mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct); 15993 if (ret) 15994 rte_flow_error_set(error, rte_errno, 15995 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15996 NULL, 15997 "Timeout to get the CT update"); 15998 } 15999 return ret; 16000 } 16001 16002 /** 16003 * Updates in place shared action configuration, lock free, 16004 * (mutex should be acquired by caller). 16005 * 16006 * @param[in] dev 16007 * Pointer to the Ethernet device structure. 16008 * @param[in] handle 16009 * The indirect action object handle to be updated. 16010 * @param[in] update 16011 * Action specification used to modify the action pointed by *handle*. 16012 * *update* could be of same type with the action pointed by the *handle* 16013 * handle argument, or some other structures like a wrapper, depending on 16014 * the indirect action type. 16015 * @param[out] error 16016 * Perform verbose error reporting if not NULL. Initialized in case of 16017 * error only. 16018 * 16019 * @return 16020 * 0 on success, otherwise negative errno value. 16021 */ 16022 int 16023 flow_dv_action_update(struct rte_eth_dev *dev, 16024 struct rte_flow_action_handle *handle, 16025 const void *update, 16026 struct rte_flow_error *err) 16027 { 16028 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 16029 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 16030 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 16031 const void *action_conf; 16032 16033 switch (type) { 16034 case MLX5_INDIRECT_ACTION_TYPE_RSS: 16035 action_conf = ((const struct rte_flow_action *)update)->conf; 16036 return __flow_dv_action_rss_update(dev, idx, action_conf, err); 16037 case MLX5_INDIRECT_ACTION_TYPE_CT: 16038 return __flow_dv_action_ct_update(dev, idx, update, err); 16039 default: 16040 return rte_flow_error_set(err, ENOTSUP, 16041 RTE_FLOW_ERROR_TYPE_ACTION, 16042 NULL, 16043 "action type update not supported"); 16044 } 16045 } 16046 16047 /** 16048 * Destroy the meter sub policy table rules. 16049 * Lock free, (mutex should be acquired by caller). 16050 * 16051 * @param[in] dev 16052 * Pointer to Ethernet device. 16053 * @param[in] sub_policy 16054 * Pointer to meter sub policy table. 16055 */ 16056 static void 16057 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, 16058 struct mlx5_flow_meter_sub_policy *sub_policy) 16059 { 16060 struct mlx5_priv *priv = dev->data->dev_private; 16061 struct mlx5_flow_tbl_data_entry *tbl; 16062 struct mlx5_flow_meter_policy *policy = sub_policy->main_policy; 16063 struct mlx5_flow_meter_info *next_fm; 16064 struct mlx5_sub_policy_color_rule *color_rule; 16065 void *tmp; 16066 uint32_t i; 16067 16068 for (i = 0; i < RTE_COLORS; i++) { 16069 next_fm = NULL; 16070 if (i <= RTE_COLOR_YELLOW && policy && 16071 policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) 16072 next_fm = mlx5_flow_meter_find(priv, 16073 policy->act_cnt[i].next_mtr_id, NULL); 16074 RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], 16075 next_port, tmp) { 16076 claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule)); 16077 tbl = container_of(color_rule->matcher->tbl, 16078 typeof(*tbl), tbl); 16079 mlx5_list_unregister(tbl->matchers, 16080 &color_rule->matcher->entry); 16081 TAILQ_REMOVE(&sub_policy->color_rules[i], 16082 color_rule, next_port); 16083 mlx5_free(color_rule); 16084 if (next_fm) 16085 mlx5_flow_meter_detach(priv, next_fm); 16086 } 16087 } 16088 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16089 if (sub_policy->rix_hrxq[i]) { 16090 if (policy && !policy->is_hierarchy) 16091 mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]); 16092 sub_policy->rix_hrxq[i] = 0; 16093 } 16094 if (sub_policy->jump_tbl[i]) { 16095 flow_dv_tbl_resource_release(MLX5_SH(dev), 16096 sub_policy->jump_tbl[i]); 16097 sub_policy->jump_tbl[i] = NULL; 16098 } 16099 } 16100 if (sub_policy->tbl_rsc) { 16101 flow_dv_tbl_resource_release(MLX5_SH(dev), 16102 sub_policy->tbl_rsc); 16103 sub_policy->tbl_rsc = NULL; 16104 } 16105 } 16106 16107 /** 16108 * Destroy policy rules, lock free, 16109 * (mutex should be acquired by caller). 16110 * Dispatcher for action type specific call. 16111 * 16112 * @param[in] dev 16113 * Pointer to the Ethernet device structure. 16114 * @param[in] mtr_policy 16115 * Meter policy struct. 16116 */ 16117 static void 16118 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, 16119 struct mlx5_flow_meter_policy *mtr_policy) 16120 { 16121 uint32_t i, j; 16122 struct mlx5_flow_meter_sub_policy *sub_policy; 16123 uint16_t sub_policy_num; 16124 16125 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16126 sub_policy_num = (mtr_policy->sub_policy_num >> 16127 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 16128 MLX5_MTR_SUB_POLICY_NUM_MASK; 16129 for (j = 0; j < sub_policy_num; j++) { 16130 sub_policy = mtr_policy->sub_policys[i][j]; 16131 if (sub_policy) 16132 __flow_dv_destroy_sub_policy_rules(dev, 16133 sub_policy); 16134 } 16135 } 16136 } 16137 16138 /** 16139 * Destroy policy action, lock free, 16140 * (mutex should be acquired by caller). 16141 * Dispatcher for action type specific call. 16142 * 16143 * @param[in] dev 16144 * Pointer to the Ethernet device structure. 16145 * @param[in] mtr_policy 16146 * Meter policy struct. 16147 */ 16148 static void 16149 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev, 16150 struct mlx5_flow_meter_policy *mtr_policy) 16151 { 16152 struct rte_flow_action *rss_action; 16153 struct mlx5_flow_handle dev_handle; 16154 uint32_t i, j; 16155 16156 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16157 if (mtr_policy->act_cnt[i].rix_mark) { 16158 flow_dv_tag_release(dev, 16159 mtr_policy->act_cnt[i].rix_mark); 16160 mtr_policy->act_cnt[i].rix_mark = 0; 16161 } 16162 if (mtr_policy->act_cnt[i].modify_hdr) { 16163 dev_handle.dvh.modify_hdr = 16164 mtr_policy->act_cnt[i].modify_hdr; 16165 flow_dv_modify_hdr_resource_release(dev, &dev_handle); 16166 } 16167 switch (mtr_policy->act_cnt[i].fate_action) { 16168 case MLX5_FLOW_FATE_SHARED_RSS: 16169 rss_action = mtr_policy->act_cnt[i].rss; 16170 mlx5_free(rss_action); 16171 break; 16172 case MLX5_FLOW_FATE_PORT_ID: 16173 if (mtr_policy->act_cnt[i].rix_port_id_action) { 16174 flow_dv_port_id_action_resource_release(dev, 16175 mtr_policy->act_cnt[i].rix_port_id_action); 16176 mtr_policy->act_cnt[i].rix_port_id_action = 0; 16177 } 16178 break; 16179 case MLX5_FLOW_FATE_DROP: 16180 case MLX5_FLOW_FATE_JUMP: 16181 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 16182 mtr_policy->act_cnt[i].dr_jump_action[j] = 16183 NULL; 16184 break; 16185 default: 16186 /*Queue action do nothing*/ 16187 break; 16188 } 16189 } 16190 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 16191 mtr_policy->dr_drop_action[j] = NULL; 16192 } 16193 16194 /** 16195 * Create yellow action for color aware meter. 16196 * 16197 * @param[in] dev 16198 * Pointer to the Ethernet device structure. 16199 * @param[in] fm 16200 * Meter information table. 16201 * @param[out] error 16202 * Perform verbose error reporting if not NULL. Initialized in case of 16203 * error only. 16204 * 16205 * @return 16206 * 0 on success, a negative errno value otherwise and rte_errno is set. 16207 */ 16208 static int 16209 __flow_dv_create_mtr_yellow_action(struct rte_eth_dev *dev, 16210 struct mlx5_flow_meter_info *fm, 16211 struct rte_mtr_error *error) 16212 { 16213 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 16214 struct mlx5_priv *priv = dev->data->dev_private; 16215 struct rte_flow_error flow_err; 16216 struct mlx5_aso_mtr *aso_mtr; 16217 struct mlx5_aso_mtr_pool *pool; 16218 uint8_t reg_id; 16219 16220 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); 16221 pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, mtrs[aso_mtr->offset]); 16222 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err); 16223 fm->meter_action_y = 16224 mlx5_glue->dv_create_flow_action_aso(priv->sh->rx_domain, 16225 pool->devx_obj->obj, 16226 aso_mtr->offset, 16227 (1 << MLX5_FLOW_COLOR_YELLOW), 16228 reg_id - REG_C_0); 16229 #else 16230 RTE_SET_USED(dev); 16231 #endif 16232 if (!fm->meter_action_y) { 16233 return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 16234 "Fail to create yellow meter action."); 16235 } 16236 return 0; 16237 } 16238 16239 /** 16240 * Create policy action per domain, lock free, 16241 * (mutex should be acquired by caller). 16242 * Dispatcher for action type specific call. 16243 * 16244 * @param[in] dev 16245 * Pointer to the Ethernet device structure. 16246 * @param[in] mtr_policy 16247 * Meter policy struct. 16248 * @param[in] action 16249 * Action specification used to create meter actions. 16250 * @param[in] attr 16251 * Pointer to the flow attributes. 16252 * @param[out] error 16253 * Perform verbose error reporting if not NULL. Initialized in case of 16254 * error only. 16255 * 16256 * @return 16257 * 0 on success, otherwise negative errno value. 16258 */ 16259 static int 16260 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, 16261 struct mlx5_flow_meter_policy *mtr_policy, 16262 const struct rte_flow_action *actions[RTE_COLORS], 16263 struct rte_flow_attr *attr, 16264 enum mlx5_meter_domain domain, 16265 struct rte_mtr_error *error) 16266 { 16267 struct mlx5_priv *priv = dev->data->dev_private; 16268 struct rte_flow_error flow_err; 16269 const struct rte_flow_action *act; 16270 uint64_t action_flags; 16271 struct mlx5_flow_handle dh; 16272 struct mlx5_flow dev_flow; 16273 struct mlx5_flow_dv_port_id_action_resource port_id_action; 16274 int i, ret; 16275 uint8_t egress, transfer; 16276 struct mlx5_meter_policy_action_container *act_cnt = NULL; 16277 union { 16278 struct mlx5_flow_dv_modify_hdr_resource res; 16279 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 16280 sizeof(struct mlx5_modification_cmd) * 16281 (MLX5_MAX_MODIFY_NUM + 1)]; 16282 } mhdr_dummy; 16283 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 16284 16285 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16286 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16287 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 16288 memset(&dev_flow, 0, sizeof(struct mlx5_flow)); 16289 memset(&port_id_action, 0, 16290 sizeof(struct mlx5_flow_dv_port_id_action_resource)); 16291 memset(mhdr_res, 0, sizeof(*mhdr_res)); 16292 mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 16293 (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 16294 MLX5DV_FLOW_TABLE_TYPE_NIC_RX); 16295 dev_flow.handle = &dh; 16296 dev_flow.dv.port_id_action = &port_id_action; 16297 dev_flow.external = true; 16298 for (i = 0; i < RTE_COLORS; i++) { 16299 if (i < MLX5_MTR_RTE_COLORS) 16300 act_cnt = &mtr_policy->act_cnt[i]; 16301 /* Skip the color policy actions creation. */ 16302 if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) || 16303 (i == RTE_COLOR_GREEN && mtr_policy->skip_g)) 16304 continue; 16305 action_flags = 0; 16306 for (act = actions[i]; 16307 act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 16308 switch (act->type) { 16309 case RTE_FLOW_ACTION_TYPE_MARK: 16310 { 16311 uint32_t tag_be = mlx5_flow_mark_set 16312 (((const struct rte_flow_action_mark *) 16313 (act->conf))->id); 16314 16315 if (i >= MLX5_MTR_RTE_COLORS) 16316 return -rte_mtr_error_set(error, 16317 ENOTSUP, 16318 RTE_MTR_ERROR_TYPE_METER_POLICY, 16319 NULL, 16320 "cannot create policy " 16321 "mark action for this color"); 16322 if (flow_dv_tag_resource_register(dev, tag_be, 16323 &dev_flow, &flow_err)) 16324 return -rte_mtr_error_set(error, 16325 ENOTSUP, 16326 RTE_MTR_ERROR_TYPE_METER_POLICY, 16327 NULL, 16328 "cannot setup policy mark action"); 16329 MLX5_ASSERT(dev_flow.dv.tag_resource); 16330 act_cnt->rix_mark = 16331 dev_flow.handle->dvh.rix_tag; 16332 action_flags |= MLX5_FLOW_ACTION_MARK; 16333 mtr_policy->mark = 1; 16334 break; 16335 } 16336 case RTE_FLOW_ACTION_TYPE_SET_TAG: 16337 if (i >= MLX5_MTR_RTE_COLORS) 16338 return -rte_mtr_error_set(error, 16339 ENOTSUP, 16340 RTE_MTR_ERROR_TYPE_METER_POLICY, 16341 NULL, 16342 "cannot create policy " 16343 "set tag action for this color"); 16344 if (flow_dv_convert_action_set_tag 16345 (dev, mhdr_res, 16346 (const struct rte_flow_action_set_tag *) 16347 act->conf, &flow_err)) 16348 return -rte_mtr_error_set(error, 16349 ENOTSUP, 16350 RTE_MTR_ERROR_TYPE_METER_POLICY, 16351 NULL, "cannot convert policy " 16352 "set tag action"); 16353 if (!mhdr_res->actions_num) 16354 return -rte_mtr_error_set(error, 16355 ENOTSUP, 16356 RTE_MTR_ERROR_TYPE_METER_POLICY, 16357 NULL, "cannot find policy " 16358 "set tag action"); 16359 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 16360 break; 16361 case RTE_FLOW_ACTION_TYPE_DROP: 16362 { 16363 struct mlx5_flow_mtr_mng *mtrmng = 16364 priv->sh->mtrmng; 16365 struct mlx5_flow_tbl_data_entry *tbl_data; 16366 16367 /* 16368 * Create the drop table with 16369 * METER DROP level. 16370 */ 16371 if (!mtrmng->drop_tbl[domain]) { 16372 mtrmng->drop_tbl[domain] = 16373 flow_dv_tbl_resource_get(dev, 16374 MLX5_FLOW_TABLE_LEVEL_METER, 16375 egress, transfer, false, NULL, 0, 16376 0, MLX5_MTR_TABLE_ID_DROP, &flow_err); 16377 if (!mtrmng->drop_tbl[domain]) 16378 return -rte_mtr_error_set 16379 (error, ENOTSUP, 16380 RTE_MTR_ERROR_TYPE_METER_POLICY, 16381 NULL, 16382 "Failed to create meter drop table"); 16383 } 16384 tbl_data = container_of 16385 (mtrmng->drop_tbl[domain], 16386 struct mlx5_flow_tbl_data_entry, tbl); 16387 if (i < MLX5_MTR_RTE_COLORS) { 16388 act_cnt->dr_jump_action[domain] = 16389 tbl_data->jump.action; 16390 act_cnt->fate_action = 16391 MLX5_FLOW_FATE_DROP; 16392 } 16393 if (i == RTE_COLOR_RED) 16394 mtr_policy->dr_drop_action[domain] = 16395 tbl_data->jump.action; 16396 action_flags |= MLX5_FLOW_ACTION_DROP; 16397 break; 16398 } 16399 case RTE_FLOW_ACTION_TYPE_QUEUE: 16400 { 16401 if (i >= MLX5_MTR_RTE_COLORS) 16402 return -rte_mtr_error_set(error, 16403 ENOTSUP, 16404 RTE_MTR_ERROR_TYPE_METER_POLICY, 16405 NULL, "cannot create policy " 16406 "fate queue for this color"); 16407 act_cnt->queue = 16408 ((const struct rte_flow_action_queue *) 16409 (act->conf))->index; 16410 act_cnt->fate_action = 16411 MLX5_FLOW_FATE_QUEUE; 16412 dev_flow.handle->fate_action = 16413 MLX5_FLOW_FATE_QUEUE; 16414 mtr_policy->is_queue = 1; 16415 action_flags |= MLX5_FLOW_ACTION_QUEUE; 16416 break; 16417 } 16418 case RTE_FLOW_ACTION_TYPE_RSS: 16419 { 16420 int rss_size; 16421 16422 if (i >= MLX5_MTR_RTE_COLORS) 16423 return -rte_mtr_error_set(error, 16424 ENOTSUP, 16425 RTE_MTR_ERROR_TYPE_METER_POLICY, 16426 NULL, 16427 "cannot create policy " 16428 "rss action for this color"); 16429 /* 16430 * Save RSS conf into policy struct 16431 * for translate stage. 16432 */ 16433 rss_size = (int)rte_flow_conv 16434 (RTE_FLOW_CONV_OP_ACTION, 16435 NULL, 0, act, &flow_err); 16436 if (rss_size <= 0) 16437 return -rte_mtr_error_set(error, 16438 ENOTSUP, 16439 RTE_MTR_ERROR_TYPE_METER_POLICY, 16440 NULL, "Get the wrong " 16441 "rss action struct size"); 16442 act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO, 16443 rss_size, 0, SOCKET_ID_ANY); 16444 if (!act_cnt->rss) 16445 return -rte_mtr_error_set(error, 16446 ENOTSUP, 16447 RTE_MTR_ERROR_TYPE_METER_POLICY, 16448 NULL, 16449 "Fail to malloc rss action memory"); 16450 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION, 16451 act_cnt->rss, rss_size, 16452 act, &flow_err); 16453 if (ret < 0) 16454 return -rte_mtr_error_set(error, 16455 ENOTSUP, 16456 RTE_MTR_ERROR_TYPE_METER_POLICY, 16457 NULL, "Fail to save " 16458 "rss action into policy struct"); 16459 act_cnt->fate_action = 16460 MLX5_FLOW_FATE_SHARED_RSS; 16461 action_flags |= MLX5_FLOW_ACTION_RSS; 16462 break; 16463 } 16464 case RTE_FLOW_ACTION_TYPE_PORT_ID: 16465 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 16466 { 16467 struct mlx5_flow_dv_port_id_action_resource 16468 port_id_resource; 16469 uint32_t port_id = 0; 16470 16471 if (i >= MLX5_MTR_RTE_COLORS) 16472 return -rte_mtr_error_set(error, 16473 ENOTSUP, 16474 RTE_MTR_ERROR_TYPE_METER_POLICY, 16475 NULL, "cannot create policy " 16476 "port action for this color"); 16477 memset(&port_id_resource, 0, 16478 sizeof(port_id_resource)); 16479 if (flow_dv_translate_action_port_id(dev, act, 16480 &port_id, &flow_err)) 16481 return -rte_mtr_error_set(error, 16482 ENOTSUP, 16483 RTE_MTR_ERROR_TYPE_METER_POLICY, 16484 NULL, "cannot translate " 16485 "policy port action"); 16486 port_id_resource.port_id = port_id; 16487 if (flow_dv_port_id_action_resource_register 16488 (dev, &port_id_resource, 16489 &dev_flow, &flow_err)) 16490 return -rte_mtr_error_set(error, 16491 ENOTSUP, 16492 RTE_MTR_ERROR_TYPE_METER_POLICY, 16493 NULL, "cannot setup " 16494 "policy port action"); 16495 act_cnt->rix_port_id_action = 16496 dev_flow.handle->rix_port_id_action; 16497 act_cnt->fate_action = 16498 MLX5_FLOW_FATE_PORT_ID; 16499 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 16500 break; 16501 } 16502 case RTE_FLOW_ACTION_TYPE_JUMP: 16503 { 16504 uint32_t jump_group = 0; 16505 uint32_t table = 0; 16506 struct mlx5_flow_tbl_data_entry *tbl_data; 16507 struct flow_grp_info grp_info = { 16508 .external = !!dev_flow.external, 16509 .transfer = !!transfer, 16510 .fdb_def_rule = !!priv->fdb_def_rule, 16511 .std_tbl_fix = 0, 16512 .skip_scale = dev_flow.skip_scale & 16513 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 16514 }; 16515 struct mlx5_flow_meter_sub_policy *sub_policy = 16516 mtr_policy->sub_policys[domain][0]; 16517 16518 if (i >= MLX5_MTR_RTE_COLORS) 16519 return -rte_mtr_error_set(error, 16520 ENOTSUP, 16521 RTE_MTR_ERROR_TYPE_METER_POLICY, 16522 NULL, 16523 "cannot create policy " 16524 "jump action for this color"); 16525 jump_group = 16526 ((const struct rte_flow_action_jump *) 16527 act->conf)->group; 16528 if (mlx5_flow_group_to_table(dev, NULL, 16529 jump_group, 16530 &table, 16531 &grp_info, &flow_err)) 16532 return -rte_mtr_error_set(error, 16533 ENOTSUP, 16534 RTE_MTR_ERROR_TYPE_METER_POLICY, 16535 NULL, "cannot setup " 16536 "policy jump action"); 16537 sub_policy->jump_tbl[i] = 16538 flow_dv_tbl_resource_get(dev, 16539 table, egress, 16540 transfer, 16541 !!dev_flow.external, 16542 NULL, jump_group, 0, 16543 0, &flow_err); 16544 if 16545 (!sub_policy->jump_tbl[i]) 16546 return -rte_mtr_error_set(error, 16547 ENOTSUP, 16548 RTE_MTR_ERROR_TYPE_METER_POLICY, 16549 NULL, "cannot create jump action."); 16550 tbl_data = container_of 16551 (sub_policy->jump_tbl[i], 16552 struct mlx5_flow_tbl_data_entry, tbl); 16553 act_cnt->dr_jump_action[domain] = 16554 tbl_data->jump.action; 16555 act_cnt->fate_action = 16556 MLX5_FLOW_FATE_JUMP; 16557 action_flags |= MLX5_FLOW_ACTION_JUMP; 16558 break; 16559 } 16560 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 16561 { 16562 if (i >= MLX5_MTR_RTE_COLORS) 16563 return -rte_mtr_error_set(error, 16564 ENOTSUP, 16565 RTE_MTR_ERROR_TYPE_METER_POLICY, 16566 NULL, 16567 "cannot create policy modify field for this color"); 16568 if (flow_dv_convert_action_modify_field 16569 (dev, mhdr_res, act, attr, &flow_err)) 16570 return -rte_mtr_error_set(error, 16571 ENOTSUP, 16572 RTE_MTR_ERROR_TYPE_METER_POLICY, 16573 NULL, "cannot setup policy modify field action"); 16574 if (!mhdr_res->actions_num) 16575 return -rte_mtr_error_set(error, 16576 ENOTSUP, 16577 RTE_MTR_ERROR_TYPE_METER_POLICY, 16578 NULL, "cannot find policy modify field action"); 16579 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 16580 break; 16581 } 16582 /* 16583 * No need to check meter hierarchy for R colors 16584 * here since it is done in the validation stage. 16585 */ 16586 case RTE_FLOW_ACTION_TYPE_METER: 16587 { 16588 const struct rte_flow_action_meter *mtr; 16589 struct mlx5_flow_meter_info *next_fm; 16590 struct mlx5_flow_meter_policy *next_policy; 16591 struct rte_flow_action tag_action; 16592 struct mlx5_rte_flow_action_set_tag set_tag; 16593 uint32_t next_mtr_idx = 0; 16594 16595 mtr = act->conf; 16596 next_fm = mlx5_flow_meter_find(priv, 16597 mtr->mtr_id, 16598 &next_mtr_idx); 16599 if (!next_fm) 16600 return -rte_mtr_error_set(error, EINVAL, 16601 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 16602 "Fail to find next meter."); 16603 if (next_fm->def_policy) 16604 return -rte_mtr_error_set(error, EINVAL, 16605 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 16606 "Hierarchy only supports termination meter."); 16607 next_policy = mlx5_flow_meter_policy_find(dev, 16608 next_fm->policy_id, NULL); 16609 MLX5_ASSERT(next_policy); 16610 if (next_fm->drop_cnt) { 16611 set_tag.id = 16612 (enum modify_reg) 16613 mlx5_flow_get_reg_id(dev, 16614 MLX5_MTR_ID, 16615 0, 16616 (struct rte_flow_error *)error); 16617 set_tag.offset = (priv->mtr_reg_share ? 16618 MLX5_MTR_COLOR_BITS : 0); 16619 set_tag.length = (priv->mtr_reg_share ? 16620 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : 16621 MLX5_REG_BITS); 16622 set_tag.data = next_mtr_idx; 16623 tag_action.type = 16624 (enum rte_flow_action_type) 16625 MLX5_RTE_FLOW_ACTION_TYPE_TAG; 16626 tag_action.conf = &set_tag; 16627 if (flow_dv_convert_action_set_reg 16628 (mhdr_res, &tag_action, 16629 (struct rte_flow_error *)error)) 16630 return -rte_errno; 16631 action_flags |= 16632 MLX5_FLOW_ACTION_SET_TAG; 16633 } 16634 if (i == RTE_COLOR_YELLOW && next_fm->color_aware && 16635 !next_fm->meter_action_y) 16636 if (__flow_dv_create_mtr_yellow_action(dev, next_fm, error)) 16637 return -rte_errno; 16638 act_cnt->fate_action = MLX5_FLOW_FATE_MTR; 16639 act_cnt->next_mtr_id = next_fm->meter_id; 16640 act_cnt->next_sub_policy = NULL; 16641 mtr_policy->is_hierarchy = 1; 16642 if (next_policy->mark) 16643 mtr_policy->mark = 1; 16644 mtr_policy->hierarchy_match_port = 16645 next_policy->hierarchy_match_port; 16646 action_flags |= 16647 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 16648 break; 16649 } 16650 default: 16651 return -rte_mtr_error_set(error, ENOTSUP, 16652 RTE_MTR_ERROR_TYPE_METER_POLICY, 16653 NULL, "action type not supported"); 16654 } 16655 if ((action_flags & MLX5_FLOW_ACTION_SET_TAG) || 16656 (action_flags & MLX5_FLOW_ACTION_MODIFY_FIELD)) { 16657 /* create modify action if needed. */ 16658 dev_flow.dv.group = 1; 16659 if (flow_dv_modify_hdr_resource_register 16660 (dev, mhdr_res, &dev_flow, &flow_err)) 16661 return -rte_mtr_error_set(error, 16662 ENOTSUP, 16663 RTE_MTR_ERROR_TYPE_METER_POLICY, 16664 NULL, "cannot register policy set tag/modify field action"); 16665 act_cnt->modify_hdr = 16666 dev_flow.handle->dvh.modify_hdr; 16667 } 16668 } 16669 } 16670 return 0; 16671 } 16672 16673 /** 16674 * Create policy action per domain, lock free, 16675 * (mutex should be acquired by caller). 16676 * Dispatcher for action type specific call. 16677 * 16678 * @param[in] dev 16679 * Pointer to the Ethernet device structure. 16680 * @param[in] mtr_policy 16681 * Meter policy struct. 16682 * @param[in] action 16683 * Action specification used to create meter actions. 16684 * @param[in] attr 16685 * Pointer to the flow attributes. 16686 * @param[out] error 16687 * Perform verbose error reporting if not NULL. Initialized in case of 16688 * error only. 16689 * 16690 * @return 16691 * 0 on success, otherwise negative errno value. 16692 */ 16693 static int 16694 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev, 16695 struct mlx5_flow_meter_policy *mtr_policy, 16696 const struct rte_flow_action *actions[RTE_COLORS], 16697 struct rte_flow_attr *attr, 16698 struct rte_mtr_error *error) 16699 { 16700 int ret, i; 16701 uint16_t sub_policy_num; 16702 16703 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16704 sub_policy_num = (mtr_policy->sub_policy_num >> 16705 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 16706 MLX5_MTR_SUB_POLICY_NUM_MASK; 16707 if (sub_policy_num) { 16708 ret = __flow_dv_create_domain_policy_acts(dev, 16709 mtr_policy, actions, attr, 16710 (enum mlx5_meter_domain)i, error); 16711 /* Cleaning resource is done in the caller level. */ 16712 if (ret) 16713 return ret; 16714 } 16715 } 16716 return 0; 16717 } 16718 16719 /** 16720 * Query a DV flow rule for its statistics via DevX. 16721 * 16722 * @param[in] dev 16723 * Pointer to Ethernet device. 16724 * @param[in] cnt_idx 16725 * Index to the flow counter. 16726 * @param[out] data 16727 * Data retrieved by the query. 16728 * @param[out] error 16729 * Perform verbose error reporting if not NULL. 16730 * 16731 * @return 16732 * 0 on success, a negative errno value otherwise and rte_errno is set. 16733 */ 16734 static int 16735 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data, 16736 struct rte_flow_error *error) 16737 { 16738 struct mlx5_priv *priv = dev->data->dev_private; 16739 struct rte_flow_query_count *qc = data; 16740 16741 if (!priv->sh->cdev->config.devx) 16742 return rte_flow_error_set(error, ENOTSUP, 16743 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16744 NULL, 16745 "counters are not supported"); 16746 if (cnt_idx) { 16747 uint64_t pkts, bytes; 16748 struct mlx5_flow_counter *cnt; 16749 int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes); 16750 16751 if (err) 16752 return rte_flow_error_set(error, -err, 16753 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16754 NULL, "cannot read counters"); 16755 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL); 16756 qc->hits_set = 1; 16757 qc->bytes_set = 1; 16758 qc->hits = pkts - cnt->hits; 16759 qc->bytes = bytes - cnt->bytes; 16760 if (qc->reset) { 16761 cnt->hits = pkts; 16762 cnt->bytes = bytes; 16763 } 16764 return 0; 16765 } 16766 return rte_flow_error_set(error, EINVAL, 16767 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16768 NULL, 16769 "counters are not available"); 16770 } 16771 16772 int 16773 flow_dv_action_query(struct rte_eth_dev *dev, 16774 const struct rte_flow_action_handle *handle, void *data, 16775 struct rte_flow_error *error) 16776 { 16777 struct mlx5_age_param *age_param; 16778 struct rte_flow_query_age *resp; 16779 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 16780 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 16781 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 16782 struct mlx5_priv *priv = dev->data->dev_private; 16783 struct mlx5_aso_ct_action *ct; 16784 uint16_t owner; 16785 uint32_t dev_idx; 16786 16787 switch (type) { 16788 case MLX5_INDIRECT_ACTION_TYPE_AGE: 16789 age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params; 16790 resp = data; 16791 resp->aged = __atomic_load_n(&age_param->state, 16792 __ATOMIC_RELAXED) == AGE_TMOUT ? 16793 1 : 0; 16794 resp->sec_since_last_hit_valid = !resp->aged; 16795 if (resp->sec_since_last_hit_valid) 16796 resp->sec_since_last_hit = __atomic_load_n 16797 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 16798 return 0; 16799 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 16800 return flow_dv_query_count(dev, idx, data, error); 16801 case MLX5_INDIRECT_ACTION_TYPE_CT: 16802 owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 16803 if (owner != PORT_ID(priv)) 16804 return rte_flow_error_set(error, EACCES, 16805 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16806 NULL, 16807 "CT object owned by another port"); 16808 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 16809 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 16810 MLX5_ASSERT(ct); 16811 if (!ct->refcnt) 16812 return rte_flow_error_set(error, EFAULT, 16813 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16814 NULL, 16815 "CT object is inactive"); 16816 ((struct rte_flow_action_conntrack *)data)->peer_port = 16817 ct->peer; 16818 ((struct rte_flow_action_conntrack *)data)->is_original_dir = 16819 ct->is_original; 16820 if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, 16821 data, NULL, true)) 16822 return rte_flow_error_set(error, EIO, 16823 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16824 NULL, 16825 "Failed to query CT context"); 16826 return 0; 16827 default: 16828 return rte_flow_error_set(error, ENOTSUP, 16829 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 16830 "action type query not supported"); 16831 } 16832 } 16833 16834 /** 16835 * Query a flow rule AGE action for aging information. 16836 * 16837 * @param[in] dev 16838 * Pointer to Ethernet device. 16839 * @param[in] flow 16840 * Pointer to the sub flow. 16841 * @param[out] data 16842 * data retrieved by the query. 16843 * @param[out] error 16844 * Perform verbose error reporting if not NULL. 16845 * 16846 * @return 16847 * 0 on success, a negative errno value otherwise and rte_errno is set. 16848 */ 16849 static int 16850 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow, 16851 void *data, struct rte_flow_error *error) 16852 { 16853 struct rte_flow_query_age *resp = data; 16854 struct mlx5_age_param *age_param; 16855 16856 if (flow->age) { 16857 struct mlx5_aso_age_action *act = 16858 flow_aso_age_get_by_idx(dev, flow->age); 16859 16860 age_param = &act->age_params; 16861 } else if (flow->counter) { 16862 age_param = flow_dv_counter_idx_get_age(dev, flow->counter); 16863 16864 if (!age_param || !age_param->timeout) 16865 return rte_flow_error_set 16866 (error, EINVAL, 16867 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16868 NULL, "cannot read age data"); 16869 } else { 16870 return rte_flow_error_set(error, EINVAL, 16871 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 16872 NULL, "age data not available"); 16873 } 16874 resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) == 16875 AGE_TMOUT ? 1 : 0; 16876 resp->sec_since_last_hit_valid = !resp->aged; 16877 if (resp->sec_since_last_hit_valid) 16878 resp->sec_since_last_hit = __atomic_load_n 16879 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 16880 return 0; 16881 } 16882 16883 /** 16884 * Query a flow. 16885 * 16886 * @see rte_flow_query() 16887 * @see rte_flow_ops 16888 */ 16889 static int 16890 flow_dv_query(struct rte_eth_dev *dev, 16891 struct rte_flow *flow __rte_unused, 16892 const struct rte_flow_action *actions __rte_unused, 16893 void *data __rte_unused, 16894 struct rte_flow_error *error __rte_unused) 16895 { 16896 int ret = -EINVAL; 16897 16898 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 16899 switch (actions->type) { 16900 case RTE_FLOW_ACTION_TYPE_VOID: 16901 break; 16902 case RTE_FLOW_ACTION_TYPE_COUNT: 16903 ret = flow_dv_query_count(dev, flow->counter, data, 16904 error); 16905 break; 16906 case RTE_FLOW_ACTION_TYPE_AGE: 16907 ret = flow_dv_query_age(dev, flow, data, error); 16908 break; 16909 default: 16910 return rte_flow_error_set(error, ENOTSUP, 16911 RTE_FLOW_ERROR_TYPE_ACTION, 16912 actions, 16913 "action not supported"); 16914 } 16915 } 16916 return ret; 16917 } 16918 16919 /** 16920 * Destroy the meter table set. 16921 * Lock free, (mutex should be acquired by caller). 16922 * 16923 * @param[in] dev 16924 * Pointer to Ethernet device. 16925 * @param[in] fm 16926 * Meter information table. 16927 */ 16928 static void 16929 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev, 16930 struct mlx5_flow_meter_info *fm) 16931 { 16932 struct mlx5_priv *priv = dev->data->dev_private; 16933 int i; 16934 16935 if (!fm || !priv->sh->config.dv_flow_en) 16936 return; 16937 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16938 if (fm->drop_rule[i]) { 16939 claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i])); 16940 fm->drop_rule[i] = NULL; 16941 } 16942 } 16943 } 16944 16945 static void 16946 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev) 16947 { 16948 struct mlx5_priv *priv = dev->data->dev_private; 16949 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16950 struct mlx5_flow_tbl_data_entry *tbl; 16951 int i, j; 16952 16953 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16954 if (mtrmng->def_rule[i]) { 16955 claim_zero(mlx5_flow_os_destroy_flow 16956 (mtrmng->def_rule[i])); 16957 mtrmng->def_rule[i] = NULL; 16958 } 16959 if (mtrmng->def_matcher[i]) { 16960 tbl = container_of(mtrmng->def_matcher[i]->tbl, 16961 struct mlx5_flow_tbl_data_entry, tbl); 16962 mlx5_list_unregister(tbl->matchers, 16963 &mtrmng->def_matcher[i]->entry); 16964 mtrmng->def_matcher[i] = NULL; 16965 } 16966 for (j = 0; j < MLX5_REG_BITS; j++) { 16967 if (mtrmng->drop_matcher[i][j]) { 16968 tbl = 16969 container_of(mtrmng->drop_matcher[i][j]->tbl, 16970 struct mlx5_flow_tbl_data_entry, 16971 tbl); 16972 mlx5_list_unregister(tbl->matchers, 16973 &mtrmng->drop_matcher[i][j]->entry); 16974 mtrmng->drop_matcher[i][j] = NULL; 16975 } 16976 } 16977 if (mtrmng->drop_tbl[i]) { 16978 flow_dv_tbl_resource_release(MLX5_SH(dev), 16979 mtrmng->drop_tbl[i]); 16980 mtrmng->drop_tbl[i] = NULL; 16981 } 16982 } 16983 } 16984 16985 /* Number of meter flow actions, count and jump or count and drop. */ 16986 #define METER_ACTIONS 2 16987 16988 static void 16989 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev, 16990 enum mlx5_meter_domain domain) 16991 { 16992 struct mlx5_priv *priv = dev->data->dev_private; 16993 struct mlx5_flow_meter_def_policy *def_policy = 16994 priv->sh->mtrmng->def_policy[domain]; 16995 16996 __flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy); 16997 mlx5_free(def_policy); 16998 priv->sh->mtrmng->def_policy[domain] = NULL; 16999 } 17000 17001 /** 17002 * Destroy the default policy table set. 17003 * 17004 * @param[in] dev 17005 * Pointer to Ethernet device. 17006 */ 17007 static void 17008 flow_dv_destroy_def_policy(struct rte_eth_dev *dev) 17009 { 17010 struct mlx5_priv *priv = dev->data->dev_private; 17011 int i; 17012 17013 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) 17014 if (priv->sh->mtrmng->def_policy[i]) 17015 __flow_dv_destroy_domain_def_policy(dev, 17016 (enum mlx5_meter_domain)i); 17017 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID; 17018 } 17019 17020 static int 17021 __flow_dv_create_policy_flow(struct rte_eth_dev *dev, 17022 uint32_t color_reg_c_idx, 17023 enum rte_color color, void *matcher_object, 17024 int actions_n, void *actions, 17025 bool match_src_port, const struct rte_flow_item *item, 17026 void **rule, const struct rte_flow_attr *attr) 17027 { 17028 int ret; 17029 struct mlx5_flow_dv_match_params value = { 17030 .size = sizeof(value.buf), 17031 }; 17032 struct mlx5_priv *priv = dev->data->dev_private; 17033 uint8_t misc_mask; 17034 17035 if (match_src_port && priv->sh->esw_mode) { 17036 if (item && item->type == RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT) 17037 ret = flow_dv_translate_item_represented_port(dev, value.buf, 17038 item, attr, MLX5_SET_MATCHER_SW_V); 17039 else if (item && item->type == RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR) 17040 ret = flow_dv_translate_item_port_representor(dev, value.buf, 17041 MLX5_SET_MATCHER_SW_V); 17042 else 17043 ret = flow_dv_translate_item_port_id(dev, value.buf, 17044 item, attr, MLX5_SET_MATCHER_SW_V); 17045 if (ret) { 17046 DRV_LOG(ERR, "Failed to create meter policy%d flow's" 17047 " value with port.", color); 17048 return -1; 17049 } 17050 } 17051 flow_dv_match_meta_reg(value.buf, (enum modify_reg)color_reg_c_idx, 17052 rte_col_2_mlx5_col(color), UINT32_MAX); 17053 misc_mask = flow_dv_matcher_enable(value.buf); 17054 __flow_dv_adjust_buf_size(&value.size, misc_mask); 17055 ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value, 17056 actions_n, actions, rule); 17057 if (ret) { 17058 DRV_LOG(ERR, "Failed to create meter policy%d flow.", color); 17059 return -1; 17060 } 17061 return 0; 17062 } 17063 17064 static int 17065 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev, 17066 uint32_t color_reg_c_idx, 17067 uint16_t priority, 17068 struct mlx5_flow_meter_sub_policy *sub_policy, 17069 const struct rte_flow_attr *attr, 17070 bool match_src_port, 17071 const struct rte_flow_item *item, 17072 struct mlx5_flow_dv_matcher **policy_matcher, 17073 struct rte_flow_error *error) 17074 { 17075 struct mlx5_list_entry *entry; 17076 struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc; 17077 struct mlx5_flow_dv_matcher matcher = { 17078 .mask = { 17079 .size = sizeof(matcher.mask.buf), 17080 }, 17081 .tbl = tbl_rsc, 17082 }; 17083 struct mlx5_flow_cb_ctx ctx = { 17084 .error = error, 17085 .data = &matcher, 17086 }; 17087 struct mlx5_flow_tbl_data_entry *tbl_data; 17088 struct mlx5_priv *priv = dev->data->dev_private; 17089 const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 17090 int ret; 17091 17092 if (match_src_port && priv->sh->esw_mode) { 17093 if (item && item->type == RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT) 17094 ret = flow_dv_translate_item_represented_port(dev, matcher.mask.buf, 17095 item, attr, MLX5_SET_MATCHER_SW_M); 17096 else if (item && item->type == RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR) 17097 ret = flow_dv_translate_item_port_representor(dev, matcher.mask.buf, 17098 MLX5_SET_MATCHER_SW_M); 17099 else 17100 ret = flow_dv_translate_item_port_id(dev, matcher.mask.buf, 17101 item, attr, MLX5_SET_MATCHER_SW_M); 17102 if (ret) { 17103 DRV_LOG(ERR, "Failed to register meter policy%d matcher" 17104 " with port.", priority); 17105 return -1; 17106 } 17107 } 17108 tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl); 17109 if (priority < RTE_COLOR_RED) 17110 flow_dv_match_meta_reg(matcher.mask.buf, 17111 (enum modify_reg)color_reg_c_idx, color_mask, color_mask); 17112 matcher.priority = priority; 17113 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 17114 matcher.mask.size); 17115 entry = mlx5_list_register(tbl_data->matchers, &ctx); 17116 if (!entry) { 17117 DRV_LOG(ERR, "Failed to register meter drop matcher."); 17118 return -1; 17119 } 17120 *policy_matcher = 17121 container_of(entry, struct mlx5_flow_dv_matcher, entry); 17122 return 0; 17123 } 17124 17125 /** 17126 * Create the policy rules per domain. 17127 * 17128 * @param[in] dev 17129 * Pointer to Ethernet device. 17130 * @param[in] sub_policy 17131 * Pointer to sub policy table.. 17132 * @param[in] egress 17133 * Direction of the table. 17134 * @param[in] transfer 17135 * E-Switch or NIC flow. 17136 * @param[in] acts 17137 * Pointer to policy action list per color. 17138 * 17139 * @return 17140 * 0 on success, -1 otherwise. 17141 */ 17142 static int 17143 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev, 17144 struct mlx5_flow_meter_sub_policy *sub_policy, 17145 uint8_t egress, uint8_t transfer, bool match_src_port, 17146 struct mlx5_meter_policy_acts acts[RTE_COLORS]) 17147 { 17148 struct mlx5_priv *priv = dev->data->dev_private; 17149 struct rte_flow_error flow_err; 17150 uint32_t color_reg_c_idx; 17151 struct rte_flow_attr attr = { 17152 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 17153 .priority = 0, 17154 .ingress = 0, 17155 .egress = !!egress, 17156 .transfer = !!transfer, 17157 .reserved = 0, 17158 }; 17159 int i; 17160 int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err); 17161 struct mlx5_sub_policy_color_rule *color_rule; 17162 bool svport_match; 17163 struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL}; 17164 17165 if (ret < 0) 17166 return -1; 17167 /* Create policy table with POLICY level. */ 17168 if (!sub_policy->tbl_rsc) 17169 sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev, 17170 MLX5_FLOW_TABLE_LEVEL_POLICY, 17171 egress, transfer, false, NULL, 0, 0, 17172 sub_policy->idx, &flow_err); 17173 if (!sub_policy->tbl_rsc) { 17174 DRV_LOG(ERR, 17175 "Failed to create meter sub policy table."); 17176 return -1; 17177 } 17178 /* Prepare matchers. */ 17179 color_reg_c_idx = ret; 17180 for (i = 0; i < RTE_COLORS; i++) { 17181 TAILQ_INIT(&sub_policy->color_rules[i]); 17182 if (!acts[i].actions_n) 17183 continue; 17184 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 17185 sizeof(struct mlx5_sub_policy_color_rule), 17186 0, SOCKET_ID_ANY); 17187 if (!color_rule) { 17188 DRV_LOG(ERR, "No memory to create color rule."); 17189 goto err_exit; 17190 } 17191 tmp_rules[i] = color_rule; 17192 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 17193 color_rule, next_port); 17194 color_rule->src_port = priv->representor_id; 17195 /* No use. */ 17196 attr.priority = i; 17197 /* Create matchers for colors. */ 17198 svport_match = (i != RTE_COLOR_RED) ? match_src_port : false; 17199 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 17200 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 17201 &attr, svport_match, NULL, 17202 &color_rule->matcher, &flow_err)) { 17203 DRV_LOG(ERR, "Failed to create color%u matcher.", i); 17204 goto err_exit; 17205 } 17206 /* Create flow, matching color. */ 17207 if (__flow_dv_create_policy_flow(dev, 17208 color_reg_c_idx, (enum rte_color)i, 17209 color_rule->matcher->matcher_object, 17210 acts[i].actions_n, acts[i].dv_actions, 17211 svport_match, NULL, &color_rule->rule, 17212 &attr)) { 17213 DRV_LOG(ERR, "Failed to create color%u rule.", i); 17214 goto err_exit; 17215 } 17216 } 17217 return 0; 17218 err_exit: 17219 /* All the policy rules will be cleared. */ 17220 do { 17221 color_rule = tmp_rules[i]; 17222 if (color_rule) { 17223 if (color_rule->rule) 17224 mlx5_flow_os_destroy_flow(color_rule->rule); 17225 if (color_rule->matcher) { 17226 struct mlx5_flow_tbl_data_entry *tbl = 17227 container_of(color_rule->matcher->tbl, 17228 typeof(*tbl), tbl); 17229 mlx5_list_unregister(tbl->matchers, 17230 &color_rule->matcher->entry); 17231 } 17232 TAILQ_REMOVE(&sub_policy->color_rules[i], 17233 color_rule, next_port); 17234 mlx5_free(color_rule); 17235 } 17236 } while (i--); 17237 return -1; 17238 } 17239 17240 static int 17241 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev, 17242 struct mlx5_flow_meter_policy *mtr_policy, 17243 struct mlx5_flow_meter_sub_policy *sub_policy, 17244 uint32_t domain) 17245 { 17246 struct mlx5_priv *priv = dev->data->dev_private; 17247 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 17248 struct mlx5_flow_dv_tag_resource *tag; 17249 struct mlx5_flow_dv_port_id_action_resource *port_action; 17250 struct mlx5_hrxq *hrxq; 17251 struct mlx5_flow_meter_info *next_fm[RTE_COLORS] = {NULL}; 17252 struct mlx5_flow_meter_policy *next_policy; 17253 struct mlx5_flow_meter_sub_policy *next_sub_policy; 17254 struct mlx5_flow_tbl_data_entry *tbl_data; 17255 struct rte_flow_error error; 17256 uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 17257 uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 17258 bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX); 17259 bool match_src_port = false; 17260 int i; 17261 17262 /* If RSS or Queue, no previous actions / rules is created. */ 17263 for (i = 0; i < RTE_COLORS; i++) { 17264 acts[i].actions_n = 0; 17265 if (i == RTE_COLOR_RED) { 17266 /* Only support drop on red. */ 17267 acts[i].dv_actions[0] = 17268 mtr_policy->dr_drop_action[domain]; 17269 acts[i].actions_n = 1; 17270 continue; 17271 } 17272 if (mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) { 17273 struct rte_flow_attr attr = { 17274 .transfer = transfer 17275 }; 17276 17277 next_fm[i] = mlx5_flow_meter_find(priv, 17278 mtr_policy->act_cnt[i].next_mtr_id, 17279 NULL); 17280 if (!next_fm[i]) { 17281 DRV_LOG(ERR, 17282 "Failed to get next hierarchy meter."); 17283 goto err_exit; 17284 } 17285 if (mlx5_flow_meter_attach(priv, next_fm[i], 17286 &attr, &error)) { 17287 DRV_LOG(ERR, "%s", error.message); 17288 next_fm[i] = NULL; 17289 goto err_exit; 17290 } 17291 /* Meter action must be the first for TX. */ 17292 if (mtr_first) { 17293 acts[i].dv_actions[acts[i].actions_n] = 17294 (next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ? 17295 next_fm[i]->meter_action_y : 17296 next_fm[i]->meter_action_g; 17297 acts[i].actions_n++; 17298 } 17299 } 17300 if (mtr_policy->act_cnt[i].rix_mark) { 17301 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], 17302 mtr_policy->act_cnt[i].rix_mark); 17303 if (!tag) { 17304 DRV_LOG(ERR, "Failed to find " 17305 "mark action for policy."); 17306 goto err_exit; 17307 } 17308 acts[i].dv_actions[acts[i].actions_n] = tag->action; 17309 acts[i].actions_n++; 17310 } 17311 if (mtr_policy->act_cnt[i].modify_hdr) { 17312 acts[i].dv_actions[acts[i].actions_n] = 17313 mtr_policy->act_cnt[i].modify_hdr->action; 17314 acts[i].actions_n++; 17315 } 17316 if (mtr_policy->act_cnt[i].fate_action) { 17317 switch (mtr_policy->act_cnt[i].fate_action) { 17318 case MLX5_FLOW_FATE_PORT_ID: 17319 port_action = mlx5_ipool_get 17320 (priv->sh->ipool[MLX5_IPOOL_PORT_ID], 17321 mtr_policy->act_cnt[i].rix_port_id_action); 17322 if (!port_action) { 17323 DRV_LOG(ERR, "Failed to find " 17324 "port action for policy."); 17325 goto err_exit; 17326 } 17327 acts[i].dv_actions[acts[i].actions_n] = 17328 port_action->action; 17329 acts[i].actions_n++; 17330 match_src_port = true; 17331 break; 17332 case MLX5_FLOW_FATE_DROP: 17333 case MLX5_FLOW_FATE_JUMP: 17334 acts[i].dv_actions[acts[i].actions_n] = 17335 mtr_policy->act_cnt[i].dr_jump_action[domain]; 17336 acts[i].actions_n++; 17337 break; 17338 case MLX5_FLOW_FATE_SHARED_RSS: 17339 case MLX5_FLOW_FATE_QUEUE: 17340 hrxq = mlx5_ipool_get 17341 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 17342 sub_policy->rix_hrxq[i]); 17343 if (!hrxq) { 17344 DRV_LOG(ERR, "Failed to find " 17345 "queue action for policy."); 17346 goto err_exit; 17347 } 17348 acts[i].dv_actions[acts[i].actions_n] = 17349 hrxq->action; 17350 acts[i].actions_n++; 17351 break; 17352 case MLX5_FLOW_FATE_MTR: 17353 if (!next_fm[i]) { 17354 DRV_LOG(ERR, 17355 "No next hierarchy meter."); 17356 goto err_exit; 17357 } 17358 if (!mtr_first) { 17359 acts[i].dv_actions[acts[i].actions_n] = 17360 (next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ? 17361 next_fm[i]->meter_action_y : 17362 next_fm[i]->meter_action_g; 17363 acts[i].actions_n++; 17364 } 17365 if (mtr_policy->act_cnt[i].next_sub_policy) { 17366 next_sub_policy = 17367 mtr_policy->act_cnt[i].next_sub_policy; 17368 } else { 17369 next_policy = 17370 mlx5_flow_meter_policy_find(dev, 17371 next_fm[i]->policy_id, NULL); 17372 MLX5_ASSERT(next_policy); 17373 next_sub_policy = 17374 next_policy->sub_policys[domain][0]; 17375 } 17376 tbl_data = 17377 container_of(next_sub_policy->tbl_rsc, 17378 struct mlx5_flow_tbl_data_entry, tbl); 17379 acts[i].dv_actions[acts[i].actions_n++] = 17380 tbl_data->jump.action; 17381 if (mtr_policy->act_cnt[i].modify_hdr) 17382 match_src_port = !!transfer; 17383 break; 17384 default: 17385 /*Queue action do nothing*/ 17386 break; 17387 } 17388 } 17389 } 17390 if (__flow_dv_create_domain_policy_rules(dev, sub_policy, 17391 egress, transfer, match_src_port, acts)) { 17392 DRV_LOG(ERR, 17393 "Failed to create policy rules per domain."); 17394 goto err_exit; 17395 } 17396 if (match_src_port) { 17397 mtr_policy->match_port = match_src_port; 17398 mtr_policy->hierarchy_match_port = match_src_port; 17399 } 17400 return 0; 17401 err_exit: 17402 for (i = 0; i < RTE_COLORS; i++) 17403 if (next_fm[i]) 17404 mlx5_flow_meter_detach(priv, next_fm[i]); 17405 return -1; 17406 } 17407 17408 /** 17409 * Create the policy rules. 17410 * 17411 * @param[in] dev 17412 * Pointer to Ethernet device. 17413 * @param[in,out] mtr_policy 17414 * Pointer to meter policy table. 17415 * 17416 * @return 17417 * 0 on success, -1 otherwise. 17418 */ 17419 static int 17420 flow_dv_create_policy_rules(struct rte_eth_dev *dev, 17421 struct mlx5_flow_meter_policy *mtr_policy) 17422 { 17423 int i; 17424 int ret = 0; 17425 uint16_t sub_policy_num; 17426 struct mlx5_flow_workspace *wks = mlx5_flow_push_thread_workspace(); 17427 17428 RTE_SET_USED(wks); 17429 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 17430 sub_policy_num = (mtr_policy->sub_policy_num >> 17431 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 17432 MLX5_MTR_SUB_POLICY_NUM_MASK; 17433 if (!sub_policy_num) 17434 continue; 17435 /* Prepare actions list and create policy rules. */ 17436 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 17437 mtr_policy->sub_policys[i][0], i)) { 17438 DRV_LOG(ERR, "Failed to create policy action " 17439 "list per domain."); 17440 ret = -1; 17441 goto exit; 17442 } 17443 } 17444 exit: 17445 mlx5_flow_pop_thread_workspace(); 17446 return ret; 17447 } 17448 17449 static int 17450 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain) 17451 { 17452 struct mlx5_priv *priv = dev->data->dev_private; 17453 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 17454 struct mlx5_flow_meter_def_policy *def_policy; 17455 struct mlx5_flow_tbl_resource *jump_tbl; 17456 struct mlx5_flow_tbl_data_entry *tbl_data; 17457 uint8_t egress, transfer; 17458 struct rte_flow_error error; 17459 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 17460 int ret; 17461 17462 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 17463 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 17464 def_policy = mtrmng->def_policy[domain]; 17465 if (!def_policy) { 17466 def_policy = mlx5_malloc(MLX5_MEM_ZERO, 17467 sizeof(struct mlx5_flow_meter_def_policy), 17468 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 17469 if (!def_policy) { 17470 DRV_LOG(ERR, "Failed to alloc default policy table."); 17471 goto def_policy_error; 17472 } 17473 mtrmng->def_policy[domain] = def_policy; 17474 /* Create the meter suffix table with SUFFIX level. */ 17475 jump_tbl = flow_dv_tbl_resource_get(dev, 17476 MLX5_FLOW_TABLE_LEVEL_METER, 17477 egress, transfer, false, NULL, 0, 17478 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 17479 if (!jump_tbl) { 17480 DRV_LOG(ERR, 17481 "Failed to create meter suffix table."); 17482 goto def_policy_error; 17483 } 17484 def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl; 17485 tbl_data = container_of(jump_tbl, 17486 struct mlx5_flow_tbl_data_entry, tbl); 17487 def_policy->dr_jump_action[RTE_COLOR_GREEN] = 17488 tbl_data->jump.action; 17489 acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action; 17490 acts[RTE_COLOR_GREEN].actions_n = 1; 17491 /* 17492 * YELLOW has the same default policy as GREEN does. 17493 * G & Y share the same table and action. The 2nd time of table 17494 * resource getting is just to update the reference count for 17495 * the releasing stage. 17496 */ 17497 jump_tbl = flow_dv_tbl_resource_get(dev, 17498 MLX5_FLOW_TABLE_LEVEL_METER, 17499 egress, transfer, false, NULL, 0, 17500 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 17501 if (!jump_tbl) { 17502 DRV_LOG(ERR, 17503 "Failed to get meter suffix table."); 17504 goto def_policy_error; 17505 } 17506 def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl; 17507 tbl_data = container_of(jump_tbl, 17508 struct mlx5_flow_tbl_data_entry, tbl); 17509 def_policy->dr_jump_action[RTE_COLOR_YELLOW] = 17510 tbl_data->jump.action; 17511 acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action; 17512 acts[RTE_COLOR_YELLOW].actions_n = 1; 17513 /* Create jump action to the drop table. */ 17514 if (!mtrmng->drop_tbl[domain]) { 17515 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get 17516 (dev, MLX5_FLOW_TABLE_LEVEL_METER, 17517 egress, transfer, false, NULL, 0, 17518 0, MLX5_MTR_TABLE_ID_DROP, &error); 17519 if (!mtrmng->drop_tbl[domain]) { 17520 DRV_LOG(ERR, "Failed to create meter " 17521 "drop table for default policy."); 17522 goto def_policy_error; 17523 } 17524 } 17525 /* all RED: unique Drop table for jump action. */ 17526 tbl_data = container_of(mtrmng->drop_tbl[domain], 17527 struct mlx5_flow_tbl_data_entry, tbl); 17528 def_policy->dr_jump_action[RTE_COLOR_RED] = 17529 tbl_data->jump.action; 17530 acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action; 17531 acts[RTE_COLOR_RED].actions_n = 1; 17532 /* Create default policy rules. */ 17533 ret = __flow_dv_create_domain_policy_rules(dev, 17534 &def_policy->sub_policy, 17535 egress, transfer, false, acts); 17536 if (ret) { 17537 DRV_LOG(ERR, "Failed to create default policy rules."); 17538 goto def_policy_error; 17539 } 17540 } 17541 return 0; 17542 def_policy_error: 17543 __flow_dv_destroy_domain_def_policy(dev, 17544 (enum mlx5_meter_domain)domain); 17545 return -1; 17546 } 17547 17548 /** 17549 * Create the default policy table set. 17550 * 17551 * @param[in] dev 17552 * Pointer to Ethernet device. 17553 * @return 17554 * 0 on success, -1 otherwise. 17555 */ 17556 static int 17557 flow_dv_create_def_policy(struct rte_eth_dev *dev) 17558 { 17559 struct mlx5_priv *priv = dev->data->dev_private; 17560 int i; 17561 17562 /* Non-termination policy table. */ 17563 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 17564 if (!priv->sh->config.dv_esw_en && 17565 i == MLX5_MTR_DOMAIN_TRANSFER) 17566 continue; 17567 if (__flow_dv_create_domain_def_policy(dev, i)) { 17568 DRV_LOG(ERR, "Failed to create default policy"); 17569 /* Rollback the created default policies for others. */ 17570 flow_dv_destroy_def_policy(dev); 17571 return -1; 17572 } 17573 } 17574 return 0; 17575 } 17576 17577 /** 17578 * Create the needed meter tables. 17579 * Lock free, (mutex should be acquired by caller). 17580 * 17581 * @param[in] dev 17582 * Pointer to Ethernet device. 17583 * @param[in] fm 17584 * Meter information table. 17585 * @param[in] mtr_idx 17586 * Meter index. 17587 * @param[in] domain_bitmap 17588 * Domain bitmap. 17589 * @return 17590 * 0 on success, -1 otherwise. 17591 */ 17592 static int 17593 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev, 17594 struct mlx5_flow_meter_info *fm, 17595 uint32_t mtr_idx, 17596 uint8_t domain_bitmap) 17597 { 17598 struct mlx5_priv *priv = dev->data->dev_private; 17599 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 17600 struct rte_flow_error error; 17601 struct mlx5_flow_tbl_data_entry *tbl_data; 17602 uint8_t egress, transfer; 17603 void *actions[METER_ACTIONS]; 17604 int domain, ret, i; 17605 struct mlx5_flow_counter *cnt; 17606 struct mlx5_flow_dv_match_params value = { 17607 .size = sizeof(value.buf), 17608 }; 17609 struct mlx5_flow_dv_match_params matcher_para = { 17610 .size = sizeof(matcher_para.buf), 17611 }; 17612 int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID, 17613 0, &error); 17614 uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1; 17615 uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0; 17616 struct mlx5_list_entry *entry; 17617 struct mlx5_flow_dv_matcher matcher = { 17618 .mask = { 17619 .size = sizeof(matcher.mask.buf), 17620 }, 17621 }; 17622 struct mlx5_flow_dv_matcher *drop_matcher; 17623 struct mlx5_flow_cb_ctx ctx = { 17624 .error = &error, 17625 .data = &matcher, 17626 }; 17627 uint8_t misc_mask; 17628 17629 if (!priv->mtr_en || mtr_id_reg_c < 0) { 17630 rte_errno = ENOTSUP; 17631 return -1; 17632 } 17633 for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) { 17634 if (!(domain_bitmap & (1 << domain)) || 17635 (mtrmng->def_rule[domain] && !fm->drop_cnt)) 17636 continue; 17637 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 17638 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 17639 /* Create the drop table with METER DROP level. */ 17640 if (!mtrmng->drop_tbl[domain]) { 17641 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev, 17642 MLX5_FLOW_TABLE_LEVEL_METER, 17643 egress, transfer, false, NULL, 0, 17644 0, MLX5_MTR_TABLE_ID_DROP, &error); 17645 if (!mtrmng->drop_tbl[domain]) { 17646 DRV_LOG(ERR, "Failed to create meter drop table."); 17647 goto policy_error; 17648 } 17649 } 17650 /* Create default matcher in drop table. */ 17651 matcher.tbl = mtrmng->drop_tbl[domain], 17652 tbl_data = container_of(mtrmng->drop_tbl[domain], 17653 struct mlx5_flow_tbl_data_entry, tbl); 17654 if (!mtrmng->def_matcher[domain]) { 17655 flow_dv_match_meta_reg_all(matcher.mask.buf, value.buf, 17656 (enum modify_reg)mtr_id_reg_c, 17657 0, 0); 17658 matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY; 17659 matcher.crc = rte_raw_cksum 17660 ((const void *)matcher.mask.buf, 17661 matcher.mask.size); 17662 entry = mlx5_list_register(tbl_data->matchers, &ctx); 17663 if (!entry) { 17664 DRV_LOG(ERR, "Failed to register meter " 17665 "drop default matcher."); 17666 goto policy_error; 17667 } 17668 mtrmng->def_matcher[domain] = container_of(entry, 17669 struct mlx5_flow_dv_matcher, entry); 17670 } 17671 /* Create default rule in drop table. */ 17672 if (!mtrmng->def_rule[domain]) { 17673 i = 0; 17674 actions[i++] = priv->sh->dr_drop_action; 17675 flow_dv_match_meta_reg_all(matcher_para.buf, value.buf, 17676 (enum modify_reg)mtr_id_reg_c, 0, 0); 17677 misc_mask = flow_dv_matcher_enable(value.buf); 17678 __flow_dv_adjust_buf_size(&value.size, misc_mask); 17679 ret = mlx5_flow_os_create_flow 17680 (mtrmng->def_matcher[domain]->matcher_object, 17681 (void *)&value, i, actions, 17682 &mtrmng->def_rule[domain]); 17683 if (ret) { 17684 DRV_LOG(ERR, "Failed to create meter " 17685 "default drop rule for drop table."); 17686 goto policy_error; 17687 } 17688 } 17689 if (!fm->drop_cnt) 17690 continue; 17691 MLX5_ASSERT(mtrmng->max_mtr_bits); 17692 if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) { 17693 /* Create matchers for Drop. */ 17694 flow_dv_match_meta_reg_all(matcher.mask.buf, value.buf, 17695 (enum modify_reg)mtr_id_reg_c, 0, 17696 (mtr_id_mask << mtr_id_offset)); 17697 matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits; 17698 matcher.crc = rte_raw_cksum 17699 ((const void *)matcher.mask.buf, 17700 matcher.mask.size); 17701 entry = mlx5_list_register(tbl_data->matchers, &ctx); 17702 if (!entry) { 17703 DRV_LOG(ERR, 17704 "Failed to register meter drop matcher."); 17705 goto policy_error; 17706 } 17707 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] = 17708 container_of(entry, struct mlx5_flow_dv_matcher, 17709 entry); 17710 } 17711 drop_matcher = 17712 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]; 17713 /* Create drop rule, matching meter_id only. */ 17714 flow_dv_match_meta_reg_all(matcher_para.buf, value.buf, 17715 (enum modify_reg)mtr_id_reg_c, 17716 (mtr_idx << mtr_id_offset), UINT32_MAX); 17717 i = 0; 17718 cnt = flow_dv_counter_get_by_idx(dev, 17719 fm->drop_cnt, NULL); 17720 actions[i++] = cnt->action; 17721 actions[i++] = priv->sh->dr_drop_action; 17722 misc_mask = flow_dv_matcher_enable(value.buf); 17723 __flow_dv_adjust_buf_size(&value.size, misc_mask); 17724 ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object, 17725 (void *)&value, i, actions, 17726 &fm->drop_rule[domain]); 17727 if (ret) { 17728 DRV_LOG(ERR, "Failed to create meter " 17729 "drop rule for drop table."); 17730 goto policy_error; 17731 } 17732 } 17733 return 0; 17734 policy_error: 17735 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 17736 if (fm->drop_rule[i]) { 17737 claim_zero(mlx5_flow_os_destroy_flow 17738 (fm->drop_rule[i])); 17739 fm->drop_rule[i] = NULL; 17740 } 17741 } 17742 return -1; 17743 } 17744 17745 static struct mlx5_flow_meter_sub_policy * 17746 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, 17747 struct mlx5_flow_meter_policy *mtr_policy, 17748 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS], 17749 struct mlx5_flow_meter_sub_policy *next_sub_policy, 17750 bool *is_reuse) 17751 { 17752 struct mlx5_priv *priv = dev->data->dev_private; 17753 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 17754 uint32_t sub_policy_idx = 0; 17755 uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0}; 17756 uint32_t i, j; 17757 struct mlx5_hrxq *hrxq; 17758 struct mlx5_flow_handle dh; 17759 struct mlx5_meter_policy_action_container *act_cnt; 17760 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 17761 uint16_t sub_policy_num; 17762 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 17763 17764 MLX5_ASSERT(wks); 17765 rte_spinlock_lock(&mtr_policy->sl); 17766 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17767 if (!rss_desc[i]) 17768 continue; 17769 hrxq = mlx5_hrxq_get(dev, rss_desc[i]); 17770 if (!hrxq) { 17771 rte_spinlock_unlock(&mtr_policy->sl); 17772 return NULL; 17773 } 17774 hrxq_idx[i] = hrxq->idx; 17775 } 17776 sub_policy_num = (mtr_policy->sub_policy_num >> 17777 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17778 MLX5_MTR_SUB_POLICY_NUM_MASK; 17779 for (j = 0; j < sub_policy_num; j++) { 17780 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17781 if (rss_desc[i] && 17782 hrxq_idx[i] != 17783 mtr_policy->sub_policys[domain][j]->rix_hrxq[i]) 17784 break; 17785 } 17786 if (i >= MLX5_MTR_RTE_COLORS) { 17787 /* 17788 * Found the sub policy table with 17789 * the same queue per color. 17790 */ 17791 rte_spinlock_unlock(&mtr_policy->sl); 17792 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 17793 mlx5_hrxq_release(dev, hrxq_idx[i]); 17794 *is_reuse = true; 17795 return mtr_policy->sub_policys[domain][j]; 17796 } 17797 } 17798 /* Create sub policy. */ 17799 if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[RTE_COLOR_GREEN] && 17800 !mtr_policy->sub_policys[domain][0]->rix_hrxq[RTE_COLOR_YELLOW]) { 17801 /* Reuse the first pre-allocated sub_policy. */ 17802 sub_policy = mtr_policy->sub_policys[domain][0]; 17803 sub_policy_idx = sub_policy->idx; 17804 } else { 17805 sub_policy = mlx5_ipool_zmalloc 17806 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17807 &sub_policy_idx); 17808 if (!sub_policy || 17809 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { 17810 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 17811 mlx5_hrxq_release(dev, hrxq_idx[i]); 17812 goto rss_sub_policy_error; 17813 } 17814 sub_policy->idx = sub_policy_idx; 17815 sub_policy->main_policy = mtr_policy; 17816 } 17817 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17818 if (!rss_desc[i]) 17819 continue; 17820 sub_policy->rix_hrxq[i] = hrxq_idx[i]; 17821 if (mtr_policy->is_hierarchy) { 17822 act_cnt = &mtr_policy->act_cnt[i]; 17823 act_cnt->next_sub_policy = next_sub_policy; 17824 mlx5_hrxq_release(dev, hrxq_idx[i]); 17825 } else { 17826 /* 17827 * Overwrite the last action from 17828 * RSS action to Queue action. 17829 */ 17830 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 17831 hrxq_idx[i]); 17832 if (!hrxq) { 17833 DRV_LOG(ERR, "Failed to get policy hrxq"); 17834 goto rss_sub_policy_error; 17835 } 17836 act_cnt = &mtr_policy->act_cnt[i]; 17837 if (act_cnt->rix_mark || act_cnt->modify_hdr) { 17838 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 17839 if (act_cnt->rix_mark) 17840 wks->mark = 1; 17841 dh.fate_action = MLX5_FLOW_FATE_QUEUE; 17842 dh.rix_hrxq = hrxq_idx[i]; 17843 flow_drv_rxq_flags_set(dev, &dh); 17844 } 17845 } 17846 } 17847 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 17848 sub_policy, domain)) { 17849 DRV_LOG(ERR, "Failed to create policy " 17850 "rules for ingress domain."); 17851 goto rss_sub_policy_error; 17852 } 17853 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 17854 i = (mtr_policy->sub_policy_num >> 17855 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17856 MLX5_MTR_SUB_POLICY_NUM_MASK; 17857 if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) { 17858 DRV_LOG(ERR, "No free sub-policy slot."); 17859 goto rss_sub_policy_error; 17860 } 17861 mtr_policy->sub_policys[domain][i] = sub_policy; 17862 i++; 17863 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17864 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 17865 mtr_policy->sub_policy_num |= 17866 (i & MLX5_MTR_SUB_POLICY_NUM_MASK) << 17867 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 17868 } 17869 rte_spinlock_unlock(&mtr_policy->sl); 17870 *is_reuse = false; 17871 return sub_policy; 17872 rss_sub_policy_error: 17873 if (sub_policy) { 17874 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 17875 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 17876 i = (mtr_policy->sub_policy_num >> 17877 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17878 MLX5_MTR_SUB_POLICY_NUM_MASK; 17879 mtr_policy->sub_policys[domain][i] = NULL; 17880 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17881 sub_policy->idx); 17882 } 17883 } 17884 rte_spinlock_unlock(&mtr_policy->sl); 17885 return NULL; 17886 } 17887 17888 /** 17889 * Find the policy table for prefix table with RSS. 17890 * 17891 * @param[in] dev 17892 * Pointer to Ethernet device. 17893 * @param[in] mtr_policy 17894 * Pointer to meter policy table. 17895 * @param[in] rss_desc 17896 * Pointer to rss_desc 17897 * @return 17898 * Pointer to table set on success, NULL otherwise and rte_errno is set. 17899 */ 17900 static struct mlx5_flow_meter_sub_policy * 17901 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev, 17902 struct mlx5_flow_meter_policy *mtr_policy, 17903 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]) 17904 { 17905 struct mlx5_priv *priv = dev->data->dev_private; 17906 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 17907 struct mlx5_flow_meter_info *next_fm; 17908 struct mlx5_flow_meter_policy *next_policy; 17909 struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL; 17910 struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM]; 17911 struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM]; 17912 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 17913 bool reuse_sub_policy; 17914 uint32_t i = 0; 17915 uint32_t j = 0; 17916 17917 while (true) { 17918 /* Iterate hierarchy to get all policies in this hierarchy. */ 17919 policies[i++] = mtr_policy; 17920 if (!mtr_policy->is_hierarchy) 17921 break; 17922 if (i >= MLX5_MTR_CHAIN_MAX_NUM) { 17923 DRV_LOG(ERR, "Exceed max meter number in hierarchy."); 17924 return NULL; 17925 } 17926 rte_spinlock_lock(&mtr_policy->sl); 17927 next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL); 17928 rte_spinlock_unlock(&mtr_policy->sl); 17929 if (!next_fm) { 17930 DRV_LOG(ERR, "Failed to get next meter in hierarchy."); 17931 return NULL; 17932 } 17933 next_policy = 17934 mlx5_flow_meter_policy_find(dev, next_fm->policy_id, 17935 NULL); 17936 MLX5_ASSERT(next_policy); 17937 mtr_policy = next_policy; 17938 } 17939 while (i) { 17940 /** 17941 * From last policy to the first one in hierarchy, 17942 * create / get the sub policy for each of them. 17943 */ 17944 sub_policy = __flow_dv_meter_get_rss_sub_policy(dev, 17945 policies[--i], 17946 rss_desc, 17947 next_sub_policy, 17948 &reuse_sub_policy); 17949 if (!sub_policy) { 17950 DRV_LOG(ERR, "Failed to get the sub policy."); 17951 goto err_exit; 17952 } 17953 if (!reuse_sub_policy) 17954 sub_policies[j++] = sub_policy; 17955 next_sub_policy = sub_policy; 17956 } 17957 return sub_policy; 17958 err_exit: 17959 while (j) { 17960 uint16_t sub_policy_num; 17961 17962 sub_policy = sub_policies[--j]; 17963 mtr_policy = sub_policy->main_policy; 17964 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 17965 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 17966 sub_policy_num = (mtr_policy->sub_policy_num >> 17967 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17968 MLX5_MTR_SUB_POLICY_NUM_MASK; 17969 mtr_policy->sub_policys[domain][sub_policy_num - 1] = 17970 NULL; 17971 sub_policy_num--; 17972 mtr_policy->sub_policy_num &= 17973 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17974 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)); 17975 mtr_policy->sub_policy_num |= 17976 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) << 17977 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i); 17978 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17979 sub_policy->idx); 17980 } 17981 } 17982 return NULL; 17983 } 17984 17985 /** 17986 * Check if need to create hierarchy tag rule. 17987 * 17988 * @param[in] priv 17989 * Pointer to mlx5_priv. 17990 * @param[in] mtr_policy 17991 * Pointer to current meter policy. 17992 * @param[in] src_port 17993 * The src port this extra rule should use. 17994 * @param[out] next_fm 17995 * Pointer to next meter in hierarchy. 17996 * @param[out] skip 17997 * Indicate if skip the tag rule creation. 17998 * @param[out] error 17999 * Perform verbose error reporting if not NULL. 18000 * @return 18001 * 0 on success, a negative errno value otherwise and rte_errno is set. 18002 */ 18003 static int 18004 mlx5_meter_hierarchy_skip_tag_rule(struct mlx5_priv *priv, 18005 struct mlx5_flow_meter_policy *mtr_policy, 18006 int32_t src_port, 18007 struct mlx5_flow_meter_info **next_fm, 18008 bool *skip, 18009 struct rte_flow_error *error) 18010 { 18011 struct mlx5_flow_meter_sub_policy *sub_policy; 18012 struct mlx5_sub_policy_color_rule *color_rule; 18013 uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER; 18014 int ret = 0; 18015 int i; 18016 18017 *next_fm = NULL; 18018 *skip = false; 18019 rte_spinlock_lock(&mtr_policy->sl); 18020 if (mtr_policy->is_hierarchy) { 18021 *next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL); 18022 if (!*next_fm) { 18023 ret = rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, 18024 NULL, "Failed to find next meter in hierarchy."); 18025 goto exit; 18026 } 18027 } 18028 if (!mtr_policy->match_port) { 18029 *skip = true; 18030 goto exit; 18031 } 18032 sub_policy = mtr_policy->sub_policys[domain][0]; 18033 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 18034 if (mtr_policy->act_cnt[i].fate_action != MLX5_FLOW_FATE_MTR && 18035 mtr_policy->act_cnt[i].fate_action != MLX5_FLOW_FATE_PORT_ID) 18036 continue; 18037 TAILQ_FOREACH(color_rule, &sub_policy->color_rules[i], next_port) 18038 if (color_rule->src_port == src_port) { 18039 *skip = true; 18040 goto exit; 18041 } 18042 } 18043 exit: 18044 rte_spinlock_unlock(&mtr_policy->sl); 18045 return ret; 18046 } 18047 18048 /** 18049 * Create the sub policy tag rule for all meters in hierarchy. 18050 * 18051 * @param[in] dev 18052 * Pointer to Ethernet device. 18053 * @param[in] fm 18054 * Meter information table. 18055 * @param[in] src_port 18056 * The src port this extra rule should use. 18057 * @param[in] item 18058 * The src port match item. 18059 * @param[out] error 18060 * Perform verbose error reporting if not NULL. 18061 * @return 18062 * 0 on success, a negative errno value otherwise and rte_errno is set. 18063 */ 18064 static int 18065 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev, 18066 struct mlx5_flow_meter_info *fm, 18067 int32_t src_port, 18068 const struct rte_flow_item *item, 18069 struct rte_flow_error *error) 18070 { 18071 struct mlx5_priv *priv = dev->data->dev_private; 18072 struct mlx5_flow_meter_policy *mtr_policy; 18073 struct mlx5_flow_meter_sub_policy *sub_policy; 18074 struct mlx5_flow_meter_info *next_fm = NULL; 18075 struct mlx5_flow_meter_policy *next_policy; 18076 struct mlx5_flow_meter_sub_policy *next_sub_policy; 18077 struct mlx5_flow_tbl_data_entry *tbl_data; 18078 struct mlx5_sub_policy_color_rule *color_rule; 18079 struct mlx5_meter_policy_acts acts; 18080 uint32_t color_reg_c_idx; 18081 bool mtr_first = (src_port != UINT16_MAX) ? true : false; 18082 struct rte_flow_attr attr = { 18083 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 18084 .priority = 0, 18085 .ingress = 0, 18086 .egress = 0, 18087 .transfer = 1, 18088 .reserved = 0, 18089 }; 18090 uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER; 18091 struct { 18092 struct mlx5_flow_meter_policy *fm_policy; 18093 struct mlx5_flow_meter_info *next_fm; 18094 struct mlx5_sub_policy_color_rule *tag_rule[MLX5_MTR_RTE_COLORS]; 18095 } fm_info[MLX5_MTR_CHAIN_MAX_NUM] = { {0} }; 18096 uint32_t fm_cnt = 0; 18097 uint32_t i, j; 18098 18099 color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); 18100 /* Get all fms who need to create the tag color rule. */ 18101 do { 18102 bool skip = false; 18103 18104 mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 18105 MLX5_ASSERT(mtr_policy); 18106 if (mlx5_meter_hierarchy_skip_tag_rule(priv, mtr_policy, src_port, 18107 &next_fm, &skip, error)) 18108 goto err_exit; 18109 if (!skip) { 18110 fm_info[fm_cnt].fm_policy = mtr_policy; 18111 fm_info[fm_cnt].next_fm = next_fm; 18112 if (++fm_cnt >= MLX5_MTR_CHAIN_MAX_NUM) { 18113 rte_flow_error_set(error, errno, 18114 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 18115 "Exceed max meter number in hierarchy."); 18116 goto err_exit; 18117 } 18118 } 18119 fm = next_fm; 18120 } while (fm); 18121 /* Create tag color rules for all needed fms. */ 18122 for (i = 0; i < fm_cnt; i++) { 18123 void *mtr_action; 18124 18125 mtr_policy = fm_info[i].fm_policy; 18126 rte_spinlock_lock(&mtr_policy->sl); 18127 sub_policy = mtr_policy->sub_policys[domain][0]; 18128 for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) { 18129 uint8_t act_n = 0; 18130 struct mlx5_flow_dv_modify_hdr_resource *modify_hdr; 18131 struct mlx5_flow_dv_port_id_action_resource *port_action; 18132 18133 if (mtr_policy->act_cnt[j].fate_action != MLX5_FLOW_FATE_MTR && 18134 mtr_policy->act_cnt[j].fate_action != MLX5_FLOW_FATE_PORT_ID) 18135 continue; 18136 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 18137 sizeof(struct mlx5_sub_policy_color_rule), 18138 0, SOCKET_ID_ANY); 18139 if (!color_rule) { 18140 rte_spinlock_unlock(&mtr_policy->sl); 18141 rte_flow_error_set(error, ENOMEM, 18142 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 18143 "No memory to create tag color rule."); 18144 goto err_exit; 18145 } 18146 color_rule->src_port = src_port; 18147 modify_hdr = mtr_policy->act_cnt[j].modify_hdr; 18148 /* Prepare to create color rule. */ 18149 if (mtr_policy->act_cnt[j].fate_action == MLX5_FLOW_FATE_MTR) { 18150 next_fm = fm_info[i].next_fm; 18151 if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) { 18152 mlx5_free(color_rule); 18153 rte_spinlock_unlock(&mtr_policy->sl); 18154 goto err_exit; 18155 } 18156 mtr_action = (next_fm->color_aware && j == RTE_COLOR_YELLOW) ? 18157 next_fm->meter_action_y : 18158 next_fm->meter_action_g; 18159 next_policy = mlx5_flow_meter_policy_find(dev, next_fm->policy_id, 18160 NULL); 18161 MLX5_ASSERT(next_policy); 18162 next_sub_policy = next_policy->sub_policys[domain][0]; 18163 tbl_data = container_of(next_sub_policy->tbl_rsc, 18164 struct mlx5_flow_tbl_data_entry, tbl); 18165 if (mtr_first) { 18166 acts.dv_actions[act_n++] = mtr_action; 18167 if (modify_hdr) 18168 acts.dv_actions[act_n++] = modify_hdr->action; 18169 } else { 18170 if (modify_hdr) 18171 acts.dv_actions[act_n++] = modify_hdr->action; 18172 acts.dv_actions[act_n++] = mtr_action; 18173 } 18174 acts.dv_actions[act_n++] = tbl_data->jump.action; 18175 acts.actions_n = act_n; 18176 } else { 18177 port_action = 18178 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], 18179 mtr_policy->act_cnt[j].rix_port_id_action); 18180 if (!port_action) { 18181 mlx5_free(color_rule); 18182 rte_spinlock_unlock(&mtr_policy->sl); 18183 goto err_exit; 18184 } 18185 if (modify_hdr) 18186 acts.dv_actions[act_n++] = modify_hdr->action; 18187 acts.dv_actions[act_n++] = port_action->action; 18188 acts.actions_n = act_n; 18189 } 18190 fm_info[i].tag_rule[j] = color_rule; 18191 TAILQ_INSERT_TAIL(&sub_policy->color_rules[j], color_rule, next_port); 18192 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 18193 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 18194 &attr, true, item, &color_rule->matcher, error)) { 18195 rte_spinlock_unlock(&mtr_policy->sl); 18196 rte_flow_error_set(error, errno, 18197 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 18198 "Failed to create hierarchy meter matcher."); 18199 goto err_exit; 18200 } 18201 if (__flow_dv_create_policy_flow(dev, color_reg_c_idx, (enum rte_color)j, 18202 color_rule->matcher->matcher_object, 18203 acts.actions_n, acts.dv_actions, 18204 true, item, &color_rule->rule, &attr)) { 18205 rte_spinlock_unlock(&mtr_policy->sl); 18206 rte_flow_error_set(error, errno, 18207 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 18208 "Failed to create hierarchy meter rule."); 18209 goto err_exit; 18210 } 18211 } 18212 rte_spinlock_unlock(&mtr_policy->sl); 18213 } 18214 return 0; 18215 err_exit: 18216 for (i = 0; i < fm_cnt; i++) { 18217 mtr_policy = fm_info[i].fm_policy; 18218 rte_spinlock_lock(&mtr_policy->sl); 18219 sub_policy = mtr_policy->sub_policys[domain][0]; 18220 for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) { 18221 color_rule = fm_info[i].tag_rule[j]; 18222 if (!color_rule) 18223 continue; 18224 if (color_rule->rule) 18225 mlx5_flow_os_destroy_flow(color_rule->rule); 18226 if (color_rule->matcher) { 18227 struct mlx5_flow_tbl_data_entry *tbl = 18228 container_of(color_rule->matcher->tbl, typeof(*tbl), tbl); 18229 mlx5_list_unregister(tbl->matchers, &color_rule->matcher->entry); 18230 } 18231 if (fm_info[i].next_fm) 18232 mlx5_flow_meter_detach(priv, fm_info[i].next_fm); 18233 TAILQ_REMOVE(&sub_policy->color_rules[j], color_rule, next_port); 18234 mlx5_free(color_rule); 18235 } 18236 rte_spinlock_unlock(&mtr_policy->sl); 18237 } 18238 return -rte_errno; 18239 } 18240 18241 /** 18242 * Destroy the sub policy table with RX queue. 18243 * 18244 * @param[in] dev 18245 * Pointer to Ethernet device. 18246 * @param[in] mtr_policy 18247 * Pointer to meter policy table. 18248 */ 18249 static void 18250 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, 18251 struct mlx5_flow_meter_policy *mtr_policy) 18252 { 18253 struct mlx5_priv *priv = dev->data->dev_private; 18254 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 18255 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 18256 uint32_t i, j; 18257 uint16_t sub_policy_num, new_policy_num; 18258 18259 rte_spinlock_lock(&mtr_policy->sl); 18260 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 18261 switch (mtr_policy->act_cnt[i].fate_action) { 18262 case MLX5_FLOW_FATE_SHARED_RSS: 18263 sub_policy_num = (mtr_policy->sub_policy_num >> 18264 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 18265 MLX5_MTR_SUB_POLICY_NUM_MASK; 18266 new_policy_num = sub_policy_num; 18267 for (j = 0; j < sub_policy_num; j++) { 18268 sub_policy = 18269 mtr_policy->sub_policys[domain][j]; 18270 if (sub_policy) { 18271 __flow_dv_destroy_sub_policy_rules(dev, 18272 sub_policy); 18273 if (sub_policy != 18274 mtr_policy->sub_policys[domain][0]) { 18275 mtr_policy->sub_policys[domain][j] = 18276 NULL; 18277 mlx5_ipool_free 18278 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 18279 sub_policy->idx); 18280 new_policy_num--; 18281 } 18282 } 18283 } 18284 if (new_policy_num != sub_policy_num) { 18285 mtr_policy->sub_policy_num &= 18286 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 18287 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 18288 mtr_policy->sub_policy_num |= 18289 (new_policy_num & 18290 MLX5_MTR_SUB_POLICY_NUM_MASK) << 18291 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 18292 } 18293 break; 18294 case MLX5_FLOW_FATE_QUEUE: 18295 sub_policy = mtr_policy->sub_policys[domain][0]; 18296 __flow_dv_destroy_sub_policy_rules(dev, 18297 sub_policy); 18298 break; 18299 default: 18300 /*Other actions without queue and do nothing*/ 18301 break; 18302 } 18303 } 18304 rte_spinlock_unlock(&mtr_policy->sl); 18305 } 18306 /** 18307 * Check whether the DR drop action is supported on the root table or not. 18308 * 18309 * Create a simple flow with DR drop action on root table to validate 18310 * if DR drop action on root table is supported or not. 18311 * 18312 * @param[in] dev 18313 * Pointer to rte_eth_dev structure. 18314 * 18315 * @return 18316 * 0 on success, a negative errno value otherwise and rte_errno is set. 18317 */ 18318 int 18319 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev) 18320 { 18321 struct mlx5_priv *priv = dev->data->dev_private; 18322 struct mlx5_dev_ctx_shared *sh = priv->sh; 18323 struct mlx5_flow_dv_match_params mask = { 18324 .size = sizeof(mask.buf), 18325 }; 18326 struct mlx5_flow_dv_match_params value = { 18327 .size = sizeof(value.buf), 18328 }; 18329 struct mlx5dv_flow_matcher_attr dv_attr = { 18330 .type = IBV_FLOW_ATTR_NORMAL, 18331 .priority = 0, 18332 .match_criteria_enable = 0, 18333 .match_mask = (void *)&mask, 18334 }; 18335 struct mlx5_flow_tbl_resource *tbl = NULL; 18336 void *matcher = NULL; 18337 void *flow = NULL; 18338 int ret = -1; 18339 18340 tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 18341 0, 0, 0, NULL); 18342 if (!tbl) 18343 goto err; 18344 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 18345 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 18346 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 18347 tbl->obj, &matcher); 18348 if (ret) 18349 goto err; 18350 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 18351 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 18352 &sh->dr_drop_action, &flow); 18353 err: 18354 /* 18355 * If DR drop action is not supported on root table, flow create will 18356 * be failed with EOPNOTSUPP or EPROTONOSUPPORT. 18357 */ 18358 if (!flow) { 18359 if (matcher && 18360 (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP)) 18361 DRV_LOG(INFO, "DR drop action is not supported in root table."); 18362 else 18363 DRV_LOG(ERR, "Unexpected error in DR drop action support detection"); 18364 ret = -1; 18365 } else { 18366 claim_zero(mlx5_flow_os_destroy_flow(flow)); 18367 } 18368 if (matcher) 18369 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 18370 if (tbl) 18371 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 18372 return ret; 18373 } 18374 18375 /** 18376 * Validate the batch counter support in root table. 18377 * 18378 * Create a simple flow with invalid counter and drop action on root table to 18379 * validate if batch counter with offset on root table is supported or not. 18380 * 18381 * @param[in] dev 18382 * Pointer to rte_eth_dev structure. 18383 * 18384 * @return 18385 * 0 on success, a negative errno value otherwise and rte_errno is set. 18386 */ 18387 int 18388 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev) 18389 { 18390 struct mlx5_priv *priv = dev->data->dev_private; 18391 struct mlx5_dev_ctx_shared *sh = priv->sh; 18392 struct mlx5_flow_dv_match_params mask = { 18393 .size = sizeof(mask.buf), 18394 }; 18395 struct mlx5_flow_dv_match_params value = { 18396 .size = sizeof(value.buf), 18397 }; 18398 struct mlx5dv_flow_matcher_attr dv_attr = { 18399 .type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS, 18400 .priority = 0, 18401 .match_criteria_enable = 0, 18402 .match_mask = (void *)&mask, 18403 }; 18404 void *actions[2] = { 0 }; 18405 struct mlx5_flow_tbl_resource *tbl = NULL; 18406 struct mlx5_devx_obj *dcs = NULL; 18407 void *matcher = NULL; 18408 void *flow = NULL; 18409 int ret = -1; 18410 18411 tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL, 18412 0, 0, 0, NULL); 18413 if (!tbl) 18414 goto err; 18415 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 18416 if (!dcs) 18417 goto err; 18418 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX, 18419 &actions[0]); 18420 if (ret) 18421 goto err; 18422 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 18423 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 18424 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 18425 tbl->obj, &matcher); 18426 if (ret) 18427 goto err; 18428 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 18429 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 18430 actions, &flow); 18431 err: 18432 /* 18433 * If batch counter with offset is not supported, the driver will not 18434 * validate the invalid offset value, flow create should success. 18435 * In this case, it means batch counter is not supported in root table. 18436 * 18437 * Otherwise, if flow create is failed, counter offset is supported. 18438 */ 18439 if (flow) { 18440 DRV_LOG(INFO, "Batch counter is not supported in root " 18441 "table. Switch to fallback mode."); 18442 rte_errno = ENOTSUP; 18443 ret = -rte_errno; 18444 claim_zero(mlx5_flow_os_destroy_flow(flow)); 18445 } else { 18446 /* Check matcher to make sure validate fail at flow create. */ 18447 if (!matcher || (matcher && errno != EINVAL)) 18448 DRV_LOG(ERR, "Unexpected error in counter offset " 18449 "support detection"); 18450 ret = 0; 18451 } 18452 if (actions[0]) 18453 claim_zero(mlx5_flow_os_destroy_flow_action(actions[0])); 18454 if (matcher) 18455 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 18456 if (tbl) 18457 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 18458 if (dcs) 18459 claim_zero(mlx5_devx_cmd_destroy(dcs)); 18460 return ret; 18461 } 18462 18463 /** 18464 * Query a devx counter. 18465 * 18466 * @param[in] dev 18467 * Pointer to the Ethernet device structure. 18468 * @param[in] cnt 18469 * Index to the flow counter. 18470 * @param[in] clear 18471 * Set to clear the counter statistics. 18472 * @param[out] pkts 18473 * The statistics value of packets. 18474 * @param[out] bytes 18475 * The statistics value of bytes. 18476 * 18477 * @return 18478 * 0 on success, otherwise return -1. 18479 */ 18480 static int 18481 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear, 18482 uint64_t *pkts, uint64_t *bytes, void **action) 18483 { 18484 struct mlx5_priv *priv = dev->data->dev_private; 18485 struct mlx5_flow_counter *cnt; 18486 uint64_t inn_pkts, inn_bytes; 18487 int ret; 18488 18489 if (!priv->sh->cdev->config.devx) 18490 return -1; 18491 18492 ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes); 18493 if (ret) 18494 return -1; 18495 cnt = flow_dv_counter_get_by_idx(dev, counter, NULL); 18496 if (cnt && action) 18497 *action = cnt->action; 18498 18499 *pkts = inn_pkts - cnt->hits; 18500 *bytes = inn_bytes - cnt->bytes; 18501 if (clear) { 18502 cnt->hits = inn_pkts; 18503 cnt->bytes = inn_bytes; 18504 } 18505 return 0; 18506 } 18507 18508 /** 18509 * Get aged-out flows. 18510 * 18511 * @param[in] dev 18512 * Pointer to the Ethernet device structure. 18513 * @param[in] context 18514 * The address of an array of pointers to the aged-out flows contexts. 18515 * @param[in] nb_contexts 18516 * The length of context array pointers. 18517 * @param[out] error 18518 * Perform verbose error reporting if not NULL. Initialized in case of 18519 * error only. 18520 * 18521 * @return 18522 * how many contexts get in success, otherwise negative errno value. 18523 * if nb_contexts is 0, return the amount of all aged contexts. 18524 * if nb_contexts is not 0 , return the amount of aged flows reported 18525 * in the context array. 18526 * @note: only stub for now 18527 */ 18528 static int 18529 flow_dv_get_aged_flows(struct rte_eth_dev *dev, 18530 void **context, 18531 uint32_t nb_contexts, 18532 struct rte_flow_error *error) 18533 { 18534 struct mlx5_priv *priv = dev->data->dev_private; 18535 struct mlx5_age_info *age_info; 18536 struct mlx5_age_param *age_param; 18537 struct mlx5_flow_counter *counter; 18538 struct mlx5_aso_age_action *act; 18539 int nb_flows = 0; 18540 18541 if (nb_contexts && !context) 18542 return rte_flow_error_set(error, EINVAL, 18543 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 18544 NULL, "empty context"); 18545 age_info = GET_PORT_AGE_INFO(priv); 18546 rte_spinlock_lock(&age_info->aged_sl); 18547 LIST_FOREACH(act, &age_info->aged_aso, next) { 18548 nb_flows++; 18549 if (nb_contexts) { 18550 context[nb_flows - 1] = 18551 act->age_params.context; 18552 if (!(--nb_contexts)) 18553 break; 18554 } 18555 } 18556 TAILQ_FOREACH(counter, &age_info->aged_counters, next) { 18557 nb_flows++; 18558 if (nb_contexts) { 18559 age_param = MLX5_CNT_TO_AGE(counter); 18560 context[nb_flows - 1] = age_param->context; 18561 if (!(--nb_contexts)) 18562 break; 18563 } 18564 } 18565 rte_spinlock_unlock(&age_info->aged_sl); 18566 MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); 18567 return nb_flows; 18568 } 18569 18570 /* 18571 * Mutex-protected thunk to lock-free flow_dv_counter_alloc(). 18572 */ 18573 static uint32_t 18574 flow_dv_counter_allocate(struct rte_eth_dev *dev) 18575 { 18576 return flow_dv_counter_alloc(dev, 0); 18577 } 18578 18579 /** 18580 * Validate indirect action. 18581 * Dispatcher for action type specific validation. 18582 * 18583 * @param[in] dev 18584 * Pointer to the Ethernet device structure. 18585 * @param[in] conf 18586 * Indirect action configuration. 18587 * @param[in] action 18588 * The indirect action object to validate. 18589 * @param[out] error 18590 * Perform verbose error reporting if not NULL. Initialized in case of 18591 * error only. 18592 * 18593 * @return 18594 * 0 on success, otherwise negative errno value. 18595 */ 18596 int 18597 flow_dv_action_validate(struct rte_eth_dev *dev, 18598 const struct rte_flow_indir_action_conf *conf, 18599 const struct rte_flow_action *action, 18600 struct rte_flow_error *err) 18601 { 18602 struct mlx5_priv *priv = dev->data->dev_private; 18603 /* called from RTE API */ 18604 18605 RTE_SET_USED(conf); 18606 switch (action->type) { 18607 case RTE_FLOW_ACTION_TYPE_RSS: 18608 /* 18609 * priv->obj_ops is set according to driver capabilities. 18610 * When DevX capabilities are 18611 * sufficient, it is set to devx_obj_ops. 18612 * Otherwise, it is set to ibv_obj_ops. 18613 * ibv_obj_ops doesn't support ind_table_modify operation. 18614 * In this case the indirect RSS action can't be used. 18615 */ 18616 if (priv->obj_ops.ind_table_modify == NULL) 18617 return rte_flow_error_set 18618 (err, ENOTSUP, 18619 RTE_FLOW_ERROR_TYPE_ACTION, 18620 NULL, 18621 "Indirect RSS action not supported"); 18622 return mlx5_validate_action_rss(dev, action, err); 18623 case RTE_FLOW_ACTION_TYPE_AGE: 18624 if (!priv->sh->aso_age_mng) 18625 return rte_flow_error_set(err, ENOTSUP, 18626 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 18627 NULL, 18628 "Indirect age action not supported"); 18629 return flow_dv_validate_action_age(0, action, dev, err); 18630 case RTE_FLOW_ACTION_TYPE_COUNT: 18631 return flow_dv_validate_action_count(dev, true, 0, false, err); 18632 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 18633 if (!priv->sh->ct_aso_en) 18634 return rte_flow_error_set(err, ENOTSUP, 18635 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 18636 "ASO CT is not supported"); 18637 return mlx5_validate_action_ct(dev, action->conf, err); 18638 default: 18639 return rte_flow_error_set(err, ENOTSUP, 18640 RTE_FLOW_ERROR_TYPE_ACTION, 18641 NULL, 18642 "action type not supported"); 18643 } 18644 } 18645 18646 /* 18647 * Check if the RSS configurations for colors of a meter policy match 18648 * each other, except the queues. 18649 * 18650 * @param[in] r1 18651 * Pointer to the first RSS flow action. 18652 * @param[in] r2 18653 * Pointer to the second RSS flow action. 18654 * 18655 * @return 18656 * 0 on match, 1 on conflict. 18657 */ 18658 static inline int 18659 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1, 18660 const struct rte_flow_action_rss *r2) 18661 { 18662 if (r1 == NULL || r2 == NULL) 18663 return 0; 18664 if (!(r1->level <= 1 && r2->level <= 1) && 18665 !(r1->level > 1 && r2->level > 1)) 18666 return 1; 18667 if (r1->types != r2->types && 18668 !((r1->types == 0 || r1->types == RTE_ETH_RSS_IP) && 18669 (r2->types == 0 || r2->types == RTE_ETH_RSS_IP))) 18670 return 1; 18671 if (r1->key || r2->key) { 18672 const void *key1 = r1->key ? r1->key : rss_hash_default_key; 18673 const void *key2 = r2->key ? r2->key : rss_hash_default_key; 18674 18675 if (memcmp(key1, key2, MLX5_RSS_HASH_KEY_LEN)) 18676 return 1; 18677 } 18678 return 0; 18679 } 18680 18681 /** 18682 * Validate the meter hierarchy chain for meter policy. 18683 * 18684 * @param[in] dev 18685 * Pointer to the Ethernet device structure. 18686 * @param[in] meter_id 18687 * Meter id. 18688 * @param[in] action_flags 18689 * Holds the actions detected until now. 18690 * @param[out] is_rss 18691 * Is RSS or not. 18692 * @param[out] hierarchy_domain 18693 * The domain bitmap for hierarchy policy. 18694 * @param[out] error 18695 * Perform verbose error reporting if not NULL. Initialized in case of 18696 * error only. 18697 * 18698 * @return 18699 * 0 on success, otherwise negative errno value with error set. 18700 */ 18701 static int 18702 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, 18703 uint32_t meter_id, 18704 uint64_t action_flags, 18705 bool *is_rss, 18706 uint8_t *hierarchy_domain, 18707 struct rte_mtr_error *error) 18708 { 18709 struct mlx5_priv *priv = dev->data->dev_private; 18710 struct mlx5_flow_meter_info *fm; 18711 struct mlx5_flow_meter_policy *policy; 18712 uint8_t cnt = 1; 18713 18714 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 18715 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 18716 return -rte_mtr_error_set(error, EINVAL, 18717 RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, 18718 NULL, 18719 "Multiple fate actions not supported."); 18720 *hierarchy_domain = 0; 18721 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 18722 while (true) { 18723 if (!fm) 18724 return -rte_mtr_error_set(error, EINVAL, 18725 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 18726 "Meter not found in meter hierarchy."); 18727 if (fm->def_policy) 18728 return -rte_mtr_error_set(error, EINVAL, 18729 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 18730 "Non termination meter not supported in hierarchy."); 18731 if (!fm->shared) 18732 return -rte_mtr_error_set(error, EINVAL, 18733 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 18734 "Only shared meter supported in hierarchy."); 18735 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 18736 MLX5_ASSERT(policy); 18737 /** 18738 * Only inherit the supported domains of the first meter in 18739 * hierarchy. 18740 * One meter supports at least one domain. 18741 */ 18742 if (!*hierarchy_domain) { 18743 if (policy->transfer) 18744 *hierarchy_domain |= 18745 MLX5_MTR_DOMAIN_TRANSFER_BIT; 18746 if (policy->ingress) 18747 *hierarchy_domain |= 18748 MLX5_MTR_DOMAIN_INGRESS_BIT; 18749 if (policy->egress) 18750 *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT; 18751 } 18752 if (!policy->is_hierarchy) { 18753 *is_rss = policy->is_rss; 18754 break; 18755 } 18756 rte_spinlock_lock(&policy->sl); 18757 fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, NULL); 18758 rte_spinlock_unlock(&policy->sl); 18759 if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM) 18760 return -rte_mtr_error_set(error, EINVAL, 18761 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 18762 "Exceed max hierarchy meter number."); 18763 } 18764 return 0; 18765 } 18766 18767 /** 18768 * Validate meter policy actions. 18769 * Dispatcher for action type specific validation. 18770 * 18771 * @param[in] dev 18772 * Pointer to the Ethernet device structure. 18773 * @param[in] action 18774 * The meter policy action object to validate. 18775 * @param[in] attr 18776 * Attributes of flow to determine steering domain. 18777 * @param[out] error 18778 * Perform verbose error reporting if not NULL. Initialized in case of 18779 * error only. 18780 * 18781 * @return 18782 * 0 on success, otherwise negative errno value. 18783 */ 18784 static int 18785 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, 18786 const struct rte_flow_action *actions[RTE_COLORS], 18787 struct rte_flow_attr *attr, 18788 bool *is_rss, 18789 uint8_t *domain_bitmap, 18790 uint8_t *policy_mode, 18791 struct rte_mtr_error *error) 18792 { 18793 struct mlx5_priv *priv = dev->data->dev_private; 18794 struct mlx5_sh_config *dev_conf = &priv->sh->config; 18795 const struct rte_flow_action *act; 18796 uint64_t action_flags[RTE_COLORS] = {0}; 18797 int actions_n; 18798 int i, ret; 18799 struct rte_flow_error flow_err; 18800 uint8_t domain_color[RTE_COLORS] = {0}; 18801 uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT; 18802 uint8_t hierarchy_domain = 0; 18803 const struct rte_flow_action_meter *mtr; 18804 const struct rte_flow_action_meter *next_mtr = NULL; 18805 bool def_green = false; 18806 bool def_yellow = false; 18807 const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; 18808 /* Called from RTE API */ 18809 bool is_root = !(attr->group || (attr->transfer && priv->fdb_def_rule)); 18810 18811 if (!dev_conf->dv_esw_en) 18812 def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 18813 *domain_bitmap = def_domain; 18814 /* Red color could only support DROP action. */ 18815 if (!actions[RTE_COLOR_RED] || 18816 actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) 18817 return -rte_mtr_error_set(error, ENOTSUP, 18818 RTE_MTR_ERROR_TYPE_METER_POLICY, 18819 NULL, "Red color only supports drop action."); 18820 /* 18821 * Check default policy actions: 18822 * Green / Yellow: no action, Red: drop action 18823 * Either G or Y will trigger default policy actions to be created. 18824 */ 18825 if (!actions[RTE_COLOR_GREEN] || 18826 actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) 18827 def_green = true; 18828 if (!actions[RTE_COLOR_YELLOW] || 18829 actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) 18830 def_yellow = true; 18831 if (def_green && def_yellow) { 18832 *policy_mode = MLX5_MTR_POLICY_MODE_DEF; 18833 return 0; 18834 } else if (!def_green && def_yellow) { 18835 *policy_mode = MLX5_MTR_POLICY_MODE_OG; 18836 } else if (def_green && !def_yellow) { 18837 *policy_mode = MLX5_MTR_POLICY_MODE_OY; 18838 } else { 18839 *policy_mode = MLX5_MTR_POLICY_MODE_ALL; 18840 } 18841 /* Set to empty string in case of NULL pointer access by user. */ 18842 flow_err.message = ""; 18843 for (i = 0; i < RTE_COLORS; i++) { 18844 act = actions[i]; 18845 for (action_flags[i] = 0, actions_n = 0; 18846 act && act->type != RTE_FLOW_ACTION_TYPE_END; 18847 act++) { 18848 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 18849 return -rte_mtr_error_set(error, ENOTSUP, 18850 RTE_MTR_ERROR_TYPE_METER_POLICY, 18851 NULL, "too many actions"); 18852 switch (act->type) { 18853 case RTE_FLOW_ACTION_TYPE_PORT_ID: 18854 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 18855 if (!dev_conf->dv_esw_en) 18856 return -rte_mtr_error_set(error, 18857 ENOTSUP, 18858 RTE_MTR_ERROR_TYPE_METER_POLICY, 18859 NULL, "PORT action validate check" 18860 " fail for ESW disable"); 18861 ret = flow_dv_validate_action_port_id(dev, 18862 action_flags[i], 18863 act, attr, &flow_err); 18864 if (ret) 18865 return -rte_mtr_error_set(error, 18866 ENOTSUP, 18867 RTE_MTR_ERROR_TYPE_METER_POLICY, 18868 NULL, flow_err.message ? 18869 flow_err.message : 18870 "PORT action validate check fail"); 18871 ++actions_n; 18872 action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID; 18873 break; 18874 case RTE_FLOW_ACTION_TYPE_MARK: 18875 ret = flow_dv_validate_action_mark(dev, act, 18876 action_flags[i], 18877 attr, &flow_err); 18878 if (ret < 0) 18879 return -rte_mtr_error_set(error, 18880 ENOTSUP, 18881 RTE_MTR_ERROR_TYPE_METER_POLICY, 18882 NULL, flow_err.message ? 18883 flow_err.message : 18884 "Mark action validate check fail"); 18885 if (dev_conf->dv_xmeta_en != 18886 MLX5_XMETA_MODE_LEGACY) 18887 return -rte_mtr_error_set(error, 18888 ENOTSUP, 18889 RTE_MTR_ERROR_TYPE_METER_POLICY, 18890 NULL, "Extend MARK action is " 18891 "not supported. Please try use " 18892 "default policy for meter."); 18893 action_flags[i] |= MLX5_FLOW_ACTION_MARK; 18894 ++actions_n; 18895 break; 18896 case RTE_FLOW_ACTION_TYPE_SET_TAG: 18897 ret = flow_dv_validate_action_set_tag(dev, 18898 act, action_flags[i], 18899 attr, &flow_err); 18900 if (ret) 18901 return -rte_mtr_error_set(error, 18902 ENOTSUP, 18903 RTE_MTR_ERROR_TYPE_METER_POLICY, 18904 NULL, flow_err.message ? 18905 flow_err.message : 18906 "Set tag action validate check fail"); 18907 action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG; 18908 ++actions_n; 18909 break; 18910 case RTE_FLOW_ACTION_TYPE_DROP: 18911 ret = mlx5_flow_validate_action_drop 18912 (action_flags[i], attr, &flow_err); 18913 if (ret < 0) 18914 return -rte_mtr_error_set(error, 18915 ENOTSUP, 18916 RTE_MTR_ERROR_TYPE_METER_POLICY, 18917 NULL, flow_err.message ? 18918 flow_err.message : 18919 "Drop action validate check fail"); 18920 action_flags[i] |= MLX5_FLOW_ACTION_DROP; 18921 ++actions_n; 18922 break; 18923 case RTE_FLOW_ACTION_TYPE_QUEUE: 18924 /* 18925 * Check whether extensive 18926 * metadata feature is engaged. 18927 */ 18928 if (dev_conf->dv_flow_en && 18929 (dev_conf->dv_xmeta_en != 18930 MLX5_XMETA_MODE_LEGACY) && 18931 mlx5_flow_ext_mreg_supported(dev)) 18932 return -rte_mtr_error_set(error, 18933 ENOTSUP, 18934 RTE_MTR_ERROR_TYPE_METER_POLICY, 18935 NULL, "Queue action with meta " 18936 "is not supported. Please try use " 18937 "default policy for meter."); 18938 ret = mlx5_flow_validate_action_queue(act, 18939 action_flags[i], dev, 18940 attr, &flow_err); 18941 if (ret < 0) 18942 return -rte_mtr_error_set(error, 18943 ENOTSUP, 18944 RTE_MTR_ERROR_TYPE_METER_POLICY, 18945 NULL, flow_err.message ? 18946 flow_err.message : 18947 "Queue action validate check fail"); 18948 action_flags[i] |= MLX5_FLOW_ACTION_QUEUE; 18949 ++actions_n; 18950 break; 18951 case RTE_FLOW_ACTION_TYPE_RSS: 18952 if (dev_conf->dv_flow_en && 18953 (dev_conf->dv_xmeta_en != 18954 MLX5_XMETA_MODE_LEGACY) && 18955 mlx5_flow_ext_mreg_supported(dev)) 18956 return -rte_mtr_error_set(error, 18957 ENOTSUP, 18958 RTE_MTR_ERROR_TYPE_METER_POLICY, 18959 NULL, "RSS action with meta " 18960 "is not supported. Please try use " 18961 "default policy for meter."); 18962 ret = mlx5_validate_action_rss(dev, act, 18963 &flow_err); 18964 if (ret < 0) 18965 return -rte_mtr_error_set(error, 18966 ENOTSUP, 18967 RTE_MTR_ERROR_TYPE_METER_POLICY, 18968 NULL, flow_err.message ? 18969 flow_err.message : 18970 "RSS action validate check fail"); 18971 action_flags[i] |= MLX5_FLOW_ACTION_RSS; 18972 ++actions_n; 18973 /* Either G or Y will set the RSS. */ 18974 rss_color[i] = act->conf; 18975 break; 18976 case RTE_FLOW_ACTION_TYPE_JUMP: 18977 ret = flow_dv_validate_action_jump(dev, 18978 NULL, act, action_flags[i], 18979 attr, true, &flow_err); 18980 if (ret) 18981 return -rte_mtr_error_set(error, 18982 ENOTSUP, 18983 RTE_MTR_ERROR_TYPE_METER_POLICY, 18984 NULL, flow_err.message ? 18985 flow_err.message : 18986 "Jump action validate check fail"); 18987 ++actions_n; 18988 action_flags[i] |= MLX5_FLOW_ACTION_JUMP; 18989 break; 18990 case RTE_FLOW_ACTION_TYPE_METER: 18991 mtr = act->conf; 18992 if (next_mtr && next_mtr->mtr_id != mtr->mtr_id) 18993 return -rte_mtr_error_set(error, ENOTSUP, 18994 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 18995 "Green and Yellow must use the same meter."); 18996 ret = flow_dv_validate_policy_mtr_hierarchy(dev, 18997 mtr->mtr_id, 18998 action_flags[i], 18999 is_rss, 19000 &hierarchy_domain, 19001 error); 19002 if (ret) 19003 return ret; 19004 ++actions_n; 19005 action_flags[i] |= 19006 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 19007 next_mtr = mtr; 19008 break; 19009 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 19010 ret = flow_dv_validate_action_modify_field(dev, 19011 action_flags[i], act, attr, is_root, &flow_err); 19012 if (ret < 0) 19013 return -rte_mtr_error_set(error, 19014 ENOTSUP, 19015 RTE_MTR_ERROR_TYPE_METER_POLICY, 19016 NULL, flow_err.message ? 19017 flow_err.message : 19018 "Modify field action validate check fail"); 19019 ++actions_n; 19020 action_flags[i] |= MLX5_FLOW_ACTION_MODIFY_FIELD; 19021 break; 19022 default: 19023 return -rte_mtr_error_set(error, ENOTSUP, 19024 RTE_MTR_ERROR_TYPE_METER_POLICY, 19025 NULL, 19026 "Doesn't support optional action"); 19027 } 19028 } 19029 if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) { 19030 domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT; 19031 } else if ((action_flags[i] & 19032 (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || 19033 (action_flags[i] & MLX5_FLOW_ACTION_MARK)) { 19034 /* 19035 * Only support MLX5_XMETA_MODE_LEGACY 19036 * so MARK action is only in ingress domain. 19037 */ 19038 domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT; 19039 } else { 19040 domain_color[i] = def_domain; 19041 if (action_flags[i] && 19042 !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 19043 domain_color[i] &= 19044 ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 19045 } 19046 if (action_flags[i] & 19047 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 19048 domain_color[i] &= hierarchy_domain; 19049 /* 19050 * Non-termination actions only support NIC Tx domain. 19051 * The adjustion should be skipped when there is no 19052 * action or only END is provided. The default domains 19053 * bit-mask is set to find the MIN intersection. 19054 * The action flags checking should also be skipped. 19055 */ 19056 if ((def_green && i == RTE_COLOR_GREEN) || 19057 (def_yellow && i == RTE_COLOR_YELLOW)) 19058 continue; 19059 /* 19060 * Validate the drop action mutual exclusion 19061 * with other actions. Drop action is mutually-exclusive 19062 * with any other action, except for Count action. 19063 */ 19064 if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) && 19065 (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) { 19066 return -rte_mtr_error_set(error, ENOTSUP, 19067 RTE_MTR_ERROR_TYPE_METER_POLICY, 19068 NULL, "Drop action is mutually-exclusive " 19069 "with any other action"); 19070 } 19071 /* Eswitch has few restrictions on using items and actions */ 19072 if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) { 19073 if (!mlx5_flow_ext_mreg_supported(dev) && 19074 action_flags[i] & MLX5_FLOW_ACTION_MARK) 19075 return -rte_mtr_error_set(error, ENOTSUP, 19076 RTE_MTR_ERROR_TYPE_METER_POLICY, 19077 NULL, "unsupported action MARK"); 19078 if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE) 19079 return -rte_mtr_error_set(error, ENOTSUP, 19080 RTE_MTR_ERROR_TYPE_METER_POLICY, 19081 NULL, "unsupported action QUEUE"); 19082 if (action_flags[i] & MLX5_FLOW_ACTION_RSS) 19083 return -rte_mtr_error_set(error, ENOTSUP, 19084 RTE_MTR_ERROR_TYPE_METER_POLICY, 19085 NULL, "unsupported action RSS"); 19086 if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 19087 return -rte_mtr_error_set(error, ENOTSUP, 19088 RTE_MTR_ERROR_TYPE_METER_POLICY, 19089 NULL, "no fate action is found"); 19090 } else { 19091 if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) && 19092 (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) { 19093 if ((domain_color[i] & 19094 MLX5_MTR_DOMAIN_EGRESS_BIT)) 19095 domain_color[i] = 19096 MLX5_MTR_DOMAIN_EGRESS_BIT; 19097 else 19098 return -rte_mtr_error_set(error, 19099 ENOTSUP, 19100 RTE_MTR_ERROR_TYPE_METER_POLICY, 19101 NULL, 19102 "no fate action is found"); 19103 } 19104 } 19105 } 19106 if (next_mtr && *policy_mode == MLX5_MTR_POLICY_MODE_ALL) { 19107 if (!(action_flags[RTE_COLOR_GREEN] & action_flags[RTE_COLOR_YELLOW] & 19108 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) 19109 return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_METER_POLICY, 19110 NULL, 19111 "Meter hierarchy supports meter action only."); 19112 } 19113 /* If both colors have RSS, the attributes should be the same. */ 19114 if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN], 19115 rss_color[RTE_COLOR_YELLOW])) 19116 return -rte_mtr_error_set(error, EINVAL, 19117 RTE_MTR_ERROR_TYPE_METER_POLICY, 19118 NULL, "policy RSS attr conflict"); 19119 if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW]) 19120 *is_rss = true; 19121 /* "domain_color[C]" is non-zero for each color, default is ALL. */ 19122 if (!def_green && !def_yellow && 19123 domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] && 19124 !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) && 19125 !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP)) 19126 return -rte_mtr_error_set(error, EINVAL, 19127 RTE_MTR_ERROR_TYPE_METER_POLICY, 19128 NULL, "policy domains conflict"); 19129 /* 19130 * At least one color policy is listed in the actions, the domains 19131 * to be supported should be the intersection. 19132 */ 19133 *domain_bitmap = domain_color[RTE_COLOR_GREEN] & 19134 domain_color[RTE_COLOR_YELLOW]; 19135 return 0; 19136 } 19137 19138 static int 19139 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags) 19140 { 19141 struct mlx5_priv *priv = dev->data->dev_private; 19142 int ret = 0; 19143 19144 if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) { 19145 ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain, 19146 flags); 19147 if (ret != 0) 19148 return ret; 19149 } 19150 if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) { 19151 ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags); 19152 if (ret != 0) 19153 return ret; 19154 } 19155 if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) { 19156 ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags); 19157 if (ret != 0) 19158 return ret; 19159 } 19160 return 0; 19161 } 19162 19163 /** 19164 * Discover the number of available flow priorities 19165 * by trying to create a flow with the highest priority value 19166 * for each possible number. 19167 * 19168 * @param[in] dev 19169 * Ethernet device. 19170 * @param[in] vprio 19171 * List of possible number of available priorities. 19172 * @param[in] vprio_n 19173 * Size of @p vprio array. 19174 * @return 19175 * On success, number of available flow priorities. 19176 * On failure, a negative errno-style code and rte_errno is set. 19177 */ 19178 static int 19179 flow_dv_discover_priorities(struct rte_eth_dev *dev, 19180 const uint16_t *vprio, int vprio_n) 19181 { 19182 struct mlx5_priv *priv = dev->data->dev_private; 19183 struct mlx5_indexed_pool *pool = priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW]; 19184 struct rte_flow_item_eth eth; 19185 struct rte_flow_item item = { 19186 .type = RTE_FLOW_ITEM_TYPE_ETH, 19187 .spec = ð, 19188 .mask = ð, 19189 }; 19190 struct mlx5_flow_dv_matcher matcher = { 19191 .mask = { 19192 .size = sizeof(matcher.mask.buf), 19193 }, 19194 }; 19195 union mlx5_flow_tbl_key tbl_key; 19196 struct mlx5_flow flow; 19197 void *action; 19198 struct rte_flow_error error; 19199 uint8_t misc_mask; 19200 int i, err, ret = -ENOTSUP; 19201 19202 /* 19203 * Prepare a flow with a catch-all pattern and a drop action. 19204 * Use drop queue, because shared drop action may be unavailable. 19205 */ 19206 action = priv->drop_queue.hrxq->action; 19207 if (action == NULL) { 19208 DRV_LOG(ERR, "Priority discovery requires a drop action"); 19209 rte_errno = ENOTSUP; 19210 return -rte_errno; 19211 } 19212 memset(&flow, 0, sizeof(flow)); 19213 flow.handle = mlx5_ipool_zmalloc(pool, &flow.handle_idx); 19214 if (flow.handle == NULL) { 19215 DRV_LOG(ERR, "Cannot create flow handle"); 19216 rte_errno = ENOMEM; 19217 return -rte_errno; 19218 } 19219 flow.ingress = true; 19220 flow.dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 19221 flow.dv.actions[0] = action; 19222 flow.dv.actions_n = 1; 19223 memset(ð, 0, sizeof(eth)); 19224 flow_dv_translate_item_eth(matcher.mask.buf, &item, 19225 /* inner */ false, /* group */ 0, 19226 MLX5_SET_MATCHER_SW_M); 19227 flow_dv_translate_item_eth(flow.dv.value.buf, &item, 19228 /* inner */ false, /* group */ 0, 19229 MLX5_SET_MATCHER_SW_V); 19230 matcher.crc = rte_raw_cksum(matcher.mask.buf, matcher.mask.size); 19231 for (i = 0; i < vprio_n; i++) { 19232 /* Configure the next proposed maximum priority. */ 19233 matcher.priority = vprio[i] - 1; 19234 memset(&tbl_key, 0, sizeof(tbl_key)); 19235 err = flow_dv_matcher_register(dev, &matcher, &tbl_key, &flow, 19236 /* tunnel */ NULL, 19237 /* group */ 0, 19238 &error); 19239 if (err != 0) { 19240 /* This action is pure SW and must always succeed. */ 19241 DRV_LOG(ERR, "Cannot register matcher"); 19242 ret = -rte_errno; 19243 break; 19244 } 19245 /* Try to apply the flow to HW. */ 19246 misc_mask = flow_dv_matcher_enable(flow.dv.value.buf); 19247 __flow_dv_adjust_buf_size(&flow.dv.value.size, misc_mask); 19248 err = mlx5_flow_os_create_flow 19249 (flow.handle->dvh.matcher->matcher_object, 19250 (void *)&flow.dv.value, flow.dv.actions_n, 19251 flow.dv.actions, &flow.handle->drv_flow); 19252 if (err == 0) { 19253 claim_zero(mlx5_flow_os_destroy_flow 19254 (flow.handle->drv_flow)); 19255 flow.handle->drv_flow = NULL; 19256 } 19257 claim_zero(flow_dv_matcher_release(dev, flow.handle)); 19258 if (err != 0) 19259 break; 19260 ret = vprio[i]; 19261 } 19262 mlx5_ipool_free(pool, flow.handle_idx); 19263 /* Set rte_errno if no expected priority value matched. */ 19264 if (ret < 0) 19265 rte_errno = -ret; 19266 return ret; 19267 } 19268 19269 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { 19270 .validate = flow_dv_validate, 19271 .prepare = flow_dv_prepare, 19272 .translate = flow_dv_translate, 19273 .apply = flow_dv_apply, 19274 .remove = flow_dv_remove, 19275 .destroy = flow_dv_destroy, 19276 .query = flow_dv_query, 19277 .create_mtr_tbls = flow_dv_create_mtr_tbls, 19278 .destroy_mtr_tbls = flow_dv_destroy_mtr_tbls, 19279 .destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls, 19280 .create_meter = flow_dv_mtr_alloc, 19281 .free_meter = flow_dv_aso_mtr_release_to_pool, 19282 .validate_mtr_acts = flow_dv_validate_mtr_policy_acts, 19283 .create_mtr_acts = flow_dv_create_mtr_policy_acts, 19284 .destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts, 19285 .create_policy_rules = flow_dv_create_policy_rules, 19286 .destroy_policy_rules = flow_dv_destroy_policy_rules, 19287 .create_def_policy = flow_dv_create_def_policy, 19288 .destroy_def_policy = flow_dv_destroy_def_policy, 19289 .meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare, 19290 .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create, 19291 .destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq, 19292 .counter_alloc = flow_dv_counter_allocate, 19293 .counter_free = flow_dv_counter_free, 19294 .counter_query = flow_dv_counter_query, 19295 .get_aged_flows = flow_dv_get_aged_flows, 19296 .action_validate = flow_dv_action_validate, 19297 .action_create = flow_dv_action_create, 19298 .action_destroy = flow_dv_action_destroy, 19299 .action_update = flow_dv_action_update, 19300 .action_query = flow_dv_action_query, 19301 .sync_domain = flow_dv_sync_domain, 19302 .discover_priorities = flow_dv_discover_priorities, 19303 .item_create = flow_dv_item_create, 19304 .item_release = flow_dv_item_release, 19305 }; 19306 19307 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ 19308