12c0ade80SHans Petter Selasky /*- 22c0ade80SHans Petter Selasky * Copyright (c) 2020-2021, Mellanox Technologies, Ltd. 32c0ade80SHans Petter Selasky * 42c0ade80SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 52c0ade80SHans Petter Selasky * modification, are permitted provided that the following conditions 62c0ade80SHans Petter Selasky * are met: 72c0ade80SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 82c0ade80SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 92c0ade80SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 102c0ade80SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 112c0ade80SHans Petter Selasky * documentation and/or other materials provided with the distribution. 122c0ade80SHans Petter Selasky * 132c0ade80SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 142c0ade80SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 152c0ade80SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 162c0ade80SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 172c0ade80SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 182c0ade80SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 192c0ade80SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 202c0ade80SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 212c0ade80SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 222c0ade80SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 232c0ade80SHans Petter Selasky * SUCH DAMAGE. 242c0ade80SHans Petter Selasky */ 252c0ade80SHans Petter Selasky 262c0ade80SHans Petter Selasky #include "opt_inet.h" 272c0ade80SHans Petter Selasky #include "opt_inet6.h" 282c0ade80SHans Petter Selasky 292c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_en/en.h> 302c0ade80SHans Petter Selasky 312c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_core/fs_core.h> 322c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_core/fs_tcp.h> 332c0ade80SHans Petter Selasky #include <dev/mlx5/device.h> 342c0ade80SHans Petter Selasky 352c0ade80SHans Petter Selasky #include <sys/domain.h> 362c0ade80SHans Petter Selasky 372c0ade80SHans Petter Selasky #include <netinet/in_pcb.h> 382c0ade80SHans Petter Selasky 392c0ade80SHans Petter Selasky #if defined(INET) || defined(INET6) 402c0ade80SHans Petter Selasky static void 412c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv4_flow(struct mlx5_flow_spec *spec, struct inpcb *inp) 422c0ade80SHans Petter Selasky { 432c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); 442c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP); 452c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version); 462c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 4); 472c0ade80SHans Petter Selasky memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 482c0ade80SHans Petter Selasky outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), 492c0ade80SHans Petter Selasky &inp->inp_faddr, 4); 502c0ade80SHans Petter Selasky memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 512c0ade80SHans Petter Selasky outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 522c0ade80SHans Petter Selasky &inp->inp_laddr, 4); 532c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 542c0ade80SHans Petter Selasky outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4); 552c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 562c0ade80SHans Petter Selasky outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 572c0ade80SHans Petter Selasky } 582c0ade80SHans Petter Selasky #endif 592c0ade80SHans Petter Selasky 602c0ade80SHans Petter Selasky #ifdef INET6 612c0ade80SHans Petter Selasky static void 622c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv6_flow(struct mlx5_flow_spec *spec, struct inpcb *inp) 632c0ade80SHans Petter Selasky { 642c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); 652c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP); 662c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version); 672c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 6); 682c0ade80SHans Petter Selasky memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 692c0ade80SHans Petter Selasky outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 702c0ade80SHans Petter Selasky &inp->in6p_faddr, 16); 712c0ade80SHans Petter Selasky memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 722c0ade80SHans Petter Selasky outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 732c0ade80SHans Petter Selasky &inp->in6p_laddr, 16); 742c0ade80SHans Petter Selasky memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 752c0ade80SHans Petter Selasky outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 762c0ade80SHans Petter Selasky 0xff, 16); 772c0ade80SHans Petter Selasky memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 782c0ade80SHans Petter Selasky outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 792c0ade80SHans Petter Selasky 0xff, 16); 802c0ade80SHans Petter Selasky } 812c0ade80SHans Petter Selasky #endif 822c0ade80SHans Petter Selasky 832c0ade80SHans Petter Selasky void 842c0ade80SHans Petter Selasky mlx5e_accel_fs_del_inpcb(struct mlx5_flow_rule *rule) 852c0ade80SHans Petter Selasky { 862c0ade80SHans Petter Selasky mlx5_del_flow_rule(rule); 872c0ade80SHans Petter Selasky } 882c0ade80SHans Petter Selasky 892c0ade80SHans Petter Selasky struct mlx5_flow_rule * 902c0ade80SHans Petter Selasky mlx5e_accel_fs_add_inpcb(struct mlx5e_priv *priv, 912c0ade80SHans Petter Selasky struct inpcb *inp, uint32_t tirn, uint32_t flow_tag, 922c0ade80SHans Petter Selasky uint16_t vlan_id) 932c0ade80SHans Petter Selasky { 942c0ade80SHans Petter Selasky struct mlx5_flow_destination dest = {}; 952c0ade80SHans Petter Selasky struct mlx5e_flow_table *ft = NULL; 9675095cd3SJohn Baldwin #if defined(INET) || defined(INET6) 9775095cd3SJohn Baldwin struct mlx5e_accel_fs_tcp *fs_tcp = &priv->fts.accel_tcp; 9875095cd3SJohn Baldwin #endif 992c0ade80SHans Petter Selasky struct mlx5_flow_rule *flow; 1002c0ade80SHans Petter Selasky struct mlx5_flow_spec *spec; 1012c0ade80SHans Petter Selasky 1022c0ade80SHans Petter Selasky spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 1032c0ade80SHans Petter Selasky if (!spec) 1042c0ade80SHans Petter Selasky return (ERR_PTR(-ENOMEM)); 1052c0ade80SHans Petter Selasky 1062c0ade80SHans Petter Selasky spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 1072c0ade80SHans Petter Selasky 1082c0ade80SHans Petter Selasky INP_RLOCK(inp); 1092c0ade80SHans Petter Selasky /* Set VLAN ID to match, if any. */ 1102c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); 1112c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); 1122c0ade80SHans Petter Selasky if (vlan_id != MLX5E_ACCEL_FS_ADD_INPCB_NO_VLAN) { 1132c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); 1142c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id); 1152c0ade80SHans Petter Selasky } 1162c0ade80SHans Petter Selasky 1172c0ade80SHans Petter Selasky /* Set TCP port numbers. */ 1182c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 1192c0ade80SHans Petter Selasky outer_headers.tcp_dport); 1202c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 1212c0ade80SHans Petter Selasky outer_headers.tcp_sport); 1222c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport, 1232c0ade80SHans Petter Selasky ntohs(inp->inp_lport)); 1242c0ade80SHans Petter Selasky MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport, 1252c0ade80SHans Petter Selasky ntohs(inp->inp_fport)); 1262c0ade80SHans Petter Selasky 1272c0ade80SHans Petter Selasky /* Set IP addresses. */ 1282c0ade80SHans Petter Selasky switch (INP_SOCKAF(inp->inp_socket)) { 1292c0ade80SHans Petter Selasky #ifdef INET 1302c0ade80SHans Petter Selasky case AF_INET: 1312c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv4_flow(spec, inp); 1322c0ade80SHans Petter Selasky ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP]; 1332c0ade80SHans Petter Selasky break; 1342c0ade80SHans Petter Selasky #endif 1352c0ade80SHans Petter Selasky #ifdef INET6 1362c0ade80SHans Petter Selasky case AF_INET6: 1372c0ade80SHans Petter Selasky if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && 1382c0ade80SHans Petter Selasky IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { 1392c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv4_flow(spec, inp); 1402c0ade80SHans Petter Selasky ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP]; 1412c0ade80SHans Petter Selasky } else { 1422c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv6_flow(spec, inp); 1432c0ade80SHans Petter Selasky ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV6_TCP]; 1442c0ade80SHans Petter Selasky } 1452c0ade80SHans Petter Selasky break; 1462c0ade80SHans Petter Selasky #endif 1472c0ade80SHans Petter Selasky default: 1482c0ade80SHans Petter Selasky break; 1492c0ade80SHans Petter Selasky } 1502c0ade80SHans Petter Selasky INP_RUNLOCK(inp); 1512c0ade80SHans Petter Selasky 1522c0ade80SHans Petter Selasky if (!ft) { 1532c0ade80SHans Petter Selasky flow = ERR_PTR(-EINVAL); 1542c0ade80SHans Petter Selasky goto out; 1552c0ade80SHans Petter Selasky } 1562c0ade80SHans Petter Selasky 1572c0ade80SHans Petter Selasky dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; 1582c0ade80SHans Petter Selasky dest.tir_num = tirn; 1592c0ade80SHans Petter Selasky 1602c0ade80SHans Petter Selasky flow = mlx5_add_flow_rule(ft->t, spec->match_criteria_enable, 1612c0ade80SHans Petter Selasky spec->match_criteria, 1622c0ade80SHans Petter Selasky spec->match_value, 1632c0ade80SHans Petter Selasky MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 1642c0ade80SHans Petter Selasky flow_tag, 1652c0ade80SHans Petter Selasky &dest); 1662c0ade80SHans Petter Selasky out: 1672c0ade80SHans Petter Selasky kvfree(spec); 1682c0ade80SHans Petter Selasky return (flow); 1692c0ade80SHans Petter Selasky } 1702c0ade80SHans Petter Selasky 1712c0ade80SHans Petter Selasky static int 1722c0ade80SHans Petter Selasky accel_fs_tcp_add_default_rule(struct mlx5e_priv *priv, int type) 1732c0ade80SHans Petter Selasky { 1742c0ade80SHans Petter Selasky static u32 match_criteria[MLX5_ST_SZ_DW(fte_match_param)]; 1752c0ade80SHans Petter Selasky static u32 match_value[MLX5_ST_SZ_DW(fte_match_param)]; 1762c0ade80SHans Petter Selasky struct mlx5_flow_destination dest = {}; 1772c0ade80SHans Petter Selasky struct mlx5e_accel_fs_tcp *fs_tcp; 1782c0ade80SHans Petter Selasky struct mlx5_flow_rule *rule; 1792c0ade80SHans Petter Selasky 1802c0ade80SHans Petter Selasky fs_tcp = &priv->fts.accel_tcp; 1812c0ade80SHans Petter Selasky 1822c0ade80SHans Petter Selasky dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 1832c0ade80SHans Petter Selasky 1842c0ade80SHans Petter Selasky /* 1852c0ade80SHans Petter Selasky * Traffic not matched by flow table rules should be forwarded 1862c0ade80SHans Petter Selasky * to the next flow table in order to not be dropped by the 1872c0ade80SHans Petter Selasky * default action. Refer to the diagram in 1882c0ade80SHans Petter Selasky * mlx5_en_flow_table.c for more information about the order 1892c0ade80SHans Petter Selasky * of flow tables. 1902c0ade80SHans Petter Selasky */ 1912c0ade80SHans Petter Selasky dest.ft = (type == MLX5E_ACCEL_FS_TCP_NUM_TYPES - 1) ? 1922c0ade80SHans Petter Selasky priv->fts.vlan.t : fs_tcp->tables[type + 1].t; 1932c0ade80SHans Petter Selasky 1942c0ade80SHans Petter Selasky rule = mlx5_add_flow_rule(fs_tcp->tables[type].t, 0, match_criteria, match_value, 1952c0ade80SHans Petter Selasky MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest); 1962c0ade80SHans Petter Selasky if (IS_ERR(rule)) 1972c0ade80SHans Petter Selasky return (PTR_ERR(rule)); 1982c0ade80SHans Petter Selasky 1992c0ade80SHans Petter Selasky fs_tcp->default_rules[type] = rule; 2002c0ade80SHans Petter Selasky return (0); 2012c0ade80SHans Petter Selasky } 2022c0ade80SHans Petter Selasky 2032c0ade80SHans Petter Selasky #define MLX5E_ACCEL_FS_TCP_NUM_GROUPS (2) 2042c0ade80SHans Petter Selasky #define MLX5E_ACCEL_FS_TCP_GROUP1_SIZE (BIT(16) - 1) 2052c0ade80SHans Petter Selasky #define MLX5E_ACCEL_FS_TCP_GROUP2_SIZE (BIT(0)) 2062c0ade80SHans Petter Selasky #define MLX5E_ACCEL_FS_TCP_TABLE_SIZE (MLX5E_ACCEL_FS_TCP_GROUP1_SIZE +\ 2072c0ade80SHans Petter Selasky MLX5E_ACCEL_FS_TCP_GROUP2_SIZE) 2082c0ade80SHans Petter Selasky static int 2092c0ade80SHans Petter Selasky accel_fs_tcp_create_groups(struct mlx5e_flow_table *ft, int type) 2102c0ade80SHans Petter Selasky { 2112c0ade80SHans Petter Selasky int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 2122c0ade80SHans Petter Selasky void *outer_headers_c; 2132c0ade80SHans Petter Selasky int ix = 0; 2142c0ade80SHans Petter Selasky u32 *in; 2152c0ade80SHans Petter Selasky int err; 2162c0ade80SHans Petter Selasky u8 *mc; 2172c0ade80SHans Petter Selasky 2182c0ade80SHans Petter Selasky ft->g = kcalloc(MLX5E_ACCEL_FS_TCP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); 2192c0ade80SHans Petter Selasky in = kvzalloc(inlen, GFP_KERNEL); 2202c0ade80SHans Petter Selasky if (!in || !ft->g) { 2212c0ade80SHans Petter Selasky kfree(ft->g); 2222c0ade80SHans Petter Selasky kvfree(in); 2232c0ade80SHans Petter Selasky return (-ENOMEM); 2242c0ade80SHans Petter Selasky } 2252c0ade80SHans Petter Selasky 2262c0ade80SHans Petter Selasky mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 2272c0ade80SHans Petter Selasky outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers); 2282c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol); 2292c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version); 2302c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, cvlan_tag); 2312c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, first_vid); 2322c0ade80SHans Petter Selasky 2332c0ade80SHans Petter Selasky switch (type) { 2342c0ade80SHans Petter Selasky case MLX5E_ACCEL_FS_IPV4_TCP: 2352c0ade80SHans Petter Selasky case MLX5E_ACCEL_FS_IPV6_TCP: 2362c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport); 2372c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport); 2382c0ade80SHans Petter Selasky break; 2392c0ade80SHans Petter Selasky default: 2402c0ade80SHans Petter Selasky err = -EINVAL; 2412c0ade80SHans Petter Selasky goto out; 2422c0ade80SHans Petter Selasky } 2432c0ade80SHans Petter Selasky 2442c0ade80SHans Petter Selasky switch (type) { 2452c0ade80SHans Petter Selasky case MLX5E_ACCEL_FS_IPV4_TCP: 2462c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, 2472c0ade80SHans Petter Selasky src_ipv4_src_ipv6.ipv4_layout.ipv4); 2482c0ade80SHans Petter Selasky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, 2492c0ade80SHans Petter Selasky dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 2502c0ade80SHans Petter Selasky break; 2512c0ade80SHans Petter Selasky case MLX5E_ACCEL_FS_IPV6_TCP: 2522c0ade80SHans Petter Selasky memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, 2532c0ade80SHans Petter Selasky src_ipv4_src_ipv6.ipv6_layout.ipv6), 2542c0ade80SHans Petter Selasky 0xff, 16); 2552c0ade80SHans Petter Selasky memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, 2562c0ade80SHans Petter Selasky dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 2572c0ade80SHans Petter Selasky 0xff, 16); 2582c0ade80SHans Petter Selasky break; 2592c0ade80SHans Petter Selasky default: 2602c0ade80SHans Petter Selasky err = -EINVAL; 2612c0ade80SHans Petter Selasky goto out; 2622c0ade80SHans Petter Selasky } 2632c0ade80SHans Petter Selasky 2642c0ade80SHans Petter Selasky MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 2652c0ade80SHans Petter Selasky MLX5_SET_CFG(in, start_flow_index, ix); 2662c0ade80SHans Petter Selasky ix += MLX5E_ACCEL_FS_TCP_GROUP1_SIZE; 2672c0ade80SHans Petter Selasky MLX5_SET_CFG(in, end_flow_index, ix - 1); 2682c0ade80SHans Petter Selasky ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 2692c0ade80SHans Petter Selasky if (IS_ERR(ft->g[ft->num_groups])) 2702c0ade80SHans Petter Selasky goto err; 2712c0ade80SHans Petter Selasky ft->num_groups++; 2722c0ade80SHans Petter Selasky 2732c0ade80SHans Petter Selasky /* Default Flow Group */ 2742c0ade80SHans Petter Selasky memset(in, 0, inlen); 2752c0ade80SHans Petter Selasky MLX5_SET_CFG(in, start_flow_index, ix); 2762c0ade80SHans Petter Selasky ix += MLX5E_ACCEL_FS_TCP_GROUP2_SIZE; 2772c0ade80SHans Petter Selasky MLX5_SET_CFG(in, end_flow_index, ix - 1); 2782c0ade80SHans Petter Selasky ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 2792c0ade80SHans Petter Selasky if (IS_ERR(ft->g[ft->num_groups])) 2802c0ade80SHans Petter Selasky goto err; 2812c0ade80SHans Petter Selasky ft->num_groups++; 2822c0ade80SHans Petter Selasky 2832c0ade80SHans Petter Selasky kvfree(in); 2842c0ade80SHans Petter Selasky return (0); 2852c0ade80SHans Petter Selasky 2862c0ade80SHans Petter Selasky err: 2872c0ade80SHans Petter Selasky err = PTR_ERR(ft->g[ft->num_groups]); 2882c0ade80SHans Petter Selasky ft->g[ft->num_groups] = NULL; 2892c0ade80SHans Petter Selasky out: 2902c0ade80SHans Petter Selasky kvfree(in); 2912c0ade80SHans Petter Selasky 2922c0ade80SHans Petter Selasky return (err); 2932c0ade80SHans Petter Selasky } 2942c0ade80SHans Petter Selasky 2952c0ade80SHans Petter Selasky static void 2962c0ade80SHans Petter Selasky accel_fs_tcp_destroy_groups(struct mlx5e_flow_table *ft) 2972c0ade80SHans Petter Selasky { 2982c0ade80SHans Petter Selasky int i; 2992c0ade80SHans Petter Selasky 3002c0ade80SHans Petter Selasky for (i = ft->num_groups - 1; i >= 0; i--) { 3012c0ade80SHans Petter Selasky if (!IS_ERR_OR_NULL(ft->g[i])) 3022c0ade80SHans Petter Selasky mlx5_destroy_flow_group(ft->g[i]); 3032c0ade80SHans Petter Selasky ft->g[i] = NULL; 3042c0ade80SHans Petter Selasky } 3052c0ade80SHans Petter Selasky ft->num_groups = 0; 3062c0ade80SHans Petter Selasky } 3072c0ade80SHans Petter Selasky 3082c0ade80SHans Petter Selasky static int 3092c0ade80SHans Petter Selasky accel_fs_tcp_create_table(struct mlx5e_priv *priv, int type) 3102c0ade80SHans Petter Selasky { 3112c0ade80SHans Petter Selasky struct mlx5e_flow_table *ft = &priv->fts.accel_tcp.tables[type]; 3122c0ade80SHans Petter Selasky int err; 3132c0ade80SHans Petter Selasky 3142c0ade80SHans Petter Selasky ft->num_groups = 0; 3152c0ade80SHans Petter Selasky ft->t = mlx5_create_flow_table(priv->fts.accel_tcp.ns, 0, "tcp", 3162c0ade80SHans Petter Selasky MLX5E_ACCEL_FS_TCP_TABLE_SIZE); 3172c0ade80SHans Petter Selasky if (IS_ERR(ft->t)) { 3182c0ade80SHans Petter Selasky err = PTR_ERR(ft->t); 3192c0ade80SHans Petter Selasky ft->t = NULL; 3202c0ade80SHans Petter Selasky return (err); 3212c0ade80SHans Petter Selasky } 3222c0ade80SHans Petter Selasky 3232c0ade80SHans Petter Selasky err = accel_fs_tcp_create_groups(ft, type); 3242c0ade80SHans Petter Selasky if (err) 3252c0ade80SHans Petter Selasky goto err_destroy_flow_table; 3262c0ade80SHans Petter Selasky 3272c0ade80SHans Petter Selasky return (0); 3282c0ade80SHans Petter Selasky 3292c0ade80SHans Petter Selasky err_destroy_flow_table: 3302c0ade80SHans Petter Selasky mlx5_destroy_flow_table(ft->t); 3312c0ade80SHans Petter Selasky ft->t = NULL; 3322c0ade80SHans Petter Selasky return (err); 3332c0ade80SHans Petter Selasky } 3342c0ade80SHans Petter Selasky 3352c0ade80SHans Petter Selasky static void 3362c0ade80SHans Petter Selasky accel_fs_tcp_destroy_table(struct mlx5e_priv *priv, int i) 3372c0ade80SHans Petter Selasky { 3382c0ade80SHans Petter Selasky struct mlx5e_accel_fs_tcp *fs_tcp; 3392c0ade80SHans Petter Selasky struct mlx5e_flow_table *ft; 3402c0ade80SHans Petter Selasky 3412c0ade80SHans Petter Selasky fs_tcp = &priv->fts.accel_tcp; 3422c0ade80SHans Petter Selasky ft = fs_tcp->tables + i; 3432c0ade80SHans Petter Selasky 3442c0ade80SHans Petter Selasky mlx5_del_flow_rule(fs_tcp->default_rules[i]); 3452c0ade80SHans Petter Selasky 3462c0ade80SHans Petter Selasky accel_fs_tcp_destroy_groups(ft); 3472c0ade80SHans Petter Selasky kfree(ft->g); 3482c0ade80SHans Petter Selasky ft->g = NULL; 3492c0ade80SHans Petter Selasky mlx5_destroy_flow_table(ft->t); 3502c0ade80SHans Petter Selasky ft->t = NULL; 3512c0ade80SHans Petter Selasky } 3522c0ade80SHans Petter Selasky 3532c0ade80SHans Petter Selasky void 3542c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv *priv) 3552c0ade80SHans Petter Selasky { 3562c0ade80SHans Petter Selasky int i; 3572c0ade80SHans Petter Selasky 3582c0ade80SHans Petter Selasky if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version)) 3592c0ade80SHans Petter Selasky return; 3602c0ade80SHans Petter Selasky 3612c0ade80SHans Petter Selasky for (i = 0; i < MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) 3622c0ade80SHans Petter Selasky accel_fs_tcp_destroy_table(priv, i); 3632c0ade80SHans Petter Selasky } 3642c0ade80SHans Petter Selasky 3652c0ade80SHans Petter Selasky int 3662c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_create(struct mlx5e_priv *priv) 3672c0ade80SHans Petter Selasky { 3682c0ade80SHans Petter Selasky int i, err; 3692c0ade80SHans Petter Selasky 3702c0ade80SHans Petter Selasky if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version)) 3712c0ade80SHans Petter Selasky return (0); 3722c0ade80SHans Petter Selasky 3732c0ade80SHans Petter Selasky /* Setup namespace pointer. */ 3742c0ade80SHans Petter Selasky priv->fts.accel_tcp.ns = mlx5_get_flow_namespace( 3752c0ade80SHans Petter Selasky priv->mdev, MLX5_FLOW_NAMESPACE_OFFLOADS); 3762c0ade80SHans Petter Selasky 3772c0ade80SHans Petter Selasky /* 3782c0ade80SHans Petter Selasky * Create flow tables first, because the priority level is 3792c0ade80SHans Petter Selasky * assigned at allocation time. 3802c0ade80SHans Petter Selasky */ 3812c0ade80SHans Petter Selasky for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) { 3822c0ade80SHans Petter Selasky err = accel_fs_tcp_create_table(priv, i); 3832c0ade80SHans Petter Selasky if (err) 3842c0ade80SHans Petter Selasky goto err_destroy_tables; 3852c0ade80SHans Petter Selasky } 3862c0ade80SHans Petter Selasky 3872c0ade80SHans Petter Selasky /* Create default rules last. */ 3882c0ade80SHans Petter Selasky for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) { 3892c0ade80SHans Petter Selasky err = accel_fs_tcp_add_default_rule(priv, i); 3902c0ade80SHans Petter Selasky if (err) 3912c0ade80SHans Petter Selasky goto err_destroy_rules; 3922c0ade80SHans Petter Selasky } 3932c0ade80SHans Petter Selasky return (0); 3942c0ade80SHans Petter Selasky 3952c0ade80SHans Petter Selasky err_destroy_rules: 3962c0ade80SHans Petter Selasky while (i--) 3972c0ade80SHans Petter Selasky mlx5_del_flow_rule(priv->fts.accel_tcp.default_rules[i]); 3982c0ade80SHans Petter Selasky i = MLX5E_ACCEL_FS_TCP_NUM_TYPES; 3992c0ade80SHans Petter Selasky 4002c0ade80SHans Petter Selasky err_destroy_tables: 4012c0ade80SHans Petter Selasky while (i--) 4022c0ade80SHans Petter Selasky accel_fs_tcp_destroy_table(priv, i); 4032c0ade80SHans Petter Selasky return (err); 4042c0ade80SHans Petter Selasky } 405