xref: /dpdk/drivers/net/sfc/sfc_flow_tunnel.c (revision f55fe01f88a6802f27df96d78a489306370406a4)
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
sfc_ft_is_supported(struct sfc_adapter * sa)19 sfc_ft_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_ADMIN);
25 }
26 
27 bool
sfc_ft_is_active(struct sfc_adapter * sa)28 sfc_ft_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_ft_ctx *
sfc_ft_ctx_pick(struct sfc_adapter * sa,uint32_t flow_mark)37 sfc_ft_ctx_pick(struct sfc_adapter *sa, uint32_t flow_mark)
38 {
39 	uint8_t ft_ctx_mark = SFC_FT_FLOW_MARK_TO_CTX_MARK(flow_mark);
40 
41 	SFC_ASSERT(sfc_adapter_is_locked(sa));
42 
43 	if (ft_ctx_mark != SFC_FT_CTX_MARK_INVALID) {
44 		sfc_ft_ctx_id_t ft_ctx_id = SFC_FT_CTX_MARK_TO_CTX_ID(ft_ctx_mark);
45 		struct sfc_ft_ctx *ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
46 
47 		ft_ctx->id = ft_ctx_id;
48 
49 		return ft_ctx;
50 	}
51 
52 	return NULL;
53 }
54 
55 int
sfc_ft_tunnel_rule_detect(struct sfc_adapter * sa,const struct rte_flow_action * actions,struct sfc_flow_spec_mae * spec,struct rte_flow_error * error)56 sfc_ft_tunnel_rule_detect(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_ft_ctx *ft_ctx;
64 	uint32_t flow_mark = 0;
65 	int rc = 0;
66 
67 	SFC_ASSERT(sfc_adapter_is_locked(sa));
68 
69 	if (!sfc_ft_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 				flow_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_ctx = sfc_ft_ctx_pick(sa, flow_mark);
117 	if (ft_ctx != NULL && action_jump != 0) {
118 		sfc_dbg(sa, "FT: TUNNEL: detected");
119 
120 		if (rc != 0) {
121 			/* The loop above might have spotted wrong actions. */
122 			sfc_err(sa, "FT: TUNNEL: invalid actions: %s",
123 				strerror(rc));
124 			goto fail;
125 		}
126 
127 		if (ft_ctx->refcnt == 0) {
128 			sfc_err(sa, "FT: TUNNEL: inactive context (ID=%u)",
129 				ft_ctx->id);
130 			rc = ENOENT;
131 			goto fail;
132 		}
133 
134 		if (ft_ctx->tunnel_rule_is_set) {
135 			sfc_err(sa, "FT: TUNNEL: already setup context (ID=%u)",
136 				ft_ctx->id);
137 			rc = EEXIST;
138 			goto fail;
139 		}
140 
141 		spec->ft_rule_type = SFC_FT_RULE_TUNNEL;
142 		spec->ft_ctx = ft_ctx;
143 	}
144 
145 	return 0;
146 
147 fail:
148 	return rte_flow_error_set(error, rc,
149 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
150 				  "FT: TUNNEL: preparsing failed");
151 }
152 
153 static int
sfc_ft_ctx_attach(struct sfc_adapter * sa,const struct rte_flow_tunnel * tunnel,struct sfc_ft_ctx ** ft_ctxp)154 sfc_ft_ctx_attach(struct sfc_adapter *sa, const struct rte_flow_tunnel *tunnel,
155 		  struct sfc_ft_ctx **ft_ctxp)
156 {
157 	sfc_ft_ctx_id_t ft_ctx_id;
158 	struct sfc_ft_ctx *ft_ctx;
159 	const char *ft_ctx_status;
160 	int ft_ctx_id_free = -1;
161 	int rc;
162 
163 	SFC_ASSERT(sfc_adapter_is_locked(sa));
164 
165 	rc = sfc_dp_ft_ctx_id_register();
166 	if (rc != 0)
167 		return rc;
168 
169 	if (tunnel->type != RTE_FLOW_ITEM_TYPE_VXLAN) {
170 		sfc_err(sa, "FT: unsupported tunnel (encapsulation) type");
171 		return ENOTSUP;
172 	}
173 
174 	for (ft_ctx_id = 0; ft_ctx_id < SFC_FT_MAX_NTUNNELS; ++ft_ctx_id) {
175 		ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
176 
177 		if (ft_ctx->refcnt == 0) {
178 			if (ft_ctx_id_free == -1)
179 				ft_ctx_id_free = ft_ctx_id;
180 
181 			continue;
182 		}
183 
184 		if (memcmp(tunnel, &ft_ctx->tunnel, sizeof(*tunnel)) == 0) {
185 			ft_ctx_status = "existing";
186 			goto attach;
187 		}
188 	}
189 
190 	if (ft_ctx_id_free == -1) {
191 		sfc_err(sa, "FT: no free slot for the new context");
192 		return ENOBUFS;
193 	}
194 
195 	ft_ctx_id = ft_ctx_id_free;
196 	ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
197 
198 	memcpy(&ft_ctx->tunnel, tunnel, sizeof(*tunnel));
199 
200 	ft_ctx->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
201 
202 	ft_ctx->action_mark.id = SFC_FT_CTX_ID_TO_FLOW_MARK(ft_ctx_id);
203 	ft_ctx->action.type = RTE_FLOW_ACTION_TYPE_MARK;
204 	ft_ctx->action.conf = &ft_ctx->action_mark;
205 
206 	ft_ctx->item_mark_v.id = ft_ctx->action_mark.id;
207 	ft_ctx->item.type = RTE_FLOW_ITEM_TYPE_MARK;
208 	ft_ctx->item.spec = &ft_ctx->item_mark_v;
209 	ft_ctx->item.mask = &ft_ctx->item_mark_m;
210 	ft_ctx->item_mark_m.id = UINT32_MAX;
211 
212 	ft_ctx->tunnel_rule_is_set = B_FALSE;
213 
214 	ft_ctx->refcnt = 0;
215 
216 	ft_ctx_status = "newly added";
217 
218 attach:
219 	sfc_dbg(sa, "FT: attaching to %s context (ID=%u)",
220 		ft_ctx_status, ft_ctx_id);
221 
222 	++(ft_ctx->refcnt);
223 	*ft_ctxp = ft_ctx;
224 
225 	return 0;
226 }
227 
228 static int
sfc_ft_ctx_detach(struct sfc_adapter * sa,uint32_t flow_mark)229 sfc_ft_ctx_detach(struct sfc_adapter *sa, uint32_t flow_mark)
230 {
231 	struct sfc_ft_ctx *ft_ctx;
232 
233 	SFC_ASSERT(sfc_adapter_is_locked(sa));
234 
235 	ft_ctx = sfc_ft_ctx_pick(sa, flow_mark);
236 	if (ft_ctx == NULL) {
237 		sfc_err(sa, "FT: invalid context");
238 		return EINVAL;
239 	}
240 
241 	if (ft_ctx->refcnt == 0) {
242 		sfc_err(sa, "FT: inactive context (ID=%u)", ft_ctx->id);
243 		return ENOENT;
244 	}
245 
246 	--(ft_ctx->refcnt);
247 
248 	return 0;
249 }
250 
251 int
sfc_ft_decap_set(struct rte_eth_dev * dev,struct rte_flow_tunnel * tunnel,struct rte_flow_action ** pmd_actions,uint32_t * num_of_actions,struct rte_flow_error * err)252 sfc_ft_decap_set(struct rte_eth_dev *dev, struct rte_flow_tunnel *tunnel,
253 		 struct rte_flow_action **pmd_actions, uint32_t *num_of_actions,
254 		 struct rte_flow_error *err)
255 {
256 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
257 	struct sfc_ft_ctx *ft_ctx;
258 	int rc;
259 
260 	sfc_adapter_lock(sa);
261 
262 	if (!sfc_ft_is_active(sa)) {
263 		rc = ENOTSUP;
264 		goto fail;
265 	}
266 
267 	rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx);
268 	if (rc != 0)
269 		goto fail;
270 
271 	*pmd_actions = &ft_ctx->action;
272 	*num_of_actions = 1;
273 
274 	sfc_adapter_unlock(sa);
275 
276 	return 0;
277 
278 fail:
279 	sfc_adapter_unlock(sa);
280 
281 	return rte_flow_error_set(err, rc,
282 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
283 				  "FT: decap_set failed");
284 }
285 
286 int
sfc_ft_match(struct rte_eth_dev * dev,struct rte_flow_tunnel * tunnel,struct rte_flow_item ** pmd_items,uint32_t * num_of_items,struct rte_flow_error * err)287 sfc_ft_match(struct rte_eth_dev *dev, struct rte_flow_tunnel *tunnel,
288 	     struct rte_flow_item **pmd_items, uint32_t *num_of_items,
289 	     struct rte_flow_error *err)
290 {
291 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
292 	struct sfc_ft_ctx *ft_ctx;
293 	int rc;
294 
295 	sfc_adapter_lock(sa);
296 
297 	if (!sfc_ft_is_active(sa)) {
298 		rc = ENOTSUP;
299 		goto fail;
300 	}
301 
302 	rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx);
303 	if (rc != 0)
304 		goto fail;
305 
306 	*pmd_items = &ft_ctx->item;
307 	*num_of_items = 1;
308 
309 	sfc_adapter_unlock(sa);
310 
311 	return 0;
312 
313 fail:
314 	sfc_adapter_unlock(sa);
315 
316 	return rte_flow_error_set(err, rc,
317 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
318 				  "FT: tunnel_match failed");
319 }
320 
321 int
sfc_ft_item_release(struct rte_eth_dev * dev,struct rte_flow_item * pmd_items,uint32_t num_items,struct rte_flow_error * err)322 sfc_ft_item_release(struct rte_eth_dev *dev, struct rte_flow_item *pmd_items,
323 		    uint32_t num_items, struct rte_flow_error *err)
324 {
325 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
326 	const struct rte_flow_item_mark *item_mark;
327 	struct rte_flow_item *item = pmd_items;
328 	int rc;
329 
330 	sfc_adapter_lock(sa);
331 
332 	if (!sfc_ft_is_active(sa)) {
333 		rc = ENOTSUP;
334 		goto fail;
335 	}
336 
337 	if (num_items != 1 || item == NULL || item->spec == NULL ||
338 	    item->type != RTE_FLOW_ITEM_TYPE_MARK) {
339 		sfc_err(sa, "FT: item_release: wrong input");
340 		rc = EINVAL;
341 		goto fail;
342 	}
343 
344 	item_mark = item->spec;
345 
346 	rc = sfc_ft_ctx_detach(sa, item_mark->id);
347 	if (rc != 0)
348 		goto fail;
349 
350 	sfc_adapter_unlock(sa);
351 
352 	return 0;
353 
354 fail:
355 	sfc_adapter_unlock(sa);
356 
357 	return rte_flow_error_set(err, rc,
358 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
359 				  "FT: item_release failed");
360 }
361 
362 int
sfc_ft_action_decap_release(struct rte_eth_dev * dev,struct rte_flow_action * pmd_actions,uint32_t num_actions,struct rte_flow_error * err)363 sfc_ft_action_decap_release(struct rte_eth_dev *dev,
364 			    struct rte_flow_action *pmd_actions,
365 			    uint32_t num_actions, struct rte_flow_error *err)
366 {
367 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
368 	const struct rte_flow_action_mark *action_mark;
369 	struct rte_flow_action *action = pmd_actions;
370 	int rc;
371 
372 	sfc_adapter_lock(sa);
373 
374 	if (!sfc_ft_is_active(sa)) {
375 		rc = ENOTSUP;
376 		goto fail;
377 	}
378 
379 	if (num_actions != 1 || action == NULL || action->conf == NULL ||
380 	    action->type != RTE_FLOW_ACTION_TYPE_MARK) {
381 		sfc_err(sa, "FT: action_decap_release: wrong input");
382 		rc = EINVAL;
383 		goto fail;
384 	}
385 
386 	action_mark = action->conf;
387 
388 	rc = sfc_ft_ctx_detach(sa, action_mark->id);
389 	if (rc != 0)
390 		goto fail;
391 
392 	sfc_adapter_unlock(sa);
393 
394 	return 0;
395 
396 fail:
397 	sfc_adapter_unlock(sa);
398 
399 	return rte_flow_error_set(err, rc,
400 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
401 				  "FT: item_release failed");
402 }
403 
404 int
sfc_ft_get_restore_info(struct rte_eth_dev * dev,struct rte_mbuf * m,struct rte_flow_restore_info * info,struct rte_flow_error * err)405 sfc_ft_get_restore_info(struct rte_eth_dev *dev, struct rte_mbuf *m,
406 			struct rte_flow_restore_info *info,
407 			struct rte_flow_error *err)
408 {
409 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
410 	const struct sfc_ft_ctx *ft_ctx;
411 	sfc_ft_ctx_id_t ft_ctx_id;
412 	int rc;
413 
414 	sfc_adapter_lock(sa);
415 
416 	if ((m->ol_flags & sfc_dp_ft_ctx_id_valid) == 0) {
417 		sfc_dbg(sa, "FT: get_restore_info: no FT context mark in the packet");
418 		rc = EINVAL;
419 		goto fail;
420 	}
421 
422 	ft_ctx_id = *RTE_MBUF_DYNFIELD(m, sfc_dp_ft_ctx_id_offset,
423 				    sfc_ft_ctx_id_t *);
424 	ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
425 
426 	if (ft_ctx->refcnt == 0) {
427 		sfc_dbg(sa, "FT: get_restore_info: inactive context (ID=%u)",
428 			ft_ctx_id);
429 		rc = ENOENT;
430 		goto fail;
431 	}
432 
433 	memcpy(&info->tunnel, &ft_ctx->tunnel, sizeof(info->tunnel));
434 
435 	/*
436 	 * The packet still has encapsulation header; TUNNEL rules never
437 	 * strip it. Therefore, set RTE_FLOW_RESTORE_INFO_ENCAPSULATED.
438 	 */
439 	info->flags = RTE_FLOW_RESTORE_INFO_ENCAPSULATED |
440 		      RTE_FLOW_RESTORE_INFO_GROUP_ID |
441 		      RTE_FLOW_RESTORE_INFO_TUNNEL;
442 
443 	info->group_id = 0;
444 
445 	sfc_adapter_unlock(sa);
446 
447 	return 0;
448 
449 fail:
450 	sfc_adapter_unlock(sa);
451 
452 	return rte_flow_error_set(err, rc,
453 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
454 				  "FT: get_restore_info failed");
455 }
456 
457 void
sfc_ft_counters_reset(struct sfc_adapter * sa)458 sfc_ft_counters_reset(struct sfc_adapter *sa)
459 {
460 	unsigned int i;
461 
462 	SFC_ASSERT(sfc_adapter_is_locked(sa));
463 	SFC_ASSERT(sa->state != SFC_ETHDEV_STARTED);
464 
465 	for (i = 0; i < RTE_DIM(sa->ft_ctx_pool); ++i) {
466 		struct sfc_ft_ctx *ft_ctx = &sa->ft_ctx_pool[i];
467 
468 		ft_ctx->reset_tunnel_hit_counter = 0;
469 		ft_ctx->switch_hit_counter = 0;
470 	}
471 }
472