From 096dba799b4a3fa7db347dcdc1a43bf9d40e14da Mon Sep 17 00:00:00 2001 From: Roman Zhukov Date: Tue, 6 Mar 2018 15:24:58 +0000 Subject: [PATCH] net/sfc: avoid creation of ineffective flow rules Despite being versatile, the hardware support for filtering has a number of special properties which must be taken into account. Namely, there is a known set of valid filters which don't take any effect despite being accepted by the hardware. The combinations of match flags and field values which can describe the exceptional filters are as follows: - ETHER_TYPE or ETHER_TYPE | LOC_MAC with IPv4 or IPv6 EtherType - ETHER_TYPE | IP_PROTO or ETHER_TYPE | IP_PROTO | LOC_MAC with UDP or TCP IP protocol value - The same combinations with OUTER_VID and/or INNER_VID These exceptional filters can be expressed in terms of RTE flow rules. If the user creates such a flow rule, no traffic will hit the underlying filter, and no errors will be reported. This patch adds a means to prevent such ineffective flow rules from being created. Signed-off-by: Roman Zhukov Signed-off-by: Andrew Rybchenko Reviewed-by: Ivan Malov --- doc/guides/nics/sfc_efx.rst | 17 ++++++++ drivers/net/sfc/sfc_flow.c | 78 +++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst index 539ce90670..f41ccdb835 100644 --- a/doc/guides/nics/sfc_efx.rst +++ b/doc/guides/nics/sfc_efx.rst @@ -193,6 +193,23 @@ in the mask of destination address. If destinaton address in the spec is multicast, it matches all multicast (and broadcast) packets, oherwise it matches unicast packets that are not filtered by other flow rules. +Exceptions to flow rules +~~~~~~~~~~~~~~~~~~~~~~~~ + +There is a list of exceptional flow rule patterns which will not be +accepted by the PMD. A pattern will be rejected if at least one of the +conditions is met: + +- Filtering by IPv4 or IPv6 EtherType without pattern items of internet + layer and above. + +- The last item is IPV4 or IPV6, and it's empty. + +- Filtering by TCP or UDP IP transport protocol without pattern items of + transport layer and above. + +- The last item is TCP or UDP, and it's empty. + Supported NICs -------------- diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index 4a81205ae7..8900ff471d 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -1919,6 +1919,77 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa, return 0; } +/** + * Check that set of match flags is referred to by a filter. Filter is + * described by match flags with the ability to add OUTER_VID and INNER_VID + * flags. + * + * @param match_flags[in] + * Set of match flags. + * @param flags_pattern[in] + * Pattern of filter match flags. + */ +static boolean_t +sfc_flow_is_match_with_vids(efx_filter_match_flags_t match_flags, + efx_filter_match_flags_t flags_pattern) +{ + if ((match_flags & flags_pattern) != flags_pattern) + return B_FALSE; + + switch (match_flags & ~flags_pattern) { + case 0: + case EFX_FILTER_MATCH_OUTER_VID: + case EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_INNER_VID: + return B_TRUE; + default: + return B_FALSE; + } +} + +/** + * Check whether the spec maps to a hardware filter which is known to be + * ineffective despite being valid. + * + * @param spec[in] + * SFC flow specification. + */ +static boolean_t +sfc_flow_is_match_flags_exception(struct sfc_flow_spec *spec) +{ + unsigned int i; + uint16_t ether_type; + uint8_t ip_proto; + efx_filter_match_flags_t match_flags; + + for (i = 0; i < spec->count; i++) { + match_flags = spec->filters[i].efs_match_flags; + + if (sfc_flow_is_match_with_vids(match_flags, + EFX_FILTER_MATCH_ETHER_TYPE) || + sfc_flow_is_match_with_vids(match_flags, + 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) + return B_TRUE; + } else if (sfc_flow_is_match_with_vids(match_flags, + EFX_FILTER_MATCH_ETHER_TYPE | + EFX_FILTER_MATCH_IP_PROTO) || + sfc_flow_is_match_with_vids(match_flags, + EFX_FILTER_MATCH_ETHER_TYPE | + 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) + return B_TRUE; + } + } + + return B_FALSE; +} + static int sfc_flow_validate_match_flags(struct sfc_adapter *sa, struct rte_flow *flow, @@ -1938,6 +2009,13 @@ sfc_flow_validate_match_flags(struct sfc_adapter *sa, return rc; } + if (sfc_flow_is_match_flags_exception(&flow->spec)) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "The flow rule pattern is unsupported"); + return -rte_errno; + } + return 0; } -- 2.20.1