1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2018 Mellanox Technologies, Ltd 3 */ 4 5 #include <sys/queue.h> 6 #include <stdalign.h> 7 #include <stdint.h> 8 #include <string.h> 9 #include <unistd.h> 10 11 #include <rte_common.h> 12 #include <rte_ether.h> 13 #include <ethdev_driver.h> 14 #include <rte_flow.h> 15 #include <rte_flow_driver.h> 16 #include <rte_malloc.h> 17 #include <rte_cycles.h> 18 #include <rte_bus_pci.h> 19 #include <rte_ip.h> 20 #include <rte_gre.h> 21 #include <rte_vxlan.h> 22 #include <rte_gtp.h> 23 #include <rte_eal_paging.h> 24 #include <rte_mpls.h> 25 #include <rte_mtr.h> 26 #include <rte_mtr_driver.h> 27 #include <rte_tailq.h> 28 29 #include <mlx5_glue.h> 30 #include <mlx5_devx_cmds.h> 31 #include <mlx5_prm.h> 32 #include <mlx5_malloc.h> 33 34 #include "mlx5_defs.h" 35 #include "mlx5.h" 36 #include "mlx5_common_os.h" 37 #include "mlx5_flow.h" 38 #include "mlx5_flow_os.h" 39 #include "mlx5_rx.h" 40 #include "mlx5_tx.h" 41 #include "rte_pmd_mlx5.h" 42 43 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) 44 45 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS 46 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0 47 #endif 48 49 #ifndef HAVE_MLX5DV_DR_ESWITCH 50 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB 51 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0 52 #endif 53 #endif 54 55 #ifndef HAVE_MLX5DV_DR 56 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1 57 #endif 58 59 /* VLAN header definitions */ 60 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13 61 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT) 62 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff 63 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK) 64 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK) 65 66 union flow_dv_attr { 67 struct { 68 uint32_t valid:1; 69 uint32_t ipv4:1; 70 uint32_t ipv6:1; 71 uint32_t tcp:1; 72 uint32_t udp:1; 73 uint32_t reserved:27; 74 }; 75 uint32_t attr; 76 }; 77 78 static int 79 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 80 struct mlx5_flow_tbl_resource *tbl); 81 82 static int 83 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 84 uint32_t encap_decap_idx); 85 86 static int 87 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 88 uint32_t port_id); 89 static void 90 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss); 91 92 static int 93 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 94 uint32_t rix_jump); 95 96 static int16_t 97 flow_dv_get_esw_manager_vport_id(struct rte_eth_dev *dev) 98 { 99 struct mlx5_priv *priv = dev->data->dev_private; 100 101 if (priv->pci_dev == NULL) 102 return 0; 103 switch (priv->pci_dev->id.device_id) { 104 case PCI_DEVICE_ID_MELLANOX_CONNECTX5BF: 105 case PCI_DEVICE_ID_MELLANOX_CONNECTX6DXBF: 106 case PCI_DEVICE_ID_MELLANOX_CONNECTX7BF: 107 return (int16_t)0xfffe; 108 default: 109 return 0; 110 } 111 } 112 113 /** 114 * Initialize flow attributes structure according to flow items' types. 115 * 116 * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel 117 * mode. For tunnel mode, the items to be modified are the outermost ones. 118 * 119 * @param[in] item 120 * Pointer to item specification. 121 * @param[out] attr 122 * Pointer to flow attributes structure. 123 * @param[in] dev_flow 124 * Pointer to the sub flow. 125 * @param[in] tunnel_decap 126 * Whether action is after tunnel decapsulation. 127 */ 128 static void 129 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr, 130 struct mlx5_flow *dev_flow, bool tunnel_decap) 131 { 132 uint64_t layers = dev_flow->handle->layers; 133 134 /* 135 * If layers is already initialized, it means this dev_flow is the 136 * suffix flow, the layers flags is set by the prefix flow. Need to 137 * use the layer flags from prefix flow as the suffix flow may not 138 * have the user defined items as the flow is split. 139 */ 140 if (layers) { 141 if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4) 142 attr->ipv4 = 1; 143 else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6) 144 attr->ipv6 = 1; 145 if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP) 146 attr->tcp = 1; 147 else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP) 148 attr->udp = 1; 149 attr->valid = 1; 150 return; 151 } 152 for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 153 uint8_t next_protocol = 0xff; 154 switch (item->type) { 155 case RTE_FLOW_ITEM_TYPE_GRE: 156 case RTE_FLOW_ITEM_TYPE_NVGRE: 157 case RTE_FLOW_ITEM_TYPE_VXLAN: 158 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 159 case RTE_FLOW_ITEM_TYPE_GENEVE: 160 case RTE_FLOW_ITEM_TYPE_MPLS: 161 if (tunnel_decap) 162 attr->attr = 0; 163 break; 164 case RTE_FLOW_ITEM_TYPE_IPV4: 165 if (!attr->ipv6) 166 attr->ipv4 = 1; 167 if (item->mask != NULL && 168 ((const struct rte_flow_item_ipv4 *) 169 item->mask)->hdr.next_proto_id) 170 next_protocol = 171 ((const struct rte_flow_item_ipv4 *) 172 (item->spec))->hdr.next_proto_id & 173 ((const struct rte_flow_item_ipv4 *) 174 (item->mask))->hdr.next_proto_id; 175 if ((next_protocol == IPPROTO_IPIP || 176 next_protocol == IPPROTO_IPV6) && tunnel_decap) 177 attr->attr = 0; 178 break; 179 case RTE_FLOW_ITEM_TYPE_IPV6: 180 if (!attr->ipv4) 181 attr->ipv6 = 1; 182 if (item->mask != NULL && 183 ((const struct rte_flow_item_ipv6 *) 184 item->mask)->hdr.proto) 185 next_protocol = 186 ((const struct rte_flow_item_ipv6 *) 187 (item->spec))->hdr.proto & 188 ((const struct rte_flow_item_ipv6 *) 189 (item->mask))->hdr.proto; 190 if ((next_protocol == IPPROTO_IPIP || 191 next_protocol == IPPROTO_IPV6) && tunnel_decap) 192 attr->attr = 0; 193 break; 194 case RTE_FLOW_ITEM_TYPE_UDP: 195 if (!attr->tcp) 196 attr->udp = 1; 197 break; 198 case RTE_FLOW_ITEM_TYPE_TCP: 199 if (!attr->udp) 200 attr->tcp = 1; 201 break; 202 default: 203 break; 204 } 205 } 206 attr->valid = 1; 207 } 208 209 /* 210 * Convert rte_mtr_color to mlx5 color. 211 * 212 * @param[in] rcol 213 * rte_mtr_color. 214 * 215 * @return 216 * mlx5 color. 217 */ 218 static inline int 219 rte_col_2_mlx5_col(enum rte_color rcol) 220 { 221 switch (rcol) { 222 case RTE_COLOR_GREEN: 223 return MLX5_FLOW_COLOR_GREEN; 224 case RTE_COLOR_YELLOW: 225 return MLX5_FLOW_COLOR_YELLOW; 226 case RTE_COLOR_RED: 227 return MLX5_FLOW_COLOR_RED; 228 default: 229 break; 230 } 231 return MLX5_FLOW_COLOR_UNDEFINED; 232 } 233 234 struct field_modify_info { 235 uint32_t size; /* Size of field in protocol header, in bytes. */ 236 uint32_t offset; /* Offset of field in protocol header, in bytes. */ 237 enum mlx5_modification_field id; 238 }; 239 240 struct field_modify_info modify_eth[] = { 241 {4, 0, MLX5_MODI_OUT_DMAC_47_16}, 242 {2, 4, MLX5_MODI_OUT_DMAC_15_0}, 243 {4, 6, MLX5_MODI_OUT_SMAC_47_16}, 244 {2, 10, MLX5_MODI_OUT_SMAC_15_0}, 245 {0, 0, 0}, 246 }; 247 248 struct field_modify_info modify_vlan_out_first_vid[] = { 249 /* Size in bits !!! */ 250 {12, 0, MLX5_MODI_OUT_FIRST_VID}, 251 {0, 0, 0}, 252 }; 253 254 struct field_modify_info modify_ipv4[] = { 255 {1, 1, MLX5_MODI_OUT_IP_DSCP}, 256 {1, 8, MLX5_MODI_OUT_IPV4_TTL}, 257 {4, 12, MLX5_MODI_OUT_SIPV4}, 258 {4, 16, MLX5_MODI_OUT_DIPV4}, 259 {0, 0, 0}, 260 }; 261 262 struct field_modify_info modify_ipv6[] = { 263 {1, 0, MLX5_MODI_OUT_IP_DSCP}, 264 {1, 7, MLX5_MODI_OUT_IPV6_HOPLIMIT}, 265 {4, 8, MLX5_MODI_OUT_SIPV6_127_96}, 266 {4, 12, MLX5_MODI_OUT_SIPV6_95_64}, 267 {4, 16, MLX5_MODI_OUT_SIPV6_63_32}, 268 {4, 20, MLX5_MODI_OUT_SIPV6_31_0}, 269 {4, 24, MLX5_MODI_OUT_DIPV6_127_96}, 270 {4, 28, MLX5_MODI_OUT_DIPV6_95_64}, 271 {4, 32, MLX5_MODI_OUT_DIPV6_63_32}, 272 {4, 36, MLX5_MODI_OUT_DIPV6_31_0}, 273 {0, 0, 0}, 274 }; 275 276 struct field_modify_info modify_udp[] = { 277 {2, 0, MLX5_MODI_OUT_UDP_SPORT}, 278 {2, 2, MLX5_MODI_OUT_UDP_DPORT}, 279 {0, 0, 0}, 280 }; 281 282 struct field_modify_info modify_tcp[] = { 283 {2, 0, MLX5_MODI_OUT_TCP_SPORT}, 284 {2, 2, MLX5_MODI_OUT_TCP_DPORT}, 285 {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM}, 286 {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM}, 287 {0, 0, 0}, 288 }; 289 290 static void 291 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused, 292 uint8_t next_protocol, uint64_t *item_flags, 293 int *tunnel) 294 { 295 MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 || 296 item->type == RTE_FLOW_ITEM_TYPE_IPV6); 297 if (next_protocol == IPPROTO_IPIP) { 298 *item_flags |= MLX5_FLOW_LAYER_IPIP; 299 *tunnel = 1; 300 } 301 if (next_protocol == IPPROTO_IPV6) { 302 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP; 303 *tunnel = 1; 304 } 305 } 306 307 static inline struct mlx5_hlist * 308 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl, 309 const char *name, uint32_t size, bool direct_key, 310 bool lcores_share, void *ctx, 311 mlx5_list_create_cb cb_create, 312 mlx5_list_match_cb cb_match, 313 mlx5_list_remove_cb cb_remove, 314 mlx5_list_clone_cb cb_clone, 315 mlx5_list_clone_free_cb cb_clone_free) 316 { 317 struct mlx5_hlist *hl; 318 struct mlx5_hlist *expected = NULL; 319 char s[MLX5_NAME_SIZE]; 320 321 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 322 if (likely(hl)) 323 return hl; 324 snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name); 325 hl = mlx5_hlist_create(s, size, direct_key, lcores_share, 326 ctx, cb_create, cb_match, cb_remove, cb_clone, 327 cb_clone_free); 328 if (!hl) { 329 DRV_LOG(ERR, "%s hash creation failed", name); 330 rte_errno = ENOMEM; 331 return NULL; 332 } 333 if (!__atomic_compare_exchange_n(phl, &expected, hl, false, 334 __ATOMIC_SEQ_CST, 335 __ATOMIC_SEQ_CST)) { 336 mlx5_hlist_destroy(hl); 337 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST); 338 } 339 return hl; 340 } 341 342 /* Update VLAN's VID/PCP based on input rte_flow_action. 343 * 344 * @param[in] action 345 * Pointer to struct rte_flow_action. 346 * @param[out] vlan 347 * Pointer to struct rte_vlan_hdr. 348 */ 349 static void 350 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, 351 struct rte_vlan_hdr *vlan) 352 { 353 uint16_t vlan_tci; 354 if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) { 355 vlan_tci = 356 ((const struct rte_flow_action_of_set_vlan_pcp *) 357 action->conf)->vlan_pcp; 358 vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT; 359 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 360 vlan->vlan_tci |= vlan_tci; 361 } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) { 362 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 363 vlan->vlan_tci |= rte_be_to_cpu_16 364 (((const struct rte_flow_action_of_set_vlan_vid *) 365 action->conf)->vlan_vid); 366 } 367 } 368 369 /** 370 * Fetch 1, 2, 3 or 4 byte field from the byte array 371 * and return as unsigned integer in host-endian format. 372 * 373 * @param[in] data 374 * Pointer to data array. 375 * @param[in] size 376 * Size of field to extract. 377 * 378 * @return 379 * converted field in host endian format. 380 */ 381 static inline uint32_t 382 flow_dv_fetch_field(const uint8_t *data, uint32_t size) 383 { 384 uint32_t ret; 385 386 switch (size) { 387 case 1: 388 ret = *data; 389 break; 390 case 2: 391 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 392 break; 393 case 3: 394 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); 395 ret = (ret << 8) | *(data + sizeof(uint16_t)); 396 break; 397 case 4: 398 ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); 399 break; 400 default: 401 MLX5_ASSERT(false); 402 ret = 0; 403 break; 404 } 405 return ret; 406 } 407 408 /** 409 * Convert modify-header action to DV specification. 410 * 411 * Data length of each action is determined by provided field description 412 * and the item mask. Data bit offset and width of each action is determined 413 * by provided item mask. 414 * 415 * @param[in] item 416 * Pointer to item specification. 417 * @param[in] field 418 * Pointer to field modification information. 419 * For MLX5_MODIFICATION_TYPE_SET specifies destination field. 420 * For MLX5_MODIFICATION_TYPE_ADD specifies destination field. 421 * For MLX5_MODIFICATION_TYPE_COPY specifies source field. 422 * @param[in] dcopy 423 * Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type. 424 * Negative offset value sets the same offset as source offset. 425 * size field is ignored, value is taken from source field. 426 * @param[in,out] resource 427 * Pointer to the modify-header resource. 428 * @param[in] type 429 * Type of modification. 430 * @param[out] error 431 * Pointer to the error structure. 432 * 433 * @return 434 * 0 on success, a negative errno value otherwise and rte_errno is set. 435 */ 436 static int 437 flow_dv_convert_modify_action(struct rte_flow_item *item, 438 struct field_modify_info *field, 439 struct field_modify_info *dcopy, 440 struct mlx5_flow_dv_modify_hdr_resource *resource, 441 uint32_t type, struct rte_flow_error *error) 442 { 443 uint32_t i = resource->actions_num; 444 struct mlx5_modification_cmd *actions = resource->actions; 445 uint32_t carry_b = 0; 446 447 /* 448 * The item and mask are provided in big-endian format. 449 * The fields should be presented as in big-endian format either. 450 * Mask must be always present, it defines the actual field width. 451 */ 452 MLX5_ASSERT(item->mask); 453 MLX5_ASSERT(field->size); 454 do { 455 uint32_t size_b; 456 uint32_t off_b; 457 uint32_t mask; 458 uint32_t data; 459 bool next_field = true; 460 bool next_dcopy = true; 461 462 if (i >= MLX5_MAX_MODIFY_NUM) 463 return rte_flow_error_set(error, EINVAL, 464 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 465 "too many items to modify"); 466 /* Fetch variable byte size mask from the array. */ 467 mask = flow_dv_fetch_field((const uint8_t *)item->mask + 468 field->offset, field->size); 469 if (!mask) { 470 ++field; 471 continue; 472 } 473 /* Deduce actual data width in bits from mask value. */ 474 off_b = rte_bsf32(mask) + carry_b; 475 size_b = sizeof(uint32_t) * CHAR_BIT - 476 off_b - __builtin_clz(mask); 477 MLX5_ASSERT(size_b); 478 actions[i] = (struct mlx5_modification_cmd) { 479 .action_type = type, 480 .field = field->id, 481 .offset = off_b, 482 .length = (size_b == sizeof(uint32_t) * CHAR_BIT) ? 483 0 : size_b, 484 }; 485 if (type == MLX5_MODIFICATION_TYPE_COPY) { 486 MLX5_ASSERT(dcopy); 487 actions[i].dst_field = dcopy->id; 488 actions[i].dst_offset = 489 (int)dcopy->offset < 0 ? off_b : dcopy->offset; 490 /* Convert entire record to big-endian format. */ 491 actions[i].data1 = rte_cpu_to_be_32(actions[i].data1); 492 /* 493 * Destination field overflow. Copy leftovers of 494 * a source field to the next destination field. 495 */ 496 carry_b = 0; 497 if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) && 498 dcopy->size != 0) { 499 actions[i].length = 500 dcopy->size * CHAR_BIT - dcopy->offset; 501 carry_b = actions[i].length; 502 next_field = false; 503 } 504 /* 505 * Not enough bits in a source filed to fill a 506 * destination field. Switch to the next source. 507 */ 508 if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) && 509 (size_b == field->size * CHAR_BIT - off_b)) { 510 actions[i].length = 511 field->size * CHAR_BIT - off_b; 512 dcopy->offset += actions[i].length; 513 next_dcopy = false; 514 } 515 if (next_dcopy) 516 ++dcopy; 517 } else { 518 MLX5_ASSERT(item->spec); 519 data = flow_dv_fetch_field((const uint8_t *)item->spec + 520 field->offset, field->size); 521 /* Shift out the trailing masked bits from data. */ 522 data = (data & mask) >> off_b; 523 actions[i].data1 = rte_cpu_to_be_32(data); 524 } 525 /* Convert entire record to expected big-endian format. */ 526 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 527 if (next_field) 528 ++field; 529 ++i; 530 } while (field->size); 531 if (resource->actions_num == i) 532 return rte_flow_error_set(error, EINVAL, 533 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 534 "invalid modification flow item"); 535 resource->actions_num = i; 536 return 0; 537 } 538 539 /** 540 * Convert modify-header set IPv4 address action to DV specification. 541 * 542 * @param[in,out] resource 543 * Pointer to the modify-header resource. 544 * @param[in] action 545 * Pointer to action specification. 546 * @param[out] error 547 * Pointer to the error structure. 548 * 549 * @return 550 * 0 on success, a negative errno value otherwise and rte_errno is set. 551 */ 552 static int 553 flow_dv_convert_action_modify_ipv4 554 (struct mlx5_flow_dv_modify_hdr_resource *resource, 555 const struct rte_flow_action *action, 556 struct rte_flow_error *error) 557 { 558 const struct rte_flow_action_set_ipv4 *conf = 559 (const struct rte_flow_action_set_ipv4 *)(action->conf); 560 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 561 struct rte_flow_item_ipv4 ipv4; 562 struct rte_flow_item_ipv4 ipv4_mask; 563 564 memset(&ipv4, 0, sizeof(ipv4)); 565 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 566 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) { 567 ipv4.hdr.src_addr = conf->ipv4_addr; 568 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr; 569 } else { 570 ipv4.hdr.dst_addr = conf->ipv4_addr; 571 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr; 572 } 573 item.spec = &ipv4; 574 item.mask = &ipv4_mask; 575 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 576 MLX5_MODIFICATION_TYPE_SET, error); 577 } 578 579 /** 580 * Convert modify-header set IPv6 address action to DV specification. 581 * 582 * @param[in,out] resource 583 * Pointer to the modify-header resource. 584 * @param[in] action 585 * Pointer to action specification. 586 * @param[out] error 587 * Pointer to the error structure. 588 * 589 * @return 590 * 0 on success, a negative errno value otherwise and rte_errno is set. 591 */ 592 static int 593 flow_dv_convert_action_modify_ipv6 594 (struct mlx5_flow_dv_modify_hdr_resource *resource, 595 const struct rte_flow_action *action, 596 struct rte_flow_error *error) 597 { 598 const struct rte_flow_action_set_ipv6 *conf = 599 (const struct rte_flow_action_set_ipv6 *)(action->conf); 600 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 601 struct rte_flow_item_ipv6 ipv6; 602 struct rte_flow_item_ipv6 ipv6_mask; 603 604 memset(&ipv6, 0, sizeof(ipv6)); 605 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 606 if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) { 607 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr, 608 sizeof(ipv6.hdr.src_addr)); 609 memcpy(&ipv6_mask.hdr.src_addr, 610 &rte_flow_item_ipv6_mask.hdr.src_addr, 611 sizeof(ipv6.hdr.src_addr)); 612 } else { 613 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr, 614 sizeof(ipv6.hdr.dst_addr)); 615 memcpy(&ipv6_mask.hdr.dst_addr, 616 &rte_flow_item_ipv6_mask.hdr.dst_addr, 617 sizeof(ipv6.hdr.dst_addr)); 618 } 619 item.spec = &ipv6; 620 item.mask = &ipv6_mask; 621 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 622 MLX5_MODIFICATION_TYPE_SET, error); 623 } 624 625 /** 626 * Convert modify-header set MAC address action to DV specification. 627 * 628 * @param[in,out] resource 629 * Pointer to the modify-header resource. 630 * @param[in] action 631 * Pointer to action specification. 632 * @param[out] error 633 * Pointer to the error structure. 634 * 635 * @return 636 * 0 on success, a negative errno value otherwise and rte_errno is set. 637 */ 638 static int 639 flow_dv_convert_action_modify_mac 640 (struct mlx5_flow_dv_modify_hdr_resource *resource, 641 const struct rte_flow_action *action, 642 struct rte_flow_error *error) 643 { 644 const struct rte_flow_action_set_mac *conf = 645 (const struct rte_flow_action_set_mac *)(action->conf); 646 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH }; 647 struct rte_flow_item_eth eth; 648 struct rte_flow_item_eth eth_mask; 649 650 memset(ð, 0, sizeof(eth)); 651 memset(ð_mask, 0, sizeof(eth_mask)); 652 if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) { 653 memcpy(ð.src.addr_bytes, &conf->mac_addr, 654 sizeof(eth.src.addr_bytes)); 655 memcpy(ð_mask.src.addr_bytes, 656 &rte_flow_item_eth_mask.src.addr_bytes, 657 sizeof(eth_mask.src.addr_bytes)); 658 } else { 659 memcpy(ð.dst.addr_bytes, &conf->mac_addr, 660 sizeof(eth.dst.addr_bytes)); 661 memcpy(ð_mask.dst.addr_bytes, 662 &rte_flow_item_eth_mask.dst.addr_bytes, 663 sizeof(eth_mask.dst.addr_bytes)); 664 } 665 item.spec = ð 666 item.mask = ð_mask; 667 return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource, 668 MLX5_MODIFICATION_TYPE_SET, error); 669 } 670 671 /** 672 * Convert modify-header set VLAN VID action to DV specification. 673 * 674 * @param[in,out] resource 675 * Pointer to the modify-header resource. 676 * @param[in] action 677 * Pointer to action specification. 678 * @param[out] error 679 * Pointer to the error structure. 680 * 681 * @return 682 * 0 on success, a negative errno value otherwise and rte_errno is set. 683 */ 684 static int 685 flow_dv_convert_action_modify_vlan_vid 686 (struct mlx5_flow_dv_modify_hdr_resource *resource, 687 const struct rte_flow_action *action, 688 struct rte_flow_error *error) 689 { 690 const struct rte_flow_action_of_set_vlan_vid *conf = 691 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf); 692 int i = resource->actions_num; 693 struct mlx5_modification_cmd *actions = resource->actions; 694 struct field_modify_info *field = modify_vlan_out_first_vid; 695 696 if (i >= MLX5_MAX_MODIFY_NUM) 697 return rte_flow_error_set(error, EINVAL, 698 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 699 "too many items to modify"); 700 actions[i] = (struct mlx5_modification_cmd) { 701 .action_type = MLX5_MODIFICATION_TYPE_SET, 702 .field = field->id, 703 .length = field->size, 704 .offset = field->offset, 705 }; 706 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 707 actions[i].data1 = conf->vlan_vid; 708 actions[i].data1 = actions[i].data1 << 16; 709 resource->actions_num = ++i; 710 return 0; 711 } 712 713 /** 714 * Convert modify-header set TP action to DV specification. 715 * 716 * @param[in,out] resource 717 * Pointer to the modify-header resource. 718 * @param[in] action 719 * Pointer to action specification. 720 * @param[in] items 721 * Pointer to rte_flow_item objects list. 722 * @param[in] attr 723 * Pointer to flow attributes structure. 724 * @param[in] dev_flow 725 * Pointer to the sub flow. 726 * @param[in] tunnel_decap 727 * Whether action is after tunnel decapsulation. 728 * @param[out] error 729 * Pointer to the error structure. 730 * 731 * @return 732 * 0 on success, a negative errno value otherwise and rte_errno is set. 733 */ 734 static int 735 flow_dv_convert_action_modify_tp 736 (struct mlx5_flow_dv_modify_hdr_resource *resource, 737 const struct rte_flow_action *action, 738 const struct rte_flow_item *items, 739 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 740 bool tunnel_decap, struct rte_flow_error *error) 741 { 742 const struct rte_flow_action_set_tp *conf = 743 (const struct rte_flow_action_set_tp *)(action->conf); 744 struct rte_flow_item item; 745 struct rte_flow_item_udp udp; 746 struct rte_flow_item_udp udp_mask; 747 struct rte_flow_item_tcp tcp; 748 struct rte_flow_item_tcp tcp_mask; 749 struct field_modify_info *field; 750 751 if (!attr->valid) 752 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 753 if (attr->udp) { 754 memset(&udp, 0, sizeof(udp)); 755 memset(&udp_mask, 0, sizeof(udp_mask)); 756 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 757 udp.hdr.src_port = conf->port; 758 udp_mask.hdr.src_port = 759 rte_flow_item_udp_mask.hdr.src_port; 760 } else { 761 udp.hdr.dst_port = conf->port; 762 udp_mask.hdr.dst_port = 763 rte_flow_item_udp_mask.hdr.dst_port; 764 } 765 item.type = RTE_FLOW_ITEM_TYPE_UDP; 766 item.spec = &udp; 767 item.mask = &udp_mask; 768 field = modify_udp; 769 } else { 770 MLX5_ASSERT(attr->tcp); 771 memset(&tcp, 0, sizeof(tcp)); 772 memset(&tcp_mask, 0, sizeof(tcp_mask)); 773 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) { 774 tcp.hdr.src_port = conf->port; 775 tcp_mask.hdr.src_port = 776 rte_flow_item_tcp_mask.hdr.src_port; 777 } else { 778 tcp.hdr.dst_port = conf->port; 779 tcp_mask.hdr.dst_port = 780 rte_flow_item_tcp_mask.hdr.dst_port; 781 } 782 item.type = RTE_FLOW_ITEM_TYPE_TCP; 783 item.spec = &tcp; 784 item.mask = &tcp_mask; 785 field = modify_tcp; 786 } 787 return flow_dv_convert_modify_action(&item, field, NULL, resource, 788 MLX5_MODIFICATION_TYPE_SET, error); 789 } 790 791 /** 792 * Convert modify-header set TTL action to DV specification. 793 * 794 * @param[in,out] resource 795 * Pointer to the modify-header resource. 796 * @param[in] action 797 * Pointer to action specification. 798 * @param[in] items 799 * Pointer to rte_flow_item objects list. 800 * @param[in] attr 801 * Pointer to flow attributes structure. 802 * @param[in] dev_flow 803 * Pointer to the sub flow. 804 * @param[in] tunnel_decap 805 * Whether action is after tunnel decapsulation. 806 * @param[out] error 807 * Pointer to the error structure. 808 * 809 * @return 810 * 0 on success, a negative errno value otherwise and rte_errno is set. 811 */ 812 static int 813 flow_dv_convert_action_modify_ttl 814 (struct mlx5_flow_dv_modify_hdr_resource *resource, 815 const struct rte_flow_action *action, 816 const struct rte_flow_item *items, 817 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 818 bool tunnel_decap, struct rte_flow_error *error) 819 { 820 const struct rte_flow_action_set_ttl *conf = 821 (const struct rte_flow_action_set_ttl *)(action->conf); 822 struct rte_flow_item item; 823 struct rte_flow_item_ipv4 ipv4; 824 struct rte_flow_item_ipv4 ipv4_mask; 825 struct rte_flow_item_ipv6 ipv6; 826 struct rte_flow_item_ipv6 ipv6_mask; 827 struct field_modify_info *field; 828 829 if (!attr->valid) 830 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 831 if (attr->ipv4) { 832 memset(&ipv4, 0, sizeof(ipv4)); 833 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 834 ipv4.hdr.time_to_live = conf->ttl_value; 835 ipv4_mask.hdr.time_to_live = 0xFF; 836 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 837 item.spec = &ipv4; 838 item.mask = &ipv4_mask; 839 field = modify_ipv4; 840 } else { 841 MLX5_ASSERT(attr->ipv6); 842 memset(&ipv6, 0, sizeof(ipv6)); 843 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 844 ipv6.hdr.hop_limits = conf->ttl_value; 845 ipv6_mask.hdr.hop_limits = 0xFF; 846 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 847 item.spec = &ipv6; 848 item.mask = &ipv6_mask; 849 field = modify_ipv6; 850 } 851 return flow_dv_convert_modify_action(&item, field, NULL, resource, 852 MLX5_MODIFICATION_TYPE_SET, error); 853 } 854 855 /** 856 * Convert modify-header decrement TTL action to DV specification. 857 * 858 * @param[in,out] resource 859 * Pointer to the modify-header resource. 860 * @param[in] action 861 * Pointer to action specification. 862 * @param[in] items 863 * Pointer to rte_flow_item objects list. 864 * @param[in] attr 865 * Pointer to flow attributes structure. 866 * @param[in] dev_flow 867 * Pointer to the sub flow. 868 * @param[in] tunnel_decap 869 * Whether action is after tunnel decapsulation. 870 * @param[out] error 871 * Pointer to the error structure. 872 * 873 * @return 874 * 0 on success, a negative errno value otherwise and rte_errno is set. 875 */ 876 static int 877 flow_dv_convert_action_modify_dec_ttl 878 (struct mlx5_flow_dv_modify_hdr_resource *resource, 879 const struct rte_flow_item *items, 880 union flow_dv_attr *attr, struct mlx5_flow *dev_flow, 881 bool tunnel_decap, struct rte_flow_error *error) 882 { 883 struct rte_flow_item item; 884 struct rte_flow_item_ipv4 ipv4; 885 struct rte_flow_item_ipv4 ipv4_mask; 886 struct rte_flow_item_ipv6 ipv6; 887 struct rte_flow_item_ipv6 ipv6_mask; 888 struct field_modify_info *field; 889 890 if (!attr->valid) 891 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap); 892 if (attr->ipv4) { 893 memset(&ipv4, 0, sizeof(ipv4)); 894 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 895 ipv4.hdr.time_to_live = 0xFF; 896 ipv4_mask.hdr.time_to_live = 0xFF; 897 item.type = RTE_FLOW_ITEM_TYPE_IPV4; 898 item.spec = &ipv4; 899 item.mask = &ipv4_mask; 900 field = modify_ipv4; 901 } else { 902 MLX5_ASSERT(attr->ipv6); 903 memset(&ipv6, 0, sizeof(ipv6)); 904 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 905 ipv6.hdr.hop_limits = 0xFF; 906 ipv6_mask.hdr.hop_limits = 0xFF; 907 item.type = RTE_FLOW_ITEM_TYPE_IPV6; 908 item.spec = &ipv6; 909 item.mask = &ipv6_mask; 910 field = modify_ipv6; 911 } 912 return flow_dv_convert_modify_action(&item, field, NULL, resource, 913 MLX5_MODIFICATION_TYPE_ADD, error); 914 } 915 916 /** 917 * Convert modify-header increment/decrement TCP Sequence number 918 * to DV specification. 919 * 920 * @param[in,out] resource 921 * Pointer to the modify-header resource. 922 * @param[in] action 923 * Pointer to action specification. 924 * @param[out] error 925 * Pointer to the error structure. 926 * 927 * @return 928 * 0 on success, a negative errno value otherwise and rte_errno is set. 929 */ 930 static int 931 flow_dv_convert_action_modify_tcp_seq 932 (struct mlx5_flow_dv_modify_hdr_resource *resource, 933 const struct rte_flow_action *action, 934 struct rte_flow_error *error) 935 { 936 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 937 uint64_t value = rte_be_to_cpu_32(*conf); 938 struct rte_flow_item item; 939 struct rte_flow_item_tcp tcp; 940 struct rte_flow_item_tcp tcp_mask; 941 942 memset(&tcp, 0, sizeof(tcp)); 943 memset(&tcp_mask, 0, sizeof(tcp_mask)); 944 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ) 945 /* 946 * The HW has no decrement operation, only increment operation. 947 * To simulate decrement X from Y using increment operation 948 * we need to add UINT32_MAX X times to Y. 949 * Each adding of UINT32_MAX decrements Y by 1. 950 */ 951 value *= UINT32_MAX; 952 tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value); 953 tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX); 954 item.type = RTE_FLOW_ITEM_TYPE_TCP; 955 item.spec = &tcp; 956 item.mask = &tcp_mask; 957 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 958 MLX5_MODIFICATION_TYPE_ADD, error); 959 } 960 961 /** 962 * Convert modify-header increment/decrement TCP Acknowledgment number 963 * to DV specification. 964 * 965 * @param[in,out] resource 966 * Pointer to the modify-header resource. 967 * @param[in] action 968 * Pointer to action specification. 969 * @param[out] error 970 * Pointer to the error structure. 971 * 972 * @return 973 * 0 on success, a negative errno value otherwise and rte_errno is set. 974 */ 975 static int 976 flow_dv_convert_action_modify_tcp_ack 977 (struct mlx5_flow_dv_modify_hdr_resource *resource, 978 const struct rte_flow_action *action, 979 struct rte_flow_error *error) 980 { 981 const rte_be32_t *conf = (const rte_be32_t *)(action->conf); 982 uint64_t value = rte_be_to_cpu_32(*conf); 983 struct rte_flow_item item; 984 struct rte_flow_item_tcp tcp; 985 struct rte_flow_item_tcp tcp_mask; 986 987 memset(&tcp, 0, sizeof(tcp)); 988 memset(&tcp_mask, 0, sizeof(tcp_mask)); 989 if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK) 990 /* 991 * The HW has no decrement operation, only increment operation. 992 * To simulate decrement X from Y using increment operation 993 * we need to add UINT32_MAX X times to Y. 994 * Each adding of UINT32_MAX decrements Y by 1. 995 */ 996 value *= UINT32_MAX; 997 tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value); 998 tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX); 999 item.type = RTE_FLOW_ITEM_TYPE_TCP; 1000 item.spec = &tcp; 1001 item.mask = &tcp_mask; 1002 return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, 1003 MLX5_MODIFICATION_TYPE_ADD, error); 1004 } 1005 1006 static enum mlx5_modification_field reg_to_field[] = { 1007 [REG_NON] = MLX5_MODI_OUT_NONE, 1008 [REG_A] = MLX5_MODI_META_DATA_REG_A, 1009 [REG_B] = MLX5_MODI_META_DATA_REG_B, 1010 [REG_C_0] = MLX5_MODI_META_REG_C_0, 1011 [REG_C_1] = MLX5_MODI_META_REG_C_1, 1012 [REG_C_2] = MLX5_MODI_META_REG_C_2, 1013 [REG_C_3] = MLX5_MODI_META_REG_C_3, 1014 [REG_C_4] = MLX5_MODI_META_REG_C_4, 1015 [REG_C_5] = MLX5_MODI_META_REG_C_5, 1016 [REG_C_6] = MLX5_MODI_META_REG_C_6, 1017 [REG_C_7] = MLX5_MODI_META_REG_C_7, 1018 }; 1019 1020 /** 1021 * Convert register set to DV specification. 1022 * 1023 * @param[in,out] resource 1024 * Pointer to the modify-header resource. 1025 * @param[in] action 1026 * Pointer to action specification. 1027 * @param[out] error 1028 * Pointer to the error structure. 1029 * 1030 * @return 1031 * 0 on success, a negative errno value otherwise and rte_errno is set. 1032 */ 1033 static int 1034 flow_dv_convert_action_set_reg 1035 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1036 const struct rte_flow_action *action, 1037 struct rte_flow_error *error) 1038 { 1039 const struct mlx5_rte_flow_action_set_tag *conf = action->conf; 1040 struct mlx5_modification_cmd *actions = resource->actions; 1041 uint32_t i = resource->actions_num; 1042 1043 if (i >= MLX5_MAX_MODIFY_NUM) 1044 return rte_flow_error_set(error, EINVAL, 1045 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 1046 "too many items to modify"); 1047 MLX5_ASSERT(conf->id != REG_NON); 1048 MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field)); 1049 actions[i] = (struct mlx5_modification_cmd) { 1050 .action_type = MLX5_MODIFICATION_TYPE_SET, 1051 .field = reg_to_field[conf->id], 1052 .offset = conf->offset, 1053 .length = conf->length, 1054 }; 1055 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); 1056 actions[i].data1 = rte_cpu_to_be_32(conf->data); 1057 ++i; 1058 resource->actions_num = i; 1059 return 0; 1060 } 1061 1062 /** 1063 * Convert SET_TAG action to DV specification. 1064 * 1065 * @param[in] dev 1066 * Pointer to the rte_eth_dev structure. 1067 * @param[in,out] resource 1068 * Pointer to the modify-header resource. 1069 * @param[in] conf 1070 * Pointer to action specification. 1071 * @param[out] error 1072 * Pointer to the error structure. 1073 * 1074 * @return 1075 * 0 on success, a negative errno value otherwise and rte_errno is set. 1076 */ 1077 static int 1078 flow_dv_convert_action_set_tag 1079 (struct rte_eth_dev *dev, 1080 struct mlx5_flow_dv_modify_hdr_resource *resource, 1081 const struct rte_flow_action_set_tag *conf, 1082 struct rte_flow_error *error) 1083 { 1084 rte_be32_t data = rte_cpu_to_be_32(conf->data); 1085 rte_be32_t mask = rte_cpu_to_be_32(conf->mask); 1086 struct rte_flow_item item = { 1087 .spec = &data, 1088 .mask = &mask, 1089 }; 1090 struct field_modify_info reg_c_x[] = { 1091 [1] = {0, 0, 0}, 1092 }; 1093 enum mlx5_modification_field reg_type; 1094 int ret; 1095 1096 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 1097 if (ret < 0) 1098 return ret; 1099 MLX5_ASSERT(ret != REG_NON); 1100 MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field)); 1101 reg_type = reg_to_field[ret]; 1102 MLX5_ASSERT(reg_type > 0); 1103 reg_c_x[0] = (struct field_modify_info){4, 0, reg_type}; 1104 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1105 MLX5_MODIFICATION_TYPE_SET, error); 1106 } 1107 1108 /** 1109 * Convert internal COPY_REG action to DV specification. 1110 * 1111 * @param[in] dev 1112 * Pointer to the rte_eth_dev structure. 1113 * @param[in,out] res 1114 * Pointer to the modify-header resource. 1115 * @param[in] action 1116 * Pointer to action specification. 1117 * @param[out] error 1118 * Pointer to the error structure. 1119 * 1120 * @return 1121 * 0 on success, a negative errno value otherwise and rte_errno is set. 1122 */ 1123 static int 1124 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev, 1125 struct mlx5_flow_dv_modify_hdr_resource *res, 1126 const struct rte_flow_action *action, 1127 struct rte_flow_error *error) 1128 { 1129 const struct mlx5_flow_action_copy_mreg *conf = action->conf; 1130 rte_be32_t mask = RTE_BE32(UINT32_MAX); 1131 struct rte_flow_item item = { 1132 .spec = NULL, 1133 .mask = &mask, 1134 }; 1135 struct field_modify_info reg_src[] = { 1136 {4, 0, reg_to_field[conf->src]}, 1137 {0, 0, 0}, 1138 }; 1139 struct field_modify_info reg_dst = { 1140 .offset = 0, 1141 .id = reg_to_field[conf->dst], 1142 }; 1143 /* Adjust reg_c[0] usage according to reported mask. */ 1144 if (conf->dst == REG_C_0 || conf->src == REG_C_0) { 1145 struct mlx5_priv *priv = dev->data->dev_private; 1146 uint32_t reg_c0 = priv->sh->dv_regc0_mask; 1147 1148 MLX5_ASSERT(reg_c0); 1149 MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY); 1150 if (conf->dst == REG_C_0) { 1151 /* Copy to reg_c[0], within mask only. */ 1152 reg_dst.offset = rte_bsf32(reg_c0); 1153 mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset); 1154 } else { 1155 reg_dst.offset = 0; 1156 mask = rte_cpu_to_be_32(reg_c0); 1157 } 1158 } 1159 return flow_dv_convert_modify_action(&item, 1160 reg_src, ®_dst, res, 1161 MLX5_MODIFICATION_TYPE_COPY, 1162 error); 1163 } 1164 1165 /** 1166 * Convert MARK action to DV specification. This routine is used 1167 * in extensive metadata only and requires metadata register to be 1168 * handled. In legacy mode hardware tag resource is engaged. 1169 * 1170 * @param[in] dev 1171 * Pointer to the rte_eth_dev structure. 1172 * @param[in] conf 1173 * Pointer to MARK action specification. 1174 * @param[in,out] resource 1175 * Pointer to the modify-header resource. 1176 * @param[out] error 1177 * Pointer to the error structure. 1178 * 1179 * @return 1180 * 0 on success, a negative errno value otherwise and rte_errno is set. 1181 */ 1182 static int 1183 flow_dv_convert_action_mark(struct rte_eth_dev *dev, 1184 const struct rte_flow_action_mark *conf, 1185 struct mlx5_flow_dv_modify_hdr_resource *resource, 1186 struct rte_flow_error *error) 1187 { 1188 struct mlx5_priv *priv = dev->data->dev_private; 1189 rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK & 1190 priv->sh->dv_mark_mask); 1191 rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask; 1192 struct rte_flow_item item = { 1193 .spec = &data, 1194 .mask = &mask, 1195 }; 1196 struct field_modify_info reg_c_x[] = { 1197 [1] = {0, 0, 0}, 1198 }; 1199 int reg; 1200 1201 if (!mask) 1202 return rte_flow_error_set(error, EINVAL, 1203 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1204 NULL, "zero mark action mask"); 1205 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1206 if (reg < 0) 1207 return reg; 1208 MLX5_ASSERT(reg > 0); 1209 if (reg == REG_C_0) { 1210 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1211 uint32_t shl_c0 = rte_bsf32(msk_c0); 1212 1213 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1214 mask = rte_cpu_to_be_32(mask) & msk_c0; 1215 mask = rte_cpu_to_be_32(mask << shl_c0); 1216 } 1217 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1218 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1219 MLX5_MODIFICATION_TYPE_SET, error); 1220 } 1221 1222 /** 1223 * Get metadata register index for specified steering domain. 1224 * 1225 * @param[in] dev 1226 * Pointer to the rte_eth_dev structure. 1227 * @param[in] attr 1228 * Attributes of flow to determine steering domain. 1229 * @param[out] error 1230 * Pointer to the error structure. 1231 * 1232 * @return 1233 * positive index on success, a negative errno value otherwise 1234 * and rte_errno is set. 1235 */ 1236 static enum modify_reg 1237 flow_dv_get_metadata_reg(struct rte_eth_dev *dev, 1238 const struct rte_flow_attr *attr, 1239 struct rte_flow_error *error) 1240 { 1241 int reg = 1242 mlx5_flow_get_reg_id(dev, attr->transfer ? 1243 MLX5_METADATA_FDB : 1244 attr->egress ? 1245 MLX5_METADATA_TX : 1246 MLX5_METADATA_RX, 0, error); 1247 if (reg < 0) 1248 return rte_flow_error_set(error, 1249 ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, 1250 NULL, "unavailable " 1251 "metadata register"); 1252 return reg; 1253 } 1254 1255 /** 1256 * Convert SET_META action to DV specification. 1257 * 1258 * @param[in] dev 1259 * Pointer to the rte_eth_dev structure. 1260 * @param[in,out] resource 1261 * Pointer to the modify-header resource. 1262 * @param[in] attr 1263 * Attributes of flow that includes this item. 1264 * @param[in] conf 1265 * Pointer to action specification. 1266 * @param[out] error 1267 * Pointer to the error structure. 1268 * 1269 * @return 1270 * 0 on success, a negative errno value otherwise and rte_errno is set. 1271 */ 1272 static int 1273 flow_dv_convert_action_set_meta 1274 (struct rte_eth_dev *dev, 1275 struct mlx5_flow_dv_modify_hdr_resource *resource, 1276 const struct rte_flow_attr *attr, 1277 const struct rte_flow_action_set_meta *conf, 1278 struct rte_flow_error *error) 1279 { 1280 uint32_t mask = rte_cpu_to_be_32(conf->mask); 1281 uint32_t data = rte_cpu_to_be_32(conf->data) & mask; 1282 struct rte_flow_item item = { 1283 .spec = &data, 1284 .mask = &mask, 1285 }; 1286 struct field_modify_info reg_c_x[] = { 1287 [1] = {0, 0, 0}, 1288 }; 1289 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1290 1291 if (reg < 0) 1292 return reg; 1293 MLX5_ASSERT(reg != REG_NON); 1294 if (reg == REG_C_0) { 1295 struct mlx5_priv *priv = dev->data->dev_private; 1296 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 1297 uint32_t shl_c0 = rte_bsf32(msk_c0); 1298 1299 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0); 1300 mask = rte_cpu_to_be_32(mask) & msk_c0; 1301 mask = rte_cpu_to_be_32(mask << shl_c0); 1302 } 1303 reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]}; 1304 /* The routine expects parameters in memory as big-endian ones. */ 1305 return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource, 1306 MLX5_MODIFICATION_TYPE_SET, error); 1307 } 1308 1309 /** 1310 * Convert modify-header set IPv4 DSCP action to DV specification. 1311 * 1312 * @param[in,out] resource 1313 * Pointer to the modify-header resource. 1314 * @param[in] action 1315 * Pointer to action specification. 1316 * @param[out] error 1317 * Pointer to the error structure. 1318 * 1319 * @return 1320 * 0 on success, a negative errno value otherwise and rte_errno is set. 1321 */ 1322 static int 1323 flow_dv_convert_action_modify_ipv4_dscp 1324 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1325 const struct rte_flow_action *action, 1326 struct rte_flow_error *error) 1327 { 1328 const struct rte_flow_action_set_dscp *conf = 1329 (const struct rte_flow_action_set_dscp *)(action->conf); 1330 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 }; 1331 struct rte_flow_item_ipv4 ipv4; 1332 struct rte_flow_item_ipv4 ipv4_mask; 1333 1334 memset(&ipv4, 0, sizeof(ipv4)); 1335 memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 1336 ipv4.hdr.type_of_service = conf->dscp; 1337 ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2; 1338 item.spec = &ipv4; 1339 item.mask = &ipv4_mask; 1340 return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, 1341 MLX5_MODIFICATION_TYPE_SET, error); 1342 } 1343 1344 /** 1345 * Convert modify-header set IPv6 DSCP action to DV specification. 1346 * 1347 * @param[in,out] resource 1348 * Pointer to the modify-header resource. 1349 * @param[in] action 1350 * Pointer to action specification. 1351 * @param[out] error 1352 * Pointer to the error structure. 1353 * 1354 * @return 1355 * 0 on success, a negative errno value otherwise and rte_errno is set. 1356 */ 1357 static int 1358 flow_dv_convert_action_modify_ipv6_dscp 1359 (struct mlx5_flow_dv_modify_hdr_resource *resource, 1360 const struct rte_flow_action *action, 1361 struct rte_flow_error *error) 1362 { 1363 const struct rte_flow_action_set_dscp *conf = 1364 (const struct rte_flow_action_set_dscp *)(action->conf); 1365 struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 }; 1366 struct rte_flow_item_ipv6 ipv6; 1367 struct rte_flow_item_ipv6 ipv6_mask; 1368 1369 memset(&ipv6, 0, sizeof(ipv6)); 1370 memset(&ipv6_mask, 0, sizeof(ipv6_mask)); 1371 /* 1372 * Even though the DSCP bits offset of IPv6 is not byte aligned, 1373 * rdma-core only accept the DSCP bits byte aligned start from 1374 * bit 0 to 5 as to be compatible with IPv4. No need to shift the 1375 * bits in IPv6 case as rdma-core requires byte aligned value. 1376 */ 1377 ipv6.hdr.vtc_flow = conf->dscp; 1378 ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22; 1379 item.spec = &ipv6; 1380 item.mask = &ipv6_mask; 1381 return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, 1382 MLX5_MODIFICATION_TYPE_SET, error); 1383 } 1384 1385 static int 1386 mlx5_flow_item_field_width(struct rte_eth_dev *dev, 1387 enum rte_flow_field_id field, int inherit, 1388 const struct rte_flow_attr *attr, 1389 struct rte_flow_error *error) 1390 { 1391 struct mlx5_priv *priv = dev->data->dev_private; 1392 1393 switch (field) { 1394 case RTE_FLOW_FIELD_START: 1395 return 32; 1396 case RTE_FLOW_FIELD_MAC_DST: 1397 case RTE_FLOW_FIELD_MAC_SRC: 1398 return 48; 1399 case RTE_FLOW_FIELD_VLAN_TYPE: 1400 return 16; 1401 case RTE_FLOW_FIELD_VLAN_ID: 1402 return 12; 1403 case RTE_FLOW_FIELD_MAC_TYPE: 1404 return 16; 1405 case RTE_FLOW_FIELD_IPV4_DSCP: 1406 return 6; 1407 case RTE_FLOW_FIELD_IPV4_TTL: 1408 return 8; 1409 case RTE_FLOW_FIELD_IPV4_SRC: 1410 case RTE_FLOW_FIELD_IPV4_DST: 1411 return 32; 1412 case RTE_FLOW_FIELD_IPV6_DSCP: 1413 return 6; 1414 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1415 return 8; 1416 case RTE_FLOW_FIELD_IPV6_SRC: 1417 case RTE_FLOW_FIELD_IPV6_DST: 1418 return 128; 1419 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1420 case RTE_FLOW_FIELD_TCP_PORT_DST: 1421 return 16; 1422 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1423 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1424 return 32; 1425 case RTE_FLOW_FIELD_TCP_FLAGS: 1426 return 9; 1427 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1428 case RTE_FLOW_FIELD_UDP_PORT_DST: 1429 return 16; 1430 case RTE_FLOW_FIELD_VXLAN_VNI: 1431 case RTE_FLOW_FIELD_GENEVE_VNI: 1432 return 24; 1433 case RTE_FLOW_FIELD_GTP_TEID: 1434 case RTE_FLOW_FIELD_TAG: 1435 return 32; 1436 case RTE_FLOW_FIELD_MARK: 1437 return __builtin_popcount(priv->sh->dv_mark_mask); 1438 case RTE_FLOW_FIELD_META: 1439 return (flow_dv_get_metadata_reg(dev, attr, error) == REG_C_0) ? 1440 __builtin_popcount(priv->sh->dv_meta_mask) : 32; 1441 case RTE_FLOW_FIELD_POINTER: 1442 case RTE_FLOW_FIELD_VALUE: 1443 return inherit < 0 ? 0 : inherit; 1444 default: 1445 MLX5_ASSERT(false); 1446 } 1447 return 0; 1448 } 1449 1450 static void 1451 mlx5_flow_field_id_to_modify_info 1452 (const struct rte_flow_action_modify_data *data, 1453 struct field_modify_info *info, uint32_t *mask, 1454 uint32_t width, uint32_t *shift, struct rte_eth_dev *dev, 1455 const struct rte_flow_attr *attr, struct rte_flow_error *error) 1456 { 1457 struct mlx5_priv *priv = dev->data->dev_private; 1458 uint32_t idx = 0; 1459 uint32_t off = 0; 1460 1461 switch (data->field) { 1462 case RTE_FLOW_FIELD_START: 1463 /* not supported yet */ 1464 MLX5_ASSERT(false); 1465 break; 1466 case RTE_FLOW_FIELD_MAC_DST: 1467 off = data->offset > 16 ? data->offset - 16 : 0; 1468 if (mask) { 1469 if (data->offset < 16) { 1470 info[idx] = (struct field_modify_info){2, 4, 1471 MLX5_MODI_OUT_DMAC_15_0}; 1472 if (width < 16) { 1473 mask[1] = rte_cpu_to_be_16(0xffff >> 1474 (16 - width)); 1475 width = 0; 1476 } else { 1477 mask[1] = RTE_BE16(0xffff); 1478 width -= 16; 1479 } 1480 if (!width) 1481 break; 1482 ++idx; 1483 } 1484 info[idx] = (struct field_modify_info){4, 0, 1485 MLX5_MODI_OUT_DMAC_47_16}; 1486 mask[0] = rte_cpu_to_be_32((0xffffffff >> 1487 (32 - width)) << off); 1488 } else { 1489 if (data->offset < 16) 1490 info[idx++] = (struct field_modify_info){2, 4, 1491 MLX5_MODI_OUT_DMAC_15_0}; 1492 info[idx] = (struct field_modify_info){4, 0, 1493 MLX5_MODI_OUT_DMAC_47_16}; 1494 } 1495 break; 1496 case RTE_FLOW_FIELD_MAC_SRC: 1497 off = data->offset > 16 ? data->offset - 16 : 0; 1498 if (mask) { 1499 if (data->offset < 16) { 1500 info[idx] = (struct field_modify_info){2, 4, 1501 MLX5_MODI_OUT_SMAC_15_0}; 1502 if (width < 16) { 1503 mask[1] = rte_cpu_to_be_16(0xffff >> 1504 (16 - width)); 1505 width = 0; 1506 } else { 1507 mask[1] = RTE_BE16(0xffff); 1508 width -= 16; 1509 } 1510 if (!width) 1511 break; 1512 ++idx; 1513 } 1514 info[idx] = (struct field_modify_info){4, 0, 1515 MLX5_MODI_OUT_SMAC_47_16}; 1516 mask[0] = rte_cpu_to_be_32((0xffffffff >> 1517 (32 - width)) << off); 1518 } else { 1519 if (data->offset < 16) 1520 info[idx++] = (struct field_modify_info){2, 4, 1521 MLX5_MODI_OUT_SMAC_15_0}; 1522 info[idx] = (struct field_modify_info){4, 0, 1523 MLX5_MODI_OUT_SMAC_47_16}; 1524 } 1525 break; 1526 case RTE_FLOW_FIELD_VLAN_TYPE: 1527 /* not supported yet */ 1528 break; 1529 case RTE_FLOW_FIELD_VLAN_ID: 1530 info[idx] = (struct field_modify_info){2, 0, 1531 MLX5_MODI_OUT_FIRST_VID}; 1532 if (mask) 1533 mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width)); 1534 break; 1535 case RTE_FLOW_FIELD_MAC_TYPE: 1536 info[idx] = (struct field_modify_info){2, 0, 1537 MLX5_MODI_OUT_ETHERTYPE}; 1538 if (mask) 1539 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1540 break; 1541 case RTE_FLOW_FIELD_IPV4_DSCP: 1542 info[idx] = (struct field_modify_info){1, 0, 1543 MLX5_MODI_OUT_IP_DSCP}; 1544 if (mask) 1545 mask[idx] = 0x3f >> (6 - width); 1546 break; 1547 case RTE_FLOW_FIELD_IPV4_TTL: 1548 info[idx] = (struct field_modify_info){1, 0, 1549 MLX5_MODI_OUT_IPV4_TTL}; 1550 if (mask) 1551 mask[idx] = 0xff >> (8 - width); 1552 break; 1553 case RTE_FLOW_FIELD_IPV4_SRC: 1554 info[idx] = (struct field_modify_info){4, 0, 1555 MLX5_MODI_OUT_SIPV4}; 1556 if (mask) 1557 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1558 (32 - width)); 1559 break; 1560 case RTE_FLOW_FIELD_IPV4_DST: 1561 info[idx] = (struct field_modify_info){4, 0, 1562 MLX5_MODI_OUT_DIPV4}; 1563 if (mask) 1564 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1565 (32 - width)); 1566 break; 1567 case RTE_FLOW_FIELD_IPV6_DSCP: 1568 info[idx] = (struct field_modify_info){1, 0, 1569 MLX5_MODI_OUT_IP_DSCP}; 1570 if (mask) 1571 mask[idx] = 0x3f >> (6 - width); 1572 break; 1573 case RTE_FLOW_FIELD_IPV6_HOPLIMIT: 1574 info[idx] = (struct field_modify_info){1, 0, 1575 MLX5_MODI_OUT_IPV6_HOPLIMIT}; 1576 if (mask) 1577 mask[idx] = 0xff >> (8 - width); 1578 break; 1579 case RTE_FLOW_FIELD_IPV6_SRC: 1580 if (mask) { 1581 if (data->offset < 32) { 1582 info[idx] = (struct field_modify_info){4, 12, 1583 MLX5_MODI_OUT_SIPV6_31_0}; 1584 if (width < 32) { 1585 mask[3] = 1586 rte_cpu_to_be_32(0xffffffff >> 1587 (32 - width)); 1588 width = 0; 1589 } else { 1590 mask[3] = RTE_BE32(0xffffffff); 1591 width -= 32; 1592 } 1593 if (!width) 1594 break; 1595 ++idx; 1596 } 1597 if (data->offset < 64) { 1598 info[idx] = (struct field_modify_info){4, 8, 1599 MLX5_MODI_OUT_SIPV6_63_32}; 1600 if (width < 32) { 1601 mask[2] = 1602 rte_cpu_to_be_32(0xffffffff >> 1603 (32 - width)); 1604 width = 0; 1605 } else { 1606 mask[2] = RTE_BE32(0xffffffff); 1607 width -= 32; 1608 } 1609 if (!width) 1610 break; 1611 ++idx; 1612 } 1613 if (data->offset < 96) { 1614 info[idx] = (struct field_modify_info){4, 4, 1615 MLX5_MODI_OUT_SIPV6_95_64}; 1616 if (width < 32) { 1617 mask[1] = 1618 rte_cpu_to_be_32(0xffffffff >> 1619 (32 - width)); 1620 width = 0; 1621 } else { 1622 mask[1] = RTE_BE32(0xffffffff); 1623 width -= 32; 1624 } 1625 if (!width) 1626 break; 1627 ++idx; 1628 } 1629 info[idx] = (struct field_modify_info){4, 0, 1630 MLX5_MODI_OUT_SIPV6_127_96}; 1631 mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); 1632 } else { 1633 if (data->offset < 32) 1634 info[idx++] = (struct field_modify_info){4, 12, 1635 MLX5_MODI_OUT_SIPV6_31_0}; 1636 if (data->offset < 64) 1637 info[idx++] = (struct field_modify_info){4, 8, 1638 MLX5_MODI_OUT_SIPV6_63_32}; 1639 if (data->offset < 96) 1640 info[idx++] = (struct field_modify_info){4, 4, 1641 MLX5_MODI_OUT_SIPV6_95_64}; 1642 if (data->offset < 128) 1643 info[idx++] = (struct field_modify_info){4, 0, 1644 MLX5_MODI_OUT_SIPV6_127_96}; 1645 } 1646 break; 1647 case RTE_FLOW_FIELD_IPV6_DST: 1648 if (mask) { 1649 if (data->offset < 32) { 1650 info[idx] = (struct field_modify_info){4, 12, 1651 MLX5_MODI_OUT_DIPV6_31_0}; 1652 if (width < 32) { 1653 mask[3] = 1654 rte_cpu_to_be_32(0xffffffff >> 1655 (32 - width)); 1656 width = 0; 1657 } else { 1658 mask[3] = RTE_BE32(0xffffffff); 1659 width -= 32; 1660 } 1661 if (!width) 1662 break; 1663 ++idx; 1664 } 1665 if (data->offset < 64) { 1666 info[idx] = (struct field_modify_info){4, 8, 1667 MLX5_MODI_OUT_DIPV6_63_32}; 1668 if (width < 32) { 1669 mask[2] = 1670 rte_cpu_to_be_32(0xffffffff >> 1671 (32 - width)); 1672 width = 0; 1673 } else { 1674 mask[2] = RTE_BE32(0xffffffff); 1675 width -= 32; 1676 } 1677 if (!width) 1678 break; 1679 ++idx; 1680 } 1681 if (data->offset < 96) { 1682 info[idx] = (struct field_modify_info){4, 4, 1683 MLX5_MODI_OUT_DIPV6_95_64}; 1684 if (width < 32) { 1685 mask[1] = 1686 rte_cpu_to_be_32(0xffffffff >> 1687 (32 - width)); 1688 width = 0; 1689 } else { 1690 mask[1] = RTE_BE32(0xffffffff); 1691 width -= 32; 1692 } 1693 if (!width) 1694 break; 1695 ++idx; 1696 } 1697 info[idx] = (struct field_modify_info){4, 0, 1698 MLX5_MODI_OUT_DIPV6_127_96}; 1699 mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); 1700 } else { 1701 if (data->offset < 32) 1702 info[idx++] = (struct field_modify_info){4, 12, 1703 MLX5_MODI_OUT_DIPV6_31_0}; 1704 if (data->offset < 64) 1705 info[idx++] = (struct field_modify_info){4, 8, 1706 MLX5_MODI_OUT_DIPV6_63_32}; 1707 if (data->offset < 96) 1708 info[idx++] = (struct field_modify_info){4, 4, 1709 MLX5_MODI_OUT_DIPV6_95_64}; 1710 if (data->offset < 128) 1711 info[idx++] = (struct field_modify_info){4, 0, 1712 MLX5_MODI_OUT_DIPV6_127_96}; 1713 } 1714 break; 1715 case RTE_FLOW_FIELD_TCP_PORT_SRC: 1716 info[idx] = (struct field_modify_info){2, 0, 1717 MLX5_MODI_OUT_TCP_SPORT}; 1718 if (mask) 1719 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1720 break; 1721 case RTE_FLOW_FIELD_TCP_PORT_DST: 1722 info[idx] = (struct field_modify_info){2, 0, 1723 MLX5_MODI_OUT_TCP_DPORT}; 1724 if (mask) 1725 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1726 break; 1727 case RTE_FLOW_FIELD_TCP_SEQ_NUM: 1728 info[idx] = (struct field_modify_info){4, 0, 1729 MLX5_MODI_OUT_TCP_SEQ_NUM}; 1730 if (mask) 1731 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1732 (32 - width)); 1733 break; 1734 case RTE_FLOW_FIELD_TCP_ACK_NUM: 1735 info[idx] = (struct field_modify_info){4, 0, 1736 MLX5_MODI_OUT_TCP_ACK_NUM}; 1737 if (mask) 1738 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1739 (32 - width)); 1740 break; 1741 case RTE_FLOW_FIELD_TCP_FLAGS: 1742 info[idx] = (struct field_modify_info){2, 0, 1743 MLX5_MODI_OUT_TCP_FLAGS}; 1744 if (mask) 1745 mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width)); 1746 break; 1747 case RTE_FLOW_FIELD_UDP_PORT_SRC: 1748 info[idx] = (struct field_modify_info){2, 0, 1749 MLX5_MODI_OUT_UDP_SPORT}; 1750 if (mask) 1751 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1752 break; 1753 case RTE_FLOW_FIELD_UDP_PORT_DST: 1754 info[idx] = (struct field_modify_info){2, 0, 1755 MLX5_MODI_OUT_UDP_DPORT}; 1756 if (mask) 1757 mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); 1758 break; 1759 case RTE_FLOW_FIELD_VXLAN_VNI: 1760 /* not supported yet */ 1761 break; 1762 case RTE_FLOW_FIELD_GENEVE_VNI: 1763 /* not supported yet*/ 1764 break; 1765 case RTE_FLOW_FIELD_GTP_TEID: 1766 info[idx] = (struct field_modify_info){4, 0, 1767 MLX5_MODI_GTP_TEID}; 1768 if (mask) 1769 mask[idx] = rte_cpu_to_be_32(0xffffffff >> 1770 (32 - width)); 1771 break; 1772 case RTE_FLOW_FIELD_TAG: 1773 { 1774 int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 1775 data->level, error); 1776 if (reg < 0) 1777 return; 1778 MLX5_ASSERT(reg != REG_NON); 1779 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1780 info[idx] = (struct field_modify_info){4, 0, 1781 reg_to_field[reg]}; 1782 if (mask) 1783 mask[idx] = 1784 rte_cpu_to_be_32(0xffffffff >> 1785 (32 - width)); 1786 } 1787 break; 1788 case RTE_FLOW_FIELD_MARK: 1789 { 1790 uint32_t mark_mask = priv->sh->dv_mark_mask; 1791 uint32_t mark_count = __builtin_popcount(mark_mask); 1792 int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 1793 0, error); 1794 if (reg < 0) 1795 return; 1796 MLX5_ASSERT(reg != REG_NON); 1797 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1798 info[idx] = (struct field_modify_info){4, 0, 1799 reg_to_field[reg]}; 1800 if (mask) 1801 mask[idx] = rte_cpu_to_be_32((mark_mask >> 1802 (mark_count - width)) & mark_mask); 1803 } 1804 break; 1805 case RTE_FLOW_FIELD_META: 1806 { 1807 uint32_t meta_mask = priv->sh->dv_meta_mask; 1808 uint32_t meta_count = __builtin_popcount(meta_mask); 1809 uint32_t msk_c0 = 1810 rte_cpu_to_be_32(priv->sh->dv_regc0_mask); 1811 uint32_t shl_c0 = rte_bsf32(msk_c0); 1812 int reg = flow_dv_get_metadata_reg(dev, attr, error); 1813 if (reg < 0) 1814 return; 1815 MLX5_ASSERT(reg != REG_NON); 1816 MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); 1817 if (reg == REG_C_0) 1818 *shift = shl_c0; 1819 info[idx] = (struct field_modify_info){4, 0, 1820 reg_to_field[reg]}; 1821 if (mask) 1822 mask[idx] = rte_cpu_to_be_32((meta_mask >> 1823 (meta_count - width)) & meta_mask); 1824 } 1825 break; 1826 case RTE_FLOW_FIELD_POINTER: 1827 case RTE_FLOW_FIELD_VALUE: 1828 default: 1829 MLX5_ASSERT(false); 1830 break; 1831 } 1832 } 1833 1834 /** 1835 * Convert modify_field action to DV specification. 1836 * 1837 * @param[in] dev 1838 * Pointer to the rte_eth_dev structure. 1839 * @param[in,out] resource 1840 * Pointer to the modify-header resource. 1841 * @param[in] action 1842 * Pointer to action specification. 1843 * @param[in] attr 1844 * Attributes of flow that includes this item. 1845 * @param[out] error 1846 * Pointer to the error structure. 1847 * 1848 * @return 1849 * 0 on success, a negative errno value otherwise and rte_errno is set. 1850 */ 1851 static int 1852 flow_dv_convert_action_modify_field 1853 (struct rte_eth_dev *dev, 1854 struct mlx5_flow_dv_modify_hdr_resource *resource, 1855 const struct rte_flow_action *action, 1856 const struct rte_flow_attr *attr, 1857 struct rte_flow_error *error) 1858 { 1859 const struct rte_flow_action_modify_field *conf = 1860 (const struct rte_flow_action_modify_field *)(action->conf); 1861 struct rte_flow_item item = { 1862 .spec = NULL, 1863 .mask = NULL 1864 }; 1865 struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = { 1866 {0, 0, 0} }; 1867 struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = { 1868 {0, 0, 0} }; 1869 uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0}; 1870 uint32_t type; 1871 uint32_t shift = 0; 1872 1873 if (conf->src.field == RTE_FLOW_FIELD_POINTER || 1874 conf->src.field == RTE_FLOW_FIELD_VALUE) { 1875 type = MLX5_MODIFICATION_TYPE_SET; 1876 /** For SET fill the destination field (field) first. */ 1877 mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, 1878 conf->width, &shift, dev, 1879 attr, error); 1880 item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? 1881 (void *)(uintptr_t)conf->src.pvalue : 1882 (void *)(uintptr_t)&conf->src.value; 1883 } else { 1884 type = MLX5_MODIFICATION_TYPE_COPY; 1885 /** For COPY fill the destination field (dcopy) without mask. */ 1886 mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL, 1887 conf->width, &shift, dev, 1888 attr, error); 1889 /** Then construct the source field (field) with mask. */ 1890 mlx5_flow_field_id_to_modify_info(&conf->src, field, mask, 1891 conf->width, &shift, 1892 dev, attr, error); 1893 } 1894 item.mask = &mask; 1895 return flow_dv_convert_modify_action(&item, 1896 field, dcopy, resource, type, error); 1897 } 1898 1899 /** 1900 * Validate MARK item. 1901 * 1902 * @param[in] dev 1903 * Pointer to the rte_eth_dev structure. 1904 * @param[in] item 1905 * Item specification. 1906 * @param[in] attr 1907 * Attributes of flow that includes this item. 1908 * @param[out] error 1909 * Pointer to error structure. 1910 * 1911 * @return 1912 * 0 on success, a negative errno value otherwise and rte_errno is set. 1913 */ 1914 static int 1915 flow_dv_validate_item_mark(struct rte_eth_dev *dev, 1916 const struct rte_flow_item *item, 1917 const struct rte_flow_attr *attr __rte_unused, 1918 struct rte_flow_error *error) 1919 { 1920 struct mlx5_priv *priv = dev->data->dev_private; 1921 struct mlx5_dev_config *config = &priv->config; 1922 const struct rte_flow_item_mark *spec = item->spec; 1923 const struct rte_flow_item_mark *mask = item->mask; 1924 const struct rte_flow_item_mark nic_mask = { 1925 .id = priv->sh->dv_mark_mask, 1926 }; 1927 int ret; 1928 1929 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 1930 return rte_flow_error_set(error, ENOTSUP, 1931 RTE_FLOW_ERROR_TYPE_ITEM, item, 1932 "extended metadata feature" 1933 " isn't enabled"); 1934 if (!mlx5_flow_ext_mreg_supported(dev)) 1935 return rte_flow_error_set(error, ENOTSUP, 1936 RTE_FLOW_ERROR_TYPE_ITEM, item, 1937 "extended metadata register" 1938 " isn't supported"); 1939 if (!nic_mask.id) 1940 return rte_flow_error_set(error, ENOTSUP, 1941 RTE_FLOW_ERROR_TYPE_ITEM, item, 1942 "extended metadata register" 1943 " isn't available"); 1944 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 1945 if (ret < 0) 1946 return ret; 1947 if (!spec) 1948 return rte_flow_error_set(error, EINVAL, 1949 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 1950 item->spec, 1951 "data cannot be empty"); 1952 if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id)) 1953 return rte_flow_error_set(error, EINVAL, 1954 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 1955 &spec->id, 1956 "mark id exceeds the limit"); 1957 if (!mask) 1958 mask = &nic_mask; 1959 if (!mask->id) 1960 return rte_flow_error_set(error, EINVAL, 1961 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 1962 "mask cannot be zero"); 1963 1964 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 1965 (const uint8_t *)&nic_mask, 1966 sizeof(struct rte_flow_item_mark), 1967 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 1968 if (ret < 0) 1969 return ret; 1970 return 0; 1971 } 1972 1973 /** 1974 * Validate META item. 1975 * 1976 * @param[in] dev 1977 * Pointer to the rte_eth_dev structure. 1978 * @param[in] item 1979 * Item specification. 1980 * @param[in] attr 1981 * Attributes of flow that includes this item. 1982 * @param[out] error 1983 * Pointer to error structure. 1984 * 1985 * @return 1986 * 0 on success, a negative errno value otherwise and rte_errno is set. 1987 */ 1988 static int 1989 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused, 1990 const struct rte_flow_item *item, 1991 const struct rte_flow_attr *attr, 1992 struct rte_flow_error *error) 1993 { 1994 struct mlx5_priv *priv = dev->data->dev_private; 1995 struct mlx5_dev_config *config = &priv->config; 1996 const struct rte_flow_item_meta *spec = item->spec; 1997 const struct rte_flow_item_meta *mask = item->mask; 1998 struct rte_flow_item_meta nic_mask = { 1999 .data = UINT32_MAX 2000 }; 2001 int reg; 2002 int ret; 2003 2004 if (!spec) 2005 return rte_flow_error_set(error, EINVAL, 2006 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2007 item->spec, 2008 "data cannot be empty"); 2009 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 2010 if (!mlx5_flow_ext_mreg_supported(dev)) 2011 return rte_flow_error_set(error, ENOTSUP, 2012 RTE_FLOW_ERROR_TYPE_ITEM, item, 2013 "extended metadata register" 2014 " isn't supported"); 2015 reg = flow_dv_get_metadata_reg(dev, attr, error); 2016 if (reg < 0) 2017 return reg; 2018 if (reg == REG_NON) 2019 return rte_flow_error_set(error, ENOTSUP, 2020 RTE_FLOW_ERROR_TYPE_ITEM, item, 2021 "unavalable extended metadata register"); 2022 if (reg == REG_B) 2023 return rte_flow_error_set(error, ENOTSUP, 2024 RTE_FLOW_ERROR_TYPE_ITEM, item, 2025 "match on reg_b " 2026 "isn't supported"); 2027 if (reg != REG_A) 2028 nic_mask.data = priv->sh->dv_meta_mask; 2029 } else { 2030 if (attr->transfer) 2031 return rte_flow_error_set(error, ENOTSUP, 2032 RTE_FLOW_ERROR_TYPE_ITEM, item, 2033 "extended metadata feature " 2034 "should be enabled when " 2035 "meta item is requested " 2036 "with e-switch mode "); 2037 if (attr->ingress) 2038 return rte_flow_error_set(error, ENOTSUP, 2039 RTE_FLOW_ERROR_TYPE_ITEM, item, 2040 "match on metadata for ingress " 2041 "is not supported in legacy " 2042 "metadata mode"); 2043 } 2044 if (!mask) 2045 mask = &rte_flow_item_meta_mask; 2046 if (!mask->data) 2047 return rte_flow_error_set(error, EINVAL, 2048 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2049 "mask cannot be zero"); 2050 2051 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2052 (const uint8_t *)&nic_mask, 2053 sizeof(struct rte_flow_item_meta), 2054 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2055 return ret; 2056 } 2057 2058 /** 2059 * Validate TAG item. 2060 * 2061 * @param[in] dev 2062 * Pointer to the rte_eth_dev structure. 2063 * @param[in] item 2064 * Item specification. 2065 * @param[in] attr 2066 * Attributes of flow that includes this item. 2067 * @param[out] error 2068 * Pointer to error structure. 2069 * 2070 * @return 2071 * 0 on success, a negative errno value otherwise and rte_errno is set. 2072 */ 2073 static int 2074 flow_dv_validate_item_tag(struct rte_eth_dev *dev, 2075 const struct rte_flow_item *item, 2076 const struct rte_flow_attr *attr __rte_unused, 2077 struct rte_flow_error *error) 2078 { 2079 const struct rte_flow_item_tag *spec = item->spec; 2080 const struct rte_flow_item_tag *mask = item->mask; 2081 const struct rte_flow_item_tag nic_mask = { 2082 .data = RTE_BE32(UINT32_MAX), 2083 .index = 0xff, 2084 }; 2085 int ret; 2086 2087 if (!mlx5_flow_ext_mreg_supported(dev)) 2088 return rte_flow_error_set(error, ENOTSUP, 2089 RTE_FLOW_ERROR_TYPE_ITEM, item, 2090 "extensive metadata register" 2091 " isn't supported"); 2092 if (!spec) 2093 return rte_flow_error_set(error, EINVAL, 2094 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 2095 item->spec, 2096 "data cannot be empty"); 2097 if (!mask) 2098 mask = &rte_flow_item_tag_mask; 2099 if (!mask->data) 2100 return rte_flow_error_set(error, EINVAL, 2101 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2102 "mask cannot be zero"); 2103 2104 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2105 (const uint8_t *)&nic_mask, 2106 sizeof(struct rte_flow_item_tag), 2107 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2108 if (ret < 0) 2109 return ret; 2110 if (mask->index != 0xff) 2111 return rte_flow_error_set(error, EINVAL, 2112 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, 2113 "partial mask for tag index" 2114 " is not supported"); 2115 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error); 2116 if (ret < 0) 2117 return ret; 2118 MLX5_ASSERT(ret != REG_NON); 2119 return 0; 2120 } 2121 2122 /** 2123 * Validate vport item. 2124 * 2125 * @param[in] dev 2126 * Pointer to the rte_eth_dev structure. 2127 * @param[in] item 2128 * Item specification. 2129 * @param[in] attr 2130 * Attributes of flow that includes this item. 2131 * @param[in] item_flags 2132 * Bit-fields that holds the items detected until now. 2133 * @param[out] error 2134 * Pointer to error structure. 2135 * 2136 * @return 2137 * 0 on success, a negative errno value otherwise and rte_errno is set. 2138 */ 2139 static int 2140 flow_dv_validate_item_port_id(struct rte_eth_dev *dev, 2141 const struct rte_flow_item *item, 2142 const struct rte_flow_attr *attr, 2143 uint64_t item_flags, 2144 struct rte_flow_error *error) 2145 { 2146 const struct rte_flow_item_port_id *spec = item->spec; 2147 const struct rte_flow_item_port_id *mask = item->mask; 2148 const struct rte_flow_item_port_id switch_mask = { 2149 .id = 0xffffffff, 2150 }; 2151 struct mlx5_priv *esw_priv; 2152 struct mlx5_priv *dev_priv; 2153 int ret; 2154 2155 if (!attr->transfer) 2156 return rte_flow_error_set(error, EINVAL, 2157 RTE_FLOW_ERROR_TYPE_ITEM, 2158 NULL, 2159 "match on port id is valid only" 2160 " when transfer flag is enabled"); 2161 if (item_flags & MLX5_FLOW_ITEM_PORT_ID) 2162 return rte_flow_error_set(error, ENOTSUP, 2163 RTE_FLOW_ERROR_TYPE_ITEM, item, 2164 "multiple source ports are not" 2165 " supported"); 2166 if (!mask) 2167 mask = &switch_mask; 2168 if (mask->id != 0xffffffff) 2169 return rte_flow_error_set(error, ENOTSUP, 2170 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2171 mask, 2172 "no support for partial mask on" 2173 " \"id\" field"); 2174 ret = mlx5_flow_item_acceptable 2175 (item, (const uint8_t *)mask, 2176 (const uint8_t *)&rte_flow_item_port_id_mask, 2177 sizeof(struct rte_flow_item_port_id), 2178 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2179 if (ret) 2180 return ret; 2181 if (!spec) 2182 return 0; 2183 if (spec->id == MLX5_PORT_ESW_MGR) 2184 return 0; 2185 esw_priv = mlx5_port_to_eswitch_info(spec->id, false); 2186 if (!esw_priv) 2187 return rte_flow_error_set(error, rte_errno, 2188 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2189 "failed to obtain E-Switch info for" 2190 " port"); 2191 dev_priv = mlx5_dev_to_eswitch_info(dev); 2192 if (!dev_priv) 2193 return rte_flow_error_set(error, rte_errno, 2194 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2195 NULL, 2196 "failed to obtain E-Switch info"); 2197 if (esw_priv->domain_id != dev_priv->domain_id) 2198 return rte_flow_error_set(error, EINVAL, 2199 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec, 2200 "cannot match on a port from a" 2201 " different E-Switch"); 2202 return 0; 2203 } 2204 2205 /** 2206 * Validate VLAN item. 2207 * 2208 * @param[in] item 2209 * Item specification. 2210 * @param[in] item_flags 2211 * Bit-fields that holds the items detected until now. 2212 * @param[in] dev 2213 * Ethernet device flow is being created on. 2214 * @param[out] error 2215 * Pointer to error structure. 2216 * 2217 * @return 2218 * 0 on success, a negative errno value otherwise and rte_errno is set. 2219 */ 2220 static int 2221 flow_dv_validate_item_vlan(const struct rte_flow_item *item, 2222 uint64_t item_flags, 2223 struct rte_eth_dev *dev, 2224 struct rte_flow_error *error) 2225 { 2226 const struct rte_flow_item_vlan *mask = item->mask; 2227 const struct rte_flow_item_vlan nic_mask = { 2228 .tci = RTE_BE16(UINT16_MAX), 2229 .inner_type = RTE_BE16(UINT16_MAX), 2230 .has_more_vlan = 1, 2231 }; 2232 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2233 int ret; 2234 const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 | 2235 MLX5_FLOW_LAYER_INNER_L4) : 2236 (MLX5_FLOW_LAYER_OUTER_L3 | 2237 MLX5_FLOW_LAYER_OUTER_L4); 2238 const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 2239 MLX5_FLOW_LAYER_OUTER_VLAN; 2240 2241 if (item_flags & vlanm) 2242 return rte_flow_error_set(error, EINVAL, 2243 RTE_FLOW_ERROR_TYPE_ITEM, item, 2244 "multiple VLAN layers not supported"); 2245 else if ((item_flags & l34m) != 0) 2246 return rte_flow_error_set(error, EINVAL, 2247 RTE_FLOW_ERROR_TYPE_ITEM, item, 2248 "VLAN cannot follow L3/L4 layer"); 2249 if (!mask) 2250 mask = &rte_flow_item_vlan_mask; 2251 ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2252 (const uint8_t *)&nic_mask, 2253 sizeof(struct rte_flow_item_vlan), 2254 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2255 if (ret) 2256 return ret; 2257 if (!tunnel && mask->tci != RTE_BE16(0x0fff)) { 2258 struct mlx5_priv *priv = dev->data->dev_private; 2259 2260 if (priv->vmwa_context) { 2261 /* 2262 * Non-NULL context means we have a virtual machine 2263 * and SR-IOV enabled, we have to create VLAN interface 2264 * to make hypervisor to setup E-Switch vport 2265 * context correctly. We avoid creating the multiple 2266 * VLAN interfaces, so we cannot support VLAN tag mask. 2267 */ 2268 return rte_flow_error_set(error, EINVAL, 2269 RTE_FLOW_ERROR_TYPE_ITEM, 2270 item, 2271 "VLAN tag mask is not" 2272 " supported in virtual" 2273 " environment"); 2274 } 2275 } 2276 return 0; 2277 } 2278 2279 /* 2280 * GTP flags are contained in 1 byte of the format: 2281 * ------------------------------------------- 2282 * | bit | 0 - 2 | 3 | 4 | 5 | 6 | 7 | 2283 * |-----------------------------------------| 2284 * | value | Version | PT | Res | E | S | PN | 2285 * ------------------------------------------- 2286 * 2287 * Matching is supported only for GTP flags E, S, PN. 2288 */ 2289 #define MLX5_GTP_FLAGS_MASK 0x07 2290 2291 /** 2292 * Validate GTP item. 2293 * 2294 * @param[in] dev 2295 * Pointer to the rte_eth_dev structure. 2296 * @param[in] item 2297 * Item specification. 2298 * @param[in] item_flags 2299 * Bit-fields that holds the items detected until now. 2300 * @param[out] error 2301 * Pointer to error structure. 2302 * 2303 * @return 2304 * 0 on success, a negative errno value otherwise and rte_errno is set. 2305 */ 2306 static int 2307 flow_dv_validate_item_gtp(struct rte_eth_dev *dev, 2308 const struct rte_flow_item *item, 2309 uint64_t item_flags, 2310 struct rte_flow_error *error) 2311 { 2312 struct mlx5_priv *priv = dev->data->dev_private; 2313 const struct rte_flow_item_gtp *spec = item->spec; 2314 const struct rte_flow_item_gtp *mask = item->mask; 2315 const struct rte_flow_item_gtp nic_mask = { 2316 .v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK, 2317 .msg_type = 0xff, 2318 .teid = RTE_BE32(0xffffffff), 2319 }; 2320 2321 if (!priv->config.hca_attr.tunnel_stateless_gtp) 2322 return rte_flow_error_set(error, ENOTSUP, 2323 RTE_FLOW_ERROR_TYPE_ITEM, item, 2324 "GTP support is not enabled"); 2325 if (item_flags & MLX5_FLOW_LAYER_TUNNEL) 2326 return rte_flow_error_set(error, ENOTSUP, 2327 RTE_FLOW_ERROR_TYPE_ITEM, item, 2328 "multiple tunnel layers not" 2329 " supported"); 2330 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP)) 2331 return rte_flow_error_set(error, EINVAL, 2332 RTE_FLOW_ERROR_TYPE_ITEM, item, 2333 "no outer UDP layer found"); 2334 if (!mask) 2335 mask = &rte_flow_item_gtp_mask; 2336 if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK) 2337 return rte_flow_error_set(error, ENOTSUP, 2338 RTE_FLOW_ERROR_TYPE_ITEM, item, 2339 "Match is supported for GTP" 2340 " flags only"); 2341 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2342 (const uint8_t *)&nic_mask, 2343 sizeof(struct rte_flow_item_gtp), 2344 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2345 } 2346 2347 /** 2348 * Validate GTP PSC item. 2349 * 2350 * @param[in] item 2351 * Item specification. 2352 * @param[in] last_item 2353 * Previous validated item in the pattern items. 2354 * @param[in] gtp_item 2355 * Previous GTP item specification. 2356 * @param[in] attr 2357 * Pointer to flow attributes. 2358 * @param[out] error 2359 * Pointer to error structure. 2360 * 2361 * @return 2362 * 0 on success, a negative errno value otherwise and rte_errno is set. 2363 */ 2364 static int 2365 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, 2366 uint64_t last_item, 2367 const struct rte_flow_item *gtp_item, 2368 const struct rte_flow_attr *attr, 2369 struct rte_flow_error *error) 2370 { 2371 const struct rte_flow_item_gtp *gtp_spec; 2372 const struct rte_flow_item_gtp *gtp_mask; 2373 const struct rte_flow_item_gtp_psc *mask; 2374 const struct rte_flow_item_gtp_psc nic_mask = { 2375 .hdr.type = 0xF, 2376 .hdr.qfi = 0x3F, 2377 }; 2378 2379 if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP)) 2380 return rte_flow_error_set 2381 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2382 "GTP PSC item must be preceded with GTP item"); 2383 gtp_spec = gtp_item->spec; 2384 gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask; 2385 /* GTP spec and E flag is requested to match zero. */ 2386 if (gtp_spec && 2387 (gtp_mask->v_pt_rsv_flags & 2388 ~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG)) 2389 return rte_flow_error_set 2390 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, 2391 "GTP E flag must be 1 to match GTP PSC"); 2392 /* Check the flow is not created in group zero. */ 2393 if (!attr->transfer && !attr->group) 2394 return rte_flow_error_set 2395 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2396 "GTP PSC is not supported for group 0"); 2397 /* GTP spec is here and E flag is requested to match zero. */ 2398 if (!item->spec) 2399 return 0; 2400 mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask; 2401 return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, 2402 (const uint8_t *)&nic_mask, 2403 sizeof(struct rte_flow_item_gtp_psc), 2404 MLX5_ITEM_RANGE_NOT_ACCEPTED, error); 2405 } 2406 2407 /** 2408 * Validate IPV4 item. 2409 * Use existing validation function mlx5_flow_validate_item_ipv4(), and 2410 * add specific validation of fragment_offset field, 2411 * 2412 * @param[in] item 2413 * Item specification. 2414 * @param[in] item_flags 2415 * Bit-fields that holds the items detected until now. 2416 * @param[out] error 2417 * Pointer to error structure. 2418 * 2419 * @return 2420 * 0 on success, a negative errno value otherwise and rte_errno is set. 2421 */ 2422 static int 2423 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev, 2424 const struct rte_flow_item *item, 2425 uint64_t item_flags, uint64_t last_item, 2426 uint16_t ether_type, struct rte_flow_error *error) 2427 { 2428 int ret; 2429 struct mlx5_priv *priv = dev->data->dev_private; 2430 const struct rte_flow_item_ipv4 *spec = item->spec; 2431 const struct rte_flow_item_ipv4 *last = item->last; 2432 const struct rte_flow_item_ipv4 *mask = item->mask; 2433 rte_be16_t fragment_offset_spec = 0; 2434 rte_be16_t fragment_offset_last = 0; 2435 struct rte_flow_item_ipv4 nic_ipv4_mask = { 2436 .hdr = { 2437 .src_addr = RTE_BE32(0xffffffff), 2438 .dst_addr = RTE_BE32(0xffffffff), 2439 .type_of_service = 0xff, 2440 .fragment_offset = RTE_BE16(0xffff), 2441 .next_proto_id = 0xff, 2442 .time_to_live = 0xff, 2443 }, 2444 }; 2445 2446 if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) { 2447 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2448 bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl : 2449 priv->config.hca_attr.inner_ipv4_ihl; 2450 if (!ihl_cap) 2451 return rte_flow_error_set(error, ENOTSUP, 2452 RTE_FLOW_ERROR_TYPE_ITEM, 2453 item, 2454 "IPV4 ihl offload not supported"); 2455 nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl; 2456 } 2457 ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item, 2458 ether_type, &nic_ipv4_mask, 2459 MLX5_ITEM_RANGE_ACCEPTED, error); 2460 if (ret < 0) 2461 return ret; 2462 if (spec && mask) 2463 fragment_offset_spec = spec->hdr.fragment_offset & 2464 mask->hdr.fragment_offset; 2465 if (!fragment_offset_spec) 2466 return 0; 2467 /* 2468 * spec and mask are valid, enforce using full mask to make sure the 2469 * complete value is used correctly. 2470 */ 2471 if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2472 != RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2473 return rte_flow_error_set(error, EINVAL, 2474 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2475 item, "must use full mask for" 2476 " fragment_offset"); 2477 /* 2478 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0, 2479 * indicating this is 1st fragment of fragmented packet. 2480 * This is not yet supported in MLX5, return appropriate error message. 2481 */ 2482 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG)) 2483 return rte_flow_error_set(error, ENOTSUP, 2484 RTE_FLOW_ERROR_TYPE_ITEM, item, 2485 "match on first fragment not " 2486 "supported"); 2487 if (fragment_offset_spec && !last) 2488 return rte_flow_error_set(error, ENOTSUP, 2489 RTE_FLOW_ERROR_TYPE_ITEM, item, 2490 "specified value not supported"); 2491 /* spec and last are valid, validate the specified range. */ 2492 fragment_offset_last = last->hdr.fragment_offset & 2493 mask->hdr.fragment_offset; 2494 /* 2495 * Match on fragment_offset spec 0x2001 and last 0x3fff 2496 * means MF is 1 and frag-offset is > 0. 2497 * This packet is fragment 2nd and onward, excluding last. 2498 * This is not yet supported in MLX5, return appropriate 2499 * error message. 2500 */ 2501 if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) && 2502 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)) 2503 return rte_flow_error_set(error, ENOTSUP, 2504 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2505 last, "match on following " 2506 "fragments not supported"); 2507 /* 2508 * Match on fragment_offset spec 0x0001 and last 0x1fff 2509 * means MF is 0 and frag-offset is > 0. 2510 * This packet is last fragment of fragmented packet. 2511 * This is not yet supported in MLX5, return appropriate 2512 * error message. 2513 */ 2514 if (fragment_offset_spec == RTE_BE16(1) && 2515 fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK)) 2516 return rte_flow_error_set(error, ENOTSUP, 2517 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2518 last, "match on last " 2519 "fragment not supported"); 2520 /* 2521 * Match on fragment_offset spec 0x0001 and last 0x3fff 2522 * means MF and/or frag-offset is not 0. 2523 * This is a fragmented packet. 2524 * Other range values are invalid and rejected. 2525 */ 2526 if (!(fragment_offset_spec == RTE_BE16(1) && 2527 fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))) 2528 return rte_flow_error_set(error, ENOTSUP, 2529 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2530 "specified range not supported"); 2531 return 0; 2532 } 2533 2534 /** 2535 * Validate IPV6 fragment extension item. 2536 * 2537 * @param[in] item 2538 * Item specification. 2539 * @param[in] item_flags 2540 * Bit-fields that holds the items detected until now. 2541 * @param[out] error 2542 * Pointer to error structure. 2543 * 2544 * @return 2545 * 0 on success, a negative errno value otherwise and rte_errno is set. 2546 */ 2547 static int 2548 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item, 2549 uint64_t item_flags, 2550 struct rte_flow_error *error) 2551 { 2552 const struct rte_flow_item_ipv6_frag_ext *spec = item->spec; 2553 const struct rte_flow_item_ipv6_frag_ext *last = item->last; 2554 const struct rte_flow_item_ipv6_frag_ext *mask = item->mask; 2555 rte_be16_t frag_data_spec = 0; 2556 rte_be16_t frag_data_last = 0; 2557 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 2558 const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 : 2559 MLX5_FLOW_LAYER_OUTER_L4; 2560 int ret = 0; 2561 struct rte_flow_item_ipv6_frag_ext nic_mask = { 2562 .hdr = { 2563 .next_header = 0xff, 2564 .frag_data = RTE_BE16(0xffff), 2565 }, 2566 }; 2567 2568 if (item_flags & l4m) 2569 return rte_flow_error_set(error, EINVAL, 2570 RTE_FLOW_ERROR_TYPE_ITEM, item, 2571 "ipv6 fragment extension item cannot " 2572 "follow L4 item."); 2573 if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 2574 (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) 2575 return rte_flow_error_set(error, EINVAL, 2576 RTE_FLOW_ERROR_TYPE_ITEM, item, 2577 "ipv6 fragment extension item must " 2578 "follow ipv6 item"); 2579 if (spec && mask) 2580 frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data; 2581 if (!frag_data_spec) 2582 return 0; 2583 /* 2584 * spec and mask are valid, enforce using full mask to make sure the 2585 * complete value is used correctly. 2586 */ 2587 if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) != 2588 RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2589 return rte_flow_error_set(error, EINVAL, 2590 RTE_FLOW_ERROR_TYPE_ITEM_MASK, 2591 item, "must use full mask for" 2592 " frag_data"); 2593 /* 2594 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0. 2595 * This is 1st fragment of fragmented packet. 2596 */ 2597 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK)) 2598 return rte_flow_error_set(error, ENOTSUP, 2599 RTE_FLOW_ERROR_TYPE_ITEM, item, 2600 "match on first fragment not " 2601 "supported"); 2602 if (frag_data_spec && !last) 2603 return rte_flow_error_set(error, EINVAL, 2604 RTE_FLOW_ERROR_TYPE_ITEM, item, 2605 "specified value not supported"); 2606 ret = mlx5_flow_item_acceptable 2607 (item, (const uint8_t *)mask, 2608 (const uint8_t *)&nic_mask, 2609 sizeof(struct rte_flow_item_ipv6_frag_ext), 2610 MLX5_ITEM_RANGE_ACCEPTED, error); 2611 if (ret) 2612 return ret; 2613 /* spec and last are valid, validate the specified range. */ 2614 frag_data_last = last->hdr.frag_data & mask->hdr.frag_data; 2615 /* 2616 * Match on frag_data spec 0x0009 and last 0xfff9 2617 * means M is 1 and frag-offset is > 0. 2618 * This packet is fragment 2nd and onward, excluding last. 2619 * This is not yet supported in MLX5, return appropriate 2620 * error message. 2621 */ 2622 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN | 2623 RTE_IPV6_EHDR_MF_MASK) && 2624 frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) 2625 return rte_flow_error_set(error, ENOTSUP, 2626 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2627 last, "match on following " 2628 "fragments not supported"); 2629 /* 2630 * Match on frag_data spec 0x0008 and last 0xfff8 2631 * means M is 0 and frag-offset is > 0. 2632 * This packet is last fragment of fragmented packet. 2633 * This is not yet supported in MLX5, return appropriate 2634 * error message. 2635 */ 2636 if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) && 2637 frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK)) 2638 return rte_flow_error_set(error, ENOTSUP, 2639 RTE_FLOW_ERROR_TYPE_ITEM_LAST, 2640 last, "match on last " 2641 "fragment not supported"); 2642 /* Other range values are invalid and rejected. */ 2643 return rte_flow_error_set(error, EINVAL, 2644 RTE_FLOW_ERROR_TYPE_ITEM_LAST, last, 2645 "specified range not supported"); 2646 } 2647 2648 /* 2649 * Validate ASO CT item. 2650 * 2651 * @param[in] dev 2652 * Pointer to the rte_eth_dev structure. 2653 * @param[in] item 2654 * Item specification. 2655 * @param[in] item_flags 2656 * Pointer to bit-fields that holds the items detected until now. 2657 * @param[out] error 2658 * Pointer to error structure. 2659 * 2660 * @return 2661 * 0 on success, a negative errno value otherwise and rte_errno is set. 2662 */ 2663 static int 2664 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev, 2665 const struct rte_flow_item *item, 2666 uint64_t *item_flags, 2667 struct rte_flow_error *error) 2668 { 2669 const struct rte_flow_item_conntrack *spec = item->spec; 2670 const struct rte_flow_item_conntrack *mask = item->mask; 2671 RTE_SET_USED(dev); 2672 uint32_t flags; 2673 2674 if (*item_flags & MLX5_FLOW_LAYER_ASO_CT) 2675 return rte_flow_error_set(error, EINVAL, 2676 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2677 "Only one CT is supported"); 2678 if (!mask) 2679 mask = &rte_flow_item_conntrack_mask; 2680 flags = spec->flags & mask->flags; 2681 if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) && 2682 ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) || 2683 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) || 2684 (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))) 2685 return rte_flow_error_set(error, EINVAL, 2686 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 2687 "Conflict status bits"); 2688 /* State change also needs to be considered. */ 2689 *item_flags |= MLX5_FLOW_LAYER_ASO_CT; 2690 return 0; 2691 } 2692 2693 /** 2694 * Validate the pop VLAN action. 2695 * 2696 * @param[in] dev 2697 * Pointer to the rte_eth_dev structure. 2698 * @param[in] action_flags 2699 * Holds the actions detected until now. 2700 * @param[in] action 2701 * Pointer to the pop vlan action. 2702 * @param[in] item_flags 2703 * The items found in this flow rule. 2704 * @param[in] attr 2705 * Pointer to flow attributes. 2706 * @param[out] error 2707 * Pointer to error structure. 2708 * 2709 * @return 2710 * 0 on success, a negative errno value otherwise and rte_errno is set. 2711 */ 2712 static int 2713 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev, 2714 uint64_t action_flags, 2715 const struct rte_flow_action *action, 2716 uint64_t item_flags, 2717 const struct rte_flow_attr *attr, 2718 struct rte_flow_error *error) 2719 { 2720 const struct mlx5_priv *priv = dev->data->dev_private; 2721 struct mlx5_dev_ctx_shared *sh = priv->sh; 2722 bool direction_error = false; 2723 2724 if (!priv->sh->pop_vlan_action) 2725 return rte_flow_error_set(error, ENOTSUP, 2726 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2727 NULL, 2728 "pop vlan action is not supported"); 2729 /* Pop VLAN is not supported in egress except for CX6 FDB mode. */ 2730 if (attr->transfer) { 2731 bool fdb_tx = priv->representor_id != UINT16_MAX; 2732 bool is_cx5 = sh->steering_format_version == 2733 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2734 2735 if (fdb_tx && is_cx5) 2736 direction_error = true; 2737 } else if (attr->egress) { 2738 direction_error = true; 2739 } 2740 if (direction_error) 2741 return rte_flow_error_set(error, ENOTSUP, 2742 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 2743 NULL, 2744 "pop vlan action not supported for egress"); 2745 if (action_flags & MLX5_FLOW_VLAN_ACTIONS) 2746 return rte_flow_error_set(error, ENOTSUP, 2747 RTE_FLOW_ERROR_TYPE_ACTION, action, 2748 "no support for multiple VLAN " 2749 "actions"); 2750 /* Pop VLAN with preceding Decap requires inner header with VLAN. */ 2751 if ((action_flags & MLX5_FLOW_ACTION_DECAP) && 2752 !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN)) 2753 return rte_flow_error_set(error, ENOTSUP, 2754 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2755 NULL, 2756 "cannot pop vlan after decap without " 2757 "match on inner vlan in the flow"); 2758 /* Pop VLAN without preceding Decap requires outer header with VLAN. */ 2759 if (!(action_flags & MLX5_FLOW_ACTION_DECAP) && 2760 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 2761 return rte_flow_error_set(error, ENOTSUP, 2762 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 2763 NULL, 2764 "cannot pop vlan without a " 2765 "match on (outer) vlan in the flow"); 2766 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2767 return rte_flow_error_set(error, EINVAL, 2768 RTE_FLOW_ERROR_TYPE_ACTION, action, 2769 "wrong action order, port_id should " 2770 "be after pop VLAN action"); 2771 if (!attr->transfer && priv->representor) 2772 return rte_flow_error_set(error, ENOTSUP, 2773 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2774 "pop vlan action for VF representor " 2775 "not supported on NIC table"); 2776 return 0; 2777 } 2778 2779 /** 2780 * Get VLAN default info from vlan match info. 2781 * 2782 * @param[in] items 2783 * the list of item specifications. 2784 * @param[out] vlan 2785 * pointer VLAN info to fill to. 2786 * 2787 * @return 2788 * 0 on success, a negative errno value otherwise and rte_errno is set. 2789 */ 2790 static void 2791 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items, 2792 struct rte_vlan_hdr *vlan) 2793 { 2794 const struct rte_flow_item_vlan nic_mask = { 2795 .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK | 2796 MLX5DV_FLOW_VLAN_VID_MASK), 2797 .inner_type = RTE_BE16(0xffff), 2798 }; 2799 2800 if (items == NULL) 2801 return; 2802 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 2803 int type = items->type; 2804 2805 if (type == RTE_FLOW_ITEM_TYPE_VLAN || 2806 type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN) 2807 break; 2808 } 2809 if (items->type != RTE_FLOW_ITEM_TYPE_END) { 2810 const struct rte_flow_item_vlan *vlan_m = items->mask; 2811 const struct rte_flow_item_vlan *vlan_v = items->spec; 2812 2813 /* If VLAN item in pattern doesn't contain data, return here. */ 2814 if (!vlan_v) 2815 return; 2816 if (!vlan_m) 2817 vlan_m = &nic_mask; 2818 /* Only full match values are accepted */ 2819 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) == 2820 MLX5DV_FLOW_VLAN_PCP_MASK_BE) { 2821 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK; 2822 vlan->vlan_tci |= 2823 rte_be_to_cpu_16(vlan_v->tci & 2824 MLX5DV_FLOW_VLAN_PCP_MASK_BE); 2825 } 2826 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) == 2827 MLX5DV_FLOW_VLAN_VID_MASK_BE) { 2828 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK; 2829 vlan->vlan_tci |= 2830 rte_be_to_cpu_16(vlan_v->tci & 2831 MLX5DV_FLOW_VLAN_VID_MASK_BE); 2832 } 2833 if (vlan_m->inner_type == nic_mask.inner_type) 2834 vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type & 2835 vlan_m->inner_type); 2836 } 2837 } 2838 2839 /** 2840 * Validate the push 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] item_flags 2847 * The items found in this flow rule. 2848 * @param[in] action 2849 * Pointer to the action structure. 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_push_vlan(struct rte_eth_dev *dev, 2860 uint64_t action_flags, 2861 const struct rte_flow_item_vlan *vlan_m, 2862 const struct rte_flow_action *action, 2863 const struct rte_flow_attr *attr, 2864 struct rte_flow_error *error) 2865 { 2866 const struct rte_flow_action_of_push_vlan *push_vlan = action->conf; 2867 const struct mlx5_priv *priv = dev->data->dev_private; 2868 struct mlx5_dev_ctx_shared *sh = priv->sh; 2869 bool direction_error = false; 2870 2871 if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && 2872 push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) 2873 return rte_flow_error_set(error, EINVAL, 2874 RTE_FLOW_ERROR_TYPE_ACTION, action, 2875 "invalid vlan ethertype"); 2876 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2877 return rte_flow_error_set(error, EINVAL, 2878 RTE_FLOW_ERROR_TYPE_ACTION, action, 2879 "wrong action order, port_id should " 2880 "be after push VLAN"); 2881 /* Push VLAN is not supported in ingress except for CX6 FDB mode. */ 2882 if (attr->transfer) { 2883 bool fdb_tx = priv->representor_id != UINT16_MAX; 2884 bool is_cx5 = sh->steering_format_version == 2885 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; 2886 2887 if (!fdb_tx && is_cx5) 2888 direction_error = true; 2889 } else if (attr->ingress) { 2890 direction_error = true; 2891 } 2892 if (direction_error) 2893 return rte_flow_error_set(error, ENOTSUP, 2894 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 2895 NULL, 2896 "push vlan action not supported for ingress"); 2897 if (!attr->transfer && priv->representor) 2898 return rte_flow_error_set(error, ENOTSUP, 2899 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 2900 "push vlan action for VF representor " 2901 "not supported on NIC table"); 2902 if (vlan_m && 2903 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) && 2904 (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) != 2905 MLX5DV_FLOW_VLAN_PCP_MASK_BE && 2906 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) && 2907 !(mlx5_flow_find_action 2908 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP))) 2909 return rte_flow_error_set(error, EINVAL, 2910 RTE_FLOW_ERROR_TYPE_ACTION, action, 2911 "not full match mask on VLAN PCP and " 2912 "there is no of_set_vlan_pcp action, " 2913 "push VLAN action cannot figure out " 2914 "PCP value"); 2915 if (vlan_m && 2916 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) && 2917 (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) != 2918 MLX5DV_FLOW_VLAN_VID_MASK_BE && 2919 !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) && 2920 !(mlx5_flow_find_action 2921 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))) 2922 return rte_flow_error_set(error, EINVAL, 2923 RTE_FLOW_ERROR_TYPE_ACTION, action, 2924 "not full match mask on VLAN VID and " 2925 "there is no of_set_vlan_vid action, " 2926 "push VLAN action cannot figure out " 2927 "VID value"); 2928 (void)attr; 2929 return 0; 2930 } 2931 2932 /** 2933 * Validate the set VLAN PCP. 2934 * 2935 * @param[in] action_flags 2936 * Holds the actions detected until now. 2937 * @param[in] actions 2938 * Pointer to the list of actions remaining in the flow rule. 2939 * @param[out] error 2940 * Pointer to error structure. 2941 * 2942 * @return 2943 * 0 on success, a negative errno value otherwise and rte_errno is set. 2944 */ 2945 static int 2946 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags, 2947 const struct rte_flow_action actions[], 2948 struct rte_flow_error *error) 2949 { 2950 const struct rte_flow_action *action = actions; 2951 const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf; 2952 2953 if (conf->vlan_pcp > 7) 2954 return rte_flow_error_set(error, EINVAL, 2955 RTE_FLOW_ERROR_TYPE_ACTION, action, 2956 "VLAN PCP value is too big"); 2957 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)) 2958 return rte_flow_error_set(error, ENOTSUP, 2959 RTE_FLOW_ERROR_TYPE_ACTION, action, 2960 "set VLAN PCP action must follow " 2961 "the push VLAN action"); 2962 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) 2963 return rte_flow_error_set(error, ENOTSUP, 2964 RTE_FLOW_ERROR_TYPE_ACTION, action, 2965 "Multiple VLAN PCP modification are " 2966 "not supported"); 2967 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 2968 return rte_flow_error_set(error, EINVAL, 2969 RTE_FLOW_ERROR_TYPE_ACTION, action, 2970 "wrong action order, port_id should " 2971 "be after set VLAN PCP"); 2972 return 0; 2973 } 2974 2975 /** 2976 * Validate the set VLAN VID. 2977 * 2978 * @param[in] item_flags 2979 * Holds the items detected in this rule. 2980 * @param[in] action_flags 2981 * Holds the actions detected until now. 2982 * @param[in] actions 2983 * Pointer to the list of actions remaining in the flow rule. 2984 * @param[out] error 2985 * Pointer to error structure. 2986 * 2987 * @return 2988 * 0 on success, a negative errno value otherwise and rte_errno is set. 2989 */ 2990 static int 2991 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags, 2992 uint64_t action_flags, 2993 const struct rte_flow_action actions[], 2994 struct rte_flow_error *error) 2995 { 2996 const struct rte_flow_action *action = actions; 2997 const struct rte_flow_action_of_set_vlan_vid *conf = action->conf; 2998 2999 if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE) 3000 return rte_flow_error_set(error, EINVAL, 3001 RTE_FLOW_ERROR_TYPE_ACTION, action, 3002 "VLAN VID value is too big"); 3003 if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) && 3004 !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN)) 3005 return rte_flow_error_set(error, ENOTSUP, 3006 RTE_FLOW_ERROR_TYPE_ACTION, action, 3007 "set VLAN VID action must follow push" 3008 " VLAN action or match on VLAN item"); 3009 if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) 3010 return rte_flow_error_set(error, ENOTSUP, 3011 RTE_FLOW_ERROR_TYPE_ACTION, action, 3012 "Multiple VLAN VID modifications are " 3013 "not supported"); 3014 if (action_flags & MLX5_FLOW_ACTION_PORT_ID) 3015 return rte_flow_error_set(error, EINVAL, 3016 RTE_FLOW_ERROR_TYPE_ACTION, action, 3017 "wrong action order, port_id should " 3018 "be after set VLAN VID"); 3019 return 0; 3020 } 3021 3022 /* 3023 * Validate the FLAG action. 3024 * 3025 * @param[in] dev 3026 * Pointer to the rte_eth_dev structure. 3027 * @param[in] action_flags 3028 * Holds the actions detected until now. 3029 * @param[in] attr 3030 * Pointer to flow attributes 3031 * @param[out] error 3032 * Pointer to error structure. 3033 * 3034 * @return 3035 * 0 on success, a negative errno value otherwise and rte_errno is set. 3036 */ 3037 static int 3038 flow_dv_validate_action_flag(struct rte_eth_dev *dev, 3039 uint64_t action_flags, 3040 const struct rte_flow_attr *attr, 3041 struct rte_flow_error *error) 3042 { 3043 struct mlx5_priv *priv = dev->data->dev_private; 3044 struct mlx5_dev_config *config = &priv->config; 3045 int ret; 3046 3047 /* Fall back if no extended metadata register support. */ 3048 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3049 return mlx5_flow_validate_action_flag(action_flags, attr, 3050 error); 3051 /* Extensive metadata mode requires registers. */ 3052 if (!mlx5_flow_ext_mreg_supported(dev)) 3053 return rte_flow_error_set(error, ENOTSUP, 3054 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3055 "no metadata registers " 3056 "to support flag action"); 3057 if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT)) 3058 return rte_flow_error_set(error, ENOTSUP, 3059 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3060 "extended metadata register" 3061 " isn't available"); 3062 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3063 if (ret < 0) 3064 return ret; 3065 MLX5_ASSERT(ret > 0); 3066 if (action_flags & MLX5_FLOW_ACTION_MARK) 3067 return rte_flow_error_set(error, EINVAL, 3068 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3069 "can't mark and flag in same flow"); 3070 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3071 return rte_flow_error_set(error, EINVAL, 3072 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3073 "can't have 2 flag" 3074 " actions in same flow"); 3075 return 0; 3076 } 3077 3078 /** 3079 * Validate MARK action. 3080 * 3081 * @param[in] dev 3082 * Pointer to the rte_eth_dev structure. 3083 * @param[in] action 3084 * Pointer to action. 3085 * @param[in] action_flags 3086 * Holds the actions detected until now. 3087 * @param[in] attr 3088 * Pointer to flow attributes 3089 * @param[out] error 3090 * Pointer to error structure. 3091 * 3092 * @return 3093 * 0 on success, a negative errno value otherwise and rte_errno is set. 3094 */ 3095 static int 3096 flow_dv_validate_action_mark(struct rte_eth_dev *dev, 3097 const struct rte_flow_action *action, 3098 uint64_t action_flags, 3099 const struct rte_flow_attr *attr, 3100 struct rte_flow_error *error) 3101 { 3102 struct mlx5_priv *priv = dev->data->dev_private; 3103 struct mlx5_dev_config *config = &priv->config; 3104 const struct rte_flow_action_mark *mark = action->conf; 3105 int ret; 3106 3107 if (is_tunnel_offload_active(dev)) 3108 return rte_flow_error_set(error, ENOTSUP, 3109 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3110 "no mark action " 3111 "if tunnel offload active"); 3112 /* Fall back if no extended metadata register support. */ 3113 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY) 3114 return mlx5_flow_validate_action_mark(action, action_flags, 3115 attr, error); 3116 /* Extensive metadata mode requires registers. */ 3117 if (!mlx5_flow_ext_mreg_supported(dev)) 3118 return rte_flow_error_set(error, ENOTSUP, 3119 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3120 "no metadata registers " 3121 "to support mark action"); 3122 if (!priv->sh->dv_mark_mask) 3123 return rte_flow_error_set(error, ENOTSUP, 3124 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3125 "extended metadata register" 3126 " isn't available"); 3127 ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); 3128 if (ret < 0) 3129 return ret; 3130 MLX5_ASSERT(ret > 0); 3131 if (!mark) 3132 return rte_flow_error_set(error, EINVAL, 3133 RTE_FLOW_ERROR_TYPE_ACTION, action, 3134 "configuration cannot be null"); 3135 if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask)) 3136 return rte_flow_error_set(error, EINVAL, 3137 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 3138 &mark->id, 3139 "mark id exceeds the limit"); 3140 if (action_flags & MLX5_FLOW_ACTION_FLAG) 3141 return rte_flow_error_set(error, EINVAL, 3142 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3143 "can't flag and mark in same flow"); 3144 if (action_flags & MLX5_FLOW_ACTION_MARK) 3145 return rte_flow_error_set(error, EINVAL, 3146 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3147 "can't have 2 mark actions in same" 3148 " flow"); 3149 return 0; 3150 } 3151 3152 /** 3153 * Validate SET_META action. 3154 * 3155 * @param[in] dev 3156 * Pointer to the rte_eth_dev structure. 3157 * @param[in] action 3158 * Pointer to the action structure. 3159 * @param[in] action_flags 3160 * Holds the actions detected until now. 3161 * @param[in] attr 3162 * Pointer to flow attributes 3163 * @param[out] error 3164 * Pointer to error structure. 3165 * 3166 * @return 3167 * 0 on success, a negative errno value otherwise and rte_errno is set. 3168 */ 3169 static int 3170 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev, 3171 const struct rte_flow_action *action, 3172 uint64_t action_flags __rte_unused, 3173 const struct rte_flow_attr *attr, 3174 struct rte_flow_error *error) 3175 { 3176 struct mlx5_priv *priv = dev->data->dev_private; 3177 struct mlx5_dev_config *config = &priv->config; 3178 const struct rte_flow_action_set_meta *conf; 3179 uint32_t nic_mask = UINT32_MAX; 3180 int reg; 3181 3182 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 3183 !mlx5_flow_ext_mreg_supported(dev)) 3184 return rte_flow_error_set(error, ENOTSUP, 3185 RTE_FLOW_ERROR_TYPE_ACTION, action, 3186 "extended metadata register" 3187 " isn't supported"); 3188 reg = flow_dv_get_metadata_reg(dev, attr, error); 3189 if (reg < 0) 3190 return reg; 3191 if (reg == REG_NON) 3192 return rte_flow_error_set(error, ENOTSUP, 3193 RTE_FLOW_ERROR_TYPE_ACTION, action, 3194 "unavalable extended metadata register"); 3195 if (reg != REG_A && reg != REG_B) { 3196 struct mlx5_priv *priv = dev->data->dev_private; 3197 3198 nic_mask = priv->sh->dv_meta_mask; 3199 } 3200 if (!(action->conf)) 3201 return rte_flow_error_set(error, EINVAL, 3202 RTE_FLOW_ERROR_TYPE_ACTION, action, 3203 "configuration cannot be null"); 3204 conf = (const struct rte_flow_action_set_meta *)action->conf; 3205 if (!conf->mask) 3206 return rte_flow_error_set(error, EINVAL, 3207 RTE_FLOW_ERROR_TYPE_ACTION, action, 3208 "zero mask doesn't have any effect"); 3209 if (conf->mask & ~nic_mask) 3210 return rte_flow_error_set(error, EINVAL, 3211 RTE_FLOW_ERROR_TYPE_ACTION, action, 3212 "meta data must be within reg C0"); 3213 return 0; 3214 } 3215 3216 /** 3217 * Validate SET_TAG action. 3218 * 3219 * @param[in] dev 3220 * Pointer to the rte_eth_dev structure. 3221 * @param[in] action 3222 * Pointer to the action structure. 3223 * @param[in] action_flags 3224 * Holds the actions detected until now. 3225 * @param[in] attr 3226 * Pointer to flow attributes 3227 * @param[out] error 3228 * Pointer to error structure. 3229 * 3230 * @return 3231 * 0 on success, a negative errno value otherwise and rte_errno is set. 3232 */ 3233 static int 3234 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, 3235 const struct rte_flow_action *action, 3236 uint64_t action_flags, 3237 const struct rte_flow_attr *attr, 3238 struct rte_flow_error *error) 3239 { 3240 const struct rte_flow_action_set_tag *conf; 3241 const uint64_t terminal_action_flags = 3242 MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | 3243 MLX5_FLOW_ACTION_RSS; 3244 int ret; 3245 3246 if (!mlx5_flow_ext_mreg_supported(dev)) 3247 return rte_flow_error_set(error, ENOTSUP, 3248 RTE_FLOW_ERROR_TYPE_ACTION, action, 3249 "extensive metadata register" 3250 " isn't supported"); 3251 if (!(action->conf)) 3252 return rte_flow_error_set(error, EINVAL, 3253 RTE_FLOW_ERROR_TYPE_ACTION, action, 3254 "configuration cannot be null"); 3255 conf = (const struct rte_flow_action_set_tag *)action->conf; 3256 if (!conf->mask) 3257 return rte_flow_error_set(error, EINVAL, 3258 RTE_FLOW_ERROR_TYPE_ACTION, action, 3259 "zero mask doesn't have any effect"); 3260 ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error); 3261 if (ret < 0) 3262 return ret; 3263 if (!attr->transfer && attr->ingress && 3264 (action_flags & terminal_action_flags)) 3265 return rte_flow_error_set(error, EINVAL, 3266 RTE_FLOW_ERROR_TYPE_ACTION, action, 3267 "set_tag has no effect" 3268 " with terminal actions"); 3269 return 0; 3270 } 3271 3272 /** 3273 * Validate count action. 3274 * 3275 * @param[in] dev 3276 * Pointer to rte_eth_dev structure. 3277 * @param[in] shared 3278 * Indicator if action is shared. 3279 * @param[in] action_flags 3280 * Holds the actions detected until now. 3281 * @param[out] error 3282 * Pointer to error structure. 3283 * 3284 * @return 3285 * 0 on success, a negative errno value otherwise and rte_errno is set. 3286 */ 3287 static int 3288 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared, 3289 uint64_t action_flags, 3290 struct rte_flow_error *error) 3291 { 3292 struct mlx5_priv *priv = dev->data->dev_private; 3293 3294 if (!priv->sh->devx) 3295 goto notsup_err; 3296 if (action_flags & MLX5_FLOW_ACTION_COUNT) 3297 return rte_flow_error_set(error, EINVAL, 3298 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3299 "duplicate count actions set"); 3300 if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) && 3301 !priv->sh->flow_hit_aso_en) 3302 return rte_flow_error_set(error, EINVAL, 3303 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3304 "old age and shared count combination is not supported"); 3305 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 3306 return 0; 3307 #endif 3308 notsup_err: 3309 return rte_flow_error_set 3310 (error, ENOTSUP, 3311 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3312 NULL, 3313 "count action not supported"); 3314 } 3315 3316 /** 3317 * Validate the L2 encap action. 3318 * 3319 * @param[in] dev 3320 * Pointer to the rte_eth_dev structure. 3321 * @param[in] action_flags 3322 * Holds the actions detected until now. 3323 * @param[in] action 3324 * Pointer to the action structure. 3325 * @param[in] attr 3326 * Pointer to flow attributes. 3327 * @param[out] error 3328 * Pointer to error structure. 3329 * 3330 * @return 3331 * 0 on success, a negative errno value otherwise and rte_errno is set. 3332 */ 3333 static int 3334 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev, 3335 uint64_t action_flags, 3336 const struct rte_flow_action *action, 3337 const struct rte_flow_attr *attr, 3338 struct rte_flow_error *error) 3339 { 3340 const struct mlx5_priv *priv = dev->data->dev_private; 3341 3342 if (!(action->conf)) 3343 return rte_flow_error_set(error, EINVAL, 3344 RTE_FLOW_ERROR_TYPE_ACTION, action, 3345 "configuration cannot be null"); 3346 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3347 return rte_flow_error_set(error, EINVAL, 3348 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3349 "can only have a single encap action " 3350 "in a flow"); 3351 if (!attr->transfer && priv->representor) 3352 return rte_flow_error_set(error, ENOTSUP, 3353 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3354 "encap action for VF representor " 3355 "not supported on NIC table"); 3356 return 0; 3357 } 3358 3359 /** 3360 * Validate a decap action. 3361 * 3362 * @param[in] dev 3363 * Pointer to the rte_eth_dev structure. 3364 * @param[in] action_flags 3365 * Holds the actions detected until now. 3366 * @param[in] action 3367 * Pointer to the action structure. 3368 * @param[in] item_flags 3369 * Holds the items detected. 3370 * @param[in] attr 3371 * Pointer to flow attributes 3372 * @param[out] error 3373 * Pointer to error structure. 3374 * 3375 * @return 3376 * 0 on success, a negative errno value otherwise and rte_errno is set. 3377 */ 3378 static int 3379 flow_dv_validate_action_decap(struct rte_eth_dev *dev, 3380 uint64_t action_flags, 3381 const struct rte_flow_action *action, 3382 const uint64_t item_flags, 3383 const struct rte_flow_attr *attr, 3384 struct rte_flow_error *error) 3385 { 3386 const struct mlx5_priv *priv = dev->data->dev_private; 3387 3388 if (priv->config.hca_attr.scatter_fcs_w_decap_disable && 3389 !priv->config.decap_en) 3390 return rte_flow_error_set(error, ENOTSUP, 3391 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3392 "decap is not enabled"); 3393 if (action_flags & MLX5_FLOW_XCAP_ACTIONS) 3394 return rte_flow_error_set(error, ENOTSUP, 3395 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3396 action_flags & 3397 MLX5_FLOW_ACTION_DECAP ? "can only " 3398 "have a single decap action" : "decap " 3399 "after encap is not supported"); 3400 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 3401 return rte_flow_error_set(error, EINVAL, 3402 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3403 "can't have decap action after" 3404 " modify action"); 3405 if (attr->egress) 3406 return rte_flow_error_set(error, ENOTSUP, 3407 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 3408 NULL, 3409 "decap action not supported for " 3410 "egress"); 3411 if (!attr->transfer && priv->representor) 3412 return rte_flow_error_set(error, ENOTSUP, 3413 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3414 "decap action for VF representor " 3415 "not supported on NIC table"); 3416 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP && 3417 !(item_flags & MLX5_FLOW_LAYER_VXLAN)) 3418 return rte_flow_error_set(error, ENOTSUP, 3419 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3420 "VXLAN item should be present for VXLAN decap"); 3421 return 0; 3422 } 3423 3424 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,}; 3425 3426 /** 3427 * Validate the raw encap and decap actions. 3428 * 3429 * @param[in] dev 3430 * Pointer to the rte_eth_dev structure. 3431 * @param[in] decap 3432 * Pointer to the decap action. 3433 * @param[in] encap 3434 * Pointer to the encap action. 3435 * @param[in] attr 3436 * Pointer to flow attributes 3437 * @param[in/out] action_flags 3438 * Holds the actions detected until now. 3439 * @param[out] actions_n 3440 * pointer to the number of actions counter. 3441 * @param[in] action 3442 * Pointer to the action structure. 3443 * @param[in] item_flags 3444 * Holds the items detected. 3445 * @param[out] error 3446 * Pointer to error structure. 3447 * 3448 * @return 3449 * 0 on success, a negative errno value otherwise and rte_errno is set. 3450 */ 3451 static int 3452 flow_dv_validate_action_raw_encap_decap 3453 (struct rte_eth_dev *dev, 3454 const struct rte_flow_action_raw_decap *decap, 3455 const struct rte_flow_action_raw_encap *encap, 3456 const struct rte_flow_attr *attr, uint64_t *action_flags, 3457 int *actions_n, const struct rte_flow_action *action, 3458 uint64_t item_flags, struct rte_flow_error *error) 3459 { 3460 const struct mlx5_priv *priv = dev->data->dev_private; 3461 int ret; 3462 3463 if (encap && (!encap->size || !encap->data)) 3464 return rte_flow_error_set(error, EINVAL, 3465 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3466 "raw encap data cannot be empty"); 3467 if (decap && encap) { 3468 if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE && 3469 encap->size > MLX5_ENCAPSULATION_DECISION_SIZE) 3470 /* L3 encap. */ 3471 decap = NULL; 3472 else if (encap->size <= 3473 MLX5_ENCAPSULATION_DECISION_SIZE && 3474 decap->size > 3475 MLX5_ENCAPSULATION_DECISION_SIZE) 3476 /* L3 decap. */ 3477 encap = NULL; 3478 else if (encap->size > 3479 MLX5_ENCAPSULATION_DECISION_SIZE && 3480 decap->size > 3481 MLX5_ENCAPSULATION_DECISION_SIZE) 3482 /* 2 L2 actions: encap and decap. */ 3483 ; 3484 else 3485 return rte_flow_error_set(error, 3486 ENOTSUP, 3487 RTE_FLOW_ERROR_TYPE_ACTION, 3488 NULL, "unsupported too small " 3489 "raw decap and too small raw " 3490 "encap combination"); 3491 } 3492 if (decap) { 3493 ret = flow_dv_validate_action_decap(dev, *action_flags, action, 3494 item_flags, attr, error); 3495 if (ret < 0) 3496 return ret; 3497 *action_flags |= MLX5_FLOW_ACTION_DECAP; 3498 ++(*actions_n); 3499 } 3500 if (encap) { 3501 if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE) 3502 return rte_flow_error_set(error, ENOTSUP, 3503 RTE_FLOW_ERROR_TYPE_ACTION, 3504 NULL, 3505 "small raw encap size"); 3506 if (*action_flags & MLX5_FLOW_ACTION_ENCAP) 3507 return rte_flow_error_set(error, EINVAL, 3508 RTE_FLOW_ERROR_TYPE_ACTION, 3509 NULL, 3510 "more than one encap action"); 3511 if (!attr->transfer && priv->representor) 3512 return rte_flow_error_set 3513 (error, ENOTSUP, 3514 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3515 "encap action for VF representor " 3516 "not supported on NIC table"); 3517 *action_flags |= MLX5_FLOW_ACTION_ENCAP; 3518 ++(*actions_n); 3519 } 3520 return 0; 3521 } 3522 3523 /* 3524 * Validate the ASO CT action. 3525 * 3526 * @param[in] dev 3527 * Pointer to the rte_eth_dev structure. 3528 * @param[in] action_flags 3529 * Holds the actions detected until now. 3530 * @param[in] item_flags 3531 * The items found in this flow rule. 3532 * @param[in] attr 3533 * Pointer to flow attributes. 3534 * @param[out] error 3535 * Pointer to error structure. 3536 * 3537 * @return 3538 * 0 on success, a negative errno value otherwise and rte_errno is set. 3539 */ 3540 static int 3541 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, 3542 uint64_t action_flags, 3543 uint64_t item_flags, 3544 const struct rte_flow_attr *attr, 3545 struct rte_flow_error *error) 3546 { 3547 RTE_SET_USED(dev); 3548 3549 if (attr->group == 0 && !attr->transfer) 3550 return rte_flow_error_set(error, ENOTSUP, 3551 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3552 NULL, 3553 "Only support non-root table"); 3554 if (action_flags & MLX5_FLOW_FATE_ACTIONS) 3555 return rte_flow_error_set(error, ENOTSUP, 3556 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3557 "CT cannot follow a fate action"); 3558 if ((action_flags & MLX5_FLOW_ACTION_METER) || 3559 (action_flags & MLX5_FLOW_ACTION_AGE)) 3560 return rte_flow_error_set(error, EINVAL, 3561 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3562 "Only one ASO action is supported"); 3563 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 3564 return rte_flow_error_set(error, EINVAL, 3565 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 3566 "Encap cannot exist before CT"); 3567 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP)) 3568 return rte_flow_error_set(error, EINVAL, 3569 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3570 "Not a outer TCP packet"); 3571 return 0; 3572 } 3573 3574 int 3575 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused, 3576 struct mlx5_list_entry *entry, void *cb_ctx) 3577 { 3578 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3579 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3580 struct mlx5_flow_dv_encap_decap_resource *resource; 3581 3582 resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource, 3583 entry); 3584 if (resource->reformat_type == ctx_resource->reformat_type && 3585 resource->ft_type == ctx_resource->ft_type && 3586 resource->flags == ctx_resource->flags && 3587 resource->size == ctx_resource->size && 3588 !memcmp((const void *)resource->buf, 3589 (const void *)ctx_resource->buf, 3590 resource->size)) 3591 return 0; 3592 return -1; 3593 } 3594 3595 struct mlx5_list_entry * 3596 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx) 3597 { 3598 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3599 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3600 struct mlx5dv_dr_domain *domain; 3601 struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data; 3602 struct mlx5_flow_dv_encap_decap_resource *resource; 3603 uint32_t idx; 3604 int ret; 3605 3606 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3607 domain = sh->fdb_domain; 3608 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3609 domain = sh->rx_domain; 3610 else 3611 domain = sh->tx_domain; 3612 /* Register new encap/decap resource. */ 3613 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx); 3614 if (!resource) { 3615 rte_flow_error_set(ctx->error, ENOMEM, 3616 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3617 "cannot allocate resource memory"); 3618 return NULL; 3619 } 3620 *resource = *ctx_resource; 3621 resource->idx = idx; 3622 ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx, 3623 domain, resource, 3624 &resource->action); 3625 if (ret) { 3626 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx); 3627 rte_flow_error_set(ctx->error, ENOMEM, 3628 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 3629 NULL, "cannot create action"); 3630 return NULL; 3631 } 3632 3633 return &resource->entry; 3634 } 3635 3636 struct mlx5_list_entry * 3637 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 3638 void *cb_ctx) 3639 { 3640 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3641 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3642 struct mlx5_flow_dv_encap_decap_resource *cache_resource; 3643 uint32_t idx; 3644 3645 cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 3646 &idx); 3647 if (!cache_resource) { 3648 rte_flow_error_set(ctx->error, ENOMEM, 3649 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3650 "cannot allocate resource memory"); 3651 return NULL; 3652 } 3653 memcpy(cache_resource, oentry, sizeof(*cache_resource)); 3654 cache_resource->idx = idx; 3655 return &cache_resource->entry; 3656 } 3657 3658 void 3659 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3660 { 3661 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3662 struct mlx5_flow_dv_encap_decap_resource *res = 3663 container_of(entry, typeof(*res), entry); 3664 3665 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 3666 } 3667 3668 /** 3669 * Find existing encap/decap resource or create and register a new one. 3670 * 3671 * @param[in, out] dev 3672 * Pointer to rte_eth_dev structure. 3673 * @param[in, out] resource 3674 * Pointer to encap/decap resource. 3675 * @parm[in, out] dev_flow 3676 * Pointer to the dev_flow. 3677 * @param[out] error 3678 * pointer to error structure. 3679 * 3680 * @return 3681 * 0 on success otherwise -errno and errno is set. 3682 */ 3683 static int 3684 flow_dv_encap_decap_resource_register 3685 (struct rte_eth_dev *dev, 3686 struct mlx5_flow_dv_encap_decap_resource *resource, 3687 struct mlx5_flow *dev_flow, 3688 struct rte_flow_error *error) 3689 { 3690 struct mlx5_priv *priv = dev->data->dev_private; 3691 struct mlx5_dev_ctx_shared *sh = priv->sh; 3692 struct mlx5_list_entry *entry; 3693 union { 3694 struct { 3695 uint32_t ft_type:8; 3696 uint32_t refmt_type:8; 3697 /* 3698 * Header reformat actions can be shared between 3699 * non-root tables. One bit to indicate non-root 3700 * table or not. 3701 */ 3702 uint32_t is_root:1; 3703 uint32_t reserve:15; 3704 }; 3705 uint32_t v32; 3706 } encap_decap_key = { 3707 { 3708 .ft_type = resource->ft_type, 3709 .refmt_type = resource->reformat_type, 3710 .is_root = !!dev_flow->dv.group, 3711 .reserve = 0, 3712 } 3713 }; 3714 struct mlx5_flow_cb_ctx ctx = { 3715 .error = error, 3716 .data = resource, 3717 }; 3718 struct mlx5_hlist *encaps_decaps; 3719 uint64_t key64; 3720 3721 encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps, 3722 "encaps_decaps", 3723 MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ, 3724 true, true, sh, 3725 flow_dv_encap_decap_create_cb, 3726 flow_dv_encap_decap_match_cb, 3727 flow_dv_encap_decap_remove_cb, 3728 flow_dv_encap_decap_clone_cb, 3729 flow_dv_encap_decap_clone_free_cb); 3730 if (unlikely(!encaps_decaps)) 3731 return -rte_errno; 3732 resource->flags = dev_flow->dv.group ? 0 : 1; 3733 key64 = __rte_raw_cksum(&encap_decap_key.v32, 3734 sizeof(encap_decap_key.v32), 0); 3735 if (resource->reformat_type != 3736 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 && 3737 resource->size) 3738 key64 = __rte_raw_cksum(resource->buf, resource->size, key64); 3739 entry = mlx5_hlist_register(encaps_decaps, key64, &ctx); 3740 if (!entry) 3741 return -rte_errno; 3742 resource = container_of(entry, typeof(*resource), entry); 3743 dev_flow->dv.encap_decap = resource; 3744 dev_flow->handle->dvh.rix_encap_decap = resource->idx; 3745 return 0; 3746 } 3747 3748 /** 3749 * Find existing table jump resource or create and register a new one. 3750 * 3751 * @param[in, out] dev 3752 * Pointer to rte_eth_dev structure. 3753 * @param[in, out] tbl 3754 * Pointer to flow table resource. 3755 * @parm[in, out] dev_flow 3756 * Pointer to the dev_flow. 3757 * @param[out] error 3758 * pointer to error structure. 3759 * 3760 * @return 3761 * 0 on success otherwise -errno and errno is set. 3762 */ 3763 static int 3764 flow_dv_jump_tbl_resource_register 3765 (struct rte_eth_dev *dev __rte_unused, 3766 struct mlx5_flow_tbl_resource *tbl, 3767 struct mlx5_flow *dev_flow, 3768 struct rte_flow_error *error __rte_unused) 3769 { 3770 struct mlx5_flow_tbl_data_entry *tbl_data = 3771 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 3772 3773 MLX5_ASSERT(tbl); 3774 MLX5_ASSERT(tbl_data->jump.action); 3775 dev_flow->handle->rix_jump = tbl_data->idx; 3776 dev_flow->dv.jump = &tbl_data->jump; 3777 return 0; 3778 } 3779 3780 int 3781 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused, 3782 struct mlx5_list_entry *entry, void *cb_ctx) 3783 { 3784 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3785 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3786 struct mlx5_flow_dv_port_id_action_resource *res = 3787 container_of(entry, typeof(*res), entry); 3788 3789 return ref->port_id != res->port_id; 3790 } 3791 3792 struct mlx5_list_entry * 3793 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx) 3794 { 3795 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3796 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3797 struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data; 3798 struct mlx5_flow_dv_port_id_action_resource *resource; 3799 uint32_t idx; 3800 int ret; 3801 3802 /* Register new port id action resource. */ 3803 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3804 if (!resource) { 3805 rte_flow_error_set(ctx->error, ENOMEM, 3806 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3807 "cannot allocate port_id action memory"); 3808 return NULL; 3809 } 3810 *resource = *ref; 3811 ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain, 3812 ref->port_id, 3813 &resource->action); 3814 if (ret) { 3815 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx); 3816 rte_flow_error_set(ctx->error, ENOMEM, 3817 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3818 "cannot create action"); 3819 return NULL; 3820 } 3821 resource->idx = idx; 3822 return &resource->entry; 3823 } 3824 3825 struct mlx5_list_entry * 3826 flow_dv_port_id_clone_cb(void *tool_ctx, 3827 struct mlx5_list_entry *entry __rte_unused, 3828 void *cb_ctx) 3829 { 3830 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3831 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3832 struct mlx5_flow_dv_port_id_action_resource *resource; 3833 uint32_t idx; 3834 3835 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx); 3836 if (!resource) { 3837 rte_flow_error_set(ctx->error, ENOMEM, 3838 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3839 "cannot allocate port_id action memory"); 3840 return NULL; 3841 } 3842 memcpy(resource, entry, sizeof(*resource)); 3843 resource->idx = idx; 3844 return &resource->entry; 3845 } 3846 3847 void 3848 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3849 { 3850 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3851 struct mlx5_flow_dv_port_id_action_resource *resource = 3852 container_of(entry, typeof(*resource), entry); 3853 3854 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 3855 } 3856 3857 /** 3858 * Find existing table port ID resource or create and register a new one. 3859 * 3860 * @param[in, out] dev 3861 * Pointer to rte_eth_dev structure. 3862 * @param[in, out] ref 3863 * Pointer to port ID action resource reference. 3864 * @parm[in, out] dev_flow 3865 * Pointer to the dev_flow. 3866 * @param[out] error 3867 * pointer to error structure. 3868 * 3869 * @return 3870 * 0 on success otherwise -errno and errno is set. 3871 */ 3872 static int 3873 flow_dv_port_id_action_resource_register 3874 (struct rte_eth_dev *dev, 3875 struct mlx5_flow_dv_port_id_action_resource *ref, 3876 struct mlx5_flow *dev_flow, 3877 struct rte_flow_error *error) 3878 { 3879 struct mlx5_priv *priv = dev->data->dev_private; 3880 struct mlx5_list_entry *entry; 3881 struct mlx5_flow_dv_port_id_action_resource *resource; 3882 struct mlx5_flow_cb_ctx ctx = { 3883 .error = error, 3884 .data = ref, 3885 }; 3886 3887 entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx); 3888 if (!entry) 3889 return -rte_errno; 3890 resource = container_of(entry, typeof(*resource), entry); 3891 dev_flow->dv.port_id_action = resource; 3892 dev_flow->handle->rix_port_id_action = resource->idx; 3893 return 0; 3894 } 3895 3896 int 3897 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused, 3898 struct mlx5_list_entry *entry, void *cb_ctx) 3899 { 3900 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3901 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3902 struct mlx5_flow_dv_push_vlan_action_resource *res = 3903 container_of(entry, typeof(*res), entry); 3904 3905 return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type; 3906 } 3907 3908 struct mlx5_list_entry * 3909 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx) 3910 { 3911 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3912 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3913 struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data; 3914 struct mlx5_flow_dv_push_vlan_action_resource *resource; 3915 struct mlx5dv_dr_domain *domain; 3916 uint32_t idx; 3917 int ret; 3918 3919 /* Register new port id action resource. */ 3920 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 3921 if (!resource) { 3922 rte_flow_error_set(ctx->error, ENOMEM, 3923 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3924 "cannot allocate push_vlan action memory"); 3925 return NULL; 3926 } 3927 *resource = *ref; 3928 if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 3929 domain = sh->fdb_domain; 3930 else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 3931 domain = sh->rx_domain; 3932 else 3933 domain = sh->tx_domain; 3934 ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag, 3935 &resource->action); 3936 if (ret) { 3937 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 3938 rte_flow_error_set(ctx->error, ENOMEM, 3939 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3940 "cannot create push vlan action"); 3941 return NULL; 3942 } 3943 resource->idx = idx; 3944 return &resource->entry; 3945 } 3946 3947 struct mlx5_list_entry * 3948 flow_dv_push_vlan_clone_cb(void *tool_ctx, 3949 struct mlx5_list_entry *entry __rte_unused, 3950 void *cb_ctx) 3951 { 3952 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3953 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 3954 struct mlx5_flow_dv_push_vlan_action_resource *resource; 3955 uint32_t idx; 3956 3957 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx); 3958 if (!resource) { 3959 rte_flow_error_set(ctx->error, ENOMEM, 3960 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 3961 "cannot allocate push_vlan action memory"); 3962 return NULL; 3963 } 3964 memcpy(resource, entry, sizeof(*resource)); 3965 resource->idx = idx; 3966 return &resource->entry; 3967 } 3968 3969 void 3970 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 3971 { 3972 struct mlx5_dev_ctx_shared *sh = tool_ctx; 3973 struct mlx5_flow_dv_push_vlan_action_resource *resource = 3974 container_of(entry, typeof(*resource), entry); 3975 3976 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 3977 } 3978 3979 /** 3980 * Find existing push vlan resource or create and register a new one. 3981 * 3982 * @param [in, out] dev 3983 * Pointer to rte_eth_dev structure. 3984 * @param[in, out] ref 3985 * Pointer to port ID action resource reference. 3986 * @parm[in, out] dev_flow 3987 * Pointer to the dev_flow. 3988 * @param[out] error 3989 * pointer to error structure. 3990 * 3991 * @return 3992 * 0 on success otherwise -errno and errno is set. 3993 */ 3994 static int 3995 flow_dv_push_vlan_action_resource_register 3996 (struct rte_eth_dev *dev, 3997 struct mlx5_flow_dv_push_vlan_action_resource *ref, 3998 struct mlx5_flow *dev_flow, 3999 struct rte_flow_error *error) 4000 { 4001 struct mlx5_priv *priv = dev->data->dev_private; 4002 struct mlx5_flow_dv_push_vlan_action_resource *resource; 4003 struct mlx5_list_entry *entry; 4004 struct mlx5_flow_cb_ctx ctx = { 4005 .error = error, 4006 .data = ref, 4007 }; 4008 4009 entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx); 4010 if (!entry) 4011 return -rte_errno; 4012 resource = container_of(entry, typeof(*resource), entry); 4013 4014 dev_flow->handle->dvh.rix_push_vlan = resource->idx; 4015 dev_flow->dv.push_vlan_res = resource; 4016 return 0; 4017 } 4018 4019 /** 4020 * Get the size of specific rte_flow_item_type hdr size 4021 * 4022 * @param[in] item_type 4023 * Tested rte_flow_item_type. 4024 * 4025 * @return 4026 * sizeof struct item_type, 0 if void or irrelevant. 4027 */ 4028 static size_t 4029 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type) 4030 { 4031 size_t retval; 4032 4033 switch (item_type) { 4034 case RTE_FLOW_ITEM_TYPE_ETH: 4035 retval = sizeof(struct rte_ether_hdr); 4036 break; 4037 case RTE_FLOW_ITEM_TYPE_VLAN: 4038 retval = sizeof(struct rte_vlan_hdr); 4039 break; 4040 case RTE_FLOW_ITEM_TYPE_IPV4: 4041 retval = sizeof(struct rte_ipv4_hdr); 4042 break; 4043 case RTE_FLOW_ITEM_TYPE_IPV6: 4044 retval = sizeof(struct rte_ipv6_hdr); 4045 break; 4046 case RTE_FLOW_ITEM_TYPE_UDP: 4047 retval = sizeof(struct rte_udp_hdr); 4048 break; 4049 case RTE_FLOW_ITEM_TYPE_TCP: 4050 retval = sizeof(struct rte_tcp_hdr); 4051 break; 4052 case RTE_FLOW_ITEM_TYPE_VXLAN: 4053 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4054 retval = sizeof(struct rte_vxlan_hdr); 4055 break; 4056 case RTE_FLOW_ITEM_TYPE_GRE: 4057 case RTE_FLOW_ITEM_TYPE_NVGRE: 4058 retval = sizeof(struct rte_gre_hdr); 4059 break; 4060 case RTE_FLOW_ITEM_TYPE_MPLS: 4061 retval = sizeof(struct rte_mpls_hdr); 4062 break; 4063 case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */ 4064 default: 4065 retval = 0; 4066 break; 4067 } 4068 return retval; 4069 } 4070 4071 #define MLX5_ENCAP_IPV4_VERSION 0x40 4072 #define MLX5_ENCAP_IPV4_IHL_MIN 0x05 4073 #define MLX5_ENCAP_IPV4_TTL_DEF 0x40 4074 #define MLX5_ENCAP_IPV6_VTC_FLOW 0x60000000 4075 #define MLX5_ENCAP_IPV6_HOP_LIMIT 0xff 4076 #define MLX5_ENCAP_VXLAN_FLAGS 0x08000000 4077 #define MLX5_ENCAP_VXLAN_GPE_FLAGS 0x04 4078 4079 /** 4080 * Convert the encap action data from list of rte_flow_item to raw buffer 4081 * 4082 * @param[in] items 4083 * Pointer to rte_flow_item objects list. 4084 * @param[out] buf 4085 * Pointer to the output buffer. 4086 * @param[out] size 4087 * Pointer to the output buffer size. 4088 * @param[out] error 4089 * Pointer to the error structure. 4090 * 4091 * @return 4092 * 0 on success, a negative errno value otherwise and rte_errno is set. 4093 */ 4094 static int 4095 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf, 4096 size_t *size, struct rte_flow_error *error) 4097 { 4098 struct rte_ether_hdr *eth = NULL; 4099 struct rte_vlan_hdr *vlan = NULL; 4100 struct rte_ipv4_hdr *ipv4 = NULL; 4101 struct rte_ipv6_hdr *ipv6 = NULL; 4102 struct rte_udp_hdr *udp = NULL; 4103 struct rte_vxlan_hdr *vxlan = NULL; 4104 struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL; 4105 struct rte_gre_hdr *gre = NULL; 4106 size_t len; 4107 size_t temp_size = 0; 4108 4109 if (!items) 4110 return rte_flow_error_set(error, EINVAL, 4111 RTE_FLOW_ERROR_TYPE_ACTION, 4112 NULL, "invalid empty data"); 4113 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 4114 len = flow_dv_get_item_hdr_len(items->type); 4115 if (len + temp_size > MLX5_ENCAP_MAX_LEN) 4116 return rte_flow_error_set(error, EINVAL, 4117 RTE_FLOW_ERROR_TYPE_ACTION, 4118 (void *)items->type, 4119 "items total size is too big" 4120 " for encap action"); 4121 rte_memcpy((void *)&buf[temp_size], items->spec, len); 4122 switch (items->type) { 4123 case RTE_FLOW_ITEM_TYPE_ETH: 4124 eth = (struct rte_ether_hdr *)&buf[temp_size]; 4125 break; 4126 case RTE_FLOW_ITEM_TYPE_VLAN: 4127 vlan = (struct rte_vlan_hdr *)&buf[temp_size]; 4128 if (!eth) 4129 return rte_flow_error_set(error, EINVAL, 4130 RTE_FLOW_ERROR_TYPE_ACTION, 4131 (void *)items->type, 4132 "eth header not found"); 4133 if (!eth->ether_type) 4134 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN); 4135 break; 4136 case RTE_FLOW_ITEM_TYPE_IPV4: 4137 ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size]; 4138 if (!vlan && !eth) 4139 return rte_flow_error_set(error, EINVAL, 4140 RTE_FLOW_ERROR_TYPE_ACTION, 4141 (void *)items->type, 4142 "neither eth nor vlan" 4143 " header found"); 4144 if (vlan && !vlan->eth_proto) 4145 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4146 else if (eth && !eth->ether_type) 4147 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4); 4148 if (!ipv4->version_ihl) 4149 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION | 4150 MLX5_ENCAP_IPV4_IHL_MIN; 4151 if (!ipv4->time_to_live) 4152 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF; 4153 break; 4154 case RTE_FLOW_ITEM_TYPE_IPV6: 4155 ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size]; 4156 if (!vlan && !eth) 4157 return rte_flow_error_set(error, EINVAL, 4158 RTE_FLOW_ERROR_TYPE_ACTION, 4159 (void *)items->type, 4160 "neither eth nor vlan" 4161 " header found"); 4162 if (vlan && !vlan->eth_proto) 4163 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4164 else if (eth && !eth->ether_type) 4165 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6); 4166 if (!ipv6->vtc_flow) 4167 ipv6->vtc_flow = 4168 RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW); 4169 if (!ipv6->hop_limits) 4170 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT; 4171 break; 4172 case RTE_FLOW_ITEM_TYPE_UDP: 4173 udp = (struct rte_udp_hdr *)&buf[temp_size]; 4174 if (!ipv4 && !ipv6) 4175 return rte_flow_error_set(error, EINVAL, 4176 RTE_FLOW_ERROR_TYPE_ACTION, 4177 (void *)items->type, 4178 "ip header not found"); 4179 if (ipv4 && !ipv4->next_proto_id) 4180 ipv4->next_proto_id = IPPROTO_UDP; 4181 else if (ipv6 && !ipv6->proto) 4182 ipv6->proto = IPPROTO_UDP; 4183 break; 4184 case RTE_FLOW_ITEM_TYPE_VXLAN: 4185 vxlan = (struct rte_vxlan_hdr *)&buf[temp_size]; 4186 if (!udp) 4187 return rte_flow_error_set(error, EINVAL, 4188 RTE_FLOW_ERROR_TYPE_ACTION, 4189 (void *)items->type, 4190 "udp header not found"); 4191 if (!udp->dst_port) 4192 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN); 4193 if (!vxlan->vx_flags) 4194 vxlan->vx_flags = 4195 RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS); 4196 break; 4197 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 4198 vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size]; 4199 if (!udp) 4200 return rte_flow_error_set(error, EINVAL, 4201 RTE_FLOW_ERROR_TYPE_ACTION, 4202 (void *)items->type, 4203 "udp header not found"); 4204 if (!vxlan_gpe->proto) 4205 return rte_flow_error_set(error, EINVAL, 4206 RTE_FLOW_ERROR_TYPE_ACTION, 4207 (void *)items->type, 4208 "next protocol not found"); 4209 if (!udp->dst_port) 4210 udp->dst_port = 4211 RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE); 4212 if (!vxlan_gpe->vx_flags) 4213 vxlan_gpe->vx_flags = 4214 MLX5_ENCAP_VXLAN_GPE_FLAGS; 4215 break; 4216 case RTE_FLOW_ITEM_TYPE_GRE: 4217 case RTE_FLOW_ITEM_TYPE_NVGRE: 4218 gre = (struct rte_gre_hdr *)&buf[temp_size]; 4219 if (!gre->proto) 4220 return rte_flow_error_set(error, EINVAL, 4221 RTE_FLOW_ERROR_TYPE_ACTION, 4222 (void *)items->type, 4223 "next protocol not found"); 4224 if (!ipv4 && !ipv6) 4225 return rte_flow_error_set(error, EINVAL, 4226 RTE_FLOW_ERROR_TYPE_ACTION, 4227 (void *)items->type, 4228 "ip header not found"); 4229 if (ipv4 && !ipv4->next_proto_id) 4230 ipv4->next_proto_id = IPPROTO_GRE; 4231 else if (ipv6 && !ipv6->proto) 4232 ipv6->proto = IPPROTO_GRE; 4233 break; 4234 case RTE_FLOW_ITEM_TYPE_VOID: 4235 break; 4236 default: 4237 return rte_flow_error_set(error, EINVAL, 4238 RTE_FLOW_ERROR_TYPE_ACTION, 4239 (void *)items->type, 4240 "unsupported item type"); 4241 break; 4242 } 4243 temp_size += len; 4244 } 4245 *size = temp_size; 4246 return 0; 4247 } 4248 4249 static int 4250 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error) 4251 { 4252 struct rte_ether_hdr *eth = NULL; 4253 struct rte_vlan_hdr *vlan = NULL; 4254 struct rte_ipv6_hdr *ipv6 = NULL; 4255 struct rte_udp_hdr *udp = NULL; 4256 char *next_hdr; 4257 uint16_t proto; 4258 4259 eth = (struct rte_ether_hdr *)data; 4260 next_hdr = (char *)(eth + 1); 4261 proto = RTE_BE16(eth->ether_type); 4262 4263 /* VLAN skipping */ 4264 while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) { 4265 vlan = (struct rte_vlan_hdr *)next_hdr; 4266 proto = RTE_BE16(vlan->eth_proto); 4267 next_hdr += sizeof(struct rte_vlan_hdr); 4268 } 4269 4270 /* HW calculates IPv4 csum. no need to proceed */ 4271 if (proto == RTE_ETHER_TYPE_IPV4) 4272 return 0; 4273 4274 /* non IPv4/IPv6 header. not supported */ 4275 if (proto != RTE_ETHER_TYPE_IPV6) { 4276 return rte_flow_error_set(error, ENOTSUP, 4277 RTE_FLOW_ERROR_TYPE_ACTION, 4278 NULL, "Cannot offload non IPv4/IPv6"); 4279 } 4280 4281 ipv6 = (struct rte_ipv6_hdr *)next_hdr; 4282 4283 /* ignore non UDP */ 4284 if (ipv6->proto != IPPROTO_UDP) 4285 return 0; 4286 4287 udp = (struct rte_udp_hdr *)(ipv6 + 1); 4288 udp->dgram_cksum = 0; 4289 4290 return 0; 4291 } 4292 4293 /** 4294 * Convert L2 encap action to DV specification. 4295 * 4296 * @param[in] dev 4297 * Pointer to rte_eth_dev structure. 4298 * @param[in] action 4299 * Pointer to action structure. 4300 * @param[in, out] dev_flow 4301 * Pointer to the mlx5_flow. 4302 * @param[in] transfer 4303 * Mark if the flow is E-Switch flow. 4304 * @param[out] error 4305 * Pointer to the error structure. 4306 * 4307 * @return 4308 * 0 on success, a negative errno value otherwise and rte_errno is set. 4309 */ 4310 static int 4311 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev, 4312 const struct rte_flow_action *action, 4313 struct mlx5_flow *dev_flow, 4314 uint8_t transfer, 4315 struct rte_flow_error *error) 4316 { 4317 const struct rte_flow_item *encap_data; 4318 const struct rte_flow_action_raw_encap *raw_encap_data; 4319 struct mlx5_flow_dv_encap_decap_resource res = { 4320 .reformat_type = 4321 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL, 4322 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4323 MLX5DV_FLOW_TABLE_TYPE_NIC_TX, 4324 }; 4325 4326 if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 4327 raw_encap_data = 4328 (const struct rte_flow_action_raw_encap *)action->conf; 4329 res.size = raw_encap_data->size; 4330 memcpy(res.buf, raw_encap_data->data, res.size); 4331 } else { 4332 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) 4333 encap_data = 4334 ((const struct rte_flow_action_vxlan_encap *) 4335 action->conf)->definition; 4336 else 4337 encap_data = 4338 ((const struct rte_flow_action_nvgre_encap *) 4339 action->conf)->definition; 4340 if (flow_dv_convert_encap_data(encap_data, res.buf, 4341 &res.size, error)) 4342 return -rte_errno; 4343 } 4344 if (flow_dv_zero_encap_udp_csum(res.buf, error)) 4345 return -rte_errno; 4346 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4347 return rte_flow_error_set(error, EINVAL, 4348 RTE_FLOW_ERROR_TYPE_ACTION, 4349 NULL, "can't create L2 encap action"); 4350 return 0; 4351 } 4352 4353 /** 4354 * Convert L2 decap action to DV specification. 4355 * 4356 * @param[in] dev 4357 * Pointer to rte_eth_dev structure. 4358 * @param[in, out] dev_flow 4359 * Pointer to the mlx5_flow. 4360 * @param[in] transfer 4361 * Mark if the flow is E-Switch flow. 4362 * @param[out] error 4363 * Pointer to the error structure. 4364 * 4365 * @return 4366 * 0 on success, a negative errno value otherwise and rte_errno is set. 4367 */ 4368 static int 4369 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev, 4370 struct mlx5_flow *dev_flow, 4371 uint8_t transfer, 4372 struct rte_flow_error *error) 4373 { 4374 struct mlx5_flow_dv_encap_decap_resource res = { 4375 .size = 0, 4376 .reformat_type = 4377 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2, 4378 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 4379 MLX5DV_FLOW_TABLE_TYPE_NIC_RX, 4380 }; 4381 4382 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4383 return rte_flow_error_set(error, EINVAL, 4384 RTE_FLOW_ERROR_TYPE_ACTION, 4385 NULL, "can't create L2 decap action"); 4386 return 0; 4387 } 4388 4389 /** 4390 * Convert raw decap/encap (L3 tunnel) action to DV specification. 4391 * 4392 * @param[in] dev 4393 * Pointer to rte_eth_dev structure. 4394 * @param[in] action 4395 * Pointer to action structure. 4396 * @param[in, out] dev_flow 4397 * Pointer to the mlx5_flow. 4398 * @param[in] attr 4399 * Pointer to the flow attributes. 4400 * @param[out] error 4401 * Pointer to the error structure. 4402 * 4403 * @return 4404 * 0 on success, a negative errno value otherwise and rte_errno is set. 4405 */ 4406 static int 4407 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev, 4408 const struct rte_flow_action *action, 4409 struct mlx5_flow *dev_flow, 4410 const struct rte_flow_attr *attr, 4411 struct rte_flow_error *error) 4412 { 4413 const struct rte_flow_action_raw_encap *encap_data; 4414 struct mlx5_flow_dv_encap_decap_resource res; 4415 4416 memset(&res, 0, sizeof(res)); 4417 encap_data = (const struct rte_flow_action_raw_encap *)action->conf; 4418 res.size = encap_data->size; 4419 memcpy(res.buf, encap_data->data, res.size); 4420 res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ? 4421 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 : 4422 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 4423 if (attr->transfer) 4424 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4425 else 4426 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4427 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4428 if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error)) 4429 return rte_flow_error_set(error, EINVAL, 4430 RTE_FLOW_ERROR_TYPE_ACTION, 4431 NULL, "can't create encap action"); 4432 return 0; 4433 } 4434 4435 /** 4436 * Create action push VLAN. 4437 * 4438 * @param[in] dev 4439 * Pointer to rte_eth_dev structure. 4440 * @param[in] attr 4441 * Pointer to the flow attributes. 4442 * @param[in] vlan 4443 * Pointer to the vlan to push to the Ethernet header. 4444 * @param[in, out] dev_flow 4445 * Pointer to the mlx5_flow. 4446 * @param[out] error 4447 * Pointer to the error structure. 4448 * 4449 * @return 4450 * 0 on success, a negative errno value otherwise and rte_errno is set. 4451 */ 4452 static int 4453 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, 4454 const struct rte_flow_attr *attr, 4455 const struct rte_vlan_hdr *vlan, 4456 struct mlx5_flow *dev_flow, 4457 struct rte_flow_error *error) 4458 { 4459 struct mlx5_flow_dv_push_vlan_action_resource res; 4460 4461 memset(&res, 0, sizeof(res)); 4462 res.vlan_tag = 4463 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 | 4464 vlan->vlan_tci); 4465 if (attr->transfer) 4466 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 4467 else 4468 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 4469 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 4470 return flow_dv_push_vlan_action_resource_register 4471 (dev, &res, dev_flow, error); 4472 } 4473 4474 /** 4475 * Validate the modify-header actions. 4476 * 4477 * @param[in] action_flags 4478 * Holds the actions detected until now. 4479 * @param[in] action 4480 * Pointer to the modify action. 4481 * @param[out] error 4482 * Pointer to error structure. 4483 * 4484 * @return 4485 * 0 on success, a negative errno value otherwise and rte_errno is set. 4486 */ 4487 static int 4488 flow_dv_validate_action_modify_hdr(const uint64_t action_flags, 4489 const struct rte_flow_action *action, 4490 struct rte_flow_error *error) 4491 { 4492 if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf) 4493 return rte_flow_error_set(error, EINVAL, 4494 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4495 NULL, "action configuration not set"); 4496 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 4497 return rte_flow_error_set(error, EINVAL, 4498 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4499 "can't have encap action before" 4500 " modify action"); 4501 return 0; 4502 } 4503 4504 /** 4505 * Validate the modify-header MAC address actions. 4506 * 4507 * @param[in] action_flags 4508 * Holds the actions detected until now. 4509 * @param[in] action 4510 * Pointer to the modify action. 4511 * @param[in] item_flags 4512 * Holds the items detected. 4513 * @param[out] error 4514 * Pointer to error structure. 4515 * 4516 * @return 4517 * 0 on success, a negative errno value otherwise and rte_errno is set. 4518 */ 4519 static int 4520 flow_dv_validate_action_modify_mac(const uint64_t action_flags, 4521 const struct rte_flow_action *action, 4522 const uint64_t item_flags, 4523 struct rte_flow_error *error) 4524 { 4525 int ret = 0; 4526 4527 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4528 if (!ret) { 4529 if (!(item_flags & MLX5_FLOW_LAYER_L2)) 4530 return rte_flow_error_set(error, EINVAL, 4531 RTE_FLOW_ERROR_TYPE_ACTION, 4532 NULL, 4533 "no L2 item in pattern"); 4534 } 4535 return ret; 4536 } 4537 4538 /** 4539 * Validate the modify-header IPv4 address actions. 4540 * 4541 * @param[in] action_flags 4542 * Holds the actions detected until now. 4543 * @param[in] action 4544 * Pointer to the modify action. 4545 * @param[in] item_flags 4546 * Holds the items detected. 4547 * @param[out] error 4548 * Pointer to error structure. 4549 * 4550 * @return 4551 * 0 on success, a negative errno value otherwise and rte_errno is set. 4552 */ 4553 static int 4554 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags, 4555 const struct rte_flow_action *action, 4556 const uint64_t item_flags, 4557 struct rte_flow_error *error) 4558 { 4559 int ret = 0; 4560 uint64_t layer; 4561 4562 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4563 if (!ret) { 4564 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4565 MLX5_FLOW_LAYER_INNER_L3_IPV4 : 4566 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 4567 if (!(item_flags & layer)) 4568 return rte_flow_error_set(error, EINVAL, 4569 RTE_FLOW_ERROR_TYPE_ACTION, 4570 NULL, 4571 "no ipv4 item in pattern"); 4572 } 4573 return ret; 4574 } 4575 4576 /** 4577 * Validate the modify-header IPv6 address actions. 4578 * 4579 * @param[in] action_flags 4580 * Holds the actions detected until now. 4581 * @param[in] action 4582 * Pointer to the modify action. 4583 * @param[in] item_flags 4584 * Holds the items detected. 4585 * @param[out] error 4586 * Pointer to error structure. 4587 * 4588 * @return 4589 * 0 on success, a negative errno value otherwise and rte_errno is set. 4590 */ 4591 static int 4592 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags, 4593 const struct rte_flow_action *action, 4594 const uint64_t item_flags, 4595 struct rte_flow_error *error) 4596 { 4597 int ret = 0; 4598 uint64_t layer; 4599 4600 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4601 if (!ret) { 4602 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4603 MLX5_FLOW_LAYER_INNER_L3_IPV6 : 4604 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 4605 if (!(item_flags & layer)) 4606 return rte_flow_error_set(error, EINVAL, 4607 RTE_FLOW_ERROR_TYPE_ACTION, 4608 NULL, 4609 "no ipv6 item in pattern"); 4610 } 4611 return ret; 4612 } 4613 4614 /** 4615 * Validate the modify-header TP actions. 4616 * 4617 * @param[in] action_flags 4618 * Holds the actions detected until now. 4619 * @param[in] action 4620 * Pointer to the modify action. 4621 * @param[in] item_flags 4622 * Holds the items detected. 4623 * @param[out] error 4624 * Pointer to error structure. 4625 * 4626 * @return 4627 * 0 on success, a negative errno value otherwise and rte_errno is set. 4628 */ 4629 static int 4630 flow_dv_validate_action_modify_tp(const uint64_t action_flags, 4631 const struct rte_flow_action *action, 4632 const uint64_t item_flags, 4633 struct rte_flow_error *error) 4634 { 4635 int ret = 0; 4636 uint64_t layer; 4637 4638 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4639 if (!ret) { 4640 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4641 MLX5_FLOW_LAYER_INNER_L4 : 4642 MLX5_FLOW_LAYER_OUTER_L4; 4643 if (!(item_flags & layer)) 4644 return rte_flow_error_set(error, EINVAL, 4645 RTE_FLOW_ERROR_TYPE_ACTION, 4646 NULL, "no transport layer " 4647 "in pattern"); 4648 } 4649 return ret; 4650 } 4651 4652 /** 4653 * Validate the modify-header actions of increment/decrement 4654 * TCP Sequence-number. 4655 * 4656 * @param[in] action_flags 4657 * Holds the actions detected until now. 4658 * @param[in] action 4659 * Pointer to the modify action. 4660 * @param[in] item_flags 4661 * Holds the items detected. 4662 * @param[out] error 4663 * Pointer to error structure. 4664 * 4665 * @return 4666 * 0 on success, a negative errno value otherwise and rte_errno is set. 4667 */ 4668 static int 4669 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags, 4670 const struct rte_flow_action *action, 4671 const uint64_t item_flags, 4672 struct rte_flow_error *error) 4673 { 4674 int ret = 0; 4675 uint64_t layer; 4676 4677 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4678 if (!ret) { 4679 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4680 MLX5_FLOW_LAYER_INNER_L4_TCP : 4681 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4682 if (!(item_flags & layer)) 4683 return rte_flow_error_set(error, EINVAL, 4684 RTE_FLOW_ERROR_TYPE_ACTION, 4685 NULL, "no TCP item in" 4686 " pattern"); 4687 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ && 4688 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) || 4689 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ && 4690 (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ))) 4691 return rte_flow_error_set(error, EINVAL, 4692 RTE_FLOW_ERROR_TYPE_ACTION, 4693 NULL, 4694 "cannot decrease and increase" 4695 " TCP sequence number" 4696 " at the same time"); 4697 } 4698 return ret; 4699 } 4700 4701 /** 4702 * Validate the modify-header actions of increment/decrement 4703 * TCP Acknowledgment number. 4704 * 4705 * @param[in] action_flags 4706 * Holds the actions detected until now. 4707 * @param[in] action 4708 * Pointer to the modify action. 4709 * @param[in] item_flags 4710 * Holds the items detected. 4711 * @param[out] error 4712 * Pointer to error structure. 4713 * 4714 * @return 4715 * 0 on success, a negative errno value otherwise and rte_errno is set. 4716 */ 4717 static int 4718 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags, 4719 const struct rte_flow_action *action, 4720 const uint64_t item_flags, 4721 struct rte_flow_error *error) 4722 { 4723 int ret = 0; 4724 uint64_t layer; 4725 4726 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4727 if (!ret) { 4728 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4729 MLX5_FLOW_LAYER_INNER_L4_TCP : 4730 MLX5_FLOW_LAYER_OUTER_L4_TCP; 4731 if (!(item_flags & layer)) 4732 return rte_flow_error_set(error, EINVAL, 4733 RTE_FLOW_ERROR_TYPE_ACTION, 4734 NULL, "no TCP item in" 4735 " pattern"); 4736 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK && 4737 (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) || 4738 (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK && 4739 (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK))) 4740 return rte_flow_error_set(error, EINVAL, 4741 RTE_FLOW_ERROR_TYPE_ACTION, 4742 NULL, 4743 "cannot decrease and increase" 4744 " TCP acknowledgment number" 4745 " at the same time"); 4746 } 4747 return ret; 4748 } 4749 4750 /** 4751 * Validate the modify-header TTL actions. 4752 * 4753 * @param[in] action_flags 4754 * Holds the actions detected until now. 4755 * @param[in] action 4756 * Pointer to the modify action. 4757 * @param[in] item_flags 4758 * Holds the items detected. 4759 * @param[out] error 4760 * Pointer to error structure. 4761 * 4762 * @return 4763 * 0 on success, a negative errno value otherwise and rte_errno is set. 4764 */ 4765 static int 4766 flow_dv_validate_action_modify_ttl(const uint64_t action_flags, 4767 const struct rte_flow_action *action, 4768 const uint64_t item_flags, 4769 struct rte_flow_error *error) 4770 { 4771 int ret = 0; 4772 uint64_t layer; 4773 4774 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4775 if (!ret) { 4776 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ? 4777 MLX5_FLOW_LAYER_INNER_L3 : 4778 MLX5_FLOW_LAYER_OUTER_L3; 4779 if (!(item_flags & layer)) 4780 return rte_flow_error_set(error, EINVAL, 4781 RTE_FLOW_ERROR_TYPE_ACTION, 4782 NULL, 4783 "no IP protocol in pattern"); 4784 } 4785 return ret; 4786 } 4787 4788 /** 4789 * Validate the generic modify field actions. 4790 * @param[in] dev 4791 * Pointer to the rte_eth_dev structure. 4792 * @param[in] action_flags 4793 * Holds the actions detected until now. 4794 * @param[in] action 4795 * Pointer to the modify action. 4796 * @param[in] attr 4797 * Pointer to the flow attributes. 4798 * @param[out] error 4799 * Pointer to error structure. 4800 * 4801 * @return 4802 * Number of header fields to modify (0 or more) on success, 4803 * a negative errno value otherwise and rte_errno is set. 4804 */ 4805 static int 4806 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, 4807 const uint64_t action_flags, 4808 const struct rte_flow_action *action, 4809 const struct rte_flow_attr *attr, 4810 struct rte_flow_error *error) 4811 { 4812 int ret = 0; 4813 struct mlx5_priv *priv = dev->data->dev_private; 4814 struct mlx5_dev_config *config = &priv->config; 4815 const struct rte_flow_action_modify_field *action_modify_field = 4816 action->conf; 4817 uint32_t dst_width = mlx5_flow_item_field_width(dev, 4818 action_modify_field->dst.field, 4819 -1, attr, error); 4820 uint32_t src_width = mlx5_flow_item_field_width(dev, 4821 action_modify_field->src.field, 4822 dst_width, attr, error); 4823 4824 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 4825 if (ret) 4826 return ret; 4827 4828 if (action_modify_field->width == 0) 4829 return rte_flow_error_set(error, EINVAL, 4830 RTE_FLOW_ERROR_TYPE_ACTION, action, 4831 "no bits are requested to be modified"); 4832 else if (action_modify_field->width > dst_width || 4833 action_modify_field->width > src_width) 4834 return rte_flow_error_set(error, EINVAL, 4835 RTE_FLOW_ERROR_TYPE_ACTION, action, 4836 "cannot modify more bits than" 4837 " the width of a field"); 4838 if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE && 4839 action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) { 4840 if ((action_modify_field->dst.offset + 4841 action_modify_field->width > dst_width) || 4842 (action_modify_field->dst.offset % 32)) 4843 return rte_flow_error_set(error, EINVAL, 4844 RTE_FLOW_ERROR_TYPE_ACTION, action, 4845 "destination offset is too big" 4846 " or not aligned to 4 bytes"); 4847 if (action_modify_field->dst.level && 4848 action_modify_field->dst.field != RTE_FLOW_FIELD_TAG) 4849 return rte_flow_error_set(error, ENOTSUP, 4850 RTE_FLOW_ERROR_TYPE_ACTION, action, 4851 "inner header fields modification" 4852 " is not supported"); 4853 } 4854 if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE && 4855 action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) { 4856 if (!attr->transfer && !attr->group) 4857 return rte_flow_error_set(error, ENOTSUP, 4858 RTE_FLOW_ERROR_TYPE_ACTION, action, 4859 "modify field action is not" 4860 " supported for group 0"); 4861 if ((action_modify_field->src.offset + 4862 action_modify_field->width > src_width) || 4863 (action_modify_field->src.offset % 32)) 4864 return rte_flow_error_set(error, EINVAL, 4865 RTE_FLOW_ERROR_TYPE_ACTION, action, 4866 "source offset is too big" 4867 " or not aligned to 4 bytes"); 4868 if (action_modify_field->src.level && 4869 action_modify_field->src.field != RTE_FLOW_FIELD_TAG) 4870 return rte_flow_error_set(error, ENOTSUP, 4871 RTE_FLOW_ERROR_TYPE_ACTION, action, 4872 "inner header fields modification" 4873 " is not supported"); 4874 } 4875 if ((action_modify_field->dst.field == 4876 action_modify_field->src.field) && 4877 (action_modify_field->dst.level == 4878 action_modify_field->src.level)) 4879 return rte_flow_error_set(error, EINVAL, 4880 RTE_FLOW_ERROR_TYPE_ACTION, action, 4881 "source and destination fields" 4882 " cannot be the same"); 4883 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE || 4884 action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER || 4885 action_modify_field->dst.field == RTE_FLOW_FIELD_MARK) 4886 return rte_flow_error_set(error, EINVAL, 4887 RTE_FLOW_ERROR_TYPE_ACTION, action, 4888 "mark, immediate value or a pointer to it" 4889 " cannot be used as a destination"); 4890 if (action_modify_field->dst.field == RTE_FLOW_FIELD_START || 4891 action_modify_field->src.field == RTE_FLOW_FIELD_START) 4892 return rte_flow_error_set(error, ENOTSUP, 4893 RTE_FLOW_ERROR_TYPE_ACTION, action, 4894 "modifications of an arbitrary" 4895 " place in a packet is not supported"); 4896 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE || 4897 action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE) 4898 return rte_flow_error_set(error, ENOTSUP, 4899 RTE_FLOW_ERROR_TYPE_ACTION, action, 4900 "modifications of the 802.1Q Tag" 4901 " Identifier is not supported"); 4902 if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI || 4903 action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI) 4904 return rte_flow_error_set(error, ENOTSUP, 4905 RTE_FLOW_ERROR_TYPE_ACTION, action, 4906 "modifications of the VXLAN Network" 4907 " Identifier is not supported"); 4908 if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI || 4909 action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI) 4910 return rte_flow_error_set(error, ENOTSUP, 4911 RTE_FLOW_ERROR_TYPE_ACTION, action, 4912 "modifications of the GENEVE Network" 4913 " Identifier is not supported"); 4914 if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK || 4915 action_modify_field->src.field == RTE_FLOW_FIELD_MARK) 4916 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY || 4917 !mlx5_flow_ext_mreg_supported(dev)) 4918 return rte_flow_error_set(error, ENOTSUP, 4919 RTE_FLOW_ERROR_TYPE_ACTION, action, 4920 "cannot modify mark in legacy mode" 4921 " or without extensive registers"); 4922 if (action_modify_field->dst.field == RTE_FLOW_FIELD_META || 4923 action_modify_field->src.field == RTE_FLOW_FIELD_META) { 4924 if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 4925 !mlx5_flow_ext_mreg_supported(dev)) 4926 return rte_flow_error_set(error, ENOTSUP, 4927 RTE_FLOW_ERROR_TYPE_ACTION, action, 4928 "cannot modify meta without" 4929 " extensive registers support"); 4930 ret = flow_dv_get_metadata_reg(dev, attr, error); 4931 if (ret < 0 || ret == REG_NON) 4932 return rte_flow_error_set(error, ENOTSUP, 4933 RTE_FLOW_ERROR_TYPE_ACTION, action, 4934 "cannot modify meta without" 4935 " extensive registers available"); 4936 } 4937 if (action_modify_field->operation != RTE_FLOW_MODIFY_SET) 4938 return rte_flow_error_set(error, ENOTSUP, 4939 RTE_FLOW_ERROR_TYPE_ACTION, action, 4940 "add and sub operations" 4941 " are not supported"); 4942 return (action_modify_field->width / 32) + 4943 !!(action_modify_field->width % 32); 4944 } 4945 4946 /** 4947 * Validate jump action. 4948 * 4949 * @param[in] action 4950 * Pointer to the jump action. 4951 * @param[in] action_flags 4952 * Holds the actions detected until now. 4953 * @param[in] attributes 4954 * Pointer to flow attributes 4955 * @param[in] external 4956 * Action belongs to flow rule created by request external to PMD. 4957 * @param[out] error 4958 * Pointer to error structure. 4959 * 4960 * @return 4961 * 0 on success, a negative errno value otherwise and rte_errno is set. 4962 */ 4963 static int 4964 flow_dv_validate_action_jump(struct rte_eth_dev *dev, 4965 const struct mlx5_flow_tunnel *tunnel, 4966 const struct rte_flow_action *action, 4967 uint64_t action_flags, 4968 const struct rte_flow_attr *attributes, 4969 bool external, struct rte_flow_error *error) 4970 { 4971 uint32_t target_group, table; 4972 int ret = 0; 4973 struct flow_grp_info grp_info = { 4974 .external = !!external, 4975 .transfer = !!attributes->transfer, 4976 .fdb_def_rule = 1, 4977 .std_tbl_fix = 0 4978 }; 4979 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 4980 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 4981 return rte_flow_error_set(error, EINVAL, 4982 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 4983 "can't have 2 fate actions in" 4984 " same flow"); 4985 if (!action->conf) 4986 return rte_flow_error_set(error, EINVAL, 4987 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 4988 NULL, "action configuration not set"); 4989 target_group = 4990 ((const struct rte_flow_action_jump *)action->conf)->group; 4991 ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table, 4992 &grp_info, error); 4993 if (ret) 4994 return ret; 4995 if (attributes->group == target_group && 4996 !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET | 4997 MLX5_FLOW_ACTION_TUNNEL_MATCH))) 4998 return rte_flow_error_set(error, EINVAL, 4999 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5000 "target group must be other than" 5001 " the current flow group"); 5002 return 0; 5003 } 5004 5005 /* 5006 * Validate action PORT_ID / REPRESENTED_PORT. 5007 * 5008 * @param[in] dev 5009 * Pointer to rte_eth_dev structure. 5010 * @param[in] action_flags 5011 * Bit-fields that holds the actions detected until now. 5012 * @param[in] action 5013 * PORT_ID / REPRESENTED_PORT action structure. 5014 * @param[in] attr 5015 * Attributes of flow that includes this action. 5016 * @param[out] error 5017 * Pointer to error structure. 5018 * 5019 * @return 5020 * 0 on success, a negative errno value otherwise and rte_errno is set. 5021 */ 5022 static int 5023 flow_dv_validate_action_port_id(struct rte_eth_dev *dev, 5024 uint64_t action_flags, 5025 const struct rte_flow_action *action, 5026 const struct rte_flow_attr *attr, 5027 struct rte_flow_error *error) 5028 { 5029 const struct rte_flow_action_port_id *port_id; 5030 const struct rte_flow_action_ethdev *ethdev; 5031 struct mlx5_priv *act_priv; 5032 struct mlx5_priv *dev_priv; 5033 uint16_t port; 5034 5035 if (!attr->transfer) 5036 return rte_flow_error_set(error, ENOTSUP, 5037 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5038 NULL, 5039 "port action is valid in transfer" 5040 " mode only"); 5041 if (!action || !action->conf) 5042 return rte_flow_error_set(error, ENOTSUP, 5043 RTE_FLOW_ERROR_TYPE_ACTION_CONF, 5044 NULL, 5045 "port action parameters must be" 5046 " specified"); 5047 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 5048 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 5049 return rte_flow_error_set(error, EINVAL, 5050 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5051 "can have only one fate actions in" 5052 " a flow"); 5053 dev_priv = mlx5_dev_to_eswitch_info(dev); 5054 if (!dev_priv) 5055 return rte_flow_error_set(error, rte_errno, 5056 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5057 NULL, 5058 "failed to obtain E-Switch info"); 5059 switch (action->type) { 5060 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5061 port_id = action->conf; 5062 port = port_id->original ? dev->data->port_id : port_id->id; 5063 break; 5064 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5065 ethdev = action->conf; 5066 port = ethdev->port_id; 5067 break; 5068 default: 5069 MLX5_ASSERT(false); 5070 return rte_flow_error_set 5071 (error, EINVAL, 5072 RTE_FLOW_ERROR_TYPE_ACTION, action, 5073 "unknown E-Switch action"); 5074 } 5075 act_priv = mlx5_port_to_eswitch_info(port, false); 5076 if (!act_priv) 5077 return rte_flow_error_set 5078 (error, rte_errno, 5079 RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf, 5080 "failed to obtain E-Switch port id for port"); 5081 if (act_priv->domain_id != dev_priv->domain_id) 5082 return rte_flow_error_set 5083 (error, EINVAL, 5084 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5085 "port does not belong to" 5086 " E-Switch being configured"); 5087 return 0; 5088 } 5089 5090 /** 5091 * Get the maximum number of modify header actions. 5092 * 5093 * @param dev 5094 * Pointer to rte_eth_dev structure. 5095 * @param root 5096 * Whether action is on root table. 5097 * 5098 * @return 5099 * Max number of modify header actions device can support. 5100 */ 5101 static inline unsigned int 5102 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused, 5103 bool root) 5104 { 5105 /* 5106 * There's no way to directly query the max capacity from FW. 5107 * The maximal value on root table should be assumed to be supported. 5108 */ 5109 if (!root) 5110 return MLX5_MAX_MODIFY_NUM; 5111 else 5112 return MLX5_ROOT_TBL_MODIFY_NUM; 5113 } 5114 5115 /** 5116 * Validate the meter action. 5117 * 5118 * @param[in] dev 5119 * Pointer to rte_eth_dev structure. 5120 * @param[in] action_flags 5121 * Bit-fields that holds the actions detected until now. 5122 * @param[in] action 5123 * Pointer to the meter action. 5124 * @param[in] attr 5125 * Attributes of flow that includes this action. 5126 * @param[in] port_id_item 5127 * Pointer to item indicating port id. 5128 * @param[out] error 5129 * Pointer to error structure. 5130 * 5131 * @return 5132 * 0 on success, a negative errno value otherwise and rte_ernno is set. 5133 */ 5134 static int 5135 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev, 5136 uint64_t action_flags, 5137 const struct rte_flow_action *action, 5138 const struct rte_flow_attr *attr, 5139 const struct rte_flow_item *port_id_item, 5140 bool *def_policy, 5141 struct rte_flow_error *error) 5142 { 5143 struct mlx5_priv *priv = dev->data->dev_private; 5144 const struct rte_flow_action_meter *am = action->conf; 5145 struct mlx5_flow_meter_info *fm; 5146 struct mlx5_flow_meter_policy *mtr_policy; 5147 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 5148 5149 if (!am) 5150 return rte_flow_error_set(error, EINVAL, 5151 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5152 "meter action conf is NULL"); 5153 5154 if (action_flags & MLX5_FLOW_ACTION_METER) 5155 return rte_flow_error_set(error, ENOTSUP, 5156 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5157 "meter chaining not support"); 5158 if (action_flags & MLX5_FLOW_ACTION_JUMP) 5159 return rte_flow_error_set(error, ENOTSUP, 5160 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5161 "meter with jump not support"); 5162 if (!priv->mtr_en) 5163 return rte_flow_error_set(error, ENOTSUP, 5164 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5165 NULL, 5166 "meter action not supported"); 5167 fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL); 5168 if (!fm) 5169 return rte_flow_error_set(error, EINVAL, 5170 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5171 "Meter not found"); 5172 /* aso meter can always be shared by different domains */ 5173 if (fm->ref_cnt && !priv->sh->meter_aso_en && 5174 !(fm->transfer == attr->transfer || 5175 (!fm->ingress && !attr->ingress && attr->egress) || 5176 (!fm->egress && !attr->egress && attr->ingress))) 5177 return rte_flow_error_set(error, EINVAL, 5178 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5179 "Flow attributes domain are either invalid " 5180 "or have a domain conflict with current " 5181 "meter attributes"); 5182 if (fm->def_policy) { 5183 if (!((attr->transfer && 5184 mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) || 5185 (attr->egress && 5186 mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) || 5187 (attr->ingress && 5188 mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS]))) 5189 return rte_flow_error_set(error, EINVAL, 5190 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5191 "Flow attributes domain " 5192 "have a conflict with current " 5193 "meter domain attributes"); 5194 *def_policy = true; 5195 } else { 5196 mtr_policy = mlx5_flow_meter_policy_find(dev, 5197 fm->policy_id, NULL); 5198 if (!mtr_policy) 5199 return rte_flow_error_set(error, EINVAL, 5200 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5201 "Invalid policy id for meter "); 5202 if (!((attr->transfer && mtr_policy->transfer) || 5203 (attr->egress && mtr_policy->egress) || 5204 (attr->ingress && mtr_policy->ingress))) 5205 return rte_flow_error_set(error, EINVAL, 5206 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5207 "Flow attributes domain " 5208 "have a conflict with current " 5209 "meter domain attributes"); 5210 if (attr->transfer && mtr_policy->dev) { 5211 /** 5212 * When policy has fate action of port_id, 5213 * the flow should have the same src port as policy. 5214 */ 5215 struct mlx5_priv *policy_port_priv = 5216 mtr_policy->dev->data->dev_private; 5217 int32_t flow_src_port = priv->representor_id; 5218 5219 if (port_id_item) { 5220 const struct rte_flow_item_port_id *spec = 5221 port_id_item->spec; 5222 struct mlx5_priv *port_priv = 5223 mlx5_port_to_eswitch_info(spec->id, 5224 false); 5225 if (!port_priv) 5226 return rte_flow_error_set(error, 5227 rte_errno, 5228 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5229 spec, 5230 "Failed to get port info."); 5231 flow_src_port = port_priv->representor_id; 5232 } 5233 if (flow_src_port != policy_port_priv->representor_id) 5234 return rte_flow_error_set(error, 5235 rte_errno, 5236 RTE_FLOW_ERROR_TYPE_ITEM_SPEC, 5237 NULL, 5238 "Flow and meter policy " 5239 "have different src port."); 5240 } 5241 *def_policy = false; 5242 } 5243 return 0; 5244 } 5245 5246 /** 5247 * Validate the age action. 5248 * 5249 * @param[in] action_flags 5250 * Holds the actions detected until now. 5251 * @param[in] action 5252 * Pointer to the age action. 5253 * @param[in] dev 5254 * Pointer to the Ethernet device structure. 5255 * @param[out] error 5256 * Pointer to error structure. 5257 * 5258 * @return 5259 * 0 on success, a negative errno value otherwise and rte_errno is set. 5260 */ 5261 static int 5262 flow_dv_validate_action_age(uint64_t action_flags, 5263 const struct rte_flow_action *action, 5264 struct rte_eth_dev *dev, 5265 struct rte_flow_error *error) 5266 { 5267 struct mlx5_priv *priv = dev->data->dev_private; 5268 const struct rte_flow_action_age *age = action->conf; 5269 5270 if (!priv->sh->devx || (priv->sh->cmng.counter_fallback && 5271 !priv->sh->aso_age_mng)) 5272 return rte_flow_error_set(error, ENOTSUP, 5273 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5274 NULL, 5275 "age action not supported"); 5276 if (!(action->conf)) 5277 return rte_flow_error_set(error, EINVAL, 5278 RTE_FLOW_ERROR_TYPE_ACTION, action, 5279 "configuration cannot be null"); 5280 if (!(age->timeout)) 5281 return rte_flow_error_set(error, EINVAL, 5282 RTE_FLOW_ERROR_TYPE_ACTION, action, 5283 "invalid timeout value 0"); 5284 if (action_flags & MLX5_FLOW_ACTION_AGE) 5285 return rte_flow_error_set(error, EINVAL, 5286 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5287 "duplicate age actions set"); 5288 return 0; 5289 } 5290 5291 /** 5292 * Validate the modify-header IPv4 DSCP actions. 5293 * 5294 * @param[in] action_flags 5295 * Holds the actions detected until now. 5296 * @param[in] action 5297 * Pointer to the modify action. 5298 * @param[in] item_flags 5299 * Holds the items detected. 5300 * @param[out] error 5301 * Pointer to error structure. 5302 * 5303 * @return 5304 * 0 on success, a negative errno value otherwise and rte_errno is set. 5305 */ 5306 static int 5307 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags, 5308 const struct rte_flow_action *action, 5309 const uint64_t item_flags, 5310 struct rte_flow_error *error) 5311 { 5312 int ret = 0; 5313 5314 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5315 if (!ret) { 5316 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4)) 5317 return rte_flow_error_set(error, EINVAL, 5318 RTE_FLOW_ERROR_TYPE_ACTION, 5319 NULL, 5320 "no ipv4 item in pattern"); 5321 } 5322 return ret; 5323 } 5324 5325 /** 5326 * Validate the modify-header IPv6 DSCP actions. 5327 * 5328 * @param[in] action_flags 5329 * Holds the actions detected until now. 5330 * @param[in] action 5331 * Pointer to the modify action. 5332 * @param[in] item_flags 5333 * Holds the items detected. 5334 * @param[out] error 5335 * Pointer to error structure. 5336 * 5337 * @return 5338 * 0 on success, a negative errno value otherwise and rte_errno is set. 5339 */ 5340 static int 5341 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags, 5342 const struct rte_flow_action *action, 5343 const uint64_t item_flags, 5344 struct rte_flow_error *error) 5345 { 5346 int ret = 0; 5347 5348 ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); 5349 if (!ret) { 5350 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6)) 5351 return rte_flow_error_set(error, EINVAL, 5352 RTE_FLOW_ERROR_TYPE_ACTION, 5353 NULL, 5354 "no ipv6 item in pattern"); 5355 } 5356 return ret; 5357 } 5358 5359 int 5360 flow_dv_modify_match_cb(void *tool_ctx __rte_unused, 5361 struct mlx5_list_entry *entry, void *cb_ctx) 5362 { 5363 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5364 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5365 struct mlx5_flow_dv_modify_hdr_resource *resource = 5366 container_of(entry, typeof(*resource), entry); 5367 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5368 5369 key_len += ref->actions_num * sizeof(ref->actions[0]); 5370 return ref->actions_num != resource->actions_num || 5371 memcmp(&ref->ft_type, &resource->ft_type, key_len); 5372 } 5373 5374 static struct mlx5_indexed_pool * 5375 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index) 5376 { 5377 struct mlx5_indexed_pool *ipool = __atomic_load_n 5378 (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST); 5379 5380 if (!ipool) { 5381 struct mlx5_indexed_pool *expected = NULL; 5382 struct mlx5_indexed_pool_config cfg = 5383 (struct mlx5_indexed_pool_config) { 5384 .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 5385 (index + 1) * 5386 sizeof(struct mlx5_modification_cmd), 5387 .trunk_size = 64, 5388 .grow_trunk = 3, 5389 .grow_shift = 2, 5390 .need_lock = 1, 5391 .release_mem_en = !!sh->reclaim_mode, 5392 .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16), 5393 .malloc = mlx5_malloc, 5394 .free = mlx5_free, 5395 .type = "mlx5_modify_action_resource", 5396 }; 5397 5398 cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool)); 5399 ipool = mlx5_ipool_create(&cfg); 5400 if (!ipool) 5401 return NULL; 5402 if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index], 5403 &expected, ipool, false, 5404 __ATOMIC_SEQ_CST, 5405 __ATOMIC_SEQ_CST)) { 5406 mlx5_ipool_destroy(ipool); 5407 ipool = __atomic_load_n(&sh->mdh_ipools[index], 5408 __ATOMIC_SEQ_CST); 5409 } 5410 } 5411 return ipool; 5412 } 5413 5414 struct mlx5_list_entry * 5415 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx) 5416 { 5417 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5418 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5419 struct mlx5dv_dr_domain *ns; 5420 struct mlx5_flow_dv_modify_hdr_resource *entry; 5421 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5422 struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh, 5423 ref->actions_num - 1); 5424 int ret; 5425 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5426 uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type); 5427 uint32_t idx; 5428 5429 if (unlikely(!ipool)) { 5430 rte_flow_error_set(ctx->error, ENOMEM, 5431 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5432 NULL, "cannot allocate modify ipool"); 5433 return NULL; 5434 } 5435 entry = mlx5_ipool_zmalloc(ipool, &idx); 5436 if (!entry) { 5437 rte_flow_error_set(ctx->error, ENOMEM, 5438 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5439 "cannot allocate resource memory"); 5440 return NULL; 5441 } 5442 rte_memcpy(&entry->ft_type, 5443 RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)), 5444 key_len + data_len); 5445 if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 5446 ns = sh->fdb_domain; 5447 else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 5448 ns = sh->tx_domain; 5449 else 5450 ns = sh->rx_domain; 5451 ret = mlx5_flow_os_create_flow_action_modify_header 5452 (sh->cdev->ctx, ns, entry, 5453 data_len, &entry->action); 5454 if (ret) { 5455 mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx); 5456 rte_flow_error_set(ctx->error, ENOMEM, 5457 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5458 NULL, "cannot create modification action"); 5459 return NULL; 5460 } 5461 entry->idx = idx; 5462 return &entry->entry; 5463 } 5464 5465 struct mlx5_list_entry * 5466 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 5467 void *cb_ctx) 5468 { 5469 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5470 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 5471 struct mlx5_flow_dv_modify_hdr_resource *entry; 5472 struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data; 5473 uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]); 5474 uint32_t idx; 5475 5476 entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1], 5477 &idx); 5478 if (!entry) { 5479 rte_flow_error_set(ctx->error, ENOMEM, 5480 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 5481 "cannot allocate resource memory"); 5482 return NULL; 5483 } 5484 memcpy(entry, oentry, sizeof(*entry) + data_len); 5485 entry->idx = idx; 5486 return &entry->entry; 5487 } 5488 5489 void 5490 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 5491 { 5492 struct mlx5_dev_ctx_shared *sh = tool_ctx; 5493 struct mlx5_flow_dv_modify_hdr_resource *res = 5494 container_of(entry, typeof(*res), entry); 5495 5496 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 5497 } 5498 5499 /** 5500 * Validate the sample action. 5501 * 5502 * @param[in, out] action_flags 5503 * Holds the actions detected until now. 5504 * @param[in] action 5505 * Pointer to the sample action. 5506 * @param[in] dev 5507 * Pointer to the Ethernet device structure. 5508 * @param[in] attr 5509 * Attributes of flow that includes this action. 5510 * @param[in] item_flags 5511 * Holds the items detected. 5512 * @param[in] rss 5513 * Pointer to the RSS action. 5514 * @param[out] sample_rss 5515 * Pointer to the RSS action in sample action list. 5516 * @param[out] count 5517 * Pointer to the COUNT action in sample action list. 5518 * @param[out] fdb_mirror_limit 5519 * Pointer to the FDB mirror limitation flag. 5520 * @param[out] error 5521 * Pointer to error structure. 5522 * 5523 * @return 5524 * 0 on success, a negative errno value otherwise and rte_errno is set. 5525 */ 5526 static int 5527 flow_dv_validate_action_sample(uint64_t *action_flags, 5528 const struct rte_flow_action *action, 5529 struct rte_eth_dev *dev, 5530 const struct rte_flow_attr *attr, 5531 uint64_t item_flags, 5532 const struct rte_flow_action_rss *rss, 5533 const struct rte_flow_action_rss **sample_rss, 5534 const struct rte_flow_action_count **count, 5535 int *fdb_mirror_limit, 5536 struct rte_flow_error *error) 5537 { 5538 struct mlx5_priv *priv = dev->data->dev_private; 5539 struct mlx5_dev_config *dev_conf = &priv->config; 5540 const struct rte_flow_action_sample *sample = action->conf; 5541 const struct rte_flow_action *act; 5542 uint64_t sub_action_flags = 0; 5543 uint16_t queue_index = 0xFFFF; 5544 int actions_n = 0; 5545 int ret; 5546 5547 if (!sample) 5548 return rte_flow_error_set(error, EINVAL, 5549 RTE_FLOW_ERROR_TYPE_ACTION, action, 5550 "configuration cannot be NULL"); 5551 if (sample->ratio == 0) 5552 return rte_flow_error_set(error, EINVAL, 5553 RTE_FLOW_ERROR_TYPE_ACTION, action, 5554 "ratio value starts from 1"); 5555 if (!priv->sh->devx || (sample->ratio > 0 && !priv->sampler_en)) 5556 return rte_flow_error_set(error, ENOTSUP, 5557 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 5558 NULL, 5559 "sample action not supported"); 5560 if (*action_flags & MLX5_FLOW_ACTION_SAMPLE) 5561 return rte_flow_error_set(error, EINVAL, 5562 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5563 "Multiple sample actions not " 5564 "supported"); 5565 if (*action_flags & MLX5_FLOW_ACTION_METER) 5566 return rte_flow_error_set(error, EINVAL, 5567 RTE_FLOW_ERROR_TYPE_ACTION, action, 5568 "wrong action order, meter should " 5569 "be after sample action"); 5570 if (*action_flags & MLX5_FLOW_ACTION_JUMP) 5571 return rte_flow_error_set(error, EINVAL, 5572 RTE_FLOW_ERROR_TYPE_ACTION, action, 5573 "wrong action order, jump should " 5574 "be after sample action"); 5575 if (*action_flags & MLX5_FLOW_ACTION_CT) 5576 return rte_flow_error_set(error, EINVAL, 5577 RTE_FLOW_ERROR_TYPE_ACTION, action, 5578 "Sample after CT not supported"); 5579 act = sample->actions; 5580 for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 5581 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 5582 return rte_flow_error_set(error, ENOTSUP, 5583 RTE_FLOW_ERROR_TYPE_ACTION, 5584 act, "too many actions"); 5585 switch (act->type) { 5586 case RTE_FLOW_ACTION_TYPE_QUEUE: 5587 ret = mlx5_flow_validate_action_queue(act, 5588 sub_action_flags, 5589 dev, 5590 attr, error); 5591 if (ret < 0) 5592 return ret; 5593 queue_index = ((const struct rte_flow_action_queue *) 5594 (act->conf))->index; 5595 sub_action_flags |= MLX5_FLOW_ACTION_QUEUE; 5596 ++actions_n; 5597 break; 5598 case RTE_FLOW_ACTION_TYPE_RSS: 5599 *sample_rss = act->conf; 5600 ret = mlx5_flow_validate_action_rss(act, 5601 sub_action_flags, 5602 dev, attr, 5603 item_flags, 5604 error); 5605 if (ret < 0) 5606 return ret; 5607 if (rss && *sample_rss && 5608 ((*sample_rss)->level != rss->level || 5609 (*sample_rss)->types != rss->types)) 5610 return rte_flow_error_set(error, ENOTSUP, 5611 RTE_FLOW_ERROR_TYPE_ACTION, 5612 NULL, 5613 "Can't use the different RSS types " 5614 "or level in the same flow"); 5615 if (*sample_rss != NULL && (*sample_rss)->queue_num) 5616 queue_index = (*sample_rss)->queue[0]; 5617 sub_action_flags |= MLX5_FLOW_ACTION_RSS; 5618 ++actions_n; 5619 break; 5620 case RTE_FLOW_ACTION_TYPE_MARK: 5621 ret = flow_dv_validate_action_mark(dev, act, 5622 sub_action_flags, 5623 attr, error); 5624 if (ret < 0) 5625 return ret; 5626 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) 5627 sub_action_flags |= MLX5_FLOW_ACTION_MARK | 5628 MLX5_FLOW_ACTION_MARK_EXT; 5629 else 5630 sub_action_flags |= MLX5_FLOW_ACTION_MARK; 5631 ++actions_n; 5632 break; 5633 case RTE_FLOW_ACTION_TYPE_COUNT: 5634 ret = flow_dv_validate_action_count 5635 (dev, false, *action_flags | sub_action_flags, 5636 error); 5637 if (ret < 0) 5638 return ret; 5639 *count = act->conf; 5640 sub_action_flags |= MLX5_FLOW_ACTION_COUNT; 5641 *action_flags |= MLX5_FLOW_ACTION_COUNT; 5642 ++actions_n; 5643 break; 5644 case RTE_FLOW_ACTION_TYPE_PORT_ID: 5645 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 5646 ret = flow_dv_validate_action_port_id(dev, 5647 sub_action_flags, 5648 act, 5649 attr, 5650 error); 5651 if (ret) 5652 return ret; 5653 sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID; 5654 ++actions_n; 5655 break; 5656 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 5657 ret = flow_dv_validate_action_raw_encap_decap 5658 (dev, NULL, act->conf, attr, &sub_action_flags, 5659 &actions_n, action, item_flags, error); 5660 if (ret < 0) 5661 return ret; 5662 ++actions_n; 5663 break; 5664 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 5665 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 5666 ret = flow_dv_validate_action_l2_encap(dev, 5667 sub_action_flags, 5668 act, attr, 5669 error); 5670 if (ret < 0) 5671 return ret; 5672 sub_action_flags |= MLX5_FLOW_ACTION_ENCAP; 5673 ++actions_n; 5674 break; 5675 default: 5676 return rte_flow_error_set(error, ENOTSUP, 5677 RTE_FLOW_ERROR_TYPE_ACTION, 5678 NULL, 5679 "Doesn't support optional " 5680 "action"); 5681 } 5682 } 5683 if (attr->ingress && !attr->transfer) { 5684 if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE | 5685 MLX5_FLOW_ACTION_RSS))) 5686 return rte_flow_error_set(error, EINVAL, 5687 RTE_FLOW_ERROR_TYPE_ACTION, 5688 NULL, 5689 "Ingress must has a dest " 5690 "QUEUE for Sample"); 5691 } else if (attr->egress && !attr->transfer) { 5692 return rte_flow_error_set(error, ENOTSUP, 5693 RTE_FLOW_ERROR_TYPE_ACTION, 5694 NULL, 5695 "Sample Only support Ingress " 5696 "or E-Switch"); 5697 } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) { 5698 MLX5_ASSERT(attr->transfer); 5699 if (sample->ratio > 1) 5700 return rte_flow_error_set(error, ENOTSUP, 5701 RTE_FLOW_ERROR_TYPE_ACTION, 5702 NULL, 5703 "E-Switch doesn't support " 5704 "any optional action " 5705 "for sampling"); 5706 if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) 5707 return rte_flow_error_set(error, ENOTSUP, 5708 RTE_FLOW_ERROR_TYPE_ACTION, 5709 NULL, 5710 "unsupported action QUEUE"); 5711 if (sub_action_flags & MLX5_FLOW_ACTION_RSS) 5712 return rte_flow_error_set(error, ENOTSUP, 5713 RTE_FLOW_ERROR_TYPE_ACTION, 5714 NULL, 5715 "unsupported action QUEUE"); 5716 if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID)) 5717 return rte_flow_error_set(error, EINVAL, 5718 RTE_FLOW_ERROR_TYPE_ACTION, 5719 NULL, 5720 "E-Switch must has a dest " 5721 "port for mirroring"); 5722 if (!priv->config.hca_attr.reg_c_preserve && 5723 priv->representor_id != UINT16_MAX) 5724 *fdb_mirror_limit = 1; 5725 } 5726 /* Continue validation for Xcap actions.*/ 5727 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) && 5728 (queue_index == 0xFFFF || 5729 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) { 5730 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) == 5731 MLX5_FLOW_XCAP_ACTIONS) 5732 return rte_flow_error_set(error, ENOTSUP, 5733 RTE_FLOW_ERROR_TYPE_ACTION, 5734 NULL, "encap and decap " 5735 "combination aren't " 5736 "supported"); 5737 if (!attr->transfer && attr->ingress && (sub_action_flags & 5738 MLX5_FLOW_ACTION_ENCAP)) 5739 return rte_flow_error_set(error, ENOTSUP, 5740 RTE_FLOW_ERROR_TYPE_ACTION, 5741 NULL, "encap is not supported" 5742 " for ingress traffic"); 5743 } 5744 return 0; 5745 } 5746 5747 /** 5748 * Find existing modify-header resource or create and register a new one. 5749 * 5750 * @param dev[in, out] 5751 * Pointer to rte_eth_dev structure. 5752 * @param[in, out] resource 5753 * Pointer to modify-header resource. 5754 * @parm[in, out] dev_flow 5755 * Pointer to the dev_flow. 5756 * @param[out] error 5757 * pointer to error structure. 5758 * 5759 * @return 5760 * 0 on success otherwise -errno and errno is set. 5761 */ 5762 static int 5763 flow_dv_modify_hdr_resource_register 5764 (struct rte_eth_dev *dev, 5765 struct mlx5_flow_dv_modify_hdr_resource *resource, 5766 struct mlx5_flow *dev_flow, 5767 struct rte_flow_error *error) 5768 { 5769 struct mlx5_priv *priv = dev->data->dev_private; 5770 struct mlx5_dev_ctx_shared *sh = priv->sh; 5771 uint32_t key_len = sizeof(*resource) - 5772 offsetof(typeof(*resource), ft_type) + 5773 resource->actions_num * sizeof(resource->actions[0]); 5774 struct mlx5_list_entry *entry; 5775 struct mlx5_flow_cb_ctx ctx = { 5776 .error = error, 5777 .data = resource, 5778 }; 5779 struct mlx5_hlist *modify_cmds; 5780 uint64_t key64; 5781 5782 modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds, 5783 "hdr_modify", 5784 MLX5_FLOW_HDR_MODIFY_HTABLE_SZ, 5785 true, false, sh, 5786 flow_dv_modify_create_cb, 5787 flow_dv_modify_match_cb, 5788 flow_dv_modify_remove_cb, 5789 flow_dv_modify_clone_cb, 5790 flow_dv_modify_clone_free_cb); 5791 if (unlikely(!modify_cmds)) 5792 return -rte_errno; 5793 resource->root = !dev_flow->dv.group; 5794 if (resource->actions_num > flow_dv_modify_hdr_action_max(dev, 5795 resource->root)) 5796 return rte_flow_error_set(error, EOVERFLOW, 5797 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 5798 "too many modify header items"); 5799 key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0); 5800 entry = mlx5_hlist_register(modify_cmds, key64, &ctx); 5801 if (!entry) 5802 return -rte_errno; 5803 resource = container_of(entry, typeof(*resource), entry); 5804 dev_flow->handle->dvh.modify_hdr = resource; 5805 return 0; 5806 } 5807 5808 /** 5809 * Get DV flow counter by index. 5810 * 5811 * @param[in] dev 5812 * Pointer to the Ethernet device structure. 5813 * @param[in] idx 5814 * mlx5 flow counter index in the container. 5815 * @param[out] ppool 5816 * mlx5 flow counter pool in the container. 5817 * 5818 * @return 5819 * Pointer to the counter, NULL otherwise. 5820 */ 5821 static struct mlx5_flow_counter * 5822 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev, 5823 uint32_t idx, 5824 struct mlx5_flow_counter_pool **ppool) 5825 { 5826 struct mlx5_priv *priv = dev->data->dev_private; 5827 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5828 struct mlx5_flow_counter_pool *pool; 5829 5830 /* Decrease to original index and clear shared bit. */ 5831 idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1); 5832 MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n); 5833 pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL]; 5834 MLX5_ASSERT(pool); 5835 if (ppool) 5836 *ppool = pool; 5837 return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL); 5838 } 5839 5840 /** 5841 * Check the devx counter belongs to the pool. 5842 * 5843 * @param[in] pool 5844 * Pointer to the counter pool. 5845 * @param[in] id 5846 * The counter devx ID. 5847 * 5848 * @return 5849 * True if counter belongs to the pool, false otherwise. 5850 */ 5851 static bool 5852 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id) 5853 { 5854 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) * 5855 MLX5_COUNTERS_PER_POOL; 5856 5857 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL) 5858 return true; 5859 return false; 5860 } 5861 5862 /** 5863 * Get a pool by devx counter ID. 5864 * 5865 * @param[in] cmng 5866 * Pointer to the counter management. 5867 * @param[in] id 5868 * The counter devx ID. 5869 * 5870 * @return 5871 * The counter pool pointer if exists, NULL otherwise, 5872 */ 5873 static struct mlx5_flow_counter_pool * 5874 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id) 5875 { 5876 uint32_t i; 5877 struct mlx5_flow_counter_pool *pool = NULL; 5878 5879 rte_spinlock_lock(&cmng->pool_update_sl); 5880 /* Check last used pool. */ 5881 if (cmng->last_pool_idx != POOL_IDX_INVALID && 5882 flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) { 5883 pool = cmng->pools[cmng->last_pool_idx]; 5884 goto out; 5885 } 5886 /* ID out of range means no suitable pool in the container. */ 5887 if (id > cmng->max_id || id < cmng->min_id) 5888 goto out; 5889 /* 5890 * Find the pool from the end of the container, since mostly counter 5891 * ID is sequence increasing, and the last pool should be the needed 5892 * one. 5893 */ 5894 i = cmng->n_valid; 5895 while (i--) { 5896 struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i]; 5897 5898 if (flow_dv_is_counter_in_pool(pool_tmp, id)) { 5899 pool = pool_tmp; 5900 break; 5901 } 5902 } 5903 out: 5904 rte_spinlock_unlock(&cmng->pool_update_sl); 5905 return pool; 5906 } 5907 5908 /** 5909 * Resize a counter container. 5910 * 5911 * @param[in] dev 5912 * Pointer to the Ethernet device structure. 5913 * 5914 * @return 5915 * 0 on success, otherwise negative errno value and rte_errno is set. 5916 */ 5917 static int 5918 flow_dv_container_resize(struct rte_eth_dev *dev) 5919 { 5920 struct mlx5_priv *priv = dev->data->dev_private; 5921 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 5922 void *old_pools = cmng->pools; 5923 uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE; 5924 uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize; 5925 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 5926 5927 if (!pools) { 5928 rte_errno = ENOMEM; 5929 return -ENOMEM; 5930 } 5931 if (old_pools) 5932 memcpy(pools, old_pools, cmng->n * 5933 sizeof(struct mlx5_flow_counter_pool *)); 5934 cmng->n = resize; 5935 cmng->pools = pools; 5936 if (old_pools) 5937 mlx5_free(old_pools); 5938 return 0; 5939 } 5940 5941 /** 5942 * Query a devx flow counter. 5943 * 5944 * @param[in] dev 5945 * Pointer to the Ethernet device structure. 5946 * @param[in] counter 5947 * Index to the flow counter. 5948 * @param[out] pkts 5949 * The statistics value of packets. 5950 * @param[out] bytes 5951 * The statistics value of bytes. 5952 * 5953 * @return 5954 * 0 on success, otherwise a negative errno value and rte_errno is set. 5955 */ 5956 static inline int 5957 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts, 5958 uint64_t *bytes) 5959 { 5960 struct mlx5_priv *priv = dev->data->dev_private; 5961 struct mlx5_flow_counter_pool *pool = NULL; 5962 struct mlx5_flow_counter *cnt; 5963 int offset; 5964 5965 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 5966 MLX5_ASSERT(pool); 5967 if (priv->sh->cmng.counter_fallback) 5968 return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0, 5969 0, pkts, bytes, 0, NULL, NULL, 0); 5970 rte_spinlock_lock(&pool->sl); 5971 if (!pool->raw) { 5972 *pkts = 0; 5973 *bytes = 0; 5974 } else { 5975 offset = MLX5_CNT_ARRAY_IDX(pool, cnt); 5976 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits); 5977 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes); 5978 } 5979 rte_spinlock_unlock(&pool->sl); 5980 return 0; 5981 } 5982 5983 /** 5984 * Create and initialize a new counter pool. 5985 * 5986 * @param[in] dev 5987 * Pointer to the Ethernet device structure. 5988 * @param[out] dcs 5989 * The devX counter handle. 5990 * @param[in] age 5991 * Whether the pool is for counter that was allocated for aging. 5992 * @param[in/out] cont_cur 5993 * Pointer to the container pointer, it will be update in pool resize. 5994 * 5995 * @return 5996 * The pool container pointer on success, NULL otherwise and rte_errno is set. 5997 */ 5998 static struct mlx5_flow_counter_pool * 5999 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs, 6000 uint32_t age) 6001 { 6002 struct mlx5_priv *priv = dev->data->dev_private; 6003 struct mlx5_flow_counter_pool *pool; 6004 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6005 bool fallback = priv->sh->cmng.counter_fallback; 6006 uint32_t size = sizeof(*pool); 6007 6008 size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE; 6009 size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE); 6010 pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY); 6011 if (!pool) { 6012 rte_errno = ENOMEM; 6013 return NULL; 6014 } 6015 pool->raw = NULL; 6016 pool->is_aged = !!age; 6017 pool->query_gen = 0; 6018 pool->min_dcs = dcs; 6019 rte_spinlock_init(&pool->sl); 6020 rte_spinlock_init(&pool->csl); 6021 TAILQ_INIT(&pool->counters[0]); 6022 TAILQ_INIT(&pool->counters[1]); 6023 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 6024 rte_spinlock_lock(&cmng->pool_update_sl); 6025 pool->index = cmng->n_valid; 6026 if (pool->index == cmng->n && flow_dv_container_resize(dev)) { 6027 mlx5_free(pool); 6028 rte_spinlock_unlock(&cmng->pool_update_sl); 6029 return NULL; 6030 } 6031 cmng->pools[pool->index] = pool; 6032 cmng->n_valid++; 6033 if (unlikely(fallback)) { 6034 int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL); 6035 6036 if (base < cmng->min_id) 6037 cmng->min_id = base; 6038 if (base > cmng->max_id) 6039 cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1; 6040 cmng->last_pool_idx = pool->index; 6041 } 6042 rte_spinlock_unlock(&cmng->pool_update_sl); 6043 return pool; 6044 } 6045 6046 /** 6047 * Prepare a new counter and/or a new counter pool. 6048 * 6049 * @param[in] dev 6050 * Pointer to the Ethernet device structure. 6051 * @param[out] cnt_free 6052 * Where to put the pointer of a new counter. 6053 * @param[in] age 6054 * Whether the pool is for counter that was allocated for aging. 6055 * 6056 * @return 6057 * The counter pool pointer and @p cnt_free is set on success, 6058 * NULL otherwise and rte_errno is set. 6059 */ 6060 static struct mlx5_flow_counter_pool * 6061 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev, 6062 struct mlx5_flow_counter **cnt_free, 6063 uint32_t age) 6064 { 6065 struct mlx5_priv *priv = dev->data->dev_private; 6066 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6067 struct mlx5_flow_counter_pool *pool; 6068 struct mlx5_counters tmp_tq; 6069 struct mlx5_devx_obj *dcs = NULL; 6070 struct mlx5_flow_counter *cnt; 6071 enum mlx5_counter_type cnt_type = 6072 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6073 bool fallback = priv->sh->cmng.counter_fallback; 6074 uint32_t i; 6075 6076 if (fallback) { 6077 /* bulk_bitmap must be 0 for single counter allocation. */ 6078 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0); 6079 if (!dcs) 6080 return NULL; 6081 pool = flow_dv_find_pool_by_id(cmng, dcs->id); 6082 if (!pool) { 6083 pool = flow_dv_pool_create(dev, dcs, age); 6084 if (!pool) { 6085 mlx5_devx_cmd_destroy(dcs); 6086 return NULL; 6087 } 6088 } 6089 i = dcs->id % MLX5_COUNTERS_PER_POOL; 6090 cnt = MLX5_POOL_GET_CNT(pool, i); 6091 cnt->pool = pool; 6092 cnt->dcs_when_free = dcs; 6093 *cnt_free = cnt; 6094 return pool; 6095 } 6096 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 6097 if (!dcs) { 6098 rte_errno = ENODATA; 6099 return NULL; 6100 } 6101 pool = flow_dv_pool_create(dev, dcs, age); 6102 if (!pool) { 6103 mlx5_devx_cmd_destroy(dcs); 6104 return NULL; 6105 } 6106 TAILQ_INIT(&tmp_tq); 6107 for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) { 6108 cnt = MLX5_POOL_GET_CNT(pool, i); 6109 cnt->pool = pool; 6110 TAILQ_INSERT_HEAD(&tmp_tq, cnt, next); 6111 } 6112 rte_spinlock_lock(&cmng->csl[cnt_type]); 6113 TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next); 6114 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6115 *cnt_free = MLX5_POOL_GET_CNT(pool, 0); 6116 (*cnt_free)->pool = pool; 6117 return pool; 6118 } 6119 6120 /** 6121 * Allocate a flow counter. 6122 * 6123 * @param[in] dev 6124 * Pointer to the Ethernet device structure. 6125 * @param[in] age 6126 * Whether the counter was allocated for aging. 6127 * 6128 * @return 6129 * Index to flow counter on success, 0 otherwise and rte_errno is set. 6130 */ 6131 static uint32_t 6132 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) 6133 { 6134 struct mlx5_priv *priv = dev->data->dev_private; 6135 struct mlx5_flow_counter_pool *pool = NULL; 6136 struct mlx5_flow_counter *cnt_free = NULL; 6137 bool fallback = priv->sh->cmng.counter_fallback; 6138 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; 6139 enum mlx5_counter_type cnt_type = 6140 age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; 6141 uint32_t cnt_idx; 6142 6143 if (!priv->sh->devx) { 6144 rte_errno = ENOTSUP; 6145 return 0; 6146 } 6147 /* Get free counters from container. */ 6148 rte_spinlock_lock(&cmng->csl[cnt_type]); 6149 cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]); 6150 if (cnt_free) 6151 TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next); 6152 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6153 if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age)) 6154 goto err; 6155 pool = cnt_free->pool; 6156 if (fallback) 6157 cnt_free->dcs_when_active = cnt_free->dcs_when_free; 6158 /* Create a DV counter action only in the first time usage. */ 6159 if (!cnt_free->action) { 6160 uint16_t offset; 6161 struct mlx5_devx_obj *dcs; 6162 int ret; 6163 6164 if (!fallback) { 6165 offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free); 6166 dcs = pool->min_dcs; 6167 } else { 6168 offset = 0; 6169 dcs = cnt_free->dcs_when_free; 6170 } 6171 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset, 6172 &cnt_free->action); 6173 if (ret) { 6174 rte_errno = errno; 6175 goto err; 6176 } 6177 } 6178 cnt_idx = MLX5_MAKE_CNT_IDX(pool->index, 6179 MLX5_CNT_ARRAY_IDX(pool, cnt_free)); 6180 /* Update the counter reset values. */ 6181 if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits, 6182 &cnt_free->bytes)) 6183 goto err; 6184 if (!fallback && !priv->sh->cmng.query_thread_on) 6185 /* Start the asynchronous batch query by the host thread. */ 6186 mlx5_set_query_alarm(priv->sh); 6187 /* 6188 * When the count action isn't shared (by ID), shared_info field is 6189 * used for indirect action API's refcnt. 6190 * When the counter action is not shared neither by ID nor by indirect 6191 * action API, shared info must be 1. 6192 */ 6193 cnt_free->shared_info.refcnt = 1; 6194 return cnt_idx; 6195 err: 6196 if (cnt_free) { 6197 cnt_free->pool = pool; 6198 if (fallback) 6199 cnt_free->dcs_when_free = cnt_free->dcs_when_active; 6200 rte_spinlock_lock(&cmng->csl[cnt_type]); 6201 TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next); 6202 rte_spinlock_unlock(&cmng->csl[cnt_type]); 6203 } 6204 return 0; 6205 } 6206 6207 /** 6208 * Get age param from counter index. 6209 * 6210 * @param[in] dev 6211 * Pointer to the Ethernet device structure. 6212 * @param[in] counter 6213 * Index to the counter handler. 6214 * 6215 * @return 6216 * The aging parameter specified for the counter index. 6217 */ 6218 static struct mlx5_age_param* 6219 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev, 6220 uint32_t counter) 6221 { 6222 struct mlx5_flow_counter *cnt; 6223 struct mlx5_flow_counter_pool *pool = NULL; 6224 6225 flow_dv_counter_get_by_idx(dev, counter, &pool); 6226 counter = (counter - 1) % MLX5_COUNTERS_PER_POOL; 6227 cnt = MLX5_POOL_GET_CNT(pool, counter); 6228 return MLX5_CNT_TO_AGE(cnt); 6229 } 6230 6231 /** 6232 * Remove a flow counter from aged counter list. 6233 * 6234 * @param[in] dev 6235 * Pointer to the Ethernet device structure. 6236 * @param[in] counter 6237 * Index to the counter handler. 6238 * @param[in] cnt 6239 * Pointer to the counter handler. 6240 */ 6241 static void 6242 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev, 6243 uint32_t counter, struct mlx5_flow_counter *cnt) 6244 { 6245 struct mlx5_age_info *age_info; 6246 struct mlx5_age_param *age_param; 6247 struct mlx5_priv *priv = dev->data->dev_private; 6248 uint16_t expected = AGE_CANDIDATE; 6249 6250 age_info = GET_PORT_AGE_INFO(priv); 6251 age_param = flow_dv_counter_idx_get_age(dev, counter); 6252 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 6253 AGE_FREE, false, __ATOMIC_RELAXED, 6254 __ATOMIC_RELAXED)) { 6255 /** 6256 * We need the lock even it is age timeout, 6257 * since counter may still in process. 6258 */ 6259 rte_spinlock_lock(&age_info->aged_sl); 6260 TAILQ_REMOVE(&age_info->aged_counters, cnt, next); 6261 rte_spinlock_unlock(&age_info->aged_sl); 6262 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 6263 } 6264 } 6265 6266 /** 6267 * Release a flow counter. 6268 * 6269 * @param[in] dev 6270 * Pointer to the Ethernet device structure. 6271 * @param[in] counter 6272 * Index to the counter handler. 6273 */ 6274 static void 6275 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) 6276 { 6277 struct mlx5_priv *priv = dev->data->dev_private; 6278 struct mlx5_flow_counter_pool *pool = NULL; 6279 struct mlx5_flow_counter *cnt; 6280 enum mlx5_counter_type cnt_type; 6281 6282 if (!counter) 6283 return; 6284 cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); 6285 MLX5_ASSERT(pool); 6286 if (pool->is_aged) { 6287 flow_dv_counter_remove_from_age(dev, counter, cnt); 6288 } else { 6289 /* 6290 * If the counter action is shared by indirect action API, 6291 * the atomic function reduces its references counter. 6292 * If after the reduction the action is still referenced, the 6293 * function returns here and does not release it. 6294 * When the counter action is not shared by 6295 * indirect action API, shared info is 1 before the reduction, 6296 * so this condition is failed and function doesn't return here. 6297 */ 6298 if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1, 6299 __ATOMIC_RELAXED)) 6300 return; 6301 } 6302 cnt->pool = pool; 6303 /* 6304 * Put the counter back to list to be updated in none fallback mode. 6305 * Currently, we are using two list alternately, while one is in query, 6306 * add the freed counter to the other list based on the pool query_gen 6307 * value. After query finishes, add counter the list to the global 6308 * container counter list. The list changes while query starts. In 6309 * this case, lock will not be needed as query callback and release 6310 * function both operate with the different list. 6311 */ 6312 if (!priv->sh->cmng.counter_fallback) { 6313 rte_spinlock_lock(&pool->csl); 6314 TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); 6315 rte_spinlock_unlock(&pool->csl); 6316 } else { 6317 cnt->dcs_when_free = cnt->dcs_when_active; 6318 cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : 6319 MLX5_COUNTER_TYPE_ORIGIN; 6320 rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]); 6321 TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type], 6322 cnt, next); 6323 rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]); 6324 } 6325 } 6326 6327 /** 6328 * Resize a meter id container. 6329 * 6330 * @param[in] dev 6331 * Pointer to the Ethernet device structure. 6332 * 6333 * @return 6334 * 0 on success, otherwise negative errno value and rte_errno is set. 6335 */ 6336 static int 6337 flow_dv_mtr_container_resize(struct rte_eth_dev *dev) 6338 { 6339 struct mlx5_priv *priv = dev->data->dev_private; 6340 struct mlx5_aso_mtr_pools_mng *pools_mng = 6341 &priv->sh->mtrmng->pools_mng; 6342 void *old_pools = pools_mng->pools; 6343 uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE; 6344 uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize; 6345 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 6346 6347 if (!pools) { 6348 rte_errno = ENOMEM; 6349 return -ENOMEM; 6350 } 6351 if (!pools_mng->n) 6352 if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { 6353 mlx5_free(pools); 6354 return -ENOMEM; 6355 } 6356 if (old_pools) 6357 memcpy(pools, old_pools, pools_mng->n * 6358 sizeof(struct mlx5_aso_mtr_pool *)); 6359 pools_mng->n = resize; 6360 pools_mng->pools = pools; 6361 if (old_pools) 6362 mlx5_free(old_pools); 6363 return 0; 6364 } 6365 6366 /** 6367 * Prepare a new meter and/or a new meter pool. 6368 * 6369 * @param[in] dev 6370 * Pointer to the Ethernet device structure. 6371 * @param[out] mtr_free 6372 * Where to put the pointer of a new meter.g. 6373 * 6374 * @return 6375 * The meter pool pointer and @mtr_free is set on success, 6376 * NULL otherwise and rte_errno is set. 6377 */ 6378 static struct mlx5_aso_mtr_pool * 6379 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free) 6380 { 6381 struct mlx5_priv *priv = dev->data->dev_private; 6382 struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng; 6383 struct mlx5_aso_mtr_pool *pool = NULL; 6384 struct mlx5_devx_obj *dcs = NULL; 6385 uint32_t i; 6386 uint32_t log_obj_size; 6387 6388 log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1); 6389 dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx, 6390 priv->sh->cdev->pdn, 6391 log_obj_size); 6392 if (!dcs) { 6393 rte_errno = ENODATA; 6394 return NULL; 6395 } 6396 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 6397 if (!pool) { 6398 rte_errno = ENOMEM; 6399 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6400 return NULL; 6401 } 6402 pool->devx_obj = dcs; 6403 rte_rwlock_write_lock(&pools_mng->resize_mtrwl); 6404 pool->index = pools_mng->n_valid; 6405 if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) { 6406 mlx5_free(pool); 6407 claim_zero(mlx5_devx_cmd_destroy(dcs)); 6408 rte_rwlock_write_unlock(&pools_mng->resize_mtrwl); 6409 return NULL; 6410 } 6411 pools_mng->pools[pool->index] = pool; 6412 pools_mng->n_valid++; 6413 rte_rwlock_write_unlock(&pools_mng->resize_mtrwl); 6414 for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) { 6415 pool->mtrs[i].offset = i; 6416 LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next); 6417 } 6418 pool->mtrs[0].offset = 0; 6419 *mtr_free = &pool->mtrs[0]; 6420 return pool; 6421 } 6422 6423 /** 6424 * Release a flow meter into pool. 6425 * 6426 * @param[in] dev 6427 * Pointer to the Ethernet device structure. 6428 * @param[in] mtr_idx 6429 * Index to aso flow meter. 6430 */ 6431 static void 6432 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx) 6433 { 6434 struct mlx5_priv *priv = dev->data->dev_private; 6435 struct mlx5_aso_mtr_pools_mng *pools_mng = 6436 &priv->sh->mtrmng->pools_mng; 6437 struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 6438 6439 MLX5_ASSERT(aso_mtr); 6440 rte_spinlock_lock(&pools_mng->mtrsl); 6441 memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info)); 6442 aso_mtr->state = ASO_METER_FREE; 6443 LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next); 6444 rte_spinlock_unlock(&pools_mng->mtrsl); 6445 } 6446 6447 /** 6448 * Allocate a aso flow meter. 6449 * 6450 * @param[in] dev 6451 * Pointer to the Ethernet device structure. 6452 * 6453 * @return 6454 * Index to aso flow meter on success, 0 otherwise and rte_errno is set. 6455 */ 6456 static uint32_t 6457 flow_dv_mtr_alloc(struct rte_eth_dev *dev) 6458 { 6459 struct mlx5_priv *priv = dev->data->dev_private; 6460 struct mlx5_aso_mtr *mtr_free = NULL; 6461 struct mlx5_aso_mtr_pools_mng *pools_mng = 6462 &priv->sh->mtrmng->pools_mng; 6463 struct mlx5_aso_mtr_pool *pool; 6464 uint32_t mtr_idx = 0; 6465 6466 if (!priv->sh->devx) { 6467 rte_errno = ENOTSUP; 6468 return 0; 6469 } 6470 /* Allocate the flow meter memory. */ 6471 /* Get free meters from management. */ 6472 rte_spinlock_lock(&pools_mng->mtrsl); 6473 mtr_free = LIST_FIRST(&pools_mng->meters); 6474 if (mtr_free) 6475 LIST_REMOVE(mtr_free, next); 6476 if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) { 6477 rte_spinlock_unlock(&pools_mng->mtrsl); 6478 return 0; 6479 } 6480 mtr_free->state = ASO_METER_WAIT; 6481 rte_spinlock_unlock(&pools_mng->mtrsl); 6482 pool = container_of(mtr_free, 6483 struct mlx5_aso_mtr_pool, 6484 mtrs[mtr_free->offset]); 6485 mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset); 6486 if (!mtr_free->fm.meter_action) { 6487 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 6488 struct rte_flow_error error; 6489 uint8_t reg_id; 6490 6491 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error); 6492 mtr_free->fm.meter_action = 6493 mlx5_glue->dv_create_flow_action_aso 6494 (priv->sh->rx_domain, 6495 pool->devx_obj->obj, 6496 mtr_free->offset, 6497 (1 << MLX5_FLOW_COLOR_GREEN), 6498 reg_id - REG_C_0); 6499 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 6500 if (!mtr_free->fm.meter_action) { 6501 flow_dv_aso_mtr_release_to_pool(dev, mtr_idx); 6502 return 0; 6503 } 6504 } 6505 return mtr_idx; 6506 } 6507 6508 /** 6509 * Verify the @p attributes will be correctly understood by the NIC and store 6510 * them in the @p flow if everything is correct. 6511 * 6512 * @param[in] dev 6513 * Pointer to dev struct. 6514 * @param[in] attributes 6515 * Pointer to flow attributes 6516 * @param[in] external 6517 * This flow rule is created by request external to PMD. 6518 * @param[out] error 6519 * Pointer to error structure. 6520 * 6521 * @return 6522 * - 0 on success and non root table. 6523 * - 1 on success and root table. 6524 * - a negative errno value otherwise and rte_errno is set. 6525 */ 6526 static int 6527 flow_dv_validate_attributes(struct rte_eth_dev *dev, 6528 const struct mlx5_flow_tunnel *tunnel, 6529 const struct rte_flow_attr *attributes, 6530 const struct flow_grp_info *grp_info, 6531 struct rte_flow_error *error) 6532 { 6533 struct mlx5_priv *priv = dev->data->dev_private; 6534 uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes); 6535 int ret = 0; 6536 6537 #ifndef HAVE_MLX5DV_DR 6538 RTE_SET_USED(tunnel); 6539 RTE_SET_USED(grp_info); 6540 if (attributes->group) 6541 return rte_flow_error_set(error, ENOTSUP, 6542 RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 6543 NULL, 6544 "groups are not supported"); 6545 #else 6546 uint32_t table = 0; 6547 6548 ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table, 6549 grp_info, error); 6550 if (ret) 6551 return ret; 6552 if (!table) 6553 ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL; 6554 #endif 6555 if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR && 6556 attributes->priority > lowest_priority) 6557 return rte_flow_error_set(error, ENOTSUP, 6558 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 6559 NULL, 6560 "priority out of range"); 6561 if (attributes->transfer) { 6562 if (!priv->config.dv_esw_en) 6563 return rte_flow_error_set 6564 (error, ENOTSUP, 6565 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 6566 "E-Switch dr is not supported"); 6567 if (!(priv->representor || priv->master)) 6568 return rte_flow_error_set 6569 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6570 NULL, "E-Switch configuration can only be" 6571 " done by a master or a representor device"); 6572 if (attributes->egress) 6573 return rte_flow_error_set 6574 (error, ENOTSUP, 6575 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes, 6576 "egress is not supported"); 6577 } 6578 if (!(attributes->egress ^ attributes->ingress)) 6579 return rte_flow_error_set(error, ENOTSUP, 6580 RTE_FLOW_ERROR_TYPE_ATTR, NULL, 6581 "must specify exactly one of " 6582 "ingress or egress"); 6583 return ret; 6584 } 6585 6586 static int 6587 validate_integrity_bits(const struct rte_flow_item_integrity *mask, 6588 int64_t pattern_flags, uint64_t l3_flags, 6589 uint64_t l4_flags, uint64_t ip4_flag, 6590 struct rte_flow_error *error) 6591 { 6592 if (mask->l3_ok && !(pattern_flags & l3_flags)) 6593 return rte_flow_error_set(error, EINVAL, 6594 RTE_FLOW_ERROR_TYPE_ITEM, 6595 NULL, "missing L3 protocol"); 6596 6597 if (mask->ipv4_csum_ok && !(pattern_flags & ip4_flag)) 6598 return rte_flow_error_set(error, EINVAL, 6599 RTE_FLOW_ERROR_TYPE_ITEM, 6600 NULL, "missing IPv4 protocol"); 6601 6602 if ((mask->l4_ok || mask->l4_csum_ok) && !(pattern_flags & l4_flags)) 6603 return rte_flow_error_set(error, EINVAL, 6604 RTE_FLOW_ERROR_TYPE_ITEM, 6605 NULL, "missing L4 protocol"); 6606 6607 return 0; 6608 } 6609 6610 static int 6611 flow_dv_validate_item_integrity_post(const struct 6612 rte_flow_item *integrity_items[2], 6613 int64_t pattern_flags, 6614 struct rte_flow_error *error) 6615 { 6616 const struct rte_flow_item_integrity *mask; 6617 int ret; 6618 6619 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) { 6620 mask = (typeof(mask))integrity_items[0]->mask; 6621 ret = validate_integrity_bits(mask, pattern_flags, 6622 MLX5_FLOW_LAYER_OUTER_L3, 6623 MLX5_FLOW_LAYER_OUTER_L4, 6624 MLX5_FLOW_LAYER_OUTER_L3_IPV4, 6625 error); 6626 if (ret) 6627 return ret; 6628 } 6629 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) { 6630 mask = (typeof(mask))integrity_items[1]->mask; 6631 ret = validate_integrity_bits(mask, pattern_flags, 6632 MLX5_FLOW_LAYER_INNER_L3, 6633 MLX5_FLOW_LAYER_INNER_L4, 6634 MLX5_FLOW_LAYER_INNER_L3_IPV4, 6635 error); 6636 if (ret) 6637 return ret; 6638 } 6639 return 0; 6640 } 6641 6642 static int 6643 flow_dv_validate_item_integrity(struct rte_eth_dev *dev, 6644 const struct rte_flow_item *integrity_item, 6645 uint64_t pattern_flags, uint64_t *last_item, 6646 const struct rte_flow_item *integrity_items[2], 6647 struct rte_flow_error *error) 6648 { 6649 struct mlx5_priv *priv = dev->data->dev_private; 6650 const struct rte_flow_item_integrity *mask = (typeof(mask)) 6651 integrity_item->mask; 6652 const struct rte_flow_item_integrity *spec = (typeof(spec)) 6653 integrity_item->spec; 6654 6655 if (!priv->config.hca_attr.pkt_integrity_match) 6656 return rte_flow_error_set(error, ENOTSUP, 6657 RTE_FLOW_ERROR_TYPE_ITEM, 6658 integrity_item, 6659 "packet integrity integrity_item not supported"); 6660 if (!spec) 6661 return rte_flow_error_set(error, ENOTSUP, 6662 RTE_FLOW_ERROR_TYPE_ITEM, 6663 integrity_item, 6664 "no spec for integrity item"); 6665 if (!mask) 6666 mask = &rte_flow_item_integrity_mask; 6667 if (!mlx5_validate_integrity_item(mask)) 6668 return rte_flow_error_set(error, ENOTSUP, 6669 RTE_FLOW_ERROR_TYPE_ITEM, 6670 integrity_item, 6671 "unsupported integrity filter"); 6672 if (spec->level > 1) { 6673 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) 6674 return rte_flow_error_set 6675 (error, ENOTSUP, 6676 RTE_FLOW_ERROR_TYPE_ITEM, 6677 NULL, "multiple inner integrity items not supported"); 6678 integrity_items[1] = integrity_item; 6679 *last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; 6680 } else { 6681 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) 6682 return rte_flow_error_set 6683 (error, ENOTSUP, 6684 RTE_FLOW_ERROR_TYPE_ITEM, 6685 NULL, "multiple outer integrity items not supported"); 6686 integrity_items[0] = integrity_item; 6687 *last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; 6688 } 6689 return 0; 6690 } 6691 6692 static int 6693 flow_dv_validate_item_flex(struct rte_eth_dev *dev, 6694 const struct rte_flow_item *item, 6695 uint64_t item_flags, 6696 uint64_t *last_item, 6697 bool is_inner, 6698 struct rte_flow_error *error) 6699 { 6700 const struct rte_flow_item_flex *flow_spec = item->spec; 6701 const struct rte_flow_item_flex *flow_mask = item->mask; 6702 struct mlx5_flex_item *flex; 6703 6704 if (!flow_spec) 6705 return rte_flow_error_set(error, EINVAL, 6706 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6707 "flex flow item spec cannot be NULL"); 6708 if (!flow_mask) 6709 return rte_flow_error_set(error, EINVAL, 6710 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6711 "flex flow item mask cannot be NULL"); 6712 if (item->last) 6713 return rte_flow_error_set(error, ENOTSUP, 6714 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6715 "flex flow item last not supported"); 6716 if (mlx5_flex_acquire_index(dev, flow_spec->handle, false) < 0) 6717 return rte_flow_error_set(error, EINVAL, 6718 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 6719 "invalid flex flow item handle"); 6720 flex = (struct mlx5_flex_item *)flow_spec->handle; 6721 switch (flex->tunnel_mode) { 6722 case FLEX_TUNNEL_MODE_SINGLE: 6723 if (item_flags & 6724 (MLX5_FLOW_ITEM_OUTER_FLEX | MLX5_FLOW_ITEM_INNER_FLEX)) 6725 rte_flow_error_set(error, EINVAL, 6726 RTE_FLOW_ERROR_TYPE_ITEM, 6727 NULL, "multiple flex items not supported"); 6728 break; 6729 case FLEX_TUNNEL_MODE_OUTER: 6730 if (is_inner) 6731 rte_flow_error_set(error, EINVAL, 6732 RTE_FLOW_ERROR_TYPE_ITEM, 6733 NULL, "inner flex item was not configured"); 6734 if (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX) 6735 rte_flow_error_set(error, ENOTSUP, 6736 RTE_FLOW_ERROR_TYPE_ITEM, 6737 NULL, "multiple flex items not supported"); 6738 break; 6739 case FLEX_TUNNEL_MODE_INNER: 6740 if (!is_inner) 6741 rte_flow_error_set(error, EINVAL, 6742 RTE_FLOW_ERROR_TYPE_ITEM, 6743 NULL, "outer flex item was not configured"); 6744 if (item_flags & MLX5_FLOW_ITEM_INNER_FLEX) 6745 rte_flow_error_set(error, EINVAL, 6746 RTE_FLOW_ERROR_TYPE_ITEM, 6747 NULL, "multiple flex items not supported"); 6748 break; 6749 case FLEX_TUNNEL_MODE_MULTI: 6750 if ((is_inner && (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)) || 6751 (!is_inner && (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX))) { 6752 rte_flow_error_set(error, EINVAL, 6753 RTE_FLOW_ERROR_TYPE_ITEM, 6754 NULL, "multiple flex items not supported"); 6755 } 6756 break; 6757 case FLEX_TUNNEL_MODE_TUNNEL: 6758 if (is_inner || (item_flags & MLX5_FLOW_ITEM_FLEX_TUNNEL)) 6759 rte_flow_error_set(error, EINVAL, 6760 RTE_FLOW_ERROR_TYPE_ITEM, 6761 NULL, "multiple flex tunnel items not supported"); 6762 break; 6763 default: 6764 rte_flow_error_set(error, EINVAL, 6765 RTE_FLOW_ERROR_TYPE_ITEM, 6766 NULL, "invalid flex item configuration"); 6767 } 6768 *last_item = flex->tunnel_mode == FLEX_TUNNEL_MODE_TUNNEL ? 6769 MLX5_FLOW_ITEM_FLEX_TUNNEL : is_inner ? 6770 MLX5_FLOW_ITEM_INNER_FLEX : MLX5_FLOW_ITEM_OUTER_FLEX; 6771 return 0; 6772 } 6773 6774 /** 6775 * Internal validation function. For validating both actions and items. 6776 * 6777 * @param[in] dev 6778 * Pointer to the rte_eth_dev structure. 6779 * @param[in] attr 6780 * Pointer to the flow attributes. 6781 * @param[in] items 6782 * Pointer to the list of items. 6783 * @param[in] actions 6784 * Pointer to the list of actions. 6785 * @param[in] external 6786 * This flow rule is created by request external to PMD. 6787 * @param[in] hairpin 6788 * Number of hairpin TX actions, 0 means classic flow. 6789 * @param[out] error 6790 * Pointer to the error structure. 6791 * 6792 * @return 6793 * 0 on success, a negative errno value otherwise and rte_errno is set. 6794 */ 6795 static int 6796 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, 6797 const struct rte_flow_item items[], 6798 const struct rte_flow_action actions[], 6799 bool external, int hairpin, struct rte_flow_error *error) 6800 { 6801 int ret; 6802 uint64_t action_flags = 0; 6803 uint64_t item_flags = 0; 6804 uint64_t last_item = 0; 6805 uint8_t next_protocol = 0xff; 6806 uint16_t ether_type = 0; 6807 int actions_n = 0; 6808 uint8_t item_ipv6_proto = 0; 6809 int fdb_mirror_limit = 0; 6810 int modify_after_mirror = 0; 6811 const struct rte_flow_item *geneve_item = NULL; 6812 const struct rte_flow_item *gre_item = NULL; 6813 const struct rte_flow_item *gtp_item = NULL; 6814 const struct rte_flow_action_raw_decap *decap; 6815 const struct rte_flow_action_raw_encap *encap; 6816 const struct rte_flow_action_rss *rss = NULL; 6817 const struct rte_flow_action_rss *sample_rss = NULL; 6818 const struct rte_flow_action_count *sample_count = NULL; 6819 const struct rte_flow_item_tcp nic_tcp_mask = { 6820 .hdr = { 6821 .tcp_flags = 0xFF, 6822 .src_port = RTE_BE16(UINT16_MAX), 6823 .dst_port = RTE_BE16(UINT16_MAX), 6824 } 6825 }; 6826 const struct rte_flow_item_ipv6 nic_ipv6_mask = { 6827 .hdr = { 6828 .src_addr = 6829 "\xff\xff\xff\xff\xff\xff\xff\xff" 6830 "\xff\xff\xff\xff\xff\xff\xff\xff", 6831 .dst_addr = 6832 "\xff\xff\xff\xff\xff\xff\xff\xff" 6833 "\xff\xff\xff\xff\xff\xff\xff\xff", 6834 .vtc_flow = RTE_BE32(0xffffffff), 6835 .proto = 0xff, 6836 .hop_limits = 0xff, 6837 }, 6838 .has_frag_ext = 1, 6839 }; 6840 const struct rte_flow_item_ecpri nic_ecpri_mask = { 6841 .hdr = { 6842 .common = { 6843 .u32 = 6844 RTE_BE32(((const struct rte_ecpri_common_hdr) { 6845 .type = 0xFF, 6846 }).u32), 6847 }, 6848 .dummy[0] = 0xffffffff, 6849 }, 6850 }; 6851 struct mlx5_priv *priv = dev->data->dev_private; 6852 struct mlx5_dev_config *dev_conf = &priv->config; 6853 uint16_t queue_index = 0xFFFF; 6854 const struct rte_flow_item_vlan *vlan_m = NULL; 6855 uint32_t rw_act_num = 0; 6856 uint64_t is_root; 6857 const struct mlx5_flow_tunnel *tunnel; 6858 enum mlx5_tof_rule_type tof_rule_type; 6859 struct flow_grp_info grp_info = { 6860 .external = !!external, 6861 .transfer = !!attr->transfer, 6862 .fdb_def_rule = !!priv->fdb_def_rule, 6863 .std_tbl_fix = true, 6864 }; 6865 const struct rte_eth_hairpin_conf *conf; 6866 const struct rte_flow_item *integrity_items[2] = {NULL, NULL}; 6867 const struct rte_flow_item *port_id_item = NULL; 6868 bool def_policy = false; 6869 uint16_t udp_dport = 0; 6870 6871 if (items == NULL) 6872 return -1; 6873 tunnel = is_tunnel_offload_active(dev) ? 6874 mlx5_get_tof(items, actions, &tof_rule_type) : NULL; 6875 if (tunnel) { 6876 if (!priv->config.dv_flow_en) 6877 return rte_flow_error_set 6878 (error, ENOTSUP, 6879 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6880 NULL, "tunnel offload requires DV flow interface"); 6881 if (priv->representor) 6882 return rte_flow_error_set 6883 (error, ENOTSUP, 6884 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 6885 NULL, "decap not supported for VF representor"); 6886 if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE) 6887 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 6888 else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE) 6889 action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH | 6890 MLX5_FLOW_ACTION_DECAP; 6891 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 6892 (dev, attr, tunnel, tof_rule_type); 6893 } 6894 ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error); 6895 if (ret < 0) 6896 return ret; 6897 is_root = (uint64_t)ret; 6898 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 6899 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 6900 int type = items->type; 6901 6902 if (!mlx5_flow_os_item_supported(type)) 6903 return rte_flow_error_set(error, ENOTSUP, 6904 RTE_FLOW_ERROR_TYPE_ITEM, 6905 NULL, "item not supported"); 6906 switch (type) { 6907 case RTE_FLOW_ITEM_TYPE_VOID: 6908 break; 6909 case RTE_FLOW_ITEM_TYPE_PORT_ID: 6910 ret = flow_dv_validate_item_port_id 6911 (dev, items, attr, item_flags, error); 6912 if (ret < 0) 6913 return ret; 6914 last_item = MLX5_FLOW_ITEM_PORT_ID; 6915 port_id_item = items; 6916 break; 6917 case RTE_FLOW_ITEM_TYPE_ETH: 6918 ret = mlx5_flow_validate_item_eth(items, item_flags, 6919 true, error); 6920 if (ret < 0) 6921 return ret; 6922 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 6923 MLX5_FLOW_LAYER_OUTER_L2; 6924 if (items->mask != NULL && items->spec != NULL) { 6925 ether_type = 6926 ((const struct rte_flow_item_eth *) 6927 items->spec)->type; 6928 ether_type &= 6929 ((const struct rte_flow_item_eth *) 6930 items->mask)->type; 6931 ether_type = rte_be_to_cpu_16(ether_type); 6932 } else { 6933 ether_type = 0; 6934 } 6935 break; 6936 case RTE_FLOW_ITEM_TYPE_VLAN: 6937 ret = flow_dv_validate_item_vlan(items, item_flags, 6938 dev, error); 6939 if (ret < 0) 6940 return ret; 6941 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : 6942 MLX5_FLOW_LAYER_OUTER_VLAN; 6943 if (items->mask != NULL && items->spec != NULL) { 6944 ether_type = 6945 ((const struct rte_flow_item_vlan *) 6946 items->spec)->inner_type; 6947 ether_type &= 6948 ((const struct rte_flow_item_vlan *) 6949 items->mask)->inner_type; 6950 ether_type = rte_be_to_cpu_16(ether_type); 6951 } else { 6952 ether_type = 0; 6953 } 6954 /* Store outer VLAN mask for of_push_vlan action. */ 6955 if (!tunnel) 6956 vlan_m = items->mask; 6957 break; 6958 case RTE_FLOW_ITEM_TYPE_IPV4: 6959 mlx5_flow_tunnel_ip_check(items, next_protocol, 6960 &item_flags, &tunnel); 6961 ret = flow_dv_validate_item_ipv4(dev, items, item_flags, 6962 last_item, ether_type, 6963 error); 6964 if (ret < 0) 6965 return ret; 6966 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 6967 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 6968 if (items->mask != NULL && 6969 ((const struct rte_flow_item_ipv4 *) 6970 items->mask)->hdr.next_proto_id) { 6971 next_protocol = 6972 ((const struct rte_flow_item_ipv4 *) 6973 (items->spec))->hdr.next_proto_id; 6974 next_protocol &= 6975 ((const struct rte_flow_item_ipv4 *) 6976 (items->mask))->hdr.next_proto_id; 6977 } else { 6978 /* Reset for inner layer. */ 6979 next_protocol = 0xff; 6980 } 6981 break; 6982 case RTE_FLOW_ITEM_TYPE_IPV6: 6983 mlx5_flow_tunnel_ip_check(items, next_protocol, 6984 &item_flags, &tunnel); 6985 ret = mlx5_flow_validate_item_ipv6(items, item_flags, 6986 last_item, 6987 ether_type, 6988 &nic_ipv6_mask, 6989 error); 6990 if (ret < 0) 6991 return ret; 6992 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 6993 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 6994 if (items->mask != NULL && 6995 ((const struct rte_flow_item_ipv6 *) 6996 items->mask)->hdr.proto) { 6997 item_ipv6_proto = 6998 ((const struct rte_flow_item_ipv6 *) 6999 items->spec)->hdr.proto; 7000 next_protocol = 7001 ((const struct rte_flow_item_ipv6 *) 7002 items->spec)->hdr.proto; 7003 next_protocol &= 7004 ((const struct rte_flow_item_ipv6 *) 7005 items->mask)->hdr.proto; 7006 } else { 7007 /* Reset for inner layer. */ 7008 next_protocol = 0xff; 7009 } 7010 break; 7011 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 7012 ret = flow_dv_validate_item_ipv6_frag_ext(items, 7013 item_flags, 7014 error); 7015 if (ret < 0) 7016 return ret; 7017 last_item = tunnel ? 7018 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 7019 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 7020 if (items->mask != NULL && 7021 ((const struct rte_flow_item_ipv6_frag_ext *) 7022 items->mask)->hdr.next_header) { 7023 next_protocol = 7024 ((const struct rte_flow_item_ipv6_frag_ext *) 7025 items->spec)->hdr.next_header; 7026 next_protocol &= 7027 ((const struct rte_flow_item_ipv6_frag_ext *) 7028 items->mask)->hdr.next_header; 7029 } else { 7030 /* Reset for inner layer. */ 7031 next_protocol = 0xff; 7032 } 7033 break; 7034 case RTE_FLOW_ITEM_TYPE_TCP: 7035 ret = mlx5_flow_validate_item_tcp 7036 (items, item_flags, 7037 next_protocol, 7038 &nic_tcp_mask, 7039 error); 7040 if (ret < 0) 7041 return ret; 7042 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 7043 MLX5_FLOW_LAYER_OUTER_L4_TCP; 7044 break; 7045 case RTE_FLOW_ITEM_TYPE_UDP: 7046 ret = mlx5_flow_validate_item_udp(items, item_flags, 7047 next_protocol, 7048 error); 7049 const struct rte_flow_item_udp *spec = items->spec; 7050 const struct rte_flow_item_udp *mask = items->mask; 7051 if (!mask) 7052 mask = &rte_flow_item_udp_mask; 7053 if (spec != NULL) 7054 udp_dport = rte_be_to_cpu_16 7055 (spec->hdr.dst_port & 7056 mask->hdr.dst_port); 7057 if (ret < 0) 7058 return ret; 7059 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 7060 MLX5_FLOW_LAYER_OUTER_L4_UDP; 7061 break; 7062 case RTE_FLOW_ITEM_TYPE_GRE: 7063 ret = mlx5_flow_validate_item_gre(items, item_flags, 7064 next_protocol, error); 7065 if (ret < 0) 7066 return ret; 7067 gre_item = items; 7068 last_item = MLX5_FLOW_LAYER_GRE; 7069 break; 7070 case RTE_FLOW_ITEM_TYPE_NVGRE: 7071 ret = mlx5_flow_validate_item_nvgre(items, item_flags, 7072 next_protocol, 7073 error); 7074 if (ret < 0) 7075 return ret; 7076 last_item = MLX5_FLOW_LAYER_NVGRE; 7077 break; 7078 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 7079 ret = mlx5_flow_validate_item_gre_key 7080 (items, item_flags, gre_item, error); 7081 if (ret < 0) 7082 return ret; 7083 last_item = MLX5_FLOW_LAYER_GRE_KEY; 7084 break; 7085 case RTE_FLOW_ITEM_TYPE_VXLAN: 7086 ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, 7087 items, item_flags, 7088 attr, error); 7089 if (ret < 0) 7090 return ret; 7091 last_item = MLX5_FLOW_LAYER_VXLAN; 7092 break; 7093 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 7094 ret = mlx5_flow_validate_item_vxlan_gpe(items, 7095 item_flags, dev, 7096 error); 7097 if (ret < 0) 7098 return ret; 7099 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 7100 break; 7101 case RTE_FLOW_ITEM_TYPE_GENEVE: 7102 ret = mlx5_flow_validate_item_geneve(items, 7103 item_flags, dev, 7104 error); 7105 if (ret < 0) 7106 return ret; 7107 geneve_item = items; 7108 last_item = MLX5_FLOW_LAYER_GENEVE; 7109 break; 7110 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 7111 ret = mlx5_flow_validate_item_geneve_opt(items, 7112 last_item, 7113 geneve_item, 7114 dev, 7115 error); 7116 if (ret < 0) 7117 return ret; 7118 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 7119 break; 7120 case RTE_FLOW_ITEM_TYPE_MPLS: 7121 ret = mlx5_flow_validate_item_mpls(dev, items, 7122 item_flags, 7123 last_item, error); 7124 if (ret < 0) 7125 return ret; 7126 last_item = MLX5_FLOW_LAYER_MPLS; 7127 break; 7128 7129 case RTE_FLOW_ITEM_TYPE_MARK: 7130 ret = flow_dv_validate_item_mark(dev, items, attr, 7131 error); 7132 if (ret < 0) 7133 return ret; 7134 last_item = MLX5_FLOW_ITEM_MARK; 7135 break; 7136 case RTE_FLOW_ITEM_TYPE_META: 7137 ret = flow_dv_validate_item_meta(dev, items, attr, 7138 error); 7139 if (ret < 0) 7140 return ret; 7141 last_item = MLX5_FLOW_ITEM_METADATA; 7142 break; 7143 case RTE_FLOW_ITEM_TYPE_ICMP: 7144 ret = mlx5_flow_validate_item_icmp(items, item_flags, 7145 next_protocol, 7146 error); 7147 if (ret < 0) 7148 return ret; 7149 last_item = MLX5_FLOW_LAYER_ICMP; 7150 break; 7151 case RTE_FLOW_ITEM_TYPE_ICMP6: 7152 ret = mlx5_flow_validate_item_icmp6(items, item_flags, 7153 next_protocol, 7154 error); 7155 if (ret < 0) 7156 return ret; 7157 item_ipv6_proto = IPPROTO_ICMPV6; 7158 last_item = MLX5_FLOW_LAYER_ICMP6; 7159 break; 7160 case RTE_FLOW_ITEM_TYPE_TAG: 7161 ret = flow_dv_validate_item_tag(dev, items, 7162 attr, error); 7163 if (ret < 0) 7164 return ret; 7165 last_item = MLX5_FLOW_ITEM_TAG; 7166 break; 7167 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 7168 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 7169 break; 7170 case RTE_FLOW_ITEM_TYPE_GTP: 7171 ret = flow_dv_validate_item_gtp(dev, items, item_flags, 7172 error); 7173 if (ret < 0) 7174 return ret; 7175 gtp_item = items; 7176 last_item = MLX5_FLOW_LAYER_GTP; 7177 break; 7178 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 7179 ret = flow_dv_validate_item_gtp_psc(items, last_item, 7180 gtp_item, attr, 7181 error); 7182 if (ret < 0) 7183 return ret; 7184 last_item = MLX5_FLOW_LAYER_GTP_PSC; 7185 break; 7186 case RTE_FLOW_ITEM_TYPE_ECPRI: 7187 /* Capacity will be checked in the translate stage. */ 7188 ret = mlx5_flow_validate_item_ecpri(items, item_flags, 7189 last_item, 7190 ether_type, 7191 &nic_ecpri_mask, 7192 error); 7193 if (ret < 0) 7194 return ret; 7195 last_item = MLX5_FLOW_LAYER_ECPRI; 7196 break; 7197 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 7198 ret = flow_dv_validate_item_integrity(dev, items, 7199 item_flags, 7200 &last_item, 7201 integrity_items, 7202 error); 7203 if (ret < 0) 7204 return ret; 7205 break; 7206 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 7207 ret = flow_dv_validate_item_aso_ct(dev, items, 7208 &item_flags, error); 7209 if (ret < 0) 7210 return ret; 7211 break; 7212 case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL: 7213 /* tunnel offload item was processed before 7214 * list it here as a supported type 7215 */ 7216 break; 7217 case RTE_FLOW_ITEM_TYPE_FLEX: 7218 ret = flow_dv_validate_item_flex(dev, items, item_flags, 7219 &last_item, 7220 tunnel != 0, error); 7221 if (ret < 0) 7222 return ret; 7223 break; 7224 default: 7225 return rte_flow_error_set(error, ENOTSUP, 7226 RTE_FLOW_ERROR_TYPE_ITEM, 7227 NULL, "item not supported"); 7228 } 7229 item_flags |= last_item; 7230 } 7231 if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) { 7232 ret = flow_dv_validate_item_integrity_post(integrity_items, 7233 item_flags, error); 7234 if (ret) 7235 return ret; 7236 } 7237 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 7238 int type = actions->type; 7239 bool shared_count = false; 7240 7241 if (!mlx5_flow_os_action_supported(type)) 7242 return rte_flow_error_set(error, ENOTSUP, 7243 RTE_FLOW_ERROR_TYPE_ACTION, 7244 actions, 7245 "action not supported"); 7246 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 7247 return rte_flow_error_set(error, ENOTSUP, 7248 RTE_FLOW_ERROR_TYPE_ACTION, 7249 actions, "too many actions"); 7250 if (action_flags & 7251 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 7252 return rte_flow_error_set(error, ENOTSUP, 7253 RTE_FLOW_ERROR_TYPE_ACTION, 7254 NULL, "meter action with policy " 7255 "must be the last action"); 7256 switch (type) { 7257 case RTE_FLOW_ACTION_TYPE_VOID: 7258 break; 7259 case RTE_FLOW_ACTION_TYPE_PORT_ID: 7260 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 7261 ret = flow_dv_validate_action_port_id(dev, 7262 action_flags, 7263 actions, 7264 attr, 7265 error); 7266 if (ret) 7267 return ret; 7268 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 7269 ++actions_n; 7270 break; 7271 case RTE_FLOW_ACTION_TYPE_FLAG: 7272 ret = flow_dv_validate_action_flag(dev, action_flags, 7273 attr, error); 7274 if (ret < 0) 7275 return ret; 7276 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7277 /* Count all modify-header actions as one. */ 7278 if (!(action_flags & 7279 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7280 ++actions_n; 7281 action_flags |= MLX5_FLOW_ACTION_FLAG | 7282 MLX5_FLOW_ACTION_MARK_EXT; 7283 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7284 modify_after_mirror = 1; 7285 7286 } else { 7287 action_flags |= MLX5_FLOW_ACTION_FLAG; 7288 ++actions_n; 7289 } 7290 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7291 break; 7292 case RTE_FLOW_ACTION_TYPE_MARK: 7293 ret = flow_dv_validate_action_mark(dev, actions, 7294 action_flags, 7295 attr, error); 7296 if (ret < 0) 7297 return ret; 7298 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 7299 /* Count all modify-header actions as one. */ 7300 if (!(action_flags & 7301 MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7302 ++actions_n; 7303 action_flags |= MLX5_FLOW_ACTION_MARK | 7304 MLX5_FLOW_ACTION_MARK_EXT; 7305 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7306 modify_after_mirror = 1; 7307 } else { 7308 action_flags |= MLX5_FLOW_ACTION_MARK; 7309 ++actions_n; 7310 } 7311 rw_act_num += MLX5_ACT_NUM_SET_MARK; 7312 break; 7313 case RTE_FLOW_ACTION_TYPE_SET_META: 7314 ret = flow_dv_validate_action_set_meta(dev, actions, 7315 action_flags, 7316 attr, error); 7317 if (ret < 0) 7318 return ret; 7319 /* Count all modify-header actions as one action. */ 7320 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7321 ++actions_n; 7322 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7323 modify_after_mirror = 1; 7324 action_flags |= MLX5_FLOW_ACTION_SET_META; 7325 rw_act_num += MLX5_ACT_NUM_SET_META; 7326 break; 7327 case RTE_FLOW_ACTION_TYPE_SET_TAG: 7328 ret = flow_dv_validate_action_set_tag(dev, actions, 7329 action_flags, 7330 attr, error); 7331 if (ret < 0) 7332 return ret; 7333 /* Count all modify-header actions as one action. */ 7334 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7335 ++actions_n; 7336 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7337 modify_after_mirror = 1; 7338 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 7339 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7340 break; 7341 case RTE_FLOW_ACTION_TYPE_DROP: 7342 ret = mlx5_flow_validate_action_drop(action_flags, 7343 attr, error); 7344 if (ret < 0) 7345 return ret; 7346 action_flags |= MLX5_FLOW_ACTION_DROP; 7347 ++actions_n; 7348 break; 7349 case RTE_FLOW_ACTION_TYPE_QUEUE: 7350 ret = mlx5_flow_validate_action_queue(actions, 7351 action_flags, dev, 7352 attr, error); 7353 if (ret < 0) 7354 return ret; 7355 queue_index = ((const struct rte_flow_action_queue *) 7356 (actions->conf))->index; 7357 action_flags |= MLX5_FLOW_ACTION_QUEUE; 7358 ++actions_n; 7359 break; 7360 case RTE_FLOW_ACTION_TYPE_RSS: 7361 rss = actions->conf; 7362 ret = mlx5_flow_validate_action_rss(actions, 7363 action_flags, dev, 7364 attr, item_flags, 7365 error); 7366 if (ret < 0) 7367 return ret; 7368 if (rss && sample_rss && 7369 (sample_rss->level != rss->level || 7370 sample_rss->types != rss->types)) 7371 return rte_flow_error_set(error, ENOTSUP, 7372 RTE_FLOW_ERROR_TYPE_ACTION, 7373 NULL, 7374 "Can't use the different RSS types " 7375 "or level in the same flow"); 7376 if (rss != NULL && rss->queue_num) 7377 queue_index = rss->queue[0]; 7378 action_flags |= MLX5_FLOW_ACTION_RSS; 7379 ++actions_n; 7380 break; 7381 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 7382 ret = 7383 mlx5_flow_validate_action_default_miss(action_flags, 7384 attr, error); 7385 if (ret < 0) 7386 return ret; 7387 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 7388 ++actions_n; 7389 break; 7390 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 7391 shared_count = true; 7392 /* fall-through. */ 7393 case RTE_FLOW_ACTION_TYPE_COUNT: 7394 ret = flow_dv_validate_action_count(dev, shared_count, 7395 action_flags, 7396 error); 7397 if (ret < 0) 7398 return ret; 7399 action_flags |= MLX5_FLOW_ACTION_COUNT; 7400 ++actions_n; 7401 break; 7402 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 7403 if (flow_dv_validate_action_pop_vlan(dev, 7404 action_flags, 7405 actions, 7406 item_flags, attr, 7407 error)) 7408 return -rte_errno; 7409 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7410 modify_after_mirror = 1; 7411 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 7412 ++actions_n; 7413 break; 7414 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 7415 ret = flow_dv_validate_action_push_vlan(dev, 7416 action_flags, 7417 vlan_m, 7418 actions, attr, 7419 error); 7420 if (ret < 0) 7421 return ret; 7422 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7423 modify_after_mirror = 1; 7424 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 7425 ++actions_n; 7426 break; 7427 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 7428 ret = flow_dv_validate_action_set_vlan_pcp 7429 (action_flags, actions, error); 7430 if (ret < 0) 7431 return ret; 7432 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7433 modify_after_mirror = 1; 7434 /* Count PCP with push_vlan command. */ 7435 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; 7436 break; 7437 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 7438 ret = flow_dv_validate_action_set_vlan_vid 7439 (item_flags, action_flags, 7440 actions, error); 7441 if (ret < 0) 7442 return ret; 7443 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7444 modify_after_mirror = 1; 7445 /* Count VID with push_vlan command. */ 7446 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 7447 rw_act_num += MLX5_ACT_NUM_MDF_VID; 7448 break; 7449 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 7450 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 7451 ret = flow_dv_validate_action_l2_encap(dev, 7452 action_flags, 7453 actions, attr, 7454 error); 7455 if (ret < 0) 7456 return ret; 7457 action_flags |= MLX5_FLOW_ACTION_ENCAP; 7458 ++actions_n; 7459 break; 7460 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 7461 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 7462 ret = flow_dv_validate_action_decap(dev, action_flags, 7463 actions, item_flags, 7464 attr, error); 7465 if (ret < 0) 7466 return ret; 7467 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7468 modify_after_mirror = 1; 7469 action_flags |= MLX5_FLOW_ACTION_DECAP; 7470 ++actions_n; 7471 break; 7472 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 7473 ret = flow_dv_validate_action_raw_encap_decap 7474 (dev, NULL, actions->conf, attr, &action_flags, 7475 &actions_n, actions, item_flags, error); 7476 if (ret < 0) 7477 return ret; 7478 break; 7479 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 7480 decap = actions->conf; 7481 while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID) 7482 ; 7483 if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 7484 encap = NULL; 7485 actions--; 7486 } else { 7487 encap = actions->conf; 7488 } 7489 ret = flow_dv_validate_action_raw_encap_decap 7490 (dev, 7491 decap ? decap : &empty_decap, encap, 7492 attr, &action_flags, &actions_n, 7493 actions, item_flags, error); 7494 if (ret < 0) 7495 return ret; 7496 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7497 (action_flags & MLX5_FLOW_ACTION_DECAP)) 7498 modify_after_mirror = 1; 7499 break; 7500 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 7501 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 7502 ret = flow_dv_validate_action_modify_mac(action_flags, 7503 actions, 7504 item_flags, 7505 error); 7506 if (ret < 0) 7507 return ret; 7508 /* Count all modify-header actions as one action. */ 7509 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7510 ++actions_n; 7511 action_flags |= actions->type == 7512 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 7513 MLX5_FLOW_ACTION_SET_MAC_SRC : 7514 MLX5_FLOW_ACTION_SET_MAC_DST; 7515 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7516 modify_after_mirror = 1; 7517 /* 7518 * Even if the source and destination MAC addresses have 7519 * overlap in the header with 4B alignment, the convert 7520 * function will handle them separately and 4 SW actions 7521 * will be created. And 2 actions will be added each 7522 * time no matter how many bytes of address will be set. 7523 */ 7524 rw_act_num += MLX5_ACT_NUM_MDF_MAC; 7525 break; 7526 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 7527 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 7528 ret = flow_dv_validate_action_modify_ipv4(action_flags, 7529 actions, 7530 item_flags, 7531 error); 7532 if (ret < 0) 7533 return ret; 7534 /* Count all modify-header actions as one action. */ 7535 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7536 ++actions_n; 7537 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7538 modify_after_mirror = 1; 7539 action_flags |= actions->type == 7540 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 7541 MLX5_FLOW_ACTION_SET_IPV4_SRC : 7542 MLX5_FLOW_ACTION_SET_IPV4_DST; 7543 rw_act_num += MLX5_ACT_NUM_MDF_IPV4; 7544 break; 7545 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 7546 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 7547 ret = flow_dv_validate_action_modify_ipv6(action_flags, 7548 actions, 7549 item_flags, 7550 error); 7551 if (ret < 0) 7552 return ret; 7553 if (item_ipv6_proto == IPPROTO_ICMPV6) 7554 return rte_flow_error_set(error, ENOTSUP, 7555 RTE_FLOW_ERROR_TYPE_ACTION, 7556 actions, 7557 "Can't change header " 7558 "with ICMPv6 proto"); 7559 /* Count all modify-header actions as one action. */ 7560 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7561 ++actions_n; 7562 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7563 modify_after_mirror = 1; 7564 action_flags |= actions->type == 7565 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 7566 MLX5_FLOW_ACTION_SET_IPV6_SRC : 7567 MLX5_FLOW_ACTION_SET_IPV6_DST; 7568 rw_act_num += MLX5_ACT_NUM_MDF_IPV6; 7569 break; 7570 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 7571 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 7572 ret = flow_dv_validate_action_modify_tp(action_flags, 7573 actions, 7574 item_flags, 7575 error); 7576 if (ret < 0) 7577 return ret; 7578 /* Count all modify-header actions as one action. */ 7579 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7580 ++actions_n; 7581 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7582 modify_after_mirror = 1; 7583 action_flags |= actions->type == 7584 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 7585 MLX5_FLOW_ACTION_SET_TP_SRC : 7586 MLX5_FLOW_ACTION_SET_TP_DST; 7587 rw_act_num += MLX5_ACT_NUM_MDF_PORT; 7588 break; 7589 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 7590 case RTE_FLOW_ACTION_TYPE_SET_TTL: 7591 ret = flow_dv_validate_action_modify_ttl(action_flags, 7592 actions, 7593 item_flags, 7594 error); 7595 if (ret < 0) 7596 return ret; 7597 /* Count all modify-header actions as one action. */ 7598 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7599 ++actions_n; 7600 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7601 modify_after_mirror = 1; 7602 action_flags |= actions->type == 7603 RTE_FLOW_ACTION_TYPE_SET_TTL ? 7604 MLX5_FLOW_ACTION_SET_TTL : 7605 MLX5_FLOW_ACTION_DEC_TTL; 7606 rw_act_num += MLX5_ACT_NUM_MDF_TTL; 7607 break; 7608 case RTE_FLOW_ACTION_TYPE_JUMP: 7609 ret = flow_dv_validate_action_jump(dev, tunnel, actions, 7610 action_flags, 7611 attr, external, 7612 error); 7613 if (ret) 7614 return ret; 7615 if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && 7616 fdb_mirror_limit) 7617 return rte_flow_error_set(error, EINVAL, 7618 RTE_FLOW_ERROR_TYPE_ACTION, 7619 NULL, 7620 "sample and jump action combination is not supported"); 7621 ++actions_n; 7622 action_flags |= MLX5_FLOW_ACTION_JUMP; 7623 break; 7624 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 7625 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 7626 ret = flow_dv_validate_action_modify_tcp_seq 7627 (action_flags, 7628 actions, 7629 item_flags, 7630 error); 7631 if (ret < 0) 7632 return ret; 7633 /* Count all modify-header actions as one action. */ 7634 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7635 ++actions_n; 7636 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7637 modify_after_mirror = 1; 7638 action_flags |= actions->type == 7639 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 7640 MLX5_FLOW_ACTION_INC_TCP_SEQ : 7641 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 7642 rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ; 7643 break; 7644 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 7645 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 7646 ret = flow_dv_validate_action_modify_tcp_ack 7647 (action_flags, 7648 actions, 7649 item_flags, 7650 error); 7651 if (ret < 0) 7652 return ret; 7653 /* Count all modify-header actions as one action. */ 7654 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7655 ++actions_n; 7656 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7657 modify_after_mirror = 1; 7658 action_flags |= actions->type == 7659 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 7660 MLX5_FLOW_ACTION_INC_TCP_ACK : 7661 MLX5_FLOW_ACTION_DEC_TCP_ACK; 7662 rw_act_num += MLX5_ACT_NUM_MDF_TCPACK; 7663 break; 7664 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 7665 break; 7666 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 7667 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 7668 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7669 break; 7670 case RTE_FLOW_ACTION_TYPE_METER: 7671 ret = mlx5_flow_validate_action_meter(dev, 7672 action_flags, 7673 actions, attr, 7674 port_id_item, 7675 &def_policy, 7676 error); 7677 if (ret < 0) 7678 return ret; 7679 action_flags |= MLX5_FLOW_ACTION_METER; 7680 if (!def_policy) 7681 action_flags |= 7682 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 7683 ++actions_n; 7684 /* Meter action will add one more TAG action. */ 7685 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7686 break; 7687 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 7688 if (!attr->transfer && !attr->group) 7689 return rte_flow_error_set(error, ENOTSUP, 7690 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 7691 NULL, 7692 "Shared ASO age action is not supported for group 0"); 7693 if (action_flags & MLX5_FLOW_ACTION_AGE) 7694 return rte_flow_error_set 7695 (error, EINVAL, 7696 RTE_FLOW_ERROR_TYPE_ACTION, 7697 NULL, 7698 "duplicate age actions set"); 7699 action_flags |= MLX5_FLOW_ACTION_AGE; 7700 ++actions_n; 7701 break; 7702 case RTE_FLOW_ACTION_TYPE_AGE: 7703 ret = flow_dv_validate_action_age(action_flags, 7704 actions, dev, 7705 error); 7706 if (ret < 0) 7707 return ret; 7708 /* 7709 * Validate the regular AGE action (using counter) 7710 * mutual exclusion with share counter actions. 7711 */ 7712 if (!priv->sh->flow_hit_aso_en) { 7713 if (shared_count) 7714 return rte_flow_error_set 7715 (error, EINVAL, 7716 RTE_FLOW_ERROR_TYPE_ACTION, 7717 NULL, 7718 "old age and shared count combination is not supported"); 7719 if (sample_count) 7720 return rte_flow_error_set 7721 (error, EINVAL, 7722 RTE_FLOW_ERROR_TYPE_ACTION, 7723 NULL, 7724 "old age action and count must be in the same sub flow"); 7725 } 7726 action_flags |= MLX5_FLOW_ACTION_AGE; 7727 ++actions_n; 7728 break; 7729 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 7730 ret = flow_dv_validate_action_modify_ipv4_dscp 7731 (action_flags, 7732 actions, 7733 item_flags, 7734 error); 7735 if (ret < 0) 7736 return ret; 7737 /* Count all modify-header actions as one action. */ 7738 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7739 ++actions_n; 7740 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7741 modify_after_mirror = 1; 7742 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 7743 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7744 break; 7745 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 7746 ret = flow_dv_validate_action_modify_ipv6_dscp 7747 (action_flags, 7748 actions, 7749 item_flags, 7750 error); 7751 if (ret < 0) 7752 return ret; 7753 /* Count all modify-header actions as one action. */ 7754 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7755 ++actions_n; 7756 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7757 modify_after_mirror = 1; 7758 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 7759 rw_act_num += MLX5_ACT_NUM_SET_DSCP; 7760 break; 7761 case RTE_FLOW_ACTION_TYPE_SAMPLE: 7762 ret = flow_dv_validate_action_sample(&action_flags, 7763 actions, dev, 7764 attr, item_flags, 7765 rss, &sample_rss, 7766 &sample_count, 7767 &fdb_mirror_limit, 7768 error); 7769 if (ret < 0) 7770 return ret; 7771 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 7772 ++actions_n; 7773 break; 7774 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 7775 ret = flow_dv_validate_action_modify_field(dev, 7776 action_flags, 7777 actions, 7778 attr, 7779 error); 7780 if (ret < 0) 7781 return ret; 7782 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 7783 modify_after_mirror = 1; 7784 /* Count all modify-header actions as one action. */ 7785 if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)) 7786 ++actions_n; 7787 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 7788 rw_act_num += ret; 7789 break; 7790 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 7791 ret = flow_dv_validate_action_aso_ct(dev, action_flags, 7792 item_flags, attr, 7793 error); 7794 if (ret < 0) 7795 return ret; 7796 action_flags |= MLX5_FLOW_ACTION_CT; 7797 break; 7798 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 7799 /* tunnel offload action was processed before 7800 * list it here as a supported type 7801 */ 7802 break; 7803 default: 7804 return rte_flow_error_set(error, ENOTSUP, 7805 RTE_FLOW_ERROR_TYPE_ACTION, 7806 actions, 7807 "action not supported"); 7808 } 7809 } 7810 /* 7811 * Validate actions in flow rules 7812 * - Explicit decap action is prohibited by the tunnel offload API. 7813 * - Drop action in tunnel steer rule is prohibited by the API. 7814 * - Application cannot use MARK action because it's value can mask 7815 * tunnel default miss nitification. 7816 * - JUMP in tunnel match rule has no support in current PMD 7817 * implementation. 7818 * - TAG & META are reserved for future uses. 7819 */ 7820 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) { 7821 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP | 7822 MLX5_FLOW_ACTION_MARK | 7823 MLX5_FLOW_ACTION_SET_TAG | 7824 MLX5_FLOW_ACTION_SET_META | 7825 MLX5_FLOW_ACTION_DROP; 7826 7827 if (action_flags & bad_actions_mask) 7828 return rte_flow_error_set 7829 (error, EINVAL, 7830 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7831 "Invalid RTE action in tunnel " 7832 "set decap rule"); 7833 if (!(action_flags & MLX5_FLOW_ACTION_JUMP)) 7834 return rte_flow_error_set 7835 (error, EINVAL, 7836 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7837 "tunnel set decap rule must terminate " 7838 "with JUMP"); 7839 if (!attr->ingress) 7840 return rte_flow_error_set 7841 (error, EINVAL, 7842 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7843 "tunnel flows for ingress traffic only"); 7844 } 7845 if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) { 7846 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP | 7847 MLX5_FLOW_ACTION_MARK | 7848 MLX5_FLOW_ACTION_SET_TAG | 7849 MLX5_FLOW_ACTION_SET_META; 7850 7851 if (action_flags & bad_actions_mask) 7852 return rte_flow_error_set 7853 (error, EINVAL, 7854 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7855 "Invalid RTE action in tunnel " 7856 "set match rule"); 7857 } 7858 /* 7859 * Validate the drop action mutual exclusion with other actions. 7860 * Drop action is mutually-exclusive with any other action, except for 7861 * Count action. 7862 * Drop action compatibility with tunnel offload was already validated. 7863 */ 7864 if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH | 7865 MLX5_FLOW_ACTION_TUNNEL_MATCH)); 7866 else if ((action_flags & MLX5_FLOW_ACTION_DROP) && 7867 (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT))) 7868 return rte_flow_error_set(error, EINVAL, 7869 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 7870 "Drop action is mutually-exclusive " 7871 "with any other action, except for " 7872 "Count action"); 7873 /* Eswitch has few restrictions on using items and actions */ 7874 if (attr->transfer) { 7875 if (!mlx5_flow_ext_mreg_supported(dev) && 7876 action_flags & MLX5_FLOW_ACTION_FLAG) 7877 return rte_flow_error_set(error, ENOTSUP, 7878 RTE_FLOW_ERROR_TYPE_ACTION, 7879 NULL, 7880 "unsupported action FLAG"); 7881 if (!mlx5_flow_ext_mreg_supported(dev) && 7882 action_flags & MLX5_FLOW_ACTION_MARK) 7883 return rte_flow_error_set(error, ENOTSUP, 7884 RTE_FLOW_ERROR_TYPE_ACTION, 7885 NULL, 7886 "unsupported action MARK"); 7887 if (action_flags & MLX5_FLOW_ACTION_QUEUE) 7888 return rte_flow_error_set(error, ENOTSUP, 7889 RTE_FLOW_ERROR_TYPE_ACTION, 7890 NULL, 7891 "unsupported action QUEUE"); 7892 if (action_flags & MLX5_FLOW_ACTION_RSS) 7893 return rte_flow_error_set(error, ENOTSUP, 7894 RTE_FLOW_ERROR_TYPE_ACTION, 7895 NULL, 7896 "unsupported action RSS"); 7897 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 7898 return rte_flow_error_set(error, EINVAL, 7899 RTE_FLOW_ERROR_TYPE_ACTION, 7900 actions, 7901 "no fate action is found"); 7902 } else { 7903 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress) 7904 return rte_flow_error_set(error, EINVAL, 7905 RTE_FLOW_ERROR_TYPE_ACTION, 7906 actions, 7907 "no fate action is found"); 7908 } 7909 /* 7910 * Continue validation for Xcap and VLAN actions. 7911 * If hairpin is working in explicit TX rule mode, there is no actions 7912 * splitting and the validation of hairpin ingress flow should be the 7913 * same as other standard flows. 7914 */ 7915 if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS | 7916 MLX5_FLOW_VLAN_ACTIONS)) && 7917 (queue_index == 0xFFFF || 7918 mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN || 7919 ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL && 7920 conf->tx_explicit != 0))) { 7921 if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) == 7922 MLX5_FLOW_XCAP_ACTIONS) 7923 return rte_flow_error_set(error, ENOTSUP, 7924 RTE_FLOW_ERROR_TYPE_ACTION, 7925 NULL, "encap and decap " 7926 "combination aren't supported"); 7927 if (!attr->transfer && attr->ingress) { 7928 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 7929 return rte_flow_error_set 7930 (error, ENOTSUP, 7931 RTE_FLOW_ERROR_TYPE_ACTION, 7932 NULL, "encap is not supported" 7933 " for ingress traffic"); 7934 else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 7935 return rte_flow_error_set 7936 (error, ENOTSUP, 7937 RTE_FLOW_ERROR_TYPE_ACTION, 7938 NULL, "push VLAN action not " 7939 "supported for ingress"); 7940 else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) == 7941 MLX5_FLOW_VLAN_ACTIONS) 7942 return rte_flow_error_set 7943 (error, ENOTSUP, 7944 RTE_FLOW_ERROR_TYPE_ACTION, 7945 NULL, "no support for " 7946 "multiple VLAN actions"); 7947 } 7948 } 7949 if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) { 7950 if ((action_flags & (MLX5_FLOW_FATE_ACTIONS & 7951 ~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) && 7952 attr->ingress) 7953 return rte_flow_error_set 7954 (error, ENOTSUP, 7955 RTE_FLOW_ERROR_TYPE_ACTION, 7956 NULL, "fate action not supported for " 7957 "meter with policy"); 7958 if (attr->egress) { 7959 if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) 7960 return rte_flow_error_set 7961 (error, ENOTSUP, 7962 RTE_FLOW_ERROR_TYPE_ACTION, 7963 NULL, "modify header action in egress " 7964 "cannot be done before meter action"); 7965 if (action_flags & MLX5_FLOW_ACTION_ENCAP) 7966 return rte_flow_error_set 7967 (error, ENOTSUP, 7968 RTE_FLOW_ERROR_TYPE_ACTION, 7969 NULL, "encap action in egress " 7970 "cannot be done before meter action"); 7971 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 7972 return rte_flow_error_set 7973 (error, ENOTSUP, 7974 RTE_FLOW_ERROR_TYPE_ACTION, 7975 NULL, "push vlan action in egress " 7976 "cannot be done before meter action"); 7977 } 7978 } 7979 /* 7980 * Hairpin flow will add one more TAG action in TX implicit mode. 7981 * In TX explicit mode, there will be no hairpin flow ID. 7982 */ 7983 if (hairpin > 0) 7984 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7985 /* extra metadata enabled: one more TAG action will be add. */ 7986 if (dev_conf->dv_flow_en && 7987 dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && 7988 mlx5_flow_ext_mreg_supported(dev)) 7989 rw_act_num += MLX5_ACT_NUM_SET_TAG; 7990 if (rw_act_num > 7991 flow_dv_modify_hdr_action_max(dev, is_root)) { 7992 return rte_flow_error_set(error, ENOTSUP, 7993 RTE_FLOW_ERROR_TYPE_ACTION, 7994 NULL, "too many header modify" 7995 " actions to support"); 7996 } 7997 /* Eswitch egress mirror and modify flow has limitation on CX5 */ 7998 if (fdb_mirror_limit && modify_after_mirror) 7999 return rte_flow_error_set(error, EINVAL, 8000 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 8001 "sample before modify action is not supported"); 8002 return 0; 8003 } 8004 8005 /** 8006 * Internal preparation function. Allocates the DV flow size, 8007 * this size is constant. 8008 * 8009 * @param[in] dev 8010 * Pointer to the rte_eth_dev structure. 8011 * @param[in] attr 8012 * Pointer to the flow attributes. 8013 * @param[in] items 8014 * Pointer to the list of items. 8015 * @param[in] actions 8016 * Pointer to the list of actions. 8017 * @param[out] error 8018 * Pointer to the error structure. 8019 * 8020 * @return 8021 * Pointer to mlx5_flow object on success, 8022 * otherwise NULL and rte_errno is set. 8023 */ 8024 static struct mlx5_flow * 8025 flow_dv_prepare(struct rte_eth_dev *dev, 8026 const struct rte_flow_attr *attr __rte_unused, 8027 const struct rte_flow_item items[] __rte_unused, 8028 const struct rte_flow_action actions[] __rte_unused, 8029 struct rte_flow_error *error) 8030 { 8031 uint32_t handle_idx = 0; 8032 struct mlx5_flow *dev_flow; 8033 struct mlx5_flow_handle *dev_handle; 8034 struct mlx5_priv *priv = dev->data->dev_private; 8035 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 8036 8037 MLX5_ASSERT(wks); 8038 wks->skip_matcher_reg = 0; 8039 wks->policy = NULL; 8040 wks->final_policy = NULL; 8041 /* In case of corrupting the memory. */ 8042 if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) { 8043 rte_flow_error_set(error, ENOSPC, 8044 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8045 "not free temporary device flow"); 8046 return NULL; 8047 } 8048 dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 8049 &handle_idx); 8050 if (!dev_handle) { 8051 rte_flow_error_set(error, ENOMEM, 8052 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 8053 "not enough memory to create flow handle"); 8054 return NULL; 8055 } 8056 MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows)); 8057 dev_flow = &wks->flows[wks->flow_idx++]; 8058 memset(dev_flow, 0, sizeof(*dev_flow)); 8059 dev_flow->handle = dev_handle; 8060 dev_flow->handle_idx = handle_idx; 8061 dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 8062 dev_flow->ingress = attr->ingress; 8063 dev_flow->dv.transfer = attr->transfer; 8064 return dev_flow; 8065 } 8066 8067 #ifdef RTE_LIBRTE_MLX5_DEBUG 8068 /** 8069 * Sanity check for match mask and value. Similar to check_valid_spec() in 8070 * kernel driver. If unmasked bit is present in value, it returns failure. 8071 * 8072 * @param match_mask 8073 * pointer to match mask buffer. 8074 * @param match_value 8075 * pointer to match value buffer. 8076 * 8077 * @return 8078 * 0 if valid, -EINVAL otherwise. 8079 */ 8080 static int 8081 flow_dv_check_valid_spec(void *match_mask, void *match_value) 8082 { 8083 uint8_t *m = match_mask; 8084 uint8_t *v = match_value; 8085 unsigned int i; 8086 8087 for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) { 8088 if (v[i] & ~m[i]) { 8089 DRV_LOG(ERR, 8090 "match_value differs from match_criteria" 8091 " %p[%u] != %p[%u]", 8092 match_value, i, match_mask, i); 8093 return -EINVAL; 8094 } 8095 } 8096 return 0; 8097 } 8098 #endif 8099 8100 /** 8101 * Add match of ip_version. 8102 * 8103 * @param[in] group 8104 * Flow group. 8105 * @param[in] headers_v 8106 * Values header pointer. 8107 * @param[in] headers_m 8108 * Masks header pointer. 8109 * @param[in] ip_version 8110 * The IP version to set. 8111 */ 8112 static inline void 8113 flow_dv_set_match_ip_version(uint32_t group, 8114 void *headers_v, 8115 void *headers_m, 8116 uint8_t ip_version) 8117 { 8118 if (group == 0) 8119 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf); 8120 else 8121 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 8122 ip_version); 8123 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version); 8124 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0); 8125 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0); 8126 } 8127 8128 /** 8129 * Add Ethernet item to matcher and to the value. 8130 * 8131 * @param[in, out] matcher 8132 * Flow matcher. 8133 * @param[in, out] key 8134 * Flow matcher value. 8135 * @param[in] item 8136 * Flow pattern to translate. 8137 * @param[in] inner 8138 * Item is inner pattern. 8139 */ 8140 static void 8141 flow_dv_translate_item_eth(void *matcher, void *key, 8142 const struct rte_flow_item *item, int inner, 8143 uint32_t group) 8144 { 8145 const struct rte_flow_item_eth *eth_m = item->mask; 8146 const struct rte_flow_item_eth *eth_v = item->spec; 8147 const struct rte_flow_item_eth nic_mask = { 8148 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8149 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff", 8150 .type = RTE_BE16(0xffff), 8151 .has_vlan = 0, 8152 }; 8153 void *hdrs_m; 8154 void *hdrs_v; 8155 char *l24_v; 8156 unsigned int i; 8157 8158 if (!eth_v) 8159 return; 8160 if (!eth_m) 8161 eth_m = &nic_mask; 8162 if (inner) { 8163 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8164 inner_headers); 8165 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8166 } else { 8167 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8168 outer_headers); 8169 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8170 } 8171 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16), 8172 ð_m->dst, sizeof(eth_m->dst)); 8173 /* The value must be in the range of the mask. */ 8174 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16); 8175 for (i = 0; i < sizeof(eth_m->dst); ++i) 8176 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i]; 8177 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16), 8178 ð_m->src, sizeof(eth_m->src)); 8179 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16); 8180 /* The value must be in the range of the mask. */ 8181 for (i = 0; i < sizeof(eth_m->dst); ++i) 8182 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i]; 8183 /* 8184 * HW supports match on one Ethertype, the Ethertype following the last 8185 * VLAN tag of the packet (see PRM). 8186 * Set match on ethertype only if ETH header is not followed by VLAN. 8187 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8188 * ethertype, and use ip_version field instead. 8189 * eCPRI over Ether layer will use type value 0xAEFE. 8190 */ 8191 if (eth_m->type == 0xFFFF) { 8192 /* Set cvlan_tag mask for any single\multi\un-tagged case. */ 8193 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8194 switch (eth_v->type) { 8195 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8196 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8197 return; 8198 case RTE_BE16(RTE_ETHER_TYPE_QINQ): 8199 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8200 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8201 return; 8202 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8203 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8204 return; 8205 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8206 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8207 return; 8208 default: 8209 break; 8210 } 8211 } 8212 if (eth_m->has_vlan) { 8213 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8214 if (eth_v->has_vlan) { 8215 /* 8216 * Here, when also has_more_vlan field in VLAN item is 8217 * not set, only single-tagged packets will be matched. 8218 */ 8219 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8220 return; 8221 } 8222 } 8223 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8224 rte_be_to_cpu_16(eth_m->type)); 8225 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 8226 *(uint16_t *)(l24_v) = eth_m->type & eth_v->type; 8227 } 8228 8229 /** 8230 * Add VLAN item to matcher and to the value. 8231 * 8232 * @param[in, out] dev_flow 8233 * Flow descriptor. 8234 * @param[in, out] matcher 8235 * Flow matcher. 8236 * @param[in, out] key 8237 * Flow matcher value. 8238 * @param[in] item 8239 * Flow pattern to translate. 8240 * @param[in] inner 8241 * Item is inner pattern. 8242 */ 8243 static void 8244 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow, 8245 void *matcher, void *key, 8246 const struct rte_flow_item *item, 8247 int inner, uint32_t group) 8248 { 8249 const struct rte_flow_item_vlan *vlan_m = item->mask; 8250 const struct rte_flow_item_vlan *vlan_v = item->spec; 8251 void *hdrs_m; 8252 void *hdrs_v; 8253 uint16_t tci_m; 8254 uint16_t tci_v; 8255 8256 if (inner) { 8257 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8258 inner_headers); 8259 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8260 } else { 8261 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, 8262 outer_headers); 8263 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8264 /* 8265 * This is workaround, masks are not supported, 8266 * and pre-validated. 8267 */ 8268 if (vlan_v) 8269 dev_flow->handle->vf_vlan.tag = 8270 rte_be_to_cpu_16(vlan_v->tci) & 0x0fff; 8271 } 8272 /* 8273 * When VLAN item exists in flow, mark packet as tagged, 8274 * even if TCI is not specified. 8275 */ 8276 if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) { 8277 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1); 8278 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1); 8279 } 8280 if (!vlan_v) 8281 return; 8282 if (!vlan_m) 8283 vlan_m = &rte_flow_item_vlan_mask; 8284 tci_m = rte_be_to_cpu_16(vlan_m->tci); 8285 tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci); 8286 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m); 8287 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v); 8288 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12); 8289 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12); 8290 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13); 8291 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13); 8292 /* 8293 * HW is optimized for IPv4/IPv6. In such cases, avoid setting 8294 * ethertype, and use ip_version field instead. 8295 */ 8296 if (vlan_m->inner_type == 0xFFFF) { 8297 switch (vlan_v->inner_type) { 8298 case RTE_BE16(RTE_ETHER_TYPE_VLAN): 8299 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8300 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8301 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8302 return; 8303 case RTE_BE16(RTE_ETHER_TYPE_IPV4): 8304 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4); 8305 return; 8306 case RTE_BE16(RTE_ETHER_TYPE_IPV6): 8307 flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6); 8308 return; 8309 default: 8310 break; 8311 } 8312 } 8313 if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) { 8314 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1); 8315 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1); 8316 /* Only one vlan_tag bit can be set. */ 8317 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0); 8318 return; 8319 } 8320 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype, 8321 rte_be_to_cpu_16(vlan_m->inner_type)); 8322 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype, 8323 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type)); 8324 } 8325 8326 /** 8327 * Add IPV4 item to matcher and to the value. 8328 * 8329 * @param[in, out] matcher 8330 * Flow matcher. 8331 * @param[in, out] key 8332 * Flow matcher value. 8333 * @param[in] item 8334 * Flow pattern to translate. 8335 * @param[in] inner 8336 * Item is inner pattern. 8337 * @param[in] group 8338 * The group to insert the rule. 8339 */ 8340 static void 8341 flow_dv_translate_item_ipv4(void *matcher, void *key, 8342 const struct rte_flow_item *item, 8343 int inner, uint32_t group) 8344 { 8345 const struct rte_flow_item_ipv4 *ipv4_m = item->mask; 8346 const struct rte_flow_item_ipv4 *ipv4_v = item->spec; 8347 const struct rte_flow_item_ipv4 nic_mask = { 8348 .hdr = { 8349 .src_addr = RTE_BE32(0xffffffff), 8350 .dst_addr = RTE_BE32(0xffffffff), 8351 .type_of_service = 0xff, 8352 .next_proto_id = 0xff, 8353 .time_to_live = 0xff, 8354 }, 8355 }; 8356 void *headers_m; 8357 void *headers_v; 8358 char *l24_m; 8359 char *l24_v; 8360 uint8_t tos, ihl_m, ihl_v; 8361 8362 if (inner) { 8363 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8364 inner_headers); 8365 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8366 } else { 8367 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8368 outer_headers); 8369 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8370 } 8371 flow_dv_set_match_ip_version(group, headers_v, headers_m, 4); 8372 if (!ipv4_v) 8373 return; 8374 if (!ipv4_m) 8375 ipv4_m = &nic_mask; 8376 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8377 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8378 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8379 dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 8380 *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr; 8381 *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr; 8382 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8383 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8384 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8385 src_ipv4_src_ipv6.ipv4_layout.ipv4); 8386 *(uint32_t *)l24_m = ipv4_m->hdr.src_addr; 8387 *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr; 8388 tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service; 8389 ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8390 ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK; 8391 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m); 8392 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v); 8393 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, 8394 ipv4_m->hdr.type_of_service); 8395 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos); 8396 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, 8397 ipv4_m->hdr.type_of_service >> 2); 8398 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2); 8399 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8400 ipv4_m->hdr.next_proto_id); 8401 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8402 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id); 8403 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8404 ipv4_m->hdr.time_to_live); 8405 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8406 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live); 8407 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8408 !!(ipv4_m->hdr.fragment_offset)); 8409 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8410 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset)); 8411 } 8412 8413 /** 8414 * Add IPV6 item to matcher and to the value. 8415 * 8416 * @param[in, out] matcher 8417 * Flow matcher. 8418 * @param[in, out] key 8419 * Flow matcher value. 8420 * @param[in] item 8421 * Flow pattern to translate. 8422 * @param[in] inner 8423 * Item is inner pattern. 8424 * @param[in] group 8425 * The group to insert the rule. 8426 */ 8427 static void 8428 flow_dv_translate_item_ipv6(void *matcher, void *key, 8429 const struct rte_flow_item *item, 8430 int inner, uint32_t group) 8431 { 8432 const struct rte_flow_item_ipv6 *ipv6_m = item->mask; 8433 const struct rte_flow_item_ipv6 *ipv6_v = item->spec; 8434 const struct rte_flow_item_ipv6 nic_mask = { 8435 .hdr = { 8436 .src_addr = 8437 "\xff\xff\xff\xff\xff\xff\xff\xff" 8438 "\xff\xff\xff\xff\xff\xff\xff\xff", 8439 .dst_addr = 8440 "\xff\xff\xff\xff\xff\xff\xff\xff" 8441 "\xff\xff\xff\xff\xff\xff\xff\xff", 8442 .vtc_flow = RTE_BE32(0xffffffff), 8443 .proto = 0xff, 8444 .hop_limits = 0xff, 8445 }, 8446 }; 8447 void *headers_m; 8448 void *headers_v; 8449 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8450 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8451 char *l24_m; 8452 char *l24_v; 8453 uint32_t vtc_m; 8454 uint32_t vtc_v; 8455 int i; 8456 int size; 8457 8458 if (inner) { 8459 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8460 inner_headers); 8461 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8462 } else { 8463 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8464 outer_headers); 8465 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8466 } 8467 flow_dv_set_match_ip_version(group, headers_v, headers_m, 6); 8468 if (!ipv6_v) 8469 return; 8470 if (!ipv6_m) 8471 ipv6_m = &nic_mask; 8472 size = sizeof(ipv6_m->hdr.dst_addr); 8473 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8474 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8475 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8476 dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 8477 memcpy(l24_m, ipv6_m->hdr.dst_addr, size); 8478 for (i = 0; i < size; ++i) 8479 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i]; 8480 l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, 8481 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8482 l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 8483 src_ipv4_src_ipv6.ipv6_layout.ipv6); 8484 memcpy(l24_m, ipv6_m->hdr.src_addr, size); 8485 for (i = 0; i < size; ++i) 8486 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i]; 8487 /* TOS. */ 8488 vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow); 8489 vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow); 8490 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20); 8491 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20); 8492 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22); 8493 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22); 8494 /* Label. */ 8495 if (inner) { 8496 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label, 8497 vtc_m); 8498 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label, 8499 vtc_v); 8500 } else { 8501 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label, 8502 vtc_m); 8503 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label, 8504 vtc_v); 8505 } 8506 /* Protocol. */ 8507 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8508 ipv6_m->hdr.proto); 8509 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8510 ipv6_v->hdr.proto & ipv6_m->hdr.proto); 8511 /* Hop limit. */ 8512 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit, 8513 ipv6_m->hdr.hop_limits); 8514 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit, 8515 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits); 8516 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 8517 !!(ipv6_m->has_frag_ext)); 8518 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 8519 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext)); 8520 } 8521 8522 /** 8523 * Add IPV6 fragment extension item to matcher and to the value. 8524 * 8525 * @param[in, out] matcher 8526 * Flow matcher. 8527 * @param[in, out] key 8528 * Flow matcher value. 8529 * @param[in] item 8530 * Flow pattern to translate. 8531 * @param[in] inner 8532 * Item is inner pattern. 8533 */ 8534 static void 8535 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key, 8536 const struct rte_flow_item *item, 8537 int inner) 8538 { 8539 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask; 8540 const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec; 8541 const struct rte_flow_item_ipv6_frag_ext nic_mask = { 8542 .hdr = { 8543 .next_header = 0xff, 8544 .frag_data = RTE_BE16(0xffff), 8545 }, 8546 }; 8547 void *headers_m; 8548 void *headers_v; 8549 8550 if (inner) { 8551 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8552 inner_headers); 8553 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8554 } else { 8555 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8556 outer_headers); 8557 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8558 } 8559 /* IPv6 fragment extension item exists, so packet is IP fragment. */ 8560 MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1); 8561 MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1); 8562 if (!ipv6_frag_ext_v) 8563 return; 8564 if (!ipv6_frag_ext_m) 8565 ipv6_frag_ext_m = &nic_mask; 8566 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 8567 ipv6_frag_ext_m->hdr.next_header); 8568 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 8569 ipv6_frag_ext_v->hdr.next_header & 8570 ipv6_frag_ext_m->hdr.next_header); 8571 } 8572 8573 /** 8574 * Add TCP item to matcher and to the value. 8575 * 8576 * @param[in, out] matcher 8577 * Flow matcher. 8578 * @param[in, out] key 8579 * Flow matcher value. 8580 * @param[in] item 8581 * Flow pattern to translate. 8582 * @param[in] inner 8583 * Item is inner pattern. 8584 */ 8585 static void 8586 flow_dv_translate_item_tcp(void *matcher, void *key, 8587 const struct rte_flow_item *item, 8588 int inner) 8589 { 8590 const struct rte_flow_item_tcp *tcp_m = item->mask; 8591 const struct rte_flow_item_tcp *tcp_v = item->spec; 8592 void *headers_m; 8593 void *headers_v; 8594 8595 if (inner) { 8596 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8597 inner_headers); 8598 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8599 } else { 8600 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8601 outer_headers); 8602 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8603 } 8604 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8605 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP); 8606 if (!tcp_v) 8607 return; 8608 if (!tcp_m) 8609 tcp_m = &rte_flow_item_tcp_mask; 8610 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport, 8611 rte_be_to_cpu_16(tcp_m->hdr.src_port)); 8612 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, 8613 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port)); 8614 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport, 8615 rte_be_to_cpu_16(tcp_m->hdr.dst_port)); 8616 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, 8617 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port)); 8618 MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags, 8619 tcp_m->hdr.tcp_flags); 8620 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, 8621 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags)); 8622 } 8623 8624 /** 8625 * Add UDP item to matcher and to the value. 8626 * 8627 * @param[in, out] matcher 8628 * Flow matcher. 8629 * @param[in, out] key 8630 * Flow matcher value. 8631 * @param[in] item 8632 * Flow pattern to translate. 8633 * @param[in] inner 8634 * Item is inner pattern. 8635 */ 8636 static void 8637 flow_dv_translate_item_udp(void *matcher, void *key, 8638 const struct rte_flow_item *item, 8639 int inner) 8640 { 8641 const struct rte_flow_item_udp *udp_m = item->mask; 8642 const struct rte_flow_item_udp *udp_v = item->spec; 8643 void *headers_m; 8644 void *headers_v; 8645 8646 if (inner) { 8647 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8648 inner_headers); 8649 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8650 } else { 8651 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8652 outer_headers); 8653 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8654 } 8655 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8656 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 8657 if (!udp_v) 8658 return; 8659 if (!udp_m) 8660 udp_m = &rte_flow_item_udp_mask; 8661 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport, 8662 rte_be_to_cpu_16(udp_m->hdr.src_port)); 8663 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, 8664 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port)); 8665 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 8666 rte_be_to_cpu_16(udp_m->hdr.dst_port)); 8667 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 8668 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port)); 8669 } 8670 8671 /** 8672 * Add GRE optional Key item to matcher and to the value. 8673 * 8674 * @param[in, out] matcher 8675 * Flow matcher. 8676 * @param[in, out] key 8677 * Flow matcher value. 8678 * @param[in] item 8679 * Flow pattern to translate. 8680 * @param[in] inner 8681 * Item is inner pattern. 8682 */ 8683 static void 8684 flow_dv_translate_item_gre_key(void *matcher, void *key, 8685 const struct rte_flow_item *item) 8686 { 8687 const rte_be32_t *key_m = item->mask; 8688 const rte_be32_t *key_v = item->spec; 8689 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8690 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8691 rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX); 8692 8693 /* GRE K bit must be on and should already be validated */ 8694 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1); 8695 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1); 8696 if (!key_v) 8697 return; 8698 if (!key_m) 8699 key_m = &gre_key_default_mask; 8700 MLX5_SET(fte_match_set_misc, misc_m, gre_key_h, 8701 rte_be_to_cpu_32(*key_m) >> 8); 8702 MLX5_SET(fte_match_set_misc, misc_v, gre_key_h, 8703 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8); 8704 MLX5_SET(fte_match_set_misc, misc_m, gre_key_l, 8705 rte_be_to_cpu_32(*key_m) & 0xFF); 8706 MLX5_SET(fte_match_set_misc, misc_v, gre_key_l, 8707 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF); 8708 } 8709 8710 /** 8711 * Add GRE item to matcher and to the value. 8712 * 8713 * @param[in, out] matcher 8714 * Flow matcher. 8715 * @param[in, out] key 8716 * Flow matcher value. 8717 * @param[in] item 8718 * Flow pattern to translate. 8719 * @param[in] inner 8720 * Item is inner pattern. 8721 */ 8722 static void 8723 flow_dv_translate_item_gre(void *matcher, void *key, 8724 const struct rte_flow_item *item, 8725 int inner) 8726 { 8727 const struct rte_flow_item_gre *gre_m = item->mask; 8728 const struct rte_flow_item_gre *gre_v = item->spec; 8729 void *headers_m; 8730 void *headers_v; 8731 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8732 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8733 struct { 8734 union { 8735 __extension__ 8736 struct { 8737 uint16_t version:3; 8738 uint16_t rsvd0:9; 8739 uint16_t s_present:1; 8740 uint16_t k_present:1; 8741 uint16_t rsvd_bit1:1; 8742 uint16_t c_present:1; 8743 }; 8744 uint16_t value; 8745 }; 8746 } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v; 8747 8748 if (inner) { 8749 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8750 inner_headers); 8751 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8752 } else { 8753 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8754 outer_headers); 8755 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8756 } 8757 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff); 8758 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE); 8759 if (!gre_v) 8760 return; 8761 if (!gre_m) 8762 gre_m = &rte_flow_item_gre_mask; 8763 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 8764 rte_be_to_cpu_16(gre_m->protocol)); 8765 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 8766 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol)); 8767 gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver); 8768 gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver); 8769 MLX5_SET(fte_match_set_misc, misc_m, gre_c_present, 8770 gre_crks_rsvd0_ver_m.c_present); 8771 MLX5_SET(fte_match_set_misc, misc_v, gre_c_present, 8772 gre_crks_rsvd0_ver_v.c_present & 8773 gre_crks_rsvd0_ver_m.c_present); 8774 MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 8775 gre_crks_rsvd0_ver_m.k_present); 8776 MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 8777 gre_crks_rsvd0_ver_v.k_present & 8778 gre_crks_rsvd0_ver_m.k_present); 8779 MLX5_SET(fte_match_set_misc, misc_m, gre_s_present, 8780 gre_crks_rsvd0_ver_m.s_present); 8781 MLX5_SET(fte_match_set_misc, misc_v, gre_s_present, 8782 gre_crks_rsvd0_ver_v.s_present & 8783 gre_crks_rsvd0_ver_m.s_present); 8784 } 8785 8786 /** 8787 * Add NVGRE item to matcher and to the value. 8788 * 8789 * @param[in, out] matcher 8790 * Flow matcher. 8791 * @param[in, out] key 8792 * Flow matcher value. 8793 * @param[in] item 8794 * Flow pattern to translate. 8795 * @param[in] inner 8796 * Item is inner pattern. 8797 */ 8798 static void 8799 flow_dv_translate_item_nvgre(void *matcher, void *key, 8800 const struct rte_flow_item *item, 8801 int inner) 8802 { 8803 const struct rte_flow_item_nvgre *nvgre_m = item->mask; 8804 const struct rte_flow_item_nvgre *nvgre_v = item->spec; 8805 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 8806 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8807 const char *tni_flow_id_m; 8808 const char *tni_flow_id_v; 8809 char *gre_key_m; 8810 char *gre_key_v; 8811 int size; 8812 int i; 8813 8814 /* For NVGRE, GRE header fields must be set with defined values. */ 8815 const struct rte_flow_item_gre gre_spec = { 8816 .c_rsvd0_ver = RTE_BE16(0x2000), 8817 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB) 8818 }; 8819 const struct rte_flow_item_gre gre_mask = { 8820 .c_rsvd0_ver = RTE_BE16(0xB000), 8821 .protocol = RTE_BE16(UINT16_MAX), 8822 }; 8823 const struct rte_flow_item gre_item = { 8824 .spec = &gre_spec, 8825 .mask = &gre_mask, 8826 .last = NULL, 8827 }; 8828 flow_dv_translate_item_gre(matcher, key, &gre_item, inner); 8829 if (!nvgre_v) 8830 return; 8831 if (!nvgre_m) 8832 nvgre_m = &rte_flow_item_nvgre_mask; 8833 tni_flow_id_m = (const char *)nvgre_m->tni; 8834 tni_flow_id_v = (const char *)nvgre_v->tni; 8835 size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id); 8836 gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h); 8837 gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h); 8838 memcpy(gre_key_m, tni_flow_id_m, size); 8839 for (i = 0; i < size; ++i) 8840 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i]; 8841 } 8842 8843 /** 8844 * Add VXLAN item to matcher and to the value. 8845 * 8846 * @param[in] dev 8847 * Pointer to the Ethernet device structure. 8848 * @param[in] attr 8849 * Flow rule attributes. 8850 * @param[in, out] matcher 8851 * Flow matcher. 8852 * @param[in, out] key 8853 * Flow matcher value. 8854 * @param[in] item 8855 * Flow pattern to translate. 8856 * @param[in] inner 8857 * Item is inner pattern. 8858 */ 8859 static void 8860 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, 8861 const struct rte_flow_attr *attr, 8862 void *matcher, void *key, 8863 const struct rte_flow_item *item, 8864 int inner) 8865 { 8866 const struct rte_flow_item_vxlan *vxlan_m = item->mask; 8867 const struct rte_flow_item_vxlan *vxlan_v = item->spec; 8868 void *headers_m; 8869 void *headers_v; 8870 void *misc5_m; 8871 void *misc5_v; 8872 uint32_t *tunnel_header_v; 8873 uint32_t *tunnel_header_m; 8874 uint16_t dport; 8875 struct mlx5_priv *priv = dev->data->dev_private; 8876 const struct rte_flow_item_vxlan nic_mask = { 8877 .vni = "\xff\xff\xff", 8878 .rsvd1 = 0xff, 8879 }; 8880 8881 if (inner) { 8882 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8883 inner_headers); 8884 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8885 } else { 8886 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8887 outer_headers); 8888 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8889 } 8890 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 8891 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 8892 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 8893 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 8894 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 8895 } 8896 dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport); 8897 if (!vxlan_v) 8898 return; 8899 if (!vxlan_m) { 8900 if ((!attr->group && !priv->sh->tunnel_header_0_1) || 8901 (attr->group && !priv->sh->misc5_cap)) 8902 vxlan_m = &rte_flow_item_vxlan_mask; 8903 else 8904 vxlan_m = &nic_mask; 8905 } 8906 if ((priv->sh->steering_format_version == 8907 MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && 8908 dport != MLX5_UDP_PORT_VXLAN) || 8909 (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) || 8910 ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) { 8911 void *misc_m; 8912 void *misc_v; 8913 char *vni_m; 8914 char *vni_v; 8915 int size; 8916 int i; 8917 misc_m = MLX5_ADDR_OF(fte_match_param, 8918 matcher, misc_parameters); 8919 misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 8920 size = sizeof(vxlan_m->vni); 8921 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni); 8922 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni); 8923 memcpy(vni_m, vxlan_m->vni, size); 8924 for (i = 0; i < size; ++i) 8925 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 8926 return; 8927 } 8928 misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5); 8929 misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5); 8930 tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8931 misc5_v, 8932 tunnel_header_1); 8933 tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5, 8934 misc5_m, 8935 tunnel_header_1); 8936 *tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) | 8937 (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 | 8938 (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16; 8939 if (*tunnel_header_v) 8940 *tunnel_header_m = vxlan_m->vni[0] | 8941 vxlan_m->vni[1] << 8 | 8942 vxlan_m->vni[2] << 16; 8943 else 8944 *tunnel_header_m = 0x0; 8945 *tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24; 8946 if (vxlan_v->rsvd1 & vxlan_m->rsvd1) 8947 *tunnel_header_m |= vxlan_m->rsvd1 << 24; 8948 } 8949 8950 /** 8951 * Add VXLAN-GPE item to matcher and to the value. 8952 * 8953 * @param[in, out] matcher 8954 * Flow matcher. 8955 * @param[in, out] key 8956 * Flow matcher value. 8957 * @param[in] item 8958 * Flow pattern to translate. 8959 * @param[in] inner 8960 * Item is inner pattern. 8961 */ 8962 8963 static void 8964 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key, 8965 const struct rte_flow_item *item, int inner) 8966 { 8967 const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask; 8968 const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec; 8969 void *headers_m; 8970 void *headers_v; 8971 void *misc_m = 8972 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3); 8973 void *misc_v = 8974 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 8975 char *vni_m; 8976 char *vni_v; 8977 uint16_t dport; 8978 int size; 8979 int i; 8980 uint8_t flags_m = 0xff; 8981 uint8_t flags_v = 0xc; 8982 8983 if (inner) { 8984 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8985 inner_headers); 8986 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 8987 } else { 8988 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 8989 outer_headers); 8990 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 8991 } 8992 dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ? 8993 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE; 8994 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 8995 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 8996 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 8997 } 8998 if (!vxlan_v) 8999 return; 9000 if (!vxlan_m) 9001 vxlan_m = &rte_flow_item_vxlan_gpe_mask; 9002 size = sizeof(vxlan_m->vni); 9003 vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni); 9004 vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni); 9005 memcpy(vni_m, vxlan_m->vni, size); 9006 for (i = 0; i < size; ++i) 9007 vni_v[i] = vni_m[i] & vxlan_v->vni[i]; 9008 if (vxlan_m->flags) { 9009 flags_m = vxlan_m->flags; 9010 flags_v = vxlan_v->flags; 9011 } 9012 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m); 9013 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v); 9014 MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol, 9015 vxlan_m->protocol); 9016 MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol, 9017 vxlan_v->protocol); 9018 } 9019 9020 /** 9021 * Add Geneve item to matcher and to the value. 9022 * 9023 * @param[in, out] matcher 9024 * Flow matcher. 9025 * @param[in, out] key 9026 * Flow matcher value. 9027 * @param[in] item 9028 * Flow pattern to translate. 9029 * @param[in] inner 9030 * Item is inner pattern. 9031 */ 9032 9033 static void 9034 flow_dv_translate_item_geneve(void *matcher, void *key, 9035 const struct rte_flow_item *item, int inner) 9036 { 9037 const struct rte_flow_item_geneve *geneve_m = item->mask; 9038 const struct rte_flow_item_geneve *geneve_v = item->spec; 9039 void *headers_m; 9040 void *headers_v; 9041 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9042 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9043 uint16_t dport; 9044 uint16_t gbhdr_m; 9045 uint16_t gbhdr_v; 9046 char *vni_m; 9047 char *vni_v; 9048 size_t size, i; 9049 9050 if (inner) { 9051 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9052 inner_headers); 9053 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9054 } else { 9055 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9056 outer_headers); 9057 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9058 } 9059 dport = MLX5_UDP_PORT_GENEVE; 9060 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9061 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9062 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9063 } 9064 if (!geneve_v) 9065 return; 9066 if (!geneve_m) 9067 geneve_m = &rte_flow_item_geneve_mask; 9068 size = sizeof(geneve_m->vni); 9069 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni); 9070 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni); 9071 memcpy(vni_m, geneve_m->vni, size); 9072 for (i = 0; i < size; ++i) 9073 vni_v[i] = vni_m[i] & geneve_v->vni[i]; 9074 MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type, 9075 rte_be_to_cpu_16(geneve_m->protocol)); 9076 MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type, 9077 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol)); 9078 gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0); 9079 gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0); 9080 MLX5_SET(fte_match_set_misc, misc_m, geneve_oam, 9081 MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9082 MLX5_SET(fte_match_set_misc, misc_v, geneve_oam, 9083 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m)); 9084 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9085 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9086 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9087 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) & 9088 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m)); 9089 } 9090 9091 /** 9092 * Create Geneve TLV option resource. 9093 * 9094 * @param dev[in, out] 9095 * Pointer to rte_eth_dev structure. 9096 * @param[in, out] tag_be24 9097 * Tag value in big endian then R-shift 8. 9098 * @parm[in, out] dev_flow 9099 * Pointer to the dev_flow. 9100 * @param[out] error 9101 * pointer to error structure. 9102 * 9103 * @return 9104 * 0 on success otherwise -errno and errno is set. 9105 */ 9106 9107 int 9108 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev, 9109 const struct rte_flow_item *item, 9110 struct rte_flow_error *error) 9111 { 9112 struct mlx5_priv *priv = dev->data->dev_private; 9113 struct mlx5_dev_ctx_shared *sh = priv->sh; 9114 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 9115 sh->geneve_tlv_option_resource; 9116 struct mlx5_devx_obj *obj; 9117 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9118 int ret = 0; 9119 9120 if (!geneve_opt_v) 9121 return -1; 9122 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 9123 if (geneve_opt_resource != NULL) { 9124 if (geneve_opt_resource->option_class == 9125 geneve_opt_v->option_class && 9126 geneve_opt_resource->option_type == 9127 geneve_opt_v->option_type && 9128 geneve_opt_resource->length == 9129 geneve_opt_v->option_len) { 9130 /* We already have GENVE TLV option obj allocated. */ 9131 __atomic_fetch_add(&geneve_opt_resource->refcnt, 1, 9132 __ATOMIC_RELAXED); 9133 } else { 9134 ret = rte_flow_error_set(error, ENOMEM, 9135 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9136 "Only one GENEVE TLV option supported"); 9137 goto exit; 9138 } 9139 } else { 9140 /* Create a GENEVE TLV object and resource. */ 9141 obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx, 9142 geneve_opt_v->option_class, 9143 geneve_opt_v->option_type, 9144 geneve_opt_v->option_len); 9145 if (!obj) { 9146 ret = rte_flow_error_set(error, ENODATA, 9147 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9148 "Failed to create GENEVE TLV Devx object"); 9149 goto exit; 9150 } 9151 sh->geneve_tlv_option_resource = 9152 mlx5_malloc(MLX5_MEM_ZERO, 9153 sizeof(*geneve_opt_resource), 9154 0, SOCKET_ID_ANY); 9155 if (!sh->geneve_tlv_option_resource) { 9156 claim_zero(mlx5_devx_cmd_destroy(obj)); 9157 ret = rte_flow_error_set(error, ENOMEM, 9158 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 9159 "GENEVE TLV object memory allocation failed"); 9160 goto exit; 9161 } 9162 geneve_opt_resource = sh->geneve_tlv_option_resource; 9163 geneve_opt_resource->obj = obj; 9164 geneve_opt_resource->option_class = geneve_opt_v->option_class; 9165 geneve_opt_resource->option_type = geneve_opt_v->option_type; 9166 geneve_opt_resource->length = geneve_opt_v->option_len; 9167 __atomic_store_n(&geneve_opt_resource->refcnt, 1, 9168 __ATOMIC_RELAXED); 9169 } 9170 exit: 9171 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 9172 return ret; 9173 } 9174 9175 /** 9176 * Add Geneve TLV option item to matcher. 9177 * 9178 * @param[in, out] dev 9179 * Pointer to rte_eth_dev structure. 9180 * @param[in, out] matcher 9181 * Flow matcher. 9182 * @param[in, out] key 9183 * Flow matcher value. 9184 * @param[in] item 9185 * Flow pattern to translate. 9186 * @param[out] error 9187 * Pointer to error structure. 9188 */ 9189 static int 9190 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher, 9191 void *key, const struct rte_flow_item *item, 9192 struct rte_flow_error *error) 9193 { 9194 const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask; 9195 const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec; 9196 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9197 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9198 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9199 misc_parameters_3); 9200 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9201 rte_be32_t opt_data_key = 0, opt_data_mask = 0; 9202 int ret = 0; 9203 9204 if (!geneve_opt_v) 9205 return -1; 9206 if (!geneve_opt_m) 9207 geneve_opt_m = &rte_flow_item_geneve_opt_mask; 9208 ret = flow_dev_geneve_tlv_option_resource_register(dev, item, 9209 error); 9210 if (ret) { 9211 DRV_LOG(ERR, "Failed to create geneve_tlv_obj"); 9212 return ret; 9213 } 9214 /* 9215 * Set the option length in GENEVE header if not requested. 9216 * The GENEVE TLV option length is expressed by the option length field 9217 * in the GENEVE header. 9218 * If the option length was not requested but the GENEVE TLV option item 9219 * is present we set the option length field implicitly. 9220 */ 9221 if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) { 9222 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len, 9223 MLX5_GENEVE_OPTLEN_MASK); 9224 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, 9225 geneve_opt_v->option_len + 1); 9226 } 9227 MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1); 9228 MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1); 9229 /* Set the data. */ 9230 if (geneve_opt_v->data) { 9231 memcpy(&opt_data_key, geneve_opt_v->data, 9232 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9233 sizeof(opt_data_key))); 9234 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9235 sizeof(opt_data_key)); 9236 memcpy(&opt_data_mask, geneve_opt_m->data, 9237 RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4), 9238 sizeof(opt_data_mask))); 9239 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <= 9240 sizeof(opt_data_mask)); 9241 MLX5_SET(fte_match_set_misc3, misc3_m, 9242 geneve_tlv_option_0_data, 9243 rte_be_to_cpu_32(opt_data_mask)); 9244 MLX5_SET(fte_match_set_misc3, misc3_v, 9245 geneve_tlv_option_0_data, 9246 rte_be_to_cpu_32(opt_data_key & opt_data_mask)); 9247 } 9248 return ret; 9249 } 9250 9251 /** 9252 * Add MPLS item to matcher and to the value. 9253 * 9254 * @param[in, out] matcher 9255 * Flow matcher. 9256 * @param[in, out] key 9257 * Flow matcher value. 9258 * @param[in] item 9259 * Flow pattern to translate. 9260 * @param[in] prev_layer 9261 * The protocol layer indicated in previous item. 9262 * @param[in] inner 9263 * Item is inner pattern. 9264 */ 9265 static void 9266 flow_dv_translate_item_mpls(void *matcher, void *key, 9267 const struct rte_flow_item *item, 9268 uint64_t prev_layer, 9269 int inner) 9270 { 9271 const uint32_t *in_mpls_m = item->mask; 9272 const uint32_t *in_mpls_v = item->spec; 9273 uint32_t *out_mpls_m = 0; 9274 uint32_t *out_mpls_v = 0; 9275 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9276 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9277 void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher, 9278 misc_parameters_2); 9279 void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9280 void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 9281 void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9282 9283 switch (prev_layer) { 9284 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9285 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff); 9286 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 9287 MLX5_UDP_PORT_MPLS); 9288 break; 9289 case MLX5_FLOW_LAYER_GRE: 9290 /* Fall-through. */ 9291 case MLX5_FLOW_LAYER_GRE_KEY: 9292 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff); 9293 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, 9294 RTE_ETHER_TYPE_MPLS); 9295 break; 9296 default: 9297 break; 9298 } 9299 if (!in_mpls_v) 9300 return; 9301 if (!in_mpls_m) 9302 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask; 9303 switch (prev_layer) { 9304 case MLX5_FLOW_LAYER_OUTER_L4_UDP: 9305 out_mpls_m = 9306 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9307 outer_first_mpls_over_udp); 9308 out_mpls_v = 9309 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9310 outer_first_mpls_over_udp); 9311 break; 9312 case MLX5_FLOW_LAYER_GRE: 9313 out_mpls_m = 9314 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m, 9315 outer_first_mpls_over_gre); 9316 out_mpls_v = 9317 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v, 9318 outer_first_mpls_over_gre); 9319 break; 9320 default: 9321 /* Inner MPLS not over GRE is not supported. */ 9322 if (!inner) { 9323 out_mpls_m = 9324 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9325 misc2_m, 9326 outer_first_mpls); 9327 out_mpls_v = 9328 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, 9329 misc2_v, 9330 outer_first_mpls); 9331 } 9332 break; 9333 } 9334 if (out_mpls_m && out_mpls_v) { 9335 *out_mpls_m = *in_mpls_m; 9336 *out_mpls_v = *in_mpls_v & *in_mpls_m; 9337 } 9338 } 9339 9340 /** 9341 * Add metadata register item to matcher 9342 * 9343 * @param[in, out] matcher 9344 * Flow matcher. 9345 * @param[in, out] key 9346 * Flow matcher value. 9347 * @param[in] reg_type 9348 * Type of device metadata register 9349 * @param[in] value 9350 * Register value 9351 * @param[in] mask 9352 * Register mask 9353 */ 9354 static void 9355 flow_dv_match_meta_reg(void *matcher, void *key, 9356 enum modify_reg reg_type, 9357 uint32_t data, uint32_t mask) 9358 { 9359 void *misc2_m = 9360 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2); 9361 void *misc2_v = 9362 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); 9363 uint32_t temp; 9364 9365 data &= mask; 9366 switch (reg_type) { 9367 case REG_A: 9368 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask); 9369 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data); 9370 break; 9371 case REG_B: 9372 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask); 9373 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data); 9374 break; 9375 case REG_C_0: 9376 /* 9377 * The metadata register C0 field might be divided into 9378 * source vport index and META item value, we should set 9379 * this field according to specified mask, not as whole one. 9380 */ 9381 temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0); 9382 temp |= mask; 9383 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp); 9384 temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0); 9385 temp &= ~mask; 9386 temp |= data; 9387 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp); 9388 break; 9389 case REG_C_1: 9390 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask); 9391 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data); 9392 break; 9393 case REG_C_2: 9394 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask); 9395 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data); 9396 break; 9397 case REG_C_3: 9398 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask); 9399 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data); 9400 break; 9401 case REG_C_4: 9402 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask); 9403 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data); 9404 break; 9405 case REG_C_5: 9406 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask); 9407 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data); 9408 break; 9409 case REG_C_6: 9410 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask); 9411 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data); 9412 break; 9413 case REG_C_7: 9414 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask); 9415 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data); 9416 break; 9417 default: 9418 MLX5_ASSERT(false); 9419 break; 9420 } 9421 } 9422 9423 /** 9424 * Add MARK item to matcher 9425 * 9426 * @param[in] dev 9427 * The device to configure through. 9428 * @param[in, out] matcher 9429 * Flow matcher. 9430 * @param[in, out] key 9431 * Flow matcher value. 9432 * @param[in] item 9433 * Flow pattern to translate. 9434 */ 9435 static void 9436 flow_dv_translate_item_mark(struct rte_eth_dev *dev, 9437 void *matcher, void *key, 9438 const struct rte_flow_item *item) 9439 { 9440 struct mlx5_priv *priv = dev->data->dev_private; 9441 const struct rte_flow_item_mark *mark; 9442 uint32_t value; 9443 uint32_t mask; 9444 9445 mark = item->mask ? (const void *)item->mask : 9446 &rte_flow_item_mark_mask; 9447 mask = mark->id & priv->sh->dv_mark_mask; 9448 mark = (const void *)item->spec; 9449 MLX5_ASSERT(mark); 9450 value = mark->id & priv->sh->dv_mark_mask & mask; 9451 if (mask) { 9452 enum modify_reg reg; 9453 9454 /* Get the metadata register index for the mark. */ 9455 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL); 9456 MLX5_ASSERT(reg > 0); 9457 if (reg == REG_C_0) { 9458 struct mlx5_priv *priv = dev->data->dev_private; 9459 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9460 uint32_t shl_c0 = rte_bsf32(msk_c0); 9461 9462 mask &= msk_c0; 9463 mask <<= shl_c0; 9464 value <<= shl_c0; 9465 } 9466 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9467 } 9468 } 9469 9470 /** 9471 * Add META item to matcher 9472 * 9473 * @param[in] dev 9474 * The devich to configure through. 9475 * @param[in, out] matcher 9476 * Flow matcher. 9477 * @param[in, out] key 9478 * Flow matcher value. 9479 * @param[in] attr 9480 * Attributes of flow that includes this item. 9481 * @param[in] item 9482 * Flow pattern to translate. 9483 */ 9484 static void 9485 flow_dv_translate_item_meta(struct rte_eth_dev *dev, 9486 void *matcher, void *key, 9487 const struct rte_flow_attr *attr, 9488 const struct rte_flow_item *item) 9489 { 9490 const struct rte_flow_item_meta *meta_m; 9491 const struct rte_flow_item_meta *meta_v; 9492 9493 meta_m = (const void *)item->mask; 9494 if (!meta_m) 9495 meta_m = &rte_flow_item_meta_mask; 9496 meta_v = (const void *)item->spec; 9497 if (meta_v) { 9498 int reg; 9499 uint32_t value = meta_v->data; 9500 uint32_t mask = meta_m->data; 9501 9502 reg = flow_dv_get_metadata_reg(dev, attr, NULL); 9503 if (reg < 0) 9504 return; 9505 MLX5_ASSERT(reg != REG_NON); 9506 if (reg == REG_C_0) { 9507 struct mlx5_priv *priv = dev->data->dev_private; 9508 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9509 uint32_t shl_c0 = rte_bsf32(msk_c0); 9510 9511 mask &= msk_c0; 9512 mask <<= shl_c0; 9513 value <<= shl_c0; 9514 } 9515 flow_dv_match_meta_reg(matcher, key, reg, value, mask); 9516 } 9517 } 9518 9519 /** 9520 * Add vport metadata Reg C0 item to matcher 9521 * 9522 * @param[in, out] matcher 9523 * Flow matcher. 9524 * @param[in, out] key 9525 * Flow matcher value. 9526 * @param[in] reg 9527 * Flow pattern to translate. 9528 */ 9529 static void 9530 flow_dv_translate_item_meta_vport(void *matcher, void *key, 9531 uint32_t value, uint32_t mask) 9532 { 9533 flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask); 9534 } 9535 9536 /** 9537 * Add tag item to matcher 9538 * 9539 * @param[in] dev 9540 * The devich to configure through. 9541 * @param[in, out] matcher 9542 * Flow matcher. 9543 * @param[in, out] key 9544 * Flow matcher value. 9545 * @param[in] item 9546 * Flow pattern to translate. 9547 */ 9548 static void 9549 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev, 9550 void *matcher, void *key, 9551 const struct rte_flow_item *item) 9552 { 9553 const struct mlx5_rte_flow_item_tag *tag_v = item->spec; 9554 const struct mlx5_rte_flow_item_tag *tag_m = item->mask; 9555 uint32_t mask, value; 9556 9557 MLX5_ASSERT(tag_v); 9558 value = tag_v->data; 9559 mask = tag_m ? tag_m->data : UINT32_MAX; 9560 if (tag_v->id == REG_C_0) { 9561 struct mlx5_priv *priv = dev->data->dev_private; 9562 uint32_t msk_c0 = priv->sh->dv_regc0_mask; 9563 uint32_t shl_c0 = rte_bsf32(msk_c0); 9564 9565 mask &= msk_c0; 9566 mask <<= shl_c0; 9567 value <<= shl_c0; 9568 } 9569 flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask); 9570 } 9571 9572 /** 9573 * Add TAG item to matcher 9574 * 9575 * @param[in] dev 9576 * The devich to configure through. 9577 * @param[in, out] matcher 9578 * Flow matcher. 9579 * @param[in, out] key 9580 * Flow matcher value. 9581 * @param[in] item 9582 * Flow pattern to translate. 9583 */ 9584 static void 9585 flow_dv_translate_item_tag(struct rte_eth_dev *dev, 9586 void *matcher, void *key, 9587 const struct rte_flow_item *item) 9588 { 9589 const struct rte_flow_item_tag *tag_v = item->spec; 9590 const struct rte_flow_item_tag *tag_m = item->mask; 9591 enum modify_reg reg; 9592 9593 MLX5_ASSERT(tag_v); 9594 tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask; 9595 /* Get the metadata register index for the tag. */ 9596 reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL); 9597 MLX5_ASSERT(reg > 0); 9598 flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data); 9599 } 9600 9601 /** 9602 * Add source vport match to the specified matcher. 9603 * 9604 * @param[in, out] matcher 9605 * Flow matcher. 9606 * @param[in, out] key 9607 * Flow matcher value. 9608 * @param[in] port 9609 * Source vport value to match 9610 * @param[in] mask 9611 * Mask 9612 */ 9613 static void 9614 flow_dv_translate_item_source_vport(void *matcher, void *key, 9615 int16_t port, uint16_t mask) 9616 { 9617 void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 9618 void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 9619 9620 MLX5_SET(fte_match_set_misc, misc_m, source_port, mask); 9621 MLX5_SET(fte_match_set_misc, misc_v, source_port, port); 9622 } 9623 9624 /** 9625 * Translate port-id item to eswitch match on port-id. 9626 * 9627 * @param[in] dev 9628 * The devich to configure through. 9629 * @param[in, out] matcher 9630 * Flow matcher. 9631 * @param[in, out] key 9632 * Flow matcher value. 9633 * @param[in] item 9634 * Flow pattern to translate. 9635 * @param[in] 9636 * Flow attributes. 9637 * 9638 * @return 9639 * 0 on success, a negative errno value otherwise. 9640 */ 9641 static int 9642 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher, 9643 void *key, const struct rte_flow_item *item, 9644 const struct rte_flow_attr *attr) 9645 { 9646 const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL; 9647 const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL; 9648 struct mlx5_priv *priv; 9649 uint16_t mask, id; 9650 9651 if (pid_v && pid_v->id == MLX5_PORT_ESW_MGR) { 9652 flow_dv_translate_item_source_vport(matcher, key, 9653 flow_dv_get_esw_manager_vport_id(dev), 0xffff); 9654 return 0; 9655 } 9656 mask = pid_m ? pid_m->id : 0xffff; 9657 id = pid_v ? pid_v->id : dev->data->port_id; 9658 priv = mlx5_port_to_eswitch_info(id, item == NULL); 9659 if (!priv) 9660 return -rte_errno; 9661 /* 9662 * Translate to vport field or to metadata, depending on mode. 9663 * Kernel can use either misc.source_port or half of C0 metadata 9664 * register. 9665 */ 9666 if (priv->vport_meta_mask) { 9667 /* 9668 * Provide the hint for SW steering library 9669 * to insert the flow into ingress domain and 9670 * save the extra vport match. 9671 */ 9672 if (mask == 0xffff && priv->vport_id == 0xffff && 9673 priv->pf_bond < 0 && attr->transfer) 9674 flow_dv_translate_item_source_vport 9675 (matcher, key, priv->vport_id, mask); 9676 /* 9677 * We should always set the vport metadata register, 9678 * otherwise the SW steering library can drop 9679 * the rule if wire vport metadata value is not zero, 9680 * it depends on kernel configuration. 9681 */ 9682 flow_dv_translate_item_meta_vport(matcher, key, 9683 priv->vport_meta_tag, 9684 priv->vport_meta_mask); 9685 } else { 9686 flow_dv_translate_item_source_vport(matcher, key, 9687 priv->vport_id, mask); 9688 } 9689 return 0; 9690 } 9691 9692 /** 9693 * Add ICMP6 item to matcher and to the value. 9694 * 9695 * @param[in, out] matcher 9696 * Flow matcher. 9697 * @param[in, out] key 9698 * Flow matcher value. 9699 * @param[in] item 9700 * Flow pattern to translate. 9701 * @param[in] inner 9702 * Item is inner pattern. 9703 */ 9704 static void 9705 flow_dv_translate_item_icmp6(void *matcher, void *key, 9706 const struct rte_flow_item *item, 9707 int inner) 9708 { 9709 const struct rte_flow_item_icmp6 *icmp6_m = item->mask; 9710 const struct rte_flow_item_icmp6 *icmp6_v = item->spec; 9711 void *headers_m; 9712 void *headers_v; 9713 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9714 misc_parameters_3); 9715 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9716 if (inner) { 9717 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9718 inner_headers); 9719 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9720 } else { 9721 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9722 outer_headers); 9723 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9724 } 9725 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9726 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6); 9727 if (!icmp6_v) 9728 return; 9729 if (!icmp6_m) 9730 icmp6_m = &rte_flow_item_icmp6_mask; 9731 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type); 9732 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type, 9733 icmp6_v->type & icmp6_m->type); 9734 MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code); 9735 MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code, 9736 icmp6_v->code & icmp6_m->code); 9737 } 9738 9739 /** 9740 * Add ICMP item to matcher and to the value. 9741 * 9742 * @param[in, out] matcher 9743 * Flow matcher. 9744 * @param[in, out] key 9745 * Flow matcher value. 9746 * @param[in] item 9747 * Flow pattern to translate. 9748 * @param[in] inner 9749 * Item is inner pattern. 9750 */ 9751 static void 9752 flow_dv_translate_item_icmp(void *matcher, void *key, 9753 const struct rte_flow_item *item, 9754 int inner) 9755 { 9756 const struct rte_flow_item_icmp *icmp_m = item->mask; 9757 const struct rte_flow_item_icmp *icmp_v = item->spec; 9758 uint32_t icmp_header_data_m = 0; 9759 uint32_t icmp_header_data_v = 0; 9760 void *headers_m; 9761 void *headers_v; 9762 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9763 misc_parameters_3); 9764 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9765 if (inner) { 9766 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9767 inner_headers); 9768 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9769 } else { 9770 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9771 outer_headers); 9772 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9773 } 9774 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF); 9775 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP); 9776 if (!icmp_v) 9777 return; 9778 if (!icmp_m) 9779 icmp_m = &rte_flow_item_icmp_mask; 9780 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type, 9781 icmp_m->hdr.icmp_type); 9782 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type, 9783 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type); 9784 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code, 9785 icmp_m->hdr.icmp_code); 9786 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code, 9787 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code); 9788 icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb); 9789 icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16; 9790 if (icmp_header_data_m) { 9791 icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb); 9792 icmp_header_data_v |= 9793 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16; 9794 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data, 9795 icmp_header_data_m); 9796 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data, 9797 icmp_header_data_v & icmp_header_data_m); 9798 } 9799 } 9800 9801 /** 9802 * Add GTP item to matcher and to the value. 9803 * 9804 * @param[in, out] matcher 9805 * Flow matcher. 9806 * @param[in, out] key 9807 * Flow matcher value. 9808 * @param[in] item 9809 * Flow pattern to translate. 9810 * @param[in] inner 9811 * Item is inner pattern. 9812 */ 9813 static void 9814 flow_dv_translate_item_gtp(void *matcher, void *key, 9815 const struct rte_flow_item *item, int inner) 9816 { 9817 const struct rte_flow_item_gtp *gtp_m = item->mask; 9818 const struct rte_flow_item_gtp *gtp_v = item->spec; 9819 void *headers_m; 9820 void *headers_v; 9821 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9822 misc_parameters_3); 9823 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9824 uint16_t dport = RTE_GTPU_UDP_PORT; 9825 9826 if (inner) { 9827 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9828 inner_headers); 9829 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 9830 } else { 9831 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 9832 outer_headers); 9833 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9834 } 9835 if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) { 9836 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); 9837 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); 9838 } 9839 if (!gtp_v) 9840 return; 9841 if (!gtp_m) 9842 gtp_m = &rte_flow_item_gtp_mask; 9843 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, 9844 gtp_m->v_pt_rsv_flags); 9845 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, 9846 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags); 9847 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type); 9848 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type, 9849 gtp_v->msg_type & gtp_m->msg_type); 9850 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid, 9851 rte_be_to_cpu_32(gtp_m->teid)); 9852 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid, 9853 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid)); 9854 } 9855 9856 /** 9857 * Add GTP PSC item to matcher. 9858 * 9859 * @param[in, out] matcher 9860 * Flow matcher. 9861 * @param[in, out] key 9862 * Flow matcher value. 9863 * @param[in] item 9864 * Flow pattern to translate. 9865 */ 9866 static int 9867 flow_dv_translate_item_gtp_psc(void *matcher, void *key, 9868 const struct rte_flow_item *item) 9869 { 9870 const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask; 9871 const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec; 9872 void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher, 9873 misc_parameters_3); 9874 void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3); 9875 union { 9876 uint32_t w32; 9877 struct { 9878 uint16_t seq_num; 9879 uint8_t npdu_num; 9880 uint8_t next_ext_header_type; 9881 }; 9882 } dw_2; 9883 uint8_t gtp_flags; 9884 9885 /* Always set E-flag match on one, regardless of GTP item settings. */ 9886 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags); 9887 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9888 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags); 9889 gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags); 9890 gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG; 9891 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags); 9892 /*Set next extension header type. */ 9893 dw_2.seq_num = 0; 9894 dw_2.npdu_num = 0; 9895 dw_2.next_ext_header_type = 0xff; 9896 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2, 9897 rte_cpu_to_be_32(dw_2.w32)); 9898 dw_2.seq_num = 0; 9899 dw_2.npdu_num = 0; 9900 dw_2.next_ext_header_type = 0x85; 9901 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2, 9902 rte_cpu_to_be_32(dw_2.w32)); 9903 if (gtp_psc_v) { 9904 union { 9905 uint32_t w32; 9906 struct { 9907 uint8_t len; 9908 uint8_t type_flags; 9909 uint8_t qfi; 9910 uint8_t reserved; 9911 }; 9912 } dw_0; 9913 9914 /*Set extension header PDU type and Qos. */ 9915 if (!gtp_psc_m) 9916 gtp_psc_m = &rte_flow_item_gtp_psc_mask; 9917 dw_0.w32 = 0; 9918 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type); 9919 dw_0.qfi = gtp_psc_m->hdr.qfi; 9920 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0, 9921 rte_cpu_to_be_32(dw_0.w32)); 9922 dw_0.w32 = 0; 9923 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type & 9924 gtp_psc_m->hdr.type); 9925 dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi; 9926 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0, 9927 rte_cpu_to_be_32(dw_0.w32)); 9928 } 9929 return 0; 9930 } 9931 9932 /** 9933 * Add eCPRI item to matcher and to the value. 9934 * 9935 * @param[in] dev 9936 * The devich to configure through. 9937 * @param[in, out] matcher 9938 * Flow matcher. 9939 * @param[in, out] key 9940 * Flow matcher value. 9941 * @param[in] item 9942 * Flow pattern to translate. 9943 * @param[in] last_item 9944 * Last item flags. 9945 */ 9946 static void 9947 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher, 9948 void *key, const struct rte_flow_item *item, 9949 uint64_t last_item) 9950 { 9951 struct mlx5_priv *priv = dev->data->dev_private; 9952 const struct rte_flow_item_ecpri *ecpri_m = item->mask; 9953 const struct rte_flow_item_ecpri *ecpri_v = item->spec; 9954 struct rte_ecpri_common_hdr common; 9955 void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher, 9956 misc_parameters_4); 9957 void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4); 9958 uint32_t *samples; 9959 void *dw_m; 9960 void *dw_v; 9961 9962 /* 9963 * In case of eCPRI over Ethernet, if EtherType is not specified, 9964 * match on eCPRI EtherType implicitly. 9965 */ 9966 if (last_item & MLX5_FLOW_LAYER_OUTER_L2) { 9967 void *hdrs_m, *hdrs_v, *l2m, *l2v; 9968 9969 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); 9970 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 9971 l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype); 9972 l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); 9973 if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) { 9974 *(uint16_t *)l2m = UINT16_MAX; 9975 *(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI); 9976 } 9977 } 9978 if (!ecpri_v) 9979 return; 9980 if (!ecpri_m) 9981 ecpri_m = &rte_flow_item_ecpri_mask; 9982 /* 9983 * Maximal four DW samples are supported in a single matching now. 9984 * Two are used now for a eCPRI matching: 9985 * 1. Type: one byte, mask should be 0x00ff0000 in network order 9986 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000 9987 * if any. 9988 */ 9989 if (!ecpri_m->hdr.common.u32) 9990 return; 9991 samples = priv->sh->ecpri_parser.ids; 9992 /* Need to take the whole DW as the mask to fill the entry. */ 9993 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 9994 prog_sample_field_value_0); 9995 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 9996 prog_sample_field_value_0); 9997 /* Already big endian (network order) in the header. */ 9998 *(uint32_t *)dw_m = ecpri_m->hdr.common.u32; 9999 *(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32; 10000 /* Sample#0, used for matching type, offset 0. */ 10001 MLX5_SET(fte_match_set_misc4, misc4_m, 10002 prog_sample_field_id_0, samples[0]); 10003 /* It makes no sense to set the sample ID in the mask field. */ 10004 MLX5_SET(fte_match_set_misc4, misc4_v, 10005 prog_sample_field_id_0, samples[0]); 10006 /* 10007 * Checking if message body part needs to be matched. 10008 * Some wildcard rules only matching type field should be supported. 10009 */ 10010 if (ecpri_m->hdr.dummy[0]) { 10011 common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32); 10012 switch (common.type) { 10013 case RTE_ECPRI_MSG_TYPE_IQ_DATA: 10014 case RTE_ECPRI_MSG_TYPE_RTC_CTRL: 10015 case RTE_ECPRI_MSG_TYPE_DLY_MSR: 10016 dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m, 10017 prog_sample_field_value_1); 10018 dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v, 10019 prog_sample_field_value_1); 10020 *(uint32_t *)dw_m = ecpri_m->hdr.dummy[0]; 10021 *(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] & 10022 ecpri_m->hdr.dummy[0]; 10023 /* Sample#1, to match message body, offset 4. */ 10024 MLX5_SET(fte_match_set_misc4, misc4_m, 10025 prog_sample_field_id_1, samples[1]); 10026 MLX5_SET(fte_match_set_misc4, misc4_v, 10027 prog_sample_field_id_1, samples[1]); 10028 break; 10029 default: 10030 /* Others, do not match any sample ID. */ 10031 break; 10032 } 10033 } 10034 } 10035 10036 /* 10037 * Add connection tracking status item to matcher 10038 * 10039 * @param[in] dev 10040 * The devich to configure through. 10041 * @param[in, out] matcher 10042 * Flow matcher. 10043 * @param[in, out] key 10044 * Flow matcher value. 10045 * @param[in] item 10046 * Flow pattern to translate. 10047 */ 10048 static void 10049 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev, 10050 void *matcher, void *key, 10051 const struct rte_flow_item *item) 10052 { 10053 uint32_t reg_value = 0; 10054 int reg_id; 10055 /* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */ 10056 uint32_t reg_mask = 0; 10057 const struct rte_flow_item_conntrack *spec = item->spec; 10058 const struct rte_flow_item_conntrack *mask = item->mask; 10059 uint32_t flags; 10060 struct rte_flow_error error; 10061 10062 if (!mask) 10063 mask = &rte_flow_item_conntrack_mask; 10064 if (!spec || !mask->flags) 10065 return; 10066 flags = spec->flags & mask->flags; 10067 /* The conflict should be checked in the validation. */ 10068 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) 10069 reg_value |= MLX5_CT_SYNDROME_VALID; 10070 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10071 reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE; 10072 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) 10073 reg_value |= MLX5_CT_SYNDROME_INVALID; 10074 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED) 10075 reg_value |= MLX5_CT_SYNDROME_TRAP; 10076 if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10077 reg_value |= MLX5_CT_SYNDROME_BAD_PACKET; 10078 if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID | 10079 RTE_FLOW_CONNTRACK_PKT_STATE_INVALID | 10080 RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)) 10081 reg_mask |= 0xc0; 10082 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED) 10083 reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE; 10084 if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) 10085 reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET; 10086 /* The REG_C_x value could be saved during startup. */ 10087 reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error); 10088 if (reg_id == REG_NON) 10089 return; 10090 flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id, 10091 reg_value, reg_mask); 10092 } 10093 10094 static void 10095 flow_dv_translate_item_flex(struct rte_eth_dev *dev, void *matcher, void *key, 10096 const struct rte_flow_item *item, 10097 struct mlx5_flow *dev_flow, bool is_inner) 10098 { 10099 const struct rte_flow_item_flex *spec = 10100 (const struct rte_flow_item_flex *)item->spec; 10101 int index = mlx5_flex_acquire_index(dev, spec->handle, false); 10102 10103 MLX5_ASSERT(index >= 0 && index <= (int)(sizeof(uint32_t) * CHAR_BIT)); 10104 if (index < 0) 10105 return; 10106 if (!(dev_flow->handle->flex_item & RTE_BIT32(index))) { 10107 /* Don't count both inner and outer flex items in one rule. */ 10108 if (mlx5_flex_acquire_index(dev, spec->handle, true) != index) 10109 MLX5_ASSERT(false); 10110 dev_flow->handle->flex_item |= RTE_BIT32(index); 10111 } 10112 mlx5_flex_flow_translate_item(dev, matcher, key, item, is_inner); 10113 } 10114 10115 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 }; 10116 10117 #define HEADER_IS_ZERO(match_criteria, headers) \ 10118 !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \ 10119 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \ 10120 10121 /** 10122 * Calculate flow matcher enable bitmap. 10123 * 10124 * @param match_criteria 10125 * Pointer to flow matcher criteria. 10126 * 10127 * @return 10128 * Bitmap of enabled fields. 10129 */ 10130 static uint8_t 10131 flow_dv_matcher_enable(uint32_t *match_criteria) 10132 { 10133 uint8_t match_criteria_enable; 10134 10135 match_criteria_enable = 10136 (!HEADER_IS_ZERO(match_criteria, outer_headers)) << 10137 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT; 10138 match_criteria_enable |= 10139 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) << 10140 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT; 10141 match_criteria_enable |= 10142 (!HEADER_IS_ZERO(match_criteria, inner_headers)) << 10143 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT; 10144 match_criteria_enable |= 10145 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) << 10146 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT; 10147 match_criteria_enable |= 10148 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) << 10149 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT; 10150 match_criteria_enable |= 10151 (!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) << 10152 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT; 10153 match_criteria_enable |= 10154 (!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) << 10155 MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT; 10156 return match_criteria_enable; 10157 } 10158 10159 static void 10160 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria) 10161 { 10162 /* 10163 * Check flow matching criteria first, subtract misc5/4 length if flow 10164 * doesn't own misc5/4 parameters. In some old rdma-core releases, 10165 * misc5/4 are not supported, and matcher creation failure is expected 10166 * w/o subtration. If misc5 is provided, misc4 must be counted in since 10167 * misc5 is right after misc4. 10168 */ 10169 if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) { 10170 *size = MLX5_ST_SZ_BYTES(fte_match_param) - 10171 MLX5_ST_SZ_BYTES(fte_match_set_misc5); 10172 if (!(match_criteria & (1 << 10173 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) { 10174 *size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4); 10175 } 10176 } 10177 } 10178 10179 static struct mlx5_list_entry * 10180 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused, 10181 struct mlx5_list_entry *entry, void *cb_ctx) 10182 { 10183 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10184 struct mlx5_flow_dv_matcher *ref = ctx->data; 10185 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10186 typeof(*tbl), tbl); 10187 struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY, 10188 sizeof(*resource), 10189 0, SOCKET_ID_ANY); 10190 10191 if (!resource) { 10192 rte_flow_error_set(ctx->error, ENOMEM, 10193 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10194 "cannot create matcher"); 10195 return NULL; 10196 } 10197 memcpy(resource, entry, sizeof(*resource)); 10198 resource->tbl = &tbl->tbl; 10199 return &resource->entry; 10200 } 10201 10202 static void 10203 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused, 10204 struct mlx5_list_entry *entry) 10205 { 10206 mlx5_free(entry); 10207 } 10208 10209 struct mlx5_list_entry * 10210 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx) 10211 { 10212 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10213 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10214 struct rte_eth_dev *dev = ctx->dev; 10215 struct mlx5_flow_tbl_data_entry *tbl_data; 10216 struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2; 10217 struct rte_flow_error *error = ctx->error; 10218 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10219 struct mlx5_flow_tbl_resource *tbl; 10220 void *domain; 10221 uint32_t idx = 0; 10222 int ret; 10223 10224 tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10225 if (!tbl_data) { 10226 rte_flow_error_set(error, ENOMEM, 10227 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10228 NULL, 10229 "cannot allocate flow table data entry"); 10230 return NULL; 10231 } 10232 tbl_data->idx = idx; 10233 tbl_data->tunnel = tt_prm->tunnel; 10234 tbl_data->group_id = tt_prm->group_id; 10235 tbl_data->external = !!tt_prm->external; 10236 tbl_data->tunnel_offload = is_tunnel_offload_active(dev); 10237 tbl_data->is_egress = !!key.is_egress; 10238 tbl_data->is_transfer = !!key.is_fdb; 10239 tbl_data->dummy = !!key.dummy; 10240 tbl_data->level = key.level; 10241 tbl_data->id = key.id; 10242 tbl = &tbl_data->tbl; 10243 if (key.dummy) 10244 return &tbl_data->entry; 10245 if (key.is_fdb) 10246 domain = sh->fdb_domain; 10247 else if (key.is_egress) 10248 domain = sh->tx_domain; 10249 else 10250 domain = sh->rx_domain; 10251 ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj); 10252 if (ret) { 10253 rte_flow_error_set(error, ENOMEM, 10254 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10255 NULL, "cannot create flow table object"); 10256 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10257 return NULL; 10258 } 10259 if (key.level != 0) { 10260 ret = mlx5_flow_os_create_flow_action_dest_flow_tbl 10261 (tbl->obj, &tbl_data->jump.action); 10262 if (ret) { 10263 rte_flow_error_set(error, ENOMEM, 10264 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10265 NULL, 10266 "cannot create flow jump action"); 10267 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10268 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10269 return NULL; 10270 } 10271 } 10272 MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list", 10273 key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress", 10274 key.level, key.id); 10275 tbl_data->matchers = mlx5_list_create(matcher_name, sh, true, 10276 flow_dv_matcher_create_cb, 10277 flow_dv_matcher_match_cb, 10278 flow_dv_matcher_remove_cb, 10279 flow_dv_matcher_clone_cb, 10280 flow_dv_matcher_clone_free_cb); 10281 if (!tbl_data->matchers) { 10282 rte_flow_error_set(error, ENOMEM, 10283 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10284 NULL, 10285 "cannot create tbl matcher list"); 10286 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10287 mlx5_flow_os_destroy_flow_tbl(tbl->obj); 10288 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx); 10289 return NULL; 10290 } 10291 return &tbl_data->entry; 10292 } 10293 10294 int 10295 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10296 void *cb_ctx) 10297 { 10298 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10299 struct mlx5_flow_tbl_data_entry *tbl_data = 10300 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10301 union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) }; 10302 10303 return tbl_data->level != key.level || 10304 tbl_data->id != key.id || 10305 tbl_data->dummy != key.dummy || 10306 tbl_data->is_transfer != !!key.is_fdb || 10307 tbl_data->is_egress != !!key.is_egress; 10308 } 10309 10310 struct mlx5_list_entry * 10311 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10312 void *cb_ctx) 10313 { 10314 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10315 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10316 struct mlx5_flow_tbl_data_entry *tbl_data; 10317 struct rte_flow_error *error = ctx->error; 10318 uint32_t idx = 0; 10319 10320 tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx); 10321 if (!tbl_data) { 10322 rte_flow_error_set(error, ENOMEM, 10323 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10324 NULL, 10325 "cannot allocate flow table data entry"); 10326 return NULL; 10327 } 10328 memcpy(tbl_data, oentry, sizeof(*tbl_data)); 10329 tbl_data->idx = idx; 10330 return &tbl_data->entry; 10331 } 10332 10333 void 10334 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10335 { 10336 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10337 struct mlx5_flow_tbl_data_entry *tbl_data = 10338 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10339 10340 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10341 } 10342 10343 /** 10344 * Get a flow table. 10345 * 10346 * @param[in, out] dev 10347 * Pointer to rte_eth_dev structure. 10348 * @param[in] table_level 10349 * Table level to use. 10350 * @param[in] egress 10351 * Direction of the table. 10352 * @param[in] transfer 10353 * E-Switch or NIC flow. 10354 * @param[in] dummy 10355 * Dummy entry for dv API. 10356 * @param[in] table_id 10357 * Table id to use. 10358 * @param[out] error 10359 * pointer to error structure. 10360 * 10361 * @return 10362 * Returns tables resource based on the index, NULL in case of failed. 10363 */ 10364 struct mlx5_flow_tbl_resource * 10365 flow_dv_tbl_resource_get(struct rte_eth_dev *dev, 10366 uint32_t table_level, uint8_t egress, 10367 uint8_t transfer, 10368 bool external, 10369 const struct mlx5_flow_tunnel *tunnel, 10370 uint32_t group_id, uint8_t dummy, 10371 uint32_t table_id, 10372 struct rte_flow_error *error) 10373 { 10374 struct mlx5_priv *priv = dev->data->dev_private; 10375 union mlx5_flow_tbl_key table_key = { 10376 { 10377 .level = table_level, 10378 .id = table_id, 10379 .reserved = 0, 10380 .dummy = !!dummy, 10381 .is_fdb = !!transfer, 10382 .is_egress = !!egress, 10383 } 10384 }; 10385 struct mlx5_flow_tbl_tunnel_prm tt_prm = { 10386 .tunnel = tunnel, 10387 .group_id = group_id, 10388 .external = external, 10389 }; 10390 struct mlx5_flow_cb_ctx ctx = { 10391 .dev = dev, 10392 .error = error, 10393 .data = &table_key.v64, 10394 .data2 = &tt_prm, 10395 }; 10396 struct mlx5_list_entry *entry; 10397 struct mlx5_flow_tbl_data_entry *tbl_data; 10398 10399 entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx); 10400 if (!entry) { 10401 rte_flow_error_set(error, ENOMEM, 10402 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10403 "cannot get table"); 10404 return NULL; 10405 } 10406 DRV_LOG(DEBUG, "table_level %u table_id %u " 10407 "tunnel %u group %u registered.", 10408 table_level, table_id, 10409 tunnel ? tunnel->tunnel_id : 0, group_id); 10410 tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10411 return &tbl_data->tbl; 10412 } 10413 10414 void 10415 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10416 { 10417 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10418 struct mlx5_flow_tbl_data_entry *tbl_data = 10419 container_of(entry, struct mlx5_flow_tbl_data_entry, entry); 10420 10421 MLX5_ASSERT(entry && sh); 10422 if (tbl_data->jump.action) 10423 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action); 10424 if (tbl_data->tbl.obj) 10425 mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj); 10426 if (tbl_data->tunnel_offload && tbl_data->external) { 10427 struct mlx5_list_entry *he; 10428 struct mlx5_hlist *tunnel_grp_hash; 10429 struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub; 10430 union tunnel_tbl_key tunnel_key = { 10431 .tunnel_id = tbl_data->tunnel ? 10432 tbl_data->tunnel->tunnel_id : 0, 10433 .group = tbl_data->group_id 10434 }; 10435 uint32_t table_level = tbl_data->level; 10436 struct mlx5_flow_cb_ctx ctx = { 10437 .data = (void *)&tunnel_key.val, 10438 }; 10439 10440 tunnel_grp_hash = tbl_data->tunnel ? 10441 tbl_data->tunnel->groups : 10442 thub->groups; 10443 he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx); 10444 if (he) 10445 mlx5_hlist_unregister(tunnel_grp_hash, he); 10446 DRV_LOG(DEBUG, 10447 "table_level %u id %u tunnel %u group %u released.", 10448 table_level, 10449 tbl_data->id, 10450 tbl_data->tunnel ? 10451 tbl_data->tunnel->tunnel_id : 0, 10452 tbl_data->group_id); 10453 } 10454 mlx5_list_destroy(tbl_data->matchers); 10455 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx); 10456 } 10457 10458 /** 10459 * Release a flow table. 10460 * 10461 * @param[in] sh 10462 * Pointer to device shared structure. 10463 * @param[in] tbl 10464 * Table resource to be released. 10465 * 10466 * @return 10467 * Returns 0 if table was released, else return 1; 10468 */ 10469 static int 10470 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, 10471 struct mlx5_flow_tbl_resource *tbl) 10472 { 10473 struct mlx5_flow_tbl_data_entry *tbl_data = 10474 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10475 10476 if (!tbl) 10477 return 0; 10478 return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry); 10479 } 10480 10481 int 10482 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused, 10483 struct mlx5_list_entry *entry, void *cb_ctx) 10484 { 10485 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10486 struct mlx5_flow_dv_matcher *ref = ctx->data; 10487 struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur), 10488 entry); 10489 10490 return cur->crc != ref->crc || 10491 cur->priority != ref->priority || 10492 memcmp((const void *)cur->mask.buf, 10493 (const void *)ref->mask.buf, ref->mask.size); 10494 } 10495 10496 struct mlx5_list_entry * 10497 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx) 10498 { 10499 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10500 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10501 struct mlx5_flow_dv_matcher *ref = ctx->data; 10502 struct mlx5_flow_dv_matcher *resource; 10503 struct mlx5dv_flow_matcher_attr dv_attr = { 10504 .type = IBV_FLOW_ATTR_NORMAL, 10505 .match_mask = (void *)&ref->mask, 10506 }; 10507 struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl, 10508 typeof(*tbl), tbl); 10509 int ret; 10510 10511 resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0, 10512 SOCKET_ID_ANY); 10513 if (!resource) { 10514 rte_flow_error_set(ctx->error, ENOMEM, 10515 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10516 "cannot create matcher"); 10517 return NULL; 10518 } 10519 *resource = *ref; 10520 dv_attr.match_criteria_enable = 10521 flow_dv_matcher_enable(resource->mask.buf); 10522 __flow_dv_adjust_buf_size(&ref->mask.size, 10523 dv_attr.match_criteria_enable); 10524 dv_attr.priority = ref->priority; 10525 if (tbl->is_egress) 10526 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS; 10527 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 10528 tbl->tbl.obj, 10529 &resource->matcher_object); 10530 if (ret) { 10531 mlx5_free(resource); 10532 rte_flow_error_set(ctx->error, ENOMEM, 10533 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10534 "cannot create matcher"); 10535 return NULL; 10536 } 10537 return &resource->entry; 10538 } 10539 10540 /** 10541 * Register the flow matcher. 10542 * 10543 * @param[in, out] dev 10544 * Pointer to rte_eth_dev structure. 10545 * @param[in, out] matcher 10546 * Pointer to flow matcher. 10547 * @param[in, out] key 10548 * Pointer to flow table key. 10549 * @parm[in, out] dev_flow 10550 * Pointer to the dev_flow. 10551 * @param[out] error 10552 * pointer to error structure. 10553 * 10554 * @return 10555 * 0 on success otherwise -errno and errno is set. 10556 */ 10557 static int 10558 flow_dv_matcher_register(struct rte_eth_dev *dev, 10559 struct mlx5_flow_dv_matcher *ref, 10560 union mlx5_flow_tbl_key *key, 10561 struct mlx5_flow *dev_flow, 10562 const struct mlx5_flow_tunnel *tunnel, 10563 uint32_t group_id, 10564 struct rte_flow_error *error) 10565 { 10566 struct mlx5_list_entry *entry; 10567 struct mlx5_flow_dv_matcher *resource; 10568 struct mlx5_flow_tbl_resource *tbl; 10569 struct mlx5_flow_tbl_data_entry *tbl_data; 10570 struct mlx5_flow_cb_ctx ctx = { 10571 .error = error, 10572 .data = ref, 10573 }; 10574 /** 10575 * tunnel offload API requires this registration for cases when 10576 * tunnel match rule was inserted before tunnel set rule. 10577 */ 10578 tbl = flow_dv_tbl_resource_get(dev, key->level, 10579 key->is_egress, key->is_fdb, 10580 dev_flow->external, tunnel, 10581 group_id, 0, key->id, error); 10582 if (!tbl) 10583 return -rte_errno; /* No need to refill the error info */ 10584 tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl); 10585 ref->tbl = tbl; 10586 entry = mlx5_list_register(tbl_data->matchers, &ctx); 10587 if (!entry) { 10588 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 10589 return rte_flow_error_set(error, ENOMEM, 10590 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10591 "cannot allocate ref memory"); 10592 } 10593 resource = container_of(entry, typeof(*resource), entry); 10594 dev_flow->handle->dvh.matcher = resource; 10595 return 0; 10596 } 10597 10598 struct mlx5_list_entry * 10599 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx) 10600 { 10601 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10602 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10603 struct mlx5_flow_dv_tag_resource *entry; 10604 uint32_t idx = 0; 10605 int ret; 10606 10607 entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10608 if (!entry) { 10609 rte_flow_error_set(ctx->error, ENOMEM, 10610 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10611 "cannot allocate resource memory"); 10612 return NULL; 10613 } 10614 entry->idx = idx; 10615 entry->tag_id = *(uint32_t *)(ctx->data); 10616 ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id, 10617 &entry->action); 10618 if (ret) { 10619 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx); 10620 rte_flow_error_set(ctx->error, ENOMEM, 10621 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 10622 NULL, "cannot create action"); 10623 return NULL; 10624 } 10625 return &entry->entry; 10626 } 10627 10628 int 10629 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, 10630 void *cb_ctx) 10631 { 10632 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10633 struct mlx5_flow_dv_tag_resource *tag = 10634 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10635 10636 return *(uint32_t *)(ctx->data) != tag->tag_id; 10637 } 10638 10639 struct mlx5_list_entry * 10640 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry, 10641 void *cb_ctx) 10642 { 10643 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10644 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 10645 struct mlx5_flow_dv_tag_resource *entry; 10646 uint32_t idx = 0; 10647 10648 entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx); 10649 if (!entry) { 10650 rte_flow_error_set(ctx->error, ENOMEM, 10651 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 10652 "cannot allocate tag resource memory"); 10653 return NULL; 10654 } 10655 memcpy(entry, oentry, sizeof(*entry)); 10656 entry->idx = idx; 10657 return &entry->entry; 10658 } 10659 10660 void 10661 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10662 { 10663 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10664 struct mlx5_flow_dv_tag_resource *tag = 10665 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10666 10667 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10668 } 10669 10670 /** 10671 * Find existing tag resource or create and register a new one. 10672 * 10673 * @param dev[in, out] 10674 * Pointer to rte_eth_dev structure. 10675 * @param[in, out] tag_be24 10676 * Tag value in big endian then R-shift 8. 10677 * @parm[in, out] dev_flow 10678 * Pointer to the dev_flow. 10679 * @param[out] error 10680 * pointer to error structure. 10681 * 10682 * @return 10683 * 0 on success otherwise -errno and errno is set. 10684 */ 10685 static int 10686 flow_dv_tag_resource_register 10687 (struct rte_eth_dev *dev, 10688 uint32_t tag_be24, 10689 struct mlx5_flow *dev_flow, 10690 struct rte_flow_error *error) 10691 { 10692 struct mlx5_priv *priv = dev->data->dev_private; 10693 struct mlx5_flow_dv_tag_resource *resource; 10694 struct mlx5_list_entry *entry; 10695 struct mlx5_flow_cb_ctx ctx = { 10696 .error = error, 10697 .data = &tag_be24, 10698 }; 10699 struct mlx5_hlist *tag_table; 10700 10701 tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table, 10702 "tags", 10703 MLX5_TAGS_HLIST_ARRAY_SIZE, 10704 false, false, priv->sh, 10705 flow_dv_tag_create_cb, 10706 flow_dv_tag_match_cb, 10707 flow_dv_tag_remove_cb, 10708 flow_dv_tag_clone_cb, 10709 flow_dv_tag_clone_free_cb); 10710 if (unlikely(!tag_table)) 10711 return -rte_errno; 10712 entry = mlx5_hlist_register(tag_table, tag_be24, &ctx); 10713 if (entry) { 10714 resource = container_of(entry, struct mlx5_flow_dv_tag_resource, 10715 entry); 10716 dev_flow->handle->dvh.rix_tag = resource->idx; 10717 dev_flow->dv.tag_resource = resource; 10718 return 0; 10719 } 10720 return -rte_errno; 10721 } 10722 10723 void 10724 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 10725 { 10726 struct mlx5_dev_ctx_shared *sh = tool_ctx; 10727 struct mlx5_flow_dv_tag_resource *tag = 10728 container_of(entry, struct mlx5_flow_dv_tag_resource, entry); 10729 10730 MLX5_ASSERT(tag && sh && tag->action); 10731 claim_zero(mlx5_flow_os_destroy_flow_action(tag->action)); 10732 DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag); 10733 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx); 10734 } 10735 10736 /** 10737 * Release the tag. 10738 * 10739 * @param dev 10740 * Pointer to Ethernet device. 10741 * @param tag_idx 10742 * Tag index. 10743 * 10744 * @return 10745 * 1 while a reference on it exists, 0 when freed. 10746 */ 10747 static int 10748 flow_dv_tag_release(struct rte_eth_dev *dev, 10749 uint32_t tag_idx) 10750 { 10751 struct mlx5_priv *priv = dev->data->dev_private; 10752 struct mlx5_flow_dv_tag_resource *tag; 10753 10754 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx); 10755 if (!tag) 10756 return 0; 10757 DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--", 10758 dev->data->port_id, (void *)tag, tag->entry.ref_cnt); 10759 return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry); 10760 } 10761 10762 /** 10763 * Translate action PORT_ID / REPRESENTED_PORT to vport. 10764 * 10765 * @param[in] dev 10766 * Pointer to rte_eth_dev structure. 10767 * @param[in] action 10768 * Pointer to action PORT_ID / REPRESENTED_PORT. 10769 * @param[out] dst_port_id 10770 * The target port ID. 10771 * @param[out] error 10772 * Pointer to the error structure. 10773 * 10774 * @return 10775 * 0 on success, a negative errno value otherwise and rte_errno is set. 10776 */ 10777 static int 10778 flow_dv_translate_action_port_id(struct rte_eth_dev *dev, 10779 const struct rte_flow_action *action, 10780 uint32_t *dst_port_id, 10781 struct rte_flow_error *error) 10782 { 10783 uint32_t port; 10784 struct mlx5_priv *priv; 10785 10786 switch (action->type) { 10787 case RTE_FLOW_ACTION_TYPE_PORT_ID: { 10788 const struct rte_flow_action_port_id *conf; 10789 10790 conf = (const struct rte_flow_action_port_id *)action->conf; 10791 port = conf->original ? dev->data->port_id : conf->id; 10792 break; 10793 } 10794 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { 10795 const struct rte_flow_action_ethdev *ethdev; 10796 10797 ethdev = (const struct rte_flow_action_ethdev *)action->conf; 10798 port = ethdev->port_id; 10799 break; 10800 } 10801 default: 10802 MLX5_ASSERT(false); 10803 return rte_flow_error_set(error, EINVAL, 10804 RTE_FLOW_ERROR_TYPE_ACTION, action, 10805 "unknown E-Switch action"); 10806 } 10807 10808 priv = mlx5_port_to_eswitch_info(port, false); 10809 if (!priv) 10810 return rte_flow_error_set(error, -rte_errno, 10811 RTE_FLOW_ERROR_TYPE_ACTION, 10812 NULL, 10813 "No eswitch info was found for port"); 10814 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT 10815 /* 10816 * This parameter is transferred to 10817 * mlx5dv_dr_action_create_dest_ib_port(). 10818 */ 10819 *dst_port_id = priv->dev_port; 10820 #else 10821 /* 10822 * Legacy mode, no LAG configurations is supported. 10823 * This parameter is transferred to 10824 * mlx5dv_dr_action_create_dest_vport(). 10825 */ 10826 *dst_port_id = priv->vport_id; 10827 #endif 10828 return 0; 10829 } 10830 10831 /** 10832 * Create a counter with aging configuration. 10833 * 10834 * @param[in] dev 10835 * Pointer to rte_eth_dev structure. 10836 * @param[in] dev_flow 10837 * Pointer to the mlx5_flow. 10838 * @param[out] count 10839 * Pointer to the counter action configuration. 10840 * @param[in] age 10841 * Pointer to the aging action configuration. 10842 * 10843 * @return 10844 * Index to flow counter on success, 0 otherwise. 10845 */ 10846 static uint32_t 10847 flow_dv_translate_create_counter(struct rte_eth_dev *dev, 10848 struct mlx5_flow *dev_flow, 10849 const struct rte_flow_action_count *count 10850 __rte_unused, 10851 const struct rte_flow_action_age *age) 10852 { 10853 uint32_t counter; 10854 struct mlx5_age_param *age_param; 10855 10856 counter = flow_dv_counter_alloc(dev, !!age); 10857 if (!counter || age == NULL) 10858 return counter; 10859 age_param = flow_dv_counter_idx_get_age(dev, counter); 10860 age_param->context = age->context ? age->context : 10861 (void *)(uintptr_t)(dev_flow->flow_idx); 10862 age_param->timeout = age->timeout; 10863 age_param->port_id = dev->data->port_id; 10864 __atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED); 10865 __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED); 10866 return counter; 10867 } 10868 10869 /** 10870 * Add Tx queue matcher 10871 * 10872 * @param[in] dev 10873 * Pointer to the dev struct. 10874 * @param[in, out] matcher 10875 * Flow matcher. 10876 * @param[in, out] key 10877 * Flow matcher value. 10878 * @param[in] item 10879 * Flow pattern to translate. 10880 * @param[in] inner 10881 * Item is inner pattern. 10882 */ 10883 static void 10884 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev, 10885 void *matcher, void *key, 10886 const struct rte_flow_item *item) 10887 { 10888 const struct mlx5_rte_flow_item_tx_queue *queue_m; 10889 const struct mlx5_rte_flow_item_tx_queue *queue_v; 10890 void *misc_m = 10891 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters); 10892 void *misc_v = 10893 MLX5_ADDR_OF(fte_match_param, key, misc_parameters); 10894 struct mlx5_txq_ctrl *txq; 10895 uint32_t queue, mask; 10896 10897 queue_m = (const void *)item->mask; 10898 queue_v = (const void *)item->spec; 10899 if (!queue_v) 10900 return; 10901 txq = mlx5_txq_get(dev, queue_v->queue); 10902 if (!txq) 10903 return; 10904 if (txq->type == MLX5_TXQ_TYPE_HAIRPIN) 10905 queue = txq->obj->sq->id; 10906 else 10907 queue = txq->obj->sq_obj.sq->id; 10908 mask = queue_m == NULL ? UINT32_MAX : queue_m->queue; 10909 MLX5_SET(fte_match_set_misc, misc_m, source_sqn, mask); 10910 MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue & mask); 10911 mlx5_txq_release(dev, queue_v->queue); 10912 } 10913 10914 /** 10915 * Set the hash fields according to the @p flow information. 10916 * 10917 * @param[in] dev_flow 10918 * Pointer to the mlx5_flow. 10919 * @param[in] rss_desc 10920 * Pointer to the mlx5_flow_rss_desc. 10921 */ 10922 static void 10923 flow_dv_hashfields_set(struct mlx5_flow *dev_flow, 10924 struct mlx5_flow_rss_desc *rss_desc) 10925 { 10926 uint64_t items = dev_flow->handle->layers; 10927 int rss_inner = 0; 10928 uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types); 10929 10930 dev_flow->hash_fields = 0; 10931 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT 10932 if (rss_desc->level >= 2) 10933 rss_inner = 1; 10934 #endif 10935 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || 10936 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { 10937 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 10938 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 10939 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4; 10940 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 10941 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4; 10942 else 10943 dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH; 10944 } 10945 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || 10946 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) { 10947 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 10948 if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 10949 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6; 10950 else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 10951 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6; 10952 else 10953 dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH; 10954 } 10955 } 10956 if (dev_flow->hash_fields == 0) 10957 /* 10958 * There is no match between the RSS types and the 10959 * L3 protocol (IPv4/IPv6) defined in the flow rule. 10960 */ 10961 return; 10962 if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || 10963 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { 10964 if (rss_types & RTE_ETH_RSS_UDP) { 10965 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 10966 dev_flow->hash_fields |= 10967 IBV_RX_HASH_SRC_PORT_UDP; 10968 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 10969 dev_flow->hash_fields |= 10970 IBV_RX_HASH_DST_PORT_UDP; 10971 else 10972 dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH; 10973 } 10974 } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) || 10975 (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) { 10976 if (rss_types & RTE_ETH_RSS_TCP) { 10977 if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 10978 dev_flow->hash_fields |= 10979 IBV_RX_HASH_SRC_PORT_TCP; 10980 else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 10981 dev_flow->hash_fields |= 10982 IBV_RX_HASH_DST_PORT_TCP; 10983 else 10984 dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH; 10985 } 10986 } 10987 if (rss_inner) 10988 dev_flow->hash_fields |= IBV_RX_HASH_INNER; 10989 } 10990 10991 /** 10992 * Prepare an Rx Hash queue. 10993 * 10994 * @param dev 10995 * Pointer to Ethernet device. 10996 * @param[in] dev_flow 10997 * Pointer to the mlx5_flow. 10998 * @param[in] rss_desc 10999 * Pointer to the mlx5_flow_rss_desc. 11000 * @param[out] hrxq_idx 11001 * Hash Rx queue index. 11002 * 11003 * @return 11004 * The Verbs/DevX object initialised, NULL otherwise and rte_errno is set. 11005 */ 11006 static struct mlx5_hrxq * 11007 flow_dv_hrxq_prepare(struct rte_eth_dev *dev, 11008 struct mlx5_flow *dev_flow, 11009 struct mlx5_flow_rss_desc *rss_desc, 11010 uint32_t *hrxq_idx) 11011 { 11012 struct mlx5_priv *priv = dev->data->dev_private; 11013 struct mlx5_flow_handle *dh = dev_flow->handle; 11014 struct mlx5_hrxq *hrxq; 11015 11016 MLX5_ASSERT(rss_desc->queue_num); 11017 rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN; 11018 rss_desc->hash_fields = dev_flow->hash_fields; 11019 rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL); 11020 rss_desc->shared_rss = 0; 11021 if (rss_desc->hash_fields == 0) 11022 rss_desc->queue_num = 1; 11023 *hrxq_idx = mlx5_hrxq_get(dev, rss_desc); 11024 if (!*hrxq_idx) 11025 return NULL; 11026 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 11027 *hrxq_idx); 11028 return hrxq; 11029 } 11030 11031 /** 11032 * Release sample sub action resource. 11033 * 11034 * @param[in, out] dev 11035 * Pointer to rte_eth_dev structure. 11036 * @param[in] act_res 11037 * Pointer to sample sub action resource. 11038 */ 11039 static void 11040 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev, 11041 struct mlx5_flow_sub_actions_idx *act_res) 11042 { 11043 if (act_res->rix_hrxq) { 11044 mlx5_hrxq_release(dev, act_res->rix_hrxq); 11045 act_res->rix_hrxq = 0; 11046 } 11047 if (act_res->rix_encap_decap) { 11048 flow_dv_encap_decap_resource_release(dev, 11049 act_res->rix_encap_decap); 11050 act_res->rix_encap_decap = 0; 11051 } 11052 if (act_res->rix_port_id_action) { 11053 flow_dv_port_id_action_resource_release(dev, 11054 act_res->rix_port_id_action); 11055 act_res->rix_port_id_action = 0; 11056 } 11057 if (act_res->rix_tag) { 11058 flow_dv_tag_release(dev, act_res->rix_tag); 11059 act_res->rix_tag = 0; 11060 } 11061 if (act_res->rix_jump) { 11062 flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump); 11063 act_res->rix_jump = 0; 11064 } 11065 } 11066 11067 int 11068 flow_dv_sample_match_cb(void *tool_ctx __rte_unused, 11069 struct mlx5_list_entry *entry, void *cb_ctx) 11070 { 11071 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11072 struct rte_eth_dev *dev = ctx->dev; 11073 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11074 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 11075 typeof(*resource), 11076 entry); 11077 11078 if (ctx_resource->ratio == resource->ratio && 11079 ctx_resource->ft_type == resource->ft_type && 11080 ctx_resource->ft_id == resource->ft_id && 11081 ctx_resource->set_action == resource->set_action && 11082 !memcmp((void *)&ctx_resource->sample_act, 11083 (void *)&resource->sample_act, 11084 sizeof(struct mlx5_flow_sub_actions_list))) { 11085 /* 11086 * Existing sample action should release the prepared 11087 * sub-actions reference counter. 11088 */ 11089 flow_dv_sample_sub_actions_release(dev, 11090 &ctx_resource->sample_idx); 11091 return 0; 11092 } 11093 return 1; 11094 } 11095 11096 struct mlx5_list_entry * 11097 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11098 { 11099 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11100 struct rte_eth_dev *dev = ctx->dev; 11101 struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data; 11102 void **sample_dv_actions = ctx_resource->sub_actions; 11103 struct mlx5_flow_dv_sample_resource *resource; 11104 struct mlx5dv_dr_flow_sampler_attr sampler_attr; 11105 struct mlx5_priv *priv = dev->data->dev_private; 11106 struct mlx5_dev_ctx_shared *sh = priv->sh; 11107 struct mlx5_flow_tbl_resource *tbl; 11108 uint32_t idx = 0; 11109 const uint32_t next_ft_step = 1; 11110 uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step; 11111 uint8_t is_egress = 0; 11112 uint8_t is_transfer = 0; 11113 struct rte_flow_error *error = ctx->error; 11114 11115 /* Register new sample resource. */ 11116 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11117 if (!resource) { 11118 rte_flow_error_set(error, ENOMEM, 11119 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11120 NULL, 11121 "cannot allocate resource memory"); 11122 return NULL; 11123 } 11124 *resource = *ctx_resource; 11125 /* Create normal path table level */ 11126 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11127 is_transfer = 1; 11128 else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX) 11129 is_egress = 1; 11130 tbl = flow_dv_tbl_resource_get(dev, next_ft_id, 11131 is_egress, is_transfer, 11132 true, NULL, 0, 0, 0, error); 11133 if (!tbl) { 11134 rte_flow_error_set(error, ENOMEM, 11135 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11136 NULL, 11137 "fail to create normal path table " 11138 "for sample"); 11139 goto error; 11140 } 11141 resource->normal_path_tbl = tbl; 11142 if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) { 11143 if (!sh->default_miss_action) { 11144 rte_flow_error_set(error, ENOMEM, 11145 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11146 NULL, 11147 "default miss action was not " 11148 "created"); 11149 goto error; 11150 } 11151 sample_dv_actions[ctx_resource->sample_act.actions_num++] = 11152 sh->default_miss_action; 11153 } 11154 /* Create a DR sample action */ 11155 sampler_attr.sample_ratio = resource->ratio; 11156 sampler_attr.default_next_table = tbl->obj; 11157 sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num; 11158 sampler_attr.sample_actions = (struct mlx5dv_dr_action **) 11159 &sample_dv_actions[0]; 11160 sampler_attr.action = resource->set_action; 11161 if (mlx5_os_flow_dr_create_flow_action_sampler 11162 (&sampler_attr, &resource->verbs_action)) { 11163 rte_flow_error_set(error, ENOMEM, 11164 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11165 NULL, "cannot create sample action"); 11166 goto error; 11167 } 11168 resource->idx = idx; 11169 resource->dev = dev; 11170 return &resource->entry; 11171 error: 11172 if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB) 11173 flow_dv_sample_sub_actions_release(dev, 11174 &resource->sample_idx); 11175 if (resource->normal_path_tbl) 11176 flow_dv_tbl_resource_release(MLX5_SH(dev), 11177 resource->normal_path_tbl); 11178 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx); 11179 return NULL; 11180 11181 } 11182 11183 struct mlx5_list_entry * 11184 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused, 11185 struct mlx5_list_entry *entry __rte_unused, 11186 void *cb_ctx) 11187 { 11188 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11189 struct rte_eth_dev *dev = ctx->dev; 11190 struct mlx5_flow_dv_sample_resource *resource; 11191 struct mlx5_priv *priv = dev->data->dev_private; 11192 struct mlx5_dev_ctx_shared *sh = priv->sh; 11193 uint32_t idx = 0; 11194 11195 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx); 11196 if (!resource) { 11197 rte_flow_error_set(ctx->error, ENOMEM, 11198 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11199 NULL, 11200 "cannot allocate resource memory"); 11201 return NULL; 11202 } 11203 memcpy(resource, entry, sizeof(*resource)); 11204 resource->idx = idx; 11205 resource->dev = dev; 11206 return &resource->entry; 11207 } 11208 11209 void 11210 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused, 11211 struct mlx5_list_entry *entry) 11212 { 11213 struct mlx5_flow_dv_sample_resource *resource = 11214 container_of(entry, typeof(*resource), entry); 11215 struct rte_eth_dev *dev = resource->dev; 11216 struct mlx5_priv *priv = dev->data->dev_private; 11217 11218 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 11219 } 11220 11221 /** 11222 * Find existing sample resource or create and register a new one. 11223 * 11224 * @param[in, out] dev 11225 * Pointer to rte_eth_dev structure. 11226 * @param[in] ref 11227 * Pointer to sample resource reference. 11228 * @parm[in, out] dev_flow 11229 * Pointer to the dev_flow. 11230 * @param[out] error 11231 * pointer to error structure. 11232 * 11233 * @return 11234 * 0 on success otherwise -errno and errno is set. 11235 */ 11236 static int 11237 flow_dv_sample_resource_register(struct rte_eth_dev *dev, 11238 struct mlx5_flow_dv_sample_resource *ref, 11239 struct mlx5_flow *dev_flow, 11240 struct rte_flow_error *error) 11241 { 11242 struct mlx5_flow_dv_sample_resource *resource; 11243 struct mlx5_list_entry *entry; 11244 struct mlx5_priv *priv = dev->data->dev_private; 11245 struct mlx5_flow_cb_ctx ctx = { 11246 .dev = dev, 11247 .error = error, 11248 .data = ref, 11249 }; 11250 11251 entry = mlx5_list_register(priv->sh->sample_action_list, &ctx); 11252 if (!entry) 11253 return -rte_errno; 11254 resource = container_of(entry, typeof(*resource), entry); 11255 dev_flow->handle->dvh.rix_sample = resource->idx; 11256 dev_flow->dv.sample_res = resource; 11257 return 0; 11258 } 11259 11260 int 11261 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused, 11262 struct mlx5_list_entry *entry, void *cb_ctx) 11263 { 11264 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11265 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11266 struct rte_eth_dev *dev = ctx->dev; 11267 struct mlx5_flow_dv_dest_array_resource *resource = 11268 container_of(entry, typeof(*resource), entry); 11269 uint32_t idx = 0; 11270 11271 if (ctx_resource->num_of_dest == resource->num_of_dest && 11272 ctx_resource->ft_type == resource->ft_type && 11273 !memcmp((void *)resource->sample_act, 11274 (void *)ctx_resource->sample_act, 11275 (ctx_resource->num_of_dest * 11276 sizeof(struct mlx5_flow_sub_actions_list)))) { 11277 /* 11278 * Existing sample action should release the prepared 11279 * sub-actions reference counter. 11280 */ 11281 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11282 flow_dv_sample_sub_actions_release(dev, 11283 &ctx_resource->sample_idx[idx]); 11284 return 0; 11285 } 11286 return 1; 11287 } 11288 11289 struct mlx5_list_entry * 11290 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx) 11291 { 11292 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11293 struct rte_eth_dev *dev = ctx->dev; 11294 struct mlx5_flow_dv_dest_array_resource *resource; 11295 struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data; 11296 struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 }; 11297 struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM]; 11298 struct mlx5_priv *priv = dev->data->dev_private; 11299 struct mlx5_dev_ctx_shared *sh = priv->sh; 11300 struct mlx5_flow_sub_actions_list *sample_act; 11301 struct mlx5dv_dr_domain *domain; 11302 uint32_t idx = 0, res_idx = 0; 11303 struct rte_flow_error *error = ctx->error; 11304 uint64_t action_flags; 11305 int ret; 11306 11307 /* Register new destination array resource. */ 11308 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11309 &res_idx); 11310 if (!resource) { 11311 rte_flow_error_set(error, ENOMEM, 11312 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11313 NULL, 11314 "cannot allocate resource memory"); 11315 return NULL; 11316 } 11317 *resource = *ctx_resource; 11318 if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) 11319 domain = sh->fdb_domain; 11320 else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX) 11321 domain = sh->rx_domain; 11322 else 11323 domain = sh->tx_domain; 11324 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11325 dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *) 11326 mlx5_malloc(MLX5_MEM_ZERO, 11327 sizeof(struct mlx5dv_dr_action_dest_attr), 11328 0, SOCKET_ID_ANY); 11329 if (!dest_attr[idx]) { 11330 rte_flow_error_set(error, ENOMEM, 11331 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11332 NULL, 11333 "cannot allocate resource memory"); 11334 goto error; 11335 } 11336 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST; 11337 sample_act = &ctx_resource->sample_act[idx]; 11338 action_flags = sample_act->action_flags; 11339 switch (action_flags) { 11340 case MLX5_FLOW_ACTION_QUEUE: 11341 dest_attr[idx]->dest = sample_act->dr_queue_action; 11342 break; 11343 case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP): 11344 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT; 11345 dest_attr[idx]->dest_reformat = &dest_reformat[idx]; 11346 dest_attr[idx]->dest_reformat->reformat = 11347 sample_act->dr_encap_action; 11348 dest_attr[idx]->dest_reformat->dest = 11349 sample_act->dr_port_id_action; 11350 break; 11351 case MLX5_FLOW_ACTION_PORT_ID: 11352 dest_attr[idx]->dest = sample_act->dr_port_id_action; 11353 break; 11354 case MLX5_FLOW_ACTION_JUMP: 11355 dest_attr[idx]->dest = sample_act->dr_jump_action; 11356 break; 11357 default: 11358 rte_flow_error_set(error, EINVAL, 11359 RTE_FLOW_ERROR_TYPE_ACTION, 11360 NULL, 11361 "unsupported actions type"); 11362 goto error; 11363 } 11364 } 11365 /* create a dest array actioin */ 11366 ret = mlx5_os_flow_dr_create_flow_action_dest_array 11367 (domain, 11368 resource->num_of_dest, 11369 dest_attr, 11370 &resource->action); 11371 if (ret) { 11372 rte_flow_error_set(error, ENOMEM, 11373 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11374 NULL, 11375 "cannot create destination array action"); 11376 goto error; 11377 } 11378 resource->idx = res_idx; 11379 resource->dev = dev; 11380 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) 11381 mlx5_free(dest_attr[idx]); 11382 return &resource->entry; 11383 error: 11384 for (idx = 0; idx < ctx_resource->num_of_dest; idx++) { 11385 flow_dv_sample_sub_actions_release(dev, 11386 &resource->sample_idx[idx]); 11387 if (dest_attr[idx]) 11388 mlx5_free(dest_attr[idx]); 11389 } 11390 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx); 11391 return NULL; 11392 } 11393 11394 struct mlx5_list_entry * 11395 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused, 11396 struct mlx5_list_entry *entry __rte_unused, 11397 void *cb_ctx) 11398 { 11399 struct mlx5_flow_cb_ctx *ctx = cb_ctx; 11400 struct rte_eth_dev *dev = ctx->dev; 11401 struct mlx5_flow_dv_dest_array_resource *resource; 11402 struct mlx5_priv *priv = dev->data->dev_private; 11403 struct mlx5_dev_ctx_shared *sh = priv->sh; 11404 uint32_t res_idx = 0; 11405 struct rte_flow_error *error = ctx->error; 11406 11407 resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY], 11408 &res_idx); 11409 if (!resource) { 11410 rte_flow_error_set(error, ENOMEM, 11411 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11412 NULL, 11413 "cannot allocate dest-array memory"); 11414 return NULL; 11415 } 11416 memcpy(resource, entry, sizeof(*resource)); 11417 resource->idx = res_idx; 11418 resource->dev = dev; 11419 return &resource->entry; 11420 } 11421 11422 void 11423 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused, 11424 struct mlx5_list_entry *entry) 11425 { 11426 struct mlx5_flow_dv_dest_array_resource *resource = 11427 container_of(entry, typeof(*resource), entry); 11428 struct rte_eth_dev *dev = resource->dev; 11429 struct mlx5_priv *priv = dev->data->dev_private; 11430 11431 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 11432 } 11433 11434 /** 11435 * Find existing destination array resource or create and register a new one. 11436 * 11437 * @param[in, out] dev 11438 * Pointer to rte_eth_dev structure. 11439 * @param[in] ref 11440 * Pointer to destination array resource reference. 11441 * @parm[in, out] dev_flow 11442 * Pointer to the dev_flow. 11443 * @param[out] error 11444 * pointer to error structure. 11445 * 11446 * @return 11447 * 0 on success otherwise -errno and errno is set. 11448 */ 11449 static int 11450 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev, 11451 struct mlx5_flow_dv_dest_array_resource *ref, 11452 struct mlx5_flow *dev_flow, 11453 struct rte_flow_error *error) 11454 { 11455 struct mlx5_flow_dv_dest_array_resource *resource; 11456 struct mlx5_priv *priv = dev->data->dev_private; 11457 struct mlx5_list_entry *entry; 11458 struct mlx5_flow_cb_ctx ctx = { 11459 .dev = dev, 11460 .error = error, 11461 .data = ref, 11462 }; 11463 11464 entry = mlx5_list_register(priv->sh->dest_array_list, &ctx); 11465 if (!entry) 11466 return -rte_errno; 11467 resource = container_of(entry, typeof(*resource), entry); 11468 dev_flow->handle->dvh.rix_dest_array = resource->idx; 11469 dev_flow->dv.dest_array_res = resource; 11470 return 0; 11471 } 11472 11473 /** 11474 * Convert Sample action to DV specification. 11475 * 11476 * @param[in] dev 11477 * Pointer to rte_eth_dev structure. 11478 * @param[in] action 11479 * Pointer to sample action structure. 11480 * @param[in, out] dev_flow 11481 * Pointer to the mlx5_flow. 11482 * @param[in] attr 11483 * Pointer to the flow attributes. 11484 * @param[in, out] num_of_dest 11485 * Pointer to the num of destination. 11486 * @param[in, out] sample_actions 11487 * Pointer to sample actions list. 11488 * @param[in, out] res 11489 * Pointer to sample resource. 11490 * @param[out] error 11491 * Pointer to the error structure. 11492 * 11493 * @return 11494 * 0 on success, a negative errno value otherwise and rte_errno is set. 11495 */ 11496 static int 11497 flow_dv_translate_action_sample(struct rte_eth_dev *dev, 11498 const struct rte_flow_action_sample *action, 11499 struct mlx5_flow *dev_flow, 11500 const struct rte_flow_attr *attr, 11501 uint32_t *num_of_dest, 11502 void **sample_actions, 11503 struct mlx5_flow_dv_sample_resource *res, 11504 struct rte_flow_error *error) 11505 { 11506 struct mlx5_priv *priv = dev->data->dev_private; 11507 const struct rte_flow_action *sub_actions; 11508 struct mlx5_flow_sub_actions_list *sample_act; 11509 struct mlx5_flow_sub_actions_idx *sample_idx; 11510 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11511 struct rte_flow *flow = dev_flow->flow; 11512 struct mlx5_flow_rss_desc *rss_desc; 11513 uint64_t action_flags = 0; 11514 11515 MLX5_ASSERT(wks); 11516 rss_desc = &wks->rss_desc; 11517 sample_act = &res->sample_act; 11518 sample_idx = &res->sample_idx; 11519 res->ratio = action->ratio; 11520 sub_actions = action->actions; 11521 for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) { 11522 int type = sub_actions->type; 11523 uint32_t pre_rix = 0; 11524 void *pre_r; 11525 switch (type) { 11526 case RTE_FLOW_ACTION_TYPE_QUEUE: 11527 { 11528 const struct rte_flow_action_queue *queue; 11529 struct mlx5_hrxq *hrxq; 11530 uint32_t hrxq_idx; 11531 11532 queue = sub_actions->conf; 11533 rss_desc->queue_num = 1; 11534 rss_desc->queue[0] = queue->index; 11535 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11536 rss_desc, &hrxq_idx); 11537 if (!hrxq) 11538 return rte_flow_error_set 11539 (error, rte_errno, 11540 RTE_FLOW_ERROR_TYPE_ACTION, 11541 NULL, 11542 "cannot create fate queue"); 11543 sample_act->dr_queue_action = hrxq->action; 11544 sample_idx->rix_hrxq = hrxq_idx; 11545 sample_actions[sample_act->actions_num++] = 11546 hrxq->action; 11547 (*num_of_dest)++; 11548 action_flags |= MLX5_FLOW_ACTION_QUEUE; 11549 if (action_flags & MLX5_FLOW_ACTION_MARK) 11550 dev_flow->handle->rix_hrxq = hrxq_idx; 11551 dev_flow->handle->fate_action = 11552 MLX5_FLOW_FATE_QUEUE; 11553 break; 11554 } 11555 case RTE_FLOW_ACTION_TYPE_RSS: 11556 { 11557 struct mlx5_hrxq *hrxq; 11558 uint32_t hrxq_idx; 11559 const struct rte_flow_action_rss *rss; 11560 const uint8_t *rss_key; 11561 11562 rss = sub_actions->conf; 11563 memcpy(rss_desc->queue, rss->queue, 11564 rss->queue_num * sizeof(uint16_t)); 11565 rss_desc->queue_num = rss->queue_num; 11566 /* NULL RSS key indicates default RSS key. */ 11567 rss_key = !rss->key ? rss_hash_default_key : rss->key; 11568 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 11569 /* 11570 * rss->level and rss.types should be set in advance 11571 * when expanding items for RSS. 11572 */ 11573 flow_dv_hashfields_set(dev_flow, rss_desc); 11574 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11575 rss_desc, &hrxq_idx); 11576 if (!hrxq) 11577 return rte_flow_error_set 11578 (error, rte_errno, 11579 RTE_FLOW_ERROR_TYPE_ACTION, 11580 NULL, 11581 "cannot create fate queue"); 11582 sample_act->dr_queue_action = hrxq->action; 11583 sample_idx->rix_hrxq = hrxq_idx; 11584 sample_actions[sample_act->actions_num++] = 11585 hrxq->action; 11586 (*num_of_dest)++; 11587 action_flags |= MLX5_FLOW_ACTION_RSS; 11588 if (action_flags & MLX5_FLOW_ACTION_MARK) 11589 dev_flow->handle->rix_hrxq = hrxq_idx; 11590 dev_flow->handle->fate_action = 11591 MLX5_FLOW_FATE_QUEUE; 11592 break; 11593 } 11594 case RTE_FLOW_ACTION_TYPE_MARK: 11595 { 11596 uint32_t tag_be = mlx5_flow_mark_set 11597 (((const struct rte_flow_action_mark *) 11598 (sub_actions->conf))->id); 11599 11600 dev_flow->handle->mark = 1; 11601 pre_rix = dev_flow->handle->dvh.rix_tag; 11602 /* Save the mark resource before sample */ 11603 pre_r = dev_flow->dv.tag_resource; 11604 if (flow_dv_tag_resource_register(dev, tag_be, 11605 dev_flow, error)) 11606 return -rte_errno; 11607 MLX5_ASSERT(dev_flow->dv.tag_resource); 11608 sample_act->dr_tag_action = 11609 dev_flow->dv.tag_resource->action; 11610 sample_idx->rix_tag = 11611 dev_flow->handle->dvh.rix_tag; 11612 sample_actions[sample_act->actions_num++] = 11613 sample_act->dr_tag_action; 11614 /* Recover the mark resource after sample */ 11615 dev_flow->dv.tag_resource = pre_r; 11616 dev_flow->handle->dvh.rix_tag = pre_rix; 11617 action_flags |= MLX5_FLOW_ACTION_MARK; 11618 break; 11619 } 11620 case RTE_FLOW_ACTION_TYPE_COUNT: 11621 { 11622 if (!flow->counter) { 11623 flow->counter = 11624 flow_dv_translate_create_counter(dev, 11625 dev_flow, sub_actions->conf, 11626 0); 11627 if (!flow->counter) 11628 return rte_flow_error_set 11629 (error, rte_errno, 11630 RTE_FLOW_ERROR_TYPE_ACTION, 11631 NULL, 11632 "cannot create counter" 11633 " object."); 11634 } 11635 sample_act->dr_cnt_action = 11636 (flow_dv_counter_get_by_idx(dev, 11637 flow->counter, NULL))->action; 11638 sample_actions[sample_act->actions_num++] = 11639 sample_act->dr_cnt_action; 11640 action_flags |= MLX5_FLOW_ACTION_COUNT; 11641 break; 11642 } 11643 case RTE_FLOW_ACTION_TYPE_PORT_ID: 11644 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 11645 { 11646 struct mlx5_flow_dv_port_id_action_resource 11647 port_id_resource; 11648 uint32_t port_id = 0; 11649 11650 memset(&port_id_resource, 0, sizeof(port_id_resource)); 11651 /* Save the port id resource before sample */ 11652 pre_rix = dev_flow->handle->rix_port_id_action; 11653 pre_r = dev_flow->dv.port_id_action; 11654 if (flow_dv_translate_action_port_id(dev, sub_actions, 11655 &port_id, error)) 11656 return -rte_errno; 11657 port_id_resource.port_id = port_id; 11658 if (flow_dv_port_id_action_resource_register 11659 (dev, &port_id_resource, dev_flow, error)) 11660 return -rte_errno; 11661 sample_act->dr_port_id_action = 11662 dev_flow->dv.port_id_action->action; 11663 sample_idx->rix_port_id_action = 11664 dev_flow->handle->rix_port_id_action; 11665 sample_actions[sample_act->actions_num++] = 11666 sample_act->dr_port_id_action; 11667 /* Recover the port id resource after sample */ 11668 dev_flow->dv.port_id_action = pre_r; 11669 dev_flow->handle->rix_port_id_action = pre_rix; 11670 (*num_of_dest)++; 11671 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 11672 break; 11673 } 11674 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 11675 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 11676 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 11677 /* Save the encap resource before sample */ 11678 pre_rix = dev_flow->handle->dvh.rix_encap_decap; 11679 pre_r = dev_flow->dv.encap_decap; 11680 if (flow_dv_create_action_l2_encap(dev, sub_actions, 11681 dev_flow, 11682 attr->transfer, 11683 error)) 11684 return -rte_errno; 11685 sample_act->dr_encap_action = 11686 dev_flow->dv.encap_decap->action; 11687 sample_idx->rix_encap_decap = 11688 dev_flow->handle->dvh.rix_encap_decap; 11689 sample_actions[sample_act->actions_num++] = 11690 sample_act->dr_encap_action; 11691 /* Recover the encap resource after sample */ 11692 dev_flow->dv.encap_decap = pre_r; 11693 dev_flow->handle->dvh.rix_encap_decap = pre_rix; 11694 action_flags |= MLX5_FLOW_ACTION_ENCAP; 11695 break; 11696 default: 11697 return rte_flow_error_set(error, EINVAL, 11698 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 11699 NULL, 11700 "Not support for sampler action"); 11701 } 11702 } 11703 sample_act->action_flags = action_flags; 11704 res->ft_id = dev_flow->dv.group; 11705 if (attr->transfer) { 11706 union { 11707 uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)]; 11708 uint64_t set_action; 11709 } action_ctx = { .set_action = 0 }; 11710 11711 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 11712 MLX5_SET(set_action_in, action_ctx.action_in, action_type, 11713 MLX5_MODIFICATION_TYPE_SET); 11714 MLX5_SET(set_action_in, action_ctx.action_in, field, 11715 MLX5_MODI_META_REG_C_0); 11716 MLX5_SET(set_action_in, action_ctx.action_in, data, 11717 priv->vport_meta_tag); 11718 res->set_action = action_ctx.set_action; 11719 } else if (attr->ingress) { 11720 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 11721 } else { 11722 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 11723 } 11724 return 0; 11725 } 11726 11727 /** 11728 * Convert Sample action to DV specification. 11729 * 11730 * @param[in] dev 11731 * Pointer to rte_eth_dev structure. 11732 * @param[in, out] dev_flow 11733 * Pointer to the mlx5_flow. 11734 * @param[in] num_of_dest 11735 * The num of destination. 11736 * @param[in, out] res 11737 * Pointer to sample resource. 11738 * @param[in, out] mdest_res 11739 * Pointer to destination array resource. 11740 * @param[in] sample_actions 11741 * Pointer to sample path actions list. 11742 * @param[in] action_flags 11743 * Holds the actions detected until now. 11744 * @param[out] error 11745 * Pointer to the error structure. 11746 * 11747 * @return 11748 * 0 on success, a negative errno value otherwise and rte_errno is set. 11749 */ 11750 static int 11751 flow_dv_create_action_sample(struct rte_eth_dev *dev, 11752 struct mlx5_flow *dev_flow, 11753 uint32_t num_of_dest, 11754 struct mlx5_flow_dv_sample_resource *res, 11755 struct mlx5_flow_dv_dest_array_resource *mdest_res, 11756 void **sample_actions, 11757 uint64_t action_flags, 11758 struct rte_flow_error *error) 11759 { 11760 /* update normal path action resource into last index of array */ 11761 uint32_t dest_index = MLX5_MAX_DEST_NUM - 1; 11762 struct mlx5_flow_sub_actions_list *sample_act = 11763 &mdest_res->sample_act[dest_index]; 11764 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 11765 struct mlx5_flow_rss_desc *rss_desc; 11766 uint32_t normal_idx = 0; 11767 struct mlx5_hrxq *hrxq; 11768 uint32_t hrxq_idx; 11769 11770 MLX5_ASSERT(wks); 11771 rss_desc = &wks->rss_desc; 11772 if (num_of_dest > 1) { 11773 if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) { 11774 /* Handle QP action for mirroring */ 11775 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, 11776 rss_desc, &hrxq_idx); 11777 if (!hrxq) 11778 return rte_flow_error_set 11779 (error, rte_errno, 11780 RTE_FLOW_ERROR_TYPE_ACTION, 11781 NULL, 11782 "cannot create rx queue"); 11783 normal_idx++; 11784 mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx; 11785 sample_act->dr_queue_action = hrxq->action; 11786 if (action_flags & MLX5_FLOW_ACTION_MARK) 11787 dev_flow->handle->rix_hrxq = hrxq_idx; 11788 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 11789 } 11790 if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) { 11791 normal_idx++; 11792 mdest_res->sample_idx[dest_index].rix_encap_decap = 11793 dev_flow->handle->dvh.rix_encap_decap; 11794 sample_act->dr_encap_action = 11795 dev_flow->dv.encap_decap->action; 11796 dev_flow->handle->dvh.rix_encap_decap = 0; 11797 } 11798 if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) { 11799 normal_idx++; 11800 mdest_res->sample_idx[dest_index].rix_port_id_action = 11801 dev_flow->handle->rix_port_id_action; 11802 sample_act->dr_port_id_action = 11803 dev_flow->dv.port_id_action->action; 11804 dev_flow->handle->rix_port_id_action = 0; 11805 } 11806 if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) { 11807 normal_idx++; 11808 mdest_res->sample_idx[dest_index].rix_jump = 11809 dev_flow->handle->rix_jump; 11810 sample_act->dr_jump_action = 11811 dev_flow->dv.jump->action; 11812 dev_flow->handle->rix_jump = 0; 11813 } 11814 sample_act->actions_num = normal_idx; 11815 /* update sample action resource into first index of array */ 11816 mdest_res->ft_type = res->ft_type; 11817 memcpy(&mdest_res->sample_idx[0], &res->sample_idx, 11818 sizeof(struct mlx5_flow_sub_actions_idx)); 11819 memcpy(&mdest_res->sample_act[0], &res->sample_act, 11820 sizeof(struct mlx5_flow_sub_actions_list)); 11821 mdest_res->num_of_dest = num_of_dest; 11822 if (flow_dv_dest_array_resource_register(dev, mdest_res, 11823 dev_flow, error)) 11824 return rte_flow_error_set(error, EINVAL, 11825 RTE_FLOW_ERROR_TYPE_ACTION, 11826 NULL, "can't create sample " 11827 "action"); 11828 } else { 11829 res->sub_actions = sample_actions; 11830 if (flow_dv_sample_resource_register(dev, res, dev_flow, error)) 11831 return rte_flow_error_set(error, EINVAL, 11832 RTE_FLOW_ERROR_TYPE_ACTION, 11833 NULL, 11834 "can't create sample action"); 11835 } 11836 return 0; 11837 } 11838 11839 /** 11840 * Remove an ASO age action from age actions list. 11841 * 11842 * @param[in] dev 11843 * Pointer to the Ethernet device structure. 11844 * @param[in] age 11845 * Pointer to the aso age action handler. 11846 */ 11847 static void 11848 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev, 11849 struct mlx5_aso_age_action *age) 11850 { 11851 struct mlx5_age_info *age_info; 11852 struct mlx5_age_param *age_param = &age->age_params; 11853 struct mlx5_priv *priv = dev->data->dev_private; 11854 uint16_t expected = AGE_CANDIDATE; 11855 11856 age_info = GET_PORT_AGE_INFO(priv); 11857 if (!__atomic_compare_exchange_n(&age_param->state, &expected, 11858 AGE_FREE, false, __ATOMIC_RELAXED, 11859 __ATOMIC_RELAXED)) { 11860 /** 11861 * We need the lock even it is age timeout, 11862 * since age action may still in process. 11863 */ 11864 rte_spinlock_lock(&age_info->aged_sl); 11865 LIST_REMOVE(age, next); 11866 rte_spinlock_unlock(&age_info->aged_sl); 11867 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); 11868 } 11869 } 11870 11871 /** 11872 * Release an ASO age action. 11873 * 11874 * @param[in] dev 11875 * Pointer to the Ethernet device structure. 11876 * @param[in] age_idx 11877 * Index of ASO age action to release. 11878 * @param[in] flow 11879 * True if the release operation is during flow destroy operation. 11880 * False if the release operation is during action destroy operation. 11881 * 11882 * @return 11883 * 0 when age action was removed, otherwise the number of references. 11884 */ 11885 static int 11886 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx) 11887 { 11888 struct mlx5_priv *priv = dev->data->dev_private; 11889 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11890 struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx); 11891 uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED); 11892 11893 if (!ret) { 11894 flow_dv_aso_age_remove_from_age(dev, age); 11895 rte_spinlock_lock(&mng->free_sl); 11896 LIST_INSERT_HEAD(&mng->free, age, next); 11897 rte_spinlock_unlock(&mng->free_sl); 11898 } 11899 return ret; 11900 } 11901 11902 /** 11903 * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools. 11904 * 11905 * @param[in] dev 11906 * Pointer to the Ethernet device structure. 11907 * 11908 * @return 11909 * 0 on success, otherwise negative errno value and rte_errno is set. 11910 */ 11911 static int 11912 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev) 11913 { 11914 struct mlx5_priv *priv = dev->data->dev_private; 11915 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11916 void *old_pools = mng->pools; 11917 uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE; 11918 uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize; 11919 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 11920 11921 if (!pools) { 11922 rte_errno = ENOMEM; 11923 return -ENOMEM; 11924 } 11925 if (old_pools) { 11926 memcpy(pools, old_pools, 11927 mng->n * sizeof(struct mlx5_flow_counter_pool *)); 11928 mlx5_free(old_pools); 11929 } else { 11930 /* First ASO flow hit allocation - starting ASO data-path. */ 11931 int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh); 11932 11933 if (ret) { 11934 mlx5_free(pools); 11935 return ret; 11936 } 11937 } 11938 mng->n = resize; 11939 mng->pools = pools; 11940 return 0; 11941 } 11942 11943 /** 11944 * Create and initialize a new ASO aging pool. 11945 * 11946 * @param[in] dev 11947 * Pointer to the Ethernet device structure. 11948 * @param[out] age_free 11949 * Where to put the pointer of a new age action. 11950 * 11951 * @return 11952 * The age actions pool pointer and @p age_free is set on success, 11953 * NULL otherwise and rte_errno is set. 11954 */ 11955 static struct mlx5_aso_age_pool * 11956 flow_dv_age_pool_create(struct rte_eth_dev *dev, 11957 struct mlx5_aso_age_action **age_free) 11958 { 11959 struct mlx5_priv *priv = dev->data->dev_private; 11960 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 11961 struct mlx5_aso_age_pool *pool = NULL; 11962 struct mlx5_devx_obj *obj = NULL; 11963 uint32_t i; 11964 11965 obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx, 11966 priv->sh->cdev->pdn); 11967 if (!obj) { 11968 rte_errno = ENODATA; 11969 DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX."); 11970 return NULL; 11971 } 11972 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 11973 if (!pool) { 11974 claim_zero(mlx5_devx_cmd_destroy(obj)); 11975 rte_errno = ENOMEM; 11976 return NULL; 11977 } 11978 pool->flow_hit_aso_obj = obj; 11979 pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; 11980 rte_rwlock_write_lock(&mng->resize_rwl); 11981 pool->index = mng->next; 11982 /* Resize pools array if there is no room for the new pool in it. */ 11983 if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) { 11984 claim_zero(mlx5_devx_cmd_destroy(obj)); 11985 mlx5_free(pool); 11986 rte_rwlock_write_unlock(&mng->resize_rwl); 11987 return NULL; 11988 } 11989 mng->pools[pool->index] = pool; 11990 mng->next++; 11991 rte_rwlock_write_unlock(&mng->resize_rwl); 11992 /* Assign the first action in the new pool, the rest go to free list. */ 11993 *age_free = &pool->actions[0]; 11994 for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) { 11995 pool->actions[i].offset = i; 11996 LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next); 11997 } 11998 return pool; 11999 } 12000 12001 /** 12002 * Allocate a ASO aging bit. 12003 * 12004 * @param[in] dev 12005 * Pointer to the Ethernet device structure. 12006 * @param[out] error 12007 * Pointer to the error structure. 12008 * 12009 * @return 12010 * Index to ASO age action on success, 0 otherwise and rte_errno is set. 12011 */ 12012 static uint32_t 12013 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12014 { 12015 struct mlx5_priv *priv = dev->data->dev_private; 12016 const struct mlx5_aso_age_pool *pool; 12017 struct mlx5_aso_age_action *age_free = NULL; 12018 struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng; 12019 12020 MLX5_ASSERT(mng); 12021 /* Try to get the next free age action bit. */ 12022 rte_spinlock_lock(&mng->free_sl); 12023 age_free = LIST_FIRST(&mng->free); 12024 if (age_free) { 12025 LIST_REMOVE(age_free, next); 12026 } else if (!flow_dv_age_pool_create(dev, &age_free)) { 12027 rte_spinlock_unlock(&mng->free_sl); 12028 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12029 NULL, "failed to create ASO age pool"); 12030 return 0; /* 0 is an error. */ 12031 } 12032 rte_spinlock_unlock(&mng->free_sl); 12033 pool = container_of 12034 ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL]) 12035 (age_free - age_free->offset), const struct mlx5_aso_age_pool, 12036 actions); 12037 if (!age_free->dr_action) { 12038 int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0, 12039 error); 12040 12041 if (reg_c < 0) { 12042 rte_flow_error_set(error, rte_errno, 12043 RTE_FLOW_ERROR_TYPE_ACTION, 12044 NULL, "failed to get reg_c " 12045 "for ASO flow hit"); 12046 return 0; /* 0 is an error. */ 12047 } 12048 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO 12049 age_free->dr_action = mlx5_glue->dv_create_flow_action_aso 12050 (priv->sh->rx_domain, 12051 pool->flow_hit_aso_obj->obj, age_free->offset, 12052 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET, 12053 (reg_c - REG_C_0)); 12054 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ 12055 if (!age_free->dr_action) { 12056 rte_errno = errno; 12057 rte_spinlock_lock(&mng->free_sl); 12058 LIST_INSERT_HEAD(&mng->free, age_free, next); 12059 rte_spinlock_unlock(&mng->free_sl); 12060 rte_flow_error_set(error, rte_errno, 12061 RTE_FLOW_ERROR_TYPE_ACTION, 12062 NULL, "failed to create ASO " 12063 "flow hit action"); 12064 return 0; /* 0 is an error. */ 12065 } 12066 } 12067 __atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED); 12068 return pool->index | ((age_free->offset + 1) << 16); 12069 } 12070 12071 /** 12072 * Initialize flow ASO age parameters. 12073 * 12074 * @param[in] dev 12075 * Pointer to rte_eth_dev structure. 12076 * @param[in] age_idx 12077 * Index of ASO age action. 12078 * @param[in] context 12079 * Pointer to flow counter age context. 12080 * @param[in] timeout 12081 * Aging timeout in seconds. 12082 * 12083 */ 12084 static void 12085 flow_dv_aso_age_params_init(struct rte_eth_dev *dev, 12086 uint32_t age_idx, 12087 void *context, 12088 uint32_t timeout) 12089 { 12090 struct mlx5_aso_age_action *aso_age; 12091 12092 aso_age = flow_aso_age_get_by_idx(dev, age_idx); 12093 MLX5_ASSERT(aso_age); 12094 aso_age->age_params.context = context; 12095 aso_age->age_params.timeout = timeout; 12096 aso_age->age_params.port_id = dev->data->port_id; 12097 __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0, 12098 __ATOMIC_RELAXED); 12099 __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE, 12100 __ATOMIC_RELAXED); 12101 } 12102 12103 static void 12104 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask, 12105 const struct rte_flow_item_integrity *value, 12106 void *headers_m, void *headers_v) 12107 { 12108 if (mask->l4_ok) { 12109 /* RTE l4_ok filter aggregates hardware l4_ok and 12110 * l4_checksum_ok filters. 12111 * Positive RTE l4_ok match requires hardware match on both L4 12112 * hardware integrity bits. 12113 * For negative match, check hardware l4_checksum_ok bit only, 12114 * because hardware sets that bit to 0 for all packets 12115 * with bad L4. 12116 */ 12117 if (value->l4_ok) { 12118 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok, 1); 12119 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok, 1); 12120 } 12121 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1); 12122 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, 12123 !!value->l4_ok); 12124 } 12125 if (mask->l4_csum_ok) { 12126 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1); 12127 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, 12128 value->l4_csum_ok); 12129 } 12130 } 12131 12132 static void 12133 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask, 12134 const struct rte_flow_item_integrity *value, 12135 void *headers_m, void *headers_v, bool is_ipv4) 12136 { 12137 if (mask->l3_ok) { 12138 /* RTE l3_ok filter aggregates for IPv4 hardware l3_ok and 12139 * ipv4_csum_ok filters. 12140 * Positive RTE l3_ok match requires hardware match on both L3 12141 * hardware integrity bits. 12142 * For negative match, check hardware l3_csum_ok bit only, 12143 * because hardware sets that bit to 0 for all packets 12144 * with bad L3. 12145 */ 12146 if (is_ipv4) { 12147 if (value->l3_ok) { 12148 MLX5_SET(fte_match_set_lyr_2_4, headers_m, 12149 l3_ok, 1); 12150 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12151 l3_ok, 1); 12152 } 12153 MLX5_SET(fte_match_set_lyr_2_4, headers_m, 12154 ipv4_checksum_ok, 1); 12155 MLX5_SET(fte_match_set_lyr_2_4, headers_v, 12156 ipv4_checksum_ok, !!value->l3_ok); 12157 } else { 12158 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok, 1); 12159 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok, 12160 value->l3_ok); 12161 } 12162 } 12163 if (mask->ipv4_csum_ok) { 12164 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 1); 12165 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok, 12166 value->ipv4_csum_ok); 12167 } 12168 } 12169 12170 static void 12171 set_integrity_bits(void *headers_m, void *headers_v, 12172 const struct rte_flow_item *integrity_item, bool is_l3_ip4) 12173 { 12174 const struct rte_flow_item_integrity *spec = integrity_item->spec; 12175 const struct rte_flow_item_integrity *mask = integrity_item->mask; 12176 12177 /* Integrity bits validation cleared spec pointer */ 12178 MLX5_ASSERT(spec != NULL); 12179 if (!mask) 12180 mask = &rte_flow_item_integrity_mask; 12181 flow_dv_translate_integrity_l3(mask, spec, headers_m, headers_v, 12182 is_l3_ip4); 12183 flow_dv_translate_integrity_l4(mask, spec, headers_m, headers_v); 12184 } 12185 12186 static void 12187 flow_dv_translate_item_integrity_post(void *matcher, void *key, 12188 const 12189 struct rte_flow_item *integrity_items[2], 12190 uint64_t pattern_flags) 12191 { 12192 void *headers_m, *headers_v; 12193 bool is_l3_ip4; 12194 12195 if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) { 12196 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12197 inner_headers); 12198 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); 12199 is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) != 12200 0; 12201 set_integrity_bits(headers_m, headers_v, 12202 integrity_items[1], is_l3_ip4); 12203 } 12204 if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) { 12205 headers_m = MLX5_ADDR_OF(fte_match_param, matcher, 12206 outer_headers); 12207 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); 12208 is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) != 12209 0; 12210 set_integrity_bits(headers_m, headers_v, 12211 integrity_items[0], is_l3_ip4); 12212 } 12213 } 12214 12215 static void 12216 flow_dv_translate_item_integrity(const struct rte_flow_item *item, 12217 const struct rte_flow_item *integrity_items[2], 12218 uint64_t *last_item) 12219 { 12220 const struct rte_flow_item_integrity *spec = (typeof(spec))item->spec; 12221 12222 /* integrity bits validation cleared spec pointer */ 12223 MLX5_ASSERT(spec != NULL); 12224 if (spec->level > 1) { 12225 integrity_items[1] = item; 12226 *last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; 12227 } else { 12228 integrity_items[0] = item; 12229 *last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; 12230 } 12231 } 12232 12233 /** 12234 * Prepares DV flow counter with aging configuration. 12235 * Gets it by index when exists, creates a new one when doesn't. 12236 * 12237 * @param[in] dev 12238 * Pointer to rte_eth_dev structure. 12239 * @param[in] dev_flow 12240 * Pointer to the mlx5_flow. 12241 * @param[in, out] flow 12242 * Pointer to the sub flow. 12243 * @param[in] count 12244 * Pointer to the counter action configuration. 12245 * @param[in] age 12246 * Pointer to the aging action configuration. 12247 * @param[out] error 12248 * Pointer to the error structure. 12249 * 12250 * @return 12251 * Pointer to the counter, NULL otherwise. 12252 */ 12253 static struct mlx5_flow_counter * 12254 flow_dv_prepare_counter(struct rte_eth_dev *dev, 12255 struct mlx5_flow *dev_flow, 12256 struct rte_flow *flow, 12257 const struct rte_flow_action_count *count, 12258 const struct rte_flow_action_age *age, 12259 struct rte_flow_error *error) 12260 { 12261 if (!flow->counter) { 12262 flow->counter = flow_dv_translate_create_counter(dev, dev_flow, 12263 count, age); 12264 if (!flow->counter) { 12265 rte_flow_error_set(error, rte_errno, 12266 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12267 "cannot create counter object."); 12268 return NULL; 12269 } 12270 } 12271 return flow_dv_counter_get_by_idx(dev, flow->counter, NULL); 12272 } 12273 12274 /* 12275 * Release an ASO CT action by its own device. 12276 * 12277 * @param[in] dev 12278 * Pointer to the Ethernet device structure. 12279 * @param[in] idx 12280 * Index of ASO CT action to release. 12281 * 12282 * @return 12283 * 0 when CT action was removed, otherwise the number of references. 12284 */ 12285 static inline int 12286 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx) 12287 { 12288 struct mlx5_priv *priv = dev->data->dev_private; 12289 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12290 uint32_t ret; 12291 struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12292 enum mlx5_aso_ct_state state = 12293 __atomic_load_n(&ct->state, __ATOMIC_RELAXED); 12294 12295 /* Cannot release when CT is in the ASO SQ. */ 12296 if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY) 12297 return -1; 12298 ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED); 12299 if (!ret) { 12300 if (ct->dr_action_orig) { 12301 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12302 claim_zero(mlx5_glue->destroy_flow_action 12303 (ct->dr_action_orig)); 12304 #endif 12305 ct->dr_action_orig = NULL; 12306 } 12307 if (ct->dr_action_rply) { 12308 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12309 claim_zero(mlx5_glue->destroy_flow_action 12310 (ct->dr_action_rply)); 12311 #endif 12312 ct->dr_action_rply = NULL; 12313 } 12314 /* Clear the state to free, no need in 1st allocation. */ 12315 MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE); 12316 rte_spinlock_lock(&mng->ct_sl); 12317 LIST_INSERT_HEAD(&mng->free_cts, ct, next); 12318 rte_spinlock_unlock(&mng->ct_sl); 12319 } 12320 return (int)ret; 12321 } 12322 12323 static inline int 12324 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx, 12325 struct rte_flow_error *error) 12326 { 12327 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx); 12328 uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx); 12329 struct rte_eth_dev *owndev = &rte_eth_devices[owner]; 12330 int ret; 12331 12332 MLX5_ASSERT(owner < RTE_MAX_ETHPORTS); 12333 if (dev->data->dev_started != 1) 12334 return rte_flow_error_set(error, EAGAIN, 12335 RTE_FLOW_ERROR_TYPE_ACTION, 12336 NULL, 12337 "Indirect CT action cannot be destroyed when the port is stopped"); 12338 ret = flow_dv_aso_ct_dev_release(owndev, idx); 12339 if (ret < 0) 12340 return rte_flow_error_set(error, EAGAIN, 12341 RTE_FLOW_ERROR_TYPE_ACTION, 12342 NULL, 12343 "Current state prevents indirect CT action from being destroyed"); 12344 return ret; 12345 } 12346 12347 /* 12348 * Resize the ASO CT pools array by 64 pools. 12349 * 12350 * @param[in] dev 12351 * Pointer to the Ethernet device structure. 12352 * 12353 * @return 12354 * 0 on success, otherwise negative errno value and rte_errno is set. 12355 */ 12356 static int 12357 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev) 12358 { 12359 struct mlx5_priv *priv = dev->data->dev_private; 12360 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12361 void *old_pools = mng->pools; 12362 /* Magic number now, need a macro. */ 12363 uint32_t resize = mng->n + 64; 12364 uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize; 12365 void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); 12366 12367 if (!pools) { 12368 rte_errno = ENOMEM; 12369 return -rte_errno; 12370 } 12371 rte_rwlock_write_lock(&mng->resize_rwl); 12372 /* ASO SQ/QP was already initialized in the startup. */ 12373 if (old_pools) { 12374 /* Realloc could be an alternative choice. */ 12375 rte_memcpy(pools, old_pools, 12376 mng->n * sizeof(struct mlx5_aso_ct_pool *)); 12377 mlx5_free(old_pools); 12378 } 12379 mng->n = resize; 12380 mng->pools = pools; 12381 rte_rwlock_write_unlock(&mng->resize_rwl); 12382 return 0; 12383 } 12384 12385 /* 12386 * Create and initialize a new ASO CT pool. 12387 * 12388 * @param[in] dev 12389 * Pointer to the Ethernet device structure. 12390 * @param[out] ct_free 12391 * Where to put the pointer of a new CT action. 12392 * 12393 * @return 12394 * The CT actions pool pointer and @p ct_free is set on success, 12395 * NULL otherwise and rte_errno is set. 12396 */ 12397 static struct mlx5_aso_ct_pool * 12398 flow_dv_ct_pool_create(struct rte_eth_dev *dev, 12399 struct mlx5_aso_ct_action **ct_free) 12400 { 12401 struct mlx5_priv *priv = dev->data->dev_private; 12402 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12403 struct mlx5_aso_ct_pool *pool = NULL; 12404 struct mlx5_devx_obj *obj = NULL; 12405 uint32_t i; 12406 uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL); 12407 12408 obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx, 12409 priv->sh->cdev->pdn, 12410 log_obj_size); 12411 if (!obj) { 12412 rte_errno = ENODATA; 12413 DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); 12414 return NULL; 12415 } 12416 pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); 12417 if (!pool) { 12418 rte_errno = ENOMEM; 12419 claim_zero(mlx5_devx_cmd_destroy(obj)); 12420 return NULL; 12421 } 12422 pool->devx_obj = obj; 12423 pool->index = mng->next; 12424 /* Resize pools array if there is no room for the new pool in it. */ 12425 if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) { 12426 claim_zero(mlx5_devx_cmd_destroy(obj)); 12427 mlx5_free(pool); 12428 return NULL; 12429 } 12430 mng->pools[pool->index] = pool; 12431 mng->next++; 12432 /* Assign the first action in the new pool, the rest go to free list. */ 12433 *ct_free = &pool->actions[0]; 12434 /* Lock outside, the list operation is safe here. */ 12435 for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) { 12436 /* refcnt is 0 when allocating the memory. */ 12437 pool->actions[i].offset = i; 12438 LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next); 12439 } 12440 return pool; 12441 } 12442 12443 /* 12444 * Allocate a ASO CT action from free list. 12445 * 12446 * @param[in] dev 12447 * Pointer to the Ethernet device structure. 12448 * @param[out] error 12449 * Pointer to the error structure. 12450 * 12451 * @return 12452 * Index to ASO CT action on success, 0 otherwise and rte_errno is set. 12453 */ 12454 static uint32_t 12455 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error) 12456 { 12457 struct mlx5_priv *priv = dev->data->dev_private; 12458 struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng; 12459 struct mlx5_aso_ct_action *ct = NULL; 12460 struct mlx5_aso_ct_pool *pool; 12461 uint8_t reg_c; 12462 uint32_t ct_idx; 12463 12464 MLX5_ASSERT(mng); 12465 if (!priv->sh->devx) { 12466 rte_errno = ENOTSUP; 12467 return 0; 12468 } 12469 /* Get a free CT action, if no, a new pool will be created. */ 12470 rte_spinlock_lock(&mng->ct_sl); 12471 ct = LIST_FIRST(&mng->free_cts); 12472 if (ct) { 12473 LIST_REMOVE(ct, next); 12474 } else if (!flow_dv_ct_pool_create(dev, &ct)) { 12475 rte_spinlock_unlock(&mng->ct_sl); 12476 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, 12477 NULL, "failed to create ASO CT pool"); 12478 return 0; 12479 } 12480 rte_spinlock_unlock(&mng->ct_sl); 12481 pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); 12482 ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset); 12483 /* 0: inactive, 1: created, 2+: used by flows. */ 12484 __atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED); 12485 reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error); 12486 if (!ct->dr_action_orig) { 12487 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12488 ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso 12489 (priv->sh->rx_domain, pool->devx_obj->obj, 12490 ct->offset, 12491 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR, 12492 reg_c - REG_C_0); 12493 #else 12494 RTE_SET_USED(reg_c); 12495 #endif 12496 if (!ct->dr_action_orig) { 12497 flow_dv_aso_ct_dev_release(dev, ct_idx); 12498 rte_flow_error_set(error, rte_errno, 12499 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12500 "failed to create ASO CT action"); 12501 return 0; 12502 } 12503 } 12504 if (!ct->dr_action_rply) { 12505 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT 12506 ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso 12507 (priv->sh->rx_domain, pool->devx_obj->obj, 12508 ct->offset, 12509 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER, 12510 reg_c - REG_C_0); 12511 #endif 12512 if (!ct->dr_action_rply) { 12513 flow_dv_aso_ct_dev_release(dev, ct_idx); 12514 rte_flow_error_set(error, rte_errno, 12515 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12516 "failed to create ASO CT action"); 12517 return 0; 12518 } 12519 } 12520 return ct_idx; 12521 } 12522 12523 /* 12524 * Create a conntrack object with context and actions by using ASO mechanism. 12525 * 12526 * @param[in] dev 12527 * Pointer to rte_eth_dev structure. 12528 * @param[in] pro 12529 * Pointer to conntrack information profile. 12530 * @param[out] error 12531 * Pointer to the error structure. 12532 * 12533 * @return 12534 * Index to conntrack object on success, 0 otherwise. 12535 */ 12536 static uint32_t 12537 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, 12538 const struct rte_flow_action_conntrack *pro, 12539 struct rte_flow_error *error) 12540 { 12541 struct mlx5_priv *priv = dev->data->dev_private; 12542 struct mlx5_dev_ctx_shared *sh = priv->sh; 12543 struct mlx5_aso_ct_action *ct; 12544 uint32_t idx; 12545 12546 if (!sh->ct_aso_en) 12547 return rte_flow_error_set(error, ENOTSUP, 12548 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12549 "Connection is not supported"); 12550 idx = flow_dv_aso_ct_alloc(dev, error); 12551 if (!idx) 12552 return rte_flow_error_set(error, rte_errno, 12553 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12554 "Failed to allocate CT object"); 12555 ct = flow_aso_ct_get_by_dev_idx(dev, idx); 12556 if (mlx5_aso_ct_update_by_wqe(sh, ct, pro)) 12557 return rte_flow_error_set(error, EBUSY, 12558 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 12559 "Failed to update CT"); 12560 ct->is_original = !!pro->is_original_dir; 12561 ct->peer = pro->peer_port; 12562 return idx; 12563 } 12564 12565 /** 12566 * Fill the flow with DV spec, lock free 12567 * (mutex should be acquired by caller). 12568 * 12569 * @param[in] dev 12570 * Pointer to rte_eth_dev structure. 12571 * @param[in, out] dev_flow 12572 * Pointer to the sub flow. 12573 * @param[in] attr 12574 * Pointer to the flow attributes. 12575 * @param[in] items 12576 * Pointer to the list of items. 12577 * @param[in] actions 12578 * Pointer to the list of actions. 12579 * @param[out] error 12580 * Pointer to the error structure. 12581 * 12582 * @return 12583 * 0 on success, a negative errno value otherwise and rte_errno is set. 12584 */ 12585 static int 12586 flow_dv_translate(struct rte_eth_dev *dev, 12587 struct mlx5_flow *dev_flow, 12588 const struct rte_flow_attr *attr, 12589 const struct rte_flow_item items[], 12590 const struct rte_flow_action actions[], 12591 struct rte_flow_error *error) 12592 { 12593 struct mlx5_priv *priv = dev->data->dev_private; 12594 struct mlx5_dev_config *dev_conf = &priv->config; 12595 struct rte_flow *flow = dev_flow->flow; 12596 struct mlx5_flow_handle *handle = dev_flow->handle; 12597 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 12598 struct mlx5_flow_rss_desc *rss_desc; 12599 uint64_t item_flags = 0; 12600 uint64_t last_item = 0; 12601 uint64_t action_flags = 0; 12602 struct mlx5_flow_dv_matcher matcher = { 12603 .mask = { 12604 .size = sizeof(matcher.mask.buf), 12605 }, 12606 }; 12607 int actions_n = 0; 12608 bool actions_end = false; 12609 union { 12610 struct mlx5_flow_dv_modify_hdr_resource res; 12611 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 12612 sizeof(struct mlx5_modification_cmd) * 12613 (MLX5_MAX_MODIFY_NUM + 1)]; 12614 } mhdr_dummy; 12615 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 12616 const struct rte_flow_action_count *count = NULL; 12617 const struct rte_flow_action_age *non_shared_age = NULL; 12618 union flow_dv_attr flow_attr = { .attr = 0 }; 12619 uint32_t tag_be; 12620 union mlx5_flow_tbl_key tbl_key; 12621 uint32_t modify_action_position = UINT32_MAX; 12622 void *match_mask = matcher.mask.buf; 12623 void *match_value = dev_flow->dv.value.buf; 12624 uint8_t next_protocol = 0xff; 12625 struct rte_vlan_hdr vlan = { 0 }; 12626 struct mlx5_flow_dv_dest_array_resource mdest_res; 12627 struct mlx5_flow_dv_sample_resource sample_res; 12628 void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 12629 const struct rte_flow_action_sample *sample = NULL; 12630 struct mlx5_flow_sub_actions_list *sample_act; 12631 uint32_t sample_act_pos = UINT32_MAX; 12632 uint32_t age_act_pos = UINT32_MAX; 12633 uint32_t num_of_dest = 0; 12634 int tmp_actions_n = 0; 12635 uint32_t table; 12636 int ret = 0; 12637 const struct mlx5_flow_tunnel *tunnel = NULL; 12638 struct flow_grp_info grp_info = { 12639 .external = !!dev_flow->external, 12640 .transfer = !!attr->transfer, 12641 .fdb_def_rule = !!priv->fdb_def_rule, 12642 .skip_scale = dev_flow->skip_scale & 12643 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 12644 .std_tbl_fix = true, 12645 }; 12646 const struct rte_flow_item *integrity_items[2] = {NULL, NULL}; 12647 12648 if (!wks) 12649 return rte_flow_error_set(error, ENOMEM, 12650 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12651 NULL, 12652 "failed to push flow workspace"); 12653 rss_desc = &wks->rss_desc; 12654 memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource)); 12655 memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource)); 12656 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12657 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12658 /* update normal path action resource into last index of array */ 12659 sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1]; 12660 if (is_tunnel_offload_active(dev)) { 12661 if (dev_flow->tunnel) { 12662 RTE_VERIFY(dev_flow->tof_type == 12663 MLX5_TUNNEL_OFFLOAD_MISS_RULE); 12664 tunnel = dev_flow->tunnel; 12665 } else { 12666 tunnel = mlx5_get_tof(items, actions, 12667 &dev_flow->tof_type); 12668 dev_flow->tunnel = tunnel; 12669 } 12670 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate 12671 (dev, attr, tunnel, dev_flow->tof_type); 12672 } 12673 mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 12674 MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 12675 ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table, 12676 &grp_info, error); 12677 if (ret) 12678 return ret; 12679 dev_flow->dv.group = table; 12680 if (attr->transfer) 12681 mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 12682 /* number of actions must be set to 0 in case of dirty stack. */ 12683 mhdr_res->actions_num = 0; 12684 if (is_flow_tunnel_match_rule(dev_flow->tof_type)) { 12685 /* 12686 * do not add decap action if match rule drops packet 12687 * HW rejects rules with decap & drop 12688 * 12689 * if tunnel match rule was inserted before matching tunnel set 12690 * rule flow table used in the match rule must be registered. 12691 * current implementation handles that in the 12692 * flow_dv_match_register() at the function end. 12693 */ 12694 bool add_decap = true; 12695 const struct rte_flow_action *ptr = actions; 12696 12697 for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) { 12698 if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) { 12699 add_decap = false; 12700 break; 12701 } 12702 } 12703 if (add_decap) { 12704 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12705 attr->transfer, 12706 error)) 12707 return -rte_errno; 12708 dev_flow->dv.actions[actions_n++] = 12709 dev_flow->dv.encap_decap->action; 12710 action_flags |= MLX5_FLOW_ACTION_DECAP; 12711 } 12712 } 12713 for (; !actions_end ; actions++) { 12714 const struct rte_flow_action_queue *queue; 12715 const struct rte_flow_action_rss *rss; 12716 const struct rte_flow_action *action = actions; 12717 const uint8_t *rss_key; 12718 struct mlx5_flow_tbl_resource *tbl; 12719 struct mlx5_aso_age_action *age_act; 12720 struct mlx5_flow_counter *cnt_act; 12721 uint32_t port_id = 0; 12722 struct mlx5_flow_dv_port_id_action_resource port_id_resource; 12723 int action_type = actions->type; 12724 const struct rte_flow_action *found_action = NULL; 12725 uint32_t jump_group = 0; 12726 uint32_t owner_idx; 12727 struct mlx5_aso_ct_action *ct; 12728 12729 if (!mlx5_flow_os_action_supported(action_type)) 12730 return rte_flow_error_set(error, ENOTSUP, 12731 RTE_FLOW_ERROR_TYPE_ACTION, 12732 actions, 12733 "action not supported"); 12734 switch (action_type) { 12735 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET: 12736 action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET; 12737 break; 12738 case RTE_FLOW_ACTION_TYPE_VOID: 12739 break; 12740 case RTE_FLOW_ACTION_TYPE_PORT_ID: 12741 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 12742 if (flow_dv_translate_action_port_id(dev, action, 12743 &port_id, error)) 12744 return -rte_errno; 12745 port_id_resource.port_id = port_id; 12746 MLX5_ASSERT(!handle->rix_port_id_action); 12747 if (flow_dv_port_id_action_resource_register 12748 (dev, &port_id_resource, dev_flow, error)) 12749 return -rte_errno; 12750 dev_flow->dv.actions[actions_n++] = 12751 dev_flow->dv.port_id_action->action; 12752 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12753 dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID; 12754 sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID; 12755 num_of_dest++; 12756 break; 12757 case RTE_FLOW_ACTION_TYPE_FLAG: 12758 action_flags |= MLX5_FLOW_ACTION_FLAG; 12759 dev_flow->handle->mark = 1; 12760 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12761 struct rte_flow_action_mark mark = { 12762 .id = MLX5_FLOW_MARK_DEFAULT, 12763 }; 12764 12765 if (flow_dv_convert_action_mark(dev, &mark, 12766 mhdr_res, 12767 error)) 12768 return -rte_errno; 12769 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12770 break; 12771 } 12772 tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT); 12773 /* 12774 * Only one FLAG or MARK is supported per device flow 12775 * right now. So the pointer to the tag resource must be 12776 * zero before the register process. 12777 */ 12778 MLX5_ASSERT(!handle->dvh.rix_tag); 12779 if (flow_dv_tag_resource_register(dev, tag_be, 12780 dev_flow, error)) 12781 return -rte_errno; 12782 MLX5_ASSERT(dev_flow->dv.tag_resource); 12783 dev_flow->dv.actions[actions_n++] = 12784 dev_flow->dv.tag_resource->action; 12785 break; 12786 case RTE_FLOW_ACTION_TYPE_MARK: 12787 action_flags |= MLX5_FLOW_ACTION_MARK; 12788 dev_flow->handle->mark = 1; 12789 if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { 12790 const struct rte_flow_action_mark *mark = 12791 (const struct rte_flow_action_mark *) 12792 actions->conf; 12793 12794 if (flow_dv_convert_action_mark(dev, mark, 12795 mhdr_res, 12796 error)) 12797 return -rte_errno; 12798 action_flags |= MLX5_FLOW_ACTION_MARK_EXT; 12799 break; 12800 } 12801 /* Fall-through */ 12802 case MLX5_RTE_FLOW_ACTION_TYPE_MARK: 12803 /* Legacy (non-extensive) MARK action. */ 12804 tag_be = mlx5_flow_mark_set 12805 (((const struct rte_flow_action_mark *) 12806 (actions->conf))->id); 12807 MLX5_ASSERT(!handle->dvh.rix_tag); 12808 if (flow_dv_tag_resource_register(dev, tag_be, 12809 dev_flow, error)) 12810 return -rte_errno; 12811 MLX5_ASSERT(dev_flow->dv.tag_resource); 12812 dev_flow->dv.actions[actions_n++] = 12813 dev_flow->dv.tag_resource->action; 12814 break; 12815 case RTE_FLOW_ACTION_TYPE_SET_META: 12816 if (flow_dv_convert_action_set_meta 12817 (dev, mhdr_res, attr, 12818 (const struct rte_flow_action_set_meta *) 12819 actions->conf, error)) 12820 return -rte_errno; 12821 action_flags |= MLX5_FLOW_ACTION_SET_META; 12822 break; 12823 case RTE_FLOW_ACTION_TYPE_SET_TAG: 12824 if (flow_dv_convert_action_set_tag 12825 (dev, mhdr_res, 12826 (const struct rte_flow_action_set_tag *) 12827 actions->conf, error)) 12828 return -rte_errno; 12829 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 12830 break; 12831 case RTE_FLOW_ACTION_TYPE_DROP: 12832 action_flags |= MLX5_FLOW_ACTION_DROP; 12833 dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP; 12834 break; 12835 case RTE_FLOW_ACTION_TYPE_QUEUE: 12836 queue = actions->conf; 12837 rss_desc->queue_num = 1; 12838 rss_desc->queue[0] = queue->index; 12839 action_flags |= MLX5_FLOW_ACTION_QUEUE; 12840 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE; 12841 sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE; 12842 num_of_dest++; 12843 break; 12844 case RTE_FLOW_ACTION_TYPE_RSS: 12845 rss = actions->conf; 12846 memcpy(rss_desc->queue, rss->queue, 12847 rss->queue_num * sizeof(uint16_t)); 12848 rss_desc->queue_num = rss->queue_num; 12849 /* NULL RSS key indicates default RSS key. */ 12850 rss_key = !rss->key ? rss_hash_default_key : rss->key; 12851 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 12852 /* 12853 * rss->level and rss.types should be set in advance 12854 * when expanding items for RSS. 12855 */ 12856 action_flags |= MLX5_FLOW_ACTION_RSS; 12857 dev_flow->handle->fate_action = rss_desc->shared_rss ? 12858 MLX5_FLOW_FATE_SHARED_RSS : 12859 MLX5_FLOW_FATE_QUEUE; 12860 break; 12861 case MLX5_RTE_FLOW_ACTION_TYPE_AGE: 12862 owner_idx = (uint32_t)(uintptr_t)action->conf; 12863 age_act = flow_aso_age_get_by_idx(dev, owner_idx); 12864 if (flow->age == 0) { 12865 flow->age = owner_idx; 12866 __atomic_fetch_add(&age_act->refcnt, 1, 12867 __ATOMIC_RELAXED); 12868 } 12869 age_act_pos = actions_n++; 12870 action_flags |= MLX5_FLOW_ACTION_AGE; 12871 break; 12872 case RTE_FLOW_ACTION_TYPE_AGE: 12873 non_shared_age = action->conf; 12874 age_act_pos = actions_n++; 12875 action_flags |= MLX5_FLOW_ACTION_AGE; 12876 break; 12877 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: 12878 owner_idx = (uint32_t)(uintptr_t)action->conf; 12879 cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx, 12880 NULL); 12881 MLX5_ASSERT(cnt_act != NULL); 12882 /** 12883 * When creating meter drop flow in drop table, the 12884 * counter should not overwrite the rte flow counter. 12885 */ 12886 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 12887 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) { 12888 dev_flow->dv.actions[actions_n++] = 12889 cnt_act->action; 12890 } else { 12891 if (flow->counter == 0) { 12892 flow->counter = owner_idx; 12893 __atomic_fetch_add 12894 (&cnt_act->shared_info.refcnt, 12895 1, __ATOMIC_RELAXED); 12896 } 12897 /* Save information first, will apply later. */ 12898 action_flags |= MLX5_FLOW_ACTION_COUNT; 12899 } 12900 break; 12901 case RTE_FLOW_ACTION_TYPE_COUNT: 12902 if (!priv->sh->devx) { 12903 return rte_flow_error_set 12904 (error, ENOTSUP, 12905 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 12906 NULL, 12907 "count action not supported"); 12908 } 12909 /* Save information first, will apply later. */ 12910 count = action->conf; 12911 action_flags |= MLX5_FLOW_ACTION_COUNT; 12912 break; 12913 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: 12914 dev_flow->dv.actions[actions_n++] = 12915 priv->sh->pop_vlan_action; 12916 action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; 12917 break; 12918 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: 12919 if (!(action_flags & 12920 MLX5_FLOW_ACTION_OF_SET_VLAN_VID)) 12921 flow_dev_get_vlan_info_from_items(items, &vlan); 12922 vlan.eth_proto = rte_be_to_cpu_16 12923 ((((const struct rte_flow_action_of_push_vlan *) 12924 actions->conf)->ethertype)); 12925 found_action = mlx5_flow_find_action 12926 (actions + 1, 12927 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID); 12928 if (found_action) 12929 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12930 found_action = mlx5_flow_find_action 12931 (actions + 1, 12932 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP); 12933 if (found_action) 12934 mlx5_update_vlan_vid_pcp(found_action, &vlan); 12935 if (flow_dv_create_action_push_vlan 12936 (dev, attr, &vlan, dev_flow, error)) 12937 return -rte_errno; 12938 dev_flow->dv.actions[actions_n++] = 12939 dev_flow->dv.push_vlan_res->action; 12940 action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; 12941 break; 12942 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: 12943 /* of_vlan_push action handled this action */ 12944 MLX5_ASSERT(action_flags & 12945 MLX5_FLOW_ACTION_OF_PUSH_VLAN); 12946 break; 12947 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: 12948 if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) 12949 break; 12950 flow_dev_get_vlan_info_from_items(items, &vlan); 12951 mlx5_update_vlan_vid_pcp(actions, &vlan); 12952 /* If no VLAN push - this is a modify header action */ 12953 if (flow_dv_convert_action_modify_vlan_vid 12954 (mhdr_res, actions, error)) 12955 return -rte_errno; 12956 action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; 12957 break; 12958 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: 12959 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: 12960 if (flow_dv_create_action_l2_encap(dev, actions, 12961 dev_flow, 12962 attr->transfer, 12963 error)) 12964 return -rte_errno; 12965 dev_flow->dv.actions[actions_n++] = 12966 dev_flow->dv.encap_decap->action; 12967 action_flags |= MLX5_FLOW_ACTION_ENCAP; 12968 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 12969 sample_act->action_flags |= 12970 MLX5_FLOW_ACTION_ENCAP; 12971 break; 12972 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: 12973 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: 12974 if (flow_dv_create_action_l2_decap(dev, dev_flow, 12975 attr->transfer, 12976 error)) 12977 return -rte_errno; 12978 dev_flow->dv.actions[actions_n++] = 12979 dev_flow->dv.encap_decap->action; 12980 action_flags |= MLX5_FLOW_ACTION_DECAP; 12981 break; 12982 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: 12983 /* Handle encap with preceding decap. */ 12984 if (action_flags & MLX5_FLOW_ACTION_DECAP) { 12985 if (flow_dv_create_action_raw_encap 12986 (dev, actions, dev_flow, attr, error)) 12987 return -rte_errno; 12988 dev_flow->dv.actions[actions_n++] = 12989 dev_flow->dv.encap_decap->action; 12990 } else { 12991 /* Handle encap without preceding decap. */ 12992 if (flow_dv_create_action_l2_encap 12993 (dev, actions, dev_flow, attr->transfer, 12994 error)) 12995 return -rte_errno; 12996 dev_flow->dv.actions[actions_n++] = 12997 dev_flow->dv.encap_decap->action; 12998 } 12999 action_flags |= MLX5_FLOW_ACTION_ENCAP; 13000 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) 13001 sample_act->action_flags |= 13002 MLX5_FLOW_ACTION_ENCAP; 13003 break; 13004 case RTE_FLOW_ACTION_TYPE_RAW_DECAP: 13005 while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID) 13006 ; 13007 if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) { 13008 if (flow_dv_create_action_l2_decap 13009 (dev, dev_flow, attr->transfer, error)) 13010 return -rte_errno; 13011 dev_flow->dv.actions[actions_n++] = 13012 dev_flow->dv.encap_decap->action; 13013 } 13014 /* If decap is followed by encap, handle it at encap. */ 13015 action_flags |= MLX5_FLOW_ACTION_DECAP; 13016 break; 13017 case MLX5_RTE_FLOW_ACTION_TYPE_JUMP: 13018 dev_flow->dv.actions[actions_n++] = 13019 (void *)(uintptr_t)action->conf; 13020 action_flags |= MLX5_FLOW_ACTION_JUMP; 13021 break; 13022 case RTE_FLOW_ACTION_TYPE_JUMP: 13023 jump_group = ((const struct rte_flow_action_jump *) 13024 action->conf)->group; 13025 grp_info.std_tbl_fix = 0; 13026 if (dev_flow->skip_scale & 13027 (1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT)) 13028 grp_info.skip_scale = 1; 13029 else 13030 grp_info.skip_scale = 0; 13031 ret = mlx5_flow_group_to_table(dev, tunnel, 13032 jump_group, 13033 &table, 13034 &grp_info, error); 13035 if (ret) 13036 return ret; 13037 tbl = flow_dv_tbl_resource_get(dev, table, attr->egress, 13038 attr->transfer, 13039 !!dev_flow->external, 13040 tunnel, jump_group, 0, 13041 0, error); 13042 if (!tbl) 13043 return rte_flow_error_set 13044 (error, errno, 13045 RTE_FLOW_ERROR_TYPE_ACTION, 13046 NULL, 13047 "cannot create jump action."); 13048 if (flow_dv_jump_tbl_resource_register 13049 (dev, tbl, dev_flow, error)) { 13050 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 13051 return rte_flow_error_set 13052 (error, errno, 13053 RTE_FLOW_ERROR_TYPE_ACTION, 13054 NULL, 13055 "cannot create jump action."); 13056 } 13057 dev_flow->dv.actions[actions_n++] = 13058 dev_flow->dv.jump->action; 13059 action_flags |= MLX5_FLOW_ACTION_JUMP; 13060 dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP; 13061 sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP; 13062 num_of_dest++; 13063 break; 13064 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: 13065 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: 13066 if (flow_dv_convert_action_modify_mac 13067 (mhdr_res, actions, error)) 13068 return -rte_errno; 13069 action_flags |= actions->type == 13070 RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? 13071 MLX5_FLOW_ACTION_SET_MAC_SRC : 13072 MLX5_FLOW_ACTION_SET_MAC_DST; 13073 break; 13074 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: 13075 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: 13076 if (flow_dv_convert_action_modify_ipv4 13077 (mhdr_res, actions, error)) 13078 return -rte_errno; 13079 action_flags |= actions->type == 13080 RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? 13081 MLX5_FLOW_ACTION_SET_IPV4_SRC : 13082 MLX5_FLOW_ACTION_SET_IPV4_DST; 13083 break; 13084 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: 13085 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: 13086 if (flow_dv_convert_action_modify_ipv6 13087 (mhdr_res, actions, error)) 13088 return -rte_errno; 13089 action_flags |= actions->type == 13090 RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? 13091 MLX5_FLOW_ACTION_SET_IPV6_SRC : 13092 MLX5_FLOW_ACTION_SET_IPV6_DST; 13093 break; 13094 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: 13095 case RTE_FLOW_ACTION_TYPE_SET_TP_DST: 13096 if (flow_dv_convert_action_modify_tp 13097 (mhdr_res, actions, items, 13098 &flow_attr, dev_flow, !!(action_flags & 13099 MLX5_FLOW_ACTION_DECAP), error)) 13100 return -rte_errno; 13101 action_flags |= actions->type == 13102 RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? 13103 MLX5_FLOW_ACTION_SET_TP_SRC : 13104 MLX5_FLOW_ACTION_SET_TP_DST; 13105 break; 13106 case RTE_FLOW_ACTION_TYPE_DEC_TTL: 13107 if (flow_dv_convert_action_modify_dec_ttl 13108 (mhdr_res, items, &flow_attr, dev_flow, 13109 !!(action_flags & 13110 MLX5_FLOW_ACTION_DECAP), error)) 13111 return -rte_errno; 13112 action_flags |= MLX5_FLOW_ACTION_DEC_TTL; 13113 break; 13114 case RTE_FLOW_ACTION_TYPE_SET_TTL: 13115 if (flow_dv_convert_action_modify_ttl 13116 (mhdr_res, actions, items, &flow_attr, 13117 dev_flow, !!(action_flags & 13118 MLX5_FLOW_ACTION_DECAP), error)) 13119 return -rte_errno; 13120 action_flags |= MLX5_FLOW_ACTION_SET_TTL; 13121 break; 13122 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: 13123 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: 13124 if (flow_dv_convert_action_modify_tcp_seq 13125 (mhdr_res, actions, error)) 13126 return -rte_errno; 13127 action_flags |= actions->type == 13128 RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ? 13129 MLX5_FLOW_ACTION_INC_TCP_SEQ : 13130 MLX5_FLOW_ACTION_DEC_TCP_SEQ; 13131 break; 13132 13133 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: 13134 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: 13135 if (flow_dv_convert_action_modify_tcp_ack 13136 (mhdr_res, actions, error)) 13137 return -rte_errno; 13138 action_flags |= actions->type == 13139 RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ? 13140 MLX5_FLOW_ACTION_INC_TCP_ACK : 13141 MLX5_FLOW_ACTION_DEC_TCP_ACK; 13142 break; 13143 case MLX5_RTE_FLOW_ACTION_TYPE_TAG: 13144 if (flow_dv_convert_action_set_reg 13145 (mhdr_res, actions, error)) 13146 return -rte_errno; 13147 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13148 break; 13149 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG: 13150 if (flow_dv_convert_action_copy_mreg 13151 (dev, mhdr_res, actions, error)) 13152 return -rte_errno; 13153 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 13154 break; 13155 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS: 13156 action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS; 13157 dev_flow->handle->fate_action = 13158 MLX5_FLOW_FATE_DEFAULT_MISS; 13159 break; 13160 case RTE_FLOW_ACTION_TYPE_METER: 13161 if (!wks->fm) 13162 return rte_flow_error_set(error, rte_errno, 13163 RTE_FLOW_ERROR_TYPE_ACTION, 13164 NULL, "Failed to get meter in flow."); 13165 /* Set the meter action. */ 13166 dev_flow->dv.actions[actions_n++] = 13167 wks->fm->meter_action; 13168 action_flags |= MLX5_FLOW_ACTION_METER; 13169 break; 13170 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: 13171 if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res, 13172 actions, error)) 13173 return -rte_errno; 13174 action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP; 13175 break; 13176 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: 13177 if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res, 13178 actions, error)) 13179 return -rte_errno; 13180 action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP; 13181 break; 13182 case RTE_FLOW_ACTION_TYPE_SAMPLE: 13183 sample_act_pos = actions_n; 13184 sample = (const struct rte_flow_action_sample *) 13185 action->conf; 13186 actions_n++; 13187 action_flags |= MLX5_FLOW_ACTION_SAMPLE; 13188 /* put encap action into group if work with port id */ 13189 if ((action_flags & MLX5_FLOW_ACTION_ENCAP) && 13190 (action_flags & MLX5_FLOW_ACTION_PORT_ID)) 13191 sample_act->action_flags |= 13192 MLX5_FLOW_ACTION_ENCAP; 13193 break; 13194 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: 13195 if (flow_dv_convert_action_modify_field 13196 (dev, mhdr_res, actions, attr, error)) 13197 return -rte_errno; 13198 action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; 13199 break; 13200 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 13201 owner_idx = (uint32_t)(uintptr_t)action->conf; 13202 ct = flow_aso_ct_get_by_idx(dev, owner_idx); 13203 if (!ct) 13204 return rte_flow_error_set(error, EINVAL, 13205 RTE_FLOW_ERROR_TYPE_ACTION, 13206 NULL, 13207 "Failed to get CT object."); 13208 if (mlx5_aso_ct_available(priv->sh, ct)) 13209 return rte_flow_error_set(error, rte_errno, 13210 RTE_FLOW_ERROR_TYPE_ACTION, 13211 NULL, 13212 "CT is unavailable."); 13213 if (ct->is_original) 13214 dev_flow->dv.actions[actions_n] = 13215 ct->dr_action_orig; 13216 else 13217 dev_flow->dv.actions[actions_n] = 13218 ct->dr_action_rply; 13219 if (flow->ct == 0) { 13220 flow->indirect_type = 13221 MLX5_INDIRECT_ACTION_TYPE_CT; 13222 flow->ct = owner_idx; 13223 __atomic_fetch_add(&ct->refcnt, 1, 13224 __ATOMIC_RELAXED); 13225 } 13226 actions_n++; 13227 action_flags |= MLX5_FLOW_ACTION_CT; 13228 break; 13229 case RTE_FLOW_ACTION_TYPE_END: 13230 actions_end = true; 13231 if (mhdr_res->actions_num) { 13232 /* create modify action if needed. */ 13233 if (flow_dv_modify_hdr_resource_register 13234 (dev, mhdr_res, dev_flow, error)) 13235 return -rte_errno; 13236 dev_flow->dv.actions[modify_action_position] = 13237 handle->dvh.modify_hdr->action; 13238 } 13239 /* 13240 * Handle AGE and COUNT action by single HW counter 13241 * when they are not shared. 13242 */ 13243 if (action_flags & MLX5_FLOW_ACTION_AGE) { 13244 if ((non_shared_age && count) || 13245 !(priv->sh->flow_hit_aso_en && 13246 (attr->group || attr->transfer))) { 13247 /* Creates age by counters. */ 13248 cnt_act = flow_dv_prepare_counter 13249 (dev, dev_flow, 13250 flow, count, 13251 non_shared_age, 13252 error); 13253 if (!cnt_act) 13254 return -rte_errno; 13255 dev_flow->dv.actions[age_act_pos] = 13256 cnt_act->action; 13257 break; 13258 } 13259 if (!flow->age && non_shared_age) { 13260 flow->age = flow_dv_aso_age_alloc 13261 (dev, error); 13262 if (!flow->age) 13263 return -rte_errno; 13264 flow_dv_aso_age_params_init 13265 (dev, flow->age, 13266 non_shared_age->context ? 13267 non_shared_age->context : 13268 (void *)(uintptr_t) 13269 (dev_flow->flow_idx), 13270 non_shared_age->timeout); 13271 } 13272 age_act = flow_aso_age_get_by_idx(dev, 13273 flow->age); 13274 dev_flow->dv.actions[age_act_pos] = 13275 age_act->dr_action; 13276 } 13277 if (action_flags & MLX5_FLOW_ACTION_COUNT) { 13278 /* 13279 * Create one count action, to be used 13280 * by all sub-flows. 13281 */ 13282 cnt_act = flow_dv_prepare_counter(dev, dev_flow, 13283 flow, count, 13284 NULL, error); 13285 if (!cnt_act) 13286 return -rte_errno; 13287 dev_flow->dv.actions[actions_n++] = 13288 cnt_act->action; 13289 } 13290 default: 13291 break; 13292 } 13293 if (mhdr_res->actions_num && 13294 modify_action_position == UINT32_MAX) 13295 modify_action_position = actions_n++; 13296 } 13297 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { 13298 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); 13299 int item_type = items->type; 13300 13301 if (!mlx5_flow_os_item_supported(item_type)) 13302 return rte_flow_error_set(error, ENOTSUP, 13303 RTE_FLOW_ERROR_TYPE_ITEM, 13304 NULL, "item not supported"); 13305 switch (item_type) { 13306 case RTE_FLOW_ITEM_TYPE_PORT_ID: 13307 flow_dv_translate_item_port_id 13308 (dev, match_mask, match_value, items, attr); 13309 last_item = MLX5_FLOW_ITEM_PORT_ID; 13310 break; 13311 case RTE_FLOW_ITEM_TYPE_ETH: 13312 flow_dv_translate_item_eth(match_mask, match_value, 13313 items, tunnel, 13314 dev_flow->dv.group); 13315 matcher.priority = action_flags & 13316 MLX5_FLOW_ACTION_DEFAULT_MISS && 13317 !dev_flow->external ? 13318 MLX5_PRIORITY_MAP_L3 : 13319 MLX5_PRIORITY_MAP_L2; 13320 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : 13321 MLX5_FLOW_LAYER_OUTER_L2; 13322 break; 13323 case RTE_FLOW_ITEM_TYPE_VLAN: 13324 flow_dv_translate_item_vlan(dev_flow, 13325 match_mask, match_value, 13326 items, tunnel, 13327 dev_flow->dv.group); 13328 matcher.priority = MLX5_PRIORITY_MAP_L2; 13329 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | 13330 MLX5_FLOW_LAYER_INNER_VLAN) : 13331 (MLX5_FLOW_LAYER_OUTER_L2 | 13332 MLX5_FLOW_LAYER_OUTER_VLAN); 13333 break; 13334 case RTE_FLOW_ITEM_TYPE_IPV4: 13335 mlx5_flow_tunnel_ip_check(items, next_protocol, 13336 &item_flags, &tunnel); 13337 flow_dv_translate_item_ipv4(match_mask, match_value, 13338 items, tunnel, 13339 dev_flow->dv.group); 13340 matcher.priority = MLX5_PRIORITY_MAP_L3; 13341 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : 13342 MLX5_FLOW_LAYER_OUTER_L3_IPV4; 13343 if (items->mask != NULL && 13344 ((const struct rte_flow_item_ipv4 *) 13345 items->mask)->hdr.next_proto_id) { 13346 next_protocol = 13347 ((const struct rte_flow_item_ipv4 *) 13348 (items->spec))->hdr.next_proto_id; 13349 next_protocol &= 13350 ((const struct rte_flow_item_ipv4 *) 13351 (items->mask))->hdr.next_proto_id; 13352 } else { 13353 /* Reset for inner layer. */ 13354 next_protocol = 0xff; 13355 } 13356 break; 13357 case RTE_FLOW_ITEM_TYPE_IPV6: 13358 mlx5_flow_tunnel_ip_check(items, next_protocol, 13359 &item_flags, &tunnel); 13360 flow_dv_translate_item_ipv6(match_mask, match_value, 13361 items, tunnel, 13362 dev_flow->dv.group); 13363 matcher.priority = MLX5_PRIORITY_MAP_L3; 13364 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : 13365 MLX5_FLOW_LAYER_OUTER_L3_IPV6; 13366 if (items->mask != NULL && 13367 ((const struct rte_flow_item_ipv6 *) 13368 items->mask)->hdr.proto) { 13369 next_protocol = 13370 ((const struct rte_flow_item_ipv6 *) 13371 items->spec)->hdr.proto; 13372 next_protocol &= 13373 ((const struct rte_flow_item_ipv6 *) 13374 items->mask)->hdr.proto; 13375 } else { 13376 /* Reset for inner layer. */ 13377 next_protocol = 0xff; 13378 } 13379 break; 13380 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: 13381 flow_dv_translate_item_ipv6_frag_ext(match_mask, 13382 match_value, 13383 items, tunnel); 13384 last_item = tunnel ? 13385 MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT : 13386 MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT; 13387 if (items->mask != NULL && 13388 ((const struct rte_flow_item_ipv6_frag_ext *) 13389 items->mask)->hdr.next_header) { 13390 next_protocol = 13391 ((const struct rte_flow_item_ipv6_frag_ext *) 13392 items->spec)->hdr.next_header; 13393 next_protocol &= 13394 ((const struct rte_flow_item_ipv6_frag_ext *) 13395 items->mask)->hdr.next_header; 13396 } else { 13397 /* Reset for inner layer. */ 13398 next_protocol = 0xff; 13399 } 13400 break; 13401 case RTE_FLOW_ITEM_TYPE_TCP: 13402 flow_dv_translate_item_tcp(match_mask, match_value, 13403 items, tunnel); 13404 matcher.priority = MLX5_PRIORITY_MAP_L4; 13405 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : 13406 MLX5_FLOW_LAYER_OUTER_L4_TCP; 13407 break; 13408 case RTE_FLOW_ITEM_TYPE_UDP: 13409 flow_dv_translate_item_udp(match_mask, match_value, 13410 items, tunnel); 13411 matcher.priority = MLX5_PRIORITY_MAP_L4; 13412 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : 13413 MLX5_FLOW_LAYER_OUTER_L4_UDP; 13414 break; 13415 case RTE_FLOW_ITEM_TYPE_GRE: 13416 flow_dv_translate_item_gre(match_mask, match_value, 13417 items, tunnel); 13418 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13419 last_item = MLX5_FLOW_LAYER_GRE; 13420 break; 13421 case RTE_FLOW_ITEM_TYPE_GRE_KEY: 13422 flow_dv_translate_item_gre_key(match_mask, 13423 match_value, items); 13424 last_item = MLX5_FLOW_LAYER_GRE_KEY; 13425 break; 13426 case RTE_FLOW_ITEM_TYPE_NVGRE: 13427 flow_dv_translate_item_nvgre(match_mask, match_value, 13428 items, tunnel); 13429 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13430 last_item = MLX5_FLOW_LAYER_GRE; 13431 break; 13432 case RTE_FLOW_ITEM_TYPE_VXLAN: 13433 flow_dv_translate_item_vxlan(dev, attr, 13434 match_mask, match_value, 13435 items, tunnel); 13436 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13437 last_item = MLX5_FLOW_LAYER_VXLAN; 13438 break; 13439 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 13440 flow_dv_translate_item_vxlan_gpe(match_mask, 13441 match_value, items, 13442 tunnel); 13443 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13444 last_item = MLX5_FLOW_LAYER_VXLAN_GPE; 13445 break; 13446 case RTE_FLOW_ITEM_TYPE_GENEVE: 13447 flow_dv_translate_item_geneve(match_mask, match_value, 13448 items, tunnel); 13449 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13450 last_item = MLX5_FLOW_LAYER_GENEVE; 13451 break; 13452 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: 13453 ret = flow_dv_translate_item_geneve_opt(dev, match_mask, 13454 match_value, 13455 items, error); 13456 if (ret) 13457 return rte_flow_error_set(error, -ret, 13458 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13459 "cannot create GENEVE TLV option"); 13460 flow->geneve_tlv_option = 1; 13461 last_item = MLX5_FLOW_LAYER_GENEVE_OPT; 13462 break; 13463 case RTE_FLOW_ITEM_TYPE_MPLS: 13464 flow_dv_translate_item_mpls(match_mask, match_value, 13465 items, last_item, tunnel); 13466 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13467 last_item = MLX5_FLOW_LAYER_MPLS; 13468 break; 13469 case RTE_FLOW_ITEM_TYPE_MARK: 13470 flow_dv_translate_item_mark(dev, match_mask, 13471 match_value, items); 13472 last_item = MLX5_FLOW_ITEM_MARK; 13473 break; 13474 case RTE_FLOW_ITEM_TYPE_META: 13475 flow_dv_translate_item_meta(dev, match_mask, 13476 match_value, attr, items); 13477 last_item = MLX5_FLOW_ITEM_METADATA; 13478 break; 13479 case RTE_FLOW_ITEM_TYPE_ICMP: 13480 flow_dv_translate_item_icmp(match_mask, match_value, 13481 items, tunnel); 13482 last_item = MLX5_FLOW_LAYER_ICMP; 13483 break; 13484 case RTE_FLOW_ITEM_TYPE_ICMP6: 13485 flow_dv_translate_item_icmp6(match_mask, match_value, 13486 items, tunnel); 13487 last_item = MLX5_FLOW_LAYER_ICMP6; 13488 break; 13489 case RTE_FLOW_ITEM_TYPE_TAG: 13490 flow_dv_translate_item_tag(dev, match_mask, 13491 match_value, items); 13492 last_item = MLX5_FLOW_ITEM_TAG; 13493 break; 13494 case MLX5_RTE_FLOW_ITEM_TYPE_TAG: 13495 flow_dv_translate_mlx5_item_tag(dev, match_mask, 13496 match_value, items); 13497 last_item = MLX5_FLOW_ITEM_TAG; 13498 break; 13499 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: 13500 flow_dv_translate_item_tx_queue(dev, match_mask, 13501 match_value, 13502 items); 13503 last_item = MLX5_FLOW_ITEM_TX_QUEUE; 13504 break; 13505 case RTE_FLOW_ITEM_TYPE_GTP: 13506 flow_dv_translate_item_gtp(match_mask, match_value, 13507 items, tunnel); 13508 matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc); 13509 last_item = MLX5_FLOW_LAYER_GTP; 13510 break; 13511 case RTE_FLOW_ITEM_TYPE_GTP_PSC: 13512 ret = flow_dv_translate_item_gtp_psc(match_mask, 13513 match_value, 13514 items); 13515 if (ret) 13516 return rte_flow_error_set(error, -ret, 13517 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 13518 "cannot create GTP PSC item"); 13519 last_item = MLX5_FLOW_LAYER_GTP_PSC; 13520 break; 13521 case RTE_FLOW_ITEM_TYPE_ECPRI: 13522 if (!mlx5_flex_parser_ecpri_exist(dev)) { 13523 /* Create it only the first time to be used. */ 13524 ret = mlx5_flex_parser_ecpri_alloc(dev); 13525 if (ret) 13526 return rte_flow_error_set 13527 (error, -ret, 13528 RTE_FLOW_ERROR_TYPE_ITEM, 13529 NULL, 13530 "cannot create eCPRI parser"); 13531 } 13532 flow_dv_translate_item_ecpri(dev, match_mask, 13533 match_value, items, 13534 last_item); 13535 /* No other protocol should follow eCPRI layer. */ 13536 last_item = MLX5_FLOW_LAYER_ECPRI; 13537 break; 13538 case RTE_FLOW_ITEM_TYPE_INTEGRITY: 13539 flow_dv_translate_item_integrity(items, integrity_items, 13540 &last_item); 13541 break; 13542 case RTE_FLOW_ITEM_TYPE_CONNTRACK: 13543 flow_dv_translate_item_aso_ct(dev, match_mask, 13544 match_value, items); 13545 break; 13546 case RTE_FLOW_ITEM_TYPE_FLEX: 13547 flow_dv_translate_item_flex(dev, match_mask, 13548 match_value, items, 13549 dev_flow, tunnel != 0); 13550 last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX : 13551 MLX5_FLOW_ITEM_OUTER_FLEX; 13552 break; 13553 default: 13554 break; 13555 } 13556 item_flags |= last_item; 13557 } 13558 /* 13559 * When E-Switch mode is enabled, we have two cases where we need to 13560 * set the source port manually. 13561 * The first one, is in case of Nic steering rule, and the second is 13562 * E-Switch rule where no port_id item was found. In both cases 13563 * the source port is set according the current port in use. 13564 */ 13565 if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) && 13566 (priv->representor || priv->master)) { 13567 if (flow_dv_translate_item_port_id(dev, match_mask, 13568 match_value, NULL, attr)) 13569 return -rte_errno; 13570 } 13571 if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) { 13572 flow_dv_translate_item_integrity_post(match_mask, match_value, 13573 integrity_items, 13574 item_flags); 13575 } 13576 #ifdef RTE_LIBRTE_MLX5_DEBUG 13577 MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf, 13578 dev_flow->dv.value.buf)); 13579 #endif 13580 /* 13581 * Layers may be already initialized from prefix flow if this dev_flow 13582 * is the suffix flow. 13583 */ 13584 handle->layers |= item_flags; 13585 if (action_flags & MLX5_FLOW_ACTION_RSS) 13586 flow_dv_hashfields_set(dev_flow, rss_desc); 13587 /* If has RSS action in the sample action, the Sample/Mirror resource 13588 * should be registered after the hash filed be update. 13589 */ 13590 if (action_flags & MLX5_FLOW_ACTION_SAMPLE) { 13591 ret = flow_dv_translate_action_sample(dev, 13592 sample, 13593 dev_flow, attr, 13594 &num_of_dest, 13595 sample_actions, 13596 &sample_res, 13597 error); 13598 if (ret < 0) 13599 return ret; 13600 ret = flow_dv_create_action_sample(dev, 13601 dev_flow, 13602 num_of_dest, 13603 &sample_res, 13604 &mdest_res, 13605 sample_actions, 13606 action_flags, 13607 error); 13608 if (ret < 0) 13609 return rte_flow_error_set 13610 (error, rte_errno, 13611 RTE_FLOW_ERROR_TYPE_ACTION, 13612 NULL, 13613 "cannot create sample action"); 13614 if (num_of_dest > 1) { 13615 dev_flow->dv.actions[sample_act_pos] = 13616 dev_flow->dv.dest_array_res->action; 13617 } else { 13618 dev_flow->dv.actions[sample_act_pos] = 13619 dev_flow->dv.sample_res->verbs_action; 13620 } 13621 } 13622 /* 13623 * For multiple destination (sample action with ratio=1), the encap 13624 * action and port id action will be combined into group action. 13625 * So need remove the original these actions in the flow and only 13626 * use the sample action instead of. 13627 */ 13628 if (num_of_dest > 1 && 13629 (sample_act->dr_port_id_action || sample_act->dr_jump_action)) { 13630 int i; 13631 void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; 13632 13633 for (i = 0; i < actions_n; i++) { 13634 if ((sample_act->dr_encap_action && 13635 sample_act->dr_encap_action == 13636 dev_flow->dv.actions[i]) || 13637 (sample_act->dr_port_id_action && 13638 sample_act->dr_port_id_action == 13639 dev_flow->dv.actions[i]) || 13640 (sample_act->dr_jump_action && 13641 sample_act->dr_jump_action == 13642 dev_flow->dv.actions[i])) 13643 continue; 13644 temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i]; 13645 } 13646 memcpy((void *)dev_flow->dv.actions, 13647 (void *)temp_actions, 13648 tmp_actions_n * sizeof(void *)); 13649 actions_n = tmp_actions_n; 13650 } 13651 dev_flow->dv.actions_n = actions_n; 13652 dev_flow->act_flags = action_flags; 13653 if (wks->skip_matcher_reg) 13654 return 0; 13655 /* Register matcher. */ 13656 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 13657 matcher.mask.size); 13658 matcher.priority = mlx5_get_matcher_priority(dev, attr, 13659 matcher.priority, 13660 dev_flow->external); 13661 /** 13662 * When creating meter drop flow in drop table, using original 13663 * 5-tuple match, the matcher priority should be lower than 13664 * mtr_id matcher. 13665 */ 13666 if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && 13667 dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP && 13668 matcher.priority <= MLX5_REG_BITS) 13669 matcher.priority += MLX5_REG_BITS; 13670 /* reserved field no needs to be set to 0 here. */ 13671 tbl_key.is_fdb = attr->transfer; 13672 tbl_key.is_egress = attr->egress; 13673 tbl_key.level = dev_flow->dv.group; 13674 tbl_key.id = dev_flow->dv.table_id; 13675 if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow, 13676 tunnel, attr->group, error)) 13677 return -rte_errno; 13678 return 0; 13679 } 13680 13681 /** 13682 * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13683 * and tunnel. 13684 * 13685 * @param[in, out] action 13686 * Shred RSS action holding hash RX queue objects. 13687 * @param[in] hash_fields 13688 * Defines combination of packet fields to participate in RX hash. 13689 * @param[in] tunnel 13690 * Tunnel type 13691 * @param[in] hrxq_idx 13692 * Hash RX queue index to set. 13693 * 13694 * @return 13695 * 0 on success, otherwise negative errno value. 13696 */ 13697 static int 13698 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action, 13699 const uint64_t hash_fields, 13700 uint32_t hrxq_idx) 13701 { 13702 uint32_t *hrxqs = action->hrxq; 13703 13704 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13705 case MLX5_RSS_HASH_IPV4: 13706 /* fall-through. */ 13707 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13708 /* fall-through. */ 13709 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13710 hrxqs[0] = hrxq_idx; 13711 return 0; 13712 case MLX5_RSS_HASH_IPV4_TCP: 13713 /* fall-through. */ 13714 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13715 /* fall-through. */ 13716 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13717 hrxqs[1] = hrxq_idx; 13718 return 0; 13719 case MLX5_RSS_HASH_IPV4_UDP: 13720 /* fall-through. */ 13721 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13722 /* fall-through. */ 13723 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13724 hrxqs[2] = hrxq_idx; 13725 return 0; 13726 case MLX5_RSS_HASH_IPV6: 13727 /* fall-through. */ 13728 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13729 /* fall-through. */ 13730 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13731 hrxqs[3] = hrxq_idx; 13732 return 0; 13733 case MLX5_RSS_HASH_IPV6_TCP: 13734 /* fall-through. */ 13735 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13736 /* fall-through. */ 13737 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13738 hrxqs[4] = hrxq_idx; 13739 return 0; 13740 case MLX5_RSS_HASH_IPV6_UDP: 13741 /* fall-through. */ 13742 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13743 /* fall-through. */ 13744 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13745 hrxqs[5] = hrxq_idx; 13746 return 0; 13747 case MLX5_RSS_HASH_NONE: 13748 hrxqs[6] = hrxq_idx; 13749 return 0; 13750 default: 13751 return -1; 13752 } 13753 } 13754 13755 /** 13756 * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields) 13757 * and tunnel. 13758 * 13759 * @param[in] dev 13760 * Pointer to the Ethernet device structure. 13761 * @param[in] idx 13762 * Shared RSS action ID holding hash RX queue objects. 13763 * @param[in] hash_fields 13764 * Defines combination of packet fields to participate in RX hash. 13765 * @param[in] tunnel 13766 * Tunnel type 13767 * 13768 * @return 13769 * Valid hash RX queue index, otherwise 0. 13770 */ 13771 static uint32_t 13772 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx, 13773 const uint64_t hash_fields) 13774 { 13775 struct mlx5_priv *priv = dev->data->dev_private; 13776 struct mlx5_shared_action_rss *shared_rss = 13777 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 13778 const uint32_t *hrxqs = shared_rss->hrxq; 13779 13780 switch (hash_fields & ~IBV_RX_HASH_INNER) { 13781 case MLX5_RSS_HASH_IPV4: 13782 /* fall-through. */ 13783 case MLX5_RSS_HASH_IPV4_DST_ONLY: 13784 /* fall-through. */ 13785 case MLX5_RSS_HASH_IPV4_SRC_ONLY: 13786 return hrxqs[0]; 13787 case MLX5_RSS_HASH_IPV4_TCP: 13788 /* fall-through. */ 13789 case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY: 13790 /* fall-through. */ 13791 case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY: 13792 return hrxqs[1]; 13793 case MLX5_RSS_HASH_IPV4_UDP: 13794 /* fall-through. */ 13795 case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY: 13796 /* fall-through. */ 13797 case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY: 13798 return hrxqs[2]; 13799 case MLX5_RSS_HASH_IPV6: 13800 /* fall-through. */ 13801 case MLX5_RSS_HASH_IPV6_DST_ONLY: 13802 /* fall-through. */ 13803 case MLX5_RSS_HASH_IPV6_SRC_ONLY: 13804 return hrxqs[3]; 13805 case MLX5_RSS_HASH_IPV6_TCP: 13806 /* fall-through. */ 13807 case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY: 13808 /* fall-through. */ 13809 case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY: 13810 return hrxqs[4]; 13811 case MLX5_RSS_HASH_IPV6_UDP: 13812 /* fall-through. */ 13813 case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY: 13814 /* fall-through. */ 13815 case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY: 13816 return hrxqs[5]; 13817 case MLX5_RSS_HASH_NONE: 13818 return hrxqs[6]; 13819 default: 13820 return 0; 13821 } 13822 13823 } 13824 13825 /** 13826 * Apply the flow to the NIC, lock free, 13827 * (mutex should be acquired by caller). 13828 * 13829 * @param[in] dev 13830 * Pointer to the Ethernet device structure. 13831 * @param[in, out] flow 13832 * Pointer to flow structure. 13833 * @param[out] error 13834 * Pointer to error structure. 13835 * 13836 * @return 13837 * 0 on success, a negative errno value otherwise and rte_errno is set. 13838 */ 13839 static int 13840 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, 13841 struct rte_flow_error *error) 13842 { 13843 struct mlx5_flow_dv_workspace *dv; 13844 struct mlx5_flow_handle *dh; 13845 struct mlx5_flow_handle_dv *dv_h; 13846 struct mlx5_flow *dev_flow; 13847 struct mlx5_priv *priv = dev->data->dev_private; 13848 uint32_t handle_idx; 13849 int n; 13850 int err; 13851 int idx; 13852 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace(); 13853 struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc; 13854 uint8_t misc_mask; 13855 13856 MLX5_ASSERT(wks); 13857 for (idx = wks->flow_idx - 1; idx >= 0; idx--) { 13858 dev_flow = &wks->flows[idx]; 13859 dv = &dev_flow->dv; 13860 dh = dev_flow->handle; 13861 dv_h = &dh->dvh; 13862 n = dv->actions_n; 13863 if (dh->fate_action == MLX5_FLOW_FATE_DROP) { 13864 if (dv->transfer) { 13865 MLX5_ASSERT(priv->sh->dr_drop_action); 13866 dv->actions[n++] = priv->sh->dr_drop_action; 13867 } else { 13868 #ifdef HAVE_MLX5DV_DR 13869 /* DR supports drop action placeholder. */ 13870 MLX5_ASSERT(priv->sh->dr_drop_action); 13871 dv->actions[n++] = dv->group ? 13872 priv->sh->dr_drop_action : 13873 priv->root_drop_action; 13874 #else 13875 /* For DV we use the explicit drop queue. */ 13876 MLX5_ASSERT(priv->drop_queue.hrxq); 13877 dv->actions[n++] = 13878 priv->drop_queue.hrxq->action; 13879 #endif 13880 } 13881 } else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE && 13882 !dv_h->rix_sample && !dv_h->rix_dest_array)) { 13883 struct mlx5_hrxq *hrxq; 13884 uint32_t hrxq_idx; 13885 13886 hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc, 13887 &hrxq_idx); 13888 if (!hrxq) { 13889 rte_flow_error_set 13890 (error, rte_errno, 13891 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13892 "cannot get hash queue"); 13893 goto error; 13894 } 13895 dh->rix_hrxq = hrxq_idx; 13896 dv->actions[n++] = hrxq->action; 13897 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13898 struct mlx5_hrxq *hrxq = NULL; 13899 uint32_t hrxq_idx; 13900 13901 hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev, 13902 rss_desc->shared_rss, 13903 dev_flow->hash_fields); 13904 if (hrxq_idx) 13905 hrxq = mlx5_ipool_get 13906 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 13907 hrxq_idx); 13908 if (!hrxq) { 13909 rte_flow_error_set 13910 (error, rte_errno, 13911 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13912 "cannot get hash queue"); 13913 goto error; 13914 } 13915 dh->rix_srss = rss_desc->shared_rss; 13916 dv->actions[n++] = hrxq->action; 13917 } else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) { 13918 if (!priv->sh->default_miss_action) { 13919 rte_flow_error_set 13920 (error, rte_errno, 13921 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 13922 "default miss action not be created."); 13923 goto error; 13924 } 13925 dv->actions[n++] = priv->sh->default_miss_action; 13926 } 13927 misc_mask = flow_dv_matcher_enable(dv->value.buf); 13928 __flow_dv_adjust_buf_size(&dv->value.size, misc_mask); 13929 err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object, 13930 (void *)&dv->value, n, 13931 dv->actions, &dh->drv_flow); 13932 if (err) { 13933 rte_flow_error_set 13934 (error, errno, 13935 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 13936 NULL, 13937 (!priv->config.allow_duplicate_pattern && 13938 errno == EEXIST) ? 13939 "duplicating pattern is not allowed" : 13940 "hardware refuses to create flow"); 13941 goto error; 13942 } 13943 if (priv->vmwa_context && 13944 dh->vf_vlan.tag && !dh->vf_vlan.created) { 13945 /* 13946 * The rule contains the VLAN pattern. 13947 * For VF we are going to create VLAN 13948 * interface to make hypervisor set correct 13949 * e-Switch vport context. 13950 */ 13951 mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan); 13952 } 13953 } 13954 return 0; 13955 error: 13956 err = rte_errno; /* Save rte_errno before cleanup. */ 13957 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles, 13958 handle_idx, dh, next) { 13959 /* hrxq is union, don't clear it if the flag is not set. */ 13960 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) { 13961 mlx5_hrxq_release(dev, dh->rix_hrxq); 13962 dh->rix_hrxq = 0; 13963 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) { 13964 dh->rix_srss = 0; 13965 } 13966 if (dh->vf_vlan.tag && dh->vf_vlan.created) 13967 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 13968 } 13969 rte_errno = err; /* Restore rte_errno. */ 13970 return -rte_errno; 13971 } 13972 13973 void 13974 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused, 13975 struct mlx5_list_entry *entry) 13976 { 13977 struct mlx5_flow_dv_matcher *resource = container_of(entry, 13978 typeof(*resource), 13979 entry); 13980 13981 claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object)); 13982 mlx5_free(resource); 13983 } 13984 13985 /** 13986 * Release the flow matcher. 13987 * 13988 * @param dev 13989 * Pointer to Ethernet device. 13990 * @param port_id 13991 * Index to port ID action resource. 13992 * 13993 * @return 13994 * 1 while a reference on it exists, 0 when freed. 13995 */ 13996 static int 13997 flow_dv_matcher_release(struct rte_eth_dev *dev, 13998 struct mlx5_flow_handle *handle) 13999 { 14000 struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher; 14001 struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl, 14002 typeof(*tbl), tbl); 14003 int ret; 14004 14005 MLX5_ASSERT(matcher->matcher_object); 14006 ret = mlx5_list_unregister(tbl->matchers, &matcher->entry); 14007 flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl); 14008 return ret; 14009 } 14010 14011 void 14012 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14013 { 14014 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14015 struct mlx5_flow_dv_encap_decap_resource *res = 14016 container_of(entry, typeof(*res), entry); 14017 14018 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 14019 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx); 14020 } 14021 14022 /** 14023 * Release an encap/decap resource. 14024 * 14025 * @param dev 14026 * Pointer to Ethernet device. 14027 * @param encap_decap_idx 14028 * Index of encap decap resource. 14029 * 14030 * @return 14031 * 1 while a reference on it exists, 0 when freed. 14032 */ 14033 static int 14034 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, 14035 uint32_t encap_decap_idx) 14036 { 14037 struct mlx5_priv *priv = dev->data->dev_private; 14038 struct mlx5_flow_dv_encap_decap_resource *resource; 14039 14040 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP], 14041 encap_decap_idx); 14042 if (!resource) 14043 return 0; 14044 MLX5_ASSERT(resource->action); 14045 return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry); 14046 } 14047 14048 /** 14049 * Release an jump to table action resource. 14050 * 14051 * @param dev 14052 * Pointer to Ethernet device. 14053 * @param rix_jump 14054 * Index to the jump action resource. 14055 * 14056 * @return 14057 * 1 while a reference on it exists, 0 when freed. 14058 */ 14059 static int 14060 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, 14061 uint32_t rix_jump) 14062 { 14063 struct mlx5_priv *priv = dev->data->dev_private; 14064 struct mlx5_flow_tbl_data_entry *tbl_data; 14065 14066 tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP], 14067 rix_jump); 14068 if (!tbl_data) 14069 return 0; 14070 return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl); 14071 } 14072 14073 void 14074 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14075 { 14076 struct mlx5_flow_dv_modify_hdr_resource *res = 14077 container_of(entry, typeof(*res), entry); 14078 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14079 14080 claim_zero(mlx5_flow_os_destroy_flow_action(res->action)); 14081 mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx); 14082 } 14083 14084 /** 14085 * Release a modify-header resource. 14086 * 14087 * @param dev 14088 * Pointer to Ethernet device. 14089 * @param handle 14090 * Pointer to mlx5_flow_handle. 14091 * 14092 * @return 14093 * 1 while a reference on it exists, 0 when freed. 14094 */ 14095 static int 14096 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev, 14097 struct mlx5_flow_handle *handle) 14098 { 14099 struct mlx5_priv *priv = dev->data->dev_private; 14100 struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr; 14101 14102 MLX5_ASSERT(entry->action); 14103 return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry); 14104 } 14105 14106 void 14107 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14108 { 14109 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14110 struct mlx5_flow_dv_port_id_action_resource *resource = 14111 container_of(entry, typeof(*resource), entry); 14112 14113 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14114 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx); 14115 } 14116 14117 /** 14118 * Release port ID action resource. 14119 * 14120 * @param dev 14121 * Pointer to Ethernet device. 14122 * @param handle 14123 * Pointer to mlx5_flow_handle. 14124 * 14125 * @return 14126 * 1 while a reference on it exists, 0 when freed. 14127 */ 14128 static int 14129 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, 14130 uint32_t port_id) 14131 { 14132 struct mlx5_priv *priv = dev->data->dev_private; 14133 struct mlx5_flow_dv_port_id_action_resource *resource; 14134 14135 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id); 14136 if (!resource) 14137 return 0; 14138 MLX5_ASSERT(resource->action); 14139 return mlx5_list_unregister(priv->sh->port_id_action_list, 14140 &resource->entry); 14141 } 14142 14143 /** 14144 * Release shared RSS action resource. 14145 * 14146 * @param dev 14147 * Pointer to Ethernet device. 14148 * @param srss 14149 * Shared RSS action index. 14150 */ 14151 static void 14152 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss) 14153 { 14154 struct mlx5_priv *priv = dev->data->dev_private; 14155 struct mlx5_shared_action_rss *shared_rss; 14156 14157 shared_rss = mlx5_ipool_get 14158 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss); 14159 __atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14160 } 14161 14162 void 14163 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry) 14164 { 14165 struct mlx5_dev_ctx_shared *sh = tool_ctx; 14166 struct mlx5_flow_dv_push_vlan_action_resource *resource = 14167 container_of(entry, typeof(*resource), entry); 14168 14169 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14170 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx); 14171 } 14172 14173 /** 14174 * Release push vlan action resource. 14175 * 14176 * @param dev 14177 * Pointer to Ethernet device. 14178 * @param handle 14179 * Pointer to mlx5_flow_handle. 14180 * 14181 * @return 14182 * 1 while a reference on it exists, 0 when freed. 14183 */ 14184 static int 14185 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev, 14186 struct mlx5_flow_handle *handle) 14187 { 14188 struct mlx5_priv *priv = dev->data->dev_private; 14189 struct mlx5_flow_dv_push_vlan_action_resource *resource; 14190 uint32_t idx = handle->dvh.rix_push_vlan; 14191 14192 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx); 14193 if (!resource) 14194 return 0; 14195 MLX5_ASSERT(resource->action); 14196 return mlx5_list_unregister(priv->sh->push_vlan_action_list, 14197 &resource->entry); 14198 } 14199 14200 /** 14201 * Release the fate resource. 14202 * 14203 * @param dev 14204 * Pointer to Ethernet device. 14205 * @param handle 14206 * Pointer to mlx5_flow_handle. 14207 */ 14208 static void 14209 flow_dv_fate_resource_release(struct rte_eth_dev *dev, 14210 struct mlx5_flow_handle *handle) 14211 { 14212 if (!handle->rix_fate) 14213 return; 14214 switch (handle->fate_action) { 14215 case MLX5_FLOW_FATE_QUEUE: 14216 if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array) 14217 mlx5_hrxq_release(dev, handle->rix_hrxq); 14218 break; 14219 case MLX5_FLOW_FATE_JUMP: 14220 flow_dv_jump_tbl_resource_release(dev, handle->rix_jump); 14221 break; 14222 case MLX5_FLOW_FATE_PORT_ID: 14223 flow_dv_port_id_action_resource_release(dev, 14224 handle->rix_port_id_action); 14225 break; 14226 default: 14227 DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action); 14228 break; 14229 } 14230 handle->rix_fate = 0; 14231 } 14232 14233 void 14234 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused, 14235 struct mlx5_list_entry *entry) 14236 { 14237 struct mlx5_flow_dv_sample_resource *resource = container_of(entry, 14238 typeof(*resource), 14239 entry); 14240 struct rte_eth_dev *dev = resource->dev; 14241 struct mlx5_priv *priv = dev->data->dev_private; 14242 14243 if (resource->verbs_action) 14244 claim_zero(mlx5_flow_os_destroy_flow_action 14245 (resource->verbs_action)); 14246 if (resource->normal_path_tbl) 14247 flow_dv_tbl_resource_release(MLX5_SH(dev), 14248 resource->normal_path_tbl); 14249 flow_dv_sample_sub_actions_release(dev, &resource->sample_idx); 14250 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx); 14251 DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource); 14252 } 14253 14254 /** 14255 * Release an sample resource. 14256 * 14257 * @param dev 14258 * Pointer to Ethernet device. 14259 * @param handle 14260 * Pointer to mlx5_flow_handle. 14261 * 14262 * @return 14263 * 1 while a reference on it exists, 0 when freed. 14264 */ 14265 static int 14266 flow_dv_sample_resource_release(struct rte_eth_dev *dev, 14267 struct mlx5_flow_handle *handle) 14268 { 14269 struct mlx5_priv *priv = dev->data->dev_private; 14270 struct mlx5_flow_dv_sample_resource *resource; 14271 14272 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE], 14273 handle->dvh.rix_sample); 14274 if (!resource) 14275 return 0; 14276 MLX5_ASSERT(resource->verbs_action); 14277 return mlx5_list_unregister(priv->sh->sample_action_list, 14278 &resource->entry); 14279 } 14280 14281 void 14282 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused, 14283 struct mlx5_list_entry *entry) 14284 { 14285 struct mlx5_flow_dv_dest_array_resource *resource = 14286 container_of(entry, typeof(*resource), entry); 14287 struct rte_eth_dev *dev = resource->dev; 14288 struct mlx5_priv *priv = dev->data->dev_private; 14289 uint32_t i = 0; 14290 14291 MLX5_ASSERT(resource->action); 14292 if (resource->action) 14293 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action)); 14294 for (; i < resource->num_of_dest; i++) 14295 flow_dv_sample_sub_actions_release(dev, 14296 &resource->sample_idx[i]); 14297 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx); 14298 DRV_LOG(DEBUG, "destination array resource %p: removed", 14299 (void *)resource); 14300 } 14301 14302 /** 14303 * Release an destination array resource. 14304 * 14305 * @param dev 14306 * Pointer to Ethernet device. 14307 * @param handle 14308 * Pointer to mlx5_flow_handle. 14309 * 14310 * @return 14311 * 1 while a reference on it exists, 0 when freed. 14312 */ 14313 static int 14314 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev, 14315 struct mlx5_flow_handle *handle) 14316 { 14317 struct mlx5_priv *priv = dev->data->dev_private; 14318 struct mlx5_flow_dv_dest_array_resource *resource; 14319 14320 resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], 14321 handle->dvh.rix_dest_array); 14322 if (!resource) 14323 return 0; 14324 MLX5_ASSERT(resource->action); 14325 return mlx5_list_unregister(priv->sh->dest_array_list, 14326 &resource->entry); 14327 } 14328 14329 static void 14330 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev) 14331 { 14332 struct mlx5_priv *priv = dev->data->dev_private; 14333 struct mlx5_dev_ctx_shared *sh = priv->sh; 14334 struct mlx5_geneve_tlv_option_resource *geneve_opt_resource = 14335 sh->geneve_tlv_option_resource; 14336 rte_spinlock_lock(&sh->geneve_tlv_opt_sl); 14337 if (geneve_opt_resource) { 14338 if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1, 14339 __ATOMIC_RELAXED))) { 14340 claim_zero(mlx5_devx_cmd_destroy 14341 (geneve_opt_resource->obj)); 14342 mlx5_free(sh->geneve_tlv_option_resource); 14343 sh->geneve_tlv_option_resource = NULL; 14344 } 14345 } 14346 rte_spinlock_unlock(&sh->geneve_tlv_opt_sl); 14347 } 14348 14349 /** 14350 * Remove the flow from the NIC but keeps it in memory. 14351 * Lock free, (mutex should be acquired by caller). 14352 * 14353 * @param[in] dev 14354 * Pointer to Ethernet device. 14355 * @param[in, out] flow 14356 * Pointer to flow structure. 14357 */ 14358 static void 14359 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow) 14360 { 14361 struct mlx5_flow_handle *dh; 14362 uint32_t handle_idx; 14363 struct mlx5_priv *priv = dev->data->dev_private; 14364 14365 if (!flow) 14366 return; 14367 handle_idx = flow->dev_handles; 14368 while (handle_idx) { 14369 dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14370 handle_idx); 14371 if (!dh) 14372 return; 14373 if (dh->drv_flow) { 14374 claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow)); 14375 dh->drv_flow = NULL; 14376 } 14377 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) 14378 flow_dv_fate_resource_release(dev, dh); 14379 if (dh->vf_vlan.tag && dh->vf_vlan.created) 14380 mlx5_vlan_vmwa_release(dev, &dh->vf_vlan); 14381 handle_idx = dh->next.next; 14382 } 14383 } 14384 14385 /** 14386 * Remove the flow from the NIC and the memory. 14387 * Lock free, (mutex should be acquired by caller). 14388 * 14389 * @param[in] dev 14390 * Pointer to the Ethernet device structure. 14391 * @param[in, out] flow 14392 * Pointer to flow structure. 14393 */ 14394 static void 14395 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) 14396 { 14397 struct mlx5_flow_handle *dev_handle; 14398 struct mlx5_priv *priv = dev->data->dev_private; 14399 struct mlx5_flow_meter_info *fm = NULL; 14400 uint32_t srss = 0; 14401 14402 if (!flow) 14403 return; 14404 flow_dv_remove(dev, flow); 14405 if (flow->counter) { 14406 flow_dv_counter_free(dev, flow->counter); 14407 flow->counter = 0; 14408 } 14409 if (flow->meter) { 14410 fm = flow_dv_meter_find_by_idx(priv, flow->meter); 14411 if (fm) 14412 mlx5_flow_meter_detach(priv, fm); 14413 flow->meter = 0; 14414 } 14415 /* Keep the current age handling by default. */ 14416 if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct) 14417 flow_dv_aso_ct_release(dev, flow->ct, NULL); 14418 else if (flow->age) 14419 flow_dv_aso_age_release(dev, flow->age); 14420 if (flow->geneve_tlv_option) { 14421 flow_dv_geneve_tlv_option_resource_release(dev); 14422 flow->geneve_tlv_option = 0; 14423 } 14424 while (flow->dev_handles) { 14425 uint32_t tmp_idx = flow->dev_handles; 14426 14427 dev_handle = mlx5_ipool_get(priv->sh->ipool 14428 [MLX5_IPOOL_MLX5_FLOW], tmp_idx); 14429 if (!dev_handle) 14430 return; 14431 flow->dev_handles = dev_handle->next.next; 14432 while (dev_handle->flex_item) { 14433 int index = rte_bsf32(dev_handle->flex_item); 14434 14435 mlx5_flex_release_index(dev, index); 14436 dev_handle->flex_item &= ~RTE_BIT32(index); 14437 } 14438 if (dev_handle->dvh.matcher) 14439 flow_dv_matcher_release(dev, dev_handle); 14440 if (dev_handle->dvh.rix_sample) 14441 flow_dv_sample_resource_release(dev, dev_handle); 14442 if (dev_handle->dvh.rix_dest_array) 14443 flow_dv_dest_array_resource_release(dev, dev_handle); 14444 if (dev_handle->dvh.rix_encap_decap) 14445 flow_dv_encap_decap_resource_release(dev, 14446 dev_handle->dvh.rix_encap_decap); 14447 if (dev_handle->dvh.modify_hdr) 14448 flow_dv_modify_hdr_resource_release(dev, dev_handle); 14449 if (dev_handle->dvh.rix_push_vlan) 14450 flow_dv_push_vlan_action_resource_release(dev, 14451 dev_handle); 14452 if (dev_handle->dvh.rix_tag) 14453 flow_dv_tag_release(dev, 14454 dev_handle->dvh.rix_tag); 14455 if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS) 14456 flow_dv_fate_resource_release(dev, dev_handle); 14457 else if (!srss) 14458 srss = dev_handle->rix_srss; 14459 if (fm && dev_handle->is_meter_flow_id && 14460 dev_handle->split_flow_id) 14461 mlx5_ipool_free(fm->flow_ipool, 14462 dev_handle->split_flow_id); 14463 else if (dev_handle->split_flow_id && 14464 !dev_handle->is_meter_flow_id) 14465 mlx5_ipool_free(priv->sh->ipool 14466 [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], 14467 dev_handle->split_flow_id); 14468 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], 14469 tmp_idx); 14470 } 14471 if (srss) 14472 flow_dv_shared_rss_action_release(dev, srss); 14473 } 14474 14475 /** 14476 * Release array of hash RX queue objects. 14477 * Helper function. 14478 * 14479 * @param[in] dev 14480 * Pointer to the Ethernet device structure. 14481 * @param[in, out] hrxqs 14482 * Array of hash RX queue objects. 14483 * 14484 * @return 14485 * Total number of references to hash RX queue objects in *hrxqs* array 14486 * after this operation. 14487 */ 14488 static int 14489 __flow_dv_hrxqs_release(struct rte_eth_dev *dev, 14490 uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN]) 14491 { 14492 size_t i; 14493 int remaining = 0; 14494 14495 for (i = 0; i < RTE_DIM(*hrxqs); i++) { 14496 int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]); 14497 14498 if (!ret) 14499 (*hrxqs)[i] = 0; 14500 remaining += ret; 14501 } 14502 return remaining; 14503 } 14504 14505 /** 14506 * Release all hash RX queue objects representing shared RSS action. 14507 * 14508 * @param[in] dev 14509 * Pointer to the Ethernet device structure. 14510 * @param[in, out] action 14511 * Shared RSS action to remove hash RX queue objects from. 14512 * 14513 * @return 14514 * Total number of references to hash RX queue objects stored in *action* 14515 * after this operation. 14516 * Expected to be 0 if no external references held. 14517 */ 14518 static int 14519 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev, 14520 struct mlx5_shared_action_rss *shared_rss) 14521 { 14522 return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq); 14523 } 14524 14525 /** 14526 * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to 14527 * user input. 14528 * 14529 * Only one hash value is available for one L3+L4 combination: 14530 * for example: 14531 * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and 14532 * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share 14533 * same slot in mlx5_rss_hash_fields. 14534 * 14535 * @param[in] rss 14536 * Pointer to the shared action RSS conf. 14537 * @param[in, out] hash_field 14538 * hash_field variable needed to be adjusted. 14539 * 14540 * @return 14541 * void 14542 */ 14543 static void 14544 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss, 14545 uint64_t *hash_field) 14546 { 14547 uint64_t rss_types = rss->origin.types; 14548 14549 switch (*hash_field & ~IBV_RX_HASH_INNER) { 14550 case MLX5_RSS_HASH_IPV4: 14551 if (rss_types & MLX5_IPV4_LAYER_TYPES) { 14552 *hash_field &= ~MLX5_RSS_HASH_IPV4; 14553 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 14554 *hash_field |= IBV_RX_HASH_DST_IPV4; 14555 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 14556 *hash_field |= IBV_RX_HASH_SRC_IPV4; 14557 else 14558 *hash_field |= MLX5_RSS_HASH_IPV4; 14559 } 14560 return; 14561 case MLX5_RSS_HASH_IPV6: 14562 if (rss_types & MLX5_IPV6_LAYER_TYPES) { 14563 *hash_field &= ~MLX5_RSS_HASH_IPV6; 14564 if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) 14565 *hash_field |= IBV_RX_HASH_DST_IPV6; 14566 else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) 14567 *hash_field |= IBV_RX_HASH_SRC_IPV6; 14568 else 14569 *hash_field |= MLX5_RSS_HASH_IPV6; 14570 } 14571 return; 14572 case MLX5_RSS_HASH_IPV4_UDP: 14573 /* fall-through. */ 14574 case MLX5_RSS_HASH_IPV6_UDP: 14575 if (rss_types & RTE_ETH_RSS_UDP) { 14576 *hash_field &= ~MLX5_UDP_IBV_RX_HASH; 14577 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 14578 *hash_field |= IBV_RX_HASH_DST_PORT_UDP; 14579 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 14580 *hash_field |= IBV_RX_HASH_SRC_PORT_UDP; 14581 else 14582 *hash_field |= MLX5_UDP_IBV_RX_HASH; 14583 } 14584 return; 14585 case MLX5_RSS_HASH_IPV4_TCP: 14586 /* fall-through. */ 14587 case MLX5_RSS_HASH_IPV6_TCP: 14588 if (rss_types & RTE_ETH_RSS_TCP) { 14589 *hash_field &= ~MLX5_TCP_IBV_RX_HASH; 14590 if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) 14591 *hash_field |= IBV_RX_HASH_DST_PORT_TCP; 14592 else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) 14593 *hash_field |= IBV_RX_HASH_SRC_PORT_TCP; 14594 else 14595 *hash_field |= MLX5_TCP_IBV_RX_HASH; 14596 } 14597 return; 14598 default: 14599 return; 14600 } 14601 } 14602 14603 /** 14604 * Setup shared RSS action. 14605 * Prepare set of hash RX queue objects sufficient to handle all valid 14606 * hash_fields combinations (see enum ibv_rx_hash_fields). 14607 * 14608 * @param[in] dev 14609 * Pointer to the Ethernet device structure. 14610 * @param[in] action_idx 14611 * Shared RSS action ipool index. 14612 * @param[in, out] action 14613 * Partially initialized shared RSS action. 14614 * @param[out] error 14615 * Perform verbose error reporting if not NULL. Initialized in case of 14616 * error only. 14617 * 14618 * @return 14619 * 0 on success, otherwise negative errno value. 14620 */ 14621 static int 14622 __flow_dv_action_rss_setup(struct rte_eth_dev *dev, 14623 uint32_t action_idx, 14624 struct mlx5_shared_action_rss *shared_rss, 14625 struct rte_flow_error *error) 14626 { 14627 struct mlx5_flow_rss_desc rss_desc = { 0 }; 14628 size_t i; 14629 int err; 14630 14631 if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) { 14632 return rte_flow_error_set(error, rte_errno, 14633 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14634 "cannot setup indirection table"); 14635 } 14636 memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN); 14637 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN; 14638 rss_desc.const_q = shared_rss->origin.queue; 14639 rss_desc.queue_num = shared_rss->origin.queue_num; 14640 /* Set non-zero value to indicate a shared RSS. */ 14641 rss_desc.shared_rss = action_idx; 14642 rss_desc.ind_tbl = shared_rss->ind_tbl; 14643 for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) { 14644 uint32_t hrxq_idx; 14645 uint64_t hash_fields = mlx5_rss_hash_fields[i]; 14646 int tunnel = 0; 14647 14648 __flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields); 14649 if (shared_rss->origin.level > 1) { 14650 hash_fields |= IBV_RX_HASH_INNER; 14651 tunnel = 1; 14652 } 14653 rss_desc.tunnel = tunnel; 14654 rss_desc.hash_fields = hash_fields; 14655 hrxq_idx = mlx5_hrxq_get(dev, &rss_desc); 14656 if (!hrxq_idx) { 14657 rte_flow_error_set 14658 (error, rte_errno, 14659 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14660 "cannot get hash queue"); 14661 goto error_hrxq_new; 14662 } 14663 err = __flow_dv_action_rss_hrxq_set 14664 (shared_rss, hash_fields, hrxq_idx); 14665 MLX5_ASSERT(!err); 14666 } 14667 return 0; 14668 error_hrxq_new: 14669 err = rte_errno; 14670 __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14671 if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true)) 14672 shared_rss->ind_tbl = NULL; 14673 rte_errno = err; 14674 return -rte_errno; 14675 } 14676 14677 /** 14678 * Create shared RSS action. 14679 * 14680 * @param[in] dev 14681 * Pointer to the Ethernet device structure. 14682 * @param[in] conf 14683 * Shared action configuration. 14684 * @param[in] rss 14685 * RSS action specification used to create shared action. 14686 * @param[out] error 14687 * Perform verbose error reporting if not NULL. Initialized in case of 14688 * error only. 14689 * 14690 * @return 14691 * A valid shared action ID in case of success, 0 otherwise and 14692 * rte_errno is set. 14693 */ 14694 static uint32_t 14695 __flow_dv_action_rss_create(struct rte_eth_dev *dev, 14696 const struct rte_flow_indir_action_conf *conf, 14697 const struct rte_flow_action_rss *rss, 14698 struct rte_flow_error *error) 14699 { 14700 struct mlx5_priv *priv = dev->data->dev_private; 14701 struct mlx5_shared_action_rss *shared_rss = NULL; 14702 void *queue = NULL; 14703 struct rte_flow_action_rss *origin; 14704 const uint8_t *rss_key; 14705 uint32_t queue_size = rss->queue_num * sizeof(uint16_t); 14706 uint32_t idx; 14707 14708 RTE_SET_USED(conf); 14709 queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 14710 0, SOCKET_ID_ANY); 14711 shared_rss = mlx5_ipool_zmalloc 14712 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx); 14713 if (!shared_rss || !queue) { 14714 rte_flow_error_set(error, ENOMEM, 14715 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14716 "cannot allocate resource memory"); 14717 goto error_rss_init; 14718 } 14719 if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) { 14720 rte_flow_error_set(error, E2BIG, 14721 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14722 "rss action number out of range"); 14723 goto error_rss_init; 14724 } 14725 shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO, 14726 sizeof(*shared_rss->ind_tbl), 14727 0, SOCKET_ID_ANY); 14728 if (!shared_rss->ind_tbl) { 14729 rte_flow_error_set(error, ENOMEM, 14730 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 14731 "cannot allocate resource memory"); 14732 goto error_rss_init; 14733 } 14734 memcpy(queue, rss->queue, queue_size); 14735 shared_rss->ind_tbl->queues = queue; 14736 shared_rss->ind_tbl->queues_n = rss->queue_num; 14737 origin = &shared_rss->origin; 14738 origin->func = rss->func; 14739 origin->level = rss->level; 14740 /* RSS type 0 indicates default RSS type (RTE_ETH_RSS_IP). */ 14741 origin->types = !rss->types ? RTE_ETH_RSS_IP : rss->types; 14742 /* NULL RSS key indicates default RSS key. */ 14743 rss_key = !rss->key ? rss_hash_default_key : rss->key; 14744 memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN); 14745 origin->key = &shared_rss->key[0]; 14746 origin->key_len = MLX5_RSS_HASH_KEY_LEN; 14747 origin->queue = queue; 14748 origin->queue_num = rss->queue_num; 14749 if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error)) 14750 goto error_rss_init; 14751 rte_spinlock_init(&shared_rss->action_rss_sl); 14752 __atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED); 14753 rte_spinlock_lock(&priv->shared_act_sl); 14754 ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14755 &priv->rss_shared_actions, idx, shared_rss, next); 14756 rte_spinlock_unlock(&priv->shared_act_sl); 14757 return idx; 14758 error_rss_init: 14759 if (shared_rss) { 14760 if (shared_rss->ind_tbl) 14761 mlx5_free(shared_rss->ind_tbl); 14762 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14763 idx); 14764 } 14765 if (queue) 14766 mlx5_free(queue); 14767 return 0; 14768 } 14769 14770 /** 14771 * Destroy the shared RSS action. 14772 * Release related hash RX queue objects. 14773 * 14774 * @param[in] dev 14775 * Pointer to the Ethernet device structure. 14776 * @param[in] idx 14777 * The shared RSS action object ID to be removed. 14778 * @param[out] error 14779 * Perform verbose error reporting if not NULL. Initialized in case of 14780 * error only. 14781 * 14782 * @return 14783 * 0 on success, otherwise negative errno value. 14784 */ 14785 static int 14786 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, 14787 struct rte_flow_error *error) 14788 { 14789 struct mlx5_priv *priv = dev->data->dev_private; 14790 struct mlx5_shared_action_rss *shared_rss = 14791 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14792 uint32_t old_refcnt = 1; 14793 int remaining; 14794 uint16_t *queue = NULL; 14795 14796 if (!shared_rss) 14797 return rte_flow_error_set(error, EINVAL, 14798 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 14799 "invalid shared action"); 14800 if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt, 14801 0, 0, __ATOMIC_ACQUIRE, 14802 __ATOMIC_RELAXED)) 14803 return rte_flow_error_set(error, EBUSY, 14804 RTE_FLOW_ERROR_TYPE_ACTION, 14805 NULL, 14806 "shared rss has references"); 14807 remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); 14808 if (remaining) 14809 return rte_flow_error_set(error, EBUSY, 14810 RTE_FLOW_ERROR_TYPE_ACTION, 14811 NULL, 14812 "shared rss hrxq has references"); 14813 queue = shared_rss->ind_tbl->queues; 14814 remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true); 14815 if (remaining) 14816 return rte_flow_error_set(error, EBUSY, 14817 RTE_FLOW_ERROR_TYPE_ACTION, 14818 NULL, 14819 "shared rss indirection table has" 14820 " references"); 14821 mlx5_free(queue); 14822 rte_spinlock_lock(&priv->shared_act_sl); 14823 ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14824 &priv->rss_shared_actions, idx, shared_rss, next); 14825 rte_spinlock_unlock(&priv->shared_act_sl); 14826 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], 14827 idx); 14828 return 0; 14829 } 14830 14831 /** 14832 * Create indirect action, lock free, 14833 * (mutex should be acquired by caller). 14834 * Dispatcher for action type specific call. 14835 * 14836 * @param[in] dev 14837 * Pointer to the Ethernet device structure. 14838 * @param[in] conf 14839 * Shared action configuration. 14840 * @param[in] action 14841 * Action specification used to create indirect action. 14842 * @param[out] error 14843 * Perform verbose error reporting if not NULL. Initialized in case of 14844 * error only. 14845 * 14846 * @return 14847 * A valid shared action handle in case of success, NULL otherwise and 14848 * rte_errno is set. 14849 */ 14850 static struct rte_flow_action_handle * 14851 flow_dv_action_create(struct rte_eth_dev *dev, 14852 const struct rte_flow_indir_action_conf *conf, 14853 const struct rte_flow_action *action, 14854 struct rte_flow_error *err) 14855 { 14856 struct mlx5_priv *priv = dev->data->dev_private; 14857 uint32_t age_idx = 0; 14858 uint32_t idx = 0; 14859 uint32_t ret = 0; 14860 14861 switch (action->type) { 14862 case RTE_FLOW_ACTION_TYPE_RSS: 14863 ret = __flow_dv_action_rss_create(dev, conf, action->conf, err); 14864 idx = (MLX5_INDIRECT_ACTION_TYPE_RSS << 14865 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14866 break; 14867 case RTE_FLOW_ACTION_TYPE_AGE: 14868 age_idx = flow_dv_aso_age_alloc(dev, err); 14869 if (!age_idx) { 14870 ret = -rte_errno; 14871 break; 14872 } 14873 idx = (MLX5_INDIRECT_ACTION_TYPE_AGE << 14874 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx; 14875 flow_dv_aso_age_params_init(dev, age_idx, 14876 ((const struct rte_flow_action_age *) 14877 action->conf)->context ? 14878 ((const struct rte_flow_action_age *) 14879 action->conf)->context : 14880 (void *)(uintptr_t)idx, 14881 ((const struct rte_flow_action_age *) 14882 action->conf)->timeout); 14883 ret = age_idx; 14884 break; 14885 case RTE_FLOW_ACTION_TYPE_COUNT: 14886 ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL); 14887 idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT << 14888 MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret; 14889 break; 14890 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 14891 ret = flow_dv_translate_create_conntrack(dev, action->conf, 14892 err); 14893 idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret); 14894 break; 14895 default: 14896 rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, 14897 NULL, "action type not supported"); 14898 break; 14899 } 14900 return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL; 14901 } 14902 14903 /** 14904 * Destroy the indirect action. 14905 * Release action related resources on the NIC and the memory. 14906 * Lock free, (mutex should be acquired by caller). 14907 * Dispatcher for action type specific call. 14908 * 14909 * @param[in] dev 14910 * Pointer to the Ethernet device structure. 14911 * @param[in] handle 14912 * The indirect action object handle to be removed. 14913 * @param[out] error 14914 * Perform verbose error reporting if not NULL. Initialized in case of 14915 * error only. 14916 * 14917 * @return 14918 * 0 on success, otherwise negative errno value. 14919 */ 14920 static int 14921 flow_dv_action_destroy(struct rte_eth_dev *dev, 14922 struct rte_flow_action_handle *handle, 14923 struct rte_flow_error *error) 14924 { 14925 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 14926 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 14927 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 14928 struct mlx5_flow_counter *cnt; 14929 uint32_t no_flow_refcnt = 1; 14930 int ret; 14931 14932 switch (type) { 14933 case MLX5_INDIRECT_ACTION_TYPE_RSS: 14934 return __flow_dv_action_rss_release(dev, idx, error); 14935 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 14936 cnt = flow_dv_counter_get_by_idx(dev, idx, NULL); 14937 if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt, 14938 &no_flow_refcnt, 1, false, 14939 __ATOMIC_ACQUIRE, 14940 __ATOMIC_RELAXED)) 14941 return rte_flow_error_set(error, EBUSY, 14942 RTE_FLOW_ERROR_TYPE_ACTION, 14943 NULL, 14944 "Indirect count action has references"); 14945 flow_dv_counter_free(dev, idx); 14946 return 0; 14947 case MLX5_INDIRECT_ACTION_TYPE_AGE: 14948 ret = flow_dv_aso_age_release(dev, idx); 14949 if (ret) 14950 /* 14951 * In this case, the last flow has a reference will 14952 * actually release the age action. 14953 */ 14954 DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was" 14955 " released with references %d.", idx, ret); 14956 return 0; 14957 case MLX5_INDIRECT_ACTION_TYPE_CT: 14958 ret = flow_dv_aso_ct_release(dev, idx, error); 14959 if (ret < 0) 14960 return ret; 14961 if (ret > 0) 14962 DRV_LOG(DEBUG, "Connection tracking object %u still " 14963 "has references %d.", idx, ret); 14964 return 0; 14965 default: 14966 return rte_flow_error_set(error, ENOTSUP, 14967 RTE_FLOW_ERROR_TYPE_ACTION, 14968 NULL, 14969 "action type not supported"); 14970 } 14971 } 14972 14973 /** 14974 * Updates in place shared RSS action configuration. 14975 * 14976 * @param[in] dev 14977 * Pointer to the Ethernet device structure. 14978 * @param[in] idx 14979 * The shared RSS action object ID to be updated. 14980 * @param[in] action_conf 14981 * RSS action specification used to modify *shared_rss*. 14982 * @param[out] error 14983 * Perform verbose error reporting if not NULL. Initialized in case of 14984 * error only. 14985 * 14986 * @return 14987 * 0 on success, otherwise negative errno value. 14988 * @note: currently only support update of RSS queues. 14989 */ 14990 static int 14991 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx, 14992 const struct rte_flow_action_rss *action_conf, 14993 struct rte_flow_error *error) 14994 { 14995 struct mlx5_priv *priv = dev->data->dev_private; 14996 struct mlx5_shared_action_rss *shared_rss = 14997 mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx); 14998 int ret = 0; 14999 void *queue = NULL; 15000 uint16_t *queue_old = NULL; 15001 uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t); 15002 15003 if (!shared_rss) 15004 return rte_flow_error_set(error, EINVAL, 15005 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15006 "invalid shared action to update"); 15007 if (priv->obj_ops.ind_table_modify == NULL) 15008 return rte_flow_error_set(error, ENOTSUP, 15009 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15010 "cannot modify indirection table"); 15011 queue = mlx5_malloc(MLX5_MEM_ZERO, 15012 RTE_ALIGN_CEIL(queue_size, sizeof(void *)), 15013 0, SOCKET_ID_ANY); 15014 if (!queue) 15015 return rte_flow_error_set(error, ENOMEM, 15016 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15017 NULL, 15018 "cannot allocate resource memory"); 15019 memcpy(queue, action_conf->queue, queue_size); 15020 MLX5_ASSERT(shared_rss->ind_tbl); 15021 rte_spinlock_lock(&shared_rss->action_rss_sl); 15022 queue_old = shared_rss->ind_tbl->queues; 15023 ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl, 15024 queue, action_conf->queue_num, true); 15025 if (ret) { 15026 mlx5_free(queue); 15027 ret = rte_flow_error_set(error, rte_errno, 15028 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15029 "cannot update indirection table"); 15030 } else { 15031 mlx5_free(queue_old); 15032 shared_rss->origin.queue = queue; 15033 shared_rss->origin.queue_num = action_conf->queue_num; 15034 } 15035 rte_spinlock_unlock(&shared_rss->action_rss_sl); 15036 return ret; 15037 } 15038 15039 /* 15040 * Updates in place conntrack context or direction. 15041 * Context update should be synchronized. 15042 * 15043 * @param[in] dev 15044 * Pointer to the Ethernet device structure. 15045 * @param[in] idx 15046 * The conntrack object ID to be updated. 15047 * @param[in] update 15048 * Pointer to the structure of information to update. 15049 * @param[out] error 15050 * Perform verbose error reporting if not NULL. Initialized in case of 15051 * error only. 15052 * 15053 * @return 15054 * 0 on success, otherwise negative errno value. 15055 */ 15056 static int 15057 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, 15058 const struct rte_flow_modify_conntrack *update, 15059 struct rte_flow_error *error) 15060 { 15061 struct mlx5_priv *priv = dev->data->dev_private; 15062 struct mlx5_aso_ct_action *ct; 15063 const struct rte_flow_action_conntrack *new_prf; 15064 int ret = 0; 15065 uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15066 uint32_t dev_idx; 15067 15068 if (PORT_ID(priv) != owner) 15069 return rte_flow_error_set(error, EACCES, 15070 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15071 NULL, 15072 "CT object owned by another port"); 15073 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15074 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15075 if (!ct->refcnt) 15076 return rte_flow_error_set(error, ENOMEM, 15077 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15078 NULL, 15079 "CT object is inactive"); 15080 new_prf = &update->new_ct; 15081 if (update->direction) 15082 ct->is_original = !!new_prf->is_original_dir; 15083 if (update->state) { 15084 /* Only validate the profile when it needs to be updated. */ 15085 ret = mlx5_validate_action_ct(dev, new_prf, error); 15086 if (ret) 15087 return ret; 15088 ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf); 15089 if (ret) 15090 return rte_flow_error_set(error, EIO, 15091 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15092 NULL, 15093 "Failed to send CT context update WQE"); 15094 /* Block until ready or a failure. */ 15095 ret = mlx5_aso_ct_available(priv->sh, ct); 15096 if (ret) 15097 rte_flow_error_set(error, rte_errno, 15098 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15099 NULL, 15100 "Timeout to get the CT update"); 15101 } 15102 return ret; 15103 } 15104 15105 /** 15106 * Updates in place shared action configuration, lock free, 15107 * (mutex should be acquired by caller). 15108 * 15109 * @param[in] dev 15110 * Pointer to the Ethernet device structure. 15111 * @param[in] handle 15112 * The indirect action object handle to be updated. 15113 * @param[in] update 15114 * Action specification used to modify the action pointed by *handle*. 15115 * *update* could be of same type with the action pointed by the *handle* 15116 * handle argument, or some other structures like a wrapper, depending on 15117 * the indirect action type. 15118 * @param[out] error 15119 * Perform verbose error reporting if not NULL. Initialized in case of 15120 * error only. 15121 * 15122 * @return 15123 * 0 on success, otherwise negative errno value. 15124 */ 15125 static int 15126 flow_dv_action_update(struct rte_eth_dev *dev, 15127 struct rte_flow_action_handle *handle, 15128 const void *update, 15129 struct rte_flow_error *err) 15130 { 15131 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15132 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15133 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15134 const void *action_conf; 15135 15136 switch (type) { 15137 case MLX5_INDIRECT_ACTION_TYPE_RSS: 15138 action_conf = ((const struct rte_flow_action *)update)->conf; 15139 return __flow_dv_action_rss_update(dev, idx, action_conf, err); 15140 case MLX5_INDIRECT_ACTION_TYPE_CT: 15141 return __flow_dv_action_ct_update(dev, idx, update, err); 15142 default: 15143 return rte_flow_error_set(err, ENOTSUP, 15144 RTE_FLOW_ERROR_TYPE_ACTION, 15145 NULL, 15146 "action type update not supported"); 15147 } 15148 } 15149 15150 /** 15151 * Destroy the meter sub policy table rules. 15152 * Lock free, (mutex should be acquired by caller). 15153 * 15154 * @param[in] dev 15155 * Pointer to Ethernet device. 15156 * @param[in] sub_policy 15157 * Pointer to meter sub policy table. 15158 */ 15159 static void 15160 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, 15161 struct mlx5_flow_meter_sub_policy *sub_policy) 15162 { 15163 struct mlx5_priv *priv = dev->data->dev_private; 15164 struct mlx5_flow_tbl_data_entry *tbl; 15165 struct mlx5_flow_meter_policy *policy = sub_policy->main_policy; 15166 struct mlx5_flow_meter_info *next_fm; 15167 struct mlx5_sub_policy_color_rule *color_rule; 15168 void *tmp; 15169 uint32_t i; 15170 15171 for (i = 0; i < RTE_COLORS; i++) { 15172 next_fm = NULL; 15173 if (i == RTE_COLOR_GREEN && policy && 15174 policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) 15175 next_fm = mlx5_flow_meter_find(priv, 15176 policy->act_cnt[i].next_mtr_id, NULL); 15177 RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], 15178 next_port, tmp) { 15179 claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule)); 15180 tbl = container_of(color_rule->matcher->tbl, 15181 typeof(*tbl), tbl); 15182 mlx5_list_unregister(tbl->matchers, 15183 &color_rule->matcher->entry); 15184 TAILQ_REMOVE(&sub_policy->color_rules[i], 15185 color_rule, next_port); 15186 mlx5_free(color_rule); 15187 if (next_fm) 15188 mlx5_flow_meter_detach(priv, next_fm); 15189 } 15190 } 15191 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15192 if (sub_policy->rix_hrxq[i]) { 15193 if (policy && !policy->is_hierarchy) 15194 mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]); 15195 sub_policy->rix_hrxq[i] = 0; 15196 } 15197 if (sub_policy->jump_tbl[i]) { 15198 flow_dv_tbl_resource_release(MLX5_SH(dev), 15199 sub_policy->jump_tbl[i]); 15200 sub_policy->jump_tbl[i] = NULL; 15201 } 15202 } 15203 if (sub_policy->tbl_rsc) { 15204 flow_dv_tbl_resource_release(MLX5_SH(dev), 15205 sub_policy->tbl_rsc); 15206 sub_policy->tbl_rsc = NULL; 15207 } 15208 } 15209 15210 /** 15211 * Destroy policy rules, lock free, 15212 * (mutex should be acquired by caller). 15213 * Dispatcher for action type specific call. 15214 * 15215 * @param[in] dev 15216 * Pointer to the Ethernet device structure. 15217 * @param[in] mtr_policy 15218 * Meter policy struct. 15219 */ 15220 static void 15221 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, 15222 struct mlx5_flow_meter_policy *mtr_policy) 15223 { 15224 uint32_t i, j; 15225 struct mlx5_flow_meter_sub_policy *sub_policy; 15226 uint16_t sub_policy_num; 15227 15228 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15229 sub_policy_num = (mtr_policy->sub_policy_num >> 15230 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15231 MLX5_MTR_SUB_POLICY_NUM_MASK; 15232 for (j = 0; j < sub_policy_num; j++) { 15233 sub_policy = mtr_policy->sub_policys[i][j]; 15234 if (sub_policy) 15235 __flow_dv_destroy_sub_policy_rules(dev, 15236 sub_policy); 15237 } 15238 } 15239 } 15240 15241 /** 15242 * Destroy policy action, lock free, 15243 * (mutex should be acquired by caller). 15244 * Dispatcher for action type specific call. 15245 * 15246 * @param[in] dev 15247 * Pointer to the Ethernet device structure. 15248 * @param[in] mtr_policy 15249 * Meter policy struct. 15250 */ 15251 static void 15252 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev, 15253 struct mlx5_flow_meter_policy *mtr_policy) 15254 { 15255 struct rte_flow_action *rss_action; 15256 struct mlx5_flow_handle dev_handle; 15257 uint32_t i, j; 15258 15259 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 15260 if (mtr_policy->act_cnt[i].rix_mark) { 15261 flow_dv_tag_release(dev, 15262 mtr_policy->act_cnt[i].rix_mark); 15263 mtr_policy->act_cnt[i].rix_mark = 0; 15264 } 15265 if (mtr_policy->act_cnt[i].modify_hdr) { 15266 dev_handle.dvh.modify_hdr = 15267 mtr_policy->act_cnt[i].modify_hdr; 15268 flow_dv_modify_hdr_resource_release(dev, &dev_handle); 15269 } 15270 switch (mtr_policy->act_cnt[i].fate_action) { 15271 case MLX5_FLOW_FATE_SHARED_RSS: 15272 rss_action = mtr_policy->act_cnt[i].rss; 15273 mlx5_free(rss_action); 15274 break; 15275 case MLX5_FLOW_FATE_PORT_ID: 15276 if (mtr_policy->act_cnt[i].rix_port_id_action) { 15277 flow_dv_port_id_action_resource_release(dev, 15278 mtr_policy->act_cnt[i].rix_port_id_action); 15279 mtr_policy->act_cnt[i].rix_port_id_action = 0; 15280 } 15281 break; 15282 case MLX5_FLOW_FATE_DROP: 15283 case MLX5_FLOW_FATE_JUMP: 15284 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15285 mtr_policy->act_cnt[i].dr_jump_action[j] = 15286 NULL; 15287 break; 15288 default: 15289 /*Queue action do nothing*/ 15290 break; 15291 } 15292 } 15293 for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++) 15294 mtr_policy->dr_drop_action[j] = NULL; 15295 } 15296 15297 /** 15298 * Create policy action per domain, lock free, 15299 * (mutex should be acquired by caller). 15300 * Dispatcher for action type specific call. 15301 * 15302 * @param[in] dev 15303 * Pointer to the Ethernet device structure. 15304 * @param[in] mtr_policy 15305 * Meter policy struct. 15306 * @param[in] action 15307 * Action specification used to create meter actions. 15308 * @param[out] error 15309 * Perform verbose error reporting if not NULL. Initialized in case of 15310 * error only. 15311 * 15312 * @return 15313 * 0 on success, otherwise negative errno value. 15314 */ 15315 static int 15316 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, 15317 struct mlx5_flow_meter_policy *mtr_policy, 15318 const struct rte_flow_action *actions[RTE_COLORS], 15319 enum mlx5_meter_domain domain, 15320 struct rte_mtr_error *error) 15321 { 15322 struct mlx5_priv *priv = dev->data->dev_private; 15323 struct rte_flow_error flow_err; 15324 const struct rte_flow_action *act; 15325 uint64_t action_flags; 15326 struct mlx5_flow_handle dh; 15327 struct mlx5_flow dev_flow; 15328 struct mlx5_flow_dv_port_id_action_resource port_id_action; 15329 int i, ret; 15330 uint8_t egress, transfer; 15331 struct mlx5_meter_policy_action_container *act_cnt = NULL; 15332 union { 15333 struct mlx5_flow_dv_modify_hdr_resource res; 15334 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + 15335 sizeof(struct mlx5_modification_cmd) * 15336 (MLX5_MAX_MODIFY_NUM + 1)]; 15337 } mhdr_dummy; 15338 struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res; 15339 15340 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 15341 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 15342 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 15343 memset(&dev_flow, 0, sizeof(struct mlx5_flow)); 15344 memset(&port_id_action, 0, 15345 sizeof(struct mlx5_flow_dv_port_id_action_resource)); 15346 memset(mhdr_res, 0, sizeof(*mhdr_res)); 15347 mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB : 15348 (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX : 15349 MLX5DV_FLOW_TABLE_TYPE_NIC_RX); 15350 dev_flow.handle = &dh; 15351 dev_flow.dv.port_id_action = &port_id_action; 15352 dev_flow.external = true; 15353 for (i = 0; i < RTE_COLORS; i++) { 15354 if (i < MLX5_MTR_RTE_COLORS) 15355 act_cnt = &mtr_policy->act_cnt[i]; 15356 /* Skip the color policy actions creation. */ 15357 if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) || 15358 (i == RTE_COLOR_GREEN && mtr_policy->skip_g)) 15359 continue; 15360 action_flags = 0; 15361 for (act = actions[i]; 15362 act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) { 15363 switch (act->type) { 15364 case RTE_FLOW_ACTION_TYPE_MARK: 15365 { 15366 uint32_t tag_be = mlx5_flow_mark_set 15367 (((const struct rte_flow_action_mark *) 15368 (act->conf))->id); 15369 15370 if (i >= MLX5_MTR_RTE_COLORS) 15371 return -rte_mtr_error_set(error, 15372 ENOTSUP, 15373 RTE_MTR_ERROR_TYPE_METER_POLICY, 15374 NULL, 15375 "cannot create policy " 15376 "mark action for this color"); 15377 dev_flow.handle->mark = 1; 15378 if (flow_dv_tag_resource_register(dev, tag_be, 15379 &dev_flow, &flow_err)) 15380 return -rte_mtr_error_set(error, 15381 ENOTSUP, 15382 RTE_MTR_ERROR_TYPE_METER_POLICY, 15383 NULL, 15384 "cannot setup policy mark action"); 15385 MLX5_ASSERT(dev_flow.dv.tag_resource); 15386 act_cnt->rix_mark = 15387 dev_flow.handle->dvh.rix_tag; 15388 action_flags |= MLX5_FLOW_ACTION_MARK; 15389 break; 15390 } 15391 case RTE_FLOW_ACTION_TYPE_SET_TAG: 15392 if (i >= MLX5_MTR_RTE_COLORS) 15393 return -rte_mtr_error_set(error, 15394 ENOTSUP, 15395 RTE_MTR_ERROR_TYPE_METER_POLICY, 15396 NULL, 15397 "cannot create policy " 15398 "set tag action for this color"); 15399 if (flow_dv_convert_action_set_tag 15400 (dev, mhdr_res, 15401 (const struct rte_flow_action_set_tag *) 15402 act->conf, &flow_err)) 15403 return -rte_mtr_error_set(error, 15404 ENOTSUP, 15405 RTE_MTR_ERROR_TYPE_METER_POLICY, 15406 NULL, "cannot convert policy " 15407 "set tag action"); 15408 if (!mhdr_res->actions_num) 15409 return -rte_mtr_error_set(error, 15410 ENOTSUP, 15411 RTE_MTR_ERROR_TYPE_METER_POLICY, 15412 NULL, "cannot find policy " 15413 "set tag action"); 15414 action_flags |= MLX5_FLOW_ACTION_SET_TAG; 15415 break; 15416 case RTE_FLOW_ACTION_TYPE_DROP: 15417 { 15418 struct mlx5_flow_mtr_mng *mtrmng = 15419 priv->sh->mtrmng; 15420 struct mlx5_flow_tbl_data_entry *tbl_data; 15421 15422 /* 15423 * Create the drop table with 15424 * METER DROP level. 15425 */ 15426 if (!mtrmng->drop_tbl[domain]) { 15427 mtrmng->drop_tbl[domain] = 15428 flow_dv_tbl_resource_get(dev, 15429 MLX5_FLOW_TABLE_LEVEL_METER, 15430 egress, transfer, false, NULL, 0, 15431 0, MLX5_MTR_TABLE_ID_DROP, &flow_err); 15432 if (!mtrmng->drop_tbl[domain]) 15433 return -rte_mtr_error_set 15434 (error, ENOTSUP, 15435 RTE_MTR_ERROR_TYPE_METER_POLICY, 15436 NULL, 15437 "Failed to create meter drop table"); 15438 } 15439 tbl_data = container_of 15440 (mtrmng->drop_tbl[domain], 15441 struct mlx5_flow_tbl_data_entry, tbl); 15442 if (i < MLX5_MTR_RTE_COLORS) { 15443 act_cnt->dr_jump_action[domain] = 15444 tbl_data->jump.action; 15445 act_cnt->fate_action = 15446 MLX5_FLOW_FATE_DROP; 15447 } 15448 if (i == RTE_COLOR_RED) 15449 mtr_policy->dr_drop_action[domain] = 15450 tbl_data->jump.action; 15451 action_flags |= MLX5_FLOW_ACTION_DROP; 15452 break; 15453 } 15454 case RTE_FLOW_ACTION_TYPE_QUEUE: 15455 { 15456 if (i >= MLX5_MTR_RTE_COLORS) 15457 return -rte_mtr_error_set(error, 15458 ENOTSUP, 15459 RTE_MTR_ERROR_TYPE_METER_POLICY, 15460 NULL, "cannot create policy " 15461 "fate queue for this color"); 15462 act_cnt->queue = 15463 ((const struct rte_flow_action_queue *) 15464 (act->conf))->index; 15465 act_cnt->fate_action = 15466 MLX5_FLOW_FATE_QUEUE; 15467 dev_flow.handle->fate_action = 15468 MLX5_FLOW_FATE_QUEUE; 15469 mtr_policy->is_queue = 1; 15470 action_flags |= MLX5_FLOW_ACTION_QUEUE; 15471 break; 15472 } 15473 case RTE_FLOW_ACTION_TYPE_RSS: 15474 { 15475 int rss_size; 15476 15477 if (i >= MLX5_MTR_RTE_COLORS) 15478 return -rte_mtr_error_set(error, 15479 ENOTSUP, 15480 RTE_MTR_ERROR_TYPE_METER_POLICY, 15481 NULL, 15482 "cannot create policy " 15483 "rss action for this color"); 15484 /* 15485 * Save RSS conf into policy struct 15486 * for translate stage. 15487 */ 15488 rss_size = (int)rte_flow_conv 15489 (RTE_FLOW_CONV_OP_ACTION, 15490 NULL, 0, act, &flow_err); 15491 if (rss_size <= 0) 15492 return -rte_mtr_error_set(error, 15493 ENOTSUP, 15494 RTE_MTR_ERROR_TYPE_METER_POLICY, 15495 NULL, "Get the wrong " 15496 "rss action struct size"); 15497 act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO, 15498 rss_size, 0, SOCKET_ID_ANY); 15499 if (!act_cnt->rss) 15500 return -rte_mtr_error_set(error, 15501 ENOTSUP, 15502 RTE_MTR_ERROR_TYPE_METER_POLICY, 15503 NULL, 15504 "Fail to malloc rss action memory"); 15505 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION, 15506 act_cnt->rss, rss_size, 15507 act, &flow_err); 15508 if (ret < 0) 15509 return -rte_mtr_error_set(error, 15510 ENOTSUP, 15511 RTE_MTR_ERROR_TYPE_METER_POLICY, 15512 NULL, "Fail to save " 15513 "rss action into policy struct"); 15514 act_cnt->fate_action = 15515 MLX5_FLOW_FATE_SHARED_RSS; 15516 action_flags |= MLX5_FLOW_ACTION_RSS; 15517 break; 15518 } 15519 case RTE_FLOW_ACTION_TYPE_PORT_ID: 15520 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 15521 { 15522 struct mlx5_flow_dv_port_id_action_resource 15523 port_id_resource; 15524 uint32_t port_id = 0; 15525 15526 if (i >= MLX5_MTR_RTE_COLORS) 15527 return -rte_mtr_error_set(error, 15528 ENOTSUP, 15529 RTE_MTR_ERROR_TYPE_METER_POLICY, 15530 NULL, "cannot create policy " 15531 "port action for this color"); 15532 memset(&port_id_resource, 0, 15533 sizeof(port_id_resource)); 15534 if (flow_dv_translate_action_port_id(dev, act, 15535 &port_id, &flow_err)) 15536 return -rte_mtr_error_set(error, 15537 ENOTSUP, 15538 RTE_MTR_ERROR_TYPE_METER_POLICY, 15539 NULL, "cannot translate " 15540 "policy port action"); 15541 port_id_resource.port_id = port_id; 15542 if (flow_dv_port_id_action_resource_register 15543 (dev, &port_id_resource, 15544 &dev_flow, &flow_err)) 15545 return -rte_mtr_error_set(error, 15546 ENOTSUP, 15547 RTE_MTR_ERROR_TYPE_METER_POLICY, 15548 NULL, "cannot setup " 15549 "policy port action"); 15550 act_cnt->rix_port_id_action = 15551 dev_flow.handle->rix_port_id_action; 15552 act_cnt->fate_action = 15553 MLX5_FLOW_FATE_PORT_ID; 15554 action_flags |= MLX5_FLOW_ACTION_PORT_ID; 15555 break; 15556 } 15557 case RTE_FLOW_ACTION_TYPE_JUMP: 15558 { 15559 uint32_t jump_group = 0; 15560 uint32_t table = 0; 15561 struct mlx5_flow_tbl_data_entry *tbl_data; 15562 struct flow_grp_info grp_info = { 15563 .external = !!dev_flow.external, 15564 .transfer = !!transfer, 15565 .fdb_def_rule = !!priv->fdb_def_rule, 15566 .std_tbl_fix = 0, 15567 .skip_scale = dev_flow.skip_scale & 15568 (1 << MLX5_SCALE_FLOW_GROUP_BIT), 15569 }; 15570 struct mlx5_flow_meter_sub_policy *sub_policy = 15571 mtr_policy->sub_policys[domain][0]; 15572 15573 if (i >= MLX5_MTR_RTE_COLORS) 15574 return -rte_mtr_error_set(error, 15575 ENOTSUP, 15576 RTE_MTR_ERROR_TYPE_METER_POLICY, 15577 NULL, 15578 "cannot create policy " 15579 "jump action for this color"); 15580 jump_group = 15581 ((const struct rte_flow_action_jump *) 15582 act->conf)->group; 15583 if (mlx5_flow_group_to_table(dev, NULL, 15584 jump_group, 15585 &table, 15586 &grp_info, &flow_err)) 15587 return -rte_mtr_error_set(error, 15588 ENOTSUP, 15589 RTE_MTR_ERROR_TYPE_METER_POLICY, 15590 NULL, "cannot setup " 15591 "policy jump action"); 15592 sub_policy->jump_tbl[i] = 15593 flow_dv_tbl_resource_get(dev, 15594 table, egress, 15595 transfer, 15596 !!dev_flow.external, 15597 NULL, jump_group, 0, 15598 0, &flow_err); 15599 if 15600 (!sub_policy->jump_tbl[i]) 15601 return -rte_mtr_error_set(error, 15602 ENOTSUP, 15603 RTE_MTR_ERROR_TYPE_METER_POLICY, 15604 NULL, "cannot create jump action."); 15605 tbl_data = container_of 15606 (sub_policy->jump_tbl[i], 15607 struct mlx5_flow_tbl_data_entry, tbl); 15608 act_cnt->dr_jump_action[domain] = 15609 tbl_data->jump.action; 15610 act_cnt->fate_action = 15611 MLX5_FLOW_FATE_JUMP; 15612 action_flags |= MLX5_FLOW_ACTION_JUMP; 15613 break; 15614 } 15615 /* 15616 * No need to check meter hierarchy for Y or R colors 15617 * here since it is done in the validation stage. 15618 */ 15619 case RTE_FLOW_ACTION_TYPE_METER: 15620 { 15621 const struct rte_flow_action_meter *mtr; 15622 struct mlx5_flow_meter_info *next_fm; 15623 struct mlx5_flow_meter_policy *next_policy; 15624 struct rte_flow_action tag_action; 15625 struct mlx5_rte_flow_action_set_tag set_tag; 15626 uint32_t next_mtr_idx = 0; 15627 15628 mtr = act->conf; 15629 next_fm = mlx5_flow_meter_find(priv, 15630 mtr->mtr_id, 15631 &next_mtr_idx); 15632 if (!next_fm) 15633 return -rte_mtr_error_set(error, EINVAL, 15634 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15635 "Fail to find next meter."); 15636 if (next_fm->def_policy) 15637 return -rte_mtr_error_set(error, EINVAL, 15638 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 15639 "Hierarchy only supports termination meter."); 15640 next_policy = mlx5_flow_meter_policy_find(dev, 15641 next_fm->policy_id, NULL); 15642 MLX5_ASSERT(next_policy); 15643 if (next_fm->drop_cnt) { 15644 set_tag.id = 15645 (enum modify_reg) 15646 mlx5_flow_get_reg_id(dev, 15647 MLX5_MTR_ID, 15648 0, 15649 (struct rte_flow_error *)error); 15650 set_tag.offset = (priv->mtr_reg_share ? 15651 MLX5_MTR_COLOR_BITS : 0); 15652 set_tag.length = (priv->mtr_reg_share ? 15653 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : 15654 MLX5_REG_BITS); 15655 set_tag.data = next_mtr_idx; 15656 tag_action.type = 15657 (enum rte_flow_action_type) 15658 MLX5_RTE_FLOW_ACTION_TYPE_TAG; 15659 tag_action.conf = &set_tag; 15660 if (flow_dv_convert_action_set_reg 15661 (mhdr_res, &tag_action, 15662 (struct rte_flow_error *)error)) 15663 return -rte_errno; 15664 action_flags |= 15665 MLX5_FLOW_ACTION_SET_TAG; 15666 } 15667 act_cnt->fate_action = MLX5_FLOW_FATE_MTR; 15668 act_cnt->next_mtr_id = next_fm->meter_id; 15669 act_cnt->next_sub_policy = NULL; 15670 mtr_policy->is_hierarchy = 1; 15671 mtr_policy->dev = next_policy->dev; 15672 action_flags |= 15673 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 15674 break; 15675 } 15676 default: 15677 return -rte_mtr_error_set(error, ENOTSUP, 15678 RTE_MTR_ERROR_TYPE_METER_POLICY, 15679 NULL, "action type not supported"); 15680 } 15681 if (action_flags & MLX5_FLOW_ACTION_SET_TAG) { 15682 /* create modify action if needed. */ 15683 dev_flow.dv.group = 1; 15684 if (flow_dv_modify_hdr_resource_register 15685 (dev, mhdr_res, &dev_flow, &flow_err)) 15686 return -rte_mtr_error_set(error, 15687 ENOTSUP, 15688 RTE_MTR_ERROR_TYPE_METER_POLICY, 15689 NULL, "cannot register policy " 15690 "set tag action"); 15691 act_cnt->modify_hdr = 15692 dev_flow.handle->dvh.modify_hdr; 15693 } 15694 } 15695 } 15696 return 0; 15697 } 15698 15699 /** 15700 * Create policy action per domain, lock free, 15701 * (mutex should be acquired by caller). 15702 * Dispatcher for action type specific call. 15703 * 15704 * @param[in] dev 15705 * Pointer to the Ethernet device structure. 15706 * @param[in] mtr_policy 15707 * Meter policy struct. 15708 * @param[in] action 15709 * Action specification used to create meter actions. 15710 * @param[out] error 15711 * Perform verbose error reporting if not NULL. Initialized in case of 15712 * error only. 15713 * 15714 * @return 15715 * 0 on success, otherwise negative errno value. 15716 */ 15717 static int 15718 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev, 15719 struct mlx5_flow_meter_policy *mtr_policy, 15720 const struct rte_flow_action *actions[RTE_COLORS], 15721 struct rte_mtr_error *error) 15722 { 15723 int ret, i; 15724 uint16_t sub_policy_num; 15725 15726 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 15727 sub_policy_num = (mtr_policy->sub_policy_num >> 15728 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 15729 MLX5_MTR_SUB_POLICY_NUM_MASK; 15730 if (sub_policy_num) { 15731 ret = __flow_dv_create_domain_policy_acts(dev, 15732 mtr_policy, actions, 15733 (enum mlx5_meter_domain)i, error); 15734 /* Cleaning resource is done in the caller level. */ 15735 if (ret) 15736 return ret; 15737 } 15738 } 15739 return 0; 15740 } 15741 15742 /** 15743 * Query a DV flow rule for its statistics via DevX. 15744 * 15745 * @param[in] dev 15746 * Pointer to Ethernet device. 15747 * @param[in] cnt_idx 15748 * Index to the flow counter. 15749 * @param[out] data 15750 * Data retrieved by the query. 15751 * @param[out] error 15752 * Perform verbose error reporting if not NULL. 15753 * 15754 * @return 15755 * 0 on success, a negative errno value otherwise and rte_errno is set. 15756 */ 15757 int 15758 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data, 15759 struct rte_flow_error *error) 15760 { 15761 struct mlx5_priv *priv = dev->data->dev_private; 15762 struct rte_flow_query_count *qc = data; 15763 15764 if (!priv->sh->devx) 15765 return rte_flow_error_set(error, ENOTSUP, 15766 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15767 NULL, 15768 "counters are not supported"); 15769 if (cnt_idx) { 15770 uint64_t pkts, bytes; 15771 struct mlx5_flow_counter *cnt; 15772 int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes); 15773 15774 if (err) 15775 return rte_flow_error_set(error, -err, 15776 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15777 NULL, "cannot read counters"); 15778 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL); 15779 qc->hits_set = 1; 15780 qc->bytes_set = 1; 15781 qc->hits = pkts - cnt->hits; 15782 qc->bytes = bytes - cnt->bytes; 15783 if (qc->reset) { 15784 cnt->hits = pkts; 15785 cnt->bytes = bytes; 15786 } 15787 return 0; 15788 } 15789 return rte_flow_error_set(error, EINVAL, 15790 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15791 NULL, 15792 "counters are not available"); 15793 } 15794 15795 15796 /** 15797 * Query counter's action pointer for a DV flow rule via DevX. 15798 * 15799 * @param[in] dev 15800 * Pointer to Ethernet device. 15801 * @param[in] cnt_idx 15802 * Index to the flow counter. 15803 * @param[out] action_ptr 15804 * Action pointer for counter. 15805 * @param[out] error 15806 * Perform verbose error reporting if not NULL. 15807 * 15808 * @return 15809 * 0 on success, a negative errno value otherwise and rte_errno is set. 15810 */ 15811 int 15812 flow_dv_query_count_ptr(struct rte_eth_dev *dev, uint32_t cnt_idx, 15813 void **action_ptr, struct rte_flow_error *error) 15814 { 15815 struct mlx5_priv *priv = dev->data->dev_private; 15816 15817 if (!priv->sh->devx || !action_ptr) 15818 return rte_flow_error_set(error, ENOTSUP, 15819 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15820 NULL, 15821 "counters are not supported"); 15822 15823 if (cnt_idx) { 15824 struct mlx5_flow_counter *cnt = NULL; 15825 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL); 15826 if (cnt) { 15827 *action_ptr = cnt->action; 15828 return 0; 15829 } 15830 } 15831 return rte_flow_error_set(error, EINVAL, 15832 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15833 NULL, 15834 "counters are not available"); 15835 } 15836 15837 static int 15838 flow_dv_action_query(struct rte_eth_dev *dev, 15839 const struct rte_flow_action_handle *handle, void *data, 15840 struct rte_flow_error *error) 15841 { 15842 struct mlx5_age_param *age_param; 15843 struct rte_flow_query_age *resp; 15844 uint32_t act_idx = (uint32_t)(uintptr_t)handle; 15845 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; 15846 uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); 15847 struct mlx5_priv *priv = dev->data->dev_private; 15848 struct mlx5_aso_ct_action *ct; 15849 uint16_t owner; 15850 uint32_t dev_idx; 15851 15852 switch (type) { 15853 case MLX5_INDIRECT_ACTION_TYPE_AGE: 15854 age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params; 15855 resp = data; 15856 resp->aged = __atomic_load_n(&age_param->state, 15857 __ATOMIC_RELAXED) == AGE_TMOUT ? 15858 1 : 0; 15859 resp->sec_since_last_hit_valid = !resp->aged; 15860 if (resp->sec_since_last_hit_valid) 15861 resp->sec_since_last_hit = __atomic_load_n 15862 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15863 return 0; 15864 case MLX5_INDIRECT_ACTION_TYPE_COUNT: 15865 return flow_dv_query_count(dev, idx, data, error); 15866 case MLX5_INDIRECT_ACTION_TYPE_CT: 15867 owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx); 15868 if (owner != PORT_ID(priv)) 15869 return rte_flow_error_set(error, EACCES, 15870 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15871 NULL, 15872 "CT object owned by another port"); 15873 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx); 15874 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx); 15875 MLX5_ASSERT(ct); 15876 if (!ct->refcnt) 15877 return rte_flow_error_set(error, EFAULT, 15878 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15879 NULL, 15880 "CT object is inactive"); 15881 ((struct rte_flow_action_conntrack *)data)->peer_port = 15882 ct->peer; 15883 ((struct rte_flow_action_conntrack *)data)->is_original_dir = 15884 ct->is_original; 15885 if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data)) 15886 return rte_flow_error_set(error, EIO, 15887 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15888 NULL, 15889 "Failed to query CT context"); 15890 return 0; 15891 default: 15892 return rte_flow_error_set(error, ENOTSUP, 15893 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 15894 "action type query not supported"); 15895 } 15896 } 15897 15898 /** 15899 * Query a flow rule AGE action for aging information. 15900 * 15901 * @param[in] dev 15902 * Pointer to Ethernet device. 15903 * @param[in] flow 15904 * Pointer to the sub flow. 15905 * @param[out] data 15906 * data retrieved by the query. 15907 * @param[out] error 15908 * Perform verbose error reporting if not NULL. 15909 * 15910 * @return 15911 * 0 on success, a negative errno value otherwise and rte_errno is set. 15912 */ 15913 static int 15914 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow, 15915 void *data, struct rte_flow_error *error) 15916 { 15917 struct rte_flow_query_age *resp = data; 15918 struct mlx5_age_param *age_param; 15919 15920 if (flow->age) { 15921 struct mlx5_aso_age_action *act = 15922 flow_aso_age_get_by_idx(dev, flow->age); 15923 15924 age_param = &act->age_params; 15925 } else if (flow->counter) { 15926 age_param = flow_dv_counter_idx_get_age(dev, flow->counter); 15927 15928 if (!age_param || !age_param->timeout) 15929 return rte_flow_error_set 15930 (error, EINVAL, 15931 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15932 NULL, "cannot read age data"); 15933 } else { 15934 return rte_flow_error_set(error, EINVAL, 15935 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 15936 NULL, "age data not available"); 15937 } 15938 resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) == 15939 AGE_TMOUT ? 1 : 0; 15940 resp->sec_since_last_hit_valid = !resp->aged; 15941 if (resp->sec_since_last_hit_valid) 15942 resp->sec_since_last_hit = __atomic_load_n 15943 (&age_param->sec_since_last_hit, __ATOMIC_RELAXED); 15944 return 0; 15945 } 15946 15947 /** 15948 * Query a flow. 15949 * 15950 * @see rte_flow_query() 15951 * @see rte_flow_ops 15952 */ 15953 static int 15954 flow_dv_query(struct rte_eth_dev *dev, 15955 struct rte_flow *flow __rte_unused, 15956 const struct rte_flow_action *actions __rte_unused, 15957 void *data __rte_unused, 15958 struct rte_flow_error *error __rte_unused) 15959 { 15960 int ret = -EINVAL; 15961 15962 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 15963 switch (actions->type) { 15964 case RTE_FLOW_ACTION_TYPE_VOID: 15965 break; 15966 case RTE_FLOW_ACTION_TYPE_COUNT: 15967 ret = flow_dv_query_count(dev, flow->counter, data, 15968 error); 15969 break; 15970 case RTE_FLOW_ACTION_TYPE_AGE: 15971 ret = flow_dv_query_age(dev, flow, data, error); 15972 break; 15973 default: 15974 return rte_flow_error_set(error, ENOTSUP, 15975 RTE_FLOW_ERROR_TYPE_ACTION, 15976 actions, 15977 "action not supported"); 15978 } 15979 } 15980 return ret; 15981 } 15982 15983 /** 15984 * Destroy the meter table set. 15985 * Lock free, (mutex should be acquired by caller). 15986 * 15987 * @param[in] dev 15988 * Pointer to Ethernet device. 15989 * @param[in] fm 15990 * Meter information table. 15991 */ 15992 static void 15993 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev, 15994 struct mlx5_flow_meter_info *fm) 15995 { 15996 struct mlx5_priv *priv = dev->data->dev_private; 15997 int i; 15998 15999 if (!fm || !priv->config.dv_flow_en) 16000 return; 16001 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16002 if (fm->drop_rule[i]) { 16003 claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i])); 16004 fm->drop_rule[i] = NULL; 16005 } 16006 } 16007 } 16008 16009 static void 16010 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev) 16011 { 16012 struct mlx5_priv *priv = dev->data->dev_private; 16013 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16014 struct mlx5_flow_tbl_data_entry *tbl; 16015 int i, j; 16016 16017 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16018 if (mtrmng->def_rule[i]) { 16019 claim_zero(mlx5_flow_os_destroy_flow 16020 (mtrmng->def_rule[i])); 16021 mtrmng->def_rule[i] = NULL; 16022 } 16023 if (mtrmng->def_matcher[i]) { 16024 tbl = container_of(mtrmng->def_matcher[i]->tbl, 16025 struct mlx5_flow_tbl_data_entry, tbl); 16026 mlx5_list_unregister(tbl->matchers, 16027 &mtrmng->def_matcher[i]->entry); 16028 mtrmng->def_matcher[i] = NULL; 16029 } 16030 for (j = 0; j < MLX5_REG_BITS; j++) { 16031 if (mtrmng->drop_matcher[i][j]) { 16032 tbl = 16033 container_of(mtrmng->drop_matcher[i][j]->tbl, 16034 struct mlx5_flow_tbl_data_entry, 16035 tbl); 16036 mlx5_list_unregister(tbl->matchers, 16037 &mtrmng->drop_matcher[i][j]->entry); 16038 mtrmng->drop_matcher[i][j] = NULL; 16039 } 16040 } 16041 if (mtrmng->drop_tbl[i]) { 16042 flow_dv_tbl_resource_release(MLX5_SH(dev), 16043 mtrmng->drop_tbl[i]); 16044 mtrmng->drop_tbl[i] = NULL; 16045 } 16046 } 16047 } 16048 16049 /* Number of meter flow actions, count and jump or count and drop. */ 16050 #define METER_ACTIONS 2 16051 16052 static void 16053 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev, 16054 enum mlx5_meter_domain domain) 16055 { 16056 struct mlx5_priv *priv = dev->data->dev_private; 16057 struct mlx5_flow_meter_def_policy *def_policy = 16058 priv->sh->mtrmng->def_policy[domain]; 16059 16060 __flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy); 16061 mlx5_free(def_policy); 16062 priv->sh->mtrmng->def_policy[domain] = NULL; 16063 } 16064 16065 /** 16066 * Destroy the default policy table set. 16067 * 16068 * @param[in] dev 16069 * Pointer to Ethernet device. 16070 */ 16071 static void 16072 flow_dv_destroy_def_policy(struct rte_eth_dev *dev) 16073 { 16074 struct mlx5_priv *priv = dev->data->dev_private; 16075 int i; 16076 16077 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) 16078 if (priv->sh->mtrmng->def_policy[i]) 16079 __flow_dv_destroy_domain_def_policy(dev, 16080 (enum mlx5_meter_domain)i); 16081 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID; 16082 } 16083 16084 static int 16085 __flow_dv_create_policy_flow(struct rte_eth_dev *dev, 16086 uint32_t color_reg_c_idx, 16087 enum rte_color color, void *matcher_object, 16088 int actions_n, void *actions, 16089 bool match_src_port, const struct rte_flow_item *item, 16090 void **rule, const struct rte_flow_attr *attr) 16091 { 16092 int ret; 16093 struct mlx5_flow_dv_match_params value = { 16094 .size = sizeof(value.buf), 16095 }; 16096 struct mlx5_flow_dv_match_params matcher = { 16097 .size = sizeof(matcher.buf), 16098 }; 16099 struct mlx5_priv *priv = dev->data->dev_private; 16100 uint8_t misc_mask; 16101 16102 if (match_src_port && (priv->representor || priv->master)) { 16103 if (flow_dv_translate_item_port_id(dev, matcher.buf, 16104 value.buf, item, attr)) { 16105 DRV_LOG(ERR, "Failed to create meter policy%d flow's" 16106 " value with port.", color); 16107 return -1; 16108 } 16109 } 16110 flow_dv_match_meta_reg(matcher.buf, value.buf, 16111 (enum modify_reg)color_reg_c_idx, 16112 rte_col_2_mlx5_col(color), UINT32_MAX); 16113 misc_mask = flow_dv_matcher_enable(value.buf); 16114 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16115 ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value, 16116 actions_n, actions, rule); 16117 if (ret) { 16118 DRV_LOG(ERR, "Failed to create meter policy%d flow.", color); 16119 return -1; 16120 } 16121 return 0; 16122 } 16123 16124 static int 16125 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev, 16126 uint32_t color_reg_c_idx, 16127 uint16_t priority, 16128 struct mlx5_flow_meter_sub_policy *sub_policy, 16129 const struct rte_flow_attr *attr, 16130 bool match_src_port, 16131 const struct rte_flow_item *item, 16132 struct mlx5_flow_dv_matcher **policy_matcher, 16133 struct rte_flow_error *error) 16134 { 16135 struct mlx5_list_entry *entry; 16136 struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc; 16137 struct mlx5_flow_dv_matcher matcher = { 16138 .mask = { 16139 .size = sizeof(matcher.mask.buf), 16140 }, 16141 .tbl = tbl_rsc, 16142 }; 16143 struct mlx5_flow_dv_match_params value = { 16144 .size = sizeof(value.buf), 16145 }; 16146 struct mlx5_flow_cb_ctx ctx = { 16147 .error = error, 16148 .data = &matcher, 16149 }; 16150 struct mlx5_flow_tbl_data_entry *tbl_data; 16151 struct mlx5_priv *priv = dev->data->dev_private; 16152 const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; 16153 16154 if (match_src_port && (priv->representor || priv->master)) { 16155 if (flow_dv_translate_item_port_id(dev, matcher.mask.buf, 16156 value.buf, item, attr)) { 16157 DRV_LOG(ERR, "Failed to register meter policy%d matcher" 16158 " with port.", priority); 16159 return -1; 16160 } 16161 } 16162 tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl); 16163 if (priority < RTE_COLOR_RED) 16164 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16165 (enum modify_reg)color_reg_c_idx, 0, color_mask); 16166 matcher.priority = priority; 16167 matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf, 16168 matcher.mask.size); 16169 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16170 if (!entry) { 16171 DRV_LOG(ERR, "Failed to register meter drop matcher."); 16172 return -1; 16173 } 16174 *policy_matcher = 16175 container_of(entry, struct mlx5_flow_dv_matcher, entry); 16176 return 0; 16177 } 16178 16179 /** 16180 * Create the policy rules per domain. 16181 * 16182 * @param[in] dev 16183 * Pointer to Ethernet device. 16184 * @param[in] sub_policy 16185 * Pointer to sub policy table.. 16186 * @param[in] egress 16187 * Direction of the table. 16188 * @param[in] transfer 16189 * E-Switch or NIC flow. 16190 * @param[in] acts 16191 * Pointer to policy action list per color. 16192 * 16193 * @return 16194 * 0 on success, -1 otherwise. 16195 */ 16196 static int 16197 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev, 16198 struct mlx5_flow_meter_sub_policy *sub_policy, 16199 uint8_t egress, uint8_t transfer, bool match_src_port, 16200 struct mlx5_meter_policy_acts acts[RTE_COLORS]) 16201 { 16202 struct mlx5_priv *priv = dev->data->dev_private; 16203 struct rte_flow_error flow_err; 16204 uint32_t color_reg_c_idx; 16205 struct rte_flow_attr attr = { 16206 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 16207 .priority = 0, 16208 .ingress = 0, 16209 .egress = !!egress, 16210 .transfer = !!transfer, 16211 .reserved = 0, 16212 }; 16213 int i; 16214 int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err); 16215 struct mlx5_sub_policy_color_rule *color_rule; 16216 bool svport_match; 16217 struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL}; 16218 16219 if (ret < 0) 16220 return -1; 16221 /* Create policy table with POLICY level. */ 16222 if (!sub_policy->tbl_rsc) 16223 sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev, 16224 MLX5_FLOW_TABLE_LEVEL_POLICY, 16225 egress, transfer, false, NULL, 0, 0, 16226 sub_policy->idx, &flow_err); 16227 if (!sub_policy->tbl_rsc) { 16228 DRV_LOG(ERR, 16229 "Failed to create meter sub policy table."); 16230 return -1; 16231 } 16232 /* Prepare matchers. */ 16233 color_reg_c_idx = ret; 16234 for (i = 0; i < RTE_COLORS; i++) { 16235 TAILQ_INIT(&sub_policy->color_rules[i]); 16236 if (!acts[i].actions_n) 16237 continue; 16238 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 16239 sizeof(struct mlx5_sub_policy_color_rule), 16240 0, SOCKET_ID_ANY); 16241 if (!color_rule) { 16242 DRV_LOG(ERR, "No memory to create color rule."); 16243 goto err_exit; 16244 } 16245 tmp_rules[i] = color_rule; 16246 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 16247 color_rule, next_port); 16248 color_rule->src_port = priv->representor_id; 16249 /* No use. */ 16250 attr.priority = i; 16251 /* Create matchers for colors. */ 16252 svport_match = (i != RTE_COLOR_RED) ? match_src_port : false; 16253 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 16254 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 16255 &attr, svport_match, NULL, 16256 &color_rule->matcher, &flow_err)) { 16257 DRV_LOG(ERR, "Failed to create color%u matcher.", i); 16258 goto err_exit; 16259 } 16260 /* Create flow, matching color. */ 16261 if (__flow_dv_create_policy_flow(dev, 16262 color_reg_c_idx, (enum rte_color)i, 16263 color_rule->matcher->matcher_object, 16264 acts[i].actions_n, acts[i].dv_actions, 16265 svport_match, NULL, &color_rule->rule, 16266 &attr)) { 16267 DRV_LOG(ERR, "Failed to create color%u rule.", i); 16268 goto err_exit; 16269 } 16270 } 16271 return 0; 16272 err_exit: 16273 /* All the policy rules will be cleared. */ 16274 do { 16275 color_rule = tmp_rules[i]; 16276 if (color_rule) { 16277 if (color_rule->rule) 16278 mlx5_flow_os_destroy_flow(color_rule->rule); 16279 if (color_rule->matcher) { 16280 struct mlx5_flow_tbl_data_entry *tbl = 16281 container_of(color_rule->matcher->tbl, 16282 typeof(*tbl), tbl); 16283 mlx5_list_unregister(tbl->matchers, 16284 &color_rule->matcher->entry); 16285 } 16286 TAILQ_REMOVE(&sub_policy->color_rules[i], 16287 color_rule, next_port); 16288 mlx5_free(color_rule); 16289 } 16290 } while (i--); 16291 return -1; 16292 } 16293 16294 static int 16295 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev, 16296 struct mlx5_flow_meter_policy *mtr_policy, 16297 struct mlx5_flow_meter_sub_policy *sub_policy, 16298 uint32_t domain) 16299 { 16300 struct mlx5_priv *priv = dev->data->dev_private; 16301 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16302 struct mlx5_flow_dv_tag_resource *tag; 16303 struct mlx5_flow_dv_port_id_action_resource *port_action; 16304 struct mlx5_hrxq *hrxq; 16305 struct mlx5_flow_meter_info *next_fm = NULL; 16306 struct mlx5_flow_meter_policy *next_policy; 16307 struct mlx5_flow_meter_sub_policy *next_sub_policy; 16308 struct mlx5_flow_tbl_data_entry *tbl_data; 16309 struct rte_flow_error error; 16310 uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16311 uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16312 bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX); 16313 bool match_src_port = false; 16314 int i; 16315 16316 /* If RSS or Queue, no previous actions / rules is created. */ 16317 for (i = 0; i < RTE_COLORS; i++) { 16318 acts[i].actions_n = 0; 16319 if (i == RTE_COLOR_RED) { 16320 /* Only support drop on red. */ 16321 acts[i].dv_actions[0] = 16322 mtr_policy->dr_drop_action[domain]; 16323 acts[i].actions_n = 1; 16324 continue; 16325 } 16326 if (i == RTE_COLOR_GREEN && 16327 mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) { 16328 struct rte_flow_attr attr = { 16329 .transfer = transfer 16330 }; 16331 16332 next_fm = mlx5_flow_meter_find(priv, 16333 mtr_policy->act_cnt[i].next_mtr_id, 16334 NULL); 16335 if (!next_fm) { 16336 DRV_LOG(ERR, 16337 "Failed to get next hierarchy meter."); 16338 goto err_exit; 16339 } 16340 if (mlx5_flow_meter_attach(priv, next_fm, 16341 &attr, &error)) { 16342 DRV_LOG(ERR, "%s", error.message); 16343 next_fm = NULL; 16344 goto err_exit; 16345 } 16346 /* Meter action must be the first for TX. */ 16347 if (mtr_first) { 16348 acts[i].dv_actions[acts[i].actions_n] = 16349 next_fm->meter_action; 16350 acts[i].actions_n++; 16351 } 16352 } 16353 if (mtr_policy->act_cnt[i].rix_mark) { 16354 tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], 16355 mtr_policy->act_cnt[i].rix_mark); 16356 if (!tag) { 16357 DRV_LOG(ERR, "Failed to find " 16358 "mark action for policy."); 16359 goto err_exit; 16360 } 16361 acts[i].dv_actions[acts[i].actions_n] = tag->action; 16362 acts[i].actions_n++; 16363 } 16364 if (mtr_policy->act_cnt[i].modify_hdr) { 16365 acts[i].dv_actions[acts[i].actions_n] = 16366 mtr_policy->act_cnt[i].modify_hdr->action; 16367 acts[i].actions_n++; 16368 } 16369 if (mtr_policy->act_cnt[i].fate_action) { 16370 switch (mtr_policy->act_cnt[i].fate_action) { 16371 case MLX5_FLOW_FATE_PORT_ID: 16372 port_action = mlx5_ipool_get 16373 (priv->sh->ipool[MLX5_IPOOL_PORT_ID], 16374 mtr_policy->act_cnt[i].rix_port_id_action); 16375 if (!port_action) { 16376 DRV_LOG(ERR, "Failed to find " 16377 "port action for policy."); 16378 goto err_exit; 16379 } 16380 acts[i].dv_actions[acts[i].actions_n] = 16381 port_action->action; 16382 acts[i].actions_n++; 16383 mtr_policy->dev = dev; 16384 match_src_port = true; 16385 break; 16386 case MLX5_FLOW_FATE_DROP: 16387 case MLX5_FLOW_FATE_JUMP: 16388 acts[i].dv_actions[acts[i].actions_n] = 16389 mtr_policy->act_cnt[i].dr_jump_action[domain]; 16390 acts[i].actions_n++; 16391 break; 16392 case MLX5_FLOW_FATE_SHARED_RSS: 16393 case MLX5_FLOW_FATE_QUEUE: 16394 hrxq = mlx5_ipool_get 16395 (priv->sh->ipool[MLX5_IPOOL_HRXQ], 16396 sub_policy->rix_hrxq[i]); 16397 if (!hrxq) { 16398 DRV_LOG(ERR, "Failed to find " 16399 "queue action for policy."); 16400 goto err_exit; 16401 } 16402 acts[i].dv_actions[acts[i].actions_n] = 16403 hrxq->action; 16404 acts[i].actions_n++; 16405 break; 16406 case MLX5_FLOW_FATE_MTR: 16407 if (!next_fm) { 16408 DRV_LOG(ERR, 16409 "No next hierarchy meter."); 16410 goto err_exit; 16411 } 16412 if (!mtr_first) { 16413 acts[i].dv_actions[acts[i].actions_n] = 16414 next_fm->meter_action; 16415 acts[i].actions_n++; 16416 } 16417 if (mtr_policy->act_cnt[i].next_sub_policy) { 16418 next_sub_policy = 16419 mtr_policy->act_cnt[i].next_sub_policy; 16420 } else { 16421 next_policy = 16422 mlx5_flow_meter_policy_find(dev, 16423 next_fm->policy_id, NULL); 16424 MLX5_ASSERT(next_policy); 16425 next_sub_policy = 16426 next_policy->sub_policys[domain][0]; 16427 } 16428 tbl_data = 16429 container_of(next_sub_policy->tbl_rsc, 16430 struct mlx5_flow_tbl_data_entry, tbl); 16431 acts[i].dv_actions[acts[i].actions_n++] = 16432 tbl_data->jump.action; 16433 if (mtr_policy->act_cnt[i].modify_hdr) 16434 match_src_port = !!transfer; 16435 break; 16436 default: 16437 /*Queue action do nothing*/ 16438 break; 16439 } 16440 } 16441 } 16442 if (__flow_dv_create_domain_policy_rules(dev, sub_policy, 16443 egress, transfer, match_src_port, acts)) { 16444 DRV_LOG(ERR, 16445 "Failed to create policy rules per domain."); 16446 goto err_exit; 16447 } 16448 return 0; 16449 err_exit: 16450 if (next_fm) 16451 mlx5_flow_meter_detach(priv, next_fm); 16452 return -1; 16453 } 16454 16455 /** 16456 * Create the policy rules. 16457 * 16458 * @param[in] dev 16459 * Pointer to Ethernet device. 16460 * @param[in,out] mtr_policy 16461 * Pointer to meter policy table. 16462 * 16463 * @return 16464 * 0 on success, -1 otherwise. 16465 */ 16466 static int 16467 flow_dv_create_policy_rules(struct rte_eth_dev *dev, 16468 struct mlx5_flow_meter_policy *mtr_policy) 16469 { 16470 int i; 16471 uint16_t sub_policy_num; 16472 16473 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16474 sub_policy_num = (mtr_policy->sub_policy_num >> 16475 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 16476 MLX5_MTR_SUB_POLICY_NUM_MASK; 16477 if (!sub_policy_num) 16478 continue; 16479 /* Prepare actions list and create policy rules. */ 16480 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16481 mtr_policy->sub_policys[i][0], i)) { 16482 DRV_LOG(ERR, "Failed to create policy action " 16483 "list per domain."); 16484 return -1; 16485 } 16486 } 16487 return 0; 16488 } 16489 16490 static int 16491 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain) 16492 { 16493 struct mlx5_priv *priv = dev->data->dev_private; 16494 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16495 struct mlx5_flow_meter_def_policy *def_policy; 16496 struct mlx5_flow_tbl_resource *jump_tbl; 16497 struct mlx5_flow_tbl_data_entry *tbl_data; 16498 uint8_t egress, transfer; 16499 struct rte_flow_error error; 16500 struct mlx5_meter_policy_acts acts[RTE_COLORS]; 16501 int ret; 16502 16503 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16504 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16505 def_policy = mtrmng->def_policy[domain]; 16506 if (!def_policy) { 16507 def_policy = mlx5_malloc(MLX5_MEM_ZERO, 16508 sizeof(struct mlx5_flow_meter_def_policy), 16509 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 16510 if (!def_policy) { 16511 DRV_LOG(ERR, "Failed to alloc default policy table."); 16512 goto def_policy_error; 16513 } 16514 mtrmng->def_policy[domain] = def_policy; 16515 /* Create the meter suffix table with SUFFIX level. */ 16516 jump_tbl = flow_dv_tbl_resource_get(dev, 16517 MLX5_FLOW_TABLE_LEVEL_METER, 16518 egress, transfer, false, NULL, 0, 16519 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16520 if (!jump_tbl) { 16521 DRV_LOG(ERR, 16522 "Failed to create meter suffix table."); 16523 goto def_policy_error; 16524 } 16525 def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl; 16526 tbl_data = container_of(jump_tbl, 16527 struct mlx5_flow_tbl_data_entry, tbl); 16528 def_policy->dr_jump_action[RTE_COLOR_GREEN] = 16529 tbl_data->jump.action; 16530 acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action; 16531 acts[RTE_COLOR_GREEN].actions_n = 1; 16532 /* 16533 * YELLOW has the same default policy as GREEN does. 16534 * G & Y share the same table and action. The 2nd time of table 16535 * resource getting is just to update the reference count for 16536 * the releasing stage. 16537 */ 16538 jump_tbl = flow_dv_tbl_resource_get(dev, 16539 MLX5_FLOW_TABLE_LEVEL_METER, 16540 egress, transfer, false, NULL, 0, 16541 0, MLX5_MTR_TABLE_ID_SUFFIX, &error); 16542 if (!jump_tbl) { 16543 DRV_LOG(ERR, 16544 "Failed to get meter suffix table."); 16545 goto def_policy_error; 16546 } 16547 def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl; 16548 tbl_data = container_of(jump_tbl, 16549 struct mlx5_flow_tbl_data_entry, tbl); 16550 def_policy->dr_jump_action[RTE_COLOR_YELLOW] = 16551 tbl_data->jump.action; 16552 acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action; 16553 acts[RTE_COLOR_YELLOW].actions_n = 1; 16554 /* Create jump action to the drop table. */ 16555 if (!mtrmng->drop_tbl[domain]) { 16556 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get 16557 (dev, MLX5_FLOW_TABLE_LEVEL_METER, 16558 egress, transfer, false, NULL, 0, 16559 0, MLX5_MTR_TABLE_ID_DROP, &error); 16560 if (!mtrmng->drop_tbl[domain]) { 16561 DRV_LOG(ERR, "Failed to create meter " 16562 "drop table for default policy."); 16563 goto def_policy_error; 16564 } 16565 } 16566 /* all RED: unique Drop table for jump action. */ 16567 tbl_data = container_of(mtrmng->drop_tbl[domain], 16568 struct mlx5_flow_tbl_data_entry, tbl); 16569 def_policy->dr_jump_action[RTE_COLOR_RED] = 16570 tbl_data->jump.action; 16571 acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action; 16572 acts[RTE_COLOR_RED].actions_n = 1; 16573 /* Create default policy rules. */ 16574 ret = __flow_dv_create_domain_policy_rules(dev, 16575 &def_policy->sub_policy, 16576 egress, transfer, false, acts); 16577 if (ret) { 16578 DRV_LOG(ERR, "Failed to create default policy rules."); 16579 goto def_policy_error; 16580 } 16581 } 16582 return 0; 16583 def_policy_error: 16584 __flow_dv_destroy_domain_def_policy(dev, 16585 (enum mlx5_meter_domain)domain); 16586 return -1; 16587 } 16588 16589 /** 16590 * Create the default policy table set. 16591 * 16592 * @param[in] dev 16593 * Pointer to Ethernet device. 16594 * @return 16595 * 0 on success, -1 otherwise. 16596 */ 16597 static int 16598 flow_dv_create_def_policy(struct rte_eth_dev *dev) 16599 { 16600 struct mlx5_priv *priv = dev->data->dev_private; 16601 int i; 16602 16603 /* Non-termination policy table. */ 16604 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16605 if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER) 16606 continue; 16607 if (__flow_dv_create_domain_def_policy(dev, i)) { 16608 DRV_LOG(ERR, "Failed to create default policy"); 16609 /* Rollback the created default policies for others. */ 16610 flow_dv_destroy_def_policy(dev); 16611 return -1; 16612 } 16613 } 16614 return 0; 16615 } 16616 16617 /** 16618 * Create the needed meter tables. 16619 * Lock free, (mutex should be acquired by caller). 16620 * 16621 * @param[in] dev 16622 * Pointer to Ethernet device. 16623 * @param[in] fm 16624 * Meter information table. 16625 * @param[in] mtr_idx 16626 * Meter index. 16627 * @param[in] domain_bitmap 16628 * Domain bitmap. 16629 * @return 16630 * 0 on success, -1 otherwise. 16631 */ 16632 static int 16633 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev, 16634 struct mlx5_flow_meter_info *fm, 16635 uint32_t mtr_idx, 16636 uint8_t domain_bitmap) 16637 { 16638 struct mlx5_priv *priv = dev->data->dev_private; 16639 struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng; 16640 struct rte_flow_error error; 16641 struct mlx5_flow_tbl_data_entry *tbl_data; 16642 uint8_t egress, transfer; 16643 void *actions[METER_ACTIONS]; 16644 int domain, ret, i; 16645 struct mlx5_flow_counter *cnt; 16646 struct mlx5_flow_dv_match_params value = { 16647 .size = sizeof(value.buf), 16648 }; 16649 struct mlx5_flow_dv_match_params matcher_para = { 16650 .size = sizeof(matcher_para.buf), 16651 }; 16652 int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID, 16653 0, &error); 16654 uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1; 16655 uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0; 16656 struct mlx5_list_entry *entry; 16657 struct mlx5_flow_dv_matcher matcher = { 16658 .mask = { 16659 .size = sizeof(matcher.mask.buf), 16660 }, 16661 }; 16662 struct mlx5_flow_dv_matcher *drop_matcher; 16663 struct mlx5_flow_cb_ctx ctx = { 16664 .error = &error, 16665 .data = &matcher, 16666 }; 16667 uint8_t misc_mask; 16668 16669 if (!priv->mtr_en || mtr_id_reg_c < 0) { 16670 rte_errno = ENOTSUP; 16671 return -1; 16672 } 16673 for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) { 16674 if (!(domain_bitmap & (1 << domain)) || 16675 (mtrmng->def_rule[domain] && !fm->drop_cnt)) 16676 continue; 16677 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0; 16678 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0; 16679 /* Create the drop table with METER DROP level. */ 16680 if (!mtrmng->drop_tbl[domain]) { 16681 mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev, 16682 MLX5_FLOW_TABLE_LEVEL_METER, 16683 egress, transfer, false, NULL, 0, 16684 0, MLX5_MTR_TABLE_ID_DROP, &error); 16685 if (!mtrmng->drop_tbl[domain]) { 16686 DRV_LOG(ERR, "Failed to create meter drop table."); 16687 goto policy_error; 16688 } 16689 } 16690 /* Create default matcher in drop table. */ 16691 matcher.tbl = mtrmng->drop_tbl[domain], 16692 tbl_data = container_of(mtrmng->drop_tbl[domain], 16693 struct mlx5_flow_tbl_data_entry, tbl); 16694 if (!mtrmng->def_matcher[domain]) { 16695 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16696 (enum modify_reg)mtr_id_reg_c, 16697 0, 0); 16698 matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY; 16699 matcher.crc = rte_raw_cksum 16700 ((const void *)matcher.mask.buf, 16701 matcher.mask.size); 16702 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16703 if (!entry) { 16704 DRV_LOG(ERR, "Failed to register meter " 16705 "drop default matcher."); 16706 goto policy_error; 16707 } 16708 mtrmng->def_matcher[domain] = container_of(entry, 16709 struct mlx5_flow_dv_matcher, entry); 16710 } 16711 /* Create default rule in drop table. */ 16712 if (!mtrmng->def_rule[domain]) { 16713 i = 0; 16714 actions[i++] = priv->sh->dr_drop_action; 16715 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16716 (enum modify_reg)mtr_id_reg_c, 0, 0); 16717 misc_mask = flow_dv_matcher_enable(value.buf); 16718 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16719 ret = mlx5_flow_os_create_flow 16720 (mtrmng->def_matcher[domain]->matcher_object, 16721 (void *)&value, i, actions, 16722 &mtrmng->def_rule[domain]); 16723 if (ret) { 16724 DRV_LOG(ERR, "Failed to create meter " 16725 "default drop rule for drop table."); 16726 goto policy_error; 16727 } 16728 } 16729 if (!fm->drop_cnt) 16730 continue; 16731 MLX5_ASSERT(mtrmng->max_mtr_bits); 16732 if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) { 16733 /* Create matchers for Drop. */ 16734 flow_dv_match_meta_reg(matcher.mask.buf, value.buf, 16735 (enum modify_reg)mtr_id_reg_c, 0, 16736 (mtr_id_mask << mtr_id_offset)); 16737 matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits; 16738 matcher.crc = rte_raw_cksum 16739 ((const void *)matcher.mask.buf, 16740 matcher.mask.size); 16741 entry = mlx5_list_register(tbl_data->matchers, &ctx); 16742 if (!entry) { 16743 DRV_LOG(ERR, 16744 "Failed to register meter drop matcher."); 16745 goto policy_error; 16746 } 16747 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] = 16748 container_of(entry, struct mlx5_flow_dv_matcher, 16749 entry); 16750 } 16751 drop_matcher = 16752 mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]; 16753 /* Create drop rule, matching meter_id only. */ 16754 flow_dv_match_meta_reg(matcher_para.buf, value.buf, 16755 (enum modify_reg)mtr_id_reg_c, 16756 (mtr_idx << mtr_id_offset), UINT32_MAX); 16757 i = 0; 16758 cnt = flow_dv_counter_get_by_idx(dev, 16759 fm->drop_cnt, NULL); 16760 actions[i++] = cnt->action; 16761 actions[i++] = priv->sh->dr_drop_action; 16762 misc_mask = flow_dv_matcher_enable(value.buf); 16763 __flow_dv_adjust_buf_size(&value.size, misc_mask); 16764 ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object, 16765 (void *)&value, i, actions, 16766 &fm->drop_rule[domain]); 16767 if (ret) { 16768 DRV_LOG(ERR, "Failed to create meter " 16769 "drop rule for drop table."); 16770 goto policy_error; 16771 } 16772 } 16773 return 0; 16774 policy_error: 16775 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 16776 if (fm->drop_rule[i]) { 16777 claim_zero(mlx5_flow_os_destroy_flow 16778 (fm->drop_rule[i])); 16779 fm->drop_rule[i] = NULL; 16780 } 16781 } 16782 return -1; 16783 } 16784 16785 static struct mlx5_flow_meter_sub_policy * 16786 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, 16787 struct mlx5_flow_meter_policy *mtr_policy, 16788 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS], 16789 struct mlx5_flow_meter_sub_policy *next_sub_policy, 16790 bool *is_reuse) 16791 { 16792 struct mlx5_priv *priv = dev->data->dev_private; 16793 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16794 uint32_t sub_policy_idx = 0; 16795 uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0}; 16796 uint32_t i, j; 16797 struct mlx5_hrxq *hrxq; 16798 struct mlx5_flow_handle dh; 16799 struct mlx5_meter_policy_action_container *act_cnt; 16800 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16801 uint16_t sub_policy_num; 16802 16803 rte_spinlock_lock(&mtr_policy->sl); 16804 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16805 if (!rss_desc[i]) 16806 continue; 16807 hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]); 16808 if (!hrxq_idx[i]) { 16809 rte_spinlock_unlock(&mtr_policy->sl); 16810 return NULL; 16811 } 16812 } 16813 sub_policy_num = (mtr_policy->sub_policy_num >> 16814 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16815 MLX5_MTR_SUB_POLICY_NUM_MASK; 16816 for (j = 0; j < sub_policy_num; j++) { 16817 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16818 if (rss_desc[i] && 16819 hrxq_idx[i] != 16820 mtr_policy->sub_policys[domain][j]->rix_hrxq[i]) 16821 break; 16822 } 16823 if (i >= MLX5_MTR_RTE_COLORS) { 16824 /* 16825 * Found the sub policy table with 16826 * the same queue per color. 16827 */ 16828 rte_spinlock_unlock(&mtr_policy->sl); 16829 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16830 mlx5_hrxq_release(dev, hrxq_idx[i]); 16831 *is_reuse = true; 16832 return mtr_policy->sub_policys[domain][j]; 16833 } 16834 } 16835 /* Create sub policy. */ 16836 if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) { 16837 /* Reuse the first pre-allocated sub_policy. */ 16838 sub_policy = mtr_policy->sub_policys[domain][0]; 16839 sub_policy_idx = sub_policy->idx; 16840 } else { 16841 sub_policy = mlx5_ipool_zmalloc 16842 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16843 &sub_policy_idx); 16844 if (!sub_policy || 16845 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { 16846 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) 16847 mlx5_hrxq_release(dev, hrxq_idx[i]); 16848 goto rss_sub_policy_error; 16849 } 16850 sub_policy->idx = sub_policy_idx; 16851 sub_policy->main_policy = mtr_policy; 16852 } 16853 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 16854 if (!rss_desc[i]) 16855 continue; 16856 sub_policy->rix_hrxq[i] = hrxq_idx[i]; 16857 if (mtr_policy->is_hierarchy) { 16858 act_cnt = &mtr_policy->act_cnt[i]; 16859 act_cnt->next_sub_policy = next_sub_policy; 16860 mlx5_hrxq_release(dev, hrxq_idx[i]); 16861 } else { 16862 /* 16863 * Overwrite the last action from 16864 * RSS action to Queue action. 16865 */ 16866 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], 16867 hrxq_idx[i]); 16868 if (!hrxq) { 16869 DRV_LOG(ERR, "Failed to get policy hrxq"); 16870 goto rss_sub_policy_error; 16871 } 16872 act_cnt = &mtr_policy->act_cnt[i]; 16873 if (act_cnt->rix_mark || act_cnt->modify_hdr) { 16874 memset(&dh, 0, sizeof(struct mlx5_flow_handle)); 16875 if (act_cnt->rix_mark) 16876 dh.mark = 1; 16877 dh.fate_action = MLX5_FLOW_FATE_QUEUE; 16878 dh.rix_hrxq = hrxq_idx[i]; 16879 flow_drv_rxq_flags_set(dev, &dh); 16880 } 16881 } 16882 } 16883 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, 16884 sub_policy, domain)) { 16885 DRV_LOG(ERR, "Failed to create policy " 16886 "rules for ingress domain."); 16887 goto rss_sub_policy_error; 16888 } 16889 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16890 i = (mtr_policy->sub_policy_num >> 16891 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16892 MLX5_MTR_SUB_POLICY_NUM_MASK; 16893 if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) { 16894 DRV_LOG(ERR, "No free sub-policy slot."); 16895 goto rss_sub_policy_error; 16896 } 16897 mtr_policy->sub_policys[domain][i] = sub_policy; 16898 i++; 16899 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 16900 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 16901 mtr_policy->sub_policy_num |= 16902 (i & MLX5_MTR_SUB_POLICY_NUM_MASK) << 16903 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 16904 } 16905 rte_spinlock_unlock(&mtr_policy->sl); 16906 *is_reuse = false; 16907 return sub_policy; 16908 rss_sub_policy_error: 16909 if (sub_policy) { 16910 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 16911 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 16912 i = (mtr_policy->sub_policy_num >> 16913 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 16914 MLX5_MTR_SUB_POLICY_NUM_MASK; 16915 mtr_policy->sub_policys[domain][i] = NULL; 16916 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 16917 sub_policy->idx); 16918 } 16919 } 16920 rte_spinlock_unlock(&mtr_policy->sl); 16921 return NULL; 16922 } 16923 16924 /** 16925 * Find the policy table for prefix table with RSS. 16926 * 16927 * @param[in] dev 16928 * Pointer to Ethernet device. 16929 * @param[in] mtr_policy 16930 * Pointer to meter policy table. 16931 * @param[in] rss_desc 16932 * Pointer to rss_desc 16933 * @return 16934 * Pointer to table set on success, NULL otherwise and rte_errno is set. 16935 */ 16936 static struct mlx5_flow_meter_sub_policy * 16937 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev, 16938 struct mlx5_flow_meter_policy *mtr_policy, 16939 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]) 16940 { 16941 struct mlx5_priv *priv = dev->data->dev_private; 16942 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 16943 struct mlx5_flow_meter_info *next_fm; 16944 struct mlx5_flow_meter_policy *next_policy; 16945 struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL; 16946 struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM]; 16947 struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM]; 16948 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 16949 bool reuse_sub_policy; 16950 uint32_t i = 0; 16951 uint32_t j = 0; 16952 16953 while (true) { 16954 /* Iterate hierarchy to get all policies in this hierarchy. */ 16955 policies[i++] = mtr_policy; 16956 if (!mtr_policy->is_hierarchy) 16957 break; 16958 if (i >= MLX5_MTR_CHAIN_MAX_NUM) { 16959 DRV_LOG(ERR, "Exceed max meter number in hierarchy."); 16960 return NULL; 16961 } 16962 next_fm = mlx5_flow_meter_find(priv, 16963 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 16964 if (!next_fm) { 16965 DRV_LOG(ERR, "Failed to get next meter in hierarchy."); 16966 return NULL; 16967 } 16968 next_policy = 16969 mlx5_flow_meter_policy_find(dev, next_fm->policy_id, 16970 NULL); 16971 MLX5_ASSERT(next_policy); 16972 mtr_policy = next_policy; 16973 } 16974 while (i) { 16975 /** 16976 * From last policy to the first one in hierarchy, 16977 * create / get the sub policy for each of them. 16978 */ 16979 sub_policy = __flow_dv_meter_get_rss_sub_policy(dev, 16980 policies[--i], 16981 rss_desc, 16982 next_sub_policy, 16983 &reuse_sub_policy); 16984 if (!sub_policy) { 16985 DRV_LOG(ERR, "Failed to get the sub policy."); 16986 goto err_exit; 16987 } 16988 if (!reuse_sub_policy) 16989 sub_policies[j++] = sub_policy; 16990 next_sub_policy = sub_policy; 16991 } 16992 return sub_policy; 16993 err_exit: 16994 while (j) { 16995 uint16_t sub_policy_num; 16996 16997 sub_policy = sub_policies[--j]; 16998 mtr_policy = sub_policy->main_policy; 16999 __flow_dv_destroy_sub_policy_rules(dev, sub_policy); 17000 if (sub_policy != mtr_policy->sub_policys[domain][0]) { 17001 sub_policy_num = (mtr_policy->sub_policy_num >> 17002 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17003 MLX5_MTR_SUB_POLICY_NUM_MASK; 17004 mtr_policy->sub_policys[domain][sub_policy_num - 1] = 17005 NULL; 17006 sub_policy_num--; 17007 mtr_policy->sub_policy_num &= 17008 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17009 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)); 17010 mtr_policy->sub_policy_num |= 17011 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) << 17012 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i); 17013 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17014 sub_policy->idx); 17015 } 17016 } 17017 return NULL; 17018 } 17019 17020 /** 17021 * Create the sub policy tag rule for all meters in hierarchy. 17022 * 17023 * @param[in] dev 17024 * Pointer to Ethernet device. 17025 * @param[in] fm 17026 * Meter information table. 17027 * @param[in] src_port 17028 * The src port this extra rule should use. 17029 * @param[in] item 17030 * The src port match item. 17031 * @param[out] error 17032 * Perform verbose error reporting if not NULL. 17033 * @return 17034 * 0 on success, a negative errno value otherwise and rte_errno is set. 17035 */ 17036 static int 17037 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev, 17038 struct mlx5_flow_meter_info *fm, 17039 int32_t src_port, 17040 const struct rte_flow_item *item, 17041 struct rte_flow_error *error) 17042 { 17043 struct mlx5_priv *priv = dev->data->dev_private; 17044 struct mlx5_flow_meter_policy *mtr_policy; 17045 struct mlx5_flow_meter_sub_policy *sub_policy; 17046 struct mlx5_flow_meter_info *next_fm = NULL; 17047 struct mlx5_flow_meter_policy *next_policy; 17048 struct mlx5_flow_meter_sub_policy *next_sub_policy; 17049 struct mlx5_flow_tbl_data_entry *tbl_data; 17050 struct mlx5_sub_policy_color_rule *color_rule; 17051 struct mlx5_meter_policy_acts acts; 17052 uint32_t color_reg_c_idx; 17053 bool mtr_first = (src_port != UINT16_MAX) ? true : false; 17054 struct rte_flow_attr attr = { 17055 .group = MLX5_FLOW_TABLE_LEVEL_POLICY, 17056 .priority = 0, 17057 .ingress = 0, 17058 .egress = 0, 17059 .transfer = 1, 17060 .reserved = 0, 17061 }; 17062 uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER; 17063 int i; 17064 17065 mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 17066 MLX5_ASSERT(mtr_policy); 17067 if (!mtr_policy->is_hierarchy) 17068 return 0; 17069 next_fm = mlx5_flow_meter_find(priv, 17070 mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL); 17071 if (!next_fm) { 17072 return rte_flow_error_set(error, EINVAL, 17073 RTE_FLOW_ERROR_TYPE_ACTION, NULL, 17074 "Failed to find next meter in hierarchy."); 17075 } 17076 if (!next_fm->drop_cnt) 17077 goto exit; 17078 color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); 17079 sub_policy = mtr_policy->sub_policys[domain][0]; 17080 for (i = 0; i < RTE_COLORS; i++) { 17081 bool rule_exist = false; 17082 struct mlx5_meter_policy_action_container *act_cnt; 17083 17084 if (i >= RTE_COLOR_YELLOW) 17085 break; 17086 TAILQ_FOREACH(color_rule, 17087 &sub_policy->color_rules[i], next_port) 17088 if (color_rule->src_port == src_port) { 17089 rule_exist = true; 17090 break; 17091 } 17092 if (rule_exist) 17093 continue; 17094 color_rule = mlx5_malloc(MLX5_MEM_ZERO, 17095 sizeof(struct mlx5_sub_policy_color_rule), 17096 0, SOCKET_ID_ANY); 17097 if (!color_rule) 17098 return rte_flow_error_set(error, ENOMEM, 17099 RTE_FLOW_ERROR_TYPE_ACTION, 17100 NULL, "No memory to create tag color rule."); 17101 color_rule->src_port = src_port; 17102 attr.priority = i; 17103 next_policy = mlx5_flow_meter_policy_find(dev, 17104 next_fm->policy_id, NULL); 17105 MLX5_ASSERT(next_policy); 17106 next_sub_policy = next_policy->sub_policys[domain][0]; 17107 tbl_data = container_of(next_sub_policy->tbl_rsc, 17108 struct mlx5_flow_tbl_data_entry, tbl); 17109 act_cnt = &mtr_policy->act_cnt[i]; 17110 if (mtr_first) { 17111 acts.dv_actions[0] = next_fm->meter_action; 17112 acts.dv_actions[1] = act_cnt->modify_hdr->action; 17113 } else { 17114 acts.dv_actions[0] = act_cnt->modify_hdr->action; 17115 acts.dv_actions[1] = next_fm->meter_action; 17116 } 17117 acts.dv_actions[2] = tbl_data->jump.action; 17118 acts.actions_n = 3; 17119 if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) { 17120 next_fm = NULL; 17121 goto err_exit; 17122 } 17123 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx, 17124 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy, 17125 &attr, true, item, 17126 &color_rule->matcher, error)) { 17127 rte_flow_error_set(error, errno, 17128 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17129 "Failed to create hierarchy meter matcher."); 17130 goto err_exit; 17131 } 17132 if (__flow_dv_create_policy_flow(dev, color_reg_c_idx, 17133 (enum rte_color)i, 17134 color_rule->matcher->matcher_object, 17135 acts.actions_n, acts.dv_actions, 17136 true, item, 17137 &color_rule->rule, &attr)) { 17138 rte_flow_error_set(error, errno, 17139 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17140 "Failed to create hierarchy meter rule."); 17141 goto err_exit; 17142 } 17143 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i], 17144 color_rule, next_port); 17145 } 17146 exit: 17147 /** 17148 * Recursive call to iterate all meters in hierarchy and 17149 * create needed rules. 17150 */ 17151 return flow_dv_meter_hierarchy_rule_create(dev, next_fm, 17152 src_port, item, error); 17153 err_exit: 17154 if (color_rule) { 17155 if (color_rule->rule) 17156 mlx5_flow_os_destroy_flow(color_rule->rule); 17157 if (color_rule->matcher) { 17158 struct mlx5_flow_tbl_data_entry *tbl = 17159 container_of(color_rule->matcher->tbl, 17160 typeof(*tbl), tbl); 17161 mlx5_list_unregister(tbl->matchers, 17162 &color_rule->matcher->entry); 17163 } 17164 mlx5_free(color_rule); 17165 } 17166 if (next_fm) 17167 mlx5_flow_meter_detach(priv, next_fm); 17168 return -rte_errno; 17169 } 17170 17171 /** 17172 * Destroy the sub policy table with RX queue. 17173 * 17174 * @param[in] dev 17175 * Pointer to Ethernet device. 17176 * @param[in] mtr_policy 17177 * Pointer to meter policy table. 17178 */ 17179 static void 17180 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, 17181 struct mlx5_flow_meter_policy *mtr_policy) 17182 { 17183 struct mlx5_priv *priv = dev->data->dev_private; 17184 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 17185 uint32_t domain = MLX5_MTR_DOMAIN_INGRESS; 17186 uint32_t i, j; 17187 uint16_t sub_policy_num, new_policy_num; 17188 17189 rte_spinlock_lock(&mtr_policy->sl); 17190 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 17191 switch (mtr_policy->act_cnt[i].fate_action) { 17192 case MLX5_FLOW_FATE_SHARED_RSS: 17193 sub_policy_num = (mtr_policy->sub_policy_num >> 17194 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & 17195 MLX5_MTR_SUB_POLICY_NUM_MASK; 17196 new_policy_num = sub_policy_num; 17197 for (j = 0; j < sub_policy_num; j++) { 17198 sub_policy = 17199 mtr_policy->sub_policys[domain][j]; 17200 if (sub_policy) { 17201 __flow_dv_destroy_sub_policy_rules(dev, 17202 sub_policy); 17203 if (sub_policy != 17204 mtr_policy->sub_policys[domain][0]) { 17205 mtr_policy->sub_policys[domain][j] = 17206 NULL; 17207 mlx5_ipool_free 17208 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 17209 sub_policy->idx); 17210 new_policy_num--; 17211 } 17212 } 17213 } 17214 if (new_policy_num != sub_policy_num) { 17215 mtr_policy->sub_policy_num &= 17216 ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 17217 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); 17218 mtr_policy->sub_policy_num |= 17219 (new_policy_num & 17220 MLX5_MTR_SUB_POLICY_NUM_MASK) << 17221 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain); 17222 } 17223 break; 17224 case MLX5_FLOW_FATE_QUEUE: 17225 sub_policy = mtr_policy->sub_policys[domain][0]; 17226 __flow_dv_destroy_sub_policy_rules(dev, 17227 sub_policy); 17228 break; 17229 default: 17230 /*Other actions without queue and do nothing*/ 17231 break; 17232 } 17233 } 17234 rte_spinlock_unlock(&mtr_policy->sl); 17235 } 17236 /** 17237 * Check whether the DR drop action is supported on the root table or not. 17238 * 17239 * Create a simple flow with DR drop action on root table to validate 17240 * if DR drop action on root table is supported or not. 17241 * 17242 * @param[in] dev 17243 * Pointer to rte_eth_dev structure. 17244 * 17245 * @return 17246 * 0 on success, a negative errno value otherwise and rte_errno is set. 17247 */ 17248 int 17249 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev) 17250 { 17251 struct mlx5_priv *priv = dev->data->dev_private; 17252 struct mlx5_dev_ctx_shared *sh = priv->sh; 17253 struct mlx5_flow_dv_match_params mask = { 17254 .size = sizeof(mask.buf), 17255 }; 17256 struct mlx5_flow_dv_match_params value = { 17257 .size = sizeof(value.buf), 17258 }; 17259 struct mlx5dv_flow_matcher_attr dv_attr = { 17260 .type = IBV_FLOW_ATTR_NORMAL, 17261 .priority = 0, 17262 .match_criteria_enable = 0, 17263 .match_mask = (void *)&mask, 17264 }; 17265 struct mlx5_flow_tbl_resource *tbl = NULL; 17266 void *matcher = NULL; 17267 void *flow = NULL; 17268 int ret = -1; 17269 17270 tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 17271 0, 0, 0, NULL); 17272 if (!tbl) 17273 goto err; 17274 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17275 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17276 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 17277 tbl->obj, &matcher); 17278 if (ret) 17279 goto err; 17280 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17281 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17282 &sh->dr_drop_action, &flow); 17283 err: 17284 /* 17285 * If DR drop action is not supported on root table, flow create will 17286 * be failed with EOPNOTSUPP or EPROTONOSUPPORT. 17287 */ 17288 if (!flow) { 17289 if (matcher && 17290 (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP)) 17291 DRV_LOG(INFO, "DR drop action is not supported in root table."); 17292 else 17293 DRV_LOG(ERR, "Unexpected error in DR drop action support detection"); 17294 ret = -1; 17295 } else { 17296 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17297 } 17298 if (matcher) 17299 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17300 if (tbl) 17301 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17302 return ret; 17303 } 17304 17305 /** 17306 * Validate the batch counter support in root table. 17307 * 17308 * Create a simple flow with invalid counter and drop action on root table to 17309 * validate if batch counter with offset on root table is supported or not. 17310 * 17311 * @param[in] dev 17312 * Pointer to rte_eth_dev structure. 17313 * 17314 * @return 17315 * 0 on success, a negative errno value otherwise and rte_errno is set. 17316 */ 17317 int 17318 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev) 17319 { 17320 struct mlx5_priv *priv = dev->data->dev_private; 17321 struct mlx5_dev_ctx_shared *sh = priv->sh; 17322 struct mlx5_flow_dv_match_params mask = { 17323 .size = sizeof(mask.buf), 17324 }; 17325 struct mlx5_flow_dv_match_params value = { 17326 .size = sizeof(value.buf), 17327 }; 17328 struct mlx5dv_flow_matcher_attr dv_attr = { 17329 .type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS, 17330 .priority = 0, 17331 .match_criteria_enable = 0, 17332 .match_mask = (void *)&mask, 17333 }; 17334 void *actions[2] = { 0 }; 17335 struct mlx5_flow_tbl_resource *tbl = NULL; 17336 struct mlx5_devx_obj *dcs = NULL; 17337 void *matcher = NULL; 17338 void *flow = NULL; 17339 int ret = -1; 17340 17341 tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL, 17342 0, 0, 0, NULL); 17343 if (!tbl) 17344 goto err; 17345 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4); 17346 if (!dcs) 17347 goto err; 17348 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX, 17349 &actions[0]); 17350 if (ret) 17351 goto err; 17352 dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); 17353 __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); 17354 ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr, 17355 tbl->obj, &matcher); 17356 if (ret) 17357 goto err; 17358 __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); 17359 ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, 17360 actions, &flow); 17361 err: 17362 /* 17363 * If batch counter with offset is not supported, the driver will not 17364 * validate the invalid offset value, flow create should success. 17365 * In this case, it means batch counter is not supported in root table. 17366 * 17367 * Otherwise, if flow create is failed, counter offset is supported. 17368 */ 17369 if (flow) { 17370 DRV_LOG(INFO, "Batch counter is not supported in root " 17371 "table. Switch to fallback mode."); 17372 rte_errno = ENOTSUP; 17373 ret = -rte_errno; 17374 claim_zero(mlx5_flow_os_destroy_flow(flow)); 17375 } else { 17376 /* Check matcher to make sure validate fail at flow create. */ 17377 if (!matcher || (matcher && errno != EINVAL)) 17378 DRV_LOG(ERR, "Unexpected error in counter offset " 17379 "support detection"); 17380 ret = 0; 17381 } 17382 if (actions[0]) 17383 claim_zero(mlx5_flow_os_destroy_flow_action(actions[0])); 17384 if (matcher) 17385 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); 17386 if (tbl) 17387 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); 17388 if (dcs) 17389 claim_zero(mlx5_devx_cmd_destroy(dcs)); 17390 return ret; 17391 } 17392 17393 /** 17394 * Query a devx counter. 17395 * 17396 * @param[in] dev 17397 * Pointer to the Ethernet device structure. 17398 * @param[in] cnt 17399 * Index to the flow counter. 17400 * @param[in] clear 17401 * Set to clear the counter statistics. 17402 * @param[out] pkts 17403 * The statistics value of packets. 17404 * @param[out] bytes 17405 * The statistics value of bytes. 17406 * 17407 * @return 17408 * 0 on success, otherwise return -1. 17409 */ 17410 static int 17411 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear, 17412 uint64_t *pkts, uint64_t *bytes) 17413 { 17414 struct mlx5_priv *priv = dev->data->dev_private; 17415 struct mlx5_flow_counter *cnt; 17416 uint64_t inn_pkts, inn_bytes; 17417 int ret; 17418 17419 if (!priv->sh->devx) 17420 return -1; 17421 17422 ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes); 17423 if (ret) 17424 return -1; 17425 cnt = flow_dv_counter_get_by_idx(dev, counter, NULL); 17426 *pkts = inn_pkts - cnt->hits; 17427 *bytes = inn_bytes - cnt->bytes; 17428 if (clear) { 17429 cnt->hits = inn_pkts; 17430 cnt->bytes = inn_bytes; 17431 } 17432 return 0; 17433 } 17434 17435 /** 17436 * Get aged-out flows. 17437 * 17438 * @param[in] dev 17439 * Pointer to the Ethernet device structure. 17440 * @param[in] context 17441 * The address of an array of pointers to the aged-out flows contexts. 17442 * @param[in] nb_contexts 17443 * The length of context array pointers. 17444 * @param[out] error 17445 * Perform verbose error reporting if not NULL. Initialized in case of 17446 * error only. 17447 * 17448 * @return 17449 * how many contexts get in success, otherwise negative errno value. 17450 * if nb_contexts is 0, return the amount of all aged contexts. 17451 * if nb_contexts is not 0 , return the amount of aged flows reported 17452 * in the context array. 17453 * @note: only stub for now 17454 */ 17455 static int 17456 flow_dv_get_aged_flows(struct rte_eth_dev *dev, 17457 void **context, 17458 uint32_t nb_contexts, 17459 struct rte_flow_error *error) 17460 { 17461 struct mlx5_priv *priv = dev->data->dev_private; 17462 struct mlx5_age_info *age_info; 17463 struct mlx5_age_param *age_param; 17464 struct mlx5_flow_counter *counter; 17465 struct mlx5_aso_age_action *act; 17466 int nb_flows = 0; 17467 17468 if (nb_contexts && !context) 17469 return rte_flow_error_set(error, EINVAL, 17470 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17471 NULL, "empty context"); 17472 age_info = GET_PORT_AGE_INFO(priv); 17473 rte_spinlock_lock(&age_info->aged_sl); 17474 LIST_FOREACH(act, &age_info->aged_aso, next) { 17475 nb_flows++; 17476 if (nb_contexts) { 17477 context[nb_flows - 1] = 17478 act->age_params.context; 17479 if (!(--nb_contexts)) 17480 break; 17481 } 17482 } 17483 TAILQ_FOREACH(counter, &age_info->aged_counters, next) { 17484 nb_flows++; 17485 if (nb_contexts) { 17486 age_param = MLX5_CNT_TO_AGE(counter); 17487 context[nb_flows - 1] = age_param->context; 17488 if (!(--nb_contexts)) 17489 break; 17490 } 17491 } 17492 rte_spinlock_unlock(&age_info->aged_sl); 17493 MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); 17494 return nb_flows; 17495 } 17496 17497 /* 17498 * Mutex-protected thunk to lock-free flow_dv_counter_alloc(). 17499 */ 17500 static uint32_t 17501 flow_dv_counter_allocate(struct rte_eth_dev *dev) 17502 { 17503 return flow_dv_counter_alloc(dev, 0); 17504 } 17505 17506 /** 17507 * Validate indirect action. 17508 * Dispatcher for action type specific validation. 17509 * 17510 * @param[in] dev 17511 * Pointer to the Ethernet device structure. 17512 * @param[in] conf 17513 * Indirect action configuration. 17514 * @param[in] action 17515 * The indirect action object to validate. 17516 * @param[out] error 17517 * Perform verbose error reporting if not NULL. Initialized in case of 17518 * error only. 17519 * 17520 * @return 17521 * 0 on success, otherwise negative errno value. 17522 */ 17523 static int 17524 flow_dv_action_validate(struct rte_eth_dev *dev, 17525 const struct rte_flow_indir_action_conf *conf, 17526 const struct rte_flow_action *action, 17527 struct rte_flow_error *err) 17528 { 17529 struct mlx5_priv *priv = dev->data->dev_private; 17530 17531 RTE_SET_USED(conf); 17532 switch (action->type) { 17533 case RTE_FLOW_ACTION_TYPE_RSS: 17534 /* 17535 * priv->obj_ops is set according to driver capabilities. 17536 * When DevX capabilities are 17537 * sufficient, it is set to devx_obj_ops. 17538 * Otherwise, it is set to ibv_obj_ops. 17539 * ibv_obj_ops doesn't support ind_table_modify operation. 17540 * In this case the indirect RSS action can't be used. 17541 */ 17542 if (priv->obj_ops.ind_table_modify == NULL) 17543 return rte_flow_error_set 17544 (err, ENOTSUP, 17545 RTE_FLOW_ERROR_TYPE_ACTION, 17546 NULL, 17547 "Indirect RSS action not supported"); 17548 return mlx5_validate_action_rss(dev, action, err); 17549 case RTE_FLOW_ACTION_TYPE_AGE: 17550 if (!priv->sh->aso_age_mng) 17551 return rte_flow_error_set(err, ENOTSUP, 17552 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 17553 NULL, 17554 "Indirect age action not supported"); 17555 return flow_dv_validate_action_age(0, action, dev, err); 17556 case RTE_FLOW_ACTION_TYPE_COUNT: 17557 return flow_dv_validate_action_count(dev, true, 0, err); 17558 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 17559 if (!priv->sh->ct_aso_en) 17560 return rte_flow_error_set(err, ENOTSUP, 17561 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 17562 "ASO CT is not supported"); 17563 return mlx5_validate_action_ct(dev, action->conf, err); 17564 default: 17565 return rte_flow_error_set(err, ENOTSUP, 17566 RTE_FLOW_ERROR_TYPE_ACTION, 17567 NULL, 17568 "action type not supported"); 17569 } 17570 } 17571 17572 /* 17573 * Check if the RSS configurations for colors of a meter policy match 17574 * each other, except the queues. 17575 * 17576 * @param[in] r1 17577 * Pointer to the first RSS flow action. 17578 * @param[in] r2 17579 * Pointer to the second RSS flow action. 17580 * 17581 * @return 17582 * 0 on match, 1 on conflict. 17583 */ 17584 static inline int 17585 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1, 17586 const struct rte_flow_action_rss *r2) 17587 { 17588 if (r1 == NULL || r2 == NULL) 17589 return 0; 17590 if (!(r1->level <= 1 && r2->level <= 1) && 17591 !(r1->level > 1 && r2->level > 1)) 17592 return 1; 17593 if (r1->types != r2->types && 17594 !((r1->types == 0 || r1->types == RTE_ETH_RSS_IP) && 17595 (r2->types == 0 || r2->types == RTE_ETH_RSS_IP))) 17596 return 1; 17597 if (r1->key || r2->key) { 17598 const void *key1 = r1->key ? r1->key : rss_hash_default_key; 17599 const void *key2 = r2->key ? r2->key : rss_hash_default_key; 17600 17601 if (memcmp(key1, key2, MLX5_RSS_HASH_KEY_LEN)) 17602 return 1; 17603 } 17604 return 0; 17605 } 17606 17607 /** 17608 * Validate the meter hierarchy chain for meter policy. 17609 * 17610 * @param[in] dev 17611 * Pointer to the Ethernet device structure. 17612 * @param[in] meter_id 17613 * Meter id. 17614 * @param[in] action_flags 17615 * Holds the actions detected until now. 17616 * @param[out] is_rss 17617 * Is RSS or not. 17618 * @param[out] hierarchy_domain 17619 * The domain bitmap for hierarchy policy. 17620 * @param[out] error 17621 * Perform verbose error reporting if not NULL. Initialized in case of 17622 * error only. 17623 * 17624 * @return 17625 * 0 on success, otherwise negative errno value with error set. 17626 */ 17627 static int 17628 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, 17629 uint32_t meter_id, 17630 uint64_t action_flags, 17631 bool *is_rss, 17632 uint8_t *hierarchy_domain, 17633 struct rte_mtr_error *error) 17634 { 17635 struct mlx5_priv *priv = dev->data->dev_private; 17636 struct mlx5_flow_meter_info *fm; 17637 struct mlx5_flow_meter_policy *policy; 17638 uint8_t cnt = 1; 17639 17640 if (action_flags & (MLX5_FLOW_FATE_ACTIONS | 17641 MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17642 return -rte_mtr_error_set(error, EINVAL, 17643 RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, 17644 NULL, 17645 "Multiple fate actions not supported."); 17646 *hierarchy_domain = 0; 17647 while (true) { 17648 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 17649 if (!fm) 17650 return -rte_mtr_error_set(error, EINVAL, 17651 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17652 "Meter not found in meter hierarchy."); 17653 if (fm->def_policy) 17654 return -rte_mtr_error_set(error, EINVAL, 17655 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 17656 "Non termination meter not supported in hierarchy."); 17657 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 17658 MLX5_ASSERT(policy); 17659 /** 17660 * Only inherit the supported domains of the first meter in 17661 * hierarchy. 17662 * One meter supports at least one domain. 17663 */ 17664 if (!*hierarchy_domain) { 17665 if (policy->transfer) 17666 *hierarchy_domain |= 17667 MLX5_MTR_DOMAIN_TRANSFER_BIT; 17668 if (policy->ingress) 17669 *hierarchy_domain |= 17670 MLX5_MTR_DOMAIN_INGRESS_BIT; 17671 if (policy->egress) 17672 *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT; 17673 } 17674 if (!policy->is_hierarchy) { 17675 *is_rss = policy->is_rss; 17676 break; 17677 } 17678 meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id; 17679 if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM) 17680 return -rte_mtr_error_set(error, EINVAL, 17681 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 17682 "Exceed max hierarchy meter number."); 17683 } 17684 return 0; 17685 } 17686 17687 /** 17688 * Validate meter policy actions. 17689 * Dispatcher for action type specific validation. 17690 * 17691 * @param[in] dev 17692 * Pointer to the Ethernet device structure. 17693 * @param[in] action 17694 * The meter policy action object to validate. 17695 * @param[in] attr 17696 * Attributes of flow to determine steering domain. 17697 * @param[out] error 17698 * Perform verbose error reporting if not NULL. Initialized in case of 17699 * error only. 17700 * 17701 * @return 17702 * 0 on success, otherwise negative errno value. 17703 */ 17704 static int 17705 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, 17706 const struct rte_flow_action *actions[RTE_COLORS], 17707 struct rte_flow_attr *attr, 17708 bool *is_rss, 17709 uint8_t *domain_bitmap, 17710 uint8_t *policy_mode, 17711 struct rte_mtr_error *error) 17712 { 17713 struct mlx5_priv *priv = dev->data->dev_private; 17714 struct mlx5_dev_config *dev_conf = &priv->config; 17715 const struct rte_flow_action *act; 17716 uint64_t action_flags[RTE_COLORS] = {0}; 17717 int actions_n; 17718 int i, ret; 17719 struct rte_flow_error flow_err; 17720 uint8_t domain_color[RTE_COLORS] = {0}; 17721 uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT; 17722 uint8_t hierarchy_domain = 0; 17723 const struct rte_flow_action_meter *mtr; 17724 bool def_green = false; 17725 bool def_yellow = false; 17726 const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; 17727 17728 if (!priv->config.dv_esw_en) 17729 def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 17730 *domain_bitmap = def_domain; 17731 /* Red color could only support DROP action. */ 17732 if (!actions[RTE_COLOR_RED] || 17733 actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) 17734 return -rte_mtr_error_set(error, ENOTSUP, 17735 RTE_MTR_ERROR_TYPE_METER_POLICY, 17736 NULL, "Red color only supports drop action."); 17737 /* 17738 * Check default policy actions: 17739 * Green / Yellow: no action, Red: drop action 17740 * Either G or Y will trigger default policy actions to be created. 17741 */ 17742 if (!actions[RTE_COLOR_GREEN] || 17743 actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) 17744 def_green = true; 17745 if (!actions[RTE_COLOR_YELLOW] || 17746 actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) 17747 def_yellow = true; 17748 if (def_green && def_yellow) { 17749 *policy_mode = MLX5_MTR_POLICY_MODE_DEF; 17750 return 0; 17751 } else if (!def_green && def_yellow) { 17752 *policy_mode = MLX5_MTR_POLICY_MODE_OG; 17753 } else if (def_green && !def_yellow) { 17754 *policy_mode = MLX5_MTR_POLICY_MODE_OY; 17755 } else { 17756 *policy_mode = MLX5_MTR_POLICY_MODE_ALL; 17757 } 17758 /* Set to empty string in case of NULL pointer access by user. */ 17759 flow_err.message = ""; 17760 for (i = 0; i < RTE_COLORS; i++) { 17761 act = actions[i]; 17762 for (action_flags[i] = 0, actions_n = 0; 17763 act && act->type != RTE_FLOW_ACTION_TYPE_END; 17764 act++) { 17765 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) 17766 return -rte_mtr_error_set(error, ENOTSUP, 17767 RTE_MTR_ERROR_TYPE_METER_POLICY, 17768 NULL, "too many actions"); 17769 switch (act->type) { 17770 case RTE_FLOW_ACTION_TYPE_PORT_ID: 17771 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: 17772 if (!priv->config.dv_esw_en) 17773 return -rte_mtr_error_set(error, 17774 ENOTSUP, 17775 RTE_MTR_ERROR_TYPE_METER_POLICY, 17776 NULL, "PORT action validate check" 17777 " fail for ESW disable"); 17778 ret = flow_dv_validate_action_port_id(dev, 17779 action_flags[i], 17780 act, attr, &flow_err); 17781 if (ret) 17782 return -rte_mtr_error_set(error, 17783 ENOTSUP, 17784 RTE_MTR_ERROR_TYPE_METER_POLICY, 17785 NULL, flow_err.message ? 17786 flow_err.message : 17787 "PORT action validate check fail"); 17788 ++actions_n; 17789 action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID; 17790 break; 17791 case RTE_FLOW_ACTION_TYPE_MARK: 17792 ret = flow_dv_validate_action_mark(dev, act, 17793 action_flags[i], 17794 attr, &flow_err); 17795 if (ret < 0) 17796 return -rte_mtr_error_set(error, 17797 ENOTSUP, 17798 RTE_MTR_ERROR_TYPE_METER_POLICY, 17799 NULL, flow_err.message ? 17800 flow_err.message : 17801 "Mark action validate check fail"); 17802 if (dev_conf->dv_xmeta_en != 17803 MLX5_XMETA_MODE_LEGACY) 17804 return -rte_mtr_error_set(error, 17805 ENOTSUP, 17806 RTE_MTR_ERROR_TYPE_METER_POLICY, 17807 NULL, "Extend MARK action is " 17808 "not supported. Please try use " 17809 "default policy for meter."); 17810 action_flags[i] |= MLX5_FLOW_ACTION_MARK; 17811 ++actions_n; 17812 break; 17813 case RTE_FLOW_ACTION_TYPE_SET_TAG: 17814 ret = flow_dv_validate_action_set_tag(dev, 17815 act, action_flags[i], 17816 attr, &flow_err); 17817 if (ret) 17818 return -rte_mtr_error_set(error, 17819 ENOTSUP, 17820 RTE_MTR_ERROR_TYPE_METER_POLICY, 17821 NULL, flow_err.message ? 17822 flow_err.message : 17823 "Set tag action validate check fail"); 17824 action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG; 17825 ++actions_n; 17826 break; 17827 case RTE_FLOW_ACTION_TYPE_DROP: 17828 ret = mlx5_flow_validate_action_drop 17829 (action_flags[i], attr, &flow_err); 17830 if (ret < 0) 17831 return -rte_mtr_error_set(error, 17832 ENOTSUP, 17833 RTE_MTR_ERROR_TYPE_METER_POLICY, 17834 NULL, flow_err.message ? 17835 flow_err.message : 17836 "Drop action validate check fail"); 17837 action_flags[i] |= MLX5_FLOW_ACTION_DROP; 17838 ++actions_n; 17839 break; 17840 case RTE_FLOW_ACTION_TYPE_QUEUE: 17841 /* 17842 * Check whether extensive 17843 * metadata feature is engaged. 17844 */ 17845 if (dev_conf->dv_flow_en && 17846 (dev_conf->dv_xmeta_en != 17847 MLX5_XMETA_MODE_LEGACY) && 17848 mlx5_flow_ext_mreg_supported(dev)) 17849 return -rte_mtr_error_set(error, 17850 ENOTSUP, 17851 RTE_MTR_ERROR_TYPE_METER_POLICY, 17852 NULL, "Queue action with meta " 17853 "is not supported. Please try use " 17854 "default policy for meter."); 17855 ret = mlx5_flow_validate_action_queue(act, 17856 action_flags[i], dev, 17857 attr, &flow_err); 17858 if (ret < 0) 17859 return -rte_mtr_error_set(error, 17860 ENOTSUP, 17861 RTE_MTR_ERROR_TYPE_METER_POLICY, 17862 NULL, flow_err.message ? 17863 flow_err.message : 17864 "Queue action validate check fail"); 17865 action_flags[i] |= MLX5_FLOW_ACTION_QUEUE; 17866 ++actions_n; 17867 break; 17868 case RTE_FLOW_ACTION_TYPE_RSS: 17869 if (dev_conf->dv_flow_en && 17870 (dev_conf->dv_xmeta_en != 17871 MLX5_XMETA_MODE_LEGACY) && 17872 mlx5_flow_ext_mreg_supported(dev)) 17873 return -rte_mtr_error_set(error, 17874 ENOTSUP, 17875 RTE_MTR_ERROR_TYPE_METER_POLICY, 17876 NULL, "RSS action with meta " 17877 "is not supported. Please try use " 17878 "default policy for meter."); 17879 ret = mlx5_validate_action_rss(dev, act, 17880 &flow_err); 17881 if (ret < 0) 17882 return -rte_mtr_error_set(error, 17883 ENOTSUP, 17884 RTE_MTR_ERROR_TYPE_METER_POLICY, 17885 NULL, flow_err.message ? 17886 flow_err.message : 17887 "RSS action validate check fail"); 17888 action_flags[i] |= MLX5_FLOW_ACTION_RSS; 17889 ++actions_n; 17890 /* Either G or Y will set the RSS. */ 17891 rss_color[i] = act->conf; 17892 break; 17893 case RTE_FLOW_ACTION_TYPE_JUMP: 17894 ret = flow_dv_validate_action_jump(dev, 17895 NULL, act, action_flags[i], 17896 attr, true, &flow_err); 17897 if (ret) 17898 return -rte_mtr_error_set(error, 17899 ENOTSUP, 17900 RTE_MTR_ERROR_TYPE_METER_POLICY, 17901 NULL, flow_err.message ? 17902 flow_err.message : 17903 "Jump action validate check fail"); 17904 ++actions_n; 17905 action_flags[i] |= MLX5_FLOW_ACTION_JUMP; 17906 break; 17907 /* 17908 * Only the last meter in the hierarchy will support 17909 * the YELLOW color steering. Then in the meter policy 17910 * actions list, there should be no other meter inside. 17911 */ 17912 case RTE_FLOW_ACTION_TYPE_METER: 17913 if (i != RTE_COLOR_GREEN) 17914 return -rte_mtr_error_set(error, 17915 ENOTSUP, 17916 RTE_MTR_ERROR_TYPE_METER_POLICY, 17917 NULL, 17918 "Meter hierarchy only supports GREEN color."); 17919 if (*policy_mode != MLX5_MTR_POLICY_MODE_OG) 17920 return -rte_mtr_error_set(error, 17921 ENOTSUP, 17922 RTE_MTR_ERROR_TYPE_METER_POLICY, 17923 NULL, 17924 "No yellow policy should be provided in meter hierarchy."); 17925 mtr = act->conf; 17926 ret = flow_dv_validate_policy_mtr_hierarchy(dev, 17927 mtr->mtr_id, 17928 action_flags[i], 17929 is_rss, 17930 &hierarchy_domain, 17931 error); 17932 if (ret) 17933 return ret; 17934 ++actions_n; 17935 action_flags[i] |= 17936 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; 17937 break; 17938 default: 17939 return -rte_mtr_error_set(error, ENOTSUP, 17940 RTE_MTR_ERROR_TYPE_METER_POLICY, 17941 NULL, 17942 "Doesn't support optional action"); 17943 } 17944 } 17945 if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) { 17946 domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT; 17947 } else if ((action_flags[i] & 17948 (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || 17949 (action_flags[i] & MLX5_FLOW_ACTION_MARK)) { 17950 /* 17951 * Only support MLX5_XMETA_MODE_LEGACY 17952 * so MARK action is only in ingress domain. 17953 */ 17954 domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT; 17955 } else { 17956 domain_color[i] = def_domain; 17957 if (action_flags[i] && 17958 !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 17959 domain_color[i] &= 17960 ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 17961 } 17962 if (action_flags[i] & 17963 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) 17964 domain_color[i] &= hierarchy_domain; 17965 /* 17966 * Non-termination actions only support NIC Tx domain. 17967 * The adjustion should be skipped when there is no 17968 * action or only END is provided. The default domains 17969 * bit-mask is set to find the MIN intersection. 17970 * The action flags checking should also be skipped. 17971 */ 17972 if ((def_green && i == RTE_COLOR_GREEN) || 17973 (def_yellow && i == RTE_COLOR_YELLOW)) 17974 continue; 17975 /* 17976 * Validate the drop action mutual exclusion 17977 * with other actions. Drop action is mutually-exclusive 17978 * with any other action, except for Count action. 17979 */ 17980 if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) && 17981 (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) { 17982 return -rte_mtr_error_set(error, ENOTSUP, 17983 RTE_MTR_ERROR_TYPE_METER_POLICY, 17984 NULL, "Drop action is mutually-exclusive " 17985 "with any other action"); 17986 } 17987 /* Eswitch has few restrictions on using items and actions */ 17988 if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) { 17989 if (!mlx5_flow_ext_mreg_supported(dev) && 17990 action_flags[i] & MLX5_FLOW_ACTION_MARK) 17991 return -rte_mtr_error_set(error, ENOTSUP, 17992 RTE_MTR_ERROR_TYPE_METER_POLICY, 17993 NULL, "unsupported action MARK"); 17994 if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE) 17995 return -rte_mtr_error_set(error, ENOTSUP, 17996 RTE_MTR_ERROR_TYPE_METER_POLICY, 17997 NULL, "unsupported action QUEUE"); 17998 if (action_flags[i] & MLX5_FLOW_ACTION_RSS) 17999 return -rte_mtr_error_set(error, ENOTSUP, 18000 RTE_MTR_ERROR_TYPE_METER_POLICY, 18001 NULL, "unsupported action RSS"); 18002 if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) 18003 return -rte_mtr_error_set(error, ENOTSUP, 18004 RTE_MTR_ERROR_TYPE_METER_POLICY, 18005 NULL, "no fate action is found"); 18006 } else { 18007 if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) && 18008 (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) { 18009 if ((domain_color[i] & 18010 MLX5_MTR_DOMAIN_EGRESS_BIT)) 18011 domain_color[i] = 18012 MLX5_MTR_DOMAIN_EGRESS_BIT; 18013 else 18014 return -rte_mtr_error_set(error, 18015 ENOTSUP, 18016 RTE_MTR_ERROR_TYPE_METER_POLICY, 18017 NULL, 18018 "no fate action is found"); 18019 } 18020 } 18021 } 18022 /* If both colors have RSS, the attributes should be the same. */ 18023 if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN], 18024 rss_color[RTE_COLOR_YELLOW])) 18025 return -rte_mtr_error_set(error, EINVAL, 18026 RTE_MTR_ERROR_TYPE_METER_POLICY, 18027 NULL, "policy RSS attr conflict"); 18028 if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW]) 18029 *is_rss = true; 18030 /* "domain_color[C]" is non-zero for each color, default is ALL. */ 18031 if (!def_green && !def_yellow && 18032 domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] && 18033 !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) && 18034 !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP)) 18035 return -rte_mtr_error_set(error, EINVAL, 18036 RTE_MTR_ERROR_TYPE_METER_POLICY, 18037 NULL, "policy domains conflict"); 18038 /* 18039 * At least one color policy is listed in the actions, the domains 18040 * to be supported should be the intersection. 18041 */ 18042 *domain_bitmap = domain_color[RTE_COLOR_GREEN] & 18043 domain_color[RTE_COLOR_YELLOW]; 18044 return 0; 18045 } 18046 18047 static int 18048 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags) 18049 { 18050 struct mlx5_priv *priv = dev->data->dev_private; 18051 int ret = 0; 18052 18053 if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) { 18054 ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain, 18055 flags); 18056 if (ret != 0) 18057 return ret; 18058 } 18059 if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) { 18060 ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags); 18061 if (ret != 0) 18062 return ret; 18063 } 18064 if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) { 18065 ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags); 18066 if (ret != 0) 18067 return ret; 18068 } 18069 return 0; 18070 } 18071 18072 /** 18073 * Discover the number of available flow priorities 18074 * by trying to create a flow with the highest priority value 18075 * for each possible number. 18076 * 18077 * @param[in] dev 18078 * Ethernet device. 18079 * @param[in] vprio 18080 * List of possible number of available priorities. 18081 * @param[in] vprio_n 18082 * Size of @p vprio array. 18083 * @return 18084 * On success, number of available flow priorities. 18085 * On failure, a negative errno-style code and rte_errno is set. 18086 */ 18087 static int 18088 flow_dv_discover_priorities(struct rte_eth_dev *dev, 18089 const uint16_t *vprio, int vprio_n) 18090 { 18091 struct mlx5_priv *priv = dev->data->dev_private; 18092 struct mlx5_indexed_pool *pool = priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW]; 18093 struct rte_flow_item_eth eth; 18094 struct rte_flow_item item = { 18095 .type = RTE_FLOW_ITEM_TYPE_ETH, 18096 .spec = ð, 18097 .mask = ð, 18098 }; 18099 struct mlx5_flow_dv_matcher matcher = { 18100 .mask = { 18101 .size = sizeof(matcher.mask.buf), 18102 }, 18103 }; 18104 union mlx5_flow_tbl_key tbl_key; 18105 struct mlx5_flow flow; 18106 void *action; 18107 struct rte_flow_error error; 18108 uint8_t misc_mask; 18109 int i, err, ret = -ENOTSUP; 18110 18111 /* 18112 * Prepare a flow with a catch-all pattern and a drop action. 18113 * Use drop queue, because shared drop action may be unavailable. 18114 */ 18115 action = priv->drop_queue.hrxq->action; 18116 if (action == NULL) { 18117 DRV_LOG(ERR, "Priority discovery requires a drop action"); 18118 rte_errno = ENOTSUP; 18119 return -rte_errno; 18120 } 18121 memset(&flow, 0, sizeof(flow)); 18122 flow.handle = mlx5_ipool_zmalloc(pool, &flow.handle_idx); 18123 if (flow.handle == NULL) { 18124 DRV_LOG(ERR, "Cannot create flow handle"); 18125 rte_errno = ENOMEM; 18126 return -rte_errno; 18127 } 18128 flow.ingress = true; 18129 flow.dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param); 18130 flow.dv.actions[0] = action; 18131 flow.dv.actions_n = 1; 18132 memset(ð, 0, sizeof(eth)); 18133 flow_dv_translate_item_eth(matcher.mask.buf, flow.dv.value.buf, 18134 &item, /* inner */ false, /* group */ 0); 18135 matcher.crc = rte_raw_cksum(matcher.mask.buf, matcher.mask.size); 18136 for (i = 0; i < vprio_n; i++) { 18137 /* Configure the next proposed maximum priority. */ 18138 matcher.priority = vprio[i] - 1; 18139 memset(&tbl_key, 0, sizeof(tbl_key)); 18140 err = flow_dv_matcher_register(dev, &matcher, &tbl_key, &flow, 18141 /* tunnel */ NULL, 18142 /* group */ 0, 18143 &error); 18144 if (err != 0) { 18145 /* This action is pure SW and must always succeed. */ 18146 DRV_LOG(ERR, "Cannot register matcher"); 18147 ret = -rte_errno; 18148 break; 18149 } 18150 /* Try to apply the flow to HW. */ 18151 misc_mask = flow_dv_matcher_enable(flow.dv.value.buf); 18152 __flow_dv_adjust_buf_size(&flow.dv.value.size, misc_mask); 18153 err = mlx5_flow_os_create_flow 18154 (flow.handle->dvh.matcher->matcher_object, 18155 (void *)&flow.dv.value, flow.dv.actions_n, 18156 flow.dv.actions, &flow.handle->drv_flow); 18157 if (err == 0) { 18158 claim_zero(mlx5_flow_os_destroy_flow 18159 (flow.handle->drv_flow)); 18160 flow.handle->drv_flow = NULL; 18161 } 18162 claim_zero(flow_dv_matcher_release(dev, flow.handle)); 18163 if (err != 0) 18164 break; 18165 ret = vprio[i]; 18166 } 18167 mlx5_ipool_free(pool, flow.handle_idx); 18168 /* Set rte_errno if no expected priority value matched. */ 18169 if (ret < 0) 18170 rte_errno = -ret; 18171 return ret; 18172 } 18173 18174 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { 18175 .validate = flow_dv_validate, 18176 .prepare = flow_dv_prepare, 18177 .translate = flow_dv_translate, 18178 .apply = flow_dv_apply, 18179 .remove = flow_dv_remove, 18180 .destroy = flow_dv_destroy, 18181 .query = flow_dv_query, 18182 .create_mtr_tbls = flow_dv_create_mtr_tbls, 18183 .destroy_mtr_tbls = flow_dv_destroy_mtr_tbls, 18184 .destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls, 18185 .create_meter = flow_dv_mtr_alloc, 18186 .free_meter = flow_dv_aso_mtr_release_to_pool, 18187 .validate_mtr_acts = flow_dv_validate_mtr_policy_acts, 18188 .create_mtr_acts = flow_dv_create_mtr_policy_acts, 18189 .destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts, 18190 .create_policy_rules = flow_dv_create_policy_rules, 18191 .destroy_policy_rules = flow_dv_destroy_policy_rules, 18192 .create_def_policy = flow_dv_create_def_policy, 18193 .destroy_def_policy = flow_dv_destroy_def_policy, 18194 .meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare, 18195 .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create, 18196 .destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq, 18197 .counter_alloc = flow_dv_counter_allocate, 18198 .counter_free = flow_dv_counter_free, 18199 .counter_query = flow_dv_counter_query, 18200 .get_aged_flows = flow_dv_get_aged_flows, 18201 .action_validate = flow_dv_action_validate, 18202 .action_create = flow_dv_action_create, 18203 .action_destroy = flow_dv_action_destroy, 18204 .action_update = flow_dv_action_update, 18205 .action_query = flow_dv_action_query, 18206 .sync_domain = flow_dv_sync_domain, 18207 .discover_priorities = flow_dv_discover_priorities, 18208 .item_create = flow_dv_item_create, 18209 .item_release = flow_dv_item_release, 18210 }; 18211 18212 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ 18213 18214