1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2021 Broadcom 3 * All rights reserved. 4 */ 5 6 #include "bnxt.h" 7 #include "bnxt_tf_common.h" 8 #include "ulp_rte_parser.h" 9 #include "ulp_matcher.h" 10 #include "ulp_flow_db.h" 11 #include "ulp_mapper.h" 12 #include "ulp_fc_mgr.h" 13 #include "ulp_port_db.h" 14 #include "ulp_ha_mgr.h" 15 #include <rte_malloc.h> 16 17 static int32_t 18 bnxt_ulp_flow_validate_args(const struct rte_flow_attr *attr, 19 const struct rte_flow_item pattern[], 20 const struct rte_flow_action actions[], 21 struct rte_flow_error *error) 22 { 23 /* Perform the validation of the arguments for null */ 24 if (!error) 25 return BNXT_TF_RC_ERROR; 26 27 if (!pattern) { 28 rte_flow_error_set(error, 29 EINVAL, 30 RTE_FLOW_ERROR_TYPE_ITEM_NUM, 31 NULL, 32 "NULL pattern."); 33 return BNXT_TF_RC_ERROR; 34 } 35 36 if (!actions) { 37 rte_flow_error_set(error, 38 EINVAL, 39 RTE_FLOW_ERROR_TYPE_ACTION_NUM, 40 NULL, 41 "NULL action."); 42 return BNXT_TF_RC_ERROR; 43 } 44 45 if (!attr) { 46 rte_flow_error_set(error, 47 EINVAL, 48 RTE_FLOW_ERROR_TYPE_ATTR, 49 NULL, 50 "NULL attribute."); 51 return BNXT_TF_RC_ERROR; 52 } 53 54 if (attr->egress && attr->ingress) { 55 rte_flow_error_set(error, 56 EINVAL, 57 RTE_FLOW_ERROR_TYPE_ATTR, 58 attr, 59 "EGRESS AND INGRESS UNSUPPORTED"); 60 return BNXT_TF_RC_ERROR; 61 } 62 return BNXT_TF_RC_SUCCESS; 63 } 64 65 static inline void 66 bnxt_ulp_set_dir_attributes(struct ulp_rte_parser_params *params, 67 const struct rte_flow_attr *attr) 68 { 69 /* Set the flow attributes */ 70 if (attr->egress) 71 params->dir_attr |= BNXT_ULP_FLOW_ATTR_EGRESS; 72 if (attr->ingress) 73 params->dir_attr |= BNXT_ULP_FLOW_ATTR_INGRESS; 74 #if RTE_VERSION_NUM(17, 11, 10, 16) < RTE_VERSION 75 if (attr->transfer) 76 params->dir_attr |= BNXT_ULP_FLOW_ATTR_TRANSFER; 77 #endif 78 } 79 80 void 81 bnxt_ulp_init_mapper_params(struct bnxt_ulp_mapper_create_parms *mapper_cparms, 82 struct ulp_rte_parser_params *params, 83 enum bnxt_ulp_fdb_type flow_type) 84 { 85 uint32_t ulp_flags = 0; 86 87 memset(mapper_cparms, 0, sizeof(*mapper_cparms)); 88 mapper_cparms->flow_type = flow_type; 89 mapper_cparms->app_priority = params->priority; 90 mapper_cparms->dir_attr = params->dir_attr; 91 mapper_cparms->class_tid = params->class_id; 92 mapper_cparms->act_tid = params->act_tmpl; 93 mapper_cparms->func_id = params->func_id; 94 mapper_cparms->hdr_bitmap = ¶ms->hdr_bitmap; 95 mapper_cparms->hdr_field = params->hdr_field; 96 mapper_cparms->comp_fld = params->comp_fld; 97 mapper_cparms->act = ¶ms->act_bitmap; 98 mapper_cparms->act_prop = ¶ms->act_prop; 99 mapper_cparms->flow_id = params->fid; 100 mapper_cparms->parent_flow = params->parent_flow; 101 mapper_cparms->parent_fid = params->parent_fid; 102 mapper_cparms->fld_bitmap = ¶ms->fld_bitmap; 103 mapper_cparms->flow_pattern_id = params->flow_pattern_id; 104 mapper_cparms->act_pattern_id = params->act_pattern_id; 105 mapper_cparms->app_id = params->app_id; 106 mapper_cparms->port_id = params->port_id; 107 108 /* update the signature fields into the computed field list */ 109 ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_HDR_SIG_ID, 110 params->hdr_sig_id); 111 ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_FLOW_SIG_ID, 112 params->flow_sig_id); 113 114 /* update the WC Priority flag */ 115 if (!bnxt_ulp_cntxt_ptr2_ulp_flags_get(params->ulp_ctx, &ulp_flags) && 116 ULP_HIGH_AVAIL_IS_ENABLED(ulp_flags)) { 117 enum ulp_ha_mgr_region region = ULP_HA_REGION_LOW; 118 int32_t rc; 119 120 rc = ulp_ha_mgr_region_get(params->ulp_ctx, ®ion); 121 if (rc) 122 BNXT_TF_DBG(ERR, "Unable to get WC region\n"); 123 if (region == ULP_HA_REGION_HI) 124 ULP_COMP_FLD_IDX_WR(params, 125 BNXT_ULP_CF_IDX_WC_IS_HA_HIGH_REG, 126 1); 127 } 128 } 129 130 /* Function to create the rte flow. */ 131 static struct rte_flow * 132 bnxt_ulp_flow_create(struct rte_eth_dev *dev, 133 const struct rte_flow_attr *attr, 134 const struct rte_flow_item pattern[], 135 const struct rte_flow_action actions[], 136 struct rte_flow_error *error) 137 { 138 struct bnxt_ulp_mapper_create_parms mapper_cparms = { 0 }; 139 struct ulp_rte_parser_params params; 140 struct bnxt_ulp_context *ulp_ctx; 141 int rc, ret = BNXT_TF_RC_ERROR; 142 struct rte_flow *flow_id; 143 uint16_t func_id; 144 uint32_t fid; 145 146 if (bnxt_ulp_flow_validate_args(attr, 147 pattern, actions, 148 error) == BNXT_TF_RC_ERROR) { 149 BNXT_TF_DBG(ERR, "Invalid arguments being passed\n"); 150 goto flow_error; 151 } 152 153 ulp_ctx = bnxt_ulp_eth_dev_ptr2_cntxt_get(dev); 154 if (!ulp_ctx) { 155 BNXT_TF_DBG(ERR, "ULP context is not initialized\n"); 156 goto flow_error; 157 } 158 159 /* Initialize the parser params */ 160 memset(¶ms, 0, sizeof(struct ulp_rte_parser_params)); 161 params.ulp_ctx = ulp_ctx; 162 163 if (bnxt_ulp_cntxt_app_id_get(params.ulp_ctx, ¶ms.app_id)) { 164 BNXT_TF_DBG(ERR, "failed to get the app id\n"); 165 goto flow_error; 166 } 167 168 /* Set the flow attributes */ 169 bnxt_ulp_set_dir_attributes(¶ms, attr); 170 171 /* copy the device port id and direction for further processing */ 172 ULP_COMP_FLD_IDX_WR(¶ms, BNXT_ULP_CF_IDX_INCOMING_IF, 173 dev->data->port_id); 174 ULP_COMP_FLD_IDX_WR(¶ms, BNXT_ULP_CF_IDX_DEV_PORT_ID, 175 dev->data->port_id); 176 ULP_COMP_FLD_IDX_WR(¶ms, BNXT_ULP_CF_IDX_SVIF_FLAG, 177 BNXT_ULP_INVALID_SVIF_VAL); 178 179 /* Get the function id */ 180 if (ulp_port_db_port_func_id_get(ulp_ctx, 181 dev->data->port_id, 182 &func_id)) { 183 BNXT_TF_DBG(ERR, "conversion of port to func id failed\n"); 184 goto flow_error; 185 } 186 187 /* Protect flow creation */ 188 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 189 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 190 goto flow_error; 191 } 192 193 /* Allocate a Flow ID for attaching all resources for the flow to. 194 * Once allocated, all errors have to walk the list of resources and 195 * free each of them. 196 */ 197 rc = ulp_flow_db_fid_alloc(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, 198 func_id, &fid); 199 if (rc) { 200 BNXT_TF_DBG(ERR, "Unable to allocate flow table entry\n"); 201 goto release_lock; 202 } 203 204 /* Parse the rte flow pattern */ 205 ret = bnxt_ulp_rte_parser_hdr_parse(pattern, ¶ms); 206 if (ret != BNXT_TF_RC_SUCCESS) 207 goto free_fid; 208 209 /* Parse the rte flow action */ 210 ret = bnxt_ulp_rte_parser_act_parse(actions, ¶ms); 211 if (ret != BNXT_TF_RC_SUCCESS) 212 goto free_fid; 213 214 params.fid = fid; 215 params.func_id = func_id; 216 params.priority = attr->priority; 217 params.port_id = dev->data->port_id; 218 /* Perform the rte flow post process */ 219 ret = bnxt_ulp_rte_parser_post_process(¶ms); 220 if (ret == BNXT_TF_RC_ERROR) 221 goto free_fid; 222 else if (ret == BNXT_TF_RC_FID) 223 goto return_fid; 224 225 ret = ulp_matcher_pattern_match(¶ms, ¶ms.class_id); 226 if (ret != BNXT_TF_RC_SUCCESS) 227 goto free_fid; 228 229 ret = ulp_matcher_action_match(¶ms, ¶ms.act_tmpl); 230 if (ret != BNXT_TF_RC_SUCCESS) 231 goto free_fid; 232 233 bnxt_ulp_init_mapper_params(&mapper_cparms, ¶ms, 234 BNXT_ULP_FDB_TYPE_REGULAR); 235 /* Call the ulp mapper to create the flow in the hardware. */ 236 ret = ulp_mapper_flow_create(ulp_ctx, &mapper_cparms); 237 if (ret) 238 goto free_fid; 239 240 return_fid: 241 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 242 243 flow_id = (struct rte_flow *)((uintptr_t)fid); 244 return flow_id; 245 246 free_fid: 247 ulp_flow_db_fid_free(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, fid); 248 release_lock: 249 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 250 flow_error: 251 rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 252 "Failed to create flow."); 253 return NULL; 254 } 255 256 /* Function to validate the rte flow. */ 257 static int 258 bnxt_ulp_flow_validate(struct rte_eth_dev *dev, 259 const struct rte_flow_attr *attr, 260 const struct rte_flow_item pattern[], 261 const struct rte_flow_action actions[], 262 struct rte_flow_error *error) 263 { 264 struct ulp_rte_parser_params params; 265 struct bnxt_ulp_context *ulp_ctx; 266 uint32_t class_id, act_tmpl; 267 int ret = BNXT_TF_RC_ERROR; 268 269 if (bnxt_ulp_flow_validate_args(attr, 270 pattern, actions, 271 error) == BNXT_TF_RC_ERROR) { 272 BNXT_TF_DBG(ERR, "Invalid arguments being passed\n"); 273 goto parse_error; 274 } 275 276 ulp_ctx = bnxt_ulp_eth_dev_ptr2_cntxt_get(dev); 277 if (!ulp_ctx) { 278 BNXT_TF_DBG(ERR, "ULP context is not initialized\n"); 279 goto parse_error; 280 } 281 282 /* Initialize the parser params */ 283 memset(¶ms, 0, sizeof(struct ulp_rte_parser_params)); 284 params.ulp_ctx = ulp_ctx; 285 286 if (bnxt_ulp_cntxt_app_id_get(params.ulp_ctx, ¶ms.app_id)) { 287 BNXT_TF_DBG(ERR, "failed to get the app id\n"); 288 goto parse_error; 289 } 290 291 /* Set the flow attributes */ 292 bnxt_ulp_set_dir_attributes(¶ms, attr); 293 294 /* Parse the rte flow pattern */ 295 ret = bnxt_ulp_rte_parser_hdr_parse(pattern, ¶ms); 296 if (ret != BNXT_TF_RC_SUCCESS) 297 goto parse_error; 298 299 /* Parse the rte flow action */ 300 ret = bnxt_ulp_rte_parser_act_parse(actions, ¶ms); 301 if (ret != BNXT_TF_RC_SUCCESS) 302 goto parse_error; 303 304 /* Perform the rte flow post process */ 305 ret = bnxt_ulp_rte_parser_post_process(¶ms); 306 if (ret == BNXT_TF_RC_ERROR) 307 goto parse_error; 308 else if (ret == BNXT_TF_RC_FID) 309 return 0; 310 311 ret = ulp_matcher_pattern_match(¶ms, &class_id); 312 313 if (ret != BNXT_TF_RC_SUCCESS) 314 goto parse_error; 315 316 ret = ulp_matcher_action_match(¶ms, &act_tmpl); 317 if (ret != BNXT_TF_RC_SUCCESS) 318 goto parse_error; 319 320 /* all good return success */ 321 return ret; 322 323 parse_error: 324 rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 325 "Failed to validate flow."); 326 return -EINVAL; 327 } 328 329 /* Function to destroy the rte flow. */ 330 int 331 bnxt_ulp_flow_destroy(struct rte_eth_dev *dev, 332 struct rte_flow *flow, 333 struct rte_flow_error *error) 334 { 335 struct bnxt_ulp_context *ulp_ctx; 336 uint32_t flow_id; 337 uint16_t func_id; 338 int ret; 339 340 ulp_ctx = bnxt_ulp_eth_dev_ptr2_cntxt_get(dev); 341 if (!ulp_ctx) { 342 BNXT_TF_DBG(ERR, "ULP context is not initialized\n"); 343 if (error) 344 rte_flow_error_set(error, EINVAL, 345 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 346 "Failed to destroy flow."); 347 return -EINVAL; 348 } 349 350 flow_id = (uint32_t)(uintptr_t)flow; 351 352 if (ulp_port_db_port_func_id_get(ulp_ctx, 353 dev->data->port_id, 354 &func_id)) { 355 BNXT_TF_DBG(ERR, "conversion of port to func id failed\n"); 356 if (error) 357 rte_flow_error_set(error, EINVAL, 358 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 359 "Failed to destroy flow."); 360 return -EINVAL; 361 } 362 363 if (ulp_flow_db_validate_flow_func(ulp_ctx, flow_id, func_id) == 364 false) { 365 BNXT_TF_DBG(ERR, "Incorrect device params\n"); 366 if (error) 367 rte_flow_error_set(error, EINVAL, 368 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 369 "Failed to destroy flow."); 370 return -EINVAL; 371 } 372 373 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 374 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 375 return -EINVAL; 376 } 377 ret = ulp_mapper_flow_destroy(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, 378 flow_id); 379 if (ret) { 380 BNXT_TF_DBG(ERR, "Failed to destroy flow.\n"); 381 if (error) 382 rte_flow_error_set(error, -ret, 383 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 384 "Failed to destroy flow."); 385 } 386 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 387 388 return ret; 389 } 390 391 /* Function to destroy the rte flows. */ 392 static int32_t 393 bnxt_ulp_flow_flush(struct rte_eth_dev *eth_dev, 394 struct rte_flow_error *error) 395 { 396 struct bnxt_ulp_context *ulp_ctx; 397 int32_t ret = 0; 398 uint16_t func_id; 399 400 ulp_ctx = bnxt_ulp_eth_dev_ptr2_cntxt_get(eth_dev); 401 if (!ulp_ctx) { 402 return ret; 403 } 404 405 /* Free the resources for the last device */ 406 if (ulp_ctx_deinit_allowed(ulp_ctx)) { 407 ret = ulp_flow_db_session_flow_flush(ulp_ctx); 408 } else if (bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx)) { 409 ret = ulp_port_db_port_func_id_get(ulp_ctx, 410 eth_dev->data->port_id, 411 &func_id); 412 if (!ret) 413 ret = ulp_flow_db_function_flow_flush(ulp_ctx, func_id); 414 else 415 BNXT_TF_DBG(ERR, "convert port to func id failed\n"); 416 } 417 if (ret) 418 rte_flow_error_set(error, ret, 419 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 420 "Failed to flush flow."); 421 return ret; 422 } 423 424 /* Function to query the rte flows. */ 425 static int32_t 426 bnxt_ulp_flow_query(struct rte_eth_dev *eth_dev, 427 struct rte_flow *flow, 428 const struct rte_flow_action *action, 429 void *data, 430 struct rte_flow_error *error) 431 { 432 int rc = 0; 433 struct bnxt_ulp_context *ulp_ctx; 434 struct rte_flow_query_count *count; 435 uint32_t flow_id; 436 437 ulp_ctx = bnxt_ulp_eth_dev_ptr2_cntxt_get(eth_dev); 438 if (!ulp_ctx) { 439 BNXT_TF_DBG(ERR, "ULP context is not initialized\n"); 440 rte_flow_error_set(error, EINVAL, 441 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 442 "Failed to query flow."); 443 return -EINVAL; 444 } 445 446 flow_id = (uint32_t)(uintptr_t)flow; 447 448 switch (action->type) { 449 case RTE_FLOW_ACTION_TYPE_COUNT: 450 count = data; 451 rc = ulp_fc_mgr_query_count_get(ulp_ctx, flow_id, count); 452 if (rc) { 453 rte_flow_error_set(error, EINVAL, 454 RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 455 "Failed to query flow."); 456 } 457 break; 458 default: 459 rte_flow_error_set(error, -rc, RTE_FLOW_ERROR_TYPE_ACTION_NUM, 460 NULL, "Unsupported action item"); 461 } 462 463 return rc; 464 } 465 466 const struct rte_flow_ops bnxt_ulp_rte_flow_ops = { 467 .validate = bnxt_ulp_flow_validate, 468 .create = bnxt_ulp_flow_create, 469 .destroy = bnxt_ulp_flow_destroy, 470 .flush = bnxt_ulp_flow_flush, 471 .query = bnxt_ulp_flow_query, 472 .isolate = NULL 473 }; 474