1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2019 Mellanox Technologies. */ 3 4 #include "dr_types.h" 5 #include "dr_ste.h" 6 7 enum dr_action_domain { 8 DR_ACTION_DOMAIN_NIC_INGRESS, 9 DR_ACTION_DOMAIN_NIC_EGRESS, 10 DR_ACTION_DOMAIN_FDB_INGRESS, 11 DR_ACTION_DOMAIN_FDB_EGRESS, 12 DR_ACTION_DOMAIN_MAX, 13 }; 14 15 enum dr_action_valid_state { 16 DR_ACTION_STATE_ERR, 17 DR_ACTION_STATE_NO_ACTION, 18 DR_ACTION_STATE_ENCAP, 19 DR_ACTION_STATE_DECAP, 20 DR_ACTION_STATE_MODIFY_HDR, 21 DR_ACTION_STATE_MODIFY_VLAN, 22 DR_ACTION_STATE_NON_TERM, 23 DR_ACTION_STATE_TERM, 24 DR_ACTION_STATE_MAX, 25 }; 26 27 static const enum dr_action_valid_state 28 next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX] = { 29 [DR_ACTION_DOMAIN_NIC_INGRESS] = { 30 [DR_ACTION_STATE_NO_ACTION] = { 31 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 32 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 33 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 34 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 35 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, 36 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 37 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, 38 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, 39 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 40 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 41 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 42 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 43 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 44 }, 45 [DR_ACTION_STATE_DECAP] = { 46 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 47 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 48 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 49 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 50 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_DECAP, 51 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, 52 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 53 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 54 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 55 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 56 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 57 }, 58 [DR_ACTION_STATE_ENCAP] = { 59 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 60 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 61 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 62 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 63 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_ENCAP, 64 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, 65 }, 66 [DR_ACTION_STATE_MODIFY_HDR] = { 67 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 68 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 69 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 70 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 71 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_HDR, 72 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, 73 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 74 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 75 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 76 }, 77 [DR_ACTION_STATE_MODIFY_VLAN] = { 78 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 79 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 80 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 81 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 82 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_VLAN, 83 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN, 84 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 85 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 86 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 87 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 88 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 89 }, 90 [DR_ACTION_STATE_NON_TERM] = { 91 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 92 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 93 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 94 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 95 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, 96 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 97 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, 98 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, 99 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 100 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 101 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 102 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 103 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 104 }, 105 [DR_ACTION_STATE_TERM] = { 106 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, 107 }, 108 }, 109 [DR_ACTION_DOMAIN_NIC_EGRESS] = { 110 [DR_ACTION_STATE_NO_ACTION] = { 111 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 112 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 113 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 114 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 115 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 116 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 117 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 118 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 119 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 120 }, 121 [DR_ACTION_STATE_ENCAP] = { 122 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 123 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 124 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 125 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, 126 }, 127 [DR_ACTION_STATE_MODIFY_HDR] = { 128 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 129 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 130 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 131 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, 132 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 133 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 134 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 135 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 136 }, 137 [DR_ACTION_STATE_MODIFY_VLAN] = { 138 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 139 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 140 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 141 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN, 142 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 143 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 144 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 145 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 146 }, 147 [DR_ACTION_STATE_NON_TERM] = { 148 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 149 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 150 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 151 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 152 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 153 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 154 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 155 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 156 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 157 }, 158 [DR_ACTION_STATE_TERM] = { 159 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, 160 }, 161 }, 162 [DR_ACTION_DOMAIN_FDB_INGRESS] = { 163 [DR_ACTION_STATE_NO_ACTION] = { 164 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 165 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 166 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 167 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 168 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, 169 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, 170 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 171 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 172 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 173 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 174 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 175 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 176 }, 177 [DR_ACTION_STATE_DECAP] = { 178 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 179 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 180 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, 181 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 182 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 183 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 184 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 185 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 186 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 187 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 188 }, 189 [DR_ACTION_STATE_ENCAP] = { 190 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 191 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, 192 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 193 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 194 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 195 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, 196 }, 197 [DR_ACTION_STATE_MODIFY_HDR] = { 198 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 199 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 200 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 201 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, 202 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 203 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 204 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 205 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 206 }, 207 [DR_ACTION_STATE_MODIFY_VLAN] = { 208 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 209 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 210 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 211 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 212 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN, 213 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 214 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 215 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 216 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 217 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 218 }, 219 [DR_ACTION_STATE_NON_TERM] = { 220 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 221 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 222 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 223 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 224 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, 225 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, 226 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 227 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 228 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 229 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 230 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 231 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 232 }, 233 [DR_ACTION_STATE_TERM] = { 234 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, 235 }, 236 }, 237 [DR_ACTION_DOMAIN_FDB_EGRESS] = { 238 [DR_ACTION_STATE_NO_ACTION] = { 239 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 240 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 241 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 242 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 243 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 244 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 245 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 246 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 247 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 248 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 249 }, 250 [DR_ACTION_STATE_ENCAP] = { 251 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 252 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 253 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, 254 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 255 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 256 }, 257 [DR_ACTION_STATE_MODIFY_HDR] = { 258 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 259 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 260 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 261 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, 262 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 263 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 264 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 265 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 266 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 267 }, 268 [DR_ACTION_STATE_MODIFY_VLAN] = { 269 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 270 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 271 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 272 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 273 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN, 274 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 275 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 276 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 277 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 278 }, 279 [DR_ACTION_STATE_NON_TERM] = { 280 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, 281 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, 282 [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, 283 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, 284 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, 285 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, 286 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, 287 [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, 288 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN, 289 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, 290 }, 291 [DR_ACTION_STATE_TERM] = { 292 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, 293 }, 294 }, 295 }; 296 297 static int 298 dr_action_reformat_to_action_type(enum mlx5dr_action_reformat_type reformat_type, 299 enum mlx5dr_action_type *action_type) 300 { 301 switch (reformat_type) { 302 case DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2: 303 *action_type = DR_ACTION_TYP_TNL_L2_TO_L2; 304 break; 305 case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2: 306 *action_type = DR_ACTION_TYP_L2_TO_TNL_L2; 307 break; 308 case DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2: 309 *action_type = DR_ACTION_TYP_TNL_L3_TO_L2; 310 break; 311 case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3: 312 *action_type = DR_ACTION_TYP_L2_TO_TNL_L3; 313 break; 314 case DR_ACTION_REFORMAT_TYP_INSERT_HDR: 315 *action_type = DR_ACTION_TYP_INSERT_HDR; 316 break; 317 default: 318 return -EINVAL; 319 } 320 321 return 0; 322 } 323 324 /* Apply the actions on the rule STE array starting from the last_ste. 325 * Actions might require more than one STE, new_num_stes will return 326 * the new size of the STEs array, rule with actions. 327 */ 328 static void dr_actions_apply(struct mlx5dr_domain *dmn, 329 enum mlx5dr_ste_entry_type ste_type, 330 u8 *action_type_set, 331 u8 *last_ste, 332 struct mlx5dr_ste_actions_attr *attr, 333 u32 *new_num_stes) 334 { 335 struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; 336 u32 added_stes = 0; 337 338 if (ste_type == MLX5DR_STE_TYPE_RX) 339 mlx5dr_ste_set_actions_rx(ste_ctx, dmn, action_type_set, 340 last_ste, attr, &added_stes); 341 else 342 mlx5dr_ste_set_actions_tx(ste_ctx, dmn, action_type_set, 343 last_ste, attr, &added_stes); 344 345 *new_num_stes += added_stes; 346 } 347 348 static enum dr_action_domain 349 dr_action_get_action_domain(enum mlx5dr_domain_type domain, 350 enum mlx5dr_ste_entry_type ste_type) 351 { 352 switch (domain) { 353 case MLX5DR_DOMAIN_TYPE_NIC_RX: 354 return DR_ACTION_DOMAIN_NIC_INGRESS; 355 case MLX5DR_DOMAIN_TYPE_NIC_TX: 356 return DR_ACTION_DOMAIN_NIC_EGRESS; 357 case MLX5DR_DOMAIN_TYPE_FDB: 358 if (ste_type == MLX5DR_STE_TYPE_RX) 359 return DR_ACTION_DOMAIN_FDB_INGRESS; 360 return DR_ACTION_DOMAIN_FDB_EGRESS; 361 default: 362 WARN_ON(true); 363 return DR_ACTION_DOMAIN_MAX; 364 } 365 } 366 367 static 368 int dr_action_validate_and_get_next_state(enum dr_action_domain action_domain, 369 u32 action_type, 370 u32 *state) 371 { 372 u32 cur_state = *state; 373 374 /* Check action state machine is valid */ 375 *state = next_action_state[action_domain][cur_state][action_type]; 376 377 if (*state == DR_ACTION_STATE_ERR) 378 return -EOPNOTSUPP; 379 380 return 0; 381 } 382 383 static int dr_action_handle_cs_recalc(struct mlx5dr_domain *dmn, 384 struct mlx5dr_action *dest_action, 385 u64 *final_icm_addr) 386 { 387 int ret; 388 389 switch (dest_action->action_type) { 390 case DR_ACTION_TYP_FT: 391 /* Allow destination flow table only if table is a terminating 392 * table, since there is an *assumption* that in such case FW 393 * will recalculate the CS. 394 */ 395 if (dest_action->dest_tbl->is_fw_tbl) { 396 *final_icm_addr = dest_action->dest_tbl->fw_tbl.rx_icm_addr; 397 } else { 398 mlx5dr_dbg(dmn, 399 "Destination FT should be terminating when modify TTL is used\n"); 400 return -EINVAL; 401 } 402 break; 403 404 case DR_ACTION_TYP_VPORT: 405 /* If destination is vport we will get the FW flow table 406 * that recalculates the CS and forwards to the vport. 407 */ 408 ret = mlx5dr_domain_cache_get_recalc_cs_ft_addr(dest_action->vport->dmn, 409 dest_action->vport->caps->num, 410 final_icm_addr); 411 if (ret) { 412 mlx5dr_err(dmn, "Failed to get FW cs recalc flow table\n"); 413 return ret; 414 } 415 break; 416 417 default: 418 break; 419 } 420 421 return 0; 422 } 423 424 #define WITH_VLAN_NUM_HW_ACTIONS 6 425 426 int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, 427 struct mlx5dr_matcher_rx_tx *nic_matcher, 428 struct mlx5dr_action *actions[], 429 u32 num_actions, 430 u8 *ste_arr, 431 u32 *new_hw_ste_arr_sz) 432 { 433 struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; 434 bool rx_rule = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX; 435 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 436 u8 action_type_set[DR_ACTION_TYP_MAX] = {}; 437 struct mlx5dr_ste_actions_attr attr = {}; 438 struct mlx5dr_action *dest_action = NULL; 439 u32 state = DR_ACTION_STATE_NO_ACTION; 440 enum dr_action_domain action_domain; 441 bool recalc_cs_required = false; 442 u8 *last_ste; 443 int i, ret; 444 445 attr.gvmi = dmn->info.caps.gvmi; 446 attr.hit_gvmi = dmn->info.caps.gvmi; 447 attr.final_icm_addr = nic_dmn->default_icm_addr; 448 action_domain = dr_action_get_action_domain(dmn->type, nic_dmn->ste_type); 449 450 for (i = 0; i < num_actions; i++) { 451 struct mlx5dr_action_dest_tbl *dest_tbl; 452 struct mlx5dr_action *action; 453 int max_actions_type = 1; 454 u32 action_type; 455 456 action = actions[i]; 457 action_type = action->action_type; 458 459 switch (action_type) { 460 case DR_ACTION_TYP_DROP: 461 attr.final_icm_addr = nic_dmn->drop_icm_addr; 462 break; 463 case DR_ACTION_TYP_FT: 464 dest_action = action; 465 dest_tbl = action->dest_tbl; 466 if (!dest_tbl->is_fw_tbl) { 467 if (dest_tbl->tbl->dmn != dmn) { 468 mlx5dr_err(dmn, 469 "Destination table belongs to a different domain\n"); 470 goto out_invalid_arg; 471 } 472 if (dest_tbl->tbl->level <= matcher->tbl->level) { 473 mlx5_core_warn_once(dmn->mdev, 474 "Connecting table to a lower/same level destination table\n"); 475 mlx5dr_dbg(dmn, 476 "Connecting table at level %d to a destination table at level %d\n", 477 matcher->tbl->level, 478 dest_tbl->tbl->level); 479 } 480 attr.final_icm_addr = rx_rule ? 481 dest_tbl->tbl->rx.s_anchor->chunk->icm_addr : 482 dest_tbl->tbl->tx.s_anchor->chunk->icm_addr; 483 } else { 484 struct mlx5dr_cmd_query_flow_table_details output; 485 int ret; 486 487 /* get the relevant addresses */ 488 if (!action->dest_tbl->fw_tbl.rx_icm_addr) { 489 ret = mlx5dr_cmd_query_flow_table(dmn->mdev, 490 dest_tbl->fw_tbl.type, 491 dest_tbl->fw_tbl.id, 492 &output); 493 if (!ret) { 494 dest_tbl->fw_tbl.tx_icm_addr = 495 output.sw_owner_icm_root_1; 496 dest_tbl->fw_tbl.rx_icm_addr = 497 output.sw_owner_icm_root_0; 498 } else { 499 mlx5dr_err(dmn, 500 "Failed mlx5_cmd_query_flow_table ret: %d\n", 501 ret); 502 return ret; 503 } 504 } 505 attr.final_icm_addr = rx_rule ? 506 dest_tbl->fw_tbl.rx_icm_addr : 507 dest_tbl->fw_tbl.tx_icm_addr; 508 } 509 break; 510 case DR_ACTION_TYP_QP: 511 mlx5dr_info(dmn, "Domain doesn't support QP\n"); 512 goto out_invalid_arg; 513 case DR_ACTION_TYP_CTR: 514 attr.ctr_id = action->ctr->ctr_id + 515 action->ctr->offeset; 516 break; 517 case DR_ACTION_TYP_TAG: 518 attr.flow_tag = action->flow_tag->flow_tag; 519 break; 520 case DR_ACTION_TYP_TNL_L2_TO_L2: 521 break; 522 case DR_ACTION_TYP_TNL_L3_TO_L2: 523 attr.decap_index = action->rewrite->index; 524 attr.decap_actions = action->rewrite->num_of_actions; 525 attr.decap_with_vlan = 526 attr.decap_actions == WITH_VLAN_NUM_HW_ACTIONS; 527 break; 528 case DR_ACTION_TYP_MODIFY_HDR: 529 attr.modify_index = action->rewrite->index; 530 attr.modify_actions = action->rewrite->num_of_actions; 531 recalc_cs_required = action->rewrite->modify_ttl && 532 !mlx5dr_ste_supp_ttl_cs_recalc(&dmn->info.caps); 533 break; 534 case DR_ACTION_TYP_L2_TO_TNL_L2: 535 case DR_ACTION_TYP_L2_TO_TNL_L3: 536 if (rx_rule && 537 !(dmn->ste_ctx->actions_caps & DR_STE_CTX_ACTION_CAP_RX_ENCAP)) { 538 mlx5dr_info(dmn, "Device doesn't support Encap on RX\n"); 539 goto out_invalid_arg; 540 } 541 attr.reformat.size = action->reformat->size; 542 attr.reformat.id = action->reformat->id; 543 break; 544 case DR_ACTION_TYP_SAMPLER: 545 attr.final_icm_addr = rx_rule ? action->sampler->rx_icm_addr : 546 action->sampler->tx_icm_addr; 547 break; 548 case DR_ACTION_TYP_VPORT: 549 attr.hit_gvmi = action->vport->caps->vhca_gvmi; 550 dest_action = action; 551 if (rx_rule) { 552 /* Loopback on WIRE vport is not supported */ 553 if (action->vport->caps->num == WIRE_PORT) 554 goto out_invalid_arg; 555 556 attr.final_icm_addr = action->vport->caps->icm_address_rx; 557 } else { 558 attr.final_icm_addr = action->vport->caps->icm_address_tx; 559 } 560 break; 561 case DR_ACTION_TYP_POP_VLAN: 562 max_actions_type = MLX5DR_MAX_VLANS; 563 attr.vlans.count++; 564 break; 565 case DR_ACTION_TYP_PUSH_VLAN: 566 max_actions_type = MLX5DR_MAX_VLANS; 567 if (attr.vlans.count == MLX5DR_MAX_VLANS) 568 return -EINVAL; 569 570 attr.vlans.headers[attr.vlans.count++] = action->push_vlan->vlan_hdr; 571 break; 572 case DR_ACTION_TYP_INSERT_HDR: 573 attr.reformat.size = action->reformat->size; 574 attr.reformat.id = action->reformat->id; 575 attr.reformat.param_0 = action->reformat->param_0; 576 attr.reformat.param_1 = action->reformat->param_1; 577 break; 578 default: 579 goto out_invalid_arg; 580 } 581 582 /* Check action duplication */ 583 if (++action_type_set[action_type] > max_actions_type) { 584 mlx5dr_err(dmn, "Action type %d supports only max %d time(s)\n", 585 action_type, max_actions_type); 586 goto out_invalid_arg; 587 } 588 589 /* Check action state machine is valid */ 590 if (dr_action_validate_and_get_next_state(action_domain, 591 action_type, 592 &state)) { 593 mlx5dr_err(dmn, "Invalid action sequence provided\n"); 594 return -EOPNOTSUPP; 595 } 596 } 597 598 *new_hw_ste_arr_sz = nic_matcher->num_of_builders; 599 last_ste = ste_arr + DR_STE_SIZE * (nic_matcher->num_of_builders - 1); 600 601 /* Due to a HW bug in some devices, modifying TTL on RX flows will 602 * cause an incorrect checksum calculation. In this case we will 603 * use a FW table to recalculate. 604 */ 605 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB && 606 rx_rule && recalc_cs_required && dest_action) { 607 ret = dr_action_handle_cs_recalc(dmn, dest_action, &attr.final_icm_addr); 608 if (ret) { 609 mlx5dr_err(dmn, 610 "Failed to handle checksum recalculation err %d\n", 611 ret); 612 return ret; 613 } 614 } 615 616 dr_actions_apply(dmn, 617 nic_dmn->ste_type, 618 action_type_set, 619 last_ste, 620 &attr, 621 new_hw_ste_arr_sz); 622 623 return 0; 624 625 out_invalid_arg: 626 return -EINVAL; 627 } 628 629 static unsigned int action_size[DR_ACTION_TYP_MAX] = { 630 [DR_ACTION_TYP_TNL_L2_TO_L2] = sizeof(struct mlx5dr_action_reformat), 631 [DR_ACTION_TYP_L2_TO_TNL_L2] = sizeof(struct mlx5dr_action_reformat), 632 [DR_ACTION_TYP_TNL_L3_TO_L2] = sizeof(struct mlx5dr_action_rewrite), 633 [DR_ACTION_TYP_L2_TO_TNL_L3] = sizeof(struct mlx5dr_action_reformat), 634 [DR_ACTION_TYP_FT] = sizeof(struct mlx5dr_action_dest_tbl), 635 [DR_ACTION_TYP_CTR] = sizeof(struct mlx5dr_action_ctr), 636 [DR_ACTION_TYP_TAG] = sizeof(struct mlx5dr_action_flow_tag), 637 [DR_ACTION_TYP_MODIFY_HDR] = sizeof(struct mlx5dr_action_rewrite), 638 [DR_ACTION_TYP_VPORT] = sizeof(struct mlx5dr_action_vport), 639 [DR_ACTION_TYP_PUSH_VLAN] = sizeof(struct mlx5dr_action_push_vlan), 640 [DR_ACTION_TYP_INSERT_HDR] = sizeof(struct mlx5dr_action_reformat), 641 [DR_ACTION_TYP_SAMPLER] = sizeof(struct mlx5dr_action_sampler), 642 }; 643 644 static struct mlx5dr_action * 645 dr_action_create_generic(enum mlx5dr_action_type action_type) 646 { 647 struct mlx5dr_action *action; 648 int extra_size; 649 650 if (action_type < DR_ACTION_TYP_MAX) 651 extra_size = action_size[action_type]; 652 else 653 return NULL; 654 655 action = kzalloc(sizeof(*action) + extra_size, GFP_KERNEL); 656 if (!action) 657 return NULL; 658 659 action->action_type = action_type; 660 refcount_set(&action->refcount, 1); 661 action->data = action + 1; 662 663 return action; 664 } 665 666 struct mlx5dr_action *mlx5dr_action_create_drop(void) 667 { 668 return dr_action_create_generic(DR_ACTION_TYP_DROP); 669 } 670 671 struct mlx5dr_action * 672 mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num) 673 { 674 struct mlx5dr_action *action; 675 676 action = dr_action_create_generic(DR_ACTION_TYP_FT); 677 if (!action) 678 return NULL; 679 680 action->dest_tbl->is_fw_tbl = true; 681 action->dest_tbl->fw_tbl.dmn = dmn; 682 action->dest_tbl->fw_tbl.id = table_num; 683 action->dest_tbl->fw_tbl.type = FS_FT_FDB; 684 refcount_inc(&dmn->refcount); 685 686 return action; 687 } 688 689 struct mlx5dr_action * 690 mlx5dr_action_create_dest_table(struct mlx5dr_table *tbl) 691 { 692 struct mlx5dr_action *action; 693 694 refcount_inc(&tbl->refcount); 695 696 action = dr_action_create_generic(DR_ACTION_TYP_FT); 697 if (!action) 698 goto dec_ref; 699 700 action->dest_tbl->tbl = tbl; 701 702 return action; 703 704 dec_ref: 705 refcount_dec(&tbl->refcount); 706 return NULL; 707 } 708 709 struct mlx5dr_action * 710 mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn, 711 struct mlx5dr_action_dest *dests, 712 u32 num_of_dests) 713 { 714 struct mlx5dr_cmd_flow_destination_hw_info *hw_dests; 715 struct mlx5dr_action **ref_actions; 716 struct mlx5dr_action *action; 717 bool reformat_req = false; 718 u32 num_of_ref = 0; 719 int ret; 720 int i; 721 722 if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { 723 mlx5dr_err(dmn, "Multiple destination support is for FDB only\n"); 724 return NULL; 725 } 726 727 hw_dests = kzalloc(sizeof(*hw_dests) * num_of_dests, GFP_KERNEL); 728 if (!hw_dests) 729 return NULL; 730 731 ref_actions = kzalloc(sizeof(*ref_actions) * num_of_dests * 2, GFP_KERNEL); 732 if (!ref_actions) 733 goto free_hw_dests; 734 735 for (i = 0; i < num_of_dests; i++) { 736 struct mlx5dr_action *reformat_action = dests[i].reformat; 737 struct mlx5dr_action *dest_action = dests[i].dest; 738 739 ref_actions[num_of_ref++] = dest_action; 740 741 switch (dest_action->action_type) { 742 case DR_ACTION_TYP_VPORT: 743 hw_dests[i].vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID; 744 hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; 745 hw_dests[i].vport.num = dest_action->vport->caps->num; 746 hw_dests[i].vport.vhca_id = dest_action->vport->caps->vhca_gvmi; 747 if (reformat_action) { 748 reformat_req = true; 749 hw_dests[i].vport.reformat_id = 750 reformat_action->reformat->id; 751 ref_actions[num_of_ref++] = reformat_action; 752 hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID; 753 } 754 break; 755 756 case DR_ACTION_TYP_FT: 757 hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 758 if (dest_action->dest_tbl->is_fw_tbl) 759 hw_dests[i].ft_id = dest_action->dest_tbl->fw_tbl.id; 760 else 761 hw_dests[i].ft_id = dest_action->dest_tbl->tbl->table_id; 762 break; 763 764 default: 765 mlx5dr_dbg(dmn, "Invalid multiple destinations action\n"); 766 goto free_ref_actions; 767 } 768 } 769 770 action = dr_action_create_generic(DR_ACTION_TYP_FT); 771 if (!action) 772 goto free_ref_actions; 773 774 ret = mlx5dr_fw_create_md_tbl(dmn, 775 hw_dests, 776 num_of_dests, 777 reformat_req, 778 &action->dest_tbl->fw_tbl.id, 779 &action->dest_tbl->fw_tbl.group_id); 780 if (ret) 781 goto free_action; 782 783 refcount_inc(&dmn->refcount); 784 785 for (i = 0; i < num_of_ref; i++) 786 refcount_inc(&ref_actions[i]->refcount); 787 788 action->dest_tbl->is_fw_tbl = true; 789 action->dest_tbl->fw_tbl.dmn = dmn; 790 action->dest_tbl->fw_tbl.type = FS_FT_FDB; 791 action->dest_tbl->fw_tbl.ref_actions = ref_actions; 792 action->dest_tbl->fw_tbl.num_of_ref_actions = num_of_ref; 793 794 kfree(hw_dests); 795 796 return action; 797 798 free_action: 799 kfree(action); 800 free_ref_actions: 801 kfree(ref_actions); 802 free_hw_dests: 803 kfree(hw_dests); 804 return NULL; 805 } 806 807 struct mlx5dr_action * 808 mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *dmn, 809 struct mlx5_flow_table *ft) 810 { 811 struct mlx5dr_action *action; 812 813 action = dr_action_create_generic(DR_ACTION_TYP_FT); 814 if (!action) 815 return NULL; 816 817 action->dest_tbl->is_fw_tbl = 1; 818 action->dest_tbl->fw_tbl.type = ft->type; 819 action->dest_tbl->fw_tbl.id = ft->id; 820 action->dest_tbl->fw_tbl.dmn = dmn; 821 822 refcount_inc(&dmn->refcount); 823 824 return action; 825 } 826 827 struct mlx5dr_action * 828 mlx5dr_action_create_flow_counter(u32 counter_id) 829 { 830 struct mlx5dr_action *action; 831 832 action = dr_action_create_generic(DR_ACTION_TYP_CTR); 833 if (!action) 834 return NULL; 835 836 action->ctr->ctr_id = counter_id; 837 838 return action; 839 } 840 841 struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value) 842 { 843 struct mlx5dr_action *action; 844 845 action = dr_action_create_generic(DR_ACTION_TYP_TAG); 846 if (!action) 847 return NULL; 848 849 action->flow_tag->flow_tag = tag_value & 0xffffff; 850 851 return action; 852 } 853 854 struct mlx5dr_action * 855 mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id) 856 { 857 struct mlx5dr_action *action; 858 u64 icm_rx, icm_tx; 859 int ret; 860 861 ret = mlx5dr_cmd_query_flow_sampler(dmn->mdev, sampler_id, 862 &icm_rx, &icm_tx); 863 if (ret) 864 return NULL; 865 866 action = dr_action_create_generic(DR_ACTION_TYP_SAMPLER); 867 if (!action) 868 return NULL; 869 870 action->sampler->dmn = dmn; 871 action->sampler->sampler_id = sampler_id; 872 action->sampler->rx_icm_addr = icm_rx; 873 action->sampler->tx_icm_addr = icm_tx; 874 875 refcount_inc(&dmn->refcount); 876 return action; 877 } 878 879 static int 880 dr_action_verify_reformat_params(enum mlx5dr_action_type reformat_type, 881 struct mlx5dr_domain *dmn, 882 u8 reformat_param_0, 883 u8 reformat_param_1, 884 size_t data_sz, 885 void *data) 886 { 887 if ((!data && data_sz) || (data && !data_sz) || 888 ((reformat_param_0 || reformat_param_1) && 889 reformat_type != DR_ACTION_TYP_INSERT_HDR) || 890 reformat_type > DR_ACTION_TYP_INSERT_HDR) { 891 mlx5dr_dbg(dmn, "Invalid reformat parameter!\n"); 892 goto out_err; 893 } 894 895 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB) 896 return 0; 897 898 if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) { 899 if (reformat_type != DR_ACTION_TYP_TNL_L2_TO_L2 && 900 reformat_type != DR_ACTION_TYP_TNL_L3_TO_L2) { 901 mlx5dr_dbg(dmn, "Action reformat type not support on RX domain\n"); 902 goto out_err; 903 } 904 } else if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) { 905 if (reformat_type != DR_ACTION_TYP_L2_TO_TNL_L2 && 906 reformat_type != DR_ACTION_TYP_L2_TO_TNL_L3) { 907 mlx5dr_dbg(dmn, "Action reformat type not support on TX domain\n"); 908 goto out_err; 909 } 910 } 911 912 return 0; 913 914 out_err: 915 return -EINVAL; 916 } 917 918 #define ACTION_CACHE_LINE_SIZE 64 919 920 static int 921 dr_action_create_reformat_action(struct mlx5dr_domain *dmn, 922 u8 reformat_param_0, u8 reformat_param_1, 923 size_t data_sz, void *data, 924 struct mlx5dr_action *action) 925 { 926 u32 reformat_id; 927 int ret; 928 929 switch (action->action_type) { 930 case DR_ACTION_TYP_L2_TO_TNL_L2: 931 case DR_ACTION_TYP_L2_TO_TNL_L3: 932 { 933 enum mlx5_reformat_ctx_type rt; 934 935 if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2) 936 rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; 937 else 938 rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 939 940 ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, 0, 0, 941 data_sz, data, 942 &reformat_id); 943 if (ret) 944 return ret; 945 946 action->reformat->id = reformat_id; 947 action->reformat->size = data_sz; 948 return 0; 949 } 950 case DR_ACTION_TYP_TNL_L2_TO_L2: 951 { 952 return 0; 953 } 954 case DR_ACTION_TYP_TNL_L3_TO_L2: 955 { 956 u8 hw_actions[ACTION_CACHE_LINE_SIZE] = {}; 957 int ret; 958 959 ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx, 960 data, data_sz, 961 hw_actions, 962 ACTION_CACHE_LINE_SIZE, 963 &action->rewrite->num_of_actions); 964 if (ret) { 965 mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n"); 966 return ret; 967 } 968 969 action->rewrite->chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool, 970 DR_CHUNK_SIZE_8); 971 if (!action->rewrite->chunk) { 972 mlx5dr_dbg(dmn, "Failed allocating modify header chunk\n"); 973 return -ENOMEM; 974 } 975 976 action->rewrite->data = (void *)hw_actions; 977 action->rewrite->index = (action->rewrite->chunk->icm_addr - 978 dmn->info.caps.hdr_modify_icm_addr) / 979 ACTION_CACHE_LINE_SIZE; 980 981 ret = mlx5dr_send_postsend_action(dmn, action); 982 if (ret) { 983 mlx5dr_dbg(dmn, "Writing decap l3 actions to ICM failed\n"); 984 mlx5dr_icm_free_chunk(action->rewrite->chunk); 985 return ret; 986 } 987 return 0; 988 } 989 case DR_ACTION_TYP_INSERT_HDR: 990 { 991 ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, 992 MLX5_REFORMAT_TYPE_INSERT_HDR, 993 reformat_param_0, 994 reformat_param_1, 995 data_sz, data, 996 &reformat_id); 997 if (ret) 998 return ret; 999 1000 action->reformat->id = reformat_id; 1001 action->reformat->size = data_sz; 1002 action->reformat->param_0 = reformat_param_0; 1003 action->reformat->param_1 = reformat_param_1; 1004 return 0; 1005 } 1006 default: 1007 mlx5dr_info(dmn, "Reformat type is not supported %d\n", action->action_type); 1008 return -EINVAL; 1009 } 1010 } 1011 1012 #define CVLAN_ETHERTYPE 0x8100 1013 #define SVLAN_ETHERTYPE 0x88a8 1014 1015 struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void) 1016 { 1017 return dr_action_create_generic(DR_ACTION_TYP_POP_VLAN); 1018 } 1019 1020 struct mlx5dr_action *mlx5dr_action_create_push_vlan(struct mlx5dr_domain *dmn, 1021 __be32 vlan_hdr) 1022 { 1023 u32 vlan_hdr_h = ntohl(vlan_hdr); 1024 u16 ethertype = vlan_hdr_h >> 16; 1025 struct mlx5dr_action *action; 1026 1027 if (ethertype != SVLAN_ETHERTYPE && ethertype != CVLAN_ETHERTYPE) { 1028 mlx5dr_dbg(dmn, "Invalid vlan ethertype\n"); 1029 return NULL; 1030 } 1031 1032 action = dr_action_create_generic(DR_ACTION_TYP_PUSH_VLAN); 1033 if (!action) 1034 return NULL; 1035 1036 action->push_vlan->vlan_hdr = vlan_hdr_h; 1037 return action; 1038 } 1039 1040 struct mlx5dr_action * 1041 mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn, 1042 enum mlx5dr_action_reformat_type reformat_type, 1043 u8 reformat_param_0, 1044 u8 reformat_param_1, 1045 size_t data_sz, 1046 void *data) 1047 { 1048 enum mlx5dr_action_type action_type; 1049 struct mlx5dr_action *action; 1050 int ret; 1051 1052 refcount_inc(&dmn->refcount); 1053 1054 /* General checks */ 1055 ret = dr_action_reformat_to_action_type(reformat_type, &action_type); 1056 if (ret) { 1057 mlx5dr_dbg(dmn, "Invalid reformat_type provided\n"); 1058 goto dec_ref; 1059 } 1060 1061 ret = dr_action_verify_reformat_params(action_type, dmn, 1062 reformat_param_0, reformat_param_1, 1063 data_sz, data); 1064 if (ret) 1065 goto dec_ref; 1066 1067 action = dr_action_create_generic(action_type); 1068 if (!action) 1069 goto dec_ref; 1070 1071 action->reformat->dmn = dmn; 1072 1073 ret = dr_action_create_reformat_action(dmn, 1074 reformat_param_0, 1075 reformat_param_1, 1076 data_sz, 1077 data, 1078 action); 1079 if (ret) { 1080 mlx5dr_dbg(dmn, "Failed creating reformat action %d\n", ret); 1081 goto free_action; 1082 } 1083 1084 return action; 1085 1086 free_action: 1087 kfree(action); 1088 dec_ref: 1089 refcount_dec(&dmn->refcount); 1090 return NULL; 1091 } 1092 1093 static int 1094 dr_action_modify_sw_to_hw_add(struct mlx5dr_domain *dmn, 1095 __be64 *sw_action, 1096 __be64 *hw_action, 1097 const struct mlx5dr_ste_action_modify_field **ret_hw_info) 1098 { 1099 const struct mlx5dr_ste_action_modify_field *hw_action_info; 1100 u8 max_length; 1101 u16 sw_field; 1102 u32 data; 1103 1104 /* Get SW modify action data */ 1105 sw_field = MLX5_GET(set_action_in, sw_action, field); 1106 data = MLX5_GET(set_action_in, sw_action, data); 1107 1108 /* Convert SW data to HW modify action format */ 1109 hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); 1110 if (!hw_action_info) { 1111 mlx5dr_dbg(dmn, "Modify add action invalid field given\n"); 1112 return -EINVAL; 1113 } 1114 1115 max_length = hw_action_info->end - hw_action_info->start + 1; 1116 1117 mlx5dr_ste_set_action_add(dmn->ste_ctx, 1118 hw_action, 1119 hw_action_info->hw_field, 1120 hw_action_info->start, 1121 max_length, 1122 data); 1123 1124 *ret_hw_info = hw_action_info; 1125 1126 return 0; 1127 } 1128 1129 static int 1130 dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn, 1131 __be64 *sw_action, 1132 __be64 *hw_action, 1133 const struct mlx5dr_ste_action_modify_field **ret_hw_info) 1134 { 1135 const struct mlx5dr_ste_action_modify_field *hw_action_info; 1136 u8 offset, length, max_length; 1137 u16 sw_field; 1138 u32 data; 1139 1140 /* Get SW modify action data */ 1141 length = MLX5_GET(set_action_in, sw_action, length); 1142 offset = MLX5_GET(set_action_in, sw_action, offset); 1143 sw_field = MLX5_GET(set_action_in, sw_action, field); 1144 data = MLX5_GET(set_action_in, sw_action, data); 1145 1146 /* Convert SW data to HW modify action format */ 1147 hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); 1148 if (!hw_action_info) { 1149 mlx5dr_dbg(dmn, "Modify set action invalid field given\n"); 1150 return -EINVAL; 1151 } 1152 1153 /* PRM defines that length zero specific length of 32bits */ 1154 length = length ? length : 32; 1155 1156 max_length = hw_action_info->end - hw_action_info->start + 1; 1157 1158 if (length + offset > max_length) { 1159 mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); 1160 return -EINVAL; 1161 } 1162 1163 mlx5dr_ste_set_action_set(dmn->ste_ctx, 1164 hw_action, 1165 hw_action_info->hw_field, 1166 hw_action_info->start + offset, 1167 length, 1168 data); 1169 1170 *ret_hw_info = hw_action_info; 1171 1172 return 0; 1173 } 1174 1175 static int 1176 dr_action_modify_sw_to_hw_copy(struct mlx5dr_domain *dmn, 1177 __be64 *sw_action, 1178 __be64 *hw_action, 1179 const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, 1180 const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) 1181 { 1182 u8 src_offset, dst_offset, src_max_length, dst_max_length, length; 1183 const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; 1184 const struct mlx5dr_ste_action_modify_field *hw_src_action_info; 1185 u16 src_field, dst_field; 1186 1187 /* Get SW modify action data */ 1188 src_field = MLX5_GET(copy_action_in, sw_action, src_field); 1189 dst_field = MLX5_GET(copy_action_in, sw_action, dst_field); 1190 src_offset = MLX5_GET(copy_action_in, sw_action, src_offset); 1191 dst_offset = MLX5_GET(copy_action_in, sw_action, dst_offset); 1192 length = MLX5_GET(copy_action_in, sw_action, length); 1193 1194 /* Convert SW data to HW modify action format */ 1195 hw_src_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, src_field); 1196 hw_dst_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, dst_field); 1197 if (!hw_src_action_info || !hw_dst_action_info) { 1198 mlx5dr_dbg(dmn, "Modify copy action invalid field given\n"); 1199 return -EINVAL; 1200 } 1201 1202 /* PRM defines that length zero specific length of 32bits */ 1203 length = length ? length : 32; 1204 1205 src_max_length = hw_src_action_info->end - 1206 hw_src_action_info->start + 1; 1207 dst_max_length = hw_dst_action_info->end - 1208 hw_dst_action_info->start + 1; 1209 1210 if (length + src_offset > src_max_length || 1211 length + dst_offset > dst_max_length) { 1212 mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); 1213 return -EINVAL; 1214 } 1215 1216 mlx5dr_ste_set_action_copy(dmn->ste_ctx, 1217 hw_action, 1218 hw_dst_action_info->hw_field, 1219 hw_dst_action_info->start + dst_offset, 1220 length, 1221 hw_src_action_info->hw_field, 1222 hw_src_action_info->start + src_offset); 1223 1224 *ret_dst_hw_info = hw_dst_action_info; 1225 *ret_src_hw_info = hw_src_action_info; 1226 1227 return 0; 1228 } 1229 1230 static int 1231 dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn, 1232 __be64 *sw_action, 1233 __be64 *hw_action, 1234 const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, 1235 const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) 1236 { 1237 u8 action; 1238 int ret; 1239 1240 *hw_action = 0; 1241 *ret_src_hw_info = NULL; 1242 1243 /* Get SW modify action type */ 1244 action = MLX5_GET(set_action_in, sw_action, action_type); 1245 1246 switch (action) { 1247 case MLX5_ACTION_TYPE_SET: 1248 ret = dr_action_modify_sw_to_hw_set(dmn, sw_action, 1249 hw_action, 1250 ret_dst_hw_info); 1251 break; 1252 1253 case MLX5_ACTION_TYPE_ADD: 1254 ret = dr_action_modify_sw_to_hw_add(dmn, sw_action, 1255 hw_action, 1256 ret_dst_hw_info); 1257 break; 1258 1259 case MLX5_ACTION_TYPE_COPY: 1260 ret = dr_action_modify_sw_to_hw_copy(dmn, sw_action, 1261 hw_action, 1262 ret_dst_hw_info, 1263 ret_src_hw_info); 1264 break; 1265 1266 default: 1267 mlx5dr_info(dmn, "Unsupported action_type for modify action\n"); 1268 ret = -EOPNOTSUPP; 1269 } 1270 1271 return ret; 1272 } 1273 1274 static int 1275 dr_action_modify_check_set_field_limitation(struct mlx5dr_action *action, 1276 const __be64 *sw_action) 1277 { 1278 u16 sw_field = MLX5_GET(set_action_in, sw_action, field); 1279 struct mlx5dr_domain *dmn = action->rewrite->dmn; 1280 1281 if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { 1282 action->rewrite->allow_rx = 0; 1283 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { 1284 mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", 1285 sw_field); 1286 return -EINVAL; 1287 } 1288 } else if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { 1289 action->rewrite->allow_tx = 0; 1290 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { 1291 mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", 1292 sw_field); 1293 return -EINVAL; 1294 } 1295 } 1296 1297 if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { 1298 mlx5dr_dbg(dmn, "Modify SET actions not supported on both RX and TX\n"); 1299 return -EINVAL; 1300 } 1301 1302 return 0; 1303 } 1304 1305 static int 1306 dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action, 1307 const __be64 *sw_action) 1308 { 1309 u16 sw_field = MLX5_GET(set_action_in, sw_action, field); 1310 struct mlx5dr_domain *dmn = action->rewrite->dmn; 1311 1312 if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL && 1313 sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT && 1314 sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM && 1315 sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) { 1316 mlx5dr_dbg(dmn, "Unsupported field %d for add action\n", 1317 sw_field); 1318 return -EINVAL; 1319 } 1320 1321 return 0; 1322 } 1323 1324 static int 1325 dr_action_modify_check_copy_field_limitation(struct mlx5dr_action *action, 1326 const __be64 *sw_action) 1327 { 1328 struct mlx5dr_domain *dmn = action->rewrite->dmn; 1329 u16 sw_fields[2]; 1330 int i; 1331 1332 sw_fields[0] = MLX5_GET(copy_action_in, sw_action, src_field); 1333 sw_fields[1] = MLX5_GET(copy_action_in, sw_action, dst_field); 1334 1335 for (i = 0; i < 2; i++) { 1336 if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { 1337 action->rewrite->allow_rx = 0; 1338 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { 1339 mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", 1340 sw_fields[i]); 1341 return -EINVAL; 1342 } 1343 } else if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { 1344 action->rewrite->allow_tx = 0; 1345 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { 1346 mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", 1347 sw_fields[i]); 1348 return -EINVAL; 1349 } 1350 } 1351 } 1352 1353 if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { 1354 mlx5dr_dbg(dmn, "Modify copy actions not supported on both RX and TX\n"); 1355 return -EINVAL; 1356 } 1357 1358 return 0; 1359 } 1360 1361 static int 1362 dr_action_modify_check_field_limitation(struct mlx5dr_action *action, 1363 const __be64 *sw_action) 1364 { 1365 struct mlx5dr_domain *dmn = action->rewrite->dmn; 1366 u8 action_type; 1367 int ret; 1368 1369 action_type = MLX5_GET(set_action_in, sw_action, action_type); 1370 1371 switch (action_type) { 1372 case MLX5_ACTION_TYPE_SET: 1373 ret = dr_action_modify_check_set_field_limitation(action, 1374 sw_action); 1375 break; 1376 1377 case MLX5_ACTION_TYPE_ADD: 1378 ret = dr_action_modify_check_add_field_limitation(action, 1379 sw_action); 1380 break; 1381 1382 case MLX5_ACTION_TYPE_COPY: 1383 ret = dr_action_modify_check_copy_field_limitation(action, 1384 sw_action); 1385 break; 1386 1387 default: 1388 mlx5dr_info(dmn, "Unsupported action %d modify action\n", 1389 action_type); 1390 ret = -EOPNOTSUPP; 1391 } 1392 1393 return ret; 1394 } 1395 1396 static bool 1397 dr_action_modify_check_is_ttl_modify(const void *sw_action) 1398 { 1399 u16 sw_field = MLX5_GET(set_action_in, sw_action, field); 1400 1401 return sw_field == MLX5_ACTION_IN_FIELD_OUT_IP_TTL; 1402 } 1403 1404 static int dr_actions_convert_modify_header(struct mlx5dr_action *action, 1405 u32 max_hw_actions, 1406 u32 num_sw_actions, 1407 __be64 sw_actions[], 1408 __be64 hw_actions[], 1409 u32 *num_hw_actions, 1410 bool *modify_ttl) 1411 { 1412 const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; 1413 const struct mlx5dr_ste_action_modify_field *hw_src_action_info; 1414 struct mlx5dr_domain *dmn = action->rewrite->dmn; 1415 int ret, i, hw_idx = 0; 1416 __be64 *sw_action; 1417 __be64 hw_action; 1418 u16 hw_field = 0; 1419 u32 l3_type = 0; 1420 u32 l4_type = 0; 1421 1422 *modify_ttl = false; 1423 1424 action->rewrite->allow_rx = 1; 1425 action->rewrite->allow_tx = 1; 1426 1427 for (i = 0; i < num_sw_actions; i++) { 1428 sw_action = &sw_actions[i]; 1429 1430 ret = dr_action_modify_check_field_limitation(action, 1431 sw_action); 1432 if (ret) 1433 return ret; 1434 1435 if (!(*modify_ttl)) 1436 *modify_ttl = dr_action_modify_check_is_ttl_modify(sw_action); 1437 1438 /* Convert SW action to HW action */ 1439 ret = dr_action_modify_sw_to_hw(dmn, 1440 sw_action, 1441 &hw_action, 1442 &hw_dst_action_info, 1443 &hw_src_action_info); 1444 if (ret) 1445 return ret; 1446 1447 /* Due to a HW limitation we cannot modify 2 different L3 types */ 1448 if (l3_type && hw_dst_action_info->l3_type && 1449 hw_dst_action_info->l3_type != l3_type) { 1450 mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n"); 1451 return -EINVAL; 1452 } 1453 if (hw_dst_action_info->l3_type) 1454 l3_type = hw_dst_action_info->l3_type; 1455 1456 /* Due to a HW limitation we cannot modify two different L4 types */ 1457 if (l4_type && hw_dst_action_info->l4_type && 1458 hw_dst_action_info->l4_type != l4_type) { 1459 mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n"); 1460 return -EINVAL; 1461 } 1462 if (hw_dst_action_info->l4_type) 1463 l4_type = hw_dst_action_info->l4_type; 1464 1465 /* HW reads and executes two actions at once this means we 1466 * need to create a gap if two actions access the same field 1467 */ 1468 if ((hw_idx % 2) && (hw_field == hw_dst_action_info->hw_field || 1469 (hw_src_action_info && 1470 hw_field == hw_src_action_info->hw_field))) { 1471 /* Check if after gap insertion the total number of HW 1472 * modify actions doesn't exceeds the limit 1473 */ 1474 hw_idx++; 1475 if ((num_sw_actions + hw_idx - i) >= max_hw_actions) { 1476 mlx5dr_dbg(dmn, "Modify header action number exceeds HW limit\n"); 1477 return -EINVAL; 1478 } 1479 } 1480 hw_field = hw_dst_action_info->hw_field; 1481 1482 hw_actions[hw_idx] = hw_action; 1483 hw_idx++; 1484 } 1485 1486 *num_hw_actions = hw_idx; 1487 1488 return 0; 1489 } 1490 1491 static int dr_action_create_modify_action(struct mlx5dr_domain *dmn, 1492 size_t actions_sz, 1493 __be64 actions[], 1494 struct mlx5dr_action *action) 1495 { 1496 struct mlx5dr_icm_chunk *chunk; 1497 u32 max_hw_actions; 1498 u32 num_hw_actions; 1499 u32 num_sw_actions; 1500 __be64 *hw_actions; 1501 bool modify_ttl; 1502 int ret; 1503 1504 num_sw_actions = actions_sz / DR_MODIFY_ACTION_SIZE; 1505 max_hw_actions = mlx5dr_icm_pool_chunk_size_to_entries(DR_CHUNK_SIZE_16); 1506 1507 if (num_sw_actions > max_hw_actions) { 1508 mlx5dr_dbg(dmn, "Max number of actions %d exceeds limit %d\n", 1509 num_sw_actions, max_hw_actions); 1510 return -EINVAL; 1511 } 1512 1513 chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool, DR_CHUNK_SIZE_16); 1514 if (!chunk) 1515 return -ENOMEM; 1516 1517 hw_actions = kcalloc(1, max_hw_actions * DR_MODIFY_ACTION_SIZE, GFP_KERNEL); 1518 if (!hw_actions) { 1519 ret = -ENOMEM; 1520 goto free_chunk; 1521 } 1522 1523 ret = dr_actions_convert_modify_header(action, 1524 max_hw_actions, 1525 num_sw_actions, 1526 actions, 1527 hw_actions, 1528 &num_hw_actions, 1529 &modify_ttl); 1530 if (ret) 1531 goto free_hw_actions; 1532 1533 action->rewrite->chunk = chunk; 1534 action->rewrite->modify_ttl = modify_ttl; 1535 action->rewrite->data = (u8 *)hw_actions; 1536 action->rewrite->num_of_actions = num_hw_actions; 1537 action->rewrite->index = (chunk->icm_addr - 1538 dmn->info.caps.hdr_modify_icm_addr) / 1539 ACTION_CACHE_LINE_SIZE; 1540 1541 ret = mlx5dr_send_postsend_action(dmn, action); 1542 if (ret) 1543 goto free_hw_actions; 1544 1545 return 0; 1546 1547 free_hw_actions: 1548 kfree(hw_actions); 1549 free_chunk: 1550 mlx5dr_icm_free_chunk(chunk); 1551 return ret; 1552 } 1553 1554 struct mlx5dr_action * 1555 mlx5dr_action_create_modify_header(struct mlx5dr_domain *dmn, 1556 u32 flags, 1557 size_t actions_sz, 1558 __be64 actions[]) 1559 { 1560 struct mlx5dr_action *action; 1561 int ret = 0; 1562 1563 refcount_inc(&dmn->refcount); 1564 1565 if (actions_sz % DR_MODIFY_ACTION_SIZE) { 1566 mlx5dr_dbg(dmn, "Invalid modify actions size provided\n"); 1567 goto dec_ref; 1568 } 1569 1570 action = dr_action_create_generic(DR_ACTION_TYP_MODIFY_HDR); 1571 if (!action) 1572 goto dec_ref; 1573 1574 action->rewrite->dmn = dmn; 1575 1576 ret = dr_action_create_modify_action(dmn, 1577 actions_sz, 1578 actions, 1579 action); 1580 if (ret) { 1581 mlx5dr_dbg(dmn, "Failed creating modify header action %d\n", ret); 1582 goto free_action; 1583 } 1584 1585 return action; 1586 1587 free_action: 1588 kfree(action); 1589 dec_ref: 1590 refcount_dec(&dmn->refcount); 1591 return NULL; 1592 } 1593 1594 struct mlx5dr_action * 1595 mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn, 1596 u32 vport, u8 vhca_id_valid, 1597 u16 vhca_id) 1598 { 1599 struct mlx5dr_cmd_vport_cap *vport_cap; 1600 struct mlx5dr_domain *vport_dmn; 1601 struct mlx5dr_action *action; 1602 u8 peer_vport; 1603 1604 peer_vport = vhca_id_valid && (vhca_id != dmn->info.caps.gvmi); 1605 vport_dmn = peer_vport ? dmn->peer_dmn : dmn; 1606 if (!vport_dmn) { 1607 mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n"); 1608 return NULL; 1609 } 1610 1611 if (vport_dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { 1612 mlx5dr_dbg(dmn, "Domain doesn't support vport actions\n"); 1613 return NULL; 1614 } 1615 1616 vport_cap = mlx5dr_get_vport_cap(&vport_dmn->info.caps, vport); 1617 if (!vport_cap) { 1618 mlx5dr_dbg(dmn, "Failed to get vport %d caps\n", vport); 1619 return NULL; 1620 } 1621 1622 action = dr_action_create_generic(DR_ACTION_TYP_VPORT); 1623 if (!action) 1624 return NULL; 1625 1626 action->vport->dmn = vport_dmn; 1627 action->vport->caps = vport_cap; 1628 1629 return action; 1630 } 1631 1632 int mlx5dr_action_destroy(struct mlx5dr_action *action) 1633 { 1634 if (refcount_read(&action->refcount) > 1) 1635 return -EBUSY; 1636 1637 switch (action->action_type) { 1638 case DR_ACTION_TYP_FT: 1639 if (action->dest_tbl->is_fw_tbl) 1640 refcount_dec(&action->dest_tbl->fw_tbl.dmn->refcount); 1641 else 1642 refcount_dec(&action->dest_tbl->tbl->refcount); 1643 1644 if (action->dest_tbl->is_fw_tbl && 1645 action->dest_tbl->fw_tbl.num_of_ref_actions) { 1646 struct mlx5dr_action **ref_actions; 1647 int i; 1648 1649 ref_actions = action->dest_tbl->fw_tbl.ref_actions; 1650 for (i = 0; i < action->dest_tbl->fw_tbl.num_of_ref_actions; i++) 1651 refcount_dec(&ref_actions[i]->refcount); 1652 1653 kfree(ref_actions); 1654 1655 mlx5dr_fw_destroy_md_tbl(action->dest_tbl->fw_tbl.dmn, 1656 action->dest_tbl->fw_tbl.id, 1657 action->dest_tbl->fw_tbl.group_id); 1658 } 1659 break; 1660 case DR_ACTION_TYP_TNL_L2_TO_L2: 1661 refcount_dec(&action->reformat->dmn->refcount); 1662 break; 1663 case DR_ACTION_TYP_TNL_L3_TO_L2: 1664 mlx5dr_icm_free_chunk(action->rewrite->chunk); 1665 refcount_dec(&action->rewrite->dmn->refcount); 1666 break; 1667 case DR_ACTION_TYP_L2_TO_TNL_L2: 1668 case DR_ACTION_TYP_L2_TO_TNL_L3: 1669 case DR_ACTION_TYP_INSERT_HDR: 1670 mlx5dr_cmd_destroy_reformat_ctx((action->reformat->dmn)->mdev, 1671 action->reformat->id); 1672 refcount_dec(&action->reformat->dmn->refcount); 1673 break; 1674 case DR_ACTION_TYP_MODIFY_HDR: 1675 mlx5dr_icm_free_chunk(action->rewrite->chunk); 1676 kfree(action->rewrite->data); 1677 refcount_dec(&action->rewrite->dmn->refcount); 1678 break; 1679 case DR_ACTION_TYP_SAMPLER: 1680 refcount_dec(&action->sampler->dmn->refcount); 1681 break; 1682 default: 1683 break; 1684 } 1685 1686 kfree(action); 1687 return 0; 1688 } 1689