1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies. */
3
4 #include "dr_types.h"
5
dr_mask_is_smac_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_dmac_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_src_addr_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_dst_addr_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_l3_base_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_ipv4_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc * misc)52 static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc)
53 {
54 return misc->vxlan_vni;
55 }
56
dr_mask_is_ttl_set(struct mlx5dr_match_spec * spec)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
dr_mask_is_gre_set(struct mlx5dr_match_misc * misc)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_misc3_vxlan_gpe_set(struct mlx5dr_match_misc3 * misc3)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
dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_cmd_caps * caps)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
dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param * mask,struct mlx5dr_domain * dmn)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
dr_mask_is_misc_geneve_set(struct mlx5dr_match_misc * misc)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
dr_matcher_supp_flex_parser_geneve(struct mlx5dr_cmd_caps * caps)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
dr_mask_is_flex_parser_tnl_geneve_set(struct mlx5dr_match_param * mask,struct mlx5dr_domain * dmn)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
dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 * misc3)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
dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 * misc2)157 static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2)
158 {
159 return misc2->metadata_reg_a;
160 }
161
dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 * misc2)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
dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 * misc2)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
dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc * misc)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
mlx5dr_matcher_select_builders(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,enum mlx5dr_ipv outer_ipv,enum mlx5dr_ipv inner_ipv)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
dr_matcher_set_ste_builders(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,enum mlx5dr_ipv outer_ipv,enum mlx5dr_ipv inner_ipv)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_ste_build *sb;
207 bool inner, rx;
208 int idx = 0;
209 int ret, i;
210
211 sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv];
212 rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX;
213
214 /* Create a temporary mask to track and clear used mask fields */
215 if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER)
216 mask.outer = matcher->mask.outer;
217
218 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC)
219 mask.misc = matcher->mask.misc;
220
221 if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER)
222 mask.inner = matcher->mask.inner;
223
224 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2)
225 mask.misc2 = matcher->mask.misc2;
226
227 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3)
228 mask.misc3 = matcher->mask.misc3;
229
230 ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria,
231 &matcher->mask, NULL);
232 if (ret)
233 return ret;
234
235 /* Outer */
236 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER |
237 DR_MATCHER_CRITERIA_MISC |
238 DR_MATCHER_CRITERIA_MISC2 |
239 DR_MATCHER_CRITERIA_MISC3)) {
240 inner = false;
241
242 if (dr_mask_is_wqe_metadata_set(&mask.misc2))
243 mlx5dr_ste_build_general_purpose(&sb[idx++], &mask, inner, rx);
244
245 if (dr_mask_is_reg_c_0_3_set(&mask.misc2))
246 mlx5dr_ste_build_register_0(&sb[idx++], &mask, inner, rx);
247
248 if (dr_mask_is_reg_c_4_7_set(&mask.misc2))
249 mlx5dr_ste_build_register_1(&sb[idx++], &mask, inner, rx);
250
251 if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) &&
252 (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
253 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) {
254 mlx5dr_ste_build_src_gvmi_qpn(&sb[idx++], &mask,
255 dmn, inner, rx);
256 }
257
258 if (dr_mask_is_smac_set(&mask.outer) &&
259 dr_mask_is_dmac_set(&mask.outer)) {
260 mlx5dr_ste_build_eth_l2_src_des(&sb[idx++], &mask,
261 inner, rx);
262 }
263
264 if (dr_mask_is_smac_set(&mask.outer))
265 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
266
267 if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer))
268 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
269
270 if (outer_ipv == DR_RULE_IPV6) {
271 if (dr_mask_is_dst_addr_set(&mask.outer))
272 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
273 inner, rx);
274
275 if (dr_mask_is_src_addr_set(&mask.outer))
276 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
277 inner, rx);
278
279 if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer))
280 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
281 inner, rx);
282 } else {
283 if (dr_mask_is_ipv4_5_tuple_set(&mask.outer))
284 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
285 inner, rx);
286
287 if (dr_mask_is_ttl_set(&mask.outer))
288 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
289 inner, rx);
290 }
291
292 if (dr_mask_is_flex_parser_tnl_vxlan_gpe_set(&mask, dmn))
293 mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++],
294 &mask,
295 inner, rx);
296 else if (dr_mask_is_flex_parser_tnl_geneve_set(&mask, dmn))
297 mlx5dr_ste_build_flex_parser_tnl_geneve(&sb[idx++],
298 &mask,
299 inner, rx);
300
301 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer))
302 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
303
304 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer))
305 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
306
307 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
308 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask,
309 inner, rx);
310
311 if ((DR_MASK_IS_FLEX_PARSER_ICMPV4_SET(&mask.misc3) &&
312 mlx5dr_matcher_supp_flex_parser_icmp_v4(&dmn->info.caps)) ||
313 (dr_mask_is_flex_parser_icmpv6_set(&mask.misc3) &&
314 mlx5dr_matcher_supp_flex_parser_icmp_v6(&dmn->info.caps))) {
315 ret = mlx5dr_ste_build_flex_parser_1(&sb[idx++],
316 &mask, &dmn->info.caps,
317 inner, rx);
318 if (ret)
319 return ret;
320 }
321 if (dr_mask_is_gre_set(&mask.misc))
322 mlx5dr_ste_build_gre(&sb[idx++], &mask, inner, rx);
323 }
324
325 /* Inner */
326 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER |
327 DR_MATCHER_CRITERIA_MISC |
328 DR_MATCHER_CRITERIA_MISC2 |
329 DR_MATCHER_CRITERIA_MISC3)) {
330 inner = true;
331
332 if (dr_mask_is_eth_l2_tnl_set(&mask.misc))
333 mlx5dr_ste_build_eth_l2_tnl(&sb[idx++], &mask, inner, rx);
334
335 if (dr_mask_is_smac_set(&mask.inner) &&
336 dr_mask_is_dmac_set(&mask.inner)) {
337 mlx5dr_ste_build_eth_l2_src_des(&sb[idx++],
338 &mask, inner, rx);
339 }
340
341 if (dr_mask_is_smac_set(&mask.inner))
342 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
343
344 if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner))
345 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
346
347 if (inner_ipv == DR_RULE_IPV6) {
348 if (dr_mask_is_dst_addr_set(&mask.inner))
349 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
350 inner, rx);
351
352 if (dr_mask_is_src_addr_set(&mask.inner))
353 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
354 inner, rx);
355
356 if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner))
357 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
358 inner, rx);
359 } else {
360 if (dr_mask_is_ipv4_5_tuple_set(&mask.inner))
361 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
362 inner, rx);
363
364 if (dr_mask_is_ttl_set(&mask.inner))
365 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
366 inner, rx);
367 }
368
369 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner))
370 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
371
372 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner))
373 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
374
375 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
376 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask, inner, rx);
377 }
378 /* Empty matcher, takes all */
379 if (matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY)
380 mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx);
381
382 if (idx == 0) {
383 mlx5dr_err(dmn, "Cannot generate any valid rules from mask\n");
384 return -EINVAL;
385 }
386
387 /* Check that all mask fields were consumed */
388 for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) {
389 if (((u8 *)&mask)[i] != 0) {
390 mlx5dr_dbg(dmn, "Mask contains unsupported parameters\n");
391 return -EOPNOTSUPP;
392 }
393 }
394
395 nic_matcher->ste_builder = sb;
396 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx;
397
398 return 0;
399 }
400
dr_matcher_connect(struct mlx5dr_domain * dmn,struct mlx5dr_matcher_rx_tx * curr_nic_matcher,struct mlx5dr_matcher_rx_tx * next_nic_matcher,struct mlx5dr_matcher_rx_tx * prev_nic_matcher)401 static int dr_matcher_connect(struct mlx5dr_domain *dmn,
402 struct mlx5dr_matcher_rx_tx *curr_nic_matcher,
403 struct mlx5dr_matcher_rx_tx *next_nic_matcher,
404 struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
405 {
406 struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl;
407 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
408 struct mlx5dr_htbl_connect_info info;
409 struct mlx5dr_ste_htbl *prev_htbl;
410 int ret;
411
412 /* Connect end anchor hash table to next_htbl or to the default address */
413 if (next_nic_matcher) {
414 info.type = CONNECT_HIT;
415 info.hit_next_htbl = next_nic_matcher->s_htbl;
416 } else {
417 info.type = CONNECT_MISS;
418 info.miss_icm_addr = nic_tbl->default_icm_addr;
419 }
420 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
421 curr_nic_matcher->e_anchor,
422 &info, info.type == CONNECT_HIT);
423 if (ret)
424 return ret;
425
426 /* Connect start hash table to end anchor */
427 info.type = CONNECT_MISS;
428 info.miss_icm_addr = curr_nic_matcher->e_anchor->chunk->icm_addr;
429 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
430 curr_nic_matcher->s_htbl,
431 &info, false);
432 if (ret)
433 return ret;
434
435 /* Connect previous hash table to matcher start hash table */
436 if (prev_nic_matcher)
437 prev_htbl = prev_nic_matcher->e_anchor;
438 else
439 prev_htbl = nic_tbl->s_anchor;
440
441 info.type = CONNECT_HIT;
442 info.hit_next_htbl = curr_nic_matcher->s_htbl;
443 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl,
444 &info, true);
445 if (ret)
446 return ret;
447
448 /* Update the pointing ste and next hash table */
449 curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->ste_arr;
450 prev_htbl->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl;
451
452 if (next_nic_matcher) {
453 next_nic_matcher->s_htbl->pointing_ste = curr_nic_matcher->e_anchor->ste_arr;
454 curr_nic_matcher->e_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
455 }
456
457 return 0;
458 }
459
dr_matcher_add_to_tbl(struct mlx5dr_matcher * matcher)460 static int dr_matcher_add_to_tbl(struct mlx5dr_matcher *matcher)
461 {
462 struct mlx5dr_matcher *next_matcher, *prev_matcher, *tmp_matcher;
463 struct mlx5dr_table *tbl = matcher->tbl;
464 struct mlx5dr_domain *dmn = tbl->dmn;
465 bool first = true;
466 int ret;
467
468 next_matcher = NULL;
469 list_for_each_entry(tmp_matcher, &tbl->matcher_list, matcher_list) {
470 if (tmp_matcher->prio >= matcher->prio) {
471 next_matcher = tmp_matcher;
472 break;
473 }
474 first = false;
475 }
476
477 prev_matcher = NULL;
478 if (next_matcher && !first)
479 prev_matcher = list_prev_entry(next_matcher, matcher_list);
480 else if (!first)
481 prev_matcher = list_last_entry(&tbl->matcher_list,
482 struct mlx5dr_matcher,
483 matcher_list);
484
485 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
486 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
487 ret = dr_matcher_connect(dmn, &matcher->rx,
488 next_matcher ? &next_matcher->rx : NULL,
489 prev_matcher ? &prev_matcher->rx : NULL);
490 if (ret)
491 return ret;
492 }
493
494 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
495 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
496 ret = dr_matcher_connect(dmn, &matcher->tx,
497 next_matcher ? &next_matcher->tx : NULL,
498 prev_matcher ? &prev_matcher->tx : NULL);
499 if (ret)
500 return ret;
501 }
502
503 if (prev_matcher)
504 list_add(&matcher->matcher_list, &prev_matcher->matcher_list);
505 else if (next_matcher)
506 list_add_tail(&matcher->matcher_list,
507 &next_matcher->matcher_list);
508 else
509 list_add(&matcher->matcher_list, &tbl->matcher_list);
510
511 return 0;
512 }
513
dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx * nic_matcher)514 static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher)
515 {
516 mlx5dr_htbl_put(nic_matcher->s_htbl);
517 mlx5dr_htbl_put(nic_matcher->e_anchor);
518 }
519
dr_matcher_uninit_fdb(struct mlx5dr_matcher * matcher)520 static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher)
521 {
522 dr_matcher_uninit_nic(&matcher->rx);
523 dr_matcher_uninit_nic(&matcher->tx);
524 }
525
dr_matcher_uninit(struct mlx5dr_matcher * matcher)526 static void dr_matcher_uninit(struct mlx5dr_matcher *matcher)
527 {
528 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
529
530 switch (dmn->type) {
531 case MLX5DR_DOMAIN_TYPE_NIC_RX:
532 dr_matcher_uninit_nic(&matcher->rx);
533 break;
534 case MLX5DR_DOMAIN_TYPE_NIC_TX:
535 dr_matcher_uninit_nic(&matcher->tx);
536 break;
537 case MLX5DR_DOMAIN_TYPE_FDB:
538 dr_matcher_uninit_fdb(matcher);
539 break;
540 default:
541 WARN_ON(true);
542 break;
543 }
544 }
545
dr_matcher_set_all_ste_builders(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher)546 static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher,
547 struct mlx5dr_matcher_rx_tx *nic_matcher)
548 {
549 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
550
551 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4);
552 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6);
553 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4);
554 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6);
555
556 if (!nic_matcher->ste_builder) {
557 mlx5dr_err(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n");
558 return -EINVAL;
559 }
560
561 return 0;
562 }
563
dr_matcher_init_nic(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher)564 static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher,
565 struct mlx5dr_matcher_rx_tx *nic_matcher)
566 {
567 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
568 int ret;
569
570 ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher);
571 if (ret)
572 return ret;
573
574 nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
575 DR_CHUNK_SIZE_1,
576 MLX5DR_STE_LU_TYPE_DONT_CARE,
577 0);
578 if (!nic_matcher->e_anchor)
579 return -ENOMEM;
580
581 nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
582 DR_CHUNK_SIZE_1,
583 nic_matcher->ste_builder[0].lu_type,
584 nic_matcher->ste_builder[0].byte_mask);
585 if (!nic_matcher->s_htbl) {
586 ret = -ENOMEM;
587 goto free_e_htbl;
588 }
589
590 /* make sure the tables exist while empty */
591 mlx5dr_htbl_get(nic_matcher->s_htbl);
592 mlx5dr_htbl_get(nic_matcher->e_anchor);
593
594 return 0;
595
596 free_e_htbl:
597 mlx5dr_ste_htbl_free(nic_matcher->e_anchor);
598 return ret;
599 }
600
dr_matcher_init_fdb(struct mlx5dr_matcher * matcher)601 static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher)
602 {
603 int ret;
604
605 ret = dr_matcher_init_nic(matcher, &matcher->rx);
606 if (ret)
607 return ret;
608
609 ret = dr_matcher_init_nic(matcher, &matcher->tx);
610 if (ret)
611 goto uninit_nic_rx;
612
613 return 0;
614
615 uninit_nic_rx:
616 dr_matcher_uninit_nic(&matcher->rx);
617 return ret;
618 }
619
dr_matcher_init(struct mlx5dr_matcher * matcher,struct mlx5dr_match_parameters * mask)620 static int dr_matcher_init(struct mlx5dr_matcher *matcher,
621 struct mlx5dr_match_parameters *mask)
622 {
623 struct mlx5dr_table *tbl = matcher->tbl;
624 struct mlx5dr_domain *dmn = tbl->dmn;
625 int ret;
626
627 if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) {
628 mlx5dr_err(dmn, "Invalid match criteria attribute\n");
629 return -EINVAL;
630 }
631
632 if (mask) {
633 if (mask->match_sz > sizeof(struct mlx5dr_match_param)) {
634 mlx5dr_err(dmn, "Invalid match size attribute\n");
635 return -EINVAL;
636 }
637 mlx5dr_ste_copy_param(matcher->match_criteria,
638 &matcher->mask, mask);
639 }
640
641 switch (dmn->type) {
642 case MLX5DR_DOMAIN_TYPE_NIC_RX:
643 matcher->rx.nic_tbl = &tbl->rx;
644 ret = dr_matcher_init_nic(matcher, &matcher->rx);
645 break;
646 case MLX5DR_DOMAIN_TYPE_NIC_TX:
647 matcher->tx.nic_tbl = &tbl->tx;
648 ret = dr_matcher_init_nic(matcher, &matcher->tx);
649 break;
650 case MLX5DR_DOMAIN_TYPE_FDB:
651 matcher->rx.nic_tbl = &tbl->rx;
652 matcher->tx.nic_tbl = &tbl->tx;
653 ret = dr_matcher_init_fdb(matcher);
654 break;
655 default:
656 WARN_ON(true);
657 return -EINVAL;
658 }
659
660 return ret;
661 }
662
663 struct mlx5dr_matcher *
mlx5dr_matcher_create(struct mlx5dr_table * tbl,u32 priority,u8 match_criteria_enable,struct mlx5dr_match_parameters * mask)664 mlx5dr_matcher_create(struct mlx5dr_table *tbl,
665 u32 priority,
666 u8 match_criteria_enable,
667 struct mlx5dr_match_parameters *mask)
668 {
669 struct mlx5dr_matcher *matcher;
670 int ret;
671
672 refcount_inc(&tbl->refcount);
673
674 matcher = kzalloc(sizeof(*matcher), GFP_KERNEL);
675 if (!matcher)
676 goto dec_ref;
677
678 matcher->tbl = tbl;
679 matcher->prio = priority;
680 matcher->match_criteria = match_criteria_enable;
681 refcount_set(&matcher->refcount, 1);
682 INIT_LIST_HEAD(&matcher->matcher_list);
683
684 mlx5dr_domain_lock(tbl->dmn);
685
686 ret = dr_matcher_init(matcher, mask);
687 if (ret)
688 goto free_matcher;
689
690 ret = dr_matcher_add_to_tbl(matcher);
691 if (ret)
692 goto matcher_uninit;
693
694 mlx5dr_domain_unlock(tbl->dmn);
695
696 return matcher;
697
698 matcher_uninit:
699 dr_matcher_uninit(matcher);
700 free_matcher:
701 mlx5dr_domain_unlock(tbl->dmn);
702 kfree(matcher);
703 dec_ref:
704 refcount_dec(&tbl->refcount);
705 return NULL;
706 }
707
dr_matcher_disconnect(struct mlx5dr_domain * dmn,struct mlx5dr_table_rx_tx * nic_tbl,struct mlx5dr_matcher_rx_tx * next_nic_matcher,struct mlx5dr_matcher_rx_tx * prev_nic_matcher)708 static int dr_matcher_disconnect(struct mlx5dr_domain *dmn,
709 struct mlx5dr_table_rx_tx *nic_tbl,
710 struct mlx5dr_matcher_rx_tx *next_nic_matcher,
711 struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
712 {
713 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
714 struct mlx5dr_htbl_connect_info info;
715 struct mlx5dr_ste_htbl *prev_anchor;
716
717 if (prev_nic_matcher)
718 prev_anchor = prev_nic_matcher->e_anchor;
719 else
720 prev_anchor = nic_tbl->s_anchor;
721
722 /* Connect previous anchor hash table to next matcher or to the default address */
723 if (next_nic_matcher) {
724 info.type = CONNECT_HIT;
725 info.hit_next_htbl = next_nic_matcher->s_htbl;
726 next_nic_matcher->s_htbl->pointing_ste = prev_anchor->ste_arr;
727 prev_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
728 } else {
729 info.type = CONNECT_MISS;
730 info.miss_icm_addr = nic_tbl->default_icm_addr;
731 prev_anchor->ste_arr[0].next_htbl = NULL;
732 }
733
734 return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor,
735 &info, true);
736 }
737
dr_matcher_remove_from_tbl(struct mlx5dr_matcher * matcher)738 static int dr_matcher_remove_from_tbl(struct mlx5dr_matcher *matcher)
739 {
740 struct mlx5dr_matcher *prev_matcher, *next_matcher;
741 struct mlx5dr_table *tbl = matcher->tbl;
742 struct mlx5dr_domain *dmn = tbl->dmn;
743 int ret = 0;
744
745 if (list_is_last(&matcher->matcher_list, &tbl->matcher_list))
746 next_matcher = NULL;
747 else
748 next_matcher = list_next_entry(matcher, matcher_list);
749
750 if (matcher->matcher_list.prev == &tbl->matcher_list)
751 prev_matcher = NULL;
752 else
753 prev_matcher = list_prev_entry(matcher, matcher_list);
754
755 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
756 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
757 ret = dr_matcher_disconnect(dmn, &tbl->rx,
758 next_matcher ? &next_matcher->rx : NULL,
759 prev_matcher ? &prev_matcher->rx : NULL);
760 if (ret)
761 return ret;
762 }
763
764 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
765 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
766 ret = dr_matcher_disconnect(dmn, &tbl->tx,
767 next_matcher ? &next_matcher->tx : NULL,
768 prev_matcher ? &prev_matcher->tx : NULL);
769 if (ret)
770 return ret;
771 }
772
773 list_del(&matcher->matcher_list);
774
775 return 0;
776 }
777
mlx5dr_matcher_destroy(struct mlx5dr_matcher * matcher)778 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher)
779 {
780 struct mlx5dr_table *tbl = matcher->tbl;
781
782 if (refcount_read(&matcher->refcount) > 1)
783 return -EBUSY;
784
785 mlx5dr_domain_lock(tbl->dmn);
786
787 dr_matcher_remove_from_tbl(matcher);
788 dr_matcher_uninit(matcher);
789 refcount_dec(&matcher->tbl->refcount);
790
791 mlx5dr_domain_unlock(tbl->dmn);
792 kfree(matcher);
793
794 return 0;
795 }
796