1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Copyright 2018 Mellanox Technologies, Ltd 4 */ 5 #include <math.h> 6 7 #include <rte_tailq.h> 8 #include <rte_malloc.h> 9 #include <rte_mtr.h> 10 #include <rte_mtr_driver.h> 11 12 #include <mlx5_devx_cmds.h> 13 14 #include "mlx5.h" 15 #include "mlx5_flow.h" 16 17 /** 18 * Create the meter action. 19 * 20 * @param priv 21 * Pointer to mlx5_priv. 22 * @param[in] fm 23 * Pointer to flow meter to be converted. 24 * 25 * @return 26 * Pointer to the meter action on success, NULL otherwise. 27 */ 28 static void * 29 mlx5_flow_meter_action_create(struct mlx5_priv *priv, 30 struct mlx5_flow_meter *fm) 31 { 32 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER 33 struct mlx5dv_dr_flow_meter_attr mtr_init; 34 void *attr = fm->mfts->fmp; 35 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = 36 &fm->profile->srtcm_prm; 37 38 fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters); 39 memset(attr, 0, fm->mfts->fmp_size); 40 MLX5_SET(flow_meter_parameters, attr, valid, 1); 41 MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1); 42 MLX5_SET(flow_meter_parameters, attr, 43 start_color, MLX5_FLOW_COLOR_GREEN); 44 MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0); 45 MLX5_SET(flow_meter_parameters, 46 attr, cbs_exponent, srtcm->cbs_exponent); 47 MLX5_SET(flow_meter_parameters, 48 attr, cbs_mantissa, srtcm->cbs_mantissa); 49 MLX5_SET(flow_meter_parameters, 50 attr, cir_exponent, srtcm->cir_exponent); 51 MLX5_SET(flow_meter_parameters, 52 attr, cir_mantissa, srtcm->cir_mantissa); 53 MLX5_SET(flow_meter_parameters, 54 attr, ebs_exponent, srtcm->ebs_exponent); 55 MLX5_SET(flow_meter_parameters, 56 attr, ebs_mantissa, srtcm->ebs_mantissa); 57 mtr_init.next_table = 58 fm->transfer ? fm->mfts->transfer.tbl->obj : 59 fm->egress ? fm->mfts->egress.tbl->obj : 60 fm->mfts->ingress.tbl->obj; 61 mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0; 62 mtr_init.flow_meter_parameter = fm->mfts->fmp; 63 mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size; 64 mtr_init.active = fm->active_state; 65 return mlx5_glue->dv_create_flow_action_meter(&mtr_init); 66 #else 67 (void)priv; 68 (void)fm; 69 return NULL; 70 #endif 71 } 72 73 /** 74 * Find meter profile by id. 75 * 76 * @param priv 77 * Pointer to mlx5_priv. 78 * @param meter_profile_id 79 * Meter profile id. 80 * 81 * @return 82 * Pointer to the profile found on success, NULL otherwise. 83 */ 84 static struct mlx5_flow_meter_profile * 85 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id) 86 { 87 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles; 88 struct mlx5_flow_meter_profile *fmp; 89 90 TAILQ_FOREACH(fmp, fmps, next) 91 if (meter_profile_id == fmp->meter_profile_id) 92 return fmp; 93 return NULL; 94 } 95 96 /** 97 * Validate the MTR profile. 98 * 99 * @param[in] dev 100 * Pointer to Ethernet device. 101 * @param[in] meter_profile_id 102 * Meter profile id. 103 * @param[in] profile 104 * Pointer to meter profile detail. 105 * @param[out] error 106 * Pointer to the error structure. 107 * 108 * @return 109 * 0 on success, a negative errno value otherwise and rte_errno is set. 110 */ 111 static int 112 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev, 113 uint32_t meter_profile_id, 114 struct rte_mtr_meter_profile *profile, 115 struct rte_mtr_error *error) 116 { 117 struct mlx5_priv *priv = dev->data->dev_private; 118 struct mlx5_flow_meter_profile *fmp; 119 120 /* Profile must not be NULL. */ 121 if (profile == NULL) 122 return -rte_mtr_error_set(error, EINVAL, 123 RTE_MTR_ERROR_TYPE_METER_PROFILE, 124 NULL, "Meter profile is null."); 125 /* Meter profile ID must be valid. */ 126 if (meter_profile_id == UINT32_MAX) 127 return -rte_mtr_error_set(error, EINVAL, 128 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 129 NULL, "Meter profile id not valid."); 130 /* Meter profile must not exist. */ 131 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 132 if (fmp) 133 return -rte_mtr_error_set(error, EEXIST, 134 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 135 NULL, 136 "Meter profile already exists."); 137 if (profile->alg == RTE_MTR_SRTCM_RFC2697) { 138 if (priv->config.hca_attr.qos.srtcm_sup) { 139 /* Verify support for flow meter parameters. */ 140 if (profile->srtcm_rfc2697.cir > 0 && 141 profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX && 142 profile->srtcm_rfc2697.cbs > 0 && 143 profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX && 144 profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX) 145 return 0; 146 else 147 return -rte_mtr_error_set 148 (error, ENOTSUP, 149 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 150 NULL, 151 profile->srtcm_rfc2697.ebs ? 152 "Metering value ebs must be 0." : 153 "Invalid metering parameters."); 154 } 155 } 156 return -rte_mtr_error_set(error, ENOTSUP, 157 RTE_MTR_ERROR_TYPE_METER_PROFILE, 158 NULL, "Metering algorithm not supported."); 159 } 160 161 /** 162 * Calculate mantissa and exponent for cir. 163 * 164 * @param[in] cir 165 * Value to be calculated. 166 * @param[out] man 167 * Pointer to the mantissa. 168 * @param[out] exp 169 * Pointer to the exp. 170 */ 171 static void 172 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp) 173 { 174 int64_t _cir; 175 int64_t delta = INT64_MAX; 176 uint8_t _man = 0; 177 uint8_t _exp = 0; 178 uint64_t m, e; 179 180 for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */ 181 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */ 182 _cir = (1000000000ULL * m) >> e; 183 if (llabs(cir - _cir) <= delta) { 184 delta = llabs(cir - _cir); 185 _man = m; 186 _exp = e; 187 } 188 } 189 } 190 *man = _man; 191 *exp = _exp; 192 } 193 194 /** 195 * Calculate mantissa and exponent for xbs. 196 * 197 * @param[in] xbs 198 * Value to be calculated. 199 * @param[out] man 200 * Pointer to the mantissa. 201 * @param[out] exp 202 * Pointer to the exp. 203 */ 204 static void 205 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp) 206 { 207 int _exp; 208 double _man; 209 210 /* Special case xbs == 0 ? both exp and matissa are 0. */ 211 if (xbs == 0) { 212 *man = 0; 213 *exp = 0; 214 return; 215 } 216 /* xbs = xbs_mantissa * 2^xbs_exponent */ 217 _man = frexp(xbs, &_exp); 218 _man = _man * pow(2, MLX5_MAN_WIDTH); 219 _exp = _exp - MLX5_MAN_WIDTH; 220 *man = (uint8_t)ceil(_man); 221 *exp = _exp; 222 } 223 224 /** 225 * Fill the prm meter parameter. 226 * 227 * @param[in,out] fmp 228 * Pointer to meter profie to be converted. 229 * @param[out] error 230 * Pointer to the error structure. 231 * 232 * @return 233 * 0 on success, a negative errno value otherwise and rte_errno is set. 234 */ 235 static int 236 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp, 237 struct rte_mtr_error *error) 238 { 239 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm; 240 uint8_t man, exp; 241 242 if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697) 243 return -rte_mtr_error_set(error, ENOTSUP, 244 RTE_MTR_ERROR_TYPE_METER_PROFILE, 245 NULL, "Metering algorithm not supported."); 246 /* cbs = cbs_mantissa * 2^cbs_exponent */ 247 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs, 248 &man, &exp); 249 srtcm->cbs_mantissa = man; 250 srtcm->cbs_exponent = exp; 251 /* Check if cbs mantissa is too large. */ 252 if (srtcm->cbs_exponent != exp) 253 return -rte_mtr_error_set(error, EINVAL, 254 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 255 "Metering profile parameter cbs is" 256 " invalid."); 257 /* ebs = ebs_mantissa * 2^ebs_exponent */ 258 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs, 259 &man, &exp); 260 srtcm->ebs_mantissa = man; 261 srtcm->ebs_exponent = exp; 262 /* Check if ebs mantissa is too large. */ 263 if (srtcm->ebs_exponent != exp) 264 return -rte_mtr_error_set(error, EINVAL, 265 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 266 "Metering profile parameter ebs is" 267 " invalid."); 268 /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */ 269 mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir, 270 &man, &exp); 271 srtcm->cir_mantissa = man; 272 srtcm->cir_exponent = exp; 273 /* Check if cir mantissa is too large. */ 274 if (srtcm->cir_exponent != exp) 275 return -rte_mtr_error_set(error, EINVAL, 276 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 277 "Metering profile parameter cir is" 278 " invalid."); 279 return 0; 280 } 281 282 /** 283 * Callback to get MTR capabilities. 284 * 285 * @param[in] dev 286 * Pointer to Ethernet device. 287 * @param[out] cap 288 * Pointer to save MTR capabilities. 289 * @param[out] error 290 * Pointer to the error structure. 291 * 292 * @return 293 * 0 on success, a negative errno value otherwise and rte_errno is set. 294 */ 295 static int 296 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev, 297 struct rte_mtr_capabilities *cap, 298 struct rte_mtr_error *error __rte_unused) 299 { 300 struct mlx5_priv *priv = dev->data->dev_private; 301 struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos; 302 303 if (!priv->mtr_en) 304 return -rte_mtr_error_set(error, ENOTSUP, 305 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 306 "Meter is not support"); 307 memset(cap, 0, sizeof(*cap)); 308 cap->n_max = 1 << qattr->log_max_flow_meter; 309 cap->n_shared_max = cap->n_max; 310 cap->identical = 1; 311 cap->shared_identical = 1; 312 cap->shared_n_flows_per_mtr_max = 4 << 20; 313 /* 2M flows can share the same meter. */ 314 cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */ 315 cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0; 316 cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */ 317 cap->policer_action_drop_supported = 1; 318 cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED | 319 RTE_MTR_STATS_N_PKTS_DROPPED; 320 return 0; 321 } 322 323 /** 324 * Callback to add MTR profile. 325 * 326 * @param[in] dev 327 * Pointer to Ethernet device. 328 * @param[in] meter_profile_id 329 * Meter profile id. 330 * @param[in] profile 331 * Pointer to meter profile detail. 332 * @param[out] error 333 * Pointer to the error structure. 334 * 335 * @return 336 * 0 on success, a negative errno value otherwise and rte_errno is set. 337 */ 338 static int 339 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev, 340 uint32_t meter_profile_id, 341 struct rte_mtr_meter_profile *profile, 342 struct rte_mtr_error *error) 343 { 344 struct mlx5_priv *priv = dev->data->dev_private; 345 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles; 346 struct mlx5_flow_meter_profile *fmp; 347 int ret; 348 349 if (!priv->mtr_en) 350 return -rte_mtr_error_set(error, ENOTSUP, 351 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 352 "Meter is not support"); 353 /* Check input params. */ 354 ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id, 355 profile, error); 356 if (ret) 357 return ret; 358 /* Meter profile memory allocation. */ 359 fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile), 360 RTE_CACHE_LINE_SIZE); 361 if (fmp == NULL) 362 return -rte_mtr_error_set(error, ENOMEM, 363 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 364 NULL, "Meter profile memory " 365 "alloc failed."); 366 /* Fill profile info. */ 367 fmp->meter_profile_id = meter_profile_id; 368 fmp->profile = *profile; 369 /* Fill the flow meter parameters for the PRM. */ 370 ret = mlx5_flow_meter_param_fill(fmp, error); 371 if (ret) 372 goto error; 373 /* Add to list. */ 374 TAILQ_INSERT_TAIL(fmps, fmp, next); 375 return 0; 376 error: 377 rte_free(fmp); 378 return ret; 379 } 380 381 /** 382 * Callback to delete MTR profile. 383 * 384 * @param[in] dev 385 * Pointer to Ethernet device. 386 * @param[in] meter_profile_id 387 * Meter profile id. 388 * @param[out] error 389 * Pointer to the error structure. 390 * 391 * @return 392 * 0 on success, a negative errno value otherwise and rte_errno is set. 393 */ 394 static int 395 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev, 396 uint32_t meter_profile_id, 397 struct rte_mtr_error *error) 398 { 399 struct mlx5_priv *priv = dev->data->dev_private; 400 struct mlx5_flow_meter_profile *fmp; 401 402 if (!priv->mtr_en) 403 return -rte_mtr_error_set(error, ENOTSUP, 404 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 405 "Meter is not support"); 406 /* Meter profile must exist. */ 407 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 408 if (fmp == NULL) 409 return -rte_mtr_error_set(error, ENOENT, 410 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 411 &meter_profile_id, 412 "Meter profile id invalid."); 413 /* Check profile is unused. */ 414 if (fmp->ref_cnt) 415 return -rte_mtr_error_set(error, EBUSY, 416 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 417 NULL, "Meter profile in use."); 418 /* Remove from list. */ 419 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next); 420 rte_free(fmp); 421 return 0; 422 } 423 424 /** 425 * Convert wrong color setting action to verbose error. 426 * 427 * @param[in] action 428 * Policy color action. 429 * 430 * @return 431 * Verbose meter color error type. 432 */ 433 static inline enum rte_mtr_error_type 434 action2error(enum rte_mtr_policer_action action) 435 { 436 switch (action) { 437 case MTR_POLICER_ACTION_COLOR_GREEN: 438 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN; 439 case MTR_POLICER_ACTION_COLOR_YELLOW: 440 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW; 441 case MTR_POLICER_ACTION_COLOR_RED: 442 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED; 443 default: 444 break; 445 } 446 return RTE_MTR_ERROR_TYPE_UNSPECIFIED; 447 } 448 449 /** 450 * Check meter validation. 451 * 452 * @param[in] priv 453 * Pointer to mlx5 private data structure. 454 * @param[in] meter_id 455 * Meter id. 456 * @param[in] params 457 * Pointer to rte meter parameters. 458 * @param[out] error 459 * Pointer to rte meter error structure. 460 * 461 * @return 462 * 0 on success, a negative errno value otherwise and rte_errno is set. 463 */ 464 static int 465 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id, 466 struct rte_mtr_params *params, 467 struct rte_mtr_error *error) 468 { 469 static enum rte_mtr_policer_action 470 valid_recol_action[RTE_COLORS] = { 471 MTR_POLICER_ACTION_COLOR_GREEN, 472 MTR_POLICER_ACTION_COLOR_YELLOW, 473 MTR_POLICER_ACTION_COLOR_RED }; 474 int i; 475 476 /* Meter params must not be NULL. */ 477 if (params == NULL) 478 return -rte_mtr_error_set(error, EINVAL, 479 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 480 NULL, "Meter object params null."); 481 /* Previous meter color is not supported. */ 482 if (params->use_prev_mtr_color) 483 return -rte_mtr_error_set(error, ENOTSUP, 484 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 485 NULL, 486 "Previous meter color " 487 "not supported."); 488 /* Validate policer settings. */ 489 for (i = 0; i < RTE_COLORS; i++) 490 if (params->action[i] != valid_recol_action[i] && 491 params->action[i] != MTR_POLICER_ACTION_DROP) 492 return -rte_mtr_error_set 493 (error, ENOTSUP, 494 action2error(params->action[i]), NULL, 495 "Recolor action not supported."); 496 /* Validate meter id. */ 497 if (mlx5_flow_meter_find(priv, meter_id)) 498 return -rte_mtr_error_set(error, EEXIST, 499 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 500 "Meter object already exists."); 501 return 0; 502 } 503 504 /** 505 * Modify the flow meter action. 506 * 507 * @param[in] priv 508 * Pointer to mlx5 private data structure. 509 * @param[in] fm 510 * Pointer to flow meter to be modified. 511 * @param[in] srtcm 512 * Pointer to meter srtcm description parameter. 513 * @param[in] modify_bits 514 * The bit in srtcm to be updated. 515 * @param[in] active_state 516 * The state to be updated. 517 * @return 518 * 0 on success, o negative value otherwise. 519 */ 520 static int 521 mlx5_flow_meter_action_modify(struct mlx5_priv *priv, 522 struct mlx5_flow_meter *fm, 523 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm, 524 uint64_t modify_bits, uint32_t active_state) 525 { 526 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER 527 uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 }; 528 uint32_t *attr; 529 struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 }; 530 int ret; 531 532 /* Fill command parameters. */ 533 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0; 534 mod_attr.flow_meter_parameter = in; 535 mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size; 536 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE) 537 mod_attr.active = !!active_state; 538 else 539 mod_attr.active = 0; 540 attr = in; 541 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) { 542 MLX5_SET(flow_meter_parameters, 543 attr, cbs_exponent, srtcm->cbs_exponent); 544 MLX5_SET(flow_meter_parameters, 545 attr, cbs_mantissa, srtcm->cbs_mantissa); 546 } 547 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) { 548 MLX5_SET(flow_meter_parameters, 549 attr, cir_exponent, srtcm->cir_exponent); 550 MLX5_SET(flow_meter_parameters, 551 attr, cir_mantissa, srtcm->cir_mantissa); 552 } 553 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) { 554 MLX5_SET(flow_meter_parameters, 555 attr, ebs_exponent, srtcm->ebs_exponent); 556 MLX5_SET(flow_meter_parameters, 557 attr, ebs_mantissa, srtcm->ebs_mantissa); 558 } 559 /* Apply modifications to meter only if it was created. */ 560 if (fm->mfts->meter_action) { 561 ret = mlx5_glue->dv_modify_flow_action_meter 562 (fm->mfts->meter_action, &mod_attr, 563 rte_cpu_to_be_64(modify_bits)); 564 if (ret) 565 return ret; 566 } 567 /* Update succeedded modify meter parameters. */ 568 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE) 569 fm->active_state = !!active_state; 570 attr = fm->mfts->fmp; 571 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) { 572 MLX5_SET(flow_meter_parameters, 573 attr, cbs_exponent, srtcm->cbs_exponent); 574 MLX5_SET(flow_meter_parameters, 575 attr, cbs_mantissa, srtcm->cbs_mantissa); 576 } 577 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) { 578 MLX5_SET(flow_meter_parameters, 579 attr, cir_exponent, srtcm->cir_exponent); 580 MLX5_SET(flow_meter_parameters, 581 attr, cir_mantissa, srtcm->cir_mantissa); 582 } 583 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) { 584 MLX5_SET(flow_meter_parameters, 585 attr, ebs_exponent, srtcm->ebs_exponent); 586 MLX5_SET(flow_meter_parameters, 587 attr, ebs_mantissa, srtcm->ebs_mantissa); 588 } 589 590 return 0; 591 #else 592 (void)priv; 593 (void)fm; 594 (void)srtcm; 595 (void)modify_bits; 596 (void)active_state; 597 return -ENOTSUP; 598 #endif 599 } 600 601 /** 602 * Create meter rules. 603 * 604 * @param[in] dev 605 * Pointer to Ethernet device. 606 * @param[in] meter_id 607 * Meter id. 608 * @param[in] params 609 * Pointer to rte meter parameters. 610 * @param[in] shared 611 * Meter shared with other flow or not. 612 * @param[out] error 613 * Pointer to rte meter error structure. 614 * 615 * @return 616 * 0 on success, a negative errno value otherwise and rte_errno is set. 617 */ 618 static int 619 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, 620 struct rte_mtr_params *params, int shared, 621 struct rte_mtr_error *error) 622 { 623 struct mlx5_priv *priv = dev->data->dev_private; 624 struct mlx5_flow_meters *fms = &priv->flow_meters; 625 struct mlx5_flow_meter_profile *fmp; 626 struct mlx5_flow_meter *fm; 627 const struct rte_flow_attr attr = { 628 .ingress = 1, 629 .egress = 1, 630 .transfer = priv->config.dv_esw_en ? 1 : 0, 631 }; 632 int ret; 633 unsigned int i; 634 uint32_t idx = 0; 635 636 if (!priv->mtr_en) 637 return -rte_mtr_error_set(error, ENOTSUP, 638 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 639 "Meter is not support"); 640 /* Validate the parameters. */ 641 ret = mlx5_flow_meter_validate(priv, meter_id, params, error); 642 if (ret) 643 return ret; 644 /* Meter profile must exist. */ 645 fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id); 646 if (fmp == NULL) 647 return -rte_mtr_error_set(error, ENOENT, 648 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 649 NULL, "Meter profile id not valid."); 650 /* Allocate the flow meter memory. */ 651 fm = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MTR], &idx); 652 if (fm == NULL) 653 return -rte_mtr_error_set(error, ENOMEM, 654 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 655 "Memory alloc failed for meter."); 656 fm->idx = idx; 657 /* Fill the flow meter parameters. */ 658 fm->meter_id = meter_id; 659 fm->profile = fmp; 660 memcpy(fm->action, params->action, sizeof(params->action)); 661 fm->stats_mask = params->stats_mask; 662 663 /* Alloc policer counters. */ 664 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) { 665 fm->policer_stats.cnt[i] = mlx5_counter_alloc(dev); 666 if (!fm->policer_stats.cnt[i]) 667 goto error; 668 } 669 fm->mfts = mlx5_flow_create_mtr_tbls(dev, fm); 670 if (!fm->mfts) 671 goto error; 672 ret = mlx5_flow_create_policer_rules(dev, fm, &attr); 673 if (ret) 674 goto error; 675 /* Add to the flow meter list. */ 676 TAILQ_INSERT_TAIL(fms, fm, next); 677 fm->active_state = 1; /* Config meter starts as active. */ 678 fm->shared = !!shared; 679 fm->policer_stats.stats_mask = params->stats_mask; 680 fm->profile->ref_cnt++; 681 return 0; 682 error: 683 mlx5_flow_destroy_policer_rules(dev, fm, &attr); 684 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts); 685 /* Free policer counters. */ 686 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) 687 if (fm->policer_stats.cnt[i]) 688 mlx5_counter_free(dev, fm->policer_stats.cnt[i]); 689 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], idx); 690 return -rte_mtr_error_set(error, -ret, 691 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 692 NULL, "Failed to create devx meter."); 693 } 694 695 /** 696 * Destroy meter rules. 697 * 698 * @param[in] dev 699 * Pointer to Ethernet device. 700 * @param[in] meter_id 701 * Meter id. 702 * @param[out] error 703 * Pointer to rte meter error structure. 704 * 705 * @return 706 * 0 on success, a negative errno value otherwise and rte_errno is set. 707 */ 708 static int 709 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id, 710 struct rte_mtr_error *error) 711 { 712 struct mlx5_priv *priv = dev->data->dev_private; 713 struct mlx5_flow_meters *fms = &priv->flow_meters; 714 struct mlx5_flow_meter_profile *fmp; 715 struct mlx5_flow_meter *fm; 716 const struct rte_flow_attr attr = { 717 .ingress = 1, 718 .egress = 1, 719 .transfer = priv->config.dv_esw_en ? 1 : 0, 720 }; 721 unsigned int i; 722 723 if (!priv->mtr_en) 724 return -rte_mtr_error_set(error, ENOTSUP, 725 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 726 "Meter is not support"); 727 /* Meter object must exist. */ 728 fm = mlx5_flow_meter_find(priv, meter_id); 729 if (fm == NULL) 730 return -rte_mtr_error_set(error, ENOENT, 731 RTE_MTR_ERROR_TYPE_MTR_ID, 732 NULL, "Meter object id not valid."); 733 /* Meter object must not have any owner. */ 734 if (fm->ref_cnt > 0) 735 return -rte_mtr_error_set(error, EBUSY, 736 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 737 NULL, "Meter object is being used."); 738 /* Get the meter profile. */ 739 fmp = fm->profile; 740 MLX5_ASSERT(fmp); 741 /* Update dependencies. */ 742 fmp->ref_cnt--; 743 /* Remove from the flow meter list. */ 744 TAILQ_REMOVE(fms, fm, next); 745 /* Free policer counters. */ 746 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) 747 if (fm->policer_stats.cnt[i]) 748 mlx5_counter_free(dev, fm->policer_stats.cnt[i]); 749 /* Free meter flow table */ 750 mlx5_flow_destroy_policer_rules(dev, fm, &attr); 751 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts); 752 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx); 753 return 0; 754 } 755 756 /** 757 * Modify meter state. 758 * 759 * @param[in] priv 760 * Pointer to mlx5 private data structure. 761 * @param[in] fm 762 * Pointer to flow meter. 763 * @param[in] new_state 764 * New state to update. 765 * @param[out] error 766 * Pointer to rte meter error structure. 767 * 768 * @return 769 * 0 on success, a negative errno value otherwise and rte_errno is set. 770 */ 771 static int 772 mlx5_flow_meter_modify_state(struct mlx5_priv *priv, 773 struct mlx5_flow_meter *fm, 774 uint32_t new_state, 775 struct rte_mtr_error *error) 776 { 777 static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = { 778 .cbs_exponent = 20, 779 .cbs_mantissa = 191, 780 .cir_exponent = 0, 781 .cir_mantissa = 200, 782 .ebs_exponent = 0, 783 .ebs_mantissa = 0, 784 }; 785 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS | 786 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR; 787 int ret; 788 789 if (new_state == MLX5_FLOW_METER_DISABLE) 790 ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm, 791 modify_bits, 0); 792 else 793 ret = mlx5_flow_meter_action_modify(priv, fm, 794 &fm->profile->srtcm_prm, 795 modify_bits, 0); 796 if (ret) 797 return -rte_mtr_error_set(error, -ret, 798 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 799 NULL, 800 new_state ? 801 "Failed to enable meter." : 802 "Failed to disable meter."); 803 return 0; 804 } 805 806 /** 807 * Callback to enable flow meter. 808 * 809 * @param[in] dev 810 * Pointer to Ethernet device. 811 * @param[in] meter_id 812 * Meter id. 813 * @param[out] error 814 * Pointer to rte meter error structure. 815 * 816 * @return 817 * 0 on success, a negative errno value otherwise and rte_errno is set. 818 */ 819 static int 820 mlx5_flow_meter_enable(struct rte_eth_dev *dev, 821 uint32_t meter_id, 822 struct rte_mtr_error *error) 823 { 824 struct mlx5_priv *priv = dev->data->dev_private; 825 struct mlx5_flow_meter *fm; 826 int ret; 827 828 if (!priv->mtr_en) 829 return -rte_mtr_error_set(error, ENOTSUP, 830 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 831 "Meter is not support"); 832 /* Meter object must exist. */ 833 fm = mlx5_flow_meter_find(priv, meter_id); 834 if (fm == NULL) 835 return -rte_mtr_error_set(error, ENOENT, 836 RTE_MTR_ERROR_TYPE_MTR_ID, 837 NULL, "Meter not found."); 838 if (fm->active_state == MLX5_FLOW_METER_ENABLE) 839 return 0; 840 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE, 841 error); 842 if (!ret) 843 fm->active_state = MLX5_FLOW_METER_ENABLE; 844 return ret; 845 } 846 847 /** 848 * Callback to disable flow meter. 849 * 850 * @param[in] dev 851 * Pointer to Ethernet device. 852 * @param[in] meter_id 853 * Meter id. 854 * @param[out] error 855 * Pointer to rte meter error structure. 856 * 857 * @return 858 * 0 on success, a negative errno value otherwise and rte_errno is set. 859 */ 860 static int 861 mlx5_flow_meter_disable(struct rte_eth_dev *dev, 862 uint32_t meter_id, 863 struct rte_mtr_error *error) 864 { 865 struct mlx5_priv *priv = dev->data->dev_private; 866 struct mlx5_flow_meter *fm; 867 int ret; 868 869 if (!priv->mtr_en) 870 return -rte_mtr_error_set(error, ENOTSUP, 871 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 872 "Meter is not support"); 873 /* Meter object must exist. */ 874 fm = mlx5_flow_meter_find(priv, meter_id); 875 if (fm == NULL) 876 return -rte_mtr_error_set(error, ENOENT, 877 RTE_MTR_ERROR_TYPE_MTR_ID, 878 NULL, "Meter not found."); 879 if (fm->active_state == MLX5_FLOW_METER_DISABLE) 880 return 0; 881 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE, 882 error); 883 if (!ret) 884 fm->active_state = MLX5_FLOW_METER_DISABLE; 885 return ret; 886 } 887 888 /** 889 * Callback to update meter profile. 890 * 891 * @param[in] dev 892 * Pointer to Ethernet device. 893 * @param[in] meter_id 894 * Meter id. 895 * @param[in] meter_profile_id 896 * To be updated meter profile id. 897 * @param[out] error 898 * Pointer to rte meter error structure. 899 * 900 * @return 901 * 0 on success, a negative errno value otherwise and rte_errno is set. 902 */ 903 static int 904 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev, 905 uint32_t meter_id, 906 uint32_t meter_profile_id, 907 struct rte_mtr_error *error) 908 { 909 struct mlx5_priv *priv = dev->data->dev_private; 910 struct mlx5_flow_meter_profile *fmp; 911 struct mlx5_flow_meter_profile *old_fmp; 912 struct mlx5_flow_meter *fm; 913 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS | 914 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR; 915 int ret; 916 917 if (!priv->mtr_en) 918 return -rte_mtr_error_set(error, ENOTSUP, 919 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 920 "Meter is not support"); 921 /* Meter profile must exist. */ 922 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 923 if (fmp == NULL) 924 return -rte_mtr_error_set(error, ENOENT, 925 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 926 NULL, "Meter profile not found."); 927 /* Meter object must exist. */ 928 fm = mlx5_flow_meter_find(priv, meter_id); 929 if (fm == NULL) 930 return -rte_mtr_error_set(error, ENOENT, 931 RTE_MTR_ERROR_TYPE_MTR_ID, 932 NULL, "Meter not found."); 933 /* MTR object already set to meter profile id. */ 934 old_fmp = fm->profile; 935 if (fmp == old_fmp) 936 return 0; 937 /* Update the profile. */ 938 fm->profile = fmp; 939 /* Update meter params in HW (if not disabled). */ 940 if (fm->active_state == MLX5_FLOW_METER_DISABLE) 941 return 0; 942 ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm, 943 modify_bits, fm->active_state); 944 if (ret) { 945 fm->profile = old_fmp; 946 return -rte_mtr_error_set(error, -ret, 947 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 948 NULL, "Failed to update meter" 949 " parmeters in hardware."); 950 } 951 old_fmp->ref_cnt--; 952 fmp->ref_cnt++; 953 return 0; 954 } 955 956 /** 957 * Callback to update meter stats mask. 958 * 959 * @param[in] dev 960 * Pointer to Ethernet device. 961 * @param[in] meter_id 962 * Meter id. 963 * @param[in] stats_mask 964 * To be updated stats_mask. 965 * @param[out] error 966 * Pointer to rte meter error structure. 967 * 968 * @return 969 * 0 on success, a negative errno value otherwise and rte_errno is set. 970 */ 971 static int 972 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev, 973 uint32_t meter_id, 974 uint64_t stats_mask, 975 struct rte_mtr_error *error) 976 { 977 struct mlx5_priv *priv = dev->data->dev_private; 978 struct mlx5_flow_meter *fm; 979 980 if (!priv->mtr_en) 981 return -rte_mtr_error_set(error, ENOTSUP, 982 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 983 "Meter is not support"); 984 /* Meter object must exist. */ 985 fm = mlx5_flow_meter_find(priv, meter_id); 986 if (fm == NULL) 987 return -rte_mtr_error_set(error, ENOENT, 988 RTE_MTR_ERROR_TYPE_MTR_ID, 989 NULL, "Meter object id not valid."); 990 fm->policer_stats.stats_mask = stats_mask; 991 return 0; 992 } 993 994 /** 995 * Callback to read meter statistics. 996 * 997 * @param[in] dev 998 * Pointer to Ethernet device. 999 * @param[in] meter_id 1000 * Meter id. 1001 * @param[out] stats 1002 * Pointer to store the statistics. 1003 * @param[out] stats_mask 1004 * Pointer to store the stats_mask. 1005 * @param[in] clear 1006 * Statistic to be cleared after read or not. 1007 * @param[out] error 1008 * Pointer to rte meter error structure. 1009 * 1010 * @return 1011 * 0 on success, a negative errno value otherwise and rte_errno is set. 1012 */ 1013 static int 1014 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev, 1015 uint32_t meter_id, 1016 struct rte_mtr_stats *stats, 1017 uint64_t *stats_mask, 1018 int clear, 1019 struct rte_mtr_error *error) 1020 { 1021 static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = { 1022 RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN, 1023 RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW, 1024 RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED, 1025 RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED 1026 }; 1027 struct mlx5_priv *priv = dev->data->dev_private; 1028 struct mlx5_flow_meter *fm; 1029 struct mlx5_flow_policer_stats *ps; 1030 uint64_t pkts_dropped = 0; 1031 uint64_t bytes_dropped = 0; 1032 uint64_t pkts; 1033 uint64_t bytes; 1034 int i; 1035 int ret = 0; 1036 1037 if (!priv->mtr_en) 1038 return -rte_mtr_error_set(error, ENOTSUP, 1039 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1040 "Meter is not support"); 1041 /* Meter object must exist. */ 1042 fm = mlx5_flow_meter_find(priv, meter_id); 1043 if (fm == NULL) 1044 return -rte_mtr_error_set(error, ENOENT, 1045 RTE_MTR_ERROR_TYPE_MTR_ID, 1046 NULL, "Meter object id not valid."); 1047 ps = &fm->policer_stats; 1048 *stats_mask = ps->stats_mask; 1049 for (i = 0; i < RTE_MTR_DROPPED; i++) { 1050 if (*stats_mask & meter2mask[i]) { 1051 ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts, 1052 &bytes); 1053 if (ret) 1054 goto error; 1055 if (fm->action[i] == MTR_POLICER_ACTION_DROP) { 1056 pkts_dropped += pkts; 1057 bytes_dropped += bytes; 1058 } 1059 /* If need to read the packets, set it. */ 1060 if ((1 << i) & (*stats_mask & meter2mask[i])) 1061 stats->n_pkts[i] = pkts; 1062 /* If need to read the bytes, set it. */ 1063 if ((1 << (RTE_MTR_DROPPED + 1 + i)) & 1064 (*stats_mask & meter2mask[i])) 1065 stats->n_bytes[i] = bytes; 1066 } 1067 } 1068 /* Dropped packets/bytes are treated differently. */ 1069 if (*stats_mask & meter2mask[i]) { 1070 ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts, 1071 &bytes); 1072 if (ret) 1073 goto error; 1074 pkts += pkts_dropped; 1075 bytes += bytes_dropped; 1076 /* If need to read the packets, set it. */ 1077 if ((*stats_mask & meter2mask[i]) & 1078 RTE_MTR_STATS_N_PKTS_DROPPED) 1079 stats->n_pkts_dropped = pkts; 1080 /* If need to read the bytes, set it. */ 1081 if ((*stats_mask & meter2mask[i]) & 1082 RTE_MTR_STATS_N_BYTES_DROPPED) 1083 stats->n_bytes_dropped = bytes; 1084 } 1085 return 0; 1086 error: 1087 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL, 1088 "Failed to read policer counters."); 1089 } 1090 1091 static const struct rte_mtr_ops mlx5_flow_mtr_ops = { 1092 .capabilities_get = mlx5_flow_mtr_cap_get, 1093 .meter_profile_add = mlx5_flow_meter_profile_add, 1094 .meter_profile_delete = mlx5_flow_meter_profile_delete, 1095 .create = mlx5_flow_meter_create, 1096 .destroy = mlx5_flow_meter_destroy, 1097 .meter_enable = mlx5_flow_meter_enable, 1098 .meter_disable = mlx5_flow_meter_disable, 1099 .meter_profile_update = mlx5_flow_meter_profile_update, 1100 .meter_dscp_table_update = NULL, 1101 .policer_actions_update = NULL, 1102 .stats_update = mlx5_flow_meter_stats_update, 1103 .stats_read = mlx5_flow_meter_stats_read, 1104 }; 1105 1106 /** 1107 * Get meter operations. 1108 * 1109 * @param dev 1110 * Pointer to Ethernet device structure. 1111 * @param arg 1112 * Pointer to set the mtr operations. 1113 * 1114 * @return 1115 * Always 0. 1116 */ 1117 int 1118 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) 1119 { 1120 *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops; 1121 return 0; 1122 } 1123 1124 /** 1125 * Find meter by id. 1126 * 1127 * @param priv 1128 * Pointer to mlx5_priv. 1129 * @param meter_id 1130 * Meter id. 1131 * 1132 * @return 1133 * Pointer to the profile found on success, NULL otherwise. 1134 */ 1135 struct mlx5_flow_meter * 1136 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id) 1137 { 1138 struct mlx5_flow_meters *fms = &priv->flow_meters; 1139 struct mlx5_flow_meter *fm; 1140 1141 TAILQ_FOREACH(fm, fms, next) 1142 if (meter_id == fm->meter_id) 1143 return fm; 1144 return NULL; 1145 } 1146 1147 /** 1148 * Attach meter to flow. 1149 * Unidirectional Meter creation can only be done 1150 * when flow direction is known, i.e. when calling meter_attach. 1151 * 1152 * @param [in] priv 1153 * Pointer to mlx5 private data. 1154 * @param [in] meter_id 1155 * Flow meter id. 1156 * @param [in] attr 1157 * Pointer to flow attributes. 1158 * @param [out] error 1159 * Pointer to error structure. 1160 * 1161 * @return the flow meter pointer, NULL otherwise. 1162 */ 1163 struct mlx5_flow_meter * 1164 mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id, 1165 const struct rte_flow_attr *attr, 1166 struct rte_flow_error *error) 1167 { 1168 struct mlx5_flow_meter *fm; 1169 1170 fm = mlx5_flow_meter_find(priv, meter_id); 1171 if (fm == NULL) { 1172 rte_flow_error_set(error, ENOENT, 1173 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1174 "Meter object id not valid"); 1175 goto error; 1176 } 1177 if (!fm->shared && fm->ref_cnt) { 1178 DRV_LOG(ERR, "Cannot share a non-shared meter."); 1179 rte_flow_error_set(error, EINVAL, 1180 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1181 "Meter can't be shared"); 1182 goto error; 1183 } 1184 if (!fm->ref_cnt++) { 1185 MLX5_ASSERT(!fm->mfts->meter_action); 1186 fm->ingress = attr->ingress; 1187 fm->egress = attr->egress; 1188 fm->transfer = attr->transfer; 1189 /* This also creates the meter object. */ 1190 fm->mfts->meter_action = mlx5_flow_meter_action_create(priv, 1191 fm); 1192 if (!fm->mfts->meter_action) 1193 goto error_detach; 1194 } else { 1195 MLX5_ASSERT(fm->mfts->meter_action); 1196 if (attr->transfer != fm->transfer || 1197 attr->ingress != fm->ingress || 1198 attr->egress != fm->egress) { 1199 DRV_LOG(ERR, "meter I/O attributes do not " 1200 "match flow I/O attributes."); 1201 goto error_detach; 1202 } 1203 } 1204 return fm; 1205 error_detach: 1206 mlx5_flow_meter_detach(fm); 1207 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1208 fm->mfts->meter_action ? "Meter attr not match" : 1209 "Meter action create failed"); 1210 error: 1211 return NULL; 1212 } 1213 1214 /** 1215 * Detach meter from flow. 1216 * 1217 * @param [in] fm 1218 * Pointer to flow meter. 1219 */ 1220 void 1221 mlx5_flow_meter_detach(struct mlx5_flow_meter *fm) 1222 { 1223 MLX5_ASSERT(fm->ref_cnt); 1224 if (--fm->ref_cnt) 1225 return; 1226 if (fm->mfts->meter_action) 1227 mlx5_glue->destroy_flow_action(fm->mfts->meter_action); 1228 fm->mfts->meter_action = NULL; 1229 fm->ingress = 0; 1230 fm->egress = 0; 1231 fm->transfer = 0; 1232 } 1233 1234 /** 1235 * Flush meter configuration. 1236 * 1237 * @param[in] dev 1238 * Pointer to Ethernet device. 1239 * @param[out] error 1240 * Pointer to rte meter error structure. 1241 * 1242 * @return 1243 * 0 on success, a negative errno value otherwise and rte_errno is set. 1244 */ 1245 int 1246 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) 1247 { 1248 struct mlx5_priv *priv = dev->data->dev_private; 1249 struct mlx5_flow_meters *fms = &priv->flow_meters; 1250 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles; 1251 struct mlx5_flow_meter_profile *fmp; 1252 struct mlx5_flow_meter *fm; 1253 const struct rte_flow_attr attr = { 1254 .ingress = 1, 1255 .egress = 1, 1256 .transfer = priv->config.dv_esw_en ? 1 : 0, 1257 }; 1258 void *tmp; 1259 uint32_t i; 1260 1261 TAILQ_FOREACH_SAFE(fm, fms, next, tmp) { 1262 /* Meter object must not have any owner. */ 1263 MLX5_ASSERT(!fm->ref_cnt); 1264 /* Get meter profile. */ 1265 fmp = fm->profile; 1266 if (fmp == NULL) 1267 return -rte_mtr_error_set(error, EINVAL, 1268 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 1269 NULL, "MTR object meter profile invalid."); 1270 /* Update dependencies. */ 1271 fmp->ref_cnt--; 1272 /* Remove from list. */ 1273 TAILQ_REMOVE(fms, fm, next); 1274 /* Free policer counters. */ 1275 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) 1276 if (fm->policer_stats.cnt[i]) 1277 mlx5_counter_free(dev, 1278 fm->policer_stats.cnt[i]); 1279 /* Free meter flow table. */ 1280 mlx5_flow_destroy_policer_rules(dev, fm, &attr); 1281 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts); 1282 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx); 1283 } 1284 TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) { 1285 /* Check unused. */ 1286 MLX5_ASSERT(!fmp->ref_cnt); 1287 /* Remove from list. */ 1288 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next); 1289 rte_free(fmp); 1290 } 1291 return 0; 1292 } 1293