X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsfc%2Fsfc_flow.c;h=371648b0eef5656c8339c744d4f120a4a250c52a;hb=061ee47cf53395a6453a97dfc6881ebfc9905743;hp=55226f12db682bf252b4275987a2dd8120d10937;hpb=01764b20c2ffd4b5755a6da40b307a12d8185b46;p=dpdk.git diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index 55226f12db..371648b0ee 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -23,6 +23,7 @@ #include "sfc_filter.h" #include "sfc_flow.h" #include "sfc_log.h" +#include "sfc_dp_rx.h" /* * At now flow API is implemented in such a manner that each @@ -92,6 +93,8 @@ static sfc_flow_spec_check sfc_flow_check_unknown_dst_flags; static sfc_flow_spec_set_vals sfc_flow_set_ethertypes; static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags; static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags; +static sfc_flow_spec_set_vals sfc_flow_set_outer_vid_flag; +static sfc_flow_spec_check sfc_flow_check_outer_vid_flag; static boolean_t sfc_flow_is_zero(const uint8_t *buf, unsigned int size) @@ -120,7 +123,6 @@ sfc_flow_parse_init(const struct rte_flow_item *item, const uint8_t *spec; const uint8_t *mask; const uint8_t *last; - uint8_t match; uint8_t supp; unsigned int i; @@ -181,12 +183,11 @@ sfc_flow_parse_init(const struct rte_flow_item *item, return -rte_errno; } - /* Check that mask and spec not asks for more match than supp_mask */ + /* Check that mask does not ask for more match than supp_mask */ for (i = 0; i < size; i++) { - match = spec[i] | mask[i]; supp = ((const uint8_t *)supp_mask)[i]; - if ((match | supp) != supp) { + if (~supp & mask[i]) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, "Item's field is not supported"); @@ -372,7 +373,8 @@ sfc_flow_parse_vlan(const struct rte_flow_item *item, * the outer tag and the next matches the inner tag. */ if (mask->tci == supp_mask.tci) { - vid = rte_bswap16(spec->tci); + /* Apply mask to keep VID only */ + vid = rte_bswap16(spec->tci & mask->tci); if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_OUTER_VID)) { @@ -1297,6 +1299,17 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, if (action_rss->level) return -EINVAL; + /* + * Dummy RSS action with only one queue and no specific settings + * for hash types and key does not require dedicated RSS context + * and may be simplified to single queue action. + */ + if (action_rss->queue_num == 1 && action_rss->types == 0 && + action_rss->key_len == 0) { + flow->spec.template.efs_dmaq_id = rxq_hw_index_min; + return 0; + } + if (action_rss->types) { int rc; @@ -1491,6 +1504,22 @@ sfc_flow_filter_remove(struct sfc_adapter *sa, return rc; } +static int +sfc_flow_parse_mark(struct sfc_adapter *sa, + const struct rte_flow_action_mark *mark, + struct rte_flow *flow) +{ + const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); + + if (mark == NULL || mark->id > encp->enc_filter_action_mark_max) + return EINVAL; + + flow->spec.template.efs_flags |= EFX_FILTER_FLAG_ACTION_MARK; + flow->spec.template.efs_mark = mark->id; + + return 0; +} + static int sfc_flow_parse_actions(struct sfc_adapter *sa, const struct rte_flow_action actions[], @@ -1498,7 +1527,13 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, struct rte_flow_error *error) { int rc; - boolean_t is_specified = B_FALSE; + const unsigned int dp_rx_features = sa->dp_rx->features; + uint32_t actions_set = 0; + const uint32_t fate_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_QUEUE) | + (1UL << RTE_FLOW_ACTION_TYPE_RSS) | + (1UL << RTE_FLOW_ACTION_TYPE_DROP); + const uint32_t mark_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_MARK) | + (1UL << RTE_FLOW_ACTION_TYPE_FLAG); if (actions == NULL) { rte_flow_error_set(error, EINVAL, @@ -1507,21 +1542,22 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, return -rte_errno; } +#define SFC_BUILD_SET_OVERFLOW(_action, _set) \ + RTE_BUILD_BUG_ON(_action >= sizeof(_set) * CHAR_BIT) + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { - /* This one may appear anywhere multiple times. */ - if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) - continue; - /* Fate-deciding actions may appear exactly once. */ - if (is_specified) { - rte_flow_error_set - (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, - actions, - "Cannot combine several fate-deciding actions," - "choose between QUEUE, RSS or DROP"); - return -rte_errno; - } switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_VOID: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VOID, + actions_set); + break; + case RTE_FLOW_ACTION_TYPE_QUEUE: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_QUEUE, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + rc = sfc_flow_parse_queue(sa, actions->conf, flow); if (rc != 0) { rte_flow_error_set(error, EINVAL, @@ -1529,27 +1565,70 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, "Bad QUEUE action"); return -rte_errno; } - - is_specified = B_TRUE; break; case RTE_FLOW_ACTION_TYPE_RSS: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_RSS, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + rc = sfc_flow_parse_rss(sa, actions->conf, flow); if (rc != 0) { - rte_flow_error_set(error, rc, + rte_flow_error_set(error, -rc, RTE_FLOW_ERROR_TYPE_ACTION, actions, "Bad RSS action"); return -rte_errno; } - - is_specified = B_TRUE; break; case RTE_FLOW_ACTION_TYPE_DROP: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + flow->spec.template.efs_dmaq_id = EFX_FILTER_SPEC_RX_DMAQ_ID_DROP; + break; + + case RTE_FLOW_ACTION_TYPE_FLAG: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG, + actions_set); + if ((actions_set & mark_actions_mask) != 0) + goto fail_actions_overlap; + + if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_FLAG) == 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "FLAG action is not supported on the current Rx datapath"); + return -rte_errno; + } + + flow->spec.template.efs_flags |= + EFX_FILTER_FLAG_ACTION_FLAG; + break; + + case RTE_FLOW_ACTION_TYPE_MARK: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK, + actions_set); + if ((actions_set & mark_actions_mask) != 0) + goto fail_actions_overlap; + + if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_MARK) == 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "MARK action is not supported on the current Rx datapath"); + return -rte_errno; + } - is_specified = B_TRUE; + rc = sfc_flow_parse_mark(sa, actions->conf, flow); + if (rc != 0) { + rte_flow_error_set(error, rc, + RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Bad MARK action"); + return -rte_errno; + } break; default: @@ -1558,15 +1637,29 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, "Action is not supported"); return -rte_errno; } + + actions_set |= (1UL << actions->type); } +#undef SFC_BUILD_SET_OVERFLOW /* When fate is unknown, drop traffic. */ - if (!is_specified) { + if ((actions_set & fate_actions_mask) == 0) { flow->spec.template.efs_dmaq_id = EFX_FILTER_SPEC_RX_DMAQ_ID_DROP; } return 0; + +fail_fate_actions: + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Cannot combine several fate-deciding actions, " + "choose between QUEUE, RSS or DROP"); + return -rte_errno; + +fail_actions_overlap: + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Overlapping actions are not supported"); + return -rte_errno; } /** @@ -1689,6 +1782,43 @@ sfc_flow_set_ethertypes(struct sfc_flow_spec *spec, return 0; } +/** + * Set the EFX_FILTER_MATCH_OUTER_VID match flag with value 0 + * in the same specifications after copying. + * + * @param spec[in, out] + * SFC flow specification to update. + * @param filters_count_for_one_val[in] + * How many specifications should have the same match flag, what is the + * number of specifications before copying. + * @param error[out] + * Perform verbose error reporting if not NULL. + */ +static int +sfc_flow_set_outer_vid_flag(struct sfc_flow_spec *spec, + unsigned int filters_count_for_one_val, + struct rte_flow_error *error) +{ + unsigned int i; + + if (filters_count_for_one_val != spec->count) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Number of specifications is incorrect " + "while copying by outer VLAN ID"); + return -rte_errno; + } + + for (i = 0; i < spec->count; i++) { + spec->filters[i].efs_match_flags |= + EFX_FILTER_MATCH_OUTER_VID; + + spec->filters[i].efs_outer_vid = 0; + } + + return 0; +} + /** * Set the EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST and * EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST match flags in the same @@ -1768,6 +1898,36 @@ sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match, return B_FALSE; } +/** + * Check that the list of supported filters has a filter that differs + * from @p match in that it has no flag EFX_FILTER_MATCH_OUTER_VID + * in this case that filter will be used and the flag + * EFX_FILTER_MATCH_OUTER_VID is not needed. + * + * @param match[in] + * The match flags of filter. + * @param spec[in] + * Specification to be supplemented. + * @param filter[in] + * SFC filter with list of supported filters. + */ +static boolean_t +sfc_flow_check_outer_vid_flag(efx_filter_match_flags_t match, + __rte_unused efx_filter_spec_t *spec, + struct sfc_filter *filter) +{ + unsigned int i; + efx_filter_match_flags_t match_without_vid = + match & ~EFX_FILTER_MATCH_OUTER_VID; + + for (i = 0; i < filter->supported_match_num; i++) { + if (match_without_vid == filter->supported_match[i]) + return B_FALSE; + } + + return B_TRUE; +} + /* * Match flags that can be automatically added to filters. * Selecting the last minimum when searching for the copy flag ensures that the @@ -1795,6 +1955,12 @@ static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = { .set_vals = sfc_flow_set_ifrm_unknown_dst_flags, .spec_check = sfc_flow_check_ifrm_unknown_dst_flags, }, + { + .flag = EFX_FILTER_MATCH_OUTER_VID, + .vals_count = 1, + .set_vals = sfc_flow_set_outer_vid_flag, + .spec_check = sfc_flow_check_outer_vid_flag, + }, }; /* Get item from array sfc_flow_copy_flags */ @@ -1956,7 +2122,7 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa, if (min_multiplier == UINT_MAX) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "Flow rule pattern is not supported"); + "The flow rule pattern is unsupported"); return -rte_errno; } @@ -2004,11 +2170,14 @@ sfc_flow_is_match_with_vids(efx_filter_match_flags_t match_flags, * Check whether the spec maps to a hardware filter which is known to be * ineffective despite being valid. * + * @param filter[in] + * SFC filter with list of supported filters. * @param spec[in] * SFC flow specification. */ static boolean_t -sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec) +sfc_flow_is_match_flags_exception(struct sfc_filter *filter, + struct sfc_flow_spec *spec) { unsigned int i; uint16_t ether_type; @@ -2024,8 +2193,9 @@ sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec) EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_MAC)) { ether_type = spec->filters[i].efs_ether_type; - if (ether_type == EFX_ETHER_TYPE_IPV4 || - ether_type == EFX_ETHER_TYPE_IPV6) + if (filter->supports_ip_proto_or_addr_filter && + (ether_type == EFX_ETHER_TYPE_IPV4 || + ether_type == EFX_ETHER_TYPE_IPV6)) return B_TRUE; } else if (sfc_flow_is_match_with_vids(match_flags, EFX_FILTER_MATCH_ETHER_TYPE | @@ -2035,8 +2205,9 @@ sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec) EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_MAC)) { ip_proto = spec->filters[i].efs_ip_proto; - if (ip_proto == EFX_IPPROTO_TCP || - ip_proto == EFX_IPPROTO_UDP) + if (filter->supports_rem_or_local_port_filter && + (ip_proto == EFX_IPPROTO_TCP || + ip_proto == EFX_IPPROTO_UDP)) return B_TRUE; } } @@ -2063,7 +2234,7 @@ sfc_flow_validate_match_flags(struct sfc_adapter *sa, return rc; } - if (sfc_flow_is_match_flags_exception(&flow->spec)) { + if (sfc_flow_is_match_flags_exception(&sa->filter, &flow->spec)) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "The flow rule pattern is unsupported");