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 /* Header removal size limited to 128B (64 words) */ 11 #define MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE 128 12 13 /* This is the maximum allowed action order for each table type: 14 * TX: POP_VLAN, CTR, ASO_METER, AS_CT, PUSH_VLAN, MODIFY, ENCAP, Term 15 * RX: TAG, DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY, 16 * ENCAP, Term 17 * FDB: DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY, 18 * ENCAP, Term 19 */ 20 static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_MAX] = { 21 [MLX5DR_TABLE_TYPE_NIC_RX] = { 22 BIT(MLX5DR_ACTION_TYP_TAG), 23 BIT(MLX5DR_ACTION_TYP_REMOVE_HEADER) | 24 BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) | 25 BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2) | 26 BIT(MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT), 27 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 28 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 29 BIT(MLX5DR_ACTION_TYP_CTR), 30 BIT(MLX5DR_ACTION_TYP_ASO_METER), 31 BIT(MLX5DR_ACTION_TYP_ASO_CT), 32 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 33 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 34 BIT(MLX5DR_ACTION_TYP_NAT64), 35 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 36 BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) | 37 BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) | 38 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) | 39 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3), 40 BIT(MLX5DR_ACTION_TYP_TBL) | 41 BIT(MLX5DR_ACTION_TYP_MISS) | 42 BIT(MLX5DR_ACTION_TYP_TIR) | 43 BIT(MLX5DR_ACTION_TYP_DROP) | 44 BIT(MLX5DR_ACTION_TYP_DEST_ROOT) | 45 BIT(MLX5DR_ACTION_TYP_DEST_ARRAY) | 46 BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER), 47 BIT(MLX5DR_ACTION_TYP_LAST), 48 }, 49 [MLX5DR_TABLE_TYPE_NIC_TX] = { 50 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 51 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 52 BIT(MLX5DR_ACTION_TYP_CTR), 53 BIT(MLX5DR_ACTION_TYP_ASO_METER), 54 BIT(MLX5DR_ACTION_TYP_ASO_CT), 55 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 56 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 57 BIT(MLX5DR_ACTION_TYP_NAT64), 58 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 59 BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) | 60 BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) | 61 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) | 62 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3), 63 BIT(MLX5DR_ACTION_TYP_TBL) | 64 BIT(MLX5DR_ACTION_TYP_MISS) | 65 BIT(MLX5DR_ACTION_TYP_DROP) | 66 BIT(MLX5DR_ACTION_TYP_DEST_ROOT) | 67 BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER), 68 BIT(MLX5DR_ACTION_TYP_LAST), 69 }, 70 [MLX5DR_TABLE_TYPE_FDB] = { 71 BIT(MLX5DR_ACTION_TYP_REMOVE_HEADER) | 72 BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) | 73 BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2) | 74 BIT(MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT), 75 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 76 BIT(MLX5DR_ACTION_TYP_POP_VLAN), 77 BIT(MLX5DR_ACTION_TYP_CTR), 78 BIT(MLX5DR_ACTION_TYP_ASO_METER), 79 BIT(MLX5DR_ACTION_TYP_ASO_CT), 80 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 81 BIT(MLX5DR_ACTION_TYP_PUSH_VLAN), 82 BIT(MLX5DR_ACTION_TYP_NAT64), 83 BIT(MLX5DR_ACTION_TYP_MODIFY_HDR), 84 BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) | 85 BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) | 86 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) | 87 BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3), 88 BIT(MLX5DR_ACTION_TYP_TBL) | 89 BIT(MLX5DR_ACTION_TYP_MISS) | 90 BIT(MLX5DR_ACTION_TYP_VPORT) | 91 BIT(MLX5DR_ACTION_TYP_DROP) | 92 BIT(MLX5DR_ACTION_TYP_DEST_ROOT) | 93 BIT(MLX5DR_ACTION_TYP_DEST_ARRAY) | 94 BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER), 95 BIT(MLX5DR_ACTION_TYP_LAST), 96 }, 97 }; 98 99 static int mlx5dr_action_get_shared_stc_nic(struct mlx5dr_context *ctx, 100 enum mlx5dr_context_shared_stc_type stc_type, 101 uint8_t tbl_type) 102 { 103 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 104 struct mlx5dr_action_shared_stc *shared_stc; 105 int ret; 106 107 pthread_spin_lock(&ctx->ctrl_lock); 108 if (ctx->common_res[tbl_type].shared_stc[stc_type]) { 109 ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++; 110 pthread_spin_unlock(&ctx->ctrl_lock); 111 return 0; 112 } 113 114 shared_stc = simple_calloc(1, sizeof(*shared_stc)); 115 if (!shared_stc) { 116 DR_LOG(ERR, "Failed to allocate memory for shared STCs"); 117 rte_errno = ENOMEM; 118 goto unlock_and_out; 119 } 120 switch (stc_type) { 121 case MLX5DR_CONTEXT_SHARED_STC_DECAP_L3: 122 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; 123 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 124 stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 125 stc_attr.remove_header.decap = 0; 126 stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 127 stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4; 128 break; 129 case MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP: 130 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; 131 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 132 stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 133 stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; 134 stc_attr.remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN; 135 break; 136 default: 137 DR_LOG(ERR, "No such type : stc_type"); 138 assert(false); 139 rte_errno = EINVAL; 140 goto unlock_and_out; 141 } 142 143 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 144 &shared_stc->remove_header); 145 if (ret) { 146 DR_LOG(ERR, "Failed to allocate shared decap l2 STC"); 147 goto free_shared_stc; 148 } 149 150 ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc; 151 ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1; 152 153 pthread_spin_unlock(&ctx->ctrl_lock); 154 155 return 0; 156 157 free_shared_stc: 158 simple_free(shared_stc); 159 unlock_and_out: 160 pthread_spin_unlock(&ctx->ctrl_lock); 161 return rte_errno; 162 } 163 164 static void mlx5dr_action_put_shared_stc_nic(struct mlx5dr_context *ctx, 165 enum mlx5dr_context_shared_stc_type stc_type, 166 uint8_t tbl_type) 167 { 168 struct mlx5dr_action_shared_stc *shared_stc; 169 170 pthread_spin_lock(&ctx->ctrl_lock); 171 if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) { 172 pthread_spin_unlock(&ctx->ctrl_lock); 173 return; 174 } 175 176 shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type]; 177 178 mlx5dr_action_free_single_stc(ctx, tbl_type, &shared_stc->remove_header); 179 simple_free(shared_stc); 180 ctx->common_res[tbl_type].shared_stc[stc_type] = NULL; 181 pthread_spin_unlock(&ctx->ctrl_lock); 182 } 183 184 static int mlx5dr_action_get_shared_stc(struct mlx5dr_action *action, 185 enum mlx5dr_context_shared_stc_type stc_type) 186 { 187 struct mlx5dr_context *ctx = action->ctx; 188 int ret; 189 190 if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) { 191 assert(false); 192 rte_errno = EINVAL; 193 return rte_errno; 194 } 195 196 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) { 197 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 198 if (ret) { 199 DR_LOG(ERR, "Failed to allocate memory for RX shared STCs (type: %d)", 200 stc_type); 201 return ret; 202 } 203 } 204 205 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) { 206 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 207 if (ret) { 208 DR_LOG(ERR, "Failed to allocate memory for TX shared STCs(type: %d)", 209 stc_type); 210 goto clean_nic_rx_stc; 211 } 212 } 213 214 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) { 215 ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB); 216 if (ret) { 217 DR_LOG(ERR, "Failed to allocate memory for FDB shared STCs (type: %d)", 218 stc_type); 219 goto clean_nic_tx_stc; 220 } 221 } 222 223 return 0; 224 225 clean_nic_tx_stc: 226 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 227 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 228 clean_nic_rx_stc: 229 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 230 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 231 232 return ret; 233 } 234 235 static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action, 236 enum mlx5dr_context_shared_stc_type stc_type) 237 { 238 struct mlx5dr_context *ctx = action->ctx; 239 240 if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) { 241 assert(false); 242 return; 243 } 244 245 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 246 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX); 247 248 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 249 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX); 250 251 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) 252 mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB); 253 } 254 255 static void 256 mlx5dr_action_create_nat64_zero_all_addr(uint8_t **action_ptr, bool is_v4_to_v6) 257 { 258 if (is_v4_to_v6) { 259 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 260 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV4); 261 MLX5_SET(set_action_in, *action_ptr, data, 0); 262 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 263 264 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 265 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV4); 266 MLX5_SET(set_action_in, *action_ptr, data, 0); 267 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 268 } else { 269 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 270 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_127_96); 271 MLX5_SET(set_action_in, *action_ptr, data, 0); 272 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 273 274 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 275 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_95_64); 276 MLX5_SET(set_action_in, *action_ptr, data, 0); 277 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 278 279 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 280 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_63_32); 281 MLX5_SET(set_action_in, *action_ptr, data, 0); 282 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 283 284 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 285 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_31_0); 286 MLX5_SET(set_action_in, *action_ptr, data, 0); 287 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 288 289 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 290 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_127_96); 291 MLX5_SET(set_action_in, *action_ptr, data, 0); 292 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 293 294 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 295 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_95_64); 296 MLX5_SET(set_action_in, *action_ptr, data, 0); 297 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 298 299 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 300 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_63_32); 301 MLX5_SET(set_action_in, *action_ptr, data, 0); 302 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 303 304 MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 305 MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_31_0); 306 MLX5_SET(set_action_in, *action_ptr, data, 0); 307 *action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 308 } 309 } 310 311 static struct mlx5dr_action * 312 mlx5dr_action_create_nat64_copy_state(struct mlx5dr_context *ctx, 313 struct mlx5dr_action_nat64_attr *attr, 314 uint32_t flags) 315 { 316 __be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS]; 317 struct mlx5dr_action_mh_pattern pat[2]; 318 struct mlx5dr_action *action; 319 uint32_t packet_len_field; 320 uint8_t *action_ptr; 321 uint32_t tos_field; 322 uint32_t tos_size; 323 uint32_t src_addr; 324 uint32_t dst_addr; 325 bool is_v4_to_v6; 326 uint32_t ecn; 327 328 is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6; 329 330 if (is_v4_to_v6) { 331 packet_len_field = MLX5_MODI_OUT_IPV4_TOTAL_LEN; 332 tos_field = MLX5_MODI_OUT_IP_DSCP; 333 tos_size = 6; 334 ecn = MLX5_MODI_OUT_IP_ECN; 335 src_addr = MLX5_MODI_OUT_SIPV4; 336 dst_addr = MLX5_MODI_OUT_DIPV4; 337 } else { 338 packet_len_field = MLX5_MODI_OUT_IPV6_PAYLOAD_LEN; 339 tos_field = MLX5_MODI_OUT_IPV6_TRAFFIC_CLASS; 340 tos_size = 8; 341 ecn = 0; 342 src_addr = MLX5_MODI_OUT_SIPV6_31_0; 343 dst_addr = MLX5_MODI_OUT_DIPV6_31_0; 344 } 345 346 memset(modify_action_data, 0, sizeof(modify_action_data)); 347 action_ptr = (uint8_t *)modify_action_data; 348 349 if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR) { 350 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 351 MLX5_SET(copy_action_in, action_ptr, src_field, src_addr); 352 MLX5_SET(copy_action_in, action_ptr, dst_field, 353 attr->registers[MLX5DR_ACTION_NAT64_REG_SRC_IP]); 354 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 355 356 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 357 MLX5_SET(copy_action_in, action_ptr, src_field, dst_addr); 358 MLX5_SET(copy_action_in, action_ptr, dst_field, 359 attr->registers[MLX5DR_ACTION_NAT64_REG_DST_IP]); 360 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 361 } 362 363 /* | 8 bit - 8 bit - 16 bit | 364 * | TOS - protocol - packet-len | 365 */ 366 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 367 MLX5_SET(copy_action_in, action_ptr, src_field, packet_len_field); 368 MLX5_SET(copy_action_in, action_ptr, dst_field, 369 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 370 MLX5_SET(copy_action_in, action_ptr, dst_offset, 0);/* 16 bits in the lsb */ 371 MLX5_SET(copy_action_in, action_ptr, length, 16); 372 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 373 374 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 375 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 376 377 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 378 MLX5_SET(copy_action_in, action_ptr, src_field, MLX5_MODI_OUT_IP_PROTOCOL); 379 MLX5_SET(copy_action_in, action_ptr, dst_field, 380 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 381 MLX5_SET(copy_action_in, action_ptr, dst_offset, 16); 382 MLX5_SET(copy_action_in, action_ptr, length, 8); 383 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 384 385 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 386 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 387 388 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 389 MLX5_SET(copy_action_in, action_ptr, src_field, tos_field); 390 MLX5_SET(copy_action_in, action_ptr, dst_field, 391 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 392 MLX5_SET(copy_action_in, action_ptr, dst_offset, 24); 393 MLX5_SET(copy_action_in, action_ptr, length, tos_size); 394 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 395 /* in ipv4 TOS = {dscp (6bits) - ecn (2bits) }*/ 396 if (ecn) { 397 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 398 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 399 400 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 401 MLX5_SET(copy_action_in, action_ptr, src_field, ecn); 402 MLX5_SET(copy_action_in, action_ptr, dst_field, 403 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 404 MLX5_SET(copy_action_in, action_ptr, dst_offset, 24 + tos_size); 405 MLX5_SET(copy_action_in, action_ptr, length, MLX5DR_ACTION_NAT64_ECN_SIZE); 406 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 407 } 408 409 /* set sip and dip to 0, in order to have new csum */ 410 mlx5dr_action_create_nat64_zero_all_addr(&action_ptr, is_v4_to_v6); 411 412 pat[0].data = modify_action_data; 413 pat[0].sz = (action_ptr - (uint8_t *)modify_action_data); 414 415 action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags); 416 if (!action) { 417 DR_LOG(ERR, "Failed to create copy for NAT64: action_sz: %zu, flags: 0x%x\n", 418 pat[0].sz, flags); 419 return NULL; 420 } 421 422 return action; 423 } 424 425 static struct mlx5dr_action * 426 mlx5dr_action_create_nat64_repalce_state(struct mlx5dr_context *ctx, 427 struct mlx5dr_action_nat64_attr *attr, 428 uint32_t flags) 429 { 430 uint32_t address_prefix[MLX5DR_ACTION_NAT64_HEADER_MINUS_ONE] = {0}; 431 __be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS]; 432 struct mlx5dr_action_mh_pattern pat[2]; 433 static struct mlx5dr_action *action; 434 uint8_t header_size_in_dw; 435 uint8_t *action_ptr; 436 uint32_t eth_type; 437 bool is_v4_to_v6; 438 uint32_t ip_ver; 439 int i; 440 441 is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6; 442 443 if (is_v4_to_v6) { 444 uint32_t nat64_well_known_pref[] = {0x00010000, 445 0x9bff6400, 0x0, 0x0, 0x0, 446 0x9bff6400, 0x0, 0x0, 0x0}; 447 448 header_size_in_dw = MLX5DR_ACTION_NAT64_IPV6_HEADER; 449 ip_ver = MLX5DR_ACTION_NAT64_IPV6_VER; 450 eth_type = RTE_ETHER_TYPE_IPV6; 451 memcpy(address_prefix, nat64_well_known_pref, 452 MLX5DR_ACTION_NAT64_HEADER_MINUS_ONE * sizeof(uint32_t)); 453 } else { 454 /* In order to fix HW csum issue, make the prefix ready */ 455 uint32_t ipv4_pref[] = {0x0, 0xffba0000, 0x0, 0x0, 0x0}; 456 457 header_size_in_dw = MLX5DR_ACTION_NAT64_IPV4_HEADER; 458 ip_ver = MLX5DR_ACTION_NAT64_IPV4_VER; 459 eth_type = RTE_ETHER_TYPE_IPV4; 460 memcpy(address_prefix, ipv4_pref, 461 MLX5DR_ACTION_NAT64_IPV4_HEADER * sizeof(uint32_t)); 462 } 463 464 memset(modify_action_data, 0, sizeof(modify_action_data)); 465 action_ptr = (uint8_t *)modify_action_data; 466 467 MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 468 MLX5_SET(set_action_in, action_ptr, field, MLX5_MODI_OUT_ETHERTYPE); 469 MLX5_SET(set_action_in, action_ptr, length, 16); 470 MLX5_SET(set_action_in, action_ptr, data, eth_type); 471 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 472 473 /* push empty header with ipv6 as version */ 474 MLX5_SET(stc_ste_param_insert, action_ptr, action_type, 475 MLX5_MODIFICATION_TYPE_INSERT); 476 MLX5_SET(stc_ste_param_insert, action_ptr, inline_data, 0x1); 477 MLX5_SET(stc_ste_param_insert, action_ptr, insert_anchor, 478 MLX5_HEADER_ANCHOR_IPV6_IPV4); 479 MLX5_SET(stc_ste_param_insert, action_ptr, insert_size, 2); 480 MLX5_SET(stc_ste_param_insert, action_ptr, insert_argument, ip_ver); 481 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 482 483 for (i = 0; i < header_size_in_dw - 1; i++) { 484 MLX5_SET(stc_ste_param_insert, action_ptr, action_type, 485 MLX5_MODIFICATION_TYPE_INSERT); 486 MLX5_SET(stc_ste_param_insert, action_ptr, inline_data, 0x1); 487 MLX5_SET(stc_ste_param_insert, action_ptr, insert_anchor, 488 MLX5_HEADER_ANCHOR_IPV6_IPV4); 489 MLX5_SET(stc_ste_param_insert, action_ptr, insert_size, 2); 490 MLX5_SET(stc_ste_param_insert, action_ptr, insert_argument, 491 htobe32(address_prefix[i])); 492 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 493 } 494 495 /* Remove orig src/dst addr (8 bytes, 4 words) */ 496 MLX5_SET(stc_ste_param_remove, action_ptr, action_type, 497 MLX5_MODIFICATION_TYPE_REMOVE); 498 MLX5_SET(stc_ste_param_remove, action_ptr, remove_start_anchor, 499 MLX5_HEADER_ANCHOR_IPV6_IPV4); 500 MLX5_SET(stc_ste_param_remove, action_ptr, remove_end_anchor, 501 MLX5_HEADER_ANCHOR_TCP_UDP); 502 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 503 504 pat[0].data = modify_action_data; 505 pat[0].sz = action_ptr - (uint8_t *)modify_action_data; 506 507 action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags); 508 if (!action) { 509 DR_LOG(ERR, "Failed to create action: action_sz: %zu flags: 0x%x\n", 510 pat[0].sz, flags); 511 return NULL; 512 } 513 514 return action; 515 } 516 517 static struct mlx5dr_action * 518 mlx5dr_action_create_nat64_copy_proto_state(struct mlx5dr_context *ctx, 519 struct mlx5dr_action_nat64_attr *attr, 520 uint32_t flags) 521 { 522 __be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS]; 523 struct mlx5dr_action_mh_pattern pat[2]; 524 struct mlx5dr_action *action; 525 uint8_t *action_ptr; 526 527 memset(modify_action_data, 0, sizeof(modify_action_data)); 528 action_ptr = (uint8_t *)modify_action_data; 529 530 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 531 MLX5_SET(copy_action_in, action_ptr, src_field, 532 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 533 MLX5_SET(copy_action_in, action_ptr, dst_field, 534 MLX5_MODI_OUT_IP_PROTOCOL); 535 MLX5_SET(copy_action_in, action_ptr, src_offset, 16); 536 MLX5_SET(copy_action_in, action_ptr, dst_offset, 0); 537 MLX5_SET(copy_action_in, action_ptr, length, 8); 538 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 539 540 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 541 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 542 543 pat[0].data = modify_action_data; 544 pat[0].sz = action_ptr - (uint8_t *)modify_action_data; 545 546 action = mlx5dr_action_create_modify_header_reparse(ctx, 1, pat, 0, flags, 547 MLX5DR_ACTION_STC_REPARSE_ON); 548 if (!action) { 549 DR_LOG(ERR, "Failed to create action: action_sz: %zu, flags: 0x%x\n", 550 pat[0].sz, flags); 551 return NULL; 552 } 553 554 return action; 555 } 556 557 static struct mlx5dr_action * 558 mlx5dr_action_create_nat64_copy_back_state(struct mlx5dr_context *ctx, 559 struct mlx5dr_action_nat64_attr *attr, 560 uint32_t flags) 561 { 562 __be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS]; 563 struct mlx5dr_action_mh_pattern pat[2]; 564 struct mlx5dr_action *action; 565 uint32_t packet_len_field; 566 uint32_t packet_len_add; 567 uint8_t *action_ptr; 568 uint32_t tos_field; 569 uint32_t ttl_field; 570 uint32_t tos_size; 571 uint32_t src_addr; 572 uint32_t dst_addr; 573 bool is_v4_to_v6; 574 uint32_t ecn; 575 576 is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6; 577 578 if (is_v4_to_v6) { 579 packet_len_field = MLX5_MODI_OUT_IPV6_PAYLOAD_LEN; 580 /* 2' comp to 20, to get -20 in add operation */ 581 packet_len_add = MLX5DR_ACTION_NAT64_DEC_20; 582 ttl_field = MLX5_MODI_OUT_IPV6_HOPLIMIT; 583 src_addr = MLX5_MODI_OUT_SIPV6_31_0; 584 dst_addr = MLX5_MODI_OUT_DIPV6_31_0; 585 tos_field = MLX5_MODI_OUT_IPV6_TRAFFIC_CLASS; 586 tos_size = 8; 587 ecn = 0; 588 } else { 589 packet_len_field = MLX5_MODI_OUT_IPV4_TOTAL_LEN; 590 /* ipv4 len is including 20 bytes of the header, so add 20 over ipv6 len */ 591 packet_len_add = MLX5DR_ACTION_NAT64_ADD_20; 592 ttl_field = MLX5_MODI_OUT_IPV4_TTL; 593 src_addr = MLX5_MODI_OUT_SIPV4; 594 dst_addr = MLX5_MODI_OUT_DIPV4; 595 tos_field = MLX5_MODI_OUT_IP_DSCP; 596 tos_size = 6; 597 ecn = MLX5_MODI_OUT_IP_ECN; 598 } 599 600 memset(modify_action_data, 0, sizeof(modify_action_data)); 601 action_ptr = (uint8_t *)modify_action_data; 602 603 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 604 MLX5_SET(copy_action_in, action_ptr, src_field, 605 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 606 MLX5_SET(copy_action_in, action_ptr, dst_field, 607 packet_len_field); 608 MLX5_SET(copy_action_in, action_ptr, src_offset, 32); 609 MLX5_SET(copy_action_in, action_ptr, length, 16); 610 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 611 612 MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET); 613 MLX5_SET(set_action_in, action_ptr, field, ttl_field); 614 MLX5_SET(set_action_in, action_ptr, length, 8); 615 MLX5_SET(set_action_in, action_ptr, data, MLX5DR_ACTION_NAT64_TTL_DEFAULT_VAL); 616 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 617 618 /* copy TOS */ 619 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 620 MLX5_SET(copy_action_in, action_ptr, src_field, 621 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 622 MLX5_SET(copy_action_in, action_ptr, dst_field, tos_field); 623 MLX5_SET(copy_action_in, action_ptr, src_offset, 24 + (ecn ? 624 MLX5DR_ACTION_NAT64_ECN_SIZE : 0)); 625 MLX5_SET(copy_action_in, action_ptr, length, tos_size); 626 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 627 628 if (ecn) { 629 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 630 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 631 632 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 633 MLX5_SET(copy_action_in, action_ptr, src_field, 634 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]); 635 MLX5_SET(copy_action_in, action_ptr, dst_field, ecn); 636 MLX5_SET(copy_action_in, action_ptr, src_offset, 24); 637 MLX5_SET(copy_action_in, action_ptr, length, MLX5DR_ACTION_NAT64_ECN_SIZE); 638 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 639 } 640 641 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP); 642 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 643 644 /* if required Copy original addresses */ 645 if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR) { 646 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 647 MLX5_SET(copy_action_in, action_ptr, src_field, 648 attr->registers[MLX5DR_ACTION_NAT64_REG_SRC_IP]); 649 MLX5_SET(copy_action_in, action_ptr, dst_field, src_addr); 650 MLX5_SET(copy_action_in, action_ptr, src_offset, 0); 651 MLX5_SET(copy_action_in, action_ptr, length, 32); 652 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 653 654 MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY); 655 MLX5_SET(copy_action_in, action_ptr, src_field, 656 attr->registers[MLX5DR_ACTION_NAT64_REG_DST_IP]); 657 MLX5_SET(copy_action_in, action_ptr, dst_field, dst_addr); 658 MLX5_SET(copy_action_in, action_ptr, src_offset, 0); 659 MLX5_SET(copy_action_in, action_ptr, length, 32); 660 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 661 } 662 663 /* take/add off 20 bytes ipv4/6 from/to the total size */ 664 MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_ADD); 665 MLX5_SET(set_action_in, action_ptr, field, packet_len_field); 666 MLX5_SET(set_action_in, action_ptr, data, packet_len_add); 667 MLX5_SET(set_action_in, action_ptr, length, 16); 668 action_ptr += MLX5DR_ACTION_DOUBLE_SIZE; 669 670 pat[0].data = modify_action_data; 671 pat[0].sz = action_ptr - (uint8_t *)modify_action_data; 672 673 action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags); 674 if (!action) { 675 DR_LOG(ERR, "Failed to create action: action_sz: %zu, flags: 0x%x\n", 676 pat[0].sz, flags); 677 return NULL; 678 } 679 680 return action; 681 } 682 683 static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions) 684 { 685 DR_LOG(ERR, "Invalid action_type sequence"); 686 while (*user_actions != MLX5DR_ACTION_TYP_LAST) { 687 DR_LOG(ERR, "%s", mlx5dr_debug_action_type_to_str(*user_actions)); 688 user_actions++; 689 } 690 } 691 692 bool mlx5dr_action_check_combo(enum mlx5dr_action_type *user_actions, 693 enum mlx5dr_table_type table_type) 694 { 695 const uint32_t *order_arr = action_order_arr[table_type]; 696 uint8_t order_idx = 0; 697 uint8_t user_idx = 0; 698 bool valid_combo; 699 700 while (order_arr[order_idx] != BIT(MLX5DR_ACTION_TYP_LAST)) { 701 /* User action order validated move to next user action */ 702 if (BIT(user_actions[user_idx]) & order_arr[order_idx]) 703 user_idx++; 704 705 /* Iterate to the next supported action in the order */ 706 order_idx++; 707 } 708 709 /* Combination is valid if all user action were processed */ 710 valid_combo = user_actions[user_idx] == MLX5DR_ACTION_TYP_LAST; 711 if (!valid_combo) 712 mlx5dr_action_print_combo(user_actions); 713 714 return valid_combo; 715 } 716 717 int mlx5dr_action_root_build_attr(struct mlx5dr_rule_action rule_actions[], 718 uint32_t num_actions, 719 struct mlx5dv_flow_action_attr *attr) 720 { 721 struct mlx5dr_action *action; 722 uint32_t i; 723 724 for (i = 0; i < num_actions; i++) { 725 action = rule_actions[i].action; 726 727 switch (action->type) { 728 case MLX5DR_ACTION_TYP_TBL: 729 case MLX5DR_ACTION_TYP_TIR: 730 attr[i].type = MLX5DV_FLOW_ACTION_DEST_DEVX; 731 attr[i].obj = action->devx_obj; 732 break; 733 case MLX5DR_ACTION_TYP_TAG: 734 attr[i].type = MLX5DV_FLOW_ACTION_TAG; 735 attr[i].tag_value = rule_actions[i].tag.value; 736 break; 737 #ifdef HAVE_MLX5_DR_CREATE_ACTION_DEFAULT_MISS 738 case MLX5DR_ACTION_TYP_MISS: 739 attr[i].type = MLX5DV_FLOW_ACTION_DEFAULT_MISS; 740 break; 741 #endif 742 case MLX5DR_ACTION_TYP_DROP: 743 attr[i].type = MLX5DV_FLOW_ACTION_DROP; 744 break; 745 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 746 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 747 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 748 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 749 case MLX5DR_ACTION_TYP_MODIFY_HDR: 750 attr[i].type = MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION; 751 attr[i].action = action->flow_action; 752 break; 753 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS 754 case MLX5DR_ACTION_TYP_CTR: 755 attr[i].type = MLX5DV_FLOW_ACTION_COUNTERS_DEVX; 756 attr[i].obj = action->devx_obj; 757 758 if (rule_actions[i].counter.offset) { 759 DR_LOG(ERR, "Counter offset not supported over root"); 760 rte_errno = ENOTSUP; 761 return rte_errno; 762 } 763 break; 764 #endif 765 default: 766 DR_LOG(ERR, "Found unsupported action type: %d", action->type); 767 rte_errno = ENOTSUP; 768 return rte_errno; 769 } 770 } 771 772 return 0; 773 } 774 775 static bool 776 mlx5dr_action_fixup_stc_attr(struct mlx5dr_context *ctx, 777 struct mlx5dr_cmd_stc_modify_attr *stc_attr, 778 struct mlx5dr_cmd_stc_modify_attr *fixup_stc_attr, 779 enum mlx5dr_table_type table_type, 780 bool is_mirror) 781 { 782 struct mlx5dr_devx_obj *devx_obj; 783 bool use_fixup = false; 784 uint32_t fw_tbl_type; 785 786 fw_tbl_type = mlx5dr_table_get_res_fw_ft_type(table_type, is_mirror); 787 788 switch (stc_attr->action_type) { 789 case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: 790 if (!is_mirror) 791 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_attr->ste_table.ste_pool, 792 &stc_attr->ste_table.ste); 793 else 794 devx_obj = 795 mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_attr->ste_table.ste_pool, 796 &stc_attr->ste_table.ste); 797 798 *fixup_stc_attr = *stc_attr; 799 fixup_stc_attr->ste_table.ste_obj_id = devx_obj->id; 800 use_fixup = true; 801 break; 802 803 case MLX5_IFC_STC_ACTION_TYPE_ALLOW: 804 if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) { 805 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; 806 fixup_stc_attr->action_offset = stc_attr->action_offset; 807 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 808 fixup_stc_attr->vport.esw_owner_vhca_id = ctx->caps->vhca_id; 809 fixup_stc_attr->vport.vport_num = ctx->caps->eswitch_manager_vport_number; 810 fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = 811 ctx->caps->merged_eswitch; 812 use_fixup = true; 813 } 814 break; 815 816 case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: 817 if (stc_attr->vport.vport_num != WIRE_PORT) 818 break; 819 820 if (fw_tbl_type == FS_FT_FDB_RX) { 821 /* The FW doesn't allow to go back to wire in RX, so change it to DROP */ 822 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 823 fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 824 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 825 } else if (fw_tbl_type == FS_FT_FDB_TX) { 826 /*The FW doesn't allow to go to wire in the TX by JUMP_TO_VPORT*/ 827 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK; 828 fixup_stc_attr->action_offset = stc_attr->action_offset; 829 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 830 fixup_stc_attr->vport.vport_num = 0; 831 fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id; 832 fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = 833 stc_attr->vport.eswitch_owner_vhca_id_valid; 834 } 835 use_fixup = true; 836 break; 837 case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR: 838 /* TIR is allowed on RX side, requires mask in case of FDB */ 839 if (fw_tbl_type == FS_FT_FDB_TX) { 840 fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 841 fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 842 fixup_stc_attr->stc_offset = stc_attr->stc_offset; 843 use_fixup = true; 844 } 845 break; 846 default: 847 break; 848 } 849 850 return use_fixup; 851 } 852 853 int mlx5dr_action_alloc_single_stc(struct mlx5dr_context *ctx, 854 struct mlx5dr_cmd_stc_modify_attr *stc_attr, 855 uint32_t table_type, 856 struct mlx5dr_pool_chunk *stc) 857 { 858 struct mlx5dr_cmd_stc_modify_attr cleanup_stc_attr = {0}; 859 struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type]; 860 struct mlx5dr_cmd_stc_modify_attr fixup_stc_attr = {0}; 861 struct mlx5dr_devx_obj *devx_obj_0; 862 bool use_fixup; 863 int ret; 864 865 ret = mlx5dr_pool_chunk_alloc(stc_pool, stc); 866 if (ret) { 867 DR_LOG(ERR, "Failed to allocate single action STC"); 868 return ret; 869 } 870 871 stc_attr->stc_offset = stc->offset; 872 873 /* Dynamic reparse not supported, overwrite and use default */ 874 if (!mlx5dr_context_cap_dynamic_reparse(ctx)) 875 stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 876 877 devx_obj_0 = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc); 878 879 /* According to table/action limitation change the stc_attr */ 880 use_fixup = mlx5dr_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false); 881 ret = mlx5dr_cmd_stc_modify(devx_obj_0, use_fixup ? &fixup_stc_attr : stc_attr); 882 if (ret) { 883 DR_LOG(ERR, "Failed to modify STC action_type %d tbl_type %d", 884 stc_attr->action_type, table_type); 885 goto free_chunk; 886 } 887 888 /* Modify the FDB peer */ 889 if (table_type == MLX5DR_TABLE_TYPE_FDB) { 890 struct mlx5dr_devx_obj *devx_obj_1; 891 892 devx_obj_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc); 893 894 use_fixup = mlx5dr_action_fixup_stc_attr(ctx, stc_attr, 895 &fixup_stc_attr, 896 table_type, true); 897 ret = mlx5dr_cmd_stc_modify(devx_obj_1, use_fixup ? &fixup_stc_attr : stc_attr); 898 if (ret) { 899 DR_LOG(ERR, "Failed to modify peer STC action_type %d tbl_type %d", 900 stc_attr->action_type, table_type); 901 goto clean_devx_obj_0; 902 } 903 } 904 905 return 0; 906 907 clean_devx_obj_0: 908 cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 909 cleanup_stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 910 cleanup_stc_attr.stc_offset = stc->offset; 911 mlx5dr_cmd_stc_modify(devx_obj_0, &cleanup_stc_attr); 912 free_chunk: 913 mlx5dr_pool_chunk_free(stc_pool, stc); 914 return rte_errno; 915 } 916 917 void mlx5dr_action_free_single_stc(struct mlx5dr_context *ctx, 918 uint32_t table_type, 919 struct mlx5dr_pool_chunk *stc) 920 { 921 struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type]; 922 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 923 struct mlx5dr_devx_obj *devx_obj; 924 925 /* Modify the STC not to point to an object */ 926 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 927 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 928 stc_attr.stc_offset = stc->offset; 929 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc); 930 mlx5dr_cmd_stc_modify(devx_obj, &stc_attr); 931 932 if (table_type == MLX5DR_TABLE_TYPE_FDB) { 933 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc); 934 mlx5dr_cmd_stc_modify(devx_obj, &stc_attr); 935 } 936 937 mlx5dr_pool_chunk_free(stc_pool, stc); 938 } 939 940 static uint32_t mlx5dr_action_get_mh_stc_type(__be64 pattern) 941 { 942 uint8_t action_type = MLX5_GET(set_action_in, &pattern, action_type); 943 944 switch (action_type) { 945 case MLX5_MODIFICATION_TYPE_SET: 946 return MLX5_IFC_STC_ACTION_TYPE_SET; 947 case MLX5_MODIFICATION_TYPE_ADD: 948 return MLX5_IFC_STC_ACTION_TYPE_ADD; 949 case MLX5_MODIFICATION_TYPE_COPY: 950 return MLX5_IFC_STC_ACTION_TYPE_COPY; 951 case MLX5_MODIFICATION_TYPE_ADD_FIELD: 952 return MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD; 953 default: 954 assert(false); 955 DR_LOG(ERR, "Unsupported action type: 0x%x", action_type); 956 rte_errno = ENOTSUP; 957 return MLX5_IFC_STC_ACTION_TYPE_NOP; 958 } 959 } 960 961 static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action, 962 struct mlx5dr_devx_obj *obj, 963 struct mlx5dr_cmd_stc_modify_attr *attr) 964 { 965 attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 966 967 switch (action->type) { 968 case MLX5DR_ACTION_TYP_TAG: 969 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG; 970 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 971 break; 972 case MLX5DR_ACTION_TYP_DROP: 973 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 974 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 975 break; 976 case MLX5DR_ACTION_TYP_MISS: 977 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; 978 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 979 break; 980 case MLX5DR_ACTION_TYP_CTR: 981 attr->id = obj->id; 982 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER; 983 attr->action_offset = MLX5DR_ACTION_OFFSET_DW0; 984 break; 985 case MLX5DR_ACTION_TYP_TIR: 986 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR; 987 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 988 attr->dest_tir_num = obj->id; 989 break; 990 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 991 case MLX5DR_ACTION_TYP_MODIFY_HDR: 992 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 993 attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 994 if (action->modify_header.require_reparse) 995 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 996 997 if (action->modify_header.num_of_actions == 1) { 998 attr->modify_action.data = action->modify_header.single_action; 999 attr->action_type = mlx5dr_action_get_mh_stc_type(attr->modify_action.data); 1000 1001 if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD || 1002 attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET) 1003 MLX5_SET(set_action_in, &attr->modify_action.data, data, 0); 1004 } else { 1005 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST; 1006 attr->modify_header.arg_id = action->modify_header.arg_obj->id; 1007 attr->modify_header.pattern_id = action->modify_header.pat_obj->id; 1008 } 1009 break; 1010 case MLX5DR_ACTION_TYP_TBL: 1011 case MLX5DR_ACTION_TYP_DEST_ARRAY: 1012 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; 1013 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 1014 attr->dest_table_id = obj->id; 1015 break; 1016 case MLX5DR_ACTION_TYP_DEST_ROOT: 1017 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; 1018 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 1019 attr->dest_table_id = action->root_tbl.sa->id; 1020 break; 1021 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 1022 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; 1023 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 1024 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 1025 attr->remove_header.decap = 1; 1026 attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 1027 attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC; 1028 break; 1029 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 1030 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 1031 case MLX5DR_ACTION_TYP_INSERT_HEADER: 1032 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 1033 if (!action->reformat.require_reparse) 1034 attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 1035 1036 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; 1037 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 1038 attr->insert_header.encap = action->reformat.encap; 1039 attr->insert_header.push_esp = action->reformat.push_esp; 1040 attr->insert_header.insert_anchor = action->reformat.anchor; 1041 attr->insert_header.arg_id = action->reformat.arg_obj->id; 1042 attr->insert_header.header_size = action->reformat.header_size; 1043 attr->insert_header.insert_offset = action->reformat.offset; 1044 break; 1045 case MLX5DR_ACTION_TYP_ASO_METER: 1046 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 1047 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; 1048 attr->aso.aso_type = ASO_OPC_MOD_POLICER; 1049 attr->aso.devx_obj_id = obj->id; 1050 attr->aso.return_reg_id = action->aso.return_reg_id; 1051 break; 1052 case MLX5DR_ACTION_TYP_ASO_CT: 1053 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 1054 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; 1055 attr->aso.aso_type = ASO_OPC_MOD_CONNECTION_TRACKING; 1056 attr->aso.devx_obj_id = obj->id; 1057 attr->aso.return_reg_id = action->aso.return_reg_id; 1058 break; 1059 case MLX5DR_ACTION_TYP_VPORT: 1060 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 1061 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; 1062 attr->vport.vport_num = action->vport.vport_num; 1063 attr->vport.esw_owner_vhca_id = action->vport.esw_owner_vhca_id; 1064 attr->vport.eswitch_owner_vhca_id_valid = action->ctx->caps->merged_eswitch; 1065 break; 1066 case MLX5DR_ACTION_TYP_POP_VLAN: 1067 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; 1068 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 1069 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 1070 attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; 1071 attr->remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN / 2; 1072 break; 1073 case MLX5DR_ACTION_TYP_PUSH_VLAN: 1074 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; 1075 attr->action_offset = MLX5DR_ACTION_OFFSET_DW6; 1076 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 1077 attr->insert_header.encap = 0; 1078 attr->insert_header.push_esp = 0; 1079 attr->insert_header.is_inline = 1; 1080 attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; 1081 attr->insert_header.insert_offset = MLX5DR_ACTION_HDR_LEN_L2_MACS; 1082 attr->insert_header.header_size = MLX5DR_ACTION_HDR_LEN_L2_VLAN; 1083 break; 1084 case MLX5DR_ACTION_TYP_REMOVE_HEADER: 1085 if (action->remove_header.type == MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER) { 1086 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; 1087 attr->remove_header.decap = action->remove_header.decap; 1088 attr->remove_header.start_anchor = action->remove_header.start_anchor; 1089 attr->remove_header.end_anchor = action->remove_header.end_anchor; 1090 } else { 1091 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; 1092 attr->remove_words.start_anchor = action->remove_header.start_anchor; 1093 attr->remove_words.num_of_words = action->remove_header.num_of_words; 1094 } 1095 attr->action_offset = MLX5DR_ACTION_OFFSET_DW5; 1096 attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; 1097 break; 1098 case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER: 1099 attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 1100 attr->action_offset = MLX5DR_ACTION_OFFSET_HIT; 1101 attr->ste_table.ste = action->jump_to_matcher.matcher->match_ste.ste; 1102 attr->ste_table.ste_pool = action->jump_to_matcher.matcher->match_ste.pool; 1103 attr->ste_table.match_definer_id = action->ctx->caps->trivial_match_definer; 1104 break; 1105 default: 1106 DR_LOG(ERR, "Invalid action type %d", action->type); 1107 assert(false); 1108 } 1109 } 1110 1111 static int 1112 mlx5dr_action_create_stcs(struct mlx5dr_action *action, 1113 struct mlx5dr_devx_obj *obj) 1114 { 1115 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 1116 struct mlx5dr_context *ctx = action->ctx; 1117 int ret; 1118 1119 mlx5dr_action_fill_stc_attr(action, obj, &stc_attr); 1120 1121 /* Block unsupported parallel devx obj modify over the same base */ 1122 pthread_spin_lock(&ctx->ctrl_lock); 1123 1124 /* Allocate STC for RX */ 1125 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) { 1126 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 1127 MLX5DR_TABLE_TYPE_NIC_RX, 1128 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 1129 if (ret) 1130 goto out_err; 1131 } 1132 1133 /* Allocate STC for TX */ 1134 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) { 1135 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 1136 MLX5DR_TABLE_TYPE_NIC_TX, 1137 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 1138 if (ret) 1139 goto free_nic_rx_stc; 1140 } 1141 1142 /* Allocate STC for FDB */ 1143 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) { 1144 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, 1145 MLX5DR_TABLE_TYPE_FDB, 1146 &action->stc[MLX5DR_TABLE_TYPE_FDB]); 1147 if (ret) 1148 goto free_nic_tx_stc; 1149 } 1150 1151 pthread_spin_unlock(&ctx->ctrl_lock); 1152 1153 return 0; 1154 1155 free_nic_tx_stc: 1156 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 1157 mlx5dr_action_free_single_stc(ctx, 1158 MLX5DR_TABLE_TYPE_NIC_TX, 1159 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 1160 free_nic_rx_stc: 1161 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 1162 mlx5dr_action_free_single_stc(ctx, 1163 MLX5DR_TABLE_TYPE_NIC_RX, 1164 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 1165 out_err: 1166 pthread_spin_unlock(&ctx->ctrl_lock); 1167 return rte_errno; 1168 } 1169 1170 static void 1171 mlx5dr_action_destroy_stcs(struct mlx5dr_action *action) 1172 { 1173 struct mlx5dr_context *ctx = action->ctx; 1174 1175 /* Block unsupported parallel devx obj modify over the same base */ 1176 pthread_spin_lock(&ctx->ctrl_lock); 1177 1178 if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) 1179 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_RX, 1180 &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]); 1181 1182 if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) 1183 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_TX, 1184 &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]); 1185 1186 if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) 1187 mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_FDB, 1188 &action->stc[MLX5DR_TABLE_TYPE_FDB]); 1189 1190 pthread_spin_unlock(&ctx->ctrl_lock); 1191 } 1192 1193 static bool 1194 mlx5dr_action_is_root_flags(uint32_t flags) 1195 { 1196 return flags & (MLX5DR_ACTION_FLAG_ROOT_RX | 1197 MLX5DR_ACTION_FLAG_ROOT_TX | 1198 MLX5DR_ACTION_FLAG_ROOT_FDB); 1199 } 1200 1201 static bool 1202 mlx5dr_action_is_hws_flags(uint32_t flags) 1203 { 1204 return flags & (MLX5DR_ACTION_FLAG_HWS_RX | 1205 MLX5DR_ACTION_FLAG_HWS_TX | 1206 MLX5DR_ACTION_FLAG_HWS_FDB); 1207 } 1208 1209 static struct mlx5dr_action * 1210 mlx5dr_action_create_generic_bulk(struct mlx5dr_context *ctx, 1211 uint32_t flags, 1212 enum mlx5dr_action_type action_type, 1213 uint8_t bulk_sz) 1214 { 1215 struct mlx5dr_action *action; 1216 int i; 1217 1218 if (!mlx5dr_action_is_root_flags(flags) && 1219 !mlx5dr_action_is_hws_flags(flags)) { 1220 DR_LOG(ERR, "Action flags must specify root or non root (HWS)"); 1221 rte_errno = ENOTSUP; 1222 return NULL; 1223 } 1224 1225 if (mlx5dr_action_is_hws_flags(flags) && 1226 !(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) { 1227 DR_LOG(ERR, "Cannot create HWS action since HWS is not supported"); 1228 rte_errno = ENOTSUP; 1229 return NULL; 1230 } 1231 1232 action = simple_calloc(bulk_sz, sizeof(*action)); 1233 if (!action) { 1234 DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type); 1235 rte_errno = ENOMEM; 1236 return NULL; 1237 } 1238 1239 for (i = 0; i < bulk_sz; i++) { 1240 action[i].ctx = ctx; 1241 action[i].flags = flags; 1242 action[i].type = action_type; 1243 } 1244 1245 return action; 1246 } 1247 1248 static struct mlx5dr_action * 1249 mlx5dr_action_create_generic(struct mlx5dr_context *ctx, 1250 uint32_t flags, 1251 enum mlx5dr_action_type action_type) 1252 { 1253 return mlx5dr_action_create_generic_bulk(ctx, flags, action_type, 1); 1254 } 1255 1256 struct mlx5dr_action * 1257 mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx, 1258 struct mlx5dr_table *tbl, 1259 uint32_t flags) 1260 { 1261 struct mlx5dr_action *action; 1262 int ret; 1263 1264 if (mlx5dr_table_is_root(tbl)) { 1265 DR_LOG(ERR, "Root table cannot be set as destination"); 1266 rte_errno = ENOTSUP; 1267 return NULL; 1268 } 1269 1270 if (mlx5dr_action_is_hws_flags(flags) && 1271 mlx5dr_action_is_root_flags(flags)) { 1272 DR_LOG(ERR, "Same action cannot be used for root and non root"); 1273 rte_errno = ENOTSUP; 1274 return NULL; 1275 } 1276 1277 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TBL); 1278 if (!action) 1279 return NULL; 1280 1281 if (mlx5dr_action_is_root_flags(flags)) { 1282 if (mlx5dr_context_shared_gvmi_used(ctx)) 1283 action->devx_obj = tbl->local_ft->obj; 1284 else 1285 action->devx_obj = tbl->ft->obj; 1286 } else { 1287 ret = mlx5dr_action_create_stcs(action, tbl->ft); 1288 if (ret) 1289 goto free_action; 1290 1291 action->devx_dest.devx_obj = tbl->ft; 1292 } 1293 1294 return action; 1295 1296 free_action: 1297 simple_free(action); 1298 return NULL; 1299 } 1300 1301 static int mlx5dr_action_get_dest_tir_obj(struct mlx5dr_context *ctx, 1302 struct mlx5dr_action *action, 1303 struct mlx5dr_devx_obj *obj, 1304 struct mlx5dr_devx_obj **ret_obj) 1305 { 1306 int ret; 1307 1308 if (mlx5dr_context_shared_gvmi_used(ctx)) { 1309 ret = mlx5dr_matcher_create_aliased_obj(ctx, 1310 ctx->local_ibv_ctx, 1311 ctx->ibv_ctx, 1312 ctx->caps->vhca_id, 1313 obj->id, 1314 MLX5_GENERAL_OBJ_TYPE_TIR_ALIAS, 1315 &action->alias.devx_obj); 1316 if (ret) { 1317 DR_LOG(ERR, "Failed to create tir alias"); 1318 return rte_errno; 1319 } 1320 *ret_obj = action->alias.devx_obj; 1321 } else { 1322 *ret_obj = obj; 1323 } 1324 1325 return 0; 1326 } 1327 1328 struct mlx5dr_action * 1329 mlx5dr_action_create_dest_tir(struct mlx5dr_context *ctx, 1330 struct mlx5dr_devx_obj *obj, 1331 uint32_t flags, 1332 bool is_local) 1333 { 1334 struct mlx5dr_action *action; 1335 int ret; 1336 1337 if (mlx5dr_action_is_hws_flags(flags) && 1338 mlx5dr_action_is_root_flags(flags)) { 1339 DR_LOG(ERR, "Same action cannot be used for root and non root"); 1340 rte_errno = ENOTSUP; 1341 return NULL; 1342 } 1343 1344 if ((flags & MLX5DR_ACTION_FLAG_ROOT_FDB) || 1345 (flags & MLX5DR_ACTION_FLAG_HWS_FDB && !ctx->caps->fdb_tir_stc)) { 1346 DR_LOG(ERR, "TIR action not support on FDB"); 1347 rte_errno = ENOTSUP; 1348 return NULL; 1349 } 1350 1351 if (!is_local) { 1352 DR_LOG(ERR, "TIR should be created on local ibv_device, flags: 0x%x", 1353 flags); 1354 rte_errno = ENOTSUP; 1355 return NULL; 1356 } 1357 1358 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TIR); 1359 if (!action) 1360 return NULL; 1361 1362 if (mlx5dr_action_is_root_flags(flags)) { 1363 action->devx_obj = obj->obj; 1364 } else { 1365 struct mlx5dr_devx_obj *cur_obj = NULL; /*compilation warn*/ 1366 1367 ret = mlx5dr_action_get_dest_tir_obj(ctx, action, obj, &cur_obj); 1368 if (ret) { 1369 DR_LOG(ERR, "Failed to create tir alias (flags: %d)", flags); 1370 goto free_action; 1371 } 1372 1373 ret = mlx5dr_action_create_stcs(action, cur_obj); 1374 if (ret) 1375 goto clean_obj; 1376 1377 action->devx_dest.devx_obj = cur_obj; 1378 } 1379 1380 return action; 1381 1382 clean_obj: 1383 mlx5dr_cmd_destroy_obj(action->alias.devx_obj); 1384 free_action: 1385 simple_free(action); 1386 return NULL; 1387 } 1388 1389 struct mlx5dr_action * 1390 mlx5dr_action_create_dest_drop(struct mlx5dr_context *ctx, 1391 uint32_t flags) 1392 { 1393 struct mlx5dr_action *action; 1394 int ret; 1395 1396 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DROP); 1397 if (!action) 1398 return NULL; 1399 1400 if (mlx5dr_action_is_hws_flags(flags)) { 1401 ret = mlx5dr_action_create_stcs(action, NULL); 1402 if (ret) 1403 goto free_action; 1404 } 1405 1406 return action; 1407 1408 free_action: 1409 simple_free(action); 1410 return NULL; 1411 } 1412 1413 struct mlx5dr_action * 1414 mlx5dr_action_create_default_miss(struct mlx5dr_context *ctx, 1415 uint32_t flags) 1416 { 1417 struct mlx5dr_action *action; 1418 int ret; 1419 1420 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MISS); 1421 if (!action) 1422 return NULL; 1423 1424 if (mlx5dr_action_is_hws_flags(flags)) { 1425 ret = mlx5dr_action_create_stcs(action, NULL); 1426 if (ret) 1427 goto free_action; 1428 } 1429 1430 return action; 1431 1432 free_action: 1433 simple_free(action); 1434 return NULL; 1435 } 1436 1437 struct mlx5dr_action * 1438 mlx5dr_action_create_tag(struct mlx5dr_context *ctx, 1439 uint32_t flags) 1440 { 1441 struct mlx5dr_action *action; 1442 int ret; 1443 1444 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TAG); 1445 if (!action) 1446 return NULL; 1447 1448 if (mlx5dr_action_is_hws_flags(flags)) { 1449 ret = mlx5dr_action_create_stcs(action, NULL); 1450 if (ret) 1451 goto free_action; 1452 } 1453 1454 return action; 1455 1456 free_action: 1457 simple_free(action); 1458 return NULL; 1459 } 1460 1461 struct mlx5dr_action * 1462 mlx5dr_action_create_last(struct mlx5dr_context *ctx, 1463 uint32_t flags) 1464 { 1465 return mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_LAST); 1466 } 1467 1468 static struct mlx5dr_action * 1469 mlx5dr_action_create_aso(struct mlx5dr_context *ctx, 1470 enum mlx5dr_action_type action_type, 1471 struct mlx5dr_devx_obj *devx_obj, 1472 uint8_t return_reg_id, 1473 uint32_t flags) 1474 { 1475 struct mlx5dr_action *action; 1476 int ret; 1477 1478 if (mlx5dr_action_is_root_flags(flags)) { 1479 DR_LOG(ERR, "ASO action cannot be used over root table"); 1480 rte_errno = ENOTSUP; 1481 return NULL; 1482 } 1483 1484 action = mlx5dr_action_create_generic(ctx, flags, action_type); 1485 if (!action) 1486 return NULL; 1487 1488 action->aso.devx_obj = devx_obj; 1489 action->aso.return_reg_id = return_reg_id; 1490 1491 ret = mlx5dr_action_create_stcs(action, devx_obj); 1492 if (ret) 1493 goto free_action; 1494 1495 return action; 1496 1497 free_action: 1498 simple_free(action); 1499 return NULL; 1500 } 1501 1502 struct mlx5dr_action * 1503 mlx5dr_action_create_aso_meter(struct mlx5dr_context *ctx, 1504 struct mlx5dr_devx_obj *devx_obj, 1505 uint8_t return_reg_id, 1506 uint32_t flags) 1507 { 1508 return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_METER, 1509 devx_obj, return_reg_id, flags); 1510 } 1511 1512 struct mlx5dr_action * 1513 mlx5dr_action_create_aso_ct(struct mlx5dr_context *ctx, 1514 struct mlx5dr_devx_obj *devx_obj, 1515 uint8_t return_reg_id, 1516 uint32_t flags) 1517 { 1518 return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_CT, 1519 devx_obj, return_reg_id, flags); 1520 } 1521 1522 struct mlx5dr_action * 1523 mlx5dr_action_create_counter(struct mlx5dr_context *ctx, 1524 struct mlx5dr_devx_obj *obj, 1525 uint32_t flags) 1526 { 1527 struct mlx5dr_action *action; 1528 int ret; 1529 1530 if (mlx5dr_action_is_hws_flags(flags) && 1531 mlx5dr_action_is_root_flags(flags)) { 1532 DR_LOG(ERR, "Same action cannot be used for root and non root"); 1533 rte_errno = ENOTSUP; 1534 return NULL; 1535 } 1536 1537 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_CTR); 1538 if (!action) 1539 return NULL; 1540 1541 if (mlx5dr_action_is_root_flags(flags)) { 1542 action->devx_obj = obj->obj; 1543 } else { 1544 ret = mlx5dr_action_create_stcs(action, obj); 1545 if (ret) 1546 goto free_action; 1547 } 1548 1549 return action; 1550 1551 free_action: 1552 simple_free(action); 1553 return NULL; 1554 } 1555 1556 static int mlx5dr_action_create_dest_vport_hws(struct mlx5dr_context *ctx, 1557 struct mlx5dr_action *action, 1558 uint32_t ib_port_num) 1559 { 1560 struct mlx5dr_cmd_query_vport_caps vport_caps = {0}; 1561 int ret; 1562 1563 ret = mlx5dr_cmd_query_ib_port(ctx->ibv_ctx, &vport_caps, ib_port_num); 1564 if (ret) { 1565 DR_LOG(ERR, "Failed querying port %d", ib_port_num); 1566 return ret; 1567 } 1568 action->vport.vport_num = vport_caps.vport_num; 1569 action->vport.esw_owner_vhca_id = vport_caps.esw_owner_vhca_id; 1570 1571 if (!ctx->caps->merged_eswitch && 1572 action->vport.esw_owner_vhca_id != ctx->caps->vhca_id) { 1573 DR_LOG(ERR, "Not merged-eswitch (%d), not allowed to send to other vhca_id (%d)", 1574 ctx->caps->vhca_id, action->vport.esw_owner_vhca_id); 1575 rte_errno = ENOTSUP; 1576 return rte_errno; 1577 } 1578 1579 ret = mlx5dr_action_create_stcs(action, NULL); 1580 if (ret) { 1581 DR_LOG(ERR, "Failed creating stc for port %d", ib_port_num); 1582 return ret; 1583 } 1584 1585 return 0; 1586 } 1587 1588 struct mlx5dr_action * 1589 mlx5dr_action_create_dest_vport(struct mlx5dr_context *ctx, 1590 uint32_t ib_port_num, 1591 uint32_t flags) 1592 { 1593 struct mlx5dr_action *action; 1594 int ret; 1595 1596 if (!(flags & MLX5DR_ACTION_FLAG_HWS_FDB)) { 1597 DR_LOG(ERR, "Vport action is supported for FDB only"); 1598 rte_errno = EINVAL; 1599 return NULL; 1600 } 1601 1602 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_VPORT); 1603 if (!action) 1604 return NULL; 1605 1606 ret = mlx5dr_action_create_dest_vport_hws(ctx, action, ib_port_num); 1607 if (ret) { 1608 DR_LOG(ERR, "Failed to create vport action HWS"); 1609 goto free_action; 1610 } 1611 1612 return action; 1613 1614 free_action: 1615 simple_free(action); 1616 return NULL; 1617 } 1618 1619 struct mlx5dr_action * 1620 mlx5dr_action_create_push_vlan(struct mlx5dr_context *ctx, uint32_t flags) 1621 { 1622 struct mlx5dr_action *action; 1623 int ret; 1624 1625 if (mlx5dr_action_is_root_flags(flags)) { 1626 DR_LOG(ERR, "Push vlan action not supported for root"); 1627 rte_errno = ENOTSUP; 1628 return NULL; 1629 } 1630 1631 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_PUSH_VLAN); 1632 if (!action) 1633 return NULL; 1634 1635 ret = mlx5dr_action_create_stcs(action, NULL); 1636 if (ret) { 1637 DR_LOG(ERR, "Failed creating stc for push vlan"); 1638 goto free_action; 1639 } 1640 1641 return action; 1642 1643 free_action: 1644 simple_free(action); 1645 return NULL; 1646 } 1647 1648 struct mlx5dr_action * 1649 mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags) 1650 { 1651 struct mlx5dr_action *action; 1652 int ret; 1653 1654 if (mlx5dr_action_is_root_flags(flags)) { 1655 DR_LOG(ERR, "Pop vlan action not supported for root"); 1656 rte_errno = ENOTSUP; 1657 return NULL; 1658 } 1659 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_POP_VLAN); 1660 if (!action) 1661 return NULL; 1662 1663 ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP); 1664 if (ret) { 1665 DR_LOG(ERR, "Failed to create remove stc for reformat"); 1666 goto free_action; 1667 } 1668 1669 ret = mlx5dr_action_create_stcs(action, NULL); 1670 if (ret) { 1671 DR_LOG(ERR, "Failed creating stc for pop vlan"); 1672 goto free_shared; 1673 } 1674 1675 return action; 1676 1677 free_shared: 1678 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP); 1679 free_action: 1680 simple_free(action); 1681 return NULL; 1682 } 1683 1684 static int 1685 mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type, 1686 uint32_t *verb_reformat_type) 1687 { 1688 switch (action_type) { 1689 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 1690 *verb_reformat_type = 1691 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2; 1692 return 0; 1693 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 1694 *verb_reformat_type = 1695 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL; 1696 return 0; 1697 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 1698 *verb_reformat_type = 1699 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2; 1700 return 0; 1701 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 1702 *verb_reformat_type = 1703 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 1704 return 0; 1705 default: 1706 DR_LOG(ERR, "Invalid root reformat action type"); 1707 rte_errno = EINVAL; 1708 return rte_errno; 1709 } 1710 } 1711 1712 static int 1713 mlx5dr_action_conv_flags_to_ft_type(uint32_t flags, enum mlx5dv_flow_table_type *ft_type) 1714 { 1715 if (flags & (MLX5DR_ACTION_FLAG_ROOT_RX | MLX5DR_ACTION_FLAG_HWS_RX)) { 1716 *ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 1717 } else if (flags & (MLX5DR_ACTION_FLAG_ROOT_TX | MLX5DR_ACTION_FLAG_HWS_TX)) { 1718 *ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 1719 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE 1720 } else if (flags & (MLX5DR_ACTION_FLAG_ROOT_FDB | MLX5DR_ACTION_FLAG_HWS_FDB)) { 1721 *ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 1722 #endif 1723 } else { 1724 rte_errno = ENOTSUP; 1725 return 1; 1726 } 1727 1728 return 0; 1729 } 1730 1731 static int 1732 mlx5dr_action_create_reformat_root(struct mlx5dr_action *action, 1733 size_t data_sz, 1734 void *data) 1735 { 1736 enum mlx5dv_flow_table_type ft_type = 0; /*fix compilation warn*/ 1737 uint32_t verb_reformat_type = 0; 1738 struct ibv_context *ibv_ctx; 1739 int ret; 1740 1741 /* Convert action to FT type and verbs reformat type */ 1742 ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type); 1743 if (ret) 1744 return rte_errno; 1745 1746 ret = mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type); 1747 if (ret) 1748 return rte_errno; 1749 1750 /* Create the reformat type for root table */ 1751 ibv_ctx = mlx5dr_context_get_local_ibv(action->ctx); 1752 action->flow_action = 1753 mlx5_glue->dv_create_flow_action_packet_reformat_root(ibv_ctx, 1754 data_sz, 1755 data, 1756 verb_reformat_type, 1757 ft_type); 1758 if (!action->flow_action) { 1759 DR_LOG(ERR, "Failed to create dv_create_flow reformat"); 1760 rte_errno = errno; 1761 return rte_errno; 1762 } 1763 1764 return 0; 1765 } 1766 1767 static int 1768 mlx5dr_action_handle_insert_with_ptr(struct mlx5dr_action *action, 1769 uint8_t num_of_hdrs, 1770 struct mlx5dr_action_reformat_header *hdrs, 1771 uint32_t log_bulk_sz, uint32_t reparse) 1772 { 1773 struct mlx5dr_devx_obj *arg_obj; 1774 size_t max_sz = 0; 1775 int ret, i; 1776 1777 for (i = 0; i < num_of_hdrs; i++) { 1778 if (hdrs[i].sz % W_SIZE != 0) { 1779 DR_LOG(ERR, "Header data size should be in WORD granularity"); 1780 rte_errno = EINVAL; 1781 return rte_errno; 1782 } 1783 max_sz = RTE_MAX(hdrs[i].sz, max_sz); 1784 } 1785 1786 /* Allocate single shared arg object for all headers */ 1787 arg_obj = mlx5dr_arg_create(action->ctx, 1788 hdrs->data, 1789 max_sz, 1790 log_bulk_sz, 1791 action->flags & MLX5DR_ACTION_FLAG_SHARED); 1792 if (!arg_obj) 1793 return rte_errno; 1794 1795 for (i = 0; i < num_of_hdrs; i++) { 1796 action[i].reformat.arg_obj = arg_obj; 1797 action[i].reformat.header_size = hdrs[i].sz; 1798 action[i].reformat.num_of_hdrs = num_of_hdrs; 1799 action[i].reformat.max_hdr_sz = max_sz; 1800 1801 if (action[i].type == MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2 || 1802 action[i].type == MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3) { 1803 action[i].reformat.anchor = MLX5_HEADER_ANCHOR_PACKET_START; 1804 action[i].reformat.offset = 0; 1805 action[i].reformat.encap = 1; 1806 action[i].reformat.push_esp = 0; 1807 } 1808 1809 if (likely(reparse == MLX5DR_ACTION_STC_REPARSE_DEFAULT)) 1810 action[i].reformat.require_reparse = true; 1811 else if (reparse == MLX5DR_ACTION_STC_REPARSE_ON) 1812 action[i].reformat.require_reparse = true; 1813 1814 ret = mlx5dr_action_create_stcs(&action[i], NULL); 1815 if (ret) { 1816 DR_LOG(ERR, "Failed to create stc for reformat"); 1817 goto free_stc; 1818 } 1819 } 1820 1821 return 0; 1822 1823 free_stc: 1824 while (i--) 1825 mlx5dr_action_destroy_stcs(&action[i]); 1826 1827 mlx5dr_cmd_destroy_obj(arg_obj); 1828 return ret; 1829 } 1830 1831 static int 1832 mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_action *action, 1833 uint8_t num_of_hdrs, 1834 struct mlx5dr_action_reformat_header *hdrs, 1835 uint32_t log_bulk_sz) 1836 { 1837 int ret; 1838 1839 /* The action is remove-l2-header + insert-l3-header */ 1840 ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3); 1841 if (ret) { 1842 DR_LOG(ERR, "Failed to create remove stc for reformat"); 1843 return ret; 1844 } 1845 1846 /* Reuse the insert with pointer for the L2L3 header */ 1847 ret = mlx5dr_action_handle_insert_with_ptr(action, 1848 num_of_hdrs, 1849 hdrs, 1850 log_bulk_sz, 1851 MLX5DR_ACTION_STC_REPARSE_DEFAULT); 1852 if (ret) 1853 goto put_shared_stc; 1854 1855 return 0; 1856 1857 put_shared_stc: 1858 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3); 1859 return ret; 1860 } 1861 1862 static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz, 1863 uint8_t *mh_data, 1864 int *num_of_actions) 1865 { 1866 int actions; 1867 uint32_t i; 1868 1869 /* Remove L2L3 outer headers */ 1870 MLX5_SET(stc_ste_param_remove, mh_data, action_type, 1871 MLX5_MODIFICATION_TYPE_REMOVE); 1872 MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1); 1873 MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor, 1874 MLX5_HEADER_ANCHOR_PACKET_START); 1875 MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor, 1876 MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4); 1877 mh_data += MLX5DR_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */ 1878 actions = 1; 1879 1880 /* Add the new header using inline action 4Byte at a time, the header 1881 * is added in reversed order to the beginning of the packet to avoid 1882 * incorrect parsing by the HW. Since header is 14B or 18B an extra 1883 * two bytes are padded and later removed. 1884 */ 1885 for (i = 0; i < data_sz / MLX5DR_ACTION_INLINE_DATA_SIZE + 1; i++) { 1886 MLX5_SET(stc_ste_param_insert, mh_data, action_type, 1887 MLX5_MODIFICATION_TYPE_INSERT); 1888 MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1); 1889 MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor, 1890 MLX5_HEADER_ANCHOR_PACKET_START); 1891 MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2); 1892 mh_data += MLX5DR_ACTION_DOUBLE_SIZE; 1893 actions++; 1894 } 1895 1896 /* Remove first 2 extra bytes */ 1897 MLX5_SET(stc_ste_param_remove_words, mh_data, action_type, 1898 MLX5_MODIFICATION_TYPE_REMOVE_WORDS); 1899 MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor, 1900 MLX5_HEADER_ANCHOR_PACKET_START); 1901 /* The hardware expects here size in words (2 bytes) */ 1902 MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1); 1903 actions++; 1904 1905 *num_of_actions = actions; 1906 } 1907 1908 static int 1909 mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_action *action, 1910 uint8_t num_of_hdrs, 1911 struct mlx5dr_action_reformat_header *hdrs, 1912 uint32_t log_bulk_sz) 1913 { 1914 uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0}; 1915 struct mlx5dr_devx_obj *arg_obj, *pat_obj; 1916 struct mlx5dr_context *ctx = action->ctx; 1917 int num_of_actions; 1918 int mh_data_size; 1919 int ret, i; 1920 1921 for (i = 0; i < num_of_hdrs; i++) { 1922 if (hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2 && 1923 hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) { 1924 DR_LOG(ERR, "Data size is not supported for decap-l3"); 1925 rte_errno = EINVAL; 1926 return rte_errno; 1927 } 1928 } 1929 1930 /* Create a full modify header action list in case shared */ 1931 mlx5dr_action_prepare_decap_l3_actions(hdrs->sz, mh_data, &num_of_actions); 1932 1933 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) 1934 mlx5dr_action_prepare_decap_l3_data(hdrs->data, mh_data, num_of_actions); 1935 1936 /* All DecapL3 cases require the same max arg size */ 1937 arg_obj = mlx5dr_arg_create_modify_header_arg(ctx, 1938 (__be64 *)mh_data, 1939 num_of_actions, 1940 log_bulk_sz, 1941 action->flags & MLX5DR_ACTION_FLAG_SHARED); 1942 if (!arg_obj) 1943 return rte_errno; 1944 1945 for (i = 0; i < num_of_hdrs; i++) { 1946 memset(mh_data, 0, MLX5DR_ACTION_REFORMAT_DATA_SIZE); 1947 mlx5dr_action_prepare_decap_l3_actions(hdrs[i].sz, mh_data, &num_of_actions); 1948 mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE; 1949 1950 pat_obj = mlx5dr_pat_get_pattern(ctx, (__be64 *)mh_data, mh_data_size); 1951 if (!pat_obj) { 1952 DR_LOG(ERR, "Failed to allocate pattern for DecapL3"); 1953 goto free_stc_and_pat; 1954 } 1955 1956 action[i].modify_header.max_num_of_actions = num_of_actions; 1957 action[i].modify_header.num_of_actions = num_of_actions; 1958 action[i].modify_header.num_of_patterns = num_of_hdrs; 1959 action[i].modify_header.arg_obj = arg_obj; 1960 action[i].modify_header.pat_obj = pat_obj; 1961 action[i].modify_header.require_reparse = 1962 mlx5dr_pat_require_reparse((__be64 *)mh_data, num_of_actions); 1963 1964 ret = mlx5dr_action_create_stcs(&action[i], NULL); 1965 if (ret) { 1966 mlx5dr_pat_put_pattern(ctx, pat_obj); 1967 goto free_stc_and_pat; 1968 } 1969 } 1970 1971 return 0; 1972 1973 1974 free_stc_and_pat: 1975 while (i--) { 1976 mlx5dr_action_destroy_stcs(&action[i]); 1977 mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj); 1978 } 1979 1980 mlx5dr_cmd_destroy_obj(arg_obj); 1981 return 0; 1982 } 1983 1984 static int 1985 mlx5dr_action_create_reformat_hws(struct mlx5dr_action *action, 1986 uint8_t num_of_hdrs, 1987 struct mlx5dr_action_reformat_header *hdrs, 1988 uint32_t bulk_size) 1989 { 1990 int ret; 1991 1992 switch (action->type) { 1993 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 1994 ret = mlx5dr_action_create_stcs(action, NULL); 1995 break; 1996 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 1997 ret = mlx5dr_action_handle_insert_with_ptr(action, num_of_hdrs, hdrs, bulk_size, 1998 MLX5DR_ACTION_STC_REPARSE_DEFAULT); 1999 break; 2000 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 2001 ret = mlx5dr_action_handle_l2_to_tunnel_l3(action, num_of_hdrs, hdrs, bulk_size); 2002 break; 2003 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 2004 ret = mlx5dr_action_handle_tunnel_l3_to_l2(action, num_of_hdrs, hdrs, bulk_size); 2005 break; 2006 default: 2007 DR_LOG(ERR, "Invalid HWS reformat action type"); 2008 rte_errno = EINVAL; 2009 return rte_errno; 2010 } 2011 2012 return ret; 2013 } 2014 2015 struct mlx5dr_action * 2016 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx, 2017 enum mlx5dr_action_type reformat_type, 2018 uint8_t num_of_hdrs, 2019 struct mlx5dr_action_reformat_header *hdrs, 2020 uint32_t log_bulk_size, 2021 uint32_t flags) 2022 { 2023 struct mlx5dr_action *action; 2024 int ret; 2025 2026 if (!num_of_hdrs) { 2027 DR_LOG(ERR, "Reformat num_of_hdrs cannot be zero"); 2028 rte_errno = EINVAL; 2029 return NULL; 2030 } 2031 2032 action = mlx5dr_action_create_generic_bulk(ctx, flags, reformat_type, num_of_hdrs); 2033 if (!action) 2034 return NULL; 2035 2036 if (mlx5dr_action_is_root_flags(flags)) { 2037 if (log_bulk_size) { 2038 DR_LOG(ERR, "Bulk reformat not supported over root"); 2039 rte_errno = ENOTSUP; 2040 goto free_action; 2041 } 2042 2043 ret = mlx5dr_action_create_reformat_root(action, 2044 hdrs ? hdrs->sz : 0, 2045 hdrs ? hdrs->data : NULL); 2046 if (ret) { 2047 DR_LOG(ERR, "Failed to create root reformat action"); 2048 goto free_action; 2049 } 2050 2051 return action; 2052 } 2053 2054 if (!mlx5dr_action_is_hws_flags(flags) || 2055 ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1))) { 2056 DR_LOG(ERR, "Reformat flags don't fit HWS (flags: 0x%x)", flags); 2057 rte_errno = EINVAL; 2058 goto free_action; 2059 } 2060 2061 ret = mlx5dr_action_create_reformat_hws(action, num_of_hdrs, hdrs, log_bulk_size); 2062 if (ret) { 2063 DR_LOG(ERR, "Failed to create HWS reformat action"); 2064 goto free_action; 2065 } 2066 2067 return action; 2068 2069 free_action: 2070 simple_free(action); 2071 return NULL; 2072 } 2073 2074 static int 2075 mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action, 2076 size_t actions_sz, 2077 __be64 *actions) 2078 { 2079 enum mlx5dv_flow_table_type ft_type = 0; 2080 struct ibv_context *local_ibv_ctx; 2081 int ret; 2082 2083 ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type); 2084 if (ret) 2085 return rte_errno; 2086 2087 local_ibv_ctx = mlx5dr_context_get_local_ibv(action->ctx); 2088 2089 action->flow_action = 2090 mlx5_glue->dv_create_flow_action_modify_header_root(local_ibv_ctx, 2091 actions_sz, 2092 (uint64_t *)actions, 2093 ft_type); 2094 if (!action->flow_action) { 2095 rte_errno = errno; 2096 return rte_errno; 2097 } 2098 2099 return 0; 2100 } 2101 2102 static int 2103 mlx5dr_action_create_modify_header_hws(struct mlx5dr_action *action, 2104 uint8_t num_of_patterns, 2105 struct mlx5dr_action_mh_pattern *pattern, 2106 uint32_t log_bulk_size, 2107 uint32_t reparse) 2108 { 2109 struct mlx5dr_devx_obj *pat_obj, *arg_obj = NULL; 2110 struct mlx5dr_context *ctx = action->ctx; 2111 uint16_t num_actions, max_mh_actions = 0; 2112 int i, ret; 2113 2114 /* Calculate maximum number of mh actions for shared arg allocation */ 2115 for (i = 0; i < num_of_patterns; i++) 2116 max_mh_actions = RTE_MAX(max_mh_actions, pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE); 2117 2118 /* Allocate single shared arg for all patterns based on the max size */ 2119 if (max_mh_actions > 1) { 2120 arg_obj = mlx5dr_arg_create_modify_header_arg(ctx, 2121 pattern->data, 2122 max_mh_actions, 2123 log_bulk_size, 2124 action->flags & 2125 MLX5DR_ACTION_FLAG_SHARED); 2126 if (!arg_obj) 2127 return rte_errno; 2128 } 2129 2130 for (i = 0; i < num_of_patterns; i++) { 2131 if (!mlx5dr_pat_verify_actions(pattern[i].data, pattern[i].sz)) { 2132 DR_LOG(ERR, "Fail to verify pattern modify actions"); 2133 rte_errno = EINVAL; 2134 goto free_stc_and_pat; 2135 } 2136 2137 num_actions = pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE; 2138 action[i].modify_header.num_of_patterns = num_of_patterns; 2139 action[i].modify_header.max_num_of_actions = max_mh_actions; 2140 action[i].modify_header.num_of_actions = num_actions; 2141 2142 if (likely(reparse == MLX5DR_ACTION_STC_REPARSE_DEFAULT)) 2143 action[i].modify_header.require_reparse = 2144 mlx5dr_pat_require_reparse(pattern[i].data, num_actions); 2145 else if (reparse == MLX5DR_ACTION_STC_REPARSE_ON) 2146 action[i].modify_header.require_reparse = true; 2147 2148 if (num_actions == 1) { 2149 pat_obj = NULL; 2150 /* Optimize single modify action to be used inline */ 2151 action[i].modify_header.single_action = pattern[i].data[0]; 2152 action[i].modify_header.single_action_type = 2153 MLX5_GET(set_action_in, pattern[i].data, action_type); 2154 } else { 2155 /* Multiple modify actions require a pattern */ 2156 pat_obj = mlx5dr_pat_get_pattern(ctx, pattern[i].data, pattern[i].sz); 2157 if (!pat_obj) { 2158 DR_LOG(ERR, "Failed to allocate pattern for modify header"); 2159 goto free_stc_and_pat; 2160 } 2161 2162 action[i].modify_header.arg_obj = arg_obj; 2163 action[i].modify_header.pat_obj = pat_obj; 2164 } 2165 /* Allocate STC for each action representing a header */ 2166 ret = mlx5dr_action_create_stcs(&action[i], NULL); 2167 if (ret) { 2168 if (pat_obj) 2169 mlx5dr_pat_put_pattern(ctx, pat_obj); 2170 goto free_stc_and_pat; 2171 } 2172 } 2173 2174 return 0; 2175 2176 free_stc_and_pat: 2177 while (i--) { 2178 mlx5dr_action_destroy_stcs(&action[i]); 2179 if (action[i].modify_header.pat_obj) 2180 mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj); 2181 } 2182 2183 if (arg_obj) 2184 mlx5dr_cmd_destroy_obj(arg_obj); 2185 2186 return rte_errno; 2187 } 2188 2189 struct mlx5dr_action * 2190 mlx5dr_action_create_modify_header_reparse(struct mlx5dr_context *ctx, 2191 uint8_t num_of_patterns, 2192 struct mlx5dr_action_mh_pattern *patterns, 2193 uint32_t log_bulk_size, 2194 uint32_t flags, uint32_t reparse) 2195 { 2196 struct mlx5dr_action *action; 2197 int ret; 2198 2199 if (!num_of_patterns) { 2200 DR_LOG(ERR, "Invalid number of patterns"); 2201 rte_errno = ENOTSUP; 2202 return NULL; 2203 } 2204 2205 action = mlx5dr_action_create_generic_bulk(ctx, flags, 2206 MLX5DR_ACTION_TYP_MODIFY_HDR, 2207 num_of_patterns); 2208 if (!action) 2209 return NULL; 2210 2211 if (mlx5dr_action_is_root_flags(flags)) { 2212 if (log_bulk_size) { 2213 DR_LOG(ERR, "Bulk modify-header not supported over root"); 2214 rte_errno = ENOTSUP; 2215 goto free_action; 2216 } 2217 2218 if (num_of_patterns != 1) { 2219 DR_LOG(ERR, "Only a single pattern supported over root"); 2220 rte_errno = ENOTSUP; 2221 goto free_action; 2222 } 2223 2224 ret = mlx5dr_action_create_modify_header_root(action, 2225 patterns->sz, 2226 patterns->data); 2227 if (ret) 2228 goto free_action; 2229 2230 return action; 2231 } 2232 2233 if ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_patterns > 1)) { 2234 DR_LOG(ERR, "Action cannot be shared with requested pattern or size"); 2235 rte_errno = EINVAL; 2236 goto free_action; 2237 } 2238 2239 ret = mlx5dr_action_create_modify_header_hws(action, 2240 num_of_patterns, 2241 patterns, 2242 log_bulk_size, 2243 reparse); 2244 if (ret) 2245 goto free_action; 2246 2247 return action; 2248 2249 free_action: 2250 simple_free(action); 2251 return NULL; 2252 } 2253 2254 struct mlx5dr_action * 2255 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx, 2256 uint8_t num_of_patterns, 2257 struct mlx5dr_action_mh_pattern *patterns, 2258 uint32_t log_bulk_size, 2259 uint32_t flags) 2260 { 2261 return mlx5dr_action_create_modify_header_reparse(ctx, num_of_patterns, patterns, 2262 log_bulk_size, flags, 2263 MLX5DR_ACTION_STC_REPARSE_DEFAULT); 2264 } 2265 static struct mlx5dr_devx_obj * 2266 mlx5dr_action_dest_array_process_reformat(struct mlx5dr_context *ctx, 2267 enum mlx5dr_action_type type, 2268 void *reformat_data, 2269 size_t reformat_data_sz) 2270 { 2271 struct mlx5dr_cmd_packet_reformat_create_attr pr_attr = {0}; 2272 struct mlx5dr_devx_obj *reformat_devx_obj; 2273 2274 if (!reformat_data || !reformat_data_sz) { 2275 DR_LOG(ERR, "Empty reformat action or data"); 2276 rte_errno = EINVAL; 2277 return NULL; 2278 } 2279 2280 switch (type) { 2281 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 2282 pr_attr.type = MLX5_PACKET_REFORMAT_CONTEXT_REFORMAT_TYPE_L2_TO_L2_TUNNEL; 2283 break; 2284 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 2285 pr_attr.type = MLX5_PACKET_REFORMAT_CONTEXT_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 2286 break; 2287 default: 2288 DR_LOG(ERR, "Invalid value for reformat type"); 2289 rte_errno = EINVAL; 2290 return NULL; 2291 } 2292 pr_attr.reformat_param_0 = 0; 2293 pr_attr.data_sz = reformat_data_sz; 2294 pr_attr.data = reformat_data; 2295 2296 reformat_devx_obj = mlx5dr_cmd_packet_reformat_create(ctx->ibv_ctx, &pr_attr); 2297 if (!reformat_devx_obj) 2298 return NULL; 2299 2300 return reformat_devx_obj; 2301 } 2302 2303 struct mlx5dr_action * 2304 mlx5dr_action_create_dest_array(struct mlx5dr_context *ctx, 2305 size_t num_dest, 2306 struct mlx5dr_action_dest_attr *dests, 2307 uint32_t flags) 2308 { 2309 struct mlx5dr_cmd_set_fte_dest *dest_list = NULL; 2310 struct mlx5dr_devx_obj *packet_reformat = NULL; 2311 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 2312 struct mlx5dr_cmd_set_fte_attr fte_attr = {0}; 2313 struct mlx5dr_cmd_forward_tbl *fw_island; 2314 enum mlx5dr_table_type table_type; 2315 struct mlx5dr_action *action; 2316 uint32_t i; 2317 int ret; 2318 2319 if (num_dest <= 1) { 2320 rte_errno = EINVAL; 2321 DR_LOG(ERR, "Action must have multiple dests"); 2322 return NULL; 2323 } 2324 2325 if (flags == (MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_SHARED)) { 2326 ft_attr.type = FS_FT_NIC_RX; 2327 ft_attr.level = MLX5_IFC_MULTI_PATH_FT_MAX_LEVEL - 1; 2328 table_type = MLX5DR_TABLE_TYPE_NIC_RX; 2329 } else if (flags == (MLX5DR_ACTION_FLAG_HWS_FDB | MLX5DR_ACTION_FLAG_SHARED)) { 2330 ft_attr.type = FS_FT_FDB; 2331 ft_attr.level = ctx->caps->fdb_ft.max_level - 1; 2332 table_type = MLX5DR_TABLE_TYPE_FDB; 2333 } else { 2334 DR_LOG(ERR, "Action flags not supported"); 2335 rte_errno = ENOTSUP; 2336 return NULL; 2337 } 2338 2339 if (mlx5dr_context_shared_gvmi_used(ctx)) { 2340 DR_LOG(ERR, "Cannot use this action in shared GVMI context"); 2341 rte_errno = ENOTSUP; 2342 return NULL; 2343 } 2344 2345 dest_list = simple_calloc(num_dest, sizeof(*dest_list)); 2346 if (!dest_list) { 2347 DR_LOG(ERR, "Failed to allocate memory for destinations"); 2348 rte_errno = ENOMEM; 2349 return NULL; 2350 } 2351 2352 for (i = 0; i < num_dest; i++) { 2353 enum mlx5dr_action_type *action_type = dests[i].action_type; 2354 2355 if (!mlx5dr_action_check_combo(dests[i].action_type, table_type)) { 2356 DR_LOG(ERR, "Invalid combination of actions"); 2357 rte_errno = EINVAL; 2358 goto free_dest_list; 2359 } 2360 2361 for (; *action_type != MLX5DR_ACTION_TYP_LAST; action_type++) { 2362 switch (*action_type) { 2363 case MLX5DR_ACTION_TYP_TBL: 2364 dest_list[i].destination_type = 2365 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 2366 dest_list[i].destination_id = dests[i].dest->devx_dest.devx_obj->id; 2367 fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 2368 fte_attr.ignore_flow_level = 1; 2369 break; 2370 case MLX5DR_ACTION_TYP_MISS: 2371 if (table_type != MLX5DR_TABLE_TYPE_FDB) { 2372 DR_LOG(ERR, "Miss action supported for FDB only"); 2373 rte_errno = ENOTSUP; 2374 goto free_dest_list; 2375 } 2376 dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; 2377 dest_list[i].destination_id = 2378 ctx->caps->eswitch_manager_vport_number; 2379 fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 2380 break; 2381 case MLX5DR_ACTION_TYP_VPORT: 2382 dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; 2383 dest_list[i].destination_id = dests[i].dest->vport.vport_num; 2384 fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 2385 if (ctx->caps->merged_eswitch) { 2386 dest_list[i].ext_flags |= 2387 MLX5DR_CMD_EXT_DEST_ESW_OWNER_VHCA_ID; 2388 dest_list[i].esw_owner_vhca_id = 2389 dests[i].dest->vport.esw_owner_vhca_id; 2390 } 2391 break; 2392 case MLX5DR_ACTION_TYP_TIR: 2393 dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_TIR; 2394 dest_list[i].destination_id = dests[i].dest->devx_dest.devx_obj->id; 2395 fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 2396 break; 2397 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 2398 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 2399 packet_reformat = mlx5dr_action_dest_array_process_reformat 2400 (ctx, 2401 *action_type, 2402 dests[i].reformat.reformat_data, 2403 dests[i].reformat.reformat_data_sz); 2404 if (!packet_reformat) 2405 goto free_dest_list; 2406 2407 dest_list[i].ext_flags |= MLX5DR_CMD_EXT_DEST_REFORMAT; 2408 dest_list[i].ext_reformat = packet_reformat; 2409 ft_attr.reformat_en = true; 2410 fte_attr.extended_dest = 1; 2411 break; 2412 default: 2413 DR_LOG(ERR, "Unsupported action in dest_array"); 2414 rte_errno = ENOTSUP; 2415 goto free_dest_list; 2416 } 2417 } 2418 } 2419 fte_attr.dests_num = num_dest; 2420 fte_attr.dests = dest_list; 2421 2422 fw_island = mlx5dr_cmd_forward_tbl_create(ctx->ibv_ctx, &ft_attr, &fte_attr); 2423 if (!fw_island) 2424 goto free_dest_list; 2425 2426 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DEST_ARRAY); 2427 if (!action) 2428 goto destroy_fw_island; 2429 2430 ret = mlx5dr_action_create_stcs(action, fw_island->ft); 2431 if (ret) 2432 goto free_action; 2433 2434 action->dest_array.fw_island = fw_island; 2435 action->dest_array.num_dest = num_dest; 2436 action->dest_array.dest_list = dest_list; 2437 2438 return action; 2439 2440 free_action: 2441 simple_free(action); 2442 destroy_fw_island: 2443 mlx5dr_cmd_forward_tbl_destroy(fw_island); 2444 free_dest_list: 2445 for (i = 0; i < num_dest; i++) { 2446 if (dest_list[i].ext_reformat) 2447 mlx5dr_cmd_destroy_obj(dest_list[i].ext_reformat); 2448 } 2449 simple_free(dest_list); 2450 return NULL; 2451 } 2452 2453 struct mlx5dr_action * 2454 mlx5dr_action_create_dest_root(struct mlx5dr_context *ctx, 2455 uint16_t priority, 2456 uint32_t flags) 2457 { 2458 struct mlx5dv_steering_anchor_attr attr = {0}; 2459 struct mlx5dv_steering_anchor *sa; 2460 struct mlx5dr_action *action; 2461 int ret; 2462 2463 if (mlx5dr_action_is_root_flags(flags)) { 2464 DR_LOG(ERR, "Action flags must be only non root (HWS)"); 2465 rte_errno = ENOTSUP; 2466 return NULL; 2467 } 2468 2469 if (mlx5dr_context_shared_gvmi_used(ctx)) { 2470 DR_LOG(ERR, "Cannot use this action in shared GVMI context"); 2471 rte_errno = ENOTSUP; 2472 return NULL; 2473 } 2474 2475 if (mlx5dr_action_conv_flags_to_ft_type(flags, &attr.ft_type)) 2476 return NULL; 2477 2478 attr.priority = priority; 2479 2480 sa = mlx5_glue->create_steering_anchor(ctx->ibv_ctx, &attr); 2481 if (!sa) { 2482 DR_LOG(ERR, "Creation of steering anchor failed"); 2483 return NULL; 2484 } 2485 2486 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DEST_ROOT); 2487 if (!action) 2488 goto free_steering_anchor; 2489 2490 action->root_tbl.sa = sa; 2491 2492 ret = mlx5dr_action_create_stcs(action, NULL); 2493 if (ret) 2494 goto free_action; 2495 2496 return action; 2497 2498 free_action: 2499 simple_free(action); 2500 free_steering_anchor: 2501 mlx5_glue->destroy_steering_anchor(sa); 2502 return NULL; 2503 } 2504 2505 static struct mlx5dr_action * 2506 mlx5dr_action_create_insert_header_reparse(struct mlx5dr_context *ctx, 2507 uint8_t num_of_hdrs, 2508 struct mlx5dr_action_insert_header *hdrs, 2509 uint32_t log_bulk_size, 2510 uint32_t flags, uint32_t reparse) 2511 { 2512 struct mlx5dr_action_reformat_header *reformat_hdrs; 2513 struct mlx5dr_action *action; 2514 int i, ret; 2515 2516 if (!num_of_hdrs) { 2517 DR_LOG(ERR, "Reformat num_of_hdrs cannot be zero"); 2518 rte_errno = EINVAL; 2519 return NULL; 2520 } 2521 2522 if (mlx5dr_action_is_root_flags(flags)) { 2523 DR_LOG(ERR, "Dynamic reformat action not supported over root"); 2524 rte_errno = ENOTSUP; 2525 return NULL; 2526 } 2527 2528 if (!mlx5dr_action_is_hws_flags(flags) || 2529 ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1))) { 2530 DR_LOG(ERR, "Reformat flags don't fit HWS (flags: 0x%x)", flags); 2531 rte_errno = EINVAL; 2532 return NULL; 2533 } 2534 2535 action = mlx5dr_action_create_generic_bulk(ctx, flags, 2536 MLX5DR_ACTION_TYP_INSERT_HEADER, 2537 num_of_hdrs); 2538 if (!action) 2539 return NULL; 2540 2541 reformat_hdrs = simple_calloc(num_of_hdrs, sizeof(*reformat_hdrs)); 2542 if (!reformat_hdrs) { 2543 DR_LOG(ERR, "Failed to allocate memory for reformat_hdrs"); 2544 rte_errno = ENOMEM; 2545 goto free_action; 2546 } 2547 2548 for (i = 0; i < num_of_hdrs; i++) { 2549 if (hdrs[i].offset % W_SIZE != 0) { 2550 DR_LOG(ERR, "Header offset should be in WORD granularity"); 2551 rte_errno = EINVAL; 2552 goto free_reformat_hdrs; 2553 } 2554 2555 action[i].reformat.anchor = hdrs[i].anchor; 2556 action[i].reformat.encap = hdrs[i].encap; 2557 action[i].reformat.push_esp = hdrs[i].push_esp; 2558 action[i].reformat.offset = hdrs[i].offset; 2559 reformat_hdrs[i].sz = hdrs[i].hdr.sz; 2560 reformat_hdrs[i].data = hdrs[i].hdr.data; 2561 } 2562 2563 ret = mlx5dr_action_handle_insert_with_ptr(action, num_of_hdrs, 2564 reformat_hdrs, log_bulk_size, 2565 reparse); 2566 if (ret) { 2567 DR_LOG(ERR, "Failed to create HWS reformat action"); 2568 goto free_reformat_hdrs; 2569 } 2570 2571 simple_free(reformat_hdrs); 2572 2573 return action; 2574 2575 free_reformat_hdrs: 2576 simple_free(reformat_hdrs); 2577 free_action: 2578 simple_free(action); 2579 return NULL; 2580 } 2581 2582 struct mlx5dr_action * 2583 mlx5dr_action_create_insert_header(struct mlx5dr_context *ctx, 2584 uint8_t num_of_hdrs, 2585 struct mlx5dr_action_insert_header *hdrs, 2586 uint32_t log_bulk_size, 2587 uint32_t flags) 2588 { 2589 return mlx5dr_action_create_insert_header_reparse(ctx, num_of_hdrs, hdrs, 2590 log_bulk_size, flags, 2591 MLX5DR_ACTION_STC_REPARSE_DEFAULT); 2592 } 2593 2594 struct mlx5dr_action * 2595 mlx5dr_action_create_remove_header(struct mlx5dr_context *ctx, 2596 struct mlx5dr_action_remove_header_attr *attr, 2597 uint32_t flags) 2598 { 2599 struct mlx5dr_action *action; 2600 2601 if (mlx5dr_action_is_root_flags(flags)) { 2602 DR_LOG(ERR, "Remove header action not supported over root"); 2603 rte_errno = ENOTSUP; 2604 return NULL; 2605 } 2606 2607 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_REMOVE_HEADER); 2608 if (!action) 2609 return NULL; 2610 2611 switch (attr->type) { 2612 case MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER: 2613 action->remove_header.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER; 2614 action->remove_header.start_anchor = attr->by_anchor.start_anchor; 2615 action->remove_header.end_anchor = attr->by_anchor.end_anchor; 2616 action->remove_header.decap = attr->by_anchor.decap; 2617 break; 2618 case MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_OFFSET: 2619 if (attr->by_offset.size % W_SIZE != 0) { 2620 DR_LOG(ERR, "Invalid size, HW supports header remove in WORD granularity"); 2621 rte_errno = EINVAL; 2622 goto free_action; 2623 } 2624 2625 if (attr->by_offset.size > MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE) { 2626 DR_LOG(ERR, "Header removal size limited to %u bytes", 2627 MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE); 2628 rte_errno = EINVAL; 2629 goto free_action; 2630 } 2631 2632 action->remove_header.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_OFFSET; 2633 action->remove_header.start_anchor = attr->by_offset.start_anchor; 2634 action->remove_header.num_of_words = attr->by_offset.size / W_SIZE; 2635 break; 2636 default: 2637 DR_LOG(ERR, "Unsupported remove header type %u", attr->type); 2638 rte_errno = ENOTSUP; 2639 goto free_action; 2640 } 2641 2642 if (mlx5dr_action_create_stcs(action, NULL)) 2643 goto free_action; 2644 2645 return action; 2646 2647 free_action: 2648 simple_free(action); 2649 return NULL; 2650 } 2651 2652 static void * 2653 mlx5dr_action_create_pop_ipv6_route_ext_mhdr1(struct mlx5dr_action *action) 2654 { 2655 struct mlx5dr_action_mh_pattern pattern; 2656 __be64 cmd[3] = {0}; 2657 uint16_t mod_id; 2658 2659 mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0); 2660 if (!mod_id) { 2661 rte_errno = EINVAL; 2662 return NULL; 2663 } 2664 2665 /* 2666 * Backup ipv6_route_ext.next_hdr to ipv6_route_ext.seg_left. 2667 * Next_hdr will be copied to ipv6.protocol after pop done. 2668 */ 2669 MLX5_SET(copy_action_in, &cmd[0], action_type, MLX5_MODIFICATION_TYPE_COPY); 2670 MLX5_SET(copy_action_in, &cmd[0], length, 8); 2671 MLX5_SET(copy_action_in, &cmd[0], src_offset, 24); 2672 MLX5_SET(copy_action_in, &cmd[0], src_field, mod_id); 2673 MLX5_SET(copy_action_in, &cmd[0], dst_field, mod_id); 2674 2675 /* Add nop between the continuous same modify field id */ 2676 MLX5_SET(copy_action_in, &cmd[1], action_type, MLX5_MODIFICATION_TYPE_NOP); 2677 2678 /* Clear next_hdr for right checksum */ 2679 MLX5_SET(set_action_in, &cmd[2], action_type, MLX5_MODIFICATION_TYPE_SET); 2680 MLX5_SET(set_action_in, &cmd[2], length, 8); 2681 MLX5_SET(set_action_in, &cmd[2], offset, 24); 2682 MLX5_SET(set_action_in, &cmd[2], field, mod_id); 2683 2684 pattern.data = cmd; 2685 pattern.sz = sizeof(cmd); 2686 2687 return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0, 2688 action->flags, 2689 MLX5DR_ACTION_STC_REPARSE_ON); 2690 } 2691 2692 static void * 2693 mlx5dr_action_create_pop_ipv6_route_ext_mhdr2(struct mlx5dr_action *action) 2694 { 2695 enum mlx5_modification_field field[MLX5_ST_SZ_DW(definer_hl_ipv6_addr)] = { 2696 MLX5_MODI_OUT_DIPV6_127_96, 2697 MLX5_MODI_OUT_DIPV6_95_64, 2698 MLX5_MODI_OUT_DIPV6_63_32, 2699 MLX5_MODI_OUT_DIPV6_31_0 2700 }; 2701 struct mlx5dr_action_mh_pattern pattern; 2702 __be64 cmd[5] = {0}; 2703 uint16_t mod_id; 2704 uint32_t i; 2705 2706 /* Copy ipv6_route_ext[first_segment].dst_addr by flex parser to ipv6.dst_addr */ 2707 for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) { 2708 mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, i + 1); 2709 if (!mod_id) { 2710 rte_errno = EINVAL; 2711 return NULL; 2712 } 2713 2714 MLX5_SET(copy_action_in, &cmd[i], action_type, MLX5_MODIFICATION_TYPE_COPY); 2715 MLX5_SET(copy_action_in, &cmd[i], dst_field, field[i]); 2716 MLX5_SET(copy_action_in, &cmd[i], src_field, mod_id); 2717 } 2718 2719 mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0); 2720 if (!mod_id) { 2721 rte_errno = EINVAL; 2722 return NULL; 2723 } 2724 2725 /* Restore next_hdr from seg_left for flex parser identifying */ 2726 MLX5_SET(copy_action_in, &cmd[4], action_type, MLX5_MODIFICATION_TYPE_COPY); 2727 MLX5_SET(copy_action_in, &cmd[4], length, 8); 2728 MLX5_SET(copy_action_in, &cmd[4], dst_offset, 24); 2729 MLX5_SET(copy_action_in, &cmd[4], src_field, mod_id); 2730 MLX5_SET(copy_action_in, &cmd[4], dst_field, mod_id); 2731 2732 pattern.data = cmd; 2733 pattern.sz = sizeof(cmd); 2734 2735 return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0, 2736 action->flags, 2737 MLX5DR_ACTION_STC_REPARSE_ON); 2738 } 2739 2740 static void * 2741 mlx5dr_action_create_pop_ipv6_route_ext_mhdr3(struct mlx5dr_action *action) 2742 { 2743 uint8_t cmd[MLX5DR_MODIFY_ACTION_SIZE] = {0}; 2744 struct mlx5dr_action_mh_pattern pattern; 2745 uint16_t mod_id; 2746 2747 mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0); 2748 if (!mod_id) { 2749 rte_errno = EINVAL; 2750 return NULL; 2751 } 2752 2753 /* Copy ipv6_route_ext.next_hdr to ipv6.protocol */ 2754 MLX5_SET(copy_action_in, cmd, action_type, MLX5_MODIFICATION_TYPE_COPY); 2755 MLX5_SET(copy_action_in, cmd, length, 8); 2756 MLX5_SET(copy_action_in, cmd, src_offset, 24); 2757 MLX5_SET(copy_action_in, cmd, src_field, mod_id); 2758 MLX5_SET(copy_action_in, cmd, dst_field, MLX5_MODI_OUT_IP_PROTOCOL); 2759 2760 pattern.data = (__be64 *)cmd; 2761 pattern.sz = sizeof(cmd); 2762 2763 return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0, 2764 action->flags, 2765 MLX5DR_ACTION_STC_REPARSE_OFF); 2766 } 2767 2768 static int 2769 mlx5dr_action_create_pop_ipv6_route_ext(struct mlx5dr_action *action) 2770 { 2771 uint8_t anchor_id = flow_hw_get_ipv6_route_ext_anchor_from_ctx(action->ctx); 2772 struct mlx5dr_action_remove_header_attr hdr_attr; 2773 uint32_t i; 2774 2775 if (!anchor_id) { 2776 rte_errno = EINVAL; 2777 return rte_errno; 2778 } 2779 2780 action->ipv6_route_ext.action[0] = 2781 mlx5dr_action_create_pop_ipv6_route_ext_mhdr1(action); 2782 action->ipv6_route_ext.action[1] = 2783 mlx5dr_action_create_pop_ipv6_route_ext_mhdr2(action); 2784 action->ipv6_route_ext.action[2] = 2785 mlx5dr_action_create_pop_ipv6_route_ext_mhdr3(action); 2786 2787 hdr_attr.by_anchor.decap = 1; 2788 hdr_attr.by_anchor.start_anchor = anchor_id; 2789 hdr_attr.by_anchor.end_anchor = MLX5_HEADER_ANCHOR_TCP_UDP; 2790 hdr_attr.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER; 2791 action->ipv6_route_ext.action[3] = 2792 mlx5dr_action_create_remove_header(action->ctx, &hdr_attr, action->flags); 2793 2794 if (!action->ipv6_route_ext.action[0] || !action->ipv6_route_ext.action[1] || 2795 !action->ipv6_route_ext.action[2] || !action->ipv6_route_ext.action[3]) { 2796 DR_LOG(ERR, "Failed to create ipv6_route_ext pop subaction"); 2797 goto err; 2798 } 2799 2800 return 0; 2801 2802 err: 2803 for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++) 2804 if (action->ipv6_route_ext.action[i]) 2805 mlx5dr_action_destroy(action->ipv6_route_ext.action[i]); 2806 2807 return rte_errno; 2808 } 2809 2810 static void * 2811 mlx5dr_action_create_push_ipv6_route_ext_mhdr1(struct mlx5dr_action *action) 2812 { 2813 uint8_t cmd[MLX5DR_MODIFY_ACTION_SIZE] = {0}; 2814 struct mlx5dr_action_mh_pattern pattern; 2815 2816 /* Set ipv6.protocol to IPPROTO_ROUTING */ 2817 MLX5_SET(set_action_in, cmd, action_type, MLX5_MODIFICATION_TYPE_SET); 2818 MLX5_SET(set_action_in, cmd, length, 8); 2819 MLX5_SET(set_action_in, cmd, field, MLX5_MODI_OUT_IP_PROTOCOL); 2820 MLX5_SET(set_action_in, cmd, data, IPPROTO_ROUTING); 2821 2822 pattern.data = (__be64 *)cmd; 2823 pattern.sz = sizeof(cmd); 2824 2825 return mlx5dr_action_create_modify_header(action->ctx, 1, &pattern, 0, 2826 action->flags | MLX5DR_ACTION_FLAG_SHARED); 2827 } 2828 2829 static void * 2830 mlx5dr_action_create_push_ipv6_route_ext_mhdr2(struct mlx5dr_action *action, 2831 uint32_t bulk_size, 2832 uint8_t *data) 2833 { 2834 enum mlx5_modification_field field[MLX5_ST_SZ_DW(definer_hl_ipv6_addr)] = { 2835 MLX5_MODI_OUT_DIPV6_127_96, 2836 MLX5_MODI_OUT_DIPV6_95_64, 2837 MLX5_MODI_OUT_DIPV6_63_32, 2838 MLX5_MODI_OUT_DIPV6_31_0 2839 }; 2840 struct mlx5dr_action_mh_pattern pattern; 2841 uint32_t *ipv6_dst_addr = NULL; 2842 uint8_t seg_left, next_hdr; 2843 __be64 cmd[5] = {0}; 2844 uint16_t mod_id; 2845 uint32_t i; 2846 2847 /* Fetch the last IPv6 address in the segment list */ 2848 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) { 2849 seg_left = MLX5_GET(header_ipv6_routing_ext, data, segments_left) - 1; 2850 ipv6_dst_addr = (uint32_t *)data + MLX5_ST_SZ_DW(header_ipv6_routing_ext) + 2851 seg_left * MLX5_ST_SZ_DW(definer_hl_ipv6_addr); 2852 } 2853 2854 /* Copy IPv6 destination address from ipv6_route_ext.last_segment */ 2855 for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) { 2856 MLX5_SET(set_action_in, &cmd[i], action_type, MLX5_MODIFICATION_TYPE_SET); 2857 MLX5_SET(set_action_in, &cmd[i], field, field[i]); 2858 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) 2859 MLX5_SET(set_action_in, &cmd[i], data, be32toh(*ipv6_dst_addr++)); 2860 } 2861 2862 mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0); 2863 if (!mod_id) { 2864 rte_errno = EINVAL; 2865 return NULL; 2866 } 2867 2868 /* Set ipv6_route_ext.next_hdr since initially pushed as 0 for right checksum */ 2869 MLX5_SET(set_action_in, &cmd[4], action_type, MLX5_MODIFICATION_TYPE_SET); 2870 MLX5_SET(set_action_in, &cmd[4], length, 8); 2871 MLX5_SET(set_action_in, &cmd[4], offset, 24); 2872 MLX5_SET(set_action_in, &cmd[4], field, mod_id); 2873 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) { 2874 next_hdr = MLX5_GET(header_ipv6_routing_ext, data, next_hdr); 2875 MLX5_SET(set_action_in, &cmd[4], data, next_hdr); 2876 } 2877 2878 pattern.data = cmd; 2879 pattern.sz = sizeof(cmd); 2880 2881 return mlx5dr_action_create_modify_header(action->ctx, 1, &pattern, 2882 bulk_size, action->flags); 2883 } 2884 2885 static int 2886 mlx5dr_action_create_push_ipv6_route_ext(struct mlx5dr_action *action, 2887 struct mlx5dr_action_reformat_header *hdr, 2888 uint32_t bulk_size) 2889 { 2890 struct mlx5dr_action_insert_header insert_hdr = { {0} }; 2891 uint8_t header[MLX5_PUSH_MAX_LEN]; 2892 uint32_t i; 2893 2894 if (!hdr || !hdr->sz || hdr->sz > MLX5_PUSH_MAX_LEN || 2895 ((action->flags & MLX5DR_ACTION_FLAG_SHARED) && !hdr->data)) { 2896 DR_LOG(ERR, "Invalid ipv6_route_ext header"); 2897 rte_errno = EINVAL; 2898 return rte_errno; 2899 } 2900 2901 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) { 2902 memcpy(header, hdr->data, hdr->sz); 2903 /* Clear ipv6_route_ext.next_hdr for right checksum */ 2904 MLX5_SET(header_ipv6_routing_ext, header, next_hdr, 0); 2905 } 2906 2907 insert_hdr.anchor = MLX5_HEADER_ANCHOR_TCP_UDP; 2908 insert_hdr.encap = 1; 2909 insert_hdr.hdr.sz = hdr->sz; 2910 insert_hdr.hdr.data = header; 2911 action->ipv6_route_ext.action[0] = 2912 mlx5dr_action_create_insert_header_reparse(action->ctx, 1, &insert_hdr, 2913 bulk_size, action->flags, 2914 MLX5DR_ACTION_STC_REPARSE_OFF); 2915 action->ipv6_route_ext.action[1] = 2916 mlx5dr_action_create_push_ipv6_route_ext_mhdr1(action); 2917 action->ipv6_route_ext.action[2] = 2918 mlx5dr_action_create_push_ipv6_route_ext_mhdr2(action, bulk_size, hdr->data); 2919 2920 if (!action->ipv6_route_ext.action[0] || 2921 !action->ipv6_route_ext.action[1] || 2922 !action->ipv6_route_ext.action[2]) { 2923 DR_LOG(ERR, "Failed to create ipv6_route_ext push subaction"); 2924 goto err; 2925 } 2926 2927 return 0; 2928 2929 err: 2930 for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++) 2931 if (action->ipv6_route_ext.action[i]) 2932 mlx5dr_action_destroy(action->ipv6_route_ext.action[i]); 2933 2934 return rte_errno; 2935 } 2936 2937 struct mlx5dr_action * 2938 mlx5dr_action_create_reformat_ipv6_ext(struct mlx5dr_context *ctx, 2939 enum mlx5dr_action_type action_type, 2940 struct mlx5dr_action_reformat_header *hdr, 2941 uint32_t log_bulk_size, 2942 uint32_t flags) 2943 { 2944 struct mlx5dr_action *action; 2945 int ret; 2946 2947 if (!mlx5dr_action_is_hws_flags(flags) || 2948 ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) { 2949 DR_LOG(ERR, "IPv6 extension flags don't fit HWS (flags: 0x%x)", flags); 2950 rte_errno = EINVAL; 2951 return NULL; 2952 } 2953 2954 action = mlx5dr_action_create_generic(ctx, flags, action_type); 2955 if (!action) { 2956 rte_errno = ENOMEM; 2957 return NULL; 2958 } 2959 2960 switch (action_type) { 2961 case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT: 2962 if (!(flags & MLX5DR_ACTION_FLAG_SHARED)) { 2963 DR_LOG(ERR, "Pop ipv6_route_ext must be shared"); 2964 rte_errno = EINVAL; 2965 goto free_action; 2966 } 2967 2968 ret = mlx5dr_action_create_pop_ipv6_route_ext(action); 2969 break; 2970 case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT: 2971 if (!mlx5dr_context_cap_dynamic_reparse(ctx)) { 2972 DR_LOG(ERR, "IPv6 routing extension push actions is not supported"); 2973 rte_errno = ENOTSUP; 2974 goto free_action; 2975 } 2976 2977 ret = mlx5dr_action_create_push_ipv6_route_ext(action, hdr, log_bulk_size); 2978 break; 2979 default: 2980 DR_LOG(ERR, "Unsupported action type %d\n", action_type); 2981 rte_errno = ENOTSUP; 2982 goto free_action; 2983 } 2984 2985 if (ret) { 2986 DR_LOG(ERR, "Failed to create IPv6 extension reformat action"); 2987 goto free_action; 2988 } 2989 2990 return action; 2991 2992 free_action: 2993 simple_free(action); 2994 return NULL; 2995 } 2996 2997 static bool 2998 mlx5dr_action_nat64_validate_param(struct mlx5dr_action_nat64_attr *attr, 2999 uint32_t flags) 3000 { 3001 if (mlx5dr_action_is_root_flags(flags)) { 3002 DR_LOG(ERR, "Nat64 action not supported for root"); 3003 rte_errno = ENOTSUP; 3004 return false; 3005 } 3006 3007 if (!(flags & MLX5DR_ACTION_FLAG_SHARED)) { 3008 DR_LOG(ERR, "Nat64 action must be with SHARED flag"); 3009 rte_errno = EINVAL; 3010 return false; 3011 } 3012 3013 if (attr->num_of_registers > MLX5DR_ACTION_NAT64_REG_MAX) { 3014 DR_LOG(ERR, "Nat64 action doesn't support more than %d registers", 3015 MLX5DR_ACTION_NAT64_REG_MAX); 3016 rte_errno = EINVAL; 3017 return false; 3018 } 3019 3020 if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR && 3021 attr->num_of_registers != MLX5DR_ACTION_NAT64_REG_MAX) { 3022 DR_LOG(ERR, "Nat64 backup addr requires %d registers", 3023 MLX5DR_ACTION_NAT64_REG_MAX); 3024 rte_errno = EINVAL; 3025 return false; 3026 } 3027 3028 if (!(attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6 || 3029 attr->flags & MLX5DR_ACTION_NAT64_V6_TO_V4)) { 3030 DR_LOG(ERR, "Nat64 backup addr requires one mode at least"); 3031 rte_errno = EINVAL; 3032 return false; 3033 } 3034 3035 return true; 3036 } 3037 3038 struct mlx5dr_action * 3039 mlx5dr_action_create_nat64(struct mlx5dr_context *ctx, 3040 struct mlx5dr_action_nat64_attr *attr, 3041 uint32_t flags) 3042 { 3043 struct mlx5dr_action *action; 3044 3045 if (!mlx5dr_action_nat64_validate_param(attr, flags)) 3046 return NULL; 3047 3048 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_NAT64); 3049 if (!action) 3050 return NULL; 3051 3052 action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY] = 3053 mlx5dr_action_create_nat64_copy_state(ctx, attr, flags); 3054 if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY]) { 3055 DR_LOG(ERR, "Nat64 failed creating copy state"); 3056 goto free_action; 3057 } 3058 3059 action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE] = 3060 mlx5dr_action_create_nat64_repalce_state(ctx, attr, flags); 3061 if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE]) { 3062 DR_LOG(ERR, "Nat64 failed creating replace state"); 3063 goto free_copy; 3064 } 3065 action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL] = 3066 mlx5dr_action_create_nat64_copy_proto_state(ctx, attr, flags); 3067 if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL]) { 3068 DR_LOG(ERR, "Nat64 failed creating copy protocol state"); 3069 goto free_replace; 3070 } 3071 3072 action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPYBACK] = 3073 mlx5dr_action_create_nat64_copy_back_state(ctx, attr, flags); 3074 if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPYBACK]) { 3075 DR_LOG(ERR, "Nat64 failed creating copyback state"); 3076 goto free_copy_proto; 3077 } 3078 3079 return action; 3080 3081 free_copy_proto: 3082 mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL]); 3083 free_replace: 3084 mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE]); 3085 free_copy: 3086 mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY]); 3087 free_action: 3088 simple_free(action); 3089 return NULL; 3090 } 3091 3092 struct mlx5dr_action * 3093 mlx5dr_action_create_jump_to_matcher(struct mlx5dr_context *ctx, 3094 struct mlx5dr_action_jump_to_matcher_attr *attr, 3095 uint32_t flags) 3096 { 3097 struct mlx5dr_matcher *matcher = attr->matcher; 3098 struct mlx5dr_matcher_attr *m_attr; 3099 struct mlx5dr_action *action; 3100 3101 if (attr->type != MLX5DR_ACTION_JUMP_TO_MATCHER_BY_INDEX) { 3102 DR_LOG(ERR, "Only jump to matcher by index is supported"); 3103 goto enotsup; 3104 } 3105 3106 if (mlx5dr_action_is_root_flags(flags)) { 3107 DR_LOG(ERR, "Action flags must be only non root (HWS)"); 3108 goto enotsup; 3109 } 3110 3111 if (mlx5dr_table_is_root(matcher->tbl)) { 3112 DR_LOG(ERR, "Root matcher cannot be set as destination"); 3113 goto enotsup; 3114 } 3115 3116 m_attr = &matcher->attr; 3117 3118 if (!(matcher->flags & MLX5DR_MATCHER_FLAGS_STE_ARRAY) && 3119 (m_attr->resizable || m_attr->table.sz_col_log || m_attr->table.sz_row_log)) { 3120 DR_LOG(ERR, "Only STE array or matcher of size 1 can be set as destination"); 3121 goto enotsup; 3122 } 3123 3124 action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_JUMP_TO_MATCHER); 3125 if (!action) 3126 return NULL; 3127 3128 action->jump_to_matcher.matcher = matcher; 3129 3130 if (mlx5dr_action_create_stcs(action, NULL)) { 3131 DR_LOG(ERR, "Failed to create action jump to matcher STC"); 3132 simple_free(action); 3133 return NULL; 3134 } 3135 3136 return action; 3137 3138 enotsup: 3139 rte_errno = ENOTSUP; 3140 return NULL; 3141 } 3142 3143 static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action) 3144 { 3145 struct mlx5dr_devx_obj *obj = NULL; 3146 uint32_t i; 3147 3148 switch (action->type) { 3149 case MLX5DR_ACTION_TYP_TIR: 3150 mlx5dr_action_destroy_stcs(action); 3151 if (mlx5dr_context_shared_gvmi_used(action->ctx)) 3152 mlx5dr_cmd_destroy_obj(action->alias.devx_obj); 3153 break; 3154 case MLX5DR_ACTION_TYP_MISS: 3155 case MLX5DR_ACTION_TYP_TAG: 3156 case MLX5DR_ACTION_TYP_DROP: 3157 case MLX5DR_ACTION_TYP_CTR: 3158 case MLX5DR_ACTION_TYP_TBL: 3159 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 3160 case MLX5DR_ACTION_TYP_ASO_METER: 3161 case MLX5DR_ACTION_TYP_ASO_CT: 3162 case MLX5DR_ACTION_TYP_PUSH_VLAN: 3163 case MLX5DR_ACTION_TYP_REMOVE_HEADER: 3164 case MLX5DR_ACTION_TYP_VPORT: 3165 case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER: 3166 mlx5dr_action_destroy_stcs(action); 3167 break; 3168 case MLX5DR_ACTION_TYP_DEST_ROOT: 3169 mlx5dr_action_destroy_stcs(action); 3170 mlx5_glue->destroy_steering_anchor(action->root_tbl.sa); 3171 break; 3172 case MLX5DR_ACTION_TYP_POP_VLAN: 3173 mlx5dr_action_destroy_stcs(action); 3174 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP); 3175 break; 3176 case MLX5DR_ACTION_TYP_DEST_ARRAY: 3177 mlx5dr_action_destroy_stcs(action); 3178 mlx5dr_cmd_forward_tbl_destroy(action->dest_array.fw_island); 3179 for (i = 0; i < action->dest_array.num_dest; i++) { 3180 if (action->dest_array.dest_list[i].ext_reformat) 3181 mlx5dr_cmd_destroy_obj 3182 (action->dest_array.dest_list[i].ext_reformat); 3183 } 3184 simple_free(action->dest_array.dest_list); 3185 break; 3186 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 3187 case MLX5DR_ACTION_TYP_MODIFY_HDR: 3188 for (i = 0; i < action->modify_header.num_of_patterns; i++) { 3189 mlx5dr_action_destroy_stcs(&action[i]); 3190 if (action[i].modify_header.num_of_actions > 1) { 3191 mlx5dr_pat_put_pattern(action[i].ctx, 3192 action[i].modify_header.pat_obj); 3193 /* Save shared arg object if was used to free */ 3194 if (action[i].modify_header.arg_obj) 3195 obj = action[i].modify_header.arg_obj; 3196 } 3197 } 3198 if (obj) 3199 mlx5dr_cmd_destroy_obj(obj); 3200 break; 3201 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 3202 mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3); 3203 for (i = 0; i < action->reformat.num_of_hdrs; i++) 3204 mlx5dr_action_destroy_stcs(&action[i]); 3205 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 3206 break; 3207 case MLX5DR_ACTION_TYP_INSERT_HEADER: 3208 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 3209 for (i = 0; i < action->reformat.num_of_hdrs; i++) 3210 mlx5dr_action_destroy_stcs(&action[i]); 3211 mlx5dr_cmd_destroy_obj(action->reformat.arg_obj); 3212 break; 3213 case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT: 3214 case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT: 3215 for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++) 3216 if (action->ipv6_route_ext.action[i]) 3217 mlx5dr_action_destroy(action->ipv6_route_ext.action[i]); 3218 break; 3219 case MLX5DR_ACTION_TYP_NAT64: 3220 for (i = 0; i < MLX5DR_ACTION_NAT64_STAGES; i++) 3221 mlx5dr_action_destroy(action->nat64.stages[i]); 3222 break; 3223 case MLX5DR_ACTION_TYP_LAST: 3224 break; 3225 default: 3226 DR_LOG(ERR, "Not supported action type: %d", action->type); 3227 assert(false); 3228 } 3229 } 3230 3231 static void mlx5dr_action_destroy_root(struct mlx5dr_action *action) 3232 { 3233 switch (action->type) { 3234 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 3235 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 3236 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 3237 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 3238 case MLX5DR_ACTION_TYP_MODIFY_HDR: 3239 ibv_destroy_flow_action(action->flow_action); 3240 break; 3241 } 3242 } 3243 3244 int mlx5dr_action_destroy(struct mlx5dr_action *action) 3245 { 3246 if (mlx5dr_action_is_root_flags(action->flags)) 3247 mlx5dr_action_destroy_root(action); 3248 else 3249 mlx5dr_action_destroy_hws(action); 3250 3251 simple_free(action); 3252 return 0; 3253 } 3254 3255 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */ 3256 int mlx5dr_action_get_default_stc(struct mlx5dr_context *ctx, 3257 uint8_t tbl_type) 3258 { 3259 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 3260 struct mlx5dr_action_default_stc *default_stc; 3261 int ret; 3262 3263 if (ctx->common_res[tbl_type].default_stc) { 3264 ctx->common_res[tbl_type].default_stc->refcount++; 3265 return 0; 3266 } 3267 3268 default_stc = simple_calloc(1, sizeof(*default_stc)); 3269 if (!default_stc) { 3270 DR_LOG(ERR, "Failed to allocate memory for default STCs"); 3271 rte_errno = ENOMEM; 3272 return rte_errno; 3273 } 3274 3275 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; 3276 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW0; 3277 stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 3278 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 3279 &default_stc->nop_ctr); 3280 if (ret) { 3281 DR_LOG(ERR, "Failed to allocate default counter STC"); 3282 goto free_default_stc; 3283 } 3284 3285 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5; 3286 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 3287 &default_stc->nop_dw5); 3288 if (ret) { 3289 DR_LOG(ERR, "Failed to allocate default NOP DW5 STC"); 3290 goto free_nop_ctr; 3291 } 3292 3293 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW6; 3294 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 3295 &default_stc->nop_dw6); 3296 if (ret) { 3297 DR_LOG(ERR, "Failed to allocate default NOP DW6 STC"); 3298 goto free_nop_dw5; 3299 } 3300 3301 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW7; 3302 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 3303 &default_stc->nop_dw7); 3304 if (ret) { 3305 DR_LOG(ERR, "Failed to allocate default NOP DW7 STC"); 3306 goto free_nop_dw6; 3307 } 3308 3309 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 3310 if (!mlx5dr_context_shared_gvmi_used(ctx)) { 3311 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; 3312 } else { 3313 /* On shared gvmi the default hit behavior is jump to alias end ft */ 3314 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; 3315 stc_attr.dest_table_id = ctx->gvmi_res[tbl_type].aliased_end_ft->id; 3316 } 3317 3318 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type, 3319 &default_stc->default_hit); 3320 if (ret) { 3321 DR_LOG(ERR, "Failed to allocate default allow STC"); 3322 goto free_nop_dw7; 3323 } 3324 3325 ctx->common_res[tbl_type].default_stc = default_stc; 3326 ctx->common_res[tbl_type].default_stc->refcount++; 3327 3328 return 0; 3329 3330 free_nop_dw7: 3331 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); 3332 free_nop_dw6: 3333 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); 3334 free_nop_dw5: 3335 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); 3336 free_nop_ctr: 3337 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); 3338 free_default_stc: 3339 simple_free(default_stc); 3340 return rte_errno; 3341 } 3342 3343 void mlx5dr_action_put_default_stc(struct mlx5dr_context *ctx, 3344 uint8_t tbl_type) 3345 { 3346 struct mlx5dr_action_default_stc *default_stc; 3347 3348 default_stc = ctx->common_res[tbl_type].default_stc; 3349 3350 default_stc = ctx->common_res[tbl_type].default_stc; 3351 if (--default_stc->refcount) 3352 return; 3353 3354 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit); 3355 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); 3356 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); 3357 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); 3358 mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); 3359 simple_free(default_stc); 3360 ctx->common_res[tbl_type].default_stc = NULL; 3361 } 3362 3363 static void mlx5dr_action_modify_write(struct mlx5dr_send_engine *queue, 3364 uint32_t arg_idx, 3365 uint8_t *arg_data, 3366 uint16_t num_of_actions) 3367 { 3368 mlx5dr_arg_write(queue, NULL, arg_idx, arg_data, 3369 num_of_actions * MLX5DR_MODIFY_ACTION_SIZE); 3370 } 3371 3372 void 3373 mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst, 3374 uint16_t num_of_actions) 3375 { 3376 uint8_t *e_src; 3377 int i; 3378 3379 /* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes 3380 * copy from end of src to the start of dst. 3381 * move to the end, 2 is the leftover from 14B or 18B 3382 */ 3383 if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN) 3384 e_src = src + MLX5DR_ACTION_HDR_LEN_L2; 3385 else 3386 e_src = src + MLX5DR_ACTION_HDR_LEN_L2_W_VLAN; 3387 3388 /* Move dst over the first remove action + zero data */ 3389 dst += MLX5DR_ACTION_DOUBLE_SIZE; 3390 /* Move dst over the first insert ctrl action */ 3391 dst += MLX5DR_ACTION_DOUBLE_SIZE / 2; 3392 /* Actions: 3393 * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. 3394 * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. 3395 * the loop is without the last insertion. 3396 */ 3397 for (i = 0; i < num_of_actions - 3; i++) { 3398 e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE; 3399 memcpy(dst, e_src, MLX5DR_ACTION_INLINE_DATA_SIZE); /* data */ 3400 dst += MLX5DR_ACTION_DOUBLE_SIZE; 3401 } 3402 /* Copy the last 2 bytes after a gap of 2 bytes which will be removed */ 3403 e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE / 2; 3404 dst += MLX5DR_ACTION_INLINE_DATA_SIZE / 2; 3405 memcpy(dst, e_src, 2); 3406 } 3407 3408 static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res, 3409 enum mlx5dr_context_shared_stc_type stc_type) 3410 { 3411 return common_res->shared_stc[stc_type]->remove_header.offset; 3412 } 3413 3414 static struct mlx5dr_actions_wqe_setter * 3415 mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter, 3416 uint8_t req_flags) 3417 { 3418 /* Use a new setter if requested flags are taken */ 3419 while (setter->flags & req_flags) 3420 setter++; 3421 3422 /* Use current setter in required flags are not used */ 3423 return setter; 3424 } 3425 3426 static void 3427 mlx5dr_action_apply_stc(struct mlx5dr_actions_apply_data *apply, 3428 enum mlx5dr_action_stc_idx stc_idx, 3429 uint8_t action_idx) 3430 { 3431 struct mlx5dr_action *action = apply->rule_action[action_idx].action; 3432 3433 apply->wqe_ctrl->stc_ix[stc_idx] = 3434 htobe32(action->stc[apply->tbl_type].offset); 3435 } 3436 3437 static void 3438 mlx5dr_action_setter_push_vlan(struct mlx5dr_actions_apply_data *apply, 3439 struct mlx5dr_actions_wqe_setter *setter) 3440 { 3441 struct mlx5dr_rule_action *rule_action; 3442 3443 rule_action = &apply->rule_action[setter->idx_double]; 3444 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 3445 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr; 3446 3447 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 3448 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3449 } 3450 3451 static void 3452 mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply, 3453 struct mlx5dr_actions_wqe_setter *setter) 3454 { 3455 struct mlx5dr_rule_action *rule_action; 3456 uint32_t stc_idx, arg_sz, arg_idx; 3457 struct mlx5dr_action *action; 3458 uint8_t *single_action; 3459 3460 rule_action = &apply->rule_action[setter->idx_double]; 3461 action = rule_action->action + rule_action->modify_header.pattern_idx; 3462 3463 stc_idx = htobe32(action->stc[apply->tbl_type].offset); 3464 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx; 3465 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3466 3467 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 3468 3469 if (action->modify_header.num_of_actions == 1) { 3470 if (action->modify_header.single_action_type == 3471 MLX5_MODIFICATION_TYPE_COPY || 3472 action->modify_header.single_action_type == 3473 MLX5_MODIFICATION_TYPE_ADD_FIELD) { 3474 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0; 3475 return; 3476 } 3477 3478 if (action->flags & MLX5DR_ACTION_FLAG_SHARED) 3479 single_action = (uint8_t *)&action->modify_header.single_action; 3480 else 3481 single_action = rule_action->modify_header.data; 3482 3483 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 3484 *(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data); 3485 } else { 3486 /* Argument offset multiple with number of args per these actions */ 3487 arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions); 3488 arg_idx = rule_action->modify_header.offset * arg_sz; 3489 3490 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 3491 3492 if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 3493 apply->require_dep = 1; 3494 mlx5dr_action_modify_write(apply->queue, 3495 action->modify_header.arg_obj->id + arg_idx, 3496 rule_action->modify_header.data, 3497 action->modify_header.num_of_actions); 3498 } 3499 } 3500 } 3501 3502 static void 3503 mlx5dr_action_setter_nat64(struct mlx5dr_actions_apply_data *apply, 3504 struct mlx5dr_actions_wqe_setter *setter) 3505 { 3506 struct mlx5dr_rule_action *rule_action; 3507 struct mlx5dr_action *cur_stage_action; 3508 struct mlx5dr_action *action; 3509 uint32_t stc_idx; 3510 3511 rule_action = &apply->rule_action[setter->idx_double]; 3512 action = rule_action->action; 3513 cur_stage_action = action->nat64.stages[setter->stage_idx]; 3514 3515 stc_idx = htobe32(cur_stage_action->stc[apply->tbl_type].offset); 3516 3517 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx; 3518 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3519 3520 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 3521 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0; 3522 } 3523 3524 static void 3525 mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply, 3526 struct mlx5dr_actions_wqe_setter *setter) 3527 { 3528 struct mlx5dr_rule_action *rule_action; 3529 uint32_t stc_idx, arg_idx, arg_sz; 3530 struct mlx5dr_action *action; 3531 3532 rule_action = &apply->rule_action[setter->idx_double]; 3533 action = rule_action->action + rule_action->reformat.hdr_idx; 3534 3535 /* Argument offset multiple on args required for header size */ 3536 arg_sz = mlx5dr_arg_data_size_to_arg_size(action->reformat.max_hdr_sz); 3537 arg_idx = rule_action->reformat.offset * arg_sz; 3538 3539 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 3540 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 3541 3542 stc_idx = htobe32(action->stc[apply->tbl_type].offset); 3543 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx; 3544 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3545 3546 if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 3547 apply->require_dep = 1; 3548 mlx5dr_arg_write(apply->queue, NULL, 3549 action->reformat.arg_obj->id + arg_idx, 3550 rule_action->reformat.data, 3551 action->reformat.header_size); 3552 } 3553 } 3554 3555 static void 3556 mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply, 3557 struct mlx5dr_actions_wqe_setter *setter) 3558 { 3559 struct mlx5dr_rule_action *rule_action; 3560 uint32_t stc_idx, arg_sz, arg_idx; 3561 struct mlx5dr_action *action; 3562 3563 rule_action = &apply->rule_action[setter->idx_double]; 3564 action = rule_action->action + rule_action->reformat.hdr_idx; 3565 3566 /* Argument offset multiple on args required for num of actions */ 3567 arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions); 3568 arg_idx = rule_action->reformat.offset * arg_sz; 3569 3570 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0; 3571 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx); 3572 3573 stc_idx = htobe32(action->stc[apply->tbl_type].offset); 3574 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx; 3575 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3576 3577 if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) { 3578 apply->require_dep = 1; 3579 mlx5dr_arg_decapl3_write(apply->queue, 3580 action->modify_header.arg_obj->id + arg_idx, 3581 rule_action->reformat.data, 3582 action->modify_header.num_of_actions); 3583 } 3584 } 3585 3586 static void 3587 mlx5dr_action_setter_aso(struct mlx5dr_actions_apply_data *apply, 3588 struct mlx5dr_actions_wqe_setter *setter) 3589 { 3590 struct mlx5dr_rule_action *rule_action; 3591 uint32_t exe_aso_ctrl; 3592 uint32_t offset; 3593 3594 rule_action = &apply->rule_action[setter->idx_double]; 3595 3596 switch (rule_action->action->type) { 3597 case MLX5DR_ACTION_TYP_ASO_METER: 3598 /* exe_aso_ctrl format: 3599 * [STC only and reserved bits 29b][init_color 2b][meter_id 1b] 3600 */ 3601 offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ; 3602 exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ; 3603 exe_aso_ctrl |= rule_action->aso_meter.init_color << 3604 MLX5DR_ACTION_METER_INIT_COLOR_OFFSET; 3605 break; 3606 case MLX5DR_ACTION_TYP_ASO_CT: 3607 /* exe_aso_ctrl CT format: 3608 * [STC only and reserved bits 31b][direction 1b] 3609 */ 3610 offset = rule_action->aso_ct.offset / MLX5_ASO_CT_NUM_PER_OBJ; 3611 exe_aso_ctrl = rule_action->aso_ct.direction; 3612 break; 3613 default: 3614 DR_LOG(ERR, "Unsupported ASO action type: %d", rule_action->action->type); 3615 rte_errno = ENOTSUP; 3616 return; 3617 } 3618 3619 /* aso_object_offset format: [24B] */ 3620 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = htobe32(offset); 3621 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(exe_aso_ctrl); 3622 3623 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double); 3624 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0; 3625 } 3626 3627 static void 3628 mlx5dr_action_setter_tag(struct mlx5dr_actions_apply_data *apply, 3629 struct mlx5dr_actions_wqe_setter *setter) 3630 { 3631 struct mlx5dr_rule_action *rule_action; 3632 3633 rule_action = &apply->rule_action[setter->idx_single]; 3634 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = htobe32(rule_action->tag.value); 3635 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single); 3636 } 3637 3638 static void 3639 mlx5dr_action_setter_ctrl_ctr(struct mlx5dr_actions_apply_data *apply, 3640 struct mlx5dr_actions_wqe_setter *setter) 3641 { 3642 struct mlx5dr_rule_action *rule_action; 3643 3644 rule_action = &apply->rule_action[setter->idx_ctr]; 3645 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW0] = htobe32(rule_action->counter.offset); 3646 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_CTRL, setter->idx_ctr); 3647 } 3648 3649 static void 3650 mlx5dr_action_setter_single(struct mlx5dr_actions_apply_data *apply, 3651 struct mlx5dr_actions_wqe_setter *setter) 3652 { 3653 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 3654 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single); 3655 } 3656 3657 static void 3658 mlx5dr_action_setter_single_double_pop(struct mlx5dr_actions_apply_data *apply, 3659 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 3660 { 3661 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 3662 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] = 3663 htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res, 3664 MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP)); 3665 } 3666 3667 static void 3668 mlx5dr_action_setter_hit(struct mlx5dr_actions_apply_data *apply, 3669 struct mlx5dr_actions_wqe_setter *setter) 3670 { 3671 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0; 3672 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit); 3673 } 3674 3675 static void 3676 mlx5dr_action_setter_default_hit(struct mlx5dr_actions_apply_data *apply, 3677 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 3678 { 3679 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0; 3680 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = 3681 htobe32(apply->common_res->default_stc->default_hit.offset); 3682 } 3683 3684 static void 3685 mlx5dr_action_setter_hit_matcher(struct mlx5dr_actions_apply_data *apply, 3686 struct mlx5dr_actions_wqe_setter *setter) 3687 { 3688 struct mlx5dr_rule_action *rule_action; 3689 3690 rule_action = &apply->rule_action[setter->idx_hit]; 3691 3692 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 3693 htobe32(rule_action->jump_to_matcher.offset << 6); 3694 mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit); 3695 } 3696 3697 static void 3698 mlx5dr_action_setter_hit_next_action(struct mlx5dr_actions_apply_data *apply, 3699 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 3700 { 3701 apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = htobe32(apply->next_direct_idx << 6); 3702 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = htobe32(apply->jump_to_action_stc); 3703 } 3704 3705 static void 3706 mlx5dr_action_setter_common_decap(struct mlx5dr_actions_apply_data *apply, 3707 __rte_unused struct mlx5dr_actions_wqe_setter *setter) 3708 { 3709 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 3710 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] = 3711 htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res, 3712 MLX5DR_CONTEXT_SHARED_STC_DECAP_L3)); 3713 } 3714 3715 static void 3716 mlx5dr_action_setter_ipv6_route_ext_gen_push_mhdr(uint8_t *data, void *mh_data) 3717 { 3718 uint8_t *action_ptr = mh_data; 3719 uint32_t *ipv6_dst_addr; 3720 uint8_t seg_left; 3721 uint32_t i; 3722 3723 /* Fetch the last IPv6 address in the segment list which is the next hop */ 3724 seg_left = MLX5_GET(header_ipv6_routing_ext, data, segments_left) - 1; 3725 ipv6_dst_addr = (uint32_t *)data + MLX5_ST_SZ_DW(header_ipv6_routing_ext) 3726 + seg_left * MLX5_ST_SZ_DW(definer_hl_ipv6_addr); 3727 3728 /* Load next hop IPv6 address in reverse order to ipv6.dst_address */ 3729 for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) { 3730 MLX5_SET(set_action_in, action_ptr, data, be32toh(*ipv6_dst_addr++)); 3731 action_ptr += MLX5DR_MODIFY_ACTION_SIZE; 3732 } 3733 3734 /* Set ipv6_route_ext.next_hdr per user input */ 3735 MLX5_SET(set_action_in, action_ptr, data, *data); 3736 } 3737 3738 static void 3739 mlx5dr_action_setter_ipv6_route_ext_mhdr(struct mlx5dr_actions_apply_data *apply, 3740 struct mlx5dr_actions_wqe_setter *setter) 3741 { 3742 struct mlx5dr_rule_action *rule_action = apply->rule_action; 3743 struct mlx5dr_actions_wqe_setter tmp_setter = {0}; 3744 struct mlx5dr_rule_action tmp_rule_action; 3745 __be64 cmd[MLX5_SRV6_SAMPLE_NUM] = {0}; 3746 struct mlx5dr_action *ipv6_ext_action; 3747 uint8_t *header; 3748 3749 header = rule_action[setter->idx_double].ipv6_ext.header; 3750 ipv6_ext_action = rule_action[setter->idx_double].action; 3751 tmp_rule_action.action = ipv6_ext_action->ipv6_route_ext.action[setter->extra_data]; 3752 3753 if (tmp_rule_action.action->flags & MLX5DR_ACTION_FLAG_SHARED) { 3754 tmp_rule_action.modify_header.offset = 0; 3755 tmp_rule_action.modify_header.pattern_idx = 0; 3756 tmp_rule_action.modify_header.data = NULL; 3757 } else { 3758 /* 3759 * Copy ipv6_dst from ipv6_route_ext.last_seg. 3760 * Set ipv6_route_ext.next_hdr. 3761 */ 3762 mlx5dr_action_setter_ipv6_route_ext_gen_push_mhdr(header, cmd); 3763 tmp_rule_action.modify_header.data = (uint8_t *)cmd; 3764 tmp_rule_action.modify_header.pattern_idx = 0; 3765 tmp_rule_action.modify_header.offset = 3766 rule_action[setter->idx_double].ipv6_ext.offset; 3767 } 3768 3769 apply->rule_action = &tmp_rule_action; 3770 3771 /* Reuse regular */ 3772 mlx5dr_action_setter_modify_header(apply, &tmp_setter); 3773 3774 /* Swap rule actions from backup */ 3775 apply->rule_action = rule_action; 3776 } 3777 3778 static void 3779 mlx5dr_action_setter_ipv6_route_ext_insert_ptr(struct mlx5dr_actions_apply_data *apply, 3780 struct mlx5dr_actions_wqe_setter *setter) 3781 { 3782 struct mlx5dr_rule_action *rule_action = apply->rule_action; 3783 struct mlx5dr_actions_wqe_setter tmp_setter = {0}; 3784 struct mlx5dr_rule_action tmp_rule_action; 3785 struct mlx5dr_action *ipv6_ext_action; 3786 uint8_t header[MLX5_PUSH_MAX_LEN]; 3787 3788 ipv6_ext_action = rule_action[setter->idx_double].action; 3789 tmp_rule_action.action = ipv6_ext_action->ipv6_route_ext.action[setter->extra_data]; 3790 3791 if (tmp_rule_action.action->flags & MLX5DR_ACTION_FLAG_SHARED) { 3792 tmp_rule_action.reformat.offset = 0; 3793 tmp_rule_action.reformat.hdr_idx = 0; 3794 tmp_rule_action.reformat.data = NULL; 3795 } else { 3796 memcpy(header, rule_action[setter->idx_double].ipv6_ext.header, 3797 tmp_rule_action.action->reformat.header_size); 3798 /* Clear ipv6_route_ext.next_hdr for right checksum */ 3799 MLX5_SET(header_ipv6_routing_ext, header, next_hdr, 0); 3800 tmp_rule_action.reformat.data = header; 3801 tmp_rule_action.reformat.hdr_idx = 0; 3802 tmp_rule_action.reformat.offset = 3803 rule_action[setter->idx_double].ipv6_ext.offset; 3804 } 3805 3806 apply->rule_action = &tmp_rule_action; 3807 3808 /* Reuse regular */ 3809 mlx5dr_action_setter_insert_ptr(apply, &tmp_setter); 3810 3811 /* Swap rule actions from backup */ 3812 apply->rule_action = rule_action; 3813 } 3814 3815 static void 3816 mlx5dr_action_setter_ipv6_route_ext_pop(struct mlx5dr_actions_apply_data *apply, 3817 struct mlx5dr_actions_wqe_setter *setter) 3818 { 3819 struct mlx5dr_rule_action *rule_action = &apply->rule_action[setter->idx_single]; 3820 uint8_t idx = MLX5DR_ACTION_IPV6_EXT_MAX_SA - 1; 3821 struct mlx5dr_action *action; 3822 3823 /* Pop the ipv6_route_ext as set_single logic */ 3824 action = rule_action->action->ipv6_route_ext.action[idx]; 3825 apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0; 3826 apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] = 3827 htobe32(action->stc[apply->tbl_type].offset); 3828 } 3829 3830 int mlx5dr_action_template_process(struct mlx5dr_action_template *at) 3831 { 3832 struct mlx5dr_actions_wqe_setter *start_setter = at->setters + 1; 3833 enum mlx5dr_action_type *action_type = at->action_type_arr; 3834 struct mlx5dr_actions_wqe_setter *setter = at->setters; 3835 struct mlx5dr_actions_wqe_setter *pop_setter = NULL; 3836 struct mlx5dr_actions_wqe_setter *last_setter; 3837 int i, j; 3838 3839 /* Note: Given action combination must be valid */ 3840 3841 /* Check if action were already processed */ 3842 if (at->num_of_action_stes) 3843 return 0; 3844 3845 for (i = 0; i < MLX5DR_ACTION_MAX_STE; i++) 3846 setter[i].set_hit = &mlx5dr_action_setter_hit_next_action; 3847 3848 /* The same action template setters can be used with jumbo or match 3849 * STE, to support both cases we reseve the first setter for cases 3850 * with jumbo STE to allow jump to the first action STE. 3851 * This extra setter can be reduced in some cases on rule creation. 3852 */ 3853 setter = start_setter; 3854 last_setter = start_setter; 3855 3856 for (i = 0; i < at->num_actions; i++) { 3857 switch (action_type[i]) { 3858 case MLX5DR_ACTION_TYP_DROP: 3859 case MLX5DR_ACTION_TYP_TIR: 3860 case MLX5DR_ACTION_TYP_TBL: 3861 case MLX5DR_ACTION_TYP_DEST_ROOT: 3862 case MLX5DR_ACTION_TYP_DEST_ARRAY: 3863 case MLX5DR_ACTION_TYP_VPORT: 3864 case MLX5DR_ACTION_TYP_MISS: 3865 /* Hit action */ 3866 last_setter->flags |= ASF_HIT; 3867 last_setter->set_hit = &mlx5dr_action_setter_hit; 3868 last_setter->idx_hit = i; 3869 break; 3870 3871 case MLX5DR_ACTION_TYP_POP_VLAN: 3872 /* Single remove header to header */ 3873 if (pop_setter) { 3874 /* We have 2 pops, use the shared */ 3875 pop_setter->set_single = &mlx5dr_action_setter_single_double_pop; 3876 break; 3877 } 3878 setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY | ASF_INSERT); 3879 setter->flags |= ASF_SINGLE1 | ASF_REMOVE; 3880 setter->set_single = &mlx5dr_action_setter_single; 3881 setter->idx_single = i; 3882 pop_setter = setter; 3883 break; 3884 3885 case MLX5DR_ACTION_TYP_PUSH_VLAN: 3886 /* Double insert inline */ 3887 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 3888 setter->flags |= ASF_DOUBLE | ASF_INSERT; 3889 setter->set_double = &mlx5dr_action_setter_push_vlan; 3890 setter->idx_double = i; 3891 break; 3892 3893 case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT: 3894 /* 3895 * Backup ipv6_route_ext.next_hdr to ipv6_route_ext.seg_left. 3896 * Set ipv6_route_ext.next_hdr to 0 for checksum bug. 3897 */ 3898 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 3899 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3900 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr; 3901 setter->idx_double = i; 3902 setter->extra_data = 0; 3903 setter++; 3904 3905 /* 3906 * Restore ipv6_route_ext.next_hdr from ipv6_route_ext.seg_left. 3907 * Load the final destination address from flex parser sample 1->4. 3908 */ 3909 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3910 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr; 3911 setter->idx_double = i; 3912 setter->extra_data = 1; 3913 setter++; 3914 3915 /* Set the ipv6.protocol per ipv6_route_ext.next_hdr */ 3916 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3917 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr; 3918 setter->idx_double = i; 3919 setter->extra_data = 2; 3920 /* Pop ipv6_route_ext */ 3921 setter->flags |= ASF_SINGLE1 | ASF_REMOVE; 3922 setter->set_single = &mlx5dr_action_setter_ipv6_route_ext_pop; 3923 setter->idx_single = i; 3924 at->need_dep_write = true; 3925 break; 3926 3927 case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT: 3928 /* Insert ipv6_route_ext with next_hdr as 0 due to checksum bug */ 3929 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 3930 setter->flags |= ASF_DOUBLE | ASF_INSERT; 3931 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_insert_ptr; 3932 setter->idx_double = i; 3933 setter->extra_data = 0; 3934 setter++; 3935 3936 /* Set ipv6.protocol as IPPROTO_ROUTING: 0x2b */ 3937 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3938 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr; 3939 setter->idx_double = i; 3940 setter->extra_data = 1; 3941 setter++; 3942 3943 /* 3944 * Load the right ipv6_route_ext.next_hdr per user input buffer. 3945 * Load the next dest_addr from the ipv6_route_ext.seg_list[last]. 3946 */ 3947 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3948 setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr; 3949 setter->idx_double = i; 3950 setter->extra_data = 2; 3951 at->need_dep_write = true; 3952 break; 3953 3954 case MLX5DR_ACTION_TYP_MODIFY_HDR: 3955 /* Double modify header list */ 3956 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 3957 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 3958 setter->set_double = &mlx5dr_action_setter_modify_header; 3959 setter->idx_double = i; 3960 at->need_dep_write = true; 3961 break; 3962 3963 case MLX5DR_ACTION_TYP_ASO_METER: 3964 case MLX5DR_ACTION_TYP_ASO_CT: 3965 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE); 3966 setter->flags |= ASF_DOUBLE; 3967 setter->set_double = &mlx5dr_action_setter_aso; 3968 setter->idx_double = i; 3969 break; 3970 3971 case MLX5DR_ACTION_TYP_REMOVE_HEADER: 3972 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: 3973 /* Single remove header to header */ 3974 setter = mlx5dr_action_setter_find_first(last_setter, 3975 ASF_SINGLE1 | ASF_MODIFY | ASF_INSERT); 3976 setter->flags |= ASF_SINGLE1 | ASF_REMOVE; 3977 setter->set_single = &mlx5dr_action_setter_single; 3978 setter->idx_single = i; 3979 break; 3980 3981 case MLX5DR_ACTION_TYP_INSERT_HEADER: 3982 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: 3983 /* Double insert header with pointer */ 3984 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 3985 setter->flags |= ASF_DOUBLE | ASF_INSERT; 3986 setter->set_double = &mlx5dr_action_setter_insert_ptr; 3987 setter->idx_double = i; 3988 at->need_dep_write = true; 3989 break; 3990 3991 case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: 3992 /* Single remove + Double insert header with pointer */ 3993 setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_DOUBLE); 3994 setter->flags |= ASF_SINGLE1 | ASF_DOUBLE; 3995 setter->set_double = &mlx5dr_action_setter_insert_ptr; 3996 setter->idx_double = i; 3997 setter->set_single = &mlx5dr_action_setter_common_decap; 3998 setter->idx_single = i; 3999 at->need_dep_write = true; 4000 break; 4001 4002 case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: 4003 /* Double modify header list with remove and push inline */ 4004 setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); 4005 setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_INSERT; 4006 setter->set_double = &mlx5dr_action_setter_tnl_l3_to_l2; 4007 setter->idx_double = i; 4008 at->need_dep_write = true; 4009 break; 4010 4011 case MLX5DR_ACTION_TYP_TAG: 4012 /* Single TAG action, search for any room from the start */ 4013 setter = mlx5dr_action_setter_find_first(start_setter, ASF_SINGLE1); 4014 setter->flags |= ASF_SINGLE1; 4015 setter->set_single = &mlx5dr_action_setter_tag; 4016 setter->idx_single = i; 4017 break; 4018 4019 case MLX5DR_ACTION_TYP_CTR: 4020 /* Control counter action 4021 * TODO: Current counter executed first. Support is needed 4022 * for single ation counter action which is done last. 4023 * Example: Decap + CTR 4024 */ 4025 setter = mlx5dr_action_setter_find_first(start_setter, ASF_CTR); 4026 setter->flags |= ASF_CTR; 4027 setter->set_ctr = &mlx5dr_action_setter_ctrl_ctr; 4028 setter->idx_ctr = i; 4029 break; 4030 4031 case MLX5DR_ACTION_TYP_NAT64: 4032 /* NAT64 requires 3 setters, each of them does specific modify header */ 4033 for (j = 0; j < MLX5DR_ACTION_NAT64_STAGES; j++) { 4034 setter = mlx5dr_action_setter_find_first(last_setter, 4035 ASF_DOUBLE | ASF_REMOVE); 4036 setter->flags |= ASF_DOUBLE | ASF_MODIFY; 4037 setter->set_double = &mlx5dr_action_setter_nat64; 4038 setter->idx_double = i; 4039 /* The stage indicates which modify-header to push */ 4040 setter->stage_idx = j; 4041 } 4042 break; 4043 4044 case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER: 4045 last_setter->flags |= ASF_HIT; 4046 last_setter->set_hit = &mlx5dr_action_setter_hit_matcher; 4047 last_setter->idx_hit = i; 4048 break; 4049 4050 default: 4051 DR_LOG(ERR, "Unsupported action type: %d", action_type[i]); 4052 rte_errno = ENOTSUP; 4053 assert(false); 4054 return rte_errno; 4055 } 4056 4057 last_setter = RTE_MAX(setter, last_setter); 4058 } 4059 4060 /* Set default hit on the last STE if no hit action provided */ 4061 if (!(last_setter->flags & ASF_HIT)) 4062 last_setter->set_hit = &mlx5dr_action_setter_default_hit; 4063 4064 at->num_of_action_stes = last_setter - start_setter + 1; 4065 4066 /* Check if action template doesn't require any action DWs */ 4067 at->only_term = (at->num_of_action_stes == 1) && 4068 !(last_setter->flags & ~(ASF_CTR | ASF_HIT)); 4069 4070 return 0; 4071 } 4072 4073 struct mlx5dr_action_template * 4074 mlx5dr_action_template_create(const enum mlx5dr_action_type action_type[], 4075 uint32_t flags) 4076 { 4077 struct mlx5dr_action_template *at; 4078 uint8_t num_actions = 0; 4079 int i; 4080 4081 if (flags > MLX5DR_ACTION_TEMPLATE_FLAG_RELAXED_ORDER) { 4082 DR_LOG(ERR, "Unsupported action template flag provided"); 4083 rte_errno = EINVAL; 4084 return NULL; 4085 } 4086 4087 at = simple_calloc(1, sizeof(*at)); 4088 if (!at) { 4089 DR_LOG(ERR, "Failed to allocate action template"); 4090 rte_errno = ENOMEM; 4091 return NULL; 4092 } 4093 4094 at->flags = flags; 4095 4096 while (action_type[num_actions++] != MLX5DR_ACTION_TYP_LAST) 4097 ; 4098 4099 at->num_actions = num_actions - 1; 4100 at->action_type_arr = simple_calloc(num_actions, sizeof(*action_type)); 4101 if (!at->action_type_arr) { 4102 DR_LOG(ERR, "Failed to allocate action type array"); 4103 rte_errno = ENOMEM; 4104 goto free_at; 4105 } 4106 4107 for (i = 0; i < num_actions; i++) 4108 at->action_type_arr[i] = action_type[i]; 4109 4110 return at; 4111 4112 free_at: 4113 simple_free(at); 4114 return NULL; 4115 } 4116 4117 int mlx5dr_action_template_destroy(struct mlx5dr_action_template *at) 4118 { 4119 simple_free(at->action_type_arr); 4120 simple_free(at); 4121 return 0; 4122 } 4123