xref: /freebsd/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c (revision 3503aa0cdcb01f141fbc1b60746e840e06ac4987)
1e23731dbSKonstantin Belousov /*-
2e23731dbSKonstantin Belousov  * Copyright (c) 2023 NVIDIA corporation & affiliates.
3e23731dbSKonstantin Belousov  *
4e23731dbSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
5e23731dbSKonstantin Belousov  * modification, are permitted provided that the following conditions
6e23731dbSKonstantin Belousov  * are met:
7e23731dbSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
8e23731dbSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
9e23731dbSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
10e23731dbSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
11e23731dbSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
12e23731dbSKonstantin Belousov  *
13e23731dbSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14e23731dbSKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15e23731dbSKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16e23731dbSKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17e23731dbSKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18e23731dbSKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19e23731dbSKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20e23731dbSKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21e23731dbSKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22e23731dbSKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23e23731dbSKonstantin Belousov  * SUCH DAMAGE.
24e23731dbSKonstantin Belousov  *
25e23731dbSKonstantin Belousov  */
26e23731dbSKonstantin Belousov 
27e23731dbSKonstantin Belousov #include "opt_ipsec.h"
28e23731dbSKonstantin Belousov 
29e23731dbSKonstantin Belousov #include <sys/types.h>
30e23731dbSKonstantin Belousov #include <netinet/in.h>
31e23731dbSKonstantin Belousov #include <sys/socket.h>
32e23731dbSKonstantin Belousov #include <sys/param.h>
33e23731dbSKonstantin Belousov #include <sys/systm.h>
34e23731dbSKonstantin Belousov #include <net/pfkeyv2.h>
35e23731dbSKonstantin Belousov #include <netipsec/key_var.h>
36e23731dbSKonstantin Belousov #include <netipsec/keydb.h>
37e23731dbSKonstantin Belousov #include <netipsec/ipsec.h>
38e23731dbSKonstantin Belousov #include <netipsec/xform.h>
39e23731dbSKonstantin Belousov #include <netipsec/ipsec_offload.h>
40e23731dbSKonstantin Belousov #include <dev/mlx5/fs.h>
41e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_en/en.h>
42e23731dbSKonstantin Belousov #include <dev/mlx5/qp.h>
43e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_accel/ipsec.h>
44e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_core/fs_core.h>
45e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_core/fs_chains.h>
46e23731dbSKonstantin Belousov 
47e23731dbSKonstantin Belousov /*
48e23731dbSKonstantin Belousov  * TX tables are organized differently for Ethernet and for RoCE:
49e23731dbSKonstantin Belousov  *
50e23731dbSKonstantin Belousov  *                       +=========+
51e23731dbSKonstantin Belousov  *       Ethernet Tx     | SA KSPI | match
52e23731dbSKonstantin Belousov  * --------------------->|Flowtable|----->+         +
53e23731dbSKonstantin Belousov  *                       |         |\     |        / \
54e23731dbSKonstantin Belousov  *                       +=========+ |    |       /   \         +=========+     +=========+
55e23731dbSKonstantin Belousov  *                              miss |    |      /     \        |  Status |     |         |
56e23731dbSKonstantin Belousov  *                      DROP<--------+    |---->|Encrypt|------>|Flowtable|---->|  TX NS  |
57e23731dbSKonstantin Belousov  *                                        |      \     /        |         |     |         |
58e23731dbSKonstantin Belousov  *                                        |       \   /         +=========+     +=========+
59e23731dbSKonstantin Belousov  *       +=========+      +=========+     |        \ /               |
60e23731dbSKonstantin Belousov  *  RoCE |  Policy | match|SA ReqId |match|         +                |
61e23731dbSKonstantin Belousov  *  Tx   |Flowtable|----->|Flowtable|---->+                          |
62e23731dbSKonstantin Belousov  *  ---->|IP header|      |ReqId+IP |                                |
63e23731dbSKonstantin Belousov  *       |         |      | header  |--------------------------------+
64e23731dbSKonstantin Belousov  *       +=========+      +=========+         miss                   |
65e23731dbSKonstantin Belousov  *            |                                                      |
66e23731dbSKonstantin Belousov  *            |                   miss                               |
67e23731dbSKonstantin Belousov  *            +-------------------------------------------------------
68e23731dbSKonstantin Belousov  *
69e23731dbSKonstantin Belousov  *                                                                                  +=========+
70e23731dbSKonstantin Belousov  *                                                                                  |   RDMA  |
71e23731dbSKonstantin Belousov  *                                                                                  |Flowtable|
72e23731dbSKonstantin Belousov  *                                                                                  |         |
73e23731dbSKonstantin Belousov  * Rx Tables and rules:                                                             +=========+
74e23731dbSKonstantin Belousov  *                                             +                                        /
75e23731dbSKonstantin Belousov  *       +=========+      +=========+         / \         +=========+      +=========+ /match
76e23731dbSKonstantin Belousov  *       |  Policy |      |   SA    |        /   \        |  Status |      |  RoCE   |/
77e23731dbSKonstantin Belousov  *  ---->|Flowtable| match|Flowtable| match /     \       |Flowtable|----->|Flowtable|
78e23731dbSKonstantin Belousov  *       |IP header|----->|IP header|----->|Decrypt|----->|         |      | Roce V2 |
79e23731dbSKonstantin Belousov  *       |         |      |+ESP+SPI |       \     /       |         |      | UDP port|\
80e23731dbSKonstantin Belousov  *       +=========+      +=========+        \   /        +=========+      +=========+ \miss
81e23731dbSKonstantin Belousov  *             |               |              \ /                                       \
82e23731dbSKonstantin Belousov  *             |               |               +                                      +=========+
83e23731dbSKonstantin Belousov  *             |     miss      |          miss                                       | Ethernet|
84e23731dbSKonstantin Belousov  *             +--------------->---------------------------------------------------->|  RX NS  |
85e23731dbSKonstantin Belousov  *                                                                                   |         |
86e23731dbSKonstantin Belousov  *                                                                                   +=========+
87e23731dbSKonstantin Belousov  *
88e23731dbSKonstantin Belousov  */
89e23731dbSKonstantin Belousov 
90e23731dbSKonstantin Belousov #define NUM_IPSEC_FTE BIT(15)
91e23731dbSKonstantin Belousov #define IPSEC_TUNNEL_DEFAULT_TTL 0x40
92e23731dbSKonstantin Belousov 
93e23731dbSKonstantin Belousov struct mlx5e_ipsec_fc {
94e23731dbSKonstantin Belousov 	struct mlx5_fc *cnt;
95e23731dbSKonstantin Belousov 	struct mlx5_fc *drop;
96e23731dbSKonstantin Belousov };
97e23731dbSKonstantin Belousov 
98e23731dbSKonstantin Belousov struct mlx5e_ipsec_ft {
99e23731dbSKonstantin Belousov 	struct mutex mutex; /* Protect changes to this struct */
100e23731dbSKonstantin Belousov 	struct mlx5_flow_table *pol;
101e23731dbSKonstantin Belousov 	struct mlx5_flow_table *sa_kspi;
102e23731dbSKonstantin Belousov 	struct mlx5_flow_table *sa;
103e23731dbSKonstantin Belousov 	struct mlx5_flow_table *status;
104e23731dbSKonstantin Belousov 	u32 refcnt;
105e23731dbSKonstantin Belousov };
106e23731dbSKonstantin Belousov 
107e23731dbSKonstantin Belousov struct mlx5e_ipsec_tx_roce {
108e23731dbSKonstantin Belousov 	struct mlx5_flow_group *g;
109e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
110e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
111e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns;
112e23731dbSKonstantin Belousov };
113e23731dbSKonstantin Belousov 
114e23731dbSKonstantin Belousov struct mlx5e_ipsec_miss {
115e23731dbSKonstantin Belousov 	struct mlx5_flow_group *group;
116e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
117e23731dbSKonstantin Belousov };
118e23731dbSKonstantin Belousov 
119e23731dbSKonstantin Belousov struct mlx5e_ipsec_tx {
120e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_ft ft;
121e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_miss pol;
122e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_miss kspi_miss;
123e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule status;
124e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule kspi_bypass_rule; /*rule for IPSEC bypass*/
125e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns;
126e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_fc *fc;
127e23731dbSKonstantin Belousov 	struct mlx5_fs_chains *chains;
128e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx_roce roce;
129e23731dbSKonstantin Belousov };
130e23731dbSKonstantin Belousov 
131e23731dbSKonstantin Belousov struct mlx5e_ipsec_rx_roce {
132e23731dbSKonstantin Belousov 	struct mlx5_flow_group *g;
133e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
134e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
135e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_miss roce_miss;
136e23731dbSKonstantin Belousov 
137e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft_rdma;
138e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns_rdma;
139e23731dbSKonstantin Belousov };
140e23731dbSKonstantin Belousov 
141e23731dbSKonstantin Belousov struct mlx5e_ipsec_rx {
142e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_ft ft;
143e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_miss pol;
144e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_miss sa;
145e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule status;
146e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns;
147e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_fc *fc;
148e23731dbSKonstantin Belousov 	struct mlx5_fs_chains *chains;
149e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rx_roce roce;
150e23731dbSKonstantin Belousov };
151e23731dbSKonstantin Belousov 
152e23731dbSKonstantin Belousov static void setup_fte_reg_a_with_tag(struct mlx5_flow_spec *spec,
153e23731dbSKonstantin Belousov                                      u16 kspi);
154e23731dbSKonstantin Belousov static void setup_fte_reg_a_no_tag(struct mlx5_flow_spec *spec);
155e23731dbSKonstantin Belousov 
setup_fte_no_frags(struct mlx5_flow_spec * spec)156e23731dbSKonstantin Belousov static void setup_fte_no_frags(struct mlx5_flow_spec *spec)
157e23731dbSKonstantin Belousov {
158e23731dbSKonstantin Belousov 	/* Non fragmented */
159e23731dbSKonstantin Belousov 	spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
160e23731dbSKonstantin Belousov 
161e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.frag);
162e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.frag, 0);
163e23731dbSKonstantin Belousov }
164e23731dbSKonstantin Belousov 
setup_fte_esp(struct mlx5_flow_spec * spec)165e23731dbSKonstantin Belousov static void setup_fte_esp(struct mlx5_flow_spec *spec)
166e23731dbSKonstantin Belousov {
167e23731dbSKonstantin Belousov 	/* ESP header */
168e23731dbSKonstantin Belousov 	spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
169e23731dbSKonstantin Belousov 
170e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
171e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_ESP);
172e23731dbSKonstantin Belousov }
173e23731dbSKonstantin Belousov 
setup_fte_spi(struct mlx5_flow_spec * spec,u32 spi,bool encap)174e23731dbSKonstantin Belousov static void setup_fte_spi(struct mlx5_flow_spec *spec, u32 spi, bool encap)
175e23731dbSKonstantin Belousov {
176e23731dbSKonstantin Belousov 	/* SPI number */
177e23731dbSKonstantin Belousov 	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
178e23731dbSKonstantin Belousov 
179e23731dbSKonstantin Belousov 	if (encap) {
180e23731dbSKonstantin Belousov 		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.inner_esp_spi);
181e23731dbSKonstantin Belousov 		MLX5_SET(fte_match_param, spec->match_value, misc_parameters.inner_esp_spi, spi);
182e23731dbSKonstantin Belousov 	} else {
183e23731dbSKonstantin Belousov 		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.outer_esp_spi);
184e23731dbSKonstantin Belousov 		MLX5_SET(fte_match_param, spec->match_value, misc_parameters.outer_esp_spi, spi);
185e23731dbSKonstantin Belousov 	}
186e23731dbSKonstantin Belousov }
187e23731dbSKonstantin Belousov 
188205263acSAriel Ehrenberg static void
setup_fte_vid(struct mlx5_flow_spec * spec,u16 vid)189205263acSAriel Ehrenberg setup_fte_vid(struct mlx5_flow_spec *spec, u16 vid)
190205263acSAriel Ehrenberg {
191205263acSAriel Ehrenberg 	/* virtual lan tag */
192205263acSAriel Ehrenberg 	spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
193205263acSAriel Ehrenberg 
194205263acSAriel Ehrenberg 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
195205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag);
196205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_value,
197205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag, 1);
198205263acSAriel Ehrenberg 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
199205263acSAriel Ehrenberg 	    outer_headers.first_vid);
200205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid,
201205263acSAriel Ehrenberg 	    vid);
202205263acSAriel Ehrenberg }
203205263acSAriel Ehrenberg 
204205263acSAriel Ehrenberg static void
clear_fte_vid(struct mlx5_flow_spec * spec)205205263acSAriel Ehrenberg clear_fte_vid(struct mlx5_flow_spec *spec)
206205263acSAriel Ehrenberg {
207205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_criteria,
208205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag, 0);
209205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_value,
210205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag, 0);
211205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_criteria,
212205263acSAriel Ehrenberg 	    outer_headers.first_vid, 0);
213205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_value,
214205263acSAriel Ehrenberg 	    outer_headers.first_vid, 0);
215205263acSAriel Ehrenberg }
216205263acSAriel Ehrenberg 
217205263acSAriel Ehrenberg static void
setup_fte_no_vid(struct mlx5_flow_spec * spec)218205263acSAriel Ehrenberg setup_fte_no_vid(struct mlx5_flow_spec *spec)
219205263acSAriel Ehrenberg {
220205263acSAriel Ehrenberg 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
221205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag);
222205263acSAriel Ehrenberg 	MLX5_SET(fte_match_param, spec->match_value,
223205263acSAriel Ehrenberg 	    outer_headers.cvlan_tag, 0);
224205263acSAriel Ehrenberg }
225205263acSAriel Ehrenberg 
226e23731dbSKonstantin Belousov static struct mlx5_fs_chains *
ipsec_chains_create(struct mlx5_core_dev * mdev,struct mlx5_flow_table * miss_ft,enum mlx5_flow_namespace_type ns,int base_prio,int base_level,struct mlx5_flow_table ** root_ft)227e23731dbSKonstantin Belousov ipsec_chains_create(struct mlx5_core_dev *mdev, struct mlx5_flow_table *miss_ft,
228e23731dbSKonstantin Belousov 		    enum mlx5_flow_namespace_type ns, int base_prio,
229e23731dbSKonstantin Belousov 		    int base_level, struct mlx5_flow_table **root_ft)
230e23731dbSKonstantin Belousov {
231e23731dbSKonstantin Belousov 	struct mlx5_chains_attr attr = {};
232e23731dbSKonstantin Belousov 	struct mlx5_fs_chains *chains;
233e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
234e23731dbSKonstantin Belousov 	int err;
235e23731dbSKonstantin Belousov 
236e23731dbSKonstantin Belousov 	attr.flags = MLX5_CHAINS_AND_PRIOS_SUPPORTED |
237e23731dbSKonstantin Belousov 		     MLX5_CHAINS_IGNORE_FLOW_LEVEL_SUPPORTED;
238e23731dbSKonstantin Belousov 	attr.max_grp_num = 2;
239e23731dbSKonstantin Belousov 	attr.default_ft = miss_ft;
240e23731dbSKonstantin Belousov 	attr.ns = ns;
241e23731dbSKonstantin Belousov 	attr.fs_base_prio = base_prio;
242e23731dbSKonstantin Belousov 	attr.fs_base_level = base_level;
243e23731dbSKonstantin Belousov 	chains = mlx5_chains_create(mdev, &attr);
244e23731dbSKonstantin Belousov 	if (IS_ERR(chains))
245e23731dbSKonstantin Belousov 		return chains;
246e23731dbSKonstantin Belousov 
247e23731dbSKonstantin Belousov 	/* Create chain 0, prio 1, level 0 to connect chains to prev in fs_core */
248e23731dbSKonstantin Belousov 	ft = mlx5_chains_get_table(chains, 0, 1, 0);
249e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
250e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
251e23731dbSKonstantin Belousov 		goto err_chains_get;
252e23731dbSKonstantin Belousov 	}
253e23731dbSKonstantin Belousov 
254e23731dbSKonstantin Belousov 	*root_ft = ft;
255e23731dbSKonstantin Belousov 	return chains;
256e23731dbSKonstantin Belousov 
257e23731dbSKonstantin Belousov err_chains_get:
258e23731dbSKonstantin Belousov 	mlx5_chains_destroy(chains);
259e23731dbSKonstantin Belousov 	return ERR_PTR(err);
260e23731dbSKonstantin Belousov }
261e23731dbSKonstantin Belousov 
ipsec_chains_destroy(struct mlx5_fs_chains * chains)262e23731dbSKonstantin Belousov static void ipsec_chains_destroy(struct mlx5_fs_chains *chains)
263e23731dbSKonstantin Belousov {
264e23731dbSKonstantin Belousov 	mlx5_chains_put_table(chains, 0, 1, 0);
265e23731dbSKonstantin Belousov 	mlx5_chains_destroy(chains);
266e23731dbSKonstantin Belousov }
267e23731dbSKonstantin Belousov 
268e23731dbSKonstantin Belousov static struct mlx5_flow_table *
ipsec_chains_get_table(struct mlx5_fs_chains * chains,u32 prio)269e23731dbSKonstantin Belousov ipsec_chains_get_table(struct mlx5_fs_chains *chains, u32 prio)
270e23731dbSKonstantin Belousov {
271e23731dbSKonstantin Belousov 	return mlx5_chains_get_table(chains, 0, prio + 1, 0);
272e23731dbSKonstantin Belousov }
273e23731dbSKonstantin Belousov 
ipsec_chains_put_table(struct mlx5_fs_chains * chains,u32 prio)274e23731dbSKonstantin Belousov static void ipsec_chains_put_table(struct mlx5_fs_chains *chains, u32 prio)
275e23731dbSKonstantin Belousov {
276e23731dbSKonstantin Belousov 	mlx5_chains_put_table(chains, 0, prio + 1, 0);
277e23731dbSKonstantin Belousov }
278e23731dbSKonstantin Belousov 
ipsec_rx_ft_create(struct mlx5_flow_namespace * ns,int level,int prio,int max_num_groups)279e23731dbSKonstantin Belousov static struct mlx5_flow_table *ipsec_rx_ft_create(struct mlx5_flow_namespace *ns,
280e23731dbSKonstantin Belousov 						  int level, int prio,
281e23731dbSKonstantin Belousov 						  int max_num_groups)
282e23731dbSKonstantin Belousov {
283e23731dbSKonstantin Belousov 	struct mlx5_flow_table_attr ft_attr = {};
284e23731dbSKonstantin Belousov 
285e23731dbSKonstantin Belousov 	ft_attr.max_fte = NUM_IPSEC_FTE;
286e23731dbSKonstantin Belousov 	ft_attr.level = level;
287e23731dbSKonstantin Belousov 	ft_attr.prio = prio;
288e23731dbSKonstantin Belousov 	ft_attr.autogroup.max_num_groups = max_num_groups;
289e23731dbSKonstantin Belousov 	ft_attr.autogroup.num_reserved_entries = 1;
290e23731dbSKonstantin Belousov 
291e23731dbSKonstantin Belousov 	return mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
292e23731dbSKonstantin Belousov }
293e23731dbSKonstantin Belousov 
ipsec_miss_create(struct mlx5_core_dev * mdev,struct mlx5_flow_table * ft,struct mlx5e_ipsec_miss * miss,struct mlx5_flow_destination * dest)294e23731dbSKonstantin Belousov static int ipsec_miss_create(struct mlx5_core_dev *mdev,
295e23731dbSKonstantin Belousov 			     struct mlx5_flow_table *ft,
296e23731dbSKonstantin Belousov 			     struct mlx5e_ipsec_miss *miss,
297e23731dbSKonstantin Belousov 			     struct mlx5_flow_destination *dest)
298e23731dbSKonstantin Belousov {
299e23731dbSKonstantin Belousov 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
300e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
301e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
302e23731dbSKonstantin Belousov 	u32 *flow_group_in;
303e23731dbSKonstantin Belousov 	int err = 0;
304e23731dbSKonstantin Belousov 
305e23731dbSKonstantin Belousov 	flow_group_in = kvzalloc(inlen, GFP_KERNEL);
306e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
307e23731dbSKonstantin Belousov 	if (!flow_group_in || !spec) {
308e23731dbSKonstantin Belousov 		err = -ENOMEM;
309e23731dbSKonstantin Belousov 		goto out;
310e23731dbSKonstantin Belousov 	}
311e23731dbSKonstantin Belousov 
312e23731dbSKonstantin Belousov 	/* Create miss_group */
313e23731dbSKonstantin Belousov 	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
314e23731dbSKonstantin Belousov 	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
315e23731dbSKonstantin Belousov 	miss->group = mlx5_create_flow_group(ft, flow_group_in);
316e23731dbSKonstantin Belousov 	if (IS_ERR(miss->group)) {
317e23731dbSKonstantin Belousov 		err = PTR_ERR(miss->group);
318e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to create IPsec miss_group err=%d\n",
319e23731dbSKonstantin Belousov 			      err);
320e23731dbSKonstantin Belousov 		goto out;
321e23731dbSKonstantin Belousov 	}
322e23731dbSKonstantin Belousov 
323e23731dbSKonstantin Belousov 	if (dest)
324e23731dbSKonstantin Belousov 		flow_act.action = MLX5_FLOW_RULE_FWD_ACTION_DEST;
325e23731dbSKonstantin Belousov 	else
326e23731dbSKonstantin Belousov 		flow_act.action = MLX5_FLOW_RULE_FWD_ACTION_DROP;
327e23731dbSKonstantin Belousov 	/* Create miss rule */
328e23731dbSKonstantin Belousov 	miss->rule = mlx5_add_flow_rules(ft, NULL, &flow_act, dest, 1);
329e23731dbSKonstantin Belousov 	if (IS_ERR(miss->rule)) {
330e23731dbSKonstantin Belousov 		mlx5_destroy_flow_group(miss->group);
331e23731dbSKonstantin Belousov 		err = PTR_ERR(miss->rule);
332e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to create IPsec miss_rule err=%d\n",
333e23731dbSKonstantin Belousov 			      err);
334e23731dbSKonstantin Belousov 		goto out;
335e23731dbSKonstantin Belousov 	}
336e23731dbSKonstantin Belousov out:
337e23731dbSKonstantin Belousov 	kvfree(flow_group_in);
338e23731dbSKonstantin Belousov 	kvfree(spec);
339e23731dbSKonstantin Belousov 	return err;
340e23731dbSKonstantin Belousov }
341e23731dbSKonstantin Belousov 
setup_modify_header(struct mlx5_core_dev * mdev,u32 val,u8 dir,struct mlx5_flow_act * flow_act)342e23731dbSKonstantin Belousov static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir,
343e23731dbSKonstantin Belousov                                struct mlx5_flow_act *flow_act)
344e23731dbSKonstantin Belousov {
345e23731dbSKonstantin Belousov         u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
346e23731dbSKonstantin Belousov         enum mlx5_flow_namespace_type ns_type;
347e23731dbSKonstantin Belousov         struct mlx5_modify_hdr *modify_hdr;
348e23731dbSKonstantin Belousov 
349e23731dbSKonstantin Belousov         MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
350e23731dbSKonstantin Belousov         switch (dir) {
351e23731dbSKonstantin Belousov         case IPSEC_DIR_INBOUND:
352e23731dbSKonstantin Belousov                 MLX5_SET(set_action_in, action, field,
353e23731dbSKonstantin Belousov                          MLX5_ACTION_IN_FIELD_METADATA_REG_B);
354e23731dbSKonstantin Belousov                 ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
355e23731dbSKonstantin Belousov                 break;
356e23731dbSKonstantin Belousov         case IPSEC_DIR_OUTBOUND:
357e23731dbSKonstantin Belousov                 MLX5_SET(set_action_in, action, field,
358e23731dbSKonstantin Belousov                          MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
359e23731dbSKonstantin Belousov                 ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
360e23731dbSKonstantin Belousov                 break;
361e23731dbSKonstantin Belousov         default:
362e23731dbSKonstantin Belousov                 return -EINVAL;
363e23731dbSKonstantin Belousov         }
364e23731dbSKonstantin Belousov 
365e23731dbSKonstantin Belousov         MLX5_SET(set_action_in, action, data, val);
366e23731dbSKonstantin Belousov         MLX5_SET(set_action_in, action, offset, 0);
367e23731dbSKonstantin Belousov         MLX5_SET(set_action_in, action, length, 32);
368e23731dbSKonstantin Belousov 
369e23731dbSKonstantin Belousov         modify_hdr = mlx5_modify_header_alloc(mdev, ns_type, 1, action);
370e23731dbSKonstantin Belousov         if (IS_ERR(modify_hdr)) {
371e23731dbSKonstantin Belousov                 mlx5_core_err(mdev, "Failed to allocate modify_header %ld\n",
372e23731dbSKonstantin Belousov                               PTR_ERR(modify_hdr));
373e23731dbSKonstantin Belousov                 return PTR_ERR(modify_hdr);
374e23731dbSKonstantin Belousov         }
375e23731dbSKonstantin Belousov 
376e23731dbSKonstantin Belousov         flow_act->modify_hdr = modify_hdr;
377e23731dbSKonstantin Belousov         flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
378e23731dbSKonstantin Belousov         return 0;
379e23731dbSKonstantin Belousov }
380e23731dbSKonstantin Belousov 
381e23731dbSKonstantin Belousov static int
setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs * attrs,struct mlx5_pkt_reformat_params * reformat_params)382e23731dbSKonstantin Belousov setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
383e23731dbSKonstantin Belousov 			     struct mlx5_pkt_reformat_params *reformat_params)
384e23731dbSKonstantin Belousov {
385e23731dbSKonstantin Belousov 	struct udphdr *udphdr;
386e23731dbSKonstantin Belousov 	size_t bfflen = 16;
387e23731dbSKonstantin Belousov 	char *reformatbf;
388e23731dbSKonstantin Belousov 	__be32 spi;
389e23731dbSKonstantin Belousov 	void *hdr;
390e23731dbSKonstantin Belousov 
391*3503aa0cSAriel Ehrenberg 	if (attrs->family == AF_INET) {
392e23731dbSKonstantin Belousov 		if (attrs->encap)
393e23731dbSKonstantin Belousov 			reformat_params->type = MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV4;
394e23731dbSKonstantin Belousov 		else
395e23731dbSKonstantin Belousov 			reformat_params->type = MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
396*3503aa0cSAriel Ehrenberg 	} else {
397*3503aa0cSAriel Ehrenberg 		if (attrs->encap)
398*3503aa0cSAriel Ehrenberg 			reformat_params->type =
399*3503aa0cSAriel Ehrenberg 			    MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV6;
400e23731dbSKonstantin Belousov 		else
401e23731dbSKonstantin Belousov 			reformat_params->type =
402e23731dbSKonstantin Belousov 			    MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
403*3503aa0cSAriel Ehrenberg 	}
404e23731dbSKonstantin Belousov 
405e23731dbSKonstantin Belousov 	if (attrs->encap)
406e23731dbSKonstantin Belousov 		bfflen += sizeof(*udphdr);
407e23731dbSKonstantin Belousov 	reformatbf = kzalloc(bfflen, GFP_KERNEL);
408e23731dbSKonstantin Belousov 	if (!reformatbf)
409e23731dbSKonstantin Belousov 		return -ENOMEM;
410e23731dbSKonstantin Belousov 
411e23731dbSKonstantin Belousov 	hdr = reformatbf;
412e23731dbSKonstantin Belousov 	if (attrs->encap) {
413e23731dbSKonstantin Belousov 		udphdr = (struct udphdr *)reformatbf;
414e23731dbSKonstantin Belousov 		udphdr->uh_sport = attrs->sport;
415e23731dbSKonstantin Belousov 		udphdr->uh_dport = attrs->dport;
416e23731dbSKonstantin Belousov 		hdr += sizeof(*udphdr);
417e23731dbSKonstantin Belousov 	}
418e23731dbSKonstantin Belousov 
419e23731dbSKonstantin Belousov 	/* convert to network format */
420e23731dbSKonstantin Belousov 	spi = htonl(attrs->spi);
421e23731dbSKonstantin Belousov 	memcpy(hdr, &spi, 4);
422e23731dbSKonstantin Belousov 
423e23731dbSKonstantin Belousov 	reformat_params->param_0 = attrs->authsize;
424e23731dbSKonstantin Belousov 	reformat_params->size = bfflen;
425e23731dbSKonstantin Belousov 	reformat_params->data = reformatbf;
426e23731dbSKonstantin Belousov 
427e23731dbSKonstantin Belousov 	return 0;
428e23731dbSKonstantin Belousov }
429e23731dbSKonstantin Belousov 
setup_pkt_reformat(struct mlx5_core_dev * mdev,struct mlx5_accel_esp_xfrm_attrs * attrs,struct mlx5_flow_act * flow_act)430e23731dbSKonstantin Belousov static int setup_pkt_reformat(struct mlx5_core_dev *mdev,
431e23731dbSKonstantin Belousov 			      struct mlx5_accel_esp_xfrm_attrs *attrs,
432e23731dbSKonstantin Belousov 			      struct mlx5_flow_act *flow_act)
433e23731dbSKonstantin Belousov {
434e23731dbSKonstantin Belousov 	enum mlx5_flow_namespace_type ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
435e23731dbSKonstantin Belousov 	struct mlx5_pkt_reformat_params reformat_params = {};
436e23731dbSKonstantin Belousov 	struct mlx5_pkt_reformat *pkt_reformat;
437e23731dbSKonstantin Belousov 	int ret;
438e23731dbSKonstantin Belousov 
439e23731dbSKonstantin Belousov 	if (attrs->dir == IPSEC_DIR_INBOUND) {
440e23731dbSKonstantin Belousov 		if (attrs->encap)
441e23731dbSKonstantin Belousov 			reformat_params.type = MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT_OVER_UDP;
442e23731dbSKonstantin Belousov 		else
443e23731dbSKonstantin Belousov 			reformat_params.type = MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
444e23731dbSKonstantin Belousov 		ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
445e23731dbSKonstantin Belousov 		goto cmd;
446e23731dbSKonstantin Belousov 	}
447e23731dbSKonstantin Belousov 
448e23731dbSKonstantin Belousov 	ret = setup_pkt_transport_reformat(attrs, &reformat_params);
449e23731dbSKonstantin Belousov 	if (ret)
450e23731dbSKonstantin Belousov 		return ret;
451e23731dbSKonstantin Belousov cmd:
452e23731dbSKonstantin Belousov 	pkt_reformat =
453e23731dbSKonstantin Belousov 		mlx5_packet_reformat_alloc(mdev, &reformat_params, ns_type);
454e23731dbSKonstantin Belousov 	if (reformat_params.data)
455e23731dbSKonstantin Belousov 		kfree(reformat_params.data);
456e23731dbSKonstantin Belousov 	if (IS_ERR(pkt_reformat))
457e23731dbSKonstantin Belousov 		return PTR_ERR(pkt_reformat);
458e23731dbSKonstantin Belousov 
459e23731dbSKonstantin Belousov 	flow_act->pkt_reformat = pkt_reformat;
460e23731dbSKonstantin Belousov 	flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
461e23731dbSKonstantin Belousov 	return 0;
462e23731dbSKonstantin Belousov }
463e23731dbSKonstantin Belousov 
setup_fte_addr4(struct mlx5_flow_spec * spec,__be32 * saddr,__be32 * daddr)464e23731dbSKonstantin Belousov static void setup_fte_addr4(struct mlx5_flow_spec *spec, __be32 *saddr,
465e23731dbSKonstantin Belousov                             __be32 *daddr)
466e23731dbSKonstantin Belousov {
467e23731dbSKonstantin Belousov         spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
468e23731dbSKonstantin Belousov 
469e23731dbSKonstantin Belousov         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
470e23731dbSKonstantin Belousov         MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 4);
471e23731dbSKonstantin Belousov 
472e23731dbSKonstantin Belousov         memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
473e23731dbSKonstantin Belousov                             outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), saddr, 4);
474e23731dbSKonstantin Belousov         memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
475e23731dbSKonstantin Belousov                             outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), daddr, 4);
476e23731dbSKonstantin Belousov         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
477e23731dbSKonstantin Belousov                          outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
478e23731dbSKonstantin Belousov         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
479e23731dbSKonstantin Belousov                          outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
480e23731dbSKonstantin Belousov }
481e23731dbSKonstantin Belousov 
setup_fte_addr6(struct mlx5_flow_spec * spec,__be32 * saddr,__be32 * daddr)482e23731dbSKonstantin Belousov static void setup_fte_addr6(struct mlx5_flow_spec *spec, __be32 *saddr,
483e23731dbSKonstantin Belousov                             __be32 *daddr)
484e23731dbSKonstantin Belousov {
485e23731dbSKonstantin Belousov         spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
486e23731dbSKonstantin Belousov 
487e23731dbSKonstantin Belousov         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
488e23731dbSKonstantin Belousov         MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 6);
489e23731dbSKonstantin Belousov 
490e23731dbSKonstantin Belousov         memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
491e23731dbSKonstantin Belousov                             outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), saddr, 16);
492e23731dbSKonstantin Belousov         memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
493e23731dbSKonstantin Belousov                             outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), daddr, 16);
494e23731dbSKonstantin Belousov         memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
495e23731dbSKonstantin Belousov                             outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 0xff, 16);
496e23731dbSKonstantin Belousov         memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
497e23731dbSKonstantin Belousov                             outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 0xff, 16);
498e23731dbSKonstantin Belousov }
499e23731dbSKonstantin Belousov 
rx_add_rule(struct mlx5e_ipsec_sa_entry * sa_entry)500e23731dbSKonstantin Belousov static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
501e23731dbSKonstantin Belousov {
502e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
503e23731dbSKonstantin Belousov 	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
504e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
505e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
506e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest[2] = {};
507e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
508e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
509e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
510e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rx *rx;
511e23731dbSKonstantin Belousov 	struct mlx5_fc *counter;
512e23731dbSKonstantin Belousov 	int err;
513e23731dbSKonstantin Belousov 
514e23731dbSKonstantin Belousov 	rx = (attrs->family == AF_INET) ? ipsec->rx_ipv4 : ipsec->rx_ipv6;
515e23731dbSKonstantin Belousov 
516e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
517e23731dbSKonstantin Belousov 	if (!spec)
518e23731dbSKonstantin Belousov 		return -ENOMEM;
519e23731dbSKonstantin Belousov 
520e23731dbSKonstantin Belousov 	if (!attrs->drop) {
521e23731dbSKonstantin Belousov 		err = setup_modify_header(mdev, sa_entry->kspi | BIT(31), IPSEC_DIR_INBOUND,
522e23731dbSKonstantin Belousov 					  &flow_act);
523e23731dbSKonstantin Belousov 		if (err)
524e23731dbSKonstantin Belousov 			goto err_mod_header;
525e23731dbSKonstantin Belousov 	}
526e23731dbSKonstantin Belousov 
527e23731dbSKonstantin Belousov 	err = setup_pkt_reformat(mdev, attrs, &flow_act);
528e23731dbSKonstantin Belousov 	if (err)
529e23731dbSKonstantin Belousov 		goto err_pkt_reformat;
530e23731dbSKonstantin Belousov 
531e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
532e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
533e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
534e23731dbSKonstantin Belousov 		goto err_add_cnt;
535e23731dbSKonstantin Belousov 	}
536e23731dbSKonstantin Belousov 
537e23731dbSKonstantin Belousov 	flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_IPSEC;
538e23731dbSKonstantin Belousov 	flow_act.crypto.op = MLX5_FLOW_ACT_CRYPTO_OP_DECRYPT;
539e23731dbSKonstantin Belousov 	flow_act.crypto.obj_id = sa_entry->ipsec_obj_id;
540e23731dbSKonstantin Belousov 	flow_act.flags |= FLOW_ACT_NO_APPEND;
541e23731dbSKonstantin Belousov 
542e23731dbSKonstantin Belousov 	flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
543e23731dbSKonstantin Belousov 		MLX5_FLOW_CONTEXT_ACTION_COUNT;
544e23731dbSKonstantin Belousov 
545e23731dbSKonstantin Belousov 	if (attrs->drop)
546e23731dbSKonstantin Belousov 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
547e23731dbSKonstantin Belousov 	else
548e23731dbSKonstantin Belousov 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
549e23731dbSKonstantin Belousov 
550e23731dbSKonstantin Belousov 	dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
551e23731dbSKonstantin Belousov 	dest[0].ft = rx->ft.status;
552e23731dbSKonstantin Belousov 	dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
553e23731dbSKonstantin Belousov 	dest[1].counter_id = mlx5_fc_id(counter);
554e23731dbSKonstantin Belousov 
555205263acSAriel Ehrenberg 	if (attrs->family == AF_INET)
556205263acSAriel Ehrenberg 		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
557205263acSAriel Ehrenberg 	else
558205263acSAriel Ehrenberg 		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
559205263acSAriel Ehrenberg 
560205263acSAriel Ehrenberg 	if (!attrs->encap)
561205263acSAriel Ehrenberg 		setup_fte_esp(spec);
562205263acSAriel Ehrenberg 
563205263acSAriel Ehrenberg 	setup_fte_spi(spec, attrs->spi, attrs->encap);
564205263acSAriel Ehrenberg 	setup_fte_no_frags(spec);
565205263acSAriel Ehrenberg 
566205263acSAriel Ehrenberg 	if (sa_entry->vid != VLAN_NONE)
567205263acSAriel Ehrenberg 		setup_fte_vid(spec, sa_entry->vid);
568205263acSAriel Ehrenberg 	else
569205263acSAriel Ehrenberg 		setup_fte_no_vid(spec);
570205263acSAriel Ehrenberg 
571e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(rx->ft.sa, spec, &flow_act, dest, 2);
572e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
573e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
574e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to add RX ipsec rule err=%d\n", err);
575e23731dbSKonstantin Belousov 		goto err_add_flow;
576e23731dbSKonstantin Belousov 	}
577205263acSAriel Ehrenberg 	ipsec_rule->rule = rule;
578205263acSAriel Ehrenberg 
579205263acSAriel Ehrenberg 	/* Add another rule for zero vid */
580205263acSAriel Ehrenberg 	if (sa_entry->vid == VLAN_NONE) {
581205263acSAriel Ehrenberg 		clear_fte_vid(spec);
582205263acSAriel Ehrenberg 		setup_fte_vid(spec, 0);
583205263acSAriel Ehrenberg 		rule = mlx5_add_flow_rules(rx->ft.sa, spec, &flow_act, dest, 2);
584205263acSAriel Ehrenberg 		if (IS_ERR(rule)) {
585205263acSAriel Ehrenberg 			err = PTR_ERR(rule);
586205263acSAriel Ehrenberg 			mlx5_core_err(mdev,
587205263acSAriel Ehrenberg 			    "fail to add RX ipsec zero vid rule err=%d\n",
588205263acSAriel Ehrenberg 			    err);
589205263acSAriel Ehrenberg 			goto err_add_flow;
590205263acSAriel Ehrenberg 		}
591205263acSAriel Ehrenberg 		ipsec_rule->vid_zero_rule = rule;
592205263acSAriel Ehrenberg 	}
593e23731dbSKonstantin Belousov 
594e23731dbSKonstantin Belousov 	kvfree(spec);
595e23731dbSKonstantin Belousov 	ipsec_rule->fc = counter;
596e23731dbSKonstantin Belousov 	ipsec_rule->modify_hdr = flow_act.modify_hdr;
597e23731dbSKonstantin Belousov 	ipsec_rule->pkt_reformat = flow_act.pkt_reformat;
598e23731dbSKonstantin Belousov 	return 0;
599e23731dbSKonstantin Belousov 
600e23731dbSKonstantin Belousov err_add_flow:
601e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, counter);
602205263acSAriel Ehrenberg 	if (ipsec_rule->rule != NULL)
603205263acSAriel Ehrenberg 		mlx5_del_flow_rules(&ipsec_rule->rule);
604e23731dbSKonstantin Belousov err_add_cnt:
605e23731dbSKonstantin Belousov 	mlx5_packet_reformat_dealloc(mdev, flow_act.pkt_reformat);
606e23731dbSKonstantin Belousov err_pkt_reformat:
607205263acSAriel Ehrenberg 	if (flow_act.modify_hdr != NULL)
608e23731dbSKonstantin Belousov 		mlx5_modify_header_dealloc(mdev, flow_act.modify_hdr);
609e23731dbSKonstantin Belousov err_mod_header:
610e23731dbSKonstantin Belousov 	kvfree(spec);
611e23731dbSKonstantin Belousov 
612e23731dbSKonstantin Belousov 	return err;
613e23731dbSKonstantin Belousov }
614e23731dbSKonstantin Belousov 
ipsec_tx_ft_create(struct mlx5_flow_namespace * ns,int level,int prio,int max_num_groups)615e23731dbSKonstantin Belousov static struct mlx5_flow_table *ipsec_tx_ft_create(struct mlx5_flow_namespace *ns,
616e23731dbSKonstantin Belousov 						  int level, int prio,
617e23731dbSKonstantin Belousov 						  int max_num_groups)
618e23731dbSKonstantin Belousov {
619e23731dbSKonstantin Belousov 	struct mlx5_flow_table_attr ft_attr = {};
620e23731dbSKonstantin Belousov 
621e23731dbSKonstantin Belousov         ft_attr.autogroup.num_reserved_entries = 1;
622e23731dbSKonstantin Belousov         ft_attr.autogroup.max_num_groups = max_num_groups;
623e23731dbSKonstantin Belousov         ft_attr.max_fte = NUM_IPSEC_FTE;
624e23731dbSKonstantin Belousov         ft_attr.level = level;
625e23731dbSKonstantin Belousov         ft_attr.prio = prio;
626e23731dbSKonstantin Belousov 
627e23731dbSKonstantin Belousov 	return mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
628e23731dbSKonstantin Belousov }
629e23731dbSKonstantin Belousov 
ipsec_counter_rule_tx(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_tx * tx)630e23731dbSKonstantin Belousov static int ipsec_counter_rule_tx(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx)
631e23731dbSKonstantin Belousov {
632e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest = {};
633e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
634e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *fte;
635e23731dbSKonstantin Belousov 	int err;
636e23731dbSKonstantin Belousov 
637e23731dbSKonstantin Belousov 	/* create fte */
638e23731dbSKonstantin Belousov 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_COUNT |
639e23731dbSKonstantin Belousov 		MLX5_FLOW_CONTEXT_ACTION_ALLOW;
640e23731dbSKonstantin Belousov 
641e23731dbSKonstantin Belousov 	dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
642e23731dbSKonstantin Belousov 	dest.counter_id = mlx5_fc_id(tx->fc->cnt);
643e23731dbSKonstantin Belousov 	fte = mlx5_add_flow_rules(tx->ft.status, NULL, &flow_act, &dest, 1);
644e23731dbSKonstantin Belousov 	if (IS_ERR_OR_NULL(fte)) {
645e23731dbSKonstantin Belousov 		err = PTR_ERR(fte);
646e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add ipsec tx counter rule err=%d\n", err);
647e23731dbSKonstantin Belousov 		goto err_rule;
648e23731dbSKonstantin Belousov 	}
649e23731dbSKonstantin Belousov 
650e23731dbSKonstantin Belousov 	tx->status.rule = fte;
651e23731dbSKonstantin Belousov 	return 0;
652e23731dbSKonstantin Belousov 
653e23731dbSKonstantin Belousov err_rule:
654e23731dbSKonstantin Belousov 	return err;
655e23731dbSKonstantin Belousov }
656e23731dbSKonstantin Belousov 
tx_destroy_roce(struct mlx5e_ipsec_tx * tx)657e23731dbSKonstantin Belousov static void tx_destroy_roce(struct mlx5e_ipsec_tx *tx) {
658e23731dbSKonstantin Belousov 	if (!tx->roce.ft)
659e23731dbSKonstantin Belousov 		return;
660e23731dbSKonstantin Belousov 
661e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->roce.rule);
662e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(tx->roce.g);
663e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->roce.ft);
664e23731dbSKonstantin Belousov 	tx->roce.ft = NULL;
665e23731dbSKonstantin Belousov }
666e23731dbSKonstantin Belousov 
667e23731dbSKonstantin Belousov /* IPsec TX flow steering */
tx_destroy(struct mlx5e_ipsec_tx * tx)668e23731dbSKonstantin Belousov static void tx_destroy(struct mlx5e_ipsec_tx *tx)
669e23731dbSKonstantin Belousov {
670e23731dbSKonstantin Belousov 	tx_destroy_roce(tx);
671e23731dbSKonstantin Belousov 	if (tx->chains) {
672e23731dbSKonstantin Belousov 		ipsec_chains_destroy(tx->chains);
673e23731dbSKonstantin Belousov 	} else {
674e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&tx->pol.rule);
675e23731dbSKonstantin Belousov 		mlx5_destroy_flow_group(tx->pol.group);
676e23731dbSKonstantin Belousov 		mlx5_destroy_flow_table(tx->ft.pol);
677e23731dbSKonstantin Belousov 	}
678e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.sa);
679e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_miss.rule);
680e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(tx->kspi_miss.group);
681e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_bypass_rule.rule);
682e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_bypass_rule.kspi_rule);
683e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.sa_kspi);
684e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->status.rule);
685e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.status);
686e23731dbSKonstantin Belousov }
687e23731dbSKonstantin Belousov 
ipsec_tx_roce_rule_setup(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_tx * tx)688e23731dbSKonstantin Belousov static int ipsec_tx_roce_rule_setup(struct mlx5_core_dev *mdev,
689e23731dbSKonstantin Belousov 				    struct mlx5e_ipsec_tx *tx)
690e23731dbSKonstantin Belousov {
691e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dst = {};
692e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
693e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
694e23731dbSKonstantin Belousov 	int err = 0;
695e23731dbSKonstantin Belousov 
696e23731dbSKonstantin Belousov 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
697e23731dbSKonstantin Belousov 	dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
698e23731dbSKonstantin Belousov 	dst.ft = tx->ft.pol;
699e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(tx->roce.ft, NULL, &flow_act, &dst, 1);
700e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
701e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
702e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add TX roce ipsec rule err=%d\n",
703e23731dbSKonstantin Belousov 			      err);
704e23731dbSKonstantin Belousov 		goto out;
705e23731dbSKonstantin Belousov 	}
706e23731dbSKonstantin Belousov 	tx->roce.rule = rule;
707e23731dbSKonstantin Belousov 
708e23731dbSKonstantin Belousov out:
709e23731dbSKonstantin Belousov 	return err;
710e23731dbSKonstantin Belousov }
711e23731dbSKonstantin Belousov 
ipsec_tx_create_roce(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_tx * tx)712e23731dbSKonstantin Belousov static int ipsec_tx_create_roce(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx)
713e23731dbSKonstantin Belousov {
714e23731dbSKonstantin Belousov 	struct mlx5_flow_table_attr ft_attr = {};
715e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
716e23731dbSKonstantin Belousov 	struct mlx5_flow_group *g;
717e23731dbSKonstantin Belousov 	int ix = 0;
718e23731dbSKonstantin Belousov 	int err;
719e23731dbSKonstantin Belousov 	u32 *in;
720e23731dbSKonstantin Belousov 
721e23731dbSKonstantin Belousov 	if (!tx->roce.ns)
722e23731dbSKonstantin Belousov 		return -EOPNOTSUPP;
723e23731dbSKonstantin Belousov 
724e23731dbSKonstantin Belousov 	in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
725e23731dbSKonstantin Belousov 	if (!in)
726e23731dbSKonstantin Belousov 		return -ENOMEM;
727e23731dbSKonstantin Belousov 
728e23731dbSKonstantin Belousov 	ft_attr.max_fte = 1;
729e23731dbSKonstantin Belousov 	ft = mlx5_create_flow_table(tx->roce.ns, &ft_attr);
730e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
731e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
732e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to create ipsec tx roce ft err=%d\n",
733e23731dbSKonstantin Belousov 			      err);
734e23731dbSKonstantin Belousov 		goto fail_table;
735e23731dbSKonstantin Belousov 	}
736e23731dbSKonstantin Belousov 	tx->roce.ft = ft;
737e23731dbSKonstantin Belousov 
738e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, start_flow_index, ix);
739e23731dbSKonstantin Belousov 	ix += 1;
740e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
741e23731dbSKonstantin Belousov 	g = mlx5_create_flow_group(ft, in);
742e23731dbSKonstantin Belousov 	if (IS_ERR(g)) {
743e23731dbSKonstantin Belousov 		err = PTR_ERR(g);
744e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to create ipsec tx roce group err=%d\n",
745e23731dbSKonstantin Belousov 			      err);
746e23731dbSKonstantin Belousov 		goto fail_group;
747e23731dbSKonstantin Belousov 	}
748e23731dbSKonstantin Belousov 	tx->roce.g = g;
749e23731dbSKonstantin Belousov 
750e23731dbSKonstantin Belousov 	err = ipsec_tx_roce_rule_setup(mdev, tx);
751e23731dbSKonstantin Belousov 	if (err) {
752e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx rules err=%d\n", err);
753e23731dbSKonstantin Belousov 		goto fail_rule;
754e23731dbSKonstantin Belousov 	}
755e23731dbSKonstantin Belousov 
756e23731dbSKonstantin Belousov 	kvfree(in);
757e23731dbSKonstantin Belousov 	return 0;
758e23731dbSKonstantin Belousov 
759e23731dbSKonstantin Belousov fail_rule:
760e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(tx->roce.g);
761e23731dbSKonstantin Belousov fail_group:
762e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->roce.ft);
763e23731dbSKonstantin Belousov 	tx->roce.ft = NULL;
764e23731dbSKonstantin Belousov fail_table:
765e23731dbSKonstantin Belousov 	kvfree(in);
766e23731dbSKonstantin Belousov 	return err;
767e23731dbSKonstantin Belousov }
768e23731dbSKonstantin Belousov 
769e23731dbSKonstantin Belousov /*
770e23731dbSKonstantin Belousov  * Setting a rule in KSPI table for values that should bypass IPSEC.
771e23731dbSKonstantin Belousov  *
772e23731dbSKonstantin Belousov  * mdev - mlx5 core device
773e23731dbSKonstantin Belousov  * tx - IPSEC TX
774e23731dbSKonstantin Belousov  * return - 0 for success errno for failure
775e23731dbSKonstantin Belousov  */
tx_create_kspi_bypass_rules(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_tx * tx)776e23731dbSKonstantin Belousov static int tx_create_kspi_bypass_rules(struct mlx5_core_dev *mdev,
777e23731dbSKonstantin Belousov                                        struct mlx5e_ipsec_tx *tx)
778e23731dbSKonstantin Belousov {
779e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest = {};
780e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
781e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act_kspi = {};
782e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
783e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
784e23731dbSKonstantin Belousov 	int err;
785e23731dbSKonstantin Belousov 
786e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
787e23731dbSKonstantin Belousov 	if (!spec)
788e23731dbSKonstantin Belousov 		return -ENOMEM;
789e23731dbSKonstantin Belousov 
790e23731dbSKonstantin Belousov 	dest.ft = tx->ft.status;
791e23731dbSKonstantin Belousov 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
792e23731dbSKonstantin Belousov 	flow_act_kspi.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
793e23731dbSKonstantin Belousov 
794e23731dbSKonstantin Belousov 	setup_fte_reg_a_with_tag(spec, IPSEC_ACCEL_DRV_SPI_BYPASS);
795e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(tx->ft.sa_kspi, spec, &flow_act_kspi,
796e23731dbSKonstantin Belousov 								&dest, 1);
797e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
798e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
799e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add ipsec kspi bypass rule err=%d\n",
800e23731dbSKonstantin Belousov                       err);
801e23731dbSKonstantin Belousov 		goto err_add_kspi_rule;
802e23731dbSKonstantin Belousov 	}
803e23731dbSKonstantin Belousov 	tx->kspi_bypass_rule.kspi_rule = rule;
804e23731dbSKonstantin Belousov 
805e23731dbSKonstantin Belousov 	/* set the rule for packets withoiut ipsec tag. */
806e23731dbSKonstantin Belousov 	flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
807e23731dbSKonstantin Belousov 	memset(spec, 0, sizeof(*spec));
808e23731dbSKonstantin Belousov 	setup_fte_reg_a_no_tag(spec);
809e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(tx->ft.sa_kspi, spec, &flow_act, &dest, 1);
810e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
811e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
812e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add ipsec kspi bypass rule err=%d\n", err);
813e23731dbSKonstantin Belousov 		goto err_add_rule;
814e23731dbSKonstantin Belousov 	}
815e23731dbSKonstantin Belousov 	tx->kspi_bypass_rule.rule = rule;
816e23731dbSKonstantin Belousov 
817e23731dbSKonstantin Belousov 	kvfree(spec);
818e23731dbSKonstantin Belousov 	return 0;
819e23731dbSKonstantin Belousov err_add_rule:
820e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_bypass_rule.kspi_rule);
821e23731dbSKonstantin Belousov err_add_kspi_rule:
822e23731dbSKonstantin Belousov 	kvfree(spec);
823e23731dbSKonstantin Belousov 	return err;
824e23731dbSKonstantin Belousov }
825e23731dbSKonstantin Belousov 
826e23731dbSKonstantin Belousov 
tx_create(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_tx * tx)827e23731dbSKonstantin Belousov static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx)
828e23731dbSKonstantin Belousov {
829e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest = {};
830e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
831e23731dbSKonstantin Belousov 	int err;
832e23731dbSKonstantin Belousov 
833e23731dbSKonstantin Belousov 	/*
834e23731dbSKonstantin Belousov 	 *  Tx flow is different for ethernet traffic then for RoCE packets
835e23731dbSKonstantin Belousov 	 *  For Ethernet packets we start in SA KSPI table that matches KSPI of SA rule
836e23731dbSKonstantin Belousov 	 *  to the KSPI in the packet metadata
837e23731dbSKonstantin Belousov 	 *  For RoCE traffic we start in Policy table, then move to SA table
838e23731dbSKonstantin Belousov 	 *  which matches either reqid of the SA rule to reqid reported by policy table
839e23731dbSKonstantin Belousov 	 *  or ip header fields of SA to the packet IP header fields.
840e23731dbSKonstantin Belousov 	 *  Tables are ordered by their level so we set kspi
841e23731dbSKonstantin Belousov 	 *  with level 0 to have it first one for ethernet traffic.
842e23731dbSKonstantin Belousov 	 *  For RoCE the RoCE TX table direct the packets to policy table explicitly
843e23731dbSKonstantin Belousov 	 */
844e23731dbSKonstantin Belousov 	ft = ipsec_tx_ft_create(tx->ns, 0, 0, 4);
845e23731dbSKonstantin Belousov 	if (IS_ERR(ft))
846e23731dbSKonstantin Belousov 		return PTR_ERR(ft);
847e23731dbSKonstantin Belousov 	tx->ft.sa_kspi = ft;
848e23731dbSKonstantin Belousov 
849e23731dbSKonstantin Belousov 	ft = ipsec_tx_ft_create(tx->ns, 2, 0, 4);
850e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
851e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
852e23731dbSKonstantin Belousov 		goto err_reqid_ft;
853e23731dbSKonstantin Belousov 	}
854e23731dbSKonstantin Belousov 	tx->ft.sa = ft;
855e23731dbSKonstantin Belousov 
856e23731dbSKonstantin Belousov 	if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
857e23731dbSKonstantin Belousov 		tx->chains = ipsec_chains_create(
858e23731dbSKonstantin Belousov 				mdev, tx->ft.sa, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC, 0, 1,
859e23731dbSKonstantin Belousov 				&tx->ft.pol);
860e23731dbSKonstantin Belousov 		if (IS_ERR(tx->chains)) {
861e23731dbSKonstantin Belousov 			err = PTR_ERR(tx->chains);
862e23731dbSKonstantin Belousov 			goto err_pol_ft;
863e23731dbSKonstantin Belousov 		}
864e23731dbSKonstantin Belousov 	} else {
865e23731dbSKonstantin Belousov 		ft = ipsec_tx_ft_create(tx->ns, 1, 0, 2);
866e23731dbSKonstantin Belousov 		if (IS_ERR(ft)) {
867e23731dbSKonstantin Belousov 			err = PTR_ERR(ft);
868e23731dbSKonstantin Belousov 			goto err_pol_ft;
869e23731dbSKonstantin Belousov 		}
870e23731dbSKonstantin Belousov 		tx->ft.pol = ft;
871e23731dbSKonstantin Belousov 		dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
872e23731dbSKonstantin Belousov 		dest.ft = tx->ft.sa;
873e23731dbSKonstantin Belousov 		err = ipsec_miss_create(mdev, tx->ft.pol, &tx->pol, &dest);
874e23731dbSKonstantin Belousov 		if (err)
875e23731dbSKonstantin Belousov 			goto err_pol_miss;
876e23731dbSKonstantin Belousov 	}
877e23731dbSKonstantin Belousov 
878e23731dbSKonstantin Belousov 	ft = ipsec_tx_ft_create(tx->ns, 2, 0, 1);
879e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
880e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
881e23731dbSKonstantin Belousov 		goto err_status_ft;
882e23731dbSKonstantin Belousov 	}
883e23731dbSKonstantin Belousov 	tx->ft.status = ft;
884e23731dbSKonstantin Belousov 
885e23731dbSKonstantin Belousov 	/* set miss rule for kspi table with drop action*/
886e23731dbSKonstantin Belousov 	err = ipsec_miss_create(mdev, tx->ft.sa_kspi, &tx->kspi_miss, NULL);
887e23731dbSKonstantin Belousov 	if (err)
888e23731dbSKonstantin Belousov 		goto err_kspi_miss;
889e23731dbSKonstantin Belousov 
890e23731dbSKonstantin Belousov 	err = tx_create_kspi_bypass_rules(mdev, tx);
891e23731dbSKonstantin Belousov 	if (err)
892e23731dbSKonstantin Belousov 		goto err_kspi_rule;
893e23731dbSKonstantin Belousov 
894e23731dbSKonstantin Belousov 	err = ipsec_counter_rule_tx(mdev, tx);
895e23731dbSKonstantin Belousov 	if (err)
896e23731dbSKonstantin Belousov 		goto err_status_rule;
897e23731dbSKonstantin Belousov 
898e23731dbSKonstantin Belousov 	err = ipsec_tx_create_roce(mdev, tx);
899e23731dbSKonstantin Belousov 	if (err)
900e23731dbSKonstantin Belousov 		goto err_counter_rule;
901e23731dbSKonstantin Belousov 
902e23731dbSKonstantin Belousov 	return 0;
903e23731dbSKonstantin Belousov 
904e23731dbSKonstantin Belousov err_counter_rule:
905e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->status.rule);
906e23731dbSKonstantin Belousov err_status_rule:
907e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_bypass_rule.rule);
908e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_bypass_rule.kspi_rule);
909e23731dbSKonstantin Belousov err_kspi_rule:
910e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.status);
911e23731dbSKonstantin Belousov err_status_ft:
912e23731dbSKonstantin Belousov 	if (tx->chains) {
913e23731dbSKonstantin Belousov 		ipsec_chains_destroy(tx->chains);
914e23731dbSKonstantin Belousov 	} else {
915e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&tx->pol.rule);
916e23731dbSKonstantin Belousov 		mlx5_destroy_flow_group(tx->pol.group);
917e23731dbSKonstantin Belousov 	}
918e23731dbSKonstantin Belousov err_pol_miss:
919e23731dbSKonstantin Belousov 	if (!tx->chains)
920e23731dbSKonstantin Belousov 		mlx5_destroy_flow_table(tx->ft.pol);
921e23731dbSKonstantin Belousov err_pol_ft:
922e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&tx->kspi_miss.rule);
923e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(tx->kspi_miss.group);
924e23731dbSKonstantin Belousov err_kspi_miss:
925e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.sa);
926e23731dbSKonstantin Belousov err_reqid_ft:
927e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(tx->ft.sa_kspi);
928e23731dbSKonstantin Belousov 	return err;
929e23731dbSKonstantin Belousov }
930e23731dbSKonstantin Belousov 
tx_get(struct mlx5_core_dev * mdev,struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_tx * tx)931e23731dbSKonstantin Belousov static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
932e23731dbSKonstantin Belousov 		  struct mlx5e_ipsec_tx *tx)
933e23731dbSKonstantin Belousov {
934e23731dbSKonstantin Belousov 	int err;
935e23731dbSKonstantin Belousov 
936e23731dbSKonstantin Belousov 	if (tx->ft.refcnt)
937e23731dbSKonstantin Belousov 		goto skip;
938e23731dbSKonstantin Belousov 
939e23731dbSKonstantin Belousov 	err = tx_create(mdev, tx);
940e23731dbSKonstantin Belousov 	if (err)
941e23731dbSKonstantin Belousov 		return err;
942e23731dbSKonstantin Belousov 
943e23731dbSKonstantin Belousov skip:
944e23731dbSKonstantin Belousov 	tx->ft.refcnt++;
945e23731dbSKonstantin Belousov 	return 0;
946e23731dbSKonstantin Belousov }
947e23731dbSKonstantin Belousov 
tx_put(struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_tx * tx)948e23731dbSKonstantin Belousov static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
949e23731dbSKonstantin Belousov {
950e23731dbSKonstantin Belousov 	if (--tx->ft.refcnt)
951e23731dbSKonstantin Belousov 		return;
952e23731dbSKonstantin Belousov 
953e23731dbSKonstantin Belousov 	tx_destroy(tx);
954e23731dbSKonstantin Belousov }
955e23731dbSKonstantin Belousov 
tx_ft_get(struct mlx5_core_dev * mdev,struct mlx5e_ipsec * ipsec)956e23731dbSKonstantin Belousov static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
957e23731dbSKonstantin Belousov 					struct mlx5e_ipsec *ipsec)
958e23731dbSKonstantin Belousov {
959e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx *tx = ipsec->tx;
960e23731dbSKonstantin Belousov 	int err;
961e23731dbSKonstantin Belousov 
962e23731dbSKonstantin Belousov 	mutex_lock(&tx->ft.mutex);
963e23731dbSKonstantin Belousov 	err = tx_get(mdev, ipsec, tx);
964e23731dbSKonstantin Belousov 	mutex_unlock(&tx->ft.mutex);
965e23731dbSKonstantin Belousov 	if (err)
966e23731dbSKonstantin Belousov 		return ERR_PTR(err);
967e23731dbSKonstantin Belousov 
968e23731dbSKonstantin Belousov 	return tx;
969e23731dbSKonstantin Belousov }
970e23731dbSKonstantin Belousov 
tx_ft_get_policy(struct mlx5_core_dev * mdev,struct mlx5e_ipsec * ipsec,u32 prio)971e23731dbSKonstantin Belousov static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
972e23731dbSKonstantin Belousov                                                 struct mlx5e_ipsec *ipsec,
973e23731dbSKonstantin Belousov                                                 u32 prio)
974e23731dbSKonstantin Belousov {
975e23731dbSKonstantin Belousov         struct mlx5e_ipsec_tx *tx = ipsec->tx;
976e23731dbSKonstantin Belousov         struct mlx5_flow_table *ft;
977e23731dbSKonstantin Belousov         int err;
978e23731dbSKonstantin Belousov 
979e23731dbSKonstantin Belousov         mutex_lock(&tx->ft.mutex);
980e23731dbSKonstantin Belousov         err = tx_get(mdev, ipsec, tx);
981e23731dbSKonstantin Belousov         if (err)
982e23731dbSKonstantin Belousov             goto err_get;
983e23731dbSKonstantin Belousov 
984e23731dbSKonstantin Belousov         ft = tx->chains ? ipsec_chains_get_table(tx->chains, prio) : tx->ft.pol;
985e23731dbSKonstantin Belousov         if (IS_ERR(ft)) {
986e23731dbSKonstantin Belousov                 err = PTR_ERR(ft);
987e23731dbSKonstantin Belousov                 goto err_get_ft;
988e23731dbSKonstantin Belousov         }
989e23731dbSKonstantin Belousov 
990e23731dbSKonstantin Belousov         mutex_unlock(&tx->ft.mutex);
991e23731dbSKonstantin Belousov         return ft;
992e23731dbSKonstantin Belousov 
993e23731dbSKonstantin Belousov err_get_ft:
994e23731dbSKonstantin Belousov         tx_put(ipsec, tx);
995e23731dbSKonstantin Belousov err_get:
996e23731dbSKonstantin Belousov         mutex_unlock(&tx->ft.mutex);
997e23731dbSKonstantin Belousov         return ERR_PTR(err);
998e23731dbSKonstantin Belousov }
999e23731dbSKonstantin Belousov 
tx_ft_put_policy(struct mlx5e_ipsec * ipsec,u32 prio)1000e23731dbSKonstantin Belousov static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio)
1001e23731dbSKonstantin Belousov {
1002e23731dbSKonstantin Belousov         struct mlx5e_ipsec_tx *tx = ipsec->tx;
1003e23731dbSKonstantin Belousov 
1004e23731dbSKonstantin Belousov         mutex_lock(&tx->ft.mutex);
1005e23731dbSKonstantin Belousov         if (tx->chains)
1006e23731dbSKonstantin Belousov                 ipsec_chains_put_table(tx->chains, prio);
1007e23731dbSKonstantin Belousov 
1008e23731dbSKonstantin Belousov         tx_put(ipsec, tx);
1009e23731dbSKonstantin Belousov         mutex_unlock(&tx->ft.mutex);
1010e23731dbSKonstantin Belousov }
1011e23731dbSKonstantin Belousov 
tx_ft_put(struct mlx5e_ipsec * ipsec)1012e23731dbSKonstantin Belousov static void tx_ft_put(struct mlx5e_ipsec *ipsec)
1013e23731dbSKonstantin Belousov {
1014e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx *tx = ipsec->tx;
1015e23731dbSKonstantin Belousov 
1016e23731dbSKonstantin Belousov 	mutex_lock(&tx->ft.mutex);
1017e23731dbSKonstantin Belousov 	tx_put(ipsec, tx);
1018e23731dbSKonstantin Belousov 	mutex_unlock(&tx->ft.mutex);
1019e23731dbSKonstantin Belousov }
1020e23731dbSKonstantin Belousov 
setup_fte_reg_a_with_tag(struct mlx5_flow_spec * spec,u16 kspi)1021e23731dbSKonstantin Belousov static void setup_fte_reg_a_with_tag(struct mlx5_flow_spec *spec,
1022e23731dbSKonstantin Belousov 									 u16 kspi)
1023e23731dbSKonstantin Belousov {
1024e23731dbSKonstantin Belousov        /* Add IPsec indicator in metadata_reg_a. */
1025e23731dbSKonstantin Belousov        spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
1026e23731dbSKonstantin Belousov 
1027e23731dbSKonstantin Belousov        MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1028e23731dbSKonstantin Belousov                         misc_parameters_2.metadata_reg_a);
1029e23731dbSKonstantin Belousov        MLX5_SET(fte_match_param, spec->match_value,
1030e23731dbSKonstantin Belousov                 misc_parameters_2.metadata_reg_a,
1031e23731dbSKonstantin Belousov                 MLX5_ETH_WQE_FT_META_IPSEC << 23 |  kspi);
1032e23731dbSKonstantin Belousov }
1033e23731dbSKonstantin Belousov 
setup_fte_reg_a_no_tag(struct mlx5_flow_spec * spec)1034e23731dbSKonstantin Belousov static void setup_fte_reg_a_no_tag(struct mlx5_flow_spec *spec)
1035e23731dbSKonstantin Belousov {
1036e23731dbSKonstantin Belousov        /* Add IPsec indicator in metadata_reg_a. */
1037e23731dbSKonstantin Belousov        spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
1038e23731dbSKonstantin Belousov 
1039e23731dbSKonstantin Belousov        MLX5_SET(fte_match_param, spec->match_criteria,
1040e23731dbSKonstantin Belousov                 misc_parameters_2.metadata_reg_a,
1041e23731dbSKonstantin Belousov 				MLX5_ETH_WQE_FT_META_IPSEC << 23);
1042e23731dbSKonstantin Belousov        MLX5_SET(fte_match_param, spec->match_value,
1043e23731dbSKonstantin Belousov                 misc_parameters_2.metadata_reg_a,
1044e23731dbSKonstantin Belousov                 0);
1045e23731dbSKonstantin Belousov }
1046e23731dbSKonstantin Belousov 
setup_fte_reg_c0(struct mlx5_flow_spec * spec,u32 reqid)1047e23731dbSKonstantin Belousov static void setup_fte_reg_c0(struct mlx5_flow_spec *spec, u32 reqid)
1048e23731dbSKonstantin Belousov {
1049e23731dbSKonstantin Belousov 	/* Pass policy check before choosing this SA */
1050e23731dbSKonstantin Belousov 	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
1051e23731dbSKonstantin Belousov 
1052e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1053e23731dbSKonstantin Belousov 			 misc_parameters_2.metadata_reg_c_0);
1054e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_param, spec->match_value,
1055e23731dbSKonstantin Belousov 		 misc_parameters_2.metadata_reg_c_0, reqid);
1056e23731dbSKonstantin Belousov }
1057e23731dbSKonstantin Belousov 
setup_fte_upper_proto_match(struct mlx5_flow_spec * spec,struct upspec * upspec)1058e23731dbSKonstantin Belousov static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upspec *upspec)
1059e23731dbSKonstantin Belousov {
1060e23731dbSKonstantin Belousov         switch (upspec->proto) {
1061e23731dbSKonstantin Belousov         case IPPROTO_UDP:
1062e23731dbSKonstantin Belousov                 if (upspec->dport) {
1063e23731dbSKonstantin Belousov                         MLX5_SET_TO_ONES(fte_match_set_lyr_2_4,
1064e23731dbSKonstantin Belousov                                          spec->match_criteria, udp_dport);
1065e23731dbSKonstantin Belousov                         MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
1066e23731dbSKonstantin Belousov                                  udp_dport, upspec->dport);
1067e23731dbSKonstantin Belousov                 }
1068e23731dbSKonstantin Belousov 
1069e23731dbSKonstantin Belousov                 if (upspec->sport) {
1070e23731dbSKonstantin Belousov                         MLX5_SET_TO_ONES(fte_match_set_lyr_2_4,
1071e23731dbSKonstantin Belousov                                          spec->match_criteria, udp_sport);
1072e23731dbSKonstantin Belousov                         MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
1073e23731dbSKonstantin Belousov                                  udp_dport, upspec->sport);
1074e23731dbSKonstantin Belousov                 }
1075e23731dbSKonstantin Belousov                 break;
1076e23731dbSKonstantin Belousov         case IPPROTO_TCP:
1077e23731dbSKonstantin Belousov                 if (upspec->dport) {
1078e23731dbSKonstantin Belousov                         MLX5_SET_TO_ONES(fte_match_set_lyr_2_4,
1079e23731dbSKonstantin Belousov                                          spec->match_criteria, tcp_dport);
1080e23731dbSKonstantin Belousov                         MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
1081e23731dbSKonstantin Belousov                                  tcp_dport, upspec->dport);
1082e23731dbSKonstantin Belousov                 }
1083e23731dbSKonstantin Belousov 
1084e23731dbSKonstantin Belousov                 if (upspec->sport) {
1085e23731dbSKonstantin Belousov                         MLX5_SET_TO_ONES(fte_match_set_lyr_2_4,
1086e23731dbSKonstantin Belousov                                          spec->match_criteria, tcp_sport);
1087e23731dbSKonstantin Belousov                         MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
1088e23731dbSKonstantin Belousov                                  tcp_dport, upspec->sport);
1089e23731dbSKonstantin Belousov                 }
1090e23731dbSKonstantin Belousov                 break;
1091e23731dbSKonstantin Belousov         default:
1092e23731dbSKonstantin Belousov                 return;
1093e23731dbSKonstantin Belousov         }
1094e23731dbSKonstantin Belousov 
1095e23731dbSKonstantin Belousov         spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
1096e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, spec->match_criteria, ip_protocol);
1097e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, ip_protocol, upspec->proto);
1098e23731dbSKonstantin Belousov }
1099e23731dbSKonstantin Belousov 
tx_add_kspi_rule(struct mlx5e_ipsec_sa_entry * sa_entry,struct mlx5e_ipsec_tx * tx,struct mlx5_flow_act * flow_act,struct mlx5_flow_destination * dest,int num_dest)1100e23731dbSKonstantin Belousov static int tx_add_kspi_rule(struct mlx5e_ipsec_sa_entry *sa_entry,
1101e23731dbSKonstantin Belousov 							struct mlx5e_ipsec_tx *tx,
1102e23731dbSKonstantin Belousov 							struct mlx5_flow_act *flow_act,
1103e23731dbSKonstantin Belousov 							struct mlx5_flow_destination *dest,
1104e23731dbSKonstantin Belousov 							int num_dest)
1105e23731dbSKonstantin Belousov {
1106e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
1107e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
1108e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
1109e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
1110e23731dbSKonstantin Belousov 	int err;
1111e23731dbSKonstantin Belousov 
1112e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1113e23731dbSKonstantin Belousov 	if (!spec)
1114e23731dbSKonstantin Belousov 		return -ENOMEM;
1115e23731dbSKonstantin Belousov 
1116e23731dbSKonstantin Belousov 	setup_fte_no_frags(spec);
1117e23731dbSKonstantin Belousov 	setup_fte_reg_a_with_tag(spec, sa_entry->kspi);
1118e23731dbSKonstantin Belousov 
1119e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(tx->ft.sa_kspi, spec, flow_act, dest, num_dest);
1120e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1121e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1122e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to add TX ipsec kspi rule err=%d\n", err);
1123e23731dbSKonstantin Belousov 		goto err_add_kspi_flow;
1124e23731dbSKonstantin Belousov 	}
1125e23731dbSKonstantin Belousov 	ipsec_rule->kspi_rule = rule;
1126e23731dbSKonstantin Belousov 	kvfree(spec);
1127e23731dbSKonstantin Belousov 	return 0;
1128e23731dbSKonstantin Belousov 
1129e23731dbSKonstantin Belousov err_add_kspi_flow:
1130e23731dbSKonstantin Belousov 	kvfree(spec);
1131e23731dbSKonstantin Belousov 	return err;
1132e23731dbSKonstantin Belousov }
1133e23731dbSKonstantin Belousov 
tx_add_reqid_ip_rules(struct mlx5e_ipsec_sa_entry * sa_entry,struct mlx5e_ipsec_tx * tx,struct mlx5_flow_act * flow_act,struct mlx5_flow_destination * dest,int num_dest)1134e23731dbSKonstantin Belousov static int tx_add_reqid_ip_rules(struct mlx5e_ipsec_sa_entry *sa_entry,
1135e23731dbSKonstantin Belousov 								struct mlx5e_ipsec_tx *tx,
1136e23731dbSKonstantin Belousov 								struct mlx5_flow_act *flow_act,
1137e23731dbSKonstantin Belousov 								struct mlx5_flow_destination *dest,
1138e23731dbSKonstantin Belousov 								int num_dest)
1139e23731dbSKonstantin Belousov {
1140e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
1141e23731dbSKonstantin Belousov 	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
1142e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
1143e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
1144e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
1145e23731dbSKonstantin Belousov 	int err;
1146e23731dbSKonstantin Belousov 
1147e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1148e23731dbSKonstantin Belousov 	if (!spec)
1149e23731dbSKonstantin Belousov 		return -ENOMEM;
1150e23731dbSKonstantin Belousov 
1151e23731dbSKonstantin Belousov 	flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
1152e23731dbSKonstantin Belousov 
1153e23731dbSKonstantin Belousov 	if(attrs->reqid) {
1154e23731dbSKonstantin Belousov 		setup_fte_no_frags(spec);
1155e23731dbSKonstantin Belousov 		setup_fte_reg_c0(spec, attrs->reqid);
1156e23731dbSKonstantin Belousov 		rule = mlx5_add_flow_rules(tx->ft.sa, spec, flow_act, dest, num_dest);
1157e23731dbSKonstantin Belousov 		if (IS_ERR(rule)) {
1158e23731dbSKonstantin Belousov 			err = PTR_ERR(rule);
1159e23731dbSKonstantin Belousov 			mlx5_core_err(mdev, "fail to add TX ipsec reqid rule err=%d\n", err);
1160e23731dbSKonstantin Belousov 			goto err_add_reqid_rule;
1161e23731dbSKonstantin Belousov 		}
1162e23731dbSKonstantin Belousov 		ipsec_rule->reqid_rule = rule;
1163e23731dbSKonstantin Belousov 		memset(spec, 0, sizeof(*spec));
1164e23731dbSKonstantin Belousov 	}
1165e23731dbSKonstantin Belousov 
1166e23731dbSKonstantin Belousov 	if (attrs->family == AF_INET)
1167e23731dbSKonstantin Belousov 		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
1168e23731dbSKonstantin Belousov 	else
1169e23731dbSKonstantin Belousov 		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
1170e23731dbSKonstantin Belousov 	setup_fte_no_frags(spec);
1171e23731dbSKonstantin Belousov 
1172e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(tx->ft.sa, spec, flow_act, dest, num_dest);
1173e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1174e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1175e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to add TX ipsec ip rule err=%d\n", err);
1176e23731dbSKonstantin Belousov 		goto err_add_ip_rule;
1177e23731dbSKonstantin Belousov 	}
1178e23731dbSKonstantin Belousov 	ipsec_rule->rule = rule;
1179e23731dbSKonstantin Belousov 	kvfree(spec);
1180e23731dbSKonstantin Belousov 	return 0;
1181e23731dbSKonstantin Belousov 
1182e23731dbSKonstantin Belousov err_add_ip_rule:
1183e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&ipsec_rule->reqid_rule);
1184e23731dbSKonstantin Belousov err_add_reqid_rule:
1185e23731dbSKonstantin Belousov 	kvfree(spec);
1186e23731dbSKonstantin Belousov 	return err;
1187e23731dbSKonstantin Belousov }
1188e23731dbSKonstantin Belousov 
tx_add_rule(struct mlx5e_ipsec_sa_entry * sa_entry)1189e23731dbSKonstantin Belousov static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
1190e23731dbSKonstantin Belousov {
1191e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
1192e23731dbSKonstantin Belousov 	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
1193e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
1194e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
1195e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest[2] = {};
1196e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
1197e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx *tx;
1198e23731dbSKonstantin Belousov 	struct mlx5_fc *counter;
1199e23731dbSKonstantin Belousov 	int err;
1200e23731dbSKonstantin Belousov 
1201e23731dbSKonstantin Belousov 	tx = tx_ft_get(mdev, ipsec);
1202e23731dbSKonstantin Belousov 	if (IS_ERR(tx))
1203e23731dbSKonstantin Belousov 		return PTR_ERR(tx);
1204e23731dbSKonstantin Belousov 
1205e23731dbSKonstantin Belousov 	err = setup_pkt_reformat(mdev, attrs, &flow_act);
1206e23731dbSKonstantin Belousov 	if (err)
1207e23731dbSKonstantin Belousov 		goto err_pkt_reformat;
1208e23731dbSKonstantin Belousov 
1209e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
1210e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
1211e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
1212e23731dbSKonstantin Belousov 		goto err_add_cnt;
1213e23731dbSKonstantin Belousov 	}
1214e23731dbSKonstantin Belousov 
1215e23731dbSKonstantin Belousov 	flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_IPSEC;
1216e23731dbSKonstantin Belousov         flow_act.crypto.obj_id = sa_entry->ipsec_obj_id;
1217e23731dbSKonstantin Belousov         flow_act.flags |= FLOW_ACT_NO_APPEND;
1218e23731dbSKonstantin Belousov         flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT |
1219e23731dbSKonstantin Belousov                            MLX5_FLOW_CONTEXT_ACTION_COUNT;
1220e23731dbSKonstantin Belousov 
1221e23731dbSKonstantin Belousov 	if (attrs->drop)
1222e23731dbSKonstantin Belousov 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
1223e23731dbSKonstantin Belousov 	else
1224e23731dbSKonstantin Belousov 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1225e23731dbSKonstantin Belousov 
1226e23731dbSKonstantin Belousov 	dest[0].ft = tx->ft.status;
1227e23731dbSKonstantin Belousov 	dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1228e23731dbSKonstantin Belousov 	dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1229e23731dbSKonstantin Belousov 	dest[1].counter_id = mlx5_fc_id(counter);
1230e23731dbSKonstantin Belousov 
1231e23731dbSKonstantin Belousov 	err = tx_add_kspi_rule(sa_entry, tx, &flow_act, dest, 2);
1232e23731dbSKonstantin Belousov 	if (err) {
1233e23731dbSKonstantin Belousov 		goto err_add_kspi_rule;
1234e23731dbSKonstantin Belousov 	}
1235e23731dbSKonstantin Belousov 
1236e23731dbSKonstantin Belousov 	err = tx_add_reqid_ip_rules(sa_entry, tx, &flow_act, dest, 2);
1237e23731dbSKonstantin Belousov 	if (err) {
1238e23731dbSKonstantin Belousov 		goto err_add_reqid_ip_rule;
1239e23731dbSKonstantin Belousov 	}
1240e23731dbSKonstantin Belousov 
1241e23731dbSKonstantin Belousov 	ipsec_rule->fc = counter;
1242e23731dbSKonstantin Belousov 	ipsec_rule->pkt_reformat = flow_act.pkt_reformat;
1243e23731dbSKonstantin Belousov 	return 0;
1244e23731dbSKonstantin Belousov 
1245e23731dbSKonstantin Belousov err_add_reqid_ip_rule:
1246e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&ipsec_rule->kspi_rule);
1247e23731dbSKonstantin Belousov err_add_kspi_rule:
1248e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, counter);
1249e23731dbSKonstantin Belousov err_add_cnt:
1250e23731dbSKonstantin Belousov 	if (flow_act.pkt_reformat)
1251e23731dbSKonstantin Belousov 		mlx5_packet_reformat_dealloc(mdev, flow_act.pkt_reformat);
1252e23731dbSKonstantin Belousov err_pkt_reformat:
1253e23731dbSKonstantin Belousov 	tx_ft_put(ipsec);
1254e23731dbSKonstantin Belousov 	return err;
1255e23731dbSKonstantin Belousov }
1256e23731dbSKonstantin Belousov 
tx_add_policy(struct mlx5e_ipsec_pol_entry * pol_entry)1257e23731dbSKonstantin Belousov static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
1258e23731dbSKonstantin Belousov {
1259e23731dbSKonstantin Belousov         struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
1260e23731dbSKonstantin Belousov         struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
1261e23731dbSKonstantin Belousov         struct mlx5e_ipsec_tx *tx = pol_entry->ipsec->tx;
1262e23731dbSKonstantin Belousov         struct mlx5_flow_destination dest[2] = {};
1263e23731dbSKonstantin Belousov         struct mlx5_flow_act flow_act = {};
1264e23731dbSKonstantin Belousov         struct mlx5_flow_handle *rule;
1265e23731dbSKonstantin Belousov         struct mlx5_flow_spec *spec;
1266e23731dbSKonstantin Belousov         struct mlx5_flow_table *ft;
1267e23731dbSKonstantin Belousov         int err, dstn = 0;
1268e23731dbSKonstantin Belousov 
1269e23731dbSKonstantin Belousov         ft = tx_ft_get_policy(mdev, pol_entry->ipsec, attrs->prio);
1270e23731dbSKonstantin Belousov         if (IS_ERR(ft))
1271e23731dbSKonstantin Belousov             return PTR_ERR(ft);
1272e23731dbSKonstantin Belousov 
1273e23731dbSKonstantin Belousov         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1274e23731dbSKonstantin Belousov         if (!spec) {
1275e23731dbSKonstantin Belousov             err = -ENOMEM;
1276e23731dbSKonstantin Belousov             goto err_alloc;
1277e23731dbSKonstantin Belousov         }
1278e23731dbSKonstantin Belousov 
1279e23731dbSKonstantin Belousov         if (attrs->family == AF_INET)
1280e23731dbSKonstantin Belousov                 setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
1281e23731dbSKonstantin Belousov         else
1282e23731dbSKonstantin Belousov                 setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
1283e23731dbSKonstantin Belousov 
1284e23731dbSKonstantin Belousov         setup_fte_no_frags(spec);
1285e23731dbSKonstantin Belousov 	setup_fte_upper_proto_match(spec, &attrs->upspec);
1286e23731dbSKonstantin Belousov 
1287e23731dbSKonstantin Belousov         switch (attrs->action) {
1288e23731dbSKonstantin Belousov         case IPSEC_POLICY_IPSEC:
1289e23731dbSKonstantin Belousov                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1290e23731dbSKonstantin Belousov                 err = setup_modify_header(mdev, attrs->reqid,
1291e23731dbSKonstantin Belousov                                           IPSEC_DIR_OUTBOUND, &flow_act);
1292e23731dbSKonstantin Belousov                 if (err)
1293e23731dbSKonstantin Belousov                         goto err_mod_header;
1294e23731dbSKonstantin Belousov                  break;
1295e23731dbSKonstantin Belousov         case IPSEC_POLICY_DISCARD:
1296e23731dbSKonstantin Belousov                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP |
1297e23731dbSKonstantin Belousov                                    MLX5_FLOW_CONTEXT_ACTION_COUNT;
1298e23731dbSKonstantin Belousov                 dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1299e23731dbSKonstantin Belousov                 dest[dstn].counter_id = mlx5_fc_id(tx->fc->drop);
1300e23731dbSKonstantin Belousov                 dstn++;
1301e23731dbSKonstantin Belousov                 break;
1302e23731dbSKonstantin Belousov         default:
1303e23731dbSKonstantin Belousov                 err = -EINVAL;
1304e23731dbSKonstantin Belousov                 goto err_mod_header;
1305e23731dbSKonstantin Belousov         }
1306e23731dbSKonstantin Belousov 
1307e23731dbSKonstantin Belousov         flow_act.flags |= FLOW_ACT_NO_APPEND;
1308e23731dbSKonstantin Belousov         dest[dstn].ft = tx->ft.sa;
1309e23731dbSKonstantin Belousov         dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1310e23731dbSKonstantin Belousov         dstn++;
1311e23731dbSKonstantin Belousov         rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn);
1312e23731dbSKonstantin Belousov         if (IS_ERR(rule)) {
1313e23731dbSKonstantin Belousov                 err = PTR_ERR(rule);
1314e23731dbSKonstantin Belousov                 mlx5_core_err(mdev, "fail to add TX ipsec rule err=%d\n", err);
1315e23731dbSKonstantin Belousov                 goto err_action;
1316e23731dbSKonstantin Belousov         }
1317e23731dbSKonstantin Belousov 
1318e23731dbSKonstantin Belousov         kvfree(spec);
1319e23731dbSKonstantin Belousov         pol_entry->ipsec_rule.rule = rule;
1320e23731dbSKonstantin Belousov         pol_entry->ipsec_rule.modify_hdr = flow_act.modify_hdr;
1321e23731dbSKonstantin Belousov         return 0;
1322e23731dbSKonstantin Belousov 
1323e23731dbSKonstantin Belousov err_action:
1324e23731dbSKonstantin Belousov         if (flow_act.modify_hdr)
1325e23731dbSKonstantin Belousov                 mlx5_modify_header_dealloc(mdev, flow_act.modify_hdr);
1326e23731dbSKonstantin Belousov err_mod_header:
1327e23731dbSKonstantin Belousov         kvfree(spec);
1328e23731dbSKonstantin Belousov err_alloc:
1329e23731dbSKonstantin Belousov         tx_ft_put_policy(pol_entry->ipsec, attrs->prio);
1330e23731dbSKonstantin Belousov         return err;
1331e23731dbSKonstantin Belousov }
1332e23731dbSKonstantin Belousov 
rx_add_policy(struct mlx5e_ipsec_pol_entry * pol_entry)1333e23731dbSKonstantin Belousov static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
1334e23731dbSKonstantin Belousov {
1335e23731dbSKonstantin Belousov         struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
1336e23731dbSKonstantin Belousov         struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
1337e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = pol_entry->ipsec;
1338e23731dbSKonstantin Belousov         struct mlx5_flow_destination dest[2];
1339e23731dbSKonstantin Belousov         struct mlx5_flow_act flow_act = {};
1340e23731dbSKonstantin Belousov         struct mlx5_flow_handle *rule;
1341e23731dbSKonstantin Belousov         struct mlx5_flow_spec *spec;
1342e23731dbSKonstantin Belousov         struct mlx5_flow_table *ft;
1343e23731dbSKonstantin Belousov         struct mlx5e_ipsec_rx *rx;
1344e23731dbSKonstantin Belousov 	int err, dstn = 0;
1345e23731dbSKonstantin Belousov 
1346e23731dbSKonstantin Belousov         rx = (attrs->family == AF_INET) ? ipsec->rx_ipv4 : ipsec->rx_ipv6;
1347e23731dbSKonstantin Belousov         ft = rx->chains ? ipsec_chains_get_table(rx->chains, attrs->prio) : rx->ft.pol;
1348e23731dbSKonstantin Belousov         if (IS_ERR(ft))
1349e23731dbSKonstantin Belousov                 return PTR_ERR(ft);
1350e23731dbSKonstantin Belousov 
1351e23731dbSKonstantin Belousov         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1352e23731dbSKonstantin Belousov         if (!spec) {
1353e23731dbSKonstantin Belousov                 err = -ENOMEM;
1354e23731dbSKonstantin Belousov                 goto err_alloc;
1355e23731dbSKonstantin Belousov         }
1356e23731dbSKonstantin Belousov 
1357e23731dbSKonstantin Belousov         switch (attrs->action) {
1358e23731dbSKonstantin Belousov         case IPSEC_POLICY_IPSEC:
1359e23731dbSKonstantin Belousov                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1360e23731dbSKonstantin Belousov                 break;
1361e23731dbSKonstantin Belousov         case IPSEC_POLICY_DISCARD:
1362e23731dbSKonstantin Belousov                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
1363e23731dbSKonstantin Belousov                 dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1364e23731dbSKonstantin Belousov                 dest[dstn].counter_id = mlx5_fc_id(rx->fc->drop);
1365e23731dbSKonstantin Belousov                 dstn++;
1366e23731dbSKonstantin Belousov                 break;
1367e23731dbSKonstantin Belousov         default:
1368e23731dbSKonstantin Belousov                 err = -EINVAL;
1369e23731dbSKonstantin Belousov                 goto err_action;
1370e23731dbSKonstantin Belousov         }
1371e23731dbSKonstantin Belousov 
1372e23731dbSKonstantin Belousov         flow_act.flags |= FLOW_ACT_NO_APPEND;
1373e23731dbSKonstantin Belousov         dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1374e23731dbSKonstantin Belousov         dest[dstn].ft = rx->ft.sa;
1375e23731dbSKonstantin Belousov         dstn++;
1376205263acSAriel Ehrenberg 
1377205263acSAriel Ehrenberg 	if (attrs->family == AF_INET)
1378205263acSAriel Ehrenberg 		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
1379205263acSAriel Ehrenberg 	else
1380205263acSAriel Ehrenberg 		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
1381205263acSAriel Ehrenberg 
1382205263acSAriel Ehrenberg 	setup_fte_no_frags(spec);
1383205263acSAriel Ehrenberg 	setup_fte_upper_proto_match(spec, &attrs->upspec);
1384205263acSAriel Ehrenberg 	if (attrs->vid != VLAN_NONE)
1385205263acSAriel Ehrenberg 		setup_fte_vid(spec, attrs->vid);
1386205263acSAriel Ehrenberg 	else
1387205263acSAriel Ehrenberg 		setup_fte_no_vid(spec);
1388205263acSAriel Ehrenberg 
1389e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn);
1390e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1391e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1392205263acSAriel Ehrenberg 		mlx5_core_err(mdev,
1393205263acSAriel Ehrenberg 		    "Failed to add RX IPsec policy rule err=%d\n", err);
1394e23731dbSKonstantin Belousov 		goto err_action;
1395e23731dbSKonstantin Belousov 	}
1396205263acSAriel Ehrenberg 	pol_entry->ipsec_rule.rule = rule;
1397205263acSAriel Ehrenberg 
1398205263acSAriel Ehrenberg 	/* Add also rule for zero vid */
1399205263acSAriel Ehrenberg 	if (attrs->vid == VLAN_NONE) {
1400205263acSAriel Ehrenberg 		clear_fte_vid(spec);
1401205263acSAriel Ehrenberg 		setup_fte_vid(spec, 0);
1402205263acSAriel Ehrenberg 		rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn);
1403205263acSAriel Ehrenberg 		if (IS_ERR(rule)) {
1404205263acSAriel Ehrenberg 			err = PTR_ERR(rule);
1405205263acSAriel Ehrenberg 			mlx5_core_err(mdev,
1406205263acSAriel Ehrenberg 			    "Failed to add RX IPsec policy rule err=%d\n",
1407205263acSAriel Ehrenberg 			    err);
1408205263acSAriel Ehrenberg 			goto err_action;
1409205263acSAriel Ehrenberg 		}
1410205263acSAriel Ehrenberg 		pol_entry->ipsec_rule.vid_zero_rule = rule;
1411205263acSAriel Ehrenberg 	}
1412e23731dbSKonstantin Belousov 
1413e23731dbSKonstantin Belousov 	kvfree(spec);
1414e23731dbSKonstantin Belousov         return 0;
1415e23731dbSKonstantin Belousov 
1416e23731dbSKonstantin Belousov err_action:
1417205263acSAriel Ehrenberg 	if (pol_entry->ipsec_rule.rule != NULL)
1418205263acSAriel Ehrenberg 		mlx5_del_flow_rules(&pol_entry->ipsec_rule.rule);
1419e23731dbSKonstantin Belousov 	kvfree(spec);
1420e23731dbSKonstantin Belousov err_alloc:
1421205263acSAriel Ehrenberg         if (rx->chains != NULL)
1422e23731dbSKonstantin Belousov                 ipsec_chains_put_table(rx->chains, attrs->prio);
1423e23731dbSKonstantin Belousov         return err;
1424e23731dbSKonstantin Belousov }
1425e23731dbSKonstantin Belousov 
ipsec_fs_destroy_counters(struct mlx5e_ipsec * ipsec)1426e23731dbSKonstantin Belousov static void ipsec_fs_destroy_counters(struct mlx5e_ipsec *ipsec)
1427e23731dbSKonstantin Belousov {
1428e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
1429e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = ipsec->mdev;
1430e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx *tx = ipsec->tx;
1431e23731dbSKonstantin Belousov 
1432e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, rx_ipv4->fc->drop);
1433e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt);
1434e23731dbSKonstantin Belousov 	kfree(rx_ipv4->fc);
1435e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, tx->fc->drop);
1436e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, tx->fc->cnt);
1437e23731dbSKonstantin Belousov 	kfree(tx->fc);
1438e23731dbSKonstantin Belousov }
1439e23731dbSKonstantin Belousov 
ipsec_fs_init_counters(struct mlx5e_ipsec * ipsec)1440e23731dbSKonstantin Belousov static int ipsec_fs_init_counters(struct mlx5e_ipsec *ipsec)
1441e23731dbSKonstantin Belousov {
1442e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
1443e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rx *rx_ipv6 = ipsec->rx_ipv6;
1444e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = ipsec->mdev;
1445e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_tx *tx = ipsec->tx;
1446e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_fc *fc;
1447e23731dbSKonstantin Belousov 	struct mlx5_fc *counter;
1448e23731dbSKonstantin Belousov 	int err;
1449e23731dbSKonstantin Belousov 
1450e23731dbSKonstantin Belousov 	fc = kzalloc(sizeof(*tx->fc), GFP_KERNEL);
1451e23731dbSKonstantin Belousov 	if (!fc)
1452e23731dbSKonstantin Belousov 		return -ENOMEM;
1453e23731dbSKonstantin Belousov 
1454e23731dbSKonstantin Belousov 	tx->fc = fc;
1455e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
1456e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
1457e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
1458e23731dbSKonstantin Belousov 		goto err_tx_fc_alloc;
1459e23731dbSKonstantin Belousov 	}
1460e23731dbSKonstantin Belousov 
1461e23731dbSKonstantin Belousov 	fc->cnt = counter;
1462e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
1463e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
1464e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
1465e23731dbSKonstantin Belousov 		goto err_tx_fc_cnt;
1466e23731dbSKonstantin Belousov 	}
1467e23731dbSKonstantin Belousov 
1468e23731dbSKonstantin Belousov 	fc->drop = counter;
1469e23731dbSKonstantin Belousov 
1470e23731dbSKonstantin Belousov 	fc = kzalloc(sizeof(*tx->fc), GFP_KERNEL);
1471e23731dbSKonstantin Belousov 	if (!fc) {
1472e23731dbSKonstantin Belousov 		err = -ENOMEM;
1473e23731dbSKonstantin Belousov 		goto err_tx_fc_drop;
1474e23731dbSKonstantin Belousov 	}
1475e23731dbSKonstantin Belousov 
1476e23731dbSKonstantin Belousov 	/* Both IPv4 and IPv6 point to same flow counters struct. */
1477e23731dbSKonstantin Belousov 	rx_ipv4->fc = fc;
1478e23731dbSKonstantin Belousov 	rx_ipv6->fc = fc;
1479e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
1480e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
1481e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
1482e23731dbSKonstantin Belousov 		goto err_rx_fc_alloc;
1483e23731dbSKonstantin Belousov 	}
1484e23731dbSKonstantin Belousov 
1485e23731dbSKonstantin Belousov 	fc->cnt = counter;
1486e23731dbSKonstantin Belousov 	counter = mlx5_fc_create(mdev, false);
1487e23731dbSKonstantin Belousov 	if (IS_ERR(counter)) {
1488e23731dbSKonstantin Belousov 		err = PTR_ERR(counter);
1489e23731dbSKonstantin Belousov 		goto err_rx_fc_cnt;
1490e23731dbSKonstantin Belousov 	}
1491e23731dbSKonstantin Belousov 
1492e23731dbSKonstantin Belousov 	fc->drop = counter;
1493e23731dbSKonstantin Belousov 	return 0;
1494e23731dbSKonstantin Belousov 
1495e23731dbSKonstantin Belousov err_rx_fc_cnt:
1496e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt);
1497e23731dbSKonstantin Belousov err_rx_fc_alloc:
1498e23731dbSKonstantin Belousov 	kfree(rx_ipv4->fc);
1499e23731dbSKonstantin Belousov err_tx_fc_drop:
1500e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, tx->fc->drop);
1501e23731dbSKonstantin Belousov err_tx_fc_cnt:
1502e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, tx->fc->cnt);
1503e23731dbSKonstantin Belousov err_tx_fc_alloc:
1504e23731dbSKonstantin Belousov 	kfree(tx->fc);
1505e23731dbSKonstantin Belousov 	return err;
1506e23731dbSKonstantin Belousov }
1507e23731dbSKonstantin Belousov 
ipsec_status_rule(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_rx * rx,struct mlx5_flow_destination * dest)1508e23731dbSKonstantin Belousov static int ipsec_status_rule(struct mlx5_core_dev *mdev,
1509e23731dbSKonstantin Belousov 			     struct mlx5e_ipsec_rx *rx,
1510e23731dbSKonstantin Belousov 			     struct mlx5_flow_destination *dest)
1511e23731dbSKonstantin Belousov {
1512e23731dbSKonstantin Belousov 	u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
1513e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
1514e23731dbSKonstantin Belousov 	struct mlx5_modify_hdr *modify_hdr;
1515e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
1516e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
1517e23731dbSKonstantin Belousov 	int err;
1518e23731dbSKonstantin Belousov 
1519e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1520e23731dbSKonstantin Belousov 	if (!spec)
1521e23731dbSKonstantin Belousov 		return -ENOMEM;
1522e23731dbSKonstantin Belousov 
1523e23731dbSKonstantin Belousov 	/* Action to copy 7 bit ipsec_syndrome to regB[24:30] */
1524e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
1525e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, src_field, MLX5_ACTION_IN_FIELD_IPSEC_SYNDROME);
1526e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, src_offset, 0);
1527e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, length, 7);
1528e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, dst_field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
1529e23731dbSKonstantin Belousov 	MLX5_SET(copy_action_in, action, dst_offset, 24);
1530e23731dbSKonstantin Belousov 
1531e23731dbSKonstantin Belousov 	modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
1532e23731dbSKonstantin Belousov 					      1, action);
1533e23731dbSKonstantin Belousov 
1534e23731dbSKonstantin Belousov 	if (IS_ERR(modify_hdr)) {
1535e23731dbSKonstantin Belousov 		err = PTR_ERR(modify_hdr);
1536e23731dbSKonstantin Belousov 		mlx5_core_err(mdev,
1537e23731dbSKonstantin Belousov 			      "fail to alloc ipsec copy modify_header_id err=%d\n", err);
1538e23731dbSKonstantin Belousov 		goto out_spec;
1539e23731dbSKonstantin Belousov 	}
1540e23731dbSKonstantin Belousov 
1541e23731dbSKonstantin Belousov 	/* create fte */
1542e23731dbSKonstantin Belousov 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
1543e23731dbSKonstantin Belousov 		MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1544e23731dbSKonstantin Belousov 		MLX5_FLOW_CONTEXT_ACTION_COUNT;
1545e23731dbSKonstantin Belousov 	flow_act.modify_hdr = modify_hdr;
1546e23731dbSKonstantin Belousov 
1547e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(rx->ft.status, spec, &flow_act, dest, 2);
1548e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1549e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1550e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "fail to add ipsec rx err copy rule err=%d\n", err);
1551e23731dbSKonstantin Belousov 		goto out;
1552e23731dbSKonstantin Belousov 	}
1553e23731dbSKonstantin Belousov 
1554e23731dbSKonstantin Belousov 	kvfree(spec);
1555e23731dbSKonstantin Belousov 	rx->status.rule = rule;
1556e23731dbSKonstantin Belousov 	rx->status.modify_hdr = modify_hdr;
1557e23731dbSKonstantin Belousov 	return 0;
1558e23731dbSKonstantin Belousov 
1559e23731dbSKonstantin Belousov out:
1560e23731dbSKonstantin Belousov 	mlx5_modify_header_dealloc(mdev, modify_hdr);
1561e23731dbSKonstantin Belousov out_spec:
1562e23731dbSKonstantin Belousov 	kvfree(spec);
1563e23731dbSKonstantin Belousov 	return err;
1564e23731dbSKonstantin Belousov }
1565e23731dbSKonstantin Belousov 
ipsec_fs_rx_roce_rules_destroy(struct mlx5e_ipsec_rx_roce * rx_roce)1566e23731dbSKonstantin Belousov static void ipsec_fs_rx_roce_rules_destroy(struct mlx5e_ipsec_rx_roce *rx_roce)
1567e23731dbSKonstantin Belousov {
1568e23731dbSKonstantin Belousov 	if (!rx_roce->ns_rdma)
1569e23731dbSKonstantin Belousov 		return;
1570e23731dbSKonstantin Belousov 
1571e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&rx_roce->roce_miss.rule);
1572e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&rx_roce->rule);
1573e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(rx_roce->roce_miss.group);
1574e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(rx_roce->g);
1575e23731dbSKonstantin Belousov }
1576e23731dbSKonstantin Belousov 
ipsec_fs_rx_catchall_rules_destroy(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_rx * rx)1577e23731dbSKonstantin Belousov static void ipsec_fs_rx_catchall_rules_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_rx *rx)
1578e23731dbSKonstantin Belousov {
1579e23731dbSKonstantin Belousov 	mutex_lock(&rx->ft.mutex);
1580e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&rx->sa.rule);
1581e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(rx->sa.group);
1582e23731dbSKonstantin Belousov 	if (rx->chains == NULL) {
1583e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&rx->pol.rule);
1584e23731dbSKonstantin Belousov 		mlx5_destroy_flow_group(rx->pol.group);
1585e23731dbSKonstantin Belousov 	}
1586e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&rx->status.rule);
1587e23731dbSKonstantin Belousov 	mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
1588e23731dbSKonstantin Belousov 	ipsec_fs_rx_roce_rules_destroy(&rx->roce);
1589e23731dbSKonstantin Belousov 	mutex_unlock(&rx->ft.mutex);
1590e23731dbSKonstantin Belousov }
1591e23731dbSKonstantin Belousov 
ipsec_fs_rx_roce_table_destroy(struct mlx5e_ipsec_rx_roce * rx_roce)1592e23731dbSKonstantin Belousov static void ipsec_fs_rx_roce_table_destroy(struct mlx5e_ipsec_rx_roce *rx_roce)
1593e23731dbSKonstantin Belousov {
1594e23731dbSKonstantin Belousov 	if (!rx_roce->ns_rdma)
1595e23731dbSKonstantin Belousov 		return;
1596e23731dbSKonstantin Belousov 
1597e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx_roce->ft_rdma);
1598e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx_roce->ft);
1599e23731dbSKonstantin Belousov }
1600e23731dbSKonstantin Belousov 
ipsec_fs_rx_table_destroy(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_rx * rx)1601e23731dbSKonstantin Belousov static void ipsec_fs_rx_table_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_rx *rx)
1602e23731dbSKonstantin Belousov {
1603e23731dbSKonstantin Belousov 	mutex_lock(&rx->ft.mutex);
1604e23731dbSKonstantin Belousov 	if (rx->chains) {
1605e23731dbSKonstantin Belousov 		ipsec_chains_destroy(rx->chains);
1606e23731dbSKonstantin Belousov 	} else {
1607e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&rx->pol.rule);
1608e23731dbSKonstantin Belousov 		mlx5_destroy_flow_table(rx->ft.pol);
1609e23731dbSKonstantin Belousov         }
1610e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->ft.sa);
1611e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->ft.status);
1612e23731dbSKonstantin Belousov 	ipsec_fs_rx_roce_table_destroy(&rx->roce);
1613e23731dbSKonstantin Belousov 	mutex_unlock(&rx->ft.mutex);
1614e23731dbSKonstantin Belousov }
1615e23731dbSKonstantin Belousov 
ipsec_roce_setup_udp_dport(struct mlx5_flow_spec * spec,u16 dport)1616e23731dbSKonstantin Belousov static void ipsec_roce_setup_udp_dport(struct mlx5_flow_spec *spec, u16 dport)
1617e23731dbSKonstantin Belousov {
1618e23731dbSKonstantin Belousov 	spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
1619e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
1620e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_UDP);
1621e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport);
1622e23731dbSKonstantin Belousov 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, dport);
1623e23731dbSKonstantin Belousov }
1624e23731dbSKonstantin Belousov 
ipsec_roce_rx_rule_setup(struct mlx5_flow_destination * default_dst,struct mlx5e_ipsec_rx_roce * roce,struct mlx5_core_dev * mdev)1625e23731dbSKonstantin Belousov static int ipsec_roce_rx_rule_setup(struct mlx5_flow_destination *default_dst,
1626e23731dbSKonstantin Belousov 				    struct mlx5e_ipsec_rx_roce *roce, struct mlx5_core_dev *mdev)
1627e23731dbSKonstantin Belousov {
1628e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dst = {};
1629e23731dbSKonstantin Belousov 	struct mlx5_flow_act flow_act = {};
1630e23731dbSKonstantin Belousov 	struct mlx5_flow_handle *rule;
1631e23731dbSKonstantin Belousov 	struct mlx5_flow_spec *spec;
1632e23731dbSKonstantin Belousov 	int err = 0;
1633e23731dbSKonstantin Belousov 
1634e23731dbSKonstantin Belousov 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1635e23731dbSKonstantin Belousov 	if (!spec)
1636e23731dbSKonstantin Belousov 		return -ENOMEM;
1637e23731dbSKonstantin Belousov 
1638e23731dbSKonstantin Belousov 	ipsec_roce_setup_udp_dport(spec, ROCE_V2_UDP_DPORT);
1639e23731dbSKonstantin Belousov 
1640e23731dbSKonstantin Belousov 	//flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;//not needed it is added in command
1641e23731dbSKonstantin Belousov 	dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
1642e23731dbSKonstantin Belousov 	dst.ft = roce->ft_rdma;
1643e23731dbSKonstantin Belousov 
1644e23731dbSKonstantin Belousov 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1645e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
1646e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1647e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1648e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add RX roce ipsec rule err=%d\n",
1649e23731dbSKonstantin Belousov 			      err);
1650e23731dbSKonstantin Belousov 		goto fail_add_rule;
1651e23731dbSKonstantin Belousov 	}
1652e23731dbSKonstantin Belousov 
1653e23731dbSKonstantin Belousov 	roce->rule = rule;
1654e23731dbSKonstantin Belousov 
1655e23731dbSKonstantin Belousov 	rule = mlx5_add_flow_rules(roce->ft, NULL, &flow_act, default_dst, 1);
1656e23731dbSKonstantin Belousov 	if (IS_ERR(rule)) {
1657e23731dbSKonstantin Belousov 		err = PTR_ERR(rule);
1658e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to add RX roce ipsec miss rule err=%d\n",
1659e23731dbSKonstantin Belousov 			      err);
1660e23731dbSKonstantin Belousov 		goto fail_add_default_rule;
1661e23731dbSKonstantin Belousov 	}
1662e23731dbSKonstantin Belousov 
1663e23731dbSKonstantin Belousov 	roce->roce_miss.rule = rule;
1664e23731dbSKonstantin Belousov 
1665e23731dbSKonstantin Belousov 	kvfree(spec);
1666e23731dbSKonstantin Belousov 	return 0;
1667e23731dbSKonstantin Belousov 
1668e23731dbSKonstantin Belousov fail_add_default_rule:
1669e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&roce->rule);
1670e23731dbSKonstantin Belousov fail_add_rule:
1671e23731dbSKonstantin Belousov 	kvfree(spec);
1672e23731dbSKonstantin Belousov 	return err;
1673e23731dbSKonstantin Belousov }
1674e23731dbSKonstantin Belousov 
ipsec_roce_rx_rules(struct mlx5e_ipsec_rx * rx,struct mlx5_flow_destination * defdst,struct mlx5_core_dev * mdev)1675e23731dbSKonstantin Belousov static int ipsec_roce_rx_rules(struct mlx5e_ipsec_rx *rx, struct mlx5_flow_destination *defdst,
1676e23731dbSKonstantin Belousov 			       struct mlx5_core_dev *mdev)
1677e23731dbSKonstantin Belousov {
1678e23731dbSKonstantin Belousov 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1679e23731dbSKonstantin Belousov 	struct mlx5_flow_group *g;
1680e23731dbSKonstantin Belousov 	void *outer_headers_c;
1681e23731dbSKonstantin Belousov 	u32 *in;
1682e23731dbSKonstantin Belousov 	int err = 0;
1683e23731dbSKonstantin Belousov 	int ix = 0;
1684e23731dbSKonstantin Belousov 	u8 *mc;
1685e23731dbSKonstantin Belousov 
1686e23731dbSKonstantin Belousov 	if (!rx->roce.ns_rdma)
1687e23731dbSKonstantin Belousov 		return 0;
1688e23731dbSKonstantin Belousov 
1689e23731dbSKonstantin Belousov 	in = kvzalloc(inlen, GFP_KERNEL);
1690e23731dbSKonstantin Belousov 	if (!in)
1691e23731dbSKonstantin Belousov 		return -ENOMEM;
1692e23731dbSKonstantin Belousov 
1693e23731dbSKonstantin Belousov 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
1694e23731dbSKonstantin Belousov 	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
1695e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
1696e23731dbSKonstantin Belousov 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
1697e23731dbSKonstantin Belousov 
1698e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1699e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, start_flow_index, ix);
1700e23731dbSKonstantin Belousov 	ix += 1;
1701e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
1702e23731dbSKonstantin Belousov 	g = mlx5_create_flow_group(rx->roce.ft, in);
1703e23731dbSKonstantin Belousov 	if (IS_ERR(g)) {
1704e23731dbSKonstantin Belousov 		err = PTR_ERR(g);
1705e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to create ipsec rx roce group at nic err=%d\n", err);
1706e23731dbSKonstantin Belousov 		goto fail_group;
1707e23731dbSKonstantin Belousov 	}
1708e23731dbSKonstantin Belousov 	rx->roce.g = g;
1709e23731dbSKonstantin Belousov 
1710e23731dbSKonstantin Belousov 	memset(in, 0, MLX5_ST_SZ_BYTES(create_flow_group_in));
1711e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, start_flow_index, ix);
1712e23731dbSKonstantin Belousov 	ix += 1;
1713e23731dbSKonstantin Belousov 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
1714e23731dbSKonstantin Belousov 	g = mlx5_create_flow_group(rx->roce.ft, in);
1715e23731dbSKonstantin Belousov 	if (IS_ERR(g)) {
1716e23731dbSKonstantin Belousov 		err = PTR_ERR(g);
1717e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Fail to create ipsec rx roce miss group at nic err=%d\n",
1718e23731dbSKonstantin Belousov 			      err);
1719e23731dbSKonstantin Belousov 		goto fail_mgroup;
1720e23731dbSKonstantin Belousov 	}
1721e23731dbSKonstantin Belousov 	rx->roce.roce_miss.group = g;
1722e23731dbSKonstantin Belousov 
1723e23731dbSKonstantin Belousov 	err = ipsec_roce_rx_rule_setup(defdst, &rx->roce, mdev);
1724e23731dbSKonstantin Belousov 	if (err)
1725e23731dbSKonstantin Belousov 		goto fail_setup_rule;
1726e23731dbSKonstantin Belousov 
1727e23731dbSKonstantin Belousov 	kvfree(in);
1728e23731dbSKonstantin Belousov 	return 0;
1729e23731dbSKonstantin Belousov 
1730e23731dbSKonstantin Belousov fail_setup_rule:
1731e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(rx->roce.roce_miss.group);
1732e23731dbSKonstantin Belousov fail_mgroup:
1733e23731dbSKonstantin Belousov 	mlx5_destroy_flow_group(rx->roce.g);
1734e23731dbSKonstantin Belousov fail_group:
1735e23731dbSKonstantin Belousov 	kvfree(in);
1736e23731dbSKonstantin Belousov 	return err;
1737e23731dbSKonstantin Belousov }
1738e23731dbSKonstantin Belousov 
ipsec_fs_rx_catchall_rules(struct mlx5e_priv * priv,struct mlx5e_ipsec_rx * rx,struct mlx5_flow_destination * defdst)1739e23731dbSKonstantin Belousov static int ipsec_fs_rx_catchall_rules(struct mlx5e_priv *priv,
1740e23731dbSKonstantin Belousov 				      struct mlx5e_ipsec_rx *rx,
1741e23731dbSKonstantin Belousov 				      struct mlx5_flow_destination *defdst)
1742e23731dbSKonstantin Belousov {
1743e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = priv->mdev;
1744e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest[2] = {};
1745e23731dbSKonstantin Belousov 	int err = 0;
1746e23731dbSKonstantin Belousov 
1747e23731dbSKonstantin Belousov 	mutex_lock(&rx->ft.mutex);
1748e23731dbSKonstantin Belousov 	/* IPsec RoCE RX rules */
1749e23731dbSKonstantin Belousov 	err = ipsec_roce_rx_rules(rx, defdst, mdev);
1750e23731dbSKonstantin Belousov 	if (err)
1751e23731dbSKonstantin Belousov 		goto out;
1752e23731dbSKonstantin Belousov 
1753e23731dbSKonstantin Belousov 	/* IPsec Rx IP Status table rule */
1754e23731dbSKonstantin Belousov 	dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1755e23731dbSKonstantin Belousov 	if (rx->roce.ft)
1756e23731dbSKonstantin Belousov 		dest[0].ft = rx->roce.ft;
1757e23731dbSKonstantin Belousov 	else
1758e23731dbSKonstantin Belousov 		dest[0].ft = priv->fts.vlan.t;
1759e23731dbSKonstantin Belousov 
1760e23731dbSKonstantin Belousov 	dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1761e23731dbSKonstantin Belousov         dest[1].counter_id = mlx5_fc_id(rx->fc->cnt);
1762e23731dbSKonstantin Belousov         err = ipsec_status_rule(mdev, rx, dest);
1763e23731dbSKonstantin Belousov         if (err)
1764e23731dbSKonstantin Belousov                 goto err_roce_rules_destroy;
1765e23731dbSKonstantin Belousov 
1766e23731dbSKonstantin Belousov 	if (!rx->chains) {
1767e23731dbSKonstantin Belousov 		/* IPsec Rx IP policy default miss rule */
1768e23731dbSKonstantin Belousov 		err = ipsec_miss_create(mdev, rx->ft.pol, &rx->pol, defdst);
1769e23731dbSKonstantin Belousov 		if (err)
1770e23731dbSKonstantin Belousov 			goto err_status_rule_destroy;
1771e23731dbSKonstantin Belousov 	}
1772e23731dbSKonstantin Belousov 
1773e23731dbSKonstantin Belousov 	/* FIXME: This is workaround to current design
1774e23731dbSKonstantin Belousov 	 * which installs SA on firt packet. So we need to forward this
1775e23731dbSKonstantin Belousov 	 * packet to the stack. It doesn't work with RoCE and eswitch traffic,
1776e23731dbSKonstantin Belousov 	 */
1777e23731dbSKonstantin Belousov 	err = ipsec_miss_create(mdev, rx->ft.sa, &rx->sa, defdst);
1778e23731dbSKonstantin Belousov 	if (err)
1779e23731dbSKonstantin Belousov 		goto err_status_sa_rule_destroy;
1780e23731dbSKonstantin Belousov 
1781e23731dbSKonstantin Belousov 	mutex_unlock(&rx->ft.mutex);
1782e23731dbSKonstantin Belousov 	return 0;
1783e23731dbSKonstantin Belousov 
1784e23731dbSKonstantin Belousov err_status_sa_rule_destroy:
1785e23731dbSKonstantin Belousov 	if (!rx->chains) {
1786e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&rx->pol.rule);
1787e23731dbSKonstantin Belousov 		mlx5_destroy_flow_group(rx->pol.group);
1788e23731dbSKonstantin Belousov 	}
1789e23731dbSKonstantin Belousov err_status_rule_destroy:
1790e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&rx->status.rule);
1791e23731dbSKonstantin Belousov 	mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
1792e23731dbSKonstantin Belousov err_roce_rules_destroy:
1793e23731dbSKonstantin Belousov 	ipsec_fs_rx_roce_rules_destroy(&rx->roce);
1794e23731dbSKonstantin Belousov out:
1795e23731dbSKonstantin Belousov 	mutex_unlock(&rx->ft.mutex);
1796e23731dbSKonstantin Belousov 	return err;
1797e23731dbSKonstantin Belousov }
1798e23731dbSKonstantin Belousov 
ipsec_fs_rx_roce_tables_create(struct mlx5e_ipsec_rx * rx,int rx_init_level,int rdma_init_level)1799e23731dbSKonstantin Belousov static int ipsec_fs_rx_roce_tables_create(struct mlx5e_ipsec_rx *rx,
1800e23731dbSKonstantin Belousov 					  int rx_init_level, int rdma_init_level)
1801e23731dbSKonstantin Belousov {
1802e23731dbSKonstantin Belousov 	struct mlx5_flow_table_attr ft_attr = {};
1803e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
1804e23731dbSKonstantin Belousov 	int err = 0;
1805e23731dbSKonstantin Belousov 
1806e23731dbSKonstantin Belousov 	if (!rx->roce.ns_rdma)
1807e23731dbSKonstantin Belousov 		return 0;
1808e23731dbSKonstantin Belousov 
1809e23731dbSKonstantin Belousov 	ft_attr.max_fte = 2;
1810e23731dbSKonstantin Belousov 	ft_attr.level = rx_init_level;
1811e23731dbSKonstantin Belousov 	ft = mlx5_create_flow_table(rx->ns, &ft_attr);
1812e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
1813e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
1814e23731dbSKonstantin Belousov 		return err;
1815e23731dbSKonstantin Belousov 	}
1816e23731dbSKonstantin Belousov 	rx->roce.ft = ft;
1817e23731dbSKonstantin Belousov 
1818e23731dbSKonstantin Belousov 	ft_attr.max_fte = 0;
1819e23731dbSKonstantin Belousov 	ft_attr.level = rdma_init_level;
1820e23731dbSKonstantin Belousov 	ft = mlx5_create_flow_table(rx->roce.ns_rdma, &ft_attr);
1821e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
1822e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
1823e23731dbSKonstantin Belousov 		goto out;
1824e23731dbSKonstantin Belousov 	}
1825e23731dbSKonstantin Belousov 	rx->roce.ft_rdma = ft;
1826e23731dbSKonstantin Belousov 
1827e23731dbSKonstantin Belousov 	return 0;
1828e23731dbSKonstantin Belousov out:
1829e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->roce.ft);
1830e23731dbSKonstantin Belousov 	rx->roce.ft = NULL;
1831e23731dbSKonstantin Belousov 	return err;
1832e23731dbSKonstantin Belousov }
1833e23731dbSKonstantin Belousov 
ipsec_fs_rx_table_create(struct mlx5_core_dev * mdev,struct mlx5e_ipsec_rx * rx,int rx_init_level,int rdma_init_level)1834e23731dbSKonstantin Belousov static int ipsec_fs_rx_table_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_rx *rx,
1835e23731dbSKonstantin Belousov 				    int rx_init_level, int rdma_init_level)
1836e23731dbSKonstantin Belousov {
1837e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns = rx->ns;
1838e23731dbSKonstantin Belousov 	struct mlx5_flow_table *ft;
1839e23731dbSKonstantin Belousov 	int err = 0;
1840e23731dbSKonstantin Belousov 
1841e23731dbSKonstantin Belousov 	mutex_lock(&rx->ft.mutex);
1842e23731dbSKonstantin Belousov 
1843e23731dbSKonstantin Belousov 	/* IPsec Rx IP SA table create */
1844e23731dbSKonstantin Belousov 	ft = ipsec_rx_ft_create(ns, rx_init_level + 1, 0, 1);
1845e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
1846e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
1847e23731dbSKonstantin Belousov 		goto out;
1848e23731dbSKonstantin Belousov 	}
1849e23731dbSKonstantin Belousov 	rx->ft.sa = ft;
1850e23731dbSKonstantin Belousov 
1851e23731dbSKonstantin Belousov 	/* IPsec Rx IP Status table create */
1852e23731dbSKonstantin Belousov 	ft = ipsec_rx_ft_create(ns, rx_init_level + 2, 0, 1);
1853e23731dbSKonstantin Belousov 	if (IS_ERR(ft)) {
1854e23731dbSKonstantin Belousov 		err = PTR_ERR(ft);
1855e23731dbSKonstantin Belousov 		goto err_sa_table_destroy;
1856e23731dbSKonstantin Belousov 	}
1857e23731dbSKonstantin Belousov 	rx->ft.status = ft;
1858e23731dbSKonstantin Belousov 
1859e23731dbSKonstantin Belousov 	if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
1860e23731dbSKonstantin Belousov 		rx->chains = ipsec_chains_create(mdev, rx->ft.sa,
1861e23731dbSKonstantin Belousov 				MLX5_FLOW_NAMESPACE_KERNEL, 0,
1862e23731dbSKonstantin Belousov 				rx_init_level, &rx->ft.pol);
1863e23731dbSKonstantin Belousov 		if (IS_ERR(rx->chains)) {
1864e23731dbSKonstantin Belousov 			err = PTR_ERR(rx->chains);
1865e23731dbSKonstantin Belousov 			goto err_status_table_destroy;
1866e23731dbSKonstantin Belousov 		}
1867e23731dbSKonstantin Belousov 	} else {
1868e23731dbSKonstantin Belousov 		ft = ipsec_rx_ft_create(ns, rx_init_level, 0, 1);
1869e23731dbSKonstantin Belousov 		if (IS_ERR(ft)) {
1870e23731dbSKonstantin Belousov 			err = PTR_ERR(ft);
1871e23731dbSKonstantin Belousov 			goto err_status_table_destroy;
1872e23731dbSKonstantin Belousov 		}
1873e23731dbSKonstantin Belousov 		rx->ft.pol = ft;
1874e23731dbSKonstantin Belousov 	}
1875e23731dbSKonstantin Belousov 
1876e23731dbSKonstantin Belousov 	/* IPsec RoCE RX tables create*/
1877e23731dbSKonstantin Belousov 	err = ipsec_fs_rx_roce_tables_create(rx, rx_init_level + 3,
1878e23731dbSKonstantin Belousov 					     rdma_init_level);
1879e23731dbSKonstantin Belousov 	if (err)
1880e23731dbSKonstantin Belousov 		goto err_pol_table_destroy;
1881e23731dbSKonstantin Belousov 
1882e23731dbSKonstantin Belousov 	goto out;
1883e23731dbSKonstantin Belousov 
1884e23731dbSKonstantin Belousov err_pol_table_destroy:
1885e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->ft.pol);
1886e23731dbSKonstantin Belousov err_status_table_destroy:
1887e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->ft.status);
1888e23731dbSKonstantin Belousov err_sa_table_destroy:
1889e23731dbSKonstantin Belousov 	mlx5_destroy_flow_table(rx->ft.sa);
1890e23731dbSKonstantin Belousov out:
1891e23731dbSKonstantin Belousov 	mutex_unlock(&rx->ft.mutex);
1892e23731dbSKonstantin Belousov 	return err;
1893e23731dbSKonstantin Belousov }
1894e23731dbSKonstantin Belousov 
1895e23731dbSKonstantin Belousov #define NIC_RDMA_BOTH_DIRS_CAPS (MLX5_FT_NIC_RX_2_NIC_RX_RDMA | MLX5_FT_NIC_TX_RDMA_2_NIC_TX)
1896e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_init_roce(struct mlx5e_ipsec * ipsec)1897e23731dbSKonstantin Belousov static void mlx5e_accel_ipsec_fs_init_roce(struct mlx5e_ipsec *ipsec)
1898e23731dbSKonstantin Belousov {
1899e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = ipsec->mdev;
1900e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *ns;
1901e23731dbSKonstantin Belousov 
1902e23731dbSKonstantin Belousov 	if ((MLX5_CAP_GEN_2(ipsec->mdev, flow_table_type_2_type) &
1903e23731dbSKonstantin Belousov 	      NIC_RDMA_BOTH_DIRS_CAPS) != NIC_RDMA_BOTH_DIRS_CAPS) {
1904e23731dbSKonstantin Belousov 		mlx5_core_dbg(mdev, "Failed to init roce ns, capabilities not supported\n");
1905e23731dbSKonstantin Belousov 		return;
1906e23731dbSKonstantin Belousov 	}
1907e23731dbSKonstantin Belousov 
1908e23731dbSKonstantin Belousov 	ns = mlx5_get_flow_namespace(ipsec->mdev, MLX5_FLOW_NAMESPACE_RDMA_RX_IPSEC);
1909e23731dbSKonstantin Belousov 	if (!ns) {
1910e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Failed to init roce rx ns\n");
1911e23731dbSKonstantin Belousov 		return;
1912e23731dbSKonstantin Belousov 	}
1913e23731dbSKonstantin Belousov 
1914e23731dbSKonstantin Belousov 	ipsec->rx_ipv4->roce.ns_rdma = ns;
1915e23731dbSKonstantin Belousov 	ipsec->rx_ipv6->roce.ns_rdma = ns;
1916e23731dbSKonstantin Belousov 
1917e23731dbSKonstantin Belousov 	ns = mlx5_get_flow_namespace(ipsec->mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_IPSEC);
1918e23731dbSKonstantin Belousov 	if (!ns) {
1919e23731dbSKonstantin Belousov 		ipsec->rx_ipv4->roce.ns_rdma = NULL;
1920e23731dbSKonstantin Belousov 		ipsec->rx_ipv6->roce.ns_rdma = NULL;
1921e23731dbSKonstantin Belousov 		mlx5_core_err(mdev, "Failed to init roce tx ns\n");
1922e23731dbSKonstantin Belousov 		return;
1923e23731dbSKonstantin Belousov 	}
1924e23731dbSKonstantin Belousov 
1925e23731dbSKonstantin Belousov 	ipsec->tx->roce.ns = ns;
1926e23731dbSKonstantin Belousov }
1927e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry * sa_entry)1928e23731dbSKonstantin Belousov int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
1929e23731dbSKonstantin Belousov {
1930e23731dbSKonstantin Belousov 	if (sa_entry->attrs.dir == IPSEC_DIR_OUTBOUND)
1931e23731dbSKonstantin Belousov 		return tx_add_rule(sa_entry);
1932e23731dbSKonstantin Belousov 
1933e23731dbSKonstantin Belousov 	return rx_add_rule(sa_entry);
1934e23731dbSKonstantin Belousov }
1935e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry * sa_entry)1936e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
1937e23731dbSKonstantin Belousov {
1938e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
1939e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
1940e23731dbSKonstantin Belousov 
1941e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&ipsec_rule->rule);
1942e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&ipsec_rule->kspi_rule);
1943205263acSAriel Ehrenberg 	if (ipsec_rule->vid_zero_rule != NULL)
1944205263acSAriel Ehrenberg 		mlx5_del_flow_rules(&ipsec_rule->vid_zero_rule);
1945205263acSAriel Ehrenberg 	if (ipsec_rule->reqid_rule != NULL)
1946e23731dbSKonstantin Belousov 		mlx5_del_flow_rules(&ipsec_rule->reqid_rule);
1947e23731dbSKonstantin Belousov 	mlx5_fc_destroy(mdev, ipsec_rule->fc);
1948e23731dbSKonstantin Belousov 	mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat);
1949e23731dbSKonstantin Belousov 	if (sa_entry->attrs.dir == IPSEC_DIR_OUTBOUND) {
1950e23731dbSKonstantin Belousov 		tx_ft_put(sa_entry->ipsec);
1951e23731dbSKonstantin Belousov 		return;
1952e23731dbSKonstantin Belousov 	}
1953e23731dbSKonstantin Belousov 
1954205263acSAriel Ehrenberg 	if (ipsec_rule->modify_hdr != NULL)
1955e23731dbSKonstantin Belousov 		mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
1956e23731dbSKonstantin Belousov }
1957e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry * pol_entry)1958e23731dbSKonstantin Belousov int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
1959e23731dbSKonstantin Belousov {
1960e23731dbSKonstantin Belousov 	if (pol_entry->attrs.dir == IPSEC_DIR_OUTBOUND)
1961e23731dbSKonstantin Belousov 		return tx_add_policy(pol_entry);
1962e23731dbSKonstantin Belousov 
1963e23731dbSKonstantin Belousov 	return rx_add_policy(pol_entry);
1964e23731dbSKonstantin Belousov }
1965e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry * pol_entry)1966e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
1967e23731dbSKonstantin Belousov {
1968e23731dbSKonstantin Belousov 	struct mlx5e_ipsec_rule *ipsec_rule = &pol_entry->ipsec_rule;
1969e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
1970e23731dbSKonstantin Belousov 
1971e23731dbSKonstantin Belousov 	mlx5_del_flow_rules(&ipsec_rule->rule);
1972205263acSAriel Ehrenberg 	if (ipsec_rule->vid_zero_rule != NULL)
1973205263acSAriel Ehrenberg 		mlx5_del_flow_rules(&ipsec_rule->vid_zero_rule);
1974e23731dbSKonstantin Belousov 
1975e23731dbSKonstantin Belousov 	if (pol_entry->attrs.dir == IPSEC_DIR_INBOUND) {
1976e23731dbSKonstantin Belousov 		struct mlx5e_ipsec_rx *rx;
1977e23731dbSKonstantin Belousov 
1978e23731dbSKonstantin Belousov                 rx = (pol_entry->attrs.family == AF_INET)
1979e23731dbSKonstantin Belousov                          ? pol_entry->ipsec->rx_ipv4
1980e23731dbSKonstantin Belousov                          : pol_entry->ipsec->rx_ipv6;
1981e23731dbSKonstantin Belousov                 if (rx->chains)
1982e23731dbSKonstantin Belousov                         ipsec_chains_put_table(rx->chains,
1983e23731dbSKonstantin Belousov                                                pol_entry->attrs.prio);
1984e23731dbSKonstantin Belousov                 return;
1985e23731dbSKonstantin Belousov 	}
1986e23731dbSKonstantin Belousov 
1987e23731dbSKonstantin Belousov 	if (ipsec_rule->modify_hdr)
1988e23731dbSKonstantin Belousov 		mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
1989e23731dbSKonstantin Belousov 
1990e23731dbSKonstantin Belousov 	tx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.prio);
1991e23731dbSKonstantin Belousov }
1992e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_rx_catchall_rules_destroy(struct mlx5e_priv * priv)1993e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_rx_catchall_rules_destroy(struct mlx5e_priv *priv)
1994e23731dbSKonstantin Belousov {
1995e23731dbSKonstantin Belousov 	/* Check if IPsec supported */
1996e23731dbSKonstantin Belousov 	if (!priv->ipsec)
1997e23731dbSKonstantin Belousov 		return;
1998e23731dbSKonstantin Belousov 
1999e23731dbSKonstantin Belousov 	ipsec_fs_rx_catchall_rules_destroy(priv->mdev, priv->ipsec->rx_ipv4);
2000e23731dbSKonstantin Belousov 	ipsec_fs_rx_catchall_rules_destroy(priv->mdev, priv->ipsec->rx_ipv6);
2001e23731dbSKonstantin Belousov }
2002e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_rx_catchall_rules(struct mlx5e_priv * priv)2003e23731dbSKonstantin Belousov int mlx5e_accel_ipsec_fs_rx_catchall_rules(struct mlx5e_priv *priv)
2004e23731dbSKonstantin Belousov {
2005e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = priv->ipsec;
2006e23731dbSKonstantin Belousov 	struct mlx5_flow_destination dest = {};
2007e23731dbSKonstantin Belousov 	int err = 0;
2008e23731dbSKonstantin Belousov 
2009e23731dbSKonstantin Belousov 	/* Check if IPsec supported */
2010e23731dbSKonstantin Belousov 	if (!ipsec)
2011e23731dbSKonstantin Belousov 		return 0;
2012e23731dbSKonstantin Belousov 
2013e23731dbSKonstantin Belousov 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2014e23731dbSKonstantin Belousov 	dest.ft = priv->fts.vlan.t;
2015e23731dbSKonstantin Belousov 	err = ipsec_fs_rx_catchall_rules(priv, ipsec->rx_ipv6, &dest);
2016e23731dbSKonstantin Belousov 	if (err)
2017e23731dbSKonstantin Belousov 		goto out;
2018e23731dbSKonstantin Belousov 
2019e23731dbSKonstantin Belousov 	err = ipsec_fs_rx_catchall_rules(priv, ipsec->rx_ipv4, &dest);
2020e23731dbSKonstantin Belousov 	if (err)
2021e23731dbSKonstantin Belousov 		ipsec_fs_rx_catchall_rules_destroy(priv->mdev, priv->ipsec->rx_ipv6);
2022e23731dbSKonstantin Belousov out:
2023e23731dbSKonstantin Belousov 	return err;
2024e23731dbSKonstantin Belousov }
2025e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_rx_tables_destroy(struct mlx5e_priv * priv)2026e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_rx_tables_destroy(struct mlx5e_priv *priv)
2027e23731dbSKonstantin Belousov {
2028e23731dbSKonstantin Belousov 	struct mlx5_core_dev *mdev = priv->mdev;
2029e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = priv->ipsec;
2030e23731dbSKonstantin Belousov 
2031e23731dbSKonstantin Belousov 	/* Check if IPsec supported */
2032e23731dbSKonstantin Belousov 	if (!ipsec)
2033e23731dbSKonstantin Belousov 		return;
2034e23731dbSKonstantin Belousov 
2035e23731dbSKonstantin Belousov 	ipsec_fs_rx_table_destroy(mdev, ipsec->rx_ipv6);
2036e23731dbSKonstantin Belousov 	ipsec_fs_rx_table_destroy(mdev, ipsec->rx_ipv4);
2037e23731dbSKonstantin Belousov }
2038e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_rx_tables_create(struct mlx5e_priv * priv)2039e23731dbSKonstantin Belousov int mlx5e_accel_ipsec_fs_rx_tables_create(struct mlx5e_priv *priv)
2040e23731dbSKonstantin Belousov {
2041e23731dbSKonstantin Belousov 	struct mlx5e_ipsec *ipsec = priv->ipsec;
2042e23731dbSKonstantin Belousov 	int err = 0;
2043e23731dbSKonstantin Belousov 
2044e23731dbSKonstantin Belousov 	/* Check if IPsec supported */
2045e23731dbSKonstantin Belousov 	if (!ipsec)
2046e23731dbSKonstantin Belousov 		return 0;
2047e23731dbSKonstantin Belousov 
2048e23731dbSKonstantin Belousov 	err = ipsec_fs_rx_table_create(ipsec->mdev, ipsec->rx_ipv4, 0, 0);
2049e23731dbSKonstantin Belousov 	if (err)
2050e23731dbSKonstantin Belousov 		goto out;
2051e23731dbSKonstantin Belousov 
2052e23731dbSKonstantin Belousov 	err = ipsec_fs_rx_table_create(ipsec->mdev, ipsec->rx_ipv6, 4, 1);
2053e23731dbSKonstantin Belousov 	if (err) {
2054e23731dbSKonstantin Belousov 		ipsec_fs_rx_table_destroy(priv->mdev, ipsec->rx_ipv4);
2055e23731dbSKonstantin Belousov 		goto out;
2056e23731dbSKonstantin Belousov 	}
2057e23731dbSKonstantin Belousov 
2058e23731dbSKonstantin Belousov 	priv->fts.ipsec_ft = priv->ipsec->rx_ipv4->ft.pol;
2059e23731dbSKonstantin Belousov out:
2060e23731dbSKonstantin Belousov 	return err;
2061e23731dbSKonstantin Belousov }
2062e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec * ipsec)2063e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
2064e23731dbSKonstantin Belousov {
2065e23731dbSKonstantin Belousov 	WARN_ON(ipsec->tx->ft.refcnt);
2066e23731dbSKonstantin Belousov 	mutex_destroy(&ipsec->rx_ipv6->ft.mutex);
2067e23731dbSKonstantin Belousov 	mutex_destroy(&ipsec->rx_ipv4->ft.mutex);
2068e23731dbSKonstantin Belousov 	mutex_destroy(&ipsec->tx->ft.mutex);
2069e23731dbSKonstantin Belousov 	ipsec_fs_destroy_counters(ipsec);
2070e23731dbSKonstantin Belousov 	kfree(ipsec->rx_ipv6);
2071e23731dbSKonstantin Belousov 	kfree(ipsec->rx_ipv4);
2072e23731dbSKonstantin Belousov 	kfree(ipsec->tx);
2073e23731dbSKonstantin Belousov }
2074e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec * ipsec)2075e23731dbSKonstantin Belousov int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
2076e23731dbSKonstantin Belousov {
2077e23731dbSKonstantin Belousov 	struct mlx5_flow_namespace *tns, *rns;
2078e23731dbSKonstantin Belousov 	int err = -ENOMEM;
2079e23731dbSKonstantin Belousov 
2080e23731dbSKonstantin Belousov 	tns = mlx5_get_flow_namespace(ipsec->mdev, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
2081e23731dbSKonstantin Belousov 	if (!tns)
2082e23731dbSKonstantin Belousov 		return -EOPNOTSUPP;
2083e23731dbSKonstantin Belousov 
2084e23731dbSKonstantin Belousov 	rns = mlx5_get_flow_namespace(ipsec->mdev, MLX5_FLOW_NAMESPACE_KERNEL);
2085e23731dbSKonstantin Belousov 	if (!rns)
2086e23731dbSKonstantin Belousov 		return -EOPNOTSUPP;
2087e23731dbSKonstantin Belousov 
2088e23731dbSKonstantin Belousov 	ipsec->tx = kzalloc(sizeof(*ipsec->tx), GFP_KERNEL);
2089e23731dbSKonstantin Belousov 	if (!ipsec->tx)
2090e23731dbSKonstantin Belousov 		return -ENOMEM;
2091e23731dbSKonstantin Belousov 
2092e23731dbSKonstantin Belousov 	ipsec->rx_ipv4 = kzalloc(sizeof(*ipsec->rx_ipv4), GFP_KERNEL);
2093e23731dbSKonstantin Belousov 	if (!ipsec->rx_ipv4)
2094e23731dbSKonstantin Belousov 		goto err_tx;
2095e23731dbSKonstantin Belousov 
2096e23731dbSKonstantin Belousov 	ipsec->rx_ipv6 = kzalloc(sizeof(*ipsec->rx_ipv6), GFP_KERNEL);
2097e23731dbSKonstantin Belousov 	if (!ipsec->rx_ipv6)
2098e23731dbSKonstantin Belousov 		goto err_rx_ipv4;
2099e23731dbSKonstantin Belousov 
2100e23731dbSKonstantin Belousov 	err = ipsec_fs_init_counters(ipsec);
2101e23731dbSKonstantin Belousov 	if (err)
2102e23731dbSKonstantin Belousov 		goto err_rx_ipv6;
2103e23731dbSKonstantin Belousov 
2104e23731dbSKonstantin Belousov 	ipsec->tx->ns = tns;
2105e23731dbSKonstantin Belousov 	mutex_init(&ipsec->tx->ft.mutex);
2106e23731dbSKonstantin Belousov 	ipsec->rx_ipv4->ns = rns;
2107e23731dbSKonstantin Belousov 	ipsec->rx_ipv6->ns = rns;
2108e23731dbSKonstantin Belousov 	mutex_init(&ipsec->rx_ipv4->ft.mutex);
2109e23731dbSKonstantin Belousov 	mutex_init(&ipsec->rx_ipv6->ft.mutex);
2110e23731dbSKonstantin Belousov 
2111e23731dbSKonstantin Belousov 	mlx5e_accel_ipsec_fs_init_roce(ipsec);
2112e23731dbSKonstantin Belousov 
2113e23731dbSKonstantin Belousov 	return 0;
2114e23731dbSKonstantin Belousov 
2115e23731dbSKonstantin Belousov err_rx_ipv6:
2116e23731dbSKonstantin Belousov 	kfree(ipsec->rx_ipv6);
2117e23731dbSKonstantin Belousov err_rx_ipv4:
2118e23731dbSKonstantin Belousov 	kfree(ipsec->rx_ipv4);
2119e23731dbSKonstantin Belousov err_tx:
2120e23731dbSKonstantin Belousov 	kfree(ipsec->tx);
2121e23731dbSKonstantin Belousov 	return err;
2122e23731dbSKonstantin Belousov }
2123e23731dbSKonstantin Belousov 
mlx5e_accel_ipsec_fs_modify(struct mlx5e_ipsec_sa_entry * sa_entry)2124e23731dbSKonstantin Belousov void mlx5e_accel_ipsec_fs_modify(struct mlx5e_ipsec_sa_entry *sa_entry)
2125e23731dbSKonstantin Belousov {
2126e23731dbSKonstantin Belousov         struct mlx5e_ipsec_sa_entry sa_entry_shadow = {};
2127e23731dbSKonstantin Belousov         int err;
2128e23731dbSKonstantin Belousov 
2129e23731dbSKonstantin Belousov         memcpy(&sa_entry_shadow, sa_entry, sizeof(*sa_entry));
2130e23731dbSKonstantin Belousov         memset(&sa_entry_shadow.ipsec_rule, 0x00, sizeof(sa_entry->ipsec_rule));
2131e23731dbSKonstantin Belousov 
2132e23731dbSKonstantin Belousov         err = mlx5e_accel_ipsec_fs_add_rule(&sa_entry_shadow);
2133e23731dbSKonstantin Belousov         if (err)
2134e23731dbSKonstantin Belousov                 return;
2135e23731dbSKonstantin Belousov         mlx5e_accel_ipsec_fs_del_rule(sa_entry);
2136e23731dbSKonstantin Belousov         memcpy(sa_entry, &sa_entry_shadow, sizeof(*sa_entry));
2137e23731dbSKonstantin Belousov }
2138