1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022 Corigine, Inc. 3 * All rights reserved. 4 */ 5 6 #include "nfp_mtr.h" 7 8 #include <rte_alarm.h> 9 #include <rte_malloc.h> 10 #include <rte_mtr_driver.h> 11 12 #include "flower/nfp_flower_representor.h" 13 #include "nfp_logs.h" 14 15 #define NFP_MAX_POLICY_CNT NFP_MAX_MTR_CNT 16 #define NFP_MAX_PROFILE_CNT NFP_MAX_MTR_CNT 17 18 #define NFP_FL_QOS_PPS RTE_BIT32(15) 19 #define NFP_FL_QOS_METER RTE_BIT32(10) 20 #define NFP_FL_QOS_RFC2697 RTE_BIT32(0) 21 22 /* Alarm timeout value in microseconds */ 23 #define NFP_METER_STATS_INTERVAL 1000000 /* 1 second */ 24 25 /** 26 * Callback to get MTR capabilities. 27 * 28 * @param[in] dev 29 * Pointer to the device (unused). 30 * @param[out] cap 31 * Pointer to the meter object capabilities. 32 * @param[out] error 33 * Pointer to the error (unused). 34 * 35 * @returns 36 * 0 on success, a negative value otherwise and rte_errno is set. 37 */ 38 static int 39 nfp_mtr_cap_get(struct rte_eth_dev *dev __rte_unused, 40 struct rte_mtr_capabilities *cap, 41 struct rte_mtr_error *error) 42 { 43 if (cap == NULL) { 44 return -rte_mtr_error_set(error, EINVAL, 45 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 46 NULL, "NULL pointer for capabilitie argument."); 47 } 48 49 memset(cap, 0, sizeof(struct rte_mtr_capabilities)); 50 51 cap->n_max = NFP_MAX_MTR_CNT; 52 cap->n_shared_max = NFP_MAX_MTR_CNT; 53 cap->identical = 1; 54 cap->shared_identical = 1; 55 cap->chaining_n_mtrs_per_flow_max = 1; 56 cap->meter_srtcm_rfc2697_n_max = NFP_MAX_MTR_CNT; 57 cap->meter_trtcm_rfc2698_n_max = NFP_MAX_MTR_CNT; 58 cap->meter_rate_max = UINT64_MAX; 59 cap->meter_policy_n_max = NFP_MAX_POLICY_CNT; 60 cap->srtcm_rfc2697_byte_mode_supported = 1; 61 cap->srtcm_rfc2697_packet_mode_supported = 1; 62 cap->trtcm_rfc2698_byte_mode_supported = 1; 63 cap->trtcm_rfc2698_packet_mode_supported = 1; 64 cap->stats_mask = RTE_MTR_STATS_N_PKTS_GREEN | 65 RTE_MTR_STATS_N_PKTS_DROPPED | 66 RTE_MTR_STATS_N_BYTES_GREEN | 67 RTE_MTR_STATS_N_BYTES_DROPPED; 68 69 return 0; 70 } 71 72 static int 73 nfp_mtr_profile_validate(uint32_t mtr_profile_id, 74 struct rte_mtr_meter_profile *profile, 75 struct rte_mtr_error *error) 76 { 77 /* Profile must not be NULL. */ 78 if (profile == NULL) { 79 return -rte_mtr_error_set(error, EINVAL, 80 RTE_MTR_ERROR_TYPE_METER_PROFILE, 81 NULL, "Meter profile is null."); 82 } 83 84 /* Meter profile ID must be valid. */ 85 if (mtr_profile_id >= NFP_MAX_PROFILE_CNT) { 86 return -rte_mtr_error_set(error, EINVAL, 87 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 88 NULL, "Meter profile id not valid."); 89 } 90 91 switch (profile->alg) { 92 case RTE_MTR_SRTCM_RFC2697: 93 case RTE_MTR_TRTCM_RFC2698: 94 return 0; 95 case RTE_MTR_TRTCM_RFC4115: 96 return -rte_mtr_error_set(error, ENOTSUP, 97 RTE_MTR_ERROR_TYPE_METER_PROFILE, 98 NULL, "Unsupported metering algorithm."); 99 default: 100 return -rte_mtr_error_set(error, ENOTSUP, 101 RTE_MTR_ERROR_TYPE_METER_PROFILE, 102 NULL, "Unknown metering algorithm."); 103 } 104 } 105 106 static void 107 nfp_mtr_profile_config_2698(uint32_t mtr_profile_id, 108 struct rte_mtr_meter_profile *profile, 109 struct nfp_profile_conf *conf) 110 { 111 if (profile->packet_mode != 0) 112 conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS); 113 114 conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER); 115 conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id); 116 117 conf->bkt_tkn_c = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs); 118 conf->bkt_tkn_p = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs); 119 conf->cbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs); 120 conf->pbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs); 121 conf->cir = rte_cpu_to_be_32(profile->trtcm_rfc2698.cir); 122 conf->pir = rte_cpu_to_be_32(profile->trtcm_rfc2698.pir); 123 } 124 125 static void 126 nfp_mtr_profile_config_2697(uint32_t mtr_profile_id, 127 struct rte_mtr_meter_profile *profile, 128 struct nfp_profile_conf *conf) 129 { 130 if (profile->packet_mode != 0) 131 conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS); 132 133 conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_RFC2697); 134 conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER); 135 conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id); 136 137 conf->bkt_tkn_c = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs); 138 conf->bkt_tkn_p = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs); 139 conf->cbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs); 140 conf->pbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs); 141 conf->cir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir); 142 conf->pir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir); 143 } 144 145 static int 146 nfp_mtr_profile_conf_mod(uint32_t mtr_profile_id, 147 struct rte_mtr_meter_profile *profile, 148 struct nfp_profile_conf *conf) 149 { 150 switch (profile->alg) { 151 case RTE_MTR_SRTCM_RFC2697: 152 nfp_mtr_profile_config_2697(mtr_profile_id, profile, conf); 153 return 0; 154 case RTE_MTR_TRTCM_RFC2698: 155 nfp_mtr_profile_config_2698(mtr_profile_id, profile, conf); 156 return 0; 157 case RTE_MTR_TRTCM_RFC4115: 158 return -ENOTSUP; 159 default: 160 return -EINVAL; 161 } 162 } 163 164 static int 165 nfp_mtr_profile_conf_insert(uint32_t mtr_profile_id, 166 struct rte_mtr_meter_profile *profile, 167 struct nfp_mtr_profile *mtr_profile) 168 { 169 mtr_profile->profile_id = mtr_profile_id; 170 mtr_profile->in_use = false; 171 172 return nfp_mtr_profile_conf_mod(mtr_profile_id, profile, 173 &mtr_profile->conf); 174 } 175 176 static struct nfp_mtr_profile * 177 nfp_mtr_profile_search(struct nfp_mtr_priv *priv, uint32_t mtr_profile_id) 178 { 179 struct nfp_mtr_profile *mtr_profile; 180 181 LIST_FOREACH(mtr_profile, &priv->profiles, next) 182 if (mtr_profile->profile_id == mtr_profile_id) 183 break; 184 185 return mtr_profile; 186 } 187 188 static int 189 nfp_mtr_profile_insert(struct nfp_app_fw_flower *app_fw_flower, 190 struct rte_mtr_meter_profile *profile, 191 uint32_t mtr_profile_id, 192 struct rte_mtr_error *error) 193 { 194 int ret; 195 struct nfp_mtr_priv *priv; 196 struct nfp_mtr_profile *mtr_profile; 197 198 priv = app_fw_flower->mtr_priv; 199 200 /* Meter profile memory allocation. */ 201 mtr_profile = rte_zmalloc(NULL, sizeof(struct nfp_mtr_profile), 0); 202 if (mtr_profile == NULL) { 203 return -rte_mtr_error_set(error, ENOMEM, 204 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 205 NULL, "Meter profile alloc failed."); 206 } 207 208 ret = nfp_mtr_profile_conf_insert(mtr_profile_id, 209 profile, mtr_profile); 210 if (ret != 0) { 211 rte_mtr_error_set(error, EINVAL, 212 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 213 NULL, "Insert profile config failed."); 214 goto free_profile; 215 } 216 217 ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf); 218 if (ret != 0) { 219 rte_mtr_error_set(error, EINVAL, 220 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 221 NULL, "Add meter to firmware failed."); 222 goto free_profile; 223 } 224 225 /* Insert profile into profile list */ 226 LIST_INSERT_HEAD(&priv->profiles, mtr_profile, next); 227 228 return 0; 229 230 free_profile: 231 rte_free(mtr_profile); 232 233 return ret; 234 } 235 236 static int 237 nfp_mtr_profile_mod(struct nfp_app_fw_flower *app_fw_flower, 238 struct rte_mtr_meter_profile *profile, 239 struct nfp_mtr_profile *mtr_profile, 240 struct rte_mtr_error *error) 241 { 242 int ret; 243 struct nfp_profile_conf old_conf; 244 245 /* Get the old profile config */ 246 rte_memcpy(&old_conf, &mtr_profile->conf, sizeof(old_conf)); 247 248 memset(&mtr_profile->conf, 0, sizeof(struct nfp_profile_conf)); 249 250 ret = nfp_mtr_profile_conf_mod(mtr_profile->profile_id, 251 profile, &mtr_profile->conf); 252 if (ret != 0) { 253 rte_mtr_error_set(error, EINVAL, 254 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 255 NULL, "Mod profile config failed."); 256 goto rollback; 257 } 258 259 ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf); 260 if (ret != 0) { 261 rte_mtr_error_set(error, EINVAL, 262 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 263 NULL, "Mod meter to firmware failed."); 264 goto rollback; 265 } 266 267 return 0; 268 269 rollback: 270 rte_memcpy(&mtr_profile->conf, &old_conf, sizeof(old_conf)); 271 272 return ret; 273 } 274 275 /** 276 * Callback to add MTR profile. 277 * 278 * @param[in] dev 279 * Pointer to Ethernet device. 280 * @param[in] mtr_profile_id 281 * Meter profile id. 282 * @param[in] profile 283 * Pointer to meter profile detail. 284 * @param[out] error 285 * Pointer to the error structure. 286 * 287 * @return 288 * 0 on success, a negative value otherwise and rte_errno is set. 289 */ 290 static int 291 nfp_mtr_profile_add(struct rte_eth_dev *dev, 292 uint32_t mtr_profile_id, 293 struct rte_mtr_meter_profile *profile, 294 struct rte_mtr_error *error) 295 { 296 int ret; 297 struct nfp_mtr_priv *priv; 298 struct nfp_mtr_profile *mtr_profile; 299 struct nfp_app_fw_flower *app_fw_flower; 300 struct nfp_flower_representor *representor; 301 302 representor = dev->data->dev_private; 303 app_fw_flower = representor->app_fw_flower; 304 priv = app_fw_flower->mtr_priv; 305 306 /* Check input params */ 307 ret = nfp_mtr_profile_validate(mtr_profile_id, profile, error); 308 if (ret != 0) 309 return ret; 310 311 /* Check if mtr profile id exist */ 312 mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id); 313 if (mtr_profile == NULL) { 314 ret = nfp_mtr_profile_insert(app_fw_flower, 315 profile, mtr_profile_id, error); 316 } else { 317 ret = nfp_mtr_profile_mod(app_fw_flower, 318 profile, mtr_profile, error); 319 } 320 321 return ret; 322 } 323 324 /** 325 * Callback to delete MTR profile. 326 * 327 * @param[in] dev 328 * Pointer to Ethernet device. 329 * @param[in] mtr_profile_id 330 * Meter profile id. 331 * @param[out] error 332 * Pointer to the error structure. 333 * 334 * @return 335 * 0 on success, a negative value otherwise and rte_errno is set. 336 */ 337 static int 338 nfp_mtr_profile_delete(struct rte_eth_dev *dev, 339 uint32_t mtr_profile_id, 340 struct rte_mtr_error *error) 341 { 342 int ret; 343 struct nfp_mtr_priv *priv; 344 struct nfp_mtr_profile *mtr_profile; 345 struct nfp_app_fw_flower *app_fw_flower; 346 struct nfp_flower_representor *representor; 347 348 representor = dev->data->dev_private; 349 app_fw_flower = representor->app_fw_flower; 350 priv = app_fw_flower->mtr_priv; 351 352 /* Check if mtr profile id exist */ 353 mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id); 354 if (mtr_profile == NULL) { 355 return -rte_mtr_error_set(error, EINVAL, 356 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 357 NULL, "Request meter profile not exist."); 358 } 359 360 if (mtr_profile->in_use) { 361 return -rte_mtr_error_set(error, EINVAL, 362 RTE_MTR_ERROR_TYPE_METER_PROFILE, 363 NULL, "Request meter profile is been used."); 364 } 365 366 ret = nfp_flower_cmsg_qos_delete(app_fw_flower, &mtr_profile->conf); 367 if (ret != 0) { 368 return -rte_mtr_error_set(error, EINVAL, 369 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 370 NULL, "Delete meter from firmware failed."); 371 } 372 373 /* Remove profile from profile list */ 374 LIST_REMOVE(mtr_profile, next); 375 rte_free(mtr_profile); 376 377 return 0; 378 } 379 380 static struct nfp_mtr_policy * 381 nfp_mtr_policy_search(struct nfp_mtr_priv *priv, uint32_t mtr_policy_id) 382 { 383 struct nfp_mtr_policy *mtr_policy; 384 385 LIST_FOREACH(mtr_policy, &priv->policies, next) 386 if (mtr_policy->policy_id == mtr_policy_id) 387 break; 388 389 return mtr_policy; 390 } 391 392 static int 393 nfp_mtr_policy_validate(uint32_t mtr_policy_id, 394 struct rte_mtr_meter_policy_params *policy, 395 struct rte_mtr_error *error) 396 { 397 const struct rte_flow_action *action; 398 399 /* Policy must not be NULL */ 400 if (policy == NULL) { 401 return -rte_mtr_error_set(error, EINVAL, 402 RTE_MTR_ERROR_TYPE_METER_POLICY, 403 NULL, "Meter policy is null."); 404 } 405 406 /* Meter policy ID must be valid. */ 407 if (mtr_policy_id >= NFP_MAX_POLICY_CNT) { 408 return -rte_mtr_error_set(error, EINVAL, 409 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 410 NULL, "Meter policy id not valid."); 411 } 412 413 /* Check green action 414 * Actions equal NULL means end action 415 */ 416 action = policy->actions[RTE_COLOR_GREEN]; 417 if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) { 418 return -rte_mtr_error_set(error, EINVAL, 419 RTE_MTR_ERROR_TYPE_METER_POLICY, 420 NULL, "Green action must be void or end."); 421 } 422 423 /* Check yellow action 424 * Actions equal NULL means end action 425 */ 426 action = policy->actions[RTE_COLOR_YELLOW]; 427 if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) { 428 return -rte_mtr_error_set(error, EINVAL, 429 RTE_MTR_ERROR_TYPE_METER_POLICY, 430 NULL, "Yellow action must be void or end."); 431 } 432 433 /* Check red action */ 434 action = policy->actions[RTE_COLOR_RED]; 435 if (action == NULL || action->type != RTE_FLOW_ACTION_TYPE_DROP) { 436 return -rte_mtr_error_set(error, EINVAL, 437 RTE_MTR_ERROR_TYPE_METER_POLICY, 438 NULL, "Red action must be drop."); 439 } 440 441 return 0; 442 } 443 444 /** 445 * Callback to add MTR policy. 446 * 447 * @param[in] dev 448 * Pointer to Ethernet device. 449 * @param[in] mtr_policy_id 450 * Meter policy id. 451 * @param[in] policy 452 * Pointer to meter policy detail. 453 * @param[out] error 454 * Pointer to the error structure. 455 * 456 * @return 457 * 0 on success, a negative value otherwise and rte_errno is set. 458 */ 459 static int 460 nfp_mtr_policy_add(struct rte_eth_dev *dev, 461 uint32_t mtr_policy_id, 462 struct rte_mtr_meter_policy_params *policy, 463 struct rte_mtr_error *error) 464 { 465 int ret; 466 struct nfp_mtr_priv *priv; 467 struct nfp_mtr_policy *mtr_policy; 468 struct nfp_flower_representor *representor; 469 470 representor = dev->data->dev_private; 471 priv = representor->app_fw_flower->mtr_priv; 472 473 /* Check if mtr policy id exist */ 474 mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id); 475 if (mtr_policy != NULL) { 476 return -rte_mtr_error_set(error, EEXIST, 477 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 478 NULL, "Meter policy already exist."); 479 } 480 481 /* Check input params */ 482 ret = nfp_mtr_policy_validate(mtr_policy_id, policy, error); 483 if (ret != 0) 484 return ret; 485 486 /* Meter policy memory alloc */ 487 mtr_policy = rte_zmalloc(NULL, sizeof(struct nfp_mtr_policy), 0); 488 if (mtr_policy == NULL) { 489 return -rte_mtr_error_set(error, ENOMEM, 490 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 491 NULL, "Meter policy alloc failed."); 492 } 493 494 mtr_policy->policy_id = mtr_policy_id; 495 rte_memcpy(&mtr_policy->policy, policy, 496 sizeof(struct rte_mtr_meter_policy_params)); 497 498 /* Insert policy into policy list */ 499 LIST_INSERT_HEAD(&priv->policies, mtr_policy, next); 500 501 return 0; 502 } 503 504 /** 505 * Callback to delete MTR policy. 506 * 507 * @param[in] dev 508 * Pointer to Ethernet device. 509 * @param[in] mtr_policy_id 510 * Meter policy id. 511 * @param[out] error 512 * Pointer to the error structure. 513 * 514 * @return 515 * 0 on success, a negative value otherwise and rte_errno is set. 516 */ 517 static int 518 nfp_mtr_policy_delete(struct rte_eth_dev *dev, 519 uint32_t mtr_policy_id, 520 struct rte_mtr_error *error) 521 { 522 struct nfp_mtr_priv *priv; 523 struct nfp_mtr_policy *mtr_policy; 524 struct nfp_flower_representor *representor; 525 526 representor = dev->data->dev_private; 527 priv = representor->app_fw_flower->mtr_priv; 528 529 /* Check if mtr policy id exist */ 530 mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id); 531 if (mtr_policy == NULL) { 532 return -rte_mtr_error_set(error, EINVAL, 533 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 534 NULL, "Request meter policy not exist."); 535 } 536 537 if (mtr_policy->ref_cnt > 0) { 538 return -rte_mtr_error_set(error, EBUSY, 539 RTE_MTR_ERROR_TYPE_METER_POLICY, 540 NULL, "Request mtr policy is been used."); 541 } 542 543 /* Remove profile from profile list */ 544 LIST_REMOVE(mtr_policy, next); 545 rte_free(mtr_policy); 546 547 return 0; 548 } 549 550 struct nfp_mtr * 551 nfp_mtr_find_by_mtr_id(struct nfp_mtr_priv *priv, uint32_t mtr_id) 552 { 553 struct nfp_mtr *mtr; 554 555 LIST_FOREACH(mtr, &priv->mtrs, next) 556 if (mtr->mtr_id == mtr_id) 557 break; 558 559 return mtr; 560 } 561 562 struct nfp_mtr * 563 nfp_mtr_find_by_profile_id(struct nfp_mtr_priv *priv, uint32_t profile_id) 564 { 565 struct nfp_mtr *mtr; 566 567 LIST_FOREACH(mtr, &priv->mtrs, next) 568 if (mtr->mtr_profile->profile_id == profile_id) 569 break; 570 571 return mtr; 572 } 573 574 static int 575 nfp_mtr_stats_mask_validate(uint64_t stats_mask, struct rte_mtr_error *error) 576 { 577 if ((stats_mask & RTE_MTR_STATS_N_PKTS_YELLOW) != 0) { 578 return -rte_mtr_error_set(error, EINVAL, 579 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 580 NULL, "RTE_MTR_STATS_N_PKTS_YELLOW not support."); 581 } 582 583 if ((stats_mask & RTE_MTR_STATS_N_PKTS_RED) != 0) { 584 return -rte_mtr_error_set(error, EINVAL, 585 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 586 NULL, "RTE_MTR_STATS_N_PKTS_RED not support."); 587 } 588 589 if ((stats_mask & RTE_MTR_STATS_N_BYTES_YELLOW) != 0) { 590 return -rte_mtr_error_set(error, EINVAL, 591 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 592 NULL, "RTE_MTR_STATS_N_BYTES_YELLOW not support."); 593 } 594 595 if ((stats_mask & RTE_MTR_STATS_N_BYTES_RED) != 0) { 596 return -rte_mtr_error_set(error, EINVAL, 597 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 598 NULL, "RTE_MTR_STATS_N_BYTES_RED not support."); 599 } 600 601 return 0; 602 } 603 604 static int 605 nfp_mtr_validate(uint32_t meter_id, 606 struct rte_mtr_params *params, 607 struct rte_mtr_error *error) 608 { 609 /* Params must not be NULL */ 610 if (params == NULL) { 611 return -rte_mtr_error_set(error, EINVAL, 612 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 613 NULL, "Meter params is null."); 614 } 615 616 /* Meter policy ID must be valid. */ 617 if (meter_id >= NFP_MAX_MTR_CNT) { 618 return -rte_mtr_error_set(error, EINVAL, 619 RTE_MTR_ERROR_TYPE_MTR_ID, 620 NULL, "Meter id not valid."); 621 } 622 623 if (params->use_prev_mtr_color != 0) { 624 return -rte_mtr_error_set(error, EINVAL, 625 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 626 NULL, "Feature use_prev_mtr_color not support."); 627 } 628 629 return nfp_mtr_stats_mask_validate(params->stats_mask, error); 630 } 631 632 static void 633 nfp_mtr_config(uint32_t mtr_id, 634 int shared, 635 struct rte_mtr_params *params, 636 struct nfp_mtr_profile *mtr_profile, 637 struct nfp_mtr_policy *mtr_policy, 638 struct nfp_mtr *mtr) 639 { 640 mtr->mtr_id = mtr_id; 641 642 if (shared != 0) 643 mtr->shared = true; 644 645 if (params->meter_enable != 0) 646 mtr->enable = true; 647 648 mtr->mtr_profile = mtr_profile; 649 mtr->mtr_policy = mtr_policy; 650 mtr->stats_mask = params->stats_mask; 651 } 652 653 /** 654 * Create meter rules. 655 * 656 * @param[in] dev 657 * Pointer to Ethernet device. 658 * @param[in] mtr_id 659 * Meter id. 660 * @param[in] params 661 * Pointer to rte meter parameters. 662 * @param[in] shared 663 * Meter shared with other flow or not. 664 * @param[out] error 665 * Pointer to rte meter error structure. 666 * 667 * @return 668 * 0 on success, a negative value otherwise and rte_errno is set. 669 */ 670 static int 671 nfp_mtr_create(struct rte_eth_dev *dev, 672 uint32_t mtr_id, 673 struct rte_mtr_params *params, 674 int shared, 675 struct rte_mtr_error *error) 676 { 677 int ret; 678 struct nfp_mtr *mtr; 679 struct nfp_mtr_priv *priv; 680 struct nfp_mtr_policy *mtr_policy; 681 struct nfp_mtr_profile *mtr_profile; 682 struct nfp_flower_representor *representor; 683 684 representor = dev->data->dev_private; 685 priv = representor->app_fw_flower->mtr_priv; 686 687 /* Check if meter id exist */ 688 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 689 if (mtr != NULL) { 690 return -rte_mtr_error_set(error, EEXIST, 691 RTE_MTR_ERROR_TYPE_MTR_ID, 692 NULL, "Meter already exist."); 693 } 694 695 /* Check input meter params */ 696 ret = nfp_mtr_validate(mtr_id, params, error); 697 if (ret != 0) 698 return ret; 699 700 mtr_profile = nfp_mtr_profile_search(priv, params->meter_profile_id); 701 if (mtr_profile == NULL) { 702 return -rte_mtr_error_set(error, EINVAL, 703 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 704 NULL, "Request meter profile not exist."); 705 } 706 707 if (mtr_profile->in_use) { 708 return -rte_mtr_error_set(error, EINVAL, 709 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 710 NULL, "Request meter profile is been used."); 711 } 712 713 mtr_policy = nfp_mtr_policy_search(priv, params->meter_policy_id); 714 if (mtr_policy == NULL) { 715 return -rte_mtr_error_set(error, EINVAL, 716 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 717 NULL, "Request meter policy not exist."); 718 } 719 720 /* Meter param memory alloc */ 721 mtr = rte_zmalloc(NULL, sizeof(struct nfp_mtr), 0); 722 if (mtr == NULL) { 723 return -rte_mtr_error_set(error, ENOMEM, 724 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 725 NULL, "Meter param alloc failed."); 726 } 727 728 nfp_mtr_config(mtr_id, shared, params, mtr_profile, mtr_policy, mtr); 729 730 /* Update profile/policy status */ 731 mtr->mtr_policy->ref_cnt++; 732 mtr->mtr_profile->in_use = true; 733 734 /* Insert mtr into mtr list */ 735 LIST_INSERT_HEAD(&priv->mtrs, mtr, next); 736 737 return 0; 738 } 739 740 /** 741 * Destroy meter rules. 742 * 743 * @param[in] dev 744 * Pointer to Ethernet device. 745 * @param[in] mtr_id 746 * Meter id. 747 * @param[out] error 748 * Pointer to rte meter error structure. 749 * 750 * @return 751 * 0 on success, a negative value otherwise and rte_errno is set. 752 */ 753 static int 754 nfp_mtr_destroy(struct rte_eth_dev *dev, 755 uint32_t mtr_id, 756 struct rte_mtr_error *error) 757 { 758 struct nfp_mtr *mtr; 759 struct nfp_mtr_priv *priv; 760 struct nfp_flower_representor *representor; 761 762 representor = dev->data->dev_private; 763 priv = representor->app_fw_flower->mtr_priv; 764 765 /* Check if meter id exist */ 766 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 767 if (mtr == NULL) { 768 return -rte_mtr_error_set(error, EINVAL, 769 RTE_MTR_ERROR_TYPE_MTR_ID, 770 NULL, "Request meter not exist."); 771 } 772 773 if (mtr->ref_cnt > 0) { 774 return -rte_mtr_error_set(error, EINVAL, 775 RTE_MTR_ERROR_TYPE_MTR_ID, 776 NULL, "Meter object is being used."); 777 } 778 779 /* Update profile/policy status */ 780 mtr->mtr_policy->ref_cnt--; 781 mtr->mtr_profile->in_use = false; 782 783 /* Remove mtr from mtr list */ 784 LIST_REMOVE(mtr, next); 785 rte_free(mtr); 786 787 return 0; 788 } 789 790 /** 791 * Enable meter object. 792 * 793 * @param[in] dev 794 * Pointer to the device. 795 * @param[in] mtr_id 796 * Id of the meter. 797 * @param[out] error 798 * Pointer to the error. 799 * 800 * @returns 801 * 0 in success, negative value otherwise and rte_errno is set.. 802 */ 803 static int 804 nfp_mtr_enable(struct rte_eth_dev *dev, 805 uint32_t mtr_id, 806 struct rte_mtr_error *error) 807 { 808 struct nfp_mtr *mtr; 809 struct nfp_mtr_priv *priv; 810 struct nfp_flower_representor *representor; 811 812 representor = dev->data->dev_private; 813 priv = representor->app_fw_flower->mtr_priv; 814 815 /* Check if meter id exist */ 816 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 817 if (mtr == NULL) { 818 return -rte_mtr_error_set(error, EINVAL, 819 RTE_MTR_ERROR_TYPE_MTR_ID, 820 NULL, "Request meter not exist."); 821 } 822 823 mtr->enable = true; 824 825 return 0; 826 } 827 828 /** 829 * Disable meter object. 830 * 831 * @param[in] dev 832 * Pointer to the device. 833 * @param[in] mtr_id 834 * Id of the meter. 835 * @param[out] error 836 * Pointer to the error. 837 * 838 * @returns 839 * 0 on success, negative value otherwise and rte_errno is set.. 840 */ 841 static int 842 nfp_mtr_disable(struct rte_eth_dev *dev, 843 uint32_t mtr_id, 844 struct rte_mtr_error *error) 845 { 846 struct nfp_mtr *mtr; 847 struct nfp_mtr_priv *priv; 848 struct nfp_flower_representor *representor; 849 850 representor = dev->data->dev_private; 851 priv = representor->app_fw_flower->mtr_priv; 852 853 /* Check if meter id exist */ 854 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 855 if (mtr == NULL) { 856 return -rte_mtr_error_set(error, EINVAL, 857 RTE_MTR_ERROR_TYPE_MTR_ID, 858 NULL, "Request meter not exist."); 859 } 860 861 if (mtr->ref_cnt > 0) { 862 return -rte_mtr_error_set(error, EINVAL, 863 RTE_MTR_ERROR_TYPE_MTR_ID, 864 NULL, "Can not disable a used meter."); 865 } 866 867 mtr->enable = false; 868 869 return 0; 870 } 871 872 /** 873 * Callback to update meter profile. 874 * 875 * @param[in] dev 876 * Pointer to Ethernet device. 877 * @param[in] mtr_id 878 * Meter id. 879 * @param[in] mtr_profile_id 880 * To be updated meter profile id. 881 * @param[out] error 882 * Pointer to rte meter error structure. 883 * 884 * @return 885 * 0 on success, a negative value otherwise and rte_errno is set. 886 */ 887 static int 888 nfp_mtr_profile_update(struct rte_eth_dev *dev, 889 uint32_t mtr_id, 890 uint32_t mtr_profile_id, 891 struct rte_mtr_error *error) 892 { 893 struct nfp_mtr *mtr; 894 struct nfp_mtr_priv *priv; 895 struct nfp_mtr_profile *mtr_profile; 896 struct nfp_flower_representor *representor; 897 898 representor = dev->data->dev_private; 899 priv = representor->app_fw_flower->mtr_priv; 900 901 /* Check if meter id exist */ 902 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 903 if (mtr == NULL) { 904 return -rte_mtr_error_set(error, EINVAL, 905 RTE_MTR_ERROR_TYPE_MTR_ID, 906 NULL, "Request meter not exist."); 907 } 908 909 if (mtr->ref_cnt > 0) { 910 return -rte_mtr_error_set(error, EINVAL, 911 RTE_MTR_ERROR_TYPE_MTR_ID, 912 NULL, "Request meter is been used."); 913 } 914 915 if (mtr->mtr_profile->profile_id == mtr_profile_id) 916 return 0; 917 918 mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id); 919 if (mtr_profile == NULL) { 920 return -rte_mtr_error_set(error, EINVAL, 921 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 922 NULL, "Request meter profile not exist."); 923 } 924 925 if (mtr_profile->in_use) { 926 return -rte_mtr_error_set(error, EINVAL, 927 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 928 NULL, "Request meter profile is been used."); 929 } 930 931 mtr_profile->in_use = true; 932 mtr->mtr_profile->in_use = false; 933 mtr->mtr_profile = mtr_profile; 934 935 return 0; 936 } 937 938 /** 939 * Callback to update meter stats mask. 940 * 941 * @param[in] dev 942 * Pointer to Ethernet device. 943 * @param[in] mtr_id 944 * Meter id. 945 * @param[in] stats_mask 946 * To be updated stats_mask. 947 * @param[out] error 948 * Pointer to rte meter error structure. 949 * 950 * @return 951 * 0 on success, a negative value otherwise and rte_errno is set. 952 */ 953 static int 954 nfp_mtr_stats_update(struct rte_eth_dev *dev, 955 uint32_t mtr_id, 956 uint64_t stats_mask, 957 struct rte_mtr_error *error) 958 { 959 int ret; 960 struct nfp_mtr *mtr; 961 struct nfp_mtr_priv *priv; 962 struct nfp_flower_representor *representor; 963 964 representor = dev->data->dev_private; 965 priv = representor->app_fw_flower->mtr_priv; 966 967 /* Check if meter id exist */ 968 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 969 if (mtr == NULL) { 970 return -rte_mtr_error_set(error, EEXIST, 971 RTE_MTR_ERROR_TYPE_MTR_ID, 972 NULL, "Request meter id not exist."); 973 } 974 975 ret = nfp_mtr_stats_mask_validate(stats_mask, error); 976 if (ret != 0) 977 return ret; 978 979 mtr->stats_mask = stats_mask; 980 981 return 0; 982 } 983 984 /** 985 * Callback to read meter statistics. 986 * 987 * @param[in] dev 988 * Pointer to Ethernet device. 989 * @param[in] mtr_id 990 * Meter id. 991 * @param[out] stats 992 * Pointer to store the statistics. 993 * @param[out] stats_mask 994 * Pointer to store the stats_mask. 995 * @param[in] clear 996 * Statistic to be cleared after read or not. 997 * @param[out] error 998 * Pointer to rte meter error structure. 999 * 1000 * @return 1001 * 0 on success, a negative value otherwise and rte_errno is set. 1002 */ 1003 static int 1004 nfp_mtr_stats_read(struct rte_eth_dev *dev, 1005 uint32_t mtr_id, 1006 struct rte_mtr_stats *stats, 1007 uint64_t *stats_mask, 1008 int clear, 1009 struct rte_mtr_error *error) 1010 { 1011 struct nfp_mtr *mtr; 1012 struct nfp_mtr_priv *priv; 1013 struct nfp_mtr_stats curr; 1014 struct nfp_mtr_stats *prev; 1015 struct nfp_flower_representor *representor; 1016 1017 representor = dev->data->dev_private; 1018 priv = representor->app_fw_flower->mtr_priv; 1019 1020 /* Check if meter id exist */ 1021 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 1022 if (mtr == NULL) { 1023 return -rte_mtr_error_set(error, EINVAL, 1024 RTE_MTR_ERROR_TYPE_MTR_ID, 1025 NULL, "Request meter not exist."); 1026 } 1027 1028 *stats_mask = mtr->stats_mask; 1029 1030 rte_spinlock_lock(&priv->mtr_stats_lock); 1031 rte_memcpy(&curr, &mtr->mtr_stats.curr, sizeof(curr)); 1032 rte_spinlock_unlock(&priv->mtr_stats_lock); 1033 1034 prev = &mtr->mtr_stats.prev; 1035 1036 stats->n_pkts[RTE_COLOR_GREEN] = curr.pass_pkts - prev->pass_pkts; 1037 stats->n_bytes[RTE_COLOR_GREEN] = curr.pass_bytes - prev->pass_bytes; 1038 stats->n_pkts_dropped = curr.drop_pkts - prev->drop_pkts; 1039 stats->n_bytes_dropped = curr.drop_bytes - prev->drop_bytes; 1040 1041 if (clear != 0) { 1042 prev->pass_pkts = curr.pass_pkts; 1043 prev->pass_bytes = curr.pass_bytes; 1044 prev->drop_pkts = curr.drop_pkts; 1045 prev->drop_bytes = curr.drop_bytes; 1046 } 1047 1048 return 0; 1049 } 1050 1051 static const struct rte_mtr_ops nfp_mtr_ops = { 1052 .capabilities_get = nfp_mtr_cap_get, 1053 .meter_profile_add = nfp_mtr_profile_add, 1054 .meter_profile_delete = nfp_mtr_profile_delete, 1055 .meter_policy_add = nfp_mtr_policy_add, 1056 .meter_policy_delete = nfp_mtr_policy_delete, 1057 .create = nfp_mtr_create, 1058 .destroy = nfp_mtr_destroy, 1059 .meter_enable = nfp_mtr_enable, 1060 .meter_disable = nfp_mtr_disable, 1061 .meter_profile_update = nfp_mtr_profile_update, 1062 .stats_update = nfp_mtr_stats_update, 1063 .stats_read = nfp_mtr_stats_read, 1064 }; 1065 1066 int 1067 nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg) 1068 { 1069 if (!rte_eth_dev_is_repr(dev)) { 1070 PMD_DRV_LOG(ERR, "Port is not a representor."); 1071 return -EINVAL; 1072 } 1073 1074 *(const struct rte_mtr_ops **)arg = &nfp_mtr_ops; 1075 1076 return 0; 1077 } 1078 1079 static void 1080 nfp_mtr_stats_request(void *arg) 1081 { 1082 struct nfp_mtr *mtr; 1083 struct nfp_app_fw_flower *app_fw_flower = arg; 1084 1085 LIST_FOREACH(mtr, &app_fw_flower->mtr_priv->mtrs, next) 1086 nfp_flower_cmsg_qos_stats(app_fw_flower, &mtr->mtr_profile->conf.head); 1087 1088 rte_eal_alarm_set(NFP_METER_STATS_INTERVAL, nfp_mtr_stats_request, arg); 1089 } 1090 1091 int 1092 nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev) 1093 { 1094 int ret; 1095 struct nfp_mtr_priv *priv; 1096 struct nfp_app_fw_flower *app_fw_flower; 1097 1098 priv = rte_zmalloc("nfp_app_mtr_priv", sizeof(struct nfp_mtr_priv), 0); 1099 if (priv == NULL) { 1100 PMD_INIT_LOG(ERR, "NFP app mtr priv creation failed."); 1101 return -ENOMEM; 1102 } 1103 1104 app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv); 1105 app_fw_flower->mtr_priv = priv; 1106 1107 ret = rte_eal_alarm_set(NFP_METER_STATS_INTERVAL, nfp_mtr_stats_request, 1108 (void *)app_fw_flower); 1109 if (ret < 0) { 1110 PMD_INIT_LOG(ERR, "NFP mtr timer init failed."); 1111 rte_free(priv); 1112 return ret; 1113 } 1114 1115 LIST_INIT(&priv->mtrs); 1116 LIST_INIT(&priv->profiles); 1117 LIST_INIT(&priv->policies); 1118 1119 rte_spinlock_init(&priv->mtr_stats_lock); 1120 1121 return 0; 1122 } 1123 1124 void 1125 nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev) 1126 { 1127 struct nfp_mtr *mtr; 1128 struct nfp_mtr_priv *priv; 1129 struct nfp_mtr_policy *mtr_policy; 1130 struct nfp_mtr_profile *mtr_profile; 1131 struct nfp_app_fw_flower *app_fw_flower; 1132 1133 app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv); 1134 priv = app_fw_flower->mtr_priv; 1135 1136 rte_eal_alarm_cancel(nfp_mtr_stats_request, (void *)app_fw_flower); 1137 1138 LIST_FOREACH(mtr, &priv->mtrs, next) { 1139 LIST_REMOVE(mtr, next); 1140 rte_free(mtr); 1141 } 1142 1143 LIST_FOREACH(mtr_profile, &priv->profiles, next) { 1144 LIST_REMOVE(mtr_profile, next); 1145 rte_free(mtr_profile); 1146 } 1147 1148 LIST_FOREACH(mtr_policy, &priv->policies, next) { 1149 LIST_REMOVE(mtr_policy, next); 1150 rte_free(mtr_policy); 1151 } 1152 1153 rte_free(priv); 1154 } 1155 1156 int 1157 nfp_mtr_update_ref_cnt(struct nfp_mtr_priv *priv, 1158 uint32_t mtr_id, 1159 bool add) 1160 { 1161 struct nfp_mtr *mtr; 1162 1163 mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id); 1164 if (mtr == NULL) 1165 return -EINVAL; 1166 1167 mtr->ref_cnt += add ? 1 : -1; 1168 1169 return 0; 1170 } 1171