1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
6 #include <rdma/ib_user_verbs.h>
7 #include <rdma/ib_verbs.h>
8 #include <rdma/uverbs_types.h>
9 #include <rdma/uverbs_ioctl.h>
10 #include <rdma/uverbs_std_types.h>
11 #include <rdma/mlx5_user_ioctl_cmds.h>
12 #include <rdma/mlx5_user_ioctl_verbs.h>
13 #include <rdma/ib_hdrs.h>
14 #include <rdma/ib_umem.h>
15 #include <linux/mlx5/driver.h>
16 #include <linux/mlx5/fs.h>
17 #include <linux/mlx5/fs_helpers.h>
18 #include <linux/mlx5/accel.h>
19 #include <linux/mlx5/eswitch.h>
20 #include <net/inet_ecn.h>
26 #define UVERBS_MODULE_NAME mlx5_ib
27 #include <rdma/uverbs_named_ioctl.h>
30 MATCH_CRITERIA_ENABLE_OUTER_BIT,
31 MATCH_CRITERIA_ENABLE_MISC_BIT,
32 MATCH_CRITERIA_ENABLE_INNER_BIT,
33 MATCH_CRITERIA_ENABLE_MISC2_BIT
36 #define HEADER_IS_ZERO(match_criteria, headers) \
37 !(memchr_inv(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \
38 0, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
40 static u8 get_match_criteria_enable(u32 *match_criteria)
42 u8 match_criteria_enable;
44 match_criteria_enable =
45 (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
46 MATCH_CRITERIA_ENABLE_OUTER_BIT;
47 match_criteria_enable |=
48 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
49 MATCH_CRITERIA_ENABLE_MISC_BIT;
50 match_criteria_enable |=
51 (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
52 MATCH_CRITERIA_ENABLE_INNER_BIT;
53 match_criteria_enable |=
54 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
55 MATCH_CRITERIA_ENABLE_MISC2_BIT;
57 return match_criteria_enable;
60 static int set_proto(void *outer_c, void *outer_v, u8 mask, u8 val)
69 entry_mask = MLX5_GET(fte_match_set_lyr_2_4, outer_c,
71 entry_val = MLX5_GET(fte_match_set_lyr_2_4, outer_v,
74 MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_protocol, mask);
75 MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_protocol, val);
78 /* Don't override existing ip protocol */
79 if (mask != entry_mask || val != entry_val)
85 static void set_flow_label(void *misc_c, void *misc_v, u32 mask, u32 val,
89 MLX5_SET(fte_match_set_misc,
90 misc_c, inner_ipv6_flow_label, mask);
91 MLX5_SET(fte_match_set_misc,
92 misc_v, inner_ipv6_flow_label, val);
94 MLX5_SET(fte_match_set_misc,
95 misc_c, outer_ipv6_flow_label, mask);
96 MLX5_SET(fte_match_set_misc,
97 misc_v, outer_ipv6_flow_label, val);
101 static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val)
103 MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_ecn, mask);
104 MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_ecn, val);
105 MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_dscp, mask >> 2);
106 MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_dscp, val >> 2);
109 static int check_mpls_supp_fields(u32 field_support, const __be32 *set_mask)
111 if (MLX5_GET(fte_match_mpls, set_mask, mpls_label) &&
112 !(field_support & MLX5_FIELD_SUPPORT_MPLS_LABEL))
115 if (MLX5_GET(fte_match_mpls, set_mask, mpls_exp) &&
116 !(field_support & MLX5_FIELD_SUPPORT_MPLS_EXP))
119 if (MLX5_GET(fte_match_mpls, set_mask, mpls_s_bos) &&
120 !(field_support & MLX5_FIELD_SUPPORT_MPLS_S_BOS))
123 if (MLX5_GET(fte_match_mpls, set_mask, mpls_ttl) &&
124 !(field_support & MLX5_FIELD_SUPPORT_MPLS_TTL))
130 #define LAST_ETH_FIELD vlan_tag
131 #define LAST_IB_FIELD sl
132 #define LAST_IPV4_FIELD tos
133 #define LAST_IPV6_FIELD traffic_class
134 #define LAST_TCP_UDP_FIELD src_port
135 #define LAST_TUNNEL_FIELD tunnel_id
136 #define LAST_FLOW_TAG_FIELD tag_id
137 #define LAST_DROP_FIELD size
138 #define LAST_COUNTERS_FIELD counters
140 /* Field is the last supported field */
141 #define FIELDS_NOT_SUPPORTED(filter, field) \
142 memchr_inv((void *)&filter.field + sizeof(filter.field), 0, \
143 sizeof(filter) - offsetofend(typeof(filter), field))
145 int parse_flow_flow_action(struct mlx5_ib_flow_action *maction,
147 struct mlx5_flow_act *action)
150 switch (maction->ib_action.type) {
151 case IB_FLOW_ACTION_ESP:
152 if (action->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
153 MLX5_FLOW_CONTEXT_ACTION_DECRYPT))
155 /* Currently only AES_GCM keymat is supported by the driver */
156 action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx;
157 action->action |= is_egress ?
158 MLX5_FLOW_CONTEXT_ACTION_ENCRYPT :
159 MLX5_FLOW_CONTEXT_ACTION_DECRYPT;
161 case IB_FLOW_ACTION_UNSPECIFIED:
162 if (maction->flow_action_raw.sub_type ==
163 MLX5_IB_FLOW_ACTION_MODIFY_HEADER) {
164 if (action->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
166 action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
168 maction->flow_action_raw.modify_hdr;
171 if (maction->flow_action_raw.sub_type ==
172 MLX5_IB_FLOW_ACTION_DECAP) {
173 if (action->action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
175 action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
178 if (maction->flow_action_raw.sub_type ==
179 MLX5_IB_FLOW_ACTION_PACKET_REFORMAT) {
181 MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)
184 MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
185 action->pkt_reformat =
186 maction->flow_action_raw.pkt_reformat;
195 static int parse_flow_attr(struct mlx5_core_dev *mdev,
196 struct mlx5_flow_spec *spec,
197 const union ib_flow_spec *ib_spec,
198 const struct ib_flow_attr *flow_attr,
199 struct mlx5_flow_act *action, u32 prev_type)
201 struct mlx5_flow_context *flow_context = &spec->flow_context;
202 u32 *match_c = spec->match_criteria;
203 u32 *match_v = spec->match_value;
204 void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c,
206 void *misc_params_v = MLX5_ADDR_OF(fte_match_param, match_v,
208 void *misc_params2_c = MLX5_ADDR_OF(fte_match_param, match_c,
210 void *misc_params2_v = MLX5_ADDR_OF(fte_match_param, match_v,
217 if (ib_spec->type & IB_FLOW_SPEC_INNER) {
218 headers_c = MLX5_ADDR_OF(fte_match_param, match_c,
220 headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
222 match_ipv = MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
223 ft_field_support.inner_ip_version);
225 headers_c = MLX5_ADDR_OF(fte_match_param, match_c,
227 headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
229 match_ipv = MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
230 ft_field_support.outer_ip_version);
233 switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) {
234 case IB_FLOW_SPEC_ETH:
235 if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD))
238 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
240 ib_spec->eth.mask.dst_mac);
241 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
243 ib_spec->eth.val.dst_mac);
245 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
247 ib_spec->eth.mask.src_mac);
248 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
250 ib_spec->eth.val.src_mac);
252 if (ib_spec->eth.mask.vlan_tag) {
253 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
255 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
258 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
259 first_vid, ntohs(ib_spec->eth.mask.vlan_tag));
260 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
261 first_vid, ntohs(ib_spec->eth.val.vlan_tag));
263 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
265 ntohs(ib_spec->eth.mask.vlan_tag) >> 12);
266 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
268 ntohs(ib_spec->eth.val.vlan_tag) >> 12);
270 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
272 ntohs(ib_spec->eth.mask.vlan_tag) >> 13);
273 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
275 ntohs(ib_spec->eth.val.vlan_tag) >> 13);
277 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
278 ethertype, ntohs(ib_spec->eth.mask.ether_type));
279 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
280 ethertype, ntohs(ib_spec->eth.val.ether_type));
282 case IB_FLOW_SPEC_IPV4:
283 if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD))
287 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
289 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
290 ip_version, MLX5_FS_IPV4_VERSION);
292 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
294 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
295 ethertype, ETH_P_IP);
298 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
299 src_ipv4_src_ipv6.ipv4_layout.ipv4),
300 &ib_spec->ipv4.mask.src_ip,
301 sizeof(ib_spec->ipv4.mask.src_ip));
302 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
303 src_ipv4_src_ipv6.ipv4_layout.ipv4),
304 &ib_spec->ipv4.val.src_ip,
305 sizeof(ib_spec->ipv4.val.src_ip));
306 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
307 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
308 &ib_spec->ipv4.mask.dst_ip,
309 sizeof(ib_spec->ipv4.mask.dst_ip));
310 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
311 dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
312 &ib_spec->ipv4.val.dst_ip,
313 sizeof(ib_spec->ipv4.val.dst_ip));
315 set_tos(headers_c, headers_v,
316 ib_spec->ipv4.mask.tos, ib_spec->ipv4.val.tos);
318 if (set_proto(headers_c, headers_v,
319 ib_spec->ipv4.mask.proto,
320 ib_spec->ipv4.val.proto))
323 case IB_FLOW_SPEC_IPV6:
324 if (FIELDS_NOT_SUPPORTED(ib_spec->ipv6.mask, LAST_IPV6_FIELD))
328 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
330 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
331 ip_version, MLX5_FS_IPV6_VERSION);
333 MLX5_SET(fte_match_set_lyr_2_4, headers_c,
335 MLX5_SET(fte_match_set_lyr_2_4, headers_v,
336 ethertype, ETH_P_IPV6);
339 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
340 src_ipv4_src_ipv6.ipv6_layout.ipv6),
341 &ib_spec->ipv6.mask.src_ip,
342 sizeof(ib_spec->ipv6.mask.src_ip));
343 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
344 src_ipv4_src_ipv6.ipv6_layout.ipv6),
345 &ib_spec->ipv6.val.src_ip,
346 sizeof(ib_spec->ipv6.val.src_ip));
347 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
348 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
349 &ib_spec->ipv6.mask.dst_ip,
350 sizeof(ib_spec->ipv6.mask.dst_ip));
351 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
352 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
353 &ib_spec->ipv6.val.dst_ip,
354 sizeof(ib_spec->ipv6.val.dst_ip));
356 set_tos(headers_c, headers_v,
357 ib_spec->ipv6.mask.traffic_class,
358 ib_spec->ipv6.val.traffic_class);
360 if (set_proto(headers_c, headers_v,
361 ib_spec->ipv6.mask.next_hdr,
362 ib_spec->ipv6.val.next_hdr))
365 set_flow_label(misc_params_c, misc_params_v,
366 ntohl(ib_spec->ipv6.mask.flow_label),
367 ntohl(ib_spec->ipv6.val.flow_label),
368 ib_spec->type & IB_FLOW_SPEC_INNER);
370 case IB_FLOW_SPEC_ESP:
371 if (ib_spec->esp.mask.seq)
374 MLX5_SET(fte_match_set_misc, misc_params_c, outer_esp_spi,
375 ntohl(ib_spec->esp.mask.spi));
376 MLX5_SET(fte_match_set_misc, misc_params_v, outer_esp_spi,
377 ntohl(ib_spec->esp.val.spi));
379 case IB_FLOW_SPEC_TCP:
380 if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask,
384 if (set_proto(headers_c, headers_v, 0xff, IPPROTO_TCP))
387 MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_sport,
388 ntohs(ib_spec->tcp_udp.mask.src_port));
389 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
390 ntohs(ib_spec->tcp_udp.val.src_port));
392 MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_dport,
393 ntohs(ib_spec->tcp_udp.mask.dst_port));
394 MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
395 ntohs(ib_spec->tcp_udp.val.dst_port));
397 case IB_FLOW_SPEC_UDP:
398 if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask,
402 if (set_proto(headers_c, headers_v, 0xff, IPPROTO_UDP))
405 MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
406 ntohs(ib_spec->tcp_udp.mask.src_port));
407 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
408 ntohs(ib_spec->tcp_udp.val.src_port));
410 MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport,
411 ntohs(ib_spec->tcp_udp.mask.dst_port));
412 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
413 ntohs(ib_spec->tcp_udp.val.dst_port));
415 case IB_FLOW_SPEC_GRE:
416 if (ib_spec->gre.mask.c_ks_res0_ver)
419 if (set_proto(headers_c, headers_v, 0xff, IPPROTO_GRE))
422 MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
424 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
427 MLX5_SET(fte_match_set_misc, misc_params_c, gre_protocol,
428 ntohs(ib_spec->gre.mask.protocol));
429 MLX5_SET(fte_match_set_misc, misc_params_v, gre_protocol,
430 ntohs(ib_spec->gre.val.protocol));
432 memcpy(MLX5_ADDR_OF(fte_match_set_misc, misc_params_c,
434 &ib_spec->gre.mask.key,
435 sizeof(ib_spec->gre.mask.key));
436 memcpy(MLX5_ADDR_OF(fte_match_set_misc, misc_params_v,
438 &ib_spec->gre.val.key,
439 sizeof(ib_spec->gre.val.key));
441 case IB_FLOW_SPEC_MPLS:
443 case IB_FLOW_SPEC_UDP:
444 if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
445 ft_field_support.outer_first_mpls_over_udp),
446 &ib_spec->mpls.mask.tag))
449 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v,
450 outer_first_mpls_over_udp),
451 &ib_spec->mpls.val.tag,
452 sizeof(ib_spec->mpls.val.tag));
453 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c,
454 outer_first_mpls_over_udp),
455 &ib_spec->mpls.mask.tag,
456 sizeof(ib_spec->mpls.mask.tag));
458 case IB_FLOW_SPEC_GRE:
459 if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
460 ft_field_support.outer_first_mpls_over_gre),
461 &ib_spec->mpls.mask.tag))
464 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v,
465 outer_first_mpls_over_gre),
466 &ib_spec->mpls.val.tag,
467 sizeof(ib_spec->mpls.val.tag));
468 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c,
469 outer_first_mpls_over_gre),
470 &ib_spec->mpls.mask.tag,
471 sizeof(ib_spec->mpls.mask.tag));
474 if (ib_spec->type & IB_FLOW_SPEC_INNER) {
475 if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
476 ft_field_support.inner_first_mpls),
477 &ib_spec->mpls.mask.tag))
480 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v,
482 &ib_spec->mpls.val.tag,
483 sizeof(ib_spec->mpls.val.tag));
484 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c,
486 &ib_spec->mpls.mask.tag,
487 sizeof(ib_spec->mpls.mask.tag));
489 if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
490 ft_field_support.outer_first_mpls),
491 &ib_spec->mpls.mask.tag))
494 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v,
496 &ib_spec->mpls.val.tag,
497 sizeof(ib_spec->mpls.val.tag));
498 memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c,
500 &ib_spec->mpls.mask.tag,
501 sizeof(ib_spec->mpls.mask.tag));
505 case IB_FLOW_SPEC_VXLAN_TUNNEL:
506 if (FIELDS_NOT_SUPPORTED(ib_spec->tunnel.mask,
510 MLX5_SET(fte_match_set_misc, misc_params_c, vxlan_vni,
511 ntohl(ib_spec->tunnel.mask.tunnel_id));
512 MLX5_SET(fte_match_set_misc, misc_params_v, vxlan_vni,
513 ntohl(ib_spec->tunnel.val.tunnel_id));
515 case IB_FLOW_SPEC_ACTION_TAG:
516 if (FIELDS_NOT_SUPPORTED(ib_spec->flow_tag,
517 LAST_FLOW_TAG_FIELD))
519 if (ib_spec->flow_tag.tag_id >= BIT(24))
522 flow_context->flow_tag = ib_spec->flow_tag.tag_id;
523 flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
525 case IB_FLOW_SPEC_ACTION_DROP:
526 if (FIELDS_NOT_SUPPORTED(ib_spec->drop,
529 action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
531 case IB_FLOW_SPEC_ACTION_HANDLE:
532 ret = parse_flow_flow_action(to_mflow_act(ib_spec->action.act),
533 flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS, action);
537 case IB_FLOW_SPEC_ACTION_COUNT:
538 if (FIELDS_NOT_SUPPORTED(ib_spec->flow_count,
539 LAST_COUNTERS_FIELD))
542 /* for now support only one counters spec per flow */
543 if (action->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
546 action->counters = ib_spec->flow_count.counters;
547 action->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
556 /* If a flow could catch both multicast and unicast packets,
557 * it won't fall into the multicast flow steering table and this rule
558 * could steal other multicast packets.
560 static bool flow_is_multicast_only(const struct ib_flow_attr *ib_attr)
562 union ib_flow_spec *flow_spec;
564 if (ib_attr->type != IB_FLOW_ATTR_NORMAL ||
565 ib_attr->num_of_specs < 1)
568 flow_spec = (union ib_flow_spec *)(ib_attr + 1);
569 if (flow_spec->type == IB_FLOW_SPEC_IPV4) {
570 struct ib_flow_spec_ipv4 *ipv4_spec;
572 ipv4_spec = (struct ib_flow_spec_ipv4 *)flow_spec;
573 if (ipv4_is_multicast(ipv4_spec->val.dst_ip))
579 if (flow_spec->type == IB_FLOW_SPEC_ETH) {
580 struct ib_flow_spec_eth *eth_spec;
582 eth_spec = (struct ib_flow_spec_eth *)flow_spec;
583 return is_multicast_ether_addr(eth_spec->mask.dst_mac) &&
584 is_multicast_ether_addr(eth_spec->val.dst_mac);
596 static enum valid_spec
597 is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev,
598 const struct mlx5_flow_spec *spec,
599 const struct mlx5_flow_act *flow_act,
602 const u32 *match_c = spec->match_criteria;
604 (flow_act->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
605 MLX5_FLOW_CONTEXT_ACTION_DECRYPT));
606 bool is_ipsec = mlx5_fs_is_ipsec_flow(match_c);
607 bool is_drop = flow_act->action & MLX5_FLOW_CONTEXT_ACTION_DROP;
610 * Currently only crypto is supported in egress, when regular egress
611 * rules would be supported, always return VALID_SPEC_NA.
614 return VALID_SPEC_NA;
616 return is_crypto && is_ipsec &&
617 (!egress || (!is_drop &&
618 !(spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG))) ?
619 VALID_SPEC_VALID : VALID_SPEC_INVALID;
622 static bool is_valid_spec(struct mlx5_core_dev *mdev,
623 const struct mlx5_flow_spec *spec,
624 const struct mlx5_flow_act *flow_act,
627 /* We curretly only support ipsec egress flow */
628 return is_valid_esp_aes_gcm(mdev, spec, flow_act, egress) != VALID_SPEC_INVALID;
631 static bool is_valid_ethertype(struct mlx5_core_dev *mdev,
632 const struct ib_flow_attr *flow_attr,
635 union ib_flow_spec *ib_spec = (union ib_flow_spec *)(flow_attr + 1);
636 int match_ipv = check_inner ?
637 MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
638 ft_field_support.inner_ip_version) :
639 MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
640 ft_field_support.outer_ip_version);
641 int inner_bit = check_inner ? IB_FLOW_SPEC_INNER : 0;
642 bool ipv4_spec_valid, ipv6_spec_valid;
643 unsigned int ip_spec_type = 0;
644 bool has_ethertype = false;
645 unsigned int spec_index;
646 bool mask_valid = true;
650 /* Validate that ethertype is correct */
651 for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
652 if ((ib_spec->type == (IB_FLOW_SPEC_ETH | inner_bit)) &&
653 ib_spec->eth.mask.ether_type) {
654 mask_valid = (ib_spec->eth.mask.ether_type ==
656 has_ethertype = true;
657 eth_type = ntohs(ib_spec->eth.val.ether_type);
658 } else if ((ib_spec->type == (IB_FLOW_SPEC_IPV4 | inner_bit)) ||
659 (ib_spec->type == (IB_FLOW_SPEC_IPV6 | inner_bit))) {
660 ip_spec_type = ib_spec->type;
662 ib_spec = (void *)ib_spec + ib_spec->size;
665 type_valid = (!has_ethertype) || (!ip_spec_type);
666 if (!type_valid && mask_valid) {
667 ipv4_spec_valid = (eth_type == ETH_P_IP) &&
668 (ip_spec_type == (IB_FLOW_SPEC_IPV4 | inner_bit));
669 ipv6_spec_valid = (eth_type == ETH_P_IPV6) &&
670 (ip_spec_type == (IB_FLOW_SPEC_IPV6 | inner_bit));
672 type_valid = (ipv4_spec_valid) || (ipv6_spec_valid) ||
673 (((eth_type == ETH_P_MPLS_UC) ||
674 (eth_type == ETH_P_MPLS_MC)) && match_ipv);
680 static bool is_valid_attr(struct mlx5_core_dev *mdev,
681 const struct ib_flow_attr *flow_attr)
683 return is_valid_ethertype(mdev, flow_attr, false) &&
684 is_valid_ethertype(mdev, flow_attr, true);
687 static void put_flow_table(struct mlx5_ib_dev *dev,
688 struct mlx5_ib_flow_prio *prio, bool ft_added)
690 prio->refcount -= !!ft_added;
691 if (!prio->refcount) {
692 mlx5_destroy_flow_table(prio->flow_table);
693 prio->flow_table = NULL;
697 static int mlx5_ib_destroy_flow(struct ib_flow *flow_id)
699 struct mlx5_ib_flow_handler *handler = container_of(flow_id,
700 struct mlx5_ib_flow_handler,
702 struct mlx5_ib_flow_handler *iter, *tmp;
703 struct mlx5_ib_dev *dev = handler->dev;
705 mutex_lock(&dev->flow_db->lock);
707 list_for_each_entry_safe(iter, tmp, &handler->list, list) {
708 mlx5_del_flow_rules(iter->rule);
709 put_flow_table(dev, iter->prio, true);
710 list_del(&iter->list);
714 mlx5_del_flow_rules(handler->rule);
715 put_flow_table(dev, handler->prio, true);
716 mlx5_ib_counters_clear_description(handler->ibcounters);
717 mutex_unlock(&dev->flow_db->lock);
718 if (handler->flow_matcher)
719 atomic_dec(&handler->flow_matcher->usecnt);
725 static int ib_prio_to_core_prio(unsigned int priority, bool dont_trap)
733 enum flow_table_type {
738 #define MLX5_FS_MAX_TYPES 6
739 #define MLX5_FS_MAX_ENTRIES BIT(16)
741 static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_flow_namespace *ns,
742 struct mlx5_ib_flow_prio *prio,
744 int num_entries, int num_groups,
747 struct mlx5_flow_table_attr ft_attr = {};
748 struct mlx5_flow_table *ft;
750 ft_attr.prio = priority;
751 ft_attr.max_fte = num_entries;
752 ft_attr.flags = flags;
753 ft_attr.autogroup.max_num_groups = num_groups;
754 ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
758 prio->flow_table = ft;
763 static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
764 struct ib_flow_attr *flow_attr,
765 enum flow_table_type ft_type)
767 bool dont_trap = flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP;
768 struct mlx5_flow_namespace *ns = NULL;
769 enum mlx5_flow_namespace_type fn_type;
770 struct mlx5_ib_flow_prio *prio;
771 struct mlx5_flow_table *ft;
779 max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
781 esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) !=
782 DEVLINK_ESWITCH_ENCAP_MODE_NONE;
783 switch (flow_attr->type) {
784 case IB_FLOW_ATTR_NORMAL:
785 if (flow_is_multicast_only(flow_attr) && !dont_trap)
786 priority = MLX5_IB_FLOW_MCAST_PRIO;
788 priority = ib_prio_to_core_prio(flow_attr->priority,
790 if (ft_type == MLX5_IB_FT_RX) {
791 fn_type = MLX5_FLOW_NAMESPACE_BYPASS;
792 prio = &dev->flow_db->prios[priority];
793 if (!dev->is_rep && !esw_encap &&
794 MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap))
795 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
796 if (!dev->is_rep && !esw_encap &&
797 MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
798 reformat_l3_tunnel_to_l2))
799 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
801 max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX(
802 dev->mdev, log_max_ft_size));
803 fn_type = MLX5_FLOW_NAMESPACE_EGRESS;
804 prio = &dev->flow_db->egress_prios[priority];
805 if (!dev->is_rep && !esw_encap &&
806 MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat))
807 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
809 ns = mlx5_get_flow_namespace(dev->mdev, fn_type);
810 num_entries = MLX5_FS_MAX_ENTRIES;
811 num_groups = MLX5_FS_MAX_TYPES;
813 case IB_FLOW_ATTR_ALL_DEFAULT:
814 case IB_FLOW_ATTR_MC_DEFAULT:
815 ns = mlx5_get_flow_namespace(dev->mdev,
816 MLX5_FLOW_NAMESPACE_LEFTOVERS);
817 build_leftovers_ft_param(&priority, &num_entries, &num_groups);
818 prio = &dev->flow_db->prios[MLX5_IB_FLOW_LEFTOVERS_PRIO];
820 case IB_FLOW_ATTR_SNIFFER:
821 if (!MLX5_CAP_FLOWTABLE(dev->mdev,
822 allow_sniffer_and_nic_rx_shared_tir))
823 return ERR_PTR(-EOPNOTSUPP);
825 ns = mlx5_get_flow_namespace(
826 dev->mdev, ft_type == MLX5_IB_FT_RX ?
827 MLX5_FLOW_NAMESPACE_SNIFFER_RX :
828 MLX5_FLOW_NAMESPACE_SNIFFER_TX);
830 prio = &dev->flow_db->sniffer[ft_type];
840 return ERR_PTR(-EOPNOTSUPP);
842 max_table_size = min_t(int, num_entries, max_table_size);
844 ft = prio->flow_table;
846 return _get_prio(ns, prio, priority, max_table_size, num_groups,
853 RDMA_RX_ECN_OPCOUNTER_PRIO,
854 RDMA_RX_CNP_OPCOUNTER_PRIO,
858 RDMA_TX_CNP_OPCOUNTER_PRIO,
861 static int set_vhca_port_spec(struct mlx5_ib_dev *dev, u32 port_num,
862 struct mlx5_flow_spec *spec)
864 if (!MLX5_CAP_FLOWTABLE_RDMA_RX(dev->mdev,
865 ft_field_support.source_vhca_port) ||
866 !MLX5_CAP_FLOWTABLE_RDMA_TX(dev->mdev,
867 ft_field_support.source_vhca_port))
870 MLX5_SET_TO_ONES(fte_match_param, &spec->match_criteria,
871 misc_parameters.source_vhca_port);
872 MLX5_SET(fte_match_param, &spec->match_value,
873 misc_parameters.source_vhca_port, port_num);
878 static int set_ecn_ce_spec(struct mlx5_ib_dev *dev, u32 port_num,
879 struct mlx5_flow_spec *spec, int ipv)
881 if (!MLX5_CAP_FLOWTABLE_RDMA_RX(dev->mdev,
882 ft_field_support.outer_ip_version))
885 if (mlx5_core_mp_enabled(dev->mdev) &&
886 set_vhca_port_spec(dev, port_num, spec))
889 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
890 outer_headers.ip_ecn);
891 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_ecn,
893 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
894 outer_headers.ip_version);
895 MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version,
898 spec->match_criteria_enable =
899 get_match_criteria_enable(spec->match_criteria);
904 static int set_cnp_spec(struct mlx5_ib_dev *dev, u32 port_num,
905 struct mlx5_flow_spec *spec)
907 if (mlx5_core_mp_enabled(dev->mdev) &&
908 set_vhca_port_spec(dev, port_num, spec))
911 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
912 misc_parameters.bth_opcode);
913 MLX5_SET(fte_match_param, spec->match_value, misc_parameters.bth_opcode,
916 spec->match_criteria_enable =
917 get_match_criteria_enable(spec->match_criteria);
922 int mlx5_ib_fs_add_op_fc(struct mlx5_ib_dev *dev, u32 port_num,
923 struct mlx5_ib_op_fc *opfc,
924 enum mlx5_ib_optional_counter_type type)
926 enum mlx5_flow_namespace_type fn_type;
927 int priority, i, err, spec_num;
928 struct mlx5_flow_act flow_act = {};
929 struct mlx5_flow_destination dst;
930 struct mlx5_flow_namespace *ns;
931 struct mlx5_ib_flow_prio *prio;
932 struct mlx5_flow_spec *spec;
934 spec = kcalloc(MAX_OPFC_RULES, sizeof(*spec), GFP_KERNEL);
939 case MLX5_IB_OPCOUNTER_CC_RX_CE_PKTS:
940 if (set_ecn_ce_spec(dev, port_num, &spec[0],
941 MLX5_FS_IPV4_VERSION) ||
942 set_ecn_ce_spec(dev, port_num, &spec[1],
943 MLX5_FS_IPV6_VERSION)) {
948 fn_type = MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS;
949 priority = RDMA_RX_ECN_OPCOUNTER_PRIO;
952 case MLX5_IB_OPCOUNTER_CC_RX_CNP_PKTS:
953 if (!MLX5_CAP_FLOWTABLE(dev->mdev,
954 ft_field_support_2_nic_receive_rdma.bth_opcode) ||
955 set_cnp_spec(dev, port_num, &spec[0])) {
960 fn_type = MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS;
961 priority = RDMA_RX_CNP_OPCOUNTER_PRIO;
964 case MLX5_IB_OPCOUNTER_CC_TX_CNP_PKTS:
965 if (!MLX5_CAP_FLOWTABLE(dev->mdev,
966 ft_field_support_2_nic_transmit_rdma.bth_opcode) ||
967 set_cnp_spec(dev, port_num, &spec[0])) {
972 fn_type = MLX5_FLOW_NAMESPACE_RDMA_TX_COUNTERS;
973 priority = RDMA_TX_CNP_OPCOUNTER_PRIO;
981 ns = mlx5_get_flow_namespace(dev->mdev, fn_type);
987 prio = &dev->flow_db->opfcs[type];
988 if (!prio->flow_table) {
989 prio = _get_prio(ns, prio, priority,
990 dev->num_ports * MAX_OPFC_RULES, 1, 0);
997 dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
998 dst.counter_id = mlx5_fc_id(opfc->fc);
1001 MLX5_FLOW_CONTEXT_ACTION_COUNT | MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1003 for (i = 0; i < spec_num; i++) {
1004 opfc->rule[i] = mlx5_add_flow_rules(prio->flow_table, &spec[i],
1005 &flow_act, &dst, 1);
1006 if (IS_ERR(opfc->rule[i])) {
1007 err = PTR_ERR(opfc->rule[i]);
1011 prio->refcount += spec_num;
1017 for (i -= 1; i >= 0; i--)
1018 mlx5_del_flow_rules(opfc->rule[i]);
1019 put_flow_table(dev, prio, false);
1025 void mlx5_ib_fs_remove_op_fc(struct mlx5_ib_dev *dev,
1026 struct mlx5_ib_op_fc *opfc,
1027 enum mlx5_ib_optional_counter_type type)
1031 for (i = 0; i < MAX_OPFC_RULES && opfc->rule[i]; i++) {
1032 mlx5_del_flow_rules(opfc->rule[i]);
1033 put_flow_table(dev, &dev->flow_db->opfcs[type], true);
1037 static void set_underlay_qp(struct mlx5_ib_dev *dev,
1038 struct mlx5_flow_spec *spec,
1041 void *misc_params_c = MLX5_ADDR_OF(fte_match_param,
1042 spec->match_criteria,
1044 void *misc_params_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1048 MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
1049 ft_field_support.bth_dst_qp)) {
1050 MLX5_SET(fte_match_set_misc,
1051 misc_params_v, bth_dst_qp, underlay_qpn);
1052 MLX5_SET(fte_match_set_misc,
1053 misc_params_c, bth_dst_qp, 0xffffff);
1057 static void mlx5_ib_set_rule_source_port(struct mlx5_ib_dev *dev,
1058 struct mlx5_flow_spec *spec,
1059 struct mlx5_eswitch_rep *rep)
1061 struct mlx5_eswitch *esw = dev->mdev->priv.eswitch;
1064 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1065 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1068 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1069 mlx5_eswitch_get_vport_metadata_for_match(rep->esw,
1071 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1074 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1075 mlx5_eswitch_get_vport_metadata_mask());
1077 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1080 MLX5_SET(fte_match_set_misc, misc, source_port, rep->vport);
1082 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1085 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1089 static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
1090 struct mlx5_ib_flow_prio *ft_prio,
1091 const struct ib_flow_attr *flow_attr,
1092 struct mlx5_flow_destination *dst,
1094 struct mlx5_ib_create_flow *ucmd)
1096 struct mlx5_flow_table *ft = ft_prio->flow_table;
1097 struct mlx5_ib_flow_handler *handler;
1098 struct mlx5_flow_act flow_act = {};
1099 struct mlx5_flow_spec *spec;
1100 struct mlx5_flow_destination dest_arr[2] = {};
1101 struct mlx5_flow_destination *rule_dst = dest_arr;
1102 const void *ib_flow = (const void *)flow_attr + sizeof(*flow_attr);
1103 unsigned int spec_index;
1107 bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
1109 if (!is_valid_attr(dev->mdev, flow_attr))
1110 return ERR_PTR(-EINVAL);
1112 if (dev->is_rep && is_egress)
1113 return ERR_PTR(-EINVAL);
1115 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1116 handler = kzalloc(sizeof(*handler), GFP_KERNEL);
1117 if (!handler || !spec) {
1122 INIT_LIST_HEAD(&handler->list);
1124 for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
1125 err = parse_flow_attr(dev->mdev, spec,
1126 ib_flow, flow_attr, &flow_act,
1131 prev_type = ((union ib_flow_spec *)ib_flow)->type;
1132 ib_flow += ((union ib_flow_spec *)ib_flow)->size;
1135 if (dst && !(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP)) {
1136 memcpy(&dest_arr[0], dst, sizeof(*dst));
1140 if (!flow_is_multicast_only(flow_attr))
1141 set_underlay_qp(dev, spec, underlay_qpn);
1143 if (dev->is_rep && flow_attr->type != IB_FLOW_ATTR_SNIFFER) {
1144 struct mlx5_eswitch_rep *rep;
1146 rep = dev->port[flow_attr->port - 1].rep;
1152 mlx5_ib_set_rule_source_port(dev, spec, rep);
1155 spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria);
1158 !is_valid_spec(dev->mdev, spec, &flow_act, is_egress)) {
1163 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
1164 struct mlx5_ib_mcounters *mcounters;
1166 err = mlx5_ib_flow_counters_set_data(flow_act.counters, ucmd);
1170 mcounters = to_mcounters(flow_act.counters);
1171 handler->ibcounters = flow_act.counters;
1172 dest_arr[dest_num].type =
1173 MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1174 dest_arr[dest_num].counter_id =
1175 mlx5_fc_id(mcounters->hw_cntrs_hndl);
1179 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
1183 if (flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP)
1185 MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
1187 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1189 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1192 if ((spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG) &&
1193 (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
1194 flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) {
1195 mlx5_ib_warn(dev, "Flow tag %u and attribute type %x isn't allowed in leftovers\n",
1196 spec->flow_context.flow_tag, flow_attr->type);
1200 handler->rule = mlx5_add_flow_rules(ft, spec,
1202 rule_dst, dest_num);
1204 if (IS_ERR(handler->rule)) {
1205 err = PTR_ERR(handler->rule);
1209 ft_prio->refcount++;
1210 handler->prio = ft_prio;
1213 ft_prio->flow_table = ft;
1215 if (err && handler) {
1216 mlx5_ib_counters_clear_description(handler->ibcounters);
1220 return err ? ERR_PTR(err) : handler;
1223 static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
1224 struct mlx5_ib_flow_prio *ft_prio,
1225 const struct ib_flow_attr *flow_attr,
1226 struct mlx5_flow_destination *dst)
1228 return _create_flow_rule(dev, ft_prio, flow_attr, dst, 0, NULL);
1236 static struct mlx5_ib_flow_handler *create_leftovers_rule(struct mlx5_ib_dev *dev,
1237 struct mlx5_ib_flow_prio *ft_prio,
1238 struct ib_flow_attr *flow_attr,
1239 struct mlx5_flow_destination *dst)
1241 struct mlx5_ib_flow_handler *handler_ucast = NULL;
1242 struct mlx5_ib_flow_handler *handler = NULL;
1245 struct ib_flow_attr flow_attr;
1246 struct ib_flow_spec_eth eth_flow;
1247 } leftovers_specs[] = {
1251 .size = sizeof(leftovers_specs[0])
1254 .type = IB_FLOW_SPEC_ETH,
1255 .size = sizeof(struct ib_flow_spec_eth),
1256 .mask = {.dst_mac = {0x1} },
1257 .val = {.dst_mac = {0x1} }
1263 .size = sizeof(leftovers_specs[0])
1266 .type = IB_FLOW_SPEC_ETH,
1267 .size = sizeof(struct ib_flow_spec_eth),
1268 .mask = {.dst_mac = {0x1} },
1269 .val = {.dst_mac = {} }
1274 handler = create_flow_rule(dev, ft_prio,
1275 &leftovers_specs[LEFTOVERS_MC].flow_attr,
1277 if (!IS_ERR(handler) &&
1278 flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT) {
1279 handler_ucast = create_flow_rule(dev, ft_prio,
1280 &leftovers_specs[LEFTOVERS_UC].flow_attr,
1282 if (IS_ERR(handler_ucast)) {
1283 mlx5_del_flow_rules(handler->rule);
1284 ft_prio->refcount--;
1286 handler = handler_ucast;
1288 list_add(&handler_ucast->list, &handler->list);
1295 static struct mlx5_ib_flow_handler *create_sniffer_rule(struct mlx5_ib_dev *dev,
1296 struct mlx5_ib_flow_prio *ft_rx,
1297 struct mlx5_ib_flow_prio *ft_tx,
1298 struct mlx5_flow_destination *dst)
1300 struct mlx5_ib_flow_handler *handler_rx;
1301 struct mlx5_ib_flow_handler *handler_tx;
1303 static const struct ib_flow_attr flow_attr = {
1305 .type = IB_FLOW_ATTR_SNIFFER,
1306 .size = sizeof(flow_attr)
1309 handler_rx = create_flow_rule(dev, ft_rx, &flow_attr, dst);
1310 if (IS_ERR(handler_rx)) {
1311 err = PTR_ERR(handler_rx);
1315 handler_tx = create_flow_rule(dev, ft_tx, &flow_attr, dst);
1316 if (IS_ERR(handler_tx)) {
1317 err = PTR_ERR(handler_tx);
1321 list_add(&handler_tx->list, &handler_rx->list);
1326 mlx5_del_flow_rules(handler_rx->rule);
1330 return ERR_PTR(err);
1333 static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
1334 struct ib_flow_attr *flow_attr,
1335 struct ib_udata *udata)
1337 struct mlx5_ib_dev *dev = to_mdev(qp->device);
1338 struct mlx5_ib_qp *mqp = to_mqp(qp);
1339 struct mlx5_ib_flow_handler *handler = NULL;
1340 struct mlx5_flow_destination *dst = NULL;
1341 struct mlx5_ib_flow_prio *ft_prio_tx = NULL;
1342 struct mlx5_ib_flow_prio *ft_prio;
1343 bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
1344 struct mlx5_ib_create_flow *ucmd = NULL, ucmd_hdr;
1345 size_t min_ucmd_sz, required_ucmd_sz;
1349 if (udata && udata->inlen) {
1350 min_ucmd_sz = offsetofend(struct mlx5_ib_create_flow, reserved);
1351 if (udata->inlen < min_ucmd_sz)
1352 return ERR_PTR(-EOPNOTSUPP);
1354 err = ib_copy_from_udata(&ucmd_hdr, udata, min_ucmd_sz);
1356 return ERR_PTR(err);
1358 /* currently supports only one counters data */
1359 if (ucmd_hdr.ncounters_data > 1)
1360 return ERR_PTR(-EINVAL);
1362 required_ucmd_sz = min_ucmd_sz +
1363 sizeof(struct mlx5_ib_flow_counters_data) *
1364 ucmd_hdr.ncounters_data;
1365 if (udata->inlen > required_ucmd_sz &&
1366 !ib_is_udata_cleared(udata, required_ucmd_sz,
1367 udata->inlen - required_ucmd_sz))
1368 return ERR_PTR(-EOPNOTSUPP);
1370 ucmd = kzalloc(required_ucmd_sz, GFP_KERNEL);
1372 return ERR_PTR(-ENOMEM);
1374 err = ib_copy_from_udata(ucmd, udata, required_ucmd_sz);
1379 if (flow_attr->priority > MLX5_IB_FLOW_LAST_PRIO) {
1384 if (flow_attr->flags &
1385 ~(IB_FLOW_ATTR_FLAGS_DONT_TRAP | IB_FLOW_ATTR_FLAGS_EGRESS)) {
1391 (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
1392 flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) {
1397 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
1403 mutex_lock(&dev->flow_db->lock);
1405 ft_prio = get_flow_table(dev, flow_attr,
1406 is_egress ? MLX5_IB_FT_TX : MLX5_IB_FT_RX);
1407 if (IS_ERR(ft_prio)) {
1408 err = PTR_ERR(ft_prio);
1411 if (flow_attr->type == IB_FLOW_ATTR_SNIFFER) {
1412 ft_prio_tx = get_flow_table(dev, flow_attr, MLX5_IB_FT_TX);
1413 if (IS_ERR(ft_prio_tx)) {
1414 err = PTR_ERR(ft_prio_tx);
1421 dst->type = MLX5_FLOW_DESTINATION_TYPE_PORT;
1423 dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
1425 dst->tir_num = mqp->rss_qp.tirn;
1427 dst->tir_num = mqp->raw_packet_qp.rq.tirn;
1430 switch (flow_attr->type) {
1431 case IB_FLOW_ATTR_NORMAL:
1432 underlay_qpn = (mqp->flags & IB_QP_CREATE_SOURCE_QPN) ?
1435 handler = _create_flow_rule(dev, ft_prio, flow_attr, dst,
1436 underlay_qpn, ucmd);
1438 case IB_FLOW_ATTR_ALL_DEFAULT:
1439 case IB_FLOW_ATTR_MC_DEFAULT:
1440 handler = create_leftovers_rule(dev, ft_prio, flow_attr, dst);
1442 case IB_FLOW_ATTR_SNIFFER:
1443 handler = create_sniffer_rule(dev, ft_prio, ft_prio_tx, dst);
1450 if (IS_ERR(handler)) {
1451 err = PTR_ERR(handler);
1456 mutex_unlock(&dev->flow_db->lock);
1460 return &handler->ibflow;
1463 put_flow_table(dev, ft_prio, false);
1465 put_flow_table(dev, ft_prio_tx, false);
1467 mutex_unlock(&dev->flow_db->lock);
1471 return ERR_PTR(err);
1474 static struct mlx5_ib_flow_prio *
1475 _get_flow_table(struct mlx5_ib_dev *dev,
1476 struct mlx5_ib_flow_matcher *fs_matcher,
1479 struct mlx5_flow_namespace *ns = NULL;
1480 struct mlx5_ib_flow_prio *prio = NULL;
1481 int max_table_size = 0;
1487 priority = MLX5_IB_FLOW_MCAST_PRIO;
1489 priority = ib_prio_to_core_prio(fs_matcher->priority, false);
1491 esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) !=
1492 DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1493 switch (fs_matcher->ns_type) {
1494 case MLX5_FLOW_NAMESPACE_BYPASS:
1495 max_table_size = BIT(
1496 MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, log_max_ft_size));
1497 if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap) && !esw_encap)
1498 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
1499 if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
1500 reformat_l3_tunnel_to_l2) &&
1502 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
1504 case MLX5_FLOW_NAMESPACE_EGRESS:
1505 max_table_size = BIT(
1506 MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, log_max_ft_size));
1507 if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat) &&
1509 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
1511 case MLX5_FLOW_NAMESPACE_FDB_BYPASS:
1512 max_table_size = BIT(
1513 MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, log_max_ft_size));
1514 if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, decap) && esw_encap)
1515 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
1516 if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev,
1517 reformat_l3_tunnel_to_l2) &&
1519 flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
1520 priority = fs_matcher->priority;
1522 case MLX5_FLOW_NAMESPACE_RDMA_RX:
1523 max_table_size = BIT(
1524 MLX5_CAP_FLOWTABLE_RDMA_RX(dev->mdev, log_max_ft_size));
1525 priority = fs_matcher->priority;
1527 case MLX5_FLOW_NAMESPACE_RDMA_TX:
1528 max_table_size = BIT(
1529 MLX5_CAP_FLOWTABLE_RDMA_TX(dev->mdev, log_max_ft_size));
1530 priority = fs_matcher->priority;
1536 max_table_size = min_t(int, max_table_size, MLX5_FS_MAX_ENTRIES);
1538 ns = mlx5_get_flow_namespace(dev->mdev, fs_matcher->ns_type);
1540 return ERR_PTR(-EOPNOTSUPP);
1542 switch (fs_matcher->ns_type) {
1543 case MLX5_FLOW_NAMESPACE_BYPASS:
1544 prio = &dev->flow_db->prios[priority];
1546 case MLX5_FLOW_NAMESPACE_EGRESS:
1547 prio = &dev->flow_db->egress_prios[priority];
1549 case MLX5_FLOW_NAMESPACE_FDB_BYPASS:
1550 prio = &dev->flow_db->fdb[priority];
1552 case MLX5_FLOW_NAMESPACE_RDMA_RX:
1553 prio = &dev->flow_db->rdma_rx[priority];
1555 case MLX5_FLOW_NAMESPACE_RDMA_TX:
1556 prio = &dev->flow_db->rdma_tx[priority];
1558 default: return ERR_PTR(-EINVAL);
1562 return ERR_PTR(-EINVAL);
1564 if (prio->flow_table)
1567 return _get_prio(ns, prio, priority, max_table_size,
1568 MLX5_FS_MAX_TYPES, flags);
1571 static struct mlx5_ib_flow_handler *
1572 _create_raw_flow_rule(struct mlx5_ib_dev *dev,
1573 struct mlx5_ib_flow_prio *ft_prio,
1574 struct mlx5_flow_destination *dst,
1575 struct mlx5_ib_flow_matcher *fs_matcher,
1576 struct mlx5_flow_context *flow_context,
1577 struct mlx5_flow_act *flow_act,
1578 void *cmd_in, int inlen,
1581 struct mlx5_ib_flow_handler *handler;
1582 struct mlx5_flow_spec *spec;
1583 struct mlx5_flow_table *ft = ft_prio->flow_table;
1586 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1587 handler = kzalloc(sizeof(*handler), GFP_KERNEL);
1588 if (!handler || !spec) {
1593 INIT_LIST_HEAD(&handler->list);
1595 memcpy(spec->match_value, cmd_in, inlen);
1596 memcpy(spec->match_criteria, fs_matcher->matcher_mask.match_params,
1597 fs_matcher->mask_len);
1598 spec->match_criteria_enable = fs_matcher->match_criteria_enable;
1599 spec->flow_context = *flow_context;
1601 handler->rule = mlx5_add_flow_rules(ft, spec,
1602 flow_act, dst, dst_num);
1604 if (IS_ERR(handler->rule)) {
1605 err = PTR_ERR(handler->rule);
1609 ft_prio->refcount++;
1610 handler->prio = ft_prio;
1612 ft_prio->flow_table = ft;
1618 return err ? ERR_PTR(err) : handler;
1621 static bool raw_fs_is_multicast(struct mlx5_ib_flow_matcher *fs_matcher,
1625 void *match_v_set_lyr_2_4, *match_c_set_lyr_2_4;
1626 void *dmac, *dmac_mask;
1627 void *ipv4, *ipv4_mask;
1629 if (!(fs_matcher->match_criteria_enable &
1630 (1 << MATCH_CRITERIA_ENABLE_OUTER_BIT)))
1633 match_c = fs_matcher->matcher_mask.match_params;
1634 match_v_set_lyr_2_4 = MLX5_ADDR_OF(fte_match_param, match_v,
1636 match_c_set_lyr_2_4 = MLX5_ADDR_OF(fte_match_param, match_c,
1639 dmac = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_v_set_lyr_2_4,
1641 dmac_mask = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_c_set_lyr_2_4,
1644 if (is_multicast_ether_addr(dmac) &&
1645 is_multicast_ether_addr(dmac_mask))
1648 ipv4 = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_v_set_lyr_2_4,
1649 dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
1651 ipv4_mask = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_c_set_lyr_2_4,
1652 dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
1654 if (ipv4_is_multicast(*(__be32 *)(ipv4)) &&
1655 ipv4_is_multicast(*(__be32 *)(ipv4_mask)))
1661 static struct mlx5_ib_flow_handler *raw_fs_rule_add(
1662 struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher,
1663 struct mlx5_flow_context *flow_context, struct mlx5_flow_act *flow_act,
1664 u32 counter_id, void *cmd_in, int inlen, int dest_id, int dest_type)
1666 struct mlx5_flow_destination *dst;
1667 struct mlx5_ib_flow_prio *ft_prio;
1668 struct mlx5_ib_flow_handler *handler;
1673 if (fs_matcher->flow_type != MLX5_IB_FLOW_TYPE_NORMAL)
1674 return ERR_PTR(-EOPNOTSUPP);
1676 if (fs_matcher->priority > MLX5_IB_FLOW_LAST_PRIO)
1677 return ERR_PTR(-ENOMEM);
1679 dst = kcalloc(2, sizeof(*dst), GFP_KERNEL);
1681 return ERR_PTR(-ENOMEM);
1683 mcast = raw_fs_is_multicast(fs_matcher, cmd_in);
1684 mutex_lock(&dev->flow_db->lock);
1686 ft_prio = _get_flow_table(dev, fs_matcher, mcast);
1687 if (IS_ERR(ft_prio)) {
1688 err = PTR_ERR(ft_prio);
1692 switch (dest_type) {
1693 case MLX5_FLOW_DESTINATION_TYPE_TIR:
1694 dst[dst_num].type = dest_type;
1695 dst[dst_num++].tir_num = dest_id;
1696 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1698 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
1699 dst[dst_num].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM;
1700 dst[dst_num++].ft_num = dest_id;
1701 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1703 case MLX5_FLOW_DESTINATION_TYPE_PORT:
1704 dst[dst_num++].type = MLX5_FLOW_DESTINATION_TYPE_PORT;
1705 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1711 if (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
1712 dst[dst_num].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1713 dst[dst_num].counter_id = counter_id;
1717 handler = _create_raw_flow_rule(dev, ft_prio, dst_num ? dst : NULL,
1718 fs_matcher, flow_context, flow_act,
1719 cmd_in, inlen, dst_num);
1721 if (IS_ERR(handler)) {
1722 err = PTR_ERR(handler);
1726 mutex_unlock(&dev->flow_db->lock);
1727 atomic_inc(&fs_matcher->usecnt);
1728 handler->flow_matcher = fs_matcher;
1735 put_flow_table(dev, ft_prio, false);
1737 mutex_unlock(&dev->flow_db->lock);
1740 return ERR_PTR(err);
1743 static u32 mlx5_ib_flow_action_flags_to_accel_xfrm_flags(u32 mlx5_flags)
1747 if (mlx5_flags & MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA)
1748 flags |= MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA;
1753 #define MLX5_FLOW_ACTION_ESP_CREATE_LAST_SUPPORTED \
1754 MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA
1755 static struct ib_flow_action *
1756 mlx5_ib_create_flow_action_esp(struct ib_device *device,
1757 const struct ib_flow_action_attrs_esp *attr,
1758 struct uverbs_attr_bundle *attrs)
1760 struct mlx5_ib_dev *mdev = to_mdev(device);
1761 struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm;
1762 struct mlx5_accel_esp_xfrm_attrs accel_attrs = {};
1763 struct mlx5_ib_flow_action *action;
1768 err = uverbs_get_flags64(
1769 &action_flags, attrs, MLX5_IB_ATTR_CREATE_FLOW_ACTION_FLAGS,
1770 ((MLX5_FLOW_ACTION_ESP_CREATE_LAST_SUPPORTED << 1) - 1));
1772 return ERR_PTR(err);
1774 flags = mlx5_ib_flow_action_flags_to_accel_xfrm_flags(action_flags);
1776 /* We current only support a subset of the standard features. Only a
1777 * keymat of type AES_GCM, with icv_len == 16, iv_algo == SEQ and esn
1778 * (with overlap). Full offload mode isn't supported.
1780 if (!attr->keymat || attr->replay || attr->encap ||
1781 attr->spi || attr->seq || attr->tfc_pad ||
1782 attr->hard_limit_pkts ||
1783 (attr->flags & ~(IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED |
1784 IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ENCRYPT)))
1785 return ERR_PTR(-EOPNOTSUPP);
1787 if (attr->keymat->protocol !=
1788 IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM)
1789 return ERR_PTR(-EOPNOTSUPP);
1791 aes_gcm = &attr->keymat->keymat.aes_gcm;
1793 if (aes_gcm->icv_len != 16 ||
1794 aes_gcm->iv_algo != IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ)
1795 return ERR_PTR(-EOPNOTSUPP);
1797 action = kmalloc(sizeof(*action), GFP_KERNEL);
1799 return ERR_PTR(-ENOMEM);
1801 action->esp_aes_gcm.ib_flags = attr->flags;
1802 memcpy(&accel_attrs.keymat.aes_gcm.aes_key, &aes_gcm->aes_key,
1803 sizeof(accel_attrs.keymat.aes_gcm.aes_key));
1804 accel_attrs.keymat.aes_gcm.key_len = aes_gcm->key_len * 8;
1805 memcpy(&accel_attrs.keymat.aes_gcm.salt, &aes_gcm->salt,
1806 sizeof(accel_attrs.keymat.aes_gcm.salt));
1807 memcpy(&accel_attrs.keymat.aes_gcm.seq_iv, &aes_gcm->iv,
1808 sizeof(accel_attrs.keymat.aes_gcm.seq_iv));
1809 accel_attrs.keymat.aes_gcm.icv_len = aes_gcm->icv_len * 8;
1810 accel_attrs.keymat.aes_gcm.iv_algo = MLX5_ACCEL_ESP_AES_GCM_IV_ALGO_SEQ;
1811 accel_attrs.keymat_type = MLX5_ACCEL_ESP_KEYMAT_AES_GCM;
1813 accel_attrs.esn = attr->esn;
1814 if (attr->flags & IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED)
1815 accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED;
1816 if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW)
1817 accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP;
1819 if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ENCRYPT)
1820 accel_attrs.action |= MLX5_ACCEL_ESP_ACTION_ENCRYPT;
1822 action->esp_aes_gcm.ctx =
1823 mlx5_accel_esp_create_xfrm(mdev->mdev, &accel_attrs, flags);
1824 if (IS_ERR(action->esp_aes_gcm.ctx)) {
1825 err = PTR_ERR(action->esp_aes_gcm.ctx);
1829 action->esp_aes_gcm.ib_flags = attr->flags;
1831 return &action->ib_action;
1835 return ERR_PTR(err);
1839 mlx5_ib_modify_flow_action_esp(struct ib_flow_action *action,
1840 const struct ib_flow_action_attrs_esp *attr,
1841 struct uverbs_attr_bundle *attrs)
1843 struct mlx5_ib_flow_action *maction = to_mflow_act(action);
1844 struct mlx5_accel_esp_xfrm_attrs accel_attrs;
1847 if (attr->keymat || attr->replay || attr->encap ||
1848 attr->spi || attr->seq || attr->tfc_pad ||
1849 attr->hard_limit_pkts ||
1850 (attr->flags & ~(IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED |
1851 IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS |
1852 IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW)))
1855 /* Only the ESN value or the MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP can
1858 if (!(maction->esp_aes_gcm.ib_flags &
1859 IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED) &&
1860 attr->flags & (IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED |
1861 IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW))
1864 memcpy(&accel_attrs, &maction->esp_aes_gcm.ctx->attrs,
1865 sizeof(accel_attrs));
1867 accel_attrs.esn = attr->esn;
1868 if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW)
1869 accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP;
1871 accel_attrs.flags &= ~MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP;
1873 err = mlx5_accel_esp_modify_xfrm(maction->esp_aes_gcm.ctx,
1878 maction->esp_aes_gcm.ib_flags &=
1879 ~IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW;
1880 maction->esp_aes_gcm.ib_flags |=
1881 attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW;
1886 static void destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
1888 switch (maction->flow_action_raw.sub_type) {
1889 case MLX5_IB_FLOW_ACTION_MODIFY_HEADER:
1890 mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev,
1891 maction->flow_action_raw.modify_hdr);
1893 case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT:
1894 mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev,
1895 maction->flow_action_raw.pkt_reformat);
1897 case MLX5_IB_FLOW_ACTION_DECAP:
1904 static int mlx5_ib_destroy_flow_action(struct ib_flow_action *action)
1906 struct mlx5_ib_flow_action *maction = to_mflow_act(action);
1908 switch (action->type) {
1909 case IB_FLOW_ACTION_ESP:
1911 * We only support aes_gcm by now, so we implicitly know this is
1912 * the underline crypto.
1914 mlx5_accel_esp_destroy_xfrm(maction->esp_aes_gcm.ctx);
1916 case IB_FLOW_ACTION_UNSPECIFIED:
1917 destroy_flow_action_raw(maction);
1929 mlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type,
1930 enum mlx5_flow_namespace_type *namespace)
1932 switch (table_type) {
1933 case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX:
1934 *namespace = MLX5_FLOW_NAMESPACE_BYPASS;
1936 case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX:
1937 *namespace = MLX5_FLOW_NAMESPACE_EGRESS;
1939 case MLX5_IB_UAPI_FLOW_TABLE_TYPE_FDB:
1940 *namespace = MLX5_FLOW_NAMESPACE_FDB_BYPASS;
1942 case MLX5_IB_UAPI_FLOW_TABLE_TYPE_RDMA_RX:
1943 *namespace = MLX5_FLOW_NAMESPACE_RDMA_RX;
1945 case MLX5_IB_UAPI_FLOW_TABLE_TYPE_RDMA_TX:
1946 *namespace = MLX5_FLOW_NAMESPACE_RDMA_TX;
1955 static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
1956 [MLX5_IB_FLOW_TYPE_NORMAL] = {
1957 .type = UVERBS_ATTR_TYPE_PTR_IN,
1959 .len = sizeof(u16), /* data is priority */
1960 .min_len = sizeof(u16),
1963 [MLX5_IB_FLOW_TYPE_SNIFFER] = {
1964 .type = UVERBS_ATTR_TYPE_PTR_IN,
1965 UVERBS_ATTR_NO_DATA(),
1967 [MLX5_IB_FLOW_TYPE_ALL_DEFAULT] = {
1968 .type = UVERBS_ATTR_TYPE_PTR_IN,
1969 UVERBS_ATTR_NO_DATA(),
1971 [MLX5_IB_FLOW_TYPE_MC_DEFAULT] = {
1972 .type = UVERBS_ATTR_TYPE_PTR_IN,
1973 UVERBS_ATTR_NO_DATA(),
1977 static bool is_flow_dest(void *obj, int *dest_id, int *dest_type)
1979 struct devx_obj *devx_obj = obj;
1980 u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, opcode);
1983 case MLX5_CMD_OP_DESTROY_TIR:
1984 *dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
1985 *dest_id = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox,
1989 case MLX5_CMD_OP_DESTROY_FLOW_TABLE:
1990 *dest_type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1991 *dest_id = MLX5_GET(destroy_flow_table_in, devx_obj->dinbox,
1999 static int get_dests(struct uverbs_attr_bundle *attrs,
2000 struct mlx5_ib_flow_matcher *fs_matcher, int *dest_id,
2001 int *dest_type, struct ib_qp **qp, u32 *flags)
2003 bool dest_devx, dest_qp;
2007 dest_devx = uverbs_attr_is_valid(attrs,
2008 MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
2009 dest_qp = uverbs_attr_is_valid(attrs,
2010 MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
2013 err = uverbs_get_flags32(flags, attrs, MLX5_IB_ATTR_CREATE_FLOW_FLAGS,
2014 MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS |
2015 MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP);
2019 /* Both flags are not allowed */
2020 if (*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS &&
2021 *flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP)
2024 if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) {
2025 if (dest_devx && (dest_qp || *flags))
2027 else if (dest_qp && *flags)
2031 /* Allow only DEVX object, drop as dest for FDB */
2032 if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB_BYPASS &&
2033 !(dest_devx || (*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP)))
2036 /* Allow only DEVX object or QP as dest when inserting to RDMA_RX */
2037 if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) &&
2038 ((!dest_devx && !dest_qp) || (dest_devx && dest_qp)))
2044 uverbs_attr_get_obj(attrs,
2045 MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
2047 /* Verify that the given DEVX object is a flow
2048 * steering destination.
2050 if (!is_flow_dest(devx_obj, dest_id, dest_type))
2052 /* Allow only flow table as dest when inserting to FDB or RDMA_RX */
2053 if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB_BYPASS ||
2054 fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) &&
2055 *dest_type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
2057 } else if (dest_qp) {
2058 struct mlx5_ib_qp *mqp;
2060 *qp = uverbs_attr_get_obj(attrs,
2061 MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
2063 return PTR_ERR(*qp);
2065 if ((*qp)->qp_type != IB_QPT_RAW_PACKET)
2070 *dest_id = mqp->rss_qp.tirn;
2072 *dest_id = mqp->raw_packet_qp.rq.tirn;
2073 *dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
2074 } else if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS ||
2075 fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_TX) &&
2076 !(*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP)) {
2077 *dest_type = MLX5_FLOW_DESTINATION_TYPE_PORT;
2080 if (*dest_type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
2081 (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS ||
2082 fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_TX))
2088 static bool is_flow_counter(void *obj, u32 offset, u32 *counter_id)
2090 struct devx_obj *devx_obj = obj;
2091 u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, opcode);
2093 if (opcode == MLX5_CMD_OP_DEALLOC_FLOW_COUNTER) {
2095 if (offset && offset >= devx_obj->flow_counter_bulk_size)
2098 *counter_id = MLX5_GET(dealloc_flow_counter_in,
2101 *counter_id += offset;
2108 #define MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS 2
2109 static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
2110 struct uverbs_attr_bundle *attrs)
2112 struct mlx5_flow_context flow_context = {.flow_tag =
2113 MLX5_FS_DEFAULT_FLOW_TAG};
2114 u32 *offset_attr, offset = 0, counter_id = 0;
2115 int dest_id, dest_type = -1, inlen, len, ret, i;
2116 struct mlx5_ib_flow_handler *flow_handler;
2117 struct mlx5_ib_flow_matcher *fs_matcher;
2118 struct ib_uobject **arr_flow_actions;
2119 struct ib_uflow_resources *uflow_res;
2120 struct mlx5_flow_act flow_act = {};
2121 struct ib_qp *qp = NULL;
2122 void *devx_obj, *cmd_in;
2123 struct ib_uobject *uobj;
2124 struct mlx5_ib_dev *dev;
2127 if (!capable(CAP_NET_RAW))
2130 fs_matcher = uverbs_attr_get_obj(attrs,
2131 MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
2132 uobj = uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE);
2133 dev = mlx5_udata_to_mdev(&attrs->driver_udata);
2135 if (get_dests(attrs, fs_matcher, &dest_id, &dest_type, &qp, &flags))
2138 if (flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS)
2139 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_NS;
2141 if (flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP)
2142 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
2144 len = uverbs_attr_get_uobjs_arr(attrs,
2145 MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX, &arr_flow_actions);
2147 devx_obj = arr_flow_actions[0]->object;
2149 if (uverbs_attr_is_valid(attrs,
2150 MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET)) {
2152 int num_offsets = uverbs_attr_ptr_get_array_size(
2154 MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET,
2157 if (num_offsets != 1)
2160 offset_attr = uverbs_attr_get_alloced_ptr(
2162 MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET);
2163 offset = *offset_attr;
2166 if (!is_flow_counter(devx_obj, offset, &counter_id))
2169 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
2172 cmd_in = uverbs_attr_get_alloced_ptr(
2173 attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
2174 inlen = uverbs_attr_get_len(attrs,
2175 MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
2177 uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS);
2181 len = uverbs_attr_get_uobjs_arr(attrs,
2182 MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, &arr_flow_actions);
2183 for (i = 0; i < len; i++) {
2184 struct mlx5_ib_flow_action *maction =
2185 to_mflow_act(arr_flow_actions[i]->object);
2187 ret = parse_flow_flow_action(maction, false, &flow_act);
2190 flow_resources_add(uflow_res, IB_FLOW_SPEC_ACTION_HANDLE,
2191 arr_flow_actions[i]->object);
2194 ret = uverbs_copy_from(&flow_context.flow_tag, attrs,
2195 MLX5_IB_ATTR_CREATE_FLOW_TAG);
2197 if (flow_context.flow_tag >= BIT(24)) {
2201 flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
2205 raw_fs_rule_add(dev, fs_matcher, &flow_context, &flow_act,
2206 counter_id, cmd_in, inlen, dest_id, dest_type);
2207 if (IS_ERR(flow_handler)) {
2208 ret = PTR_ERR(flow_handler);
2212 ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, uflow_res);
2216 ib_uverbs_flow_resources_free(uflow_res);
2220 static int flow_matcher_cleanup(struct ib_uobject *uobject,
2221 enum rdma_remove_reason why,
2222 struct uverbs_attr_bundle *attrs)
2224 struct mlx5_ib_flow_matcher *obj = uobject->object;
2226 if (atomic_read(&obj->usecnt))
2233 static int mlx5_ib_matcher_ns(struct uverbs_attr_bundle *attrs,
2234 struct mlx5_ib_flow_matcher *obj)
2236 enum mlx5_ib_uapi_flow_table_type ft_type =
2237 MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX;
2241 /* New users should use MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE and older
2242 * users should switch to it. We leave this to not break userspace
2244 if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE) &&
2245 uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS))
2248 if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE)) {
2249 err = uverbs_get_const(&ft_type, attrs,
2250 MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE);
2254 err = mlx5_ib_ft_type_to_namespace(ft_type, &obj->ns_type);
2261 if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS)) {
2262 err = uverbs_get_flags32(&flags, attrs,
2263 MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
2264 IB_FLOW_ATTR_FLAGS_EGRESS);
2269 mlx5_ib_ft_type_to_namespace(
2270 MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX,
2276 obj->ns_type = MLX5_FLOW_NAMESPACE_BYPASS;
2281 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
2282 struct uverbs_attr_bundle *attrs)
2284 struct ib_uobject *uobj = uverbs_attr_get_uobject(
2285 attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE);
2286 struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata);
2287 struct mlx5_ib_flow_matcher *obj;
2290 obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL);
2294 obj->mask_len = uverbs_attr_get_len(
2295 attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
2296 err = uverbs_copy_from(&obj->matcher_mask,
2298 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
2302 obj->flow_type = uverbs_attr_get_enum_id(
2303 attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
2305 if (obj->flow_type == MLX5_IB_FLOW_TYPE_NORMAL) {
2306 err = uverbs_copy_from(&obj->priority,
2308 MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
2313 err = uverbs_copy_from(&obj->match_criteria_enable,
2315 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA);
2319 err = mlx5_ib_matcher_ns(attrs, obj);
2323 if (obj->ns_type == MLX5_FLOW_NAMESPACE_FDB_BYPASS &&
2324 mlx5_eswitch_mode(dev->mdev) != MLX5_ESWITCH_OFFLOADS) {
2330 obj->mdev = dev->mdev;
2331 atomic_set(&obj->usecnt, 0);
2339 static struct ib_flow_action *
2340 mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev,
2341 enum mlx5_ib_uapi_flow_table_type ft_type,
2342 u8 num_actions, void *in)
2344 enum mlx5_flow_namespace_type namespace;
2345 struct mlx5_ib_flow_action *maction;
2348 ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
2350 return ERR_PTR(-EINVAL);
2352 maction = kzalloc(sizeof(*maction), GFP_KERNEL);
2354 return ERR_PTR(-ENOMEM);
2356 maction->flow_action_raw.modify_hdr =
2357 mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in);
2359 if (IS_ERR(maction->flow_action_raw.modify_hdr)) {
2360 ret = PTR_ERR(maction->flow_action_raw.modify_hdr);
2362 return ERR_PTR(ret);
2364 maction->flow_action_raw.sub_type =
2365 MLX5_IB_FLOW_ACTION_MODIFY_HEADER;
2366 maction->flow_action_raw.dev = dev;
2368 return &maction->ib_action;
2371 static bool mlx5_ib_modify_header_supported(struct mlx5_ib_dev *dev)
2373 return MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
2374 max_modify_header_actions) ||
2375 MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev,
2376 max_modify_header_actions) ||
2377 MLX5_CAP_FLOWTABLE_RDMA_TX(dev->mdev,
2378 max_modify_header_actions);
2381 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)(
2382 struct uverbs_attr_bundle *attrs)
2384 struct ib_uobject *uobj = uverbs_attr_get_uobject(
2385 attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE);
2386 struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata);
2387 enum mlx5_ib_uapi_flow_table_type ft_type;
2388 struct ib_flow_action *action;
2393 if (!mlx5_ib_modify_header_supported(mdev))
2396 in = uverbs_attr_get_alloced_ptr(attrs,
2397 MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM);
2399 num_actions = uverbs_attr_ptr_get_array_size(
2400 attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
2401 MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto));
2402 if (num_actions < 0)
2405 ret = uverbs_get_const(&ft_type, attrs,
2406 MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE);
2409 action = mlx5_ib_create_modify_header(mdev, ft_type, num_actions, in);
2411 return PTR_ERR(action);
2413 uverbs_flow_action_fill_action(action, uobj, &mdev->ib_dev,
2414 IB_FLOW_ACTION_UNSPECIFIED);
2419 static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev,
2420 u8 packet_reformat_type,
2423 switch (packet_reformat_type) {
2424 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
2425 if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
2426 return MLX5_CAP_FLOWTABLE(ibdev->mdev,
2427 encap_general_header);
2429 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
2430 if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
2431 return MLX5_CAP_FLOWTABLE_NIC_TX(ibdev->mdev,
2432 reformat_l2_to_l3_tunnel);
2434 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
2435 if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
2436 return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev,
2437 reformat_l3_tunnel_to_l2);
2439 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2:
2440 if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
2441 return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap);
2450 static int mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt, u8 *prm_prt)
2453 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
2454 *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
2456 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
2457 *prm_prt = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
2459 case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
2460 *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
2469 static int mlx5_ib_flow_action_create_packet_reformat_ctx(
2470 struct mlx5_ib_dev *dev,
2471 struct mlx5_ib_flow_action *maction,
2472 u8 ft_type, u8 dv_prt,
2473 void *in, size_t len)
2475 struct mlx5_pkt_reformat_params reformat_params;
2476 enum mlx5_flow_namespace_type namespace;
2480 ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
2484 ret = mlx5_ib_dv_to_prm_packet_reforamt_type(dv_prt, &prm_prt);
2488 memset(&reformat_params, 0, sizeof(reformat_params));
2489 reformat_params.type = prm_prt;
2490 reformat_params.size = len;
2491 reformat_params.data = in;
2492 maction->flow_action_raw.pkt_reformat =
2493 mlx5_packet_reformat_alloc(dev->mdev, &reformat_params,
2495 if (IS_ERR(maction->flow_action_raw.pkt_reformat)) {
2496 ret = PTR_ERR(maction->flow_action_raw.pkt_reformat);
2500 maction->flow_action_raw.sub_type =
2501 MLX5_IB_FLOW_ACTION_PACKET_REFORMAT;
2502 maction->flow_action_raw.dev = dev;
2507 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)(
2508 struct uverbs_attr_bundle *attrs)
2510 struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
2511 MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE);
2512 struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata);
2513 enum mlx5_ib_uapi_flow_action_packet_reformat_type dv_prt;
2514 enum mlx5_ib_uapi_flow_table_type ft_type;
2515 struct mlx5_ib_flow_action *maction;
2518 ret = uverbs_get_const(&ft_type, attrs,
2519 MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE);
2523 ret = uverbs_get_const(&dv_prt, attrs,
2524 MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE);
2528 if (!mlx5_ib_flow_action_packet_reformat_valid(mdev, dv_prt, ft_type))
2531 maction = kzalloc(sizeof(*maction), GFP_KERNEL);
2536 MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2) {
2537 maction->flow_action_raw.sub_type =
2538 MLX5_IB_FLOW_ACTION_DECAP;
2539 maction->flow_action_raw.dev = mdev;
2544 in = uverbs_attr_get_alloced_ptr(attrs,
2545 MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
2551 len = uverbs_attr_get_len(attrs,
2552 MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
2554 ret = mlx5_ib_flow_action_create_packet_reformat_ctx(mdev,
2555 maction, ft_type, dv_prt, in, len);
2560 uverbs_flow_action_fill_action(&maction->ib_action, uobj, &mdev->ib_dev,
2561 IB_FLOW_ACTION_UNSPECIFIED);
2569 DECLARE_UVERBS_NAMED_METHOD(
2570 MLX5_IB_METHOD_CREATE_FLOW,
2571 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
2576 MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE,
2577 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
2580 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_MATCHER,
2581 MLX5_IB_OBJECT_FLOW_MATCHER,
2584 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_QP,
2586 UVERBS_ACCESS_READ),
2587 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
2588 MLX5_IB_OBJECT_DEVX_OBJ,
2589 UVERBS_ACCESS_READ),
2590 UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS,
2591 UVERBS_OBJECT_FLOW_ACTION,
2592 UVERBS_ACCESS_READ, 1,
2593 MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS,
2595 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_TAG,
2596 UVERBS_ATTR_TYPE(u32),
2598 UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX,
2599 MLX5_IB_OBJECT_DEVX_OBJ,
2600 UVERBS_ACCESS_READ, 1, 1,
2602 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET,
2603 UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
2606 UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_CREATE_FLOW_FLAGS,
2607 enum mlx5_ib_create_flow_flags,
2610 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
2611 MLX5_IB_METHOD_DESTROY_FLOW,
2612 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
2614 UVERBS_ACCESS_DESTROY,
2617 ADD_UVERBS_METHODS(mlx5_ib_fs,
2619 &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW),
2620 &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW));
2622 DECLARE_UVERBS_NAMED_METHOD(
2623 MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER,
2624 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE,
2625 UVERBS_OBJECT_FLOW_ACTION,
2628 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
2629 UVERBS_ATTR_MIN_SIZE(MLX5_UN_SZ_BYTES(
2630 set_add_copy_action_in_auto)),
2633 UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE,
2634 enum mlx5_ib_uapi_flow_table_type,
2637 DECLARE_UVERBS_NAMED_METHOD(
2638 MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT,
2639 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE,
2640 UVERBS_OBJECT_FLOW_ACTION,
2643 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF,
2644 UVERBS_ATTR_MIN_SIZE(1),
2647 UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE,
2648 enum mlx5_ib_uapi_flow_action_packet_reformat_type,
2650 UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE,
2651 enum mlx5_ib_uapi_flow_table_type,
2655 mlx5_ib_flow_actions,
2656 UVERBS_OBJECT_FLOW_ACTION,
2657 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER),
2658 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT));
2660 DECLARE_UVERBS_NAMED_METHOD(
2661 MLX5_IB_METHOD_FLOW_MATCHER_CREATE,
2662 UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE,
2663 MLX5_IB_OBJECT_FLOW_MATCHER,
2667 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK,
2668 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
2670 UVERBS_ATTR_ENUM_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE,
2673 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
2674 UVERBS_ATTR_TYPE(u8),
2676 UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
2679 UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE,
2680 enum mlx5_ib_uapi_flow_table_type,
2683 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
2684 MLX5_IB_METHOD_FLOW_MATCHER_DESTROY,
2685 UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE,
2686 MLX5_IB_OBJECT_FLOW_MATCHER,
2687 UVERBS_ACCESS_DESTROY,
2690 DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER,
2691 UVERBS_TYPE_ALLOC_IDR(flow_matcher_cleanup),
2692 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
2693 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
2695 const struct uapi_definition mlx5_ib_flow_defs[] = {
2696 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
2697 MLX5_IB_OBJECT_FLOW_MATCHER),
2698 UAPI_DEF_CHAIN_OBJ_TREE(
2701 UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
2702 &mlx5_ib_flow_actions),
2706 static const struct ib_device_ops flow_ops = {
2707 .create_flow = mlx5_ib_create_flow,
2708 .destroy_flow = mlx5_ib_destroy_flow,
2709 .destroy_flow_action = mlx5_ib_destroy_flow_action,
2712 static const struct ib_device_ops flow_ipsec_ops = {
2713 .create_flow_action_esp = mlx5_ib_create_flow_action_esp,
2714 .modify_flow_action_esp = mlx5_ib_modify_flow_action_esp,
2717 int mlx5_ib_fs_init(struct mlx5_ib_dev *dev)
2719 dev->flow_db = kzalloc(sizeof(*dev->flow_db), GFP_KERNEL);
2724 mutex_init(&dev->flow_db->lock);
2726 ib_set_device_ops(&dev->ib_dev, &flow_ops);
2727 if (mlx5_accel_ipsec_device_caps(dev->mdev) &
2728 MLX5_ACCEL_IPSEC_CAP_DEVICE)
2729 ib_set_device_ops(&dev->ib_dev, &flow_ipsec_ops);