* [PATCH 2/2] ethdev: fix race on ports for telemetry commands [not found] <20241002155709.2522273-1-david.marchand@redhat.com> @ 2024-10-02 15:57 ` David Marchand 2024-10-02 16:27 ` Bruce Richardson 2024-10-08 2:07 ` lihuisong (C) 2024-10-03 11:24 ` [PATCH dpdk v2 2/2] ethdev: fix potential race in telemetry endpoints Robin Jarry [not found] ` <20241014193237.1992382-1-rjarry@redhat.com> 2 siblings, 2 replies; 17+ messages in thread From: David Marchand @ 2024-10-02 15:57 UTC (permalink / raw) To: dev Cc: bruce.richardson, rjarry, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power While invoking telemetry commands (which may happen at any time, out of control of the application), an application thread may concurrently add/remove ports. The telemetry callbacks may then access partially initialised/uninitialised ethdev data. Reuse the ethdev lock that protects port allocation/destruction. Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") Cc: stable@dpdk.org Signed-off-by: David Marchand <david.marchand@redhat.com> --- lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c index 8031a58595..7f9c924209 100644 --- a/lib/ethdev/rte_ethdev_telemetry.c +++ b/lib/ethdev/rte_ethdev_telemetry.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <rte_kvargs.h> +#include <rte_spinlock.h> #include <rte_telemetry.h> #include "rte_ethdev.h" @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, return ret; } +#define ETHDEV_TELEMETRY_HANDLERS \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ + "Returns list of available ethdev ports. Takes no parameters") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ + "Returns the common stats for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ + "Returns dump private information for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ + "Returns the link status for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ + "Returns the device info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ + "Returns the MAC addresses for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ + "Returns flow ctrl info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ + "Returns DCB info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ + "Returns RSS info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ + "Returns FEC info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ + "Returns VLAN info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ + "Returns TM Capabilities info for a port. Parameters: int port_id") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") + +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ +static int func ## _locked(const char *cmd __rte_unused, const char *params, \ + struct rte_tel_data *d) \ +{ \ + int ret; \ + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); \ + ret = func(cmd, params, d); \ + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); \ + return ret; \ +} +ETHDEV_TELEMETRY_HANDLERS +#undef ETHDEV_TELEMETRY_HANDLER + RTE_INIT(ethdev_init_telemetry) { - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, - "Returns list of available ethdev ports. Takes no parameters"); - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, - "Returns the common stats for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, - "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, - "Returns dump private information for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/link_status", - eth_dev_handle_port_link_status, - "Returns the link status for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, - "Returns the device info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, - "Returns module EEPROM info with SFF specs. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, - "Returns the MAC addresses for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, - "Returns flow ctrl info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, - "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, - "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, - "Returns DCB info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, - "Returns RSS info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, - "Returns FEC info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, - "Returns VLAN info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, - "Returns TM Capabilities info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, - "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, - "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ + rte_telemetry_register_cmd(command, func ## _locked, usage); + ETHDEV_TELEMETRY_HANDLERS +#undef ETHDEV_TELEMETRY_HANDLER } -- 2.46.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 15:57 ` [PATCH 2/2] ethdev: fix race on ports for telemetry commands David Marchand @ 2024-10-02 16:27 ` Bruce Richardson 2024-10-02 19:06 ` David Marchand 2024-10-08 2:07 ` lihuisong (C) 1 sibling, 1 reply; 17+ messages in thread From: Bruce Richardson @ 2024-10-02 16:27 UTC (permalink / raw) To: David Marchand Cc: dev, rjarry, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Wed, Oct 02, 2024 at 05:57:08PM +0200, David Marchand wrote: > While invoking telemetry commands (which may happen at any time, > out of control of the application), an application thread may > concurrently add/remove ports. > The telemetry callbacks may then access partially > initialised/uninitialised ethdev data. > > Reuse the ethdev lock that protects port allocation/destruction. > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > Cc: stable@dpdk.org > > Signed-off-by: David Marchand <david.marchand@redhat.com> > --- > lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ > 1 file changed, 56 insertions(+), 37 deletions(-) > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > index 8031a58595..7f9c924209 100644 > --- a/lib/ethdev/rte_ethdev_telemetry.c > +++ b/lib/ethdev/rte_ethdev_telemetry.c > @@ -6,6 +6,7 @@ > #include <stdlib.h> > > #include <rte_kvargs.h> > +#include <rte_spinlock.h> > #include <rte_telemetry.h> > > #include "rte_ethdev.h" > @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > return ret; > } > > +#define ETHDEV_TELEMETRY_HANDLERS \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ > + "Returns list of available ethdev ports. Takes no parameters") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ > + "Returns the common stats for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ > + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ > + "Returns dump private information for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ > + "Returns the link status for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ > + "Returns the device info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ > + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ > + "Returns the MAC addresses for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ > + "Returns flow ctrl info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ > + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ > + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ > + "Returns DCB info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ > + "Returns RSS info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ > + "Returns FEC info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ > + "Returns VLAN info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ > + "Returns TM Capabilities info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ > + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ > + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") > + > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > +static int func ## _locked(const char *cmd __rte_unused, const char *params, \ > + struct rte_tel_data *d) \ > +{ \ > + int ret; \ > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); \ > + ret = func(cmd, params, d); \ > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); \ > + return ret; \ > +} > +ETHDEV_TELEMETRY_HANDLERS > +#undef ETHDEV_TELEMETRY_HANDLER > + Not really a massive fan of such use of macros in the code, since I think it makes things obscure for the casual reader. However, I see why this approach has been taken. I think the macro code needs some documentation explaining why this was done this way. > RTE_INIT(ethdev_init_telemetry) > { > - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, > - "Returns list of available ethdev ports. Takes no parameters"); > - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, > - "Returns the common stats for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, > - "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); > - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, > - "Returns dump private information for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/link_status", > - eth_dev_handle_port_link_status, > - "Returns the link status for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, > - "Returns the device info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, > - "Returns module EEPROM info with SFF specs. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, > - "Returns the MAC addresses for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, > - "Returns flow ctrl info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, > - "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, > - "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, > - "Returns DCB info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, > - "Returns RSS info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, > - "Returns FEC info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, > - "Returns VLAN info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, > - "Returns TM Capabilities info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, > - "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); > - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, > - "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > + rte_telemetry_register_cmd(command, func ## _locked, usage); > + ETHDEV_TELEMETRY_HANDLERS > +#undef ETHDEV_TELEMETRY_HANDLER > } An alternative to this macro-fu, is to just define a single ethdev telemetry function, and within that, take the lock and then dispatch to the appropriate subfunction based upon the actual command coming in. The dispatch may be slightly slower due to the additional text matching (only from byte 8 onwards, so very short strings), but I think the code could be a simpler in C rather than in macros, and the perf impact for telemetry is likely to be negligible, compared to the overhead of the socket I/O etc. /Bruce ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 16:27 ` Bruce Richardson @ 2024-10-02 19:06 ` David Marchand 2024-10-02 19:09 ` Robin Jarry 0 siblings, 1 reply; 17+ messages in thread From: David Marchand @ 2024-10-02 19:06 UTC (permalink / raw) To: Bruce Richardson Cc: dev, rjarry, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Wed, Oct 2, 2024 at 6:27 PM Bruce Richardson <bruce.richardson@intel.com> wrote: > > On Wed, Oct 02, 2024 at 05:57:08PM +0200, David Marchand wrote: > > While invoking telemetry commands (which may happen at any time, > > out of control of the application), an application thread may > > concurrently add/remove ports. > > The telemetry callbacks may then access partially > > initialised/uninitialised ethdev data. > > > > Reuse the ethdev lock that protects port allocation/destruction. > > > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > > Cc: stable@dpdk.org > > > > Signed-off-by: David Marchand <david.marchand@redhat.com> > > --- > > lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ > > 1 file changed, 56 insertions(+), 37 deletions(-) > > > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > > index 8031a58595..7f9c924209 100644 > > --- a/lib/ethdev/rte_ethdev_telemetry.c > > +++ b/lib/ethdev/rte_ethdev_telemetry.c > > @@ -6,6 +6,7 @@ > > #include <stdlib.h> > > > > #include <rte_kvargs.h> > > +#include <rte_spinlock.h> > > #include <rte_telemetry.h> > > > > #include "rte_ethdev.h" > > @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > > return ret; > > } > > > > +#define ETHDEV_TELEMETRY_HANDLERS \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ > > + "Returns list of available ethdev ports. Takes no parameters") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ > > + "Returns the common stats for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ > > + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ > > + "Returns dump private information for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ > > + "Returns the link status for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ > > + "Returns the device info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ > > + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ > > + "Returns the MAC addresses for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ > > + "Returns flow ctrl info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ > > + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ > > + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ > > + "Returns DCB info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ > > + "Returns RSS info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ > > + "Returns FEC info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ > > + "Returns VLAN info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ > > + "Returns TM Capabilities info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ > > + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ > > + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") > > + > > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > > +static int func ## _locked(const char *cmd __rte_unused, const char *params, \ > > + struct rte_tel_data *d) \ > > +{ \ > > + int ret; \ > > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); \ > > + ret = func(cmd, params, d); \ > > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); \ > > + return ret; \ > > +} > > +ETHDEV_TELEMETRY_HANDLERS > > +#undef ETHDEV_TELEMETRY_HANDLER > > + > > Not really a massive fan of such use of macros in the code, since I think > it makes things obscure for the casual reader. However, I see why this > approach has been taken. I think the macro code needs some documentation > explaining why this was done this way. I can add comments explaining how this is for protecting accesses to port. > > > RTE_INIT(ethdev_init_telemetry) > > { > > - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, > > - "Returns list of available ethdev ports. Takes no parameters"); > > - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, > > - "Returns the common stats for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, > > - "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); > > - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, > > - "Returns dump private information for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/link_status", > > - eth_dev_handle_port_link_status, > > - "Returns the link status for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, > > - "Returns the device info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, > > - "Returns module EEPROM info with SFF specs. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, > > - "Returns the MAC addresses for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, > > - "Returns flow ctrl info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, > > - "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > > - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, > > - "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > > - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, > > - "Returns DCB info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, > > - "Returns RSS info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, > > - "Returns FEC info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, > > - "Returns VLAN info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, > > - "Returns TM Capabilities info for a port. Parameters: int port_id"); > > - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, > > - "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); > > - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, > > - "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); > > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > > + rte_telemetry_register_cmd(command, func ## _locked, usage); > > + ETHDEV_TELEMETRY_HANDLERS > > +#undef ETHDEV_TELEMETRY_HANDLER > > } > > An alternative to this macro-fu, is to just define a single ethdev > telemetry function, and within that, take the lock and then dispatch to the > appropriate subfunction based upon the actual command coming in. The > dispatch may be slightly slower due to the additional text matching (only > from byte 8 onwards, so very short strings), but I think the code could be > a simpler in C rather than in macros, and the perf impact for telemetry is > likely to be negligible, compared to the overhead of the socket I/O etc. Hopefully, dispatching performance is not important here. (skipping the byte 8 stuff) is your proposal something like: static int one_callback_to_rule_them_all(const char *cmd, const char *params, struct rte_tel_data *d) { telemetry_cb cb = NULL; int ret = -EINVAL; if (strcmp(cmd, "/ethdev/list") == 0) { cb = eth_dev_handle_port_list; } else if (strcmp(cmd, "/ethdev/stats") == 0) { cb = eth_dev_handle_port_stats; } else if (strcmp(cmd, "/ethdev/xstats") == 0) { cb = eth_dev_handle_port_xstats; } ... if (cb != NULL) { rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); ret = cb(cmd, params, d); rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); } return ret; } RTE_INIT(ethdev_init_telemetry) { rte_telemetry_register_cmd("/ethdev/list", one_callback_to_rule_them_all, "Returns list of available ethdev ports. Takes no parameters"); rte_telemetry_register_cmd("/ethdev/stats", one_callback_to_rule_them_all, "Returns the common stats for a port. Parameters: int port_id"); rte_telemetry_register_cmd("/ethdev/xstats", one_callback_to_rule_them_all, "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); ... Which I find inelegant and not that great for maintenance: having the same info (especially strings that are only evaluated at runtime) in two locations is a call to inadvertence bugs. The macros I propose are a way to avoid splitting the callback function and the command names. Then addition of a handler is tied with a single declaration. + ETHDEV_TELEMETRY_HANDLER("/ethdev/newstuff", eth_dev_new_handler, \ + "New shiny command. Takes no parameters") \ -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 19:06 ` David Marchand @ 2024-10-02 19:09 ` Robin Jarry 2024-10-02 19:18 ` David Marchand 0 siblings, 1 reply; 17+ messages in thread From: Robin Jarry @ 2024-10-02 19:09 UTC (permalink / raw) To: David Marchand, Bruce Richardson Cc: dev, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power David Marchand, Oct 02, 2024 at 21:06: > On Wed, Oct 2, 2024 at 6:27 PM Bruce Richardson > <bruce.richardson@intel.com> wrote: >> >> On Wed, Oct 02, 2024 at 05:57:08PM +0200, David Marchand wrote: >> > While invoking telemetry commands (which may happen at any time, >> > out of control of the application), an application thread may >> > concurrently add/remove ports. >> > The telemetry callbacks may then access partially >> > initialised/uninitialised ethdev data. >> > >> > Reuse the ethdev lock that protects port allocation/destruction. >> > >> > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") >> > Cc: stable@dpdk.org >> > >> > Signed-off-by: David Marchand <david.marchand@redhat.com> >> > --- >> > lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ >> > 1 file changed, 56 insertions(+), 37 deletions(-) >> > >> > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c >> > index 8031a58595..7f9c924209 100644 >> > --- a/lib/ethdev/rte_ethdev_telemetry.c >> > +++ b/lib/ethdev/rte_ethdev_telemetry.c >> > @@ -6,6 +6,7 @@ >> > #include <stdlib.h> >> > >> > #include <rte_kvargs.h> >> > +#include <rte_spinlock.h> >> > #include <rte_telemetry.h> >> > >> > #include "rte_ethdev.h" >> > @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, >> > return ret; >> > } >> > >> > +#define ETHDEV_TELEMETRY_HANDLERS \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ >> > + "Returns list of available ethdev ports. Takes no parameters") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ >> > + "Returns the common stats for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ >> > + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ >> > + "Returns dump private information for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ >> > + "Returns the link status for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ >> > + "Returns the device info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ >> > + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ >> > + "Returns the MAC addresses for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ >> > + "Returns flow ctrl info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ >> > + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ >> > + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ >> > + "Returns DCB info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ >> > + "Returns RSS info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ >> > + "Returns FEC info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ >> > + "Returns VLAN info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ >> > + "Returns TM Capabilities info for a port. Parameters: int port_id") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ >> > + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ >> > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ >> > + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") >> > + >> > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ >> > +static int func ## _locked(const char *cmd __rte_unused, const char *params, \ >> > + struct rte_tel_data *d) \ >> > +{ \ >> > + int ret; \ >> > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); \ >> > + ret = func(cmd, params, d); \ >> > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); \ >> > + return ret; \ >> > +} >> > +ETHDEV_TELEMETRY_HANDLERS >> > +#undef ETHDEV_TELEMETRY_HANDLER >> > + >> >> Not really a massive fan of such use of macros in the code, since I think >> it makes things obscure for the casual reader. However, I see why this >> approach has been taken. I think the macro code needs some documentation >> explaining why this was done this way. > > I can add comments explaining how this is for protecting accesses to port. > >> >> > RTE_INIT(ethdev_init_telemetry) >> > { >> > - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, >> > - "Returns list of available ethdev ports. Takes no parameters"); >> > - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, >> > - "Returns the common stats for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, >> > - "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); >> > - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, >> > - "Returns dump private information for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/link_status", >> > - eth_dev_handle_port_link_status, >> > - "Returns the link status for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, >> > - "Returns the device info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, >> > - "Returns module EEPROM info with SFF specs. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, >> > - "Returns the MAC addresses for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, >> > - "Returns flow ctrl info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, >> > - "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); >> > - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, >> > - "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); >> > - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, >> > - "Returns DCB info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, >> > - "Returns RSS info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, >> > - "Returns FEC info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, >> > - "Returns VLAN info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, >> > - "Returns TM Capabilities info for a port. Parameters: int port_id"); >> > - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, >> > - "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); >> > - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, >> > - "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); >> > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ >> > + rte_telemetry_register_cmd(command, func ## _locked, usage); >> > + ETHDEV_TELEMETRY_HANDLERS >> > +#undef ETHDEV_TELEMETRY_HANDLER >> > } >> >> An alternative to this macro-fu, is to just define a single ethdev >> telemetry function, and within that, take the lock and then dispatch to the >> appropriate subfunction based upon the actual command coming in. The >> dispatch may be slightly slower due to the additional text matching (only >> from byte 8 onwards, so very short strings), but I think the code could be >> a simpler in C rather than in macros, and the perf impact for telemetry is >> likely to be negligible, compared to the overhead of the socket I/O etc. > > Hopefully, dispatching performance is not important here. I was going to suggest adding a rte_spinlock_t* parameter to a new telemetry register function that would need to be held while the callback is invoked. Or if we want to keep doors open to other kinds of lock, a wrapper callback. Thoughts? ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 19:09 ` Robin Jarry @ 2024-10-02 19:18 ` David Marchand 2024-10-02 19:26 ` Robin Jarry 0 siblings, 1 reply; 17+ messages in thread From: David Marchand @ 2024-10-02 19:18 UTC (permalink / raw) To: Robin Jarry Cc: Bruce Richardson, dev, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Wed, Oct 2, 2024 at 9:09 PM Robin Jarry <rjarry@redhat.com> wrote: > >> An alternative to this macro-fu, is to just define a single ethdev > >> telemetry function, and within that, take the lock and then dispatch to the > >> appropriate subfunction based upon the actual command coming in. The > >> dispatch may be slightly slower due to the additional text matching (only > >> from byte 8 onwards, so very short strings), but I think the code could be > >> a simpler in C rather than in macros, and the perf impact for telemetry is > >> likely to be negligible, compared to the overhead of the socket I/O etc. > > > > Hopefully, dispatching performance is not important here. > > I was going to suggest adding a rte_spinlock_t* parameter to a new > telemetry register function that would need to be held while the > callback is invoked. Or if we want to keep doors open to other kinds of > lock, a wrapper callback. Well, as you had experimented this approach, we know this does not work: the ethdev lock is in dpdk shared memory which is not available yet at the time RTE_INIT() is called. A single callback is strange, I guess you mean pre/post callbacks then. -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 19:18 ` David Marchand @ 2024-10-02 19:26 ` Robin Jarry 2024-10-03 9:46 ` Bruce Richardson 0 siblings, 1 reply; 17+ messages in thread From: Robin Jarry @ 2024-10-02 19:26 UTC (permalink / raw) To: David Marchand Cc: Bruce Richardson, dev, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power David Marchand, Oct 02, 2024 at 21:18: > On Wed, Oct 2, 2024 at 9:09 PM Robin Jarry <rjarry@redhat.com> wrote: >> I was going to suggest adding a rte_spinlock_t* parameter to a new >> telemetry register function that would need to be held while the >> callback is invoked. Or if we want to keep doors open to other kinds of >> lock, a wrapper callback. > > Well, as you had experimented this approach, we know this does not > work: the ethdev lock is in dpdk shared memory which is not available > yet at the time RTE_INIT() is called. > > A single callback is strange, I guess you mean pre/post callbacks then. It could be a single function that will wrap the callbacks. E.g.: static int eth_dev_telemetry_with_lock( telemetry_cb fn, const char *cmd, const char *params, struct rte_tel_data *d) { int ret; rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); ret = fn(cmd, params, d); rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); return ret; } RTE_INIT(ethdev_init_telemetry) { .... rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, "Returns the common stats for a port. Parameters: int port_id", eth_dev_telemetry_with_lock); .... } I'm not sure which solution is the uglier :D ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 19:26 ` Robin Jarry @ 2024-10-03 9:46 ` Bruce Richardson 2024-10-03 9:58 ` David Marchand 0 siblings, 1 reply; 17+ messages in thread From: Bruce Richardson @ 2024-10-03 9:46 UTC (permalink / raw) To: Robin Jarry Cc: David Marchand, dev, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Wed, Oct 02, 2024 at 09:26:10PM +0200, Robin Jarry wrote: > David Marchand, Oct 02, 2024 at 21:18: > > On Wed, Oct 2, 2024 at 9:09 PM Robin Jarry <rjarry@redhat.com> wrote: > > > I was going to suggest adding a rte_spinlock_t* parameter to a new > > > telemetry register function that would need to be held while the > > > callback is invoked. Or if we want to keep doors open to other kinds of > > > lock, a wrapper callback. > > > > Well, as you had experimented this approach, we know this does not > > work: the ethdev lock is in dpdk shared memory which is not available > > yet at the time RTE_INIT() is called. > > > > A single callback is strange, I guess you mean pre/post callbacks then. > > It could be a single function that will wrap the callbacks. E.g.: > > static int > eth_dev_telemetry_with_lock( > telemetry_cb fn, const char *cmd, const char *params, struct rte_tel_data *d) > { > int ret; > rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); > ret = fn(cmd, params, d); > rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); > return ret; > } > > RTE_INIT(ethdev_init_telemetry) > { > .... > rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, > "Returns the common stats for a port. Parameters: int port_id", > eth_dev_telemetry_with_lock); > .... > } > > I'm not sure which solution is the uglier :D > I don't actually mind this latter solution, except that the order of the parameters should be reversed (and it breaks the ABI, unless we add a special new function for it) For me, the wrapper function should be the main callback, and the real (unwrapped) function the extra parameter to be called. That extra parameter to callbacks should just be a generic pointer, so it can be data or function that is passed around. rte_telemetry_register_param_cmd(const char *cmd, telemetry_cb fn, void *param, const char *help) Or more specifically: rte_telemetry_register_param_cmd("/ethdev/stats", eth_dev_telemetry_with_lock, /* callback */ eth_dev_handle_port_stats, /* parameter */ "Returns the common stats for a port. Parameters: int port_id"); /Bruce PS: Yes, I realise that using void * as function pointers is not always recommended, but we already use dlsym which does so! ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-03 9:46 ` Bruce Richardson @ 2024-10-03 9:58 ` David Marchand 0 siblings, 0 replies; 17+ messages in thread From: David Marchand @ 2024-10-03 9:58 UTC (permalink / raw) To: Bruce Richardson Cc: Robin Jarry, dev, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Thu, Oct 3, 2024 at 11:46 AM Bruce Richardson <bruce.richardson@intel.com> wrote: > > On Wed, Oct 02, 2024 at 09:26:10PM +0200, Robin Jarry wrote: > > David Marchand, Oct 02, 2024 at 21:18: > > > On Wed, Oct 2, 2024 at 9:09 PM Robin Jarry <rjarry@redhat.com> wrote: > > > > I was going to suggest adding a rte_spinlock_t* parameter to a new > > > > telemetry register function that would need to be held while the > > > > callback is invoked. Or if we want to keep doors open to other kinds of > > > > lock, a wrapper callback. > > > > > > Well, as you had experimented this approach, we know this does not > > > work: the ethdev lock is in dpdk shared memory which is not available > > > yet at the time RTE_INIT() is called. > > > > > > A single callback is strange, I guess you mean pre/post callbacks then. > > > > It could be a single function that will wrap the callbacks. E.g.: > > > > static int > > eth_dev_telemetry_with_lock( > > telemetry_cb fn, const char *cmd, const char *params, struct rte_tel_data *d) > > { > > int ret; > > rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); > > ret = fn(cmd, params, d); > > rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); > > return ret; > > } > > > > RTE_INIT(ethdev_init_telemetry) > > { > > .... > > rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, > > "Returns the common stats for a port. Parameters: int port_id", > > eth_dev_telemetry_with_lock); > > .... > > } > > > > I'm not sure which solution is the uglier :D > > > > I don't actually mind this latter solution, except that the order of the > parameters should be reversed (and it breaks the ABI, unless we add a > special new function for it) For me, the wrapper function should be the > main callback, and the real (unwrapped) function the extra parameter to be > called. That extra parameter to callbacks should just be a generic pointer, > so it can be data or function that is passed around. > > rte_telemetry_register_param_cmd(const char *cmd, telemetry_cb fn, > void *param, const char *help) > > Or more specifically: > > > rte_telemetry_register_param_cmd("/ethdev/stats", > eth_dev_telemetry_with_lock, /* callback */ > eth_dev_handle_port_stats, /* parameter */ > "Returns the common stats for a port. Parameters: int port_id"); Ok, this way seems nicer. I'll let Robin submit a v2. -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-02 15:57 ` [PATCH 2/2] ethdev: fix race on ports for telemetry commands David Marchand 2024-10-02 16:27 ` Bruce Richardson @ 2024-10-08 2:07 ` lihuisong (C) 2024-10-08 6:48 ` David Marchand 1 sibling, 1 reply; 17+ messages in thread From: lihuisong (C) @ 2024-10-08 2:07 UTC (permalink / raw) To: David Marchand, dev Cc: bruce.richardson, rjarry, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power 在 2024/10/2 23:57, David Marchand 写道: > While invoking telemetry commands (which may happen at any time, > out of control of the application), an application thread may > concurrently add/remove ports. > The telemetry callbacks may then access partially > initialised/uninitialised ethdev data. > > Reuse the ethdev lock that protects port allocation/destruction. Agree to lock for telemetry. > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > Cc: stable@dpdk.org > > Signed-off-by: David Marchand <david.marchand@redhat.com> > --- > lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ > 1 file changed, 56 insertions(+), 37 deletions(-) > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > index 8031a58595..7f9c924209 100644 > --- a/lib/ethdev/rte_ethdev_telemetry.c > +++ b/lib/ethdev/rte_ethdev_telemetry.c > @@ -6,6 +6,7 @@ > #include <stdlib.h> > > #include <rte_kvargs.h> > +#include <rte_spinlock.h> > #include <rte_telemetry.h> > > #include "rte_ethdev.h" > @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > return ret; > } > > +#define ETHDEV_TELEMETRY_HANDLERS \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ > + "Returns list of available ethdev ports. Takes no parameters") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ > + "Returns the common stats for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ > + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ > + "Returns dump private information for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ > + "Returns the link status for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ > + "Returns the device info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ > + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ > + "Returns the MAC addresses for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ > + "Returns flow ctrl info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ > + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ > + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ > + "Returns DCB info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ > + "Returns RSS info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ > + "Returns FEC info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ > + "Returns VLAN info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ > + "Returns TM Capabilities info for a port. Parameters: int port_id") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ > + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ > + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") > + > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ In addition, the "command" and "usage" are unuseful in this definition. This is confused to me. Can the first macro definition just use 'func' as input parameter? The name of this macro define is the same as the below one. I prefer to use two different macros to do this. > +static int func ## _locked(const char *cmd __rte_unused, const char *params, \ > + struct rte_tel_data *d) \ > +{ \ > + int ret; \ > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); \ > + ret = func(cmd, params, d); \ > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); \ > + return ret; \ > +} > +ETHDEV_TELEMETRY_HANDLERS > +#undef ETHDEV_TELEMETRY_HANDLER > + > RTE_INIT(ethdev_init_telemetry) > { > - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, > - "Returns list of available ethdev ports. Takes no parameters"); > - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, > - "Returns the common stats for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, > - "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); > - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, > - "Returns dump private information for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/link_status", > - eth_dev_handle_port_link_status, > - "Returns the link status for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, > - "Returns the device info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, > - "Returns module EEPROM info with SFF specs. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, > - "Returns the MAC addresses for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, > - "Returns flow ctrl info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, > - "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, > - "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); > - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, > - "Returns DCB info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, > - "Returns RSS info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, > - "Returns FEC info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, > - "Returns VLAN info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, > - "Returns TM Capabilities info for a port. Parameters: int port_id"); > - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, > - "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); > - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, > - "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > + rte_telemetry_register_cmd(command, func ## _locked, usage); > + ETHDEV_TELEMETRY_HANDLERS > +#undef ETHDEV_TELEMETRY_HANDLER > } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/2] ethdev: fix race on ports for telemetry commands 2024-10-08 2:07 ` lihuisong (C) @ 2024-10-08 6:48 ` David Marchand 0 siblings, 0 replies; 17+ messages in thread From: David Marchand @ 2024-10-08 6:48 UTC (permalink / raw) To: lihuisong (C) Cc: dev, bruce.richardson, rjarry, ktraynor, stable, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Keith Wiles, Ciara Power On Tue, Oct 8, 2024 at 4:09 AM lihuisong (C) <lihuisong@huawei.com> wrote: > > > 在 2024/10/2 23:57, David Marchand 写道: > > While invoking telemetry commands (which may happen at any time, > > out of control of the application), an application thread may > > concurrently add/remove ports. > > The telemetry callbacks may then access partially > > initialised/uninitialised ethdev data. > > > > Reuse the ethdev lock that protects port allocation/destruction. > Agree to lock for telemetry. > > > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > > Cc: stable@dpdk.org > > > > Signed-off-by: David Marchand <david.marchand@redhat.com> > > --- > > lib/ethdev/rte_ethdev_telemetry.c | 93 +++++++++++++++++++------------ > > 1 file changed, 56 insertions(+), 37 deletions(-) > > > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > > index 8031a58595..7f9c924209 100644 > > --- a/lib/ethdev/rte_ethdev_telemetry.c > > +++ b/lib/ethdev/rte_ethdev_telemetry.c > > @@ -6,6 +6,7 @@ > > #include <stdlib.h> > > > > #include <rte_kvargs.h> > > +#include <rte_spinlock.h> > > #include <rte_telemetry.h> > > > > #include "rte_ethdev.h" > > @@ -1403,43 +1404,61 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > > return ret; > > } > > > > +#define ETHDEV_TELEMETRY_HANDLERS \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/list", eth_dev_handle_port_list, \ > > + "Returns list of available ethdev ports. Takes no parameters") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/stats", eth_dev_handle_port_stats, \ > > + "Returns the common stats for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/xstats", eth_dev_handle_port_xstats, \ > > + "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, \ > > + "Returns dump private information for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/link_status", eth_dev_handle_port_link_status, \ > > + "Returns the link status for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/info", eth_dev_handle_port_info, \ > > + "Returns the device info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, \ > > + "Returns module EEPROM info with SFF specs. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/macs", eth_dev_handle_port_macs, \ > > + "Returns the MAC addresses for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, \ > > + "Returns flow ctrl info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rx_queue", eth_dev_handle_port_rxq, \ > > + "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tx_queue", eth_dev_handle_port_txq, \ > > + "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/dcb", eth_dev_handle_port_dcb, \ > > + "Returns DCB info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/rss_info", eth_dev_handle_port_rss_info, \ > > + "Returns RSS info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/fec", eth_dev_handle_port_fec, \ > > + "Returns FEC info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/vlan", eth_dev_handle_port_vlan, \ > > + "Returns VLAN info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, \ > > + "Returns TM Capabilities info for a port. Parameters: int port_id") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, \ > > + "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)") \ > > + ETHDEV_TELEMETRY_HANDLER("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, \ > > + "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)") > > + > > +#define ETHDEV_TELEMETRY_HANDLER(command, func, usage) \ > In addition, the "command" and "usage" are unuseful in this definition. > This is confused to me. > Can the first macro definition just use 'func' as input parameter? > The name of this macro define is the same as the below one. > I prefer to use two different macros to do this. This patch has been withdrawn. Robin is working on another approach, see: https://patchwork.dpdk.org/project/dpdk/patch/20241003112438.902397-6-rjarry@redhat.com/ https://patchwork.dpdk.org/project/dpdk/patch/20241003112438.902397-7-rjarry@redhat.com/ -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH dpdk v2 2/2] ethdev: fix potential race in telemetry endpoints [not found] <20241002155709.2522273-1-david.marchand@redhat.com> 2024-10-02 15:57 ` [PATCH 2/2] ethdev: fix race on ports for telemetry commands David Marchand @ 2024-10-03 11:24 ` Robin Jarry 2024-10-03 11:39 ` Bruce Richardson [not found] ` <20241014193237.1992382-1-rjarry@redhat.com> 2 siblings, 1 reply; 17+ messages in thread From: Robin Jarry @ 2024-10-03 11:24 UTC (permalink / raw) To: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Keith Wiles, Bruce Richardson Cc: david.marchand, ktraynor, stable While invoking telemetry commands (which may happen at any time, out of control of the application), an application thread may concurrently add/remove ports. The telemetry callbacks may then access partially initialized/uninitialised ethdev data. Reuse the ethdev lock that protects port allocation/destruction and the new telemetry callback register api that takes an additional private argument. Pass eth_dev_telemetry_do as the main callback and the actual endpoint callbacks as private argument. Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") Cc: stable@dpdk.org Signed-off-by: Robin Jarry <rjarry@redhat.com> --- lib/ethdev/rte_ethdev_telemetry.c | 66 ++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c index 6b873e7abe68..a9336a81b73b 100644 --- a/lib/ethdev/rte_ethdev_telemetry.c +++ b/lib/ethdev/rte_ethdev_telemetry.c @@ -1395,45 +1395,73 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, return ret; } +static int eth_dev_telemetry_do(const char *cmd, const char *params, struct rte_tel_data *d, + void *arg) +{ + int ret; + telemetry_cb fn = arg; + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); + ret = fn(cmd, params, d); + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); + return ret; +} + RTE_INIT(ethdev_init_telemetry) { - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, + rte_telemetry_register_cmd_arg("/ethdev/list", + eth_dev_telemetry_do, eth_dev_handle_port_list, "Returns list of available ethdev ports. Takes no parameters"); - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, + rte_telemetry_register_cmd_arg("/ethdev/stats", + eth_dev_telemetry_do, eth_dev_handle_port_stats, "Returns the common stats for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, + rte_telemetry_register_cmd_arg("/ethdev/xstats", + eth_dev_telemetry_do, eth_dev_handle_port_xstats, "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); #ifndef RTE_EXEC_ENV_WINDOWS - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, + rte_telemetry_register_cmd_arg("/ethdev/dump_priv", + eth_dev_telemetry_do, eth_dev_handle_port_dump_priv, "Returns dump private information for a port. Parameters: int port_id"); #endif - rte_telemetry_register_cmd("/ethdev/link_status", - eth_dev_handle_port_link_status, + rte_telemetry_register_cmd_arg("/ethdev/link_status", + eth_dev_telemetry_do, eth_dev_handle_port_link_status, "Returns the link status for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, + rte_telemetry_register_cmd_arg("/ethdev/info", + eth_dev_telemetry_do, eth_dev_handle_port_info, "Returns the device info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, + rte_telemetry_register_cmd_arg("/ethdev/module_eeprom", + eth_dev_telemetry_do, eth_dev_handle_port_module_eeprom, "Returns module EEPROM info with SFF specs. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, + rte_telemetry_register_cmd_arg("/ethdev/macs", + eth_dev_telemetry_do, eth_dev_handle_port_macs, "Returns the MAC addresses for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, + rte_telemetry_register_cmd_arg("/ethdev/flow_ctrl", + eth_dev_telemetry_do, eth_dev_handle_port_flow_ctrl, "Returns flow ctrl info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, + rte_telemetry_register_cmd_arg("/ethdev/rx_queue", + eth_dev_telemetry_do, eth_dev_handle_port_rxq, "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, + rte_telemetry_register_cmd_arg("/ethdev/tx_queue", + eth_dev_telemetry_do, eth_dev_handle_port_txq, "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, + rte_telemetry_register_cmd_arg("/ethdev/dcb", + eth_dev_telemetry_do, eth_dev_handle_port_dcb, "Returns DCB info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, + rte_telemetry_register_cmd_arg("/ethdev/rss_info", + eth_dev_telemetry_do, eth_dev_handle_port_rss_info, "Returns RSS info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, + rte_telemetry_register_cmd_arg("/ethdev/fec", + eth_dev_telemetry_do, eth_dev_handle_port_fec, "Returns FEC info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, + rte_telemetry_register_cmd_arg("/ethdev/vlan", + eth_dev_telemetry_do, eth_dev_handle_port_vlan, "Returns VLAN info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_caps, "Returns TM Capabilities info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_level_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_level_caps, "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_node_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_node_caps, "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); } -- 2.46.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH dpdk v2 2/2] ethdev: fix potential race in telemetry endpoints 2024-10-03 11:24 ` [PATCH dpdk v2 2/2] ethdev: fix potential race in telemetry endpoints Robin Jarry @ 2024-10-03 11:39 ` Bruce Richardson 0 siblings, 0 replies; 17+ messages in thread From: Bruce Richardson @ 2024-10-03 11:39 UTC (permalink / raw) To: Robin Jarry Cc: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Keith Wiles, david.marchand, ktraynor, stable On Thu, Oct 03, 2024 at 01:24:42PM +0200, Robin Jarry wrote: > While invoking telemetry commands (which may happen at any time, out of > control of the application), an application thread may concurrently > add/remove ports. The telemetry callbacks may then access partially > initialized/uninitialised ethdev data. > > Reuse the ethdev lock that protects port allocation/destruction and the > new telemetry callback register api that takes an additional private > argument. Pass eth_dev_telemetry_do as the main callback and the actual > endpoint callbacks as private argument. > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > Cc: stable@dpdk.org > > Signed-off-by: Robin Jarry <rjarry@redhat.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 17+ messages in thread
[parent not found: <20241014193237.1992382-1-rjarry@redhat.com>]
* [PATCH dpdk v3 2/2] ethdev: fix potential race in telemetry endpoints [not found] ` <20241014193237.1992382-1-rjarry@redhat.com> @ 2024-10-14 19:32 ` Robin Jarry 2024-10-14 20:01 ` Stephen Hemminger 2024-10-15 8:38 ` David Marchand 0 siblings, 2 replies; 17+ messages in thread From: Robin Jarry @ 2024-10-14 19:32 UTC (permalink / raw) To: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Bruce Richardson, Keith Wiles Cc: stable While invoking telemetry commands (which may happen at any time, out of control of the application), an application thread may concurrently add/remove ports. The telemetry callbacks may then access partially initialized/uninitialised ethdev data. Reuse the ethdev lock that protects port allocation/destruction and the new telemetry callback register api that takes an additional private argument. Pass eth_dev_telemetry_do as the main callback and the actual endpoint callbacks as private argument. Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") Cc: stable@dpdk.org Signed-off-by: Robin Jarry <rjarry@redhat.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/ethdev/rte_ethdev_telemetry.c | 66 ++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c index 6b873e7abe68..7599fa2852b6 100644 --- a/lib/ethdev/rte_ethdev_telemetry.c +++ b/lib/ethdev/rte_ethdev_telemetry.c @@ -1395,45 +1395,73 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, return ret; } +static int eth_dev_telemetry_do(const char *cmd, const char *params, + void *arg, struct rte_tel_data *d) +{ + int ret; + telemetry_cb fn = arg; + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); + ret = fn(cmd, params, d); + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); + return ret; +} + RTE_INIT(ethdev_init_telemetry) { - rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, + rte_telemetry_register_cmd_arg("/ethdev/list", + eth_dev_telemetry_do, eth_dev_handle_port_list, "Returns list of available ethdev ports. Takes no parameters"); - rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, + rte_telemetry_register_cmd_arg("/ethdev/stats", + eth_dev_telemetry_do, eth_dev_handle_port_stats, "Returns the common stats for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, + rte_telemetry_register_cmd_arg("/ethdev/xstats", + eth_dev_telemetry_do, eth_dev_handle_port_xstats, "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); #ifndef RTE_EXEC_ENV_WINDOWS - rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, + rte_telemetry_register_cmd_arg("/ethdev/dump_priv", + eth_dev_telemetry_do, eth_dev_handle_port_dump_priv, "Returns dump private information for a port. Parameters: int port_id"); #endif - rte_telemetry_register_cmd("/ethdev/link_status", - eth_dev_handle_port_link_status, + rte_telemetry_register_cmd_arg("/ethdev/link_status", + eth_dev_telemetry_do, eth_dev_handle_port_link_status, "Returns the link status for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, + rte_telemetry_register_cmd_arg("/ethdev/info", + eth_dev_telemetry_do, eth_dev_handle_port_info, "Returns the device info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, + rte_telemetry_register_cmd_arg("/ethdev/module_eeprom", + eth_dev_telemetry_do, eth_dev_handle_port_module_eeprom, "Returns module EEPROM info with SFF specs. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, + rte_telemetry_register_cmd_arg("/ethdev/macs", + eth_dev_telemetry_do, eth_dev_handle_port_macs, "Returns the MAC addresses for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, + rte_telemetry_register_cmd_arg("/ethdev/flow_ctrl", + eth_dev_telemetry_do, eth_dev_handle_port_flow_ctrl, "Returns flow ctrl info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, + rte_telemetry_register_cmd_arg("/ethdev/rx_queue", + eth_dev_telemetry_do, eth_dev_handle_port_rxq, "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, + rte_telemetry_register_cmd_arg("/ethdev/tx_queue", + eth_dev_telemetry_do, eth_dev_handle_port_txq, "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); - rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, + rte_telemetry_register_cmd_arg("/ethdev/dcb", + eth_dev_telemetry_do, eth_dev_handle_port_dcb, "Returns DCB info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, + rte_telemetry_register_cmd_arg("/ethdev/rss_info", + eth_dev_telemetry_do, eth_dev_handle_port_rss_info, "Returns RSS info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, + rte_telemetry_register_cmd_arg("/ethdev/fec", + eth_dev_telemetry_do, eth_dev_handle_port_fec, "Returns FEC info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, + rte_telemetry_register_cmd_arg("/ethdev/vlan", + eth_dev_telemetry_do, eth_dev_handle_port_vlan, "Returns VLAN info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_capability", eth_dev_handle_port_tm_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_caps, "Returns TM Capabilities info for a port. Parameters: int port_id"); - rte_telemetry_register_cmd("/ethdev/tm_level_capability", eth_dev_handle_port_tm_level_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_level_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_level_caps, "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); - rte_telemetry_register_cmd("/ethdev/tm_node_capability", eth_dev_handle_port_tm_node_caps, + rte_telemetry_register_cmd_arg("/ethdev/tm_node_capability", + eth_dev_telemetry_do, eth_dev_handle_port_tm_node_caps, "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); } -- 2.46.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH dpdk v3 2/2] ethdev: fix potential race in telemetry endpoints 2024-10-14 19:32 ` [PATCH dpdk v3 " Robin Jarry @ 2024-10-14 20:01 ` Stephen Hemminger 2024-10-15 8:02 ` David Marchand 2024-10-15 8:38 ` David Marchand 1 sibling, 1 reply; 17+ messages in thread From: Stephen Hemminger @ 2024-10-14 20:01 UTC (permalink / raw) To: Robin Jarry Cc: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Bruce Richardson, Keith Wiles, stable On Mon, 14 Oct 2024 21:32:37 +0200 Robin Jarry <rjarry@redhat.com> wrote: > While invoking telemetry commands (which may happen at any time, out of > control of the application), an application thread may concurrently > add/remove ports. The telemetry callbacks may then access partially > initialized/uninitialised ethdev data. > > Reuse the ethdev lock that protects port allocation/destruction and the > new telemetry callback register api that takes an additional private > argument. Pass eth_dev_telemetry_do as the main callback and the actual > endpoint callbacks as private argument. > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > Cc: stable@dpdk.org > > Signed-off-by: Robin Jarry <rjarry@redhat.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > --- > lib/ethdev/rte_ethdev_telemetry.c | 66 ++++++++++++++++++++++--------- > 1 file changed, 47 insertions(+), 19 deletions(-) > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > index 6b873e7abe68..7599fa2852b6 100644 > --- a/lib/ethdev/rte_ethdev_telemetry.c > +++ b/lib/ethdev/rte_ethdev_telemetry.c > @@ -1395,45 +1395,73 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > return ret; > } > > +static int eth_dev_telemetry_do(const char *cmd, const char *params, > + void *arg, struct rte_tel_data *d) > +{ > + int ret; > + telemetry_cb fn = arg; > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); > + ret = fn(cmd, params, d); > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); > + return ret; > +} If this happens often, and the function takes a long time (like doing i/o) it might be worth changing this to reader/writer in future. Also, would be best to add a comment here as to what is being protected if you do another version. Acked-by: Stephen Hemminger <stephen@networkplumber.org> ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH dpdk v3 2/2] ethdev: fix potential race in telemetry endpoints 2024-10-14 20:01 ` Stephen Hemminger @ 2024-10-15 8:02 ` David Marchand 2024-10-15 8:04 ` Robin Jarry 0 siblings, 1 reply; 17+ messages in thread From: David Marchand @ 2024-10-15 8:02 UTC (permalink / raw) To: Stephen Hemminger, Robin Jarry Cc: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Bruce Richardson, Keith Wiles, stable On Mon, Oct 14, 2024 at 10:01 PM Stephen Hemminger <stephen@networkplumber.org> wrote: > > On Mon, 14 Oct 2024 21:32:37 +0200 > Robin Jarry <rjarry@redhat.com> wrote: > > > While invoking telemetry commands (which may happen at any time, out of > > control of the application), an application thread may concurrently > > add/remove ports. The telemetry callbacks may then access partially > > initialized/uninitialised ethdev data. > > > > Reuse the ethdev lock that protects port allocation/destruction and the > > new telemetry callback register api that takes an additional private > > argument. Pass eth_dev_telemetry_do as the main callback and the actual > > endpoint callbacks as private argument. > > > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > > Cc: stable@dpdk.org > > > > Signed-off-by: Robin Jarry <rjarry@redhat.com> > > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > > --- > > lib/ethdev/rte_ethdev_telemetry.c | 66 ++++++++++++++++++++++--------- > > 1 file changed, 47 insertions(+), 19 deletions(-) > > > > diff --git a/lib/ethdev/rte_ethdev_telemetry.c b/lib/ethdev/rte_ethdev_telemetry.c > > index 6b873e7abe68..7599fa2852b6 100644 > > --- a/lib/ethdev/rte_ethdev_telemetry.c > > +++ b/lib/ethdev/rte_ethdev_telemetry.c > > @@ -1395,45 +1395,73 @@ eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, > > return ret; > > } > > > > +static int eth_dev_telemetry_do(const char *cmd, const char *params, > > + void *arg, struct rte_tel_data *d) > > +{ > > + int ret; > > + telemetry_cb fn = arg; > > + rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); > > + ret = fn(cmd, params, d); > > + rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); > > + return ret; > > +} > > If this happens often, and the function takes a long time (like doing i/o) > it might be worth changing this to reader/writer in future. Yes, this was an option mentionned when we discussed the issue in Montréal. For now, a spinlock seems enough. > > Also, would be best to add a comment here as to what is being protected > if you do another version. I can add something when applying, like: @@ -1400,6 +1400,7 @@ static int eth_dev_telemetry_do(const char *cmd, const char *params, { int ret; telemetry_cb fn = arg; + /* Protect against port removal while invoking callback, calling ethdev API. */ rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); ret = fn(cmd, params, d); rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH dpdk v3 2/2] ethdev: fix potential race in telemetry endpoints 2024-10-15 8:02 ` David Marchand @ 2024-10-15 8:04 ` Robin Jarry 0 siblings, 0 replies; 17+ messages in thread From: Robin Jarry @ 2024-10-15 8:04 UTC (permalink / raw) To: David Marchand, Stephen Hemminger Cc: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Ciara Power, Bruce Richardson, Keith Wiles, stable David Marchand, Oct 15, 2024 at 10:02: > On Mon, Oct 14, 2024 at 10:01 PM Stephen Hemminger >> If this happens often, and the function takes a long time (like doing i/o) >> it might be worth changing this to reader/writer in future. > > Yes, this was an option mentionned when we discussed the issue in Montréal. > For now, a spinlock seems enough. As far as I know, no ethdev telemetry endpoint handlers do any i/o. They only access stuff in memory. >> Also, would be best to add a comment here as to what is being protected >> if you do another version. > > I can add something when applying, like: > > @@ -1400,6 +1400,7 @@ static int eth_dev_telemetry_do(const char *cmd, > const char *params, > { > int ret; > telemetry_cb fn = arg; > + /* Protect against port removal while invoking callback, > calling ethdev API. */ > rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); > ret = fn(cmd, params, d); > rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); Ack, thank you. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH dpdk v3 2/2] ethdev: fix potential race in telemetry endpoints 2024-10-14 19:32 ` [PATCH dpdk v3 " Robin Jarry 2024-10-14 20:01 ` Stephen Hemminger @ 2024-10-15 8:38 ` David Marchand 1 sibling, 0 replies; 17+ messages in thread From: David Marchand @ 2024-10-15 8:38 UTC (permalink / raw) To: Robin Jarry Cc: dev, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, Bruce Richardson, Keith Wiles, stable, Stephen Hemminger On Mon, Oct 14, 2024 at 9:33 PM Robin Jarry <rjarry@redhat.com> wrote: > > While invoking telemetry commands (which may happen at any time, out of > control of the application), an application thread may concurrently > add/remove ports. The telemetry callbacks may then access partially > initialized/uninitialised ethdev data. > > Reuse the ethdev lock that protects port allocation/destruction and the > new telemetry callback register api that takes an additional private > argument. Pass eth_dev_telemetry_do as the main callback and the actual > endpoint callbacks as private argument. > > Fixes: c190daedb9b1 ("ethdev: add telemetry callbacks") > Cc: stable@dpdk.org > > Signed-off-by: Robin Jarry <rjarry@redhat.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> Thanks for the fix Robin, series applied. -- David Marchand ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2024-10-15 8:39 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <20241002155709.2522273-1-david.marchand@redhat.com> 2024-10-02 15:57 ` [PATCH 2/2] ethdev: fix race on ports for telemetry commands David Marchand 2024-10-02 16:27 ` Bruce Richardson 2024-10-02 19:06 ` David Marchand 2024-10-02 19:09 ` Robin Jarry 2024-10-02 19:18 ` David Marchand 2024-10-02 19:26 ` Robin Jarry 2024-10-03 9:46 ` Bruce Richardson 2024-10-03 9:58 ` David Marchand 2024-10-08 2:07 ` lihuisong (C) 2024-10-08 6:48 ` David Marchand 2024-10-03 11:24 ` [PATCH dpdk v2 2/2] ethdev: fix potential race in telemetry endpoints Robin Jarry 2024-10-03 11:39 ` Bruce Richardson [not found] ` <20241014193237.1992382-1-rjarry@redhat.com> 2024-10-14 19:32 ` [PATCH dpdk v3 " Robin Jarry 2024-10-14 20:01 ` Stephen Hemminger 2024-10-15 8:02 ` David Marchand 2024-10-15 8:04 ` Robin Jarry 2024-10-15 8:38 ` David Marchand
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).