Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2019-2021 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_byteorder.h>
13 : : #include <rte_bitops.h>
14 : : #include <rte_common.h>
15 : : #include <rte_vxlan.h>
16 : :
17 : : #include "efx.h"
18 : :
19 : : #include "sfc.h"
20 : : #include "sfc_flow_tunnel.h"
21 : : #include "sfc_mae_counter.h"
22 : : #include "sfc_mae_ct.h"
23 : : #include "sfc_log.h"
24 : : #include "sfc_switch.h"
25 : : #include "sfc_service.h"
26 : :
27 : : static int
28 : 0 : sfc_mae_assign_ethdev_mport(struct sfc_adapter *sa,
29 : : efx_mport_sel_t *mportp)
30 : : {
31 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
32 : :
33 : 0 : return efx_mae_mport_by_pcie_function(encp->enc_pf, encp->enc_vf,
34 : : mportp);
35 : : }
36 : :
37 : : static int
38 : 0 : sfc_mae_assign_entity_mport(struct sfc_adapter *sa,
39 : : efx_mport_sel_t *mportp)
40 : : {
41 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
42 : : int rc = 0;
43 : :
44 [ # # ]: 0 : if (encp->enc_mae_admin) {
45 : : /*
46 : : * This ethdev sits on MAE admin PF. The represented
47 : : * entity is the network port assigned to that PF.
48 : : */
49 : 0 : rc = efx_mae_mport_by_phy_port(encp->enc_assigned_port, mportp);
50 : : } else {
51 : : /*
52 : : * This ethdev sits on unprivileged PF / VF. The entity
53 : : * represented by the ethdev can change dynamically
54 : : * as MAE admin changes default traffic rules.
55 : : *
56 : : * For the sake of simplicity, do not fill in the m-port
57 : : * and assume that flow rules should not be allowed to
58 : : * reference the entity represented by this ethdev.
59 : : */
60 : 0 : efx_mae_mport_invalid(mportp);
61 : : }
62 : :
63 : 0 : return rc;
64 : : }
65 : :
66 : : static int
67 : 0 : sfc_mae_counter_registry_init(struct sfc_mae_counter_registry *registry,
68 : : uint32_t nb_action_counters_max,
69 : : uint32_t nb_conntrack_counters_max)
70 : : {
71 : : int ret;
72 : :
73 : 0 : ret = sfc_mae_counters_init(®istry->action_counters,
74 : : nb_action_counters_max);
75 [ # # ]: 0 : if (ret != 0)
76 : : return ret;
77 : :
78 : 0 : registry->action_counters.type = EFX_COUNTER_TYPE_ACTION;
79 : :
80 : 0 : ret = sfc_mae_counters_init(®istry->conntrack_counters,
81 : : nb_conntrack_counters_max);
82 [ # # ]: 0 : if (ret != 0)
83 : : return ret;
84 : :
85 : 0 : registry->conntrack_counters.type = EFX_COUNTER_TYPE_CONNTRACK;
86 : :
87 : 0 : return 0;
88 : : }
89 : :
90 : : static void
91 : : sfc_mae_counter_registry_fini(struct sfc_mae_counter_registry *registry)
92 : : {
93 : 0 : sfc_mae_counters_fini(®istry->conntrack_counters);
94 : 0 : sfc_mae_counters_fini(®istry->action_counters);
95 : 0 : }
96 : :
97 : : struct rte_flow *
98 : 0 : sfc_mae_repr_flow_create(struct sfc_adapter *sa, int prio, uint16_t port_id,
99 : : enum rte_flow_action_type dst_type,
100 : : enum rte_flow_item_type src_type)
101 : : {
102 : 0 : const struct rte_flow_item_ethdev item_spec = { .port_id = port_id };
103 : 0 : const struct rte_flow_action_ethdev action = { .port_id = port_id };
104 : : const void *item_mask = &rte_flow_item_ethdev_mask;
105 : 0 : struct rte_flow_attr attr = { .transfer = 1 };
106 : 0 : const struct rte_flow_action actions[] = {
107 : : { .type = dst_type, .conf = &action },
108 : : { .type = RTE_FLOW_ACTION_TYPE_END }
109 : : };
110 : 0 : const struct rte_flow_item items[] = {
111 : : { .type = src_type, .mask = item_mask, .spec = &item_spec },
112 : : { .type = RTE_FLOW_ITEM_TYPE_END }
113 : : };
114 : : struct sfc_mae *mae = &sa->mae;
115 : : struct rte_flow_error error;
116 : :
117 [ # # # # ]: 0 : if (prio > 0 && (unsigned int)prio >= mae->nb_action_rule_prios_max) {
118 : 0 : sfc_err(sa, "failed: invalid priority %d (max %u)", prio,
119 : : mae->nb_action_rule_prios_max);
120 : 0 : return NULL;
121 : : }
122 [ # # ]: 0 : if (prio < 0)
123 : 0 : prio = mae->nb_action_rule_prios_max - 1;
124 : :
125 : 0 : attr.priority = prio;
126 : :
127 : 0 : return sfc_flow_create_locked(sa, true, &attr, items, actions, &error);
128 : : }
129 : :
130 : : void
131 : 0 : sfc_mae_repr_flow_destroy(struct sfc_adapter *sa, struct rte_flow *flow)
132 : : {
133 : : struct rte_flow_error error;
134 : : int rc;
135 : :
136 : 0 : rc = sfc_flow_destroy_locked(sa, flow, &error);
137 [ # # ]: 0 : if (rc != 0)
138 : 0 : sfc_err(sa, "failed to destroy the internal flow");
139 : 0 : }
140 : :
141 : : int
142 : 0 : sfc_mae_attach(struct sfc_adapter *sa)
143 : : {
144 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
145 : 0 : struct sfc_mae_switch_port_request switch_port_request = {0};
146 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
147 : : efx_mport_sel_t ethdev_mport;
148 : : efx_mport_sel_t entity_mport;
149 : : struct sfc_mae *mae = &sa->mae;
150 : : struct sfc_mae_bounce_eh *bounce_eh = &mae->bounce_eh;
151 : : efx_mae_limits_t limits;
152 : : int rc;
153 : :
154 : 0 : sfc_log_init(sa, "entry");
155 : :
156 [ # # ]: 0 : if (!encp->enc_mae_supported) {
157 : 0 : mae->status = SFC_MAE_STATUS_UNSUPPORTED;
158 : 0 : return 0;
159 : : }
160 : :
161 [ # # ]: 0 : if (encp->enc_mae_admin) {
162 : 0 : sfc_log_init(sa, "init MAE");
163 : 0 : rc = efx_mae_init(sa->nic);
164 [ # # ]: 0 : if (rc != 0)
165 : 0 : goto fail_mae_init;
166 : :
167 : 0 : sfc_log_init(sa, "get MAE limits");
168 : 0 : rc = efx_mae_get_limits(sa->nic, &limits);
169 [ # # ]: 0 : if (rc != 0)
170 : 0 : goto fail_mae_get_limits;
171 : :
172 : 0 : sfc_log_init(sa, "init MAE counter record registry");
173 : 0 : rc = sfc_mae_counter_registry_init(&mae->counter_registry,
174 : : limits.eml_max_n_action_counters,
175 : : limits.eml_max_n_conntrack_counters);
176 [ # # ]: 0 : if (rc != 0) {
177 : 0 : sfc_err(sa, "failed to init record registry for %u AR and %u CT counters: %s",
178 : : limits.eml_max_n_action_counters,
179 : : limits.eml_max_n_conntrack_counters,
180 : : rte_strerror(rc));
181 : 0 : goto fail_counter_registry_init;
182 : : }
183 : : }
184 : :
185 : 0 : sfc_log_init(sa, "assign ethdev MPORT");
186 : 0 : rc = sfc_mae_assign_ethdev_mport(sa, ðdev_mport);
187 [ # # ]: 0 : if (rc != 0)
188 : 0 : goto fail_mae_assign_ethdev_mport;
189 : :
190 : 0 : sfc_log_init(sa, "assign entity MPORT");
191 : 0 : rc = sfc_mae_assign_entity_mport(sa, &entity_mport);
192 [ # # ]: 0 : if (rc != 0)
193 : 0 : goto fail_mae_assign_entity_mport;
194 : :
195 : 0 : sfc_log_init(sa, "assign RTE switch domain");
196 : 0 : rc = sfc_mae_assign_switch_domain(sa, &mae->switch_domain_id);
197 [ # # ]: 0 : if (rc != 0)
198 : 0 : goto fail_mae_assign_switch_domain;
199 : :
200 : 0 : sfc_log_init(sa, "assign RTE switch port");
201 : 0 : switch_port_request.type = SFC_MAE_SWITCH_PORT_INDEPENDENT;
202 : 0 : switch_port_request.ethdev_mportp = ðdev_mport;
203 : 0 : switch_port_request.entity_mportp = &entity_mport;
204 : 0 : switch_port_request.ethdev_port_id = sas->port_id;
205 : 0 : switch_port_request.port_data.indep.mae_admin =
206 : 0 : encp->enc_mae_admin == B_TRUE;
207 : 0 : rc = sfc_mae_assign_switch_port(mae->switch_domain_id,
208 : : &switch_port_request,
209 : : &mae->switch_port_id);
210 [ # # ]: 0 : if (rc != 0)
211 : 0 : goto fail_mae_assign_switch_port;
212 : :
213 [ # # ]: 0 : if (encp->enc_mae_admin) {
214 : 0 : sfc_log_init(sa, "allocate encap. header bounce buffer");
215 : 0 : bounce_eh->buf_size = limits.eml_encap_header_size_limit;
216 : 0 : bounce_eh->buf = rte_malloc("sfc_mae_bounce_eh",
217 : : bounce_eh->buf_size, 0);
218 [ # # ]: 0 : if (bounce_eh->buf == NULL) {
219 : : rc = ENOMEM;
220 : 0 : goto fail_mae_alloc_bounce_eh;
221 : : }
222 : :
223 : 0 : sfc_log_init(sa, "allocate bounce action set pointer array");
224 : 0 : mae->bounce_aset_ptrs = rte_calloc("sfc_mae_bounce_aset_ptrs",
225 : : EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES,
226 : : sizeof(*mae->bounce_aset_ptrs), 0);
227 [ # # ]: 0 : if (mae->bounce_aset_ptrs == NULL) {
228 : : rc = ENOMEM;
229 : 0 : goto fail_mae_alloc_bounce_aset_ptrs;
230 : : }
231 : :
232 : 0 : sfc_log_init(sa, "allocate bounce action set contexts");
233 : 0 : mae->bounce_aset_ctxs = rte_calloc("sfc_mae_bounce_aset_ctxs",
234 : : EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES,
235 : : sizeof(*mae->bounce_aset_ctxs), 0);
236 [ # # ]: 0 : if (mae->bounce_aset_ctxs == NULL) {
237 : : rc = ENOMEM;
238 : 0 : goto fail_mae_alloc_bounce_aset_ctxs;
239 : : }
240 : :
241 : 0 : sfc_log_init(sa, "allocate bounce action set ID array");
242 : 0 : mae->bounce_aset_ids = rte_calloc("sfc_mae_bounce_aset_ids",
243 : : EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES,
244 : : sizeof(*mae->bounce_aset_ids), 0);
245 [ # # ]: 0 : if (mae->bounce_aset_ids == NULL) {
246 : : rc = ENOMEM;
247 : 0 : goto fail_mae_alloc_bounce_aset_ids;
248 : : }
249 : :
250 : 0 : mae->nb_outer_rule_prios_max = limits.eml_max_n_outer_prios;
251 : 0 : mae->nb_action_rule_prios_max = limits.eml_max_n_action_prios;
252 : 0 : mae->encap_types_supported = limits.eml_encap_types_supported;
253 : : }
254 : :
255 : 0 : TAILQ_INIT(&mae->outer_rules);
256 : 0 : TAILQ_INIT(&mae->mac_addrs);
257 : 0 : TAILQ_INIT(&mae->encap_headers);
258 : 0 : TAILQ_INIT(&mae->counters);
259 : 0 : TAILQ_INIT(&mae->action_sets);
260 : 0 : TAILQ_INIT(&mae->action_set_lists);
261 : 0 : TAILQ_INIT(&mae->action_rules);
262 : :
263 [ # # ]: 0 : if (encp->enc_mae_admin)
264 : 0 : mae->status = SFC_MAE_STATUS_ADMIN;
265 : : else
266 : 0 : mae->status = SFC_MAE_STATUS_SUPPORTED;
267 : :
268 : 0 : sfc_log_init(sa, "done");
269 : :
270 : 0 : return 0;
271 : :
272 : : fail_mae_alloc_bounce_aset_ids:
273 : 0 : rte_free(mae->bounce_aset_ctxs);
274 : :
275 : 0 : fail_mae_alloc_bounce_aset_ctxs:
276 : 0 : rte_free(mae->bounce_aset_ptrs);
277 : :
278 : 0 : fail_mae_alloc_bounce_aset_ptrs:
279 : 0 : rte_free(mae->bounce_eh.buf);
280 : :
281 : 0 : fail_mae_alloc_bounce_eh:
282 : 0 : fail_mae_assign_switch_port:
283 : 0 : fail_mae_assign_switch_domain:
284 : 0 : fail_mae_assign_entity_mport:
285 : 0 : fail_mae_assign_ethdev_mport:
286 [ # # ]: 0 : if (encp->enc_mae_admin)
287 : : sfc_mae_counter_registry_fini(&mae->counter_registry);
288 : :
289 : 0 : fail_counter_registry_init:
290 : 0 : fail_mae_get_limits:
291 [ # # ]: 0 : if (encp->enc_mae_admin)
292 : 0 : efx_mae_fini(sa->nic);
293 : :
294 : 0 : fail_mae_init:
295 : 0 : sfc_log_init(sa, "failed %d", rc);
296 : :
297 : 0 : return rc;
298 : : }
299 : :
300 : : void
301 : 0 : sfc_mae_detach(struct sfc_adapter *sa)
302 : : {
303 : : struct sfc_mae *mae = &sa->mae;
304 : 0 : enum sfc_mae_status status_prev = mae->status;
305 : :
306 : 0 : sfc_log_init(sa, "entry");
307 : :
308 : 0 : mae->nb_action_rule_prios_max = 0;
309 : 0 : mae->status = SFC_MAE_STATUS_UNKNOWN;
310 : :
311 [ # # ]: 0 : if (status_prev != SFC_MAE_STATUS_ADMIN)
312 : : return;
313 : :
314 : 0 : rte_free(mae->bounce_aset_ids);
315 : 0 : rte_free(mae->bounce_aset_ctxs);
316 : 0 : rte_free(mae->bounce_aset_ptrs);
317 : 0 : rte_free(mae->bounce_eh.buf);
318 : : sfc_mae_counter_registry_fini(&mae->counter_registry);
319 : :
320 : 0 : efx_mae_fini(sa->nic);
321 : :
322 : 0 : sfc_log_init(sa, "done");
323 : : }
324 : :
325 : : static struct sfc_mae_outer_rule *
326 : 0 : sfc_mae_outer_rule_attach(struct sfc_adapter *sa,
327 : : const efx_mae_match_spec_t *match_spec,
328 : : efx_tunnel_protocol_t encap_type)
329 : : {
330 : : struct sfc_mae_outer_rule *rule;
331 : : struct sfc_mae *mae = &sa->mae;
332 : :
333 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
334 : :
335 [ # # ]: 0 : TAILQ_FOREACH(rule, &mae->outer_rules, entries) {
336 [ # # ]: 0 : if (efx_mae_match_specs_equal(rule->match_spec, match_spec) &&
337 [ # # ]: 0 : rule->encap_type == encap_type) {
338 : 0 : sfc_dbg(sa, "attaching to outer_rule=%p", rule);
339 : 0 : ++(rule->refcnt);
340 : 0 : return rule;
341 : : }
342 : : }
343 : :
344 : : return NULL;
345 : : }
346 : :
347 : : static int
348 : 0 : sfc_mae_outer_rule_add(struct sfc_adapter *sa,
349 : : efx_mae_match_spec_t *match_spec,
350 : : efx_tunnel_protocol_t encap_type,
351 : : struct sfc_mae_outer_rule **rulep)
352 : : {
353 : : struct sfc_mae_outer_rule *rule;
354 : : struct sfc_mae *mae = &sa->mae;
355 : :
356 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
357 : :
358 : 0 : rule = rte_zmalloc("sfc_mae_outer_rule", sizeof(*rule), 0);
359 [ # # ]: 0 : if (rule == NULL)
360 : : return ENOMEM;
361 : :
362 : 0 : rule->refcnt = 1;
363 : 0 : rule->match_spec = match_spec;
364 : 0 : rule->encap_type = encap_type;
365 : :
366 : 0 : rule->fw_rsrc.rule_id.id = EFX_MAE_RSRC_ID_INVALID;
367 : :
368 : 0 : TAILQ_INSERT_TAIL(&mae->outer_rules, rule, entries);
369 : :
370 : 0 : *rulep = rule;
371 : :
372 : 0 : sfc_dbg(sa, "added outer_rule=%p", rule);
373 : :
374 : 0 : return 0;
375 : : }
376 : :
377 : : static void
378 : 0 : sfc_mae_outer_rule_del(struct sfc_adapter *sa,
379 : : struct sfc_mae_outer_rule *rule)
380 : : {
381 : : struct sfc_mae *mae = &sa->mae;
382 : :
383 [ # # ]: 0 : if (rule == NULL)
384 : : return;
385 : :
386 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
387 : : SFC_ASSERT(rule->refcnt != 0);
388 : :
389 : 0 : --(rule->refcnt);
390 : :
391 [ # # ]: 0 : if (rule->refcnt != 0)
392 : : return;
393 : :
394 [ # # ]: 0 : if (rule->fw_rsrc.rule_id.id != EFX_MAE_RSRC_ID_INVALID ||
395 [ # # ]: 0 : rule->fw_rsrc.refcnt != 0) {
396 : 0 : sfc_err(sa, "deleting outer_rule=%p abandons its FW resource: OR_ID=0x%08x, refcnt=%u",
397 : : rule, rule->fw_rsrc.rule_id.id, rule->fw_rsrc.refcnt);
398 : : }
399 : :
400 : 0 : efx_mae_match_spec_fini(sa->nic, rule->match_spec);
401 : :
402 [ # # ]: 0 : TAILQ_REMOVE(&mae->outer_rules, rule, entries);
403 : 0 : sfc_dbg(sa, "deleted outer_rule=%p", rule);
404 : 0 : rte_free(rule);
405 : : }
406 : :
407 : : static int
408 : 0 : sfc_mae_outer_rule_enable(struct sfc_adapter *sa,
409 : : struct sfc_mae_outer_rule *rule,
410 : : efx_mae_match_spec_t *match_spec_action)
411 : : {
412 : : struct sfc_mae_fw_rsrc *fw_rsrc;
413 : : int rc;
414 : :
415 [ # # ]: 0 : if (rule == NULL)
416 : : return 0;
417 : :
418 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
419 : :
420 : : fw_rsrc = &rule->fw_rsrc;
421 : :
422 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
423 : : SFC_ASSERT(fw_rsrc->rule_id.id == EFX_MAE_RSRC_ID_INVALID);
424 : : SFC_ASSERT(rule->match_spec != NULL);
425 : :
426 : 0 : rc = efx_mae_outer_rule_insert(sa->nic, rule->match_spec,
427 : : rule->encap_type,
428 : : &fw_rsrc->rule_id);
429 [ # # ]: 0 : if (rc != 0) {
430 : 0 : sfc_err(sa, "failed to enable outer_rule=%p: %s",
431 : : rule, strerror(rc));
432 : 0 : return rc;
433 : : }
434 : : }
435 : :
436 [ # # ]: 0 : if (match_spec_action == NULL)
437 : 0 : goto skip_action_rule;
438 : :
439 : 0 : rc = efx_mae_match_spec_outer_rule_id_set(match_spec_action,
440 : 0 : &fw_rsrc->rule_id);
441 [ # # ]: 0 : if (rc != 0) {
442 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
443 : 0 : (void)efx_mae_outer_rule_remove(sa->nic,
444 : : &fw_rsrc->rule_id);
445 : 0 : fw_rsrc->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
446 : : }
447 : :
448 : 0 : sfc_err(sa, "can't match on outer rule ID: %s", strerror(rc));
449 : :
450 : 0 : return rc;
451 : : }
452 : :
453 : 0 : skip_action_rule:
454 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
455 : 0 : sfc_dbg(sa, "enabled outer_rule=%p: OR_ID=0x%08x",
456 : : rule, fw_rsrc->rule_id.id);
457 : : }
458 : :
459 : 0 : ++(fw_rsrc->refcnt);
460 : :
461 : 0 : return 0;
462 : : }
463 : :
464 : : static void
465 : 0 : sfc_mae_outer_rule_disable(struct sfc_adapter *sa,
466 : : struct sfc_mae_outer_rule *rule,
467 : : efx_mae_match_spec_t *match_spec_action)
468 : : {
469 : 0 : efx_mae_rule_id_t invalid_rule_id = { .id = EFX_MAE_RSRC_ID_INVALID };
470 : : struct sfc_mae_fw_rsrc *fw_rsrc;
471 : : int rc;
472 : :
473 [ # # ]: 0 : if (rule == NULL)
474 : 0 : return;
475 : :
476 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
477 : :
478 : : fw_rsrc = &rule->fw_rsrc;
479 : :
480 [ # # ]: 0 : if (match_spec_action == NULL)
481 : 0 : goto skip_action_rule;
482 : :
483 : 0 : rc = efx_mae_match_spec_outer_rule_id_set(match_spec_action,
484 : : &invalid_rule_id);
485 [ # # ]: 0 : if (rc != 0) {
486 : 0 : sfc_err(sa, "cannot restore match on invalid outer rule ID: %s",
487 : : strerror(rc));
488 : 0 : return;
489 : : }
490 : :
491 : 0 : skip_action_rule:
492 [ # # ]: 0 : if (fw_rsrc->rule_id.id == EFX_MAE_RSRC_ID_INVALID ||
493 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
494 : 0 : sfc_err(sa, "failed to disable outer_rule=%p: already disabled; OR_ID=0x%08x, refcnt=%u",
495 : : rule, fw_rsrc->rule_id.id, fw_rsrc->refcnt);
496 : 0 : return;
497 : : }
498 : :
499 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
500 : 0 : rc = efx_mae_outer_rule_remove(sa->nic, &fw_rsrc->rule_id);
501 [ # # ]: 0 : if (rc == 0) {
502 : 0 : sfc_dbg(sa, "disabled outer_rule=%p with OR_ID=0x%08x",
503 : : rule, fw_rsrc->rule_id.id);
504 : : } else {
505 : 0 : sfc_err(sa, "failed to disable outer_rule=%p with OR_ID=0x%08x: %s",
506 : : rule, fw_rsrc->rule_id.id, strerror(rc));
507 : : }
508 : 0 : fw_rsrc->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
509 : : }
510 : :
511 : 0 : --(fw_rsrc->refcnt);
512 : : }
513 : :
514 : : static struct sfc_mae_mac_addr *
515 : 0 : sfc_mae_mac_addr_attach(struct sfc_adapter *sa,
516 : : const uint8_t addr_bytes[EFX_MAC_ADDR_LEN])
517 : : {
518 : : struct sfc_mae_mac_addr *mac_addr;
519 : : struct sfc_mae *mae = &sa->mae;
520 : :
521 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
522 : :
523 [ # # ]: 0 : TAILQ_FOREACH(mac_addr, &mae->mac_addrs, entries) {
524 [ # # ]: 0 : if (memcmp(mac_addr->addr_bytes, addr_bytes,
525 : : EFX_MAC_ADDR_LEN) == 0) {
526 : 0 : sfc_dbg(sa, "attaching to mac_addr=%p", mac_addr);
527 : 0 : ++(mac_addr->refcnt);
528 : 0 : return mac_addr;
529 : : }
530 : : }
531 : :
532 : : return NULL;
533 : : }
534 : :
535 : : static int
536 : 0 : sfc_mae_mac_addr_add(struct sfc_adapter *sa,
537 : : const uint8_t addr_bytes[EFX_MAC_ADDR_LEN],
538 : : struct sfc_mae_mac_addr **mac_addrp)
539 : : {
540 : : struct sfc_mae_mac_addr *mac_addr;
541 : : struct sfc_mae *mae = &sa->mae;
542 : :
543 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
544 : :
545 : 0 : mac_addr = rte_zmalloc("sfc_mae_mac_addr", sizeof(*mac_addr), 0);
546 [ # # ]: 0 : if (mac_addr == NULL)
547 : : return ENOMEM;
548 : :
549 [ # # ]: 0 : rte_memcpy(mac_addr->addr_bytes, addr_bytes, EFX_MAC_ADDR_LEN);
550 : :
551 : 0 : mac_addr->refcnt = 1;
552 : 0 : mac_addr->fw_rsrc.mac_id.id = EFX_MAE_RSRC_ID_INVALID;
553 : :
554 : 0 : TAILQ_INSERT_TAIL(&mae->mac_addrs, mac_addr, entries);
555 : :
556 : 0 : *mac_addrp = mac_addr;
557 : :
558 : 0 : sfc_dbg(sa, "added mac_addr=%p", mac_addr);
559 : :
560 : 0 : return 0;
561 : : }
562 : :
563 : : static void
564 : 0 : sfc_mae_mac_addr_del(struct sfc_adapter *sa, struct sfc_mae_mac_addr *mac_addr)
565 : : {
566 : : struct sfc_mae *mae = &sa->mae;
567 : :
568 [ # # ]: 0 : if (mac_addr == NULL)
569 : : return;
570 : :
571 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
572 : : SFC_ASSERT(mac_addr->refcnt != 0);
573 : :
574 : 0 : --(mac_addr->refcnt);
575 : :
576 [ # # ]: 0 : if (mac_addr->refcnt != 0)
577 : : return;
578 : :
579 [ # # ]: 0 : if (mac_addr->fw_rsrc.mac_id.id != EFX_MAE_RSRC_ID_INVALID ||
580 [ # # ]: 0 : mac_addr->fw_rsrc.refcnt != 0) {
581 : 0 : sfc_err(sa, "deleting mac_addr=%p abandons its FW resource: MAC_ID=0x%08x, refcnt=%u",
582 : : mac_addr, mac_addr->fw_rsrc.mac_id.id,
583 : : mac_addr->fw_rsrc.refcnt);
584 : : }
585 : :
586 [ # # ]: 0 : TAILQ_REMOVE(&mae->mac_addrs, mac_addr, entries);
587 : 0 : sfc_dbg(sa, "deleted mac_addr=%p", mac_addr);
588 : 0 : rte_free(mac_addr);
589 : : }
590 : :
591 : : enum sfc_mae_mac_addr_type {
592 : : SFC_MAE_MAC_ADDR_DST,
593 : : SFC_MAE_MAC_ADDR_SRC
594 : : };
595 : :
596 : : static int
597 : 0 : sfc_mae_mac_addr_enable(struct sfc_adapter *sa,
598 : : struct sfc_mae_mac_addr *mac_addr,
599 : : enum sfc_mae_mac_addr_type type,
600 : : efx_mae_actions_t *aset_spec)
601 : : {
602 : : struct sfc_mae_fw_rsrc *fw_rsrc;
603 : : int rc = 0;
604 : :
605 [ # # ]: 0 : if (mac_addr == NULL)
606 : : return 0;
607 : :
608 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
609 : :
610 : : fw_rsrc = &mac_addr->fw_rsrc;
611 : :
612 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
613 : : SFC_ASSERT(fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID);
614 : :
615 : 0 : rc = efx_mae_mac_addr_alloc(sa->nic, mac_addr->addr_bytes,
616 : : &fw_rsrc->mac_id);
617 [ # # ]: 0 : if (rc != 0) {
618 : 0 : sfc_err(sa, "failed to enable mac_addr=%p: %s",
619 : : mac_addr, strerror(rc));
620 : 0 : return rc;
621 : : }
622 : : }
623 : :
624 [ # # # ]: 0 : switch (type) {
625 : 0 : case SFC_MAE_MAC_ADDR_DST:
626 : 0 : rc = efx_mae_action_set_fill_in_dst_mac_id(aset_spec,
627 : 0 : &fw_rsrc->mac_id);
628 : 0 : break;
629 : 0 : case SFC_MAE_MAC_ADDR_SRC:
630 : 0 : rc = efx_mae_action_set_fill_in_src_mac_id(aset_spec,
631 : 0 : &fw_rsrc->mac_id);
632 : 0 : break;
633 : : default:
634 : : rc = EINVAL;
635 : : break;
636 : : }
637 : :
638 [ # # ]: 0 : if (rc != 0) {
639 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
640 : 0 : (void)efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id);
641 : 0 : fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID;
642 : : }
643 : :
644 : 0 : sfc_err(sa, "cannot fill in MAC address entry ID: %s",
645 : : strerror(rc));
646 : :
647 : 0 : return rc;
648 : : }
649 : :
650 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
651 : 0 : sfc_dbg(sa, "enabled mac_addr=%p: MAC_ID=0x%08x",
652 : : mac_addr, fw_rsrc->mac_id.id);
653 : : }
654 : :
655 : 0 : ++(fw_rsrc->refcnt);
656 : :
657 : 0 : return 0;
658 : : }
659 : :
660 : : static void
661 : 0 : sfc_mae_mac_addr_disable(struct sfc_adapter *sa,
662 : : struct sfc_mae_mac_addr *mac_addr)
663 : : {
664 : : struct sfc_mae_fw_rsrc *fw_rsrc;
665 : : int rc;
666 : :
667 [ # # ]: 0 : if (mac_addr == NULL)
668 : : return;
669 : :
670 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
671 : :
672 : : fw_rsrc = &mac_addr->fw_rsrc;
673 : :
674 [ # # ]: 0 : if (fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID ||
675 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
676 : 0 : sfc_err(sa, "failed to disable mac_addr=%p: already disabled; MAC_ID=0x%08x, refcnt=%u",
677 : : mac_addr, fw_rsrc->mac_id.id, fw_rsrc->refcnt);
678 : 0 : return;
679 : : }
680 : :
681 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
682 : 0 : rc = efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id);
683 [ # # ]: 0 : if (rc == 0) {
684 : 0 : sfc_dbg(sa, "disabled mac_addr=%p with MAC_ID=0x%08x",
685 : : mac_addr, fw_rsrc->mac_id.id);
686 : : } else {
687 : 0 : sfc_err(sa, "failed to disable mac_addr=%p with MAC_ID=0x%08x: %s",
688 : : mac_addr, fw_rsrc->mac_id.id, strerror(rc));
689 : : }
690 : 0 : fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID;
691 : : }
692 : :
693 : 0 : --(fw_rsrc->refcnt);
694 : : }
695 : :
696 : : static struct sfc_mae_encap_header *
697 : 0 : sfc_mae_encap_header_attach(struct sfc_adapter *sa,
698 : : const struct sfc_mae_bounce_eh *bounce_eh)
699 : : {
700 : : struct sfc_mae_encap_header *encap_header;
701 : : struct sfc_mae *mae = &sa->mae;
702 : :
703 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
704 : :
705 [ # # ]: 0 : TAILQ_FOREACH(encap_header, &mae->encap_headers, entries) {
706 [ # # ]: 0 : if (encap_header->indirect)
707 : 0 : continue;
708 : :
709 [ # # ]: 0 : if (encap_header->size == bounce_eh->size &&
710 [ # # ]: 0 : memcmp(encap_header->buf, bounce_eh->buf,
711 : : bounce_eh->size) == 0) {
712 : 0 : sfc_dbg(sa, "attaching to encap_header=%p",
713 : : encap_header);
714 : 0 : ++(encap_header->refcnt);
715 : 0 : return encap_header;
716 : : }
717 : : }
718 : :
719 : : return NULL;
720 : : }
721 : :
722 : : static int
723 : 0 : sfc_mae_encap_header_add(struct sfc_adapter *sa,
724 : : const struct sfc_mae_bounce_eh *bounce_eh,
725 : : struct sfc_mae_encap_header **encap_headerp)
726 : : {
727 : : struct sfc_mae_encap_header *encap_header;
728 : : struct sfc_mae *mae = &sa->mae;
729 : :
730 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
731 : :
732 : 0 : encap_header = rte_zmalloc("sfc_mae_encap_header",
733 : : sizeof(*encap_header), 0);
734 [ # # ]: 0 : if (encap_header == NULL)
735 : : return ENOMEM;
736 : :
737 : 0 : encap_header->size = bounce_eh->size;
738 : :
739 : 0 : encap_header->buf = rte_malloc("sfc_mae_encap_header_buf",
740 : : encap_header->size, 0);
741 [ # # ]: 0 : if (encap_header->buf == NULL) {
742 : 0 : rte_free(encap_header);
743 : 0 : return ENOMEM;
744 : : }
745 : :
746 [ # # ]: 0 : rte_memcpy(encap_header->buf, bounce_eh->buf, bounce_eh->size);
747 : :
748 : 0 : encap_header->refcnt = 1;
749 : 0 : encap_header->type = bounce_eh->type;
750 : 0 : encap_header->fw_rsrc.eh_id.id = EFX_MAE_RSRC_ID_INVALID;
751 : :
752 : 0 : TAILQ_INSERT_TAIL(&mae->encap_headers, encap_header, entries);
753 : :
754 : 0 : *encap_headerp = encap_header;
755 : :
756 : 0 : sfc_dbg(sa, "added encap_header=%p", encap_header);
757 : :
758 : 0 : return 0;
759 : : }
760 : :
761 : : static void
762 : 0 : sfc_mae_encap_header_del(struct sfc_adapter *sa,
763 : : struct sfc_mae_encap_header *encap_header)
764 : : {
765 : : struct sfc_mae *mae = &sa->mae;
766 : :
767 [ # # ]: 0 : if (encap_header == NULL)
768 : : return;
769 : :
770 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
771 : : SFC_ASSERT(encap_header->refcnt != 0);
772 : :
773 : 0 : --(encap_header->refcnt);
774 : :
775 [ # # ]: 0 : if (encap_header->refcnt != 0)
776 : : return;
777 : :
778 [ # # ]: 0 : if (encap_header->fw_rsrc.eh_id.id != EFX_MAE_RSRC_ID_INVALID ||
779 [ # # ]: 0 : encap_header->fw_rsrc.refcnt != 0) {
780 : 0 : sfc_err(sa, "deleting encap_header=%p abandons its FW resource: EH_ID=0x%08x, refcnt=%u",
781 : : encap_header, encap_header->fw_rsrc.eh_id.id,
782 : : encap_header->fw_rsrc.refcnt);
783 : : }
784 : :
785 [ # # ]: 0 : TAILQ_REMOVE(&mae->encap_headers, encap_header, entries);
786 : 0 : sfc_dbg(sa, "deleted encap_header=%p", encap_header);
787 : :
788 : 0 : rte_free(encap_header->buf);
789 : 0 : rte_free(encap_header);
790 : : }
791 : :
792 : : static int
793 : 0 : sfc_mae_encap_header_update(struct sfc_adapter *sa,
794 : : struct sfc_mae_encap_header *encap_header)
795 : : {
796 : : const struct sfc_mae_bounce_eh *bounce_eh = &sa->mae.bounce_eh;
797 : : struct sfc_mae_fw_rsrc *fw_rsrc;
798 : : uint8_t *buf;
799 : : int ret;
800 : :
801 [ # # ]: 0 : if (bounce_eh->type != encap_header->type ||
802 [ # # ]: 0 : bounce_eh->size == 0)
803 : : return EINVAL;
804 : :
805 : 0 : buf = rte_malloc("sfc_mae_encap_header_buf", bounce_eh->size, 0);
806 [ # # ]: 0 : if (buf == NULL)
807 : : return ENOMEM;
808 : :
809 [ # # ]: 0 : rte_memcpy(buf, bounce_eh->buf, bounce_eh->size);
810 : :
811 : : fw_rsrc = &encap_header->fw_rsrc;
812 : :
813 [ # # ]: 0 : if (fw_rsrc->refcnt > 0) {
814 : : SFC_ASSERT(fw_rsrc->eh_id.id != EFX_MAE_RSRC_ID_INVALID);
815 : :
816 : 0 : ret = efx_mae_encap_header_update(sa->nic, &fw_rsrc->eh_id,
817 : : encap_header->type, buf,
818 : : bounce_eh->size);
819 [ # # ]: 0 : if (ret != 0) {
820 : 0 : sfc_err(sa, "failed to update encap_header=%p: %s",
821 : : encap_header, strerror(ret));
822 : 0 : rte_free(buf);
823 : 0 : return ret;
824 : : }
825 : : }
826 : :
827 : 0 : encap_header->size = bounce_eh->size;
828 : 0 : rte_free(encap_header->buf);
829 : 0 : encap_header->buf = buf;
830 : :
831 : 0 : sfc_dbg(sa, "updated encap_header=%p", encap_header);
832 : :
833 : 0 : return 0;
834 : : }
835 : :
836 : : static int
837 : 0 : sfc_mae_encap_header_enable(struct sfc_adapter *sa,
838 : : struct sfc_mae_encap_header *encap_header,
839 : : efx_mae_actions_t *action_set_spec)
840 : : {
841 : : struct sfc_mae_fw_rsrc *fw_rsrc;
842 : : int rc;
843 : :
844 [ # # ]: 0 : if (encap_header == NULL)
845 : : return 0;
846 : :
847 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
848 : :
849 : : fw_rsrc = &encap_header->fw_rsrc;
850 : :
851 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
852 : : SFC_ASSERT(fw_rsrc->eh_id.id == EFX_MAE_RSRC_ID_INVALID);
853 : : SFC_ASSERT(encap_header->buf != NULL);
854 : : SFC_ASSERT(encap_header->size != 0);
855 : :
856 : 0 : rc = efx_mae_encap_header_alloc(sa->nic, encap_header->type,
857 : : encap_header->buf,
858 : : encap_header->size,
859 : : &fw_rsrc->eh_id);
860 [ # # ]: 0 : if (rc != 0) {
861 : 0 : sfc_err(sa, "failed to enable encap_header=%p: %s",
862 : : encap_header, strerror(rc));
863 : 0 : return rc;
864 : : }
865 : : }
866 : :
867 : 0 : rc = efx_mae_action_set_fill_in_eh_id(action_set_spec,
868 : 0 : &fw_rsrc->eh_id);
869 [ # # ]: 0 : if (rc != 0) {
870 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
871 : 0 : (void)efx_mae_encap_header_free(sa->nic,
872 : : &fw_rsrc->eh_id);
873 : 0 : fw_rsrc->eh_id.id = EFX_MAE_RSRC_ID_INVALID;
874 : : }
875 : :
876 : 0 : sfc_err(sa, "can't fill in encap. header ID: %s", strerror(rc));
877 : :
878 : 0 : return rc;
879 : : }
880 : :
881 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
882 : 0 : sfc_dbg(sa, "enabled encap_header=%p: EH_ID=0x%08x",
883 : : encap_header, fw_rsrc->eh_id.id);
884 : : }
885 : :
886 : 0 : ++(fw_rsrc->refcnt);
887 : :
888 : 0 : return 0;
889 : : }
890 : :
891 : : static void
892 : 0 : sfc_mae_encap_header_disable(struct sfc_adapter *sa,
893 : : struct sfc_mae_encap_header *encap_header)
894 : : {
895 : : struct sfc_mae_fw_rsrc *fw_rsrc;
896 : : int rc;
897 : :
898 [ # # ]: 0 : if (encap_header == NULL)
899 : : return;
900 : :
901 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
902 : :
903 : : fw_rsrc = &encap_header->fw_rsrc;
904 : :
905 [ # # ]: 0 : if (fw_rsrc->eh_id.id == EFX_MAE_RSRC_ID_INVALID ||
906 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
907 : 0 : sfc_err(sa, "failed to disable encap_header=%p: already disabled; EH_ID=0x%08x, refcnt=%u",
908 : : encap_header, fw_rsrc->eh_id.id, fw_rsrc->refcnt);
909 : 0 : return;
910 : : }
911 : :
912 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
913 : 0 : rc = efx_mae_encap_header_free(sa->nic, &fw_rsrc->eh_id);
914 [ # # ]: 0 : if (rc == 0) {
915 : 0 : sfc_dbg(sa, "disabled encap_header=%p with EH_ID=0x%08x",
916 : : encap_header, fw_rsrc->eh_id.id);
917 : : } else {
918 : 0 : sfc_err(sa, "failed to disable encap_header=%p with EH_ID=0x%08x: %s",
919 : : encap_header, fw_rsrc->eh_id.id, strerror(rc));
920 : : }
921 : 0 : fw_rsrc->eh_id.id = EFX_MAE_RSRC_ID_INVALID;
922 : : }
923 : :
924 : 0 : --(fw_rsrc->refcnt);
925 : : }
926 : :
927 : : static int
928 : 0 : sfc_mae_counter_add(struct sfc_adapter *sa,
929 : : const struct sfc_mae_counter *counter_tmp,
930 : : struct sfc_mae_counter **counterp)
931 : : {
932 : : struct sfc_mae_counter *counter;
933 : : struct sfc_mae *mae = &sa->mae;
934 : :
935 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
936 : :
937 : 0 : counter = rte_zmalloc("sfc_mae_counter", sizeof(*counter), 0);
938 [ # # ]: 0 : if (counter == NULL)
939 : : return ENOMEM;
940 : :
941 [ # # ]: 0 : if (counter_tmp != NULL) {
942 : 0 : counter->rte_id_valid = counter_tmp->rte_id_valid;
943 : 0 : counter->rte_id = counter_tmp->rte_id;
944 : 0 : counter->type = counter_tmp->type;
945 : : } else {
946 : 0 : counter->type = EFX_COUNTER_TYPE_ACTION;
947 : : }
948 : :
949 : 0 : counter->fw_rsrc.counter_id.id = EFX_MAE_RSRC_ID_INVALID;
950 : 0 : counter->refcnt = 1;
951 : :
952 : 0 : TAILQ_INSERT_TAIL(&mae->counters, counter, entries);
953 : 0 : *counterp = counter;
954 : :
955 : 0 : sfc_dbg(sa, "added counter=%p", counter);
956 : :
957 : 0 : return 0;
958 : : }
959 : :
960 : : static void
961 : 0 : sfc_mae_counter_del(struct sfc_adapter *sa, struct sfc_mae_counter *counter)
962 : : {
963 : : struct sfc_mae *mae = &sa->mae;
964 : :
965 [ # # ]: 0 : if (counter == NULL)
966 : : return;
967 : :
968 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
969 : : SFC_ASSERT(counter->refcnt != 0);
970 : :
971 : 0 : --(counter->refcnt);
972 : :
973 [ # # ]: 0 : if (counter->refcnt == 1)
974 : 0 : counter->ft_switch_hit_counter = NULL;
975 : :
976 [ # # ]: 0 : if (counter->refcnt != 0)
977 : : return;
978 : :
979 [ # # ]: 0 : if (counter->fw_rsrc.counter_id.id != EFX_MAE_RSRC_ID_INVALID ||
980 : : counter->fw_rsrc.refcnt != 0) {
981 : 0 : sfc_err(sa, "deleting counter=%p abandons its FW resource: COUNTER_ID=0x%x-#%u, refcnt=%u",
982 : : counter, counter->type, counter->fw_rsrc.counter_id.id,
983 : : counter->fw_rsrc.refcnt);
984 : : }
985 : :
986 [ # # ]: 0 : TAILQ_REMOVE(&mae->counters, counter, entries);
987 : 0 : sfc_dbg(sa, "deleted counter=%p", counter);
988 : 0 : rte_free(counter);
989 : : }
990 : :
991 : : static int
992 : 0 : sfc_mae_counter_enable(struct sfc_adapter *sa, struct sfc_mae_counter *counter,
993 : : efx_mae_actions_t *action_set_spec)
994 : : {
995 : : struct sfc_mae_fw_rsrc *fw_rsrc;
996 : : int rc;
997 : :
998 [ # # ]: 0 : if (counter == NULL)
999 : : return 0;
1000 : :
1001 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1002 : :
1003 : : fw_rsrc = &counter->fw_rsrc;
1004 : :
1005 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1006 : : SFC_ASSERT(fw_rsrc->counter_id.id == EFX_MAE_RSRC_ID_INVALID);
1007 : :
1008 : 0 : rc = sfc_mae_counter_fw_rsrc_enable(sa, counter);
1009 [ # # ]: 0 : if (rc != 0) {
1010 : 0 : sfc_err(sa, "failed to enable counter=%p: %s",
1011 : : counter, rte_strerror(rc));
1012 : 0 : return rc;
1013 : : }
1014 : : }
1015 : :
1016 [ # # ]: 0 : if (action_set_spec != NULL) {
1017 : 0 : rc = efx_mae_action_set_fill_in_counter_id(
1018 : 0 : action_set_spec, &fw_rsrc->counter_id);
1019 [ # # ]: 0 : if (rc != 0) {
1020 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1021 : 0 : (void)sfc_mae_counter_fw_rsrc_disable(sa, counter);
1022 : 0 : fw_rsrc->counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1023 : : }
1024 : :
1025 : 0 : sfc_err(sa, "cannot fill in counter ID: %s",
1026 : : strerror(rc));
1027 : 0 : return rc;
1028 : : }
1029 : : }
1030 : :
1031 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1032 : 0 : sfc_dbg(sa, "enabled counter=%p: COUNTER_ID=0x%x-#%u",
1033 : : counter, counter->type, fw_rsrc->counter_id.id);
1034 : : }
1035 : :
1036 : 0 : ++(fw_rsrc->refcnt);
1037 : :
1038 : 0 : return 0;
1039 : : }
1040 : :
1041 : : static void
1042 : 0 : sfc_mae_counter_disable(struct sfc_adapter *sa, struct sfc_mae_counter *counter)
1043 : : {
1044 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1045 : : int rc;
1046 : :
1047 [ # # ]: 0 : if (counter == NULL)
1048 : : return;
1049 : :
1050 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1051 : :
1052 : : fw_rsrc = &counter->fw_rsrc;
1053 : :
1054 [ # # ]: 0 : if (fw_rsrc->counter_id.id == EFX_MAE_RSRC_ID_INVALID ||
1055 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
1056 : 0 : sfc_err(sa, "failed to disable counter=%p: already disabled; COUNTER_ID=0x%x-#%u, refcnt=%u",
1057 : : counter, counter->type, fw_rsrc->counter_id.id, fw_rsrc->refcnt);
1058 : 0 : return;
1059 : : }
1060 : :
1061 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
1062 : : uint32_t counter_id = fw_rsrc->counter_id.id;
1063 : :
1064 : 0 : rc = sfc_mae_counter_fw_rsrc_disable(sa, counter);
1065 [ # # ]: 0 : if (rc == 0) {
1066 : 0 : sfc_dbg(sa, "disabled counter=%p with COUNTER_ID=0x%x-#%u",
1067 : : counter, counter->type, counter_id);
1068 : : } else {
1069 : 0 : sfc_err(sa, "failed to disable counter=%p with COUNTER_ID=0x%x-#%u: %s",
1070 : : counter, counter->type, counter_id, strerror(rc));
1071 : : }
1072 : :
1073 : 0 : fw_rsrc->counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1074 : : }
1075 : :
1076 : 0 : --(fw_rsrc->refcnt);
1077 : : }
1078 : :
1079 : : static struct sfc_mae_action_set *
1080 : 0 : sfc_mae_action_set_attach(struct sfc_adapter *sa,
1081 : : const struct sfc_mae_aset_ctx *ctx)
1082 : : {
1083 : : struct sfc_mae_action_set *action_set;
1084 : : struct sfc_mae *mae = &sa->mae;
1085 : :
1086 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1087 : :
1088 [ # # ]: 0 : TAILQ_FOREACH(action_set, &mae->action_sets, entries) {
1089 [ # # ]: 0 : if (action_set->encap_header == ctx->encap_header &&
1090 [ # # ]: 0 : action_set->dst_mac_addr == ctx->dst_mac &&
1091 [ # # ]: 0 : action_set->src_mac_addr == ctx->src_mac &&
1092 [ # # # # ]: 0 : action_set->counter == ctx->counter &&
1093 : 0 : efx_mae_action_set_specs_equal(action_set->spec,
1094 : 0 : ctx->spec)) {
1095 : 0 : sfc_dbg(sa, "attaching to action_set=%p", action_set);
1096 : 0 : ++(action_set->refcnt);
1097 : 0 : return action_set;
1098 : : }
1099 : : }
1100 : :
1101 : : return NULL;
1102 : : }
1103 : :
1104 : : static int
1105 : 0 : sfc_mae_action_set_add(struct sfc_adapter *sa,
1106 : : const struct sfc_mae_aset_ctx *ctx,
1107 : : struct sfc_mae_action_set **action_setp)
1108 : : {
1109 : : struct sfc_mae_action_set *action_set;
1110 : : struct sfc_mae *mae = &sa->mae;
1111 : :
1112 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1113 : :
1114 : 0 : action_set = rte_zmalloc("sfc_mae_action_set", sizeof(*action_set), 0);
1115 [ # # ]: 0 : if (action_set == NULL) {
1116 : 0 : sfc_err(sa, "failed to alloc action set");
1117 : 0 : return ENOMEM;
1118 : : }
1119 : :
1120 : 0 : action_set->refcnt = 1;
1121 : 0 : action_set->spec = ctx->spec;
1122 : 0 : action_set->encap_header = ctx->encap_header;
1123 : 0 : action_set->dst_mac_addr = ctx->dst_mac;
1124 : 0 : action_set->src_mac_addr = ctx->src_mac;
1125 : 0 : action_set->counter = ctx->counter;
1126 : :
1127 : 0 : action_set->fw_rsrc.aset_id.id = EFX_MAE_RSRC_ID_INVALID;
1128 : :
1129 : 0 : TAILQ_INSERT_TAIL(&mae->action_sets, action_set, entries);
1130 : :
1131 : 0 : *action_setp = action_set;
1132 : :
1133 : 0 : sfc_dbg(sa, "added action_set=%p", action_set);
1134 : :
1135 : 0 : return 0;
1136 : : }
1137 : :
1138 : : static void
1139 : 0 : sfc_mae_action_set_del(struct sfc_adapter *sa,
1140 : : struct sfc_mae_action_set *action_set)
1141 : : {
1142 : : struct sfc_mae *mae = &sa->mae;
1143 : :
1144 [ # # ]: 0 : if (action_set == NULL)
1145 : : return;
1146 : :
1147 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1148 : : SFC_ASSERT(action_set->refcnt != 0);
1149 : :
1150 : 0 : --(action_set->refcnt);
1151 : :
1152 [ # # ]: 0 : if (action_set->refcnt != 0)
1153 : : return;
1154 : :
1155 [ # # ]: 0 : if (action_set->fw_rsrc.aset_id.id != EFX_MAE_RSRC_ID_INVALID ||
1156 : : action_set->fw_rsrc.refcnt != 0) {
1157 : 0 : sfc_err(sa, "deleting action_set=%p abandons its FW resource: AS_ID=0x%08x, refcnt=%u",
1158 : : action_set, action_set->fw_rsrc.aset_id.id,
1159 : : action_set->fw_rsrc.refcnt);
1160 : : }
1161 : :
1162 : 0 : efx_mae_action_set_spec_fini(sa->nic, action_set->spec);
1163 : 0 : sfc_mae_encap_header_del(sa, action_set->encap_header);
1164 : 0 : sfc_mae_mac_addr_del(sa, action_set->dst_mac_addr);
1165 : 0 : sfc_mae_mac_addr_del(sa, action_set->src_mac_addr);
1166 : 0 : sfc_mae_counter_del(sa, action_set->counter);
1167 [ # # ]: 0 : TAILQ_REMOVE(&mae->action_sets, action_set, entries);
1168 : 0 : sfc_dbg(sa, "deleted action_set=%p", action_set);
1169 : 0 : rte_free(action_set);
1170 : : }
1171 : :
1172 : : static int
1173 : 0 : sfc_mae_action_set_enable(struct sfc_adapter *sa,
1174 : : struct sfc_mae_action_set *action_set)
1175 : : {
1176 : : struct sfc_mae_encap_header *encap_header;
1177 : : struct sfc_mae_mac_addr *dst_mac_addr;
1178 : : struct sfc_mae_mac_addr *src_mac_addr;
1179 : : struct sfc_mae_counter *counter;
1180 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1181 : : int rc;
1182 : :
1183 [ # # ]: 0 : if (action_set == NULL)
1184 : : return 0;
1185 : :
1186 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1187 : :
1188 : 0 : encap_header = action_set->encap_header;
1189 : 0 : dst_mac_addr = action_set->dst_mac_addr;
1190 : 0 : src_mac_addr = action_set->src_mac_addr;
1191 : : fw_rsrc = &action_set->fw_rsrc;
1192 : 0 : counter = action_set->counter;
1193 : :
1194 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1195 : : SFC_ASSERT(fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID);
1196 : : SFC_ASSERT(action_set->spec != NULL);
1197 : :
1198 : 0 : rc = sfc_mae_mac_addr_enable(sa, dst_mac_addr,
1199 : : SFC_MAE_MAC_ADDR_DST,
1200 : : action_set->spec);
1201 [ # # ]: 0 : if (rc != 0)
1202 : : return rc;
1203 : :
1204 : 0 : rc = sfc_mae_mac_addr_enable(sa, src_mac_addr,
1205 : : SFC_MAE_MAC_ADDR_SRC,
1206 : : action_set->spec);
1207 [ # # ]: 0 : if (rc != 0) {
1208 : 0 : sfc_mae_mac_addr_disable(sa, dst_mac_addr);
1209 : 0 : return rc;
1210 : : }
1211 : :
1212 : 0 : rc = sfc_mae_encap_header_enable(sa, encap_header,
1213 : : action_set->spec);
1214 [ # # ]: 0 : if (rc != 0) {
1215 : 0 : sfc_mae_mac_addr_disable(sa, src_mac_addr);
1216 : 0 : sfc_mae_mac_addr_disable(sa, dst_mac_addr);
1217 : 0 : return rc;
1218 : : }
1219 : :
1220 [ # # ]: 0 : if (counter != NULL) {
1221 : 0 : rc = sfc_mae_counter_start(sa);
1222 [ # # ]: 0 : if (rc != 0) {
1223 : 0 : sfc_err(sa, "failed to start MAE counters support: %s",
1224 : : rte_strerror(rc));
1225 : 0 : sfc_mae_encap_header_disable(sa, encap_header);
1226 : 0 : sfc_mae_mac_addr_disable(sa, src_mac_addr);
1227 : 0 : sfc_mae_mac_addr_disable(sa, dst_mac_addr);
1228 : 0 : return rc;
1229 : : }
1230 : : }
1231 : :
1232 : 0 : rc = sfc_mae_counter_enable(sa, counter, action_set->spec);
1233 [ # # ]: 0 : if (rc != 0) {
1234 : 0 : sfc_mae_encap_header_disable(sa, encap_header);
1235 : 0 : sfc_mae_mac_addr_disable(sa, src_mac_addr);
1236 : 0 : sfc_mae_mac_addr_disable(sa, dst_mac_addr);
1237 : 0 : return rc;
1238 : : }
1239 : :
1240 : 0 : rc = efx_mae_action_set_alloc(sa->nic, action_set->spec,
1241 : : &fw_rsrc->aset_id);
1242 [ # # ]: 0 : if (rc != 0) {
1243 : 0 : sfc_err(sa, "failed to enable action_set=%p: %s",
1244 : : action_set, strerror(rc));
1245 : :
1246 : 0 : sfc_mae_encap_header_disable(sa, encap_header);
1247 : 0 : sfc_mae_mac_addr_disable(sa, src_mac_addr);
1248 : 0 : sfc_mae_mac_addr_disable(sa, dst_mac_addr);
1249 : 0 : sfc_mae_counter_disable(sa, counter);
1250 : 0 : return rc;
1251 : : }
1252 : :
1253 : 0 : sfc_dbg(sa, "enabled action_set=%p: AS_ID=0x%08x",
1254 : : action_set, fw_rsrc->aset_id.id);
1255 : : }
1256 : :
1257 : 0 : ++(fw_rsrc->refcnt);
1258 : :
1259 : 0 : return 0;
1260 : : }
1261 : :
1262 : : static void
1263 : 0 : sfc_mae_action_set_disable(struct sfc_adapter *sa,
1264 : : struct sfc_mae_action_set *action_set)
1265 : : {
1266 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1267 : : int rc;
1268 : :
1269 [ # # ]: 0 : if (action_set == NULL)
1270 : : return;
1271 : :
1272 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1273 : :
1274 : : fw_rsrc = &action_set->fw_rsrc;
1275 : :
1276 [ # # ]: 0 : if (fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID ||
1277 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
1278 : 0 : sfc_err(sa, "failed to disable action_set=%p: already disabled; AS_ID=0x%08x, refcnt=%u",
1279 : : action_set, fw_rsrc->aset_id.id, fw_rsrc->refcnt);
1280 : 0 : return;
1281 : : }
1282 : :
1283 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
1284 : 0 : efx_mae_action_set_clear_fw_rsrc_ids(action_set->spec);
1285 : :
1286 : 0 : rc = efx_mae_action_set_free(sa->nic, &fw_rsrc->aset_id);
1287 [ # # ]: 0 : if (rc == 0) {
1288 : 0 : sfc_dbg(sa, "disabled action_set=%p with AS_ID=0x%08x",
1289 : : action_set, fw_rsrc->aset_id.id);
1290 : : } else {
1291 : 0 : sfc_err(sa, "failed to disable action_set=%p with AS_ID=0x%08x: %s",
1292 : : action_set, fw_rsrc->aset_id.id, strerror(rc));
1293 : : }
1294 : 0 : fw_rsrc->aset_id.id = EFX_MAE_RSRC_ID_INVALID;
1295 : :
1296 : 0 : sfc_mae_encap_header_disable(sa, action_set->encap_header);
1297 : 0 : sfc_mae_mac_addr_disable(sa, action_set->src_mac_addr);
1298 : 0 : sfc_mae_mac_addr_disable(sa, action_set->dst_mac_addr);
1299 : 0 : sfc_mae_counter_disable(sa, action_set->counter);
1300 : : }
1301 : :
1302 : 0 : --(fw_rsrc->refcnt);
1303 : : }
1304 : :
1305 : : static struct sfc_mae_action_set_list *
1306 : 0 : sfc_mae_action_set_list_attach(struct sfc_adapter *sa)
1307 : : {
1308 : : struct sfc_mae_action_set_list *action_set_list;
1309 : : struct sfc_mae *mae = &sa->mae;
1310 : :
1311 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1312 : :
1313 [ # # ]: 0 : TAILQ_FOREACH(action_set_list, &mae->action_set_lists, entries) {
1314 [ # # ]: 0 : if (action_set_list->nb_action_sets != mae->nb_bounce_asets)
1315 : 0 : continue;
1316 : :
1317 : 0 : if (memcmp(action_set_list->action_sets, mae->bounce_aset_ptrs,
1318 : : sizeof(struct sfc_mae_action_set *) *
1319 [ # # ]: 0 : mae->nb_bounce_asets) == 0) {
1320 : 0 : sfc_dbg(sa, "attaching to action_set_list=%p",
1321 : : action_set_list);
1322 : 0 : ++(action_set_list->refcnt);
1323 : 0 : return action_set_list;
1324 : : }
1325 : : }
1326 : :
1327 : : return NULL;
1328 : : }
1329 : :
1330 : : static int
1331 : 0 : sfc_mae_action_set_list_add(struct sfc_adapter *sa,
1332 : : struct sfc_mae_action_set_list **action_set_listp)
1333 : : {
1334 : : struct sfc_mae_action_set_list *action_set_list;
1335 : : struct sfc_mae *mae = &sa->mae;
1336 : :
1337 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1338 : :
1339 : 0 : action_set_list = rte_zmalloc("sfc_mae_action_set_list",
1340 : : sizeof(*action_set_list), 0);
1341 [ # # ]: 0 : if (action_set_list == NULL) {
1342 : 0 : sfc_err(sa, "failed to allocate action set list");
1343 : 0 : return ENOMEM;
1344 : : }
1345 : :
1346 : 0 : action_set_list->refcnt = 1;
1347 : 0 : action_set_list->nb_action_sets = mae->nb_bounce_asets;
1348 : 0 : action_set_list->fw_rsrc.aset_list_id.id = EFX_MAE_RSRC_ID_INVALID;
1349 : :
1350 : 0 : action_set_list->action_sets =
1351 : 0 : rte_calloc("sfc_mae_action_set_list_action_sets",
1352 : : action_set_list->nb_action_sets,
1353 : : sizeof(struct sfc_mae_action_set *), 0);
1354 [ # # ]: 0 : if (action_set_list->action_sets == NULL) {
1355 : 0 : sfc_err(sa, "failed to allocate action set list");
1356 : 0 : rte_free(action_set_list);
1357 : 0 : return ENOMEM;
1358 : : }
1359 : :
1360 : 0 : rte_memcpy(action_set_list->action_sets, mae->bounce_aset_ptrs,
1361 : : sizeof(struct sfc_mae_action_set *) *
1362 [ # # ]: 0 : action_set_list->nb_action_sets);
1363 : :
1364 : 0 : TAILQ_INSERT_TAIL(&mae->action_set_lists, action_set_list, entries);
1365 : :
1366 : 0 : *action_set_listp = action_set_list;
1367 : :
1368 : 0 : sfc_dbg(sa, "added action_set_list=%p", action_set_list);
1369 : :
1370 : 0 : return 0;
1371 : : }
1372 : :
1373 : : static void
1374 : 0 : sfc_mae_action_set_list_del(struct sfc_adapter *sa,
1375 : : struct sfc_mae_action_set_list *action_set_list)
1376 : : {
1377 : : struct sfc_mae *mae = &sa->mae;
1378 : : unsigned int i;
1379 : :
1380 [ # # ]: 0 : if (action_set_list == NULL)
1381 : : return;
1382 : :
1383 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1384 : : SFC_ASSERT(action_set_list->refcnt != 0);
1385 : :
1386 : 0 : --(action_set_list->refcnt);
1387 : :
1388 [ # # ]: 0 : if (action_set_list->refcnt != 0)
1389 : : return;
1390 : :
1391 : 0 : if (action_set_list->fw_rsrc.aset_list_id.id !=
1392 [ # # ]: 0 : EFX_MAE_RSRC_ID_INVALID || action_set_list->fw_rsrc.refcnt != 0) {
1393 : 0 : sfc_err(sa, "deleting action_set_list=%p abandons its FW resource: ASL_ID=0x%08x, refcnt=%u",
1394 : : action_set_list,
1395 : : action_set_list->fw_rsrc.aset_list_id.id,
1396 : : action_set_list->fw_rsrc.refcnt);
1397 : : }
1398 : :
1399 [ # # ]: 0 : for (i = 0; i < action_set_list->nb_action_sets; ++i)
1400 : 0 : sfc_mae_action_set_del(sa, action_set_list->action_sets[i]);
1401 : :
1402 [ # # ]: 0 : TAILQ_REMOVE(&mae->action_set_lists, action_set_list, entries);
1403 : 0 : sfc_dbg(sa, "deleted action_set_list=%p", action_set_list);
1404 : :
1405 : 0 : rte_free(action_set_list->action_sets);
1406 : 0 : rte_free(action_set_list);
1407 : : }
1408 : :
1409 : : static int
1410 : 0 : sfc_mae_action_set_list_enable(struct sfc_adapter *sa,
1411 : : struct sfc_mae_action_set_list *action_set_list)
1412 : : {
1413 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1414 : : unsigned int i;
1415 : : unsigned int j;
1416 : : int rc;
1417 : :
1418 [ # # ]: 0 : if (action_set_list == NULL)
1419 : : return 0;
1420 : :
1421 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1422 : :
1423 : : fw_rsrc = &action_set_list->fw_rsrc;
1424 : :
1425 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1426 : : struct sfc_mae *mae = &sa->mae;
1427 : :
1428 : : SFC_ASSERT(fw_rsrc->aset_list_id.id == EFX_MAE_RSRC_ID_INVALID);
1429 : :
1430 [ # # ]: 0 : for (i = 0; i < action_set_list->nb_action_sets; ++i) {
1431 : : const struct sfc_mae_fw_rsrc *as_fw_rsrc;
1432 : :
1433 : 0 : rc = sfc_mae_action_set_enable(sa,
1434 : 0 : action_set_list->action_sets[i]);
1435 [ # # ]: 0 : if (rc != 0)
1436 : 0 : goto fail_action_set_enable;
1437 : :
1438 : 0 : as_fw_rsrc = &action_set_list->action_sets[i]->fw_rsrc;
1439 : 0 : mae->bounce_aset_ids[i].id = as_fw_rsrc->aset_id.id;
1440 : : }
1441 : :
1442 : 0 : rc = efx_mae_action_set_list_alloc(sa->nic,
1443 : : action_set_list->nb_action_sets,
1444 : 0 : mae->bounce_aset_ids,
1445 : : &fw_rsrc->aset_list_id);
1446 [ # # ]: 0 : if (rc != 0) {
1447 : 0 : sfc_err(sa, "failed to enable action_set_list=%p: %s",
1448 : : action_set_list, strerror(rc));
1449 : 0 : goto fail_action_set_list_alloc;
1450 : : }
1451 : :
1452 : 0 : sfc_dbg(sa, "enabled action_set_list=%p: ASL_ID=0x%08x",
1453 : : action_set_list, fw_rsrc->aset_list_id.id);
1454 : : }
1455 : :
1456 : 0 : ++(fw_rsrc->refcnt);
1457 : :
1458 : 0 : return 0;
1459 : :
1460 : : fail_action_set_list_alloc:
1461 : 0 : fail_action_set_enable:
1462 [ # # ]: 0 : for (j = 0; j < i; ++j)
1463 : 0 : sfc_mae_action_set_disable(sa, action_set_list->action_sets[j]);
1464 : :
1465 : : return rc;
1466 : : }
1467 : :
1468 : : static void
1469 : 0 : sfc_mae_action_set_list_disable(struct sfc_adapter *sa,
1470 : : struct sfc_mae_action_set_list *action_set_list)
1471 : : {
1472 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1473 : : int rc;
1474 : :
1475 [ # # ]: 0 : if (action_set_list == NULL)
1476 : : return;
1477 : :
1478 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1479 : :
1480 : : fw_rsrc = &action_set_list->fw_rsrc;
1481 : :
1482 [ # # ]: 0 : if (fw_rsrc->aset_list_id.id == EFX_MAE_RSRC_ID_INVALID ||
1483 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
1484 : 0 : sfc_err(sa, "failed to disable action_set_list=%p: already disabled; ASL_ID=0x%08x, refcnt=%u",
1485 : : action_set_list, fw_rsrc->aset_list_id.id,
1486 : : fw_rsrc->refcnt);
1487 : 0 : return;
1488 : : }
1489 : :
1490 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
1491 : : unsigned int i;
1492 : :
1493 : 0 : rc = efx_mae_action_set_list_free(sa->nic,
1494 : 0 : &fw_rsrc->aset_list_id);
1495 [ # # ]: 0 : if (rc == 0) {
1496 : 0 : sfc_dbg(sa, "disabled action_set_list=%p with ASL_ID=0x%08x",
1497 : : action_set_list, fw_rsrc->aset_list_id.id);
1498 : : } else {
1499 : 0 : sfc_err(sa, "failed to disable action_set_list=%p with ASL_ID=0x%08x: %s",
1500 : : action_set_list, fw_rsrc->aset_list_id.id,
1501 : : strerror(rc));
1502 : : }
1503 : 0 : fw_rsrc->aset_list_id.id = EFX_MAE_RSRC_ID_INVALID;
1504 : :
1505 [ # # ]: 0 : for (i = 0; i < action_set_list->nb_action_sets; ++i) {
1506 : 0 : sfc_mae_action_set_disable(sa,
1507 : 0 : action_set_list->action_sets[i]);
1508 : : }
1509 : : }
1510 : :
1511 : 0 : --(fw_rsrc->refcnt);
1512 : : }
1513 : :
1514 : : struct sfc_mae_action_rule_ctx {
1515 : : struct sfc_mae_outer_rule *outer_rule;
1516 : : /*
1517 : : * When action_set_list != NULL, action_set is NULL, and vice versa.
1518 : : */
1519 : : struct sfc_mae_action_set *action_set;
1520 : : struct sfc_mae_action_set_list *action_set_list;
1521 : : efx_mae_match_spec_t *match_spec;
1522 : : uint32_t ct_mark;
1523 : : };
1524 : :
1525 : : static int
1526 : 0 : sfc_mae_action_rule_attach(struct sfc_adapter *sa,
1527 : : struct sfc_mae_action_rule_ctx *ctx,
1528 : : struct sfc_mae_action_rule **rulep,
1529 : : struct rte_flow_error *error)
1530 : : {
1531 : 0 : uint32_t new_ct_mark = ctx->ct_mark;
1532 : : struct sfc_mae_action_rule *rule;
1533 : : int rc;
1534 : :
1535 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1536 : :
1537 : : SFC_ASSERT(ctx->ct_mark <= 1);
1538 : :
1539 : : /*
1540 : : * It is assumed that the caller of this helper has already properly
1541 : : * tailored ctx->match_spec to match on OR_ID / 0xffffffff (when
1542 : : * ctx->outer_rule refers to a currently active outer rule) or
1543 : : * on 0xffffffff / 0xffffffff, so that specs compare correctly.
1544 : : */
1545 [ # # ]: 0 : TAILQ_FOREACH(rule, &sa->mae.action_rules, entries) {
1546 [ # # ]: 0 : if (rule->ct_mark == new_ct_mark)
1547 : 0 : ++new_ct_mark;
1548 : :
1549 [ # # ]: 0 : if (rule->outer_rule != ctx->outer_rule ||
1550 [ # # ]: 0 : rule->action_set != ctx->action_set ||
1551 [ # # ]: 0 : rule->action_set_list != ctx->action_set_list ||
1552 [ # # ]: 0 : !!rule->ct_mark != !!ctx->ct_mark)
1553 : 0 : continue;
1554 : :
1555 [ # # ]: 0 : if (ctx->ct_mark != 0) {
1556 : 0 : rc = efx_mae_match_spec_ct_mark_set(ctx->match_spec,
1557 : : rule->ct_mark);
1558 [ # # ]: 0 : if (rc != 0) {
1559 : 0 : return rte_flow_error_set(error, EFAULT,
1560 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1561 : : NULL, "AR: failed to set CT mark for comparison");
1562 : : }
1563 : : }
1564 : :
1565 [ # # ]: 0 : if (efx_mae_match_specs_equal(rule->match_spec,
1566 : 0 : ctx->match_spec)) {
1567 : 0 : sfc_dbg(sa, "attaching to action_rule=%p", rule);
1568 : 0 : ++(rule->refcnt);
1569 : 0 : *rulep = rule;
1570 : 0 : return 0;
1571 : : }
1572 : : }
1573 : :
1574 [ # # ]: 0 : if (ctx->ct_mark != 0) {
1575 [ # # ]: 0 : if (new_ct_mark == UINT32_MAX) {
1576 : 0 : return rte_flow_error_set(error, ERANGE,
1577 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1578 : : NULL, "AR: failed to allocate CT mark");
1579 : : }
1580 : :
1581 : 0 : rc = efx_mae_match_spec_ct_mark_set(ctx->match_spec,
1582 : : new_ct_mark);
1583 [ # # ]: 0 : if (rc != 0) {
1584 : 0 : return rte_flow_error_set(error, EFAULT,
1585 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1586 : : NULL, "AR: failed to set CT mark");
1587 : : }
1588 : :
1589 : 0 : ctx->ct_mark = new_ct_mark;
1590 : : }
1591 : :
1592 : : /*
1593 : : * No need to set RTE error, as this
1594 : : * code should be handled gracefully.
1595 : : */
1596 : : return -ENOENT;
1597 : : }
1598 : :
1599 : : static int
1600 : 0 : sfc_mae_action_rule_add(struct sfc_adapter *sa,
1601 : : const struct sfc_mae_action_rule_ctx *ctx,
1602 : : struct sfc_mae_action_rule **rulep)
1603 : : {
1604 : : struct sfc_mae_action_rule *rule;
1605 : : struct sfc_mae *mae = &sa->mae;
1606 : :
1607 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1608 : :
1609 : 0 : rule = rte_zmalloc("sfc_mae_action_rule", sizeof(*rule), 0);
1610 [ # # ]: 0 : if (rule == NULL)
1611 : : return ENOMEM;
1612 : :
1613 : 0 : rule->refcnt = 1;
1614 : :
1615 : : /*
1616 : : * It is assumed that the caller invoked sfc_mae_action_rule_attach()
1617 : : * and got (-ENOENT) before getting here. That ensures a unique CT
1618 : : * mark value or, if no CT is involved at all, simply zero.
1619 : : *
1620 : : * It is also assumed that match on the mark (if non-zero)
1621 : : * is already set in the action rule match specification.
1622 : : */
1623 : 0 : rule->ct_mark = ctx->ct_mark;
1624 : :
1625 : 0 : rule->outer_rule = ctx->outer_rule;
1626 : 0 : rule->action_set = ctx->action_set;
1627 : 0 : rule->action_set_list = ctx->action_set_list;
1628 : 0 : rule->match_spec = ctx->match_spec;
1629 : :
1630 : 0 : rule->fw_rsrc.rule_id.id = EFX_MAE_RSRC_ID_INVALID;
1631 : :
1632 : 0 : TAILQ_INSERT_TAIL(&mae->action_rules, rule, entries);
1633 : :
1634 : 0 : *rulep = rule;
1635 : :
1636 : 0 : sfc_dbg(sa, "added action_rule=%p", rule);
1637 : :
1638 : 0 : return 0;
1639 : : }
1640 : :
1641 : : static void
1642 : 0 : sfc_mae_action_rule_del(struct sfc_adapter *sa,
1643 : : struct sfc_mae_action_rule *rule)
1644 : : {
1645 : : struct sfc_mae *mae = &sa->mae;
1646 [ # # ]: 0 : if (rule == NULL)
1647 : : return;
1648 : :
1649 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1650 : : SFC_ASSERT(rule->refcnt != 0);
1651 : :
1652 : 0 : --(rule->refcnt);
1653 : :
1654 [ # # ]: 0 : if (rule->refcnt != 0)
1655 : : return;
1656 : :
1657 [ # # ]: 0 : if (rule->fw_rsrc.rule_id.id != EFX_MAE_RSRC_ID_INVALID ||
1658 : : rule->fw_rsrc.refcnt != 0) {
1659 : 0 : sfc_err(sa, "deleting action_rule=%p abandons its FW resource: AR_ID=0x%08x, refcnt=%u",
1660 : : rule, rule->fw_rsrc.rule_id.id, rule->fw_rsrc.refcnt);
1661 : : }
1662 : :
1663 : 0 : efx_mae_match_spec_fini(sa->nic, rule->match_spec);
1664 : 0 : sfc_mae_action_set_list_del(sa, rule->action_set_list);
1665 : 0 : sfc_mae_action_set_del(sa, rule->action_set);
1666 : 0 : sfc_mae_outer_rule_del(sa, rule->outer_rule);
1667 : :
1668 [ # # ]: 0 : TAILQ_REMOVE(&mae->action_rules, rule, entries);
1669 : 0 : sfc_dbg(sa, "deleted action_rule=%p", rule);
1670 : 0 : rte_free(rule);
1671 : : }
1672 : :
1673 : : static int
1674 : 0 : sfc_mae_action_rule_enable(struct sfc_adapter *sa,
1675 : : struct sfc_mae_action_rule *rule)
1676 : : {
1677 : : const efx_mae_aset_list_id_t *asl_idp = NULL;
1678 : : const efx_mae_aset_id_t *as_idp = NULL;
1679 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1680 : : int rc;
1681 : :
1682 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1683 : :
1684 : : fw_rsrc = &rule->fw_rsrc;
1685 : :
1686 [ # # ]: 0 : if (fw_rsrc->refcnt != 0)
1687 : 0 : goto success;
1688 : :
1689 : 0 : rc = sfc_mae_outer_rule_enable(sa, rule->outer_rule, rule->match_spec);
1690 [ # # ]: 0 : if (rc != 0)
1691 : 0 : goto fail_outer_rule_enable;
1692 : :
1693 : 0 : rc = sfc_mae_action_set_enable(sa, rule->action_set);
1694 [ # # ]: 0 : if (rc != 0)
1695 : 0 : goto fail_action_set_enable;
1696 : :
1697 : 0 : rc = sfc_mae_action_set_list_enable(sa, rule->action_set_list);
1698 [ # # ]: 0 : if (rc != 0)
1699 : 0 : goto fail_action_set_list_enable;
1700 : :
1701 [ # # ]: 0 : if (rule->action_set_list != NULL)
1702 : 0 : asl_idp = &rule->action_set_list->fw_rsrc.aset_list_id;
1703 : :
1704 [ # # ]: 0 : if (rule->action_set != NULL)
1705 : 0 : as_idp = &rule->action_set->fw_rsrc.aset_id;
1706 : :
1707 : 0 : rc = efx_mae_action_rule_insert(sa->nic, rule->match_spec, asl_idp,
1708 : : as_idp, &fw_rsrc->rule_id);
1709 [ # # ]: 0 : if (rc != 0) {
1710 : 0 : sfc_err(sa, "failed to enable action_rule=%p: %s",
1711 : : rule, strerror(rc));
1712 : 0 : goto fail_action_rule_insert;
1713 : : }
1714 : :
1715 : 0 : success:
1716 [ # # ]: 0 : if (fw_rsrc->refcnt == 0) {
1717 : 0 : sfc_dbg(sa, "enabled action_rule=%p: AR_ID=0x%08x",
1718 : : rule, fw_rsrc->rule_id.id);
1719 : : }
1720 : :
1721 : 0 : ++(fw_rsrc->refcnt);
1722 : :
1723 : 0 : return 0;
1724 : :
1725 : : fail_action_rule_insert:
1726 : 0 : sfc_mae_action_set_list_disable(sa, rule->action_set_list);
1727 : :
1728 : 0 : fail_action_set_list_enable:
1729 : 0 : sfc_mae_action_set_disable(sa, rule->action_set);
1730 : :
1731 : 0 : fail_action_set_enable:
1732 : 0 : sfc_mae_outer_rule_disable(sa, rule->outer_rule, rule->match_spec);
1733 : :
1734 : : fail_outer_rule_enable:
1735 : : return rc;
1736 : : }
1737 : : static void
1738 : 0 : sfc_mae_action_rule_disable(struct sfc_adapter *sa,
1739 : : struct sfc_mae_action_rule *rule)
1740 : : {
1741 : : struct sfc_mae_fw_rsrc *fw_rsrc;
1742 : : int rc;
1743 : :
1744 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
1745 : :
1746 : : fw_rsrc = &rule->fw_rsrc;
1747 : :
1748 [ # # ]: 0 : if (fw_rsrc->rule_id.id == EFX_MAE_RSRC_ID_INVALID ||
1749 [ # # ]: 0 : fw_rsrc->refcnt == 0) {
1750 : 0 : sfc_err(sa, "failed to disable action_rule=%p: already disabled; AR_ID=0x%08x, refcnt=%u",
1751 : : rule, fw_rsrc->rule_id.id, fw_rsrc->refcnt);
1752 : 0 : return;
1753 : : }
1754 : :
1755 [ # # ]: 0 : if (fw_rsrc->refcnt == 1) {
1756 : 0 : rc = efx_mae_action_rule_remove(sa->nic, &fw_rsrc->rule_id);
1757 [ # # ]: 0 : if (rc == 0) {
1758 : 0 : sfc_dbg(sa, "disabled action_rule=%p with AR_ID=0x%08x",
1759 : : rule, fw_rsrc->rule_id.id);
1760 : : } else {
1761 : 0 : sfc_err(sa, "failed to disable action_rule=%p with AR_ID=0x%08x: %s",
1762 : : rule, fw_rsrc->rule_id.id, strerror(rc));
1763 : : }
1764 : :
1765 : 0 : fw_rsrc->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
1766 : :
1767 : 0 : sfc_mae_action_set_list_disable(sa, rule->action_set_list);
1768 : :
1769 : 0 : sfc_mae_action_set_disable(sa, rule->action_set);
1770 : :
1771 : 0 : sfc_mae_outer_rule_disable(sa, rule->outer_rule,
1772 : : rule->match_spec);
1773 : : }
1774 : :
1775 : 0 : --(fw_rsrc->refcnt);
1776 : : }
1777 : :
1778 : : void
1779 : 0 : sfc_mae_flow_cleanup(struct sfc_adapter *sa,
1780 : : struct rte_flow *flow)
1781 : : {
1782 : : struct sfc_flow_spec_mae *spec_mae;
1783 : :
1784 [ # # ]: 0 : if (flow == NULL)
1785 : : return;
1786 : :
1787 : : spec_mae = &flow->spec.mae;
1788 : :
1789 [ # # ]: 0 : if (spec_mae->ft_ctx != NULL) {
1790 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL)
1791 : 0 : spec_mae->ft_ctx->tunnel_rule_is_set = B_FALSE;
1792 : :
1793 : : SFC_ASSERT(spec_mae->ft_ctx->refcnt != 0);
1794 : 0 : --(spec_mae->ft_ctx->refcnt);
1795 : : }
1796 : :
1797 : 0 : sfc_mae_action_rule_del(sa, spec_mae->action_rule);
1798 : :
1799 : 0 : sfc_mae_counter_del(sa, spec_mae->ct_counter);
1800 : : }
1801 : :
1802 : : static int
1803 : 0 : sfc_mae_set_ethertypes(struct sfc_mae_parse_ctx *ctx)
1804 : : {
1805 : : struct sfc_mae_pattern_data *pdata = &ctx->pattern_data;
1806 : 0 : const efx_mae_field_id_t *fremap = ctx->field_ids_remap;
1807 : 0 : const efx_mae_field_id_t field_ids[] = {
1808 : : EFX_MAE_FIELD_VLAN0_PROTO_BE,
1809 : : EFX_MAE_FIELD_VLAN1_PROTO_BE,
1810 : : };
1811 : : const struct sfc_mae_ethertype *et;
1812 : : unsigned int i;
1813 : : int rc;
1814 : :
1815 : : /*
1816 : : * In accordance with RTE flow API convention, the innermost L2
1817 : : * item's "type" ("inner_type") is a L3 EtherType. If there is
1818 : : * no L3 item, it's 0x0000/0x0000.
1819 : : */
1820 : 0 : et = &pdata->ethertypes[pdata->nb_vlan_tags];
1821 : 0 : rc = efx_mae_match_spec_field_set(ctx->match_spec,
1822 : : fremap[EFX_MAE_FIELD_ETHER_TYPE_BE],
1823 : : sizeof(et->value),
1824 : 0 : (const uint8_t *)&et->value,
1825 : : sizeof(et->mask),
1826 : 0 : (const uint8_t *)&et->mask);
1827 [ # # ]: 0 : if (rc != 0)
1828 : : return rc;
1829 : :
1830 : : /*
1831 : : * sfc_mae_rule_parse_item_vlan() has already made sure
1832 : : * that pdata->nb_vlan_tags does not exceed this figure.
1833 : : */
1834 : : RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2);
1835 : :
1836 [ # # ]: 0 : for (i = 0; i < pdata->nb_vlan_tags; ++i) {
1837 : : et = &pdata->ethertypes[i];
1838 : :
1839 : 0 : rc = efx_mae_match_spec_field_set(ctx->match_spec,
1840 : 0 : fremap[field_ids[i]],
1841 : : sizeof(et->value),
1842 : 0 : (const uint8_t *)&et->value,
1843 : : sizeof(et->mask),
1844 : 0 : (const uint8_t *)&et->mask);
1845 [ # # ]: 0 : if (rc != 0)
1846 : 0 : return rc;
1847 : : }
1848 : :
1849 : : return 0;
1850 : : }
1851 : :
1852 : : static int
1853 : 0 : sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx,
1854 : : struct rte_flow_error *error)
1855 : : {
1856 : 0 : const efx_mae_field_id_t *fremap = ctx->field_ids_remap;
1857 : : struct sfc_mae_pattern_data *pdata = &ctx->pattern_data;
1858 : 0 : struct sfc_mae_ethertype *ethertypes = pdata->ethertypes;
1859 : 0 : const rte_be16_t supported_tpids[] = {
1860 : : /* VLAN standard TPID (always the first element) */
1861 : : RTE_BE16(RTE_ETHER_TYPE_VLAN),
1862 : :
1863 : : /* Double-tagging TPIDs */
1864 : : RTE_BE16(RTE_ETHER_TYPE_QINQ),
1865 : : RTE_BE16(RTE_ETHER_TYPE_QINQ1),
1866 : : RTE_BE16(RTE_ETHER_TYPE_QINQ2),
1867 : : RTE_BE16(RTE_ETHER_TYPE_QINQ3),
1868 : : };
1869 : 0 : bool enforce_tag_presence[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {0};
1870 : : unsigned int nb_supported_tpids = RTE_DIM(supported_tpids);
1871 : : unsigned int ethertype_idx;
1872 : : const uint8_t *valuep;
1873 : : const uint8_t *maskp;
1874 : : int rc;
1875 : :
1876 [ # # ]: 0 : if (pdata->innermost_ethertype_restriction.mask != 0 &&
1877 [ # # ]: 0 : pdata->nb_vlan_tags < SFC_MAE_MATCH_VLAN_MAX_NTAGS) {
1878 : : /*
1879 : : * If a single item VLAN is followed by a L3 item, value
1880 : : * of "type" in item ETH can't be a double-tagging TPID.
1881 : : */
1882 : : nb_supported_tpids = 1;
1883 : : }
1884 : :
1885 : : /*
1886 : : * sfc_mae_rule_parse_item_vlan() has already made sure
1887 : : * that pdata->nb_vlan_tags does not exceed this figure.
1888 : : */
1889 : : RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2);
1890 : :
1891 : : for (ethertype_idx = 0;
1892 [ # # ]: 0 : ethertype_idx < pdata->nb_vlan_tags; ++ethertype_idx) {
1893 : 0 : rte_be16_t tpid_v = ethertypes[ethertype_idx].value;
1894 : 0 : rte_be16_t tpid_m = ethertypes[ethertype_idx].mask;
1895 : : unsigned int tpid_idx;
1896 : :
1897 : : /*
1898 : : * This loop can have only two iterations. On the second one,
1899 : : * drop outer tag presence enforcement bit because the inner
1900 : : * tag presence automatically assumes that for the outer tag.
1901 : : */
1902 : 0 : enforce_tag_presence[0] = B_FALSE;
1903 : :
1904 [ # # ]: 0 : if (tpid_m == RTE_BE16(0)) {
1905 [ # # ]: 0 : if (pdata->tci_masks[ethertype_idx] == RTE_BE16(0))
1906 : 0 : enforce_tag_presence[ethertype_idx] = B_TRUE;
1907 : :
1908 : : /* No match on this field, and no value check. */
1909 : : nb_supported_tpids = 1;
1910 : 0 : continue;
1911 : : }
1912 : :
1913 : : /* Exact match is supported only. */
1914 [ # # ]: 0 : if (tpid_m != RTE_BE16(0xffff)) {
1915 [ # # ]: 0 : sfc_err(ctx->sa, "TPID mask must be 0x0 or 0xffff; got 0x%04x",
1916 : : rte_be_to_cpu_16(tpid_m));
1917 : : rc = EINVAL;
1918 : 0 : goto fail;
1919 : : }
1920 : :
1921 : 0 : for (tpid_idx = pdata->nb_vlan_tags - ethertype_idx - 1;
1922 [ # # ]: 0 : tpid_idx < nb_supported_tpids; ++tpid_idx) {
1923 [ # # ]: 0 : if (tpid_v == supported_tpids[tpid_idx])
1924 : : break;
1925 : : }
1926 : :
1927 [ # # ]: 0 : if (tpid_idx == nb_supported_tpids) {
1928 [ # # ]: 0 : sfc_err(ctx->sa, "TPID 0x%04x is unsupported",
1929 : : rte_be_to_cpu_16(tpid_v));
1930 : : rc = EINVAL;
1931 : 0 : goto fail;
1932 : : }
1933 : :
1934 : : nb_supported_tpids = 1;
1935 : : }
1936 : :
1937 [ # # ]: 0 : if (pdata->innermost_ethertype_restriction.mask == RTE_BE16(0xffff)) {
1938 : 0 : struct sfc_mae_ethertype *et = ðertypes[ethertype_idx];
1939 : : rte_be16_t enforced_et;
1940 : :
1941 : 0 : enforced_et = pdata->innermost_ethertype_restriction.value;
1942 : :
1943 [ # # ]: 0 : if (et->mask == 0) {
1944 : 0 : et->mask = RTE_BE16(0xffff);
1945 : 0 : et->value = enforced_et;
1946 [ # # ]: 0 : } else if (et->mask != RTE_BE16(0xffff) ||
1947 [ # # ]: 0 : et->value != enforced_et) {
1948 [ # # # # : 0 : sfc_err(ctx->sa, "L3 EtherType must be 0x0/0x0 or 0x%04x/0xffff; got 0x%04x/0x%04x",
# # ]
1949 : : rte_be_to_cpu_16(enforced_et),
1950 : : rte_be_to_cpu_16(et->value),
1951 : : rte_be_to_cpu_16(et->mask));
1952 : : rc = EINVAL;
1953 : 0 : goto fail;
1954 : : }
1955 : : }
1956 : :
1957 : : /*
1958 : : * Now, when the number of VLAN tags is known, set fields
1959 : : * ETHER_TYPE, VLAN0_PROTO and VLAN1_PROTO so that the first
1960 : : * one is either a valid L3 EtherType (or 0x0000/0x0000),
1961 : : * and the last two are valid TPIDs (or 0x0000/0x0000).
1962 : : */
1963 : 0 : rc = sfc_mae_set_ethertypes(ctx);
1964 [ # # ]: 0 : if (rc != 0)
1965 : 0 : goto fail;
1966 : :
1967 [ # # ]: 0 : if (pdata->l3_next_proto_restriction_mask == 0xff) {
1968 [ # # ]: 0 : if (pdata->l3_next_proto_mask == 0) {
1969 : 0 : pdata->l3_next_proto_mask = 0xff;
1970 : 0 : pdata->l3_next_proto_value =
1971 : 0 : pdata->l3_next_proto_restriction_value;
1972 [ # # ]: 0 : } else if (pdata->l3_next_proto_mask != 0xff ||
1973 : 0 : pdata->l3_next_proto_value !=
1974 [ # # ]: 0 : pdata->l3_next_proto_restriction_value) {
1975 : 0 : sfc_err(ctx->sa, "L3 next protocol must be 0x0/0x0 or 0x%02x/0xff; got 0x%02x/0x%02x",
1976 : : pdata->l3_next_proto_restriction_value,
1977 : : pdata->l3_next_proto_value,
1978 : : pdata->l3_next_proto_mask);
1979 : : rc = EINVAL;
1980 : 0 : goto fail;
1981 : : }
1982 : : }
1983 : :
1984 [ # # # # ]: 0 : if (enforce_tag_presence[0] || pdata->has_ovlan_mask) {
1985 : 0 : rc = efx_mae_match_spec_bit_set(ctx->match_spec,
1986 : : fremap[EFX_MAE_FIELD_HAS_OVLAN],
1987 [ # # ]: 0 : enforce_tag_presence[0] ||
1988 [ # # ]: 0 : pdata->has_ovlan_value);
1989 [ # # ]: 0 : if (rc != 0)
1990 : 0 : goto fail;
1991 : : }
1992 : :
1993 [ # # # # ]: 0 : if (enforce_tag_presence[1] || pdata->has_ivlan_mask) {
1994 : 0 : rc = efx_mae_match_spec_bit_set(ctx->match_spec,
1995 : : fremap[EFX_MAE_FIELD_HAS_IVLAN],
1996 [ # # ]: 0 : enforce_tag_presence[1] ||
1997 [ # # ]: 0 : pdata->has_ivlan_value);
1998 [ # # ]: 0 : if (rc != 0)
1999 : 0 : goto fail;
2000 : : }
2001 : :
2002 : 0 : valuep = (const uint8_t *)&pdata->l3_next_proto_value;
2003 : 0 : maskp = (const uint8_t *)&pdata->l3_next_proto_mask;
2004 : 0 : rc = efx_mae_match_spec_field_set(ctx->match_spec,
2005 : : fremap[EFX_MAE_FIELD_IP_PROTO],
2006 : : sizeof(pdata->l3_next_proto_value),
2007 : : valuep,
2008 : : sizeof(pdata->l3_next_proto_mask),
2009 : : maskp);
2010 [ # # ]: 0 : if (rc != 0)
2011 : 0 : goto fail;
2012 : :
2013 [ # # ]: 0 : if (pdata->l3_frag_ofst_mask != 0) {
2014 : : const rte_be16_t hdr_mask = RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK);
2015 : : rte_be16_t value;
2016 : : rte_be16_t last;
2017 : : boolean_t first_frag;
2018 : : boolean_t is_ip_frag;
2019 : : boolean_t any_frag;
2020 : :
2021 [ # # ]: 0 : if (pdata->l3_frag_ofst_mask & RTE_BE16(RTE_IPV4_HDR_DF_FLAG)) {
2022 : 0 : sfc_err(ctx->sa, "Don't fragment flag is not supported.");
2023 : : rc = ENOTSUP;
2024 : 0 : goto fail;
2025 : : }
2026 : :
2027 [ # # ]: 0 : if ((pdata->l3_frag_ofst_mask & hdr_mask) != hdr_mask) {
2028 : 0 : sfc_err(ctx->sa, "Invalid value for fragment offset mask.");
2029 : : rc = EINVAL;
2030 : 0 : goto fail;
2031 : : }
2032 : :
2033 : 0 : value = pdata->l3_frag_ofst_mask & pdata->l3_frag_ofst_value;
2034 : 0 : last = pdata->l3_frag_ofst_mask & pdata->l3_frag_ofst_last;
2035 : :
2036 : : /*
2037 : : * value: last: matches:
2038 : : * 0 0 Non-fragmented packet
2039 : : * 1 0x1fff Non-first fragment
2040 : : * 1 0x1fff+MF Any fragment
2041 : : * MF 0 First fragment
2042 : : */
2043 [ # # ]: 0 : if (last == 0 &&
2044 [ # # ]: 0 : (pdata->l3_frag_ofst_value & hdr_mask) != 0) {
2045 : 0 : sfc_err(ctx->sa,
2046 : : "Exact matching is prohibited for non-zero offsets, but ranges are allowed.");
2047 : : rc = EINVAL;
2048 : 0 : goto fail;
2049 : : }
2050 : :
2051 [ # # ]: 0 : if (value == 0 && last == 0) {
2052 : : is_ip_frag = false;
2053 : : any_frag = true;
2054 [ # # # # ]: 0 : } else if (value == RTE_BE16(1) && (last & hdr_mask) == hdr_mask) {
2055 [ # # ]: 0 : if (last & RTE_BE16(RTE_IPV4_HDR_MF_FLAG)) {
2056 : : is_ip_frag = true;
2057 : : any_frag = true;
2058 : : } else {
2059 : : is_ip_frag = true;
2060 : : any_frag = false;
2061 : : first_frag = false;
2062 : : }
2063 [ # # ]: 0 : } else if (value == RTE_BE16(RTE_IPV4_HDR_MF_FLAG) && last == 0) {
2064 : : is_ip_frag = true;
2065 : : any_frag = false;
2066 : : first_frag = true;
2067 : : } else {
2068 : 0 : sfc_err(ctx->sa, "Invalid value for fragment offset.");
2069 : : rc = EINVAL;
2070 : 0 : goto fail;
2071 : : }
2072 : :
2073 : 0 : rc = efx_mae_match_spec_bit_set(ctx->match_spec,
2074 : : fremap[EFX_MAE_FIELD_IS_IP_FRAG], is_ip_frag);
2075 [ # # ]: 0 : if (rc != 0)
2076 : 0 : goto fail;
2077 : :
2078 [ # # ]: 0 : if (!any_frag) {
2079 : 0 : rc = efx_mae_match_spec_bit_set(ctx->match_spec,
2080 : : fremap[EFX_MAE_FIELD_IP_FIRST_FRAG],
2081 : : first_frag);
2082 [ # # ]: 0 : if (rc != 0)
2083 : 0 : goto fail;
2084 : : }
2085 : : }
2086 : :
2087 : : return 0;
2088 : :
2089 : 0 : fail:
2090 : 0 : return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2091 : : "Failed to process pattern data");
2092 : : }
2093 : :
2094 : : static int
2095 : 0 : sfc_mae_rule_parse_item_mark(const struct rte_flow_item *item,
2096 : : struct sfc_flow_parse_ctx *ctx,
2097 : : struct rte_flow_error *error)
2098 : : {
2099 : 0 : const struct rte_flow_item_mark *spec = item->spec;
2100 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2101 : 0 : struct sfc_ft_ctx *ft_ctx = ctx_mae->ft_ctx;
2102 : :
2103 [ # # ]: 0 : if (spec == NULL) {
2104 : 0 : return rte_flow_error_set(error, EINVAL,
2105 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2106 : : "NULL spec in item MARK");
2107 : : }
2108 : :
2109 : : /*
2110 : : * This item is used in tunnel offload support only.
2111 : : * It must go before any network header items. This
2112 : : * way, sfc_mae_rule_preparse_item_mark() must have
2113 : : * already parsed it. Only one item MARK is allowed.
2114 : : */
2115 [ # # ]: 0 : if (ctx_mae->ft_rule_type != SFC_FT_RULE_SWITCH ||
2116 [ # # ]: 0 : spec->id != (uint32_t)SFC_FT_CTX_ID_TO_FLOW_MARK(ft_ctx->id)) {
2117 : 0 : return rte_flow_error_set(error, EINVAL,
2118 : : RTE_FLOW_ERROR_TYPE_ITEM,
2119 : : item, "invalid item MARK");
2120 : : }
2121 : :
2122 : : return 0;
2123 : : }
2124 : :
2125 : : static int
2126 : 0 : sfc_mae_rule_parse_item_port_id(const struct rte_flow_item *item,
2127 : : struct sfc_flow_parse_ctx *ctx,
2128 : : struct rte_flow_error *error)
2129 : : {
2130 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2131 : 0 : const struct rte_flow_item_port_id supp_mask = {
2132 : : .id = 0xffffffff,
2133 : : };
2134 : : const void *def_mask = &rte_flow_item_port_id_mask;
2135 : 0 : const struct rte_flow_item_port_id *spec = NULL;
2136 : 0 : const struct rte_flow_item_port_id *mask = NULL;
2137 : : efx_mport_sel_t mport_sel;
2138 : : unsigned int type_mask;
2139 : : int rc;
2140 : :
2141 [ # # ]: 0 : if (ctx_mae->match_mport_set) {
2142 : 0 : return rte_flow_error_set(error, ENOTSUP,
2143 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2144 : : "Can't handle multiple traffic source items");
2145 : : }
2146 : :
2147 : 0 : rc = sfc_flow_parse_init(item,
2148 : : (const void **)&spec, (const void **)&mask,
2149 : : (const void *)&supp_mask, def_mask,
2150 : : sizeof(struct rte_flow_item_port_id), error);
2151 [ # # ]: 0 : if (rc != 0)
2152 : : return rc;
2153 : :
2154 [ # # ]: 0 : if (mask->id != supp_mask.id) {
2155 : 0 : return rte_flow_error_set(error, EINVAL,
2156 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2157 : : "Bad mask in the PORT_ID pattern item");
2158 : : }
2159 : :
2160 : : /* If "spec" is not set, could be any port ID */
2161 [ # # ]: 0 : if (spec == NULL)
2162 : : return 0;
2163 : :
2164 [ # # ]: 0 : if (spec->id > UINT16_MAX) {
2165 : 0 : return rte_flow_error_set(error, EOVERFLOW,
2166 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2167 : : "The port ID is too large");
2168 : : }
2169 : :
2170 : : type_mask = 1U << SFC_MAE_SWITCH_PORT_INDEPENDENT;
2171 : :
2172 : 0 : rc = sfc_mae_switch_get_ethdev_mport(ctx_mae->sa->mae.switch_domain_id,
2173 : : spec->id, type_mask, &mport_sel);
2174 [ # # ]: 0 : if (rc != 0) {
2175 : 0 : return rte_flow_error_set(error, rc,
2176 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2177 : : "Can't get m-port for the given ethdev");
2178 : : }
2179 : :
2180 : 0 : rc = efx_mae_match_spec_mport_set(ctx_mae->match_spec,
2181 : : &mport_sel, NULL);
2182 [ # # ]: 0 : if (rc != 0) {
2183 : 0 : return rte_flow_error_set(error, rc,
2184 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2185 : : "Failed to set MPORT for the port ID");
2186 : : }
2187 : :
2188 : 0 : ctx_mae->match_mport_set = B_TRUE;
2189 : :
2190 : 0 : return 0;
2191 : : }
2192 : :
2193 : : static int
2194 : 0 : sfc_mae_rule_parse_item_ethdev_based(const struct rte_flow_item *item,
2195 : : struct sfc_flow_parse_ctx *ctx,
2196 : : struct rte_flow_error *error)
2197 : : {
2198 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2199 : 0 : const struct rte_flow_item_ethdev supp_mask = {
2200 : : .port_id = 0xffff,
2201 : : };
2202 : : const void *def_mask = &rte_flow_item_ethdev_mask;
2203 : 0 : const struct rte_flow_item_ethdev *spec = NULL;
2204 : 0 : const struct rte_flow_item_ethdev *mask = NULL;
2205 : : efx_mport_sel_t mport_sel;
2206 : : unsigned int type_mask;
2207 : : int rc;
2208 : :
2209 [ # # ]: 0 : if (ctx_mae->match_mport_set) {
2210 : 0 : return rte_flow_error_set(error, ENOTSUP,
2211 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2212 : : "Can't handle multiple traffic source items");
2213 : : }
2214 : :
2215 : 0 : rc = sfc_flow_parse_init(item,
2216 : : (const void **)&spec, (const void **)&mask,
2217 : : (const void *)&supp_mask, def_mask,
2218 : : sizeof(struct rte_flow_item_ethdev), error);
2219 [ # # ]: 0 : if (rc != 0)
2220 : : return rc;
2221 : :
2222 [ # # ]: 0 : if (mask->port_id != supp_mask.port_id) {
2223 : 0 : return rte_flow_error_set(error, EINVAL,
2224 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2225 : : "Bad mask in the ethdev-based pattern item");
2226 : : }
2227 : :
2228 : : /* If "spec" is not set, could be any port ID */
2229 [ # # ]: 0 : if (spec == NULL)
2230 : : return 0;
2231 : :
2232 [ # # # ]: 0 : switch (item->type) {
2233 : 0 : case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR:
2234 : : type_mask = 1U << SFC_MAE_SWITCH_PORT_INDEPENDENT;
2235 : :
2236 : 0 : rc = sfc_mae_switch_get_ethdev_mport(
2237 : 0 : ctx_mae->sa->mae.switch_domain_id,
2238 : 0 : spec->port_id, type_mask, &mport_sel);
2239 [ # # ]: 0 : if (rc != 0) {
2240 : 0 : return rte_flow_error_set(error, rc,
2241 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2242 : : "Can't get m-port for the given ethdev");
2243 : : }
2244 : : break;
2245 : 0 : case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
2246 : 0 : rc = sfc_mae_switch_get_entity_mport(
2247 : 0 : ctx_mae->sa->mae.switch_domain_id,
2248 : 0 : spec->port_id, &mport_sel);
2249 [ # # ]: 0 : if (rc != 0) {
2250 : 0 : return rte_flow_error_set(error, rc,
2251 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2252 : : "Can't get m-port for the given ethdev");
2253 : : }
2254 : : break;
2255 : 0 : default:
2256 : 0 : return rte_flow_error_set(error, EINVAL,
2257 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2258 : : "Unsupported ethdev-based flow item");
2259 : : }
2260 : :
2261 : 0 : rc = efx_mae_match_spec_mport_set(ctx_mae->match_spec,
2262 : : &mport_sel, NULL);
2263 [ # # ]: 0 : if (rc != 0) {
2264 : 0 : return rte_flow_error_set(error, rc,
2265 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2266 : : "Failed to set MPORT for the port ID");
2267 : : }
2268 : :
2269 : 0 : ctx_mae->match_mport_set = B_TRUE;
2270 : :
2271 : 0 : return 0;
2272 : : }
2273 : :
2274 : : /*
2275 : : * Having this field ID in a field locator means that this
2276 : : * locator cannot be used to actually set the field at the
2277 : : * time when the corresponding item gets encountered. Such
2278 : : * fields get stashed in the parsing context instead. This
2279 : : * is required to resolve dependencies between the stashed
2280 : : * fields. See sfc_mae_rule_process_pattern_data().
2281 : : */
2282 : : #define SFC_MAE_FIELD_HANDLING_DEFERRED EFX_MAE_FIELD_NIDS
2283 : :
2284 : : struct sfc_mae_field_locator {
2285 : : efx_mae_field_id_t field_id;
2286 : : size_t size;
2287 : : /* Field offset in the corresponding rte_flow_item_ struct */
2288 : : size_t ofst;
2289 : :
2290 : : uint8_t ct_key_field;
2291 : : };
2292 : :
2293 : : static void
2294 : 0 : sfc_mae_item_build_supp_mask(const struct sfc_mae_field_locator *field_locators,
2295 : : unsigned int nb_field_locators, void *mask_ptr,
2296 : : size_t mask_size)
2297 : : {
2298 : : unsigned int i;
2299 : :
2300 : : memset(mask_ptr, 0, mask_size);
2301 : :
2302 [ # # ]: 0 : for (i = 0; i < nb_field_locators; ++i) {
2303 : 0 : const struct sfc_mae_field_locator *fl = &field_locators[i];
2304 : :
2305 : : SFC_ASSERT(fl->ofst + fl->size <= mask_size);
2306 : 0 : memset(RTE_PTR_ADD(mask_ptr, fl->ofst), 0xff, fl->size);
2307 : : }
2308 : 0 : }
2309 : :
2310 : : static int
2311 : 0 : sfc_mae_parse_item(const struct sfc_mae_field_locator *field_locators,
2312 : : unsigned int nb_field_locators, const uint8_t *spec,
2313 : : const uint8_t *mask, struct sfc_mae_parse_ctx *ctx,
2314 : : struct rte_flow_error *error)
2315 : : {
2316 : 0 : const efx_mae_field_id_t *fremap = ctx->field_ids_remap;
2317 : : unsigned int i;
2318 : : int rc = 0;
2319 : :
2320 [ # # ]: 0 : for (i = 0; i < nb_field_locators; ++i) {
2321 : 0 : const struct sfc_mae_field_locator *fl = &field_locators[i];
2322 : :
2323 [ # # ]: 0 : if (fl->field_id == SFC_MAE_FIELD_HANDLING_DEFERRED)
2324 : 0 : continue;
2325 : :
2326 : 0 : rc = efx_mae_match_spec_field_set(ctx->match_spec,
2327 : 0 : fremap[fl->field_id],
2328 : : fl->size, spec + fl->ofst,
2329 : 0 : fl->size, mask + fl->ofst);
2330 [ # # ]: 0 : if (rc != 0)
2331 : : break;
2332 : : }
2333 : :
2334 [ # # ]: 0 : if (rc != 0) {
2335 : 0 : rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM,
2336 : : NULL, "Failed to process item fields");
2337 : : }
2338 : :
2339 : 0 : return rc;
2340 : : }
2341 : :
2342 : : static const struct sfc_mae_field_locator flocs_eth[] = {
2343 : : {
2344 : : /*
2345 : : * This locator is used only for building supported fields mask.
2346 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2347 : : */
2348 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2349 : : RTE_SIZEOF_FIELD(struct rte_flow_item_eth, hdr.ether_type),
2350 : : offsetof(struct rte_flow_item_eth, hdr.ether_type),
2351 : : },
2352 : : {
2353 : : EFX_MAE_FIELD_ETH_DADDR_BE,
2354 : : RTE_SIZEOF_FIELD(struct rte_flow_item_eth, hdr.dst_addr),
2355 : : offsetof(struct rte_flow_item_eth, hdr.dst_addr),
2356 : : },
2357 : : {
2358 : : EFX_MAE_FIELD_ETH_SADDR_BE,
2359 : : RTE_SIZEOF_FIELD(struct rte_flow_item_eth, hdr.src_addr),
2360 : : offsetof(struct rte_flow_item_eth, hdr.src_addr),
2361 : : },
2362 : : };
2363 : :
2364 : : static int
2365 : 0 : sfc_mae_rule_parse_item_eth(const struct rte_flow_item *item,
2366 : : struct sfc_flow_parse_ctx *ctx,
2367 : : struct rte_flow_error *error)
2368 : : {
2369 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2370 : : struct rte_flow_item_eth override_mask;
2371 : : struct rte_flow_item_eth supp_mask;
2372 : 0 : const uint8_t *spec = NULL;
2373 : 0 : const uint8_t *mask = NULL;
2374 : : int rc;
2375 : :
2376 : 0 : sfc_mae_item_build_supp_mask(flocs_eth, RTE_DIM(flocs_eth),
2377 : : &supp_mask, sizeof(supp_mask));
2378 : 0 : supp_mask.has_vlan = 1;
2379 : :
2380 : 0 : rc = sfc_flow_parse_init(item,
2381 : : (const void **)&spec, (const void **)&mask,
2382 : : (const void *)&supp_mask,
2383 : : &rte_flow_item_eth_mask,
2384 : : sizeof(struct rte_flow_item_eth), error);
2385 [ # # ]: 0 : if (rc != 0)
2386 : : return rc;
2387 : :
2388 [ # # # # ]: 0 : if (ctx_mae->ft_rule_type == SFC_FT_RULE_TUNNEL && mask != NULL) {
2389 : : /*
2390 : : * The HW/FW hasn't got support for match on MAC addresses in
2391 : : * outer rules yet (this will change). Match on VLAN presence
2392 : : * isn't supported either. Ignore these match criteria.
2393 : : */
2394 : : memcpy(&override_mask, mask, sizeof(override_mask));
2395 : : memset(&override_mask.hdr.dst_addr, 0,
2396 : : sizeof(override_mask.hdr.dst_addr));
2397 : : memset(&override_mask.hdr.src_addr, 0,
2398 : : sizeof(override_mask.hdr.src_addr));
2399 : 0 : override_mask.has_vlan = 0;
2400 : :
2401 : 0 : mask = (const uint8_t *)&override_mask;
2402 : : }
2403 : :
2404 [ # # ]: 0 : if (spec != NULL) {
2405 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2406 : : struct sfc_mae_ethertype *ethertypes = pdata->ethertypes;
2407 : : const struct rte_flow_item_eth *item_spec;
2408 : : const struct rte_flow_item_eth *item_mask;
2409 : :
2410 : : item_spec = (const struct rte_flow_item_eth *)spec;
2411 : 0 : item_mask = (const struct rte_flow_item_eth *)mask;
2412 : :
2413 : : /*
2414 : : * Remember various match criteria in the parsing context.
2415 : : * sfc_mae_rule_process_pattern_data() will consider them
2416 : : * altogether when the rest of the items have been parsed.
2417 : : */
2418 : 0 : ethertypes[0].value = item_spec->hdr.ether_type;
2419 : 0 : ethertypes[0].mask = item_mask->hdr.ether_type;
2420 [ # # ]: 0 : if (item_mask->has_vlan) {
2421 : 0 : pdata->has_ovlan_mask = B_TRUE;
2422 [ # # ]: 0 : if (item_spec->has_vlan)
2423 : 0 : pdata->has_ovlan_value = B_TRUE;
2424 : : }
2425 : : } else {
2426 : : /*
2427 : : * The specification is empty. The overall pattern
2428 : : * validity will be enforced at the end of parsing.
2429 : : * See sfc_mae_rule_process_pattern_data().
2430 : : */
2431 : : return 0;
2432 : : }
2433 : :
2434 : 0 : return sfc_mae_parse_item(flocs_eth, RTE_DIM(flocs_eth), spec, mask,
2435 : : ctx_mae, error);
2436 : : }
2437 : :
2438 : : static const struct sfc_mae_field_locator flocs_vlan[] = {
2439 : : /* Outermost tag */
2440 : : {
2441 : : EFX_MAE_FIELD_VLAN0_TCI_BE,
2442 : : RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, hdr.vlan_tci),
2443 : : offsetof(struct rte_flow_item_vlan, hdr.vlan_tci),
2444 : : },
2445 : : {
2446 : : /*
2447 : : * This locator is used only for building supported fields mask.
2448 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2449 : : */
2450 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2451 : : RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, hdr.eth_proto),
2452 : : offsetof(struct rte_flow_item_vlan, hdr.eth_proto),
2453 : : },
2454 : :
2455 : : /* Innermost tag */
2456 : : {
2457 : : EFX_MAE_FIELD_VLAN1_TCI_BE,
2458 : : RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, hdr.vlan_tci),
2459 : : offsetof(struct rte_flow_item_vlan, hdr.vlan_tci),
2460 : : },
2461 : : {
2462 : : /*
2463 : : * This locator is used only for building supported fields mask.
2464 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2465 : : */
2466 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2467 : : RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, hdr.eth_proto),
2468 : : offsetof(struct rte_flow_item_vlan, hdr.eth_proto),
2469 : : },
2470 : : };
2471 : :
2472 : : static int
2473 : 0 : sfc_mae_rule_parse_item_vlan(const struct rte_flow_item *item,
2474 : : struct sfc_flow_parse_ctx *ctx,
2475 : : struct rte_flow_error *error)
2476 : : {
2477 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2478 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2479 : 0 : boolean_t *has_vlan_mp_by_nb_tags[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {
2480 : 0 : &pdata->has_ovlan_mask,
2481 : 0 : &pdata->has_ivlan_mask,
2482 : : };
2483 : 0 : boolean_t *has_vlan_vp_by_nb_tags[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {
2484 : 0 : &pdata->has_ovlan_value,
2485 : 0 : &pdata->has_ivlan_value,
2486 : : };
2487 : : boolean_t *cur_tag_presence_bit_mp;
2488 : : boolean_t *cur_tag_presence_bit_vp;
2489 : : const struct sfc_mae_field_locator *flocs;
2490 : : struct rte_flow_item_vlan supp_mask;
2491 : 0 : const uint8_t *spec = NULL;
2492 : 0 : const uint8_t *mask = NULL;
2493 : : unsigned int nb_flocs;
2494 : : int rc;
2495 : :
2496 : : RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2);
2497 : :
2498 [ # # ]: 0 : if (pdata->nb_vlan_tags == SFC_MAE_MATCH_VLAN_MAX_NTAGS) {
2499 : 0 : return rte_flow_error_set(error, ENOTSUP,
2500 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2501 : : "Can't match that many VLAN tags");
2502 : : }
2503 : :
2504 : 0 : cur_tag_presence_bit_mp = has_vlan_mp_by_nb_tags[pdata->nb_vlan_tags];
2505 : 0 : cur_tag_presence_bit_vp = has_vlan_vp_by_nb_tags[pdata->nb_vlan_tags];
2506 : :
2507 [ # # ]: 0 : if (*cur_tag_presence_bit_mp == B_TRUE &&
2508 [ # # ]: 0 : *cur_tag_presence_bit_vp == B_FALSE) {
2509 : 0 : return rte_flow_error_set(error, EINVAL,
2510 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2511 : : "The previous item enforces no (more) VLAN, "
2512 : : "so the current item (VLAN) must not exist");
2513 : : }
2514 : :
2515 : : nb_flocs = RTE_DIM(flocs_vlan) / SFC_MAE_MATCH_VLAN_MAX_NTAGS;
2516 : 0 : flocs = flocs_vlan + pdata->nb_vlan_tags * nb_flocs;
2517 : :
2518 : 0 : sfc_mae_item_build_supp_mask(flocs, nb_flocs,
2519 : : &supp_mask, sizeof(supp_mask));
2520 : : /*
2521 : : * This only means that the field is supported by the driver and libefx.
2522 : : * Support on NIC level will be checked when all items have been parsed.
2523 : : */
2524 : 0 : supp_mask.has_more_vlan = 1;
2525 : :
2526 : 0 : rc = sfc_flow_parse_init(item,
2527 : : (const void **)&spec, (const void **)&mask,
2528 : : (const void *)&supp_mask,
2529 : : &rte_flow_item_vlan_mask,
2530 : : sizeof(struct rte_flow_item_vlan), error);
2531 [ # # ]: 0 : if (rc != 0)
2532 : : return rc;
2533 : :
2534 [ # # ]: 0 : if (spec != NULL) {
2535 : 0 : struct sfc_mae_ethertype *et = pdata->ethertypes;
2536 : : const struct rte_flow_item_vlan *item_spec;
2537 : : const struct rte_flow_item_vlan *item_mask;
2538 : :
2539 : : item_spec = (const struct rte_flow_item_vlan *)spec;
2540 : 0 : item_mask = (const struct rte_flow_item_vlan *)mask;
2541 : :
2542 : : /*
2543 : : * Remember various match criteria in the parsing context.
2544 : : * sfc_mae_rule_process_pattern_data() will consider them
2545 : : * altogether when the rest of the items have been parsed.
2546 : : */
2547 : 0 : et[pdata->nb_vlan_tags + 1].value = item_spec->hdr.eth_proto;
2548 : 0 : et[pdata->nb_vlan_tags + 1].mask = item_mask->hdr.eth_proto;
2549 : 0 : pdata->tci_masks[pdata->nb_vlan_tags] = item_mask->hdr.vlan_tci;
2550 [ # # ]: 0 : if (item_mask->has_more_vlan) {
2551 [ # # ]: 0 : if (pdata->nb_vlan_tags ==
2552 : : SFC_MAE_MATCH_VLAN_MAX_NTAGS) {
2553 : 0 : return rte_flow_error_set(error, ENOTSUP,
2554 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2555 : : "Can't use 'has_more_vlan' in "
2556 : : "the second item VLAN");
2557 : : }
2558 : 0 : pdata->has_ivlan_mask = B_TRUE;
2559 [ # # ]: 0 : if (item_spec->has_more_vlan)
2560 : 0 : pdata->has_ivlan_value = B_TRUE;
2561 : : }
2562 : :
2563 : : /* Convert TCI to MAE representation right now. */
2564 : 0 : rc = sfc_mae_parse_item(flocs, nb_flocs, spec, mask,
2565 : : ctx_mae, error);
2566 [ # # ]: 0 : if (rc != 0)
2567 : : return rc;
2568 : : }
2569 : :
2570 : 0 : ++(pdata->nb_vlan_tags);
2571 : :
2572 : 0 : return 0;
2573 : : }
2574 : :
2575 : : static const struct sfc_mae_field_locator flocs_ipv4[] = {
2576 : : {
2577 : : EFX_MAE_FIELD_SRC_IP4_BE,
2578 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.src_addr),
2579 : : offsetof(struct rte_flow_item_ipv4, hdr.src_addr),
2580 : : },
2581 : : {
2582 : : EFX_MAE_FIELD_DST_IP4_BE,
2583 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.dst_addr),
2584 : : offsetof(struct rte_flow_item_ipv4, hdr.dst_addr),
2585 : : },
2586 : : {
2587 : : /*
2588 : : * This locator is used only for building supported fields mask.
2589 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2590 : : */
2591 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2592 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.next_proto_id),
2593 : : offsetof(struct rte_flow_item_ipv4, hdr.next_proto_id),
2594 : : },
2595 : : {
2596 : : /*
2597 : : * This locator is used only for building supported fields mask.
2598 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2599 : : */
2600 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2601 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.fragment_offset),
2602 : : offsetof(struct rte_flow_item_ipv4, hdr.fragment_offset),
2603 : : },
2604 : : {
2605 : : EFX_MAE_FIELD_IP_TOS,
2606 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4,
2607 : : hdr.type_of_service),
2608 : : offsetof(struct rte_flow_item_ipv4, hdr.type_of_service),
2609 : : },
2610 : : {
2611 : : EFX_MAE_FIELD_IP_TTL,
2612 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.time_to_live),
2613 : : offsetof(struct rte_flow_item_ipv4, hdr.time_to_live),
2614 : : },
2615 : : };
2616 : :
2617 : : static int
2618 : 0 : sfc_mae_rule_parse_item_ipv4(const struct rte_flow_item *item,
2619 : : struct sfc_flow_parse_ctx *ctx,
2620 : : struct rte_flow_error *error)
2621 : : {
2622 : : rte_be16_t ethertype_ipv4_be = RTE_BE16(RTE_ETHER_TYPE_IPV4);
2623 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2624 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2625 : : struct rte_flow_item_ipv4 supp_mask;
2626 : : struct rte_flow_item item_dup;
2627 : 0 : const uint8_t *spec = NULL;
2628 : 0 : const uint8_t *mask = NULL;
2629 : : const uint8_t *last = NULL;
2630 : : int rc;
2631 : :
2632 : 0 : item_dup.spec = item->spec;
2633 : 0 : item_dup.mask = item->mask;
2634 : 0 : item_dup.last = item->last;
2635 : 0 : item_dup.type = item->type;
2636 : :
2637 : 0 : sfc_mae_item_build_supp_mask(flocs_ipv4, RTE_DIM(flocs_ipv4),
2638 : : &supp_mask, sizeof(supp_mask));
2639 : :
2640 : : /* We don't support IPv4 fragmentation in the outer frames. */
2641 [ # # ]: 0 : if (ctx_mae->match_spec != ctx_mae->match_spec_action)
2642 : 0 : supp_mask.hdr.fragment_offset = 0;
2643 : :
2644 [ # # ]: 0 : if (item->last != NULL) {
2645 : : last = item->last;
2646 : 0 : item_dup.last = NULL;
2647 : : }
2648 : :
2649 : 0 : rc = sfc_flow_parse_init(&item_dup,
2650 : : (const void **)&spec, (const void **)&mask,
2651 : : (const void *)&supp_mask,
2652 : : &rte_flow_item_ipv4_mask,
2653 : : sizeof(struct rte_flow_item_ipv4), error);
2654 [ # # ]: 0 : if (rc != 0)
2655 : : return rc;
2656 : :
2657 : 0 : pdata->innermost_ethertype_restriction.value = ethertype_ipv4_be;
2658 : 0 : pdata->innermost_ethertype_restriction.mask = RTE_BE16(0xffff);
2659 : :
2660 [ # # ]: 0 : if (spec != NULL) {
2661 : : const struct rte_flow_item_ipv4 *item_spec;
2662 : : const struct rte_flow_item_ipv4 *item_mask;
2663 : : const struct rte_flow_item_ipv4 *item_last;
2664 : :
2665 : : item_spec = (const struct rte_flow_item_ipv4 *)spec;
2666 : 0 : item_mask = (const struct rte_flow_item_ipv4 *)mask;
2667 [ # # ]: 0 : if (last != NULL)
2668 : : item_last = (const struct rte_flow_item_ipv4 *)last;
2669 : :
2670 : 0 : pdata->l3_next_proto_value = item_spec->hdr.next_proto_id;
2671 : 0 : pdata->l3_next_proto_mask = item_mask->hdr.next_proto_id;
2672 : 0 : pdata->l3_frag_ofst_mask = item_mask->hdr.fragment_offset;
2673 : 0 : pdata->l3_frag_ofst_value = item_spec->hdr.fragment_offset;
2674 [ # # ]: 0 : if (last != NULL)
2675 : 0 : pdata->l3_frag_ofst_last = item_last->hdr.fragment_offset;
2676 : : } else {
2677 : : return 0;
2678 : : }
2679 : :
2680 : 0 : return sfc_mae_parse_item(flocs_ipv4, RTE_DIM(flocs_ipv4), spec, mask,
2681 : : ctx_mae, error);
2682 : : }
2683 : :
2684 : : static const struct sfc_mae_field_locator flocs_ipv6[] = {
2685 : : {
2686 : : EFX_MAE_FIELD_SRC_IP6_BE,
2687 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.src_addr),
2688 : : offsetof(struct rte_flow_item_ipv6, hdr.src_addr),
2689 : : },
2690 : : {
2691 : : EFX_MAE_FIELD_DST_IP6_BE,
2692 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.dst_addr),
2693 : : offsetof(struct rte_flow_item_ipv6, hdr.dst_addr),
2694 : : },
2695 : : {
2696 : : /*
2697 : : * This locator is used only for building supported fields mask.
2698 : : * The field is handled by sfc_mae_rule_process_pattern_data().
2699 : : */
2700 : : SFC_MAE_FIELD_HANDLING_DEFERRED,
2701 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.proto),
2702 : : offsetof(struct rte_flow_item_ipv6, hdr.proto),
2703 : : },
2704 : : {
2705 : : EFX_MAE_FIELD_IP_TTL,
2706 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.hop_limits),
2707 : : offsetof(struct rte_flow_item_ipv6, hdr.hop_limits),
2708 : : },
2709 : : };
2710 : :
2711 : : static int
2712 : 0 : sfc_mae_rule_parse_item_ipv6(const struct rte_flow_item *item,
2713 : : struct sfc_flow_parse_ctx *ctx,
2714 : : struct rte_flow_error *error)
2715 : : {
2716 : : rte_be16_t ethertype_ipv6_be = RTE_BE16(RTE_ETHER_TYPE_IPV6);
2717 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2718 : 0 : const efx_mae_field_id_t *fremap = ctx_mae->field_ids_remap;
2719 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2720 : : struct rte_flow_item_ipv6 supp_mask;
2721 : 0 : const uint8_t *spec = NULL;
2722 : 0 : const uint8_t *mask = NULL;
2723 : : rte_be32_t vtc_flow_be;
2724 : : uint32_t vtc_flow;
2725 : : uint8_t tc_value;
2726 : : uint8_t tc_mask;
2727 : : int rc;
2728 : :
2729 : 0 : sfc_mae_item_build_supp_mask(flocs_ipv6, RTE_DIM(flocs_ipv6),
2730 : : &supp_mask, sizeof(supp_mask));
2731 : :
2732 : 0 : vtc_flow_be = RTE_BE32(RTE_IPV6_HDR_TC_MASK);
2733 : : memcpy(&supp_mask, &vtc_flow_be, sizeof(vtc_flow_be));
2734 : :
2735 : 0 : rc = sfc_flow_parse_init(item,
2736 : : (const void **)&spec, (const void **)&mask,
2737 : : (const void *)&supp_mask,
2738 : : &rte_flow_item_ipv6_mask,
2739 : : sizeof(struct rte_flow_item_ipv6), error);
2740 [ # # ]: 0 : if (rc != 0)
2741 : : return rc;
2742 : :
2743 : 0 : pdata->innermost_ethertype_restriction.value = ethertype_ipv6_be;
2744 : 0 : pdata->innermost_ethertype_restriction.mask = RTE_BE16(0xffff);
2745 : :
2746 [ # # ]: 0 : if (spec != NULL) {
2747 : : const struct rte_flow_item_ipv6 *item_spec;
2748 : : const struct rte_flow_item_ipv6 *item_mask;
2749 : :
2750 : : item_spec = (const struct rte_flow_item_ipv6 *)spec;
2751 : 0 : item_mask = (const struct rte_flow_item_ipv6 *)mask;
2752 : :
2753 : 0 : pdata->l3_next_proto_value = item_spec->hdr.proto;
2754 : 0 : pdata->l3_next_proto_mask = item_mask->hdr.proto;
2755 : : } else {
2756 : : return 0;
2757 : : }
2758 : :
2759 : 0 : rc = sfc_mae_parse_item(flocs_ipv6, RTE_DIM(flocs_ipv6), spec, mask,
2760 : : ctx_mae, error);
2761 [ # # ]: 0 : if (rc != 0)
2762 : : return rc;
2763 : :
2764 : 0 : memcpy(&vtc_flow_be, spec, sizeof(vtc_flow_be));
2765 [ # # ]: 0 : vtc_flow = rte_be_to_cpu_32(vtc_flow_be);
2766 : 0 : tc_value = (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> RTE_IPV6_HDR_TC_SHIFT;
2767 : :
2768 : 0 : memcpy(&vtc_flow_be, mask, sizeof(vtc_flow_be));
2769 [ # # ]: 0 : vtc_flow = rte_be_to_cpu_32(vtc_flow_be);
2770 : 0 : tc_mask = (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> RTE_IPV6_HDR_TC_SHIFT;
2771 : :
2772 : 0 : rc = efx_mae_match_spec_field_set(ctx_mae->match_spec,
2773 : : fremap[EFX_MAE_FIELD_IP_TOS],
2774 : : sizeof(tc_value), &tc_value,
2775 : : sizeof(tc_mask), &tc_mask);
2776 [ # # ]: 0 : if (rc != 0) {
2777 : 0 : return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM,
2778 : : NULL, "Failed to process item fields");
2779 : : }
2780 : :
2781 : : return 0;
2782 : : }
2783 : :
2784 : : static const struct sfc_mae_field_locator flocs_tcp[] = {
2785 : : {
2786 : : EFX_MAE_FIELD_L4_SPORT_BE,
2787 : : RTE_SIZEOF_FIELD(struct rte_flow_item_tcp, hdr.src_port),
2788 : : offsetof(struct rte_flow_item_tcp, hdr.src_port),
2789 : : },
2790 : : {
2791 : : EFX_MAE_FIELD_L4_DPORT_BE,
2792 : : RTE_SIZEOF_FIELD(struct rte_flow_item_tcp, hdr.dst_port),
2793 : : offsetof(struct rte_flow_item_tcp, hdr.dst_port),
2794 : : },
2795 : : {
2796 : : EFX_MAE_FIELD_TCP_FLAGS_BE,
2797 : : /*
2798 : : * The values have been picked intentionally since the
2799 : : * target MAE field is oversize (16 bit). This mapping
2800 : : * relies on the fact that the MAE field is big-endian.
2801 : : */
2802 : : RTE_SIZEOF_FIELD(struct rte_flow_item_tcp, hdr.data_off) +
2803 : : RTE_SIZEOF_FIELD(struct rte_flow_item_tcp, hdr.tcp_flags),
2804 : : offsetof(struct rte_flow_item_tcp, hdr.data_off),
2805 : : },
2806 : : };
2807 : :
2808 : : static int
2809 : 0 : sfc_mae_rule_parse_item_tcp(const struct rte_flow_item *item,
2810 : : struct sfc_flow_parse_ctx *ctx,
2811 : : struct rte_flow_error *error)
2812 : : {
2813 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2814 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2815 : : struct rte_flow_item_tcp supp_mask;
2816 : 0 : const uint8_t *spec = NULL;
2817 : 0 : const uint8_t *mask = NULL;
2818 : : int rc;
2819 : :
2820 : : /*
2821 : : * When encountered among outermost items, item TCP is invalid.
2822 : : * Check which match specification is being constructed now.
2823 : : */
2824 [ # # ]: 0 : if (ctx_mae->match_spec != ctx_mae->match_spec_action) {
2825 : 0 : return rte_flow_error_set(error, EINVAL,
2826 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
2827 : : "TCP in outer frame is invalid");
2828 : : }
2829 : :
2830 : 0 : sfc_mae_item_build_supp_mask(flocs_tcp, RTE_DIM(flocs_tcp),
2831 : : &supp_mask, sizeof(supp_mask));
2832 : :
2833 : 0 : rc = sfc_flow_parse_init(item,
2834 : : (const void **)&spec, (const void **)&mask,
2835 : : (const void *)&supp_mask,
2836 : : &rte_flow_item_tcp_mask,
2837 : : sizeof(struct rte_flow_item_tcp), error);
2838 [ # # ]: 0 : if (rc != 0)
2839 : : return rc;
2840 : :
2841 : 0 : pdata->l3_next_proto_restriction_value = IPPROTO_TCP;
2842 : 0 : pdata->l3_next_proto_restriction_mask = 0xff;
2843 : :
2844 [ # # ]: 0 : if (spec == NULL)
2845 : : return 0;
2846 : :
2847 : 0 : return sfc_mae_parse_item(flocs_tcp, RTE_DIM(flocs_tcp), spec, mask,
2848 : : ctx_mae, error);
2849 : : }
2850 : :
2851 : : static const struct sfc_mae_field_locator flocs_udp[] = {
2852 : : {
2853 : : EFX_MAE_FIELD_L4_SPORT_BE,
2854 : : RTE_SIZEOF_FIELD(struct rte_flow_item_udp, hdr.src_port),
2855 : : offsetof(struct rte_flow_item_udp, hdr.src_port),
2856 : : },
2857 : : {
2858 : : EFX_MAE_FIELD_L4_DPORT_BE,
2859 : : RTE_SIZEOF_FIELD(struct rte_flow_item_udp, hdr.dst_port),
2860 : : offsetof(struct rte_flow_item_udp, hdr.dst_port),
2861 : : },
2862 : : };
2863 : :
2864 : : static int
2865 : 0 : sfc_mae_rule_parse_item_udp(const struct rte_flow_item *item,
2866 : : struct sfc_flow_parse_ctx *ctx,
2867 : : struct rte_flow_error *error)
2868 : : {
2869 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2870 : : struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
2871 : : struct rte_flow_item_udp supp_mask;
2872 : 0 : const uint8_t *spec = NULL;
2873 : 0 : const uint8_t *mask = NULL;
2874 : : int rc;
2875 : :
2876 : 0 : sfc_mae_item_build_supp_mask(flocs_udp, RTE_DIM(flocs_udp),
2877 : : &supp_mask, sizeof(supp_mask));
2878 : :
2879 : 0 : rc = sfc_flow_parse_init(item,
2880 : : (const void **)&spec, (const void **)&mask,
2881 : : (const void *)&supp_mask,
2882 : : &rte_flow_item_udp_mask,
2883 : : sizeof(struct rte_flow_item_udp), error);
2884 [ # # ]: 0 : if (rc != 0)
2885 : : return rc;
2886 : :
2887 : 0 : pdata->l3_next_proto_restriction_value = IPPROTO_UDP;
2888 : 0 : pdata->l3_next_proto_restriction_mask = 0xff;
2889 : :
2890 [ # # ]: 0 : if (spec == NULL)
2891 : : return 0;
2892 : :
2893 : 0 : return sfc_mae_parse_item(flocs_udp, RTE_DIM(flocs_udp), spec, mask,
2894 : : ctx_mae, error);
2895 : : }
2896 : :
2897 : : static const struct sfc_mae_field_locator flocs_tunnel[] = {
2898 : : {
2899 : : /*
2900 : : * The size and offset values are relevant
2901 : : * for Geneve and NVGRE, too.
2902 : : */
2903 : : .size = RTE_SIZEOF_FIELD(struct rte_flow_item_vxlan, hdr.vni),
2904 : : .ofst = offsetof(struct rte_flow_item_vxlan, hdr.vni),
2905 : : },
2906 : : };
2907 : :
2908 : : /*
2909 : : * An auxiliary registry which allows using non-encap. field IDs
2910 : : * directly when building a match specification of type ACTION.
2911 : : *
2912 : : * See sfc_mae_rule_parse_pattern() and sfc_mae_rule_parse_item_tunnel().
2913 : : */
2914 : : static const efx_mae_field_id_t field_ids_no_remap[] = {
2915 : : #define FIELD_ID_NO_REMAP(_field) \
2916 : : [EFX_MAE_FIELD_##_field] = EFX_MAE_FIELD_##_field
2917 : :
2918 : : FIELD_ID_NO_REMAP(ETHER_TYPE_BE),
2919 : : FIELD_ID_NO_REMAP(ETH_SADDR_BE),
2920 : : FIELD_ID_NO_REMAP(ETH_DADDR_BE),
2921 : : FIELD_ID_NO_REMAP(VLAN0_TCI_BE),
2922 : : FIELD_ID_NO_REMAP(VLAN0_PROTO_BE),
2923 : : FIELD_ID_NO_REMAP(VLAN1_TCI_BE),
2924 : : FIELD_ID_NO_REMAP(VLAN1_PROTO_BE),
2925 : : FIELD_ID_NO_REMAP(SRC_IP4_BE),
2926 : : FIELD_ID_NO_REMAP(DST_IP4_BE),
2927 : : FIELD_ID_NO_REMAP(IP_PROTO),
2928 : : FIELD_ID_NO_REMAP(IP_TOS),
2929 : : FIELD_ID_NO_REMAP(IP_TTL),
2930 : : FIELD_ID_NO_REMAP(SRC_IP6_BE),
2931 : : FIELD_ID_NO_REMAP(DST_IP6_BE),
2932 : : FIELD_ID_NO_REMAP(L4_SPORT_BE),
2933 : : FIELD_ID_NO_REMAP(L4_DPORT_BE),
2934 : : FIELD_ID_NO_REMAP(TCP_FLAGS_BE),
2935 : : FIELD_ID_NO_REMAP(HAS_OVLAN),
2936 : : FIELD_ID_NO_REMAP(HAS_IVLAN),
2937 : : FIELD_ID_NO_REMAP(IS_IP_FRAG),
2938 : : FIELD_ID_NO_REMAP(IP_FIRST_FRAG),
2939 : :
2940 : : #undef FIELD_ID_NO_REMAP
2941 : : };
2942 : :
2943 : : /*
2944 : : * An auxiliary registry which allows using "ENC" field IDs
2945 : : * when building a match specification of type OUTER.
2946 : : *
2947 : : * See sfc_mae_rule_encap_parse_init().
2948 : : */
2949 : : static const efx_mae_field_id_t field_ids_remap_to_encap[] = {
2950 : : #define FIELD_ID_REMAP_TO_ENCAP(_field) \
2951 : : [EFX_MAE_FIELD_##_field] = EFX_MAE_FIELD_ENC_##_field
2952 : :
2953 : : FIELD_ID_REMAP_TO_ENCAP(ETHER_TYPE_BE),
2954 : : FIELD_ID_REMAP_TO_ENCAP(ETH_SADDR_BE),
2955 : : FIELD_ID_REMAP_TO_ENCAP(ETH_DADDR_BE),
2956 : : FIELD_ID_REMAP_TO_ENCAP(VLAN0_TCI_BE),
2957 : : FIELD_ID_REMAP_TO_ENCAP(VLAN0_PROTO_BE),
2958 : : FIELD_ID_REMAP_TO_ENCAP(VLAN1_TCI_BE),
2959 : : FIELD_ID_REMAP_TO_ENCAP(VLAN1_PROTO_BE),
2960 : : FIELD_ID_REMAP_TO_ENCAP(SRC_IP4_BE),
2961 : : FIELD_ID_REMAP_TO_ENCAP(DST_IP4_BE),
2962 : : FIELD_ID_REMAP_TO_ENCAP(IP_PROTO),
2963 : : FIELD_ID_REMAP_TO_ENCAP(IP_TOS),
2964 : : FIELD_ID_REMAP_TO_ENCAP(IP_TTL),
2965 : : FIELD_ID_REMAP_TO_ENCAP(SRC_IP6_BE),
2966 : : FIELD_ID_REMAP_TO_ENCAP(DST_IP6_BE),
2967 : : FIELD_ID_REMAP_TO_ENCAP(L4_SPORT_BE),
2968 : : FIELD_ID_REMAP_TO_ENCAP(L4_DPORT_BE),
2969 : : FIELD_ID_REMAP_TO_ENCAP(HAS_OVLAN),
2970 : : FIELD_ID_REMAP_TO_ENCAP(HAS_IVLAN),
2971 : :
2972 : : #undef FIELD_ID_REMAP_TO_ENCAP
2973 : : };
2974 : :
2975 : : static int
2976 : 0 : sfc_mae_rule_parse_item_tunnel(const struct rte_flow_item *item,
2977 : : struct sfc_flow_parse_ctx *ctx,
2978 : : struct rte_flow_error *error)
2979 : : {
2980 : 0 : struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
2981 : 0 : uint8_t vnet_id_v[sizeof(uint32_t)] = {0};
2982 : 0 : uint8_t vnet_id_m[sizeof(uint32_t)] = {0};
2983 : : const struct rte_flow_item_vxlan *vxp;
2984 : : uint8_t supp_mask[sizeof(uint64_t)];
2985 : 0 : const uint8_t *spec = NULL;
2986 : 0 : const uint8_t *mask = NULL;
2987 : : int rc;
2988 : :
2989 [ # # ]: 0 : if (ctx_mae->ft_rule_type == SFC_FT_RULE_SWITCH) {
2990 : : /*
2991 : : * As a workaround, pattern processing has started from
2992 : : * this (tunnel) item. No pattern data to process yet.
2993 : : */
2994 : : } else {
2995 : : /*
2996 : : * We're about to start processing inner frame items.
2997 : : * Process pattern data that has been deferred so far
2998 : : * and reset pattern data storage.
2999 : : */
3000 : 0 : rc = sfc_mae_rule_process_pattern_data(ctx_mae, error);
3001 [ # # ]: 0 : if (rc != 0)
3002 : : return rc;
3003 : : }
3004 : :
3005 : 0 : memset(&ctx_mae->pattern_data, 0, sizeof(ctx_mae->pattern_data));
3006 : :
3007 : 0 : sfc_mae_item_build_supp_mask(flocs_tunnel, RTE_DIM(flocs_tunnel),
3008 : : &supp_mask, sizeof(supp_mask));
3009 : :
3010 : : /*
3011 : : * This tunnel item was preliminarily detected by
3012 : : * sfc_mae_rule_encap_parse_init(). Default mask
3013 : : * was also picked by that helper. Use it here.
3014 : : */
3015 : 0 : rc = sfc_flow_parse_init(item,
3016 : : (const void **)&spec, (const void **)&mask,
3017 : : (const void *)&supp_mask,
3018 : : ctx_mae->tunnel_def_mask,
3019 : 0 : ctx_mae->tunnel_def_mask_size, error);
3020 [ # # ]: 0 : if (rc != 0)
3021 : : return rc;
3022 : :
3023 : : /*
3024 : : * This item and later ones comprise a
3025 : : * match specification of type ACTION.
3026 : : */
3027 : 0 : ctx_mae->match_spec = ctx_mae->match_spec_action;
3028 : :
3029 : : /* This item and later ones use non-encap. EFX MAE field IDs. */
3030 : 0 : ctx_mae->field_ids_remap = field_ids_no_remap;
3031 : :
3032 [ # # ]: 0 : if (spec == NULL)
3033 : : return 0;
3034 : :
3035 : : /*
3036 : : * Field EFX_MAE_FIELD_ENC_VNET_ID_BE is a 32-bit one.
3037 : : * Copy 24-bit VNI, which is BE, at offset 1 in it.
3038 : : * The extra byte is 0 both in the mask and in the value.
3039 : : */
3040 : : vxp = (const struct rte_flow_item_vxlan *)spec;
3041 : 0 : memcpy(vnet_id_v + 1, &vxp->hdr.vni, sizeof(vxp->hdr.vni));
3042 : :
3043 : 0 : vxp = (const struct rte_flow_item_vxlan *)mask;
3044 : 0 : memcpy(vnet_id_m + 1, &vxp->hdr.vni, sizeof(vxp->hdr.vni));
3045 : :
3046 : 0 : rc = efx_mae_match_spec_field_set(ctx_mae->match_spec,
3047 : : EFX_MAE_FIELD_ENC_VNET_ID_BE,
3048 : : sizeof(vnet_id_v), vnet_id_v,
3049 : : sizeof(vnet_id_m), vnet_id_m);
3050 [ # # ]: 0 : if (rc != 0) {
3051 : 0 : rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM,
3052 : : item, "Failed to set VXLAN VNI");
3053 : : }
3054 : :
3055 : : return rc;
3056 : : }
3057 : :
3058 : : static const struct sfc_flow_item sfc_flow_items[] = {
3059 : : {
3060 : : .type = RTE_FLOW_ITEM_TYPE_MARK,
3061 : : .name = "MARK",
3062 : : .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
3063 : : .layer = SFC_FLOW_ITEM_ANY_LAYER,
3064 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3065 : : .parse = sfc_mae_rule_parse_item_mark,
3066 : : },
3067 : : {
3068 : : .type = RTE_FLOW_ITEM_TYPE_PORT_ID,
3069 : : .name = "PORT_ID",
3070 : : /*
3071 : : * In terms of RTE flow, this item is a META one,
3072 : : * and its position in the pattern is don't care.
3073 : : */
3074 : : .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
3075 : : .layer = SFC_FLOW_ITEM_ANY_LAYER,
3076 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3077 : : .parse = sfc_mae_rule_parse_item_port_id,
3078 : : },
3079 : : {
3080 : : .type = RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR,
3081 : : .name = "PORT_REPRESENTOR",
3082 : : /*
3083 : : * In terms of RTE flow, this item is a META one,
3084 : : * and its position in the pattern is don't care.
3085 : : */
3086 : : .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
3087 : : .layer = SFC_FLOW_ITEM_ANY_LAYER,
3088 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3089 : : .parse = sfc_mae_rule_parse_item_ethdev_based,
3090 : : },
3091 : : {
3092 : : .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT,
3093 : : .name = "REPRESENTED_PORT",
3094 : : /*
3095 : : * In terms of RTE flow, this item is a META one,
3096 : : * and its position in the pattern is don't care.
3097 : : */
3098 : : .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
3099 : : .layer = SFC_FLOW_ITEM_ANY_LAYER,
3100 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3101 : : .parse = sfc_mae_rule_parse_item_ethdev_based,
3102 : : },
3103 : : {
3104 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
3105 : : .name = "ETH",
3106 : : .prev_layer = SFC_FLOW_ITEM_START_LAYER,
3107 : : .layer = SFC_FLOW_ITEM_L2,
3108 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3109 : : .parse = sfc_mae_rule_parse_item_eth,
3110 : : },
3111 : : {
3112 : : .type = RTE_FLOW_ITEM_TYPE_VLAN,
3113 : : .name = "VLAN",
3114 : : .prev_layer = SFC_FLOW_ITEM_L2,
3115 : : .layer = SFC_FLOW_ITEM_L2,
3116 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3117 : : .parse = sfc_mae_rule_parse_item_vlan,
3118 : : },
3119 : : {
3120 : : .type = RTE_FLOW_ITEM_TYPE_IPV4,
3121 : : .name = "IPV4",
3122 : : .prev_layer = SFC_FLOW_ITEM_L2,
3123 : : .layer = SFC_FLOW_ITEM_L3,
3124 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3125 : : .parse = sfc_mae_rule_parse_item_ipv4,
3126 : : },
3127 : : {
3128 : : .type = RTE_FLOW_ITEM_TYPE_IPV6,
3129 : : .name = "IPV6",
3130 : : .prev_layer = SFC_FLOW_ITEM_L2,
3131 : : .layer = SFC_FLOW_ITEM_L3,
3132 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3133 : : .parse = sfc_mae_rule_parse_item_ipv6,
3134 : : },
3135 : : {
3136 : : .type = RTE_FLOW_ITEM_TYPE_TCP,
3137 : : .name = "TCP",
3138 : : .prev_layer = SFC_FLOW_ITEM_L3,
3139 : : .layer = SFC_FLOW_ITEM_L4,
3140 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3141 : : .parse = sfc_mae_rule_parse_item_tcp,
3142 : : },
3143 : : {
3144 : : .type = RTE_FLOW_ITEM_TYPE_UDP,
3145 : : .name = "UDP",
3146 : : .prev_layer = SFC_FLOW_ITEM_L3,
3147 : : .layer = SFC_FLOW_ITEM_L4,
3148 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3149 : : .parse = sfc_mae_rule_parse_item_udp,
3150 : : },
3151 : : {
3152 : : .type = RTE_FLOW_ITEM_TYPE_VXLAN,
3153 : : .name = "VXLAN",
3154 : : .prev_layer = SFC_FLOW_ITEM_L4,
3155 : : .layer = SFC_FLOW_ITEM_START_LAYER,
3156 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3157 : : .parse = sfc_mae_rule_parse_item_tunnel,
3158 : : },
3159 : : {
3160 : : .type = RTE_FLOW_ITEM_TYPE_GENEVE,
3161 : : .name = "GENEVE",
3162 : : .prev_layer = SFC_FLOW_ITEM_L4,
3163 : : .layer = SFC_FLOW_ITEM_START_LAYER,
3164 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3165 : : .parse = sfc_mae_rule_parse_item_tunnel,
3166 : : },
3167 : : {
3168 : : .type = RTE_FLOW_ITEM_TYPE_NVGRE,
3169 : : .name = "NVGRE",
3170 : : .prev_layer = SFC_FLOW_ITEM_L3,
3171 : : .layer = SFC_FLOW_ITEM_START_LAYER,
3172 : : .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
3173 : : .parse = sfc_mae_rule_parse_item_tunnel,
3174 : : },
3175 : : };
3176 : :
3177 : : #define SFC_MAE_CT_KEY_ET 0x01 /* EtherType */
3178 : : #define SFC_MAE_CT_KEY_DA 0x02 /* IPv4/IPv6 destination address */
3179 : : #define SFC_MAE_CT_KEY_SA 0x04 /* IPv4/IPv6 source address */
3180 : : #define SFC_MAE_CT_KEY_L4 0x08 /* IPv4/IPv6 L4 protocol ID */
3181 : : #define SFC_MAE_CT_KEY_DP 0x10 /* L4 destination port */
3182 : : #define SFC_MAE_CT_KEY_SP 0x20 /* L4 source port */
3183 : :
3184 : : #define SFC_MAE_CT_KEY_FIELD_SIZE_MAX sizeof(sfc_mae_conntrack_key_t)
3185 : :
3186 : : static const struct sfc_mae_field_locator flocs_ct[] = {
3187 : : {
3188 : : EFX_MAE_FIELD_ETHER_TYPE_BE,
3189 : : RTE_SIZEOF_FIELD(sfc_mae_conntrack_key_t, ether_type_le),
3190 : : offsetof(sfc_mae_conntrack_key_t, ether_type_le),
3191 : : SFC_MAE_CT_KEY_ET,
3192 : : },
3193 : : {
3194 : : EFX_MAE_FIELD_DST_IP4_BE,
3195 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.dst_addr),
3196 : : offsetof(sfc_mae_conntrack_key_t, dst_addr_le) +
3197 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.dst_addr) -
3198 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.dst_addr),
3199 : : SFC_MAE_CT_KEY_DA,
3200 : : },
3201 : : {
3202 : : EFX_MAE_FIELD_SRC_IP4_BE,
3203 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.src_addr),
3204 : : offsetof(sfc_mae_conntrack_key_t, src_addr_le) +
3205 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.src_addr) -
3206 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv4, hdr.src_addr),
3207 : : SFC_MAE_CT_KEY_SA,
3208 : : },
3209 : : {
3210 : : EFX_MAE_FIELD_DST_IP6_BE,
3211 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.dst_addr),
3212 : : offsetof(sfc_mae_conntrack_key_t, dst_addr_le),
3213 : : SFC_MAE_CT_KEY_DA,
3214 : : },
3215 : : {
3216 : : EFX_MAE_FIELD_SRC_IP6_BE,
3217 : : RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.src_addr),
3218 : : offsetof(sfc_mae_conntrack_key_t, src_addr_le),
3219 : : SFC_MAE_CT_KEY_SA,
3220 : : },
3221 : : {
3222 : : EFX_MAE_FIELD_IP_PROTO,
3223 : : RTE_SIZEOF_FIELD(sfc_mae_conntrack_key_t, ip_proto),
3224 : : offsetof(sfc_mae_conntrack_key_t, ip_proto),
3225 : : SFC_MAE_CT_KEY_L4,
3226 : : },
3227 : : {
3228 : : EFX_MAE_FIELD_L4_DPORT_BE,
3229 : : RTE_SIZEOF_FIELD(sfc_mae_conntrack_key_t, dst_port_le),
3230 : : offsetof(sfc_mae_conntrack_key_t, dst_port_le),
3231 : : SFC_MAE_CT_KEY_DP,
3232 : : },
3233 : : {
3234 : : EFX_MAE_FIELD_L4_SPORT_BE,
3235 : : RTE_SIZEOF_FIELD(sfc_mae_conntrack_key_t, src_port_le),
3236 : : offsetof(sfc_mae_conntrack_key_t, src_port_le),
3237 : : SFC_MAE_CT_KEY_SP,
3238 : : },
3239 : : };
3240 : :
3241 : : static int
3242 : 0 : sfc_mae_rule_process_ct(struct sfc_adapter *sa, struct sfc_mae_parse_ctx *pctx,
3243 : : struct sfc_mae_action_rule_ctx *action_rule_ctx,
3244 : : struct sfc_flow_spec_mae *spec,
3245 : : struct rte_flow_error *error)
3246 : : {
3247 : : efx_mae_match_spec_t *match_spec_tmp;
3248 : : uint8_t ct_key_missing_fields =
3249 : : SFC_MAE_CT_KEY_ET | SFC_MAE_CT_KEY_DA | SFC_MAE_CT_KEY_SA |
3250 : : SFC_MAE_CT_KEY_L4 | SFC_MAE_CT_KEY_DP | SFC_MAE_CT_KEY_SP;
3251 : : unsigned int i;
3252 : : int rc;
3253 : :
3254 [ # # ]: 0 : if (pctx->ft_rule_type == SFC_FT_RULE_TUNNEL) {
3255 : : /*
3256 : : * TUNNEL rules have no network match fields that belong
3257 : : * in an action rule match specification, so nothing can
3258 : : * be possibly utilised for conntrack assistance offload.
3259 : : */
3260 : : return 0;
3261 : : }
3262 : :
3263 [ # # ]: 0 : if (!sfc_mae_conntrack_is_supported(sa))
3264 : : return 0;
3265 : :
3266 : 0 : rc = efx_mae_match_spec_clone(sa->nic, pctx->match_spec_action,
3267 : : &match_spec_tmp);
3268 [ # # ]: 0 : if (rc != 0) {
3269 : 0 : return rte_flow_error_set(error, rc,
3270 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3271 : : "AR: failed to clone the match specification");
3272 : : }
3273 : :
3274 [ # # ]: 0 : for (i = 0; i < RTE_DIM(flocs_ct); ++i) {
3275 : : const struct sfc_mae_field_locator *fl = &flocs_ct[i];
3276 : : uint8_t mask_full[SFC_MAE_CT_KEY_FIELD_SIZE_MAX];
3277 : : uint8_t mask_zero[SFC_MAE_CT_KEY_FIELD_SIZE_MAX];
3278 : : uint8_t value[SFC_MAE_CT_KEY_FIELD_SIZE_MAX];
3279 : : uint8_t mask[SFC_MAE_CT_KEY_FIELD_SIZE_MAX];
3280 : 0 : uint8_t *ct_key = (uint8_t *)&spec->ct_key;
3281 : 0 : efx_mae_field_id_t fid = fl->field_id;
3282 : : unsigned int j;
3283 : :
3284 : 0 : rc = efx_mae_match_spec_field_get(match_spec_tmp, fid,
3285 : : fl->size, value,
3286 : 0 : fl->size, mask);
3287 [ # # ]: 0 : if (rc != 0) {
3288 : 0 : return rte_flow_error_set(error, rc,
3289 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3290 : : "AR: failed to extract match field");
3291 : : }
3292 : :
3293 : : memset(mask_full, 0xff, fl->size);
3294 : :
3295 [ # # ]: 0 : if (memcmp(mask, mask_full, fl->size) != 0)
3296 : 0 : continue;
3297 : :
3298 : : memset(mask_zero, 0, fl->size);
3299 : :
3300 : 0 : rc = efx_mae_match_spec_field_set(match_spec_tmp, fid,
3301 : : fl->size, mask_zero,
3302 : : fl->size, mask_zero);
3303 [ # # ]: 0 : if (rc != 0) {
3304 : 0 : return rte_flow_error_set(error, rc,
3305 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3306 : : "AR: failed to erase match field");
3307 : : }
3308 : :
3309 [ # # ]: 0 : for (j = 0; j < fl->size; ++j) {
3310 : 0 : uint8_t *byte_dst = ct_key + fl->ofst + fl->size - 1 - j;
3311 : 0 : const uint8_t *byte_src = value + j;
3312 : :
3313 : 0 : *byte_dst = *byte_src;
3314 : : }
3315 : :
3316 : 0 : ct_key_missing_fields &= ~(fl->ct_key_field);
3317 : : }
3318 : :
3319 [ # # ]: 0 : if (ct_key_missing_fields != 0) {
3320 : 0 : efx_mae_match_spec_fini(sa->nic, match_spec_tmp);
3321 : 0 : return 0;
3322 : : }
3323 : :
3324 : 0 : efx_mae_match_spec_fini(sa->nic, pctx->match_spec_action);
3325 : 0 : pctx->match_spec_action = match_spec_tmp;
3326 : :
3327 [ # # ]: 0 : if (pctx->ft_rule_type == SFC_FT_RULE_SWITCH) {
3328 : : /*
3329 : : * A SWITCH rule re-uses the corresponding TUNNEL rule's
3330 : : * outer rule, where conntrack request should have been
3331 : : * configured already, so skip outer rule processing.
3332 : : */
3333 : 0 : goto skip_outer_rule;
3334 : : }
3335 : :
3336 [ # # ]: 0 : if (pctx->match_spec_outer == NULL) {
3337 : : const struct sfc_mae_pattern_data *pdata = &pctx->pattern_data;
3338 : : const struct sfc_mae_ethertype *et;
3339 : : struct sfc_mae *mae = &sa->mae;
3340 : :
3341 : 0 : rc = efx_mae_match_spec_init(sa->nic,
3342 : : EFX_MAE_RULE_OUTER,
3343 : 0 : mae->nb_outer_rule_prios_max - 1,
3344 : : &pctx->match_spec_outer);
3345 [ # # ]: 0 : if (rc != 0) {
3346 : 0 : return rte_flow_error_set(error, rc,
3347 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3348 : : "OR: failed to initialise the match specification");
3349 : : }
3350 : :
3351 : : /* Match on EtherType appears to be compulsory in outer rules */
3352 : :
3353 : 0 : et = &pdata->ethertypes[pdata->nb_vlan_tags];
3354 : :
3355 : 0 : rc = efx_mae_match_spec_field_set(pctx->match_spec_outer,
3356 : : EFX_MAE_FIELD_ENC_ETHER_TYPE_BE,
3357 : 0 : sizeof(et->value), (const uint8_t *)&et->value,
3358 : 0 : sizeof(et->mask), (const uint8_t *)&et->mask);
3359 [ # # ]: 0 : if (rc != 0) {
3360 : 0 : return rte_flow_error_set(error, rc,
3361 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3362 : : "OR: failed to set match on EtherType");
3363 : : }
3364 : : }
3365 : :
3366 : 0 : rc = efx_mae_outer_rule_do_ct_set(pctx->match_spec_outer);
3367 [ # # ]: 0 : if (rc != 0) {
3368 : 0 : return rte_flow_error_set(error, rc,
3369 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3370 : : "OR: failed to request CT lookup");
3371 : : }
3372 : :
3373 : 0 : skip_outer_rule:
3374 : : /* Initial/dummy CT mark value */
3375 : 0 : action_rule_ctx->ct_mark = 1;
3376 : :
3377 : 0 : return 0;
3378 : : }
3379 : :
3380 : : #undef SFC_MAE_CT_KEY_ET
3381 : : #undef SFC_MAE_CT_KEY_DA
3382 : : #undef SFC_MAE_CT_KEY_SA
3383 : : #undef SFC_MAE_CT_KEY_L4
3384 : : #undef SFC_MAE_CT_KEY_DP
3385 : : #undef SFC_MAE_CT_KEY_SP
3386 : :
3387 : : static int
3388 : 0 : sfc_mae_rule_process_outer(struct sfc_adapter *sa,
3389 : : struct sfc_mae_parse_ctx *ctx,
3390 : : struct sfc_mae_outer_rule **rulep,
3391 : : struct rte_flow_error *error)
3392 : : {
3393 : 0 : efx_mae_rule_id_t or_id = { .id = EFX_MAE_RSRC_ID_INVALID };
3394 : : int rc;
3395 : :
3396 [ # # ]: 0 : if (ctx->internal) {
3397 : : /*
3398 : : * A driver-internal flow may not comprise an outer rule,
3399 : : * but it must not match on invalid outer rule ID since
3400 : : * it must catch all missed packets, including those
3401 : : * that hit an outer rule of another flow entry but
3402 : : * do not hit a higher-priority action rule later.
3403 : : * So do not set match on outer rule ID here.
3404 : : */
3405 : : SFC_ASSERT(ctx->match_spec_outer == NULL);
3406 : 0 : *rulep = NULL;
3407 : 0 : return 0;
3408 : : }
3409 : :
3410 [ # # ]: 0 : if (ctx->match_spec_outer == NULL) {
3411 : 0 : *rulep = NULL;
3412 : 0 : goto no_or_id;
3413 : : }
3414 : :
3415 [ # # ]: 0 : if (!efx_mae_match_spec_is_valid(sa->nic, ctx->match_spec_outer)) {
3416 : 0 : return rte_flow_error_set(error, ENOTSUP,
3417 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
3418 : : "Inconsistent pattern (outer)");
3419 : : }
3420 : :
3421 : 0 : *rulep = sfc_mae_outer_rule_attach(sa, ctx->match_spec_outer,
3422 : : ctx->encap_type);
3423 [ # # ]: 0 : if (*rulep != NULL) {
3424 : 0 : efx_mae_match_spec_fini(sa->nic, ctx->match_spec_outer);
3425 : : } else {
3426 : 0 : rc = sfc_mae_outer_rule_add(sa, ctx->match_spec_outer,
3427 : : ctx->encap_type, rulep);
3428 [ # # ]: 0 : if (rc != 0) {
3429 : 0 : return rte_flow_error_set(error, rc,
3430 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
3431 : : "Failed to process the pattern");
3432 : : }
3433 : : }
3434 : :
3435 : : /* The spec has now been tracked by the outer rule entry. */
3436 : 0 : ctx->match_spec_outer = NULL;
3437 : :
3438 : 0 : or_id.id = (*rulep)->fw_rsrc.rule_id.id;
3439 : :
3440 : 0 : no_or_id:
3441 [ # # ]: 0 : switch (ctx->ft_rule_type) {
3442 : : case SFC_FT_RULE_NONE:
3443 : : break;
3444 : : case SFC_FT_RULE_TUNNEL:
3445 : : /*
3446 : : * Workaround. TUNNEL flows are not supposed to involve
3447 : : * MAE action rules, but, due to the currently limited
3448 : : * HW/FW implementation, action rules are still needed.
3449 : : * See sfc_mae_rule_parse_pattern().
3450 : : */
3451 : : break;
3452 : 0 : case SFC_FT_RULE_SWITCH:
3453 : : /*
3454 : : * Match on recirculation ID rather than
3455 : : * on the outer rule allocation handle.
3456 : : */
3457 : 0 : rc = efx_mae_match_spec_recirc_id_set(ctx->match_spec_action,
3458 : 0 : SFC_FT_CTX_ID_TO_CTX_MARK(ctx->ft_ctx->id));
3459 [ # # ]: 0 : if (rc != 0) {
3460 : 0 : return rte_flow_error_set(error, rc,
3461 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3462 : : "FT: SWITCH: AR: failed to request match on RECIRC_ID");
3463 : : }
3464 : : return 0;
3465 : 0 : default:
3466 : : SFC_ASSERT(B_FALSE);
3467 : : }
3468 : :
3469 : : /*
3470 : : * In MAE, lookup sequence comprises outer parse, outer rule lookup,
3471 : : * inner parse (when some outer rule is hit) and action rule lookup.
3472 : : * If the currently processed flow does not come with an outer rule,
3473 : : * its action rule must be available only for packets which miss in
3474 : : * outer rule table. Set OR_ID match field to 0xffffffff/0xffffffff
3475 : : * in the action rule specification; this ensures correct behaviour.
3476 : : *
3477 : : * If, however, this flow does have an outer rule, OR_ID match must
3478 : : * be set to the currently known value for that outer rule. It will
3479 : : * be either 0xffffffff or some valid ID, depending on whether this
3480 : : * outer rule is currently active (adapter state is STARTED) or not.
3481 : : */
3482 : 0 : rc = efx_mae_match_spec_outer_rule_id_set(ctx->match_spec_action,
3483 : : &or_id);
3484 [ # # ]: 0 : if (rc != 0) {
3485 : 0 : sfc_mae_outer_rule_del(sa, *rulep);
3486 : 0 : *rulep = NULL;
3487 : :
3488 : 0 : return rte_flow_error_set(error, rc,
3489 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
3490 : : "Failed to process the pattern");
3491 : : }
3492 : :
3493 : : return 0;
3494 : : }
3495 : :
3496 : : static int
3497 : 0 : sfc_mae_rule_preparse_item_mark(const struct rte_flow_item_mark *spec,
3498 : : struct sfc_mae_parse_ctx *ctx)
3499 : : {
3500 : : struct sfc_ft_ctx *ft_ctx;
3501 : : uint32_t user_mark;
3502 : :
3503 [ # # ]: 0 : if (spec == NULL) {
3504 : 0 : sfc_err(ctx->sa, "FT: SWITCH: NULL spec in item MARK");
3505 : 0 : return EINVAL;
3506 : : }
3507 : :
3508 : 0 : ft_ctx = sfc_ft_ctx_pick(ctx->sa, spec->id);
3509 [ # # ]: 0 : if (ft_ctx == NULL) {
3510 : 0 : sfc_err(ctx->sa, "FT: SWITCH: invalid context");
3511 : 0 : return EINVAL;
3512 : : }
3513 : :
3514 [ # # ]: 0 : if (ft_ctx->refcnt == 0) {
3515 : 0 : sfc_err(ctx->sa, "FT: SWITCH: inactive context (ID=%u)",
3516 : : ft_ctx->id);
3517 : 0 : return ENOENT;
3518 : : }
3519 : :
3520 : 0 : user_mark = SFC_FT_FLOW_MARK_TO_USER_MARK(spec->id);
3521 [ # # ]: 0 : if (user_mark != 0) {
3522 : 0 : sfc_err(ctx->sa, "FT: SWITCH: invalid item MARK");
3523 : 0 : return EINVAL;
3524 : : }
3525 : :
3526 : 0 : sfc_dbg(ctx->sa, "FT: SWITCH: detected");
3527 : :
3528 : 0 : ctx->ft_rule_type = SFC_FT_RULE_SWITCH;
3529 : 0 : ctx->ft_ctx = ft_ctx;
3530 : :
3531 : 0 : return 0;
3532 : : }
3533 : :
3534 : : static int
3535 : 0 : sfc_mae_rule_encap_parse_init(struct sfc_adapter *sa,
3536 : : struct sfc_mae_parse_ctx *ctx,
3537 : : struct rte_flow_error *error)
3538 : : {
3539 : 0 : const struct rte_flow_item *pattern = ctx->pattern;
3540 : : struct sfc_mae *mae = &sa->mae;
3541 : : bool request_ct = false;
3542 : : uint8_t recirc_id = 0;
3543 : : int rc;
3544 : :
3545 [ # # ]: 0 : if (pattern == NULL) {
3546 : 0 : rte_flow_error_set(error, EINVAL,
3547 : : RTE_FLOW_ERROR_TYPE_ITEM_NUM, NULL,
3548 : : "NULL pattern");
3549 : 0 : return -rte_errno;
3550 : : }
3551 : :
3552 : : for (;;) {
3553 [ # # # # : 0 : switch (pattern->type) {
# # ]
3554 : 0 : case RTE_FLOW_ITEM_TYPE_MARK:
3555 : 0 : rc = sfc_mae_rule_preparse_item_mark(pattern->spec,
3556 : : ctx);
3557 [ # # ]: 0 : if (rc != 0) {
3558 : 0 : return rte_flow_error_set(error, rc,
3559 : : RTE_FLOW_ERROR_TYPE_ITEM,
3560 : : pattern, "FT: SWITCH: invalid item MARK");
3561 : : }
3562 : 0 : ++pattern;
3563 : 0 : continue;
3564 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
3565 : 0 : ctx->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
3566 : 0 : ctx->tunnel_def_mask = &rte_flow_item_vxlan_mask;
3567 : 0 : ctx->tunnel_def_mask_size =
3568 : : sizeof(rte_flow_item_vxlan_mask);
3569 : 0 : break;
3570 : 0 : case RTE_FLOW_ITEM_TYPE_GENEVE:
3571 : 0 : ctx->encap_type = EFX_TUNNEL_PROTOCOL_GENEVE;
3572 : 0 : ctx->tunnel_def_mask = &rte_flow_item_geneve_mask;
3573 : 0 : ctx->tunnel_def_mask_size =
3574 : : sizeof(rte_flow_item_geneve_mask);
3575 : 0 : break;
3576 : 0 : case RTE_FLOW_ITEM_TYPE_NVGRE:
3577 : 0 : ctx->encap_type = EFX_TUNNEL_PROTOCOL_NVGRE;
3578 : 0 : ctx->tunnel_def_mask = &rte_flow_item_nvgre_mask;
3579 : 0 : ctx->tunnel_def_mask_size =
3580 : : sizeof(rte_flow_item_nvgre_mask);
3581 : 0 : break;
3582 : : case RTE_FLOW_ITEM_TYPE_END:
3583 : : break;
3584 : 0 : default:
3585 : 0 : ++pattern;
3586 : 0 : continue;
3587 : : };
3588 : :
3589 : : break;
3590 : : }
3591 : :
3592 [ # # # # ]: 0 : switch (ctx->ft_rule_type) {
3593 : 0 : case SFC_FT_RULE_NONE:
3594 [ # # ]: 0 : if (pattern->type == RTE_FLOW_ITEM_TYPE_END)
3595 : : return 0;
3596 : : break;
3597 : 0 : case SFC_FT_RULE_TUNNEL:
3598 [ # # ]: 0 : if (pattern->type != RTE_FLOW_ITEM_TYPE_END) {
3599 : 0 : return rte_flow_error_set(error, ENOTSUP,
3600 : : RTE_FLOW_ERROR_TYPE_ITEM,
3601 : : pattern, "FT: TUNNEL: invalid item");
3602 : : }
3603 : 0 : ctx->encap_type = ctx->ft_ctx->encap_type;
3604 : 0 : break;
3605 : 0 : case SFC_FT_RULE_SWITCH:
3606 [ # # ]: 0 : if (pattern->type == RTE_FLOW_ITEM_TYPE_END) {
3607 : 0 : return rte_flow_error_set(error, EINVAL,
3608 : : RTE_FLOW_ERROR_TYPE_ITEM,
3609 : : NULL, "FT: SWITCH: missing tunnel item");
3610 [ # # ]: 0 : } else if (ctx->encap_type != ctx->ft_ctx->encap_type) {
3611 : 0 : return rte_flow_error_set(error, EINVAL,
3612 : : RTE_FLOW_ERROR_TYPE_ITEM,
3613 : : pattern, "FT: SWITCH: tunnel type mismatch");
3614 : : }
3615 : :
3616 : : /*
3617 : : * The HW/FW hasn't got support for the use of "ENC" fields in
3618 : : * action rules (except the VNET_ID one) yet. As a workaround,
3619 : : * start parsing the pattern from the tunnel item.
3620 : : */
3621 : 0 : ctx->pattern = pattern;
3622 : 0 : break;
3623 : : default:
3624 : : SFC_ASSERT(B_FALSE);
3625 : : break;
3626 : : }
3627 : :
3628 [ # # ]: 0 : if ((mae->encap_types_supported & (1U << ctx->encap_type)) == 0) {
3629 : 0 : return rte_flow_error_set(error, ENOTSUP,
3630 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3631 : : "OR: unsupported tunnel type");
3632 : : }
3633 : :
3634 [ # # # # ]: 0 : switch (ctx->ft_rule_type) {
3635 : 0 : case SFC_FT_RULE_TUNNEL:
3636 : 0 : recirc_id = SFC_FT_CTX_ID_TO_CTX_MARK(ctx->ft_ctx->id);
3637 : :
3638 [ # # ]: 0 : if (sfc_mae_conntrack_is_supported(sa)) {
3639 : : /*
3640 : : * Request lookup in conntrack table since SWITCH rules
3641 : : * are eligible to utilise this type of assistance.
3642 : : */
3643 : : request_ct = true;
3644 : : }
3645 : : /* FALLTHROUGH */
3646 : : case SFC_FT_RULE_NONE:
3647 [ # # ]: 0 : if (ctx->priority >= mae->nb_outer_rule_prios_max) {
3648 : 0 : return rte_flow_error_set(error, ENOTSUP,
3649 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
3650 : : NULL, "OR: unsupported priority level");
3651 : : }
3652 : :
3653 : 0 : rc = efx_mae_match_spec_init(sa->nic,
3654 : : EFX_MAE_RULE_OUTER, ctx->priority,
3655 : : &ctx->match_spec_outer);
3656 [ # # ]: 0 : if (rc != 0) {
3657 : 0 : return rte_flow_error_set(error, rc,
3658 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3659 : : "OR: failed to initialise the match specification");
3660 : : }
3661 : :
3662 : : /*
3663 : : * Outermost items comprise a match
3664 : : * specification of type OUTER.
3665 : : */
3666 : 0 : ctx->match_spec = ctx->match_spec_outer;
3667 : :
3668 : : /* Outermost items use "ENC" EFX MAE field IDs. */
3669 : 0 : ctx->field_ids_remap = field_ids_remap_to_encap;
3670 : :
3671 : 0 : rc = efx_mae_outer_rule_recirc_id_set(ctx->match_spec,
3672 : : recirc_id);
3673 [ # # ]: 0 : if (rc != 0) {
3674 : 0 : return rte_flow_error_set(error, rc,
3675 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3676 : : "OR: failed to initialise RECIRC_ID");
3677 : : }
3678 : :
3679 [ # # ]: 0 : if (!request_ct)
3680 : : break;
3681 : :
3682 : 0 : rc = efx_mae_outer_rule_do_ct_set(ctx->match_spec_outer);
3683 [ # # ]: 0 : if (rc != 0) {
3684 : 0 : return rte_flow_error_set(error, rc,
3685 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3686 : : "OR: failed to request CT lookup");
3687 : : }
3688 : : break;
3689 : 0 : case SFC_FT_RULE_SWITCH:
3690 : : /* Outermost items -> "ENC" match fields in the action rule. */
3691 : 0 : ctx->field_ids_remap = field_ids_remap_to_encap;
3692 : 0 : ctx->match_spec = ctx->match_spec_action;
3693 : :
3694 : : /* No own outer rule; match on TUNNEL OR's RECIRC_ID is used. */
3695 : 0 : ctx->encap_type = EFX_TUNNEL_PROTOCOL_NONE;
3696 : 0 : break;
3697 : : default:
3698 : : SFC_ASSERT(B_FALSE);
3699 : : break;
3700 : : }
3701 : :
3702 : : return 0;
3703 : : }
3704 : :
3705 : : static void
3706 : : sfc_mae_rule_encap_parse_fini(struct sfc_adapter *sa,
3707 : : struct sfc_mae_parse_ctx *ctx)
3708 : : {
3709 : 0 : if (ctx->match_spec_outer != NULL)
3710 : 0 : efx_mae_match_spec_fini(sa->nic, ctx->match_spec_outer);
3711 : : }
3712 : :
3713 : : static int
3714 : 0 : sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
3715 : : const struct rte_flow_item pattern[],
3716 : : struct rte_flow *flow,
3717 : : struct sfc_mae_action_rule_ctx *action_rule_ctx,
3718 : : struct rte_flow_error *error)
3719 : : {
3720 [ # # # # ]: 0 : struct sfc_flow_spec_mae *spec = &flow->spec.mae;
3721 : : struct sfc_mae_outer_rule **outer_rulep;
3722 : : struct sfc_mae_parse_ctx ctx_mae;
3723 : : unsigned int priority_shift = 0;
3724 : : struct sfc_flow_parse_ctx ctx;
3725 : : int rc;
3726 : :
3727 : : memset(&ctx_mae, 0, sizeof(ctx_mae));
3728 : 0 : ctx_mae.ft_rule_type = spec->ft_rule_type;
3729 : 0 : ctx_mae.internal = flow->internal;
3730 : 0 : ctx_mae.priority = spec->priority;
3731 : 0 : ctx_mae.ft_ctx = spec->ft_ctx;
3732 : 0 : ctx_mae.sa = sa;
3733 : :
3734 : 0 : outer_rulep = &action_rule_ctx->outer_rule;
3735 : :
3736 [ # # # # ]: 0 : switch (ctx_mae.ft_rule_type) {
3737 : 0 : case SFC_FT_RULE_TUNNEL:
3738 : : /*
3739 : : * By design, this flow should be represented solely by the
3740 : : * outer rule. But the HW/FW hasn't got support for setting
3741 : : * Rx mark from RECIRC_ID on outer rule lookup yet. Neither
3742 : : * does it support outer rule counters. As a workaround, an
3743 : : * action rule of lower priority is used to do the job.
3744 : : */
3745 : : priority_shift = 1;
3746 : :
3747 : : /* FALLTHROUGH */
3748 : 0 : case SFC_FT_RULE_SWITCH:
3749 [ # # ]: 0 : if (ctx_mae.priority != 0) {
3750 : : /*
3751 : : * Because of the above workaround, deny the use
3752 : : * of priorities to TUNNEL and SWITCH rules.
3753 : : */
3754 : 0 : rc = rte_flow_error_set(error, ENOTSUP,
3755 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, NULL,
3756 : : "FT: priorities are not supported");
3757 : 0 : goto fail_priority_check;
3758 : : }
3759 : :
3760 : : /* FALLTHROUGH */
3761 : : case SFC_FT_RULE_NONE:
3762 : 0 : rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION,
3763 : : spec->priority + priority_shift,
3764 : : &ctx_mae.match_spec_action);
3765 [ # # ]: 0 : if (rc != 0) {
3766 : 0 : rc = rte_flow_error_set(error, rc,
3767 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3768 : : "AR: failed to initialise the match specification");
3769 : 0 : goto fail_init_match_spec_action;
3770 : : }
3771 : : break;
3772 : 0 : default:
3773 : 0 : rc = rte_flow_error_set(error, EINVAL,
3774 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3775 : : "FT: unexpected rule type");
3776 : 0 : goto fail_unexpected_ft_rule_type;
3777 : : }
3778 : :
3779 : : /*
3780 : : * As a preliminary setting, assume that there is no encapsulation
3781 : : * in the pattern. That is, pattern items are about to comprise a
3782 : : * match specification of type ACTION and use non-encap. field IDs.
3783 : : *
3784 : : * sfc_mae_rule_encap_parse_init() below may override this.
3785 : : */
3786 : 0 : ctx_mae.encap_type = EFX_TUNNEL_PROTOCOL_NONE;
3787 : 0 : ctx_mae.match_spec = ctx_mae.match_spec_action;
3788 : 0 : ctx_mae.field_ids_remap = field_ids_no_remap;
3789 : 0 : ctx_mae.pattern = pattern;
3790 : :
3791 : 0 : ctx.type = SFC_FLOW_PARSE_CTX_MAE;
3792 : 0 : ctx.mae = &ctx_mae;
3793 : :
3794 : 0 : rc = sfc_mae_rule_encap_parse_init(sa, &ctx_mae, error);
3795 [ # # ]: 0 : if (rc != 0)
3796 : 0 : goto fail_encap_parse_init;
3797 : :
3798 : : /*
3799 : : * sfc_mae_rule_encap_parse_init() may have detected tunnel offload
3800 : : * SWITCH rule. Remember its properties for later use.
3801 : : */
3802 : 0 : spec->ft_rule_type = ctx_mae.ft_rule_type;
3803 : 0 : spec->ft_ctx = ctx_mae.ft_ctx;
3804 : :
3805 : 0 : rc = sfc_flow_parse_pattern(sa, sfc_flow_items, RTE_DIM(sfc_flow_items),
3806 : : ctx_mae.pattern, &ctx, error);
3807 [ # # ]: 0 : if (rc != 0)
3808 : 0 : goto fail_parse_pattern;
3809 : :
3810 : 0 : rc = sfc_mae_rule_process_pattern_data(&ctx_mae, error);
3811 [ # # ]: 0 : if (rc != 0)
3812 : 0 : goto fail_process_pattern_data;
3813 : :
3814 : 0 : rc = sfc_mae_rule_process_ct(sa, &ctx_mae, action_rule_ctx,
3815 : : spec, error);
3816 [ # # ]: 0 : if (rc != 0)
3817 : 0 : goto fail_process_ct;
3818 : :
3819 : 0 : rc = sfc_mae_rule_process_outer(sa, &ctx_mae, outer_rulep, error);
3820 [ # # ]: 0 : if (rc != 0)
3821 : 0 : goto fail_process_outer;
3822 : :
3823 [ # # # # ]: 0 : if (ctx_mae.match_spec_action != NULL &&
3824 : 0 : !efx_mae_match_spec_is_valid(sa->nic, ctx_mae.match_spec_action)) {
3825 : 0 : rc = rte_flow_error_set(error, ENOTSUP,
3826 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
3827 : : "Inconsistent pattern");
3828 : 0 : goto fail_validate_match_spec_action;
3829 : : }
3830 : :
3831 : 0 : action_rule_ctx->match_spec = ctx_mae.match_spec_action;
3832 : :
3833 : 0 : return 0;
3834 : :
3835 : : fail_validate_match_spec_action:
3836 : 0 : fail_process_outer:
3837 : 0 : fail_process_ct:
3838 : 0 : fail_process_pattern_data:
3839 [ # # ]: 0 : fail_parse_pattern:
3840 : : sfc_mae_rule_encap_parse_fini(sa, &ctx_mae);
3841 : :
3842 : 0 : fail_encap_parse_init:
3843 [ # # ]: 0 : if (ctx_mae.match_spec_action != NULL)
3844 : 0 : efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action);
3845 : :
3846 : 0 : fail_unexpected_ft_rule_type:
3847 : : fail_init_match_spec_action:
3848 : : fail_priority_check:
3849 : : return rc;
3850 : : }
3851 : :
3852 : : static int
3853 : 0 : sfc_mae_rule_parse_action_set_mac(struct sfc_adapter *sa,
3854 : : enum sfc_mae_mac_addr_type type,
3855 : : const struct rte_flow_action_set_mac *conf,
3856 : : struct sfc_mae_aset_ctx *ctx,
3857 : : struct rte_flow_error *error)
3858 : : {
3859 : : struct sfc_mae_mac_addr **mac_addrp;
3860 : : int rc;
3861 : :
3862 [ # # ]: 0 : if (conf == NULL) {
3863 : 0 : return rte_flow_error_set(error, EINVAL,
3864 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
3865 : : "the MAC address entry definition is NULL");
3866 : : }
3867 : :
3868 [ # # # ]: 0 : switch (type) {
3869 : 0 : case SFC_MAE_MAC_ADDR_DST:
3870 : 0 : rc = efx_mae_action_set_populate_set_dst_mac(ctx->spec);
3871 : 0 : mac_addrp = &ctx->dst_mac;
3872 : 0 : break;
3873 : 0 : case SFC_MAE_MAC_ADDR_SRC:
3874 : 0 : rc = efx_mae_action_set_populate_set_src_mac(ctx->spec);
3875 : 0 : mac_addrp = &ctx->src_mac;
3876 : 0 : break;
3877 : : default:
3878 : : rc = EINVAL;
3879 : : break;
3880 : : }
3881 : :
3882 [ # # ]: 0 : if (rc != 0)
3883 : 0 : goto error;
3884 : :
3885 : 0 : *mac_addrp = sfc_mae_mac_addr_attach(sa, conf->mac_addr);
3886 [ # # ]: 0 : if (*mac_addrp != NULL)
3887 : : return 0;
3888 : :
3889 : 0 : rc = sfc_mae_mac_addr_add(sa, conf->mac_addr, mac_addrp);
3890 [ # # ]: 0 : if (rc != 0)
3891 : 0 : goto error;
3892 : :
3893 : : return 0;
3894 : :
3895 : 0 : error:
3896 : 0 : return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION,
3897 : : NULL, "failed to request set MAC action");
3898 : : }
3899 : :
3900 : : /*
3901 : : * An action supported by MAE may correspond to a bundle of RTE flow actions,
3902 : : * in example, VLAN_PUSH = OF_PUSH_VLAN + OF_VLAN_SET_VID + OF_VLAN_SET_PCP.
3903 : : * That is, related RTE flow actions need to be tracked as parts of a whole
3904 : : * so that they can be combined into a single action and submitted to MAE
3905 : : * representation of a given rule's action set.
3906 : : *
3907 : : * Each RTE flow action provided by an application gets classified as
3908 : : * one belonging to some bundle type. If an action is not supposed to
3909 : : * belong to any bundle, or if this action is END, it is described as
3910 : : * one belonging to a dummy bundle of type EMPTY.
3911 : : *
3912 : : * A currently tracked bundle will be submitted if a repeating
3913 : : * action or an action of different bundle type follows.
3914 : : */
3915 : :
3916 : : enum sfc_mae_actions_bundle_type {
3917 : : SFC_MAE_ACTIONS_BUNDLE_EMPTY = 0,
3918 : : SFC_MAE_ACTIONS_BUNDLE_VLAN_PUSH,
3919 : : SFC_MAE_ACTIONS_BUNDLE_NAT_DST,
3920 : : SFC_MAE_ACTIONS_BUNDLE_NAT_SRC,
3921 : : };
3922 : :
3923 : : struct sfc_mae_actions_bundle {
3924 : : enum sfc_mae_actions_bundle_type type;
3925 : :
3926 : : /* Indicates actions already tracked by the current bundle */
3927 : : uint64_t actions_mask;
3928 : :
3929 : : /* Parameters used by SFC_MAE_ACTIONS_BUNDLE_VLAN_PUSH */
3930 : : rte_be16_t vlan_push_tpid;
3931 : : rte_be16_t vlan_push_tci;
3932 : : };
3933 : :
3934 : : /*
3935 : : * Combine configuration of RTE flow actions tracked by the bundle into a
3936 : : * single action and submit the result to MAE action set specification.
3937 : : * Do nothing in the case of dummy action bundle.
3938 : : */
3939 : : static int
3940 : 0 : sfc_mae_actions_bundle_submit(const struct sfc_mae_actions_bundle *bundle,
3941 : : struct sfc_flow_spec_mae *flow_spec,
3942 : : bool ct, efx_mae_actions_t *spec)
3943 : : {
3944 : : int rc = 0;
3945 : :
3946 [ # # # # ]: 0 : switch (bundle->type) {
3947 : : case SFC_MAE_ACTIONS_BUNDLE_EMPTY:
3948 : : break;
3949 : 0 : case SFC_MAE_ACTIONS_BUNDLE_VLAN_PUSH:
3950 : 0 : rc = efx_mae_action_set_populate_vlan_push(
3951 : 0 : spec, bundle->vlan_push_tpid, bundle->vlan_push_tci);
3952 : 0 : break;
3953 : 0 : case SFC_MAE_ACTIONS_BUNDLE_NAT_DST:
3954 : 0 : flow_spec->ct_resp.nat.dir_is_dst = true;
3955 : : /* FALLTHROUGH */
3956 : 0 : case SFC_MAE_ACTIONS_BUNDLE_NAT_SRC:
3957 [ # # # # ]: 0 : if (ct && flow_spec->ct_resp.nat.ip_le != 0 &&
3958 [ # # ]: 0 : flow_spec->ct_resp.nat.port_le != 0)
3959 : 0 : rc = efx_mae_action_set_populate_nat(spec);
3960 : : else
3961 : : rc = EINVAL;
3962 : : break;
3963 : : default:
3964 : : SFC_ASSERT(B_FALSE);
3965 : : break;
3966 : : }
3967 : :
3968 : 0 : return rc;
3969 : : }
3970 : :
3971 : : /*
3972 : : * Given the type of the next RTE flow action in the line, decide
3973 : : * whether a new bundle is about to start, and, if this is the case,
3974 : : * submit and reset the current bundle.
3975 : : */
3976 : : static int
3977 : 0 : sfc_mae_actions_bundle_sync(const struct rte_flow_action *action,
3978 : : struct sfc_mae_actions_bundle *bundle,
3979 : : struct sfc_flow_spec_mae *flow_spec,
3980 : : efx_mae_actions_t *spec, bool ct,
3981 : : struct rte_flow_error *error)
3982 : : {
3983 : : enum sfc_mae_actions_bundle_type bundle_type_new;
3984 : : int rc;
3985 : :
3986 [ # # # # ]: 0 : switch (action->type) {
3987 : : case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
3988 : : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
3989 : : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
3990 : : bundle_type_new = SFC_MAE_ACTIONS_BUNDLE_VLAN_PUSH;
3991 : : break;
3992 : 0 : case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
3993 : : case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
3994 : : bundle_type_new = SFC_MAE_ACTIONS_BUNDLE_NAT_DST;
3995 : 0 : break;
3996 : 0 : case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
3997 : : case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
3998 : : bundle_type_new = SFC_MAE_ACTIONS_BUNDLE_NAT_SRC;
3999 : 0 : break;
4000 : 0 : default:
4001 : : /*
4002 : : * Self-sufficient actions, including END, are handled in this
4003 : : * case. No checks for unsupported actions are needed here
4004 : : * because parsing doesn't occur at this point.
4005 : : */
4006 : : bundle_type_new = SFC_MAE_ACTIONS_BUNDLE_EMPTY;
4007 : 0 : break;
4008 : : }
4009 : :
4010 [ # # ]: 0 : if (bundle_type_new != bundle->type ||
4011 [ # # ]: 0 : (bundle->actions_mask & (1ULL << action->type)) != 0) {
4012 : 0 : rc = sfc_mae_actions_bundle_submit(bundle, flow_spec, ct, spec);
4013 [ # # ]: 0 : if (rc != 0)
4014 : 0 : goto fail_submit;
4015 : :
4016 : : memset(bundle, 0, sizeof(*bundle));
4017 : : }
4018 : :
4019 : 0 : bundle->type = bundle_type_new;
4020 : :
4021 : 0 : return 0;
4022 : :
4023 : : fail_submit:
4024 : 0 : return rte_flow_error_set(error, rc,
4025 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4026 : : "Failed to request the (group of) action(s)");
4027 : : }
4028 : :
4029 : : static void
4030 : : sfc_mae_rule_parse_action_nat_addr(const struct rte_flow_action_set_ipv4 *conf,
4031 : : uint32_t *nat_addr_le)
4032 : : {
4033 : 0 : *nat_addr_le = rte_bswap32(conf->ipv4_addr);
4034 : 0 : }
4035 : :
4036 : : static void
4037 : : sfc_mae_rule_parse_action_nat_port(const struct rte_flow_action_set_tp *conf,
4038 : : uint16_t *nat_port_le)
4039 : : {
4040 : 0 : *nat_port_le = rte_bswap16(conf->port);
4041 : 0 : }
4042 : :
4043 : : static void
4044 : : sfc_mae_rule_parse_action_of_push_vlan(
4045 : : const struct rte_flow_action_of_push_vlan *conf,
4046 : : struct sfc_mae_actions_bundle *bundle)
4047 : : {
4048 : 0 : bundle->vlan_push_tpid = conf->ethertype;
4049 : 0 : }
4050 : :
4051 : : static void
4052 : : sfc_mae_rule_parse_action_of_set_vlan_vid(
4053 : : const struct rte_flow_action_of_set_vlan_vid *conf,
4054 : : struct sfc_mae_actions_bundle *bundle)
4055 : : {
4056 : 0 : bundle->vlan_push_tci |= (conf->vlan_vid &
4057 : : rte_cpu_to_be_16(RTE_LEN2MASK(12, uint16_t)));
4058 : 0 : }
4059 : :
4060 : : static void
4061 : : sfc_mae_rule_parse_action_of_set_vlan_pcp(
4062 : : const struct rte_flow_action_of_set_vlan_pcp *conf,
4063 : : struct sfc_mae_actions_bundle *bundle)
4064 : : {
4065 : 0 : uint16_t vlan_tci_pcp = (uint16_t)(conf->vlan_pcp &
4066 : 0 : RTE_LEN2MASK(3, uint8_t)) << 13;
4067 : :
4068 : 0 : bundle->vlan_push_tci |= rte_cpu_to_be_16(vlan_tci_pcp);
4069 : 0 : }
4070 : :
4071 : : struct sfc_mae_parsed_item {
4072 : : const struct rte_flow_item *item;
4073 : : size_t proto_header_ofst;
4074 : : size_t proto_header_size;
4075 : : };
4076 : :
4077 : : /*
4078 : : * For each 16-bit word of the given header, override
4079 : : * bits enforced by the corresponding 16-bit mask.
4080 : : */
4081 : : static void
4082 : 0 : sfc_mae_header_force_item_masks(uint8_t *header_buf,
4083 : : const struct sfc_mae_parsed_item *parsed_items,
4084 : : unsigned int nb_parsed_items)
4085 : : {
4086 : : unsigned int item_idx;
4087 : :
4088 [ # # ]: 0 : for (item_idx = 0; item_idx < nb_parsed_items; ++item_idx) {
4089 : : const struct sfc_mae_parsed_item *parsed_item;
4090 : : const struct rte_flow_item *item;
4091 : : size_t proto_header_size;
4092 : : size_t ofst;
4093 : :
4094 : 0 : parsed_item = &parsed_items[item_idx];
4095 : 0 : proto_header_size = parsed_item->proto_header_size;
4096 : 0 : item = parsed_item->item;
4097 : :
4098 [ # # ]: 0 : for (ofst = 0; ofst < proto_header_size;
4099 : 0 : ofst += sizeof(rte_be16_t)) {
4100 : 0 : rte_be16_t *wp = RTE_PTR_ADD(header_buf, ofst);
4101 : : const rte_be16_t *w_maskp;
4102 : : const rte_be16_t *w_specp;
4103 : :
4104 : 0 : w_maskp = RTE_PTR_ADD(item->mask, ofst);
4105 : 0 : w_specp = RTE_PTR_ADD(item->spec, ofst);
4106 : :
4107 : 0 : *wp &= ~(*w_maskp);
4108 : 0 : *wp |= (*w_specp & *w_maskp);
4109 : : }
4110 : :
4111 : 0 : header_buf += proto_header_size;
4112 : : }
4113 : 0 : }
4114 : :
4115 : : #define SFC_IPV4_TTL_DEF 0x40
4116 : : #define SFC_IPV6_VTC_FLOW_DEF 0x60000000
4117 : : #define SFC_IPV6_HOP_LIMITS_DEF 0xff
4118 : : #define SFC_VXLAN_FLAGS_DEF 0x08000000
4119 : :
4120 : : static int
4121 : 0 : sfc_mae_rule_parse_action_vxlan_encap(
4122 : : struct sfc_mae *mae,
4123 : : const struct rte_flow_action_vxlan_encap *conf,
4124 : : efx_mae_actions_t *spec,
4125 : : struct rte_flow_error *error)
4126 : 0 : {
4127 : : struct sfc_mae_bounce_eh *bounce_eh = &mae->bounce_eh;
4128 : 0 : struct rte_flow_item *pattern = conf->definition;
4129 : 0 : uint8_t *buf = bounce_eh->buf;
4130 : :
4131 : : /* This array will keep track of non-VOID pattern items. */
4132 : : struct sfc_mae_parsed_item parsed_items[1 /* Ethernet */ +
4133 : : 2 /* VLAN tags */ +
4134 : : 1 /* IPv4 or IPv6 */ +
4135 : : 1 /* UDP */ +
4136 : : 1 /* VXLAN */];
4137 : : unsigned int nb_parsed_items = 0;
4138 : :
4139 : : size_t eth_ethertype_ofst = offsetof(struct rte_ether_hdr, ether_type);
4140 : 0 : uint8_t dummy_buf[RTE_MAX(sizeof(struct rte_ipv4_hdr),
4141 : : sizeof(struct rte_ipv6_hdr))];
4142 : : struct rte_ipv4_hdr *ipv4 = (void *)dummy_buf;
4143 : : struct rte_ipv6_hdr *ipv6 = (void *)dummy_buf;
4144 : : struct rte_vxlan_hdr *vxlan = NULL;
4145 : : struct rte_udp_hdr *udp = NULL;
4146 : : unsigned int nb_vlan_tags = 0;
4147 : : size_t next_proto_ofst = 0;
4148 : : size_t ethertype_ofst = 0;
4149 : : uint64_t exp_items;
4150 : : int rc;
4151 : :
4152 [ # # ]: 0 : if (pattern == NULL) {
4153 : 0 : return rte_flow_error_set(error, EINVAL,
4154 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4155 : : "The encap. header definition is NULL");
4156 : : }
4157 : :
4158 : 0 : bounce_eh->type = EFX_TUNNEL_PROTOCOL_VXLAN;
4159 : 0 : bounce_eh->size = 0;
4160 : :
4161 : : /*
4162 : : * Process pattern items and remember non-VOID ones.
4163 : : * Defer applying masks until after the complete header
4164 : : * has been built from the pattern items.
4165 : : */
4166 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_ETH);
4167 : :
4168 [ # # ]: 0 : for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; ++pattern) {
4169 : : struct sfc_mae_parsed_item *parsed_item;
4170 : 0 : const uint64_t exp_items_extra_vlan[] = {
4171 : : RTE_BIT64(RTE_FLOW_ITEM_TYPE_VLAN), 0
4172 : : };
4173 : : size_t proto_header_size;
4174 : : rte_be16_t *ethertypep;
4175 : : uint8_t *next_protop;
4176 : : uint8_t *buf_cur;
4177 : :
4178 [ # # ]: 0 : if (pattern->spec == NULL) {
4179 : 0 : return rte_flow_error_set(error, EINVAL,
4180 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4181 : : "NULL item spec in the encap. header");
4182 : : }
4183 : :
4184 [ # # ]: 0 : if (pattern->mask == NULL) {
4185 : 0 : return rte_flow_error_set(error, EINVAL,
4186 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4187 : : "NULL item mask in the encap. header");
4188 : : }
4189 : :
4190 [ # # ]: 0 : if (pattern->last != NULL) {
4191 : : /* This is not a match pattern, so disallow range. */
4192 : 0 : return rte_flow_error_set(error, EINVAL,
4193 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4194 : : "Range item in the encap. header");
4195 : : }
4196 : :
4197 [ # # ]: 0 : if (pattern->type == RTE_FLOW_ITEM_TYPE_VOID) {
4198 : : /* Handle VOID separately, for clarity. */
4199 : 0 : continue;
4200 : : }
4201 : :
4202 [ # # ]: 0 : if ((exp_items & RTE_BIT64(pattern->type)) == 0) {
4203 : 0 : return rte_flow_error_set(error, ENOTSUP,
4204 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4205 : : "Unexpected item in the encap. header");
4206 : : }
4207 : :
4208 : : parsed_item = &parsed_items[nb_parsed_items];
4209 : 0 : buf_cur = buf + bounce_eh->size;
4210 : :
4211 [ # # # # : 0 : switch (pattern->type) {
# # # ]
4212 : : case RTE_FLOW_ITEM_TYPE_ETH:
4213 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_ETH,
4214 : : exp_items);
4215 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_eth,
4216 : : hdr) != 0);
4217 : :
4218 : : proto_header_size = sizeof(struct rte_ether_hdr);
4219 : :
4220 : : ethertype_ofst = eth_ethertype_ofst;
4221 : :
4222 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_VLAN) |
4223 : : RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV4) |
4224 : : RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV6);
4225 : : break;
4226 : 0 : case RTE_FLOW_ITEM_TYPE_VLAN:
4227 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_VLAN,
4228 : : exp_items);
4229 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_vlan,
4230 : : hdr) != 0);
4231 : :
4232 : : proto_header_size = sizeof(struct rte_vlan_hdr);
4233 : :
4234 : 0 : ethertypep = RTE_PTR_ADD(buf, eth_ethertype_ofst);
4235 : 0 : *ethertypep = RTE_BE16(RTE_ETHER_TYPE_QINQ);
4236 : :
4237 : 0 : ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
4238 : 0 : *ethertypep = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4239 : :
4240 : 0 : ethertype_ofst =
4241 : : bounce_eh->size +
4242 : : offsetof(struct rte_vlan_hdr, eth_proto);
4243 : :
4244 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV4) |
4245 : : RTE_BIT64(RTE_FLOW_ITEM_TYPE_IPV6);
4246 : 0 : exp_items |= exp_items_extra_vlan[nb_vlan_tags];
4247 : :
4248 : 0 : ++nb_vlan_tags;
4249 : 0 : break;
4250 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
4251 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_IPV4,
4252 : : exp_items);
4253 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_ipv4,
4254 : : hdr) != 0);
4255 : :
4256 : : proto_header_size = sizeof(struct rte_ipv4_hdr);
4257 : :
4258 : 0 : ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
4259 : 0 : *ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4260 : :
4261 : 0 : next_proto_ofst =
4262 : : bounce_eh->size +
4263 : : offsetof(struct rte_ipv4_hdr, next_proto_id);
4264 : :
4265 : : ipv4 = (struct rte_ipv4_hdr *)buf_cur;
4266 : :
4267 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_UDP);
4268 : 0 : break;
4269 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
4270 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_IPV6,
4271 : : exp_items);
4272 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_ipv6,
4273 : : hdr) != 0);
4274 : :
4275 : : proto_header_size = sizeof(struct rte_ipv6_hdr);
4276 : :
4277 : 0 : ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
4278 : 0 : *ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4279 : :
4280 : 0 : next_proto_ofst = bounce_eh->size +
4281 : : offsetof(struct rte_ipv6_hdr, proto);
4282 : :
4283 : : ipv6 = (struct rte_ipv6_hdr *)buf_cur;
4284 : :
4285 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_UDP);
4286 : 0 : break;
4287 : 0 : case RTE_FLOW_ITEM_TYPE_UDP:
4288 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_UDP,
4289 : : exp_items);
4290 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_udp,
4291 : : hdr) != 0);
4292 : :
4293 : : proto_header_size = sizeof(struct rte_udp_hdr);
4294 : :
4295 : 0 : next_protop = RTE_PTR_ADD(buf, next_proto_ofst);
4296 : 0 : *next_protop = IPPROTO_UDP;
4297 : :
4298 : : udp = (struct rte_udp_hdr *)buf_cur;
4299 : :
4300 : : exp_items = RTE_BIT64(RTE_FLOW_ITEM_TYPE_VXLAN);
4301 : 0 : break;
4302 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
4303 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ITEM_TYPE_VXLAN,
4304 : : exp_items);
4305 : : RTE_BUILD_BUG_ON(offsetof(struct rte_flow_item_vxlan,
4306 : : hdr) != 0);
4307 : :
4308 : : proto_header_size = sizeof(struct rte_vxlan_hdr);
4309 : :
4310 : : vxlan = (struct rte_vxlan_hdr *)buf_cur;
4311 : :
4312 : 0 : udp->dst_port = RTE_BE16(RTE_VXLAN_DEFAULT_PORT);
4313 : 0 : udp->dgram_len = RTE_BE16(sizeof(*udp) +
4314 : : sizeof(*vxlan));
4315 : 0 : udp->dgram_cksum = 0;
4316 : :
4317 : : exp_items = 0;
4318 : 0 : break;
4319 : 0 : default:
4320 : 0 : return rte_flow_error_set(error, ENOTSUP,
4321 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4322 : : "Unknown item in the encap. header");
4323 : : }
4324 : :
4325 [ # # ]: 0 : if (bounce_eh->size + proto_header_size > bounce_eh->buf_size) {
4326 : 0 : return rte_flow_error_set(error, E2BIG,
4327 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4328 : : "The encap. header is too big");
4329 : : }
4330 : :
4331 : : if ((proto_header_size & 1) != 0) {
4332 : : return rte_flow_error_set(error, EINVAL,
4333 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4334 : : "Odd layer size in the encap. header");
4335 : : }
4336 : :
4337 [ # # ]: 0 : rte_memcpy(buf_cur, pattern->spec, proto_header_size);
4338 : 0 : bounce_eh->size += proto_header_size;
4339 : :
4340 : 0 : parsed_item->item = pattern;
4341 : 0 : parsed_item->proto_header_size = proto_header_size;
4342 : 0 : ++nb_parsed_items;
4343 : : }
4344 : :
4345 [ # # ]: 0 : if (exp_items != 0) {
4346 : : /* Parsing item VXLAN would have reset exp_items to 0. */
4347 : 0 : return rte_flow_error_set(error, ENOTSUP,
4348 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
4349 : : "No item VXLAN in the encap. header");
4350 : : }
4351 : :
4352 : : /* One of the pointers (ipv4, ipv6) refers to a dummy area. */
4353 : 0 : ipv4->version_ihl = RTE_IPV4_VHL_DEF;
4354 : 0 : ipv4->time_to_live = SFC_IPV4_TTL_DEF;
4355 : 0 : ipv4->total_length = RTE_BE16(sizeof(*ipv4) + sizeof(*udp) +
4356 : : sizeof(*vxlan));
4357 : : /* The HW cannot compute this checksum. */
4358 : 0 : ipv4->hdr_checksum = 0;
4359 : 0 : ipv4->hdr_checksum = rte_ipv4_cksum(ipv4);
4360 : :
4361 : 0 : ipv6->vtc_flow = RTE_BE32(SFC_IPV6_VTC_FLOW_DEF);
4362 : 0 : ipv6->hop_limits = SFC_IPV6_HOP_LIMITS_DEF;
4363 : 0 : ipv6->payload_len = udp->dgram_len;
4364 : :
4365 : 0 : vxlan->vx_flags = RTE_BE32(SFC_VXLAN_FLAGS_DEF);
4366 : :
4367 : : /* Take care of the masks. */
4368 : 0 : sfc_mae_header_force_item_masks(buf, parsed_items, nb_parsed_items);
4369 : :
4370 [ # # ]: 0 : if (spec == NULL)
4371 : : return 0;
4372 : :
4373 : 0 : rc = efx_mae_action_set_populate_encap(spec);
4374 [ # # ]: 0 : if (rc != 0) {
4375 : 0 : rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION,
4376 : : NULL, "failed to request action ENCAP");
4377 : : }
4378 : :
4379 : : return rc;
4380 : : }
4381 : :
4382 : : static int
4383 : 0 : sfc_mae_rule_parse_action_mark(struct sfc_adapter *sa,
4384 : : const struct rte_flow_action_mark *conf,
4385 : : const struct sfc_flow_spec_mae *spec_mae,
4386 : : efx_mae_actions_t *spec)
4387 : : {
4388 : : int rc;
4389 : :
4390 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL) {
4391 : : /* Workaround. See sfc_flow_parse_rte_to_mae() */
4392 [ # # ]: 0 : } else if (conf->id > SFC_FT_USER_MARK_MASK) {
4393 : 0 : sfc_err(sa, "the mark value is too large");
4394 : 0 : return EINVAL;
4395 : : }
4396 : :
4397 : 0 : rc = efx_mae_action_set_populate_mark(spec, conf->id);
4398 [ # # ]: 0 : if (rc != 0)
4399 : 0 : sfc_err(sa, "failed to request action MARK: %s", strerror(rc));
4400 : :
4401 : : return rc;
4402 : : }
4403 : :
4404 : : static int
4405 : 0 : sfc_mae_rule_parse_action_count(struct sfc_adapter *sa,
4406 : : const struct rte_flow_action_count *conf,
4407 : : efx_counter_type_t mae_counter_type,
4408 : : struct sfc_mae_counter **counterp,
4409 : : efx_mae_actions_t *spec)
4410 : : {
4411 : 0 : struct sfc_mae_counter counter_tmp = {};
4412 : : int rc;
4413 : :
4414 [ # # ]: 0 : if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_INITIALIZED) == 0) {
4415 : 0 : sfc_err(sa,
4416 : : "counter queue is not configured for COUNT action");
4417 : : rc = EINVAL;
4418 : 0 : goto fail_counter_queue_uninit;
4419 : : }
4420 : :
4421 [ # # ]: 0 : if (sfc_get_service_lcore(SOCKET_ID_ANY) == RTE_MAX_LCORE) {
4422 : : rc = EINVAL;
4423 : 0 : goto fail_no_service_core;
4424 : : }
4425 : :
4426 [ # # ]: 0 : if (*counterp != NULL) {
4427 : 0 : sfc_err(sa, "cannot request more than 1 action COUNT per flow");
4428 : : rc = EINVAL;
4429 : 0 : goto fail_more_than_one;
4430 : : }
4431 : :
4432 [ # # ]: 0 : if (spec != NULL) {
4433 : 0 : rc = efx_mae_action_set_populate_count(spec);
4434 [ # # ]: 0 : if (rc != 0) {
4435 : 0 : sfc_err(sa,
4436 : : "failed to populate counters in MAE action set: %s",
4437 : : rte_strerror(rc));
4438 : 0 : goto fail_populate_count;
4439 : : }
4440 : : }
4441 : :
4442 [ # # ]: 0 : if (conf != NULL) {
4443 : 0 : counter_tmp.rte_id_valid = true;
4444 : 0 : counter_tmp.rte_id = conf->id;
4445 : : }
4446 : :
4447 : 0 : counter_tmp.type = mae_counter_type;
4448 : :
4449 : 0 : return sfc_mae_counter_add(sa, &counter_tmp, counterp);
4450 : :
4451 : : return 0;
4452 : :
4453 : : fail_populate_count:
4454 : : fail_more_than_one:
4455 : : fail_no_service_core:
4456 : : fail_counter_queue_uninit:
4457 : :
4458 : : return rc;
4459 : : }
4460 : :
4461 : : static int
4462 : 0 : sfc_mae_rule_parse_action_indirect(struct sfc_adapter *sa, bool replayable_only,
4463 : : const struct rte_flow_action_handle *handle,
4464 : : enum sfc_ft_rule_type ft_rule_type,
4465 : : struct sfc_mae_aset_ctx *ctx,
4466 : : struct rte_flow_error *error)
4467 : : {
4468 : : struct rte_flow_action_handle *entry;
4469 : : int rc;
4470 : :
4471 [ # # ]: 0 : TAILQ_FOREACH(entry, &sa->flow_indir_actions, entries) {
4472 [ # # ]: 0 : if (entry == handle) {
4473 : : bool replayable = false;
4474 : :
4475 : 0 : sfc_dbg(sa, "attaching to indirect_action=%p", entry);
4476 : :
4477 [ # # ]: 0 : switch (entry->type) {
4478 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
4479 : : replayable = true;
4480 : 0 : break;
4481 : : default:
4482 : : break;
4483 : : }
4484 : :
4485 [ # # ]: 0 : if (replayable_only && !replayable) {
4486 : 0 : return rte_flow_error_set(error, EINVAL,
4487 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4488 : : "the indirect action handle cannot be used");
4489 : : }
4490 : :
4491 [ # # # ]: 0 : switch (entry->type) {
4492 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
4493 [ # # ]: 0 : if (ctx->encap_header != NULL) {
4494 : 0 : return rte_flow_error_set(error, EINVAL,
4495 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4496 : : "cannot have multiple actions VXLAN_ENCAP in one flow");
4497 : : }
4498 : :
4499 : 0 : rc = efx_mae_action_set_populate_encap(ctx->spec);
4500 [ # # ]: 0 : if (rc != 0) {
4501 : 0 : return rte_flow_error_set(error, rc,
4502 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4503 : : "failed to add ENCAP to MAE action set");
4504 : : }
4505 : :
4506 : 0 : ctx->encap_header = entry->encap_header;
4507 : 0 : ++(ctx->encap_header->refcnt);
4508 : 0 : break;
4509 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
4510 [ # # # # ]: 0 : if (!replayable_only && ctx->counter != NULL) {
4511 : : /*
4512 : : * Signal the caller to "replay" the action
4513 : : * set context and re-invoke this function.
4514 : : */
4515 : : return EEXIST;
4516 : : }
4517 : :
4518 [ # # ]: 0 : if (ft_rule_type != SFC_FT_RULE_SWITCH &&
4519 [ # # ]: 0 : entry->counter->ft_switch_hit_counter != NULL) {
4520 : 0 : return rte_flow_error_set(error, EBUSY,
4521 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4522 : : "cannot use requested indirect counter as it is in use by incompatible offload");
4523 : : }
4524 : :
4525 : : SFC_ASSERT(ctx->counter == NULL);
4526 : :
4527 : 0 : rc = efx_mae_action_set_populate_count(ctx->spec);
4528 [ # # # # ]: 0 : if (rc != 0 && !ctx->counter_implicit) {
4529 : 0 : return rte_flow_error_set(error, rc,
4530 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4531 : : "failed to add COUNT to MAE action set");
4532 : : }
4533 : :
4534 : 0 : ctx->counter_implicit = false;
4535 : 0 : ctx->counter = entry->counter;
4536 : 0 : ++(ctx->counter->refcnt);
4537 : 0 : break;
4538 : : default:
4539 : : SFC_ASSERT(B_FALSE);
4540 : : break;
4541 : : }
4542 : :
4543 : 0 : return 0;
4544 : : }
4545 : : }
4546 : :
4547 : 0 : return rte_flow_error_set(error, ENOENT,
4548 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4549 : : "indirect action handle not found");
4550 : : }
4551 : :
4552 : : static int
4553 : 0 : sfc_mae_rule_parse_action_pf_vf(struct sfc_adapter *sa,
4554 : : const struct rte_flow_action_vf *vf_conf,
4555 : : efx_mae_actions_t *spec)
4556 : : {
4557 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
4558 : : efx_mport_sel_t mport;
4559 : : uint32_t vf;
4560 : : int rc;
4561 : :
4562 [ # # ]: 0 : if (vf_conf == NULL)
4563 : : vf = EFX_PCI_VF_INVALID;
4564 [ # # ]: 0 : else if (vf_conf->original != 0)
4565 : 0 : vf = encp->enc_vf;
4566 : : else
4567 : 0 : vf = vf_conf->id;
4568 : :
4569 : 0 : rc = efx_mae_mport_by_pcie_function(encp->enc_pf, vf, &mport);
4570 [ # # ]: 0 : if (rc != 0) {
4571 [ # # ]: 0 : sfc_err(sa, "failed to convert PF %u VF %d to m-port: %s",
4572 : : encp->enc_pf, (vf != EFX_PCI_VF_INVALID) ? (int)vf : -1,
4573 : : strerror(rc));
4574 : 0 : return rc;
4575 : : }
4576 : :
4577 : 0 : rc = efx_mae_action_set_populate_deliver(spec, &mport);
4578 [ # # ]: 0 : if (rc != 0) {
4579 : 0 : sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s",
4580 : : mport.sel, strerror(rc));
4581 : : }
4582 : :
4583 : : return rc;
4584 : : }
4585 : :
4586 : : static int
4587 [ # # ]: 0 : sfc_mae_rule_parse_action_port_id(struct sfc_adapter *sa,
4588 : : const struct rte_flow_action_port_id *conf,
4589 : : efx_mae_actions_t *spec)
4590 : : {
4591 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
4592 : : struct sfc_mae *mae = &sa->mae;
4593 : : unsigned int type_mask;
4594 : : efx_mport_sel_t mport;
4595 : : uint16_t port_id;
4596 : : int rc;
4597 : :
4598 [ # # ]: 0 : if (conf->id > UINT16_MAX)
4599 : : return EOVERFLOW;
4600 : :
4601 [ # # ]: 0 : port_id = (conf->original != 0) ? sas->port_id : conf->id;
4602 : :
4603 : : type_mask = 1U << SFC_MAE_SWITCH_PORT_INDEPENDENT;
4604 : :
4605 : 0 : rc = sfc_mae_switch_get_ethdev_mport(mae->switch_domain_id,
4606 : : port_id, type_mask, &mport);
4607 [ # # ]: 0 : if (rc != 0) {
4608 : 0 : sfc_err(sa, "failed to get m-port for the given ethdev (port_id=%u): %s",
4609 : : port_id, strerror(rc));
4610 : 0 : return rc;
4611 : : }
4612 : :
4613 : 0 : rc = efx_mae_action_set_populate_deliver(spec, &mport);
4614 [ # # ]: 0 : if (rc != 0) {
4615 : 0 : sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s",
4616 : : mport.sel, strerror(rc));
4617 : : }
4618 : :
4619 : : return rc;
4620 : : }
4621 : :
4622 : : static int
4623 : 0 : sfc_mae_rule_parse_action_port_representor(struct sfc_adapter *sa,
4624 : : const struct rte_flow_action_ethdev *conf,
4625 : : unsigned int type_mask, efx_mae_actions_t *spec)
4626 : : {
4627 : : struct sfc_mae *mae = &sa->mae;
4628 : : efx_mport_sel_t mport;
4629 : : int rc;
4630 : :
4631 : 0 : rc = sfc_mae_switch_get_ethdev_mport(mae->switch_domain_id,
4632 : 0 : conf->port_id, type_mask, &mport);
4633 [ # # ]: 0 : if (rc != 0) {
4634 : 0 : sfc_err(sa, "failed to get m-port for the given ethdev (port_id=%u): %s",
4635 : : conf->port_id, strerror(rc));
4636 : 0 : return rc;
4637 : : }
4638 : :
4639 : 0 : rc = efx_mae_action_set_populate_deliver(spec, &mport);
4640 [ # # ]: 0 : if (rc != 0) {
4641 : 0 : sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s",
4642 : : mport.sel, strerror(rc));
4643 : : }
4644 : :
4645 : : return rc;
4646 : : }
4647 : :
4648 : : static int
4649 : 0 : sfc_mae_rule_parse_action_represented_port(struct sfc_adapter *sa,
4650 : : const struct rte_flow_action_ethdev *conf,
4651 : : efx_mae_actions_t *spec)
4652 : : {
4653 : : struct sfc_mae *mae = &sa->mae;
4654 : : efx_mport_sel_t mport;
4655 : : int rc;
4656 : :
4657 : 0 : rc = sfc_mae_switch_get_entity_mport(mae->switch_domain_id,
4658 : 0 : conf->port_id, &mport);
4659 [ # # ]: 0 : if (rc != 0) {
4660 : 0 : sfc_err(sa, "failed to get m-port for the given ethdev (port_id=%u): %s",
4661 : : conf->port_id, strerror(rc));
4662 : 0 : return rc;
4663 : : }
4664 : :
4665 : 0 : rc = efx_mae_action_set_populate_deliver(spec, &mport);
4666 [ # # ]: 0 : if (rc != 0) {
4667 : 0 : sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s",
4668 : : mport.sel, strerror(rc));
4669 : : }
4670 : :
4671 : : return rc;
4672 : : }
4673 : :
4674 : : static const char * const action_names[] = {
4675 : : [RTE_FLOW_ACTION_TYPE_VXLAN_DECAP] = "VXLAN_DECAP",
4676 : : [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] = "OF_POP_VLAN",
4677 : : [RTE_FLOW_ACTION_TYPE_SET_MAC_DST] = "SET_MAC_DST",
4678 : : [RTE_FLOW_ACTION_TYPE_SET_MAC_SRC] = "SET_MAC_SRC",
4679 : : [RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL] = "OF_DEC_NW_TTL",
4680 : : [RTE_FLOW_ACTION_TYPE_DEC_TTL] = "DEC_TTL",
4681 : : [RTE_FLOW_ACTION_TYPE_SET_IPV4_DST] = "SET_IPV4_DST",
4682 : : [RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC] = "SET_IPV4_SRC",
4683 : : [RTE_FLOW_ACTION_TYPE_SET_TP_DST] = "SET_TP_DST",
4684 : : [RTE_FLOW_ACTION_TYPE_SET_TP_SRC] = "SET_TP_SRC",
4685 : : [RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN] = "OF_PUSH_VLAN",
4686 : : [RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID] = "OF_SET_VLAN_VID",
4687 : : [RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP] = "OF_SET_VLAN_PCP",
4688 : : [RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP] = "VXLAN_ENCAP",
4689 : : [RTE_FLOW_ACTION_TYPE_COUNT] = "COUNT",
4690 : : [RTE_FLOW_ACTION_TYPE_INDIRECT] = "INDIRECT",
4691 : : [RTE_FLOW_ACTION_TYPE_FLAG] = "FLAG",
4692 : : [RTE_FLOW_ACTION_TYPE_MARK] = "MARK",
4693 : : [RTE_FLOW_ACTION_TYPE_PF] = "PF",
4694 : : [RTE_FLOW_ACTION_TYPE_VF] = "VF",
4695 : : [RTE_FLOW_ACTION_TYPE_PORT_ID] = "PORT_ID",
4696 : : [RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR] = "PORT_REPRESENTOR",
4697 : : [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = "REPRESENTED_PORT",
4698 : : [RTE_FLOW_ACTION_TYPE_DROP] = "DROP",
4699 : : [RTE_FLOW_ACTION_TYPE_JUMP] = "JUMP",
4700 : : };
4701 : :
4702 : : static void sfc_mae_bounce_eh_invalidate(struct sfc_mae_bounce_eh *bounce_eh);
4703 : :
4704 : : static int sfc_mae_process_encap_header(struct sfc_adapter *sa,
4705 : : const struct sfc_mae_bounce_eh *bounce_eh,
4706 : : struct sfc_mae_encap_header **encap_headerp);
4707 : :
4708 : : static int
4709 : 0 : sfc_mae_aset_ctx_replay(struct sfc_adapter *sa, struct sfc_mae_aset_ctx **ctxp)
4710 : : {
4711 : : const struct sfc_mae_aset_ctx *ctx_cur;
4712 : : struct sfc_mae_aset_ctx *ctx_new;
4713 : : struct sfc_mae *mae = &sa->mae;
4714 : : int rc;
4715 : :
4716 : : RTE_BUILD_BUG_ON(EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES == 0);
4717 : :
4718 : : /* Check the number of complete action set contexts. */
4719 [ # # ]: 0 : if (mae->nb_bounce_asets >= (EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES - 1))
4720 : : return ENOSPC;
4721 : :
4722 : 0 : ctx_cur = &mae->bounce_aset_ctxs[mae->nb_bounce_asets];
4723 : :
4724 : 0 : ++(mae->nb_bounce_asets);
4725 : :
4726 : 0 : ctx_new = &mae->bounce_aset_ctxs[mae->nb_bounce_asets];
4727 : :
4728 : 0 : *ctx_new = *ctx_cur;
4729 : 0 : ctx_new->counter = NULL;
4730 : 0 : ctx_new->fate_set = false;
4731 : :
4732 : : /*
4733 : : * This clones the action set specification and drops
4734 : : * actions COUNT and DELIVER from the clone so that
4735 : : * such can be added to it by later action parsing.
4736 : : */
4737 : 0 : rc = efx_mae_action_set_replay(sa->nic, ctx_cur->spec, &ctx_new->spec);
4738 [ # # ]: 0 : if (rc != 0)
4739 : : return rc;
4740 : :
4741 : 0 : *ctxp = ctx_new;
4742 : :
4743 : 0 : return 0;
4744 : : }
4745 : :
4746 : : static int
4747 : 0 : sfc_mae_rule_parse_action_rc(struct sfc_adapter *sa,
4748 : : struct sfc_mae_actions_bundle *bundle,
4749 : : const struct rte_flow_action *action,
4750 : : struct rte_flow_error *error,
4751 : : int rc, bool custom_error)
4752 : : {
4753 [ # # ]: 0 : if (rc == 0) {
4754 : 0 : bundle->actions_mask |= (1ULL << action->type);
4755 [ # # ]: 0 : } else if (!custom_error) {
4756 [ # # ]: 0 : if (action->type < RTE_DIM(action_names)) {
4757 : 0 : const char *action_name = action_names[action->type];
4758 : :
4759 [ # # ]: 0 : if (action_name != NULL) {
4760 : 0 : sfc_err(sa, "action %s was rejected: %s",
4761 : : action_name, strerror(rc));
4762 : : }
4763 : : }
4764 : 0 : rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION,
4765 : : NULL, "Failed to request the action");
4766 : : }
4767 : :
4768 : 0 : return rc;
4769 : : }
4770 : :
4771 : : static int
4772 : 0 : sfc_mae_rule_parse_action_replayable(struct sfc_adapter *sa,
4773 : : const struct rte_flow *flow,
4774 : : struct sfc_mae_actions_bundle *bundle,
4775 : : const struct rte_flow_action *action,
4776 : : struct sfc_mae_aset_ctx *ctx,
4777 : : struct rte_flow_error *error)
4778 : : {
4779 : : const struct sfc_flow_spec_mae *spec_mae = &flow->spec.mae;
4780 : 0 : efx_mae_actions_t *spec = ctx->spec;
4781 : : unsigned int switch_port_type_mask;
4782 : : bool custom_error = false;
4783 : : bool new_fate_set = false;
4784 : : bool need_replay = false;
4785 : : int rc;
4786 : :
4787 : : /*
4788 : : * Decide whether the current action set context is
4789 : : * complete. If yes, "replay" it = go to a new one.
4790 : : */
4791 [ # # # ]: 0 : switch (action->type) {
4792 : 0 : case RTE_FLOW_ACTION_TYPE_INDIRECT:
4793 [ # # # # ]: 0 : if (ctx->fate_set || ctx->counter != NULL)
4794 : : need_replay = true;
4795 : : break;
4796 : 0 : case RTE_FLOW_ACTION_TYPE_PF:
4797 : : case RTE_FLOW_ACTION_TYPE_VF:
4798 : : case RTE_FLOW_ACTION_TYPE_PORT_ID:
4799 : : case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
4800 : : case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
4801 : : /* FALLTHROUGH */
4802 : : case RTE_FLOW_ACTION_TYPE_DROP:
4803 [ # # ]: 0 : if (ctx->fate_set)
4804 : : need_replay = true;
4805 : :
4806 : : new_fate_set = true;
4807 : : break;
4808 : 0 : default:
4809 : 0 : return rte_flow_error_set(error, ENOTSUP,
4810 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4811 : : "Unsupported action");
4812 : : }
4813 : :
4814 : : if (need_replay) {
4815 [ # # ]: 0 : if (spec_mae->ft_rule_type != SFC_FT_RULE_NONE) {
4816 : 0 : return rte_flow_error_set(error, EINVAL,
4817 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4818 : : "no support for packet replay in tunnel offload");
4819 : : }
4820 : :
4821 [ # # ]: 0 : if (!ctx->fate_set) {
4822 : : /*
4823 : : * With regard to replayable actions, the current action
4824 : : * set is only needed to hold one of the counters.
4825 : : * That is, it does not have a fate action, so
4826 : : * add one to suppress undesired delivery.
4827 : : */
4828 : 0 : rc = efx_mae_action_set_populate_drop(spec);
4829 [ # # ]: 0 : if (rc != 0) {
4830 : 0 : return rte_flow_error_set(error, rc,
4831 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4832 : : "failed to auto-add action DROP");
4833 : : }
4834 : : }
4835 : :
4836 : 0 : rc = sfc_mae_aset_ctx_replay(sa, &ctx);
4837 [ # # ]: 0 : if (rc != 0) {
4838 : 0 : return rte_flow_error_set(error, rc,
4839 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4840 : : "failed to replay the action set");
4841 : : }
4842 : :
4843 : 0 : spec = ctx->spec;
4844 : : }
4845 : :
4846 : 0 : ctx->fate_set = new_fate_set;
4847 : :
4848 [ # # # # : 0 : switch (action->type) {
# # # # ]
4849 : 0 : case RTE_FLOW_ACTION_TYPE_INDIRECT:
4850 : 0 : rc = sfc_mae_rule_parse_action_indirect(sa, true, action->conf,
4851 : 0 : spec_mae->ft_rule_type,
4852 : : ctx, error);
4853 : : custom_error = true;
4854 : 0 : break;
4855 : 0 : case RTE_FLOW_ACTION_TYPE_PF:
4856 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PF,
4857 : : bundle->actions_mask);
4858 : 0 : rc = sfc_mae_rule_parse_action_pf_vf(sa, NULL, spec);
4859 : 0 : break;
4860 : 0 : case RTE_FLOW_ACTION_TYPE_VF:
4861 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VF,
4862 : : bundle->actions_mask);
4863 : 0 : rc = sfc_mae_rule_parse_action_pf_vf(sa, action->conf, spec);
4864 : 0 : break;
4865 : 0 : case RTE_FLOW_ACTION_TYPE_PORT_ID:
4866 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PORT_ID,
4867 : : bundle->actions_mask);
4868 : 0 : rc = sfc_mae_rule_parse_action_port_id(sa, action->conf, spec);
4869 : 0 : break;
4870 : 0 : case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
4871 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR,
4872 : : bundle->actions_mask);
4873 : :
4874 : : switch_port_type_mask = 1U << SFC_MAE_SWITCH_PORT_INDEPENDENT;
4875 : :
4876 [ # # ]: 0 : if (flow->internal) {
4877 : : switch_port_type_mask |=
4878 : : 1U << SFC_MAE_SWITCH_PORT_REPRESENTOR;
4879 : : }
4880 : :
4881 : 0 : rc = sfc_mae_rule_parse_action_port_representor(sa,
4882 : 0 : action->conf, switch_port_type_mask, spec);
4883 : 0 : break;
4884 : 0 : case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
4885 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT,
4886 : : bundle->actions_mask);
4887 : 0 : rc = sfc_mae_rule_parse_action_represented_port(sa,
4888 : 0 : action->conf, spec);
4889 : 0 : break;
4890 : 0 : case RTE_FLOW_ACTION_TYPE_DROP:
4891 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP,
4892 : : bundle->actions_mask);
4893 : 0 : rc = efx_mae_action_set_populate_drop(spec);
4894 : 0 : break;
4895 : : default:
4896 : : SFC_ASSERT(B_FALSE);
4897 : : break;
4898 : : }
4899 : :
4900 : 0 : return sfc_mae_rule_parse_action_rc(sa, bundle, action, error,
4901 : : rc, custom_error);
4902 : : }
4903 : :
4904 : : static int
4905 : 0 : sfc_mae_rule_parse_action(struct sfc_adapter *sa,
4906 : : const struct rte_flow_action *action,
4907 : : struct rte_flow *flow, bool ct,
4908 : : struct sfc_mae_actions_bundle *bundle,
4909 : : struct rte_flow_error *error)
4910 : : {
4911 : 0 : struct sfc_flow_spec_mae *spec_mae = &flow->spec.mae;
4912 : 0 : const struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule;
4913 : : efx_counter_type_t mae_counter_type = EFX_COUNTER_TYPE_ACTION;
4914 : 0 : const uint64_t rx_metadata = sa->negotiated_rx_metadata;
4915 : : struct sfc_mae_counter **counterp;
4916 : : bool non_replayable_found = true;
4917 : 0 : struct sfc_mae *mae = &sa->mae;
4918 : : struct sfc_mae_aset_ctx *ctx;
4919 : : efx_mae_actions_t *spec_ptr;
4920 : : bool custom_error = B_FALSE;
4921 : : efx_mae_actions_t *spec;
4922 : : int rc = 0;
4923 : :
4924 : : /* Check the number of complete action set contexts. */
4925 [ # # ]: 0 : if (mae->nb_bounce_asets > (EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES - 1)) {
4926 : 0 : return sfc_mae_rule_parse_action_rc(sa, bundle, action, error,
4927 : : ENOSPC, custom_error);
4928 : : }
4929 : :
4930 : 0 : ctx = &mae->bounce_aset_ctxs[mae->nb_bounce_asets];
4931 : 0 : counterp = &ctx->counter;
4932 : 0 : spec = ctx->spec;
4933 : : spec_ptr = spec;
4934 : :
4935 [ # # ]: 0 : if (ct) {
4936 : : mae_counter_type = EFX_COUNTER_TYPE_CONNTRACK;
4937 : 0 : counterp = &spec_mae->ct_counter;
4938 : : spec_ptr = NULL;
4939 : : }
4940 : :
4941 [ # # # # ]: 0 : if (mae->nb_bounce_asets != 0 || ctx->fate_set) {
4942 : : /*
4943 : : * When at least one delivery action has been encountered,
4944 : : * non-replayable actions (packet edits, for instance)
4945 : : * will be turned down.
4946 : : */
4947 : 0 : return sfc_mae_rule_parse_action_replayable(sa, flow, bundle,
4948 : : action, ctx, error);
4949 : : }
4950 : :
4951 [ # # # # : 0 : switch (action->type) {
# # # # #
# # # # #
# # # ]
4952 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
4953 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VXLAN_DECAP,
4954 : : bundle->actions_mask);
4955 [ # # ]: 0 : if (outer_rule == NULL ||
4956 [ # # ]: 0 : outer_rule->encap_type != EFX_TUNNEL_PROTOCOL_VXLAN)
4957 : : rc = EINVAL;
4958 : : else
4959 : 0 : rc = efx_mae_action_set_populate_decap(spec);
4960 : : break;
4961 : 0 : case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
4962 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_POP_VLAN,
4963 : : bundle->actions_mask);
4964 : 0 : rc = efx_mae_action_set_populate_vlan_pop(spec);
4965 : 0 : break;
4966 : 0 : case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
4967 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_MAC_DST,
4968 : : bundle->actions_mask);
4969 : 0 : rc = sfc_mae_rule_parse_action_set_mac(sa, SFC_MAE_MAC_ADDR_DST,
4970 : 0 : action->conf, ctx,
4971 : : error);
4972 : : custom_error = B_TRUE;
4973 : 0 : break;
4974 : 0 : case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
4975 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_MAC_SRC,
4976 : : bundle->actions_mask);
4977 : 0 : rc = sfc_mae_rule_parse_action_set_mac(sa, SFC_MAE_MAC_ADDR_SRC,
4978 : 0 : action->conf, ctx,
4979 : : error);
4980 : : custom_error = B_TRUE;
4981 : 0 : break;
4982 : 0 : case RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL:
4983 : : case RTE_FLOW_ACTION_TYPE_DEC_TTL:
4984 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL,
4985 : : bundle->actions_mask);
4986 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DEC_TTL,
4987 : : bundle->actions_mask);
4988 : 0 : rc = efx_mae_action_set_populate_decr_ip_ttl(spec);
4989 : 0 : break;
4990 : 0 : case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
4991 : : case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
4992 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_IPV4_DST,
4993 : : bundle->actions_mask);
4994 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC,
4995 : : bundle->actions_mask);
4996 [ # # ]: 0 : sfc_mae_rule_parse_action_nat_addr(action->conf,
4997 : : &spec_mae->ct_resp.nat.ip_le);
4998 : : break;
4999 : 0 : case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
5000 : : case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
5001 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_TP_DST,
5002 : : bundle->actions_mask);
5003 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_TP_SRC,
5004 : : bundle->actions_mask);
5005 [ # # ]: 0 : sfc_mae_rule_parse_action_nat_port(action->conf,
5006 : : &spec_mae->ct_resp.nat.port_le);
5007 : : break;
5008 : 0 : case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
5009 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN,
5010 : : bundle->actions_mask);
5011 : 0 : sfc_mae_rule_parse_action_of_push_vlan(action->conf, bundle);
5012 : : break;
5013 : 0 : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
5014 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID,
5015 : : bundle->actions_mask);
5016 : 0 : sfc_mae_rule_parse_action_of_set_vlan_vid(action->conf, bundle);
5017 : : break;
5018 : 0 : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
5019 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP,
5020 : : bundle->actions_mask);
5021 [ # # ]: 0 : sfc_mae_rule_parse_action_of_set_vlan_pcp(action->conf, bundle);
5022 : : break;
5023 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5024 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
5025 : : bundle->actions_mask);
5026 : :
5027 : : /* Cleanup after previous encap. header bounce buffer usage. */
5028 : : sfc_mae_bounce_eh_invalidate(&mae->bounce_eh);
5029 : :
5030 : 0 : rc = sfc_mae_rule_parse_action_vxlan_encap(mae, action->conf,
5031 : : spec, error);
5032 [ # # ]: 0 : if (rc == 0) {
5033 : 0 : rc = sfc_mae_process_encap_header(sa, &mae->bounce_eh,
5034 : : &ctx->encap_header);
5035 : : } else {
5036 : : custom_error = true;
5037 : : }
5038 : : break;
5039 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
5040 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_COUNT,
5041 : : bundle->actions_mask);
5042 : 0 : rc = sfc_mae_rule_parse_action_count(sa, action->conf,
5043 : : mae_counter_type,
5044 : : counterp, spec_ptr);
5045 : 0 : break;
5046 : 0 : case RTE_FLOW_ACTION_TYPE_INDIRECT:
5047 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_INDIRECT,
5048 : : bundle->actions_mask);
5049 : 0 : rc = sfc_mae_rule_parse_action_indirect(sa, false, action->conf,
5050 : : spec_mae->ft_rule_type,
5051 : : ctx, error);
5052 [ # # ]: 0 : if (rc == EEXIST) {
5053 : : /* Handle the action as a replayable one below. */
5054 : : non_replayable_found = false;
5055 : : }
5056 : : custom_error = B_TRUE;
5057 : : break;
5058 : 0 : case RTE_FLOW_ACTION_TYPE_FLAG:
5059 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG,
5060 : : bundle->actions_mask);
5061 [ # # ]: 0 : if ((rx_metadata & RTE_ETH_RX_METADATA_USER_FLAG) != 0) {
5062 : 0 : rc = efx_mae_action_set_populate_flag(spec);
5063 : : } else {
5064 : 0 : rc = rte_flow_error_set(error, ENOTSUP,
5065 : : RTE_FLOW_ERROR_TYPE_ACTION,
5066 : : action,
5067 : : "flag delivery has not been negotiated");
5068 : : custom_error = B_TRUE;
5069 : : }
5070 : : break;
5071 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
5072 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK,
5073 : : bundle->actions_mask);
5074 [ # # ]: 0 : if ((rx_metadata & RTE_ETH_RX_METADATA_USER_MARK) != 0 ||
5075 [ # # ]: 0 : spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL) {
5076 : 0 : rc = sfc_mae_rule_parse_action_mark(sa, action->conf,
5077 : : spec_mae, spec);
5078 : : } else {
5079 : 0 : rc = rte_flow_error_set(error, ENOTSUP,
5080 : : RTE_FLOW_ERROR_TYPE_ACTION,
5081 : : action,
5082 : : "mark delivery has not been negotiated");
5083 : : custom_error = B_TRUE;
5084 : : }
5085 : : break;
5086 : 0 : case RTE_FLOW_ACTION_TYPE_JUMP:
5087 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL) {
5088 : : /* Workaround. See sfc_flow_parse_rte_to_mae() */
5089 : : break;
5090 : : }
5091 : : /* FALLTHROUGH */
5092 : : default:
5093 : : non_replayable_found = false;
5094 : : }
5095 : :
5096 [ # # ]: 0 : if (non_replayable_found) {
5097 : 0 : return sfc_mae_rule_parse_action_rc(sa, bundle, action, error,
5098 : : rc, custom_error);
5099 : : }
5100 : :
5101 : 0 : return sfc_mae_rule_parse_action_replayable(sa, flow, bundle,
5102 : : action, ctx, error);
5103 : : }
5104 : :
5105 : : static void
5106 : : sfc_mae_bounce_eh_invalidate(struct sfc_mae_bounce_eh *bounce_eh)
5107 : : {
5108 : 0 : bounce_eh->type = EFX_TUNNEL_PROTOCOL_NONE;
5109 : : }
5110 : :
5111 : : static int
5112 : 0 : sfc_mae_process_encap_header(struct sfc_adapter *sa,
5113 : : const struct sfc_mae_bounce_eh *bounce_eh,
5114 : : struct sfc_mae_encap_header **encap_headerp)
5115 : : {
5116 [ # # ]: 0 : if (bounce_eh->type == EFX_TUNNEL_PROTOCOL_NONE) {
5117 : : encap_headerp = NULL;
5118 : : return 0;
5119 : : }
5120 : :
5121 : 0 : *encap_headerp = sfc_mae_encap_header_attach(sa, bounce_eh);
5122 [ # # ]: 0 : if (*encap_headerp != NULL)
5123 : : return 0;
5124 : :
5125 : 0 : return sfc_mae_encap_header_add(sa, bounce_eh, encap_headerp);
5126 : : }
5127 : :
5128 : : static int
5129 : 0 : sfc_mae_rule_process_replay(struct sfc_adapter *sa,
5130 : : struct sfc_mae_action_rule_ctx *action_rule_ctx)
5131 : : {
5132 : : struct sfc_mae_action_set *base_aset;
5133 : : struct sfc_mae_action_set **asetp;
5134 : : struct sfc_mae *mae = &sa->mae;
5135 : : struct sfc_mae_aset_ctx *ctx;
5136 : : unsigned int i;
5137 : : unsigned int j;
5138 : : int rc;
5139 : :
5140 [ # # ]: 0 : if (mae->nb_bounce_asets == 1)
5141 : : return 0;
5142 : :
5143 : 0 : mae->bounce_aset_ptrs[0] = action_rule_ctx->action_set;
5144 : : base_aset = mae->bounce_aset_ptrs[0];
5145 : :
5146 [ # # ]: 0 : for (i = 1; i < mae->nb_bounce_asets; ++i) {
5147 : 0 : asetp = &mae->bounce_aset_ptrs[i];
5148 : 0 : ctx = &mae->bounce_aset_ctxs[i];
5149 : :
5150 : 0 : *asetp = sfc_mae_action_set_attach(sa, ctx);
5151 [ # # ]: 0 : if (*asetp != NULL) {
5152 : 0 : efx_mae_action_set_spec_fini(sa->nic, ctx->spec);
5153 : 0 : sfc_mae_counter_del(sa, ctx->counter);
5154 : 0 : continue;
5155 : : }
5156 : :
5157 : 0 : rc = sfc_mae_action_set_add(sa, ctx, asetp);
5158 [ # # ]: 0 : if (rc != 0)
5159 : 0 : goto fail_action_set_add;
5160 : :
5161 [ # # ]: 0 : if (base_aset->encap_header != NULL)
5162 : 0 : ++(base_aset->encap_header->refcnt);
5163 : :
5164 [ # # ]: 0 : if (base_aset->dst_mac_addr != NULL)
5165 : 0 : ++(base_aset->dst_mac_addr->refcnt);
5166 : :
5167 [ # # ]: 0 : if (base_aset->src_mac_addr != NULL)
5168 : 0 : ++(base_aset->src_mac_addr->refcnt);
5169 : : }
5170 : :
5171 : 0 : action_rule_ctx->action_set_list = sfc_mae_action_set_list_attach(sa);
5172 [ # # ]: 0 : if (action_rule_ctx->action_set_list != NULL) {
5173 [ # # ]: 0 : for (i = 0; i < mae->nb_bounce_asets; ++i)
5174 : 0 : sfc_mae_action_set_del(sa, mae->bounce_aset_ptrs[i]);
5175 : : } else {
5176 : 0 : rc = sfc_mae_action_set_list_add(sa,
5177 : : &action_rule_ctx->action_set_list);
5178 [ # # ]: 0 : if (rc != 0)
5179 : 0 : goto fail_action_set_list_add;
5180 : : }
5181 : :
5182 : 0 : action_rule_ctx->action_set = NULL;
5183 : :
5184 : 0 : return 0;
5185 : :
5186 : : fail_action_set_list_add:
5187 : 0 : fail_action_set_add:
5188 [ # # ]: 0 : for (j = i; j < mae->nb_bounce_asets; ++j) {
5189 : 0 : ctx = &mae->bounce_aset_ctxs[j];
5190 : 0 : efx_mae_action_set_spec_fini(sa->nic, ctx->spec);
5191 : 0 : sfc_mae_counter_del(sa, ctx->counter);
5192 : : }
5193 : :
5194 [ # # ]: 0 : while (--i > 0)
5195 : 0 : sfc_mae_action_set_del(sa, mae->bounce_aset_ptrs[i]);
5196 : :
5197 : : return rc;
5198 : : }
5199 : :
5200 : : static int
5201 : 0 : sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
5202 : : const struct rte_flow_action actions[],
5203 : : struct rte_flow *flow,
5204 : : struct sfc_mae_action_rule_ctx *action_rule_ctx,
5205 : : struct rte_flow_error *error)
5206 : : {
5207 : 0 : struct sfc_flow_spec_mae *spec_mae = &flow->spec.mae;
5208 : 0 : struct sfc_mae_actions_bundle bundle = {0};
5209 : 0 : bool ct = (action_rule_ctx->ct_mark != 0);
5210 : : const struct rte_flow_action *action;
5211 : : struct sfc_mae_aset_ctx *last_ctx;
5212 : : struct sfc_mae *mae = &sa->mae;
5213 : : struct sfc_mae_aset_ctx *ctx;
5214 : : int rc;
5215 : :
5216 : 0 : rte_errno = 0;
5217 : :
5218 [ # # ]: 0 : if (actions == NULL) {
5219 : 0 : return rte_flow_error_set(error, EINVAL,
5220 : : RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
5221 : : "NULL actions");
5222 : : }
5223 : :
5224 : : /*
5225 : : * Cleanup after action parsing of the previous flow.
5226 : : *
5227 : : * This particular variable always points at the
5228 : : * 1st (base) action set context, which can hold
5229 : : * both non-replayable and replayable actions.
5230 : : */
5231 : 0 : ctx = &mae->bounce_aset_ctxs[0];
5232 : : memset(ctx, 0, sizeof(*ctx));
5233 : 0 : mae->nb_bounce_asets = 0;
5234 : :
5235 : 0 : rc = efx_mae_action_set_spec_init(sa->nic, &ctx->spec);
5236 [ # # ]: 0 : if (rc != 0)
5237 : 0 : goto fail_action_set_spec_init;
5238 : :
5239 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_SWITCH) {
5240 : : bool have_inline_action_count = false;
5241 : :
5242 : : /* TUNNEL rules don't decapsulate packets. SWITCH rules do. */
5243 : 0 : rc = efx_mae_action_set_populate_decap(ctx->spec);
5244 [ # # ]: 0 : if (rc != 0)
5245 : 0 : goto fail_enforce_ft_decap;
5246 : :
5247 : : for (action = actions;
5248 [ # # ]: 0 : action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
5249 [ # # ]: 0 : if (action->type == RTE_FLOW_ACTION_TYPE_COUNT) {
5250 : : have_inline_action_count = true;
5251 : : break;
5252 : : }
5253 : : }
5254 : :
5255 [ # # # # ]: 0 : if (!have_inline_action_count &&
5256 : 0 : sfc_mae_counter_stream_enabled(sa)) {
5257 : : /*
5258 : : * The user might have opted not to have a counter here,
5259 : : * but the counter should be enabled implicitly because
5260 : : * packets hitting this rule contribute to the tunnel's
5261 : : * total number of hits. See sfc_mae_counter_get().
5262 : : */
5263 : 0 : rc = efx_mae_action_set_populate_count(ctx->spec);
5264 [ # # ]: 0 : if (rc != 0)
5265 : 0 : goto fail_enforce_ft_count;
5266 : :
5267 : : /*
5268 : : * An action of type COUNT may come inlined (see above)
5269 : : * or via a shareable handle (enclosed by an action of
5270 : : * type INDIRECT). The latter is expensive to resolve
5271 : : * here. For now assume an implicit counter is needed.
5272 : : *
5273 : : * But if the flow does come with an indirect counter,
5274 : : * sfc_mae_rule_parse_action_indirect() will test the
5275 : : * flag to cope with its "populate" failure. It will
5276 : : * reset the flag so that below code can skip
5277 : : * creating a software object for the counter.
5278 : : */
5279 : 0 : ctx->counter_implicit = true;
5280 : : }
5281 : : }
5282 : :
5283 : : for (action = actions;
5284 [ # # ]: 0 : action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
5285 [ # # ]: 0 : if (mae->nb_bounce_asets == 0) {
5286 : 0 : rc = sfc_mae_actions_bundle_sync(action, &bundle,
5287 : : spec_mae, ctx->spec,
5288 : : ct, error);
5289 [ # # ]: 0 : if (rc != 0)
5290 : 0 : goto fail_rule_parse_action;
5291 : : }
5292 : :
5293 : 0 : rc = sfc_mae_rule_parse_action(sa, action, flow, ct,
5294 : : &bundle, error);
5295 [ # # ]: 0 : if (rc != 0)
5296 : 0 : goto fail_rule_parse_action;
5297 : : }
5298 : :
5299 [ # # ]: 0 : if (mae->nb_bounce_asets == 0) {
5300 : 0 : rc = sfc_mae_actions_bundle_sync(action, &bundle, spec_mae,
5301 : : ctx->spec, ct, error);
5302 [ # # ]: 0 : if (rc != 0)
5303 : 0 : goto fail_rule_parse_action;
5304 : : }
5305 : :
5306 [ # # # ]: 0 : switch (spec_mae->ft_rule_type) {
5307 : : case SFC_FT_RULE_NONE:
5308 : : break;
5309 : 0 : case SFC_FT_RULE_TUNNEL:
5310 : : /* Workaround. See sfc_flow_parse_rte_to_mae() */
5311 : 0 : rc = sfc_mae_rule_parse_action_pf_vf(sa, NULL, ctx->spec);
5312 [ # # ]: 0 : if (rc != 0)
5313 : 0 : goto fail_workaround_tunnel_delivery;
5314 : :
5315 [ # # ]: 0 : if (ctx->counter != NULL)
5316 : 0 : (ctx->counter)->ft_ctx = spec_mae->ft_ctx;
5317 : :
5318 : 0 : ctx->fate_set = true;
5319 : 0 : break;
5320 : 0 : case SFC_FT_RULE_SWITCH:
5321 : : /*
5322 : : * Packets that go to the rule's AR have FT mark set (from
5323 : : * the TUNNEL rule OR's RECIRC_ID). Reset the mark to zero.
5324 : : */
5325 : 0 : efx_mae_action_set_populate_mark_reset(ctx->spec);
5326 : :
5327 [ # # ]: 0 : if (ctx->counter_implicit) {
5328 : : /*
5329 : : * Turns out the rule indeed does not have a user
5330 : : * counter, so add one. The action bit in the
5331 : : * action set specification has already been
5332 : : * populated by the above preparse logic.
5333 : : */
5334 : 0 : rc = sfc_mae_counter_add(sa, NULL, &ctx->counter);
5335 [ # # ]: 0 : if (rc != 0)
5336 : 0 : goto fail_add_implicit_counter;
5337 : : }
5338 : :
5339 [ # # ]: 0 : if (ctx->counter != NULL) {
5340 : : struct sfc_mae_counter *counter = ctx->counter;
5341 : :
5342 [ # # ]: 0 : if (counter->indirect &&
5343 [ # # ]: 0 : counter->refcnt > 1 /* indirect handle */ +
5344 : 0 : 1 /* 1st use */ &&
5345 : 0 : counter->ft_switch_hit_counter !=
5346 [ # # ]: 0 : &spec_mae->ft_ctx->switch_hit_counter) {
5347 : 0 : rc = rte_flow_error_set(error, EBUSY,
5348 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5349 : : "requested indirect counter is in use by another tunnel context");
5350 : 0 : goto fail_check_indirect_counter_ft_ctx;
5351 : : }
5352 : :
5353 : 0 : counter->ft_switch_hit_counter =
5354 : 0 : &spec_mae->ft_ctx->switch_hit_counter;
5355 [ # # ]: 0 : } else if (sfc_mae_counter_stream_enabled(sa)) {
5356 : : SFC_ASSERT(ct);
5357 : :
5358 : 0 : spec_mae->ct_counter->ft_switch_hit_counter =
5359 : 0 : &spec_mae->ft_ctx->switch_hit_counter;
5360 : : }
5361 : : break;
5362 : 0 : default:
5363 : : SFC_ASSERT(B_FALSE);
5364 : : }
5365 : :
5366 : : SFC_ASSERT(mae->nb_bounce_asets < EFX_MAE_ACTION_SET_LIST_MAX_NENTRIES);
5367 : 0 : last_ctx = &mae->bounce_aset_ctxs[mae->nb_bounce_asets];
5368 : 0 : ++(mae->nb_bounce_asets);
5369 : :
5370 [ # # ]: 0 : if (!last_ctx->fate_set) {
5371 : 0 : rc = rte_flow_error_set(error, EINVAL,
5372 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5373 : : "no fate action found");
5374 : 0 : goto fail_check_fate_action;
5375 : : }
5376 : :
5377 : 0 : action_rule_ctx->action_set = sfc_mae_action_set_attach(sa, ctx);
5378 [ # # ]: 0 : if (action_rule_ctx->action_set != NULL) {
5379 : 0 : sfc_mae_counter_del(sa, ctx->counter);
5380 : 0 : sfc_mae_mac_addr_del(sa, ctx->src_mac);
5381 : 0 : sfc_mae_mac_addr_del(sa, ctx->dst_mac);
5382 : 0 : sfc_mae_encap_header_del(sa, ctx->encap_header);
5383 : 0 : efx_mae_action_set_spec_fini(sa->nic, ctx->spec);
5384 : : } else {
5385 : 0 : rc = sfc_mae_action_set_add(sa, ctx,
5386 : : &action_rule_ctx->action_set);
5387 [ # # ]: 0 : if (rc != 0)
5388 : 0 : goto fail_action_set_add;
5389 : : }
5390 : :
5391 : : memset(ctx, 0, sizeof(*ctx));
5392 : :
5393 : 0 : rc = sfc_mae_rule_process_replay(sa, action_rule_ctx);
5394 [ # # ]: 0 : if (rc != 0)
5395 : 0 : goto fail_rule_parse_replay;
5396 : :
5397 : : return 0;
5398 : :
5399 : : fail_rule_parse_replay:
5400 : 0 : sfc_mae_action_set_del(sa, action_rule_ctx->action_set);
5401 : :
5402 : 0 : fail_action_set_add:
5403 : 0 : fail_check_fate_action:
5404 : 0 : fail_check_indirect_counter_ft_ctx:
5405 : 0 : fail_add_implicit_counter:
5406 : 0 : fail_workaround_tunnel_delivery:
5407 : 0 : fail_rule_parse_action:
5408 : 0 : sfc_mae_encap_header_del(sa, ctx->encap_header);
5409 : 0 : sfc_mae_counter_del(sa, ctx->counter);
5410 : 0 : sfc_mae_mac_addr_del(sa, ctx->src_mac);
5411 : 0 : sfc_mae_mac_addr_del(sa, ctx->dst_mac);
5412 : :
5413 [ # # ]: 0 : if (ctx->spec != NULL)
5414 : 0 : efx_mae_action_set_spec_fini(sa->nic, ctx->spec);
5415 : :
5416 : 0 : fail_enforce_ft_count:
5417 : 0 : fail_enforce_ft_decap:
5418 : 0 : fail_action_set_spec_init:
5419 [ # # # # ]: 0 : if (rc > 0 && rte_errno == 0) {
5420 : 0 : rc = rte_flow_error_set(error, rc,
5421 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5422 : : NULL, "Failed to process the action");
5423 : : }
5424 : : return rc;
5425 : : }
5426 : :
5427 : : int
5428 : 0 : sfc_mae_rule_parse(struct sfc_adapter *sa, const struct rte_flow_item pattern[],
5429 : : const struct rte_flow_action actions[],
5430 : : struct rte_flow *flow, struct rte_flow_error *error)
5431 : : {
5432 : : struct sfc_flow_spec *spec = &flow->spec;
5433 : 0 : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
5434 : 0 : struct sfc_mae_action_rule_ctx ctx = {};
5435 : : int rc;
5436 : :
5437 : : /*
5438 : : * If the flow is meant to be a TUNNEL rule in a FT context,
5439 : : * preparse its actions and save its properties in spec_mae.
5440 : : */
5441 : 0 : rc = sfc_ft_tunnel_rule_detect(sa, actions, spec_mae, error);
5442 [ # # ]: 0 : if (rc != 0)
5443 : 0 : goto fail;
5444 : :
5445 : 0 : rc = sfc_mae_rule_parse_pattern(sa, pattern, flow, &ctx, error);
5446 [ # # ]: 0 : if (rc != 0)
5447 : 0 : goto fail;
5448 : :
5449 : : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL) {
5450 : : /*
5451 : : * By design, this flow should be represented solely by the
5452 : : * outer rule. But the HW/FW hasn't got support for setting
5453 : : * Rx mark from RECIRC_ID on outer rule lookup yet. Neither
5454 : : * does it support outer rule counters. As a workaround, an
5455 : : * action rule of lower priority is used to do the job.
5456 : : *
5457 : : * So don't skip sfc_mae_rule_parse_actions() below.
5458 : : */
5459 : : }
5460 : :
5461 : 0 : spec_mae->outer_rule = ctx.outer_rule;
5462 : :
5463 : 0 : rc = sfc_mae_rule_parse_actions(sa, actions, flow, &ctx, error);
5464 [ # # ]: 0 : if (rc != 0)
5465 : 0 : goto fail;
5466 : :
5467 : 0 : rc = sfc_mae_action_rule_attach(sa, &ctx, &spec_mae->action_rule,
5468 : : error);
5469 [ # # ]: 0 : if (rc == 0) {
5470 : 0 : efx_mae_match_spec_fini(sa->nic, ctx.match_spec);
5471 : 0 : sfc_mae_action_set_list_del(sa, ctx.action_set_list);
5472 : 0 : sfc_mae_action_set_del(sa, ctx.action_set);
5473 : 0 : sfc_mae_outer_rule_del(sa, ctx.outer_rule);
5474 [ # # ]: 0 : } else if (rc == -ENOENT) {
5475 : 0 : rc = sfc_mae_action_rule_add(sa, &ctx, &spec_mae->action_rule);
5476 [ # # ]: 0 : if (rc != 0) {
5477 : 0 : rc = rte_flow_error_set(error, rc,
5478 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5479 : : NULL, "AR: failed to add the entry");
5480 : 0 : goto fail;
5481 : : }
5482 : : } else {
5483 : 0 : goto fail;
5484 : : }
5485 : :
5486 [ # # ]: 0 : if (spec_mae->ft_ctx != NULL) {
5487 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL)
5488 : 0 : spec_mae->ft_ctx->tunnel_rule_is_set = B_TRUE;
5489 : :
5490 : 0 : ++(spec_mae->ft_ctx->refcnt);
5491 : : }
5492 : :
5493 : : return 0;
5494 : :
5495 : 0 : fail:
5496 [ # # ]: 0 : if (ctx.match_spec != NULL)
5497 : 0 : efx_mae_match_spec_fini(sa->nic, ctx.match_spec);
5498 : :
5499 : 0 : sfc_mae_action_set_list_del(sa, ctx.action_set_list);
5500 : 0 : sfc_mae_action_set_del(sa, ctx.action_set);
5501 : 0 : sfc_mae_outer_rule_del(sa, ctx.outer_rule);
5502 : :
5503 : : /* Reset these values to avoid confusing sfc_mae_flow_cleanup(). */
5504 : 0 : spec_mae->ft_rule_type = SFC_FT_RULE_NONE;
5505 : 0 : spec_mae->ft_ctx = NULL;
5506 : :
5507 : 0 : return rc;
5508 : : }
5509 : :
5510 : : static bool
5511 : : sfc_mae_rules_class_cmp(struct sfc_adapter *sa,
5512 : : const efx_mae_match_spec_t *left,
5513 : : const efx_mae_match_spec_t *right)
5514 : : {
5515 : : bool have_same_class;
5516 : : int rc;
5517 : :
5518 : 0 : rc = efx_mae_match_specs_class_cmp(sa->nic, left, right,
5519 : : &have_same_class);
5520 : :
5521 [ # # # # : 0 : return (rc == 0) ? have_same_class : false;
# # # # ]
5522 : : }
5523 : :
5524 : : static int
5525 : 0 : sfc_mae_outer_rule_class_verify(struct sfc_adapter *sa,
5526 : : struct sfc_mae_outer_rule *rule)
5527 : : {
5528 : : struct sfc_mae_outer_rule *entry;
5529 : : struct sfc_mae_fw_rsrc *fw_rsrc;
5530 : : struct sfc_mae *mae = &sa->mae;
5531 : :
5532 [ # # ]: 0 : if (rule == NULL)
5533 : : return 0;
5534 : :
5535 : : fw_rsrc = &rule->fw_rsrc;
5536 : :
5537 [ # # ]: 0 : if (fw_rsrc->rule_id.id != EFX_MAE_RSRC_ID_INVALID) {
5538 : : /* An active rule is reused. It's class is wittingly valid. */
5539 : : return 0;
5540 : : }
5541 : :
5542 [ # # ]: 0 : TAILQ_FOREACH_REVERSE(entry, &mae->outer_rules,
5543 : : sfc_mae_outer_rules, entries) {
5544 : 0 : const efx_mae_match_spec_t *left = entry->match_spec;
5545 : 0 : const efx_mae_match_spec_t *right = rule->match_spec;
5546 : :
5547 [ # # ]: 0 : if (entry == rule)
5548 : 0 : continue;
5549 : :
5550 : : if (sfc_mae_rules_class_cmp(sa, left, right))
5551 : 0 : return 0;
5552 : : }
5553 : :
5554 : 0 : sfc_info(sa, "for now, the HW doesn't support rule validation, and HW "
5555 : : "support for outer frame pattern items is not guaranteed; "
5556 : : "other than that, the items are valid from SW standpoint");
5557 : 0 : return 0;
5558 : : }
5559 : :
5560 : : static int
5561 : 0 : sfc_mae_action_rule_class_verify(struct sfc_adapter *sa,
5562 : : struct sfc_mae_action_rule *rule)
5563 : : {
5564 : : struct sfc_mae_fw_rsrc *fw_rsrc = &rule->fw_rsrc;
5565 : : const struct sfc_mae_action_rule *entry;
5566 : : struct sfc_mae *mae = &sa->mae;
5567 : :
5568 [ # # ]: 0 : if (fw_rsrc->rule_id.id != EFX_MAE_RSRC_ID_INVALID) {
5569 : : /* An active rule is reused. Its class is known to be valid. */
5570 : : return 0;
5571 : : }
5572 : :
5573 [ # # ]: 0 : TAILQ_FOREACH_REVERSE(entry, &mae->action_rules,
5574 : : sfc_mae_action_rules, entries) {
5575 : 0 : const efx_mae_match_spec_t *left = entry->match_spec;
5576 : 0 : const efx_mae_match_spec_t *right = rule->match_spec;
5577 : :
5578 [ # # ]: 0 : if (entry == rule)
5579 : 0 : continue;
5580 : :
5581 : : if (sfc_mae_rules_class_cmp(sa, left, right))
5582 : 0 : return 0;
5583 : : }
5584 : :
5585 : 0 : sfc_info(sa, "for now, the HW doesn't support rule validation, and HW "
5586 : : "support for inner frame pattern items is not guaranteed; "
5587 : : "other than that, the items are valid from SW standpoint");
5588 : 0 : return 0;
5589 : : }
5590 : :
5591 : : /**
5592 : : * Confirm that a given flow can be accepted by the FW.
5593 : : *
5594 : : * @param sa
5595 : : * Software adapter context
5596 : : * @param flow
5597 : : * Flow to be verified
5598 : : * @return
5599 : : * Zero on success and non-zero in the case of error.
5600 : : * A special value of EAGAIN indicates that the adapter is
5601 : : * not in started state. This state is compulsory because
5602 : : * it only makes sense to compare the rule class of the flow
5603 : : * being validated with classes of the active rules.
5604 : : * Such classes are wittingly supported by the FW.
5605 : : */
5606 : : int
5607 : 0 : sfc_mae_flow_verify(struct sfc_adapter *sa,
5608 : : struct rte_flow *flow)
5609 : : {
5610 : : struct sfc_flow_spec *spec = &flow->spec;
5611 : : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
5612 : 0 : struct sfc_mae_action_rule *action_rule = spec_mae->action_rule;
5613 : 0 : struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule;
5614 : : int rc;
5615 : :
5616 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
5617 : :
5618 [ # # ]: 0 : if (sa->state != SFC_ETHDEV_STARTED)
5619 : : return EAGAIN;
5620 : :
5621 : 0 : rc = sfc_mae_outer_rule_class_verify(sa, outer_rule);
5622 [ # # ]: 0 : if (rc != 0)
5623 : : return rc;
5624 : :
5625 : 0 : return sfc_mae_action_rule_class_verify(sa, action_rule);
5626 : : }
5627 : :
5628 : : int
5629 : 0 : sfc_mae_flow_insert(struct sfc_adapter *sa,
5630 : : struct rte_flow *flow)
5631 : : {
5632 : : struct sfc_flow_spec *spec = &flow->spec;
5633 : : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
5634 : 0 : struct sfc_mae_action_rule *action_rule = spec_mae->action_rule;
5635 : : int rc;
5636 : :
5637 [ # # ]: 0 : if (spec_mae->ft_rule_type == SFC_FT_RULE_TUNNEL) {
5638 : 0 : spec_mae->ft_ctx->reset_tunnel_hit_counter =
5639 : 0 : spec_mae->ft_ctx->switch_hit_counter;
5640 : : }
5641 : :
5642 [ # # ]: 0 : if (action_rule == NULL)
5643 : : return 0;
5644 : :
5645 : 0 : rc = sfc_mae_action_rule_enable(sa, action_rule);
5646 [ # # ]: 0 : if (rc != 0)
5647 : : return rc;
5648 : :
5649 [ # # ]: 0 : if (spec_mae->action_rule->ct_mark != 0) {
5650 : 0 : struct sfc_mae_counter *counter = spec_mae->ct_counter;
5651 : :
5652 : 0 : rc = sfc_mae_counter_enable(sa, counter, NULL);
5653 [ # # ]: 0 : if (rc != 0) {
5654 : 0 : sfc_mae_action_rule_disable(sa, action_rule);
5655 : 0 : return rc;
5656 : : }
5657 : :
5658 [ # # ]: 0 : if (counter != NULL) {
5659 : : struct sfc_mae_fw_rsrc *fw_rsrc = &counter->fw_rsrc;
5660 : :
5661 : 0 : spec_mae->ct_resp.counter_id = fw_rsrc->counter_id.id;
5662 : :
5663 : 0 : rc = sfc_mae_counter_start(sa);
5664 [ # # ]: 0 : if (rc != 0) {
5665 : 0 : sfc_mae_action_rule_disable(sa, action_rule);
5666 : 0 : return rc;
5667 : : }
5668 : : } else {
5669 : 0 : spec_mae->ct_resp.counter_id = EFX_MAE_RSRC_ID_INVALID;
5670 : : }
5671 : :
5672 : 0 : spec_mae->ct_resp.ct_mark = spec_mae->action_rule->ct_mark;
5673 : :
5674 : 0 : rc = sfc_mae_conntrack_insert(sa, &spec_mae->ct_key,
5675 : 0 : &spec_mae->ct_resp);
5676 [ # # ]: 0 : if (rc != 0) {
5677 : 0 : sfc_mae_counter_disable(sa, counter);
5678 : 0 : sfc_mae_action_rule_disable(sa, action_rule);
5679 : 0 : return rc;
5680 : : }
5681 : : }
5682 : :
5683 : : return 0;
5684 : : }
5685 : :
5686 : : int
5687 : 0 : sfc_mae_flow_remove(struct sfc_adapter *sa,
5688 : : struct rte_flow *flow)
5689 : : {
5690 : : struct sfc_flow_spec *spec = &flow->spec;
5691 : : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
5692 : 0 : struct sfc_mae_action_rule *action_rule = spec_mae->action_rule;
5693 : :
5694 [ # # ]: 0 : if (action_rule == NULL)
5695 : : return 0;
5696 : :
5697 [ # # ]: 0 : if (action_rule->ct_mark != 0)
5698 : 0 : (void)sfc_mae_conntrack_delete(sa, &spec_mae->ct_key);
5699 : :
5700 : 0 : sfc_mae_counter_disable(sa, spec_mae->ct_counter);
5701 : :
5702 : 0 : sfc_mae_action_rule_disable(sa, action_rule);
5703 : :
5704 : 0 : return 0;
5705 : : }
5706 : :
5707 : : static int
5708 : 0 : sfc_mae_query_counter(struct sfc_adapter *sa,
5709 : : struct sfc_flow_spec_mae *spec,
5710 : : const struct rte_flow_action *action,
5711 : : struct rte_flow_query_count *data,
5712 : : struct rte_flow_error *error)
5713 : : {
5714 : 0 : const struct sfc_mae_action_rule *action_rule = spec->action_rule;
5715 : 0 : const struct rte_flow_action_count *conf = action->conf;
5716 : : struct sfc_mae_counter *counters[1 /* action rule counter */ +
5717 : : 1 /* conntrack counter */];
5718 : : struct sfc_mae_counter *counter;
5719 : : unsigned int i;
5720 : : int rc;
5721 : :
5722 : : /*
5723 : : * The check for counter unavailability is done based
5724 : : * on counter traversal results. See error set below.
5725 : : */
5726 [ # # # # ]: 0 : if (action_rule != NULL && action_rule->action_set != NULL &&
5727 [ # # ]: 0 : action_rule->action_set->counter != NULL &&
5728 [ # # ]: 0 : !action_rule->action_set->counter->indirect)
5729 : 0 : counters[0] = action_rule->action_set->counter;
5730 : : else
5731 : 0 : counters[0] = NULL;
5732 : :
5733 : 0 : counters[1] = spec->ct_counter;
5734 : :
5735 [ # # ]: 0 : for (i = 0; i < RTE_DIM(counters); ++i) {
5736 : 0 : counter = counters[i];
5737 : :
5738 [ # # ]: 0 : if (counter == NULL)
5739 : 0 : continue;
5740 : :
5741 [ # # ]: 0 : if (conf == NULL ||
5742 [ # # # # ]: 0 : (counter->rte_id_valid && conf->id == counter->rte_id)) {
5743 : 0 : rc = sfc_mae_counter_get(sa, counter, data);
5744 [ # # ]: 0 : if (rc != 0) {
5745 : 0 : return rte_flow_error_set(error, EINVAL,
5746 : : RTE_FLOW_ERROR_TYPE_ACTION, action,
5747 : : "Queried flow rule counter action is invalid");
5748 : : }
5749 : :
5750 : : return 0;
5751 : : }
5752 : : }
5753 : :
5754 [ # # # # ]: 0 : if (action_rule == NULL || action_rule->action_set_list == NULL)
5755 : 0 : goto exit;
5756 : :
5757 [ # # ]: 0 : for (i = 0; i < action_rule->action_set_list->nb_action_sets; ++i) {
5758 : 0 : counter = action_rule->action_set_list->action_sets[i]->counter;
5759 : :
5760 [ # # # # ]: 0 : if (counter == NULL || counter->indirect)
5761 : 0 : continue;
5762 : :
5763 [ # # ]: 0 : if (conf == NULL ||
5764 [ # # # # ]: 0 : (counter->rte_id_valid && conf->id == counter->rte_id)) {
5765 : 0 : rc = sfc_mae_counter_get(sa, counter, data);
5766 [ # # ]: 0 : if (rc != 0) {
5767 : 0 : return rte_flow_error_set(error, EINVAL,
5768 : : RTE_FLOW_ERROR_TYPE_ACTION, action,
5769 : : "Queried flow rule counter action is invalid");
5770 : : }
5771 : :
5772 : : return 0;
5773 : : }
5774 : : }
5775 : :
5776 : 0 : exit:
5777 : 0 : return rte_flow_error_set(error, ENOENT,
5778 : : RTE_FLOW_ERROR_TYPE_ACTION, action,
5779 : : "no such flow rule action or such count ID");
5780 : : }
5781 : :
5782 : : int
5783 [ # # ]: 0 : sfc_mae_flow_query(struct rte_eth_dev *dev,
5784 : : struct rte_flow *flow,
5785 : : const struct rte_flow_action *action,
5786 : : void *data,
5787 : : struct rte_flow_error *error)
5788 : : {
5789 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
5790 : : struct sfc_flow_spec *spec = &flow->spec;
5791 : 0 : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
5792 : :
5793 [ # # ]: 0 : switch (action->type) {
5794 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
5795 : 0 : return sfc_mae_query_counter(sa, spec_mae, action,
5796 : : data, error);
5797 : 0 : default:
5798 : 0 : return rte_flow_error_set(error, ENOTSUP,
5799 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5800 : : "Query for action of this type is not supported");
5801 : : }
5802 : : }
5803 : :
5804 : : int
5805 : 0 : sfc_mae_switchdev_init(struct sfc_adapter *sa)
5806 : : {
5807 : : struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
5808 : : struct sfc_mae *mae = &sa->mae;
5809 : : int rc = EINVAL;
5810 : :
5811 : 0 : sfc_log_init(sa, "entry");
5812 : :
5813 [ # # ]: 0 : if (!sa->switchdev) {
5814 : 0 : sfc_log_init(sa, "switchdev is not enabled - skip");
5815 : 0 : return 0;
5816 : : }
5817 : :
5818 [ # # ]: 0 : if (mae->status != SFC_MAE_STATUS_ADMIN) {
5819 : : rc = ENOTSUP;
5820 : 0 : sfc_err(sa, "failed to init switchdev - no admin MAE privilege");
5821 : 0 : goto fail_no_mae;
5822 : : }
5823 : :
5824 : 0 : mae->switchdev_rule_pf_to_ext = sfc_mae_repr_flow_create(sa,
5825 : 0 : SFC_MAE_RULE_PRIO_LOWEST, sas->port_id,
5826 : : RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT,
5827 : : RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR);
5828 [ # # ]: 0 : if (mae->switchdev_rule_pf_to_ext == NULL) {
5829 : 0 : sfc_err(sa, "failed add MAE rule to forward from PF to PHY");
5830 : 0 : goto fail_pf_add;
5831 : : }
5832 : :
5833 : 0 : mae->switchdev_rule_ext_to_pf = sfc_mae_repr_flow_create(sa,
5834 : 0 : SFC_MAE_RULE_PRIO_LOWEST, sas->port_id,
5835 : : RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR,
5836 : : RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT);
5837 [ # # ]: 0 : if (mae->switchdev_rule_ext_to_pf == NULL) {
5838 : 0 : sfc_err(sa, "failed add MAE rule to forward from PHY to PF");
5839 : 0 : goto fail_phy_add;
5840 : : }
5841 : :
5842 : 0 : sfc_log_init(sa, "done");
5843 : :
5844 : 0 : return 0;
5845 : :
5846 : : fail_phy_add:
5847 : 0 : sfc_mae_repr_flow_destroy(sa, mae->switchdev_rule_pf_to_ext);
5848 : :
5849 : 0 : fail_pf_add:
5850 : 0 : fail_no_mae:
5851 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
5852 : 0 : return rc;
5853 : : }
5854 : :
5855 : : void
5856 : 0 : sfc_mae_switchdev_fini(struct sfc_adapter *sa)
5857 : : {
5858 : : struct sfc_mae *mae = &sa->mae;
5859 : :
5860 [ # # ]: 0 : if (!sa->switchdev)
5861 : : return;
5862 : :
5863 : 0 : sfc_mae_repr_flow_destroy(sa, mae->switchdev_rule_pf_to_ext);
5864 : 0 : sfc_mae_repr_flow_destroy(sa, mae->switchdev_rule_ext_to_pf);
5865 : : }
5866 : :
5867 : : int
5868 : 0 : sfc_mae_indir_action_create(struct sfc_adapter *sa,
5869 : : const struct rte_flow_action *action,
5870 : : struct rte_flow_action_handle *handle,
5871 : : struct rte_flow_error *error)
5872 : : {
5873 : 0 : struct sfc_mae *mae = &sa->mae;
5874 : : bool custom_error = false;
5875 : : int ret;
5876 : :
5877 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
5878 : : SFC_ASSERT(handle != NULL);
5879 : :
5880 [ # # # ]: 0 : switch (action->type) {
5881 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5882 : : /* Cleanup after previous encap. header bounce buffer usage. */
5883 : : sfc_mae_bounce_eh_invalidate(&mae->bounce_eh);
5884 : :
5885 : 0 : ret = sfc_mae_rule_parse_action_vxlan_encap(mae, action->conf,
5886 : : NULL, error);
5887 [ # # ]: 0 : if (ret != 0) {
5888 : : custom_error = true;
5889 : : break;
5890 : : }
5891 : :
5892 : 0 : ret = sfc_mae_encap_header_add(sa, &mae->bounce_eh,
5893 : : &handle->encap_header);
5894 [ # # ]: 0 : if (ret == 0)
5895 : 0 : handle->encap_header->indirect = true;
5896 : : break;
5897 : :
5898 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
5899 : 0 : ret = sfc_mae_rule_parse_action_count(sa, action->conf,
5900 : : EFX_COUNTER_TYPE_ACTION,
5901 : : &handle->counter, NULL);
5902 [ # # ]: 0 : if (ret == 0)
5903 : 0 : handle->counter->indirect = true;
5904 : : break;
5905 : : default:
5906 : : ret = ENOTSUP;
5907 : : }
5908 : :
5909 : : if (custom_error)
5910 : : return ret;
5911 : :
5912 [ # # ]: 0 : if (ret != 0) {
5913 : 0 : return rte_flow_error_set(error, ret,
5914 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5915 : : "failed to parse indirect action to mae object");
5916 : : }
5917 : :
5918 : 0 : handle->type = action->type;
5919 : :
5920 : 0 : return 0;
5921 : : }
5922 : :
5923 : : int
5924 : 0 : sfc_mae_indir_action_destroy(struct sfc_adapter *sa,
5925 : : const struct rte_flow_action_handle *handle,
5926 : : struct rte_flow_error *error)
5927 : : {
5928 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
5929 : : SFC_ASSERT(handle != NULL);
5930 : :
5931 [ # # # ]: 0 : switch (handle->type) {
5932 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5933 [ # # ]: 0 : if (handle->encap_header->refcnt != 1)
5934 : 0 : goto fail;
5935 : :
5936 : 0 : sfc_mae_encap_header_del(sa, handle->encap_header);
5937 : 0 : break;
5938 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
5939 [ # # ]: 0 : if (handle->counter->refcnt != 1)
5940 : 0 : goto fail;
5941 : :
5942 : 0 : sfc_mae_counter_del(sa, handle->counter);
5943 : 0 : break;
5944 : : default:
5945 : : SFC_ASSERT(B_FALSE);
5946 : : break;
5947 : : }
5948 : :
5949 : : return 0;
5950 : :
5951 : 0 : fail:
5952 : 0 : return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5953 : : NULL, "indirect action is still in use");
5954 : : }
5955 : :
5956 : : int
5957 : 0 : sfc_mae_indir_action_update(struct sfc_adapter *sa,
5958 : : struct rte_flow_action_handle *handle,
5959 : : const void *update, struct rte_flow_error *error)
5960 : : {
5961 : : const struct rte_flow_action *action = update;
5962 : 0 : struct sfc_mae *mae = &sa->mae;
5963 : : bool custom_error = false;
5964 : : int ret;
5965 : :
5966 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
5967 : : SFC_ASSERT(action != NULL);
5968 : : SFC_ASSERT(handle != NULL);
5969 : :
5970 [ # # ]: 0 : switch (handle->type) {
5971 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5972 : : /* Cleanup after previous encap. header bounce buffer usage. */
5973 : : sfc_mae_bounce_eh_invalidate(&mae->bounce_eh);
5974 : :
5975 : 0 : ret = sfc_mae_rule_parse_action_vxlan_encap(mae, action->conf,
5976 : : NULL, error);
5977 [ # # ]: 0 : if (ret != 0) {
5978 : : custom_error = true;
5979 : : break;
5980 : : }
5981 : :
5982 : 0 : ret = sfc_mae_encap_header_update(sa, handle->encap_header);
5983 : : break;
5984 : : default:
5985 : : ret = ENOTSUP;
5986 : : }
5987 : :
5988 : : if (custom_error)
5989 : : return ret;
5990 : :
5991 [ # # ]: 0 : if (ret != 0) {
5992 : 0 : return rte_flow_error_set(error, ret,
5993 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5994 : : "failed to parse indirect action to mae object");
5995 : : }
5996 : :
5997 : : return 0;
5998 : : }
5999 : :
6000 : : int
6001 : 0 : sfc_mae_indir_action_query(struct sfc_adapter *sa,
6002 : : const struct rte_flow_action_handle *handle,
6003 : : void *data, struct rte_flow_error *error)
6004 : : {
6005 : : int ret;
6006 : :
6007 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
6008 : : SFC_ASSERT(handle != NULL);
6009 : :
6010 [ # # ]: 0 : switch (handle->type) {
6011 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
6012 : : SFC_ASSERT(handle->counter != NULL);
6013 : :
6014 [ # # ]: 0 : if (handle->counter->fw_rsrc.refcnt == 0)
6015 : 0 : goto fail_not_in_use;
6016 : :
6017 : 0 : ret = sfc_mae_counter_get(sa, handle->counter, data);
6018 [ # # ]: 0 : if (ret != 0)
6019 : 0 : goto fail_counter_get;
6020 : :
6021 : : break;
6022 : 0 : default:
6023 : 0 : goto fail_unsup;
6024 : : }
6025 : :
6026 : : return 0;
6027 : :
6028 : : fail_not_in_use:
6029 : 0 : return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6030 : : NULL, "indirect action is not in use");
6031 : :
6032 : : fail_counter_get:
6033 : 0 : return rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6034 : : NULL, "failed to collect indirect action COUNT data");
6035 : :
6036 : : fail_unsup:
6037 : 0 : return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6038 : : NULL, "indirect action of this type cannot be queried");
6039 : : }
|