From b0df5b32aedab8dec1fe7dd52aaba9a8356eaff0 Mon Sep 17 00:00:00 2001 From: Igor Romanov Date: Sat, 14 Jul 2018 08:38:23 +0100 Subject: [PATCH] net/sfc: fix filter exceptions logic Now exception logic handles these cases: When FW variant does not support filters with transport ports, but IP protocol filters are supported, TCP/UDP protocol filters may be used. When FW variant does not support filters with IPv4/6 addresses or IP protocol, but filters with EtherType are supported, IPv4 and IPv6 EtherTypes may be used Fixes: 096dba799b4a ("net/sfc: avoid creation of ineffective flow rules") Cc: stable@dpdk.org Signed-off-by: Igor Romanov Signed-off-by: Andrew Rybchenko --- drivers/net/sfc/sfc_filter.c | 14 ++++++++++++++ drivers/net/sfc/sfc_filter.h | 10 ++++++++++ drivers/net/sfc/sfc_flow.c | 17 +++++++++++------ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/sfc/sfc_filter.c b/drivers/net/sfc/sfc_filter.c index 77e2ea5624..6ff380a363 100644 --- a/drivers/net/sfc/sfc_filter.c +++ b/drivers/net/sfc/sfc_filter.c @@ -75,6 +75,7 @@ int sfc_filter_attach(struct sfc_adapter *sa) { int rc; + unsigned int i; sfc_log_init(sa, "entry"); @@ -88,6 +89,19 @@ sfc_filter_attach(struct sfc_adapter *sa) efx_filter_fini(sa->nic); + sa->filter.supports_ip_proto_or_addr_filter = B_FALSE; + sa->filter.supports_rem_or_local_port_filter = B_FALSE; + for (i = 0; i < sa->filter.supported_match_num; ++i) { + if (sa->filter.supported_match[i] & + (EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | + EFX_FILTER_MATCH_REM_HOST)) + sa->filter.supports_ip_proto_or_addr_filter = B_TRUE; + + if (sa->filter.supported_match[i] & + (EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT)) + sa->filter.supports_rem_or_local_port_filter = B_TRUE; + } + sfc_log_init(sa, "done"); return 0; diff --git a/drivers/net/sfc/sfc_filter.h b/drivers/net/sfc/sfc_filter.h index d3e1c2f9cd..64ab114e06 100644 --- a/drivers/net/sfc/sfc_filter.h +++ b/drivers/net/sfc/sfc_filter.h @@ -25,6 +25,16 @@ struct sfc_filter { uint32_t *supported_match; /** List of flow rules */ struct sfc_flow_list flow_list; + /** + * Supports any of ip_proto, remote host or local host + * filters. This flag is used for filter match exceptions + */ + boolean_t supports_ip_proto_or_addr_filter; + /** + * Supports any of remote port or local port filters. + * This flag is used for filter match exceptions + */ + boolean_t supports_rem_or_local_port_filter; }; struct sfc_adapter; diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index 18387415e2..bfb7b24f05 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -2095,11 +2095,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; @@ -2115,8 +2118,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 | @@ -2126,8 +2130,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; } } @@ -2154,7 +2159,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"); -- 2.20.1