net/sfc: add infrastructure to make many filters from flow
authorRoman Zhukov <roman.zhukov@oktetlabs.ru>
Tue, 6 Mar 2018 15:24:54 +0000 (15:24 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 30 Mar 2018 12:08:43 +0000 (14:08 +0200)
Not all flow rules can be expressed in one hardware filter, so some flow
rules have to be expressed in terms of multiple hardware filters. This
patch provides a means to produce a filter spec template from the flow
rule which then can be used to produce a set of fully elaborated specs
to be inserted.

Signed-off-by: Roman Zhukov <roman.zhukov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
drivers/net/sfc/sfc_flow.c
drivers/net/sfc/sfc_flow.h

index 0da6383..3f6b7b7 100644 (file)
 
 /*
  * At now flow API is implemented in such a manner that each
- * flow rule is converted to a hardware filter.
+ * flow rule is converted to one or more hardware filters.
  * All elements of flow rule (attributes, pattern items, actions)
  * correspond to one or more fields in the efx_filter_spec_s structure
  * that is responsible for the hardware filter.
+ * If some required field is unset in the flow rule, then a handful
+ * of filter copies will be created to cover all possible values
+ * of such a field.
  */
 
 enum sfc_flow_item_layers {
@@ -1095,8 +1098,8 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr,
                return -rte_errno;
        }
 
-       flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
-       flow->spec.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+       flow->spec.template.efs_flags |= EFX_FILTER_FLAG_RX;
+       flow->spec.template.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
 
        return 0;
 }
@@ -1187,7 +1190,7 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
                        break;
                }
 
-               rc = item->parse(pattern, &flow->spec, error);
+               rc = item->parse(pattern, &flow->spec.template, error);
                if (rc != 0)
                        return rc;
 
@@ -1209,7 +1212,7 @@ sfc_flow_parse_queue(struct sfc_adapter *sa,
                return -EINVAL;
 
        rxq = sa->rxq_info[queue->index].rxq;
-       flow->spec.efs_dmaq_id = (uint16_t)rxq->hw_index;
+       flow->spec.template.efs_dmaq_id = (uint16_t)rxq->hw_index;
 
        return 0;
 }
@@ -1284,14 +1287,58 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
 }
 #endif /* EFSYS_OPT_RX_SCALE */
 
+static int
+sfc_flow_spec_flush(struct sfc_adapter *sa, struct sfc_flow_spec *spec,
+                   unsigned int filters_count)
+{
+       unsigned int i;
+       int ret = 0;
+
+       for (i = 0; i < filters_count; i++) {
+               int rc;
+
+               rc = efx_filter_remove(sa->nic, &spec->filters[i]);
+               if (ret == 0 && rc != 0) {
+                       sfc_err(sa, "failed to remove filter specification "
+                               "(rc = %d)", rc);
+                       ret = rc;
+               }
+       }
+
+       return ret;
+}
+
+static int
+sfc_flow_spec_insert(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+       unsigned int i;
+       int rc = 0;
+
+       for (i = 0; i < spec->count; i++) {
+               rc = efx_filter_insert(sa->nic, &spec->filters[i]);
+               if (rc != 0) {
+                       sfc_flow_spec_flush(sa, spec, i);
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+static int
+sfc_flow_spec_remove(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
+{
+       return sfc_flow_spec_flush(sa, spec, spec->count);
+}
+
 static int
 sfc_flow_filter_insert(struct sfc_adapter *sa,
                       struct rte_flow *flow)
 {
-       efx_filter_spec_t *spec = &flow->spec;
-
 #if EFSYS_OPT_RX_SCALE
        struct sfc_flow_rss *rss = &flow->rss_conf;
+       uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
+       unsigned int i;
        int rc = 0;
 
        if (flow->rss) {
@@ -1302,27 +1349,38 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
                rc = efx_rx_scale_context_alloc(sa->nic,
                                                EFX_RX_SCALE_EXCLUSIVE,
                                                rss_spread,
-                                               &spec->efs_rss_context);
+                                               &efs_rss_context);
                if (rc != 0)
                        goto fail_scale_context_alloc;
 
-               rc = efx_rx_scale_mode_set(sa->nic, spec->efs_rss_context,
+               rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context,
                                           EFX_RX_HASHALG_TOEPLITZ,
                                           rss->rss_hash_types, B_TRUE);
                if (rc != 0)
                        goto fail_scale_mode_set;
 
-               rc = efx_rx_scale_key_set(sa->nic, spec->efs_rss_context,
+               rc = efx_rx_scale_key_set(sa->nic, efs_rss_context,
                                          rss->rss_key,
                                          sizeof(sa->rss_key));
                if (rc != 0)
                        goto fail_scale_key_set;
 
-               spec->efs_dmaq_id = rss->rxq_hw_index_min;
-               spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+               /*
+                * At this point, fully elaborated filter specifications
+                * have been produced from the template. To make sure that
+                * RSS behaviour is consistent between them, set the same
+                * RSS context value everywhere.
+                */
+               for (i = 0; i < flow->spec.count; i++) {
+                       efx_filter_spec_t *spec = &flow->spec.filters[i];
+
+                       spec->efs_rss_context = efs_rss_context;
+                       spec->efs_dmaq_id = rss->rxq_hw_index_min;
+                       spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+               }
        }
 
-       rc = efx_filter_insert(sa->nic, spec);
+       rc = sfc_flow_spec_insert(sa, &flow->spec);
        if (rc != 0)
                goto fail_filter_insert;
 
@@ -1335,7 +1393,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
                 * the HW knows all the information needed to verify
                 * the table entries, and the operation will succeed
                 */
-               rc = efx_rx_scale_tbl_set(sa->nic, spec->efs_rss_context,
+               rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context,
                                          rss->rss_tbl, RTE_DIM(rss->rss_tbl));
                if (rc != 0)
                        goto fail_scale_tbl_set;
@@ -1344,18 +1402,18 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
        return 0;
 
 fail_scale_tbl_set:
-       efx_filter_remove(sa->nic, spec);
+       sfc_flow_spec_remove(sa, &flow->spec);
 
 fail_filter_insert:
 fail_scale_key_set:
 fail_scale_mode_set:
-       if (flow->rss)
-               efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+       if (efs_rss_context != EFX_RSS_CONTEXT_DEFAULT)
+               efx_rx_scale_context_free(sa->nic, efs_rss_context);
 
 fail_scale_context_alloc:
        return rc;
 #else /* !EFSYS_OPT_RX_SCALE */
-       return efx_filter_insert(sa->nic, spec);
+       return sfc_flow_spec_insert(sa, &flow->spec);
 #endif /* EFSYS_OPT_RX_SCALE */
 }
 
@@ -1363,16 +1421,23 @@ static int
 sfc_flow_filter_remove(struct sfc_adapter *sa,
                       struct rte_flow *flow)
 {
-       efx_filter_spec_t *spec = &flow->spec;
        int rc = 0;
 
-       rc = efx_filter_remove(sa->nic, spec);
+       rc = sfc_flow_spec_remove(sa, &flow->spec);
        if (rc != 0)
                return rc;
 
 #if EFSYS_OPT_RX_SCALE
-       if (flow->rss)
+       if (flow->rss) {
+               /*
+                * All specifications for a given flow rule have the same RSS
+                * context, so that RSS context value is taken from the first
+                * filter specification
+                */
+               efx_filter_spec_t *spec = &flow->spec.filters[0];
+
                rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+       }
 #endif /* EFSYS_OPT_RX_SCALE */
 
        return rc;
@@ -1452,6 +1517,8 @@ sfc_flow_parse(struct rte_eth_dev *dev,
               struct rte_flow_error *error)
 {
        struct sfc_adapter *sa = dev->data->dev_private;
+       efx_filter_match_flags_t match_flags =
+               flow->spec.template.efs_match_flags;
        int rc;
 
        rc = sfc_flow_parse_attr(attr, flow, error);
@@ -1466,13 +1533,20 @@ sfc_flow_parse(struct rte_eth_dev *dev,
        if (rc != 0)
                goto fail_bad_value;
 
-       if (!sfc_filter_is_match_supported(sa, flow->spec.efs_match_flags)) {
+       if (!sfc_filter_is_match_supported(sa, match_flags)) {
                rte_flow_error_set(error, ENOTSUP,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
                                   "Flow rule pattern is not supported");
                return -rte_errno;
        }
 
+       /*
+        * At this point, template specification simply becomes the first
+        * fully elaborated spec
+        */
+       flow->spec.filters[0] = flow->spec.template;
+       flow->spec.count = 1;
+
 fail_bad_value:
        return rc;
 }
index 35472ad..634c310 100644 (file)
 extern "C" {
 #endif
 
+/*
+ * The maximum number of fully elaborated hardware filter specifications
+ * which can be produced from a template by means of multiplication, if
+ * missing match flags are needed to be taken into account
+ */
+#define SF_FLOW_SPEC_NB_FILTERS_MAX 1
+
 #if EFSYS_OPT_RX_SCALE
 /* RSS configuration storage */
 struct sfc_flow_rss {
@@ -30,9 +37,19 @@ struct sfc_flow_rss {
 };
 #endif /* EFSYS_OPT_RX_SCALE */
 
+/* Filter specification storage */
+struct sfc_flow_spec {
+       /* partial specification from flow rule */
+       efx_filter_spec_t template;
+       /* fully elaborated hardware filters specifications */
+       efx_filter_spec_t filters[SF_FLOW_SPEC_NB_FILTERS_MAX];
+       /* number of complete specifications */
+       unsigned int count;
+};
+
 /* PMD-specific definition of the opaque type from rte_flow.h */
 struct rte_flow {
-       efx_filter_spec_t spec;         /* filter specification */
+       struct sfc_flow_spec spec;      /* flow spec for hardware filter(s) */
 #if EFSYS_OPT_RX_SCALE
        boolean_t rss;                  /* RSS toggle */
        struct sfc_flow_rss rss_conf;   /* RSS configuration */