xref: /dpdk/drivers/net/sfc/sfc_flow_tunnel.c (revision 081e42dab11d1add2d038fdf2bd4c86b20043d08)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2021 Xilinx, Inc.
4  */
5 
6 #include <stdbool.h>
7 #include <stdint.h>
8 
9 #include <rte_flow.h>
10 
11 #include "sfc.h"
12 #include "sfc_dp.h"
13 #include "sfc_flow.h"
14 #include "sfc_dp_rx.h"
15 #include "sfc_flow_tunnel.h"
16 #include "sfc_mae.h"
17 
18 bool
19 sfc_flow_tunnel_is_supported(struct sfc_adapter *sa)
20 {
21 	SFC_ASSERT(sfc_adapter_is_locked(sa));
22 
23 	return ((sa->priv.dp_rx->features & SFC_DP_RX_FEAT_FLOW_MARK) != 0 &&
24 		sa->mae.status == SFC_MAE_STATUS_SUPPORTED);
25 }
26 
27 bool
28 sfc_flow_tunnel_is_active(struct sfc_adapter *sa)
29 {
30 	SFC_ASSERT(sfc_adapter_is_locked(sa));
31 
32 	return ((sa->negotiated_rx_metadata &
33 		 RTE_ETH_RX_METADATA_TUNNEL_ID) != 0);
34 }
35 
36 struct sfc_flow_tunnel *
37 sfc_flow_tunnel_pick(struct sfc_adapter *sa, uint32_t ft_mark)
38 {
39 	uint32_t tunnel_mark = SFC_FT_GET_TUNNEL_MARK(ft_mark);
40 
41 	SFC_ASSERT(sfc_adapter_is_locked(sa));
42 
43 	if (tunnel_mark != SFC_FT_TUNNEL_MARK_INVALID) {
44 		sfc_ft_id_t ft_id = SFC_FT_TUNNEL_MARK_TO_ID(tunnel_mark);
45 		struct sfc_flow_tunnel *ft = &sa->flow_tunnels[ft_id];
46 
47 		ft->id = ft_id;
48 
49 		return ft;
50 	}
51 
52 	return NULL;
53 }
54 
55 int
56 sfc_flow_tunnel_detect_jump_rule(struct sfc_adapter *sa,
57 				 const struct rte_flow_action *actions,
58 				 struct sfc_flow_spec_mae *spec,
59 				 struct rte_flow_error *error)
60 {
61 	const struct rte_flow_action_mark *action_mark = NULL;
62 	const struct rte_flow_action_jump *action_jump = NULL;
63 	struct sfc_flow_tunnel *ft;
64 	uint32_t ft_mark = 0;
65 	int rc = 0;
66 
67 	SFC_ASSERT(sfc_adapter_is_locked(sa));
68 
69 	if (!sfc_flow_tunnel_is_active(sa)) {
70 		/* Tunnel-related actions (if any) will be turned down later. */
71 		return 0;
72 	}
73 
74 	if (actions == NULL) {
75 		rte_flow_error_set(error, EINVAL,
76 				   RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
77 				   "NULL actions");
78 		return -rte_errno;
79 	}
80 
81 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
82 		if (actions->type == RTE_FLOW_ACTION_TYPE_VOID)
83 			continue;
84 
85 		if (actions->conf == NULL) {
86 			rc = EINVAL;
87 			continue;
88 		}
89 
90 		switch (actions->type) {
91 		case RTE_FLOW_ACTION_TYPE_COUNT:
92 			break;
93 		case RTE_FLOW_ACTION_TYPE_MARK:
94 			if (action_mark == NULL) {
95 				action_mark = actions->conf;
96 				ft_mark = action_mark->id;
97 			} else {
98 				rc = EINVAL;
99 			}
100 			break;
101 		case RTE_FLOW_ACTION_TYPE_JUMP:
102 			if (action_jump == NULL) {
103 				action_jump = actions->conf;
104 				if (action_jump->group != 0)
105 					rc = EINVAL;
106 			} else {
107 				rc = EINVAL;
108 			}
109 			break;
110 		default:
111 			rc = ENOTSUP;
112 			break;
113 		}
114 	}
115 
116 	ft = sfc_flow_tunnel_pick(sa, ft_mark);
117 	if (ft != NULL && action_jump != 0) {
118 		sfc_dbg(sa, "tunnel offload: JUMP: detected");
119 
120 		if (rc != 0) {
121 			/* The loop above might have spotted wrong actions. */
122 			sfc_err(sa, "tunnel offload: JUMP: invalid actions: %s",
123 				strerror(rc));
124 			goto fail;
125 		}
126 
127 		if (ft->refcnt == 0) {
128 			sfc_err(sa, "tunnel offload: JUMP: tunnel=%u does not exist",
129 				ft->id);
130 			rc = ENOENT;
131 			goto fail;
132 		}
133 
134 		if (ft->jump_rule_is_set) {
135 			sfc_err(sa, "tunnel offload: JUMP: already exists in tunnel=%u",
136 				ft->id);
137 			rc = EEXIST;
138 			goto fail;
139 		}
140 
141 		spec->ft_rule_type = SFC_FT_RULE_JUMP;
142 		spec->ft = ft;
143 	}
144 
145 	return 0;
146 
147 fail:
148 	return rte_flow_error_set(error, rc,
149 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
150 				  "tunnel offload: JUMP: preparsing failed");
151 }
152 
153 static int
154 sfc_flow_tunnel_attach(struct sfc_adapter *sa,
155 		       struct rte_flow_tunnel *tunnel,
156 		       struct sfc_flow_tunnel **ftp)
157 {
158 	struct sfc_flow_tunnel *ft;
159 	const char *ft_status;
160 	int ft_id_free = -1;
161 	sfc_ft_id_t ft_id;
162 	int rc;
163 
164 	SFC_ASSERT(sfc_adapter_is_locked(sa));
165 
166 	rc = sfc_dp_ft_id_register();
167 	if (rc != 0)
168 		return rc;
169 
170 	if (tunnel->type != RTE_FLOW_ITEM_TYPE_VXLAN) {
171 		sfc_err(sa, "tunnel offload: unsupported tunnel (encapsulation) type");
172 		return ENOTSUP;
173 	}
174 
175 	for (ft_id = 0; ft_id < SFC_FT_MAX_NTUNNELS; ++ft_id) {
176 		ft = &sa->flow_tunnels[ft_id];
177 
178 		if (ft->refcnt == 0) {
179 			if (ft_id_free == -1)
180 				ft_id_free = ft_id;
181 
182 			continue;
183 		}
184 
185 		if (memcmp(tunnel, &ft->rte_tunnel, sizeof(*tunnel)) == 0) {
186 			ft_status = "existing";
187 			goto attach;
188 		}
189 	}
190 
191 	if (ft_id_free == -1) {
192 		sfc_err(sa, "tunnel offload: no free slot for the new tunnel");
193 		return ENOBUFS;
194 	}
195 
196 	ft_id = ft_id_free;
197 	ft = &sa->flow_tunnels[ft_id];
198 
199 	memcpy(&ft->rte_tunnel, tunnel, sizeof(*tunnel));
200 
201 	ft->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
202 
203 	ft->action_mark.id = SFC_FT_ID_TO_MARK(ft_id_free);
204 	ft->action.type = RTE_FLOW_ACTION_TYPE_MARK;
205 	ft->action.conf = &ft->action_mark;
206 
207 	ft->item.type = RTE_FLOW_ITEM_TYPE_MARK;
208 	ft->item_mark_v.id = ft->action_mark.id;
209 	ft->item.spec = &ft->item_mark_v;
210 	ft->item.mask = &ft->item_mark_m;
211 	ft->item_mark_m.id = UINT32_MAX;
212 
213 	ft->jump_rule_is_set = B_FALSE;
214 
215 	ft->refcnt = 0;
216 
217 	ft_status = "newly added";
218 
219 attach:
220 	sfc_dbg(sa, "tunnel offload: attaching to %s tunnel=%u",
221 		ft_status, ft_id);
222 
223 	++(ft->refcnt);
224 	*ftp = ft;
225 
226 	return 0;
227 }
228 
229 static int
230 sfc_flow_tunnel_detach(struct sfc_adapter *sa,
231 		       uint32_t ft_mark)
232 {
233 	struct sfc_flow_tunnel *ft;
234 
235 	SFC_ASSERT(sfc_adapter_is_locked(sa));
236 
237 	ft = sfc_flow_tunnel_pick(sa, ft_mark);
238 	if (ft == NULL) {
239 		sfc_err(sa, "tunnel offload: invalid tunnel");
240 		return EINVAL;
241 	}
242 
243 	if (ft->refcnt == 0) {
244 		sfc_err(sa, "tunnel offload: tunnel=%u does not exist", ft->id);
245 		return ENOENT;
246 	}
247 
248 	--(ft->refcnt);
249 
250 	return 0;
251 }
252 
253 int
254 sfc_flow_tunnel_decap_set(struct rte_eth_dev *dev,
255 			  struct rte_flow_tunnel *tunnel,
256 			  struct rte_flow_action **pmd_actions,
257 			  uint32_t *num_of_actions,
258 			  struct rte_flow_error *err)
259 {
260 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
261 	struct sfc_flow_tunnel *ft;
262 	int rc;
263 
264 	sfc_adapter_lock(sa);
265 
266 	if (!sfc_flow_tunnel_is_active(sa)) {
267 		rc = ENOTSUP;
268 		goto fail;
269 	}
270 
271 	rc = sfc_flow_tunnel_attach(sa, tunnel, &ft);
272 	if (rc != 0)
273 		goto fail;
274 
275 	*pmd_actions = &ft->action;
276 	*num_of_actions = 1;
277 
278 	sfc_adapter_unlock(sa);
279 
280 	return 0;
281 
282 fail:
283 	sfc_adapter_unlock(sa);
284 
285 	return rte_flow_error_set(err, rc,
286 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
287 				  "tunnel offload: decap_set failed");
288 }
289 
290 int
291 sfc_flow_tunnel_match(struct rte_eth_dev *dev,
292 		      struct rte_flow_tunnel *tunnel,
293 		      struct rte_flow_item **pmd_items,
294 		      uint32_t *num_of_items,
295 		      struct rte_flow_error *err)
296 {
297 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
298 	struct sfc_flow_tunnel *ft;
299 	int rc;
300 
301 	sfc_adapter_lock(sa);
302 
303 	if (!sfc_flow_tunnel_is_active(sa)) {
304 		rc = ENOTSUP;
305 		goto fail;
306 	}
307 
308 	rc = sfc_flow_tunnel_attach(sa, tunnel, &ft);
309 	if (rc != 0)
310 		goto fail;
311 
312 	*pmd_items = &ft->item;
313 	*num_of_items = 1;
314 
315 	sfc_adapter_unlock(sa);
316 
317 	return 0;
318 
319 fail:
320 	sfc_adapter_unlock(sa);
321 
322 	return rte_flow_error_set(err, rc,
323 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
324 				  "tunnel offload: tunnel_match failed");
325 }
326 
327 int
328 sfc_flow_tunnel_item_release(struct rte_eth_dev *dev,
329 			     struct rte_flow_item *pmd_items,
330 			     uint32_t num_items,
331 			     struct rte_flow_error *err)
332 {
333 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
334 	const struct rte_flow_item_mark *item_mark;
335 	struct rte_flow_item *item = pmd_items;
336 	int rc;
337 
338 	sfc_adapter_lock(sa);
339 
340 	if (!sfc_flow_tunnel_is_active(sa)) {
341 		rc = ENOTSUP;
342 		goto fail;
343 	}
344 
345 	if (num_items != 1 || item == NULL || item->spec == NULL ||
346 	    item->type != RTE_FLOW_ITEM_TYPE_MARK) {
347 		sfc_err(sa, "tunnel offload: item_release: wrong input");
348 		rc = EINVAL;
349 		goto fail;
350 	}
351 
352 	item_mark = item->spec;
353 
354 	rc = sfc_flow_tunnel_detach(sa, item_mark->id);
355 	if (rc != 0)
356 		goto fail;
357 
358 	sfc_adapter_unlock(sa);
359 
360 	return 0;
361 
362 fail:
363 	sfc_adapter_unlock(sa);
364 
365 	return rte_flow_error_set(err, rc,
366 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
367 				  "tunnel offload: item_release failed");
368 }
369 
370 int
371 sfc_flow_tunnel_action_decap_release(struct rte_eth_dev *dev,
372 				     struct rte_flow_action *pmd_actions,
373 				     uint32_t num_actions,
374 				     struct rte_flow_error *err)
375 {
376 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
377 	const struct rte_flow_action_mark *action_mark;
378 	struct rte_flow_action *action = pmd_actions;
379 	int rc;
380 
381 	sfc_adapter_lock(sa);
382 
383 	if (!sfc_flow_tunnel_is_active(sa)) {
384 		rc = ENOTSUP;
385 		goto fail;
386 	}
387 
388 	if (num_actions != 1 || action == NULL || action->conf == NULL ||
389 	    action->type != RTE_FLOW_ACTION_TYPE_MARK) {
390 		sfc_err(sa, "tunnel offload: action_decap_release: wrong input");
391 		rc = EINVAL;
392 		goto fail;
393 	}
394 
395 	action_mark = action->conf;
396 
397 	rc = sfc_flow_tunnel_detach(sa, action_mark->id);
398 	if (rc != 0)
399 		goto fail;
400 
401 	sfc_adapter_unlock(sa);
402 
403 	return 0;
404 
405 fail:
406 	sfc_adapter_unlock(sa);
407 
408 	return rte_flow_error_set(err, rc,
409 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
410 				  "tunnel offload: item_release failed");
411 }
412 
413 int
414 sfc_flow_tunnel_get_restore_info(struct rte_eth_dev *dev,
415 				 struct rte_mbuf *m,
416 				 struct rte_flow_restore_info *info,
417 				 struct rte_flow_error *err)
418 {
419 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
420 	const struct sfc_flow_tunnel *ft;
421 	sfc_ft_id_t ft_id;
422 	int rc;
423 
424 	sfc_adapter_lock(sa);
425 
426 	if ((m->ol_flags & sfc_dp_ft_id_valid) == 0) {
427 		sfc_dbg(sa, "tunnel offload: get_restore_info: no tunnel mark in the packet");
428 		rc = EINVAL;
429 		goto fail;
430 	}
431 
432 	ft_id = *RTE_MBUF_DYNFIELD(m, sfc_dp_ft_id_offset, sfc_ft_id_t *);
433 	ft = &sa->flow_tunnels[ft_id];
434 
435 	if (ft->refcnt == 0) {
436 		sfc_err(sa, "tunnel offload: get_restore_info: tunnel=%u does not exist",
437 			ft_id);
438 		rc = ENOENT;
439 		goto fail;
440 	}
441 
442 	memcpy(&info->tunnel, &ft->rte_tunnel, sizeof(info->tunnel));
443 
444 	/*
445 	 * The packet still has encapsulation header; JUMP rules never
446 	 * strip it. Therefore, set RTE_FLOW_RESTORE_INFO_ENCAPSULATED.
447 	 */
448 	info->flags = RTE_FLOW_RESTORE_INFO_ENCAPSULATED |
449 		      RTE_FLOW_RESTORE_INFO_GROUP_ID |
450 		      RTE_FLOW_RESTORE_INFO_TUNNEL;
451 
452 	info->group_id = 0;
453 
454 	sfc_adapter_unlock(sa);
455 
456 	return 0;
457 
458 fail:
459 	sfc_adapter_unlock(sa);
460 
461 	return rte_flow_error_set(err, rc,
462 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
463 				  "tunnel offload: get_restore_info failed");
464 }
465 
466 void
467 sfc_flow_tunnel_reset_hit_counters(struct sfc_adapter *sa)
468 {
469 	unsigned int i;
470 
471 	SFC_ASSERT(sfc_adapter_is_locked(sa));
472 	SFC_ASSERT(sa->state != SFC_ETHDEV_STARTED);
473 
474 	for (i = 0; i < RTE_DIM(sa->flow_tunnels); ++i) {
475 		struct sfc_flow_tunnel *ft = &sa->flow_tunnels[i];
476 
477 		ft->reset_jump_hit_counter = 0;
478 		ft->group_hit_counter = 0;
479 	}
480 }
481