X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsfc%2Fsfc_flow.c;h=5613d59a9cce9a3205f54f83220516511e603757;hb=c6034a20d9e221dc6125db57e4378520af3a515d;hp=cd6a61b3952b2c1fd1c7a2590f64acd6bd34705c;hpb=e58638c32411b7ae60ed4dea131728faee962327;p=dpdk.git diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index cd6a61b395..5613d59a9c 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -23,6 +23,7 @@ #include "sfc_filter.h" #include "sfc_flow.h" #include "sfc_log.h" +#include "sfc_dp_rx.h" /* * At now flow API is implemented in such a manner that each @@ -120,7 +121,6 @@ sfc_flow_parse_init(const struct rte_flow_item *item, const uint8_t *spec; const uint8_t *mask; const uint8_t *last; - uint8_t match; uint8_t supp; unsigned int i; @@ -181,12 +181,11 @@ sfc_flow_parse_init(const struct rte_flow_item *item, return -rte_errno; } - /* Check that mask and spec not asks for more match than supp_mask */ + /* Check that mask does not ask for more match than supp_mask */ for (i = 0; i < size; i++) { - match = spec[i] | mask[i]; supp = ((const uint8_t *)supp_mask)[i]; - if ((match | supp) != supp) { + if (~supp & mask[i]) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, "Item's field is not supported"); @@ -1116,6 +1115,12 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr, "Egress is not supported"); return -rte_errno; } + if (attr->transfer != 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, attr, + "Transfer is not supported"); + return -rte_errno; + } if (attr->ingress == 0) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr, @@ -1242,21 +1247,22 @@ sfc_flow_parse_queue(struct sfc_adapter *sa, return 0; } -#if EFSYS_OPT_RX_SCALE static int sfc_flow_parse_rss(struct sfc_adapter *sa, - const struct rte_flow_action_rss *rss, + const struct rte_flow_action_rss *action_rss, struct rte_flow *flow) { + struct sfc_rss *rss = &sa->rss; unsigned int rxq_sw_index; struct sfc_rxq *rxq; unsigned int rxq_hw_index_min; unsigned int rxq_hw_index_max; + efx_rx_hash_type_t efx_hash_types; const uint8_t *rss_key; struct sfc_flow_rss *sfc_rss_conf = &flow->rss_conf; unsigned int i; - if (rss->queue_num == 0) + if (action_rss->queue_num == 0) return -EINVAL; rxq_sw_index = sa->rxq_count - 1; @@ -1264,8 +1270,8 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, rxq_hw_index_min = rxq->hw_index; rxq_hw_index_max = 0; - for (i = 0; i < rss->queue_num; ++i) { - rxq_sw_index = rss->queue[i]; + for (i = 0; i < action_rss->queue_num; ++i) { + rxq_sw_index = action_rss->queue[i]; if (rxq_sw_index >= sa->rxq_count) return -EINVAL; @@ -1279,7 +1285,7 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, rxq_hw_index_max = rxq->hw_index; } - switch (rss->func) { + switch (action_rss->func) { case RTE_ETH_HASH_FUNCTION_DEFAULT: case RTE_ETH_HASH_FUNCTION_TOEPLITZ: break; @@ -1287,30 +1293,54 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, return -EINVAL; } - if (rss->level) + if (action_rss->level) return -EINVAL; - if ((rss->types & ~SFC_RSS_OFFLOADS) != 0) - return -EINVAL; + /* + * Dummy RSS action with only one queue and no specific settings + * for hash types and key does not require dedicated RSS context + * and may be simplified to single queue action. + */ + if (action_rss->queue_num == 1 && action_rss->types == 0 && + action_rss->key_len == 0) { + flow->spec.template.efs_dmaq_id = rxq_hw_index_min; + return 0; + } + + if (action_rss->types) { + int rc; + + rc = sfc_rx_hf_rte_to_efx(sa, action_rss->types, + &efx_hash_types); + if (rc != 0) + return -rc; + } else { + unsigned int i; + + efx_hash_types = 0; + for (i = 0; i < rss->hf_map_nb_entries; ++i) + efx_hash_types |= rss->hf_map[i].efx; + } - if (rss->key_len) { - if (rss->key_len != sizeof(sa->rss_key)) + if (action_rss->key_len) { + if (action_rss->key_len != sizeof(rss->key)) return -EINVAL; - rss_key = rss->key; + rss_key = action_rss->key; } else { - rss_key = sa->rss_key; + rss_key = rss->key; } flow->rss = B_TRUE; sfc_rss_conf->rxq_hw_index_min = rxq_hw_index_min; sfc_rss_conf->rxq_hw_index_max = rxq_hw_index_max; - sfc_rss_conf->rss_hash_types = sfc_rte_to_efx_hash_type(rss->types); - rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(sa->rss_key)); + sfc_rss_conf->rss_hash_types = efx_hash_types; + rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(rss->key)); for (i = 0; i < RTE_DIM(sfc_rss_conf->rss_tbl); ++i) { - unsigned int rxq_sw_index = rss->queue[i % rss->queue_num]; + unsigned int nb_queues = action_rss->queue_num; + unsigned int rxq_sw_index = action_rss->queue[i % nb_queues]; struct sfc_rxq *rxq = sa->rxq_info[rxq_sw_index].rxq; sfc_rss_conf->rss_tbl[i] = rxq->hw_index - rxq_hw_index_min; @@ -1318,7 +1348,6 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, return 0; } -#endif /* EFSYS_OPT_RX_SCALE */ static int sfc_flow_spec_flush(struct sfc_adapter *sa, struct sfc_flow_spec *spec, @@ -1368,15 +1397,15 @@ static int sfc_flow_filter_insert(struct sfc_adapter *sa, struct rte_flow *flow) { -#if EFSYS_OPT_RX_SCALE - struct sfc_flow_rss *rss = &flow->rss_conf; + struct sfc_rss *rss = &sa->rss; + struct sfc_flow_rss *flow_rss = &flow->rss_conf; uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT; unsigned int i; int rc = 0; if (flow->rss) { - unsigned int rss_spread = MIN(rss->rxq_hw_index_max - - rss->rxq_hw_index_min + 1, + unsigned int rss_spread = MIN(flow_rss->rxq_hw_index_max - + flow_rss->rxq_hw_index_min + 1, EFX_MAXRSS); rc = efx_rx_scale_context_alloc(sa->nic, @@ -1387,14 +1416,14 @@ sfc_flow_filter_insert(struct sfc_adapter *sa, goto fail_scale_context_alloc; rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context, - EFX_RX_HASHALG_TOEPLITZ, - rss->rss_hash_types, B_TRUE); + rss->hash_alg, + flow_rss->rss_hash_types, B_TRUE); if (rc != 0) goto fail_scale_mode_set; rc = efx_rx_scale_key_set(sa->nic, efs_rss_context, - rss->rss_key, - sizeof(sa->rss_key)); + flow_rss->rss_key, + sizeof(rss->key)); if (rc != 0) goto fail_scale_key_set; @@ -1408,7 +1437,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa, 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_dmaq_id = flow_rss->rxq_hw_index_min; spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS; } } @@ -1427,7 +1456,8 @@ sfc_flow_filter_insert(struct sfc_adapter *sa, * the table entries, and the operation will succeed */ rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context, - rss->rss_tbl, RTE_DIM(rss->rss_tbl)); + flow_rss->rss_tbl, + RTE_DIM(flow_rss->rss_tbl)); if (rc != 0) goto fail_scale_tbl_set; } @@ -1445,9 +1475,6 @@ fail_scale_mode_set: fail_scale_context_alloc: return rc; -#else /* !EFSYS_OPT_RX_SCALE */ - return sfc_flow_spec_insert(sa, &flow->spec); -#endif /* EFSYS_OPT_RX_SCALE */ } static int @@ -1460,7 +1487,6 @@ sfc_flow_filter_remove(struct sfc_adapter *sa, if (rc != 0) return rc; -#if EFSYS_OPT_RX_SCALE if (flow->rss) { /* * All specifications for a given flow rule have the same RSS @@ -1471,11 +1497,26 @@ sfc_flow_filter_remove(struct sfc_adapter *sa, rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context); } -#endif /* EFSYS_OPT_RX_SCALE */ return rc; } +static int +sfc_flow_parse_mark(struct sfc_adapter *sa, + const struct rte_flow_action_mark *mark, + struct rte_flow *flow) +{ + const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); + + if (mark == NULL || mark->id > encp->enc_filter_action_mark_max) + return EINVAL; + + flow->spec.template.efs_flags |= EFX_FILTER_FLAG_ACTION_MARK; + flow->spec.template.efs_mark = mark->id; + + return 0; +} + static int sfc_flow_parse_actions(struct sfc_adapter *sa, const struct rte_flow_action actions[], @@ -1483,7 +1524,13 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, struct rte_flow_error *error) { int rc; - boolean_t is_specified = B_FALSE; + const unsigned int dp_rx_features = sa->dp_rx->features; + uint32_t actions_set = 0; + const uint32_t fate_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_QUEUE) | + (1UL << RTE_FLOW_ACTION_TYPE_RSS) | + (1UL << RTE_FLOW_ACTION_TYPE_DROP); + const uint32_t mark_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_MARK) | + (1UL << RTE_FLOW_ACTION_TYPE_FLAG); if (actions == NULL) { rte_flow_error_set(error, EINVAL, @@ -1492,21 +1539,22 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, return -rte_errno; } +#define SFC_BUILD_SET_OVERFLOW(_action, _set) \ + RTE_BUILD_BUG_ON(_action >= sizeof(_set) * CHAR_BIT) + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { - /* This one may appear anywhere multiple times. */ - if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) - continue; - /* Fate-deciding actions may appear exactly once. */ - if (is_specified) { - rte_flow_error_set - (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, - actions, - "Cannot combine several fate-deciding actions," - "choose between QUEUE, RSS or DROP"); - return -rte_errno; - } switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_VOID: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VOID, + actions_set); + break; + case RTE_FLOW_ACTION_TYPE_QUEUE: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_QUEUE, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + rc = sfc_flow_parse_queue(sa, actions->conf, flow); if (rc != 0) { rte_flow_error_set(error, EINVAL, @@ -1514,29 +1562,70 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, "Bad QUEUE action"); return -rte_errno; } - - is_specified = B_TRUE; break; -#if EFSYS_OPT_RX_SCALE case RTE_FLOW_ACTION_TYPE_RSS: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_RSS, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + rc = sfc_flow_parse_rss(sa, actions->conf, flow); if (rc != 0) { - rte_flow_error_set(error, rc, + rte_flow_error_set(error, -rc, RTE_FLOW_ERROR_TYPE_ACTION, actions, "Bad RSS action"); return -rte_errno; } - - is_specified = B_TRUE; break; -#endif /* EFSYS_OPT_RX_SCALE */ case RTE_FLOW_ACTION_TYPE_DROP: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP, + actions_set); + if ((actions_set & fate_actions_mask) != 0) + goto fail_fate_actions; + flow->spec.template.efs_dmaq_id = EFX_FILTER_SPEC_RX_DMAQ_ID_DROP; + break; + + case RTE_FLOW_ACTION_TYPE_FLAG: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG, + actions_set); + if ((actions_set & mark_actions_mask) != 0) + goto fail_actions_overlap; + + if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_FLAG) == 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "FLAG action is not supported on the current Rx datapath"); + return -rte_errno; + } + + flow->spec.template.efs_flags |= + EFX_FILTER_FLAG_ACTION_FLAG; + break; - is_specified = B_TRUE; + case RTE_FLOW_ACTION_TYPE_MARK: + SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK, + actions_set); + if ((actions_set & mark_actions_mask) != 0) + goto fail_actions_overlap; + + if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_MARK) == 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "MARK action is not supported on the current Rx datapath"); + return -rte_errno; + } + + rc = sfc_flow_parse_mark(sa, actions->conf, flow); + if (rc != 0) { + rte_flow_error_set(error, rc, + RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Bad MARK action"); + return -rte_errno; + } break; default: @@ -1545,15 +1634,29 @@ sfc_flow_parse_actions(struct sfc_adapter *sa, "Action is not supported"); return -rte_errno; } + + actions_set |= (1UL << actions->type); } +#undef SFC_BUILD_SET_OVERFLOW /* When fate is unknown, drop traffic. */ - if (!is_specified) { + if ((actions_set & fate_actions_mask) == 0) { flow->spec.template.efs_dmaq_id = EFX_FILTER_SPEC_RX_DMAQ_ID_DROP; } return 0; + +fail_fate_actions: + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Cannot combine several fate-deciding actions, " + "choose between QUEUE, RSS or DROP"); + return -rte_errno; + +fail_actions_overlap: + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Overlapping actions are not supported"); + return -rte_errno; } /** @@ -1943,7 +2046,7 @@ sfc_flow_spec_filters_complete(struct sfc_adapter *sa, if (min_multiplier == UINT_MAX) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "Flow rule pattern is not supported"); + "The flow rule pattern is unsupported"); return -rte_errno; }