X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsfc%2Fsfc_mae.c;h=7be77054abc0782dfdf199b0956a373f7c6dbe3b;hb=6ded2e01380e5f3bd48154ca8f23eaad35ffe839;hp=21b6ea3b20f897404adf90b86cf43b862bc2e543;hpb=5cb474620583703e4fd28252188b8552f022267b;p=dpdk.git diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c index 21b6ea3b20..7be77054ab 100644 --- a/drivers/net/sfc/sfc_mae.c +++ b/drivers/net/sfc/sfc_mae.c @@ -44,6 +44,139 @@ sfc_mae_counter_registry_fini(struct sfc_mae_counter_registry *registry) sfc_mae_counters_fini(®istry->counters); } +static int +sfc_mae_internal_rule_find_empty_slot(struct sfc_adapter *sa, + struct sfc_mae_rule **rule) +{ + struct sfc_mae *mae = &sa->mae; + struct sfc_mae_internal_rules *internal_rules = &mae->internal_rules; + unsigned int entry; + int rc; + + for (entry = 0; entry < SFC_MAE_NB_RULES_MAX; entry++) { + if (internal_rules->rules[entry].spec == NULL) + break; + } + + if (entry == SFC_MAE_NB_RULES_MAX) { + rc = ENOSPC; + sfc_err(sa, "failed too many rules (%u rules used)", entry); + goto fail_too_many_rules; + } + + *rule = &internal_rules->rules[entry]; + + return 0; + +fail_too_many_rules: + return rc; +} + +int +sfc_mae_rule_add_mport_match_deliver(struct sfc_adapter *sa, + const efx_mport_sel_t *mport_match, + const efx_mport_sel_t *mport_deliver, + int prio, struct sfc_mae_rule **rulep) +{ + struct sfc_mae *mae = &sa->mae; + struct sfc_mae_rule *rule; + int rc; + + sfc_log_init(sa, "entry"); + + if (prio > 0 && (unsigned int)prio >= mae->nb_action_rule_prios_max) { + rc = EINVAL; + sfc_err(sa, "failed: invalid priority %d (max %u)", prio, + mae->nb_action_rule_prios_max); + goto fail_invalid_prio; + } + if (prio < 0) + prio = mae->nb_action_rule_prios_max - 1; + + rc = sfc_mae_internal_rule_find_empty_slot(sa, &rule); + if (rc != 0) + goto fail_find_empty_slot; + + sfc_log_init(sa, "init MAE match spec"); + rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION, + (uint32_t)prio, &rule->spec); + if (rc != 0) { + sfc_err(sa, "failed to init MAE match spec"); + goto fail_match_init; + } + + rc = efx_mae_match_spec_mport_set(rule->spec, mport_match, NULL); + if (rc != 0) { + sfc_err(sa, "failed to get MAE match mport selector"); + goto fail_mport_set; + } + + rc = efx_mae_action_set_spec_init(sa->nic, &rule->actions); + if (rc != 0) { + sfc_err(sa, "failed to init MAE action set"); + goto fail_action_init; + } + + rc = efx_mae_action_set_populate_deliver(rule->actions, + mport_deliver); + if (rc != 0) { + sfc_err(sa, "failed to populate deliver action"); + goto fail_populate_deliver; + } + + rc = efx_mae_action_set_alloc(sa->nic, rule->actions, + &rule->action_set); + if (rc != 0) { + sfc_err(sa, "failed to allocate action set"); + goto fail_action_set_alloc; + } + + rc = efx_mae_action_rule_insert(sa->nic, rule->spec, NULL, + &rule->action_set, + &rule->rule_id); + if (rc != 0) { + sfc_err(sa, "failed to insert action rule"); + goto fail_rule_insert; + } + + *rulep = rule; + + sfc_log_init(sa, "done"); + + return 0; + +fail_rule_insert: + efx_mae_action_set_free(sa->nic, &rule->action_set); + +fail_action_set_alloc: +fail_populate_deliver: + efx_mae_action_set_spec_fini(sa->nic, rule->actions); + +fail_action_init: +fail_mport_set: + efx_mae_match_spec_fini(sa->nic, rule->spec); + +fail_match_init: +fail_find_empty_slot: +fail_invalid_prio: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +void +sfc_mae_rule_del(struct sfc_adapter *sa, struct sfc_mae_rule *rule) +{ + if (rule == NULL || rule->spec == NULL) + return; + + efx_mae_action_rule_remove(sa->nic, &rule->rule_id); + efx_mae_action_set_free(sa->nic, &rule->action_set); + efx_mae_action_set_spec_fini(sa->nic, rule->actions); + efx_mae_match_spec_fini(sa->nic, rule->spec); + + rule->spec = NULL; +} + int sfc_mae_attach(struct sfc_adapter *sa) { @@ -908,6 +1041,8 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, for (ethertype_idx = 0; ethertype_idx < pdata->nb_vlan_tags; ++ethertype_idx) { + rte_be16_t tpid_v = ethertypes[ethertype_idx].value; + rte_be16_t tpid_m = ethertypes[ethertype_idx].mask; unsigned int tpid_idx; /* @@ -917,7 +1052,7 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, */ enforce_tag_presence[0] = B_FALSE; - if (ethertypes[ethertype_idx].mask == RTE_BE16(0)) { + if (tpid_m == RTE_BE16(0)) { if (pdata->tci_masks[ethertype_idx] == RTE_BE16(0)) enforce_tag_presence[ethertype_idx] = B_TRUE; @@ -927,19 +1062,22 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, } /* Exact match is supported only. */ - if (ethertypes[ethertype_idx].mask != RTE_BE16(0xffff)) { + if (tpid_m != RTE_BE16(0xffff)) { + sfc_err(ctx->sa, "TPID mask must be 0x0 or 0xffff; got 0x%04x", + rte_be_to_cpu_16(tpid_m)); rc = EINVAL; goto fail; } for (tpid_idx = pdata->nb_vlan_tags - ethertype_idx - 1; tpid_idx < nb_supported_tpids; ++tpid_idx) { - if (ethertypes[ethertype_idx].value == - supported_tpids[tpid_idx]) + if (tpid_v == supported_tpids[tpid_idx]) break; } if (tpid_idx == nb_supported_tpids) { + sfc_err(ctx->sa, "TPID 0x%04x is unsupported", + rte_be_to_cpu_16(tpid_v)); rc = EINVAL; goto fail; } @@ -949,14 +1087,19 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, if (pdata->innermost_ethertype_restriction.mask == RTE_BE16(0xffff)) { struct sfc_mae_ethertype *et = ðertypes[ethertype_idx]; + rte_be16_t enforced_et; + + enforced_et = pdata->innermost_ethertype_restriction.value; if (et->mask == 0) { et->mask = RTE_BE16(0xffff); - et->value = - pdata->innermost_ethertype_restriction.value; + et->value = enforced_et; } else if (et->mask != RTE_BE16(0xffff) || - et->value != - pdata->innermost_ethertype_restriction.value) { + et->value != enforced_et) { + sfc_err(ctx->sa, "L3 EtherType must be 0x0/0x0 or 0x%04x/0xffff; got 0x%04x/0x%04x", + rte_be_to_cpu_16(enforced_et), + rte_be_to_cpu_16(et->value), + rte_be_to_cpu_16(et->mask)); rc = EINVAL; goto fail; } @@ -976,10 +1119,14 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, if (pdata->l3_next_proto_mask == 0) { pdata->l3_next_proto_mask = 0xff; pdata->l3_next_proto_value = - pdata->l3_next_proto_restriction_value; + pdata->l3_next_proto_restriction_value; } else if (pdata->l3_next_proto_mask != 0xff || pdata->l3_next_proto_value != pdata->l3_next_proto_restriction_value) { + sfc_err(ctx->sa, "L3 next protocol must be 0x0/0x0 or 0x%02x/0xff; got 0x%02x/0x%02x", + pdata->l3_next_proto_restriction_value, + pdata->l3_next_proto_value, + pdata->l3_next_proto_mask); rc = EINVAL; goto fail; } @@ -1971,6 +2118,7 @@ sfc_mae_rule_parse_item_tunnel(const struct rte_flow_item *item, static const struct sfc_flow_item sfc_flow_items[] = { { .type = RTE_FLOW_ITEM_TYPE_PORT_ID, + .name = "PORT_ID", /* * In terms of RTE flow, this item is a META one, * and its position in the pattern is don't care. @@ -1982,6 +2130,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_PHY_PORT, + .name = "PHY_PORT", /* * In terms of RTE flow, this item is a META one, * and its position in the pattern is don't care. @@ -1993,6 +2142,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_PF, + .name = "PF", /* * In terms of RTE flow, this item is a META one, * and its position in the pattern is don't care. @@ -2004,6 +2154,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_VF, + .name = "VF", /* * In terms of RTE flow, this item is a META one, * and its position in the pattern is don't care. @@ -2015,6 +2166,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_ETH, + .name = "ETH", .prev_layer = SFC_FLOW_ITEM_START_LAYER, .layer = SFC_FLOW_ITEM_L2, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2022,6 +2174,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_VLAN, + .name = "VLAN", .prev_layer = SFC_FLOW_ITEM_L2, .layer = SFC_FLOW_ITEM_L2, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2029,6 +2182,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_IPV4, + .name = "IPV4", .prev_layer = SFC_FLOW_ITEM_L2, .layer = SFC_FLOW_ITEM_L3, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2036,6 +2190,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_IPV6, + .name = "IPV6", .prev_layer = SFC_FLOW_ITEM_L2, .layer = SFC_FLOW_ITEM_L3, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2043,6 +2198,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_TCP, + .name = "TCP", .prev_layer = SFC_FLOW_ITEM_L3, .layer = SFC_FLOW_ITEM_L4, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2050,6 +2206,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_UDP, + .name = "UDP", .prev_layer = SFC_FLOW_ITEM_L3, .layer = SFC_FLOW_ITEM_L4, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2057,6 +2214,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_VXLAN, + .name = "VXLAN", .prev_layer = SFC_FLOW_ITEM_L4, .layer = SFC_FLOW_ITEM_START_LAYER, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2064,6 +2222,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_GENEVE, + .name = "GENEVE", .prev_layer = SFC_FLOW_ITEM_L4, .layer = SFC_FLOW_ITEM_START_LAYER, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2071,6 +2230,7 @@ static const struct sfc_flow_item sfc_flow_items[] = { }, { .type = RTE_FLOW_ITEM_TYPE_NVGRE, + .name = "NVGRE", .prev_layer = SFC_FLOW_ITEM_L3, .layer = SFC_FLOW_ITEM_START_LAYER, .ctx_type = SFC_FLOW_PARSE_CTX_MAE, @@ -2279,7 +2439,7 @@ sfc_mae_rule_parse_pattern(struct sfc_adapter *sa, if (rc != 0) goto fail_encap_parse_init; - rc = sfc_flow_parse_pattern(sfc_flow_items, RTE_DIM(sfc_flow_items), + rc = sfc_flow_parse_pattern(sa, sfc_flow_items, RTE_DIM(sfc_flow_items), pattern, &ctx, error); if (rc != 0) goto fail_parse_pattern; @@ -2530,6 +2690,7 @@ sfc_mae_rule_parse_action_vxlan_encap( size_t next_proto_ofst = 0; size_t ethertype_ofst = 0; uint64_t exp_items; + int rc; if (pattern == NULL) { return rte_flow_error_set(error, EINVAL, @@ -2749,14 +2910,27 @@ sfc_mae_rule_parse_action_vxlan_encap( /* Take care of the masks. */ sfc_mae_header_force_item_masks(buf, parsed_items, nb_parsed_items); - return (spec != NULL) ? efx_mae_action_set_populate_encap(spec) : 0; + rc = efx_mae_action_set_populate_encap(spec); + if (rc != 0) { + rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "failed to request action ENCAP"); + } + + return rc; } static int -sfc_mae_rule_parse_action_mark(const struct rte_flow_action_mark *conf, +sfc_mae_rule_parse_action_mark(struct sfc_adapter *sa, + const struct rte_flow_action_mark *conf, efx_mae_actions_t *spec) { - return efx_mae_action_set_populate_mark(spec, conf->id); + int rc; + + rc = efx_mae_action_set_populate_mark(spec, conf->id); + if (rc != 0) + sfc_err(sa, "failed to request action MARK: %s", strerror(rc)); + + return rc; } static int @@ -2816,10 +2990,19 @@ sfc_mae_rule_parse_action_phy_port(struct sfc_adapter *sa, phy_port = conf->index; rc = efx_mae_mport_by_phy_port(phy_port, &mport); - if (rc != 0) + if (rc != 0) { + sfc_err(sa, "failed to convert phys. port ID %u to m-port selector: %s", + phy_port, strerror(rc)); return rc; + } + + rc = efx_mae_action_set_populate_deliver(spec, &mport); + if (rc != 0) { + sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s", + mport.sel, strerror(rc)); + } - return efx_mae_action_set_populate_deliver(spec, &mport); + return rc; } static int @@ -2840,10 +3023,20 @@ sfc_mae_rule_parse_action_pf_vf(struct sfc_adapter *sa, vf = vf_conf->id; rc = efx_mae_mport_by_pcie_function(encp->enc_pf, vf, &mport); - if (rc != 0) + if (rc != 0) { + sfc_err(sa, "failed to convert PF %u VF %d to m-port: %s", + encp->enc_pf, (vf != EFX_PCI_VF_INVALID) ? (int)vf : -1, + strerror(rc)); return rc; + } - return efx_mae_action_set_populate_deliver(spec, &mport); + rc = efx_mae_action_set_populate_deliver(spec, &mport); + if (rc != 0) { + sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s", + mport.sel, strerror(rc)); + } + + return rc; } static int @@ -2864,12 +3057,37 @@ sfc_mae_rule_parse_action_port_id(struct sfc_adapter *sa, rc = sfc_mae_switch_port_by_ethdev(mae->switch_domain_id, port_id, &mport); - if (rc != 0) + if (rc != 0) { + sfc_err(sa, "failed to find MAE switch port SW entry for RTE ethdev port %u: %s", + port_id, strerror(rc)); return rc; + } + + rc = efx_mae_action_set_populate_deliver(spec, &mport); + if (rc != 0) { + sfc_err(sa, "failed to request action DELIVER with m-port selector 0x%08x: %s", + mport.sel, strerror(rc)); + } - return efx_mae_action_set_populate_deliver(spec, &mport); + return rc; } +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_OF_PUSH_VLAN] = "OF_PUSH_VLAN", + [RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID] = "OF_SET_VLAN_VID", + [RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP] = "OF_SET_VLAN_PCP", + [RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP] = "VXLAN_ENCAP", + [RTE_FLOW_ACTION_TYPE_FLAG] = "FLAG", + [RTE_FLOW_ACTION_TYPE_MARK] = "MARK", + [RTE_FLOW_ACTION_TYPE_PHY_PORT] = "PHY_PORT", + [RTE_FLOW_ACTION_TYPE_PF] = "PF", + [RTE_FLOW_ACTION_TYPE_VF] = "VF", + [RTE_FLOW_ACTION_TYPE_PORT_ID] = "PORT_ID", + [RTE_FLOW_ACTION_TYPE_DROP] = "DROP", +}; + static int sfc_mae_rule_parse_action(struct sfc_adapter *sa, const struct rte_flow_action *action, @@ -2932,7 +3150,7 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa, case RTE_FLOW_ACTION_TYPE_MARK: SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK, bundle->actions_mask); - rc = sfc_mae_rule_parse_action_mark(action->conf, spec); + rc = sfc_mae_rule_parse_action_mark(sa, action->conf, spec); break; case RTE_FLOW_ACTION_TYPE_PHY_PORT: SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PHY_PORT, @@ -2968,6 +3186,14 @@ sfc_mae_rule_parse_action(struct sfc_adapter *sa, if (rc == 0) { bundle->actions_mask |= (1ULL << action->type); } else if (!custom_error) { + if (action->type < RTE_DIM(action_names)) { + const char *action_name = action_names[action->type]; + + if (action_name != NULL) { + sfc_err(sa, "action %s was rejected: %s", + action_name, strerror(rc)); + } + } rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Failed to request the action"); } @@ -3188,7 +3414,7 @@ sfc_mae_flow_verify(struct sfc_adapter *sa, SFC_ASSERT(sfc_adapter_is_locked(sa)); - if (sa->state != SFC_ADAPTER_STARTED) + if (sa->state != SFC_ETHDEV_STARTED) return EAGAIN; if (outer_rule != NULL) { @@ -3350,3 +3576,81 @@ sfc_mae_flow_query(struct rte_eth_dev *dev, "Query for action of this type is not supported"); } } + +int +sfc_mae_switchdev_init(struct sfc_adapter *sa) +{ + const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); + struct sfc_mae *mae = &sa->mae; + efx_mport_sel_t pf; + efx_mport_sel_t phy; + int rc; + + sfc_log_init(sa, "entry"); + + if (!sa->switchdev) { + sfc_log_init(sa, "switchdev is not enabled - skip"); + return 0; + } + + if (mae->status != SFC_MAE_STATUS_SUPPORTED) { + rc = ENOTSUP; + sfc_err(sa, "failed to init switchdev - no MAE support"); + goto fail_no_mae; + } + + rc = efx_mae_mport_by_pcie_function(encp->enc_pf, EFX_PCI_VF_INVALID, + &pf); + if (rc != 0) { + sfc_err(sa, "failed get PF mport"); + goto fail_pf_get; + } + + rc = efx_mae_mport_by_phy_port(encp->enc_assigned_port, &phy); + if (rc != 0) { + sfc_err(sa, "failed get PHY mport"); + goto fail_phy_get; + } + + rc = sfc_mae_rule_add_mport_match_deliver(sa, &pf, &phy, + SFC_MAE_RULE_PRIO_LOWEST, + &mae->switchdev_rule_pf_to_ext); + if (rc != 0) { + sfc_err(sa, "failed add MAE rule to forward from PF to PHY"); + goto fail_pf_add; + } + + rc = sfc_mae_rule_add_mport_match_deliver(sa, &phy, &pf, + SFC_MAE_RULE_PRIO_LOWEST, + &mae->switchdev_rule_ext_to_pf); + if (rc != 0) { + sfc_err(sa, "failed add MAE rule to forward from PHY to PF"); + goto fail_phy_add; + } + + sfc_log_init(sa, "done"); + + return 0; + +fail_phy_add: + sfc_mae_rule_del(sa, mae->switchdev_rule_pf_to_ext); + +fail_pf_add: +fail_phy_get: +fail_pf_get: +fail_no_mae: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +void +sfc_mae_switchdev_fini(struct sfc_adapter *sa) +{ + struct sfc_mae *mae = &sa->mae; + + if (!sa->switchdev) + return; + + sfc_mae_rule_del(sa, mae->switchdev_rule_pf_to_ext); + sfc_mae_rule_del(sa, mae->switchdev_rule_ext_to_pf); +}