DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info
@ 2020-01-16 10:14 Xiaoyu Min
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
                   ` (5 more replies)
  0 siblings, 6 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland; +Cc: dev

This serial patchs is based on RFC [1] and the comments on it.

A new rte flow API is added to dump device internal representation
information for the offloaded rte flows.

This is very helpful for user and developer to debug flow offloading
stuff, i.e, to check whether PMD offloads the rte flow in a correct way
from HW perspective.

The output file is in vendor specific format. An external vendor
provided tool may be needed in order to get human readable info.

[1]: https://patches.dpdk.org/cover/64597/

Xiaoyu Min (2):
  ethdev: add API to dump device internal flow info
  net/mlx5: support flow dump API

Xueming Li (3):
  app/testpmd: new flow dump CLI
  net/mlx5: add socket server for external tools
  doc: update mlx5 document for flow dump feature

 app/test-pmd/cmdline_flow.c              |  91 +++++++++
 app/test-pmd/config.c                    |  27 +++
 app/test-pmd/testpmd.h                   |   1 +
 doc/guides/nics/mlx5.rst                 |  28 +++
 drivers/net/mlx5/Makefile                |   8 +-
 drivers/net/mlx5/meson.build             |   3 +
 drivers/net/mlx5/mlx5.c                  |   2 +
 drivers/net/mlx5/mlx5.h                  |   9 +
 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 +
 drivers/net/mlx5/mlx5_socket.c           | 227 +++++++++++++++++++++++
 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 +
 17 files changed, 513 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mlx5/mlx5_socket.c

-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
@ 2020-01-16 10:14 ` Xiaoyu Min
  2020-01-16 10:37   ` Jerin Jacob
  2020-01-16 20:37   ` Ferruh Yigit
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 2/5] net/mlx5: support flow dump API Xiaoyu Min
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko, Adrien Mazarguil
  Cc: dev

Introduce an API which dump the device's internal representation
information of rte flows in hardware.

Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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);
 };
 
 /**
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH 2/5] net/mlx5: support flow dump API
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
@ 2020-01-16 10:14 ` Xiaoyu Min
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler
  Cc: dev, Xueming Li

Dump fdb/nic_rx/nic_tx raw flow data into specified file.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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;
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 2/5] net/mlx5: support flow dump API Xiaoyu Min
@ 2020-01-16 10:14 ` Xiaoyu Min
  2020-01-16 14:10   ` Ori Kam
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland,
	Adrien Mazarguil, Wenzhuo Lu, Jingjing Wu, Bernard Iremonger
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

New flow dump CLI to dump device internal representation information
of flows into screen.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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);
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                   ` (2 preceding siblings ...)
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
@ 2020-01-16 10:14 ` Xiaoyu Min
  2020-01-17  8:47   ` Slava Ovsiienko
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  5 siblings, 1 reply; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler,
	Anatoly Burakov
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

Add pmd unix socket server to enable external tool applications to
trigger flow dump.

Socket path:
	/var/tmp/dpdk_mlx5_<pid>
Socket format:
	io_raw: port_id of uint16
	file: file descriptor of int

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#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));
+}
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH 5/5] doc: update mlx5 document for flow dump feature
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                   ` (3 preceding siblings ...)
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
@ 2020-01-16 10:14 ` Xiaoyu Min
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-16 10:14 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler,
	John McNamara, Marko Kovacevic
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

Guide of mlx5 is updated on how to dump HW flows.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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 <port> <output_file>
+
+   - 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 <output_file>
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
@ 2020-01-16 10:37   ` Jerin Jacob
  2020-01-16 13:29     ` Ori Kam
  2020-01-16 20:37   ` Ferruh Yigit
  1 sibling, 1 reply; 24+ messages in thread
From: Jerin Jacob @ 2020-01-16 10:37 UTC (permalink / raw)
  To: Xiaoyu Min
  Cc: Ori Kam, Slava Ovsiienko, Matan Azrad, Raslan Darawsheh,
	Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko,
	Adrien Mazarguil, dpdk-dev

On Thu, Jan 16, 2020 at 3:45 PM Xiaoyu Min <jackmin@mellanox.com> wrote:
>
> Introduce an API which dump the device's internal representation
> information of rte flows in hardware.
>
> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>

Looks good to me.

> ---
>  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);
>  };
>
>  /**
> --
> 2.24.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 10:37   ` Jerin Jacob
@ 2020-01-16 13:29     ` Ori Kam
  0 siblings, 0 replies; 24+ messages in thread
From: Ori Kam @ 2020-01-16 13:29 UTC (permalink / raw)
  To: Jerin Jacob, Jack Min
  Cc: Slava Ovsiienko, Matan Azrad, Raslan Darawsheh, Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko, Adrien Mazarguil, dpdk-dev



> -----Original Message-----
> <adrien.mazarguil@6wind.com>; dpdk-dev <dev@dpdk.org>
> Subject: Re: [PATCH 1/5] ethdev: add API to dump device internal flow info
> 
> On Thu, Jan 16, 2020 at 3:45 PM Xiaoyu Min <jackmin@mellanox.com> wrote:
> >
> > Introduce an API which dump the device's internal representation
> > information of rte flows in hardware.
> >
> > Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
> 
> Looks good to me.

Acked-by: Ori Kam <orika@mellanox.com>
Thanks,
Ori
> 
> > ---
> >  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);
> >  };
> >
> >  /**
> > --
> > 2.24.1
> >

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
@ 2020-01-16 14:10   ` Ori Kam
  0 siblings, 0 replies; 24+ messages in thread
From: Ori Kam @ 2020-01-16 14:10 UTC (permalink / raw)
  To: Jack Min, jerinjacobk, Slava Ovsiienko, Matan Azrad,
	Raslan Darawsheh, Adrien Mazarguil, Wenzhuo Lu, Jingjing Wu,
	Bernard Iremonger
  Cc: dev, Xueming(Steven) Li



> -----Original Message-----
> Subject: [PATCH 3/5] app/testpmd: new flow dump CLI
> 
> From: Xueming Li <xuemingl@mellanox.com>
> 
> New flow dump CLI to dump device internal representation information
> of flows into screen.
> 
> Signed-off-by: Xueming Li <xuemingl@mellanox.com>
> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
> ---

Acked-by: Ori Kam <orika@mellanox.com>
Thanks,
Ori


>  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);
> --
> 2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
  2020-01-16 10:37   ` Jerin Jacob
@ 2020-01-16 20:37   ` Ferruh Yigit
  2020-01-16 22:56     ` Stephen Hemminger
  1 sibling, 1 reply; 24+ messages in thread
From: Ferruh Yigit @ 2020-01-16 20:37 UTC (permalink / raw)
  To: Xiaoyu Min, jerinjacobk, orika, viacheslavo, matan, rasland,
	Thomas Monjalon, Andrew Rybchenko, Adrien Mazarguil
  Cc: dev

On 1/16/2020 10:14 AM, Xiaoyu Min wrote:
> Introduce an API which dump the device's internal representation
> information of rte flows in hardware.
> 
> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>

<...>

> @@ -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));
> +}

Should API validate user provided input "FILE *file" ?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 20:37   ` Ferruh Yigit
@ 2020-01-16 22:56     ` Stephen Hemminger
  2020-01-17  9:20       ` Ferruh Yigit
  0 siblings, 1 reply; 24+ messages in thread
From: Stephen Hemminger @ 2020-01-16 22:56 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Xiaoyu Min, jerinjacobk, orika, viacheslavo, matan, rasland,
	Thomas Monjalon, Andrew Rybchenko, Adrien Mazarguil, dev

On Thu, 16 Jan 2020 20:37:36 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 1/16/2020 10:14 AM, Xiaoyu Min wrote:
> > Introduce an API which dump the device's internal representation
> > information of rte flows in hardware.
> > 
> > Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>  
> 
> <...>
> 
> > @@ -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));
> > +}  
> 
> Should API validate user provided input "FILE *file" ?

None of the other DPDK dump routines do.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
@ 2020-01-17  8:47   ` Slava Ovsiienko
  2020-01-17  9:01     ` Jack Min
  0 siblings, 1 reply; 24+ messages in thread
From: Slava Ovsiienko @ 2020-01-17  8:47 UTC (permalink / raw)
  To: Jack Min, jerinjacobk, Ori Kam, Matan Azrad, Raslan Darawsheh,
	Shahaf Shuler, Anatoly Burakov
  Cc: dev, Xueming(Steven) Li

Hi, Jack

> -----Original Message-----
> From: Xiaoyu Min <jackmin@mellanox.com>
> Sent: Thursday, January 16, 2020 12:14
> To: jerinjacobk@gmail.com; Ori Kam <orika@mellanox.com>; Slava Ovsiienko
> <viacheslavo@mellanox.com>; Matan Azrad <matan@mellanox.com>; Raslan
> Darawsheh <rasland@mellanox.com>; Shahaf Shuler
> <shahafs@mellanox.com>; Anatoly Burakov <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Xueming(Steven) Li <xuemingl@mellanox.com>
> Subject: [PATCH 4/5] net/mlx5: add socket server for external tools
> 
> From: Xueming Li <xuemingl@mellanox.com>
> 
> Add pmd unix socket server to enable external tool applications to trigger
> flow dump.
> 
> Socket path:
> 	/var/tmp/dpdk_mlx5_<pid>
> Socket format:
> 	io_raw: port_id of uint16
> 	file: file descriptor of int
> 
> Signed-off-by: Xueming Li <xuemingl@mellanox.com>
> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
> ---
>  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 <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/stat.h>
> +
> +#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));
I would add the port_id check here.
The message with wrong port_id may crash the server.


> +	/* 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());
I would move the MKSTR a couple lines below, after the close() call.

> +	claim_zero(close(server_socket));
> +	server_socket = 0;
> +	claim_zero(remove(path));
> +}
> --
> 2.24.1
With best regards, Slava

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools
  2020-01-17  8:47   ` Slava Ovsiienko
@ 2020-01-17  9:01     ` Jack Min
  0 siblings, 0 replies; 24+ messages in thread
From: Jack Min @ 2020-01-17  9:01 UTC (permalink / raw)
  To: Slava Ovsiienko
  Cc: jerinjacobk, Ori Kam, Matan Azrad, Raslan Darawsheh,
	Shahaf Shuler, Anatoly Burakov, dev, Xueming(Steven) Li

On Fri, 20-01-17, 16:47, Slava Ovsiienko wrote:
> Hi, Jack
> 
> > -----Original Message-----
> > From: Xiaoyu Min <jackmin@mellanox.com>
> > Sent: Thursday, January 16, 2020 12:14
> > To: jerinjacobk@gmail.com; Ori Kam <orika@mellanox.com>; Slava Ovsiienko
> > <viacheslavo@mellanox.com>; Matan Azrad <matan@mellanox.com>; Raslan
> > Darawsheh <rasland@mellanox.com>; Shahaf Shuler
> > <shahafs@mellanox.com>; Anatoly Burakov <anatoly.burakov@intel.com>
> > Cc: dev@dpdk.org; Xueming(Steven) Li <xuemingl@mellanox.com>
> > Subject: [PATCH 4/5] net/mlx5: add socket server for external tools
> > 
> > From: Xueming Li <xuemingl@mellanox.com>
> > 
> > Add pmd unix socket server to enable external tool applications to trigger
> > flow dump.
> > 
> > Socket path:
> > 	/var/tmp/dpdk_mlx5_<pid>
> > Socket format:
> > 	io_raw: port_id of uint16
> > 	file: file descriptor of int
> > 
> > Signed-off-by: Xueming Li <xuemingl@mellanox.com>
> > Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
> > ---
> >  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 <sys/types.h>
> > +#include <sys/socket.h>
> > +#include <sys/un.h>
> > +#include <fcntl.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <sys/stat.h>
> > +
> > +#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));
> I would add the port_id check here.
> The message with wrong port_id may crash the server.
Yes, you are right. I'll update it in v2.

> 
> 
> > +	/* 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());
> I would move the MKSTR a couple lines below, after the close() call.
OK, this seems make code more readable. I'll update it in v2.

> 
> > +	claim_zero(close(server_socket));
> > +	server_socket = 0;
> > +	claim_zero(remove(path));
> > +}
> > --
> > 2.24.1
> With best regards, Slava
Thank you~
-Jack

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH 1/5] ethdev: add API to dump device internal flow info
  2020-01-16 22:56     ` Stephen Hemminger
@ 2020-01-17  9:20       ` Ferruh Yigit
  0 siblings, 0 replies; 24+ messages in thread
From: Ferruh Yigit @ 2020-01-17  9:20 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Xiaoyu Min, jerinjacobk, orika, viacheslavo, matan, rasland,
	Thomas Monjalon, Andrew Rybchenko, Adrien Mazarguil, dev

On 1/16/2020 10:56 PM, Stephen Hemminger wrote:
> On Thu, 16 Jan 2020 20:37:36 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> On 1/16/2020 10:14 AM, Xiaoyu Min wrote:
>>> Introduce an API which dump the device's internal representation
>>> information of rte flows in hardware.
>>>
>>> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>  
>>
>> <...>
>>
>>> @@ -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));
>>> +}  
>>
>> Should API validate user provided input "FILE *file" ?
> 
> None of the other DPDK dump routines do.
> 

You are right, a few samples I checked doesn't validating it, I wonder if this
is intentional decision or just missed the user input validation.
For me, APIs should validate user input.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info
  2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                   ` (4 preceding siblings ...)
  2020-01-16 10:14 ` [dpdk-dev] [PATCH 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
@ 2020-01-17 11:55 ` Xiaoyu Min
  2020-01-17 11:55   ` [dpdk-dev] [PATCH v2 1/5] " Xiaoyu Min
                     ` (5 more replies)
  5 siblings, 6 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:55 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland; +Cc: dev

This serial patchs is based on RFC [1] and the comments on it.

A new rte flow API is added to dump device internal representation
information for the offloaded rte flows.

This is very helpful for user and developer to debug flow offloading
stuff, i.e, to check whether PMD offloads the rte flow in a correct way
from HW perspective.

The output file is in vendor specific format. An external vendor
provided tool may be needed in order to get human readable info.

[1]: https://patches.dpdk.org/cover/64597/

v2:
  * Bump MLX5 PMD glue version to 20.02.0
  * MLX5 PMD validate port id
  * Code improvement per review comments

Xiaoyu Min (2):
  ethdev: add API to dump device internal flow info
  net/mlx5: support flow dump API

Xueming Li (3):
  app/testpmd: new flow dump CLI
  net/mlx5: add socket server for external tools
  doc: update mlx5 document for flow dump feature

 app/test-pmd/cmdline_flow.c              |  91 +++++++++
 app/test-pmd/config.c                    |  27 +++
 app/test-pmd/testpmd.h                   |   1 +
 doc/guides/nics/mlx5.rst                 |  28 +++
 drivers/net/mlx5/Makefile                |   8 +-
 drivers/net/mlx5/meson.build             |   5 +-
 drivers/net/mlx5/mlx5.c                  |   2 +
 drivers/net/mlx5/mlx5.h                  |   9 +
 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 +
 drivers/net/mlx5/mlx5_socket.c           | 231 +++++++++++++++++++++++
 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 +
 17 files changed, 518 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/mlx5/mlx5_socket.c

-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 1/5] ethdev: add API to dump device internal flow info
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
@ 2020-01-17 11:55   ` Xiaoyu Min
  2020-01-17 19:26     ` Ferruh Yigit
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 2/5] net/mlx5: support flow dump API Xiaoyu Min
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:55 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko, Adrien Mazarguil
  Cc: dev

Introduce an API which dump the device's internal representation
information of rte flows in hardware.

Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Ori Kam <orika@mellanox.com>
---
 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);
 };
 
 /**
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 2/5] net/mlx5: support flow dump API
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  2020-01-17 11:55   ` [dpdk-dev] [PATCH v2 1/5] " Xiaoyu Min
@ 2020-01-17 11:56   ` Xiaoyu Min
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:56 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler
  Cc: dev, Xueming Li

Dump fdb/nic_rx/nic_tx raw flow data into specified file.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
---
 drivers/net/mlx5/Makefile         |  7 ++++++-
 drivers/net/mlx5/meson.build      |  4 +++-
 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, 86 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index c5cf4397ac..3e71516ea9 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 = 20.02.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..b6736965e3 100644
--- a/drivers/net/mlx5/meson.build
+++ b/drivers/net/mlx5/meson.build
@@ -11,7 +11,7 @@ build = true
 
 pmd_dlopen = (get_option('ibverbs_link') == 'dlopen')
 LIB_GLUE_BASE = 'librte_pmd_mlx5_glue.so'
-LIB_GLUE_VERSION = '19.08.0'
+LIB_GLUE_VERSION = '20.02.0'
 LIB_GLUE = LIB_GLUE_BASE + '.' + LIB_GLUE_VERSION
 if pmd_dlopen
 	dpdk_conf.set('RTE_IBVERBS_LINK_DLOPEN', 1)
@@ -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;
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 3/5] app/testpmd: new flow dump CLI
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
  2020-01-17 11:55   ` [dpdk-dev] [PATCH v2 1/5] " Xiaoyu Min
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 2/5] net/mlx5: support flow dump API Xiaoyu Min
@ 2020-01-17 11:56   ` Xiaoyu Min
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:56 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland,
	Adrien Mazarguil, Wenzhuo Lu, Jingjing Wu, Bernard Iremonger
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

New flow dump CLI to dump device internal representation information
of flows into screen.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Ori Kam <orika@mellanox.com>
---
 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);
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 4/5] net/mlx5: add socket server for external tools
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                     ` (2 preceding siblings ...)
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
@ 2020-01-17 11:56   ` Xiaoyu Min
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
  2020-01-17 19:26   ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Ferruh Yigit
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:56 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler,
	Anatoly Burakov
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

Add pmd unix socket server to enable external tool applications to
trigger flow dump.

Socket path:
	/var/tmp/dpdk_mlx5_<pid>
Socket format:
	io_raw: port_id of uint16
	file: file descriptor of int

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
---
 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 | 231 +++++++++++++++++++++++++++++++++
 5 files changed, 240 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_socket.c

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index 3e71516ea9..0466d9d00c 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 b6736965e3..3ad4f02a53 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..b037f77af5
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_socket.c
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2019 Mellanox Technologies, Ltd
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#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));
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		DRV_LOG(WARNING, "Invalid port %u", port_id);
+		goto error;
+	}
+	/* 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();
+	claim_zero(close(server_socket));
+	server_socket = 0;
+	MKSTR(path, "/var/tmp/dpdk_%s_%d", MLX5_DRIVER_NAME, getpid());
+	claim_zero(remove(path));
+}
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [dpdk-dev] [PATCH v2 5/5] doc: update mlx5 document for flow dump feature
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                     ` (3 preceding siblings ...)
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
@ 2020-01-17 11:56   ` Xiaoyu Min
  2020-01-17 19:26   ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Ferruh Yigit
  5 siblings, 0 replies; 24+ messages in thread
From: Xiaoyu Min @ 2020-01-17 11:56 UTC (permalink / raw)
  To: jerinjacobk, orika, viacheslavo, matan, rasland, Shahaf Shuler,
	John McNamara, Marko Kovacevic
  Cc: dev, Xueming Li

From: Xueming Li <xuemingl@mellanox.com>

Guide of mlx5 is updated on how to dump HW flows.

Signed-off-by: Xueming Li <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
---
 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 <port> <output_file>
+
+   - 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 <output_file>
-- 
2.24.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/5] ethdev: add API to dump device internal flow info
  2020-01-17 11:55   ` [dpdk-dev] [PATCH v2 1/5] " Xiaoyu Min
@ 2020-01-17 19:26     ` Ferruh Yigit
  0 siblings, 0 replies; 24+ messages in thread
From: Ferruh Yigit @ 2020-01-17 19:26 UTC (permalink / raw)
  To: Xiaoyu Min, jerinjacobk, orika, viacheslavo, matan, rasland,
	Thomas Monjalon, Andrew Rybchenko, Adrien Mazarguil
  Cc: dev

On 1/17/2020 11:55 AM, Xiaoyu Min wrote:
> Introduce an API which dump the device's internal representation
> information of rte flows in hardware.
> 
> Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
> Acked-by: Ori Kam <orika@mellanox.com>

Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info
  2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
                     ` (4 preceding siblings ...)
  2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
@ 2020-01-17 19:26   ` Ferruh Yigit
  2020-01-19 21:08     ` Thomas Monjalon
  5 siblings, 1 reply; 24+ messages in thread
From: Ferruh Yigit @ 2020-01-17 19:26 UTC (permalink / raw)
  To: Xiaoyu Min, jerinjacobk, orika, viacheslavo, matan, rasland; +Cc: dev

On 1/17/2020 11:55 AM, Xiaoyu Min wrote:
> This serial patchs is based on RFC [1] and the comments on it.
> 
> A new rte flow API is added to dump device internal representation
> information for the offloaded rte flows.
> 
> This is very helpful for user and developer to debug flow offloading
> stuff, i.e, to check whether PMD offloads the rte flow in a correct way
> from HW perspective.
> 
> The output file is in vendor specific format. An external vendor
> provided tool may be needed in order to get human readable info.
> 
> [1]: https://patches.dpdk.org/cover/64597/
> 
> v2:
>   * Bump MLX5 PMD glue version to 20.02.0
>   * MLX5 PMD validate port id
>   * Code improvement per review comments
> 
> Xiaoyu Min (2):
>   ethdev: add API to dump device internal flow info
>   net/mlx5: support flow dump API
> 
> Xueming Li (3):
>   app/testpmd: new flow dump CLI
>   net/mlx5: add socket server for external tools
>   doc: update mlx5 document for flow dump feature

Series applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info
  2020-01-17 19:26   ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Ferruh Yigit
@ 2020-01-19 21:08     ` Thomas Monjalon
  2020-01-20  1:40       ` Jack Min
  0 siblings, 1 reply; 24+ messages in thread
From: Thomas Monjalon @ 2020-01-19 21:08 UTC (permalink / raw)
  To: Xiaoyu Min, Ferruh Yigit
  Cc: jerinjacobk, orika, viacheslavo, matan, rasland, dev,
	bernard.iremonger, xuemingl

17/01/2020 20:26, Ferruh Yigit:
> On 1/17/2020 11:55 AM, Xiaoyu Min wrote:
> > Xiaoyu Min (2):
> >   ethdev: add API to dump device internal flow info
> >   net/mlx5: support flow dump API
> > 
> > Xueming Li (3):
> >   app/testpmd: new flow dump CLI
> >   net/mlx5: add socket server for external tools
> >   doc: update mlx5 document for flow dump feature
> 
> Series applied to dpdk-next-net/master, thanks.

I think we are missing an update of the testpmd doc.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info
  2020-01-19 21:08     ` Thomas Monjalon
@ 2020-01-20  1:40       ` Jack Min
  0 siblings, 0 replies; 24+ messages in thread
From: Jack Min @ 2020-01-20  1:40 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Ferruh Yigit, jerinjacobk, Ori Kam, Slava Ovsiienko, Matan Azrad,
	Raslan Darawsheh, dev, bernard.iremonger, Xueming(Steven) Li

On Sun, 20-01-19, 22:08, Thomas Monjalon wrote:
> 17/01/2020 20:26, Ferruh Yigit:
> > On 1/17/2020 11:55 AM, Xiaoyu Min wrote:
> > > Xiaoyu Min (2):
> > >   ethdev: add API to dump device internal flow info
> > >   net/mlx5: support flow dump API
> > > 
> > > Xueming Li (3):
> > >   app/testpmd: new flow dump CLI
> > >   net/mlx5: add socket server for external tools
> > >   doc: update mlx5 document for flow dump feature
> > 
> > Series applied to dpdk-next-net/master, thanks.
> 
> I think we are missing an update of the testpmd doc.
> 
Yes, you are right. I'll update testpmd doc.

-Jack

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2020-01-20  1:40 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-16 10:14 [dpdk-dev] [PATCH 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
2020-01-16 10:14 ` [dpdk-dev] [PATCH 1/5] " Xiaoyu Min
2020-01-16 10:37   ` Jerin Jacob
2020-01-16 13:29     ` Ori Kam
2020-01-16 20:37   ` Ferruh Yigit
2020-01-16 22:56     ` Stephen Hemminger
2020-01-17  9:20       ` Ferruh Yigit
2020-01-16 10:14 ` [dpdk-dev] [PATCH 2/5] net/mlx5: support flow dump API Xiaoyu Min
2020-01-16 10:14 ` [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
2020-01-16 14:10   ` Ori Kam
2020-01-16 10:14 ` [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
2020-01-17  8:47   ` Slava Ovsiienko
2020-01-17  9:01     ` Jack Min
2020-01-16 10:14 ` [dpdk-dev] [PATCH 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
2020-01-17 11:55 ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Xiaoyu Min
2020-01-17 11:55   ` [dpdk-dev] [PATCH v2 1/5] " Xiaoyu Min
2020-01-17 19:26     ` Ferruh Yigit
2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 2/5] net/mlx5: support flow dump API Xiaoyu Min
2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 3/5] app/testpmd: new flow dump CLI Xiaoyu Min
2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 4/5] net/mlx5: add socket server for external tools Xiaoyu Min
2020-01-17 11:56   ` [dpdk-dev] [PATCH v2 5/5] doc: update mlx5 document for flow dump feature Xiaoyu Min
2020-01-17 19:26   ` [dpdk-dev] [PATCH v2 0/5] ethdev: add API to dump device internal flow info Ferruh Yigit
2020-01-19 21:08     ` Thomas Monjalon
2020-01-20  1:40       ` Jack Min

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).