From patchwork Tue Oct 10 14:22:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?N=C3=A9lio_Laranjeiro?= X-Patchwork-Id: 30068 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 1AF6E1B328; Tue, 10 Oct 2017 16:23:18 +0200 (CEST) Received: from mail-wm0-f53.google.com (mail-wm0-f53.google.com [74.125.82.53]) by dpdk.org (Postfix) with ESMTP id 6FE381B319 for ; Tue, 10 Oct 2017 16:23:13 +0200 (CEST) Received: by mail-wm0-f53.google.com with SMTP id u138so5664030wmu.5 for ; Tue, 10 Oct 2017 07:23:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/S16mlfjIicCs+o5egMWPd8cgMnz/Mv5uZOLa3M72BM=; b=TI1aBvvUIEJVfv+gqrDfEV6SrB2Ec164Nmagjd1k8k6P0/Yv+uHJsPHIYT76gDVwXg JU8bmD7SKecM0m2IDlDmLhLgLWEUvRd4uXSih08vW7s4aFgHJRjaioqtHTu9Psd30YaC j8CV6X/7RYYt0Vc4Sb5Wb5T3EQxHIUh74mtMlsjj8dEJ+DLR+ePWPSQ7vvtUb7mLW6Xm irD3fgCbmAFlkA3TRg6nRsDkigjljUg6TR/sfh7xXdrBajERfVFt1gGrmdJMFPHkNaW5 P7VuQJ81e7akaeZGy66CYys58rUzmZDTR9Ywx7NTmKTyZ4qZezdW0bFw3KlhfBKyX73B 3uvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/S16mlfjIicCs+o5egMWPd8cgMnz/Mv5uZOLa3M72BM=; b=FSM1RSyKdT9fr5eY3/7dJMXyrit6+zuUesvP3HFKuBR5SU8TLNn0+J72piYbhZjZZK 0HeN6mOTn8pUXB2f+oHV0Q6aHpiBjYaT2aSXtLjEy5znrMSd7PFDTDDLRTshti4cocuN om4dNepe/TV/VyC6E6D7yaquJvzGDCBx9RomdMeJmGM6Ix+yUHqjIPapYuxvx+7WTKA/ qnd8G7rv9LwWRRtOJW+l93QTGQwdTydahjz8Ddm8Tz974jUlV4/Vn1EaZxddSE42+rx2 hyx6bc7tQtQSK8kpt65bQik4yfa75VsrDactk8q0197cc5MdcnFIorHnmYWauwjskQL7 rd7Q== X-Gm-Message-State: AMCzsaUv+aqL8Q0WCHU0luf4fPgu7jmc9zkbsYGbqo8rkUWY+f/maujh h2WT2FJsCe++2WMHrPAkWh0FuzRKNg== X-Google-Smtp-Source: AOwi7QBz8ZaBhSlYbGOAJXdrJ/3EXYJoSDn2zGu0Bcm3mF/C9spG6TEWaziT6glGU9NUumH2sg0HwA== X-Received: by 10.28.136.83 with SMTP id k80mr13348181wmd.159.1507645392595; Tue, 10 Oct 2017 07:23:12 -0700 (PDT) Received: from ping.dev.6wind.com (host.78.145.23.62.rev.coltfrance.com. [62.23.145.78]) by smtp.gmail.com with ESMTPSA id q81sm23542114wrb.88.2017.10.10.07.23.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 10 Oct 2017 07:23:12 -0700 (PDT) From: Nelio Laranjeiro To: dev@dpdk.org Cc: Ori Kam , adrien.mazarguil@6wind.com, yskoh@mellanox.com, ferruh.yigit@intel.com Date: Tue, 10 Oct 2017 16:22:54 +0200 Message-Id: X-Mailer: git-send-email 2.1.4 In-Reply-To: <1503318941-42015-1-git-send-email-orika@mellanox.com> References: <1503318941-42015-1-git-send-email-orika@mellanox.com> Subject: [dpdk-dev] [PATCH v2] net/mlx5: flow counter support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ori Kam Example for setting rule for counting packets with dest ip = 192.168.3.1 in testpmd: testpmd: flow create 0 ingress pattern eth / ipv4 dst is 192.168.3.1 / end actions queue index 0 / count / end Reading the number of packets and bytes for the rule: testpmd: flow query 0 0 count Note: This feature is only supported starting Mellanox OFED 4.2 Signed-off-by: Ori Kam Signed-off-by: Nelio Laranjeiro Acked-by: Yongseok Koh --- Changes in V2: * finalise implementation after all remarks --- --- drivers/net/mlx5/Makefile | 5 ++ drivers/net/mlx5/mlx5.c | 12 +++ drivers/net/mlx5/mlx5.h | 4 + drivers/net/mlx5/mlx5_flow.c | 193 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+) diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile index e7aca04..2e90692 100644 --- a/drivers/net/mlx5/Makefile +++ b/drivers/net/mlx5/Makefile @@ -144,6 +144,11 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh /usr/include/linux/ethtool.h \ enum ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT \ $(AUTOCONF_OUTPUT) + $Q sh -- '$<' '$@' \ + HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT \ + infiniband/verbs.h \ + enum IBV_FLOW_SPEC_ACTION_COUNT \ + $(AUTOCONF_OUTPUT) # Create mlx5_autoconf.h or update it in case it differs from the new one. diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index c0f7b1b..29221dc 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -548,6 +548,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) int idx; int i; struct mlx5dv_context attrs_out; +#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT + struct ibv_counter_set_description cs_desc; +#endif (void)pci_drv; assert(pci_drv == &mlx5_driver); @@ -667,6 +670,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) struct ibv_device_attr_ex device_attr_ex; struct ether_addr mac; uint16_t num_vfs = 0; + struct ibv_device_attr_ex device_attr; struct mlx5_args args = { .cqe_comp = MLX5_ARG_UNSET, .txq_inline = MLX5_ARG_UNSET, @@ -721,6 +725,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) goto port_error; } + ibv_query_device_ex(ctx, NULL, &device_attr); /* Check port status. */ err = ibv_query_port(ctx, port, &port_attr); if (err) { @@ -798,6 +803,13 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) DEBUG("L2 tunnel checksum offloads are %ssupported", (priv->hw_csum_l2tun ? "" : "not ")); +#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT + priv->counter_set_supported = !!(device_attr.max_counter_sets); + ibv_describe_counter_set(ctx, 0, &cs_desc); + DEBUG("counter type = %d, num of cs = %ld, attributes = %d", + cs_desc.counter_type, cs_desc.num_of_cs, + cs_desc.attributes); +#endif priv->ind_table_max_size = device_attr_ex.rss_caps.max_rwq_indirection_table_size; /* Remove this check once DPDK supports larger/variable diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 643bab6..9ade624 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -117,6 +117,7 @@ struct priv { unsigned int isolated:1; /* Whether isolated mode is enabled. */ unsigned int tx_vec_en:1; /* Whether Tx vector is enabled. */ unsigned int rx_vec_en:1; /* Whether Rx vector is enabled. */ + unsigned int counter_set_supported:1; /* Counter set is supported. */ /* Whether Tx offloads for tunneled packets are supported. */ unsigned int max_tso_payload_sz; /* Maximum TCP payload for TSO. */ unsigned int txq_inline; /* Maximum packet size for inlining. */ @@ -276,6 +277,9 @@ int mlx5_flow_destroy(struct rte_eth_dev *, struct rte_flow *, struct rte_flow_error *); void priv_flow_flush(struct priv *, struct mlx5_flows *); int mlx5_flow_flush(struct rte_eth_dev *, struct rte_flow_error *); +int mlx5_flow_query(struct rte_eth_dev *, struct rte_flow *, + enum rte_flow_action_type, void *, + struct rte_flow_error *); int mlx5_flow_isolate(struct rte_eth_dev *, int, struct rte_flow_error *); int priv_flow_start(struct priv *, struct mlx5_flows *); void priv_flow_stop(struct priv *, struct mlx5_flows *); diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 3321b3e..2b6380f 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -59,6 +59,25 @@ #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; @@ -107,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, @@ -190,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. */ @@ -220,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; } @@ -837,6 +879,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, @@ -1111,6 +1163,11 @@ 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. @@ -1142,6 +1199,10 @@ priv_flow_convert(struct priv *priv, 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; } /** @@ -1539,6 +1600,40 @@ mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id) } /** + * 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. * * @param priv @@ -1580,6 +1675,8 @@ priv_flow_create_action_queue_drop(struct priv *priv, 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"); @@ -1597,6 +1694,11 @@ priv_flow_create_action_queue_drop(struct priv *priv, 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; } @@ -1687,6 +1789,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) { @@ -1727,6 +1831,11 @@ priv_flow_create_action_queue(struct priv *priv, 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; } @@ -1870,6 +1979,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) { @@ -2340,6 +2453,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. *