From 4c6005999e41d71fb449652ee7f1ff4924e0affe Mon Sep 17 00:00:00 2001 From: Ivan Malov Date: Wed, 17 Nov 2021 14:44:38 +0300 Subject: [PATCH] net/sfc: support MAC address edits in transfer flows These edits affect the outermost header in the current processing state of the packet, which might have been decapsulated by prior action DECAP. Signed-off-by: Ivan Malov Reviewed-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- doc/guides/nics/features/sfc.ini | 2 + doc/guides/nics/sfc_efx.rst | 4 + drivers/net/sfc/sfc_mae.c | 292 ++++++++++++++++++++++++++++++- drivers/net/sfc/sfc_mae.h | 15 ++ 4 files changed, 310 insertions(+), 3 deletions(-) diff --git a/doc/guides/nics/features/sfc.ini b/doc/guides/nics/features/sfc.ini index 1ce2dc46ba..2e798b5ef5 100644 --- a/doc/guides/nics/features/sfc.ini +++ b/doc/guides/nics/features/sfc.ini @@ -79,6 +79,8 @@ port_representor = Y represented_port = Y queue = Y rss = Y +set_mac_dst = Y +set_mac_src = Y vf = Y vxlan_decap = Y vxlan_encap = Y diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst index 00b95a4f58..39c6e23d5b 100644 --- a/doc/guides/nics/sfc_efx.rst +++ b/doc/guides/nics/sfc_efx.rst @@ -234,6 +234,10 @@ Supported actions (***transfer*** rules): - OF_VLAN_SET_PCP +- SET_MAC_DST + +- SET_MAC_SRC + - OF_DEC_NW_TTL - DEC_TTL diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c index b7a148afae..b34c9afd5b 100644 --- a/drivers/net/sfc/sfc_mae.c +++ b/drivers/net/sfc/sfc_mae.c @@ -290,6 +290,7 @@ sfc_mae_attach(struct sfc_adapter *sa) } TAILQ_INIT(&mae->outer_rules); + TAILQ_INIT(&mae->mac_addrs); TAILQ_INIT(&mae->encap_headers); TAILQ_INIT(&mae->action_sets); @@ -506,6 +507,189 @@ sfc_mae_outer_rule_disable(struct sfc_adapter *sa, --(fw_rsrc->refcnt); } +static struct sfc_mae_mac_addr * +sfc_mae_mac_addr_attach(struct sfc_adapter *sa, + const uint8_t addr_bytes[EFX_MAC_ADDR_LEN]) +{ + struct sfc_mae_mac_addr *mac_addr; + struct sfc_mae *mae = &sa->mae; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + TAILQ_FOREACH(mac_addr, &mae->mac_addrs, entries) { + if (memcmp(mac_addr->addr_bytes, addr_bytes, + EFX_MAC_ADDR_LEN) == 0) { + sfc_dbg(sa, "attaching to mac_addr=%p", mac_addr); + ++(mac_addr->refcnt); + return mac_addr; + } + } + + return NULL; +} + +static int +sfc_mae_mac_addr_add(struct sfc_adapter *sa, + const uint8_t addr_bytes[EFX_MAC_ADDR_LEN], + struct sfc_mae_mac_addr **mac_addrp) +{ + struct sfc_mae_mac_addr *mac_addr; + struct sfc_mae *mae = &sa->mae; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + mac_addr = rte_zmalloc("sfc_mae_mac_addr", sizeof(*mac_addr), 0); + if (mac_addr == NULL) + return ENOMEM; + + rte_memcpy(mac_addr->addr_bytes, addr_bytes, EFX_MAC_ADDR_LEN); + + mac_addr->refcnt = 1; + mac_addr->fw_rsrc.mac_id.id = EFX_MAE_RSRC_ID_INVALID; + + TAILQ_INSERT_TAIL(&mae->mac_addrs, mac_addr, entries); + + *mac_addrp = mac_addr; + + sfc_dbg(sa, "added mac_addr=%p", mac_addr); + + return 0; +} + +static void +sfc_mae_mac_addr_del(struct sfc_adapter *sa, struct sfc_mae_mac_addr *mac_addr) +{ + struct sfc_mae *mae = &sa->mae; + + if (mac_addr == NULL) + return; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + SFC_ASSERT(mac_addr->refcnt != 0); + + --(mac_addr->refcnt); + + if (mac_addr->refcnt != 0) + return; + + if (mac_addr->fw_rsrc.mac_id.id != EFX_MAE_RSRC_ID_INVALID || + mac_addr->fw_rsrc.refcnt != 0) { + sfc_err(sa, "deleting mac_addr=%p abandons its FW resource: MAC_ID=0x%08x, refcnt=%u", + mac_addr, mac_addr->fw_rsrc.mac_id.id, + mac_addr->fw_rsrc.refcnt); + } + + TAILQ_REMOVE(&mae->mac_addrs, mac_addr, entries); + rte_free(mac_addr); + + sfc_dbg(sa, "deleted mac_addr=%p", mac_addr); +} + +enum sfc_mae_mac_addr_type { + SFC_MAE_MAC_ADDR_DST, + SFC_MAE_MAC_ADDR_SRC +}; + +static int +sfc_mae_mac_addr_enable(struct sfc_adapter *sa, + struct sfc_mae_mac_addr *mac_addr, + enum sfc_mae_mac_addr_type type, + efx_mae_actions_t *aset_spec) +{ + struct sfc_mae_fw_rsrc *fw_rsrc; + int rc = 0; + + if (mac_addr == NULL) + return 0; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + fw_rsrc = &mac_addr->fw_rsrc; + + if (fw_rsrc->refcnt == 0) { + SFC_ASSERT(fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID); + + rc = efx_mae_mac_addr_alloc(sa->nic, mac_addr->addr_bytes, + &fw_rsrc->mac_id); + if (rc != 0) { + sfc_err(sa, "failed to enable mac_addr=%p: %s", + mac_addr, strerror(rc)); + return rc; + } + } + + switch (type) { + case SFC_MAE_MAC_ADDR_DST: + rc = efx_mae_action_set_fill_in_dst_mac_id(aset_spec, + &fw_rsrc->mac_id); + break; + case SFC_MAE_MAC_ADDR_SRC: + rc = efx_mae_action_set_fill_in_src_mac_id(aset_spec, + &fw_rsrc->mac_id); + break; + default: + rc = EINVAL; + break; + } + + if (rc != 0) { + if (fw_rsrc->refcnt == 0) { + (void)efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id); + fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID; + } + + sfc_err(sa, "cannot fill in MAC address entry ID: %s", + strerror(rc)); + + return rc; + } + + if (fw_rsrc->refcnt == 0) { + sfc_dbg(sa, "enabled mac_addr=%p: MAC_ID=0x%08x", + mac_addr, fw_rsrc->mac_id.id); + } + + ++(fw_rsrc->refcnt); + + return 0; +} + +static void +sfc_mae_mac_addr_disable(struct sfc_adapter *sa, + struct sfc_mae_mac_addr *mac_addr) +{ + struct sfc_mae_fw_rsrc *fw_rsrc; + int rc; + + if (mac_addr == NULL) + return; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + fw_rsrc = &mac_addr->fw_rsrc; + + if (fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID || + fw_rsrc->refcnt == 0) { + sfc_err(sa, "failed to disable mac_addr=%p: already disabled; MAC_ID=0x%08x, refcnt=%u", + mac_addr, fw_rsrc->mac_id.id, fw_rsrc->refcnt); + return; + } + + if (fw_rsrc->refcnt == 1) { + rc = efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id); + if (rc == 0) { + sfc_dbg(sa, "disabled mac_addr=%p with MAC_ID=0x%08x", + mac_addr, fw_rsrc->mac_id.id); + } else { + sfc_err(sa, "failed to disable mac_addr=%p with MAC_ID=0x%08x: %s", + mac_addr, fw_rsrc->mac_id.id, strerror(rc)); + } + fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID; + } + + --(fw_rsrc->refcnt); +} + static struct sfc_mae_encap_header * sfc_mae_encap_header_attach(struct sfc_adapter *sa, const struct sfc_mae_bounce_eh *bounce_eh) @@ -757,6 +941,8 @@ struct sfc_mae_aset_ctx { struct sfc_mae_encap_header *encap_header; struct sfc_flow_tunnel *counter_ft; unsigned int n_counters; + struct sfc_mae_mac_addr *dst_mac; + struct sfc_mae_mac_addr *src_mac; efx_mae_actions_t *spec; }; @@ -779,6 +965,8 @@ sfc_mae_action_set_attach(struct sfc_adapter *sa, TAILQ_FOREACH(action_set, &mae->action_sets, entries) { if (action_set->encap_header == ctx->encap_header && + action_set->dst_mac_addr == ctx->dst_mac && + action_set->src_mac_addr == ctx->src_mac && efx_mae_action_set_specs_equal(action_set->spec, ctx->spec)) { sfc_dbg(sa, "attaching to action_set=%p", action_set); @@ -849,6 +1037,8 @@ sfc_mae_action_set_add(struct sfc_adapter *sa, action_set->refcnt = 1; action_set->spec = ctx->spec; action_set->encap_header = ctx->encap_header; + action_set->dst_mac_addr = ctx->dst_mac; + action_set->src_mac_addr = ctx->src_mac; action_set->fw_rsrc.aset_id.id = EFX_MAE_RSRC_ID_INVALID; @@ -884,6 +1074,8 @@ sfc_mae_action_set_del(struct sfc_adapter *sa, efx_mae_action_set_spec_fini(sa->nic, action_set->spec); sfc_mae_encap_header_del(sa, action_set->encap_header); + sfc_mae_mac_addr_del(sa, action_set->dst_mac_addr); + sfc_mae_mac_addr_del(sa, action_set->src_mac_addr); if (action_set->n_counters > 0) { SFC_ASSERT(action_set->n_counters == 1); SFC_ASSERT(action_set->counters[0].mae_id.id == @@ -901,6 +1093,8 @@ sfc_mae_action_set_enable(struct sfc_adapter *sa, struct sfc_mae_action_set *action_set) { struct sfc_mae_encap_header *encap_header = action_set->encap_header; + struct sfc_mae_mac_addr *dst_mac_addr = action_set->dst_mac_addr; + struct sfc_mae_mac_addr *src_mac_addr = action_set->src_mac_addr; struct sfc_mae_counter_id *counters = action_set->counters; struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc; int rc; @@ -911,10 +1105,27 @@ sfc_mae_action_set_enable(struct sfc_adapter *sa, SFC_ASSERT(fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID); SFC_ASSERT(action_set->spec != NULL); + rc = sfc_mae_mac_addr_enable(sa, dst_mac_addr, + SFC_MAE_MAC_ADDR_DST, + action_set->spec); + if (rc != 0) + return rc; + + rc = sfc_mae_mac_addr_enable(sa, src_mac_addr, + SFC_MAE_MAC_ADDR_SRC, + action_set->spec); + if (rc != 0) { + sfc_mae_mac_addr_disable(sa, dst_mac_addr); + return rc; + } + rc = sfc_mae_encap_header_enable(sa, encap_header, action_set->spec); - if (rc != 0) + if (rc != 0) { + sfc_mae_mac_addr_disable(sa, src_mac_addr); + sfc_mae_mac_addr_disable(sa, dst_mac_addr); return rc; + } rc = sfc_mae_counters_enable(sa, counters, action_set->n_counters, @@ -924,6 +1135,8 @@ sfc_mae_action_set_enable(struct sfc_adapter *sa, action_set->n_counters, rte_strerror(rc)); sfc_mae_encap_header_disable(sa, encap_header); + sfc_mae_mac_addr_disable(sa, src_mac_addr); + sfc_mae_mac_addr_disable(sa, dst_mac_addr); return rc; } @@ -936,6 +1149,8 @@ sfc_mae_action_set_enable(struct sfc_adapter *sa, (void)sfc_mae_counters_disable(sa, counters, action_set->n_counters); sfc_mae_encap_header_disable(sa, encap_header); + sfc_mae_mac_addr_disable(sa, src_mac_addr); + sfc_mae_mac_addr_disable(sa, dst_mac_addr); return rc; } @@ -983,6 +1198,8 @@ sfc_mae_action_set_disable(struct sfc_adapter *sa, } sfc_mae_encap_header_disable(sa, action_set->encap_header); + sfc_mae_mac_addr_disable(sa, action_set->src_mac_addr); + sfc_mae_mac_addr_disable(sa, action_set->dst_mac_addr); } --(fw_rsrc->refcnt); @@ -2895,6 +3112,54 @@ fail_priority_check: return rc; } +static int +sfc_mae_rule_parse_action_set_mac(struct sfc_adapter *sa, + enum sfc_mae_mac_addr_type type, + const struct rte_flow_action_set_mac *conf, + struct sfc_mae_aset_ctx *ctx, + struct rte_flow_error *error) +{ + struct sfc_mae_mac_addr **mac_addrp; + int rc; + + if (conf == NULL) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL, + "the MAC address entry definition is NULL"); + } + + switch (type) { + case SFC_MAE_MAC_ADDR_DST: + rc = efx_mae_action_set_populate_set_dst_mac(ctx->spec); + mac_addrp = &ctx->dst_mac; + break; + case SFC_MAE_MAC_ADDR_SRC: + rc = efx_mae_action_set_populate_set_src_mac(ctx->spec); + mac_addrp = &ctx->src_mac; + break; + default: + rc = EINVAL; + break; + } + + if (rc != 0) + goto error; + + *mac_addrp = sfc_mae_mac_addr_attach(sa, conf->mac_addr); + if (*mac_addrp != NULL) + return 0; + + rc = sfc_mae_mac_addr_add(sa, conf->mac_addr, mac_addrp); + if (rc != 0) + goto error; + + return 0; + +error: + return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "failed to request set MAC action"); +} + /* * An action supported by MAE may correspond to a bundle of RTE flow actions, * in example, VLAN_PUSH = OF_PUSH_VLAN + OF_VLAN_SET_VID + OF_VLAN_SET_PCP. @@ -3549,6 +3814,8 @@ sfc_mae_rule_parse_action_represented_port(struct sfc_adapter *sa, static const char * const action_names[] = { [RTE_FLOW_ACTION_TYPE_VXLAN_DECAP] = "VXLAN_DECAP", [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] = "OF_POP_VLAN", + [RTE_FLOW_ACTION_TYPE_SET_MAC_DST] = "SET_MAC_DST", + [RTE_FLOW_ACTION_TYPE_SET_MAC_SRC] = "SET_MAC_SRC", [RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL] = "OF_DEC_NW_TTL", [RTE_FLOW_ACTION_TYPE_DEC_TTL] = "DEC_TTL", [RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN] = "OF_PUSH_VLAN", @@ -3573,11 +3840,12 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa, const struct rte_flow_action *action, const struct sfc_flow_spec_mae *spec_mae, struct sfc_mae_actions_bundle *bundle, - efx_mae_actions_t *spec, + struct sfc_mae_aset_ctx *ctx, struct rte_flow_error *error) { const struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule; const uint64_t rx_metadata = sa->negotiated_rx_metadata; + efx_mae_actions_t *spec = ctx->spec; bool custom_error = B_FALSE; int rc = 0; @@ -3596,6 +3864,22 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa, bundle->actions_mask); rc = efx_mae_action_set_populate_vlan_pop(spec); break; + case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_MAC_DST, + bundle->actions_mask); + rc = sfc_mae_rule_parse_action_set_mac(sa, SFC_MAE_MAC_ADDR_DST, + action->conf, ctx, + error); + custom_error = B_TRUE; + break; + case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_SET_MAC_SRC, + bundle->actions_mask); + rc = sfc_mae_rule_parse_action_set_mac(sa, SFC_MAE_MAC_ADDR_SRC, + action->conf, ctx, + error); + custom_error = B_TRUE; + break; case RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL: case RTE_FLOW_ACTION_TYPE_DEC_TTL: SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_DEC_NW_TTL, @@ -3813,7 +4097,7 @@ sfc_mae_rule_parse_actions(struct sfc_adapter *sa, goto fail_rule_parse_action; rc = sfc_mae_rule_parse_action(sa, action, spec_mae, - &bundle, ctx.spec, error); + &bundle, &ctx, error); if (rc != 0) goto fail_rule_parse_action; } @@ -3880,6 +4164,8 @@ fail_nb_count: fail_process_encap_header: fail_rule_parse_action: + sfc_mae_mac_addr_del(sa, ctx.src_mac); + sfc_mae_mac_addr_del(sa, ctx.dst_mac); efx_mae_action_set_spec_fini(sa->nic, ctx.spec); fail_enforce_ft_count: diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h index 2750fbb9b1..3431aaa734 100644 --- a/drivers/net/sfc/sfc_mae.h +++ b/drivers/net/sfc/sfc_mae.h @@ -29,6 +29,7 @@ struct sfc_mae_fw_rsrc { union { efx_mae_aset_id_t aset_id; efx_mae_rule_id_t rule_id; + efx_mae_mac_id_t mac_id; efx_mae_eh_id_t eh_id; }; }; @@ -44,6 +45,16 @@ struct sfc_mae_outer_rule { TAILQ_HEAD(sfc_mae_outer_rules, sfc_mae_outer_rule); +/** MAC address registry entry */ +struct sfc_mae_mac_addr { + TAILQ_ENTRY(sfc_mae_mac_addr) entries; + unsigned int refcnt; + uint8_t addr_bytes[EFX_MAC_ADDR_LEN]; + struct sfc_mae_fw_rsrc fw_rsrc; +}; + +TAILQ_HEAD(sfc_mae_mac_addrs, sfc_mae_mac_addr); + /** Encap. header registry entry */ struct sfc_mae_encap_header { TAILQ_ENTRY(sfc_mae_encap_header) entries; @@ -79,6 +90,8 @@ struct sfc_mae_action_set { uint32_t n_counters; efx_mae_actions_t *spec; struct sfc_mae_encap_header *encap_header; + struct sfc_mae_mac_addr *dst_mac_addr; + struct sfc_mae_mac_addr *src_mac_addr; struct sfc_mae_fw_rsrc fw_rsrc; }; @@ -211,6 +224,8 @@ struct sfc_mae { struct sfc_mae_outer_rules outer_rules; /** Encap. header registry */ struct sfc_mae_encap_headers encap_headers; + /** MAC address registry */ + struct sfc_mae_mac_addrs mac_addrs; /** Action set registry */ struct sfc_mae_action_sets action_sets; /** Encap. header bounce buffer */ -- 2.20.1