xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_fs_tcp.c (revision 76ed99ed)
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
accel_fs_tcp_set_ipv4_flow(struct mlx5_flow_spec * spec,struct inpcb * inp)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
accel_fs_tcp_set_ipv6_flow(struct mlx5_flow_spec * spec,struct inpcb * inp)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
mlx5e_accel_fs_del_inpcb(struct mlx5_flow_rule * rule)842c0ade80SHans Petter Selasky mlx5e_accel_fs_del_inpcb(struct mlx5_flow_rule *rule)
852c0ade80SHans Petter Selasky {
86b0b87d91SHans Petter Selasky 	mlx5_del_flow_rule(&rule);
872c0ade80SHans Petter Selasky }
882c0ade80SHans Petter Selasky 
892c0ade80SHans Petter Selasky struct mlx5_flow_rule *
mlx5e_accel_fs_add_inpcb(struct mlx5e_priv * priv,struct inpcb * inp,uint32_t tirn,uint32_t flow_tag,uint16_t vlan_id)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;
101cb054a49SMark Bloch 	struct mlx5_flow_act flow_act = {
102cb054a49SMark Bloch 		.actions = MLX5_FLOW_ACT_ACTIONS_FLOW_TAG,
103cb054a49SMark Bloch 		.flow_tag = flow_tag,
104cb054a49SMark Bloch 	};
1052c0ade80SHans Petter Selasky 
1062c0ade80SHans Petter Selasky 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1072c0ade80SHans Petter Selasky 	if (!spec)
1082c0ade80SHans Petter Selasky 		return (ERR_PTR(-ENOMEM));
1092c0ade80SHans Petter Selasky 
1102c0ade80SHans Petter Selasky 	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1112c0ade80SHans Petter Selasky 
1122c0ade80SHans Petter Selasky 	INP_RLOCK(inp);
1132c0ade80SHans Petter Selasky 	/* Set VLAN ID to match, if any. */
1142c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1152c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1162c0ade80SHans Petter Selasky 	if (vlan_id != MLX5E_ACCEL_FS_ADD_INPCB_NO_VLAN) {
1172c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1182c0ade80SHans Petter Selasky 		MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);
1192c0ade80SHans Petter Selasky 	}
1202c0ade80SHans Petter Selasky 
1212c0ade80SHans Petter Selasky 	/* Set TCP port numbers. */
1222c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1232c0ade80SHans Petter Selasky 	    outer_headers.tcp_dport);
1242c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1252c0ade80SHans Petter Selasky 	    outer_headers.tcp_sport);
1262c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport,
1272c0ade80SHans Petter Selasky 	    ntohs(inp->inp_lport));
1282c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport,
1292c0ade80SHans Petter Selasky 	    ntohs(inp->inp_fport));
1302c0ade80SHans Petter Selasky 
1312c0ade80SHans Petter Selasky 	/* Set IP addresses. */
1322c0ade80SHans Petter Selasky 	switch (INP_SOCKAF(inp->inp_socket)) {
1332c0ade80SHans Petter Selasky #ifdef INET
1342c0ade80SHans Petter Selasky 	case AF_INET:
1352c0ade80SHans Petter Selasky 		accel_fs_tcp_set_ipv4_flow(spec, inp);
1362c0ade80SHans Petter Selasky 		ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP];
1372c0ade80SHans Petter Selasky 		break;
1382c0ade80SHans Petter Selasky #endif
1392c0ade80SHans Petter Selasky #ifdef INET6
1402c0ade80SHans Petter Selasky 	case AF_INET6:
1412c0ade80SHans Petter Selasky 		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
1422c0ade80SHans Petter Selasky 		    IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) {
1432c0ade80SHans Petter Selasky 			accel_fs_tcp_set_ipv4_flow(spec, inp);
1442c0ade80SHans Petter Selasky 			ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP];
1452c0ade80SHans Petter Selasky 		} else {
1462c0ade80SHans Petter Selasky 			accel_fs_tcp_set_ipv6_flow(spec, inp);
1472c0ade80SHans Petter Selasky 			ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV6_TCP];
1482c0ade80SHans Petter Selasky 		}
1492c0ade80SHans Petter Selasky 		break;
1502c0ade80SHans Petter Selasky #endif
1512c0ade80SHans Petter Selasky 	default:
1522c0ade80SHans Petter Selasky 		break;
1532c0ade80SHans Petter Selasky 	}
1542c0ade80SHans Petter Selasky 	INP_RUNLOCK(inp);
1552c0ade80SHans Petter Selasky 
1562c0ade80SHans Petter Selasky 	if (!ft) {
1572c0ade80SHans Petter Selasky 		flow = ERR_PTR(-EINVAL);
1582c0ade80SHans Petter Selasky 		goto out;
1592c0ade80SHans Petter Selasky 	}
1602c0ade80SHans Petter Selasky 
1612c0ade80SHans Petter Selasky 	dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
1622c0ade80SHans Petter Selasky 	dest.tir_num = tirn;
1632c0ade80SHans Petter Selasky 
1642c0ade80SHans Petter Selasky 	flow = mlx5_add_flow_rule(ft->t, spec->match_criteria_enable,
1652c0ade80SHans Petter Selasky 	    spec->match_criteria,
1662c0ade80SHans Petter Selasky 	    spec->match_value,
16776ed99edSMark Bloch 	    MLX5_FLOW_RULE_FWD_ACTION_DEST,
168cb054a49SMark Bloch 	    &flow_act,
1692c0ade80SHans Petter Selasky 	    &dest);
1702c0ade80SHans Petter Selasky out:
1712c0ade80SHans Petter Selasky 	kvfree(spec);
1722c0ade80SHans Petter Selasky 	return (flow);
1732c0ade80SHans Petter Selasky }
1742c0ade80SHans Petter Selasky 
1752c0ade80SHans Petter Selasky static int
accel_fs_tcp_add_default_rule(struct mlx5e_priv * priv,int type)1762c0ade80SHans Petter Selasky accel_fs_tcp_add_default_rule(struct mlx5e_priv *priv, int type)
1772c0ade80SHans Petter Selasky {
1782c0ade80SHans Petter Selasky 	static u32 match_criteria[MLX5_ST_SZ_DW(fte_match_param)];
1792c0ade80SHans Petter Selasky 	static u32 match_value[MLX5_ST_SZ_DW(fte_match_param)];
1802c0ade80SHans Petter Selasky 	struct mlx5_flow_destination dest = {};
1812c0ade80SHans Petter Selasky 	struct mlx5e_accel_fs_tcp *fs_tcp;
1822c0ade80SHans Petter Selasky 	struct mlx5_flow_rule *rule;
183cb054a49SMark Bloch 	struct mlx5_flow_act flow_act = {
184cb054a49SMark Bloch 		.actions = MLX5_FLOW_ACT_ACTIONS_FLOW_TAG,
185cb054a49SMark Bloch 		.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG,
186cb054a49SMark Bloch 	};
1872c0ade80SHans Petter Selasky 
1882c0ade80SHans Petter Selasky 	fs_tcp = &priv->fts.accel_tcp;
1892c0ade80SHans Petter Selasky 
1902c0ade80SHans Petter Selasky 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1912c0ade80SHans Petter Selasky 
1922c0ade80SHans Petter Selasky 	/*
1932c0ade80SHans Petter Selasky 	 * Traffic not matched by flow table rules should be forwarded
1942c0ade80SHans Petter Selasky 	 * to the next flow table in order to not be dropped by the
1952c0ade80SHans Petter Selasky 	 * default action. Refer to the diagram in
1962c0ade80SHans Petter Selasky 	 * mlx5_en_flow_table.c for more information about the order
1972c0ade80SHans Petter Selasky 	 * of flow tables.
1982c0ade80SHans Petter Selasky 	 */
1992c0ade80SHans Petter Selasky 	dest.ft = (type == MLX5E_ACCEL_FS_TCP_NUM_TYPES - 1) ?
2002c0ade80SHans Petter Selasky 	    priv->fts.vlan.t : fs_tcp->tables[type + 1].t;
2012c0ade80SHans Petter Selasky 
2022c0ade80SHans Petter Selasky 	rule = mlx5_add_flow_rule(fs_tcp->tables[type].t, 0, match_criteria, match_value,
20376ed99edSMark Bloch 	    MLX5_FLOW_RULE_FWD_ACTION_DEST, &flow_act, &dest);
2042c0ade80SHans Petter Selasky 	if (IS_ERR(rule))
2052c0ade80SHans Petter Selasky 		return (PTR_ERR(rule));
2062c0ade80SHans Petter Selasky 
2072c0ade80SHans Petter Selasky 	fs_tcp->default_rules[type] = rule;
2082c0ade80SHans Petter Selasky 	return (0);
2092c0ade80SHans Petter Selasky }
2102c0ade80SHans Petter Selasky 
2112c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_NUM_GROUPS	(2)
2122c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_GROUP1_SIZE	(BIT(16) - 1)
2132c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_GROUP2_SIZE	(BIT(0))
2142c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_TABLE_SIZE	(MLX5E_ACCEL_FS_TCP_GROUP1_SIZE +\
2152c0ade80SHans Petter Selasky 					 MLX5E_ACCEL_FS_TCP_GROUP2_SIZE)
2162c0ade80SHans Petter Selasky static int
accel_fs_tcp_create_groups(struct mlx5e_flow_table * ft,int type)2172c0ade80SHans Petter Selasky accel_fs_tcp_create_groups(struct mlx5e_flow_table *ft, int type)
2182c0ade80SHans Petter Selasky {
2192c0ade80SHans Petter Selasky 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
2202c0ade80SHans Petter Selasky 	void *outer_headers_c;
2212c0ade80SHans Petter Selasky 	int ix = 0;
2222c0ade80SHans Petter Selasky 	u32 *in;
2232c0ade80SHans Petter Selasky 	int err;
2242c0ade80SHans Petter Selasky 	u8 *mc;
2252c0ade80SHans Petter Selasky 
2262c0ade80SHans Petter Selasky 	ft->g = kcalloc(MLX5E_ACCEL_FS_TCP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
2272c0ade80SHans Petter Selasky 	in = kvzalloc(inlen, GFP_KERNEL);
2282c0ade80SHans Petter Selasky 	if (!in || !ft->g) {
2292c0ade80SHans Petter Selasky 		kfree(ft->g);
2302c0ade80SHans Petter Selasky 		kvfree(in);
2312c0ade80SHans Petter Selasky 		return (-ENOMEM);
2322c0ade80SHans Petter Selasky 	}
2332c0ade80SHans Petter Selasky 
2342c0ade80SHans Petter Selasky 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
2352c0ade80SHans Petter Selasky 	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
2362c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
2372c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version);
2382c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, cvlan_tag);
2392c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, first_vid);
2402c0ade80SHans Petter Selasky 
2412c0ade80SHans Petter Selasky 	switch (type) {
2422c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV4_TCP:
2432c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV6_TCP:
2442c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport);
2452c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport);
2462c0ade80SHans Petter Selasky 		break;
2472c0ade80SHans Petter Selasky 	default:
2482c0ade80SHans Petter Selasky 		err = -EINVAL;
2492c0ade80SHans Petter Selasky 		goto out;
2502c0ade80SHans Petter Selasky 	}
2512c0ade80SHans Petter Selasky 
2522c0ade80SHans Petter Selasky 	switch (type) {
2532c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV4_TCP:
2542c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
2552c0ade80SHans Petter Selasky 		    src_ipv4_src_ipv6.ipv4_layout.ipv4);
2562c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
2572c0ade80SHans Petter Selasky 		    dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
2582c0ade80SHans Petter Selasky 		break;
2592c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV6_TCP:
2602c0ade80SHans Petter Selasky 		memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
2612c0ade80SHans Petter Selasky 		    src_ipv4_src_ipv6.ipv6_layout.ipv6),
2622c0ade80SHans Petter Selasky 		    0xff, 16);
2632c0ade80SHans Petter Selasky 		memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
2642c0ade80SHans Petter Selasky 		    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
2652c0ade80SHans Petter Selasky 		    0xff, 16);
2662c0ade80SHans Petter Selasky 		break;
2672c0ade80SHans Petter Selasky 	default:
2682c0ade80SHans Petter Selasky 		err = -EINVAL;
2692c0ade80SHans Petter Selasky 		goto out;
2702c0ade80SHans Petter Selasky 	}
2712c0ade80SHans Petter Selasky 
2722c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
2732c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, start_flow_index, ix);
2742c0ade80SHans Petter Selasky 	ix += MLX5E_ACCEL_FS_TCP_GROUP1_SIZE;
2752c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
2762c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
2772c0ade80SHans Petter Selasky 	if (IS_ERR(ft->g[ft->num_groups]))
2782c0ade80SHans Petter Selasky 		goto err;
2792c0ade80SHans Petter Selasky 	ft->num_groups++;
2802c0ade80SHans Petter Selasky 
2812c0ade80SHans Petter Selasky 	/* Default Flow Group */
2822c0ade80SHans Petter Selasky 	memset(in, 0, inlen);
2832c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, start_flow_index, ix);
2842c0ade80SHans Petter Selasky 	ix += MLX5E_ACCEL_FS_TCP_GROUP2_SIZE;
2852c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
2862c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
2872c0ade80SHans Petter Selasky 	if (IS_ERR(ft->g[ft->num_groups]))
2882c0ade80SHans Petter Selasky 		goto err;
2892c0ade80SHans Petter Selasky 	ft->num_groups++;
2902c0ade80SHans Petter Selasky 
2912c0ade80SHans Petter Selasky 	kvfree(in);
2922c0ade80SHans Petter Selasky 	return (0);
2932c0ade80SHans Petter Selasky 
2942c0ade80SHans Petter Selasky err:
2952c0ade80SHans Petter Selasky 	err = PTR_ERR(ft->g[ft->num_groups]);
2962c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = NULL;
2972c0ade80SHans Petter Selasky out:
2982c0ade80SHans Petter Selasky 	kvfree(in);
2992c0ade80SHans Petter Selasky 
3002c0ade80SHans Petter Selasky 	return (err);
3012c0ade80SHans Petter Selasky }
3022c0ade80SHans Petter Selasky 
3032c0ade80SHans Petter Selasky static void
accel_fs_tcp_destroy_groups(struct mlx5e_flow_table * ft)3042c0ade80SHans Petter Selasky accel_fs_tcp_destroy_groups(struct mlx5e_flow_table *ft)
3052c0ade80SHans Petter Selasky {
3062c0ade80SHans Petter Selasky         int i;
3072c0ade80SHans Petter Selasky 
3082c0ade80SHans Petter Selasky         for (i = ft->num_groups - 1; i >= 0; i--) {
3092c0ade80SHans Petter Selasky                 if (!IS_ERR_OR_NULL(ft->g[i]))
3102c0ade80SHans Petter Selasky                         mlx5_destroy_flow_group(ft->g[i]);
3112c0ade80SHans Petter Selasky                 ft->g[i] = NULL;
3122c0ade80SHans Petter Selasky         }
3132c0ade80SHans Petter Selasky         ft->num_groups = 0;
3142c0ade80SHans Petter Selasky }
3152c0ade80SHans Petter Selasky 
3162c0ade80SHans Petter Selasky static int
accel_fs_tcp_create_table(struct mlx5e_priv * priv,int type)3172c0ade80SHans Petter Selasky accel_fs_tcp_create_table(struct mlx5e_priv *priv, int type)
3182c0ade80SHans Petter Selasky {
3192c0ade80SHans Petter Selasky 	struct mlx5e_flow_table *ft = &priv->fts.accel_tcp.tables[type];
3202c0ade80SHans Petter Selasky 	int err;
3212c0ade80SHans Petter Selasky 
3222c0ade80SHans Petter Selasky 	ft->num_groups = 0;
3232c0ade80SHans Petter Selasky 	ft->t = mlx5_create_flow_table(priv->fts.accel_tcp.ns, 0, "tcp",
3242c0ade80SHans Petter Selasky 	    MLX5E_ACCEL_FS_TCP_TABLE_SIZE);
3252c0ade80SHans Petter Selasky 	if (IS_ERR(ft->t)) {
3262c0ade80SHans Petter Selasky 		err = PTR_ERR(ft->t);
3272c0ade80SHans Petter Selasky 		ft->t = NULL;
3282c0ade80SHans Petter Selasky 		return (err);
3292c0ade80SHans Petter Selasky 	}
3302c0ade80SHans Petter Selasky 
3312c0ade80SHans Petter Selasky 	err = accel_fs_tcp_create_groups(ft, type);
3322c0ade80SHans Petter Selasky 	if (err)
3332c0ade80SHans Petter Selasky 		goto err_destroy_flow_table;
3342c0ade80SHans Petter Selasky 
3352c0ade80SHans Petter Selasky 	return (0);
3362c0ade80SHans Petter Selasky 
3372c0ade80SHans Petter Selasky err_destroy_flow_table:
3382c0ade80SHans Petter Selasky 	mlx5_destroy_flow_table(ft->t);
3392c0ade80SHans Petter Selasky 	ft->t = NULL;
3402c0ade80SHans Petter Selasky 	return (err);
3412c0ade80SHans Petter Selasky }
3422c0ade80SHans Petter Selasky 
3432c0ade80SHans Petter Selasky static void
accel_fs_tcp_destroy_table(struct mlx5e_priv * priv,int i)3442c0ade80SHans Petter Selasky accel_fs_tcp_destroy_table(struct mlx5e_priv *priv, int i)
3452c0ade80SHans Petter Selasky {
3462c0ade80SHans Petter Selasky 	struct mlx5e_accel_fs_tcp *fs_tcp;
3472c0ade80SHans Petter Selasky 	struct mlx5e_flow_table *ft;
3482c0ade80SHans Petter Selasky 
3492c0ade80SHans Petter Selasky 	fs_tcp = &priv->fts.accel_tcp;
3502c0ade80SHans Petter Selasky 	ft = fs_tcp->tables + i;
3512c0ade80SHans Petter Selasky 
3522c0ade80SHans Petter Selasky 	accel_fs_tcp_destroy_groups(ft);
3532c0ade80SHans Petter Selasky 	kfree(ft->g);
3542c0ade80SHans Petter Selasky 	ft->g = NULL;
3552c0ade80SHans Petter Selasky 	mlx5_destroy_flow_table(ft->t);
3562c0ade80SHans Petter Selasky 	ft->t = NULL;
3572c0ade80SHans Petter Selasky }
3582c0ade80SHans Petter Selasky 
3592c0ade80SHans Petter Selasky void
mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv * priv)3602c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv *priv)
3612c0ade80SHans Petter Selasky {
3622c0ade80SHans Petter Selasky 	int i;
3632c0ade80SHans Petter Selasky 
3642c0ade80SHans Petter Selasky 	if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version))
3652c0ade80SHans Petter Selasky 		return;
3662c0ade80SHans Petter Selasky 
3672f7e9a8aSHans Petter Selasky 	for (i = 0; i < MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) {
3682f7e9a8aSHans Petter Selasky 		mlx5_del_flow_rule(&priv->fts.accel_tcp.default_rules[i]);
3692c0ade80SHans Petter Selasky 		accel_fs_tcp_destroy_table(priv, i);
3702c0ade80SHans Petter Selasky 	}
3712f7e9a8aSHans Petter Selasky }
3722c0ade80SHans Petter Selasky 
3732c0ade80SHans Petter Selasky int
mlx5e_accel_fs_tcp_create(struct mlx5e_priv * priv)3742c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_create(struct mlx5e_priv *priv)
3752c0ade80SHans Petter Selasky {
3762c0ade80SHans Petter Selasky 	int i, err;
3772c0ade80SHans Petter Selasky 
3782c0ade80SHans Petter Selasky 	if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version))
3792c0ade80SHans Petter Selasky 		return (0);
3802c0ade80SHans Petter Selasky 
3812c0ade80SHans Petter Selasky 	/* Setup namespace pointer. */
3822c0ade80SHans Petter Selasky 	priv->fts.accel_tcp.ns = mlx5_get_flow_namespace(
3832c0ade80SHans Petter Selasky 	    priv->mdev, MLX5_FLOW_NAMESPACE_OFFLOADS);
3842c0ade80SHans Petter Selasky 
3852c0ade80SHans Petter Selasky 	/*
3862c0ade80SHans Petter Selasky 	 * Create flow tables first, because the priority level is
3872c0ade80SHans Petter Selasky 	 * assigned at allocation time.
3882c0ade80SHans Petter Selasky 	 */
3892c0ade80SHans Petter Selasky 	for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) {
3902c0ade80SHans Petter Selasky 		err = accel_fs_tcp_create_table(priv, i);
3912c0ade80SHans Petter Selasky 		if (err)
3922c0ade80SHans Petter Selasky 			goto err_destroy_tables;
3932c0ade80SHans Petter Selasky 	}
3942c0ade80SHans Petter Selasky 
3952c0ade80SHans Petter Selasky 	/* Create default rules last. */
3962c0ade80SHans Petter Selasky 	for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) {
3972c0ade80SHans Petter Selasky 		err = accel_fs_tcp_add_default_rule(priv, i);
3982c0ade80SHans Petter Selasky 		if (err)
3992c0ade80SHans Petter Selasky 			goto err_destroy_rules;
4002c0ade80SHans Petter Selasky 	}
4012c0ade80SHans Petter Selasky 	return (0);
4022c0ade80SHans Petter Selasky 
4032c0ade80SHans Petter Selasky err_destroy_rules:
4042c0ade80SHans Petter Selasky 	while (i--)
405b0b87d91SHans Petter Selasky 		mlx5_del_flow_rule(&priv->fts.accel_tcp.default_rules[i]);
4062c0ade80SHans Petter Selasky 	i = MLX5E_ACCEL_FS_TCP_NUM_TYPES;
4072c0ade80SHans Petter Selasky 
4082c0ade80SHans Petter Selasky err_destroy_tables:
4092c0ade80SHans Petter Selasky 	while (i--)
4102c0ade80SHans Petter Selasky 		accel_fs_tcp_destroy_table(priv, i);
4112c0ade80SHans Petter Selasky 	return (err);
4122c0ade80SHans Petter Selasky }
413