#include <stdint.h>
#include "sfc.h"
+#include "sfc_flow.h"
#include "sfc_dp_rx.h"
#include "sfc_flow_tunnel.h"
#include "sfc_mae.h"
return ((sa->negotiated_rx_metadata &
RTE_ETH_RX_METADATA_TUNNEL_ID) != 0);
}
+
+struct sfc_flow_tunnel *
+sfc_flow_tunnel_pick(struct sfc_adapter *sa, uint32_t ft_mark)
+{
+ uint32_t tunnel_mark = SFC_FT_GET_TUNNEL_MARK(ft_mark);
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ if (tunnel_mark != SFC_FT_TUNNEL_MARK_INVALID) {
+ sfc_ft_id_t ft_id = SFC_FT_TUNNEL_MARK_TO_ID(tunnel_mark);
+ struct sfc_flow_tunnel *ft = &sa->flow_tunnels[ft_id];
+
+ ft->id = ft_id;
+
+ return ft;
+ }
+
+ return NULL;
+}
+
+int
+sfc_flow_tunnel_detect_jump_rule(struct sfc_adapter *sa,
+ const struct rte_flow_action *actions,
+ struct sfc_flow_spec_mae *spec,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_action_mark *action_mark = NULL;
+ const struct rte_flow_action_jump *action_jump = NULL;
+ struct sfc_flow_tunnel *ft;
+ uint32_t ft_mark = 0;
+ int rc = 0;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ if (!sfc_flow_tunnel_is_active(sa)) {
+ /* Tunnel-related actions (if any) will be turned down later. */
+ return 0;
+ }
+
+ if (actions == NULL) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
+ "NULL actions");
+ return -rte_errno;
+ }
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
+ if (actions->type == RTE_FLOW_ACTION_TYPE_VOID)
+ continue;
+
+ if (actions->conf == NULL) {
+ rc = EINVAL;
+ continue;
+ }
+
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_MARK:
+ if (action_mark == NULL) {
+ action_mark = actions->conf;
+ ft_mark = action_mark->id;
+ } else {
+ rc = EINVAL;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_JUMP:
+ if (action_jump == NULL) {
+ action_jump = actions->conf;
+ if (action_jump->group != 0)
+ rc = EINVAL;
+ } else {
+ rc = EINVAL;
+ }
+ break;
+ default:
+ rc = ENOTSUP;
+ break;
+ }
+ }
+
+ ft = sfc_flow_tunnel_pick(sa, ft_mark);
+ if (ft != NULL && action_jump != 0) {
+ sfc_dbg(sa, "tunnel offload: JUMP: detected");
+
+ if (rc != 0) {
+ /* The loop above might have spotted wrong actions. */
+ sfc_err(sa, "tunnel offload: JUMP: invalid actions: %s",
+ strerror(rc));
+ goto fail;
+ }
+
+ if (ft->refcnt == 0) {
+ sfc_err(sa, "tunnel offload: JUMP: tunnel=%u does not exist",
+ ft->id);
+ rc = ENOENT;
+ goto fail;
+ }
+
+ if (ft->jump_rule_is_set) {
+ sfc_err(sa, "tunnel offload: JUMP: already exists in tunnel=%u",
+ ft->id);
+ rc = EEXIST;
+ goto fail;
+ }
+
+ spec->ft_rule_type = SFC_FT_RULE_JUMP;
+ spec->ft = ft;
+ }
+
+ return 0;
+
+fail:
+ return rte_flow_error_set(error, rc,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "tunnel offload: JUMP: preparsing failed");
+}
}
}
+ if (match_spec_action == NULL)
+ goto skip_action_rule;
+
rc = efx_mae_match_spec_outer_rule_id_set(match_spec_action,
&fw_rsrc->rule_id);
if (rc != 0) {
return rc;
}
+skip_action_rule:
if (fw_rsrc->refcnt == 0) {
sfc_dbg(sa, "enabled outer_rule=%p: OR_ID=0x%08x",
rule, fw_rsrc->rule_id.id);
spec_mae = &spec->mae;
+ if (spec_mae->ft != NULL) {
+ if (spec_mae->ft_rule_type == SFC_FT_RULE_JUMP)
+ spec_mae->ft->jump_rule_is_set = B_FALSE;
+
+ SFC_ASSERT(spec_mae->ft->refcnt != 0);
+ --(spec_mae->ft->refcnt);
+ }
+
SFC_ASSERT(spec_mae->rule_id.id == EFX_MAE_RSRC_ID_INVALID);
if (spec_mae->outer_rule != NULL)
ctx->match_spec_outer = NULL;
no_or_id:
+ switch (ctx->ft_rule_type) {
+ case SFC_FT_RULE_NONE:
+ break;
+ case SFC_FT_RULE_JUMP:
+ /* No action rule */
+ return 0;
+ default:
+ SFC_ASSERT(B_FALSE);
+ }
+
/*
* In MAE, lookup sequence comprises outer parse, outer rule lookup,
* inner parse (when some outer rule is hit) and action rule lookup.
struct rte_flow_error *error)
{
struct sfc_mae *mae = &sa->mae;
+ uint8_t recirc_id = 0;
int rc;
if (pattern == NULL) {
break;
}
- if (pattern->type == RTE_FLOW_ITEM_TYPE_END)
- return 0;
+ switch (ctx->ft_rule_type) {
+ case SFC_FT_RULE_NONE:
+ if (pattern->type == RTE_FLOW_ITEM_TYPE_END)
+ return 0;
+ break;
+ case SFC_FT_RULE_JUMP:
+ if (pattern->type != RTE_FLOW_ITEM_TYPE_END) {
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ pattern, "tunnel offload: JUMP: invalid item");
+ }
+ ctx->encap_type = ctx->ft->encap_type;
+ break;
+ default:
+ SFC_ASSERT(B_FALSE);
+ break;
+ }
if ((mae->encap_types_supported & (1U << ctx->encap_type)) == 0) {
return rte_flow_error_set(error, ENOTSUP,
- RTE_FLOW_ERROR_TYPE_ITEM,
- pattern, "Unsupported tunnel item");
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "OR: unsupported tunnel type");
}
- if (ctx->priority >= mae->nb_outer_rule_prios_max) {
- return rte_flow_error_set(error, ENOTSUP,
- RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
- NULL, "Unsupported priority level");
- }
+ switch (ctx->ft_rule_type) {
+ case SFC_FT_RULE_JUMP:
+ recirc_id = SFC_FT_ID_TO_TUNNEL_MARK(ctx->ft->id);
+ /* FALLTHROUGH */
+ case SFC_FT_RULE_NONE:
+ if (ctx->priority >= mae->nb_outer_rule_prios_max) {
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ NULL, "OR: unsupported priority level");
+ }
- rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_OUTER, ctx->priority,
- &ctx->match_spec_outer);
- if (rc != 0) {
- return rte_flow_error_set(error, rc,
- RTE_FLOW_ERROR_TYPE_ITEM, pattern,
- "Failed to initialise outer rule match specification");
- }
+ rc = efx_mae_match_spec_init(sa->nic,
+ EFX_MAE_RULE_OUTER, ctx->priority,
+ &ctx->match_spec_outer);
+ if (rc != 0) {
+ return rte_flow_error_set(error, rc,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "OR: failed to initialise the match specification");
+ }
- /* Outermost items comprise a match specification of type OUTER. */
- ctx->match_spec = ctx->match_spec_outer;
+ /*
+ * Outermost items comprise a match
+ * specification of type OUTER.
+ */
+ ctx->match_spec = ctx->match_spec_outer;
- /* Outermost items use "ENC" EFX MAE field IDs. */
- ctx->field_ids_remap = field_ids_remap_to_encap;
+ /* Outermost items use "ENC" EFX MAE field IDs. */
+ ctx->field_ids_remap = field_ids_remap_to_encap;
+
+ rc = efx_mae_outer_rule_recirc_id_set(ctx->match_spec,
+ recirc_id);
+ if (rc != 0) {
+ return rte_flow_error_set(error, rc,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "OR: failed to initialise RECIRC_ID");
+ }
+ break;
+ default:
+ SFC_ASSERT(B_FALSE);
+ break;
+ }
return 0;
}
int rc;
memset(&ctx_mae, 0, sizeof(ctx_mae));
+ ctx_mae.ft_rule_type = spec->ft_rule_type;
ctx_mae.priority = spec->priority;
+ ctx_mae.ft = spec->ft;
ctx_mae.sa = sa;
- rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION,
- spec->priority,
- &ctx_mae.match_spec_action);
- if (rc != 0) {
- rc = rte_flow_error_set(error, rc,
- RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
- "Failed to initialise action rule match specification");
- goto fail_init_match_spec_action;
+ switch (ctx_mae.ft_rule_type) {
+ case SFC_FT_RULE_JUMP:
+ /* No action rule */
+ break;
+ case SFC_FT_RULE_NONE:
+ rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION,
+ spec->priority,
+ &ctx_mae.match_spec_action);
+ if (rc != 0) {
+ rc = rte_flow_error_set(error, rc,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "AR: failed to initialise the match specification");
+ goto fail_init_match_spec_action;
+ }
+ break;
+ default:
+ SFC_ASSERT(B_FALSE);
+ break;
}
/*
if (rc != 0)
goto fail_process_outer;
- if (!efx_mae_match_spec_is_valid(sa->nic, ctx_mae.match_spec_action)) {
+ if (ctx_mae.match_spec_action != NULL &&
+ !efx_mae_match_spec_is_valid(sa->nic, ctx_mae.match_spec_action)) {
rc = rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ITEM, NULL,
"Inconsistent pattern");
sfc_mae_rule_encap_parse_fini(sa, &ctx_mae);
fail_encap_parse_init:
- efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action);
+ if (ctx_mae.match_spec_action != NULL)
+ efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action);
fail_init_match_spec_action:
return rc;
{
const struct rte_flow *entry;
+ if (spec->match_spec == NULL)
+ return 0;
+
TAILQ_FOREACH_REVERSE(entry, &sa->flow_list, sfc_flow_list, entries) {
const struct sfc_flow_spec *entry_spec = &entry->spec;
const struct sfc_flow_spec_mae *es_mae = &entry_spec->mae;
struct sfc_flow_spec_mae *spec_mae = &spec->mae;
struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule;
struct sfc_mae_action_set *action_set = spec_mae->action_set;
- struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc;
+ struct sfc_mae_fw_rsrc *fw_rsrc;
int rc;
SFC_ASSERT(spec_mae->rule_id.id == EFX_MAE_RSRC_ID_INVALID);
- SFC_ASSERT(action_set != NULL);
if (outer_rule != NULL) {
rc = sfc_mae_outer_rule_enable(sa, outer_rule,
goto fail_outer_rule_enable;
}
+ if (action_set == NULL) {
+ sfc_dbg(sa, "enabled flow=%p (no AR)", flow);
+ return 0;
+ }
+
rc = sfc_mae_action_set_enable(sa, action_set);
if (rc != 0)
goto fail_action_set_enable;
}
}
+ fw_rsrc = &action_set->fw_rsrc;
+
rc = efx_mae_action_rule_insert(sa->nic, spec_mae->match_spec,
NULL, &fw_rsrc->aset_id,
&spec_mae->rule_id);
struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule;
int rc;
+ if (action_set == NULL) {
+ sfc_dbg(sa, "disabled flow=%p (no AR)", flow);
+ goto skip_action_rule;
+ }
+
SFC_ASSERT(spec_mae->rule_id.id != EFX_MAE_RSRC_ID_INVALID);
- SFC_ASSERT(action_set != NULL);
rc = efx_mae_action_rule_remove(sa->nic, &spec_mae->rule_id);
if (rc != 0) {
sfc_mae_action_set_disable(sa, action_set);
+skip_action_rule:
if (outer_rule != NULL)
sfc_mae_outer_rule_disable(sa, outer_rule);
unsigned int i;
int rc;
- if (action_set->n_counters == 0) {
+ if (action_set == NULL || action_set->n_counters == 0) {
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION, action,
"Queried flow rule does not have count actions");