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