1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2019 Mellanox Technologies. */ 3 4 #include "dr_types.h" 5 6 static bool dr_mask_is_smac_set(struct mlx5dr_match_spec *spec) 7 { 8 return (spec->smac_47_16 || spec->smac_15_0); 9 } 10 11 static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec) 12 { 13 return (spec->dmac_47_16 || spec->dmac_15_0); 14 } 15 16 static bool dr_mask_is_src_addr_set(struct mlx5dr_match_spec *spec) 17 { 18 return (spec->src_ip_127_96 || spec->src_ip_95_64 || 19 spec->src_ip_63_32 || spec->src_ip_31_0); 20 } 21 22 static bool dr_mask_is_dst_addr_set(struct mlx5dr_match_spec *spec) 23 { 24 return (spec->dst_ip_127_96 || spec->dst_ip_95_64 || 25 spec->dst_ip_63_32 || spec->dst_ip_31_0); 26 } 27 28 static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec) 29 { 30 return (spec->ip_protocol || spec->frag || spec->tcp_flags || 31 spec->ip_ecn || spec->ip_dscp); 32 } 33 34 static bool dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec *spec) 35 { 36 return (spec->tcp_sport || spec->tcp_dport || 37 spec->udp_sport || spec->udp_dport); 38 } 39 40 static bool dr_mask_is_ipv4_set(struct mlx5dr_match_spec *spec) 41 { 42 return (spec->dst_ip_31_0 || spec->src_ip_31_0); 43 } 44 45 static bool dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec *spec) 46 { 47 return (dr_mask_is_l3_base_set(spec) || 48 dr_mask_is_tcp_udp_base_set(spec) || 49 dr_mask_is_ipv4_set(spec)); 50 } 51 52 static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc) 53 { 54 return misc->vxlan_vni; 55 } 56 57 static bool dr_mask_is_ttl_set(struct mlx5dr_match_spec *spec) 58 { 59 return spec->ttl_hoplimit; 60 } 61 62 #define DR_MASK_IS_L2_DST(_spec, _misc, _inner_outer) (_spec.first_vid || \ 63 (_spec).first_cfi || (_spec).first_prio || (_spec).cvlan_tag || \ 64 (_spec).svlan_tag || (_spec).dmac_47_16 || (_spec).dmac_15_0 || \ 65 (_spec).ethertype || (_spec).ip_version || \ 66 (_misc)._inner_outer##_second_vid || \ 67 (_misc)._inner_outer##_second_cfi || \ 68 (_misc)._inner_outer##_second_prio || \ 69 (_misc)._inner_outer##_second_cvlan_tag || \ 70 (_misc)._inner_outer##_second_svlan_tag) 71 72 #define DR_MASK_IS_ETH_L4_SET(_spec, _misc, _inner_outer) ( \ 73 dr_mask_is_l3_base_set(&(_spec)) || \ 74 dr_mask_is_tcp_udp_base_set(&(_spec)) || \ 75 dr_mask_is_ttl_set(&(_spec)) || \ 76 (_misc)._inner_outer##_ipv6_flow_label) 77 78 #define DR_MASK_IS_ETH_L4_MISC_SET(_misc3, _inner_outer) ( \ 79 (_misc3)._inner_outer##_tcp_seq_num || \ 80 (_misc3)._inner_outer##_tcp_ack_num) 81 82 #define DR_MASK_IS_FIRST_MPLS_SET(_misc2, _inner_outer) ( \ 83 (_misc2)._inner_outer##_first_mpls_label || \ 84 (_misc2)._inner_outer##_first_mpls_exp || \ 85 (_misc2)._inner_outer##_first_mpls_s_bos || \ 86 (_misc2)._inner_outer##_first_mpls_ttl) 87 88 static bool dr_mask_is_gre_set(struct mlx5dr_match_misc *misc) 89 { 90 return (misc->gre_key_h || misc->gre_key_l || 91 misc->gre_protocol || misc->gre_c_present || 92 misc->gre_k_present || misc->gre_s_present); 93 } 94 95 #define DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET(_misc2, gre_udp) ( \ 96 (_misc2).outer_first_mpls_over_##gre_udp##_label || \ 97 (_misc2).outer_first_mpls_over_##gre_udp##_exp || \ 98 (_misc2).outer_first_mpls_over_##gre_udp##_s_bos || \ 99 (_misc2).outer_first_mpls_over_##gre_udp##_ttl) 100 101 #define DR_MASK_IS_FLEX_PARSER_0_SET(_misc2) ( \ 102 DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), gre) || \ 103 DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), udp)) 104 105 static bool 106 dr_mask_is_misc3_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) 107 { 108 return (misc3->outer_vxlan_gpe_vni || 109 misc3->outer_vxlan_gpe_next_protocol || 110 misc3->outer_vxlan_gpe_flags); 111 } 112 113 static bool 114 dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_cmd_caps *caps) 115 { 116 return caps->flex_protocols & 117 MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; 118 } 119 120 static bool 121 dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param *mask, 122 struct mlx5dr_domain *dmn) 123 { 124 return dr_mask_is_misc3_vxlan_gpe_set(&mask->misc3) && 125 dr_matcher_supp_flex_parser_vxlan_gpe(&dmn->info.caps); 126 } 127 128 static bool dr_mask_is_misc_geneve_set(struct mlx5dr_match_misc *misc) 129 { 130 return misc->geneve_vni || 131 misc->geneve_oam || 132 misc->geneve_protocol_type || 133 misc->geneve_opt_len; 134 } 135 136 static bool 137 dr_matcher_supp_flex_parser_geneve(struct mlx5dr_cmd_caps *caps) 138 { 139 return caps->flex_protocols & 140 MLX5_FLEX_PARSER_GENEVE_ENABLED; 141 } 142 143 static bool 144 dr_mask_is_flex_parser_tnl_geneve_set(struct mlx5dr_match_param *mask, 145 struct mlx5dr_domain *dmn) 146 { 147 return dr_mask_is_misc_geneve_set(&mask->misc) && 148 dr_matcher_supp_flex_parser_geneve(&dmn->info.caps); 149 } 150 151 static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3) 152 { 153 return (misc3->icmpv6_type || misc3->icmpv6_code || 154 misc3->icmpv6_header_data); 155 } 156 157 static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2) 158 { 159 return misc2->metadata_reg_a; 160 } 161 162 static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2) 163 { 164 return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 || 165 misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3); 166 } 167 168 static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2) 169 { 170 return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 || 171 misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7); 172 } 173 174 static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) 175 { 176 return (misc->source_sqn || misc->source_port); 177 } 178 179 int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, 180 struct mlx5dr_matcher_rx_tx *nic_matcher, 181 enum mlx5dr_ipv outer_ipv, 182 enum mlx5dr_ipv inner_ipv) 183 { 184 nic_matcher->ste_builder = 185 nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; 186 nic_matcher->num_of_builders = 187 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; 188 189 if (!nic_matcher->num_of_builders) { 190 mlx5dr_dbg(matcher->tbl->dmn, 191 "Rule not supported on this matcher due to IP related fields\n"); 192 return -EINVAL; 193 } 194 195 return 0; 196 } 197 198 static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, 199 struct mlx5dr_matcher_rx_tx *nic_matcher, 200 enum mlx5dr_ipv outer_ipv, 201 enum mlx5dr_ipv inner_ipv) 202 { 203 struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; 204 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 205 struct mlx5dr_match_param mask = {}; 206 struct mlx5dr_match_misc3 *misc3; 207 struct mlx5dr_ste_build *sb; 208 bool inner, rx; 209 int idx = 0; 210 int ret, i; 211 212 sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; 213 rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX; 214 215 /* Create a temporary mask to track and clear used mask fields */ 216 if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER) 217 mask.outer = matcher->mask.outer; 218 219 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC) 220 mask.misc = matcher->mask.misc; 221 222 if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER) 223 mask.inner = matcher->mask.inner; 224 225 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2) 226 mask.misc2 = matcher->mask.misc2; 227 228 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3) 229 mask.misc3 = matcher->mask.misc3; 230 231 ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, 232 &matcher->mask, NULL); 233 if (ret) 234 return ret; 235 236 /* Outer */ 237 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER | 238 DR_MATCHER_CRITERIA_MISC | 239 DR_MATCHER_CRITERIA_MISC2 | 240 DR_MATCHER_CRITERIA_MISC3)) { 241 inner = false; 242 243 if (dr_mask_is_wqe_metadata_set(&mask.misc2)) 244 mlx5dr_ste_build_general_purpose(&sb[idx++], &mask, inner, rx); 245 246 if (dr_mask_is_reg_c_0_3_set(&mask.misc2)) 247 mlx5dr_ste_build_register_0(&sb[idx++], &mask, inner, rx); 248 249 if (dr_mask_is_reg_c_4_7_set(&mask.misc2)) 250 mlx5dr_ste_build_register_1(&sb[idx++], &mask, inner, rx); 251 252 if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) && 253 (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 254 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) { 255 ret = mlx5dr_ste_build_src_gvmi_qpn(&sb[idx++], &mask, 256 dmn, inner, rx); 257 if (ret) 258 return ret; 259 } 260 261 if (dr_mask_is_smac_set(&mask.outer) && 262 dr_mask_is_dmac_set(&mask.outer)) { 263 ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++], &mask, 264 inner, rx); 265 if (ret) 266 return ret; 267 } 268 269 if (dr_mask_is_smac_set(&mask.outer)) 270 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx); 271 272 if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) 273 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); 274 275 if (outer_ipv == DR_RULE_IPV6) { 276 if (dr_mask_is_dst_addr_set(&mask.outer)) 277 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, 278 inner, rx); 279 280 if (dr_mask_is_src_addr_set(&mask.outer)) 281 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask, 282 inner, rx); 283 284 if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer)) 285 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask, 286 inner, rx); 287 } else { 288 if (dr_mask_is_ipv4_5_tuple_set(&mask.outer)) 289 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask, 290 inner, rx); 291 292 if (dr_mask_is_ttl_set(&mask.outer)) 293 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask, 294 inner, rx); 295 } 296 297 if (dr_mask_is_flex_parser_tnl_vxlan_gpe_set(&mask, dmn)) 298 mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++], 299 &mask, 300 inner, rx); 301 else if (dr_mask_is_flex_parser_tnl_geneve_set(&mask, dmn)) 302 mlx5dr_ste_build_flex_parser_tnl_geneve(&sb[idx++], 303 &mask, 304 inner, rx); 305 306 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) 307 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx); 308 309 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer)) 310 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx); 311 312 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2)) 313 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask, 314 inner, rx); 315 316 misc3 = &mask.misc3; 317 if ((DR_MASK_IS_FLEX_PARSER_ICMPV4_SET(misc3) && 318 mlx5dr_matcher_supp_flex_parser_icmp_v4(&dmn->info.caps)) || 319 (dr_mask_is_flex_parser_icmpv6_set(&mask.misc3) && 320 mlx5dr_matcher_supp_flex_parser_icmp_v6(&dmn->info.caps))) { 321 ret = mlx5dr_ste_build_flex_parser_1(&sb[idx++], 322 &mask, &dmn->info.caps, 323 inner, rx); 324 if (ret) 325 return ret; 326 } 327 if (dr_mask_is_gre_set(&mask.misc)) 328 mlx5dr_ste_build_gre(&sb[idx++], &mask, inner, rx); 329 } 330 331 /* Inner */ 332 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER | 333 DR_MATCHER_CRITERIA_MISC | 334 DR_MATCHER_CRITERIA_MISC2 | 335 DR_MATCHER_CRITERIA_MISC3)) { 336 inner = true; 337 338 if (dr_mask_is_eth_l2_tnl_set(&mask.misc)) 339 mlx5dr_ste_build_eth_l2_tnl(&sb[idx++], &mask, inner, rx); 340 341 if (dr_mask_is_smac_set(&mask.inner) && 342 dr_mask_is_dmac_set(&mask.inner)) { 343 ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++], 344 &mask, inner, rx); 345 if (ret) 346 return ret; 347 } 348 349 if (dr_mask_is_smac_set(&mask.inner)) 350 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx); 351 352 if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) 353 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); 354 355 if (inner_ipv == DR_RULE_IPV6) { 356 if (dr_mask_is_dst_addr_set(&mask.inner)) 357 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, 358 inner, rx); 359 360 if (dr_mask_is_src_addr_set(&mask.inner)) 361 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask, 362 inner, rx); 363 364 if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner)) 365 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask, 366 inner, rx); 367 } else { 368 if (dr_mask_is_ipv4_5_tuple_set(&mask.inner)) 369 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask, 370 inner, rx); 371 372 if (dr_mask_is_ttl_set(&mask.inner)) 373 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask, 374 inner, rx); 375 } 376 377 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner)) 378 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx); 379 380 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner)) 381 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx); 382 383 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2)) 384 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask, inner, rx); 385 } 386 /* Empty matcher, takes all */ 387 if (matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY) 388 mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx); 389 390 if (idx == 0) { 391 mlx5dr_err(dmn, "Cannot generate any valid rules from mask\n"); 392 return -EINVAL; 393 } 394 395 /* Check that all mask fields were consumed */ 396 for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) { 397 if (((u8 *)&mask)[i] != 0) { 398 mlx5dr_dbg(dmn, "Mask contains unsupported parameters\n"); 399 return -EOPNOTSUPP; 400 } 401 } 402 403 nic_matcher->ste_builder = sb; 404 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; 405 406 return 0; 407 } 408 409 static int dr_matcher_connect(struct mlx5dr_domain *dmn, 410 struct mlx5dr_matcher_rx_tx *curr_nic_matcher, 411 struct mlx5dr_matcher_rx_tx *next_nic_matcher, 412 struct mlx5dr_matcher_rx_tx *prev_nic_matcher) 413 { 414 struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl; 415 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; 416 struct mlx5dr_htbl_connect_info info; 417 struct mlx5dr_ste_htbl *prev_htbl; 418 int ret; 419 420 /* Connect end anchor hash table to next_htbl or to the default address */ 421 if (next_nic_matcher) { 422 info.type = CONNECT_HIT; 423 info.hit_next_htbl = next_nic_matcher->s_htbl; 424 } else { 425 info.type = CONNECT_MISS; 426 info.miss_icm_addr = nic_tbl->default_icm_addr; 427 } 428 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, 429 curr_nic_matcher->e_anchor, 430 &info, info.type == CONNECT_HIT); 431 if (ret) 432 return ret; 433 434 /* Connect start hash table to end anchor */ 435 info.type = CONNECT_MISS; 436 info.miss_icm_addr = curr_nic_matcher->e_anchor->chunk->icm_addr; 437 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, 438 curr_nic_matcher->s_htbl, 439 &info, false); 440 if (ret) 441 return ret; 442 443 /* Connect previous hash table to matcher start hash table */ 444 if (prev_nic_matcher) 445 prev_htbl = prev_nic_matcher->e_anchor; 446 else 447 prev_htbl = nic_tbl->s_anchor; 448 449 info.type = CONNECT_HIT; 450 info.hit_next_htbl = curr_nic_matcher->s_htbl; 451 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl, 452 &info, true); 453 if (ret) 454 return ret; 455 456 /* Update the pointing ste and next hash table */ 457 curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->ste_arr; 458 prev_htbl->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl; 459 460 if (next_nic_matcher) { 461 next_nic_matcher->s_htbl->pointing_ste = curr_nic_matcher->e_anchor->ste_arr; 462 curr_nic_matcher->e_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl; 463 } 464 465 return 0; 466 } 467 468 static int dr_matcher_add_to_tbl(struct mlx5dr_matcher *matcher) 469 { 470 struct mlx5dr_matcher *next_matcher, *prev_matcher, *tmp_matcher; 471 struct mlx5dr_table *tbl = matcher->tbl; 472 struct mlx5dr_domain *dmn = tbl->dmn; 473 bool first = true; 474 int ret; 475 476 next_matcher = NULL; 477 list_for_each_entry(tmp_matcher, &tbl->matcher_list, matcher_list) { 478 if (tmp_matcher->prio >= matcher->prio) { 479 next_matcher = tmp_matcher; 480 break; 481 } 482 first = false; 483 } 484 485 prev_matcher = NULL; 486 if (next_matcher && !first) 487 prev_matcher = list_prev_entry(next_matcher, matcher_list); 488 else if (!first) 489 prev_matcher = list_last_entry(&tbl->matcher_list, 490 struct mlx5dr_matcher, 491 matcher_list); 492 493 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 494 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) { 495 ret = dr_matcher_connect(dmn, &matcher->rx, 496 next_matcher ? &next_matcher->rx : NULL, 497 prev_matcher ? &prev_matcher->rx : NULL); 498 if (ret) 499 return ret; 500 } 501 502 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 503 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) { 504 ret = dr_matcher_connect(dmn, &matcher->tx, 505 next_matcher ? &next_matcher->tx : NULL, 506 prev_matcher ? &prev_matcher->tx : NULL); 507 if (ret) 508 return ret; 509 } 510 511 if (prev_matcher) 512 list_add(&matcher->matcher_list, &prev_matcher->matcher_list); 513 else if (next_matcher) 514 list_add_tail(&matcher->matcher_list, 515 &next_matcher->matcher_list); 516 else 517 list_add(&matcher->matcher_list, &tbl->matcher_list); 518 519 return 0; 520 } 521 522 static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher) 523 { 524 mlx5dr_htbl_put(nic_matcher->s_htbl); 525 mlx5dr_htbl_put(nic_matcher->e_anchor); 526 } 527 528 static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher) 529 { 530 dr_matcher_uninit_nic(&matcher->rx); 531 dr_matcher_uninit_nic(&matcher->tx); 532 } 533 534 static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) 535 { 536 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 537 538 switch (dmn->type) { 539 case MLX5DR_DOMAIN_TYPE_NIC_RX: 540 dr_matcher_uninit_nic(&matcher->rx); 541 break; 542 case MLX5DR_DOMAIN_TYPE_NIC_TX: 543 dr_matcher_uninit_nic(&matcher->tx); 544 break; 545 case MLX5DR_DOMAIN_TYPE_FDB: 546 dr_matcher_uninit_fdb(matcher); 547 break; 548 default: 549 WARN_ON(true); 550 break; 551 } 552 } 553 554 static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, 555 struct mlx5dr_matcher_rx_tx *nic_matcher) 556 { 557 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 558 559 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); 560 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); 561 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); 562 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); 563 564 if (!nic_matcher->ste_builder) { 565 mlx5dr_err(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); 566 return -EINVAL; 567 } 568 569 return 0; 570 } 571 572 static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, 573 struct mlx5dr_matcher_rx_tx *nic_matcher) 574 { 575 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 576 int ret; 577 578 ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); 579 if (ret) 580 return ret; 581 582 nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 583 DR_CHUNK_SIZE_1, 584 MLX5DR_STE_LU_TYPE_DONT_CARE, 585 0); 586 if (!nic_matcher->e_anchor) 587 return -ENOMEM; 588 589 nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 590 DR_CHUNK_SIZE_1, 591 nic_matcher->ste_builder[0].lu_type, 592 nic_matcher->ste_builder[0].byte_mask); 593 if (!nic_matcher->s_htbl) { 594 ret = -ENOMEM; 595 goto free_e_htbl; 596 } 597 598 /* make sure the tables exist while empty */ 599 mlx5dr_htbl_get(nic_matcher->s_htbl); 600 mlx5dr_htbl_get(nic_matcher->e_anchor); 601 602 return 0; 603 604 free_e_htbl: 605 mlx5dr_ste_htbl_free(nic_matcher->e_anchor); 606 return ret; 607 } 608 609 static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher) 610 { 611 int ret; 612 613 ret = dr_matcher_init_nic(matcher, &matcher->rx); 614 if (ret) 615 return ret; 616 617 ret = dr_matcher_init_nic(matcher, &matcher->tx); 618 if (ret) 619 goto uninit_nic_rx; 620 621 return 0; 622 623 uninit_nic_rx: 624 dr_matcher_uninit_nic(&matcher->rx); 625 return ret; 626 } 627 628 static int dr_matcher_init(struct mlx5dr_matcher *matcher, 629 struct mlx5dr_match_parameters *mask) 630 { 631 struct mlx5dr_table *tbl = matcher->tbl; 632 struct mlx5dr_domain *dmn = tbl->dmn; 633 int ret; 634 635 if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) { 636 mlx5dr_err(dmn, "Invalid match criteria attribute\n"); 637 return -EINVAL; 638 } 639 640 if (mask) { 641 if (mask->match_sz > sizeof(struct mlx5dr_match_param)) { 642 mlx5dr_err(dmn, "Invalid match size attribute\n"); 643 return -EINVAL; 644 } 645 mlx5dr_ste_copy_param(matcher->match_criteria, 646 &matcher->mask, mask); 647 } 648 649 switch (dmn->type) { 650 case MLX5DR_DOMAIN_TYPE_NIC_RX: 651 matcher->rx.nic_tbl = &tbl->rx; 652 ret = dr_matcher_init_nic(matcher, &matcher->rx); 653 break; 654 case MLX5DR_DOMAIN_TYPE_NIC_TX: 655 matcher->tx.nic_tbl = &tbl->tx; 656 ret = dr_matcher_init_nic(matcher, &matcher->tx); 657 break; 658 case MLX5DR_DOMAIN_TYPE_FDB: 659 matcher->rx.nic_tbl = &tbl->rx; 660 matcher->tx.nic_tbl = &tbl->tx; 661 ret = dr_matcher_init_fdb(matcher); 662 break; 663 default: 664 WARN_ON(true); 665 return -EINVAL; 666 } 667 668 return ret; 669 } 670 671 struct mlx5dr_matcher * 672 mlx5dr_matcher_create(struct mlx5dr_table *tbl, 673 u32 priority, 674 u8 match_criteria_enable, 675 struct mlx5dr_match_parameters *mask) 676 { 677 struct mlx5dr_matcher *matcher; 678 int ret; 679 680 refcount_inc(&tbl->refcount); 681 682 matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); 683 if (!matcher) 684 goto dec_ref; 685 686 matcher->tbl = tbl; 687 matcher->prio = priority; 688 matcher->match_criteria = match_criteria_enable; 689 refcount_set(&matcher->refcount, 1); 690 INIT_LIST_HEAD(&matcher->matcher_list); 691 692 mlx5dr_domain_lock(tbl->dmn); 693 694 ret = dr_matcher_init(matcher, mask); 695 if (ret) 696 goto free_matcher; 697 698 ret = dr_matcher_add_to_tbl(matcher); 699 if (ret) 700 goto matcher_uninit; 701 702 mlx5dr_domain_unlock(tbl->dmn); 703 704 return matcher; 705 706 matcher_uninit: 707 dr_matcher_uninit(matcher); 708 free_matcher: 709 mlx5dr_domain_unlock(tbl->dmn); 710 kfree(matcher); 711 dec_ref: 712 refcount_dec(&tbl->refcount); 713 return NULL; 714 } 715 716 static int dr_matcher_disconnect(struct mlx5dr_domain *dmn, 717 struct mlx5dr_table_rx_tx *nic_tbl, 718 struct mlx5dr_matcher_rx_tx *next_nic_matcher, 719 struct mlx5dr_matcher_rx_tx *prev_nic_matcher) 720 { 721 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; 722 struct mlx5dr_htbl_connect_info info; 723 struct mlx5dr_ste_htbl *prev_anchor; 724 725 if (prev_nic_matcher) 726 prev_anchor = prev_nic_matcher->e_anchor; 727 else 728 prev_anchor = nic_tbl->s_anchor; 729 730 /* Connect previous anchor hash table to next matcher or to the default address */ 731 if (next_nic_matcher) { 732 info.type = CONNECT_HIT; 733 info.hit_next_htbl = next_nic_matcher->s_htbl; 734 next_nic_matcher->s_htbl->pointing_ste = prev_anchor->ste_arr; 735 prev_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl; 736 } else { 737 info.type = CONNECT_MISS; 738 info.miss_icm_addr = nic_tbl->default_icm_addr; 739 prev_anchor->ste_arr[0].next_htbl = NULL; 740 } 741 742 return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor, 743 &info, true); 744 } 745 746 static int dr_matcher_remove_from_tbl(struct mlx5dr_matcher *matcher) 747 { 748 struct mlx5dr_matcher *prev_matcher, *next_matcher; 749 struct mlx5dr_table *tbl = matcher->tbl; 750 struct mlx5dr_domain *dmn = tbl->dmn; 751 int ret = 0; 752 753 if (list_is_last(&matcher->matcher_list, &tbl->matcher_list)) 754 next_matcher = NULL; 755 else 756 next_matcher = list_next_entry(matcher, matcher_list); 757 758 if (matcher->matcher_list.prev == &tbl->matcher_list) 759 prev_matcher = NULL; 760 else 761 prev_matcher = list_prev_entry(matcher, matcher_list); 762 763 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 764 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) { 765 ret = dr_matcher_disconnect(dmn, &tbl->rx, 766 next_matcher ? &next_matcher->rx : NULL, 767 prev_matcher ? &prev_matcher->rx : NULL); 768 if (ret) 769 return ret; 770 } 771 772 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 773 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) { 774 ret = dr_matcher_disconnect(dmn, &tbl->tx, 775 next_matcher ? &next_matcher->tx : NULL, 776 prev_matcher ? &prev_matcher->tx : NULL); 777 if (ret) 778 return ret; 779 } 780 781 list_del(&matcher->matcher_list); 782 783 return 0; 784 } 785 786 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) 787 { 788 struct mlx5dr_table *tbl = matcher->tbl; 789 790 if (refcount_read(&matcher->refcount) > 1) 791 return -EBUSY; 792 793 mlx5dr_domain_lock(tbl->dmn); 794 795 dr_matcher_remove_from_tbl(matcher); 796 dr_matcher_uninit(matcher); 797 refcount_dec(&matcher->tbl->refcount); 798 799 mlx5dr_domain_unlock(tbl->dmn); 800 kfree(matcher); 801 802 return 0; 803 } 804