net/sfc: support flow item PHY PORT in MAE backend
[dpdk.git] / drivers / net / sfc / sfc_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2020 Xilinx, Inc.
4  * Copyright(c) 2019 Solarflare Communications Inc.
5  *
6  * This software was jointly developed between OKTET Labs (under contract
7  * for Solarflare) and Solarflare Communications, Inc.
8  */
9
10 #include <stdbool.h>
11
12 #include <rte_common.h>
13
14 #include "efx.h"
15
16 #include "sfc.h"
17 #include "sfc_log.h"
18
19 int
20 sfc_mae_attach(struct sfc_adapter *sa)
21 {
22         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
23         struct sfc_mae *mae = &sa->mae;
24         efx_mae_limits_t limits;
25         int rc;
26
27         sfc_log_init(sa, "entry");
28
29         if (!encp->enc_mae_supported) {
30                 mae->status = SFC_MAE_STATUS_UNSUPPORTED;
31                 return 0;
32         }
33
34         sfc_log_init(sa, "init MAE");
35         rc = efx_mae_init(sa->nic);
36         if (rc != 0)
37                 goto fail_mae_init;
38
39         sfc_log_init(sa, "get MAE limits");
40         rc = efx_mae_get_limits(sa->nic, &limits);
41         if (rc != 0)
42                 goto fail_mae_get_limits;
43
44         mae->status = SFC_MAE_STATUS_SUPPORTED;
45         mae->nb_action_rule_prios_max = limits.eml_max_n_action_prios;
46         TAILQ_INIT(&mae->action_sets);
47
48         sfc_log_init(sa, "done");
49
50         return 0;
51
52 fail_mae_get_limits:
53         efx_mae_fini(sa->nic);
54
55 fail_mae_init:
56         sfc_log_init(sa, "failed %d", rc);
57
58         return rc;
59 }
60
61 void
62 sfc_mae_detach(struct sfc_adapter *sa)
63 {
64         struct sfc_mae *mae = &sa->mae;
65         enum sfc_mae_status status_prev = mae->status;
66
67         sfc_log_init(sa, "entry");
68
69         mae->nb_action_rule_prios_max = 0;
70         mae->status = SFC_MAE_STATUS_UNKNOWN;
71
72         if (status_prev != SFC_MAE_STATUS_SUPPORTED)
73                 return;
74
75         efx_mae_fini(sa->nic);
76
77         sfc_log_init(sa, "done");
78 }
79
80 static struct sfc_mae_action_set *
81 sfc_mae_action_set_attach(struct sfc_adapter *sa,
82                           const efx_mae_actions_t *spec)
83 {
84         struct sfc_mae_action_set *action_set;
85         struct sfc_mae *mae = &sa->mae;
86
87         SFC_ASSERT(sfc_adapter_is_locked(sa));
88
89         TAILQ_FOREACH(action_set, &mae->action_sets, entries) {
90                 if (efx_mae_action_set_specs_equal(action_set->spec, spec)) {
91                         ++(action_set->refcnt);
92                         return action_set;
93                 }
94         }
95
96         return NULL;
97 }
98
99 static int
100 sfc_mae_action_set_add(struct sfc_adapter *sa,
101                        efx_mae_actions_t *spec,
102                        struct sfc_mae_action_set **action_setp)
103 {
104         struct sfc_mae_action_set *action_set;
105         struct sfc_mae *mae = &sa->mae;
106
107         SFC_ASSERT(sfc_adapter_is_locked(sa));
108
109         action_set = rte_zmalloc("sfc_mae_action_set", sizeof(*action_set), 0);
110         if (action_set == NULL)
111                 return ENOMEM;
112
113         action_set->refcnt = 1;
114         action_set->spec = spec;
115
116         TAILQ_INSERT_TAIL(&mae->action_sets, action_set, entries);
117
118         *action_setp = action_set;
119
120         return 0;
121 }
122
123 static void
124 sfc_mae_action_set_del(struct sfc_adapter *sa,
125                        struct sfc_mae_action_set *action_set)
126 {
127         struct sfc_mae *mae = &sa->mae;
128
129         SFC_ASSERT(sfc_adapter_is_locked(sa));
130         SFC_ASSERT(action_set->refcnt != 0);
131
132         --(action_set->refcnt);
133
134         if (action_set->refcnt != 0)
135                 return;
136
137         efx_mae_action_set_spec_fini(sa->nic, action_set->spec);
138         TAILQ_REMOVE(&mae->action_sets, action_set, entries);
139         rte_free(action_set);
140 }
141
142 void
143 sfc_mae_flow_cleanup(struct sfc_adapter *sa,
144                      struct rte_flow *flow)
145 {
146         struct sfc_flow_spec *spec;
147         struct sfc_flow_spec_mae *spec_mae;
148
149         if (flow == NULL)
150                 return;
151
152         spec = &flow->spec;
153
154         if (spec == NULL)
155                 return;
156
157         spec_mae = &spec->mae;
158
159         if (spec_mae->action_set != NULL)
160                 sfc_mae_action_set_del(sa, spec_mae->action_set);
161
162         if (spec_mae->match_spec != NULL)
163                 efx_mae_match_spec_fini(sa->nic, spec_mae->match_spec);
164 }
165
166 static int
167 sfc_mae_rule_parse_item_phy_port(const struct rte_flow_item *item,
168                                  struct sfc_flow_parse_ctx *ctx,
169                                  struct rte_flow_error *error)
170 {
171         struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
172         const struct rte_flow_item_phy_port supp_mask = {
173                 .index = 0xffffffff,
174         };
175         const void *def_mask = &rte_flow_item_phy_port_mask;
176         const struct rte_flow_item_phy_port *spec = NULL;
177         const struct rte_flow_item_phy_port *mask = NULL;
178         efx_mport_sel_t mport_v;
179         int rc;
180
181         if (ctx_mae->match_mport_set) {
182                 return rte_flow_error_set(error, ENOTSUP,
183                                 RTE_FLOW_ERROR_TYPE_ITEM, item,
184                                 "Can't handle multiple traffic source items");
185         }
186
187         rc = sfc_flow_parse_init(item,
188                                  (const void **)&spec, (const void **)&mask,
189                                  (const void *)&supp_mask, def_mask,
190                                  sizeof(struct rte_flow_item_phy_port), error);
191         if (rc != 0)
192                 return rc;
193
194         if (mask->index != supp_mask.index) {
195                 return rte_flow_error_set(error, EINVAL,
196                                 RTE_FLOW_ERROR_TYPE_ITEM, item,
197                                 "Bad mask in the PHY_PORT pattern item");
198         }
199
200         /* If "spec" is not set, could be any physical port */
201         if (spec == NULL)
202                 return 0;
203
204         rc = efx_mae_mport_by_phy_port(spec->index, &mport_v);
205         if (rc != 0) {
206                 return rte_flow_error_set(error, rc,
207                                 RTE_FLOW_ERROR_TYPE_ITEM, item,
208                                 "Failed to convert the PHY_PORT index");
209         }
210
211         rc = efx_mae_match_spec_mport_set(ctx_mae->match_spec_action,
212                                           &mport_v, NULL);
213         if (rc != 0) {
214                 return rte_flow_error_set(error, rc,
215                                 RTE_FLOW_ERROR_TYPE_ITEM, item,
216                                 "Failed to set MPORT for the PHY_PORT");
217         }
218
219         ctx_mae->match_mport_set = B_TRUE;
220
221         return 0;
222 }
223
224 static const struct sfc_flow_item sfc_flow_items[] = {
225         {
226                 .type = RTE_FLOW_ITEM_TYPE_PHY_PORT,
227                 /*
228                  * In terms of RTE flow, this item is a META one,
229                  * and its position in the pattern is don't care.
230                  */
231                 .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
232                 .layer = SFC_FLOW_ITEM_ANY_LAYER,
233                 .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
234                 .parse = sfc_mae_rule_parse_item_phy_port,
235         },
236 };
237
238 int
239 sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
240                            const struct rte_flow_item pattern[],
241                            struct sfc_flow_spec_mae *spec,
242                            struct rte_flow_error *error)
243 {
244         struct sfc_mae_parse_ctx ctx_mae;
245         struct sfc_flow_parse_ctx ctx;
246         int rc;
247
248         memset(&ctx_mae, 0, sizeof(ctx_mae));
249
250         rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION,
251                                      spec->priority,
252                                      &ctx_mae.match_spec_action);
253         if (rc != 0) {
254                 rc = rte_flow_error_set(error, rc,
255                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
256                         "Failed to initialise action rule match specification");
257                 goto fail_init_match_spec_action;
258         }
259
260         ctx.type = SFC_FLOW_PARSE_CTX_MAE;
261         ctx.mae = &ctx_mae;
262
263         rc = sfc_flow_parse_pattern(sfc_flow_items, RTE_DIM(sfc_flow_items),
264                                     pattern, &ctx, error);
265         if (rc != 0)
266                 goto fail_parse_pattern;
267
268         if (!efx_mae_match_spec_is_valid(sa->nic, ctx_mae.match_spec_action)) {
269                 rc = rte_flow_error_set(error, ENOTSUP,
270                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
271                                         "Inconsistent pattern");
272                 goto fail_validate_match_spec_action;
273         }
274
275         spec->match_spec = ctx_mae.match_spec_action;
276
277         return 0;
278
279 fail_validate_match_spec_action:
280 fail_parse_pattern:
281         efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action);
282
283 fail_init_match_spec_action:
284         return rc;
285 }
286
287 static int
288 sfc_mae_rule_parse_action(const struct rte_flow_action *action,
289                           __rte_unused efx_mae_actions_t *spec,
290                           struct rte_flow_error *error)
291 {
292         switch (action->type) {
293         default:
294                 return rte_flow_error_set(error, ENOTSUP,
295                                 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
296                                 "Unsupported action");
297         }
298
299         return 0;
300 }
301
302 int
303 sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
304                            const struct rte_flow_action actions[],
305                            struct sfc_mae_action_set **action_setp,
306                            struct rte_flow_error *error)
307 {
308         const struct rte_flow_action *action;
309         efx_mae_actions_t *spec;
310         int rc;
311
312         if (actions == NULL) {
313                 return rte_flow_error_set(error, EINVAL,
314                                 RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
315                                 "NULL actions");
316         }
317
318         rc = efx_mae_action_set_spec_init(sa->nic, &spec);
319         if (rc != 0)
320                 goto fail_action_set_spec_init;
321
322         for (action = actions;
323              action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
324                 rc = sfc_mae_rule_parse_action(action, spec, error);
325                 if (rc != 0)
326                         goto fail_rule_parse_action;
327         }
328
329         *action_setp = sfc_mae_action_set_attach(sa, spec);
330         if (*action_setp != NULL) {
331                 efx_mae_action_set_spec_fini(sa->nic, spec);
332                 return 0;
333         }
334
335         rc = sfc_mae_action_set_add(sa, spec, action_setp);
336         if (rc != 0)
337                 goto fail_action_set_add;
338
339         return 0;
340
341 fail_action_set_add:
342 fail_rule_parse_action:
343         efx_mae_action_set_spec_fini(sa->nic, spec);
344
345 fail_action_set_spec_init:
346         if (rc > 0) {
347                 rc = rte_flow_error_set(error, rc,
348                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
349                         NULL, "Failed to process the action");
350         }
351         return rc;
352 }
353
354 static bool
355 sfc_mae_rules_class_cmp(struct sfc_adapter *sa,
356                         const efx_mae_match_spec_t *left,
357                         const efx_mae_match_spec_t *right)
358 {
359         bool have_same_class;
360         int rc;
361
362         rc = efx_mae_match_specs_class_cmp(sa->nic, left, right,
363                                            &have_same_class);
364
365         return (rc == 0) ? have_same_class : false;
366 }
367
368 static int
369 sfc_mae_action_rule_class_verify(struct sfc_adapter *sa,
370                                  struct sfc_flow_spec_mae *spec)
371 {
372         const struct rte_flow *entry;
373
374         TAILQ_FOREACH_REVERSE(entry, &sa->flow_list, sfc_flow_list, entries) {
375                 const struct sfc_flow_spec *entry_spec = &entry->spec;
376                 const struct sfc_flow_spec_mae *es_mae = &entry_spec->mae;
377                 const efx_mae_match_spec_t *left = es_mae->match_spec;
378                 const efx_mae_match_spec_t *right = spec->match_spec;
379
380                 switch (entry_spec->type) {
381                 case SFC_FLOW_SPEC_FILTER:
382                         /* Ignore VNIC-level flows */
383                         break;
384                 case SFC_FLOW_SPEC_MAE:
385                         if (sfc_mae_rules_class_cmp(sa, left, right))
386                                 return 0;
387                         break;
388                 default:
389                         SFC_ASSERT(false);
390                 }
391         }
392
393         sfc_info(sa, "for now, the HW doesn't support rule validation, and HW "
394                  "support for inner frame pattern items is not guaranteed; "
395                  "other than that, the items are valid from SW standpoint");
396         return 0;
397 }
398
399 /**
400  * Confirm that a given flow can be accepted by the FW.
401  *
402  * @param sa
403  *   Software adapter context
404  * @param flow
405  *   Flow to be verified
406  * @return
407  *   Zero on success and non-zero in the case of error.
408  *   A special value of EAGAIN indicates that the adapter is
409  *   not in started state. This state is compulsory because
410  *   it only makes sense to compare the rule class of the flow
411  *   being validated with classes of the active rules.
412  *   Such classes are wittingly supported by the FW.
413  */
414 int
415 sfc_mae_flow_verify(struct sfc_adapter *sa,
416                     struct rte_flow *flow)
417 {
418         struct sfc_flow_spec *spec = &flow->spec;
419         struct sfc_flow_spec_mae *spec_mae = &spec->mae;
420
421         SFC_ASSERT(sfc_adapter_is_locked(sa));
422
423         if (sa->state != SFC_ADAPTER_STARTED)
424                 return EAGAIN;
425
426         return sfc_mae_action_rule_class_verify(sa, spec_mae);
427 }