From patchwork Thu Jan 16 10:14:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 64763 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 227ADA0352; Thu, 16 Jan 2020 11:15:51 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 155F51C1E4; Thu, 16 Jan 2020 11:15:46 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id C8B081C1AF for ; Thu, 16 Jan 2020 11:15:42 +0100 (CET) From: Xiaoyu Min To: jerinjacobk@gmail.com, orika@mellanox.com, viacheslavo@mellanox.com, matan@mellanox.com, rasland@mellanox.com, Thomas Monjalon , Ferruh Yigit , Andrew Rybchenko , Adrien Mazarguil Cc: dev@dpdk.org Date: Thu, 16 Jan 2020 12:14:13 +0200 Message-Id: X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info 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" Introduce an API which dump the device's internal representation information of rte flows in hardware. Signed-off-by: Xiaoyu Min Acked-by: Ori Kam --- lib/librte_ethdev/rte_ethdev_version.map | 3 +++ lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++++ lib/librte_ethdev/rte_flow.h | 21 +++++++++++++++++++++ lib/librte_ethdev/rte_flow_driver.h | 5 +++++ 4 files changed, 45 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index a7dacf2cf2..3f32fdecf7 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -227,4 +227,7 @@ EXPERIMENTAL { rte_flow_dynf_metadata_mask; rte_flow_dynf_metadata_register; rte_eth_dev_set_ptypes; + + # added in 20.02 + rte_flow_dev_dump; }; diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index 87a3e8c4c6..751ce721b2 100644 --- a/lib/librte_ethdev/rte_flow.c +++ b/lib/librte_ethdev/rte_flow.c @@ -1212,3 +1212,19 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, } return lsize; } + +int +rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error *error) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error); + + if (unlikely(!ops)) + return -rte_errno; + if (likely(!!ops->dev_dump)) + return flow_err(port_id, ops->dev_dump(dev, file, error), + error); + return rte_flow_error_set(error, ENOSYS, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, rte_strerror(ENOSYS)); +} diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h index 58b50265d2..cf7cf61ae8 100644 --- a/lib/librte_ethdev/rte_flow.h +++ b/lib/librte_ethdev/rte_flow.h @@ -2790,6 +2790,27 @@ enum rte_flow_conv_op { RTE_FLOW_CONV_OP_ACTION_NAME_PTR, }; +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Dump hardware internal representation information of + * rte flow to file. + * + * @param[in] port_id + * The port identifier of the Ethernet device. + * @param[in] file + * A pointer to a file for output. + * @param[out] error + * Perform verbose error reporting if not NULL. PMDs initialize this + * structure in case of error only. + * @return + * 0 on success, a nagative value otherwise. + */ +__rte_experimental +int +rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error *error); + /** * Check if mbuf dynamic field for metadata is registered. * diff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_flow_driver.h index a0359853e6..51a9a57a0f 100644 --- a/lib/librte_ethdev/rte_flow_driver.h +++ b/lib/librte_ethdev/rte_flow_driver.h @@ -96,6 +96,11 @@ struct rte_flow_ops { (struct rte_eth_dev *, int, struct rte_flow_error *); + /** See rte_flow_dev_dump(). */ + int (*dev_dump) + (struct rte_eth_dev *dev, + FILE *file, + struct rte_flow_error *error); }; /** From patchwork Thu Jan 16 10:14:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 64764 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 67FD5A0352; Thu, 16 Jan 2020 11:15:58 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 378BC1C1EA; Thu, 16 Jan 2020 11:15:48 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 4376A1C1DE for ; Thu, 16 Jan 2020 11:15:44 +0100 (CET) From: Xiaoyu Min To: jerinjacobk@gmail.com, orika@mellanox.com, viacheslavo@mellanox.com, matan@mellanox.com, rasland@mellanox.com, Shahaf Shuler Cc: dev@dpdk.org, Xueming Li Date: Thu, 16 Jan 2020 12:14:14 +0200 Message-Id: <87ca94513977186064949d272c5785597f664d20.1579168182.git.jackmin@mellanox.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 2/5] net/mlx5: support flow dump API 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" Dump fdb/nic_rx/nic_tx raw flow data into specified file. Signed-off-by: Xueming Li Signed-off-by: Xiaoyu Min --- drivers/net/mlx5/Makefile | 7 ++++++- drivers/net/mlx5/meson.build | 2 ++ drivers/net/mlx5/mlx5.h | 4 ++++ drivers/net/mlx5/mlx5_devx_cmds.c | 35 +++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_flow.c | 24 +++++++++++++++++++++ drivers/net/mlx5/mlx5_glue.c | 13 ++++++++++++ drivers/net/mlx5/mlx5_glue.h | 1 + 7 files changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile index c5cf4397ac..6e5921b292 100644 --- a/drivers/net/mlx5/Makefile +++ b/drivers/net/mlx5/Makefile @@ -8,7 +8,7 @@ include $(RTE_SDK)/mk/rte.vars.mk LIB = librte_pmd_mlx5.a LIB_GLUE = $(LIB_GLUE_BASE).$(LIB_GLUE_VERSION) LIB_GLUE_BASE = librte_pmd_mlx5_glue.so -LIB_GLUE_VERSION = 19.08.0 +LIB_GLUE_VERSION = 19.11.0 # Sources. SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5.c @@ -203,6 +203,11 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh infiniband/mlx5dv.h \ func mlx5dv_dr_action_create_flow_meter \ $(AUTOCONF_OUTPUT) + $Q sh -- '$<' '$@' \ + HAVE_MLX5_DR_FLOW_DUMP \ + infiniband/mlx5dv.h \ + func mlx5dv_dump_dr_domain \ + $(AUTOCONF_OUTPUT) $Q sh -- '$<' '$@' \ HAVE_MLX5DV_MMAP_GET_NC_PAGES_CMD \ infiniband/mlx5dv.h \ diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index d6b32db794..d7ef032afb 100644 --- a/drivers/net/mlx5/meson.build +++ b/drivers/net/mlx5/meson.build @@ -186,6 +186,8 @@ if build 'RDMA_NLDEV_ATTR_PORT_INDEX' ], [ 'HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX', 'rdma/rdma_netlink.h', 'RDMA_NLDEV_ATTR_NDEV_INDEX' ], + [ 'HAVE_MLX5_DR_FLOW_DUMP', 'infiniband/mlx5dv.h', + 'mlx5dv_dump_dr_domain'], ] config = configuration_data() foreach arg:has_sym_args diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index c3df8256ce..047181b32e 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -975,6 +975,8 @@ struct mlx5_flow_counter *mlx5_counter_alloc(struct rte_eth_dev *dev); void mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt); int mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt, bool clear, uint64_t *pkts, uint64_t *bytes); +int mlx5_flow_dev_dump(struct rte_eth_dev *dev, FILE *file, + struct rte_flow_error *error); /* mlx5_mp.c */ void mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev); @@ -1049,6 +1051,8 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis (struct ibv_context *ctx, struct mlx5_devx_tis_attr *tis_attr); struct mlx5_devx_obj *mlx5_devx_cmd_create_td(struct ibv_context *ctx); +int mlx5_devx_cmd_flow_dump(struct mlx5_ibv_shared *sh, FILE *file); + /* mlx5_flow_meter.c */ int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg); diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c b/drivers/net/mlx5/mlx5_devx_cmds.c index 9893287ba8..d6bf15689d 100644 --- a/drivers/net/mlx5/mlx5_devx_cmds.c +++ b/drivers/net/mlx5/mlx5_devx_cmds.c @@ -927,3 +927,38 @@ mlx5_devx_cmd_create_td(struct ibv_context *ctx) transport_domain); return td; } + +/** + * Dump all flows to file. + * + * @param[in] sh + * Pointer to context. + * @param[out] file + * Pointer to file stream. + * + * @return + * 0 on success, a nagative value otherwise. + */ +int +mlx5_devx_cmd_flow_dump(struct mlx5_ibv_shared *sh __rte_unused, + FILE *file __rte_unused) +{ + int ret = 0; + +#ifdef HAVE_MLX5_DR_FLOW_DUMP + if (sh->fdb_domain) { + ret = mlx5_glue->dr_dump_domain(file, sh->fdb_domain); + if (ret) + return ret; + } + assert(sh->rx_domain); + ret = mlx5_glue->dr_dump_domain(file, sh->rx_domain); + if (ret) + return ret; + assert(sh->tx_domain); + ret = mlx5_glue->dr_dump_domain(file, sh->tx_domain); +#else + ret = ENOTSUP; +#endif + return -ret; +} diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index cb9d265f6f..0126cd8f92 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -236,6 +236,7 @@ static const struct rte_flow_ops mlx5_flow_ops = { .flush = mlx5_flow_flush, .isolate = mlx5_flow_isolate, .query = mlx5_flow_query, + .dev_dump = mlx5_flow_dev_dump, }; /* Convert FDIR request to Generic flow. */ @@ -5679,3 +5680,26 @@ mlx5_flow_discover_mreg_c(struct rte_eth_dev *dev) config->flow_mreg_c[n] = REG_NONE; return 0; } + +/** + * Dump flow raw hw data to file + * + * @param[in] dev + * The pointer to Ethernet device. + * @param[in] file + * A pointer to a file for output. + * @param[out] error + * Perform verbose error reporting if not NULL. PMDs initialize this + * structure in case of error only. + * @return + * 0 on success, a nagative value otherwise. + */ +int +mlx5_flow_dev_dump(struct rte_eth_dev *dev, + FILE *file, + struct rte_flow_error *error __rte_unused) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + return mlx5_devx_cmd_flow_dump(priv->sh, file); +} diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c index 0917bf28d6..4906eebc01 100644 --- a/drivers/net/mlx5/mlx5_glue.c +++ b/drivers/net/mlx5/mlx5_glue.c @@ -1037,6 +1037,18 @@ mlx5_glue_devx_port_query(struct ibv_context *ctx, #endif } +static int +mlx5_glue_dr_dump_domain(FILE *file, void *domain) +{ +#ifdef HAVE_MLX5_DR_FLOW_DUMP + return mlx5dv_dump_dr_domain(file, domain); +#else + RTE_SET_USED(file); + RTE_SET_USED(domain); + return -ENOTSUP; +#endif +} + alignas(RTE_CACHE_LINE_SIZE) const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){ .version = MLX5_GLUE_VERSION, @@ -1134,4 +1146,5 @@ const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){ .devx_umem_dereg = mlx5_glue_devx_umem_dereg, .devx_qp_query = mlx5_glue_devx_qp_query, .devx_port_query = mlx5_glue_devx_port_query, + .dr_dump_domain = mlx5_glue_dr_dump_domain, }; diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h index 6442f1eba8..6771a18c64 100644 --- a/drivers/net/mlx5/mlx5_glue.h +++ b/drivers/net/mlx5/mlx5_glue.h @@ -256,6 +256,7 @@ struct mlx5_glue { int (*devx_port_query)(struct ibv_context *ctx, uint32_t port_num, struct mlx5dv_devx_port *mlx5_devx_port); + int (*dr_dump_domain)(FILE *file, void *domain); }; const struct mlx5_glue *mlx5_glue; From patchwork Thu Jan 16 10:14:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 64765 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 53008A0352; Thu, 16 Jan 2020 11:16:08 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 3CEB31C1F1; Thu, 16 Jan 2020 11:15:50 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id ABF2D1C1E1 for ; Thu, 16 Jan 2020 11:15:45 +0100 (CET) From: Xiaoyu Min To: jerinjacobk@gmail.com, orika@mellanox.com, viacheslavo@mellanox.com, matan@mellanox.com, rasland@mellanox.com, Adrien Mazarguil , Wenzhuo Lu , Jingjing Wu , Bernard Iremonger Cc: dev@dpdk.org, Xueming Li Date: Thu, 16 Jan 2020 12:14:15 +0200 Message-Id: X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI 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: Xueming Li New flow dump CLI to dump device internal representation information of flows into screen. Signed-off-by: Xueming Li Signed-off-by: Xiaoyu Min Acked-by: Ori Kam --- app/test-pmd/cmdline_flow.c | 91 +++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 27 +++++++++++ app/test-pmd/testpmd.h | 1 + 3 files changed, 119 insertions(+) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 99dade7d8c..19336e5d42 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -41,6 +41,7 @@ enum index { BOOLEAN, STRING, HEX, + FILE_PATH, MAC_ADDR, IPV4_ADDR, IPV6_ADDR, @@ -63,6 +64,7 @@ enum index { CREATE, DESTROY, FLUSH, + DUMP, QUERY, LIST, ISOLATE, @@ -631,6 +633,9 @@ struct buffer { uint32_t *rule; uint32_t rule_n; } destroy; /**< Destroy arguments. */ + struct { + char file[128]; + } dump; /**< Dump arguments. */ struct { uint32_t rule; struct rte_flow_action action; @@ -685,6 +690,12 @@ static const enum index next_destroy_attr[] = { ZERO, }; +static const enum index next_dump_attr[] = { + FILE_PATH, + END, + ZERO, +}; + static const enum index next_list_attr[] = { LIST_GROUP, END, @@ -1374,6 +1385,9 @@ static int parse_destroy(struct context *, const struct token *, static int parse_flush(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_dump(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_query(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1401,6 +1415,9 @@ static int parse_string(struct context *, const struct token *, static int parse_hex(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, unsigned int size); +static int parse_string0(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_mac_addr(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1494,6 +1511,12 @@ static const struct token token_list[] = { .type = "HEX", .help = "fixed string", .call = parse_hex, + }, + [FILE_PATH] = { + .name = "{file path}", + .type = "STRING", + .help = "file path", + .call = parse_string0, .comp = comp_none, }, [MAC_ADDR] = { @@ -1555,6 +1578,7 @@ static const struct token token_list[] = { CREATE, DESTROY, FLUSH, + DUMP, LIST, QUERY, ISOLATE)), @@ -1589,6 +1613,14 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY(struct buffer, port)), .call = parse_flush, }, + [DUMP] = { + .name = "dump", + .help = "dump all flow rules to file", + .next = NEXT(next_dump_attr, NEXT_ENTRY(PORT_ID)), + .args = ARGS(ARGS_ENTRY(struct buffer, args.dump.file), + ARGS_ENTRY(struct buffer, port)), + .call = parse_dump, + }, [QUERY] = { .name = "query", .help = "query an existing flow rule", @@ -5012,6 +5044,33 @@ parse_flush(struct context *ctx, const struct token *token, return len; } +/** Parse tokens for dump command. */ +static int +parse_dump(struct context *ctx, const struct token *token, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + struct buffer *out = buf; + + /* Token name must match. */ + if (parse_default(ctx, token, str, len, NULL, 0) < 0) + return -1; + /* Nothing else to do if there is no buffer. */ + if (!out) + return len; + if (!out->command) { + if (ctx->curr != DUMP) + return -1; + if (sizeof(*out) > size) + return -1; + out->command = ctx->curr; + ctx->objdata = 0; + ctx->object = out; + ctx->objmask = NULL; + } + return len; +} + /** Parse tokens for query command. */ static int parse_query(struct context *ctx, const struct token *token, @@ -5409,6 +5468,35 @@ parse_hex(struct context *ctx, const struct token *token, } +/** + * Parse a zero-ended string. + */ +static int +parse_string0(struct context *ctx, const struct token *token __rte_unused, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + const struct arg *arg_data = pop_args(ctx); + + /* Arguments are expected. */ + if (!arg_data) + return -1; + size = arg_data->size; + /* Bit-mask fill is not supported. */ + if (arg_data->mask || size < len + 1) + goto error; + if (!ctx->object) + return len; + buf = (uint8_t *)ctx->object + arg_data->offset; + strncpy(buf, str, len); + if (ctx->objmask) + memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); + return len; +error: + push_args(ctx, arg_data); + return -1; +} + /** * Parse a MAC address. * @@ -6068,6 +6156,9 @@ cmd_flow_parsed(const struct buffer *in) case FLUSH: port_flow_flush(in->port); break; + case DUMP: + port_flow_dump(in->port, in->args.dump.file); + break; case QUERY: port_flow_query(in->port, in->args.query.rule, &in->args.query.action); diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 9da1ffb034..1b4bdf7bf3 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -1441,6 +1441,33 @@ port_flow_flush(portid_t port_id) return ret; } +/** Dump all flow rules. */ +int +port_flow_dump(portid_t port_id, const char *file_name) +{ + int ret = 0; + FILE *file = stdout; + struct rte_flow_error error; + + if (file_name && strlen(file_name)) { + file = fopen(file_name, "w"); + if (!file) { + printf("Failed to create file %s: %s\n", file_name, + strerror(errno)); + return -errno; + } + } + ret = rte_flow_dev_dump(port_id, file, &error); + if (ret) { + port_flow_complain(&error); + printf("Failed to dump flow: %s\n", strerror(-ret)); + } else + printf("Flow dump finished\n"); + if (file_name && strlen(file_name)) + fclose(file); + return ret; +} + /** Query a flow rule. */ int port_flow_query(portid_t port_id, uint32_t rule, diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 857a11f8de..e1b9aba360 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -734,6 +734,7 @@ int port_flow_create(portid_t port_id, const struct rte_flow_action *actions); int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule); int port_flow_flush(portid_t port_id); +int port_flow_dump(portid_t port_id, const char *file_name); int port_flow_query(portid_t port_id, uint32_t rule, const struct rte_flow_action *action); void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); From patchwork Thu Jan 16 10:14:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 64766 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 04E5EA0352; Thu, 16 Jan 2020 11:16:17 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id F18AC1C1FC; Thu, 16 Jan 2020 11:15:51 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 2A5191C1E6 for ; Thu, 16 Jan 2020 11:15:47 +0100 (CET) From: Xiaoyu Min To: jerinjacobk@gmail.com, orika@mellanox.com, viacheslavo@mellanox.com, matan@mellanox.com, rasland@mellanox.com, Shahaf Shuler , Anatoly Burakov Cc: dev@dpdk.org, Xueming Li Date: Thu, 16 Jan 2020 12:14:16 +0200 Message-Id: X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools 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: Xueming Li Add pmd unix socket server to enable external tool applications to trigger flow dump. Socket path: /var/tmp/dpdk_mlx5_ Socket format: io_raw: port_id of uint16 file: file descriptor of int Signed-off-by: Xueming Li Signed-off-by: Xiaoyu Min --- drivers/net/mlx5/Makefile | 1 + drivers/net/mlx5/meson.build | 1 + drivers/net/mlx5/mlx5.c | 2 + drivers/net/mlx5/mlx5.h | 5 + drivers/net/mlx5/mlx5_socket.c | 227 +++++++++++++++++++++++++++++++++ 5 files changed, 236 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_socket.c diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile index 6e5921b292..397e29dcbb 100644 --- a/drivers/net/mlx5/Makefile +++ b/drivers/net/mlx5/Makefile @@ -39,6 +39,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mp.c SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_nl.c SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_devx_cmds.c SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_utils.c +SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c ifeq ($(CONFIG_RTE_IBVERBS_LINK_DLOPEN),y) INSTALL-$(CONFIG_RTE_LIBRTE_MLX5_PMD)-lib += $(LIB_GLUE) diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index d7ef032afb..cb2fb90495 100644 --- a/drivers/net/mlx5/meson.build +++ b/drivers/net/mlx5/meson.build @@ -61,6 +61,7 @@ if build 'mlx5_vlan.c', 'mlx5_devx_cmds.c', 'mlx5_utils.c', + 'mlx5_socket.c', ) if (dpdk_conf.has('RTE_ARCH_X86_64') or dpdk_conf.has('RTE_ARCH_ARM64') diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 50960c91ce..ffee39c1a0 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -2954,6 +2954,8 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, struct mlx5_dev_config dev_config; int ret; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + mlx5_pmd_socket_init(); ret = mlx5_init_once(); if (ret) { DRV_LOG(ERR, "unable to init PMD global data: %s", diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 047181b32e..ceb6de821e 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -990,6 +990,11 @@ void mlx5_mp_uninit_primary(void); int mlx5_mp_init_secondary(void); void mlx5_mp_uninit_secondary(void); +/* mlx5_socket.c */ + +int mlx5_pmd_socket_init(void); +void mlx5_pmd_socket_uninit(void); + /* mlx5_nl.c */ int mlx5_nl_init(int protocol); diff --git a/drivers/net/mlx5/mlx5_socket.c b/drivers/net/mlx5/mlx5_socket.c new file mode 100644 index 0000000000..e4c93c4312 --- /dev/null +++ b/drivers/net/mlx5/mlx5_socket.c @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2019 Mellanox Technologies, Ltd + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "rte_eal.h" +#include "mlx5_utils.h" +#include "mlx5.h" + +/* PMD socket service for tools. */ + +int server_socket; /* Unix socket for primary process. */ +struct rte_intr_handle server_intr_handle; /* Interrupt handler. */ + +static void +mlx5_pmd_make_path(struct sockaddr_un *addr, int pid) +{ + snprintf(addr->sun_path, sizeof(addr->sun_path), "/var/tmp/dpdk_%s_%d", + MLX5_DRIVER_NAME, pid); +} + +/** + * Handle server pmd socket interrupts. + */ +static void +mlx5_pmd_socket_handle(void *cb __rte_unused) +{ + int conn_sock; + int ret = -1; + struct cmsghdr *cmsg = NULL; + int data; + char buf[CMSG_SPACE(sizeof(int))] = { 0 }; + struct iovec io = { + .iov_base = &data, + .iov_len = sizeof(data), + }; + struct msghdr msg = { + .msg_iov = &io, + .msg_iovlen = 1, + .msg_control = buf, + .msg_controllen = sizeof(buf), + }; + uint16_t port_id; + int fd; + FILE *file = NULL; + struct rte_eth_dev *dev; + + /* Accept the connection from the client. */ + conn_sock = accept(server_socket, NULL, NULL); + if (conn_sock < 0) { + DRV_LOG(WARNING, "connection failed: %s", strerror(errno)); + return; + } + ret = recvmsg(conn_sock, &msg, MSG_WAITALL); + if (ret < 0) { + DRV_LOG(WARNING, "wrong message received: %s", + strerror(errno)); + goto error; + } + /* Receive file descriptor. */ + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS || + cmsg->cmsg_len < sizeof(int)) { + DRV_LOG(WARNING, "invalid file descriptor message"); + goto error; + } + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + file = fdopen(fd, "w"); + if (!file) { + DRV_LOG(WARNING, "Failed to open file"); + goto error; + } + /* Receive port number. */ + if (msg.msg_iovlen != 1 || msg.msg_iov->iov_len < sizeof(uint16_t)) { + DRV_LOG(WARNING, "wrong port number message"); + goto error; + } + memcpy(&port_id, msg.msg_iov->iov_base, sizeof(port_id)); + /* Dump flow. */ + dev = &rte_eth_devices[port_id]; + ret = mlx5_flow_dev_dump(dev, file, NULL); + /* Set-up the ancillary data and reply. */ + msg.msg_controllen = 0; + msg.msg_control = NULL; + msg.msg_iovlen = 1; + msg.msg_iov = &io; + data = -ret; + io.iov_len = sizeof(data); + io.iov_base = &data; + do { + ret = sendmsg(conn_sock, &msg, 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + DRV_LOG(WARNING, "failed to send response %s", + strerror(errno)); +error: + if (conn_sock > 0) + close(conn_sock); + if (file) + fclose(file); +} + +/** + * Install interrupt handler. + * + * @param dev + * Pointer to Ethernet device. + * @return + * 0 on success, a negative errno value otherwise. + */ +static int +mlx5_pmd_interrupt_handler_install(void) +{ + assert(server_socket); + server_intr_handle.fd = server_socket; + server_intr_handle.type = RTE_INTR_HANDLE_EXT; + return rte_intr_callback_register(&server_intr_handle, + mlx5_pmd_socket_handle, NULL); +} + +/** + * Uninstall interrupt handler. + */ +static void +mlx5_pmd_interrupt_handler_uninstall(void) +{ + if (server_socket) { + mlx5_intr_callback_unregister(&server_intr_handle, + mlx5_pmd_socket_handle, + NULL); + } + server_intr_handle.fd = 0; + server_intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; +} + +/** + * Initialise the socket to communicate with the secondary process + * + * @param[in] dev + * Pointer to Ethernet device. + * + * @return + * 0 on success, a negative value otherwise. + */ +int +mlx5_pmd_socket_init(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + }; + int ret = -1; + int flags; + + assert(rte_eal_process_type() == RTE_PROC_PRIMARY); + if (server_socket) + return 0; + /* + * Initialize the socket to communicate with the secondary + * process. + */ + ret = socket(AF_UNIX, SOCK_STREAM, 0); + if (ret < 0) { + DRV_LOG(WARNING, "Failed to open mlx5 socket: %s", + strerror(errno)); + goto error; + } + server_socket = ret; + flags = fcntl(server_socket, F_GETFL, 0); + if (flags == -1) + goto error; + ret = fcntl(server_socket, F_SETFL, flags | O_NONBLOCK); + if (ret < 0) + goto error; + mlx5_pmd_make_path(&sun, getpid()); + remove(sun.sun_path); + ret = bind(server_socket, (const struct sockaddr *)&sun, sizeof(sun)); + if (ret < 0) { + DRV_LOG(WARNING, + "cannot bind mlx5 socket: %s", strerror(errno)); + goto close; + } + ret = listen(server_socket, 0); + if (ret < 0) { + DRV_LOG(WARNING, "cannot listen on mlx5 socket: %s", + strerror(errno)); + goto close; + } + if (mlx5_pmd_interrupt_handler_install()) { + DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s", + strerror(errno)); + goto close; + } + return 0; +close: + remove(sun.sun_path); +error: + claim_zero(close(server_socket)); + server_socket = 0; + DRV_LOG(ERR, "Cannot initialize socket: %s", strerror(errno)); + return -errno; +} + +/** + * Un-Initialize the pmd socket + */ +void __attribute__((destructor)) +mlx5_pmd_socket_uninit(void) +{ + if (!server_socket) + return; + mlx5_pmd_interrupt_handler_uninstall(); + MKSTR(path, "/var/tmp/dpdk_%s_%d", MLX5_DRIVER_NAME, getpid()); + claim_zero(close(server_socket)); + server_socket = 0; + claim_zero(remove(path)); +} From patchwork Thu Jan 16 10:14:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 64767 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id AB58BA0352; Thu, 16 Jan 2020 11:16:25 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 372A81C20D; Thu, 16 Jan 2020 11:15:54 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 7FC851C1EF for ; Thu, 16 Jan 2020 11:15:48 +0100 (CET) From: Xiaoyu Min To: jerinjacobk@gmail.com, orika@mellanox.com, viacheslavo@mellanox.com, matan@mellanox.com, rasland@mellanox.com, Shahaf Shuler , John McNamara , Marko Kovacevic Cc: dev@dpdk.org, Xueming Li Date: Thu, 16 Jan 2020 12:14:17 +0200 Message-Id: X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 5/5] doc: update mlx5 document for flow dump feature 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: Xueming Li Guide of mlx5 is updated on how to dump HW flows. Signed-off-by: Xueming Li Signed-off-by: Xiaoyu Min --- doc/guides/nics/mlx5.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index 92228d3cca..e6d09521e2 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -1316,3 +1316,31 @@ ConnectX-4/ConnectX-5/ConnectX-6/BlueField devices managed by librte_pmd_mlx5. Port 3 Link Up - speed 10000 Mbps - full-duplex Done testpmd> + +HowTo dump flows +---------------- + +This section demonstrates how to dump flows. Currently, it's possible to dump +all flows with assistence of external tools. + +#. 2 ways to get flow raw file: + + - Using testpmd CLI: + + .. code-block:: console + + testpmd> flow dump + + - call rte_flow_dev_dump api: + + .. code-block:: console + + rte_flow_dev_dump(port, file, NULL); + +#. Dump humanreadable flows from raw file: + + Get flow parsing tool from: https://github.com/Mellanox/mlx_steering_dump + + .. code-block:: console + + mlx_steering_dump.py -f