Branch data Line data Source code
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 : 0 : sfc_ft_is_supported(struct sfc_adapter *sa)
20 : : {
21 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
22 : :
23 [ # # ]: 0 : return ((sa->priv.dp_rx->features & SFC_DP_RX_FEAT_FLOW_MARK) != 0 &&
24 [ # # ]: 0 : sa->mae.status == SFC_MAE_STATUS_ADMIN);
25 : : }
26 : :
27 : : bool
28 : 0 : sfc_ft_is_active(struct sfc_adapter *sa)
29 : : {
30 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
31 : :
32 : 0 : return ((sa->negotiated_rx_metadata &
33 : 0 : RTE_ETH_RX_METADATA_TUNNEL_ID) != 0);
34 : : }
35 : :
36 : : struct sfc_ft_ctx *
37 : 0 : sfc_ft_ctx_pick(struct sfc_adapter *sa, uint32_t flow_mark)
38 : : {
39 : 0 : 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 [ # # ]: 0 : if (ft_ctx_mark != SFC_FT_CTX_MARK_INVALID) {
44 : 0 : sfc_ft_ctx_id_t ft_ctx_id = SFC_FT_CTX_MARK_TO_CTX_ID(ft_ctx_mark);
45 : 0 : struct sfc_ft_ctx *ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
46 : :
47 : 0 : ft_ctx->id = ft_ctx_id;
48 : :
49 : 0 : return ft_ctx;
50 : : }
51 : :
52 : : return NULL;
53 : : }
54 : :
55 : : int
56 : 0 : 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 [ # # ]: 0 : if (!sfc_ft_is_active(sa)) {
70 : : /* Tunnel-related actions (if any) will be turned down later. */
71 : : return 0;
72 : : }
73 : :
74 [ # # ]: 0 : if (actions == NULL) {
75 : 0 : rte_flow_error_set(error, EINVAL,
76 : : RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
77 : : "NULL actions");
78 : 0 : return -rte_errno;
79 : : }
80 : :
81 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
82 [ # # ]: 0 : if (actions->type == RTE_FLOW_ACTION_TYPE_VOID)
83 : 0 : continue;
84 : :
85 [ # # ]: 0 : if (actions->conf == NULL) {
86 : : rc = EINVAL;
87 : 0 : continue;
88 : : }
89 : :
90 [ # # # # ]: 0 : switch (actions->type) {
91 : : case RTE_FLOW_ACTION_TYPE_COUNT:
92 : : break;
93 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
94 [ # # ]: 0 : if (action_mark == NULL) {
95 : : action_mark = actions->conf;
96 : 0 : flow_mark = action_mark->id;
97 : : } else {
98 : : rc = EINVAL;
99 : : }
100 : : break;
101 : 0 : case RTE_FLOW_ACTION_TYPE_JUMP:
102 [ # # ]: 0 : if (action_jump == NULL) {
103 : : action_jump = actions->conf;
104 [ # # ]: 0 : if (action_jump->group != 0)
105 : : rc = EINVAL;
106 : : } else {
107 : : rc = EINVAL;
108 : : }
109 : : break;
110 : 0 : default:
111 : : rc = ENOTSUP;
112 : 0 : break;
113 : : }
114 : : }
115 : :
116 : 0 : ft_ctx = sfc_ft_ctx_pick(sa, flow_mark);
117 [ # # ]: 0 : if (ft_ctx != NULL && action_jump != 0) {
118 : 0 : sfc_dbg(sa, "FT: TUNNEL: detected");
119 : :
120 [ # # ]: 0 : if (rc != 0) {
121 : : /* The loop above might have spotted wrong actions. */
122 : 0 : sfc_err(sa, "FT: TUNNEL: invalid actions: %s",
123 : : strerror(rc));
124 : 0 : goto fail;
125 : : }
126 : :
127 [ # # ]: 0 : if (ft_ctx->refcnt == 0) {
128 : 0 : sfc_err(sa, "FT: TUNNEL: inactive context (ID=%u)",
129 : : ft_ctx->id);
130 : : rc = ENOENT;
131 : 0 : goto fail;
132 : : }
133 : :
134 [ # # ]: 0 : if (ft_ctx->tunnel_rule_is_set) {
135 : 0 : sfc_err(sa, "FT: TUNNEL: already setup context (ID=%u)",
136 : : ft_ctx->id);
137 : : rc = EEXIST;
138 : 0 : goto fail;
139 : : }
140 : :
141 : 0 : spec->ft_rule_type = SFC_FT_RULE_TUNNEL;
142 : 0 : spec->ft_ctx = ft_ctx;
143 : : }
144 : :
145 : : return 0;
146 : :
147 : 0 : fail:
148 : 0 : return rte_flow_error_set(error, rc,
149 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
150 : : "FT: TUNNEL: preparsing failed");
151 : : }
152 : :
153 : : static int
154 : 0 : 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 : 0 : rc = sfc_dp_ft_ctx_id_register();
166 [ # # ]: 0 : if (rc != 0)
167 : : return rc;
168 : :
169 [ # # ]: 0 : if (tunnel->type != RTE_FLOW_ITEM_TYPE_VXLAN) {
170 : 0 : sfc_err(sa, "FT: unsupported tunnel (encapsulation) type");
171 : 0 : return ENOTSUP;
172 : : }
173 : :
174 [ # # ]: 0 : for (ft_ctx_id = 0; ft_ctx_id < SFC_FT_MAX_NTUNNELS; ++ft_ctx_id) {
175 : 0 : ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
176 : :
177 [ # # ]: 0 : if (ft_ctx->refcnt == 0) {
178 [ # # ]: 0 : if (ft_ctx_id_free == -1)
179 : : ft_ctx_id_free = ft_ctx_id;
180 : :
181 : 0 : continue;
182 : : }
183 : :
184 [ # # ]: 0 : if (memcmp(tunnel, &ft_ctx->tunnel, sizeof(*tunnel)) == 0) {
185 : : ft_ctx_status = "existing";
186 : 0 : goto attach;
187 : : }
188 : : }
189 : :
190 [ # # ]: 0 : if (ft_ctx_id_free == -1) {
191 : 0 : sfc_err(sa, "FT: no free slot for the new context");
192 : 0 : return ENOBUFS;
193 : : }
194 : :
195 : 0 : ft_ctx_id = ft_ctx_id_free;
196 : 0 : ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
197 : :
198 : 0 : memcpy(&ft_ctx->tunnel, tunnel, sizeof(*tunnel));
199 : :
200 : 0 : ft_ctx->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
201 : :
202 : 0 : ft_ctx->action_mark.id = SFC_FT_CTX_ID_TO_FLOW_MARK(ft_ctx_id);
203 : 0 : ft_ctx->action.type = RTE_FLOW_ACTION_TYPE_MARK;
204 : 0 : ft_ctx->action.conf = &ft_ctx->action_mark;
205 : :
206 : 0 : ft_ctx->item_mark_v.id = ft_ctx->action_mark.id;
207 : 0 : ft_ctx->item.type = RTE_FLOW_ITEM_TYPE_MARK;
208 : 0 : ft_ctx->item.spec = &ft_ctx->item_mark_v;
209 : 0 : ft_ctx->item.mask = &ft_ctx->item_mark_m;
210 : 0 : ft_ctx->item_mark_m.id = UINT32_MAX;
211 : :
212 : 0 : ft_ctx->tunnel_rule_is_set = B_FALSE;
213 : :
214 : 0 : ft_ctx->refcnt = 0;
215 : :
216 : : ft_ctx_status = "newly added";
217 : :
218 : 0 : attach:
219 : 0 : sfc_dbg(sa, "FT: attaching to %s context (ID=%u)",
220 : : ft_ctx_status, ft_ctx_id);
221 : :
222 : 0 : ++(ft_ctx->refcnt);
223 : 0 : *ft_ctxp = ft_ctx;
224 : :
225 : 0 : return 0;
226 : : }
227 : :
228 : : static int
229 : 0 : 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 : 0 : ft_ctx = sfc_ft_ctx_pick(sa, flow_mark);
236 [ # # ]: 0 : if (ft_ctx == NULL) {
237 : 0 : sfc_err(sa, "FT: invalid context");
238 : 0 : return EINVAL;
239 : : }
240 : :
241 [ # # ]: 0 : if (ft_ctx->refcnt == 0) {
242 : 0 : sfc_err(sa, "FT: inactive context (ID=%u)", ft_ctx->id);
243 : 0 : return ENOENT;
244 : : }
245 : :
246 : 0 : --(ft_ctx->refcnt);
247 : :
248 : 0 : return 0;
249 : : }
250 : :
251 : : int
252 : 0 : 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 : 0 : sfc_adapter_lock(sa);
261 : :
262 [ # # ]: 0 : if (!sfc_ft_is_active(sa)) {
263 : : rc = ENOTSUP;
264 : 0 : goto fail;
265 : : }
266 : :
267 : 0 : rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx);
268 [ # # ]: 0 : if (rc != 0)
269 : 0 : goto fail;
270 : :
271 : 0 : *pmd_actions = &ft_ctx->action;
272 : 0 : *num_of_actions = 1;
273 : :
274 : : sfc_adapter_unlock(sa);
275 : :
276 : 0 : return 0;
277 : :
278 : 0 : fail:
279 : : sfc_adapter_unlock(sa);
280 : :
281 : 0 : return rte_flow_error_set(err, rc,
282 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
283 : : "FT: decap_set failed");
284 : : }
285 : :
286 : : int
287 : 0 : 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 : 0 : sfc_adapter_lock(sa);
296 : :
297 [ # # ]: 0 : if (!sfc_ft_is_active(sa)) {
298 : : rc = ENOTSUP;
299 : 0 : goto fail;
300 : : }
301 : :
302 : 0 : rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx);
303 [ # # ]: 0 : if (rc != 0)
304 : 0 : goto fail;
305 : :
306 : 0 : *pmd_items = &ft_ctx->item;
307 : 0 : *num_of_items = 1;
308 : :
309 : : sfc_adapter_unlock(sa);
310 : :
311 : 0 : return 0;
312 : :
313 : 0 : fail:
314 : : sfc_adapter_unlock(sa);
315 : :
316 : 0 : return rte_flow_error_set(err, rc,
317 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
318 : : "FT: tunnel_match failed");
319 : : }
320 : :
321 : : int
322 : 0 : 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 : 0 : sfc_adapter_lock(sa);
331 : :
332 [ # # ]: 0 : if (!sfc_ft_is_active(sa)) {
333 : : rc = ENOTSUP;
334 : 0 : goto fail;
335 : : }
336 : :
337 [ # # # # ]: 0 : if (num_items != 1 || item == NULL || item->spec == NULL ||
338 [ # # ]: 0 : item->type != RTE_FLOW_ITEM_TYPE_MARK) {
339 : 0 : sfc_err(sa, "FT: item_release: wrong input");
340 : : rc = EINVAL;
341 : 0 : goto fail;
342 : : }
343 : :
344 : : item_mark = item->spec;
345 : :
346 : 0 : rc = sfc_ft_ctx_detach(sa, item_mark->id);
347 [ # # ]: 0 : if (rc != 0)
348 : 0 : goto fail;
349 : :
350 : : sfc_adapter_unlock(sa);
351 : :
352 : 0 : return 0;
353 : :
354 : 0 : fail:
355 : : sfc_adapter_unlock(sa);
356 : :
357 : 0 : return rte_flow_error_set(err, rc,
358 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
359 : : "FT: item_release failed");
360 : : }
361 : :
362 : : int
363 : 0 : 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 : 0 : sfc_adapter_lock(sa);
373 : :
374 [ # # ]: 0 : if (!sfc_ft_is_active(sa)) {
375 : : rc = ENOTSUP;
376 : 0 : goto fail;
377 : : }
378 : :
379 [ # # # # ]: 0 : if (num_actions != 1 || action == NULL || action->conf == NULL ||
380 [ # # ]: 0 : action->type != RTE_FLOW_ACTION_TYPE_MARK) {
381 : 0 : sfc_err(sa, "FT: action_decap_release: wrong input");
382 : : rc = EINVAL;
383 : 0 : goto fail;
384 : : }
385 : :
386 : : action_mark = action->conf;
387 : :
388 : 0 : rc = sfc_ft_ctx_detach(sa, action_mark->id);
389 [ # # ]: 0 : if (rc != 0)
390 : 0 : goto fail;
391 : :
392 : : sfc_adapter_unlock(sa);
393 : :
394 : 0 : return 0;
395 : :
396 : 0 : fail:
397 : : sfc_adapter_unlock(sa);
398 : :
399 : 0 : return rte_flow_error_set(err, rc,
400 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
401 : : "FT: item_release failed");
402 : : }
403 : :
404 : : int
405 : 0 : 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 : 0 : sfc_adapter_lock(sa);
415 : :
416 [ # # ]: 0 : if ((m->ol_flags & sfc_dp_ft_ctx_id_valid) == 0) {
417 : 0 : sfc_dbg(sa, "FT: get_restore_info: no FT context mark in the packet");
418 : : rc = EINVAL;
419 : 0 : goto fail;
420 : : }
421 : :
422 : 0 : ft_ctx_id = *RTE_MBUF_DYNFIELD(m, sfc_dp_ft_ctx_id_offset,
423 : : sfc_ft_ctx_id_t *);
424 : 0 : ft_ctx = &sa->ft_ctx_pool[ft_ctx_id];
425 : :
426 [ # # ]: 0 : if (ft_ctx->refcnt == 0) {
427 : 0 : sfc_dbg(sa, "FT: get_restore_info: inactive context (ID=%u)",
428 : : ft_ctx_id);
429 : : rc = ENOENT;
430 : 0 : goto fail;
431 : : }
432 : :
433 : 0 : 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 : 0 : info->flags = RTE_FLOW_RESTORE_INFO_ENCAPSULATED |
440 : : RTE_FLOW_RESTORE_INFO_GROUP_ID |
441 : : RTE_FLOW_RESTORE_INFO_TUNNEL;
442 : :
443 : 0 : info->group_id = 0;
444 : :
445 : : sfc_adapter_unlock(sa);
446 : :
447 : 0 : return 0;
448 : :
449 : 0 : fail:
450 : : sfc_adapter_unlock(sa);
451 : :
452 : 0 : return rte_flow_error_set(err, rc,
453 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
454 : : "FT: get_restore_info failed");
455 : : }
456 : :
457 : : void
458 : 0 : 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 [ # # ]: 0 : 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 : 0 : ft_ctx->reset_tunnel_hit_counter = 0;
469 : 0 : ft_ctx->switch_hit_counter = 0;
470 : : }
471 : 0 : }
|