This source file includes following definitions.
- dr_mask_is_smac_set
- dr_mask_is_dmac_set
- dr_mask_is_src_addr_set
- dr_mask_is_dst_addr_set
- dr_mask_is_l3_base_set
- dr_mask_is_tcp_udp_base_set
- dr_mask_is_ipv4_set
- dr_mask_is_ipv4_5_tuple_set
- dr_mask_is_eth_l2_tnl_set
- dr_mask_is_ttl_set
- dr_mask_is_gre_set
- dr_mask_is_flex_parser_tnl_set
- dr_mask_is_flex_parser_icmpv6_set
- dr_mask_is_wqe_metadata_set
- dr_mask_is_reg_c_0_3_set
- dr_mask_is_reg_c_4_7_set
- dr_mask_is_gvmi_or_qpn_set
- dr_matcher_supp_flex_parser_vxlan_gpe
- mlx5dr_matcher_select_builders
- dr_matcher_set_ste_builders
- dr_matcher_connect
- dr_matcher_add_to_tbl
- dr_matcher_uninit_nic
- dr_matcher_uninit_fdb
- dr_matcher_uninit
- dr_matcher_init_nic
- dr_matcher_init_fdb
- dr_matcher_init
- mlx5dr_matcher_create
- dr_matcher_disconnect
- dr_matcher_remove_from_tbl
- mlx5dr_matcher_destroy
1
2
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
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
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
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
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
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
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
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
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
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
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
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 }