1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include <rte_flow.h> 6 7 #include <mlx5_malloc.h> 8 #include <stdint.h> 9 10 #include "generic/rte_byteorder.h" 11 #include "mlx5.h" 12 #include "mlx5_flow.h" 13 #include "rte_pmd_mlx5.h" 14 15 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) 16 17 #define MAX_GENEVE_OPTION_DATA_SIZE 32 18 #define MAX_GENEVE_OPTION_TOTAL_DATA_SIZE \ 19 (MAX_GENEVE_OPTION_DATA_SIZE * MAX_GENEVE_OPTIONS_RESOURCES) 20 21 #define INVALID_SAMPLE_ID (UINT8_MAX) 22 23 /** 24 * Single DW inside GENEVE TLV option. 25 */ 26 struct mlx5_geneve_tlv_resource { 27 struct mlx5_devx_obj *obj; /* FW object returned in parser creation. */ 28 uint32_t modify_field; /* Modify field ID for this DW. */ 29 uint8_t offset; /* Offset used in obj creation, from option start. */ 30 }; 31 32 /** 33 * Single GENEVE TLV option context. 34 * May include some FW objects for different DWs in same option. 35 */ 36 struct mlx5_geneve_tlv_option { 37 uint8_t type; 38 uint16_t class; 39 uint8_t class_mode; 40 struct mlx5_hl_data match_data[MAX_GENEVE_OPTION_DATA_SIZE]; 41 uint32_t match_data_size; 42 struct mlx5_hl_data hl_ok_bit; 43 struct mlx5_geneve_tlv_resource resources[MAX_GENEVE_OPTIONS_RESOURCES]; 44 RTE_ATOMIC(uint32_t) refcnt; 45 }; 46 47 /** 48 * List of GENEVE TLV options. 49 */ 50 struct mlx5_geneve_tlv_options { 51 /* List of configured GENEVE TLV options. */ 52 struct mlx5_geneve_tlv_option options[MAX_GENEVE_OPTIONS_RESOURCES]; 53 /* 54 * Copy of list given in parser creation, use to compare with new 55 * configuration. 56 */ 57 struct rte_pmd_mlx5_geneve_tlv spec[MAX_GENEVE_OPTIONS_RESOURCES]; 58 rte_be32_t buffer[MAX_GENEVE_OPTION_TOTAL_DATA_SIZE]; 59 uint8_t nb_options; /* Number entries in above lists. */ 60 RTE_ATOMIC(uint32_t) refcnt; 61 }; 62 63 /** 64 * Check if type and class is matching to given GENEVE TLV option. 65 * 66 * @param type 67 * GENEVE option type. 68 * @param class 69 * GENEVE option class. 70 * @param option 71 * Pointer to GENEVE TLV option structure. 72 * 73 * @return 74 * True if this type and class match to this option, false otherwise. 75 */ 76 static inline bool 77 option_match_type_and_class(uint8_t type, uint16_t class, 78 struct mlx5_geneve_tlv_option *option) 79 { 80 if (type != option->type) 81 return false; 82 if (option->class_mode == 1 && option->class != class) 83 return false; 84 return true; 85 } 86 87 /** 88 * Get GENEVE TLV option matching to given type and class. 89 * 90 * @param priv 91 * Pointer to port's private data. 92 * @param type 93 * GENEVE option type. 94 * @param class 95 * GENEVE option class. 96 * 97 * @return 98 * Pointer to option structure if exist, NULL otherwise and rte_errno is set. 99 */ 100 static struct mlx5_geneve_tlv_option * 101 mlx5_geneve_tlv_option_get(const struct mlx5_priv *priv, uint8_t type, 102 uint16_t class) 103 { 104 struct mlx5_geneve_tlv_options *options; 105 uint8_t i; 106 107 if (priv->tlv_options == NULL) { 108 DRV_LOG(ERR, 109 "Port %u doesn't have configured GENEVE TLV options.", 110 priv->dev_data->port_id); 111 rte_errno = EINVAL; 112 return NULL; 113 } 114 options = priv->tlv_options; 115 MLX5_ASSERT(options != NULL); 116 for (i = 0; i < options->nb_options; ++i) { 117 struct mlx5_geneve_tlv_option *option = &options->options[i]; 118 119 if (option_match_type_and_class(type, class, option)) 120 return option; 121 } 122 DRV_LOG(ERR, "TLV option type %u class %u doesn't exist.", type, class); 123 rte_errno = ENOENT; 124 return NULL; 125 } 126 127 int 128 mlx5_get_geneve_hl_data(const void *dr_ctx, uint8_t type, uint16_t class, 129 struct mlx5_hl_data ** const hl_ok_bit, 130 uint8_t *num_of_dws, 131 struct mlx5_hl_data ** const hl_dws, 132 bool *ok_bit_on_class) 133 { 134 uint16_t port_id; 135 136 MLX5_ETH_FOREACH_DEV(port_id, NULL) { 137 struct mlx5_priv *priv; 138 struct mlx5_geneve_tlv_option *option; 139 140 priv = rte_eth_devices[port_id].data->dev_private; 141 if (priv->dr_ctx != dr_ctx) 142 continue; 143 /* Find specific option inside list. */ 144 option = mlx5_geneve_tlv_option_get(priv, type, class); 145 if (option == NULL) 146 return -rte_errno; 147 *hl_ok_bit = &option->hl_ok_bit; 148 *hl_dws = option->match_data; 149 *num_of_dws = option->match_data_size; 150 *ok_bit_on_class = !!(option->class_mode == 1); 151 return 0; 152 } 153 DRV_LOG(ERR, "DR CTX %p doesn't belong to any DPDK port.", dr_ctx); 154 return -EINVAL; 155 } 156 157 /** 158 * Calculate total data size. 159 * 160 * @param[in] priv 161 * Pointer to port's private data. 162 * @param[in] geneve_opt 163 * Pointer to GENEVE option item structure. 164 * @param[out] error 165 * Pointer to error structure. 166 * 167 * @return 168 * 0 on success, a negative errno value otherwise and rte_errno is set. 169 */ 170 int 171 mlx5_flow_geneve_tlv_option_validate(struct mlx5_priv *priv, 172 const struct rte_flow_item *geneve_opt, 173 struct rte_flow_error *error) 174 { 175 const struct rte_flow_item_geneve_opt *spec = geneve_opt->spec; 176 const struct rte_flow_item_geneve_opt *mask = geneve_opt->mask; 177 struct mlx5_geneve_tlv_option *option; 178 179 option = mlx5_geneve_tlv_option_get(priv, spec->option_type, spec->option_class); 180 if (option == NULL) 181 return rte_flow_error_set(error, rte_errno, 182 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 183 "Unregistered GENEVE option"); 184 if (mask->option_type != UINT8_MAX) 185 return rte_flow_error_set(error, EINVAL, 186 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 187 "GENEVE option type must be fully masked"); 188 if (option->class_mode == 1 && mask->option_class != UINT16_MAX) 189 return rte_flow_error_set(error, EINVAL, 190 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 191 "GENEVE option class must be fully masked"); 192 return 0; 193 } 194 195 /** 196 * Register single GENEVE TLV option as used by pattern template. 197 * 198 * @param[in] priv 199 * Pointer to port's private data. 200 * @param[in] spec 201 * Pointer to GENEVE option item structure. 202 * @param[out] mng 203 * Pointer to GENEVE option manager. 204 * 205 * @return 206 * 0 on success, a negative errno value otherwise and rte_errno is set. 207 */ 208 int 209 mlx5_geneve_tlv_option_register(struct mlx5_priv *priv, 210 const struct rte_flow_item_geneve_opt *spec, 211 struct mlx5_geneve_tlv_options_mng *mng) 212 { 213 struct mlx5_geneve_tlv_option *option; 214 215 option = mlx5_geneve_tlv_option_get(priv, spec->option_type, spec->option_class); 216 if (option == NULL) 217 return -rte_errno; 218 /* Increase the option reference counter. */ 219 rte_atomic_fetch_add_explicit(&option->refcnt, 1, 220 rte_memory_order_relaxed); 221 /* Update the manager with option information. */ 222 mng->options[mng->nb_options].opt_type = spec->option_type; 223 mng->options[mng->nb_options].opt_class = spec->option_class; 224 mng->nb_options++; 225 return 0; 226 } 227 228 /** 229 * Unregister all GENEVE TLV options used by pattern template. 230 * 231 * @param[in] priv 232 * Pointer to port's private data. 233 * @param[in] mng 234 * Pointer to GENEVE option manager. 235 */ 236 void 237 mlx5_geneve_tlv_options_unregister(struct mlx5_priv *priv, 238 struct mlx5_geneve_tlv_options_mng *mng) 239 { 240 struct mlx5_geneve_tlv_option *option; 241 uint8_t i; 242 243 for (i = 0; i < mng->nb_options; ++i) { 244 option = mlx5_geneve_tlv_option_get(priv, 245 mng->options[i].opt_type, 246 mng->options[i].opt_class); 247 MLX5_ASSERT(option != NULL); 248 /* Decrease the option reference counter. */ 249 rte_atomic_fetch_sub_explicit(&option->refcnt, 1, 250 rte_memory_order_relaxed); 251 mng->options[i].opt_type = 0; 252 mng->options[i].opt_class = 0; 253 } 254 mng->nb_options = 0; 255 } 256 257 /** 258 * Get single DW resource from given option. 259 * 260 * @param option 261 * Pointer to single GENEVE TLV option. 262 * @param offset 263 * Offset of DW related to option start. 264 * 265 * @return 266 * DW resource on success, NULL otherwise and rte_errno is set. 267 */ 268 static struct mlx5_geneve_tlv_resource * 269 mlx5_geneve_tlv_option_get_resource_by_offset(struct mlx5_geneve_tlv_option *option, 270 uint8_t offset) 271 { 272 uint8_t i; 273 274 for (i = 0; option->resources[i].obj != NULL; ++i) { 275 if (option->resources[i].offset < offset) 276 continue; 277 if (option->resources[i].offset == offset) 278 return &option->resources[i]; 279 break; 280 } 281 DRV_LOG(ERR, "The DW in offset %u wasn't configured.", offset); 282 rte_errno = EINVAL; 283 return NULL; 284 } 285 286 int 287 mlx5_get_geneve_option_modify_field_id(const void *dr_ctx, uint8_t type, 288 uint16_t class, uint8_t dw_offset) 289 { 290 uint16_t port_id; 291 292 MLX5_ETH_FOREACH_DEV(port_id, NULL) { 293 struct mlx5_priv *priv; 294 struct mlx5_geneve_tlv_option *option; 295 struct mlx5_geneve_tlv_resource *resource; 296 297 priv = rte_eth_devices[port_id].data->dev_private; 298 if (priv->dr_ctx != dr_ctx) 299 continue; 300 /* Find specific option inside list. */ 301 option = mlx5_geneve_tlv_option_get(priv, type, class); 302 if (option == NULL) 303 return -rte_errno; 304 /* Find specific FW object inside option resources. */ 305 resource = mlx5_geneve_tlv_option_get_resource_by_offset(option, 306 dw_offset); 307 if (resource == NULL) 308 return -rte_errno; 309 return resource->modify_field; 310 } 311 DRV_LOG(ERR, "DR CTX %p doesn't belong to any DPDK port.", dr_ctx); 312 rte_errno = EINVAL; 313 return -rte_errno; 314 } 315 316 /** 317 * Get modify field ID for single DW inside configured GENEVE TLV option. 318 * 319 * @param[in] priv 320 * Pointer to port's private data. 321 * @param[in] data 322 * Pointer to modify field data structure. 323 * 324 * @return 325 * Modify field ID on success, negative errno otherwise and rte_errno is set. 326 */ 327 int 328 mlx5_geneve_opt_modi_field_get(struct mlx5_priv *priv, 329 const struct rte_flow_field_data *data) 330 { 331 uint16_t class = data->class_id; 332 uint8_t type = data->type; 333 struct mlx5_geneve_tlv_option *option; 334 struct mlx5_geneve_tlv_resource *resource; 335 uint8_t offset; 336 337 option = mlx5_geneve_tlv_option_get(priv, type, class); 338 if (option == NULL) 339 return -rte_errno; 340 switch (data->field) { 341 case RTE_FLOW_FIELD_GENEVE_OPT_TYPE: 342 case RTE_FLOW_FIELD_GENEVE_OPT_CLASS: 343 if (!option->match_data[0].dw_mask) { 344 DRV_LOG(ERR, "DW0 isn't configured"); 345 rte_errno = EINVAL; 346 return -rte_errno; 347 } 348 resource = &option->resources[0]; 349 MLX5_ASSERT(resource->offset == 0); 350 break; 351 case RTE_FLOW_FIELD_GENEVE_OPT_DATA: 352 /* 353 * Convert offset twice: 354 * - First conversion from bit offset to DW offset. 355 * - Second conversion is to be related to data start instead 356 * of option start. 357 */ 358 offset = (data->offset >> 5) + 1; 359 resource = mlx5_geneve_tlv_option_get_resource_by_offset(option, 360 offset); 361 break; 362 default: 363 DRV_LOG(ERR, 364 "Field ID %u doesn't describe GENEVE option header.", 365 data->field); 366 rte_errno = EINVAL; 367 return -rte_errno; 368 } 369 if (resource == NULL) 370 return -rte_errno; 371 return resource->modify_field; 372 } 373 374 /** 375 * Create single GENEVE TLV option sample. 376 * 377 * @param ctx 378 * Context returned from mlx5 open_device() glue function. 379 * @param attr 380 * Pointer to GENEVE TLV option attributes structure. 381 * @param query_attr 382 * Pointer to match sample info attributes structure. 383 * @param match_data 384 * Pointer to header layout structure to update. 385 * @param resource 386 * Pointer to single sample context to fill. 387 * @param sample_id 388 * The flex parser id for single DW or UINT8_MAX for multiple DWs. 389 * 390 * @return 391 * 0 on success, a negative errno otherwise and rte_errno is set. 392 */ 393 static int 394 mlx5_geneve_tlv_option_create_sample(void *ctx, 395 struct mlx5_devx_geneve_tlv_option_attr *attr, 396 struct mlx5_devx_match_sample_info_query_attr *query_attr, 397 struct mlx5_hl_data *match_data, 398 struct mlx5_geneve_tlv_resource *resource, uint8_t sample_id) 399 { 400 struct mlx5_devx_obj *obj; 401 int ret; 402 403 obj = mlx5_devx_cmd_create_geneve_tlv_option(ctx, attr); 404 if (obj == NULL) 405 return -rte_errno; 406 if (sample_id == INVALID_SAMPLE_ID) 407 ret = mlx5_devx_cmd_query_geneve_tlv_option(ctx, obj, query_attr); 408 else 409 ret = mlx5_devx_cmd_match_sample_info_query(ctx, sample_id, query_attr); 410 if (ret) { 411 claim_zero(mlx5_devx_cmd_destroy(obj)); 412 return ret; 413 } 414 resource->obj = obj; 415 resource->offset = attr->sample_offset; 416 resource->modify_field = query_attr->modify_field_id; 417 match_data->dw_offset = query_attr->sample_dw_data; 418 match_data->dw_mask = 0xffffffff; 419 return 0; 420 } 421 422 /** 423 * Destroy single GENEVE TLV option sample. 424 * 425 * @param resource 426 * Pointer to single sample context to clean. 427 */ 428 static void 429 mlx5_geneve_tlv_option_destroy_sample(struct mlx5_geneve_tlv_resource *resource) 430 { 431 claim_zero(mlx5_devx_cmd_destroy(resource->obj)); 432 resource->obj = NULL; 433 } 434 435 /* 436 * Sample for DW0 are created when one of two conditions is met: 437 * 1. Header is matchable. 438 * 2. This option doesn't configure any data DW. 439 */ 440 static bool 441 should_configure_sample_for_dw0(const struct rte_pmd_mlx5_geneve_tlv *spec) 442 { 443 uint8_t i; 444 445 if (spec->match_on_class_mode == 2) 446 return true; 447 for (i = 0; i < spec->sample_len; ++i) 448 if (spec->match_data_mask[i] != 0) 449 return false; 450 return true; 451 } 452 453 /** 454 * Create single GENEVE TLV option. 455 * 456 * @param ctx 457 * Context returned from mlx5 open_device() glue function. 458 * @param spec 459 * Pointer to user configuration. 460 * @param option 461 * Pointer to single GENEVE TLV option to fill. 462 * @param sample_id 463 * The flex parser id for single DW or UINT8_MAX for multiple DWs. 464 * 465 * @return 466 * 0 on success, a negative errno otherwise and rte_errno is set. 467 */ 468 static int 469 mlx5_geneve_tlv_option_create(void *ctx, const struct rte_pmd_mlx5_geneve_tlv *spec, 470 struct mlx5_geneve_tlv_option *option, uint8_t sample_id) 471 { 472 struct mlx5_devx_geneve_tlv_option_attr attr = { 473 .option_class = spec->option_class, 474 .option_type = spec->option_type, 475 .option_data_len = spec->option_len, 476 .option_class_ignore = spec->match_on_class_mode == 1 ? 0 : 1, 477 .offset_valid = sample_id == INVALID_SAMPLE_ID ? 1 : 0, 478 }; 479 struct mlx5_devx_match_sample_info_query_attr query_attr = {0}; 480 struct mlx5_geneve_tlv_resource *resource; 481 uint8_t i, resource_id = 0; 482 int ret; 483 484 if (should_configure_sample_for_dw0(spec)) { 485 MLX5_ASSERT(sample_id == INVALID_SAMPLE_ID); 486 attr.sample_offset = 0; 487 resource = &option->resources[resource_id]; 488 ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr, 489 &query_attr, 490 &option->match_data[0], 491 resource, 492 INVALID_SAMPLE_ID); 493 if (ret) 494 return ret; 495 resource_id++; 496 } 497 /* 498 * Create FW object for each DW request by user. 499 * Starting from 1 since FW offset starts from header. 500 */ 501 for (i = 1; i <= spec->sample_len; ++i) { 502 if (spec->match_data_mask[i - 1] == 0) 503 continue; 504 /* offset of data + offset inside data = specific DW offset. */ 505 attr.sample_offset = spec->offset + i; 506 resource = &option->resources[resource_id]; 507 ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr, 508 &query_attr, 509 &option->match_data[i], 510 resource, 511 sample_id); 512 if (ret) 513 goto error; 514 resource_id++; 515 } 516 /* 517 * Update the OK bit information according to last query. 518 * It should be same for each query under same option. 519 */ 520 option->hl_ok_bit.dw_offset = query_attr.sample_dw_ok_bit; 521 option->hl_ok_bit.dw_mask = 1 << query_attr.sample_dw_ok_bit_offset; 522 option->match_data_size = spec->sample_len + 1; 523 option->type = spec->option_type; 524 option->class = spec->option_class; 525 option->class_mode = spec->match_on_class_mode; 526 rte_atomic_store_explicit(&option->refcnt, 0, rte_memory_order_relaxed); 527 return 0; 528 error: 529 for (i = 0; i < resource_id; ++i) { 530 resource = &option->resources[i]; 531 mlx5_geneve_tlv_option_destroy_sample(resource); 532 } 533 return ret; 534 } 535 536 /** 537 * Destroy single GENEVE TLV option. 538 * 539 * @param option 540 * Pointer to single GENEVE TLV option to destroy. 541 * 542 * @return 543 * 0 on success, a negative errno otherwise and rte_errno is set. 544 */ 545 static int 546 mlx5_geneve_tlv_option_destroy(struct mlx5_geneve_tlv_option *option) 547 { 548 uint8_t i; 549 550 if (rte_atomic_load_explicit(&option->refcnt, rte_memory_order_relaxed)) { 551 DRV_LOG(ERR, 552 "Option type %u class %u is still in used by %u tables.", 553 option->type, option->class, option->refcnt); 554 rte_errno = EBUSY; 555 return -rte_errno; 556 } 557 for (i = 0; option->resources[i].obj != NULL; ++i) 558 mlx5_geneve_tlv_option_destroy_sample(&option->resources[i]); 559 return 0; 560 } 561 562 /** 563 * Copy the GENEVE TLV option user configuration for future comparing. 564 * 565 * @param dst 566 * Pointer to internal user configuration copy. 567 * @param src 568 * Pointer to user configuration. 569 * @param match_data_mask 570 * Pointer to allocated data array. 571 */ 572 static void 573 mlx5_geneve_tlv_option_copy(struct rte_pmd_mlx5_geneve_tlv *dst, 574 const struct rte_pmd_mlx5_geneve_tlv *src, 575 rte_be32_t *match_data_mask) 576 { 577 uint8_t i; 578 579 dst->option_type = src->option_type; 580 dst->option_class = src->option_class; 581 dst->option_len = src->option_len; 582 dst->offset = src->offset; 583 dst->match_on_class_mode = src->match_on_class_mode; 584 dst->sample_len = src->sample_len; 585 for (i = 0; i < dst->sample_len; ++i) 586 match_data_mask[i] = src->match_data_mask[i]; 587 dst->match_data_mask = match_data_mask; 588 } 589 590 /** 591 * Create list of GENEVE TLV options according to user configuration list. 592 * 593 * @param sh 594 * Shared context the options are being created on. 595 * @param tlv_list 596 * A list of GENEVE TLV options to create parser for them. 597 * @param nb_options 598 * The number of options in TLV list. 599 * @param sample_id 600 * The flex parser id for single DW or UINT8_MAX for multiple DWs. 601 * 602 * @return 603 * A pointer to GENEVE TLV options parser structure on success, 604 * NULL otherwise and rte_errno is set. 605 */ 606 static struct mlx5_geneve_tlv_options * 607 mlx5_geneve_tlv_options_create(struct mlx5_dev_ctx_shared *sh, 608 const struct rte_pmd_mlx5_geneve_tlv tlv_list[], 609 uint8_t nb_options, uint8_t sample_id) 610 { 611 struct mlx5_geneve_tlv_options *options; 612 const struct rte_pmd_mlx5_geneve_tlv *spec; 613 rte_be32_t *data_mask; 614 uint8_t i, j; 615 int ret; 616 617 options = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, 618 sizeof(struct mlx5_geneve_tlv_options), 619 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 620 if (options == NULL) { 621 DRV_LOG(ERR, 622 "Failed to allocate memory for GENEVE TLV options."); 623 rte_errno = ENOMEM; 624 return NULL; 625 } 626 for (i = 0; i < nb_options; ++i) { 627 spec = &tlv_list[i]; 628 ret = mlx5_geneve_tlv_option_create(sh->cdev->ctx, spec, 629 &options->options[i], sample_id); 630 if (ret < 0) 631 goto error; 632 /* Copy the user list for comparing future configuration. */ 633 data_mask = options->buffer + i * MAX_GENEVE_OPTION_DATA_SIZE; 634 mlx5_geneve_tlv_option_copy(&options->spec[i], spec, data_mask); 635 } 636 MLX5_ASSERT(sh->phdev->sh == NULL); 637 sh->phdev->sh = sh; 638 options->nb_options = nb_options; 639 options->refcnt = 1; 640 return options; 641 error: 642 for (j = 0; j < i; ++j) 643 mlx5_geneve_tlv_option_destroy(&options->options[j]); 644 mlx5_free(options); 645 return NULL; 646 } 647 648 /** 649 * Destroy GENEVE TLV options structure. 650 * 651 * @param options 652 * Pointer to GENEVE TLV options structure to destroy. 653 * @param phdev 654 * Pointer physical device options were created on. 655 * 656 * @return 657 * 0 on success, a negative errno otherwise and rte_errno is set. 658 */ 659 int 660 mlx5_geneve_tlv_options_destroy(struct mlx5_geneve_tlv_options *options, 661 struct mlx5_physical_device *phdev) 662 { 663 uint8_t i; 664 int ret; 665 666 if (--options->refcnt) 667 return 0; 668 for (i = 0; i < options->nb_options; ++i) { 669 ret = mlx5_geneve_tlv_option_destroy(&options->options[i]); 670 if (ret < 0) { 671 DRV_LOG(ERR, 672 "Failed to destroy option %u, %u/%u is already destroyed.", 673 i, i, options->nb_options); 674 return ret; 675 } 676 } 677 mlx5_free(options); 678 phdev->tlv_options = NULL; 679 phdev->sh = NULL; 680 return 0; 681 } 682 683 /** 684 * Check if GENEVE TLV options are hosted on the current port 685 * and the port can be closed 686 * 687 * @param priv 688 * Device private data. 689 * 690 * @return 691 * 0 on success, a negative EBUSY and rte_errno is set. 692 */ 693 int 694 mlx5_geneve_tlv_options_check_busy(struct mlx5_priv *priv) 695 { 696 struct mlx5_physical_device *phdev = mlx5_get_locked_physical_device(priv); 697 struct mlx5_dev_ctx_shared *sh = priv->sh; 698 699 if (!phdev || phdev->sh != sh) { 700 mlx5_unlock_physical_device(); 701 return 0; 702 } 703 if (!sh->phdev->tlv_options || sh->phdev->tlv_options->refcnt == 1) { 704 /* Mark port as being closed one */ 705 sh->phdev->sh = NULL; 706 mlx5_unlock_physical_device(); 707 return 0; 708 } 709 mlx5_unlock_physical_device(); 710 rte_errno = EBUSY; 711 return -EBUSY; 712 } 713 714 /** 715 * Validate GENEVE TLV option user request structure. 716 * 717 * @param attr 718 * Pointer to HCA attribute structure. 719 * @param option 720 * Pointer to user configuration. 721 * 722 * @return 723 * 0 on success, a negative errno otherwise and rte_errno is set. 724 */ 725 static int 726 mlx5_geneve_tlv_option_validate(struct mlx5_hca_attr *attr, 727 const struct rte_pmd_mlx5_geneve_tlv *option) 728 { 729 if (option->option_len > attr->max_geneve_tlv_option_data_len) { 730 DRV_LOG(ERR, 731 "GENEVE TLV option length (%u) exceeds the limit (%u).", 732 option->option_len, 733 attr->max_geneve_tlv_option_data_len); 734 rte_errno = ENOTSUP; 735 return -rte_errno; 736 } 737 if (option->option_len < option->offset + option->sample_len) { 738 DRV_LOG(ERR, 739 "GENEVE TLV option length is smaller than (offset + sample_len)."); 740 rte_errno = EINVAL; 741 return -rte_errno; 742 } 743 if (option->match_on_class_mode > 2) { 744 DRV_LOG(ERR, 745 "GENEVE TLV option match_on_class_mode is invalid."); 746 rte_errno = EINVAL; 747 return -rte_errno; 748 } 749 return 0; 750 } 751 752 /** 753 * Get the number of requested DWs in given GENEVE TLV option. 754 * 755 * @param option 756 * Pointer to user configuration. 757 * 758 * @return 759 * Number of requested DWs for given GENEVE TLV option. 760 */ 761 static uint8_t 762 mlx5_geneve_tlv_option_get_nb_dws(const struct rte_pmd_mlx5_geneve_tlv *option) 763 { 764 uint8_t nb_dws = 0; 765 uint8_t i; 766 767 if (option->match_on_class_mode == 2) 768 nb_dws++; 769 for (i = 0; i < option->sample_len; ++i) { 770 if (option->match_data_mask[i] == 0xffffffff) 771 nb_dws++; 772 } 773 return nb_dws; 774 } 775 776 /** 777 * Compare GENEVE TLV option user request structure. 778 * 779 * @param option1 780 * Pointer to first user configuration. 781 * @param option2 782 * Pointer to second user configuration. 783 * 784 * @return 785 * True if the options are equal, false otherwise. 786 */ 787 static bool 788 mlx5_geneve_tlv_option_compare(const struct rte_pmd_mlx5_geneve_tlv *option1, 789 const struct rte_pmd_mlx5_geneve_tlv *option2) 790 { 791 uint8_t i; 792 793 if (option1->option_type != option2->option_type || 794 option1->option_class != option2->option_class || 795 option1->option_len != option2->option_len || 796 option1->offset != option2->offset || 797 option1->match_on_class_mode != option2->match_on_class_mode || 798 option1->sample_len != option2->sample_len) 799 return false; 800 for (i = 0; i < option1->sample_len; ++i) { 801 if (option1->match_data_mask[i] != option2->match_data_mask[i]) 802 return false; 803 } 804 return true; 805 } 806 807 /** 808 * Check whether the given GENEVE TLV option list is equal to internal list. 809 * The lists are equal when they have same size and same options in the same 810 * order inside the list. 811 * 812 * @param options 813 * Pointer to GENEVE TLV options structure. 814 * @param tlv_list 815 * A list of GENEVE TLV options to compare. 816 * @param nb_options 817 * The number of options in TLV list. 818 * 819 * @return 820 * True if the lists are equal, false otherwise. 821 */ 822 static bool 823 mlx5_is_same_geneve_tlv_options(const struct mlx5_geneve_tlv_options *options, 824 const struct rte_pmd_mlx5_geneve_tlv tlv_list[], 825 uint8_t nb_options) 826 { 827 const struct rte_pmd_mlx5_geneve_tlv *spec = options->spec; 828 uint8_t i; 829 830 if (options->nb_options != nb_options) 831 return false; 832 for (i = 0; i < nb_options; ++i) { 833 if (!mlx5_geneve_tlv_option_compare(&spec[i], &tlv_list[i])) 834 return false; 835 } 836 return true; 837 } 838 839 static inline bool 840 multiple_dws_supported(struct mlx5_hca_attr *attr) 841 { 842 return attr->geneve_tlv_option_offset && attr->geneve_tlv_sample; 843 } 844 845 void * 846 mlx5_geneve_tlv_parser_create(uint16_t port_id, 847 const struct rte_pmd_mlx5_geneve_tlv tlv_list[], 848 uint8_t nb_options) 849 { 850 struct mlx5_geneve_tlv_options *options = NULL; 851 struct mlx5_physical_device *phdev; 852 struct rte_eth_dev *dev; 853 struct mlx5_priv *priv; 854 struct mlx5_hca_attr *attr; 855 uint8_t sample_id; 856 857 /* 858 * Validate the input before taking a lock and before any memory 859 * allocation. 860 */ 861 if (rte_eth_dev_is_valid_port(port_id) < 0) { 862 DRV_LOG(ERR, "There is no Ethernet device for port %u.", 863 port_id); 864 rte_errno = ENODEV; 865 return NULL; 866 } 867 dev = &rte_eth_devices[port_id]; 868 priv = dev->data->dev_private; 869 if (priv->tlv_options) { 870 DRV_LOG(ERR, "Port %u already has GENEVE TLV parser.", port_id); 871 rte_errno = EEXIST; 872 return NULL; 873 } 874 if (priv->sh->config.dv_flow_en < 2) { 875 DRV_LOG(ERR, 876 "GENEVE TLV parser is only supported for HW steering."); 877 rte_errno = ENOTSUP; 878 return NULL; 879 } 880 attr = &priv->sh->cdev->config.hca_attr; 881 if (!attr->query_match_sample_info || !attr->geneve_tlv_opt) { 882 DRV_LOG(ERR, "Not enough capabilities to support GENEVE TLV parser, is this device eswitch manager?"); 883 rte_errno = ENOTSUP; 884 return NULL; 885 } 886 DRV_LOG(DEBUG, "Max DWs supported for GENEVE TLV option is %u", 887 attr->max_geneve_tlv_options); 888 if (nb_options > attr->max_geneve_tlv_options) { 889 DRV_LOG(ERR, 890 "GENEVE TLV option number (%u) exceeds the limit (%u).", 891 nb_options, attr->max_geneve_tlv_options); 892 rte_errno = EINVAL; 893 return NULL; 894 } 895 if (multiple_dws_supported(attr)) { 896 uint8_t total_dws = 0; 897 uint8_t i; 898 899 MLX5_ASSERT(attr->max_geneve_tlv_options >= MAX_GENEVE_OPTIONS_RESOURCES); 900 for (i = 0; i < nb_options; ++i) { 901 if (mlx5_geneve_tlv_option_validate(attr, &tlv_list[i]) < 0) { 902 DRV_LOG(ERR, "GENEVE TLV option %u is invalid.", i); 903 return NULL; 904 } 905 total_dws += mlx5_geneve_tlv_option_get_nb_dws(&tlv_list[i]); 906 } 907 if (total_dws > MAX_GENEVE_OPTIONS_RESOURCES) { 908 DRV_LOG(ERR, 909 "Total requested DWs (%u) exceeds the limit (%u).", 910 total_dws, MAX_GENEVE_OPTIONS_RESOURCES); 911 rte_errno = EINVAL; 912 return NULL; 913 } 914 /* Multiple DWs is supported, each of the has sample ID given later. */ 915 sample_id = INVALID_SAMPLE_ID; 916 DRV_LOG(DEBUG, "GENEVE TLV parser supports multiple DWs, FLEX_PARSER_PROFILE_ENABLE == 8"); 917 } else { 918 const struct rte_pmd_mlx5_geneve_tlv *option = &tlv_list[0]; 919 920 if (option->offset != 0) { 921 DRV_LOG(ERR, 922 "GENEVE TLV option offset %u is required but not supported.", 923 option->offset); 924 rte_errno = ENOTSUP; 925 return NULL; 926 } 927 if (option->sample_len != option->option_len) { 928 DRV_LOG(ERR, 929 "GENEVE TLV option length (%u) should be equal to sample length (%u).", 930 option->option_len, option->sample_len); 931 rte_errno = ENOTSUP; 932 return NULL; 933 } 934 if (option->match_on_class_mode != 1) { 935 DRV_LOG(ERR, 936 "GENEVE TLV option match_on_class_mode %u is invalid for flex parser profile 0.", 937 option->match_on_class_mode); 938 rte_errno = EINVAL; 939 return NULL; 940 } 941 if (mlx5_geneve_tlv_option_validate(attr, option) < 0) 942 return NULL; 943 /* Single DW is supported, its sample ID is given. */ 944 sample_id = attr->geneve_tlv_option_sample_id; 945 DRV_LOG(DEBUG, "GENEVE TLV parser supports only single DW, FLEX_PARSER_PROFILE_ENABLE == 0"); 946 } 947 /* Take lock for this physical device and manage the options. */ 948 phdev = mlx5_get_locked_physical_device(priv); 949 options = priv->sh->phdev->tlv_options; 950 if (options) { 951 if (!mlx5_is_same_geneve_tlv_options(options, tlv_list, 952 nb_options)) { 953 mlx5_unlock_physical_device(); 954 DRV_LOG(ERR, "Another port has already prepared different GENEVE TLV parser."); 955 rte_errno = EEXIST; 956 return NULL; 957 } 958 if (phdev->sh == NULL) { 959 mlx5_unlock_physical_device(); 960 DRV_LOG(ERR, "GENEVE TLV options are hosted on port being closed."); 961 rte_errno = EBUSY; 962 return NULL; 963 } 964 /* Use existing options. */ 965 options->refcnt++; 966 goto exit; 967 } 968 /* Create GENEVE TLV options for this physical device. */ 969 options = mlx5_geneve_tlv_options_create(priv->sh, tlv_list, nb_options, sample_id); 970 if (!options) { 971 mlx5_unlock_physical_device(); 972 return NULL; 973 } 974 phdev->tlv_options = options; 975 exit: 976 mlx5_unlock_physical_device(); 977 priv->tlv_options = options; 978 return priv; 979 } 980 981 int 982 mlx5_geneve_tlv_parser_destroy(void *handle) 983 { 984 struct mlx5_priv *priv = (struct mlx5_priv *)handle; 985 struct mlx5_physical_device *phdev; 986 int ret; 987 988 if (priv == NULL) { 989 DRV_LOG(ERR, "Handle input is invalid (NULL)."); 990 rte_errno = EINVAL; 991 return -rte_errno; 992 } 993 if (priv->tlv_options == NULL) { 994 DRV_LOG(ERR, "This parser has been already released."); 995 rte_errno = ENOENT; 996 return -rte_errno; 997 } 998 /* Take lock for this physical device and manage the options. */ 999 phdev = mlx5_get_locked_physical_device(priv); 1000 /* Destroy the options */ 1001 ret = mlx5_geneve_tlv_options_destroy(phdev->tlv_options, phdev); 1002 if (ret < 0) { 1003 mlx5_unlock_physical_device(); 1004 return ret; 1005 } 1006 priv->tlv_options = NULL; 1007 mlx5_unlock_physical_device(); 1008 return 0; 1009 } 1010 1011 #endif /* defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) */ 1012