net/sfc: fix filter exceptions logic
authorIgor Romanov <igor.romanov@oktetlabs.ru>
Sat, 14 Jul 2018 07:38:23 +0000 (08:38 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 23 Jul 2018 21:55:26 +0000 (23:55 +0200)
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 <igor.romanov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
drivers/net/sfc/sfc_filter.c
drivers/net/sfc/sfc_filter.h
drivers/net/sfc/sfc_flow.c

index 77e2ea5..6ff380a 100644 (file)
@@ -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;
index d3e1c2f..64ab114 100644 (file)
@@ -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;
index 1838741..bfb7b24 100644 (file)
@@ -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");