1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 #define WIRE_PORT 0xFFFF 8 9 #define MLX5DR_ACTION_METER_INIT_COLOR_OFFSET 1 10 11 /* This is the maximum allowed action order for each table type: 12 * TX: POP_VLAN, CTR, ASO_METER, AS_CT, PUSH_VLAN, MODIFY, ENCAP, Term 13 * RX: TAG, DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY, 14 * ENCAP, Term 15 * FDB: DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY, 16 * ENCAP, Term 17 */ 18 static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_MAX] = { 19 [MLX5DR_TABLE_TYPE_NIC_RX] = { 20 BIT(MLX5DR_ACTION_TYP_TAG), 21 BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) | 22 BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2), 23 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 24 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 25 BIT(MLX5DR_ACTION_TYP_CTR), 26 BIT(MLX5DR_ACTION_TYP_ASO_METER), 27 BIT(MLX5DR_ACTION_TYP_ASO_CT), 28 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 29 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 30 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 31 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) | 32 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3), 33 BIT(MLX5DR_ACTION_TYP_FT) | 34 BIT(MLX5DR_ACTION_TYP_MISS) | 35 BIT(MLX5DR_ACTION_TYP_TIR) | 36 BIT(MLX5DR_ACTION_TYP_DROP), 37 BIT(MLX5DR_ACTION_TYP_LAST), 38 }, 39 [MLX5DR_TABLE_TYPE_NIC_TX] = { 40 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 41 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 42 BIT(MLX5DR_ACTION_TYP_CTR), 43 BIT(MLX5DR_ACTION_TYP_ASO_METER), 44 BIT(MLX5DR_ACTION_TYP_ASO_CT), 45 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 46 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 47 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 48 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) | 49 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3), 50 BIT(MLX5DR_ACTION_TYP_FT) | 51 BIT(MLX5DR_ACTION_TYP_MISS) | 52 BIT(MLX5DR_ACTION_TYP_DROP), 53 BIT(MLX5DR_ACTION_TYP_LAST), 54 }, 55 [MLX5DR_TABLE_TYPE_FDB] = { 56 BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) | 57 BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2), 58 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 59 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 60 BIT(MLX5DR_ACTION_TYP_CTR), 61 BIT(MLX5DR_ACTION_TYP_ASO_METER), 62 BIT(MLX5DR_ACTION_TYP_ASO_CT), 63 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 64 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 65 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 66 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) | 67 BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3), 68 BIT(MLX5DR_ACTION_TYP_FT) | 69 BIT(MLX5DR_ACTION_TYP_MISS) | 70 BIT(MLX5DR_ACTION_TYP_VPORT) | 71 BIT(MLX5DR_ACTION_TYP_DROP), 72 BIT(MLX5DR_ACTION_TYP_LAST), 73 }, 74 }; 75 76 static int mlx5dr_action_get_shared_stc_nic(struct mlx5dr_context *ctx, 77 enum mlx5dr_context_shared_stc_type stc_type, 78 uint8_t tbl_type) 79 { 80 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 81 struct mlx5dr_action_shared_stc *shared_stc; 82 int ret; 83 84 pthread_spin_lock(&ctx->ctrl_lock); 85 if (ctx->common_res[tbl_type].shared_stc[stc_type]) { 86 rte_atomic32_add(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount, 1); 87 pthread_spin_unlock(&ctx->ctrl_lock); 88 return 0; 89 } 90 91 shared_stc = simple_calloc(1, sizeof(*shared_stc)); 92 if (!shared_stc) { 93 DR_LOG(ERR, "Failed to allocate memory for shared STCs"); 94 rte_errno = ENOMEM; 95 goto unlock_and_out; 96 } 97 switch (stc_type) { 98 case MLX5DR_CONTEXT_SHARED_STC_DECAP: 99 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; 100 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 101 stc_attr.remove_header.decap = 0; 102 stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 103 stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4; 104 break; 105 case MLX5DR_CONTEXT_SHARED_STC_POP: 106 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; 107 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 108 stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; 109 stc_attr.remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN; 110 break; 111 default: 112 DR_LOG(ERR, "No such type : stc_type\n"); 113 assert(false); 114 rte_errno = EINVAL; 115 goto unlock_and_out; 116 } 117 118 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 119 &shared_stc->remove_header); 120 if (ret) { 121 DR_LOG(ERR, "Failed to allocate shared decap l2 STC"); 122 goto free_shared_stc; 123 } 124 125 ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc; 126 127 rte_atomic32_init(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount); 128 rte_atomic32_set(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount, 1); 129 130 pthread_spin_unlock(&ctx->ctrl_lock); 131 132 return 0; 133 134 free_shared_stc: 135 simple_free(shared_stc); 136 unlock_and_out: 137 pthread_spin_unlock(&ctx->ctrl_lock); 138 return rte_errno; 139 } 140 141 static void mlx5dr_action_put_shared_stc_nic(struct mlx5dr_context *ctx, 142 enum mlx5dr_context_shared_stc_type stc_type, 143 uint8_t tbl_type) 144 { 145 struct mlx5dr_action_shared_stc *shared_stc; 146 147 pthread_spin_lock(&ctx->ctrl_lock); 148 if (!rte_atomic32_dec_and_test(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount)) { 149 pthread_spin_unlock(&ctx->ctrl_lock); 150 return; 151 } 152 153 shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type]; 154 155 mlx5dr_action_free_single_stc(ctx, tbl_type, &shared_stc->remove_header); 156 simple_free(shared_stc); 157 ctx->common_res[tbl_type].shared_stc[stc_type] = NULL; 158 pthread_spin_unlock(&ctx->ctrl_lock); 159 } 160 161 static int mlx5dr_action_get_shared_stc(struct mlx5dr_action *action, 162 enum mlx5dr_context_shared_stc_type stc_type) 163 { 164 struct mlx5dr_context *ctx = action->ctx; 165 int ret; 166 167 if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) { 168 assert(false); 169 rte_errno = EINVAL; 170 return rte_errno; 171 } 172 173 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) { 174 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 175 if (ret) { 176 DR_LOG(ERR, "Failed to allocate memory for RX shared STCs (type: %d)", 177 stc_type); 178 return ret; 179 } 180 } 181 182 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) { 183 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 184 if (ret) { 185 DR_LOG(ERR, "Failed to allocate memory for TX shared STCs(type: %d)", 186 stc_type); 187 goto clean_nic_rx_stc; 188 } 189 } 190 191 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) { 192 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB); 193 if (ret) { 194 DR_LOG(ERR, "Failed to allocate memory for FDB shared STCs (type: %d)", 195 stc_type); 196 goto clean_nic_tx_stc; 197 } 198 } 199 200 return 0; 201 202 clean_nic_tx_stc: 203 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 204 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 205 clean_nic_rx_stc: 206 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 207 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 208 209 return ret; 210 } 211 212 static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action, 213 enum mlx5dr_context_shared_stc_type stc_type) 214 { 215 struct mlx5dr_context *ctx = action->ctx; 216 217 if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) { 218 assert(false); 219 return; 220 } 221 222 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 223 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 224 225 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 226 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 227 228 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) 229 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB); 230 } 231 232 static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions) 233 { 234 DR_LOG(ERR, "Invalid action_type sequence"); 235 while (*user_actions != MLX5DR_ACTION_TYP_LAST) { 236 DR_LOG(ERR, "%s", mlx5dr_debug_action_type_to_str(*user_actions)); 237 user_actions++; 238 } 239 } 240 241 bool mlx5dr_action_check_combo(enum mlx5dr_action_type *user_actions, 242 enum mlx5dr_table_type table_type) 243 { 244 const uint32_t *order_arr = action_order_arr[table_type]; 245 uint8_t order_idx = 0; 246 uint8_t user_idx = 0; 247 bool valid_combo; 248 249 while (order_arr[order_idx] != BIT(MLX5DR_ACTION_TYP_LAST)) { 250 /* User action order validated move to next user action */ 251 if (BIT(user_actions[user_idx]) & order_arr[order_idx]) 252 user_idx++; 253 254 /* Iterate to the next supported action in the order */ 255 order_idx++; 256 } 257 258 /* Combination is valid if all user action were processed */ 259 valid_combo = user_actions[user_idx] == MLX5DR_ACTION_TYP_LAST; 260 if (!valid_combo) 261 mlx5dr_action_print_combo(user_actions); 262 263 return valid_combo; 264 } 265 266 int mlx5dr_action_root_build_attr(struct mlx5dr_rule_action rule_actions[], 267 uint32_t num_actions, 268 struct mlx5dv_flow_action_attr *attr) 269 { 270 struct mlx5dr_action *action; 271 uint32_t i; 272 273 for (i = 0; i < num_actions; i++) { 274 action = rule_actions[i].action; 275 276 switch (action->type) { 277 case MLX5DR_ACTION_TYP_FT: 278 case MLX5DR_ACTION_TYP_TIR: 279 attr[i].type = MLX5DV_FLOW_ACTION_DEST_DEVX; 280 attr[i].obj = action->devx_obj; 281 break; 282 case MLX5DR_ACTION_TYP_TAG: 283 attr[i].type = MLX5DV_FLOW_ACTION_TAG; 284 attr[i].tag_value = rule_actions[i].tag.value; 285 break; 286 #ifdef HAVE_MLX5_DR_CREATE_ACTION_DEFAULT_MISS 287 case MLX5DR_ACTION_TYP_MISS: 288 attr[i].type = MLX5DV_FLOW_ACTION_DEFAULT_MISS; 289 break; 290 #endif 291 case MLX5DR_ACTION_TYP_DROP: 292 attr[i].type = MLX5DV_FLOW_ACTION_DROP; 293 break; 294 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 295 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 296 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 297 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 298 case MLX5DR_ACTION_TYP_MODIFY_HDR: 299 attr[i].type = MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION; 300 attr[i].action = action->flow_action; 301 break; 302 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 303 case MLX5DR_ACTION_TYP_CTR: 304 attr[i].type = MLX5DV_FLOW_ACTION_COUNTERS_DEVX; 305 attr[i].obj = action->devx_obj; 306 307 if (rule_actions[i].counter.offset) { 308 DR_LOG(ERR, "Counter offset not supported over root"); 309 rte_errno = ENOTSUP; 310 return rte_errno; 311 } 312 break; 313 #endif 314 default: 315 DR_LOG(ERR, "Found unsupported action type: %d", action->type); 316 rte_errno = ENOTSUP; 317 return rte_errno; 318 } 319 } 320 321 return 0; 322 } 323 324 static bool mlx5dr_action_fixup_stc_attr(struct mlx5dr_cmd_stc_modify_attr *stc_attr, 325 struct mlx5dr_cmd_stc_modify_attr *fixup_stc_attr, 326 enum mlx5dr_table_type table_type, 327 bool is_mirror) 328 { 329 struct mlx5dr_devx_obj *devx_obj; 330 bool use_fixup = false; 331 uint32_t fw_tbl_type; 332 333 fw_tbl_type = mlx5dr_table_get_res_fw_ft_type(table_type, is_mirror); 334 335 switch (stc_attr->action_type) { 336 case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: 337 if (!is_mirror) 338 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_attr->ste_table.ste_pool, 339 &stc_attr->ste_table.ste); 340 else 341 devx_obj = 342 mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_attr->ste_table.ste_pool, 343 &stc_attr->ste_table.ste); 344 345 *fixup_stc_attr = *stc_attr; 346 fixup_stc_attr->ste_table.ste_obj_id = devx_obj->id; 347 use_fixup = true; 348 break; 349 350 case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: 351 if (stc_attr->vport.vport_num != WIRE_PORT) 352 break; 353 354 if (fw_tbl_type == FS_FT_FDB_RX) { 355 /* The FW doesn't allow to go back to wire in RX, so change it to DROP */ 356 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 357 fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 358 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 359 } else if (fw_tbl_type == FS_FT_FDB_TX) { 360 /*The FW doesn't allow to go to wire in the TX by JUMP_TO_VPORT*/ 361 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK; 362 fixup_stc_attr->action_offset = stc_attr->action_offset; 363 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 364 fixup_stc_attr->vport.vport_num = 0; 365 fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id; 366 } 367 use_fixup = true; 368 break; 369 370 default: 371 break; 372 } 373 374 return use_fixup; 375 } 376 377 int mlx5dr_action_alloc_single_stc(struct mlx5dr_context *ctx, 378 struct mlx5dr_cmd_stc_modify_attr *stc_attr, 379 uint32_t table_type, 380 struct mlx5dr_pool_chunk *stc) 381 { 382 struct mlx5dr_cmd_stc_modify_attr cleanup_stc_attr = {0}; 383 struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type]; 384 struct mlx5dr_cmd_stc_modify_attr fixup_stc_attr = {0}; 385 struct mlx5dr_devx_obj *devx_obj_0; 386 bool use_fixup; 387 int ret; 388 389 ret = mlx5dr_pool_chunk_alloc(stc_pool, stc); 390 if (ret) { 391 DR_LOG(ERR, "Failed to allocate single action STC"); 392 return ret; 393 } 394 395 stc_attr->stc_offset = stc->offset; 396 devx_obj_0 = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc); 397 398 /* According to table/action limitation change the stc_attr */ 399 use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr, table_type, false); 400 ret = mlx5dr_cmd_stc_modify(devx_obj_0, use_fixup ? &fixup_stc_attr : stc_attr); 401 if (ret) { 402 DR_LOG(ERR, "Failed to modify STC action_type %d tbl_type %d", 403 stc_attr->action_type, table_type); 404 goto free_chunk; 405 } 406 407 /* Modify the FDB peer */ 408 if (table_type == MLX5DR_TABLE_TYPE_FDB) { 409 struct mlx5dr_devx_obj *devx_obj_1; 410 411 devx_obj_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc); 412 413 use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr, 414 table_type, true); 415 ret = mlx5dr_cmd_stc_modify(devx_obj_1, use_fixup ? &fixup_stc_attr : stc_attr); 416 if (ret) { 417 DR_LOG(ERR, "Failed to modify peer STC action_type %d tbl_type %d", 418 stc_attr->action_type, table_type); 419 goto clean_devx_obj_0; 420 } 421 } 422 423 return 0; 424 425 clean_devx_obj_0: 426 cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 427 cleanup_stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 428 cleanup_stc_attr.stc_offset = stc->offset; 429 mlx5dr_cmd_stc_modify(devx_obj_0, &cleanup_stc_attr); 430 free_chunk: 431 mlx5dr_pool_chunk_free(stc_pool, stc); 432 return rte_errno; 433 } 434 435 void mlx5dr_action_free_single_stc(struct mlx5dr_context *ctx, 436 uint32_t table_type, 437 struct mlx5dr_pool_chunk *stc) 438 { 439 struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type]; 440 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 441 struct mlx5dr_devx_obj *devx_obj; 442 443 /* Modify the STC not to point to an object */ 444 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 445 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 446 stc_attr.stc_offset = stc->offset; 447 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc); 448 mlx5dr_cmd_stc_modify(devx_obj, &stc_attr); 449 450 if (table_type == MLX5DR_TABLE_TYPE_FDB) { 451 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc); 452 mlx5dr_cmd_stc_modify(devx_obj, &stc_attr); 453 } 454 455 mlx5dr_pool_chunk_free(stc_pool, stc); 456 } 457 458 static uint32_t mlx5dr_action_get_mh_stc_type(__be64 pattern) 459 { 460 uint8_t action_type = MLX5_GET(set_action_in, &pattern, action_type); 461 462 switch (action_type) { 463 case MLX5_MODIFICATION_TYPE_SET: 464 return MLX5_IFC_STC_ACTION_TYPE_SET; 465 case MLX5_MODIFICATION_TYPE_ADD: 466 return MLX5_IFC_STC_ACTION_TYPE_ADD; 467 case MLX5_MODIFICATION_TYPE_COPY: 468 return MLX5_IFC_STC_ACTION_TYPE_COPY; 469 default: 470 assert(false); 471 DR_LOG(ERR, "Unsupported action type: 0x%x\n", action_type); 472 rte_errno = ENOTSUP; 473 return MLX5_IFC_STC_ACTION_TYPE_NOP; 474 } 475 } 476 477 static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action, 478 struct mlx5dr_devx_obj *obj, 479 struct mlx5dr_cmd_stc_modify_attr *attr) 480 { 481 switch (action->type) { 482 case MLX5DR_ACTION_TYP_TAG: 483 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG; 484 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 485 break; 486 case MLX5DR_ACTION_TYP_DROP: 487 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 488 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 489 break; 490 case MLX5DR_ACTION_TYP_MISS: 491 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; 492 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 493 /* TODO Need to support default miss for FDB */ 494 break; 495 case MLX5DR_ACTION_TYP_CTR: 496 attr->id = obj->id; 497 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER; 498 attr->action_offset = MLX5DR_ACTION_OFFSET_DW0; 499 break; 500 case MLX5DR_ACTION_TYP_TIR: 501 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR; 502 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 503 attr->dest_tir_num = obj->id; 504 break; 505 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 506 case MLX5DR_ACTION_TYP_MODIFY_HDR: 507 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 508 if (action->modify_header.num_of_actions == 1) { 509 attr->modify_action.data = action->modify_header.single_action; 510 attr->action_type = mlx5dr_action_get_mh_stc_type(attr->modify_action.data); 511 512 if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD || 513 attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET) 514 MLX5_SET(set_action_in, &attr->modify_action.data, data, 0); 515 } else { 516 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST; 517 attr->modify_header.arg_id = action->modify_header.arg_obj->id; 518 attr->modify_header.pattern_id = action->modify_header.pattern_obj->id; 519 } 520 break; 521 case MLX5DR_ACTION_TYP_FT: 522 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; 523 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 524 attr->dest_table_id = obj->id; 525 break; 526 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 527 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; 528 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 529 attr->remove_header.decap = 1; 530 attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 531 attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC; 532 break; 533 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 534 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; 535 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 536 attr->insert_header.encap = 1; 537 attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 538 attr->insert_header.arg_id = action->reformat.arg_obj->id; 539 attr->insert_header.header_size = action->reformat.header_size; 540 break; 541 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 542 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; 543 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 544 attr->insert_header.encap = 1; 545 attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 546 attr->insert_header.arg_id = action->reformat.arg_obj->id; 547 attr->insert_header.header_size = action->reformat.header_size; 548 break; 549 case MLX5DR_ACTION_TYP_ASO_METER: 550 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 551 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; 552 attr->aso.aso_type = ASO_OPC_MOD_POLICER; 553 attr->aso.devx_obj_id = obj->id; 554 attr->aso.return_reg_id = action->aso.return_reg_id; 555 break; 556 case MLX5DR_ACTION_TYP_ASO_CT: 557 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 558 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; 559 attr->aso.aso_type = ASO_OPC_MOD_CONNECTION_TRACKING; 560 attr->aso.devx_obj_id = obj->id; 561 attr->aso.return_reg_id = action->aso.return_reg_id; 562 break; 563 case MLX5DR_ACTION_TYP_VPORT: 564 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 565 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; 566 attr->vport.vport_num = action->vport.vport_num; 567 attr->vport.esw_owner_vhca_id = action->vport.esw_owner_vhca_id; 568 break; 569 case MLX5DR_ACTION_TYP_POP_VLAN: 570 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; 571 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 572 attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; 573 attr->remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN / 2; 574 break; 575 case MLX5DR_ACTION_TYP_PUSH_VLAN: 576 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; 577 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 578 attr->insert_header.encap = 0; 579 attr->insert_header.is_inline = 1; 580 attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 581 attr->insert_header.insert_offset = MLX5DR_ACTION_HDR_LEN_L2_MACS; 582 attr->insert_header.header_size = MLX5DR_ACTION_HDR_LEN_L2_VLAN; 583 break; 584 default: 585 DR_LOG(ERR, "Invalid action type %d", action->type); 586 assert(false); 587 } 588 } 589 590 static int 591 mlx5dr_action_create_stcs(struct mlx5dr_action *action, 592 struct mlx5dr_devx_obj *obj) 593 { 594 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 595 struct mlx5dr_context *ctx = action->ctx; 596 int ret; 597 598 mlx5dr_action_fill_stc_attr(action, obj, &stc_attr); 599 600 /* Block unsupported parallel devx obj modify over the same base */ 601 pthread_spin_lock(&ctx->ctrl_lock); 602 603 /* Allocate STC for RX */ 604 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) { 605 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 606 MLX5DR_TABLE_TYPE_NIC_RX, 607 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 608 if (ret) 609 goto out_err; 610 } 611 612 /* Allocate STC for TX */ 613 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) { 614 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 615 MLX5DR_TABLE_TYPE_NIC_TX, 616 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 617 if (ret) 618 goto free_nic_rx_stc; 619 } 620 621 /* Allocate STC for FDB */ 622 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) { 623 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 624 MLX5DR_TABLE_TYPE_FDB, 625 &action->stc[MLX5DR_TABLE_TYPE_FDB]); 626 if (ret) 627 goto free_nic_tx_stc; 628 } 629 630 pthread_spin_unlock(&ctx->ctrl_lock); 631 632 return 0; 633 634 free_nic_tx_stc: 635 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 636 mlx5dr_action_free_single_stc(ctx, 637 MLX5DR_TABLE_TYPE_NIC_TX, 638 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 639 free_nic_rx_stc: 640 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 641 mlx5dr_action_free_single_stc(ctx, 642 MLX5DR_TABLE_TYPE_NIC_RX, 643 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 644 out_err: 645 pthread_spin_unlock(&ctx->ctrl_lock); 646 return rte_errno; 647 } 648 649 static void 650 mlx5dr_action_destroy_stcs(struct mlx5dr_action *action) 651 { 652 struct mlx5dr_context *ctx = action->ctx; 653 654 /* Block unsupported parallel devx obj modify over the same base */ 655 pthread_spin_lock(&ctx->ctrl_lock); 656 657 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 658 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_RX, 659 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 660 661 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 662 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_TX, 663 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 664 665 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) 666 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_FDB, 667 &action->stc[MLX5DR_TABLE_TYPE_FDB]); 668 669 pthread_spin_unlock(&ctx->ctrl_lock); 670 } 671 672 static bool 673 mlx5dr_action_is_root_flags(uint32_t flags) 674 { 675 return flags & (MLX5DR_ACTION_FLAG_ROOT_RX | 676 MLX5DR_ACTION_FLAG_ROOT_TX | 677 MLX5DR_ACTION_FLAG_ROOT_FDB); 678 } 679 680 static bool 681 mlx5dr_action_is_hws_flags(uint32_t flags) 682 { 683 return flags & (MLX5DR_ACTION_FLAG_HWS_RX | 684 MLX5DR_ACTION_FLAG_HWS_TX | 685 MLX5DR_ACTION_FLAG_HWS_FDB); 686 } 687 688 static struct mlx5dr_action * 689 mlx5dr_action_create_generic(struct mlx5dr_context *ctx, 690 uint32_t flags, 691 enum mlx5dr_action_type action_type) 692 { 693 struct mlx5dr_action *action; 694 695 if (!mlx5dr_action_is_root_flags(flags) && 696 !mlx5dr_action_is_hws_flags(flags)) { 697 DR_LOG(ERR, "Action flags must specify root or non root (HWS)"); 698 rte_errno = ENOTSUP; 699 return NULL; 700 } 701 702 action = simple_calloc(1, sizeof(*action)); 703 if (!action) { 704 DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type); 705 rte_errno = ENOMEM; 706 return NULL; 707 } 708 709 action->ctx = ctx; 710 action->flags = flags; 711 action->type = action_type; 712 713 return action; 714 } 715 716 struct mlx5dr_action * 717 mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx, 718 struct mlx5dr_table *tbl, 719 uint32_t flags) 720 { 721 struct mlx5dr_action *action; 722 int ret; 723 724 if (mlx5dr_table_is_root(tbl)) { 725 DR_LOG(ERR, "Root table cannot be set as destination"); 726 rte_errno = ENOTSUP; 727 return NULL; 728 } 729 730 if (mlx5dr_action_is_hws_flags(flags) && 731 mlx5dr_action_is_root_flags(flags)) { 732 DR_LOG(ERR, "Same action cannot be used for root and non root"); 733 rte_errno = ENOTSUP; 734 return NULL; 735 } 736 737 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_FT); 738 if (!action) 739 return NULL; 740 741 if (mlx5dr_action_is_root_flags(flags)) { 742 action->devx_obj = tbl->ft->obj; 743 } else { 744 ret = mlx5dr_action_create_stcs(action, tbl->ft); 745 if (ret) 746 goto free_action; 747 } 748 749 return action; 750 751 free_action: 752 simple_free(action); 753 return NULL; 754 } 755 756 struct mlx5dr_action * 757 mlx5dr_action_create_dest_tir(struct mlx5dr_context *ctx, 758 struct mlx5dr_devx_obj *obj, 759 uint32_t flags) 760 { 761 struct mlx5dr_action *action; 762 int ret; 763 764 if (mlx5dr_action_is_hws_flags(flags) && 765 mlx5dr_action_is_root_flags(flags)) { 766 DR_LOG(ERR, "Same action cannot be used for root and non root"); 767 rte_errno = ENOTSUP; 768 return NULL; 769 } 770 771 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TIR); 772 if (!action) 773 return NULL; 774 775 if (mlx5dr_action_is_root_flags(flags)) { 776 action->devx_obj = obj->obj; 777 } else { 778 ret = mlx5dr_action_create_stcs(action, obj); 779 if (ret) 780 goto free_action; 781 } 782 783 return action; 784 785 free_action: 786 simple_free(action); 787 return NULL; 788 } 789 790 struct mlx5dr_action * 791 mlx5dr_action_create_dest_drop(struct mlx5dr_context *ctx, 792 uint32_t flags) 793 { 794 struct mlx5dr_action *action; 795 int ret; 796 797 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DROP); 798 if (!action) 799 return NULL; 800 801 if (mlx5dr_action_is_hws_flags(flags)) { 802 ret = mlx5dr_action_create_stcs(action, NULL); 803 if (ret) 804 goto free_action; 805 } 806 807 return action; 808 809 free_action: 810 simple_free(action); 811 return NULL; 812 } 813 814 struct mlx5dr_action * 815 mlx5dr_action_create_default_miss(struct mlx5dr_context *ctx, 816 uint32_t flags) 817 { 818 struct mlx5dr_action *action; 819 int ret; 820 821 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MISS); 822 if (!action) 823 return NULL; 824 825 if (mlx5dr_action_is_hws_flags(flags)) { 826 ret = mlx5dr_action_create_stcs(action, NULL); 827 if (ret) 828 goto free_action; 829 } 830 831 return action; 832 833 free_action: 834 simple_free(action); 835 return NULL; 836 } 837 838 struct mlx5dr_action * 839 mlx5dr_action_create_tag(struct mlx5dr_context *ctx, 840 uint32_t flags) 841 { 842 struct mlx5dr_action *action; 843 int ret; 844 845 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TAG); 846 if (!action) 847 return NULL; 848 849 if (mlx5dr_action_is_hws_flags(flags)) { 850 ret = mlx5dr_action_create_stcs(action, NULL); 851 if (ret) 852 goto free_action; 853 } 854 855 return action; 856 857 free_action: 858 simple_free(action); 859 return NULL; 860 } 861 862 static struct mlx5dr_action * 863 mlx5dr_action_create_aso(struct mlx5dr_context *ctx, 864 enum mlx5dr_action_type action_type, 865 struct mlx5dr_devx_obj *devx_obj, 866 uint8_t return_reg_id, 867 uint32_t flags) 868 { 869 struct mlx5dr_action *action; 870 int ret; 871 872 if (mlx5dr_action_is_root_flags(flags)) { 873 DR_LOG(ERR, "ASO action cannot be used over root table"); 874 rte_errno = ENOTSUP; 875 return NULL; 876 } 877 878 action = mlx5dr_action_create_generic(ctx, flags, action_type); 879 if (!action) 880 return NULL; 881 882 action->aso.devx_obj = devx_obj; 883 action->aso.return_reg_id = return_reg_id; 884 885 ret = mlx5dr_action_create_stcs(action, devx_obj); 886 if (ret) 887 goto free_action; 888 889 return action; 890 891 free_action: 892 simple_free(action); 893 return NULL; 894 } 895 896 struct mlx5dr_action * 897 mlx5dr_action_create_aso_meter(struct mlx5dr_context *ctx, 898 struct mlx5dr_devx_obj *devx_obj, 899 uint8_t return_reg_id, 900 uint32_t flags) 901 { 902 return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_METER, 903 devx_obj, return_reg_id, flags); 904 } 905 906 struct mlx5dr_action * 907 mlx5dr_action_create_aso_ct(struct mlx5dr_context *ctx, 908 struct mlx5dr_devx_obj *devx_obj, 909 uint8_t return_reg_id, 910 uint32_t flags) 911 { 912 return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_CT, 913 devx_obj, return_reg_id, flags); 914 } 915 916 struct mlx5dr_action * 917 mlx5dr_action_create_counter(struct mlx5dr_context *ctx, 918 struct mlx5dr_devx_obj *obj, 919 uint32_t flags) 920 { 921 struct mlx5dr_action *action; 922 int ret; 923 924 if (mlx5dr_action_is_hws_flags(flags) && 925 mlx5dr_action_is_root_flags(flags)) { 926 DR_LOG(ERR, "Same action cannot be used for root and non root"); 927 rte_errno = ENOTSUP; 928 return NULL; 929 } 930 931 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_CTR); 932 if (!action) 933 return NULL; 934 935 if (mlx5dr_action_is_root_flags(flags)) { 936 action->devx_obj = obj->obj; 937 } else { 938 ret = mlx5dr_action_create_stcs(action, obj); 939 if (ret) 940 goto free_action; 941 } 942 943 return action; 944 945 free_action: 946 simple_free(action); 947 return NULL; 948 } 949 950 static int mlx5dr_action_create_dest_vport_hws(struct mlx5dr_context *ctx, 951 struct mlx5dr_action *action, 952 uint32_t ib_port_num) 953 { 954 struct mlx5dr_cmd_query_vport_caps vport_caps = {0}; 955 int ret; 956 957 ret = mlx5dr_cmd_query_ib_port(ctx->ibv_ctx, &vport_caps, ib_port_num); 958 if (ret) { 959 DR_LOG(ERR, "Failed querying port %d\n", ib_port_num); 960 return ret; 961 } 962 action->vport.vport_num = vport_caps.vport_num; 963 action->vport.esw_owner_vhca_id = vport_caps.esw_owner_vhca_id; 964 965 ret = mlx5dr_action_create_stcs(action, NULL); 966 if (ret) { 967 DR_LOG(ERR, "Failed creating stc for port %d\n", ib_port_num); 968 return ret; 969 } 970 971 return 0; 972 } 973 974 struct mlx5dr_action * 975 mlx5dr_action_create_dest_vport(struct mlx5dr_context *ctx, 976 uint32_t ib_port_num, 977 uint32_t flags) 978 { 979 struct mlx5dr_action *action; 980 int ret; 981 982 if (!(flags & MLX5DR_ACTION_FLAG_HWS_FDB)) { 983 DR_LOG(ERR, "Vport action is supported for FDB only\n"); 984 rte_errno = EINVAL; 985 return NULL; 986 } 987 988 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_VPORT); 989 if (!action) 990 return NULL; 991 992 ret = mlx5dr_action_create_dest_vport_hws(ctx, action, ib_port_num); 993 if (ret) { 994 DR_LOG(ERR, "Failed to create vport action HWS\n"); 995 goto free_action; 996 } 997 998 return action; 999 1000 free_action: 1001 simple_free(action); 1002 return NULL; 1003 } 1004 1005 struct mlx5dr_action * 1006 mlx5dr_action_create_push_vlan(struct mlx5dr_context *ctx, uint32_t flags) 1007 { 1008 struct mlx5dr_action *action; 1009 int ret; 1010 1011 if (mlx5dr_action_is_root_flags(flags)) { 1012 DR_LOG(ERR, "Push vlan action not supported for root"); 1013 rte_errno = ENOTSUP; 1014 return NULL; 1015 } 1016 1017 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_PUSH_VLAN); 1018 if (!action) 1019 return NULL; 1020 1021 ret = mlx5dr_action_create_stcs(action, NULL); 1022 if (ret) { 1023 DR_LOG(ERR, "Failed creating stc for push vlan\n"); 1024 goto free_action; 1025 } 1026 1027 return action; 1028 1029 free_action: 1030 simple_free(action); 1031 return NULL; 1032 } 1033 1034 struct mlx5dr_action * 1035 mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags) 1036 { 1037 struct mlx5dr_action *action; 1038 int ret; 1039 1040 if (mlx5dr_action_is_root_flags(flags)) { 1041 DR_LOG(ERR, "Pop vlan action not supported for root"); 1042 rte_errno = ENOTSUP; 1043 return NULL; 1044 } 1045 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_POP_VLAN); 1046 if (!action) 1047 return NULL; 1048 1049 ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP); 1050 if (ret) { 1051 DR_LOG(ERR, "Failed to create remove stc for reformat"); 1052 goto free_action; 1053 } 1054 1055 ret = mlx5dr_action_create_stcs(action, NULL); 1056 if (ret) { 1057 DR_LOG(ERR, "Failed creating stc for pop vlan\n"); 1058 goto free_shared; 1059 } 1060 1061 return action; 1062 1063 free_shared: 1064 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP); 1065 free_action: 1066 simple_free(action); 1067 return NULL; 1068 } 1069 1070 static int 1071 mlx5dr_action_conv_reformat_type_to_action(uint32_t reformat_type, 1072 enum mlx5dr_action_type *action_type) 1073 { 1074 switch (reformat_type) { 1075 case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2: 1076 *action_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2; 1077 break; 1078 case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2: 1079 *action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L2; 1080 break; 1081 case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2: 1082 *action_type = MLX5DR_ACTION_TYP_TNL_L3_TO_L2; 1083 break; 1084 case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3: 1085 *action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L3; 1086 break; 1087 default: 1088 DR_LOG(ERR, "Invalid reformat type requested"); 1089 rte_errno = ENOTSUP; 1090 return rte_errno; 1091 } 1092 return 0; 1093 } 1094 1095 static void 1096 mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type, 1097 uint32_t *verb_reformat_type) 1098 { 1099 switch (action_type) { 1100 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 1101 *verb_reformat_type = 1102 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2; 1103 break; 1104 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 1105 *verb_reformat_type = 1106 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL; 1107 break; 1108 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 1109 *verb_reformat_type = 1110 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2; 1111 break; 1112 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 1113 *verb_reformat_type = 1114 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 1115 break; 1116 } 1117 } 1118 1119 static int 1120 mlx5dr_action_conv_flags_to_ft_type(uint32_t flags, enum mlx5dv_flow_table_type *ft_type) 1121 { 1122 if (flags & MLX5DR_ACTION_FLAG_ROOT_RX) { 1123 *ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 1124 } else if (flags & MLX5DR_ACTION_FLAG_ROOT_TX) { 1125 *ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 1126 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE 1127 } else if (flags & MLX5DR_ACTION_FLAG_ROOT_FDB) { 1128 *ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 1129 #endif 1130 } else { 1131 rte_errno = ENOTSUP; 1132 return 1; 1133 } 1134 1135 return 0; 1136 } 1137 1138 static int 1139 mlx5dr_action_create_reformat_root(struct mlx5dr_action *action, 1140 size_t data_sz, 1141 void *data) 1142 { 1143 enum mlx5dv_flow_table_type ft_type = 0; /*fix compilation warn*/ 1144 uint32_t verb_reformat_type = 0; 1145 int ret; 1146 1147 /* Convert action to FT type and verbs reformat type */ 1148 ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type); 1149 if (ret) 1150 return rte_errno; 1151 1152 mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type); 1153 1154 /* Create the reformat type for root table */ 1155 action->flow_action = 1156 mlx5_glue->dv_create_flow_action_packet_reformat_root(action->ctx->ibv_ctx, 1157 data_sz, 1158 data, 1159 verb_reformat_type, 1160 ft_type); 1161 if (!action->flow_action) { 1162 rte_errno = errno; 1163 return rte_errno; 1164 } 1165 1166 return 0; 1167 } 1168 1169 static int mlx5dr_action_handle_reformat_args(struct mlx5dr_context *ctx, 1170 size_t data_sz, 1171 void *data, 1172 uint32_t bulk_size, 1173 struct mlx5dr_action *action) 1174 { 1175 uint32_t args_log_size; 1176 int ret; 1177 1178 if (data_sz % 2 != 0) { 1179 DR_LOG(ERR, "Data size should be multiply of 2"); 1180 rte_errno = EINVAL; 1181 return rte_errno; 1182 } 1183 action->reformat.header_size = data_sz; 1184 1185 args_log_size = mlx5dr_arg_data_size_to_arg_log_size(data_sz); 1186 if (args_log_size >= MLX5DR_ARG_CHUNK_SIZE_MAX) { 1187 DR_LOG(ERR, "Data size is bigger than supported"); 1188 rte_errno = EINVAL; 1189 return rte_errno; 1190 } 1191 args_log_size += bulk_size; 1192 1193 if (!mlx5dr_arg_is_valid_arg_request_size(ctx, args_log_size)) { 1194 DR_LOG(ERR, "Arg size %d does not fit FW requests", 1195 args_log_size); 1196 rte_errno = EINVAL; 1197 return rte_errno; 1198 } 1199 1200 action->reformat.arg_obj = mlx5dr_cmd_arg_create(ctx->ibv_ctx, 1201 args_log_size, 1202 ctx->pd_num); 1203 if (!action->reformat.arg_obj) { 1204 DR_LOG(ERR, "Failed to create arg for reformat"); 1205 return rte_errno; 1206 } 1207 1208 /* When INLINE need to write the arg data */ 1209 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) { 1210 ret = mlx5dr_arg_write_inline_arg_data(ctx, 1211 action->reformat.arg_obj->id, 1212 data, 1213 data_sz); 1214 if (ret) { 1215 DR_LOG(ERR, "Failed to write inline arg for reformat"); 1216 goto free_arg; 1217 } 1218 } 1219 1220 return 0; 1221 1222 free_arg: 1223 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 1224 return ret; 1225 } 1226 1227 static int mlx5dr_action_handle_l2_to_tunnel_l2(struct mlx5dr_context *ctx, 1228 size_t data_sz, 1229 void *data, 1230 uint32_t bulk_size, 1231 struct mlx5dr_action *action) 1232 { 1233 int ret; 1234 1235 ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size, 1236 action); 1237 if (ret) { 1238 DR_LOG(ERR, "Failed to create args for reformat"); 1239 return ret; 1240 } 1241 1242 ret = mlx5dr_action_create_stcs(action, NULL); 1243 if (ret) { 1244 DR_LOG(ERR, "Failed to create stc for reformat"); 1245 goto free_arg; 1246 } 1247 1248 return 0; 1249 1250 free_arg: 1251 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 1252 return ret; 1253 } 1254 1255 static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res, 1256 enum mlx5dr_context_shared_stc_type stc_type) 1257 { 1258 return common_res->shared_stc[stc_type]->remove_header.offset; 1259 } 1260 1261 static int mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_context *ctx, 1262 size_t data_sz, 1263 void *data, 1264 uint32_t bulk_size, 1265 struct mlx5dr_action *action) 1266 { 1267 int ret; 1268 1269 ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size, 1270 action); 1271 if (ret) { 1272 DR_LOG(ERR, "Failed to create args for reformat"); 1273 return ret; 1274 } 1275 1276 /* The action is remove-l2-header + insert-l3-header */ 1277 ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP); 1278 if (ret) { 1279 DR_LOG(ERR, "Failed to create remove stc for reformat"); 1280 goto free_arg; 1281 } 1282 1283 ret = mlx5dr_action_create_stcs(action, NULL); 1284 if (ret) { 1285 DR_LOG(ERR, "Failed to create insert stc for reformat"); 1286 goto down_shared; 1287 } 1288 1289 return 0; 1290 1291 down_shared: 1292 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP); 1293 free_arg: 1294 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 1295 return ret; 1296 } 1297 1298 static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz, 1299 uint8_t *mh_data, 1300 int *num_of_actions) 1301 { 1302 int actions; 1303 uint32_t i; 1304 1305 /* Remove L2L3 outer headers */ 1306 MLX5_SET(stc_ste_param_remove, mh_data, action_type, 1307 MLX5_MODIFICATION_TYPE_REMOVE); 1308 MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1); 1309 MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor, 1310 MLX5_HEADER_ANCHOR_PACKET_START); 1311 MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor, 1312 MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4); 1313 mh_data += MLX5DR_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */ 1314 actions = 1; 1315 1316 /* Add the new header using inline action 4Byte at a time, the header 1317 * is added in reversed order to the beginning of the packet to avoid 1318 * incorrect parsing by the HW. Since header is 14B or 18B an extra 1319 * two bytes are padded and later removed. 1320 */ 1321 for (i = 0; i < data_sz / MLX5DR_ACTION_INLINE_DATA_SIZE + 1; i++) { 1322 MLX5_SET(stc_ste_param_insert, mh_data, action_type, 1323 MLX5_MODIFICATION_TYPE_INSERT); 1324 MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1); 1325 MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor, 1326 MLX5_HEADER_ANCHOR_PACKET_START); 1327 MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2); 1328 mh_data += MLX5DR_ACTION_DOUBLE_SIZE; 1329 actions++; 1330 } 1331 1332 /* Remove first 2 extra bytes */ 1333 MLX5_SET(stc_ste_param_remove_words, mh_data, action_type, 1334 MLX5_MODIFICATION_TYPE_REMOVE_WORDS); 1335 MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor, 1336 MLX5_HEADER_ANCHOR_PACKET_START); 1337 /* The hardware expects here size in words (2 bytes) */ 1338 MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1); 1339 actions++; 1340 1341 *num_of_actions = actions; 1342 } 1343 1344 static int 1345 mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_context *ctx, 1346 size_t data_sz, 1347 void *data, 1348 uint32_t bulk_size, 1349 struct mlx5dr_action *action) 1350 { 1351 uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0}; 1352 int num_of_actions; 1353 int mh_data_size; 1354 int ret; 1355 1356 if (data_sz != MLX5DR_ACTION_HDR_LEN_L2 && 1357 data_sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) { 1358 DR_LOG(ERR, "Data size is not supported for decap-l3\n"); 1359 rte_errno = EINVAL; 1360 return rte_errno; 1361 } 1362 1363 mlx5dr_action_prepare_decap_l3_actions(data_sz, mh_data, &num_of_actions); 1364 1365 mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE; 1366 1367 ret = mlx5dr_pat_arg_create_modify_header(ctx, action, mh_data_size, 1368 (__be64 *)mh_data, bulk_size); 1369 if (ret) { 1370 DR_LOG(ERR, "Failed allocating modify-header for decap-l3\n"); 1371 return ret; 1372 } 1373 1374 ret = mlx5dr_action_create_stcs(action, NULL); 1375 if (ret) 1376 goto free_mh_obj; 1377 1378 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) { 1379 mlx5dr_action_prepare_decap_l3_data(data, mh_data, num_of_actions); 1380 ret = mlx5dr_arg_write_inline_arg_data(ctx, 1381 action->modify_header.arg_obj->id, 1382 (uint8_t *)mh_data, 1383 num_of_actions * 1384 MLX5DR_MODIFY_ACTION_SIZE); 1385 if (ret) { 1386 DR_LOG(ERR, "Failed writing INLINE arg decap_l3"); 1387 goto clean_stc; 1388 } 1389 } 1390 1391 return 0; 1392 1393 clean_stc: 1394 mlx5dr_action_destroy_stcs(action); 1395 free_mh_obj: 1396 mlx5dr_pat_arg_destroy_modify_header(ctx, action); 1397 return ret; 1398 } 1399 1400 static int 1401 mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx, 1402 size_t data_sz, 1403 void *data, 1404 uint32_t bulk_size, 1405 struct mlx5dr_action *action) 1406 { 1407 int ret; 1408 1409 switch (action->type) { 1410 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 1411 ret = mlx5dr_action_create_stcs(action, NULL); 1412 break; 1413 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 1414 ret = mlx5dr_action_handle_l2_to_tunnel_l2(ctx, data_sz, data, bulk_size, action); 1415 break; 1416 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 1417 ret = mlx5dr_action_handle_l2_to_tunnel_l3(ctx, data_sz, data, bulk_size, action); 1418 break; 1419 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 1420 ret = mlx5dr_action_handle_tunnel_l3_to_l2(ctx, data_sz, data, bulk_size, action); 1421 break; 1422 1423 default: 1424 assert(false); 1425 rte_errno = ENOTSUP; 1426 return rte_errno; 1427 } 1428 1429 return ret; 1430 } 1431 1432 struct mlx5dr_action * 1433 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx, 1434 enum mlx5dr_action_reformat_type reformat_type, 1435 size_t data_sz, 1436 void *inline_data, 1437 uint32_t log_bulk_size, 1438 uint32_t flags) 1439 { 1440 enum mlx5dr_action_type action_type; 1441 struct mlx5dr_action *action; 1442 int ret; 1443 1444 ret = mlx5dr_action_conv_reformat_type_to_action(reformat_type, &action_type); 1445 if (ret) 1446 return NULL; 1447 1448 action = mlx5dr_action_create_generic(ctx, flags, action_type); 1449 if (!action) 1450 return NULL; 1451 1452 if (mlx5dr_action_is_root_flags(flags)) { 1453 if (log_bulk_size) { 1454 DR_LOG(ERR, "Bulk reformat not supported over root"); 1455 rte_errno = ENOTSUP; 1456 goto free_action; 1457 } 1458 1459 ret = mlx5dr_action_create_reformat_root(action, data_sz, inline_data); 1460 if (ret) 1461 goto free_action; 1462 1463 return action; 1464 } 1465 1466 if (!mlx5dr_action_is_hws_flags(flags) || 1467 ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) { 1468 DR_LOG(ERR, "Reformat flags don't fit HWS (flags: %x0x)\n", 1469 flags); 1470 rte_errno = EINVAL; 1471 goto free_action; 1472 } 1473 1474 ret = mlx5dr_action_create_reformat_hws(ctx, data_sz, inline_data, log_bulk_size, action); 1475 if (ret) { 1476 DR_LOG(ERR, "Failed to create reformat.\n"); 1477 rte_errno = EINVAL; 1478 goto free_action; 1479 } 1480 1481 return action; 1482 1483 free_action: 1484 simple_free(action); 1485 return NULL; 1486 } 1487 1488 static int 1489 mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action, 1490 size_t actions_sz, 1491 __be64 *actions) 1492 { 1493 enum mlx5dv_flow_table_type ft_type = 0; 1494 int ret; 1495 1496 ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type); 1497 if (ret) 1498 return rte_errno; 1499 1500 action->flow_action = 1501 mlx5_glue->dv_create_flow_action_modify_header_root(action->ctx->ibv_ctx, 1502 actions_sz, 1503 (uint64_t *)actions, 1504 ft_type); 1505 if (!action->flow_action) { 1506 rte_errno = errno; 1507 return rte_errno; 1508 } 1509 1510 return 0; 1511 } 1512 1513 struct mlx5dr_action * 1514 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx, 1515 size_t pattern_sz, 1516 __be64 pattern[], 1517 uint32_t log_bulk_size, 1518 uint32_t flags) 1519 { 1520 struct mlx5dr_action *action; 1521 int ret; 1522 1523 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MODIFY_HDR); 1524 if (!action) 1525 return NULL; 1526 1527 if (mlx5dr_action_is_root_flags(flags)) { 1528 if (log_bulk_size) { 1529 DR_LOG(ERR, "Bulk modify-header not supported over root"); 1530 rte_errno = ENOTSUP; 1531 goto free_action; 1532 } 1533 ret = mlx5dr_action_create_modify_header_root(action, pattern_sz, pattern); 1534 if (ret) 1535 goto free_action; 1536 1537 return action; 1538 } 1539 1540 if (!mlx5dr_action_is_hws_flags(flags) || 1541 ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) { 1542 DR_LOG(ERR, "Flags don't fit hws (flags: %x0x, log_bulk_size: %d)\n", 1543 flags, log_bulk_size); 1544 rte_errno = EINVAL; 1545 goto free_action; 1546 } 1547 1548 if (pattern_sz / MLX5DR_MODIFY_ACTION_SIZE == 1) { 1549 /* Optimize single modiy action to be used inline */ 1550 action->modify_header.single_action = pattern[0]; 1551 action->modify_header.num_of_actions = 1; 1552 action->modify_header.single_action_type = 1553 MLX5_GET(set_action_in, pattern, action_type); 1554 } else { 1555 /* Use multi action pattern and argument */ 1556 ret = mlx5dr_pat_arg_create_modify_header(ctx, action, pattern_sz, 1557 pattern, log_bulk_size); 1558 if (ret) { 1559 DR_LOG(ERR, "Failed allocating modify-header\n"); 1560 goto free_action; 1561 } 1562 } 1563 1564 ret = mlx5dr_action_create_stcs(action, NULL); 1565 if (ret) 1566 goto free_mh_obj; 1567 1568 return action; 1569 1570 free_mh_obj: 1571 if (action->modify_header.num_of_actions > 1) 1572 mlx5dr_pat_arg_destroy_modify_header(ctx, action); 1573 free_action: 1574 simple_free(action); 1575 return NULL; 1576 } 1577 1578 static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action) 1579 { 1580 switch (action->type) { 1581 case MLX5DR_ACTION_TYP_TIR: 1582 case MLX5DR_ACTION_TYP_MISS: 1583 case MLX5DR_ACTION_TYP_TAG: 1584 case MLX5DR_ACTION_TYP_DROP: 1585 case MLX5DR_ACTION_TYP_CTR: 1586 case MLX5DR_ACTION_TYP_FT: 1587 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 1588 case MLX5DR_ACTION_TYP_ASO_METER: 1589 case MLX5DR_ACTION_TYP_ASO_CT: 1590 case MLX5DR_ACTION_TYP_PUSH_VLAN: 1591 mlx5dr_action_destroy_stcs(action); 1592 break; 1593 case MLX5DR_ACTION_TYP_POP_VLAN: 1594 mlx5dr_action_destroy_stcs(action); 1595 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP); 1596 break; 1597 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 1598 case MLX5DR_ACTION_TYP_MODIFY_HDR: 1599 mlx5dr_action_destroy_stcs(action); 1600 if (action->modify_header.num_of_actions > 1) 1601 mlx5dr_pat_arg_destroy_modify_header(action->ctx, action); 1602 break; 1603 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 1604 mlx5dr_action_destroy_stcs(action); 1605 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP); 1606 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 1607 break; 1608 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 1609 mlx5dr_action_destroy_stcs(action); 1610 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 1611 break; 1612 } 1613 } 1614 1615 static void mlx5dr_action_destroy_root(struct mlx5dr_action *action) 1616 { 1617 switch (action->type) { 1618 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 1619 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 1620 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 1621 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 1622 case MLX5DR_ACTION_TYP_MODIFY_HDR: 1623 ibv_destroy_flow_action(action->flow_action); 1624 break; 1625 } 1626 } 1627 1628 int mlx5dr_action_destroy(struct mlx5dr_action *action) 1629 { 1630 if (mlx5dr_action_is_root_flags(action->flags)) 1631 mlx5dr_action_destroy_root(action); 1632 else 1633 mlx5dr_action_destroy_hws(action); 1634 1635 simple_free(action); 1636 return 0; 1637 } 1638 1639 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */ 1640 int mlx5dr_action_get_default_stc(struct mlx5dr_context *ctx, 1641 uint8_t tbl_type) 1642 { 1643 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 1644 struct mlx5dr_action_default_stc *default_stc; 1645 int ret; 1646 1647 if (ctx->common_res[tbl_type].default_stc) { 1648 ctx->common_res[tbl_type].default_stc->refcount++; 1649 return 0; 1650 } 1651 1652 default_stc = simple_calloc(1, sizeof(*default_stc)); 1653 if (!default_stc) { 1654 DR_LOG(ERR, "Failed to allocate memory for default STCs"); 1655 rte_errno = ENOMEM; 1656 return rte_errno; 1657 } 1658 1659 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; 1660 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW0; 1661 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 1662 &default_stc->nop_ctr); 1663 if (ret) { 1664 DR_LOG(ERR, "Failed to allocate default counter STC"); 1665 goto free_default_stc; 1666 } 1667 1668 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 1669 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 1670 &default_stc->nop_dw5); 1671 if (ret) { 1672 DR_LOG(ERR, "Failed to allocate default NOP DW5 STC"); 1673 goto free_nop_ctr; 1674 } 1675 1676 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW6; 1677 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 1678 &default_stc->nop_dw6); 1679 if (ret) { 1680 DR_LOG(ERR, "Failed to allocate default NOP DW6 STC"); 1681 goto free_nop_dw5; 1682 } 1683 1684 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW7; 1685 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 1686 &default_stc->nop_dw7); 1687 if (ret) { 1688 DR_LOG(ERR, "Failed to allocate default NOP DW7 STC"); 1689 goto free_nop_dw6; 1690 } 1691 1692 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; 1693 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 1694 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 1695 &default_stc->default_hit); 1696 if (ret) { 1697 DR_LOG(ERR, "Failed to allocate default allow STC"); 1698 goto free_nop_dw7; 1699 } 1700 1701 ctx->common_res[tbl_type].default_stc = default_stc; 1702 ctx->common_res[tbl_type].default_stc->refcount++; 1703 1704 return 0; 1705 1706 free_nop_dw7: 1707 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); 1708 free_nop_dw6: 1709 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); 1710 free_nop_dw5: 1711 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); 1712 free_nop_ctr: 1713 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); 1714 free_default_stc: 1715 simple_free(default_stc); 1716 return rte_errno; 1717 } 1718 1719 void mlx5dr_action_put_default_stc(struct mlx5dr_context *ctx, 1720 uint8_t tbl_type) 1721 { 1722 struct mlx5dr_action_default_stc *default_stc; 1723 1724 default_stc = ctx->common_res[tbl_type].default_stc; 1725 1726 default_stc = ctx->common_res[tbl_type].default_stc; 1727 if (--default_stc->refcount) 1728 return; 1729 1730 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit); 1731 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); 1732 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); 1733 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); 1734 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); 1735 simple_free(default_stc); 1736 ctx->common_res[tbl_type].default_stc = NULL; 1737 } 1738 1739 static void mlx5dr_action_modify_write(struct mlx5dr_send_engine *queue, 1740 uint32_t arg_idx, 1741 uint8_t *arg_data, 1742 uint16_t num_of_actions) 1743 { 1744 mlx5dr_arg_write(queue, NULL, arg_idx, arg_data, 1745 num_of_actions * MLX5DR_MODIFY_ACTION_SIZE); 1746 } 1747 1748 void 1749 mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst, 1750 uint16_t num_of_actions) 1751 { 1752 uint8_t *e_src; 1753 int i; 1754 1755 /* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes 1756 * copy from end of src to the start of dst. 1757 * move to the end, 2 is the leftover from 14B or 18B 1758 */ 1759 if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN) 1760 e_src = src + MLX5DR_ACTION_HDR_LEN_L2; 1761 else 1762 e_src = src + MLX5DR_ACTION_HDR_LEN_L2_W_VLAN; 1763 1764 /* Move dst over the first remove action + zero data */ 1765 dst += MLX5DR_ACTION_DOUBLE_SIZE; 1766 /* Move dst over the first insert ctrl action */ 1767 dst += MLX5DR_ACTION_DOUBLE_SIZE / 2; 1768 /* Actions: 1769 * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. 1770 * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. 1771 * the loop is without the last insertion. 1772 */ 1773 for (i = 0; i < num_of_actions - 3; i++) { 1774 e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE; 1775 memcpy(dst, e_src, MLX5DR_ACTION_INLINE_DATA_SIZE); /* data */ 1776 dst += MLX5DR_ACTION_DOUBLE_SIZE; 1777 } 1778 /* Copy the last 2 bytes after a gap of 2 bytes which will be removed */ 1779 e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE / 2; 1780 dst += MLX5DR_ACTION_INLINE_DATA_SIZE / 2; 1781 memcpy(dst, e_src, 2); 1782 } 1783 1784 static struct mlx5dr_actions_wqe_setter * 1785 mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter, 1786 uint8_t req_flags) 1787 { 1788 /* Use a new setter if requested flags are taken */ 1789 while (setter->flags & req_flags) 1790 setter++; 1791 1792 /* Use current setter in required flags are not used */ 1793 return setter; 1794 } 1795 1796 static void 1797 mlx5dr_action_apply_stc(struct mlx5dr_actions_apply_data *apply, 1798 enum mlx5dr_action_stc_idx stc_idx, 1799 uint8_t action_idx) 1800 { 1801 struct mlx5dr_action *action = apply->rule_action[action_idx].action; 1802 1803 apply->wqe_ctrl->stc_ix[stc_idx] = 1804 htobe32(action->stc[apply->tbl_type].offset); 1805 } 1806 1807 static void 1808 mlx5dr_action_setter_push_vlan(struct mlx5dr_actions_apply_data *apply, 1809 struct mlx5dr_actions_wqe_setter *setter) 1810 { 1811 struct mlx5dr_rule_action *rule_action; 1812 1813 rule_action = &apply->rule_action[setter->idx_double]; 1814 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 1815 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr; 1816 1817 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 1818 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 1819 } 1820 1821 static void 1822 mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply, 1823 struct mlx5dr_actions_wqe_setter *setter) 1824 { 1825 struct mlx5dr_rule_action *rule_action; 1826 struct mlx5dr_action *action; 1827 uint32_t arg_sz, arg_idx; 1828 uint8_t *single_action; 1829 1830 rule_action = &apply->rule_action[setter->idx_double]; 1831 action = rule_action->action; 1832 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 1833 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 1834 1835 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 1836 1837 if (action->modify_header.num_of_actions == 1) { 1838 if (action->modify_header.single_action_type == 1839 MLX5_MODIFICATION_TYPE_COPY) { 1840 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0; 1841 return; 1842 } 1843 1844 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) 1845 single_action = (uint8_t *)&action->modify_header.single_action; 1846 else 1847 single_action = rule_action->modify_header.data; 1848 1849 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 1850 *(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data); 1851 } else { 1852 /* Argument offset multiple with number of args per these actions */ 1853 arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions); 1854 arg_idx = rule_action->modify_header.offset * arg_sz; 1855 1856 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 1857 1858 if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 1859 apply->require_dep = 1; 1860 mlx5dr_action_modify_write(apply->queue, 1861 action->modify_header.arg_obj->id + arg_idx, 1862 rule_action->modify_header.data, 1863 action->modify_header.num_of_actions); 1864 } 1865 } 1866 } 1867 1868 static void 1869 mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply, 1870 struct mlx5dr_actions_wqe_setter *setter) 1871 { 1872 struct mlx5dr_rule_action *rule_action; 1873 uint32_t arg_idx, arg_sz; 1874 1875 rule_action = &apply->rule_action[setter->idx_double]; 1876 1877 /* Argument offset multiple on args required for header size */ 1878 arg_sz = mlx5dr_arg_data_size_to_arg_size(rule_action->action->reformat.header_size); 1879 arg_idx = rule_action->reformat.offset * arg_sz; 1880 1881 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 1882 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 1883 1884 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 1885 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 1886 1887 if (!(rule_action->action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 1888 apply->require_dep = 1; 1889 mlx5dr_arg_write(apply->queue, NULL, 1890 rule_action->action->reformat.arg_obj->id + arg_idx, 1891 rule_action->reformat.data, 1892 rule_action->action->reformat.header_size); 1893 } 1894 } 1895 1896 static void 1897 mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply, 1898 struct mlx5dr_actions_wqe_setter *setter) 1899 { 1900 struct mlx5dr_rule_action *rule_action; 1901 struct mlx5dr_action *action; 1902 uint32_t arg_sz, arg_idx; 1903 1904 rule_action = &apply->rule_action[setter->idx_double]; 1905 action = rule_action->action; 1906 1907 /* Argument offset multiple on args required for num of actions */ 1908 arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions); 1909 arg_idx = rule_action->reformat.offset * arg_sz; 1910 1911 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 1912 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 1913 1914 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 1915 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 1916 1917 if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 1918 apply->require_dep = 1; 1919 mlx5dr_arg_decapl3_write(apply->queue, 1920 action->modify_header.arg_obj->id + arg_idx, 1921 rule_action->reformat.data, 1922 action->modify_header.num_of_actions); 1923 } 1924 } 1925 1926 static void 1927 mlx5dr_action_setter_aso(struct mlx5dr_actions_apply_data *apply, 1928 struct mlx5dr_actions_wqe_setter *setter) 1929 { 1930 struct mlx5dr_rule_action *rule_action; 1931 uint32_t exe_aso_ctrl; 1932 uint32_t offset; 1933 1934 rule_action = &apply->rule_action[setter->idx_double]; 1935 1936 switch (rule_action->action->type) { 1937 case MLX5DR_ACTION_TYP_ASO_METER: 1938 /* exe_aso_ctrl format: 1939 * [STC only and reserved bits 29b][init_color 2b][meter_id 1b] 1940 */ 1941 offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ; 1942 exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ; 1943 exe_aso_ctrl |= rule_action->aso_meter.init_color << 1944 MLX5DR_ACTION_METER_INIT_COLOR_OFFSET; 1945 break; 1946 case MLX5DR_ACTION_TYP_ASO_CT: 1947 /* exe_aso_ctrl CT format: 1948 * [STC only and reserved bits 31b][direction 1b] 1949 */ 1950 offset = rule_action->aso_ct.offset / MLX5_ASO_CT_NUM_PER_OBJ; 1951 exe_aso_ctrl = rule_action->aso_ct.direction; 1952 break; 1953 default: 1954 DR_LOG(ERR, "Unsupported ASO action type: %d", rule_action->action->type); 1955 rte_errno = ENOTSUP; 1956 return; 1957 } 1958 1959 /* aso_object_offset format: [24B] */ 1960 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = htobe32(offset); 1961 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(exe_aso_ctrl); 1962 1963 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 1964 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 1965 } 1966 1967 static void 1968 mlx5dr_action_setter_tag(struct mlx5dr_actions_apply_data *apply, 1969 struct mlx5dr_actions_wqe_setter *setter) 1970 { 1971 struct mlx5dr_rule_action *rule_action; 1972 1973 rule_action = &apply->rule_action[setter->idx_single]; 1974 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = htobe32(rule_action->tag.value); 1975 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single); 1976 } 1977 1978 static void 1979 mlx5dr_action_setter_ctrl_ctr(struct mlx5dr_actions_apply_data *apply, 1980 struct mlx5dr_actions_wqe_setter *setter) 1981 { 1982 struct mlx5dr_rule_action *rule_action; 1983 1984 rule_action = &apply->rule_action[setter->idx_ctr]; 1985 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW0] = htobe32(rule_action->counter.offset); 1986 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_CTRL, setter->idx_ctr); 1987 } 1988 1989 static void 1990 mlx5dr_action_setter_single(struct mlx5dr_actions_apply_data *apply, 1991 struct mlx5dr_actions_wqe_setter *setter) 1992 { 1993 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 1994 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single); 1995 } 1996 1997 static void 1998 mlx5dr_action_setter_single_double_pop(struct mlx5dr_actions_apply_data *apply, 1999 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 2000 { 2001 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 2002 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] = 2003 htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res, 2004 MLX5DR_CONTEXT_SHARED_STC_POP)); 2005 } 2006 2007 static void 2008 mlx5dr_action_setter_hit(struct mlx5dr_actions_apply_data *apply, 2009 struct mlx5dr_actions_wqe_setter *setter) 2010 { 2011 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0; 2012 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit); 2013 } 2014 2015 static void 2016 mlx5dr_action_setter_default_hit(struct mlx5dr_actions_apply_data *apply, 2017 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 2018 { 2019 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0; 2020 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = 2021 htobe32(apply->common_res->default_stc->default_hit.offset); 2022 } 2023 2024 static void 2025 mlx5dr_action_setter_hit_next_action(struct mlx5dr_actions_apply_data *apply, 2026 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 2027 { 2028 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = htobe32(apply->next_direct_idx << 6); 2029 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = htobe32(apply->jump_to_action_stc); 2030 } 2031 2032 static void 2033 mlx5dr_action_setter_common_decap(struct mlx5dr_actions_apply_data *apply, 2034 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 2035 { 2036 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 2037 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] = 2038 htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res, 2039 MLX5DR_CONTEXT_SHARED_STC_DECAP)); 2040 } 2041 2042 int mlx5dr_action_template_process(struct mlx5dr_action_template *at) 2043 { 2044 struct mlx5dr_actions_wqe_setter *start_setter = at->setters + 1; 2045 enum mlx5dr_action_type *action_type = at->action_type_arr; 2046 struct mlx5dr_actions_wqe_setter *setter = at->setters; 2047 struct mlx5dr_actions_wqe_setter *pop_setter = NULL; 2048 struct mlx5dr_actions_wqe_setter *last_setter; 2049 int i; 2050 2051 /* Note: Given action combination must be valid */ 2052 2053 /* Check if action were already processed */ 2054 if (at->num_of_action_stes) 2055 return 0; 2056 2057 for (i = 0; i < MLX5DR_ACTION_MAX_STE; i++) 2058 setter[i].set_hit = &mlx5dr_action_setter_hit_next_action; 2059 2060 /* The same action template setters can be used with jumbo or match 2061 * STE, to support both cases we reseve the first setter for cases 2062 * with jumbo STE to allow jump to the first action STE. 2063 * This extra setter can be reduced in some cases on rule creation. 2064 */ 2065 setter = start_setter; 2066 last_setter = start_setter; 2067 2068 for (i = 0; i < at->num_actions; i++) { 2069 switch (action_type[i]) { 2070 case MLX5DR_ACTION_TYP_DROP: 2071 case MLX5DR_ACTION_TYP_TIR: 2072 case MLX5DR_ACTION_TYP_FT: 2073 case MLX5DR_ACTION_TYP_VPORT: 2074 case MLX5DR_ACTION_TYP_MISS: 2075 /* Hit action */ 2076 last_setter->flags |= ASF_HIT; 2077 last_setter->set_hit = &mlx5dr_action_setter_hit; 2078 last_setter->idx_hit = i; 2079 break; 2080 2081 case MLX5DR_ACTION_TYP_POP_VLAN: 2082 /* Single remove header to header */ 2083 if (pop_setter) { 2084 /* We have 2 pops, use the shared */ 2085 pop_setter->set_single = &mlx5dr_action_setter_single_double_pop; 2086 break; 2087 } 2088 setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY); 2089 setter->flags |= ASF_SINGLE1 | ASF_REPARSE | ASF_REMOVE; 2090 setter->set_single = &mlx5dr_action_setter_single; 2091 setter->idx_single = i; 2092 pop_setter = setter; 2093 break; 2094 2095 case MLX5DR_ACTION_TYP_PUSH_VLAN: 2096 /* Double insert inline */ 2097 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 2098 setter->flags |= ASF_DOUBLE | ASF_REPARSE | ASF_MODIFY; 2099 setter->set_double = &mlx5dr_action_setter_push_vlan; 2100 setter->idx_double = i; 2101 break; 2102 2103 case MLX5DR_ACTION_TYP_MODIFY_HDR: 2104 /* Double modify header list */ 2105 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 2106 setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE; 2107 setter->set_double = &mlx5dr_action_setter_modify_header; 2108 setter->idx_double = i; 2109 break; 2110 2111 case MLX5DR_ACTION_TYP_ASO_METER: 2112 case MLX5DR_ACTION_TYP_ASO_CT: 2113 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE); 2114 setter->flags |= ASF_DOUBLE; 2115 setter->set_double = &mlx5dr_action_setter_aso; 2116 setter->idx_double = i; 2117 break; 2118 2119 case MLX5DR_ACTION_TYP_TNL_L2_TO_L2: 2120 /* Single remove header to header */ 2121 setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY); 2122 setter->flags |= ASF_SINGLE1 | ASF_REMOVE | ASF_REPARSE; 2123 setter->set_single = &mlx5dr_action_setter_single; 2124 setter->idx_single = i; 2125 break; 2126 2127 case MLX5DR_ACTION_TYP_L2_TO_TNL_L2: 2128 /* Double insert header with pointer */ 2129 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE); 2130 setter->flags |= ASF_DOUBLE | ASF_REPARSE; 2131 setter->set_double = &mlx5dr_action_setter_insert_ptr; 2132 setter->idx_double = i; 2133 break; 2134 2135 case MLX5DR_ACTION_TYP_L2_TO_TNL_L3: 2136 /* Single remove + Double insert header with pointer */ 2137 setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_DOUBLE); 2138 setter->flags |= ASF_SINGLE1 | ASF_DOUBLE | ASF_REPARSE | ASF_REMOVE; 2139 setter->set_double = &mlx5dr_action_setter_insert_ptr; 2140 setter->idx_double = i; 2141 setter->set_single = &mlx5dr_action_setter_common_decap; 2142 setter->idx_single = i; 2143 break; 2144 2145 case MLX5DR_ACTION_TYP_TNL_L3_TO_L2: 2146 /* Double modify header list with remove and push inline */ 2147 setter = mlx5dr_action_setter_find_first(last_setter, 2148 ASF_DOUBLE | ASF_REMOVE); 2149 setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE; 2150 setter->set_double = &mlx5dr_action_setter_tnl_l3_to_l2; 2151 setter->idx_double = i; 2152 break; 2153 2154 case MLX5DR_ACTION_TYP_TAG: 2155 /* Single TAG action, search for any room from the start */ 2156 setter = mlx5dr_action_setter_find_first(start_setter, ASF_SINGLE1); 2157 setter->flags |= ASF_SINGLE1; 2158 setter->set_single = &mlx5dr_action_setter_tag; 2159 setter->idx_single = i; 2160 break; 2161 2162 case MLX5DR_ACTION_TYP_CTR: 2163 /* Control counter action 2164 * TODO: Current counter executed first. Support is needed 2165 * for single ation counter action which is done last. 2166 * Example: Decap + CTR 2167 */ 2168 setter = mlx5dr_action_setter_find_first(start_setter, ASF_CTR); 2169 setter->flags |= ASF_CTR; 2170 setter->set_ctr = &mlx5dr_action_setter_ctrl_ctr; 2171 setter->idx_ctr = i; 2172 break; 2173 2174 default: 2175 DR_LOG(ERR, "Unsupported action type: %d", action_type[i]); 2176 rte_errno = ENOTSUP; 2177 assert(false); 2178 return rte_errno; 2179 } 2180 2181 last_setter = RTE_MAX(setter, last_setter); 2182 } 2183 2184 /* Set default hit on the last STE if no hit action provided */ 2185 if (!(last_setter->flags & ASF_HIT)) 2186 last_setter->set_hit = &mlx5dr_action_setter_default_hit; 2187 2188 at->num_of_action_stes = last_setter - start_setter + 1; 2189 2190 /* Check if action template doesn't require any action DWs */ 2191 at->only_term = (at->num_of_action_stes == 1) && 2192 !(last_setter->flags & ~(ASF_CTR | ASF_HIT)); 2193 2194 return 0; 2195 } 2196 2197 struct mlx5dr_action_template * 2198 mlx5dr_action_template_create(const enum mlx5dr_action_type action_type[]) 2199 { 2200 struct mlx5dr_action_template *at; 2201 uint8_t num_actions = 0; 2202 int i; 2203 2204 at = simple_calloc(1, sizeof(*at)); 2205 if (!at) { 2206 DR_LOG(ERR, "Failed to allocate action template"); 2207 rte_errno = ENOMEM; 2208 return NULL; 2209 } 2210 2211 while (action_type[num_actions++] != MLX5DR_ACTION_TYP_LAST) 2212 ; 2213 2214 at->num_actions = num_actions - 1; 2215 at->action_type_arr = simple_calloc(num_actions, sizeof(*action_type)); 2216 if (!at->action_type_arr) { 2217 DR_LOG(ERR, "Failed to allocate action type array"); 2218 rte_errno = ENOMEM; 2219 goto free_at; 2220 } 2221 2222 for (i = 0; i < num_actions; i++) 2223 at->action_type_arr[i] = action_type[i]; 2224 2225 return at; 2226 2227 free_at: 2228 simple_free(at); 2229 return NULL; 2230 } 2231 2232 int mlx5dr_action_template_destroy(struct mlx5dr_action_template *at) 2233 { 2234 simple_free(at->action_type_arr); 2235 simple_free(at); 2236 return 0; 2237 } 2238