ethdev: add API to dump device internal flow info
Subsystems (2)
cover ethdev: add API to dump device internal flow info
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
Signature · 1 line
2.24.1
PATCH 1/5 ethdev: add API to dump device internal flow info
Introduce an API which dump the device's internal representation information of rte flows in hardware.
--- 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(+)
lib/librte_ethdev/rte_ethdev_version.map +3 -0
@@ -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; };
lib/librte_ethdev/rte_flow.c +16 -0
@@ -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 )); +}
lib/librte_ethdev/rte_flow.h +21 -0
@@ -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. *
lib/librte_ethdev/rte_flow_driver.h +5 -0
@@ -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); };/**
Signature · 1 line
2.24.1
Quoted 5 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]>
Looks good to me.
Quoted 94 lines
--- 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(+)lib/librte_ethdev/rte_ethdev_version.map +3
-0@@ -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; };lib/librte_ethdev/rte_flow.c +16
-0@@ -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 )); +}lib/librte_ethdev/rte_flow.h +21
-0@@ -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. * lib/librte_ethdev/rte_flow_driver.h +5
-1@@ -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
Ori Kam
Acked-byQuoted 6 lines
-----Original Message-----
<[email protected]>; dpdk-dev <[email protected]>
Subject: Re: [PATCH 1/5] ethdev: add API to dump device internal flow info
Quoted 8 lines
Quoted 5 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]>Looks good to me.
Thanks,
Ori
Quoted 100 lines
Review
Quoted 9 lines
--- 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(+)(quoted diff) +0
-0b/lib/librte_ethdev/rte_ethdev_version.map
lib/librte_ethdev/rte_flow.c rte_flow_expand_rss(struct
Quoted 16 lines
index
a7dacf2cf2..3f32fdecf7100644lib/librte_ethdev/rte_ethdev_version.map +3
-0@@ -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; };lib/librte_ethdev/rte_flow.c +0
-0@@ -1212,3 +1212,19 @@ rte_flow_expand_rss(struct
rte_flow_expand_rss*buf,size_tsize,lib/librte_ethdev/rte_flow.c rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,
Quoted 6 lines
lib/librte_ethdev/rte_flow.c +3
-0}return lsize; } + +int +rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error*error)
Quoted 31 lines
lib/librte_ethdev/rte_flow.c +13
-0+{ +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 )); +}lib/librte_ethdev/rte_flow.h +10
-0@@ -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 lib/librte_ethdev/rte_flow.h enum rte_flow_conv_op { · line 2812
Quoted 10 lines
lib/librte_ethdev/rte_flow.h +10
-0+* 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);
Review
Quoted 5 lines
lib/librte_ethdev/rte_flow.h +1
-0+/** * Check if mbuf dynamic field for metadata is registered. * (quoted diff) +0
-0
b/lib/librte_ethdev/rte_flow_driver.hQuoted 18 lines
index
a0359853e6..51a9a57a0f100644lib/librte_ethdev/rte_flow_driver.h +5
-1@@ -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
Quoted 4 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]>
<...>
Quoted 10 lines
lib/librte_ethdev/rte_flow.c +6
-0@@ -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);
lib/librte_ethdev/rte_flow.c rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, · line 1230
Quoted 10 lines
lib/librte_ethdev/rte_flow.c +10
-0+ +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" ?
Quoted 22 lines · On Thu, 16 Jan 2020 20:37:36 +0000 Ferruh Yigit <[email protected]> wrote:
Quoted 4 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]><...>
Quoted 14 lines
lib/librte_ethdev/rte_flow.c +10
-0@@ -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))
Quoted 8 lines
lib/librte_ethdev/rte_flow.c rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, · line 1230
Quoted 6 lines
lib/librte_ethdev/rte_flow.c +6
-0+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.
Quoted 34 lines · Stephen Hemminger
Quoted 22 lines · On Thu, 16 Jan 2020 20:37:36 +0000 Ferruh Yigit <[email protected]> wrote:
Quoted 4 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]><...>
Quoted 14 lines
lib/librte_ethdev/rte_flow.c +10
-0@@ -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))Quoted 8 lines
lib/librte_ethdev/rte_flow.c rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, · line 1230
Quoted 6 lines
lib/librte_ethdev/rte_flow.c +6
-0+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" ?
Quoted 2 lines
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.
PATCH 2/5 net/mlx5: support flow dump API
In reply to Xiaoyu MinDump fdb/nic_rx/nic_tx raw flow data into specified file.
--- 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(-)
drivers/net/mlx5/Makefile +6 -1
@@ -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 \
drivers/net/mlx5/meson.build +2 -0
@@ -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
drivers/net/mlx5/mlx5.h +4 -0
@@ -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);
drivers/net/mlx5/mlx5_devx_cmds.c +35 -0
@@ -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; +}
drivers/net/mlx5/mlx5_flow.c +24 -0
@@ -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); +}
drivers/net/mlx5/mlx5_glue.c +13 -0
@@ -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, };
drivers/net/mlx5/mlx5_glue.h +1 -0
@@ -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;
Signature · 1 line
2.24.1
PATCH 3/5 app/testpmd: new flow dump CLI
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
New flow dump CLI to dump device internal representation information of flows into screen.
--- app/test-pmd/cmdline_flow.c | 91 +++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 27 +++++++++++ app/test-pmd/testpmd.h | 1 + 3 files changed, 119 insertions(+)
app/test-pmd/cmdline_flow.c +91 -0
@@ -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);
app/test-pmd/config.c +27 -0
@@ -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,
app/test-pmd/testpmd.h +1 -0
@@ -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);
Signature · 1 line
2.24.1
Re: [dpdk-dev] [PATCH 3/5] app/testpmd: new flow dump CLI
Quoted 5 lines
-----Original Message-----
Subject: [PATCH 3/5] app/testpmd: new flow dump CLI
Quoted 8 lines
From: Xueming Li <[email protected]>
New flow dump CLI to dump device internal representation information of flows into screen.
Signed-off-by Xueming Li <[email protected]>Signed-off-by Xiaoyu Min <[email protected]>---
Thanks,
Ori
Quoted 242 lines
app/test-pmd/cmdline_flow.c | 91 +++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 27 +++++++++++ app/test-pmd/testpmd.h | 1 + 3 files changed, 119 insertions(+)app/test-pmd/cmdline_flow.c +14
-0@@ -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,app/test-pmd/cmdline_flow.c +3
-0void *, 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,app/test-pmd/cmdline_flow.c +42
-0void *, 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 intparse_query(struct context *ctx, const struct token *token,
app/test-pmd/cmdline_flow.c +29
-0@@ -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.
*app/test-pmd/cmdline_flow.c +3
-0@@ -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);app/test-pmd/config.c +27
-0@@ -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,app/test-pmd/testpmd.h +1
-1@@ -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
PATCH 4/5 net/mlx5: add socket server for external tools
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
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
--- 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
drivers/net/mlx5/Makefile +1 -0
@@ -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)
drivers/net/mlx5/meson.build +1 -0
@@ -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')
drivers/net/mlx5/mlx5.c +2 -0
@@ -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",
drivers/net/mlx5/mlx5.h +5 -0
@@ -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);
drivers/net/mlx5/mlx5_socket.c new file +227 -0
227 lines not on this page · raw message
Signature · 1 line
2.24.1
Re: [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools
Hi, Jack
Quoted 167 lines
-----Original Message-----
From: Xiaoyu Min <[email protected]>
Sent: Thursday, January 16, 2020 12:14
To: [email protected]; Ori Kam <[email protected]>; Slava Ovsiienko <[email protected]>; Matan Azrad <[email protected]>; Raslan Darawsheh <[email protected]>; Shahaf Shuler <[email protected]>; Anatoly Burakov <[email protected]>
Cc: [email protected]; Xueming(Steven) Li <[email protected]>
Subject: [PATCH 4/5] net/mlx5: add socket server for external toolsFrom: Xueming Li <[email protected]>
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_idof uint16
file: file descriptor of intSigned-off-by Xueming Li <[email protected]>Signed-off-by Xiaoyu Min <[email protected]>--- 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.cdrivers/net/mlx5/Makefile index renamed from drivers/net/mlx5/Makefile +0
-0
6e5921b292..397e29dcbb100644drivers/net/mlx5/Makefile +1
-0@@ -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 --gita/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index
d7ef032afb..cb2fb90495100644drivers/net/mlx5/meson.build +1
-0@@ -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')drivers/net/mlx5/mlx5.c index renamed from drivers/net/mlx5/mlx5.c +0
-0
50960c91ce..ffee39c1a0100644drivers/net/mlx5/mlx5.c +2
-0@@ -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.hb/drivers/net/mlx5/mlx5.hindex047181b32e..ceb6de821e100644drivers/net/mlx5/mlx5.h +5
-0@@ -990,6 +990,11 @@ void mlx5_mp_uninit_primary(void); intmlx5_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);drivers/net/mlx5/mlx5_socket.c new file +27
-0@@ -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",
drivers/net/mlx5/mlx5_socket.c new file +49
-0+ 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" );
drivers/net/mlx5/mlx5_socket.c line 89
Quoted 10 lines
drivers/net/mlx5/mlx5_socket.c new file +10
-0+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.
Quoted 134 lines
drivers/net/mlx5/mlx5_socket.c new file +110
-0+/* 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 formlx5 socket: %s",
drivers/net/mlx5/mlx5_socket.c new file +23
-0+ 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,
Quoted 1 line
getpid());
I would move the MKSTR a couple lines below, after the close() call.
Quoted 6 lines
drivers/net/mlx5/mlx5_socket.c new file +4
-1+claim_zero (close (server_socket)); + server_socket =0 ; +claim_zero (remove (path)); +} --2.24.1
With best regards, Slava
Re: [dpdk-dev] [PATCH 4/5] net/mlx5: add socket server for external tools
Quoted 173 lines · Slava Ovsiienko
Hi, Jack
Quoted 171 lines
-----Original Message-----
From: Xiaoyu Min <[email protected]>
Sent: Thursday, January 16, 2020 12:14
To: [email protected]; Ori Kam <[email protected]>; Slava Ovsiienko <[email protected]>; Matan Azrad <[email protected]>; Raslan Darawsheh <[email protected]>; Shahaf Shuler <[email protected]>; Anatoly Burakov <[email protected]>
Cc: [email protected]; Xueming(Steven) Li <[email protected]>
Subject: [PATCH 4/5] net/mlx5: add socket server for external toolsFrom: Xueming Li <[email protected]>
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_idof uint16
file: file descriptor of intSigned-off-by Xueming Li <[email protected]>Signed-off-by Xiaoyu Min <[email protected]>--- 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.cdrivers/net/mlx5/Makefile index renamed from drivers/net/mlx5/Makefile +0
-0
6e5921b292..397e29dcbb100644drivers/net/mlx5/Makefile +1
-0@@ -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 --gita/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index
d7ef032afb..cb2fb90495100644drivers/net/mlx5/meson.build +1
-0@@ -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')drivers/net/mlx5/mlx5.c index renamed from drivers/net/mlx5/mlx5.c +0
-0
50960c91ce..ffee39c1a0100644drivers/net/mlx5/mlx5.c +2
-0@@ -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.hb/drivers/net/mlx5/mlx5.hindex047181b32e..ceb6de821e100644drivers/net/mlx5/mlx5.h +5
-0@@ -990,6 +990,11 @@ void mlx5_mp_uninit_primary(void); intmlx5_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);drivers/net/mlx5/mlx5_socket.c new file +27
-0@@ -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",
drivers/net/mlx5/mlx5_socket.c new file +53
-0+ 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; + }
Quoted 8 lines
drivers/net/mlx5/mlx5_socket.c line 89
Quoted 6 lines
drivers/net/mlx5/mlx5_socket.c new file +6
-0+/* 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_idcheck here.
The message with wrongport_idmay crash the server.
Yes, you are right. I'll update it in v2.
Quoted 130 lines
Quoted 130 lines
drivers/net/mlx5/mlx5_socket.c new file +110
-0+/* 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 formlx5 socket: %s",
drivers/net/mlx5/mlx5_socket.c new file +17
-0+ 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))
Quoted 8 lines
Quoted 7 lines
drivers/net/mlx5/mlx5_socket.c new file +6
-0+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.
Quoted 8 lines
Quoted 7 lines
drivers/net/mlx5/mlx5_socket.c new file +4
-1+claim_zero (close (server_socket)); + server_socket =0 ; +claim_zero (remove (path)); +} --2.24.1
With best regards, Slava
Thank you~
-Jack
PATCH 5/5 doc: update mlx5 document for flow dump feature
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
Guide of mlx5 is updated on how to dump HW flows.
--- doc/guides/nics/mlx5.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
doc/guides/nics/mlx5.rst +28 -0
@@ -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>
Signature · 1 line
2.24.1
v2 cover ethdev: add API to dump device internal flow info
In reply to Xiaoyu MinThis 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
Signature · 1 line
2.24.1
PATCH v2 1/5 ethdev: add API to dump device internal flow info
Introduce an API which dump the device's internal representation information of rte flows in hardware.
--- 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(+)
lib/librte_ethdev/rte_ethdev_version.map +3 -0
@@ -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; };
lib/librte_ethdev/rte_flow.c +16 -0
@@ -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 )); +}
lib/librte_ethdev/rte_flow.h +21 -0
@@ -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. *
lib/librte_ethdev/rte_flow_driver.h +5 -0
@@ -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); };/**
Signature · 1 line
2.24.1
Quoted 5 lines · Xiaoyu Min
Introduce an API which dump the device's internal representation information of rte flows in hardware.
Signed-off-by Xiaoyu Min <[email protected]>Acked-by Ori Kam <[email protected]>
PATCH v2 2/5 net/mlx5: support flow dump API
In reply to Xiaoyu MinDump fdb/nic_rx/nic_tx raw flow data into specified file.
--- 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(-)
drivers/net/mlx5/Makefile +6 -1
@@ -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 \
drivers/net/mlx5/meson.build +3 -1
@@ -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
drivers/net/mlx5/mlx5.h +4 -0
@@ -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);
drivers/net/mlx5/mlx5_devx_cmds.c +35 -0
@@ -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; +}
drivers/net/mlx5/mlx5_flow.c +24 -0
@@ -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); +}
drivers/net/mlx5/mlx5_glue.c +13 -0
@@ -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, };
drivers/net/mlx5/mlx5_glue.h +1 -0
@@ -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;
Signature · 1 line
2.24.1
PATCH v2 3/5 app/testpmd: new flow dump CLI
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
New flow dump CLI to dump device internal representation information of flows into screen.
--- app/test-pmd/cmdline_flow.c | 91 +++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 27 +++++++++++ app/test-pmd/testpmd.h | 1 + 3 files changed, 119 insertions(+)
app/test-pmd/cmdline_flow.c +91 -0
@@ -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);
app/test-pmd/config.c +27 -0
@@ -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,
app/test-pmd/testpmd.h +1 -0
@@ -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);
Signature · 1 line
2.24.1
PATCH v2 4/5 net/mlx5: add socket server for external tools
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
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
--- 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
drivers/net/mlx5/Makefile +1 -0
@@ -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)
drivers/net/mlx5/meson.build +1 -0
@@ -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')
drivers/net/mlx5/mlx5.c +2 -0
@@ -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",
drivers/net/mlx5/mlx5.h +5 -0
@@ -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);
drivers/net/mlx5/mlx5_socket.c new file +231 -0
231 lines not on this page · raw message
Signature · 1 line
2.24.1
PATCH v2 5/5 doc: update mlx5 document for flow dump feature
In reply to Xiaoyu MinFrom: Xueming Li <[email protected]>
Guide of mlx5 is updated on how to dump HW flows.
--- doc/guides/nics/mlx5.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
doc/guides/nics/mlx5.rst +28 -0
@@ -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>
Signature · 1 line
2.24.1
Quoted 19 lines · Xiaoyu Min
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
Quoted 8 lines
Xiaoyu Min (2):
ethdev: add API to dump device internal flow info net/mlx5: support flow dump APIXueming 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.
17/01/2020 20:26, Ferruh Yigit:
Quoted 11 lines · Xiaoyu Min
Quoted 8 lines
Xiaoyu Min (2):
ethdev: add API to dump device internal flow info net/mlx5: support flow dump APIXueming Li (3):
app/testpmd: new flow dump CLI
net/mlx5: add socket server for external tools
doc: update mlx5 document for flow dump featureSeries applied to dpdk-next-net/master, thanks.
I think we are missing an update of the testpmd doc.
Quoted 6 lines · Thomas Monjalon
17/01/2020 20:26, Ferruh Yigit:
Quoted 5 lines · Xiaoyu Min
Quoted 4 lines
Xiaoyu Min (2):
ethdev: add API to dump device internal flow info net/mlx5: support flow dump API
Quoted 9 lines
Quoted 6 lines
Quoted 4 lines
Xueming Li (3):
app/testpmd: new flow dump CLI
net/mlx5: add socket server for external tools
doc: update mlx5 document for flow dump featureSeries 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