From 814260e0384dcd951ba88490e0249e1adb0439fb Mon Sep 17 00:00:00 2001 From: Roman Zhukov Date: Tue, 6 Mar 2018 15:24:54 +0000 Subject: [PATCH] net/sfc: add infrastructure to make many filters from flow 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 Signed-off-by: Andrew Rybchenko Reviewed-by: Ivan Malov --- drivers/net/sfc/sfc_flow.c | 118 ++++++++++++++++++++++++++++++------- drivers/net/sfc/sfc_flow.h | 19 +++++- 2 files changed, 114 insertions(+), 23 deletions(-) diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index 0da63839af..3f6b7b78b4 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -25,10 +25,13 @@ /* * 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; } diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h index 35472ad3e8..634c31093d 100644 --- a/drivers/net/sfc/sfc_flow.h +++ b/drivers/net/sfc/sfc_flow.h @@ -19,6 +19,13 @@ 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 */ -- 2.20.1