18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 78c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 88c2ecf20Sopenharmony_ci#include <rdma/uverbs_types.h> 98c2ecf20Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 108c2ecf20Sopenharmony_ci#include <rdma/uverbs_std_types.h> 118c2ecf20Sopenharmony_ci#include <rdma/mlx5_user_ioctl_cmds.h> 128c2ecf20Sopenharmony_ci#include <rdma/mlx5_user_ioctl_verbs.h> 138c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 148c2ecf20Sopenharmony_ci#include <linux/mlx5/driver.h> 158c2ecf20Sopenharmony_ci#include <linux/mlx5/fs.h> 168c2ecf20Sopenharmony_ci#include <linux/mlx5/fs_helpers.h> 178c2ecf20Sopenharmony_ci#include <linux/mlx5/accel.h> 188c2ecf20Sopenharmony_ci#include <linux/mlx5/eswitch.h> 198c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 208c2ecf20Sopenharmony_ci#include "counters.h" 218c2ecf20Sopenharmony_ci#include "devx.h" 228c2ecf20Sopenharmony_ci#include "fs.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define UVERBS_MODULE_NAME mlx5_ib 258c2ecf20Sopenharmony_ci#include <rdma/uverbs_named_ioctl.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cienum { 288c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_OUTER_BIT, 298c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_MISC_BIT, 308c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_INNER_BIT, 318c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_MISC2_BIT 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define HEADER_IS_ZERO(match_criteria, headers) \ 358c2ecf20Sopenharmony_ci !(memchr_inv(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \ 368c2ecf20Sopenharmony_ci 0, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic u8 get_match_criteria_enable(u32 *match_criteria) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci u8 match_criteria_enable; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci match_criteria_enable = 438c2ecf20Sopenharmony_ci (!HEADER_IS_ZERO(match_criteria, outer_headers)) << 448c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_OUTER_BIT; 458c2ecf20Sopenharmony_ci match_criteria_enable |= 468c2ecf20Sopenharmony_ci (!HEADER_IS_ZERO(match_criteria, misc_parameters)) << 478c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_MISC_BIT; 488c2ecf20Sopenharmony_ci match_criteria_enable |= 498c2ecf20Sopenharmony_ci (!HEADER_IS_ZERO(match_criteria, inner_headers)) << 508c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_INNER_BIT; 518c2ecf20Sopenharmony_ci match_criteria_enable |= 528c2ecf20Sopenharmony_ci (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) << 538c2ecf20Sopenharmony_ci MATCH_CRITERIA_ENABLE_MISC2_BIT; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return match_criteria_enable; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int set_proto(void *outer_c, void *outer_v, u8 mask, u8 val) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci u8 entry_mask; 618c2ecf20Sopenharmony_ci u8 entry_val; 628c2ecf20Sopenharmony_ci int err = 0; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (!mask) 658c2ecf20Sopenharmony_ci goto out; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci entry_mask = MLX5_GET(fte_match_set_lyr_2_4, outer_c, 688c2ecf20Sopenharmony_ci ip_protocol); 698c2ecf20Sopenharmony_ci entry_val = MLX5_GET(fte_match_set_lyr_2_4, outer_v, 708c2ecf20Sopenharmony_ci ip_protocol); 718c2ecf20Sopenharmony_ci if (!entry_mask) { 728c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_protocol, mask); 738c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_protocol, val); 748c2ecf20Sopenharmony_ci goto out; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci /* Don't override existing ip protocol */ 778c2ecf20Sopenharmony_ci if (mask != entry_mask || val != entry_val) 788c2ecf20Sopenharmony_ci err = -EINVAL; 798c2ecf20Sopenharmony_ciout: 808c2ecf20Sopenharmony_ci return err; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void set_flow_label(void *misc_c, void *misc_v, u32 mask, u32 val, 848c2ecf20Sopenharmony_ci bool inner) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci if (inner) { 878c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 888c2ecf20Sopenharmony_ci misc_c, inner_ipv6_flow_label, mask); 898c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 908c2ecf20Sopenharmony_ci misc_v, inner_ipv6_flow_label, val); 918c2ecf20Sopenharmony_ci } else { 928c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 938c2ecf20Sopenharmony_ci misc_c, outer_ipv6_flow_label, mask); 948c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 958c2ecf20Sopenharmony_ci misc_v, outer_ipv6_flow_label, val); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_ecn, mask); 1028c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_ecn, val); 1038c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_dscp, mask >> 2); 1048c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_dscp, val >> 2); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int check_mpls_supp_fields(u32 field_support, const __be32 *set_mask) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (MLX5_GET(fte_match_mpls, set_mask, mpls_label) && 1108c2ecf20Sopenharmony_ci !(field_support & MLX5_FIELD_SUPPORT_MPLS_LABEL)) 1118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (MLX5_GET(fte_match_mpls, set_mask, mpls_exp) && 1148c2ecf20Sopenharmony_ci !(field_support & MLX5_FIELD_SUPPORT_MPLS_EXP)) 1158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (MLX5_GET(fte_match_mpls, set_mask, mpls_s_bos) && 1188c2ecf20Sopenharmony_ci !(field_support & MLX5_FIELD_SUPPORT_MPLS_S_BOS)) 1198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (MLX5_GET(fte_match_mpls, set_mask, mpls_ttl) && 1228c2ecf20Sopenharmony_ci !(field_support & MLX5_FIELD_SUPPORT_MPLS_TTL)) 1238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define LAST_ETH_FIELD vlan_tag 1298c2ecf20Sopenharmony_ci#define LAST_IB_FIELD sl 1308c2ecf20Sopenharmony_ci#define LAST_IPV4_FIELD tos 1318c2ecf20Sopenharmony_ci#define LAST_IPV6_FIELD traffic_class 1328c2ecf20Sopenharmony_ci#define LAST_TCP_UDP_FIELD src_port 1338c2ecf20Sopenharmony_ci#define LAST_TUNNEL_FIELD tunnel_id 1348c2ecf20Sopenharmony_ci#define LAST_FLOW_TAG_FIELD tag_id 1358c2ecf20Sopenharmony_ci#define LAST_DROP_FIELD size 1368c2ecf20Sopenharmony_ci#define LAST_COUNTERS_FIELD counters 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Field is the last supported field */ 1398c2ecf20Sopenharmony_ci#define FIELDS_NOT_SUPPORTED(filter, field) \ 1408c2ecf20Sopenharmony_ci memchr_inv((void *)&filter.field + sizeof(filter.field), 0, \ 1418c2ecf20Sopenharmony_ci sizeof(filter) - offsetofend(typeof(filter), field)) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciint parse_flow_flow_action(struct mlx5_ib_flow_action *maction, 1448c2ecf20Sopenharmony_ci bool is_egress, 1458c2ecf20Sopenharmony_ci struct mlx5_flow_act *action) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci switch (maction->ib_action.type) { 1498c2ecf20Sopenharmony_ci case IB_FLOW_ACTION_ESP: 1508c2ecf20Sopenharmony_ci if (action->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | 1518c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_DECRYPT)) 1528c2ecf20Sopenharmony_ci return -EINVAL; 1538c2ecf20Sopenharmony_ci /* Currently only AES_GCM keymat is supported by the driver */ 1548c2ecf20Sopenharmony_ci action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx; 1558c2ecf20Sopenharmony_ci action->action |= is_egress ? 1568c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_ENCRYPT : 1578c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_DECRYPT; 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci case IB_FLOW_ACTION_UNSPECIFIED: 1608c2ecf20Sopenharmony_ci if (maction->flow_action_raw.sub_type == 1618c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_MODIFY_HEADER) { 1628c2ecf20Sopenharmony_ci if (action->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; 1658c2ecf20Sopenharmony_ci action->modify_hdr = 1668c2ecf20Sopenharmony_ci maction->flow_action_raw.modify_hdr; 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (maction->flow_action_raw.sub_type == 1708c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_DECAP) { 1718c2ecf20Sopenharmony_ci if (action->action & MLX5_FLOW_CONTEXT_ACTION_DECAP) 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci if (maction->flow_action_raw.sub_type == 1778c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_PACKET_REFORMAT) { 1788c2ecf20Sopenharmony_ci if (action->action & 1798c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci action->action |= 1828c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; 1838c2ecf20Sopenharmony_ci action->pkt_reformat = 1848c2ecf20Sopenharmony_ci maction->flow_action_raw.pkt_reformat; 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci fallthrough; 1888c2ecf20Sopenharmony_ci default: 1898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int parse_flow_attr(struct mlx5_core_dev *mdev, 1948c2ecf20Sopenharmony_ci struct mlx5_flow_spec *spec, 1958c2ecf20Sopenharmony_ci const union ib_flow_spec *ib_spec, 1968c2ecf20Sopenharmony_ci const struct ib_flow_attr *flow_attr, 1978c2ecf20Sopenharmony_ci struct mlx5_flow_act *action, u32 prev_type) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct mlx5_flow_context *flow_context = &spec->flow_context; 2008c2ecf20Sopenharmony_ci u32 *match_c = spec->match_criteria; 2018c2ecf20Sopenharmony_ci u32 *match_v = spec->match_value; 2028c2ecf20Sopenharmony_ci void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c, 2038c2ecf20Sopenharmony_ci misc_parameters); 2048c2ecf20Sopenharmony_ci void *misc_params_v = MLX5_ADDR_OF(fte_match_param, match_v, 2058c2ecf20Sopenharmony_ci misc_parameters); 2068c2ecf20Sopenharmony_ci void *misc_params2_c = MLX5_ADDR_OF(fte_match_param, match_c, 2078c2ecf20Sopenharmony_ci misc_parameters_2); 2088c2ecf20Sopenharmony_ci void *misc_params2_v = MLX5_ADDR_OF(fte_match_param, match_v, 2098c2ecf20Sopenharmony_ci misc_parameters_2); 2108c2ecf20Sopenharmony_ci void *headers_c; 2118c2ecf20Sopenharmony_ci void *headers_v; 2128c2ecf20Sopenharmony_ci int match_ipv; 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (ib_spec->type & IB_FLOW_SPEC_INNER) { 2168c2ecf20Sopenharmony_ci headers_c = MLX5_ADDR_OF(fte_match_param, match_c, 2178c2ecf20Sopenharmony_ci inner_headers); 2188c2ecf20Sopenharmony_ci headers_v = MLX5_ADDR_OF(fte_match_param, match_v, 2198c2ecf20Sopenharmony_ci inner_headers); 2208c2ecf20Sopenharmony_ci match_ipv = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 2218c2ecf20Sopenharmony_ci ft_field_support.inner_ip_version); 2228c2ecf20Sopenharmony_ci } else { 2238c2ecf20Sopenharmony_ci headers_c = MLX5_ADDR_OF(fte_match_param, match_c, 2248c2ecf20Sopenharmony_ci outer_headers); 2258c2ecf20Sopenharmony_ci headers_v = MLX5_ADDR_OF(fte_match_param, match_v, 2268c2ecf20Sopenharmony_ci outer_headers); 2278c2ecf20Sopenharmony_ci match_ipv = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 2288c2ecf20Sopenharmony_ci ft_field_support.outer_ip_version); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) { 2328c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ETH: 2338c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD)) 2348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 2378c2ecf20Sopenharmony_ci dmac_47_16), 2388c2ecf20Sopenharmony_ci ib_spec->eth.mask.dst_mac); 2398c2ecf20Sopenharmony_ci ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 2408c2ecf20Sopenharmony_ci dmac_47_16), 2418c2ecf20Sopenharmony_ci ib_spec->eth.val.dst_mac); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 2448c2ecf20Sopenharmony_ci smac_47_16), 2458c2ecf20Sopenharmony_ci ib_spec->eth.mask.src_mac); 2468c2ecf20Sopenharmony_ci ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 2478c2ecf20Sopenharmony_ci smac_47_16), 2488c2ecf20Sopenharmony_ci ib_spec->eth.val.src_mac); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (ib_spec->eth.mask.vlan_tag) { 2518c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2528c2ecf20Sopenharmony_ci cvlan_tag, 1); 2538c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2548c2ecf20Sopenharmony_ci cvlan_tag, 1); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2578c2ecf20Sopenharmony_ci first_vid, ntohs(ib_spec->eth.mask.vlan_tag)); 2588c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2598c2ecf20Sopenharmony_ci first_vid, ntohs(ib_spec->eth.val.vlan_tag)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2628c2ecf20Sopenharmony_ci first_cfi, 2638c2ecf20Sopenharmony_ci ntohs(ib_spec->eth.mask.vlan_tag) >> 12); 2648c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2658c2ecf20Sopenharmony_ci first_cfi, 2668c2ecf20Sopenharmony_ci ntohs(ib_spec->eth.val.vlan_tag) >> 12); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2698c2ecf20Sopenharmony_ci first_prio, 2708c2ecf20Sopenharmony_ci ntohs(ib_spec->eth.mask.vlan_tag) >> 13); 2718c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2728c2ecf20Sopenharmony_ci first_prio, 2738c2ecf20Sopenharmony_ci ntohs(ib_spec->eth.val.vlan_tag) >> 13); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2768c2ecf20Sopenharmony_ci ethertype, ntohs(ib_spec->eth.mask.ether_type)); 2778c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2788c2ecf20Sopenharmony_ci ethertype, ntohs(ib_spec->eth.val.ether_type)); 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_IPV4: 2818c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD)) 2828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (match_ipv) { 2858c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2868c2ecf20Sopenharmony_ci ip_version, 0xf); 2878c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2888c2ecf20Sopenharmony_ci ip_version, MLX5_FS_IPV4_VERSION); 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 2918c2ecf20Sopenharmony_ci ethertype, 0xffff); 2928c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 2938c2ecf20Sopenharmony_ci ethertype, ETH_P_IP); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 2978c2ecf20Sopenharmony_ci src_ipv4_src_ipv6.ipv4_layout.ipv4), 2988c2ecf20Sopenharmony_ci &ib_spec->ipv4.mask.src_ip, 2998c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv4.mask.src_ip)); 3008c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 3018c2ecf20Sopenharmony_ci src_ipv4_src_ipv6.ipv4_layout.ipv4), 3028c2ecf20Sopenharmony_ci &ib_spec->ipv4.val.src_ip, 3038c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv4.val.src_ip)); 3048c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 3058c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 3068c2ecf20Sopenharmony_ci &ib_spec->ipv4.mask.dst_ip, 3078c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv4.mask.dst_ip)); 3088c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 3098c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 3108c2ecf20Sopenharmony_ci &ib_spec->ipv4.val.dst_ip, 3118c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv4.val.dst_ip)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci set_tos(headers_c, headers_v, 3148c2ecf20Sopenharmony_ci ib_spec->ipv4.mask.tos, ib_spec->ipv4.val.tos); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (set_proto(headers_c, headers_v, 3178c2ecf20Sopenharmony_ci ib_spec->ipv4.mask.proto, 3188c2ecf20Sopenharmony_ci ib_spec->ipv4.val.proto)) 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_IPV6: 3228c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->ipv6.mask, LAST_IPV6_FIELD)) 3238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (match_ipv) { 3268c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 3278c2ecf20Sopenharmony_ci ip_version, 0xf); 3288c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 3298c2ecf20Sopenharmony_ci ip_version, MLX5_FS_IPV6_VERSION); 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, 3328c2ecf20Sopenharmony_ci ethertype, 0xffff); 3338c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, 3348c2ecf20Sopenharmony_ci ethertype, ETH_P_IPV6); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 3388c2ecf20Sopenharmony_ci src_ipv4_src_ipv6.ipv6_layout.ipv6), 3398c2ecf20Sopenharmony_ci &ib_spec->ipv6.mask.src_ip, 3408c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv6.mask.src_ip)); 3418c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 3428c2ecf20Sopenharmony_ci src_ipv4_src_ipv6.ipv6_layout.ipv6), 3438c2ecf20Sopenharmony_ci &ib_spec->ipv6.val.src_ip, 3448c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv6.val.src_ip)); 3458c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 3468c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 3478c2ecf20Sopenharmony_ci &ib_spec->ipv6.mask.dst_ip, 3488c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv6.mask.dst_ip)); 3498c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 3508c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 3518c2ecf20Sopenharmony_ci &ib_spec->ipv6.val.dst_ip, 3528c2ecf20Sopenharmony_ci sizeof(ib_spec->ipv6.val.dst_ip)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci set_tos(headers_c, headers_v, 3558c2ecf20Sopenharmony_ci ib_spec->ipv6.mask.traffic_class, 3568c2ecf20Sopenharmony_ci ib_spec->ipv6.val.traffic_class); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (set_proto(headers_c, headers_v, 3598c2ecf20Sopenharmony_ci ib_spec->ipv6.mask.next_hdr, 3608c2ecf20Sopenharmony_ci ib_spec->ipv6.val.next_hdr)) 3618c2ecf20Sopenharmony_ci return -EINVAL; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci set_flow_label(misc_params_c, misc_params_v, 3648c2ecf20Sopenharmony_ci ntohl(ib_spec->ipv6.mask.flow_label), 3658c2ecf20Sopenharmony_ci ntohl(ib_spec->ipv6.val.flow_label), 3668c2ecf20Sopenharmony_ci ib_spec->type & IB_FLOW_SPEC_INNER); 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ESP: 3698c2ecf20Sopenharmony_ci if (ib_spec->esp.mask.seq) 3708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_c, outer_esp_spi, 3738c2ecf20Sopenharmony_ci ntohl(ib_spec->esp.mask.spi)); 3748c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_v, outer_esp_spi, 3758c2ecf20Sopenharmony_ci ntohl(ib_spec->esp.val.spi)); 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_TCP: 3788c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, 3798c2ecf20Sopenharmony_ci LAST_TCP_UDP_FIELD)) 3808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (set_proto(headers_c, headers_v, 0xff, IPPROTO_TCP)) 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_sport, 3868c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.mask.src_port)); 3878c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, 3888c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.val.src_port)); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_dport, 3918c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.mask.dst_port)); 3928c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, 3938c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.val.dst_port)); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_UDP: 3968c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, 3978c2ecf20Sopenharmony_ci LAST_TCP_UDP_FIELD)) 3988c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (set_proto(headers_c, headers_v, 0xff, IPPROTO_UDP)) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport, 4048c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.mask.src_port)); 4058c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, 4068c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.val.src_port)); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport, 4098c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.mask.dst_port)); 4108c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, 4118c2ecf20Sopenharmony_ci ntohs(ib_spec->tcp_udp.val.dst_port)); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_GRE: 4148c2ecf20Sopenharmony_ci if (ib_spec->gre.mask.c_ks_res0_ver) 4158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (set_proto(headers_c, headers_v, 0xff, IPPROTO_GRE)) 4188c2ecf20Sopenharmony_ci return -EINVAL; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 4218c2ecf20Sopenharmony_ci 0xff); 4228c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 4238c2ecf20Sopenharmony_ci IPPROTO_GRE); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_c, gre_protocol, 4268c2ecf20Sopenharmony_ci ntohs(ib_spec->gre.mask.protocol)); 4278c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_v, gre_protocol, 4288c2ecf20Sopenharmony_ci ntohs(ib_spec->gre.val.protocol)); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc, misc_params_c, 4318c2ecf20Sopenharmony_ci gre_key.nvgre.hi), 4328c2ecf20Sopenharmony_ci &ib_spec->gre.mask.key, 4338c2ecf20Sopenharmony_ci sizeof(ib_spec->gre.mask.key)); 4348c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc, misc_params_v, 4358c2ecf20Sopenharmony_ci gre_key.nvgre.hi), 4368c2ecf20Sopenharmony_ci &ib_spec->gre.val.key, 4378c2ecf20Sopenharmony_ci sizeof(ib_spec->gre.val.key)); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_MPLS: 4408c2ecf20Sopenharmony_ci switch (prev_type) { 4418c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_UDP: 4428c2ecf20Sopenharmony_ci if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 4438c2ecf20Sopenharmony_ci ft_field_support.outer_first_mpls_over_udp), 4448c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag)) 4458c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v, 4488c2ecf20Sopenharmony_ci outer_first_mpls_over_udp), 4498c2ecf20Sopenharmony_ci &ib_spec->mpls.val.tag, 4508c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.val.tag)); 4518c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c, 4528c2ecf20Sopenharmony_ci outer_first_mpls_over_udp), 4538c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag, 4548c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.mask.tag)); 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_GRE: 4578c2ecf20Sopenharmony_ci if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 4588c2ecf20Sopenharmony_ci ft_field_support.outer_first_mpls_over_gre), 4598c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag)) 4608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v, 4638c2ecf20Sopenharmony_ci outer_first_mpls_over_gre), 4648c2ecf20Sopenharmony_ci &ib_spec->mpls.val.tag, 4658c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.val.tag)); 4668c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c, 4678c2ecf20Sopenharmony_ci outer_first_mpls_over_gre), 4688c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag, 4698c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.mask.tag)); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci default: 4728c2ecf20Sopenharmony_ci if (ib_spec->type & IB_FLOW_SPEC_INNER) { 4738c2ecf20Sopenharmony_ci if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 4748c2ecf20Sopenharmony_ci ft_field_support.inner_first_mpls), 4758c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag)) 4768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v, 4798c2ecf20Sopenharmony_ci inner_first_mpls), 4808c2ecf20Sopenharmony_ci &ib_spec->mpls.val.tag, 4818c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.val.tag)); 4828c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c, 4838c2ecf20Sopenharmony_ci inner_first_mpls), 4848c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag, 4858c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.mask.tag)); 4868c2ecf20Sopenharmony_ci } else { 4878c2ecf20Sopenharmony_ci if (check_mpls_supp_fields(MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 4888c2ecf20Sopenharmony_ci ft_field_support.outer_first_mpls), 4898c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag)) 4908c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_v, 4938c2ecf20Sopenharmony_ci outer_first_mpls), 4948c2ecf20Sopenharmony_ci &ib_spec->mpls.val.tag, 4958c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.val.tag)); 4968c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(fte_match_set_misc2, misc_params2_c, 4978c2ecf20Sopenharmony_ci outer_first_mpls), 4988c2ecf20Sopenharmony_ci &ib_spec->mpls.mask.tag, 4998c2ecf20Sopenharmony_ci sizeof(ib_spec->mpls.mask.tag)); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_VXLAN_TUNNEL: 5048c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->tunnel.mask, 5058c2ecf20Sopenharmony_ci LAST_TUNNEL_FIELD)) 5068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_c, vxlan_vni, 5098c2ecf20Sopenharmony_ci ntohl(ib_spec->tunnel.mask.tunnel_id)); 5108c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc_params_v, vxlan_vni, 5118c2ecf20Sopenharmony_ci ntohl(ib_spec->tunnel.val.tunnel_id)); 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ACTION_TAG: 5148c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->flow_tag, 5158c2ecf20Sopenharmony_ci LAST_FLOW_TAG_FIELD)) 5168c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5178c2ecf20Sopenharmony_ci if (ib_spec->flow_tag.tag_id >= BIT(24)) 5188c2ecf20Sopenharmony_ci return -EINVAL; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci flow_context->flow_tag = ib_spec->flow_tag.tag_id; 5218c2ecf20Sopenharmony_ci flow_context->flags |= FLOW_CONTEXT_HAS_TAG; 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ACTION_DROP: 5248c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->drop, 5258c2ecf20Sopenharmony_ci LAST_DROP_FIELD)) 5268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5278c2ecf20Sopenharmony_ci action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ACTION_HANDLE: 5308c2ecf20Sopenharmony_ci ret = parse_flow_flow_action(to_mflow_act(ib_spec->action.act), 5318c2ecf20Sopenharmony_ci flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS, action); 5328c2ecf20Sopenharmony_ci if (ret) 5338c2ecf20Sopenharmony_ci return ret; 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case IB_FLOW_SPEC_ACTION_COUNT: 5368c2ecf20Sopenharmony_ci if (FIELDS_NOT_SUPPORTED(ib_spec->flow_count, 5378c2ecf20Sopenharmony_ci LAST_COUNTERS_FIELD)) 5388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* for now support only one counters spec per flow */ 5418c2ecf20Sopenharmony_ci if (action->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci action->counters = ib_spec->flow_count.counters; 5458c2ecf20Sopenharmony_ci action->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci default: 5488c2ecf20Sopenharmony_ci return -EINVAL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* If a flow could catch both multicast and unicast packets, 5558c2ecf20Sopenharmony_ci * it won't fall into the multicast flow steering table and this rule 5568c2ecf20Sopenharmony_ci * could steal other multicast packets. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_cistatic bool flow_is_multicast_only(const struct ib_flow_attr *ib_attr) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci union ib_flow_spec *flow_spec; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (ib_attr->type != IB_FLOW_ATTR_NORMAL || 5638c2ecf20Sopenharmony_ci ib_attr->num_of_specs < 1) 5648c2ecf20Sopenharmony_ci return false; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci flow_spec = (union ib_flow_spec *)(ib_attr + 1); 5678c2ecf20Sopenharmony_ci if (flow_spec->type == IB_FLOW_SPEC_IPV4) { 5688c2ecf20Sopenharmony_ci struct ib_flow_spec_ipv4 *ipv4_spec; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ipv4_spec = (struct ib_flow_spec_ipv4 *)flow_spec; 5718c2ecf20Sopenharmony_ci if (ipv4_is_multicast(ipv4_spec->val.dst_ip)) 5728c2ecf20Sopenharmony_ci return true; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return false; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (flow_spec->type == IB_FLOW_SPEC_ETH) { 5788c2ecf20Sopenharmony_ci struct ib_flow_spec_eth *eth_spec; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci eth_spec = (struct ib_flow_spec_eth *)flow_spec; 5818c2ecf20Sopenharmony_ci return is_multicast_ether_addr(eth_spec->mask.dst_mac) && 5828c2ecf20Sopenharmony_ci is_multicast_ether_addr(eth_spec->val.dst_mac); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return false; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cienum valid_spec { 5898c2ecf20Sopenharmony_ci VALID_SPEC_INVALID, 5908c2ecf20Sopenharmony_ci VALID_SPEC_VALID, 5918c2ecf20Sopenharmony_ci VALID_SPEC_NA, 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic enum valid_spec 5958c2ecf20Sopenharmony_ciis_valid_esp_aes_gcm(struct mlx5_core_dev *mdev, 5968c2ecf20Sopenharmony_ci const struct mlx5_flow_spec *spec, 5978c2ecf20Sopenharmony_ci const struct mlx5_flow_act *flow_act, 5988c2ecf20Sopenharmony_ci bool egress) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci const u32 *match_c = spec->match_criteria; 6018c2ecf20Sopenharmony_ci bool is_crypto = 6028c2ecf20Sopenharmony_ci (flow_act->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | 6038c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_DECRYPT)); 6048c2ecf20Sopenharmony_ci bool is_ipsec = mlx5_fs_is_ipsec_flow(match_c); 6058c2ecf20Sopenharmony_ci bool is_drop = flow_act->action & MLX5_FLOW_CONTEXT_ACTION_DROP; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* 6088c2ecf20Sopenharmony_ci * Currently only crypto is supported in egress, when regular egress 6098c2ecf20Sopenharmony_ci * rules would be supported, always return VALID_SPEC_NA. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci if (!is_crypto) 6128c2ecf20Sopenharmony_ci return VALID_SPEC_NA; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return is_crypto && is_ipsec && 6158c2ecf20Sopenharmony_ci (!egress || (!is_drop && 6168c2ecf20Sopenharmony_ci !(spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG))) ? 6178c2ecf20Sopenharmony_ci VALID_SPEC_VALID : VALID_SPEC_INVALID; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic bool is_valid_spec(struct mlx5_core_dev *mdev, 6218c2ecf20Sopenharmony_ci const struct mlx5_flow_spec *spec, 6228c2ecf20Sopenharmony_ci const struct mlx5_flow_act *flow_act, 6238c2ecf20Sopenharmony_ci bool egress) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci /* We curretly only support ipsec egress flow */ 6268c2ecf20Sopenharmony_ci return is_valid_esp_aes_gcm(mdev, spec, flow_act, egress) != VALID_SPEC_INVALID; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic bool is_valid_ethertype(struct mlx5_core_dev *mdev, 6308c2ecf20Sopenharmony_ci const struct ib_flow_attr *flow_attr, 6318c2ecf20Sopenharmony_ci bool check_inner) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci union ib_flow_spec *ib_spec = (union ib_flow_spec *)(flow_attr + 1); 6348c2ecf20Sopenharmony_ci int match_ipv = check_inner ? 6358c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 6368c2ecf20Sopenharmony_ci ft_field_support.inner_ip_version) : 6378c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 6388c2ecf20Sopenharmony_ci ft_field_support.outer_ip_version); 6398c2ecf20Sopenharmony_ci int inner_bit = check_inner ? IB_FLOW_SPEC_INNER : 0; 6408c2ecf20Sopenharmony_ci bool ipv4_spec_valid, ipv6_spec_valid; 6418c2ecf20Sopenharmony_ci unsigned int ip_spec_type = 0; 6428c2ecf20Sopenharmony_ci bool has_ethertype = false; 6438c2ecf20Sopenharmony_ci unsigned int spec_index; 6448c2ecf20Sopenharmony_ci bool mask_valid = true; 6458c2ecf20Sopenharmony_ci u16 eth_type = 0; 6468c2ecf20Sopenharmony_ci bool type_valid; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* Validate that ethertype is correct */ 6498c2ecf20Sopenharmony_ci for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) { 6508c2ecf20Sopenharmony_ci if ((ib_spec->type == (IB_FLOW_SPEC_ETH | inner_bit)) && 6518c2ecf20Sopenharmony_ci ib_spec->eth.mask.ether_type) { 6528c2ecf20Sopenharmony_ci mask_valid = (ib_spec->eth.mask.ether_type == 6538c2ecf20Sopenharmony_ci htons(0xffff)); 6548c2ecf20Sopenharmony_ci has_ethertype = true; 6558c2ecf20Sopenharmony_ci eth_type = ntohs(ib_spec->eth.val.ether_type); 6568c2ecf20Sopenharmony_ci } else if ((ib_spec->type == (IB_FLOW_SPEC_IPV4 | inner_bit)) || 6578c2ecf20Sopenharmony_ci (ib_spec->type == (IB_FLOW_SPEC_IPV6 | inner_bit))) { 6588c2ecf20Sopenharmony_ci ip_spec_type = ib_spec->type; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci ib_spec = (void *)ib_spec + ib_spec->size; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci type_valid = (!has_ethertype) || (!ip_spec_type); 6648c2ecf20Sopenharmony_ci if (!type_valid && mask_valid) { 6658c2ecf20Sopenharmony_ci ipv4_spec_valid = (eth_type == ETH_P_IP) && 6668c2ecf20Sopenharmony_ci (ip_spec_type == (IB_FLOW_SPEC_IPV4 | inner_bit)); 6678c2ecf20Sopenharmony_ci ipv6_spec_valid = (eth_type == ETH_P_IPV6) && 6688c2ecf20Sopenharmony_ci (ip_spec_type == (IB_FLOW_SPEC_IPV6 | inner_bit)); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci type_valid = (ipv4_spec_valid) || (ipv6_spec_valid) || 6718c2ecf20Sopenharmony_ci (((eth_type == ETH_P_MPLS_UC) || 6728c2ecf20Sopenharmony_ci (eth_type == ETH_P_MPLS_MC)) && match_ipv); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return type_valid; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic bool is_valid_attr(struct mlx5_core_dev *mdev, 6798c2ecf20Sopenharmony_ci const struct ib_flow_attr *flow_attr) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci return is_valid_ethertype(mdev, flow_attr, false) && 6828c2ecf20Sopenharmony_ci is_valid_ethertype(mdev, flow_attr, true); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic void put_flow_table(struct mlx5_ib_dev *dev, 6868c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *prio, bool ft_added) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci prio->refcount -= !!ft_added; 6898c2ecf20Sopenharmony_ci if (!prio->refcount) { 6908c2ecf20Sopenharmony_ci mlx5_destroy_flow_table(prio->flow_table); 6918c2ecf20Sopenharmony_ci prio->flow_table = NULL; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int mlx5_ib_destroy_flow(struct ib_flow *flow_id) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler = container_of(flow_id, 6988c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler, 6998c2ecf20Sopenharmony_ci ibflow); 7008c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *iter, *tmp; 7018c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = handler->dev; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci mutex_lock(&dev->flow_db->lock); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci list_for_each_entry_safe(iter, tmp, &handler->list, list) { 7068c2ecf20Sopenharmony_ci mlx5_del_flow_rules(iter->rule); 7078c2ecf20Sopenharmony_ci put_flow_table(dev, iter->prio, true); 7088c2ecf20Sopenharmony_ci list_del(&iter->list); 7098c2ecf20Sopenharmony_ci kfree(iter); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci mlx5_del_flow_rules(handler->rule); 7138c2ecf20Sopenharmony_ci put_flow_table(dev, handler->prio, true); 7148c2ecf20Sopenharmony_ci mlx5_ib_counters_clear_description(handler->ibcounters); 7158c2ecf20Sopenharmony_ci mutex_unlock(&dev->flow_db->lock); 7168c2ecf20Sopenharmony_ci if (handler->flow_matcher) 7178c2ecf20Sopenharmony_ci atomic_dec(&handler->flow_matcher->usecnt); 7188c2ecf20Sopenharmony_ci kfree(handler); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int ib_prio_to_core_prio(unsigned int priority, bool dont_trap) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci priority *= 2; 7268c2ecf20Sopenharmony_ci if (!dont_trap) 7278c2ecf20Sopenharmony_ci priority++; 7288c2ecf20Sopenharmony_ci return priority; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cienum flow_table_type { 7328c2ecf20Sopenharmony_ci MLX5_IB_FT_RX, 7338c2ecf20Sopenharmony_ci MLX5_IB_FT_TX 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci#define MLX5_FS_MAX_TYPES 6 7378c2ecf20Sopenharmony_ci#define MLX5_FS_MAX_ENTRIES BIT(16) 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_prio *_get_prio(struct mlx5_flow_namespace *ns, 7408c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *prio, 7418c2ecf20Sopenharmony_ci int priority, 7428c2ecf20Sopenharmony_ci int num_entries, int num_groups, 7438c2ecf20Sopenharmony_ci u32 flags) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci struct mlx5_flow_table_attr ft_attr = {}; 7468c2ecf20Sopenharmony_ci struct mlx5_flow_table *ft; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci ft_attr.prio = priority; 7498c2ecf20Sopenharmony_ci ft_attr.max_fte = num_entries; 7508c2ecf20Sopenharmony_ci ft_attr.flags = flags; 7518c2ecf20Sopenharmony_ci ft_attr.autogroup.max_num_groups = num_groups; 7528c2ecf20Sopenharmony_ci ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 7538c2ecf20Sopenharmony_ci if (IS_ERR(ft)) 7548c2ecf20Sopenharmony_ci return ERR_CAST(ft); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci prio->flow_table = ft; 7578c2ecf20Sopenharmony_ci prio->refcount = 0; 7588c2ecf20Sopenharmony_ci return prio; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, 7628c2ecf20Sopenharmony_ci struct ib_flow_attr *flow_attr, 7638c2ecf20Sopenharmony_ci enum flow_table_type ft_type) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci bool dont_trap = flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP; 7668c2ecf20Sopenharmony_ci struct mlx5_flow_namespace *ns = NULL; 7678c2ecf20Sopenharmony_ci enum mlx5_flow_namespace_type fn_type; 7688c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *prio; 7698c2ecf20Sopenharmony_ci struct mlx5_flow_table *ft; 7708c2ecf20Sopenharmony_ci int max_table_size; 7718c2ecf20Sopenharmony_ci int num_entries; 7728c2ecf20Sopenharmony_ci int num_groups; 7738c2ecf20Sopenharmony_ci bool esw_encap; 7748c2ecf20Sopenharmony_ci u32 flags = 0; 7758c2ecf20Sopenharmony_ci int priority; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, 7788c2ecf20Sopenharmony_ci log_max_ft_size)); 7798c2ecf20Sopenharmony_ci esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) != 7808c2ecf20Sopenharmony_ci DEVLINK_ESWITCH_ENCAP_MODE_NONE; 7818c2ecf20Sopenharmony_ci switch (flow_attr->type) { 7828c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_NORMAL: 7838c2ecf20Sopenharmony_ci if (flow_is_multicast_only(flow_attr) && !dont_trap) 7848c2ecf20Sopenharmony_ci priority = MLX5_IB_FLOW_MCAST_PRIO; 7858c2ecf20Sopenharmony_ci else 7868c2ecf20Sopenharmony_ci priority = ib_prio_to_core_prio(flow_attr->priority, 7878c2ecf20Sopenharmony_ci dont_trap); 7888c2ecf20Sopenharmony_ci if (ft_type == MLX5_IB_FT_RX) { 7898c2ecf20Sopenharmony_ci fn_type = MLX5_FLOW_NAMESPACE_BYPASS; 7908c2ecf20Sopenharmony_ci prio = &dev->flow_db->prios[priority]; 7918c2ecf20Sopenharmony_ci if (!dev->is_rep && !esw_encap && 7928c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap)) 7938c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; 7948c2ecf20Sopenharmony_ci if (!dev->is_rep && !esw_encap && 7958c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, 7968c2ecf20Sopenharmony_ci reformat_l3_tunnel_to_l2)) 7978c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX( 8008c2ecf20Sopenharmony_ci dev->mdev, log_max_ft_size)); 8018c2ecf20Sopenharmony_ci fn_type = MLX5_FLOW_NAMESPACE_EGRESS; 8028c2ecf20Sopenharmony_ci prio = &dev->flow_db->egress_prios[priority]; 8038c2ecf20Sopenharmony_ci if (!dev->is_rep && !esw_encap && 8048c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat)) 8058c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci ns = mlx5_get_flow_namespace(dev->mdev, fn_type); 8088c2ecf20Sopenharmony_ci num_entries = MLX5_FS_MAX_ENTRIES; 8098c2ecf20Sopenharmony_ci num_groups = MLX5_FS_MAX_TYPES; 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_ALL_DEFAULT: 8128c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_MC_DEFAULT: 8138c2ecf20Sopenharmony_ci ns = mlx5_get_flow_namespace(dev->mdev, 8148c2ecf20Sopenharmony_ci MLX5_FLOW_NAMESPACE_LEFTOVERS); 8158c2ecf20Sopenharmony_ci build_leftovers_ft_param(&priority, &num_entries, &num_groups); 8168c2ecf20Sopenharmony_ci prio = &dev->flow_db->prios[MLX5_IB_FLOW_LEFTOVERS_PRIO]; 8178c2ecf20Sopenharmony_ci break; 8188c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_SNIFFER: 8198c2ecf20Sopenharmony_ci if (!MLX5_CAP_FLOWTABLE(dev->mdev, 8208c2ecf20Sopenharmony_ci allow_sniffer_and_nic_rx_shared_tir)) 8218c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ns = mlx5_get_flow_namespace( 8248c2ecf20Sopenharmony_ci dev->mdev, ft_type == MLX5_IB_FT_RX ? 8258c2ecf20Sopenharmony_ci MLX5_FLOW_NAMESPACE_SNIFFER_RX : 8268c2ecf20Sopenharmony_ci MLX5_FLOW_NAMESPACE_SNIFFER_TX); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci prio = &dev->flow_db->sniffer[ft_type]; 8298c2ecf20Sopenharmony_ci priority = 0; 8308c2ecf20Sopenharmony_ci num_entries = 1; 8318c2ecf20Sopenharmony_ci num_groups = 1; 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci default: 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (!ns) 8388c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci max_table_size = min_t(int, num_entries, max_table_size); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ft = prio->flow_table; 8438c2ecf20Sopenharmony_ci if (!ft) 8448c2ecf20Sopenharmony_ci return _get_prio(ns, prio, priority, max_table_size, num_groups, 8458c2ecf20Sopenharmony_ci flags); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return prio; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic void set_underlay_qp(struct mlx5_ib_dev *dev, 8518c2ecf20Sopenharmony_ci struct mlx5_flow_spec *spec, 8528c2ecf20Sopenharmony_ci u32 underlay_qpn) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci void *misc_params_c = MLX5_ADDR_OF(fte_match_param, 8558c2ecf20Sopenharmony_ci spec->match_criteria, 8568c2ecf20Sopenharmony_ci misc_parameters); 8578c2ecf20Sopenharmony_ci void *misc_params_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 8588c2ecf20Sopenharmony_ci misc_parameters); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (underlay_qpn && 8618c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, 8628c2ecf20Sopenharmony_ci ft_field_support.bth_dst_qp)) { 8638c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 8648c2ecf20Sopenharmony_ci misc_params_v, bth_dst_qp, underlay_qpn); 8658c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, 8668c2ecf20Sopenharmony_ci misc_params_c, bth_dst_qp, 0xffffff); 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic void mlx5_ib_set_rule_source_port(struct mlx5_ib_dev *dev, 8718c2ecf20Sopenharmony_ci struct mlx5_flow_spec *spec, 8728c2ecf20Sopenharmony_ci struct mlx5_eswitch_rep *rep) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct mlx5_eswitch *esw = dev->mdev->priv.eswitch; 8758c2ecf20Sopenharmony_ci void *misc; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (mlx5_eswitch_vport_match_metadata_enabled(esw)) { 8788c2ecf20Sopenharmony_ci misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, 8798c2ecf20Sopenharmony_ci misc_parameters_2); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, 8828c2ecf20Sopenharmony_ci mlx5_eswitch_get_vport_metadata_for_match(esw, 8838c2ecf20Sopenharmony_ci rep->vport)); 8848c2ecf20Sopenharmony_ci misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 8858c2ecf20Sopenharmony_ci misc_parameters_2); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, 8888c2ecf20Sopenharmony_ci mlx5_eswitch_get_vport_metadata_mask()); 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, 8918c2ecf20Sopenharmony_ci misc_parameters); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci MLX5_SET(fte_match_set_misc, misc, source_port, rep->vport); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 8968c2ecf20Sopenharmony_ci misc_parameters); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, 9038c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio, 9048c2ecf20Sopenharmony_ci const struct ib_flow_attr *flow_attr, 9058c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst, 9068c2ecf20Sopenharmony_ci u32 underlay_qpn, 9078c2ecf20Sopenharmony_ci struct mlx5_ib_create_flow *ucmd) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct mlx5_flow_table *ft = ft_prio->flow_table; 9108c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler; 9118c2ecf20Sopenharmony_ci struct mlx5_flow_act flow_act = {}; 9128c2ecf20Sopenharmony_ci struct mlx5_flow_spec *spec; 9138c2ecf20Sopenharmony_ci struct mlx5_flow_destination dest_arr[2] = {}; 9148c2ecf20Sopenharmony_ci struct mlx5_flow_destination *rule_dst = dest_arr; 9158c2ecf20Sopenharmony_ci const void *ib_flow = (const void *)flow_attr + sizeof(*flow_attr); 9168c2ecf20Sopenharmony_ci unsigned int spec_index; 9178c2ecf20Sopenharmony_ci u32 prev_type = 0; 9188c2ecf20Sopenharmony_ci int err = 0; 9198c2ecf20Sopenharmony_ci int dest_num = 0; 9208c2ecf20Sopenharmony_ci bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (!is_valid_attr(dev->mdev, flow_attr)) 9238c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (dev->is_rep && is_egress) 9268c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 9298c2ecf20Sopenharmony_ci handler = kzalloc(sizeof(*handler), GFP_KERNEL); 9308c2ecf20Sopenharmony_ci if (!handler || !spec) { 9318c2ecf20Sopenharmony_ci err = -ENOMEM; 9328c2ecf20Sopenharmony_ci goto free; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&handler->list); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) { 9388c2ecf20Sopenharmony_ci err = parse_flow_attr(dev->mdev, spec, 9398c2ecf20Sopenharmony_ci ib_flow, flow_attr, &flow_act, 9408c2ecf20Sopenharmony_ci prev_type); 9418c2ecf20Sopenharmony_ci if (err < 0) 9428c2ecf20Sopenharmony_ci goto free; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci prev_type = ((union ib_flow_spec *)ib_flow)->type; 9458c2ecf20Sopenharmony_ci ib_flow += ((union ib_flow_spec *)ib_flow)->size; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (dst && !(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP)) { 9498c2ecf20Sopenharmony_ci memcpy(&dest_arr[0], dst, sizeof(*dst)); 9508c2ecf20Sopenharmony_ci dest_num++; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (!flow_is_multicast_only(flow_attr)) 9548c2ecf20Sopenharmony_ci set_underlay_qp(dev, spec, underlay_qpn); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (dev->is_rep && flow_attr->type != IB_FLOW_ATTR_SNIFFER) { 9578c2ecf20Sopenharmony_ci struct mlx5_eswitch_rep *rep; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci rep = dev->port[flow_attr->port - 1].rep; 9608c2ecf20Sopenharmony_ci if (!rep) { 9618c2ecf20Sopenharmony_ci err = -EINVAL; 9628c2ecf20Sopenharmony_ci goto free; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci mlx5_ib_set_rule_source_port(dev, spec, rep); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (is_egress && 9718c2ecf20Sopenharmony_ci !is_valid_spec(dev->mdev, spec, &flow_act, is_egress)) { 9728c2ecf20Sopenharmony_ci err = -EINVAL; 9738c2ecf20Sopenharmony_ci goto free; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 9778c2ecf20Sopenharmony_ci struct mlx5_ib_mcounters *mcounters; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci err = mlx5_ib_flow_counters_set_data(flow_act.counters, ucmd); 9808c2ecf20Sopenharmony_ci if (err) 9818c2ecf20Sopenharmony_ci goto free; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci mcounters = to_mcounters(flow_act.counters); 9848c2ecf20Sopenharmony_ci handler->ibcounters = flow_act.counters; 9858c2ecf20Sopenharmony_ci dest_arr[dest_num].type = 9868c2ecf20Sopenharmony_ci MLX5_FLOW_DESTINATION_TYPE_COUNTER; 9878c2ecf20Sopenharmony_ci dest_arr[dest_num].counter_id = 9888c2ecf20Sopenharmony_ci mlx5_fc_id(mcounters->hw_cntrs_hndl); 9898c2ecf20Sopenharmony_ci dest_num++; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { 9938c2ecf20Sopenharmony_ci if (!dest_num) 9948c2ecf20Sopenharmony_ci rule_dst = NULL; 9958c2ecf20Sopenharmony_ci } else { 9968c2ecf20Sopenharmony_ci if (flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) 9978c2ecf20Sopenharmony_ci flow_act.action |= 9988c2ecf20Sopenharmony_ci MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; 9998c2ecf20Sopenharmony_ci if (is_egress) 10008c2ecf20Sopenharmony_ci flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW; 10018c2ecf20Sopenharmony_ci else if (dest_num) 10028c2ecf20Sopenharmony_ci flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if ((spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG) && 10068c2ecf20Sopenharmony_ci (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT || 10078c2ecf20Sopenharmony_ci flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) { 10088c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "Flow tag %u and attribute type %x isn't allowed in leftovers\n", 10098c2ecf20Sopenharmony_ci spec->flow_context.flow_tag, flow_attr->type); 10108c2ecf20Sopenharmony_ci err = -EINVAL; 10118c2ecf20Sopenharmony_ci goto free; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci handler->rule = mlx5_add_flow_rules(ft, spec, 10148c2ecf20Sopenharmony_ci &flow_act, 10158c2ecf20Sopenharmony_ci rule_dst, dest_num); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (IS_ERR(handler->rule)) { 10188c2ecf20Sopenharmony_ci err = PTR_ERR(handler->rule); 10198c2ecf20Sopenharmony_ci goto free; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci ft_prio->refcount++; 10238c2ecf20Sopenharmony_ci handler->prio = ft_prio; 10248c2ecf20Sopenharmony_ci handler->dev = dev; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci ft_prio->flow_table = ft; 10278c2ecf20Sopenharmony_cifree: 10288c2ecf20Sopenharmony_ci if (err && handler) { 10298c2ecf20Sopenharmony_ci mlx5_ib_counters_clear_description(handler->ibcounters); 10308c2ecf20Sopenharmony_ci kfree(handler); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci kvfree(spec); 10338c2ecf20Sopenharmony_ci return err ? ERR_PTR(err) : handler; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, 10378c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio, 10388c2ecf20Sopenharmony_ci const struct ib_flow_attr *flow_attr, 10398c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci return _create_flow_rule(dev, ft_prio, flow_attr, dst, 0, NULL); 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cienum { 10458c2ecf20Sopenharmony_ci LEFTOVERS_MC, 10468c2ecf20Sopenharmony_ci LEFTOVERS_UC, 10478c2ecf20Sopenharmony_ci}; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler *create_leftovers_rule(struct mlx5_ib_dev *dev, 10508c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio, 10518c2ecf20Sopenharmony_ci struct ib_flow_attr *flow_attr, 10528c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler_ucast = NULL; 10558c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler = NULL; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci static struct { 10588c2ecf20Sopenharmony_ci struct ib_flow_attr flow_attr; 10598c2ecf20Sopenharmony_ci struct ib_flow_spec_eth eth_flow; 10608c2ecf20Sopenharmony_ci } leftovers_specs[] = { 10618c2ecf20Sopenharmony_ci [LEFTOVERS_MC] = { 10628c2ecf20Sopenharmony_ci .flow_attr = { 10638c2ecf20Sopenharmony_ci .num_of_specs = 1, 10648c2ecf20Sopenharmony_ci .size = sizeof(leftovers_specs[0]) 10658c2ecf20Sopenharmony_ci }, 10668c2ecf20Sopenharmony_ci .eth_flow = { 10678c2ecf20Sopenharmony_ci .type = IB_FLOW_SPEC_ETH, 10688c2ecf20Sopenharmony_ci .size = sizeof(struct ib_flow_spec_eth), 10698c2ecf20Sopenharmony_ci .mask = {.dst_mac = {0x1} }, 10708c2ecf20Sopenharmony_ci .val = {.dst_mac = {0x1} } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci }, 10738c2ecf20Sopenharmony_ci [LEFTOVERS_UC] = { 10748c2ecf20Sopenharmony_ci .flow_attr = { 10758c2ecf20Sopenharmony_ci .num_of_specs = 1, 10768c2ecf20Sopenharmony_ci .size = sizeof(leftovers_specs[0]) 10778c2ecf20Sopenharmony_ci }, 10788c2ecf20Sopenharmony_ci .eth_flow = { 10798c2ecf20Sopenharmony_ci .type = IB_FLOW_SPEC_ETH, 10808c2ecf20Sopenharmony_ci .size = sizeof(struct ib_flow_spec_eth), 10818c2ecf20Sopenharmony_ci .mask = {.dst_mac = {0x1} }, 10828c2ecf20Sopenharmony_ci .val = {.dst_mac = {} } 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci }; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci handler = create_flow_rule(dev, ft_prio, 10888c2ecf20Sopenharmony_ci &leftovers_specs[LEFTOVERS_MC].flow_attr, 10898c2ecf20Sopenharmony_ci dst); 10908c2ecf20Sopenharmony_ci if (!IS_ERR(handler) && 10918c2ecf20Sopenharmony_ci flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT) { 10928c2ecf20Sopenharmony_ci handler_ucast = create_flow_rule(dev, ft_prio, 10938c2ecf20Sopenharmony_ci &leftovers_specs[LEFTOVERS_UC].flow_attr, 10948c2ecf20Sopenharmony_ci dst); 10958c2ecf20Sopenharmony_ci if (IS_ERR(handler_ucast)) { 10968c2ecf20Sopenharmony_ci mlx5_del_flow_rules(handler->rule); 10978c2ecf20Sopenharmony_ci ft_prio->refcount--; 10988c2ecf20Sopenharmony_ci kfree(handler); 10998c2ecf20Sopenharmony_ci handler = handler_ucast; 11008c2ecf20Sopenharmony_ci } else { 11018c2ecf20Sopenharmony_ci list_add(&handler_ucast->list, &handler->list); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return handler; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler *create_sniffer_rule(struct mlx5_ib_dev *dev, 11098c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_rx, 11108c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_tx, 11118c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler_rx; 11148c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler_tx; 11158c2ecf20Sopenharmony_ci int err; 11168c2ecf20Sopenharmony_ci static const struct ib_flow_attr flow_attr = { 11178c2ecf20Sopenharmony_ci .num_of_specs = 0, 11188c2ecf20Sopenharmony_ci .type = IB_FLOW_ATTR_SNIFFER, 11198c2ecf20Sopenharmony_ci .size = sizeof(flow_attr) 11208c2ecf20Sopenharmony_ci }; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci handler_rx = create_flow_rule(dev, ft_rx, &flow_attr, dst); 11238c2ecf20Sopenharmony_ci if (IS_ERR(handler_rx)) { 11248c2ecf20Sopenharmony_ci err = PTR_ERR(handler_rx); 11258c2ecf20Sopenharmony_ci goto err; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci handler_tx = create_flow_rule(dev, ft_tx, &flow_attr, dst); 11298c2ecf20Sopenharmony_ci if (IS_ERR(handler_tx)) { 11308c2ecf20Sopenharmony_ci err = PTR_ERR(handler_tx); 11318c2ecf20Sopenharmony_ci goto err_tx; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci list_add(&handler_tx->list, &handler_rx->list); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return handler_rx; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cierr_tx: 11398c2ecf20Sopenharmony_ci mlx5_del_flow_rules(handler_rx->rule); 11408c2ecf20Sopenharmony_ci ft_rx->refcount--; 11418c2ecf20Sopenharmony_ci kfree(handler_rx); 11428c2ecf20Sopenharmony_cierr: 11438c2ecf20Sopenharmony_ci return ERR_PTR(err); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp, 11478c2ecf20Sopenharmony_ci struct ib_flow_attr *flow_attr, 11488c2ecf20Sopenharmony_ci struct ib_udata *udata) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 11518c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 11528c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler = NULL; 11538c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst = NULL; 11548c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio_tx = NULL; 11558c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio; 11568c2ecf20Sopenharmony_ci bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS; 11578c2ecf20Sopenharmony_ci struct mlx5_ib_create_flow *ucmd = NULL, ucmd_hdr; 11588c2ecf20Sopenharmony_ci size_t min_ucmd_sz, required_ucmd_sz; 11598c2ecf20Sopenharmony_ci int err; 11608c2ecf20Sopenharmony_ci int underlay_qpn; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (udata && udata->inlen) { 11638c2ecf20Sopenharmony_ci min_ucmd_sz = offsetofend(struct mlx5_ib_create_flow, reserved); 11648c2ecf20Sopenharmony_ci if (udata->inlen < min_ucmd_sz) 11658c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci err = ib_copy_from_udata(&ucmd_hdr, udata, min_ucmd_sz); 11688c2ecf20Sopenharmony_ci if (err) 11698c2ecf20Sopenharmony_ci return ERR_PTR(err); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci /* currently supports only one counters data */ 11728c2ecf20Sopenharmony_ci if (ucmd_hdr.ncounters_data > 1) 11738c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci required_ucmd_sz = min_ucmd_sz + 11768c2ecf20Sopenharmony_ci sizeof(struct mlx5_ib_flow_counters_data) * 11778c2ecf20Sopenharmony_ci ucmd_hdr.ncounters_data; 11788c2ecf20Sopenharmony_ci if (udata->inlen > required_ucmd_sz && 11798c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, required_ucmd_sz, 11808c2ecf20Sopenharmony_ci udata->inlen - required_ucmd_sz)) 11818c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci ucmd = kzalloc(required_ucmd_sz, GFP_KERNEL); 11848c2ecf20Sopenharmony_ci if (!ucmd) 11858c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci err = ib_copy_from_udata(ucmd, udata, required_ucmd_sz); 11888c2ecf20Sopenharmony_ci if (err) 11898c2ecf20Sopenharmony_ci goto free_ucmd; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (flow_attr->priority > MLX5_IB_FLOW_LAST_PRIO) { 11938c2ecf20Sopenharmony_ci err = -ENOMEM; 11948c2ecf20Sopenharmony_ci goto free_ucmd; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (flow_attr->port > dev->num_ports || 11988c2ecf20Sopenharmony_ci (flow_attr->flags & 11998c2ecf20Sopenharmony_ci ~(IB_FLOW_ATTR_FLAGS_DONT_TRAP | IB_FLOW_ATTR_FLAGS_EGRESS))) { 12008c2ecf20Sopenharmony_ci err = -EINVAL; 12018c2ecf20Sopenharmony_ci goto free_ucmd; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (is_egress && 12058c2ecf20Sopenharmony_ci (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT || 12068c2ecf20Sopenharmony_ci flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) { 12078c2ecf20Sopenharmony_ci err = -EINVAL; 12088c2ecf20Sopenharmony_ci goto free_ucmd; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci dst = kzalloc(sizeof(*dst), GFP_KERNEL); 12128c2ecf20Sopenharmony_ci if (!dst) { 12138c2ecf20Sopenharmony_ci err = -ENOMEM; 12148c2ecf20Sopenharmony_ci goto free_ucmd; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci mutex_lock(&dev->flow_db->lock); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci ft_prio = get_flow_table(dev, flow_attr, 12208c2ecf20Sopenharmony_ci is_egress ? MLX5_IB_FT_TX : MLX5_IB_FT_RX); 12218c2ecf20Sopenharmony_ci if (IS_ERR(ft_prio)) { 12228c2ecf20Sopenharmony_ci err = PTR_ERR(ft_prio); 12238c2ecf20Sopenharmony_ci goto unlock; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci if (flow_attr->type == IB_FLOW_ATTR_SNIFFER) { 12268c2ecf20Sopenharmony_ci ft_prio_tx = get_flow_table(dev, flow_attr, MLX5_IB_FT_TX); 12278c2ecf20Sopenharmony_ci if (IS_ERR(ft_prio_tx)) { 12288c2ecf20Sopenharmony_ci err = PTR_ERR(ft_prio_tx); 12298c2ecf20Sopenharmony_ci ft_prio_tx = NULL; 12308c2ecf20Sopenharmony_ci goto destroy_ft; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci if (is_egress) { 12358c2ecf20Sopenharmony_ci dst->type = MLX5_FLOW_DESTINATION_TYPE_PORT; 12368c2ecf20Sopenharmony_ci } else { 12378c2ecf20Sopenharmony_ci dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR; 12388c2ecf20Sopenharmony_ci if (mqp->is_rss) 12398c2ecf20Sopenharmony_ci dst->tir_num = mqp->rss_qp.tirn; 12408c2ecf20Sopenharmony_ci else 12418c2ecf20Sopenharmony_ci dst->tir_num = mqp->raw_packet_qp.rq.tirn; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci switch (flow_attr->type) { 12458c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_NORMAL: 12468c2ecf20Sopenharmony_ci underlay_qpn = (mqp->flags & IB_QP_CREATE_SOURCE_QPN) ? 12478c2ecf20Sopenharmony_ci mqp->underlay_qpn : 12488c2ecf20Sopenharmony_ci 0; 12498c2ecf20Sopenharmony_ci handler = _create_flow_rule(dev, ft_prio, flow_attr, dst, 12508c2ecf20Sopenharmony_ci underlay_qpn, ucmd); 12518c2ecf20Sopenharmony_ci break; 12528c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_ALL_DEFAULT: 12538c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_MC_DEFAULT: 12548c2ecf20Sopenharmony_ci handler = create_leftovers_rule(dev, ft_prio, flow_attr, dst); 12558c2ecf20Sopenharmony_ci break; 12568c2ecf20Sopenharmony_ci case IB_FLOW_ATTR_SNIFFER: 12578c2ecf20Sopenharmony_ci handler = create_sniffer_rule(dev, ft_prio, ft_prio_tx, dst); 12588c2ecf20Sopenharmony_ci break; 12598c2ecf20Sopenharmony_ci default: 12608c2ecf20Sopenharmony_ci err = -EINVAL; 12618c2ecf20Sopenharmony_ci goto destroy_ft; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (IS_ERR(handler)) { 12658c2ecf20Sopenharmony_ci err = PTR_ERR(handler); 12668c2ecf20Sopenharmony_ci handler = NULL; 12678c2ecf20Sopenharmony_ci goto destroy_ft; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci mutex_unlock(&dev->flow_db->lock); 12718c2ecf20Sopenharmony_ci kfree(dst); 12728c2ecf20Sopenharmony_ci kfree(ucmd); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci return &handler->ibflow; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cidestroy_ft: 12778c2ecf20Sopenharmony_ci put_flow_table(dev, ft_prio, false); 12788c2ecf20Sopenharmony_ci if (ft_prio_tx) 12798c2ecf20Sopenharmony_ci put_flow_table(dev, ft_prio_tx, false); 12808c2ecf20Sopenharmony_ciunlock: 12818c2ecf20Sopenharmony_ci mutex_unlock(&dev->flow_db->lock); 12828c2ecf20Sopenharmony_ci kfree(dst); 12838c2ecf20Sopenharmony_cifree_ucmd: 12848c2ecf20Sopenharmony_ci kfree(ucmd); 12858c2ecf20Sopenharmony_ci return ERR_PTR(err); 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_prio * 12898c2ecf20Sopenharmony_ci_get_flow_table(struct mlx5_ib_dev *dev, 12908c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *fs_matcher, 12918c2ecf20Sopenharmony_ci bool mcast) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct mlx5_flow_namespace *ns = NULL; 12948c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *prio = NULL; 12958c2ecf20Sopenharmony_ci int max_table_size = 0; 12968c2ecf20Sopenharmony_ci bool esw_encap; 12978c2ecf20Sopenharmony_ci u32 flags = 0; 12988c2ecf20Sopenharmony_ci int priority; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (mcast) 13018c2ecf20Sopenharmony_ci priority = MLX5_IB_FLOW_MCAST_PRIO; 13028c2ecf20Sopenharmony_ci else 13038c2ecf20Sopenharmony_ci priority = ib_prio_to_core_prio(fs_matcher->priority, false); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) != 13068c2ecf20Sopenharmony_ci DEVLINK_ESWITCH_ENCAP_MODE_NONE; 13078c2ecf20Sopenharmony_ci switch (fs_matcher->ns_type) { 13088c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_BYPASS: 13098c2ecf20Sopenharmony_ci max_table_size = BIT( 13108c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, log_max_ft_size)); 13118c2ecf20Sopenharmony_ci if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap) && !esw_encap) 13128c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; 13138c2ecf20Sopenharmony_ci if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, 13148c2ecf20Sopenharmony_ci reformat_l3_tunnel_to_l2) && 13158c2ecf20Sopenharmony_ci !esw_encap) 13168c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 13178c2ecf20Sopenharmony_ci break; 13188c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_EGRESS: 13198c2ecf20Sopenharmony_ci max_table_size = BIT( 13208c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, log_max_ft_size)); 13218c2ecf20Sopenharmony_ci if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat) && 13228c2ecf20Sopenharmony_ci !esw_encap) 13238c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 13248c2ecf20Sopenharmony_ci break; 13258c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_FDB: 13268c2ecf20Sopenharmony_ci max_table_size = BIT( 13278c2ecf20Sopenharmony_ci MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, log_max_ft_size)); 13288c2ecf20Sopenharmony_ci if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, decap) && esw_encap) 13298c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; 13308c2ecf20Sopenharmony_ci if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, 13318c2ecf20Sopenharmony_ci reformat_l3_tunnel_to_l2) && 13328c2ecf20Sopenharmony_ci esw_encap) 13338c2ecf20Sopenharmony_ci flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 13348c2ecf20Sopenharmony_ci priority = FDB_BYPASS_PATH; 13358c2ecf20Sopenharmony_ci break; 13368c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_RDMA_RX: 13378c2ecf20Sopenharmony_ci max_table_size = BIT( 13388c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_RDMA_RX(dev->mdev, log_max_ft_size)); 13398c2ecf20Sopenharmony_ci priority = fs_matcher->priority; 13408c2ecf20Sopenharmony_ci break; 13418c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_RDMA_TX: 13428c2ecf20Sopenharmony_ci max_table_size = BIT( 13438c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_RDMA_TX(dev->mdev, log_max_ft_size)); 13448c2ecf20Sopenharmony_ci priority = fs_matcher->priority; 13458c2ecf20Sopenharmony_ci break; 13468c2ecf20Sopenharmony_ci default: 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci max_table_size = min_t(int, max_table_size, MLX5_FS_MAX_ENTRIES); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci ns = mlx5_get_flow_namespace(dev->mdev, fs_matcher->ns_type); 13538c2ecf20Sopenharmony_ci if (!ns) 13548c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci switch (fs_matcher->ns_type) { 13578c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_BYPASS: 13588c2ecf20Sopenharmony_ci prio = &dev->flow_db->prios[priority]; 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_EGRESS: 13618c2ecf20Sopenharmony_ci prio = &dev->flow_db->egress_prios[priority]; 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_FDB: 13648c2ecf20Sopenharmony_ci prio = &dev->flow_db->fdb; 13658c2ecf20Sopenharmony_ci break; 13668c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_RDMA_RX: 13678c2ecf20Sopenharmony_ci prio = &dev->flow_db->rdma_rx[priority]; 13688c2ecf20Sopenharmony_ci break; 13698c2ecf20Sopenharmony_ci case MLX5_FLOW_NAMESPACE_RDMA_TX: 13708c2ecf20Sopenharmony_ci prio = &dev->flow_db->rdma_tx[priority]; 13718c2ecf20Sopenharmony_ci break; 13728c2ecf20Sopenharmony_ci default: return ERR_PTR(-EINVAL); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (!prio) 13768c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (prio->flow_table) 13798c2ecf20Sopenharmony_ci return prio; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return _get_prio(ns, prio, priority, max_table_size, 13828c2ecf20Sopenharmony_ci MLX5_FS_MAX_TYPES, flags); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler * 13868c2ecf20Sopenharmony_ci_create_raw_flow_rule(struct mlx5_ib_dev *dev, 13878c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio, 13888c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst, 13898c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *fs_matcher, 13908c2ecf20Sopenharmony_ci struct mlx5_flow_context *flow_context, 13918c2ecf20Sopenharmony_ci struct mlx5_flow_act *flow_act, 13928c2ecf20Sopenharmony_ci void *cmd_in, int inlen, 13938c2ecf20Sopenharmony_ci int dst_num) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler; 13968c2ecf20Sopenharmony_ci struct mlx5_flow_spec *spec; 13978c2ecf20Sopenharmony_ci struct mlx5_flow_table *ft = ft_prio->flow_table; 13988c2ecf20Sopenharmony_ci int err = 0; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 14018c2ecf20Sopenharmony_ci handler = kzalloc(sizeof(*handler), GFP_KERNEL); 14028c2ecf20Sopenharmony_ci if (!handler || !spec) { 14038c2ecf20Sopenharmony_ci err = -ENOMEM; 14048c2ecf20Sopenharmony_ci goto free; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&handler->list); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci memcpy(spec->match_value, cmd_in, inlen); 14108c2ecf20Sopenharmony_ci memcpy(spec->match_criteria, fs_matcher->matcher_mask.match_params, 14118c2ecf20Sopenharmony_ci fs_matcher->mask_len); 14128c2ecf20Sopenharmony_ci spec->match_criteria_enable = fs_matcher->match_criteria_enable; 14138c2ecf20Sopenharmony_ci spec->flow_context = *flow_context; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci handler->rule = mlx5_add_flow_rules(ft, spec, 14168c2ecf20Sopenharmony_ci flow_act, dst, dst_num); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (IS_ERR(handler->rule)) { 14198c2ecf20Sopenharmony_ci err = PTR_ERR(handler->rule); 14208c2ecf20Sopenharmony_ci goto free; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci ft_prio->refcount++; 14248c2ecf20Sopenharmony_ci handler->prio = ft_prio; 14258c2ecf20Sopenharmony_ci handler->dev = dev; 14268c2ecf20Sopenharmony_ci ft_prio->flow_table = ft; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cifree: 14298c2ecf20Sopenharmony_ci if (err) 14308c2ecf20Sopenharmony_ci kfree(handler); 14318c2ecf20Sopenharmony_ci kvfree(spec); 14328c2ecf20Sopenharmony_ci return err ? ERR_PTR(err) : handler; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic bool raw_fs_is_multicast(struct mlx5_ib_flow_matcher *fs_matcher, 14368c2ecf20Sopenharmony_ci void *match_v) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci void *match_c; 14398c2ecf20Sopenharmony_ci void *match_v_set_lyr_2_4, *match_c_set_lyr_2_4; 14408c2ecf20Sopenharmony_ci void *dmac, *dmac_mask; 14418c2ecf20Sopenharmony_ci void *ipv4, *ipv4_mask; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (!(fs_matcher->match_criteria_enable & 14448c2ecf20Sopenharmony_ci (1 << MATCH_CRITERIA_ENABLE_OUTER_BIT))) 14458c2ecf20Sopenharmony_ci return false; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci match_c = fs_matcher->matcher_mask.match_params; 14488c2ecf20Sopenharmony_ci match_v_set_lyr_2_4 = MLX5_ADDR_OF(fte_match_param, match_v, 14498c2ecf20Sopenharmony_ci outer_headers); 14508c2ecf20Sopenharmony_ci match_c_set_lyr_2_4 = MLX5_ADDR_OF(fte_match_param, match_c, 14518c2ecf20Sopenharmony_ci outer_headers); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci dmac = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_v_set_lyr_2_4, 14548c2ecf20Sopenharmony_ci dmac_47_16); 14558c2ecf20Sopenharmony_ci dmac_mask = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_c_set_lyr_2_4, 14568c2ecf20Sopenharmony_ci dmac_47_16); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(dmac) && 14598c2ecf20Sopenharmony_ci is_multicast_ether_addr(dmac_mask)) 14608c2ecf20Sopenharmony_ci return true; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci ipv4 = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_v_set_lyr_2_4, 14638c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci ipv4_mask = MLX5_ADDR_OF(fte_match_set_lyr_2_4, match_c_set_lyr_2_4, 14668c2ecf20Sopenharmony_ci dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (ipv4_is_multicast(*(__be32 *)(ipv4)) && 14698c2ecf20Sopenharmony_ci ipv4_is_multicast(*(__be32 *)(ipv4_mask))) 14708c2ecf20Sopenharmony_ci return true; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci return false; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic struct mlx5_ib_flow_handler *raw_fs_rule_add( 14768c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher, 14778c2ecf20Sopenharmony_ci struct mlx5_flow_context *flow_context, struct mlx5_flow_act *flow_act, 14788c2ecf20Sopenharmony_ci u32 counter_id, void *cmd_in, int inlen, int dest_id, int dest_type) 14798c2ecf20Sopenharmony_ci{ 14808c2ecf20Sopenharmony_ci struct mlx5_flow_destination *dst; 14818c2ecf20Sopenharmony_ci struct mlx5_ib_flow_prio *ft_prio; 14828c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *handler; 14838c2ecf20Sopenharmony_ci int dst_num = 0; 14848c2ecf20Sopenharmony_ci bool mcast; 14858c2ecf20Sopenharmony_ci int err; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (fs_matcher->flow_type != MLX5_IB_FLOW_TYPE_NORMAL) 14888c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (fs_matcher->priority > MLX5_IB_FLOW_LAST_PRIO) 14918c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci dst = kcalloc(2, sizeof(*dst), GFP_KERNEL); 14948c2ecf20Sopenharmony_ci if (!dst) 14958c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci mcast = raw_fs_is_multicast(fs_matcher, cmd_in); 14988c2ecf20Sopenharmony_ci mutex_lock(&dev->flow_db->lock); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci ft_prio = _get_flow_table(dev, fs_matcher, mcast); 15018c2ecf20Sopenharmony_ci if (IS_ERR(ft_prio)) { 15028c2ecf20Sopenharmony_ci err = PTR_ERR(ft_prio); 15038c2ecf20Sopenharmony_ci goto unlock; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci switch (dest_type) { 15078c2ecf20Sopenharmony_ci case MLX5_FLOW_DESTINATION_TYPE_TIR: 15088c2ecf20Sopenharmony_ci dst[dst_num].type = dest_type; 15098c2ecf20Sopenharmony_ci dst[dst_num++].tir_num = dest_id; 15108c2ecf20Sopenharmony_ci flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: 15138c2ecf20Sopenharmony_ci dst[dst_num].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM; 15148c2ecf20Sopenharmony_ci dst[dst_num++].ft_num = dest_id; 15158c2ecf20Sopenharmony_ci flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 15168c2ecf20Sopenharmony_ci break; 15178c2ecf20Sopenharmony_ci case MLX5_FLOW_DESTINATION_TYPE_PORT: 15188c2ecf20Sopenharmony_ci dst[dst_num++].type = MLX5_FLOW_DESTINATION_TYPE_PORT; 15198c2ecf20Sopenharmony_ci flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW; 15208c2ecf20Sopenharmony_ci break; 15218c2ecf20Sopenharmony_ci default: 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 15268c2ecf20Sopenharmony_ci dst[dst_num].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 15278c2ecf20Sopenharmony_ci dst[dst_num].counter_id = counter_id; 15288c2ecf20Sopenharmony_ci dst_num++; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci handler = _create_raw_flow_rule(dev, ft_prio, dst_num ? dst : NULL, 15328c2ecf20Sopenharmony_ci fs_matcher, flow_context, flow_act, 15338c2ecf20Sopenharmony_ci cmd_in, inlen, dst_num); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (IS_ERR(handler)) { 15368c2ecf20Sopenharmony_ci err = PTR_ERR(handler); 15378c2ecf20Sopenharmony_ci goto destroy_ft; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci mutex_unlock(&dev->flow_db->lock); 15418c2ecf20Sopenharmony_ci atomic_inc(&fs_matcher->usecnt); 15428c2ecf20Sopenharmony_ci handler->flow_matcher = fs_matcher; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci kfree(dst); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci return handler; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cidestroy_ft: 15498c2ecf20Sopenharmony_ci put_flow_table(dev, ft_prio, false); 15508c2ecf20Sopenharmony_ciunlock: 15518c2ecf20Sopenharmony_ci mutex_unlock(&dev->flow_db->lock); 15528c2ecf20Sopenharmony_ci kfree(dst); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return ERR_PTR(err); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic u32 mlx5_ib_flow_action_flags_to_accel_xfrm_flags(u32 mlx5_flags) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci u32 flags = 0; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (mlx5_flags & MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA) 15628c2ecf20Sopenharmony_ci flags |= MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci return flags; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci#define MLX5_FLOW_ACTION_ESP_CREATE_LAST_SUPPORTED \ 15688c2ecf20Sopenharmony_ci MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA 15698c2ecf20Sopenharmony_cistatic struct ib_flow_action * 15708c2ecf20Sopenharmony_cimlx5_ib_create_flow_action_esp(struct ib_device *device, 15718c2ecf20Sopenharmony_ci const struct ib_flow_action_attrs_esp *attr, 15728c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci struct mlx5_ib_dev *mdev = to_mdev(device); 15758c2ecf20Sopenharmony_ci struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm; 15768c2ecf20Sopenharmony_ci struct mlx5_accel_esp_xfrm_attrs accel_attrs = {}; 15778c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *action; 15788c2ecf20Sopenharmony_ci u64 action_flags; 15798c2ecf20Sopenharmony_ci u64 flags; 15808c2ecf20Sopenharmony_ci int err = 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci err = uverbs_get_flags64( 15838c2ecf20Sopenharmony_ci &action_flags, attrs, MLX5_IB_ATTR_CREATE_FLOW_ACTION_FLAGS, 15848c2ecf20Sopenharmony_ci ((MLX5_FLOW_ACTION_ESP_CREATE_LAST_SUPPORTED << 1) - 1)); 15858c2ecf20Sopenharmony_ci if (err) 15868c2ecf20Sopenharmony_ci return ERR_PTR(err); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci flags = mlx5_ib_flow_action_flags_to_accel_xfrm_flags(action_flags); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* We current only support a subset of the standard features. Only a 15918c2ecf20Sopenharmony_ci * keymat of type AES_GCM, with icv_len == 16, iv_algo == SEQ and esn 15928c2ecf20Sopenharmony_ci * (with overlap). Full offload mode isn't supported. 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_ci if (!attr->keymat || attr->replay || attr->encap || 15958c2ecf20Sopenharmony_ci attr->spi || attr->seq || attr->tfc_pad || 15968c2ecf20Sopenharmony_ci attr->hard_limit_pkts || 15978c2ecf20Sopenharmony_ci (attr->flags & ~(IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED | 15988c2ecf20Sopenharmony_ci IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ENCRYPT))) 15998c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (attr->keymat->protocol != 16028c2ecf20Sopenharmony_ci IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM) 16038c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci aes_gcm = &attr->keymat->keymat.aes_gcm; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (aes_gcm->icv_len != 16 || 16088c2ecf20Sopenharmony_ci aes_gcm->iv_algo != IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ) 16098c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci action = kmalloc(sizeof(*action), GFP_KERNEL); 16128c2ecf20Sopenharmony_ci if (!action) 16138c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci action->esp_aes_gcm.ib_flags = attr->flags; 16168c2ecf20Sopenharmony_ci memcpy(&accel_attrs.keymat.aes_gcm.aes_key, &aes_gcm->aes_key, 16178c2ecf20Sopenharmony_ci sizeof(accel_attrs.keymat.aes_gcm.aes_key)); 16188c2ecf20Sopenharmony_ci accel_attrs.keymat.aes_gcm.key_len = aes_gcm->key_len * 8; 16198c2ecf20Sopenharmony_ci memcpy(&accel_attrs.keymat.aes_gcm.salt, &aes_gcm->salt, 16208c2ecf20Sopenharmony_ci sizeof(accel_attrs.keymat.aes_gcm.salt)); 16218c2ecf20Sopenharmony_ci memcpy(&accel_attrs.keymat.aes_gcm.seq_iv, &aes_gcm->iv, 16228c2ecf20Sopenharmony_ci sizeof(accel_attrs.keymat.aes_gcm.seq_iv)); 16238c2ecf20Sopenharmony_ci accel_attrs.keymat.aes_gcm.icv_len = aes_gcm->icv_len * 8; 16248c2ecf20Sopenharmony_ci accel_attrs.keymat.aes_gcm.iv_algo = MLX5_ACCEL_ESP_AES_GCM_IV_ALGO_SEQ; 16258c2ecf20Sopenharmony_ci accel_attrs.keymat_type = MLX5_ACCEL_ESP_KEYMAT_AES_GCM; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci accel_attrs.esn = attr->esn; 16288c2ecf20Sopenharmony_ci if (attr->flags & IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED) 16298c2ecf20Sopenharmony_ci accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED; 16308c2ecf20Sopenharmony_ci if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW) 16318c2ecf20Sopenharmony_ci accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ENCRYPT) 16348c2ecf20Sopenharmony_ci accel_attrs.action |= MLX5_ACCEL_ESP_ACTION_ENCRYPT; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci action->esp_aes_gcm.ctx = 16378c2ecf20Sopenharmony_ci mlx5_accel_esp_create_xfrm(mdev->mdev, &accel_attrs, flags); 16388c2ecf20Sopenharmony_ci if (IS_ERR(action->esp_aes_gcm.ctx)) { 16398c2ecf20Sopenharmony_ci err = PTR_ERR(action->esp_aes_gcm.ctx); 16408c2ecf20Sopenharmony_ci goto err_parse; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci action->esp_aes_gcm.ib_flags = attr->flags; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return &action->ib_action; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_cierr_parse: 16488c2ecf20Sopenharmony_ci kfree(action); 16498c2ecf20Sopenharmony_ci return ERR_PTR(err); 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic int 16538c2ecf20Sopenharmony_cimlx5_ib_modify_flow_action_esp(struct ib_flow_action *action, 16548c2ecf20Sopenharmony_ci const struct ib_flow_action_attrs_esp *attr, 16558c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction = to_mflow_act(action); 16588c2ecf20Sopenharmony_ci struct mlx5_accel_esp_xfrm_attrs accel_attrs; 16598c2ecf20Sopenharmony_ci int err = 0; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (attr->keymat || attr->replay || attr->encap || 16628c2ecf20Sopenharmony_ci attr->spi || attr->seq || attr->tfc_pad || 16638c2ecf20Sopenharmony_ci attr->hard_limit_pkts || 16648c2ecf20Sopenharmony_ci (attr->flags & ~(IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED | 16658c2ecf20Sopenharmony_ci IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS | 16668c2ecf20Sopenharmony_ci IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW))) 16678c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci /* Only the ESN value or the MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP can 16708c2ecf20Sopenharmony_ci * be modified. 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_ci if (!(maction->esp_aes_gcm.ib_flags & 16738c2ecf20Sopenharmony_ci IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED) && 16748c2ecf20Sopenharmony_ci attr->flags & (IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED | 16758c2ecf20Sopenharmony_ci IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW)) 16768c2ecf20Sopenharmony_ci return -EINVAL; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci memcpy(&accel_attrs, &maction->esp_aes_gcm.ctx->attrs, 16798c2ecf20Sopenharmony_ci sizeof(accel_attrs)); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci accel_attrs.esn = attr->esn; 16828c2ecf20Sopenharmony_ci if (attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW) 16838c2ecf20Sopenharmony_ci accel_attrs.flags |= MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP; 16848c2ecf20Sopenharmony_ci else 16858c2ecf20Sopenharmony_ci accel_attrs.flags &= ~MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci err = mlx5_accel_esp_modify_xfrm(maction->esp_aes_gcm.ctx, 16888c2ecf20Sopenharmony_ci &accel_attrs); 16898c2ecf20Sopenharmony_ci if (err) 16908c2ecf20Sopenharmony_ci return err; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci maction->esp_aes_gcm.ib_flags &= 16938c2ecf20Sopenharmony_ci ~IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW; 16948c2ecf20Sopenharmony_ci maction->esp_aes_gcm.ib_flags |= 16958c2ecf20Sopenharmony_ci attr->flags & IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci return 0; 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cistatic void destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci switch (maction->flow_action_raw.sub_type) { 17038c2ecf20Sopenharmony_ci case MLX5_IB_FLOW_ACTION_MODIFY_HEADER: 17048c2ecf20Sopenharmony_ci mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev, 17058c2ecf20Sopenharmony_ci maction->flow_action_raw.modify_hdr); 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT: 17088c2ecf20Sopenharmony_ci mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev, 17098c2ecf20Sopenharmony_ci maction->flow_action_raw.pkt_reformat); 17108c2ecf20Sopenharmony_ci break; 17118c2ecf20Sopenharmony_ci case MLX5_IB_FLOW_ACTION_DECAP: 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci default: 17148c2ecf20Sopenharmony_ci break; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic int mlx5_ib_destroy_flow_action(struct ib_flow_action *action) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction = to_mflow_act(action); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci switch (action->type) { 17238c2ecf20Sopenharmony_ci case IB_FLOW_ACTION_ESP: 17248c2ecf20Sopenharmony_ci /* 17258c2ecf20Sopenharmony_ci * We only support aes_gcm by now, so we implicitly know this is 17268c2ecf20Sopenharmony_ci * the underline crypto. 17278c2ecf20Sopenharmony_ci */ 17288c2ecf20Sopenharmony_ci mlx5_accel_esp_destroy_xfrm(maction->esp_aes_gcm.ctx); 17298c2ecf20Sopenharmony_ci break; 17308c2ecf20Sopenharmony_ci case IB_FLOW_ACTION_UNSPECIFIED: 17318c2ecf20Sopenharmony_ci destroy_flow_action_raw(maction); 17328c2ecf20Sopenharmony_ci break; 17338c2ecf20Sopenharmony_ci default: 17348c2ecf20Sopenharmony_ci WARN_ON(true); 17358c2ecf20Sopenharmony_ci break; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci kfree(maction); 17398c2ecf20Sopenharmony_ci return 0; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic int 17438c2ecf20Sopenharmony_cimlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type, 17448c2ecf20Sopenharmony_ci enum mlx5_flow_namespace_type *namespace) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci switch (table_type) { 17478c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX: 17488c2ecf20Sopenharmony_ci *namespace = MLX5_FLOW_NAMESPACE_BYPASS; 17498c2ecf20Sopenharmony_ci break; 17508c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX: 17518c2ecf20Sopenharmony_ci *namespace = MLX5_FLOW_NAMESPACE_EGRESS; 17528c2ecf20Sopenharmony_ci break; 17538c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_TABLE_TYPE_FDB: 17548c2ecf20Sopenharmony_ci *namespace = MLX5_FLOW_NAMESPACE_FDB; 17558c2ecf20Sopenharmony_ci break; 17568c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_TABLE_TYPE_RDMA_RX: 17578c2ecf20Sopenharmony_ci *namespace = MLX5_FLOW_NAMESPACE_RDMA_RX; 17588c2ecf20Sopenharmony_ci break; 17598c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_TABLE_TYPE_RDMA_TX: 17608c2ecf20Sopenharmony_ci *namespace = MLX5_FLOW_NAMESPACE_RDMA_TX; 17618c2ecf20Sopenharmony_ci break; 17628c2ecf20Sopenharmony_ci default: 17638c2ecf20Sopenharmony_ci return -EINVAL; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return 0; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic const struct uverbs_attr_spec mlx5_ib_flow_type[] = { 17708c2ecf20Sopenharmony_ci [MLX5_IB_FLOW_TYPE_NORMAL] = { 17718c2ecf20Sopenharmony_ci .type = UVERBS_ATTR_TYPE_PTR_IN, 17728c2ecf20Sopenharmony_ci .u.ptr = { 17738c2ecf20Sopenharmony_ci .len = sizeof(u16), /* data is priority */ 17748c2ecf20Sopenharmony_ci .min_len = sizeof(u16), 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci }, 17778c2ecf20Sopenharmony_ci [MLX5_IB_FLOW_TYPE_SNIFFER] = { 17788c2ecf20Sopenharmony_ci .type = UVERBS_ATTR_TYPE_PTR_IN, 17798c2ecf20Sopenharmony_ci UVERBS_ATTR_NO_DATA(), 17808c2ecf20Sopenharmony_ci }, 17818c2ecf20Sopenharmony_ci [MLX5_IB_FLOW_TYPE_ALL_DEFAULT] = { 17828c2ecf20Sopenharmony_ci .type = UVERBS_ATTR_TYPE_PTR_IN, 17838c2ecf20Sopenharmony_ci UVERBS_ATTR_NO_DATA(), 17848c2ecf20Sopenharmony_ci }, 17858c2ecf20Sopenharmony_ci [MLX5_IB_FLOW_TYPE_MC_DEFAULT] = { 17868c2ecf20Sopenharmony_ci .type = UVERBS_ATTR_TYPE_PTR_IN, 17878c2ecf20Sopenharmony_ci UVERBS_ATTR_NO_DATA(), 17888c2ecf20Sopenharmony_ci }, 17898c2ecf20Sopenharmony_ci}; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_cistatic bool is_flow_dest(void *obj, int *dest_id, int *dest_type) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci struct devx_obj *devx_obj = obj; 17948c2ecf20Sopenharmony_ci u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, opcode); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci switch (opcode) { 17978c2ecf20Sopenharmony_ci case MLX5_CMD_OP_DESTROY_TIR: 17988c2ecf20Sopenharmony_ci *dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR; 17998c2ecf20Sopenharmony_ci *dest_id = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, 18008c2ecf20Sopenharmony_ci obj_id); 18018c2ecf20Sopenharmony_ci return true; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci case MLX5_CMD_OP_DESTROY_FLOW_TABLE: 18048c2ecf20Sopenharmony_ci *dest_type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 18058c2ecf20Sopenharmony_ci *dest_id = MLX5_GET(destroy_flow_table_in, devx_obj->dinbox, 18068c2ecf20Sopenharmony_ci table_id); 18078c2ecf20Sopenharmony_ci return true; 18088c2ecf20Sopenharmony_ci default: 18098c2ecf20Sopenharmony_ci return false; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic int get_dests(struct uverbs_attr_bundle *attrs, 18148c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *fs_matcher, int *dest_id, 18158c2ecf20Sopenharmony_ci int *dest_type, struct ib_qp **qp, u32 *flags) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci bool dest_devx, dest_qp; 18188c2ecf20Sopenharmony_ci void *devx_obj; 18198c2ecf20Sopenharmony_ci int err; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci dest_devx = uverbs_attr_is_valid(attrs, 18228c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX); 18238c2ecf20Sopenharmony_ci dest_qp = uverbs_attr_is_valid(attrs, 18248c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_DEST_QP); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci *flags = 0; 18278c2ecf20Sopenharmony_ci err = uverbs_get_flags32(flags, attrs, MLX5_IB_ATTR_CREATE_FLOW_FLAGS, 18288c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS | 18298c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP); 18308c2ecf20Sopenharmony_ci if (err) 18318c2ecf20Sopenharmony_ci return err; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci /* Both flags are not allowed */ 18348c2ecf20Sopenharmony_ci if (*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS && 18358c2ecf20Sopenharmony_ci *flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP) 18368c2ecf20Sopenharmony_ci return -EINVAL; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) { 18398c2ecf20Sopenharmony_ci if (dest_devx && (dest_qp || *flags)) 18408c2ecf20Sopenharmony_ci return -EINVAL; 18418c2ecf20Sopenharmony_ci else if (dest_qp && *flags) 18428c2ecf20Sopenharmony_ci return -EINVAL; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* Allow only DEVX object, drop as dest for FDB */ 18468c2ecf20Sopenharmony_ci if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB && !(dest_devx || 18478c2ecf20Sopenharmony_ci (*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP))) 18488c2ecf20Sopenharmony_ci return -EINVAL; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci /* Allow only DEVX object or QP as dest when inserting to RDMA_RX */ 18518c2ecf20Sopenharmony_ci if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) && 18528c2ecf20Sopenharmony_ci ((!dest_devx && !dest_qp) || (dest_devx && dest_qp))) 18538c2ecf20Sopenharmony_ci return -EINVAL; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci *qp = NULL; 18568c2ecf20Sopenharmony_ci if (dest_devx) { 18578c2ecf20Sopenharmony_ci devx_obj = 18588c2ecf20Sopenharmony_ci uverbs_attr_get_obj(attrs, 18598c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* Verify that the given DEVX object is a flow 18628c2ecf20Sopenharmony_ci * steering destination. 18638c2ecf20Sopenharmony_ci */ 18648c2ecf20Sopenharmony_ci if (!is_flow_dest(devx_obj, dest_id, dest_type)) 18658c2ecf20Sopenharmony_ci return -EINVAL; 18668c2ecf20Sopenharmony_ci /* Allow only flow table as dest when inserting to FDB or RDMA_RX */ 18678c2ecf20Sopenharmony_ci if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB || 18688c2ecf20Sopenharmony_ci fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) && 18698c2ecf20Sopenharmony_ci *dest_type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) 18708c2ecf20Sopenharmony_ci return -EINVAL; 18718c2ecf20Sopenharmony_ci } else if (dest_qp) { 18728c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci *qp = uverbs_attr_get_obj(attrs, 18758c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_DEST_QP); 18768c2ecf20Sopenharmony_ci if (IS_ERR(*qp)) 18778c2ecf20Sopenharmony_ci return PTR_ERR(*qp); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if ((*qp)->qp_type != IB_QPT_RAW_PACKET) 18808c2ecf20Sopenharmony_ci return -EINVAL; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci mqp = to_mqp(*qp); 18838c2ecf20Sopenharmony_ci if (mqp->is_rss) 18848c2ecf20Sopenharmony_ci *dest_id = mqp->rss_qp.tirn; 18858c2ecf20Sopenharmony_ci else 18868c2ecf20Sopenharmony_ci *dest_id = mqp->raw_packet_qp.rq.tirn; 18878c2ecf20Sopenharmony_ci *dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR; 18888c2ecf20Sopenharmony_ci } else if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS || 18898c2ecf20Sopenharmony_ci fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_TX) && 18908c2ecf20Sopenharmony_ci !(*flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP)) { 18918c2ecf20Sopenharmony_ci *dest_type = MLX5_FLOW_DESTINATION_TYPE_PORT; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (*dest_type == MLX5_FLOW_DESTINATION_TYPE_TIR && 18958c2ecf20Sopenharmony_ci (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS || 18968c2ecf20Sopenharmony_ci fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_TX)) 18978c2ecf20Sopenharmony_ci return -EINVAL; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci return 0; 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic bool is_flow_counter(void *obj, u32 offset, u32 *counter_id) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci struct devx_obj *devx_obj = obj; 19058c2ecf20Sopenharmony_ci u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, opcode); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (opcode == MLX5_CMD_OP_DEALLOC_FLOW_COUNTER) { 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (offset && offset >= devx_obj->flow_counter_bulk_size) 19108c2ecf20Sopenharmony_ci return false; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci *counter_id = MLX5_GET(dealloc_flow_counter_in, 19138c2ecf20Sopenharmony_ci devx_obj->dinbox, 19148c2ecf20Sopenharmony_ci flow_counter_id); 19158c2ecf20Sopenharmony_ci *counter_id += offset; 19168c2ecf20Sopenharmony_ci return true; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci return false; 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci#define MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS 2 19238c2ecf20Sopenharmony_cistatic int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( 19248c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci struct mlx5_flow_context flow_context = {.flow_tag = 19278c2ecf20Sopenharmony_ci MLX5_FS_DEFAULT_FLOW_TAG}; 19288c2ecf20Sopenharmony_ci u32 *offset_attr, offset = 0, counter_id = 0; 19298c2ecf20Sopenharmony_ci int dest_id, dest_type = -1, inlen, len, ret, i; 19308c2ecf20Sopenharmony_ci struct mlx5_ib_flow_handler *flow_handler; 19318c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *fs_matcher; 19328c2ecf20Sopenharmony_ci struct ib_uobject **arr_flow_actions; 19338c2ecf20Sopenharmony_ci struct ib_uflow_resources *uflow_res; 19348c2ecf20Sopenharmony_ci struct mlx5_flow_act flow_act = {}; 19358c2ecf20Sopenharmony_ci struct ib_qp *qp = NULL; 19368c2ecf20Sopenharmony_ci void *devx_obj, *cmd_in; 19378c2ecf20Sopenharmony_ci struct ib_uobject *uobj; 19388c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev; 19398c2ecf20Sopenharmony_ci u32 flags; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (!capable(CAP_NET_RAW)) 19428c2ecf20Sopenharmony_ci return -EPERM; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci fs_matcher = uverbs_attr_get_obj(attrs, 19458c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_MATCHER); 19468c2ecf20Sopenharmony_ci uobj = uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE); 19478c2ecf20Sopenharmony_ci dev = mlx5_udata_to_mdev(&attrs->driver_udata); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (get_dests(attrs, fs_matcher, &dest_id, &dest_type, &qp, &flags)) 19508c2ecf20Sopenharmony_ci return -EINVAL; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS) 19538c2ecf20Sopenharmony_ci flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_NS; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (flags & MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DROP) 19568c2ecf20Sopenharmony_ci flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci len = uverbs_attr_get_uobjs_arr(attrs, 19598c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX, &arr_flow_actions); 19608c2ecf20Sopenharmony_ci if (len) { 19618c2ecf20Sopenharmony_ci devx_obj = arr_flow_actions[0]->object; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (uverbs_attr_is_valid(attrs, 19648c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET)) { 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci int num_offsets = uverbs_attr_ptr_get_array_size( 19678c2ecf20Sopenharmony_ci attrs, 19688c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET, 19698c2ecf20Sopenharmony_ci sizeof(u32)); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci if (num_offsets != 1) 19728c2ecf20Sopenharmony_ci return -EINVAL; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci offset_attr = uverbs_attr_get_alloced_ptr( 19758c2ecf20Sopenharmony_ci attrs, 19768c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET); 19778c2ecf20Sopenharmony_ci offset = *offset_attr; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci if (!is_flow_counter(devx_obj, offset, &counter_id)) 19818c2ecf20Sopenharmony_ci return -EINVAL; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci cmd_in = uverbs_attr_get_alloced_ptr( 19878c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); 19888c2ecf20Sopenharmony_ci inlen = uverbs_attr_get_len(attrs, 19898c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS); 19928c2ecf20Sopenharmony_ci if (!uflow_res) 19938c2ecf20Sopenharmony_ci return -ENOMEM; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci len = uverbs_attr_get_uobjs_arr(attrs, 19968c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, &arr_flow_actions); 19978c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 19988c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction = 19998c2ecf20Sopenharmony_ci to_mflow_act(arr_flow_actions[i]->object); 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci ret = parse_flow_flow_action(maction, false, &flow_act); 20028c2ecf20Sopenharmony_ci if (ret) 20038c2ecf20Sopenharmony_ci goto err_out; 20048c2ecf20Sopenharmony_ci flow_resources_add(uflow_res, IB_FLOW_SPEC_ACTION_HANDLE, 20058c2ecf20Sopenharmony_ci arr_flow_actions[i]->object); 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci ret = uverbs_copy_from(&flow_context.flow_tag, attrs, 20098c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_TAG); 20108c2ecf20Sopenharmony_ci if (!ret) { 20118c2ecf20Sopenharmony_ci if (flow_context.flow_tag >= BIT(24)) { 20128c2ecf20Sopenharmony_ci ret = -EINVAL; 20138c2ecf20Sopenharmony_ci goto err_out; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci flow_context.flags |= FLOW_CONTEXT_HAS_TAG; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci flow_handler = 20198c2ecf20Sopenharmony_ci raw_fs_rule_add(dev, fs_matcher, &flow_context, &flow_act, 20208c2ecf20Sopenharmony_ci counter_id, cmd_in, inlen, dest_id, dest_type); 20218c2ecf20Sopenharmony_ci if (IS_ERR(flow_handler)) { 20228c2ecf20Sopenharmony_ci ret = PTR_ERR(flow_handler); 20238c2ecf20Sopenharmony_ci goto err_out; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, uflow_res); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci return 0; 20298c2ecf20Sopenharmony_cierr_out: 20308c2ecf20Sopenharmony_ci ib_uverbs_flow_resources_free(uflow_res); 20318c2ecf20Sopenharmony_ci return ret; 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_cistatic int flow_matcher_cleanup(struct ib_uobject *uobject, 20358c2ecf20Sopenharmony_ci enum rdma_remove_reason why, 20368c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *obj = uobject->object; 20398c2ecf20Sopenharmony_ci int ret; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci ret = ib_destroy_usecnt(&obj->usecnt, why, uobject); 20428c2ecf20Sopenharmony_ci if (ret) 20438c2ecf20Sopenharmony_ci return ret; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci kfree(obj); 20468c2ecf20Sopenharmony_ci return 0; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistatic int mlx5_ib_matcher_ns(struct uverbs_attr_bundle *attrs, 20508c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *obj) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type ft_type = 20538c2ecf20Sopenharmony_ci MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX; 20548c2ecf20Sopenharmony_ci u32 flags; 20558c2ecf20Sopenharmony_ci int err; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci /* New users should use MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE and older 20588c2ecf20Sopenharmony_ci * users should switch to it. We leave this to not break userspace 20598c2ecf20Sopenharmony_ci */ 20608c2ecf20Sopenharmony_ci if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE) && 20618c2ecf20Sopenharmony_ci uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS)) 20628c2ecf20Sopenharmony_ci return -EINVAL; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE)) { 20658c2ecf20Sopenharmony_ci err = uverbs_get_const(&ft_type, attrs, 20668c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE); 20678c2ecf20Sopenharmony_ci if (err) 20688c2ecf20Sopenharmony_ci return err; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci err = mlx5_ib_ft_type_to_namespace(ft_type, &obj->ns_type); 20718c2ecf20Sopenharmony_ci if (err) 20728c2ecf20Sopenharmony_ci return err; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci return 0; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS)) { 20788c2ecf20Sopenharmony_ci err = uverbs_get_flags32(&flags, attrs, 20798c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS, 20808c2ecf20Sopenharmony_ci IB_FLOW_ATTR_FLAGS_EGRESS); 20818c2ecf20Sopenharmony_ci if (err) 20828c2ecf20Sopenharmony_ci return err; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (flags) 20858c2ecf20Sopenharmony_ci return mlx5_ib_ft_type_to_namespace( 20868c2ecf20Sopenharmony_ci MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX, 20878c2ecf20Sopenharmony_ci &obj->ns_type); 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci obj->ns_type = MLX5_FLOW_NAMESPACE_BYPASS; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci return 0; 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)( 20968c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci struct ib_uobject *uobj = uverbs_attr_get_uobject( 20998c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE); 21008c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata); 21018c2ecf20Sopenharmony_ci struct mlx5_ib_flow_matcher *obj; 21028c2ecf20Sopenharmony_ci int err; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL); 21058c2ecf20Sopenharmony_ci if (!obj) 21068c2ecf20Sopenharmony_ci return -ENOMEM; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci obj->mask_len = uverbs_attr_get_len( 21098c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK); 21108c2ecf20Sopenharmony_ci err = uverbs_copy_from(&obj->matcher_mask, 21118c2ecf20Sopenharmony_ci attrs, 21128c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK); 21138c2ecf20Sopenharmony_ci if (err) 21148c2ecf20Sopenharmony_ci goto end; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci obj->flow_type = uverbs_attr_get_enum_id( 21178c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (obj->flow_type == MLX5_IB_FLOW_TYPE_NORMAL) { 21208c2ecf20Sopenharmony_ci err = uverbs_copy_from(&obj->priority, 21218c2ecf20Sopenharmony_ci attrs, 21228c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE); 21238c2ecf20Sopenharmony_ci if (err) 21248c2ecf20Sopenharmony_ci goto end; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci err = uverbs_copy_from(&obj->match_criteria_enable, 21288c2ecf20Sopenharmony_ci attrs, 21298c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA); 21308c2ecf20Sopenharmony_ci if (err) 21318c2ecf20Sopenharmony_ci goto end; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci err = mlx5_ib_matcher_ns(attrs, obj); 21348c2ecf20Sopenharmony_ci if (err) 21358c2ecf20Sopenharmony_ci goto end; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (obj->ns_type == MLX5_FLOW_NAMESPACE_FDB && 21388c2ecf20Sopenharmony_ci mlx5_eswitch_mode(dev->mdev->priv.eswitch) != 21398c2ecf20Sopenharmony_ci MLX5_ESWITCH_OFFLOADS) { 21408c2ecf20Sopenharmony_ci err = -EINVAL; 21418c2ecf20Sopenharmony_ci goto end; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci uobj->object = obj; 21458c2ecf20Sopenharmony_ci obj->mdev = dev->mdev; 21468c2ecf20Sopenharmony_ci atomic_set(&obj->usecnt, 0); 21478c2ecf20Sopenharmony_ci return 0; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ciend: 21508c2ecf20Sopenharmony_ci kfree(obj); 21518c2ecf20Sopenharmony_ci return err; 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic struct ib_flow_action * 21558c2ecf20Sopenharmony_cimlx5_ib_create_modify_header(struct mlx5_ib_dev *dev, 21568c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type ft_type, 21578c2ecf20Sopenharmony_ci u8 num_actions, void *in) 21588c2ecf20Sopenharmony_ci{ 21598c2ecf20Sopenharmony_ci enum mlx5_flow_namespace_type namespace; 21608c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction; 21618c2ecf20Sopenharmony_ci int ret; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace); 21648c2ecf20Sopenharmony_ci if (ret) 21658c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci maction = kzalloc(sizeof(*maction), GFP_KERNEL); 21688c2ecf20Sopenharmony_ci if (!maction) 21698c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci maction->flow_action_raw.modify_hdr = 21728c2ecf20Sopenharmony_ci mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci if (IS_ERR(maction->flow_action_raw.modify_hdr)) { 21758c2ecf20Sopenharmony_ci ret = PTR_ERR(maction->flow_action_raw.modify_hdr); 21768c2ecf20Sopenharmony_ci kfree(maction); 21778c2ecf20Sopenharmony_ci return ERR_PTR(ret); 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci maction->flow_action_raw.sub_type = 21808c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_MODIFY_HEADER; 21818c2ecf20Sopenharmony_ci maction->flow_action_raw.dev = dev; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci return &maction->ib_action; 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_cistatic bool mlx5_ib_modify_header_supported(struct mlx5_ib_dev *dev) 21878c2ecf20Sopenharmony_ci{ 21888c2ecf20Sopenharmony_ci return MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, 21898c2ecf20Sopenharmony_ci max_modify_header_actions) || 21908c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, 21918c2ecf20Sopenharmony_ci max_modify_header_actions) || 21928c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_RDMA_TX(dev->mdev, 21938c2ecf20Sopenharmony_ci max_modify_header_actions); 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_cistatic int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)( 21978c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci struct ib_uobject *uobj = uverbs_attr_get_uobject( 22008c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE); 22018c2ecf20Sopenharmony_ci struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata); 22028c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type ft_type; 22038c2ecf20Sopenharmony_ci struct ib_flow_action *action; 22048c2ecf20Sopenharmony_ci int num_actions; 22058c2ecf20Sopenharmony_ci void *in; 22068c2ecf20Sopenharmony_ci int ret; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (!mlx5_ib_modify_header_supported(mdev)) 22098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci in = uverbs_attr_get_alloced_ptr(attrs, 22128c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci num_actions = uverbs_attr_ptr_get_array_size( 22158c2ecf20Sopenharmony_ci attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM, 22168c2ecf20Sopenharmony_ci MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)); 22178c2ecf20Sopenharmony_ci if (num_actions < 0) 22188c2ecf20Sopenharmony_ci return num_actions; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci ret = uverbs_get_const(&ft_type, attrs, 22218c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE); 22228c2ecf20Sopenharmony_ci if (ret) 22238c2ecf20Sopenharmony_ci return ret; 22248c2ecf20Sopenharmony_ci action = mlx5_ib_create_modify_header(mdev, ft_type, num_actions, in); 22258c2ecf20Sopenharmony_ci if (IS_ERR(action)) 22268c2ecf20Sopenharmony_ci return PTR_ERR(action); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci uverbs_flow_action_fill_action(action, uobj, &mdev->ib_dev, 22298c2ecf20Sopenharmony_ci IB_FLOW_ACTION_UNSPECIFIED); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return 0; 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev, 22358c2ecf20Sopenharmony_ci u8 packet_reformat_type, 22368c2ecf20Sopenharmony_ci u8 ft_type) 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci switch (packet_reformat_type) { 22398c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL: 22408c2ecf20Sopenharmony_ci if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX) 22418c2ecf20Sopenharmony_ci return MLX5_CAP_FLOWTABLE(ibdev->mdev, 22428c2ecf20Sopenharmony_ci encap_general_header); 22438c2ecf20Sopenharmony_ci break; 22448c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL: 22458c2ecf20Sopenharmony_ci if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX) 22468c2ecf20Sopenharmony_ci return MLX5_CAP_FLOWTABLE_NIC_TX(ibdev->mdev, 22478c2ecf20Sopenharmony_ci reformat_l2_to_l3_tunnel); 22488c2ecf20Sopenharmony_ci break; 22498c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2: 22508c2ecf20Sopenharmony_ci if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX) 22518c2ecf20Sopenharmony_ci return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, 22528c2ecf20Sopenharmony_ci reformat_l3_tunnel_to_l2); 22538c2ecf20Sopenharmony_ci break; 22548c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2: 22558c2ecf20Sopenharmony_ci if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX) 22568c2ecf20Sopenharmony_ci return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap); 22578c2ecf20Sopenharmony_ci break; 22588c2ecf20Sopenharmony_ci default: 22598c2ecf20Sopenharmony_ci break; 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci return false; 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_cistatic int mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt, u8 *prm_prt) 22668c2ecf20Sopenharmony_ci{ 22678c2ecf20Sopenharmony_ci switch (dv_prt) { 22688c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL: 22698c2ecf20Sopenharmony_ci *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; 22708c2ecf20Sopenharmony_ci break; 22718c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2: 22728c2ecf20Sopenharmony_ci *prm_prt = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; 22738c2ecf20Sopenharmony_ci break; 22748c2ecf20Sopenharmony_ci case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL: 22758c2ecf20Sopenharmony_ci *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 22768c2ecf20Sopenharmony_ci break; 22778c2ecf20Sopenharmony_ci default: 22788c2ecf20Sopenharmony_ci return -EINVAL; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci return 0; 22828c2ecf20Sopenharmony_ci} 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_cistatic int mlx5_ib_flow_action_create_packet_reformat_ctx( 22858c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev, 22868c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction, 22878c2ecf20Sopenharmony_ci u8 ft_type, u8 dv_prt, 22888c2ecf20Sopenharmony_ci void *in, size_t len) 22898c2ecf20Sopenharmony_ci{ 22908c2ecf20Sopenharmony_ci enum mlx5_flow_namespace_type namespace; 22918c2ecf20Sopenharmony_ci u8 prm_prt; 22928c2ecf20Sopenharmony_ci int ret; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace); 22958c2ecf20Sopenharmony_ci if (ret) 22968c2ecf20Sopenharmony_ci return ret; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci ret = mlx5_ib_dv_to_prm_packet_reforamt_type(dv_prt, &prm_prt); 22998c2ecf20Sopenharmony_ci if (ret) 23008c2ecf20Sopenharmony_ci return ret; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci maction->flow_action_raw.pkt_reformat = 23038c2ecf20Sopenharmony_ci mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len, 23048c2ecf20Sopenharmony_ci in, namespace); 23058c2ecf20Sopenharmony_ci if (IS_ERR(maction->flow_action_raw.pkt_reformat)) { 23068c2ecf20Sopenharmony_ci ret = PTR_ERR(maction->flow_action_raw.pkt_reformat); 23078c2ecf20Sopenharmony_ci return ret; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci maction->flow_action_raw.sub_type = 23118c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_PACKET_REFORMAT; 23128c2ecf20Sopenharmony_ci maction->flow_action_raw.dev = dev; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci return 0; 23158c2ecf20Sopenharmony_ci} 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_cistatic int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)( 23188c2ecf20Sopenharmony_ci struct uverbs_attr_bundle *attrs) 23198c2ecf20Sopenharmony_ci{ 23208c2ecf20Sopenharmony_ci struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, 23218c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE); 23228c2ecf20Sopenharmony_ci struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata); 23238c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_action_packet_reformat_type dv_prt; 23248c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type ft_type; 23258c2ecf20Sopenharmony_ci struct mlx5_ib_flow_action *maction; 23268c2ecf20Sopenharmony_ci int ret; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci ret = uverbs_get_const(&ft_type, attrs, 23298c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE); 23308c2ecf20Sopenharmony_ci if (ret) 23318c2ecf20Sopenharmony_ci return ret; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci ret = uverbs_get_const(&dv_prt, attrs, 23348c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE); 23358c2ecf20Sopenharmony_ci if (ret) 23368c2ecf20Sopenharmony_ci return ret; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci if (!mlx5_ib_flow_action_packet_reformat_valid(mdev, dv_prt, ft_type)) 23398c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci maction = kzalloc(sizeof(*maction), GFP_KERNEL); 23428c2ecf20Sopenharmony_ci if (!maction) 23438c2ecf20Sopenharmony_ci return -ENOMEM; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (dv_prt == 23468c2ecf20Sopenharmony_ci MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2) { 23478c2ecf20Sopenharmony_ci maction->flow_action_raw.sub_type = 23488c2ecf20Sopenharmony_ci MLX5_IB_FLOW_ACTION_DECAP; 23498c2ecf20Sopenharmony_ci maction->flow_action_raw.dev = mdev; 23508c2ecf20Sopenharmony_ci } else { 23518c2ecf20Sopenharmony_ci void *in; 23528c2ecf20Sopenharmony_ci int len; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci in = uverbs_attr_get_alloced_ptr(attrs, 23558c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF); 23568c2ecf20Sopenharmony_ci if (IS_ERR(in)) { 23578c2ecf20Sopenharmony_ci ret = PTR_ERR(in); 23588c2ecf20Sopenharmony_ci goto free_maction; 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci len = uverbs_attr_get_len(attrs, 23628c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci ret = mlx5_ib_flow_action_create_packet_reformat_ctx(mdev, 23658c2ecf20Sopenharmony_ci maction, ft_type, dv_prt, in, len); 23668c2ecf20Sopenharmony_ci if (ret) 23678c2ecf20Sopenharmony_ci goto free_maction; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci uverbs_flow_action_fill_action(&maction->ib_action, uobj, &mdev->ib_dev, 23718c2ecf20Sopenharmony_ci IB_FLOW_ACTION_UNSPECIFIED); 23728c2ecf20Sopenharmony_ci return 0; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_cifree_maction: 23758c2ecf20Sopenharmony_ci kfree(maction); 23768c2ecf20Sopenharmony_ci return ret; 23778c2ecf20Sopenharmony_ci} 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD( 23808c2ecf20Sopenharmony_ci MLX5_IB_METHOD_CREATE_FLOW, 23818c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE, 23828c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW, 23838c2ecf20Sopenharmony_ci UVERBS_ACCESS_NEW, 23848c2ecf20Sopenharmony_ci UA_MANDATORY), 23858c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN( 23868c2ecf20Sopenharmony_ci MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE, 23878c2ecf20Sopenharmony_ci UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)), 23888c2ecf20Sopenharmony_ci UA_MANDATORY, 23898c2ecf20Sopenharmony_ci UA_ALLOC_AND_COPY), 23908c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_MATCHER, 23918c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_FLOW_MATCHER, 23928c2ecf20Sopenharmony_ci UVERBS_ACCESS_READ, 23938c2ecf20Sopenharmony_ci UA_MANDATORY), 23948c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_QP, 23958c2ecf20Sopenharmony_ci UVERBS_OBJECT_QP, 23968c2ecf20Sopenharmony_ci UVERBS_ACCESS_READ), 23978c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX, 23988c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_DEVX_OBJ, 23998c2ecf20Sopenharmony_ci UVERBS_ACCESS_READ), 24008c2ecf20Sopenharmony_ci UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, 24018c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW_ACTION, 24028c2ecf20Sopenharmony_ci UVERBS_ACCESS_READ, 1, 24038c2ecf20Sopenharmony_ci MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS, 24048c2ecf20Sopenharmony_ci UA_OPTIONAL), 24058c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_TAG, 24068c2ecf20Sopenharmony_ci UVERBS_ATTR_TYPE(u32), 24078c2ecf20Sopenharmony_ci UA_OPTIONAL), 24088c2ecf20Sopenharmony_ci UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX, 24098c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_DEVX_OBJ, 24108c2ecf20Sopenharmony_ci UVERBS_ACCESS_READ, 1, 1, 24118c2ecf20Sopenharmony_ci UA_OPTIONAL), 24128c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET, 24138c2ecf20Sopenharmony_ci UVERBS_ATTR_MIN_SIZE(sizeof(u32)), 24148c2ecf20Sopenharmony_ci UA_OPTIONAL, 24158c2ecf20Sopenharmony_ci UA_ALLOC_AND_COPY), 24168c2ecf20Sopenharmony_ci UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_CREATE_FLOW_FLAGS, 24178c2ecf20Sopenharmony_ci enum mlx5_ib_create_flow_flags, 24188c2ecf20Sopenharmony_ci UA_OPTIONAL)); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD_DESTROY( 24218c2ecf20Sopenharmony_ci MLX5_IB_METHOD_DESTROY_FLOW, 24228c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE, 24238c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW, 24248c2ecf20Sopenharmony_ci UVERBS_ACCESS_DESTROY, 24258c2ecf20Sopenharmony_ci UA_MANDATORY)); 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ciADD_UVERBS_METHODS(mlx5_ib_fs, 24288c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW, 24298c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW), 24308c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW)); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD( 24338c2ecf20Sopenharmony_ci MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER, 24348c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE, 24358c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW_ACTION, 24368c2ecf20Sopenharmony_ci UVERBS_ACCESS_NEW, 24378c2ecf20Sopenharmony_ci UA_MANDATORY), 24388c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM, 24398c2ecf20Sopenharmony_ci UVERBS_ATTR_MIN_SIZE(MLX5_UN_SZ_BYTES( 24408c2ecf20Sopenharmony_ci set_add_copy_action_in_auto)), 24418c2ecf20Sopenharmony_ci UA_MANDATORY, 24428c2ecf20Sopenharmony_ci UA_ALLOC_AND_COPY), 24438c2ecf20Sopenharmony_ci UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE, 24448c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type, 24458c2ecf20Sopenharmony_ci UA_MANDATORY)); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD( 24488c2ecf20Sopenharmony_ci MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT, 24498c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE, 24508c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW_ACTION, 24518c2ecf20Sopenharmony_ci UVERBS_ACCESS_NEW, 24528c2ecf20Sopenharmony_ci UA_MANDATORY), 24538c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF, 24548c2ecf20Sopenharmony_ci UVERBS_ATTR_MIN_SIZE(1), 24558c2ecf20Sopenharmony_ci UA_ALLOC_AND_COPY, 24568c2ecf20Sopenharmony_ci UA_OPTIONAL), 24578c2ecf20Sopenharmony_ci UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE, 24588c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_action_packet_reformat_type, 24598c2ecf20Sopenharmony_ci UA_MANDATORY), 24608c2ecf20Sopenharmony_ci UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE, 24618c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type, 24628c2ecf20Sopenharmony_ci UA_MANDATORY)); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ciADD_UVERBS_METHODS( 24658c2ecf20Sopenharmony_ci mlx5_ib_flow_actions, 24668c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW_ACTION, 24678c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER), 24688c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD( 24718c2ecf20Sopenharmony_ci MLX5_IB_METHOD_FLOW_MATCHER_CREATE, 24728c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE, 24738c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_FLOW_MATCHER, 24748c2ecf20Sopenharmony_ci UVERBS_ACCESS_NEW, 24758c2ecf20Sopenharmony_ci UA_MANDATORY), 24768c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN( 24778c2ecf20Sopenharmony_ci MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK, 24788c2ecf20Sopenharmony_ci UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)), 24798c2ecf20Sopenharmony_ci UA_MANDATORY), 24808c2ecf20Sopenharmony_ci UVERBS_ATTR_ENUM_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE, 24818c2ecf20Sopenharmony_ci mlx5_ib_flow_type, 24828c2ecf20Sopenharmony_ci UA_MANDATORY), 24838c2ecf20Sopenharmony_ci UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA, 24848c2ecf20Sopenharmony_ci UVERBS_ATTR_TYPE(u8), 24858c2ecf20Sopenharmony_ci UA_MANDATORY), 24868c2ecf20Sopenharmony_ci UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS, 24878c2ecf20Sopenharmony_ci enum ib_flow_flags, 24888c2ecf20Sopenharmony_ci UA_OPTIONAL), 24898c2ecf20Sopenharmony_ci UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE, 24908c2ecf20Sopenharmony_ci enum mlx5_ib_uapi_flow_table_type, 24918c2ecf20Sopenharmony_ci UA_OPTIONAL)); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_METHOD_DESTROY( 24948c2ecf20Sopenharmony_ci MLX5_IB_METHOD_FLOW_MATCHER_DESTROY, 24958c2ecf20Sopenharmony_ci UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE, 24968c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_FLOW_MATCHER, 24978c2ecf20Sopenharmony_ci UVERBS_ACCESS_DESTROY, 24988c2ecf20Sopenharmony_ci UA_MANDATORY)); 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ciDECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER, 25018c2ecf20Sopenharmony_ci UVERBS_TYPE_ALLOC_IDR(flow_matcher_cleanup), 25028c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE), 25038c2ecf20Sopenharmony_ci &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY)); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ciconst struct uapi_definition mlx5_ib_flow_defs[] = { 25068c2ecf20Sopenharmony_ci UAPI_DEF_CHAIN_OBJ_TREE_NAMED( 25078c2ecf20Sopenharmony_ci MLX5_IB_OBJECT_FLOW_MATCHER), 25088c2ecf20Sopenharmony_ci UAPI_DEF_CHAIN_OBJ_TREE( 25098c2ecf20Sopenharmony_ci UVERBS_OBJECT_FLOW, 25108c2ecf20Sopenharmony_ci &mlx5_ib_fs), 25118c2ecf20Sopenharmony_ci UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION, 25128c2ecf20Sopenharmony_ci &mlx5_ib_flow_actions), 25138c2ecf20Sopenharmony_ci {}, 25148c2ecf20Sopenharmony_ci}; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_cistatic const struct ib_device_ops flow_ops = { 25178c2ecf20Sopenharmony_ci .create_flow = mlx5_ib_create_flow, 25188c2ecf20Sopenharmony_ci .destroy_flow = mlx5_ib_destroy_flow, 25198c2ecf20Sopenharmony_ci .destroy_flow_action = mlx5_ib_destroy_flow_action, 25208c2ecf20Sopenharmony_ci}; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_cistatic const struct ib_device_ops flow_ipsec_ops = { 25238c2ecf20Sopenharmony_ci .create_flow_action_esp = mlx5_ib_create_flow_action_esp, 25248c2ecf20Sopenharmony_ci .modify_flow_action_esp = mlx5_ib_modify_flow_action_esp, 25258c2ecf20Sopenharmony_ci}; 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ciint mlx5_ib_fs_init(struct mlx5_ib_dev *dev) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci dev->flow_db = kzalloc(sizeof(*dev->flow_db), GFP_KERNEL); 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (!dev->flow_db) 25328c2ecf20Sopenharmony_ci return -ENOMEM; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci mutex_init(&dev->flow_db->lock); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, &flow_ops); 25378c2ecf20Sopenharmony_ci if (mlx5_accel_ipsec_device_caps(dev->mdev) & 25388c2ecf20Sopenharmony_ci MLX5_ACCEL_IPSEC_CAP_DEVICE) 25398c2ecf20Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, &flow_ipsec_ops); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci return 0; 25428c2ecf20Sopenharmony_ci} 2543