root/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dr_mask_is_smac_set
  2. dr_mask_is_dmac_set
  3. dr_mask_is_src_addr_set
  4. dr_mask_is_dst_addr_set
  5. dr_mask_is_l3_base_set
  6. dr_mask_is_tcp_udp_base_set
  7. dr_mask_is_ipv4_set
  8. dr_mask_is_ipv4_5_tuple_set
  9. dr_mask_is_eth_l2_tnl_set
  10. dr_mask_is_ttl_set
  11. dr_mask_is_gre_set
  12. dr_mask_is_flex_parser_tnl_set
  13. dr_mask_is_flex_parser_icmpv6_set
  14. dr_mask_is_wqe_metadata_set
  15. dr_mask_is_reg_c_0_3_set
  16. dr_mask_is_reg_c_4_7_set
  17. dr_mask_is_gvmi_or_qpn_set
  18. dr_matcher_supp_flex_parser_vxlan_gpe
  19. mlx5dr_matcher_select_builders
  20. dr_matcher_set_ste_builders
  21. dr_matcher_connect
  22. dr_matcher_add_to_tbl
  23. dr_matcher_uninit_nic
  24. dr_matcher_uninit_fdb
  25. dr_matcher_uninit
  26. dr_matcher_init_nic
  27. dr_matcher_init_fdb
  28. dr_matcher_init
  29. mlx5dr_matcher_create
  30. dr_matcher_disconnect
  31. dr_matcher_remove_from_tbl
  32. mlx5dr_matcher_destroy

   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 dr_mask_is_flex_parser_tnl_set(struct mlx5dr_match_misc3 *misc3)
 106 {
 107         return (misc3->outer_vxlan_gpe_vni ||
 108                 misc3->outer_vxlan_gpe_next_protocol ||
 109                 misc3->outer_vxlan_gpe_flags);
 110 }
 111 
 112 static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3)
 113 {
 114         return (misc3->icmpv6_type || misc3->icmpv6_code ||
 115                 misc3->icmpv6_header_data);
 116 }
 117 
 118 static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2)
 119 {
 120         return misc2->metadata_reg_a;
 121 }
 122 
 123 static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2)
 124 {
 125         return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 ||
 126                 misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3);
 127 }
 128 
 129 static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2)
 130 {
 131         return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 ||
 132                 misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7);
 133 }
 134 
 135 static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc)
 136 {
 137         return (misc->source_sqn || misc->source_port);
 138 }
 139 
 140 static bool
 141 dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_domain *dmn)
 142 {
 143         return dmn->info.caps.flex_protocols &
 144                MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED;
 145 }
 146 
 147 int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher,
 148                                    struct mlx5dr_matcher_rx_tx *nic_matcher,
 149                                    bool ipv6)
 150 {
 151         if (ipv6) {
 152                 nic_matcher->ste_builder = nic_matcher->ste_builder6;
 153                 nic_matcher->num_of_builders = nic_matcher->num_of_builders6;
 154         } else {
 155                 nic_matcher->ste_builder = nic_matcher->ste_builder4;
 156                 nic_matcher->num_of_builders = nic_matcher->num_of_builders4;
 157         }
 158 
 159         if (!nic_matcher->num_of_builders) {
 160                 mlx5dr_dbg(matcher->tbl->dmn,
 161                            "Rule not supported on this matcher due to IP related fields\n");
 162                 return -EINVAL;
 163         }
 164 
 165         return 0;
 166 }
 167 
 168 static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher,
 169                                        struct mlx5dr_matcher_rx_tx *nic_matcher,
 170                                        bool ipv6)
 171 {
 172         struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn;
 173         struct mlx5dr_domain *dmn = matcher->tbl->dmn;
 174         struct mlx5dr_match_param mask = {};
 175         struct mlx5dr_match_misc3 *misc3;
 176         struct mlx5dr_ste_build *sb;
 177         u8 *num_of_builders;
 178         bool inner, rx;
 179         int idx = 0;
 180         int ret, i;
 181 
 182         if (ipv6) {
 183                 sb = nic_matcher->ste_builder6;
 184                 num_of_builders = &nic_matcher->num_of_builders6;
 185         } else {
 186                 sb = nic_matcher->ste_builder4;
 187                 num_of_builders = &nic_matcher->num_of_builders4;
 188         }
 189 
 190         rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX;
 191 
 192         /* Create a temporary mask to track and clear used mask fields */
 193         if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER)
 194                 mask.outer = matcher->mask.outer;
 195 
 196         if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC)
 197                 mask.misc = matcher->mask.misc;
 198 
 199         if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER)
 200                 mask.inner = matcher->mask.inner;
 201 
 202         if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2)
 203                 mask.misc2 = matcher->mask.misc2;
 204 
 205         if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3)
 206                 mask.misc3 = matcher->mask.misc3;
 207 
 208         ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria,
 209                                          &matcher->mask, NULL);
 210         if (ret)
 211                 return ret;
 212 
 213         /* Outer */
 214         if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER |
 215                                        DR_MATCHER_CRITERIA_MISC |
 216                                        DR_MATCHER_CRITERIA_MISC2 |
 217                                        DR_MATCHER_CRITERIA_MISC3)) {
 218                 inner = false;
 219 
 220                 if (dr_mask_is_wqe_metadata_set(&mask.misc2))
 221                         mlx5dr_ste_build_general_purpose(&sb[idx++], &mask, inner, rx);
 222 
 223                 if (dr_mask_is_reg_c_0_3_set(&mask.misc2))
 224                         mlx5dr_ste_build_register_0(&sb[idx++], &mask, inner, rx);
 225 
 226                 if (dr_mask_is_reg_c_4_7_set(&mask.misc2))
 227                         mlx5dr_ste_build_register_1(&sb[idx++], &mask, inner, rx);
 228 
 229                 if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) &&
 230                     (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
 231                      dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) {
 232                         ret = mlx5dr_ste_build_src_gvmi_qpn(&sb[idx++], &mask,
 233                                                             dmn, inner, rx);
 234                         if (ret)
 235                                 return ret;
 236                 }
 237 
 238                 if (dr_mask_is_smac_set(&mask.outer) &&
 239                     dr_mask_is_dmac_set(&mask.outer)) {
 240                         ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++], &mask,
 241                                                               inner, rx);
 242                         if (ret)
 243                                 return ret;
 244                 }
 245 
 246                 if (dr_mask_is_smac_set(&mask.outer))
 247                         mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
 248 
 249                 if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer))
 250                         mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
 251 
 252                 if (ipv6) {
 253                         if (dr_mask_is_dst_addr_set(&mask.outer))
 254                                 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
 255                                                                  inner, rx);
 256 
 257                         if (dr_mask_is_src_addr_set(&mask.outer))
 258                                 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
 259                                                                  inner, rx);
 260 
 261                         if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer))
 262                                 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
 263                                                             inner, rx);
 264                 } else {
 265                         if (dr_mask_is_ipv4_5_tuple_set(&mask.outer))
 266                                 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
 267                                                                      inner, rx);
 268 
 269                         if (dr_mask_is_ttl_set(&mask.outer))
 270                                 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
 271                                                                   inner, rx);
 272                 }
 273 
 274                 if (dr_mask_is_flex_parser_tnl_set(&mask.misc3) &&
 275                     dr_matcher_supp_flex_parser_vxlan_gpe(dmn))
 276                         mlx5dr_ste_build_flex_parser_tnl(&sb[idx++], &mask,
 277                                                          inner, rx);
 278 
 279                 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer))
 280                         mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
 281 
 282                 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer))
 283                         mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
 284 
 285                 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
 286                         mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask,
 287                                                        inner, rx);
 288 
 289                 misc3 = &mask.misc3;
 290                 if ((DR_MASK_IS_FLEX_PARSER_ICMPV4_SET(misc3) &&
 291                      mlx5dr_matcher_supp_flex_parser_icmp_v4(&dmn->info.caps)) ||
 292                     (dr_mask_is_flex_parser_icmpv6_set(&mask.misc3) &&
 293                      mlx5dr_matcher_supp_flex_parser_icmp_v6(&dmn->info.caps))) {
 294                         ret = mlx5dr_ste_build_flex_parser_1(&sb[idx++],
 295                                                              &mask, &dmn->info.caps,
 296                                                              inner, rx);
 297                         if (ret)
 298                                 return ret;
 299                 }
 300                 if (dr_mask_is_gre_set(&mask.misc))
 301                         mlx5dr_ste_build_gre(&sb[idx++], &mask, inner, rx);
 302         }
 303 
 304         /* Inner */
 305         if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER |
 306                                        DR_MATCHER_CRITERIA_MISC |
 307                                        DR_MATCHER_CRITERIA_MISC2 |
 308                                        DR_MATCHER_CRITERIA_MISC3)) {
 309                 inner = true;
 310 
 311                 if (dr_mask_is_eth_l2_tnl_set(&mask.misc))
 312                         mlx5dr_ste_build_eth_l2_tnl(&sb[idx++], &mask, inner, rx);
 313 
 314                 if (dr_mask_is_smac_set(&mask.inner) &&
 315                     dr_mask_is_dmac_set(&mask.inner)) {
 316                         ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++],
 317                                                               &mask, inner, rx);
 318                         if (ret)
 319                                 return ret;
 320                 }
 321 
 322                 if (dr_mask_is_smac_set(&mask.inner))
 323                         mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
 324 
 325                 if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner))
 326                         mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
 327 
 328                 if (ipv6) {
 329                         if (dr_mask_is_dst_addr_set(&mask.inner))
 330                                 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
 331                                                                  inner, rx);
 332 
 333                         if (dr_mask_is_src_addr_set(&mask.inner))
 334                                 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
 335                                                                  inner, rx);
 336 
 337                         if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner))
 338                                 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
 339                                                             inner, rx);
 340                 } else {
 341                         if (dr_mask_is_ipv4_5_tuple_set(&mask.inner))
 342                                 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
 343                                                                      inner, rx);
 344 
 345                         if (dr_mask_is_ttl_set(&mask.inner))
 346                                 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
 347                                                                   inner, rx);
 348                 }
 349 
 350                 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner))
 351                         mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
 352 
 353                 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner))
 354                         mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
 355 
 356                 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
 357                         mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask, inner, rx);
 358         }
 359         /* Empty matcher, takes all */
 360         if (matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY)
 361                 mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx);
 362 
 363         if (idx == 0) {
 364                 mlx5dr_dbg(dmn, "Cannot generate any valid rules from mask\n");
 365                 return -EINVAL;
 366         }
 367 
 368         /* Check that all mask fields were consumed */
 369         for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) {
 370                 if (((u8 *)&mask)[i] != 0) {
 371                         mlx5dr_info(dmn, "Mask contains unsupported parameters\n");
 372                         return -EOPNOTSUPP;
 373                 }
 374         }
 375 
 376         *num_of_builders = idx;
 377 
 378         return 0;
 379 }
 380 
 381 static int dr_matcher_connect(struct mlx5dr_domain *dmn,
 382                               struct mlx5dr_matcher_rx_tx *curr_nic_matcher,
 383                               struct mlx5dr_matcher_rx_tx *next_nic_matcher,
 384                               struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
 385 {
 386         struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl;
 387         struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
 388         struct mlx5dr_htbl_connect_info info;
 389         struct mlx5dr_ste_htbl *prev_htbl;
 390         int ret;
 391 
 392         /* Connect end anchor hash table to next_htbl or to the default address */
 393         if (next_nic_matcher) {
 394                 info.type = CONNECT_HIT;
 395                 info.hit_next_htbl = next_nic_matcher->s_htbl;
 396         } else {
 397                 info.type = CONNECT_MISS;
 398                 info.miss_icm_addr = nic_tbl->default_icm_addr;
 399         }
 400         ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
 401                                                 curr_nic_matcher->e_anchor,
 402                                                 &info, info.type == CONNECT_HIT);
 403         if (ret)
 404                 return ret;
 405 
 406         /* Connect start hash table to end anchor */
 407         info.type = CONNECT_MISS;
 408         info.miss_icm_addr = curr_nic_matcher->e_anchor->chunk->icm_addr;
 409         ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
 410                                                 curr_nic_matcher->s_htbl,
 411                                                 &info, false);
 412         if (ret)
 413                 return ret;
 414 
 415         /* Connect previous hash table to matcher start hash table */
 416         if (prev_nic_matcher)
 417                 prev_htbl = prev_nic_matcher->e_anchor;
 418         else
 419                 prev_htbl = nic_tbl->s_anchor;
 420 
 421         info.type = CONNECT_HIT;
 422         info.hit_next_htbl = curr_nic_matcher->s_htbl;
 423         ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl,
 424                                                 &info, true);
 425         if (ret)
 426                 return ret;
 427 
 428         /* Update the pointing ste and next hash table */
 429         curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->ste_arr;
 430         prev_htbl->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl;
 431 
 432         if (next_nic_matcher) {
 433                 next_nic_matcher->s_htbl->pointing_ste = curr_nic_matcher->e_anchor->ste_arr;
 434                 curr_nic_matcher->e_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
 435         }
 436 
 437         return 0;
 438 }
 439 
 440 static int dr_matcher_add_to_tbl(struct mlx5dr_matcher *matcher)
 441 {
 442         struct mlx5dr_matcher *next_matcher, *prev_matcher, *tmp_matcher;
 443         struct mlx5dr_table *tbl = matcher->tbl;
 444         struct mlx5dr_domain *dmn = tbl->dmn;
 445         bool first = true;
 446         int ret;
 447 
 448         next_matcher = NULL;
 449         if (!list_empty(&tbl->matcher_list))
 450                 list_for_each_entry(tmp_matcher, &tbl->matcher_list, matcher_list) {
 451                         if (tmp_matcher->prio >= matcher->prio) {
 452                                 next_matcher = tmp_matcher;
 453                                 break;
 454                         }
 455                         first = false;
 456                 }
 457 
 458         prev_matcher = NULL;
 459         if (next_matcher && !first)
 460                 prev_matcher = list_prev_entry(next_matcher, matcher_list);
 461         else if (!first)
 462                 prev_matcher = list_last_entry(&tbl->matcher_list,
 463                                                struct mlx5dr_matcher,
 464                                                matcher_list);
 465 
 466         if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
 467             dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
 468                 ret = dr_matcher_connect(dmn, &matcher->rx,
 469                                          next_matcher ? &next_matcher->rx : NULL,
 470                                          prev_matcher ? &prev_matcher->rx : NULL);
 471                 if (ret)
 472                         return ret;
 473         }
 474 
 475         if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
 476             dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
 477                 ret = dr_matcher_connect(dmn, &matcher->tx,
 478                                          next_matcher ? &next_matcher->tx : NULL,
 479                                          prev_matcher ? &prev_matcher->tx : NULL);
 480                 if (ret)
 481                         return ret;
 482         }
 483 
 484         if (prev_matcher)
 485                 list_add(&matcher->matcher_list, &prev_matcher->matcher_list);
 486         else if (next_matcher)
 487                 list_add_tail(&matcher->matcher_list,
 488                               &next_matcher->matcher_list);
 489         else
 490                 list_add(&matcher->matcher_list, &tbl->matcher_list);
 491 
 492         return 0;
 493 }
 494 
 495 static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher)
 496 {
 497         mlx5dr_htbl_put(nic_matcher->s_htbl);
 498         mlx5dr_htbl_put(nic_matcher->e_anchor);
 499 }
 500 
 501 static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher)
 502 {
 503         dr_matcher_uninit_nic(&matcher->rx);
 504         dr_matcher_uninit_nic(&matcher->tx);
 505 }
 506 
 507 static void dr_matcher_uninit(struct mlx5dr_matcher *matcher)
 508 {
 509         struct mlx5dr_domain *dmn = matcher->tbl->dmn;
 510 
 511         switch (dmn->type) {
 512         case MLX5DR_DOMAIN_TYPE_NIC_RX:
 513                 dr_matcher_uninit_nic(&matcher->rx);
 514                 break;
 515         case MLX5DR_DOMAIN_TYPE_NIC_TX:
 516                 dr_matcher_uninit_nic(&matcher->tx);
 517                 break;
 518         case MLX5DR_DOMAIN_TYPE_FDB:
 519                 dr_matcher_uninit_fdb(matcher);
 520                 break;
 521         default:
 522                 WARN_ON(true);
 523                 break;
 524         }
 525 }
 526 
 527 static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher,
 528                                struct mlx5dr_matcher_rx_tx *nic_matcher)
 529 {
 530         struct mlx5dr_domain *dmn = matcher->tbl->dmn;
 531         int ret, ret_v4, ret_v6;
 532 
 533         ret_v4 = dr_matcher_set_ste_builders(matcher, nic_matcher, false);
 534         ret_v6 = dr_matcher_set_ste_builders(matcher, nic_matcher, true);
 535 
 536         if (ret_v4 && ret_v6) {
 537                 mlx5dr_dbg(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n");
 538                 return -EINVAL;
 539         }
 540 
 541         if (!ret_v4)
 542                 nic_matcher->ste_builder = nic_matcher->ste_builder4;
 543         else
 544                 nic_matcher->ste_builder = nic_matcher->ste_builder6;
 545 
 546         nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
 547                                                       DR_CHUNK_SIZE_1,
 548                                                       MLX5DR_STE_LU_TYPE_DONT_CARE,
 549                                                       0);
 550         if (!nic_matcher->e_anchor)
 551                 return -ENOMEM;
 552 
 553         nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
 554                                                     DR_CHUNK_SIZE_1,
 555                                                     nic_matcher->ste_builder[0].lu_type,
 556                                                     nic_matcher->ste_builder[0].byte_mask);
 557         if (!nic_matcher->s_htbl) {
 558                 ret = -ENOMEM;
 559                 goto free_e_htbl;
 560         }
 561 
 562         /* make sure the tables exist while empty */
 563         mlx5dr_htbl_get(nic_matcher->s_htbl);
 564         mlx5dr_htbl_get(nic_matcher->e_anchor);
 565 
 566         return 0;
 567 
 568 free_e_htbl:
 569         mlx5dr_ste_htbl_free(nic_matcher->e_anchor);
 570         return ret;
 571 }
 572 
 573 static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher)
 574 {
 575         int ret;
 576 
 577         ret = dr_matcher_init_nic(matcher, &matcher->rx);
 578         if (ret)
 579                 return ret;
 580 
 581         ret = dr_matcher_init_nic(matcher, &matcher->tx);
 582         if (ret)
 583                 goto uninit_nic_rx;
 584 
 585         return 0;
 586 
 587 uninit_nic_rx:
 588         dr_matcher_uninit_nic(&matcher->rx);
 589         return ret;
 590 }
 591 
 592 static int dr_matcher_init(struct mlx5dr_matcher *matcher,
 593                            struct mlx5dr_match_parameters *mask)
 594 {
 595         struct mlx5dr_table *tbl = matcher->tbl;
 596         struct mlx5dr_domain *dmn = tbl->dmn;
 597         int ret;
 598 
 599         if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) {
 600                 mlx5dr_info(dmn, "Invalid match criteria attribute\n");
 601                 return -EINVAL;
 602         }
 603 
 604         if (mask) {
 605                 if (mask->match_sz > sizeof(struct mlx5dr_match_param)) {
 606                         mlx5dr_info(dmn, "Invalid match size attribute\n");
 607                         return -EINVAL;
 608                 }
 609                 mlx5dr_ste_copy_param(matcher->match_criteria,
 610                                       &matcher->mask, mask);
 611         }
 612 
 613         switch (dmn->type) {
 614         case MLX5DR_DOMAIN_TYPE_NIC_RX:
 615                 matcher->rx.nic_tbl = &tbl->rx;
 616                 ret = dr_matcher_init_nic(matcher, &matcher->rx);
 617                 break;
 618         case MLX5DR_DOMAIN_TYPE_NIC_TX:
 619                 matcher->tx.nic_tbl = &tbl->tx;
 620                 ret = dr_matcher_init_nic(matcher, &matcher->tx);
 621                 break;
 622         case MLX5DR_DOMAIN_TYPE_FDB:
 623                 matcher->rx.nic_tbl = &tbl->rx;
 624                 matcher->tx.nic_tbl = &tbl->tx;
 625                 ret = dr_matcher_init_fdb(matcher);
 626                 break;
 627         default:
 628                 WARN_ON(true);
 629                 return -EINVAL;
 630         }
 631 
 632         return ret;
 633 }
 634 
 635 struct mlx5dr_matcher *
 636 mlx5dr_matcher_create(struct mlx5dr_table *tbl,
 637                       u16 priority,
 638                       u8 match_criteria_enable,
 639                       struct mlx5dr_match_parameters *mask)
 640 {
 641         struct mlx5dr_matcher *matcher;
 642         int ret;
 643 
 644         refcount_inc(&tbl->refcount);
 645 
 646         matcher = kzalloc(sizeof(*matcher), GFP_KERNEL);
 647         if (!matcher)
 648                 goto dec_ref;
 649 
 650         matcher->tbl = tbl;
 651         matcher->prio = priority;
 652         matcher->match_criteria = match_criteria_enable;
 653         refcount_set(&matcher->refcount, 1);
 654         INIT_LIST_HEAD(&matcher->matcher_list);
 655 
 656         mutex_lock(&tbl->dmn->mutex);
 657 
 658         ret = dr_matcher_init(matcher, mask);
 659         if (ret)
 660                 goto free_matcher;
 661 
 662         ret = dr_matcher_add_to_tbl(matcher);
 663         if (ret)
 664                 goto matcher_uninit;
 665 
 666         mutex_unlock(&tbl->dmn->mutex);
 667 
 668         return matcher;
 669 
 670 matcher_uninit:
 671         dr_matcher_uninit(matcher);
 672 free_matcher:
 673         mutex_unlock(&tbl->dmn->mutex);
 674         kfree(matcher);
 675 dec_ref:
 676         refcount_dec(&tbl->refcount);
 677         return NULL;
 678 }
 679 
 680 static int dr_matcher_disconnect(struct mlx5dr_domain *dmn,
 681                                  struct mlx5dr_table_rx_tx *nic_tbl,
 682                                  struct mlx5dr_matcher_rx_tx *next_nic_matcher,
 683                                  struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
 684 {
 685         struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
 686         struct mlx5dr_htbl_connect_info info;
 687         struct mlx5dr_ste_htbl *prev_anchor;
 688 
 689         if (prev_nic_matcher)
 690                 prev_anchor = prev_nic_matcher->e_anchor;
 691         else
 692                 prev_anchor = nic_tbl->s_anchor;
 693 
 694         /* Connect previous anchor hash table to next matcher or to the default address */
 695         if (next_nic_matcher) {
 696                 info.type = CONNECT_HIT;
 697                 info.hit_next_htbl = next_nic_matcher->s_htbl;
 698                 next_nic_matcher->s_htbl->pointing_ste = prev_anchor->ste_arr;
 699                 prev_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
 700         } else {
 701                 info.type = CONNECT_MISS;
 702                 info.miss_icm_addr = nic_tbl->default_icm_addr;
 703                 prev_anchor->ste_arr[0].next_htbl = NULL;
 704         }
 705 
 706         return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor,
 707                                                  &info, true);
 708 }
 709 
 710 static int dr_matcher_remove_from_tbl(struct mlx5dr_matcher *matcher)
 711 {
 712         struct mlx5dr_matcher *prev_matcher, *next_matcher;
 713         struct mlx5dr_table *tbl = matcher->tbl;
 714         struct mlx5dr_domain *dmn = tbl->dmn;
 715         int ret = 0;
 716 
 717         if (list_is_last(&matcher->matcher_list, &tbl->matcher_list))
 718                 next_matcher = NULL;
 719         else
 720                 next_matcher = list_next_entry(matcher, matcher_list);
 721 
 722         if (matcher->matcher_list.prev == &tbl->matcher_list)
 723                 prev_matcher = NULL;
 724         else
 725                 prev_matcher = list_prev_entry(matcher, matcher_list);
 726 
 727         if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
 728             dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
 729                 ret = dr_matcher_disconnect(dmn, &tbl->rx,
 730                                             next_matcher ? &next_matcher->rx : NULL,
 731                                             prev_matcher ? &prev_matcher->rx : NULL);
 732                 if (ret)
 733                         return ret;
 734         }
 735 
 736         if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
 737             dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
 738                 ret = dr_matcher_disconnect(dmn, &tbl->tx,
 739                                             next_matcher ? &next_matcher->tx : NULL,
 740                                             prev_matcher ? &prev_matcher->tx : NULL);
 741                 if (ret)
 742                         return ret;
 743         }
 744 
 745         list_del(&matcher->matcher_list);
 746 
 747         return 0;
 748 }
 749 
 750 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher)
 751 {
 752         struct mlx5dr_table *tbl = matcher->tbl;
 753 
 754         if (refcount_read(&matcher->refcount) > 1)
 755                 return -EBUSY;
 756 
 757         mutex_lock(&tbl->dmn->mutex);
 758 
 759         dr_matcher_remove_from_tbl(matcher);
 760         dr_matcher_uninit(matcher);
 761         refcount_dec(&matcher->tbl->refcount);
 762 
 763         mutex_unlock(&tbl->dmn->mutex);
 764         kfree(matcher);
 765 
 766         return 0;
 767 }

/* [<][>][^][v][top][bottom][index][help] */