X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_flow.c;h=f392f1f657143c7b547e5910622f0c6adaaa156f;hb=d04fc01de2298e2b7e405f499a919d1bd4d551f1;hp=36c060eb6e631c97a1cc1dee769f01749e786367;hpb=4c3e9bcdd52ee4a656c3e56f5e334d9b3cb997bf;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 36c060eb6e..f392f1f657 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -59,6 +59,29 @@ #define MLX5_IPV4 4 #define MLX5_IPV6 6 +#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT +struct ibv_counter_set_init_attr { + int dummy; +}; +struct ibv_flow_spec_counter_action { + int dummy; +}; +struct ibv_counter_set { + int dummy; +}; + +static inline int +ibv_destroy_counter_set(struct ibv_counter_set *cs) +{ + (void)cs; + return -ENOTSUP; +} +#endif + +/* Dev ops structure defined in mlx5.c */ +extern const struct eth_dev_ops mlx5_dev_ops; +extern const struct eth_dev_ops mlx5_dev_ops_isolate; + static int mlx5_flow_create_eth(const struct rte_flow_item *item, const void *default_mask, @@ -103,6 +126,9 @@ mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src, static int mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id); +static int +mlx5_flow_create_count(struct priv *priv, struct mlx5_flow_parse *parser); + /* Hash RX queue types. */ enum hash_rxq_type { HASH_RXQ_TCPV4, @@ -186,6 +212,12 @@ const struct hash_rxq_init hash_rxq_init[] = { /* Number of entries in hash_rxq_init[]. */ const unsigned int hash_rxq_init_n = RTE_DIM(hash_rxq_init); +/** Structure for holding counter stats. */ +struct mlx5_flow_counter_stats { + uint64_t hits; /**< Number of packets matched by the rule. */ + uint64_t bytes; /**< Number of bytes matched by the rule. */ +}; + /** Structure for Drop queue. */ struct mlx5_hrxq_drop { struct ibv_rwq_ind_table *ind_table; /**< Indirection table. */ @@ -216,6 +248,8 @@ struct rte_flow { uint16_t (*queues)[]; /**< Queues indexes to use. */ struct rte_eth_rss_conf rss_conf; /**< RSS configuration */ uint8_t rss_key[40]; /**< copy of the RSS key. */ + struct ibv_counter_set *cs; /**< Holds the counters for the rule. */ + struct mlx5_flow_counter_stats counter_stats;/**mark_id = mark->id; } else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) { parser->mark = 1; + } else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT && + priv->counter_set_supported) { + parser->count = 1; } else { goto exit_action_not_supported; } } + if (parser->drop && parser->mark) + parser->mark = 0; if (!parser->queues_n && !parser->drop) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "no valid action"); @@ -833,6 +881,16 @@ priv_flow_convert_items_validate(struct priv *priv, parser->queue[i].offset += sizeof(struct ibv_flow_spec_action_tag); } + if (parser->count) { + unsigned int size = sizeof(struct ibv_flow_spec_counter_action); + + if (parser->drop) { + parser->drop_q.offset += size; + } else { + for (i = 0; i != hash_rxq_init_n; ++i) + parser->queue[i].offset += size; + } + } return 0; exit_item_not_supported: rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, @@ -1107,12 +1165,35 @@ priv_flow_convert(struct priv *priv, } if (parser->mark) mlx5_flow_create_flag_mark(parser, parser->mark_id); + if (parser->count && parser->create) { + mlx5_flow_create_count(priv, parser); + if (!parser->cs) + goto exit_count_error; + } /* * Last step. Complete missing specification to reach the RSS * configuration. */ - if (parser->queues_n > 1) + if (parser->drop) { + /* + * Drop queue priority needs to be adjusted to + * their most specific layer priority. + */ + parser->drop_q.ibv_attr->priority = + attr->priority + + hash_rxq_init[parser->layer].flow_priority; + } else if (parser->queues_n > 1) { priv_flow_convert_finalise(priv, parser); + } else { + /* + * Action queue have their priority overridden with + * Ethernet priority, this priority needs to be adjusted to + * their most specific layer priority. + */ + parser->queue[HASH_RXQ_ETH].ibv_attr->priority = + attr->priority + + hash_rxq_init[parser->layer].flow_priority; + } exit_free: /* Only verification is expected, all resources should be released. */ if (!parser->create) { @@ -1138,6 +1219,10 @@ exit_enomem: rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "cannot allocate verbs spec attributes."); return ret; +exit_count_error: + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "cannot create counter."); + return rte_errno; } /** @@ -1534,6 +1619,40 @@ mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id) return 0; } +/** + * Convert count action to Verbs specification. + * + * @param priv + * Pointer to private structure. + * @param parser + * Pointer to MLX5 flow parser structure. + * + * @return + * 0 on success, errno value on failure. + */ +static int +mlx5_flow_create_count(struct priv *priv __rte_unused, + struct mlx5_flow_parse *parser __rte_unused) +{ +#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT + unsigned int size = sizeof(struct ibv_flow_spec_counter_action); + struct ibv_counter_set_init_attr init_attr = {0}; + struct ibv_flow_spec_counter_action counter = { + .type = IBV_FLOW_SPEC_ACTION_COUNT, + .size = size, + .counter_set_handle = 0, + }; + + init_attr.counter_set_id = 0; + parser->cs = ibv_create_counter_set(priv->ctx, &init_attr); + if (!parser->cs) + return EINVAL; + counter.counter_set_handle = parser->cs->handle; + mlx5_flow_create_copy(parser, &counter, size); +#endif + return 0; +} + /** * Complete flow rule creation with a drop queue. * @@ -1570,12 +1689,14 @@ priv_flow_create_action_queue_drop(struct priv *priv, }; ++parser->drop_q.ibv_attr->num_of_specs; parser->drop_q.offset += size; + flow->drxq.ibv_attr = parser->drop_q.ibv_attr; if (!priv->dev->data->dev_started) return 0; - flow->drxq.ibv_attr = parser->drop_q.ibv_attr; parser->drop_q.ibv_attr = NULL; flow->drxq.ibv_flow = ibv_create_flow(priv->flow_drop_queue->qp, flow->drxq.ibv_attr); + if (parser->count) + flow->cs = parser->cs; if (!flow->drxq.ibv_flow) { rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "flow rule creation failure"); @@ -1593,6 +1714,11 @@ error: rte_free(flow->drxq.ibv_attr); flow->drxq.ibv_attr = NULL; } + if (flow->cs) { + claim_zero(ibv_destroy_counter_set(flow->cs)); + flow->cs = NULL; + parser->cs = NULL; + } return err; } @@ -1627,6 +1753,8 @@ priv_flow_create_action_queue_rss(struct priv *priv, flow->frxq[i].ibv_attr = parser->queue[i].ibv_attr; parser->queue[i].ibv_attr = NULL; hash_fields = hash_rxq_init[i].hash_fields; + if (!priv->dev->data->dev_started) + continue; flow->frxq[i].hrxq = mlx5_priv_hrxq_get(priv, parser->rss_conf.rss_key, @@ -1683,6 +1811,8 @@ priv_flow_create_action_queue(struct priv *priv, err = priv_flow_create_action_queue_rss(priv, parser, flow, error); if (err) goto error; + if (parser->count) + flow->cs = parser->cs; if (!priv->dev->data->dev_started) return 0; for (i = 0; i != hash_rxq_init_n; ++i) { @@ -1723,6 +1853,11 @@ error: if (flow->frxq[i].ibv_attr) rte_free(flow->frxq[i].ibv_attr); } + if (flow->cs) { + claim_zero(ibv_destroy_counter_set(flow->cs)); + flow->cs = NULL; + parser->cs = NULL; + } return err; } @@ -1866,6 +2001,10 @@ priv_flow_destroy(struct priv *priv, { unsigned int i; + if (flow->cs) { + claim_zero(ibv_destroy_counter_set(flow->cs)); + flow->cs = NULL; + } if (flow->drop || !flow->mark) goto free; for (i = 0; i != flow->queues_n; ++i) { @@ -2336,6 +2475,86 @@ mlx5_flow_flush(struct rte_eth_dev *dev, return 0; } +#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT +/** + * Query flow counter. + * + * @param cs + * the counter set. + * @param counter_value + * returned data from the counter. + * + * @return + * 0 on success, a errno value otherwise and rte_errno is set. + */ +static int +priv_flow_query_count(struct ibv_counter_set *cs, + struct mlx5_flow_counter_stats *counter_stats, + struct rte_flow_query_count *query_count, + struct rte_flow_error *error) +{ + uint64_t counters[2]; + struct ibv_query_counter_set_attr query_cs_attr = { + .cs = cs, + .query_flags = IBV_COUNTER_SET_FORCE_UPDATE, + }; + struct ibv_counter_set_data query_out = { + .out = counters, + .outlen = 2 * sizeof(uint64_t), + }; + int res = ibv_query_counter_set(&query_cs_attr, &query_out); + + if (res) { + rte_flow_error_set(error, -res, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "cannot read counter"); + return -res; + } + query_count->hits_set = 1; + query_count->bytes_set = 1; + query_count->hits = counters[0] - counter_stats->hits; + query_count->bytes = counters[1] - counter_stats->bytes; + if (query_count->reset) { + counter_stats->hits = counters[0]; + counter_stats->bytes = counters[1]; + } + return 0; +} + +/** + * Query a flows. + * + * @see rte_flow_query() + * @see rte_flow_ops + */ +int +mlx5_flow_query(struct rte_eth_dev *dev, + struct rte_flow *flow, + enum rte_flow_action_type action __rte_unused, + void *data, + struct rte_flow_error *error) +{ + struct priv *priv = dev->data->dev_private; + int res = EINVAL; + + priv_lock(priv); + if (flow->cs) { + res = priv_flow_query_count(flow->cs, + &flow->counter_stats, + (struct rte_flow_query_count *)data, + error); + } else { + rte_flow_error_set(error, res, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "no counter found for flow"); + } + priv_unlock(priv); + return -res; +} +#endif + /** * Isolated mode. * @@ -2359,6 +2578,10 @@ mlx5_flow_isolate(struct rte_eth_dev *dev, return -rte_errno; } priv->isolated = !!enable; + if (enable) + priv->dev->dev_ops = &mlx5_dev_ops_isolate; + else + priv->dev->dev_ops = &mlx5_dev_ops; priv_unlock(priv); return 0; } @@ -2388,20 +2611,27 @@ priv_fdir_filter_convert(struct priv *priv, ERROR("invalid queue number %d", fdir_filter->action.rx_queue); return EINVAL; } - /* Validate the behavior. */ - if (fdir_filter->action.behavior != RTE_ETH_FDIR_ACCEPT) { - ERROR("invalid behavior %d", fdir_filter->action.behavior); - return ENOTSUP; - } attributes->attr.ingress = 1; attributes->items[0] = (struct rte_flow_item) { .type = RTE_FLOW_ITEM_TYPE_ETH, .spec = &attributes->l2, }; - attributes->actions[0] = (struct rte_flow_action){ - .type = RTE_FLOW_ACTION_TYPE_QUEUE, - .conf = &attributes->queue, - }; + switch (fdir_filter->action.behavior) { + case RTE_ETH_FDIR_ACCEPT: + attributes->actions[0] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_QUEUE, + .conf = &attributes->queue, + }; + break; + case RTE_ETH_FDIR_REJECT: + attributes->actions[0] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_DROP, + }; + break; + default: + ERROR("invalid behavior %d", fdir_filter->action.behavior); + return ENOTSUP; + } attributes->queue.index = fdir_filter->action.rx_queue; switch (fdir_filter->input.flow_type) { case RTE_ETH_FLOW_NONFRAG_IPV4_UDP: @@ -2570,7 +2800,6 @@ priv_fdir_filter_add(struct priv *priv, attributes.actions, &error); if (flow) { - TAILQ_INSERT_TAIL(&priv->flows, flow, next); DEBUG("FDIR created %p", (void *)flow); return 0; }