ethdev: add namespace
[dpdk.git] / drivers / net / sfc / sfc_flow_tunnel.c
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 }