1*0d9f9647SVlad Buslov // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2*0d9f9647SVlad Buslov /* Copyright (c) 2021 Mellanox Technologies. */
3*0d9f9647SVlad Buslov 
4*0d9f9647SVlad Buslov #include "tc_tun_encap.h"
5*0d9f9647SVlad Buslov #include "en_tc.h"
6*0d9f9647SVlad Buslov #include "tc_tun.h"
7*0d9f9647SVlad Buslov #include "rep/tc.h"
8*0d9f9647SVlad Buslov #include "diag/en_tc_tracepoint.h"
9*0d9f9647SVlad Buslov 
10*0d9f9647SVlad Buslov int mlx5e_tc_set_attr_rx_tun(struct mlx5e_tc_flow *flow,
11*0d9f9647SVlad Buslov 			     struct mlx5_flow_spec *spec)
12*0d9f9647SVlad Buslov {
13*0d9f9647SVlad Buslov 	struct mlx5_esw_flow_attr *esw_attr = flow->attr->esw_attr;
14*0d9f9647SVlad Buslov 	struct mlx5_rx_tun_attr *tun_attr;
15*0d9f9647SVlad Buslov 	void *daddr, *saddr;
16*0d9f9647SVlad Buslov 	u8 ip_version;
17*0d9f9647SVlad Buslov 
18*0d9f9647SVlad Buslov 	tun_attr = kvzalloc(sizeof(*tun_attr), GFP_KERNEL);
19*0d9f9647SVlad Buslov 	if (!tun_attr)
20*0d9f9647SVlad Buslov 		return -ENOMEM;
21*0d9f9647SVlad Buslov 
22*0d9f9647SVlad Buslov 	esw_attr->rx_tun_attr = tun_attr;
23*0d9f9647SVlad Buslov 	ip_version = mlx5e_tc_get_ip_version(spec, true);
24*0d9f9647SVlad Buslov 
25*0d9f9647SVlad Buslov 	if (ip_version == 4) {
26*0d9f9647SVlad Buslov 		daddr = MLX5_ADDR_OF(fte_match_param, spec->match_value,
27*0d9f9647SVlad Buslov 				     outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
28*0d9f9647SVlad Buslov 		saddr = MLX5_ADDR_OF(fte_match_param, spec->match_value,
29*0d9f9647SVlad Buslov 				     outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
30*0d9f9647SVlad Buslov 		tun_attr->dst_ip.v4 = *(__be32 *)daddr;
31*0d9f9647SVlad Buslov 		tun_attr->src_ip.v4 = *(__be32 *)saddr;
32*0d9f9647SVlad Buslov 	}
33*0d9f9647SVlad Buslov #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
34*0d9f9647SVlad Buslov 	else if (ip_version == 6) {
35*0d9f9647SVlad Buslov 		int ipv6_size = MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6);
36*0d9f9647SVlad Buslov 
37*0d9f9647SVlad Buslov 		daddr = MLX5_ADDR_OF(fte_match_param, spec->match_value,
38*0d9f9647SVlad Buslov 				     outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
39*0d9f9647SVlad Buslov 		saddr = MLX5_ADDR_OF(fte_match_param, spec->match_value,
40*0d9f9647SVlad Buslov 				     outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6);
41*0d9f9647SVlad Buslov 		memcpy(&tun_attr->dst_ip.v6, daddr, ipv6_size);
42*0d9f9647SVlad Buslov 		memcpy(&tun_attr->src_ip.v6, saddr, ipv6_size);
43*0d9f9647SVlad Buslov 	}
44*0d9f9647SVlad Buslov #endif
45*0d9f9647SVlad Buslov 	return 0;
46*0d9f9647SVlad Buslov }
47*0d9f9647SVlad Buslov 
48*0d9f9647SVlad Buslov void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
49*0d9f9647SVlad Buslov 			      struct mlx5e_encap_entry *e,
50*0d9f9647SVlad Buslov 			      struct list_head *flow_list)
51*0d9f9647SVlad Buslov {
52*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
53*0d9f9647SVlad Buslov 	struct mlx5_esw_flow_attr *esw_attr;
54*0d9f9647SVlad Buslov 	struct mlx5_flow_handle *rule;
55*0d9f9647SVlad Buslov 	struct mlx5_flow_attr *attr;
56*0d9f9647SVlad Buslov 	struct mlx5_flow_spec *spec;
57*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow *flow;
58*0d9f9647SVlad Buslov 	int err;
59*0d9f9647SVlad Buslov 
60*0d9f9647SVlad Buslov 	e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
61*0d9f9647SVlad Buslov 						     e->reformat_type,
62*0d9f9647SVlad Buslov 						     e->encap_size, e->encap_header,
63*0d9f9647SVlad Buslov 						     MLX5_FLOW_NAMESPACE_FDB);
64*0d9f9647SVlad Buslov 	if (IS_ERR(e->pkt_reformat)) {
65*0d9f9647SVlad Buslov 		mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %lu\n",
66*0d9f9647SVlad Buslov 			       PTR_ERR(e->pkt_reformat));
67*0d9f9647SVlad Buslov 		return;
68*0d9f9647SVlad Buslov 	}
69*0d9f9647SVlad Buslov 	e->flags |= MLX5_ENCAP_ENTRY_VALID;
70*0d9f9647SVlad Buslov 	mlx5e_rep_queue_neigh_stats_work(priv);
71*0d9f9647SVlad Buslov 
72*0d9f9647SVlad Buslov 	list_for_each_entry(flow, flow_list, tmp_list) {
73*0d9f9647SVlad Buslov 		bool all_flow_encaps_valid = true;
74*0d9f9647SVlad Buslov 		int i;
75*0d9f9647SVlad Buslov 
76*0d9f9647SVlad Buslov 		if (!mlx5e_is_offloaded_flow(flow))
77*0d9f9647SVlad Buslov 			continue;
78*0d9f9647SVlad Buslov 		attr = flow->attr;
79*0d9f9647SVlad Buslov 		esw_attr = attr->esw_attr;
80*0d9f9647SVlad Buslov 		spec = &attr->parse_attr->spec;
81*0d9f9647SVlad Buslov 
82*0d9f9647SVlad Buslov 		esw_attr->dests[flow->tmp_efi_index].pkt_reformat = e->pkt_reformat;
83*0d9f9647SVlad Buslov 		esw_attr->dests[flow->tmp_efi_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
84*0d9f9647SVlad Buslov 		/* Flow can be associated with multiple encap entries.
85*0d9f9647SVlad Buslov 		 * Before offloading the flow verify that all of them have
86*0d9f9647SVlad Buslov 		 * a valid neighbour.
87*0d9f9647SVlad Buslov 		 */
88*0d9f9647SVlad Buslov 		for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
89*0d9f9647SVlad Buslov 			if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP))
90*0d9f9647SVlad Buslov 				continue;
91*0d9f9647SVlad Buslov 			if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP_VALID)) {
92*0d9f9647SVlad Buslov 				all_flow_encaps_valid = false;
93*0d9f9647SVlad Buslov 				break;
94*0d9f9647SVlad Buslov 			}
95*0d9f9647SVlad Buslov 		}
96*0d9f9647SVlad Buslov 		/* Do not offload flows with unresolved neighbors */
97*0d9f9647SVlad Buslov 		if (!all_flow_encaps_valid)
98*0d9f9647SVlad Buslov 			continue;
99*0d9f9647SVlad Buslov 		/* update from slow path rule to encap rule */
100*0d9f9647SVlad Buslov 		rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, attr);
101*0d9f9647SVlad Buslov 		if (IS_ERR(rule)) {
102*0d9f9647SVlad Buslov 			err = PTR_ERR(rule);
103*0d9f9647SVlad Buslov 			mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
104*0d9f9647SVlad Buslov 				       err);
105*0d9f9647SVlad Buslov 			continue;
106*0d9f9647SVlad Buslov 		}
107*0d9f9647SVlad Buslov 
108*0d9f9647SVlad Buslov 		mlx5e_tc_unoffload_from_slow_path(esw, flow);
109*0d9f9647SVlad Buslov 		flow->rule[0] = rule;
110*0d9f9647SVlad Buslov 		/* was unset when slow path rule removed */
111*0d9f9647SVlad Buslov 		flow_flag_set(flow, OFFLOADED);
112*0d9f9647SVlad Buslov 	}
113*0d9f9647SVlad Buslov }
114*0d9f9647SVlad Buslov 
115*0d9f9647SVlad Buslov void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
116*0d9f9647SVlad Buslov 			      struct mlx5e_encap_entry *e,
117*0d9f9647SVlad Buslov 			      struct list_head *flow_list)
118*0d9f9647SVlad Buslov {
119*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
120*0d9f9647SVlad Buslov 	struct mlx5_esw_flow_attr *esw_attr;
121*0d9f9647SVlad Buslov 	struct mlx5_flow_handle *rule;
122*0d9f9647SVlad Buslov 	struct mlx5_flow_attr *attr;
123*0d9f9647SVlad Buslov 	struct mlx5_flow_spec *spec;
124*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow *flow;
125*0d9f9647SVlad Buslov 	int err;
126*0d9f9647SVlad Buslov 
127*0d9f9647SVlad Buslov 	list_for_each_entry(flow, flow_list, tmp_list) {
128*0d9f9647SVlad Buslov 		if (!mlx5e_is_offloaded_flow(flow))
129*0d9f9647SVlad Buslov 			continue;
130*0d9f9647SVlad Buslov 		attr = flow->attr;
131*0d9f9647SVlad Buslov 		esw_attr = attr->esw_attr;
132*0d9f9647SVlad Buslov 		spec = &attr->parse_attr->spec;
133*0d9f9647SVlad Buslov 
134*0d9f9647SVlad Buslov 		/* update from encap rule to slow path rule */
135*0d9f9647SVlad Buslov 		rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec);
136*0d9f9647SVlad Buslov 		/* mark the flow's encap dest as non-valid */
137*0d9f9647SVlad Buslov 		esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
138*0d9f9647SVlad Buslov 
139*0d9f9647SVlad Buslov 		if (IS_ERR(rule)) {
140*0d9f9647SVlad Buslov 			err = PTR_ERR(rule);
141*0d9f9647SVlad Buslov 			mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n",
142*0d9f9647SVlad Buslov 				       err);
143*0d9f9647SVlad Buslov 			continue;
144*0d9f9647SVlad Buslov 		}
145*0d9f9647SVlad Buslov 
146*0d9f9647SVlad Buslov 		mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
147*0d9f9647SVlad Buslov 		flow->rule[0] = rule;
148*0d9f9647SVlad Buslov 		/* was unset when fast path rule removed */
149*0d9f9647SVlad Buslov 		flow_flag_set(flow, OFFLOADED);
150*0d9f9647SVlad Buslov 	}
151*0d9f9647SVlad Buslov 
152*0d9f9647SVlad Buslov 	/* we know that the encap is valid */
153*0d9f9647SVlad Buslov 	e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
154*0d9f9647SVlad Buslov 	mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat);
155*0d9f9647SVlad Buslov }
156*0d9f9647SVlad Buslov 
157*0d9f9647SVlad Buslov /* Takes reference to all flows attached to encap and adds the flows to
158*0d9f9647SVlad Buslov  * flow_list using 'tmp_list' list_head in mlx5e_tc_flow.
159*0d9f9647SVlad Buslov  */
160*0d9f9647SVlad Buslov void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list)
161*0d9f9647SVlad Buslov {
162*0d9f9647SVlad Buslov 	struct encap_flow_item *efi;
163*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow *flow;
164*0d9f9647SVlad Buslov 
165*0d9f9647SVlad Buslov 	list_for_each_entry(efi, &e->flows, list) {
166*0d9f9647SVlad Buslov 		flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
167*0d9f9647SVlad Buslov 		if (IS_ERR(mlx5e_flow_get(flow)))
168*0d9f9647SVlad Buslov 			continue;
169*0d9f9647SVlad Buslov 		wait_for_completion(&flow->init_done);
170*0d9f9647SVlad Buslov 
171*0d9f9647SVlad Buslov 		flow->tmp_efi_index = efi->index;
172*0d9f9647SVlad Buslov 		list_add(&flow->tmp_list, flow_list);
173*0d9f9647SVlad Buslov 	}
174*0d9f9647SVlad Buslov }
175*0d9f9647SVlad Buslov 
176*0d9f9647SVlad Buslov static struct mlx5e_encap_entry *
177*0d9f9647SVlad Buslov mlx5e_get_next_valid_encap(struct mlx5e_neigh_hash_entry *nhe,
178*0d9f9647SVlad Buslov 			   struct mlx5e_encap_entry *e)
179*0d9f9647SVlad Buslov {
180*0d9f9647SVlad Buslov 	struct mlx5e_encap_entry *next = NULL;
181*0d9f9647SVlad Buslov 
182*0d9f9647SVlad Buslov retry:
183*0d9f9647SVlad Buslov 	rcu_read_lock();
184*0d9f9647SVlad Buslov 
185*0d9f9647SVlad Buslov 	/* find encap with non-zero reference counter value */
186*0d9f9647SVlad Buslov 	for (next = e ?
187*0d9f9647SVlad Buslov 		     list_next_or_null_rcu(&nhe->encap_list,
188*0d9f9647SVlad Buslov 					   &e->encap_list,
189*0d9f9647SVlad Buslov 					   struct mlx5e_encap_entry,
190*0d9f9647SVlad Buslov 					   encap_list) :
191*0d9f9647SVlad Buslov 		     list_first_or_null_rcu(&nhe->encap_list,
192*0d9f9647SVlad Buslov 					    struct mlx5e_encap_entry,
193*0d9f9647SVlad Buslov 					    encap_list);
194*0d9f9647SVlad Buslov 	     next;
195*0d9f9647SVlad Buslov 	     next = list_next_or_null_rcu(&nhe->encap_list,
196*0d9f9647SVlad Buslov 					  &next->encap_list,
197*0d9f9647SVlad Buslov 					  struct mlx5e_encap_entry,
198*0d9f9647SVlad Buslov 					  encap_list))
199*0d9f9647SVlad Buslov 		if (mlx5e_encap_take(next))
200*0d9f9647SVlad Buslov 			break;
201*0d9f9647SVlad Buslov 
202*0d9f9647SVlad Buslov 	rcu_read_unlock();
203*0d9f9647SVlad Buslov 
204*0d9f9647SVlad Buslov 	/* release starting encap */
205*0d9f9647SVlad Buslov 	if (e)
206*0d9f9647SVlad Buslov 		mlx5e_encap_put(netdev_priv(e->out_dev), e);
207*0d9f9647SVlad Buslov 	if (!next)
208*0d9f9647SVlad Buslov 		return next;
209*0d9f9647SVlad Buslov 
210*0d9f9647SVlad Buslov 	/* wait for encap to be fully initialized */
211*0d9f9647SVlad Buslov 	wait_for_completion(&next->res_ready);
212*0d9f9647SVlad Buslov 	/* continue searching if encap entry is not in valid state after completion */
213*0d9f9647SVlad Buslov 	if (!(next->flags & MLX5_ENCAP_ENTRY_VALID)) {
214*0d9f9647SVlad Buslov 		e = next;
215*0d9f9647SVlad Buslov 		goto retry;
216*0d9f9647SVlad Buslov 	}
217*0d9f9647SVlad Buslov 
218*0d9f9647SVlad Buslov 	return next;
219*0d9f9647SVlad Buslov }
220*0d9f9647SVlad Buslov 
221*0d9f9647SVlad Buslov void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
222*0d9f9647SVlad Buslov {
223*0d9f9647SVlad Buslov 	struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
224*0d9f9647SVlad Buslov 	struct mlx5e_encap_entry *e = NULL;
225*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow *flow;
226*0d9f9647SVlad Buslov 	struct mlx5_fc *counter;
227*0d9f9647SVlad Buslov 	struct neigh_table *tbl;
228*0d9f9647SVlad Buslov 	bool neigh_used = false;
229*0d9f9647SVlad Buslov 	struct neighbour *n;
230*0d9f9647SVlad Buslov 	u64 lastuse;
231*0d9f9647SVlad Buslov 
232*0d9f9647SVlad Buslov 	if (m_neigh->family == AF_INET)
233*0d9f9647SVlad Buslov 		tbl = &arp_tbl;
234*0d9f9647SVlad Buslov #if IS_ENABLED(CONFIG_IPV6)
235*0d9f9647SVlad Buslov 	else if (m_neigh->family == AF_INET6)
236*0d9f9647SVlad Buslov 		tbl = ipv6_stub->nd_tbl;
237*0d9f9647SVlad Buslov #endif
238*0d9f9647SVlad Buslov 	else
239*0d9f9647SVlad Buslov 		return;
240*0d9f9647SVlad Buslov 
241*0d9f9647SVlad Buslov 	/* mlx5e_get_next_valid_encap() releases previous encap before returning
242*0d9f9647SVlad Buslov 	 * next one.
243*0d9f9647SVlad Buslov 	 */
244*0d9f9647SVlad Buslov 	while ((e = mlx5e_get_next_valid_encap(nhe, e)) != NULL) {
245*0d9f9647SVlad Buslov 		struct mlx5e_priv *priv = netdev_priv(e->out_dev);
246*0d9f9647SVlad Buslov 		struct encap_flow_item *efi, *tmp;
247*0d9f9647SVlad Buslov 		struct mlx5_eswitch *esw;
248*0d9f9647SVlad Buslov 		LIST_HEAD(flow_list);
249*0d9f9647SVlad Buslov 
250*0d9f9647SVlad Buslov 		esw = priv->mdev->priv.eswitch;
251*0d9f9647SVlad Buslov 		mutex_lock(&esw->offloads.encap_tbl_lock);
252*0d9f9647SVlad Buslov 		list_for_each_entry_safe(efi, tmp, &e->flows, list) {
253*0d9f9647SVlad Buslov 			flow = container_of(efi, struct mlx5e_tc_flow,
254*0d9f9647SVlad Buslov 					    encaps[efi->index]);
255*0d9f9647SVlad Buslov 			if (IS_ERR(mlx5e_flow_get(flow)))
256*0d9f9647SVlad Buslov 				continue;
257*0d9f9647SVlad Buslov 			list_add(&flow->tmp_list, &flow_list);
258*0d9f9647SVlad Buslov 
259*0d9f9647SVlad Buslov 			if (mlx5e_is_offloaded_flow(flow)) {
260*0d9f9647SVlad Buslov 				counter = mlx5e_tc_get_counter(flow);
261*0d9f9647SVlad Buslov 				lastuse = mlx5_fc_query_lastuse(counter);
262*0d9f9647SVlad Buslov 				if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
263*0d9f9647SVlad Buslov 					neigh_used = true;
264*0d9f9647SVlad Buslov 					break;
265*0d9f9647SVlad Buslov 				}
266*0d9f9647SVlad Buslov 			}
267*0d9f9647SVlad Buslov 		}
268*0d9f9647SVlad Buslov 		mutex_unlock(&esw->offloads.encap_tbl_lock);
269*0d9f9647SVlad Buslov 
270*0d9f9647SVlad Buslov 		mlx5e_put_encap_flow_list(priv, &flow_list);
271*0d9f9647SVlad Buslov 		if (neigh_used) {
272*0d9f9647SVlad Buslov 			/* release current encap before breaking the loop */
273*0d9f9647SVlad Buslov 			mlx5e_encap_put(priv, e);
274*0d9f9647SVlad Buslov 			break;
275*0d9f9647SVlad Buslov 		}
276*0d9f9647SVlad Buslov 	}
277*0d9f9647SVlad Buslov 
278*0d9f9647SVlad Buslov 	trace_mlx5e_tc_update_neigh_used_value(nhe, neigh_used);
279*0d9f9647SVlad Buslov 
280*0d9f9647SVlad Buslov 	if (neigh_used) {
281*0d9f9647SVlad Buslov 		nhe->reported_lastuse = jiffies;
282*0d9f9647SVlad Buslov 
283*0d9f9647SVlad Buslov 		/* find the relevant neigh according to the cached device and
284*0d9f9647SVlad Buslov 		 * dst ip pair
285*0d9f9647SVlad Buslov 		 */
286*0d9f9647SVlad Buslov 		n = neigh_lookup(tbl, &m_neigh->dst_ip, m_neigh->dev);
287*0d9f9647SVlad Buslov 		if (!n)
288*0d9f9647SVlad Buslov 			return;
289*0d9f9647SVlad Buslov 
290*0d9f9647SVlad Buslov 		neigh_event_send(n, NULL);
291*0d9f9647SVlad Buslov 		neigh_release(n);
292*0d9f9647SVlad Buslov 	}
293*0d9f9647SVlad Buslov }
294*0d9f9647SVlad Buslov 
295*0d9f9647SVlad Buslov static void mlx5e_encap_dealloc(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
296*0d9f9647SVlad Buslov {
297*0d9f9647SVlad Buslov 	WARN_ON(!list_empty(&e->flows));
298*0d9f9647SVlad Buslov 
299*0d9f9647SVlad Buslov 	if (e->compl_result > 0) {
300*0d9f9647SVlad Buslov 		mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
301*0d9f9647SVlad Buslov 
302*0d9f9647SVlad Buslov 		if (e->flags & MLX5_ENCAP_ENTRY_VALID)
303*0d9f9647SVlad Buslov 			mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat);
304*0d9f9647SVlad Buslov 	}
305*0d9f9647SVlad Buslov 
306*0d9f9647SVlad Buslov 	kfree(e->tun_info);
307*0d9f9647SVlad Buslov 	kfree(e->encap_header);
308*0d9f9647SVlad Buslov 	kfree_rcu(e, rcu);
309*0d9f9647SVlad Buslov }
310*0d9f9647SVlad Buslov 
311*0d9f9647SVlad Buslov static void mlx5e_decap_dealloc(struct mlx5e_priv *priv,
312*0d9f9647SVlad Buslov 				struct mlx5e_decap_entry *d)
313*0d9f9647SVlad Buslov {
314*0d9f9647SVlad Buslov 	WARN_ON(!list_empty(&d->flows));
315*0d9f9647SVlad Buslov 
316*0d9f9647SVlad Buslov 	if (!d->compl_result)
317*0d9f9647SVlad Buslov 		mlx5_packet_reformat_dealloc(priv->mdev, d->pkt_reformat);
318*0d9f9647SVlad Buslov 
319*0d9f9647SVlad Buslov 	kfree_rcu(d, rcu);
320*0d9f9647SVlad Buslov }
321*0d9f9647SVlad Buslov 
322*0d9f9647SVlad Buslov void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
323*0d9f9647SVlad Buslov {
324*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
325*0d9f9647SVlad Buslov 
326*0d9f9647SVlad Buslov 	if (!refcount_dec_and_mutex_lock(&e->refcnt, &esw->offloads.encap_tbl_lock))
327*0d9f9647SVlad Buslov 		return;
328*0d9f9647SVlad Buslov 	hash_del_rcu(&e->encap_hlist);
329*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
330*0d9f9647SVlad Buslov 
331*0d9f9647SVlad Buslov 	mlx5e_encap_dealloc(priv, e);
332*0d9f9647SVlad Buslov }
333*0d9f9647SVlad Buslov 
334*0d9f9647SVlad Buslov static void mlx5e_decap_put(struct mlx5e_priv *priv, struct mlx5e_decap_entry *d)
335*0d9f9647SVlad Buslov {
336*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
337*0d9f9647SVlad Buslov 
338*0d9f9647SVlad Buslov 	if (!refcount_dec_and_mutex_lock(&d->refcnt, &esw->offloads.decap_tbl_lock))
339*0d9f9647SVlad Buslov 		return;
340*0d9f9647SVlad Buslov 	hash_del_rcu(&d->hlist);
341*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
342*0d9f9647SVlad Buslov 
343*0d9f9647SVlad Buslov 	mlx5e_decap_dealloc(priv, d);
344*0d9f9647SVlad Buslov }
345*0d9f9647SVlad Buslov 
346*0d9f9647SVlad Buslov void mlx5e_detach_encap(struct mlx5e_priv *priv,
347*0d9f9647SVlad Buslov 			struct mlx5e_tc_flow *flow, int out_index)
348*0d9f9647SVlad Buslov {
349*0d9f9647SVlad Buslov 	struct mlx5e_encap_entry *e = flow->encaps[out_index].e;
350*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
351*0d9f9647SVlad Buslov 
352*0d9f9647SVlad Buslov 	/* flow wasn't fully initialized */
353*0d9f9647SVlad Buslov 	if (!e)
354*0d9f9647SVlad Buslov 		return;
355*0d9f9647SVlad Buslov 
356*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.encap_tbl_lock);
357*0d9f9647SVlad Buslov 	list_del(&flow->encaps[out_index].list);
358*0d9f9647SVlad Buslov 	flow->encaps[out_index].e = NULL;
359*0d9f9647SVlad Buslov 	if (!refcount_dec_and_test(&e->refcnt)) {
360*0d9f9647SVlad Buslov 		mutex_unlock(&esw->offloads.encap_tbl_lock);
361*0d9f9647SVlad Buslov 		return;
362*0d9f9647SVlad Buslov 	}
363*0d9f9647SVlad Buslov 	hash_del_rcu(&e->encap_hlist);
364*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
365*0d9f9647SVlad Buslov 
366*0d9f9647SVlad Buslov 	mlx5e_encap_dealloc(priv, e);
367*0d9f9647SVlad Buslov }
368*0d9f9647SVlad Buslov 
369*0d9f9647SVlad Buslov void mlx5e_detach_decap(struct mlx5e_priv *priv,
370*0d9f9647SVlad Buslov 			struct mlx5e_tc_flow *flow)
371*0d9f9647SVlad Buslov {
372*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
373*0d9f9647SVlad Buslov 	struct mlx5e_decap_entry *d = flow->decap_reformat;
374*0d9f9647SVlad Buslov 
375*0d9f9647SVlad Buslov 	if (!d)
376*0d9f9647SVlad Buslov 		return;
377*0d9f9647SVlad Buslov 
378*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.decap_tbl_lock);
379*0d9f9647SVlad Buslov 	list_del(&flow->l3_to_l2_reformat);
380*0d9f9647SVlad Buslov 	flow->decap_reformat = NULL;
381*0d9f9647SVlad Buslov 
382*0d9f9647SVlad Buslov 	if (!refcount_dec_and_test(&d->refcnt)) {
383*0d9f9647SVlad Buslov 		mutex_unlock(&esw->offloads.decap_tbl_lock);
384*0d9f9647SVlad Buslov 		return;
385*0d9f9647SVlad Buslov 	}
386*0d9f9647SVlad Buslov 	hash_del_rcu(&d->hlist);
387*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
388*0d9f9647SVlad Buslov 
389*0d9f9647SVlad Buslov 	mlx5e_decap_dealloc(priv, d);
390*0d9f9647SVlad Buslov }
391*0d9f9647SVlad Buslov 
392*0d9f9647SVlad Buslov struct encap_key {
393*0d9f9647SVlad Buslov 	const struct ip_tunnel_key *ip_tun_key;
394*0d9f9647SVlad Buslov 	struct mlx5e_tc_tunnel *tc_tunnel;
395*0d9f9647SVlad Buslov };
396*0d9f9647SVlad Buslov 
397*0d9f9647SVlad Buslov static int cmp_encap_info(struct encap_key *a,
398*0d9f9647SVlad Buslov 			  struct encap_key *b)
399*0d9f9647SVlad Buslov {
400*0d9f9647SVlad Buslov 	return memcmp(a->ip_tun_key, b->ip_tun_key, sizeof(*a->ip_tun_key)) ||
401*0d9f9647SVlad Buslov 		a->tc_tunnel->tunnel_type != b->tc_tunnel->tunnel_type;
402*0d9f9647SVlad Buslov }
403*0d9f9647SVlad Buslov 
404*0d9f9647SVlad Buslov static int cmp_decap_info(struct mlx5e_decap_key *a,
405*0d9f9647SVlad Buslov 			  struct mlx5e_decap_key *b)
406*0d9f9647SVlad Buslov {
407*0d9f9647SVlad Buslov 	return memcmp(&a->key, &b->key, sizeof(b->key));
408*0d9f9647SVlad Buslov }
409*0d9f9647SVlad Buslov 
410*0d9f9647SVlad Buslov static int hash_encap_info(struct encap_key *key)
411*0d9f9647SVlad Buslov {
412*0d9f9647SVlad Buslov 	return jhash(key->ip_tun_key, sizeof(*key->ip_tun_key),
413*0d9f9647SVlad Buslov 		     key->tc_tunnel->tunnel_type);
414*0d9f9647SVlad Buslov }
415*0d9f9647SVlad Buslov 
416*0d9f9647SVlad Buslov static int hash_decap_info(struct mlx5e_decap_key *key)
417*0d9f9647SVlad Buslov {
418*0d9f9647SVlad Buslov 	return jhash(&key->key, sizeof(key->key), 0);
419*0d9f9647SVlad Buslov }
420*0d9f9647SVlad Buslov 
421*0d9f9647SVlad Buslov bool mlx5e_encap_take(struct mlx5e_encap_entry *e)
422*0d9f9647SVlad Buslov {
423*0d9f9647SVlad Buslov 	return refcount_inc_not_zero(&e->refcnt);
424*0d9f9647SVlad Buslov }
425*0d9f9647SVlad Buslov 
426*0d9f9647SVlad Buslov static bool mlx5e_decap_take(struct mlx5e_decap_entry *e)
427*0d9f9647SVlad Buslov {
428*0d9f9647SVlad Buslov 	return refcount_inc_not_zero(&e->refcnt);
429*0d9f9647SVlad Buslov }
430*0d9f9647SVlad Buslov 
431*0d9f9647SVlad Buslov static struct mlx5e_encap_entry *
432*0d9f9647SVlad Buslov mlx5e_encap_get(struct mlx5e_priv *priv, struct encap_key *key,
433*0d9f9647SVlad Buslov 		uintptr_t hash_key)
434*0d9f9647SVlad Buslov {
435*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
436*0d9f9647SVlad Buslov 	struct mlx5e_encap_entry *e;
437*0d9f9647SVlad Buslov 	struct encap_key e_key;
438*0d9f9647SVlad Buslov 
439*0d9f9647SVlad Buslov 	hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
440*0d9f9647SVlad Buslov 				   encap_hlist, hash_key) {
441*0d9f9647SVlad Buslov 		e_key.ip_tun_key = &e->tun_info->key;
442*0d9f9647SVlad Buslov 		e_key.tc_tunnel = e->tunnel;
443*0d9f9647SVlad Buslov 		if (!cmp_encap_info(&e_key, key) &&
444*0d9f9647SVlad Buslov 		    mlx5e_encap_take(e))
445*0d9f9647SVlad Buslov 			return e;
446*0d9f9647SVlad Buslov 	}
447*0d9f9647SVlad Buslov 
448*0d9f9647SVlad Buslov 	return NULL;
449*0d9f9647SVlad Buslov }
450*0d9f9647SVlad Buslov 
451*0d9f9647SVlad Buslov static struct mlx5e_decap_entry *
452*0d9f9647SVlad Buslov mlx5e_decap_get(struct mlx5e_priv *priv, struct mlx5e_decap_key *key,
453*0d9f9647SVlad Buslov 		uintptr_t hash_key)
454*0d9f9647SVlad Buslov {
455*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
456*0d9f9647SVlad Buslov 	struct mlx5e_decap_key r_key;
457*0d9f9647SVlad Buslov 	struct mlx5e_decap_entry *e;
458*0d9f9647SVlad Buslov 
459*0d9f9647SVlad Buslov 	hash_for_each_possible_rcu(esw->offloads.decap_tbl, e,
460*0d9f9647SVlad Buslov 				   hlist, hash_key) {
461*0d9f9647SVlad Buslov 		r_key = e->key;
462*0d9f9647SVlad Buslov 		if (!cmp_decap_info(&r_key, key) &&
463*0d9f9647SVlad Buslov 		    mlx5e_decap_take(e))
464*0d9f9647SVlad Buslov 			return e;
465*0d9f9647SVlad Buslov 	}
466*0d9f9647SVlad Buslov 	return NULL;
467*0d9f9647SVlad Buslov }
468*0d9f9647SVlad Buslov 
469*0d9f9647SVlad Buslov struct ip_tunnel_info *mlx5e_dup_tun_info(const struct ip_tunnel_info *tun_info)
470*0d9f9647SVlad Buslov {
471*0d9f9647SVlad Buslov 	size_t tun_size = sizeof(*tun_info) + tun_info->options_len;
472*0d9f9647SVlad Buslov 
473*0d9f9647SVlad Buslov 	return kmemdup(tun_info, tun_size, GFP_KERNEL);
474*0d9f9647SVlad Buslov }
475*0d9f9647SVlad Buslov 
476*0d9f9647SVlad Buslov static bool is_duplicated_encap_entry(struct mlx5e_priv *priv,
477*0d9f9647SVlad Buslov 				      struct mlx5e_tc_flow *flow,
478*0d9f9647SVlad Buslov 				      int out_index,
479*0d9f9647SVlad Buslov 				      struct mlx5e_encap_entry *e,
480*0d9f9647SVlad Buslov 				      struct netlink_ext_ack *extack)
481*0d9f9647SVlad Buslov {
482*0d9f9647SVlad Buslov 	int i;
483*0d9f9647SVlad Buslov 
484*0d9f9647SVlad Buslov 	for (i = 0; i < out_index; i++) {
485*0d9f9647SVlad Buslov 		if (flow->encaps[i].e != e)
486*0d9f9647SVlad Buslov 			continue;
487*0d9f9647SVlad Buslov 		NL_SET_ERR_MSG_MOD(extack, "can't duplicate encap action");
488*0d9f9647SVlad Buslov 		netdev_err(priv->netdev, "can't duplicate encap action\n");
489*0d9f9647SVlad Buslov 		return true;
490*0d9f9647SVlad Buslov 	}
491*0d9f9647SVlad Buslov 
492*0d9f9647SVlad Buslov 	return false;
493*0d9f9647SVlad Buslov }
494*0d9f9647SVlad Buslov 
495*0d9f9647SVlad Buslov static int mlx5e_set_vf_tunnel(struct mlx5_eswitch *esw,
496*0d9f9647SVlad Buslov 			       struct mlx5_flow_attr *attr,
497*0d9f9647SVlad Buslov 			       struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts,
498*0d9f9647SVlad Buslov 			       struct net_device *out_dev,
499*0d9f9647SVlad Buslov 			       int route_dev_ifindex,
500*0d9f9647SVlad Buslov 			       int out_index)
501*0d9f9647SVlad Buslov {
502*0d9f9647SVlad Buslov 	struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
503*0d9f9647SVlad Buslov 	struct net_device *route_dev;
504*0d9f9647SVlad Buslov 	u16 vport_num;
505*0d9f9647SVlad Buslov 	int err = 0;
506*0d9f9647SVlad Buslov 	u32 data;
507*0d9f9647SVlad Buslov 
508*0d9f9647SVlad Buslov 	route_dev = dev_get_by_index(dev_net(out_dev), route_dev_ifindex);
509*0d9f9647SVlad Buslov 
510*0d9f9647SVlad Buslov 	if (!route_dev || route_dev->netdev_ops != &mlx5e_netdev_ops ||
511*0d9f9647SVlad Buslov 	    !mlx5e_tc_is_vf_tunnel(out_dev, route_dev))
512*0d9f9647SVlad Buslov 		goto out;
513*0d9f9647SVlad Buslov 
514*0d9f9647SVlad Buslov 	err = mlx5e_tc_query_route_vport(out_dev, route_dev, &vport_num);
515*0d9f9647SVlad Buslov 	if (err)
516*0d9f9647SVlad Buslov 		goto out;
517*0d9f9647SVlad Buslov 
518*0d9f9647SVlad Buslov 	attr->dest_chain = 0;
519*0d9f9647SVlad Buslov 	attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
520*0d9f9647SVlad Buslov 	esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE;
521*0d9f9647SVlad Buslov 	data = mlx5_eswitch_get_vport_metadata_for_set(esw_attr->in_mdev->priv.eswitch,
522*0d9f9647SVlad Buslov 						       vport_num);
523*0d9f9647SVlad Buslov 	err = mlx5e_tc_match_to_reg_set(esw->dev, mod_hdr_acts,
524*0d9f9647SVlad Buslov 					MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG, data);
525*0d9f9647SVlad Buslov 	if (err)
526*0d9f9647SVlad Buslov 		goto out;
527*0d9f9647SVlad Buslov 
528*0d9f9647SVlad Buslov out:
529*0d9f9647SVlad Buslov 	if (route_dev)
530*0d9f9647SVlad Buslov 		dev_put(route_dev);
531*0d9f9647SVlad Buslov 	return err;
532*0d9f9647SVlad Buslov }
533*0d9f9647SVlad Buslov 
534*0d9f9647SVlad Buslov int mlx5e_attach_encap(struct mlx5e_priv *priv,
535*0d9f9647SVlad Buslov 		       struct mlx5e_tc_flow *flow,
536*0d9f9647SVlad Buslov 		       struct net_device *mirred_dev,
537*0d9f9647SVlad Buslov 		       int out_index,
538*0d9f9647SVlad Buslov 		       struct netlink_ext_ack *extack,
539*0d9f9647SVlad Buslov 		       struct net_device **encap_dev,
540*0d9f9647SVlad Buslov 		       bool *encap_valid)
541*0d9f9647SVlad Buslov {
542*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
543*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow_parse_attr *parse_attr;
544*0d9f9647SVlad Buslov 	struct mlx5_flow_attr *attr = flow->attr;
545*0d9f9647SVlad Buslov 	const struct ip_tunnel_info *tun_info;
546*0d9f9647SVlad Buslov 	struct encap_key key;
547*0d9f9647SVlad Buslov 	struct mlx5e_encap_entry *e;
548*0d9f9647SVlad Buslov 	unsigned short family;
549*0d9f9647SVlad Buslov 	uintptr_t hash_key;
550*0d9f9647SVlad Buslov 	int err = 0;
551*0d9f9647SVlad Buslov 
552*0d9f9647SVlad Buslov 	parse_attr = attr->parse_attr;
553*0d9f9647SVlad Buslov 	tun_info = parse_attr->tun_info[out_index];
554*0d9f9647SVlad Buslov 	family = ip_tunnel_info_af(tun_info);
555*0d9f9647SVlad Buslov 	key.ip_tun_key = &tun_info->key;
556*0d9f9647SVlad Buslov 	key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
557*0d9f9647SVlad Buslov 	if (!key.tc_tunnel) {
558*0d9f9647SVlad Buslov 		NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel");
559*0d9f9647SVlad Buslov 		return -EOPNOTSUPP;
560*0d9f9647SVlad Buslov 	}
561*0d9f9647SVlad Buslov 
562*0d9f9647SVlad Buslov 	hash_key = hash_encap_info(&key);
563*0d9f9647SVlad Buslov 
564*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.encap_tbl_lock);
565*0d9f9647SVlad Buslov 	e = mlx5e_encap_get(priv, &key, hash_key);
566*0d9f9647SVlad Buslov 
567*0d9f9647SVlad Buslov 	/* must verify if encap is valid or not */
568*0d9f9647SVlad Buslov 	if (e) {
569*0d9f9647SVlad Buslov 		/* Check that entry was not already attached to this flow */
570*0d9f9647SVlad Buslov 		if (is_duplicated_encap_entry(priv, flow, out_index, e, extack)) {
571*0d9f9647SVlad Buslov 			err = -EOPNOTSUPP;
572*0d9f9647SVlad Buslov 			goto out_err;
573*0d9f9647SVlad Buslov 		}
574*0d9f9647SVlad Buslov 
575*0d9f9647SVlad Buslov 		mutex_unlock(&esw->offloads.encap_tbl_lock);
576*0d9f9647SVlad Buslov 		wait_for_completion(&e->res_ready);
577*0d9f9647SVlad Buslov 
578*0d9f9647SVlad Buslov 		/* Protect against concurrent neigh update. */
579*0d9f9647SVlad Buslov 		mutex_lock(&esw->offloads.encap_tbl_lock);
580*0d9f9647SVlad Buslov 		if (e->compl_result < 0) {
581*0d9f9647SVlad Buslov 			err = -EREMOTEIO;
582*0d9f9647SVlad Buslov 			goto out_err;
583*0d9f9647SVlad Buslov 		}
584*0d9f9647SVlad Buslov 		goto attach_flow;
585*0d9f9647SVlad Buslov 	}
586*0d9f9647SVlad Buslov 
587*0d9f9647SVlad Buslov 	e = kzalloc(sizeof(*e), GFP_KERNEL);
588*0d9f9647SVlad Buslov 	if (!e) {
589*0d9f9647SVlad Buslov 		err = -ENOMEM;
590*0d9f9647SVlad Buslov 		goto out_err;
591*0d9f9647SVlad Buslov 	}
592*0d9f9647SVlad Buslov 
593*0d9f9647SVlad Buslov 	refcount_set(&e->refcnt, 1);
594*0d9f9647SVlad Buslov 	init_completion(&e->res_ready);
595*0d9f9647SVlad Buslov 
596*0d9f9647SVlad Buslov 	tun_info = mlx5e_dup_tun_info(tun_info);
597*0d9f9647SVlad Buslov 	if (!tun_info) {
598*0d9f9647SVlad Buslov 		err = -ENOMEM;
599*0d9f9647SVlad Buslov 		goto out_err_init;
600*0d9f9647SVlad Buslov 	}
601*0d9f9647SVlad Buslov 	e->tun_info = tun_info;
602*0d9f9647SVlad Buslov 	err = mlx5e_tc_tun_init_encap_attr(mirred_dev, priv, e, extack);
603*0d9f9647SVlad Buslov 	if (err)
604*0d9f9647SVlad Buslov 		goto out_err_init;
605*0d9f9647SVlad Buslov 
606*0d9f9647SVlad Buslov 	INIT_LIST_HEAD(&e->flows);
607*0d9f9647SVlad Buslov 	hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);
608*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
609*0d9f9647SVlad Buslov 
610*0d9f9647SVlad Buslov 	if (family == AF_INET)
611*0d9f9647SVlad Buslov 		err = mlx5e_tc_tun_create_header_ipv4(priv, mirred_dev, e);
612*0d9f9647SVlad Buslov 	else if (family == AF_INET6)
613*0d9f9647SVlad Buslov 		err = mlx5e_tc_tun_create_header_ipv6(priv, mirred_dev, e);
614*0d9f9647SVlad Buslov 
615*0d9f9647SVlad Buslov 	/* Protect against concurrent neigh update. */
616*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.encap_tbl_lock);
617*0d9f9647SVlad Buslov 	complete_all(&e->res_ready);
618*0d9f9647SVlad Buslov 	if (err) {
619*0d9f9647SVlad Buslov 		e->compl_result = err;
620*0d9f9647SVlad Buslov 		goto out_err;
621*0d9f9647SVlad Buslov 	}
622*0d9f9647SVlad Buslov 	e->compl_result = 1;
623*0d9f9647SVlad Buslov 
624*0d9f9647SVlad Buslov attach_flow:
625*0d9f9647SVlad Buslov 	err = mlx5e_set_vf_tunnel(esw, attr, &parse_attr->mod_hdr_acts, e->out_dev,
626*0d9f9647SVlad Buslov 				  e->route_dev_ifindex, out_index);
627*0d9f9647SVlad Buslov 	if (err)
628*0d9f9647SVlad Buslov 		goto out_err;
629*0d9f9647SVlad Buslov 
630*0d9f9647SVlad Buslov 	flow->encaps[out_index].e = e;
631*0d9f9647SVlad Buslov 	list_add(&flow->encaps[out_index].list, &e->flows);
632*0d9f9647SVlad Buslov 	flow->encaps[out_index].index = out_index;
633*0d9f9647SVlad Buslov 	*encap_dev = e->out_dev;
634*0d9f9647SVlad Buslov 	if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
635*0d9f9647SVlad Buslov 		attr->esw_attr->dests[out_index].pkt_reformat = e->pkt_reformat;
636*0d9f9647SVlad Buslov 		attr->esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
637*0d9f9647SVlad Buslov 		*encap_valid = true;
638*0d9f9647SVlad Buslov 	} else {
639*0d9f9647SVlad Buslov 		*encap_valid = false;
640*0d9f9647SVlad Buslov 	}
641*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
642*0d9f9647SVlad Buslov 
643*0d9f9647SVlad Buslov 	return err;
644*0d9f9647SVlad Buslov 
645*0d9f9647SVlad Buslov out_err:
646*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
647*0d9f9647SVlad Buslov 	if (e)
648*0d9f9647SVlad Buslov 		mlx5e_encap_put(priv, e);
649*0d9f9647SVlad Buslov 	return err;
650*0d9f9647SVlad Buslov 
651*0d9f9647SVlad Buslov out_err_init:
652*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.encap_tbl_lock);
653*0d9f9647SVlad Buslov 	kfree(tun_info);
654*0d9f9647SVlad Buslov 	kfree(e);
655*0d9f9647SVlad Buslov 	return err;
656*0d9f9647SVlad Buslov }
657*0d9f9647SVlad Buslov 
658*0d9f9647SVlad Buslov int mlx5e_attach_decap(struct mlx5e_priv *priv,
659*0d9f9647SVlad Buslov 		       struct mlx5e_tc_flow *flow,
660*0d9f9647SVlad Buslov 		       struct netlink_ext_ack *extack)
661*0d9f9647SVlad Buslov {
662*0d9f9647SVlad Buslov 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
663*0d9f9647SVlad Buslov 	struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
664*0d9f9647SVlad Buslov 	struct mlx5e_tc_flow_parse_attr *parse_attr;
665*0d9f9647SVlad Buslov 	struct mlx5e_decap_entry *d;
666*0d9f9647SVlad Buslov 	struct mlx5e_decap_key key;
667*0d9f9647SVlad Buslov 	uintptr_t hash_key;
668*0d9f9647SVlad Buslov 	int err = 0;
669*0d9f9647SVlad Buslov 
670*0d9f9647SVlad Buslov 	parse_attr = flow->attr->parse_attr;
671*0d9f9647SVlad Buslov 	if (sizeof(parse_attr->eth) > MLX5_CAP_ESW(priv->mdev, max_encap_header_size)) {
672*0d9f9647SVlad Buslov 		NL_SET_ERR_MSG_MOD(extack,
673*0d9f9647SVlad Buslov 				   "encap header larger than max supported");
674*0d9f9647SVlad Buslov 		return -EOPNOTSUPP;
675*0d9f9647SVlad Buslov 	}
676*0d9f9647SVlad Buslov 
677*0d9f9647SVlad Buslov 	key.key = parse_attr->eth;
678*0d9f9647SVlad Buslov 	hash_key = hash_decap_info(&key);
679*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.decap_tbl_lock);
680*0d9f9647SVlad Buslov 	d = mlx5e_decap_get(priv, &key, hash_key);
681*0d9f9647SVlad Buslov 	if (d) {
682*0d9f9647SVlad Buslov 		mutex_unlock(&esw->offloads.decap_tbl_lock);
683*0d9f9647SVlad Buslov 		wait_for_completion(&d->res_ready);
684*0d9f9647SVlad Buslov 		mutex_lock(&esw->offloads.decap_tbl_lock);
685*0d9f9647SVlad Buslov 		if (d->compl_result) {
686*0d9f9647SVlad Buslov 			err = -EREMOTEIO;
687*0d9f9647SVlad Buslov 			goto out_free;
688*0d9f9647SVlad Buslov 		}
689*0d9f9647SVlad Buslov 		goto found;
690*0d9f9647SVlad Buslov 	}
691*0d9f9647SVlad Buslov 
692*0d9f9647SVlad Buslov 	d = kzalloc(sizeof(*d), GFP_KERNEL);
693*0d9f9647SVlad Buslov 	if (!d) {
694*0d9f9647SVlad Buslov 		err = -ENOMEM;
695*0d9f9647SVlad Buslov 		goto out_err;
696*0d9f9647SVlad Buslov 	}
697*0d9f9647SVlad Buslov 
698*0d9f9647SVlad Buslov 	d->key = key;
699*0d9f9647SVlad Buslov 	refcount_set(&d->refcnt, 1);
700*0d9f9647SVlad Buslov 	init_completion(&d->res_ready);
701*0d9f9647SVlad Buslov 	INIT_LIST_HEAD(&d->flows);
702*0d9f9647SVlad Buslov 	hash_add_rcu(esw->offloads.decap_tbl, &d->hlist, hash_key);
703*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
704*0d9f9647SVlad Buslov 
705*0d9f9647SVlad Buslov 	d->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
706*0d9f9647SVlad Buslov 						     MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2,
707*0d9f9647SVlad Buslov 						     sizeof(parse_attr->eth),
708*0d9f9647SVlad Buslov 						     &parse_attr->eth,
709*0d9f9647SVlad Buslov 						     MLX5_FLOW_NAMESPACE_FDB);
710*0d9f9647SVlad Buslov 	if (IS_ERR(d->pkt_reformat)) {
711*0d9f9647SVlad Buslov 		err = PTR_ERR(d->pkt_reformat);
712*0d9f9647SVlad Buslov 		d->compl_result = err;
713*0d9f9647SVlad Buslov 	}
714*0d9f9647SVlad Buslov 	mutex_lock(&esw->offloads.decap_tbl_lock);
715*0d9f9647SVlad Buslov 	complete_all(&d->res_ready);
716*0d9f9647SVlad Buslov 	if (err)
717*0d9f9647SVlad Buslov 		goto out_free;
718*0d9f9647SVlad Buslov 
719*0d9f9647SVlad Buslov found:
720*0d9f9647SVlad Buslov 	flow->decap_reformat = d;
721*0d9f9647SVlad Buslov 	attr->decap_pkt_reformat = d->pkt_reformat;
722*0d9f9647SVlad Buslov 	list_add(&flow->l3_to_l2_reformat, &d->flows);
723*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
724*0d9f9647SVlad Buslov 	return 0;
725*0d9f9647SVlad Buslov 
726*0d9f9647SVlad Buslov out_free:
727*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
728*0d9f9647SVlad Buslov 	mlx5e_decap_put(priv, d);
729*0d9f9647SVlad Buslov 	return err;
730*0d9f9647SVlad Buslov 
731*0d9f9647SVlad Buslov out_err:
732*0d9f9647SVlad Buslov 	mutex_unlock(&esw->offloads.decap_tbl_lock);
733*0d9f9647SVlad Buslov 	return err;
734*0d9f9647SVlad Buslov }
735