[v4,1/1] ethdev: parsing multiple representor devargs string

Message ID 20240121191908.156149-2-hkalra@marvell.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series multiple representors in one device |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/github-robot: build success github build: passed
ci/iol-broadcom-Functional success Functional Testing PASS
ci/intel-Functional success Functional PASS
ci/iol-abi-testing success Testing PASS
ci/iol-compile-amd64-testing success Testing PASS
ci/iol-unit-amd64-testing success Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-sample-apps-testing success Testing PASS
ci/iol-unit-arm64-testing success Testing PASS
ci/iol-compile-arm64-testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS

Commit Message

Harman Kalra Jan. 21, 2024, 7:19 p.m. UTC
  Adding support for parsing multiple representor devargs strings
passed to a PCI BDF. There may be scenario where port representors
for various PFs or VFs under PFs are required and all these are
representor ports shall be backed by single pci device. In such
case port representors can be created using devargs string:
<PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]

Signed-off-by: Harman Kalra <hkalra@marvell.com>
---
 doc/guides/prog_guide/poll_mode_drv.rst       |   4 +-
 .../prog_guide/switch_representation.rst      |   1 +
 drivers/net/bnxt/bnxt_ethdev.c                |   4 +-
 drivers/net/enic/enic_ethdev.c                |   4 +-
 drivers/net/i40e/i40e_ethdev.c                |   4 +-
 drivers/net/ice/ice_dcf_ethdev.c              |   4 +-
 drivers/net/ixgbe/ixgbe_ethdev.c              |   4 +-
 drivers/net/mlx5/linux/mlx5_os.c              |   8 +-
 .../net/nfp/flower/nfp_flower_representor.c   |   4 +-
 drivers/net/sfc/sfc_ethdev.c                  |   4 +-
 lib/ethdev/ethdev_driver.c                    | 108 +++++++++++++++---
 lib/ethdev/ethdev_driver.h                    |   9 +-
 12 files changed, 122 insertions(+), 36 deletions(-)
  

Comments

Chaoyong He Jan. 22, 2024, 1:13 a.m. UTC | #1
> -----Original Message-----
> From: Harman Kalra <hkalra@marvell.com>
> Sent: Monday, January 22, 2024 3:19 AM
> To: dev@dpdk.org; Thomas Monjalon <thomas@monjalon.net>; Ferruh Yigit
> <ferruh.yigit@amd.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
> <ajit.khaparde@broadcom.com>; Somnath Kotur
> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>; Hyong
> Youb Kim <hyonkim@cisco.com>; Yuying Zhang <Yuying.Zhang@intel.com>;
> Beilei Xing <beilei.xing@intel.com>; Qiming Yang <qiming.yang@intel.com>; Qi
> Zhang <qi.z.zhang@intel.com>; Wenjun Wu <wenjun1.wu@intel.com>;
> Dariusz Sosnowski <dsosnowski@nvidia.com>; Viacheslav Ovsiienko
> <viacheslavo@nvidia.com>; Ori Kam <orika@nvidia.com>; Suanming Mou
> <suanmingm@nvidia.com>; Matan Azrad <matan@nvidia.com>; Chaoyong
> He <chaoyong.he@corigine.com>
> Cc: Harman Kalra <hkalra@marvell.com>
> Subject: [PATCH v4 1/1] ethdev: parsing multiple representor devargs string
> 
> [You don't often get email from hkalra@marvell.com. Learn why this is
> important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> Adding support for parsing multiple representor devargs strings passed to a
> PCI BDF. There may be scenario where port representors for various PFs or VFs
> under PFs are required and all these are representor ports shall be backed by
> single pci device. In such case port representors can be created using devargs
> string:
> <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
> 
> Signed-off-by: Harman Kalra <hkalra@marvell.com>
> ---
>  doc/guides/prog_guide/poll_mode_drv.rst       |   4 +-
>  .../prog_guide/switch_representation.rst      |   1 +
>  drivers/net/bnxt/bnxt_ethdev.c                |   4 +-
>  drivers/net/enic/enic_ethdev.c                |   4 +-
>  drivers/net/i40e/i40e_ethdev.c                |   4 +-
>  drivers/net/ice/ice_dcf_ethdev.c              |   4 +-
>  drivers/net/ixgbe/ixgbe_ethdev.c              |   4 +-
>  drivers/net/mlx5/linux/mlx5_os.c              |   8 +-
>  .../net/nfp/flower/nfp_flower_representor.c   |   4 +-
>  drivers/net/sfc/sfc_ethdev.c                  |   4 +-
>  lib/ethdev/ethdev_driver.c                    | 108 +++++++++++++++---
>  lib/ethdev/ethdev_driver.h                    |   9 +-
>  12 files changed, 122 insertions(+), 36 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/poll_mode_drv.rst
> b/doc/guides/prog_guide/poll_mode_drv.rst
> index c145a9066c..5008b41c60 100644
> --- a/doc/guides/prog_guide/poll_mode_drv.rst
> +++ b/doc/guides/prog_guide/poll_mode_drv.rst
> @@ -376,7 +376,7 @@ parameters to those ports.
> 
>  * ``representor`` for a device which supports the creation of representor ports
>    this argument allows user to specify which switch ports to enable port
> -  representors for. Multiple representors in one device argument is invalid::
> +  representors for::
> 
>     -a DBDF,representor=vf0
>     -a DBDF,representor=vf[0,4,6,9]
> @@ -389,6 +389,8 @@ parameters to those ports.
>     -a DBDF,representor=pf1vf0
>     -a DBDF,representor=pf[0-1]sf[0-127]
>     -a DBDF,representor=pf1
> +   -a DBDF,representor=[pf[0-1],pf2vf[0-2],pf3[3,5-8]]
> +   (Multiple representors in one device argument can be represented as
> + a list)
> 
>  Note: PMDs are not required to support the standard device arguments and
> users  should consult the relevant PMD documentation to see support
> devargs.
> diff --git a/doc/guides/prog_guide/switch_representation.rst
> b/doc/guides/prog_guide/switch_representation.rst
> index 6fd7b98bdc..46e0ca85a5 100644
> --- a/doc/guides/prog_guide/switch_representation.rst
> +++ b/doc/guides/prog_guide/switch_representation.rst
> @@ -77,6 +77,7 @@ thought as a software "patch panel" front-end for
> applications.
>     -a pci:dbdf,representor=sf1
>     -a pci:dbdf,representor=sf[0-1023]
>     -a pci:dbdf,representor=sf[0,2-1023]
> +   -a pci:dbdf,representor=[pf[0-1],pf2vf[0-2],pf3[3,5]]
> 
>  - As virtual devices, they may be more limited than their physical
>    counterparts, for instance by exposing only a subset of device diff --git
> a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c index
> acf7e6e46e..5d4f599044 100644
> --- a/drivers/net/bnxt/bnxt_ethdev.c
> +++ b/drivers/net/bnxt/bnxt_ethdev.c
> @@ -6383,8 +6383,8 @@ static int bnxt_pci_probe(struct rte_pci_driver
> *pci_drv __rte_unused,
> 
>         if (pci_dev->device.devargs) {
>                 ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> -                                           &eth_da);
> -               if (ret)
> +                                           &eth_da, 1);
> +               if (ret < 0)
>                         return ret;
>         }
> 
...
> a/drivers/net/nfp/flower/nfp_flower_representor.c
> b/drivers/net/nfp/flower/nfp_flower_representor.c
> index 5f7c1fa737..63fe37c8d7 100644
> --- a/drivers/net/nfp/flower/nfp_flower_representor.c
> +++ b/drivers/net/nfp/flower/nfp_flower_representor.c
> @@ -792,8 +792,8 @@ nfp_flower_repr_create(struct nfp_app_fw_flower
> *app_fw_flower)
> 
>         /* Now parse PCI device args passed for representor info */
>         if (pci_dev->device.devargs != NULL) {
> -               ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da);
> -               if (ret != 0) {
> +               ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da, 1);
> +               if (ret < 0) {
>                         PMD_INIT_LOG(ERR, "devarg parse failed");
>                         return -EINVAL;
>                 }

Sorry, I don't quite understand why change 'ret != 0' to 'ret < 0'?
Compare return value with 0 or NULL is the specification for our PMD, we prefer not to change it if don't have a good reason.
Thanks.

> --
> 2.18.0
  
Harman Kalra Jan. 22, 2024, 9:07 a.m. UTC | #2
Hi Chaoyong,

Please see responses inline


<snip>

> >                         return ret;
> >         }
> >
> ...
> > a/drivers/net/nfp/flower/nfp_flower_representor.c
> > b/drivers/net/nfp/flower/nfp_flower_representor.c
> > index 5f7c1fa737..63fe37c8d7 100644
> > --- a/drivers/net/nfp/flower/nfp_flower_representor.c
> > +++ b/drivers/net/nfp/flower/nfp_flower_representor.c
> > @@ -792,8 +792,8 @@ nfp_flower_repr_create(struct nfp_app_fw_flower
> > *app_fw_flower)
> >
> >         /* Now parse PCI device args passed for representor info */
> >         if (pci_dev->device.devargs != NULL) {
> > -               ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> > &eth_da);
> > -               if (ret != 0) {
> > +               ret =
> > + rte_eth_devargs_parse(pci_dev->device.devargs->args,
> > &eth_da, 1);
> > +               if (ret < 0) {
> >                         PMD_INIT_LOG(ERR, "devarg parse failed");
> >                         return -EINVAL;
> >                 }
> 
> Sorry, I don't quite understand why change 'ret != 0' to 'ret < 0'?
> Compare return value with 0 or NULL is the specification for our PMD, we
> prefer not to change it if don't have a good reason.
> Thanks.

To support multiple representors under one PCI BDF, "eth_devargs args" parameter
passed to rte_eth_devargs_parse() is now an array which gets populated with multiple
"struct rte_eth_devargs" elements viz different pfvf representor devargs. 

We are proposing a change to the return value of this API, I.e. negative means error condition
and positive value refers to no of "struct rte_eth_devargs" elements populated. So it can't be
zero, else we wont know how many elements were populated in the array.

Thanks
Harman

> 
> > --
> > 2.18.0
  
Chaoyong He Jan. 22, 2024, 10:10 a.m. UTC | #3
> 
> Hi Chaoyong,
> 
> Please see responses inline
> 
> 
> <snip>
> 
> > >                         return ret;
> > >         }
> > >
> > ...
> > > a/drivers/net/nfp/flower/nfp_flower_representor.c
> > > b/drivers/net/nfp/flower/nfp_flower_representor.c
> > > index 5f7c1fa737..63fe37c8d7 100644
> > > --- a/drivers/net/nfp/flower/nfp_flower_representor.c
> > > +++ b/drivers/net/nfp/flower/nfp_flower_representor.c
> > > @@ -792,8 +792,8 @@ nfp_flower_repr_create(struct
> nfp_app_fw_flower
> > > *app_fw_flower)
> > >
> > >         /* Now parse PCI device args passed for representor info */
> > >         if (pci_dev->device.devargs != NULL) {
> > > -               ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> > > &eth_da);
> > > -               if (ret != 0) {
> > > +               ret =
> > > + rte_eth_devargs_parse(pci_dev->device.devargs->args,
> > > &eth_da, 1);
> > > +               if (ret < 0) {
> > >                         PMD_INIT_LOG(ERR, "devarg parse failed");
> > >                         return -EINVAL;
> > >                 }
> >
> > Sorry, I don't quite understand why change 'ret != 0' to 'ret < 0'?
> > Compare return value with 0 or NULL is the specification for our PMD,
> > we prefer not to change it if don't have a good reason.
> > Thanks.
> 
> To support multiple representors under one PCI BDF, "eth_devargs args"
> parameter passed to rte_eth_devargs_parse() is now an array which gets
> populated with multiple "struct rte_eth_devargs" elements viz different pfvf
> representor devargs.
> 
> We are proposing a change to the return value of this API, I.e. negative means
> error condition and positive value refers to no of "struct rte_eth_devargs"
> elements populated. So it can't be zero, else we wont know how many
> elements were populated in the array.
> 
> Thanks
> Harman
> 

Got it, thanks to make it clear.
Then it looks good to me.

> >
> > > --
> > > 2.18.0
  
Harman Kalra Jan. 25, 2024, 5:28 a.m. UTC | #4
Ping...
Request for review comments please.

Thanks
Harman

> -----Original Message-----
> From: Harman Kalra <hkalra@marvell.com>
> Sent: Monday, January 22, 2024 12:49 AM
> To: dev@dpdk.org; Thomas Monjalon <thomas@monjalon.net>; Ferruh Yigit
> <ferruh.yigit@amd.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
> <ajit.khaparde@broadcom.com>; Somnath Kotur
> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>;
> Hyong Youb Kim <hyonkim@cisco.com>; Yuying Zhang
> <Yuying.Zhang@intel.com>; Beilei Xing <beilei.xing@intel.com>; Qiming Yang
> <qiming.yang@intel.com>; Qi Zhang <qi.z.zhang@intel.com>; Wenjun Wu
> <wenjun1.wu@intel.com>; Dariusz Sosnowski <dsosnowski@nvidia.com>;
> Viacheslav Ovsiienko <viacheslavo@nvidia.com>; Ori Kam
> <orika@nvidia.com>; Suanming Mou <suanmingm@nvidia.com>; Matan
> Azrad <matan@nvidia.com>; Chaoyong He <chaoyong.he@corigine.com>
> Cc: Harman Kalra <hkalra@marvell.com>
> Subject: [PATCH v4 1/1] ethdev: parsing multiple representor devargs string
> 
> Adding support for parsing multiple representor devargs strings passed to a
> PCI BDF. There may be scenario where port representors for various PFs or
> VFs under PFs are required and all these are representor ports shall be
> backed by single pci device. In such case port representors can be created
> using devargs string:
> <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
> 
> Signed-off-by: Harman Kalra <hkalra@marvell.com>
> ---
>  doc/guides/prog_guide/poll_mode_drv.rst       |   4 +-
>  .../prog_guide/switch_representation.rst      |   1 +
>  drivers/net/bnxt/bnxt_ethdev.c                |   4 +-
>  drivers/net/enic/enic_ethdev.c                |   4 +-
>  drivers/net/i40e/i40e_ethdev.c                |   4 +-
>  drivers/net/ice/ice_dcf_ethdev.c              |   4 +-
>  drivers/net/ixgbe/ixgbe_ethdev.c              |   4 +-
>  drivers/net/mlx5/linux/mlx5_os.c              |   8 +-
>  .../net/nfp/flower/nfp_flower_representor.c   |   4 +-
>  drivers/net/sfc/sfc_ethdev.c                  |   4 +-
>  lib/ethdev/ethdev_driver.c                    | 108 +++++++++++++++---
>  lib/ethdev/ethdev_driver.h                    |   9 +-
>  12 files changed, 122 insertions(+), 36 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/poll_mode_drv.rst
> b/doc/guides/prog_guide/poll_mode_drv.rst
> index c145a9066c..5008b41c60 100644
> --- a/doc/guides/prog_guide/poll_mode_drv.rst
> +++ b/doc/guides/prog_guide/poll_mode_drv.rst
> @@ -376,7 +376,7 @@ parameters to those ports.
> 
>  * ``representor`` for a device which supports the creation of representor
> ports
>    this argument allows user to specify which switch ports to enable port
> -  representors for. Multiple representors in one device argument is invalid::
> +  representors for::
> 
>     -a DBDF,representor=vf0
>     -a DBDF,representor=vf[0,4,6,9]
> @@ -389,6 +389,8 @@ parameters to those ports.
>     -a DBDF,representor=pf1vf0
>     -a DBDF,representor=pf[0-1]sf[0-127]
>     -a DBDF,representor=pf1
> +   -a DBDF,representor=[pf[0-1],pf2vf[0-2],pf3[3,5-8]]
> +   (Multiple representors in one device argument can be represented as
> + a list)
> 
>  Note: PMDs are not required to support the standard device arguments and
> users  should consult the relevant PMD documentation to see support
> devargs.
> diff --git a/doc/guides/prog_guide/switch_representation.rst
> b/doc/guides/prog_guide/switch_representation.rst
> index 6fd7b98bdc..46e0ca85a5 100644
> --- a/doc/guides/prog_guide/switch_representation.rst
> +++ b/doc/guides/prog_guide/switch_representation.rst
> @@ -77,6 +77,7 @@ thought as a software "patch panel" front-end for
> applications.
>     -a pci:dbdf,representor=sf1
>     -a pci:dbdf,representor=sf[0-1023]
>     -a pci:dbdf,representor=sf[0,2-1023]
> +   -a pci:dbdf,representor=[pf[0-1],pf2vf[0-2],pf3[3,5]]
> 
>  - As virtual devices, they may be more limited than their physical
>    counterparts, for instance by exposing only a subset of device diff --git
> a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c index
> acf7e6e46e..5d4f599044 100644
> --- a/drivers/net/bnxt/bnxt_ethdev.c
> +++ b/drivers/net/bnxt/bnxt_ethdev.c
> @@ -6383,8 +6383,8 @@ static int bnxt_pci_probe(struct rte_pci_driver
> *pci_drv __rte_unused,
> 
>  	if (pci_dev->device.devargs) {
>  		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> -					    &eth_da);
> -		if (ret)
> +					    &eth_da, 1);
> +		if (ret < 0)
>  			return ret;
>  	}
> 
> diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
> index b04b6c9aa1..33d96ec07a 100644
> --- a/drivers/net/enic/enic_ethdev.c
> +++ b/drivers/net/enic/enic_ethdev.c
> @@ -1317,8 +1317,8 @@ static int eth_enic_pci_probe(struct rte_pci_driver
> *pci_drv __rte_unused,
>  	ENICPMD_FUNC_TRACE();
>  	if (pci_dev->device.devargs) {
>  		retval = rte_eth_devargs_parse(pci_dev->device.devargs-
> >args,
> -				&eth_da);
> -		if (retval)
> +				&eth_da, 1);
> +		if (retval < 0)
>  			return retval;
>  	}
>  	if (eth_da.nb_representor_ports > 0 && diff --git
> a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index
> 3ca226156b..4d21341382 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -646,8 +646,8 @@ eth_i40e_pci_probe(struct rte_pci_driver *pci_drv
> __rte_unused,
> 
>  	if (pci_dev->device.devargs) {
>  		retval = rte_eth_devargs_parse(pci_dev->device.devargs-
> >args,
> -				&eth_da);
> -		if (retval)
> +				&eth_da, 1);
> +		if (retval < 0)
>  			return retval;
>  	}
> 
> diff --git a/drivers/net/ice/ice_dcf_ethdev.c
> b/drivers/net/ice/ice_dcf_ethdev.c
> index 5d845bba31..0e991fe4b8 100644
> --- a/drivers/net/ice/ice_dcf_ethdev.c
> +++ b/drivers/net/ice/ice_dcf_ethdev.c
> @@ -2041,8 +2041,8 @@ eth_ice_dcf_pci_probe(__rte_unused struct
> rte_pci_driver *pci_drv,
>  	if (!ice_devargs_check(pci_dev->device.devargs,
> ICE_DCF_DEVARG_CAP))
>  		return 1;
> 
> -	ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da);
> -	if (ret)
> +	ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da, 1);
> +	if (ret < 0)
>  		return ret;
> 
>  	ret = rte_eth_dev_pci_generic_probe(pci_dev,
> diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c
> b/drivers/net/ixgbe/ixgbe_ethdev.c
> index d6cf00317e..98e9b8a031 100644
> --- a/drivers/net/ixgbe/ixgbe_ethdev.c
> +++ b/drivers/net/ixgbe/ixgbe_ethdev.c
> @@ -1765,8 +1765,8 @@ eth_ixgbe_pci_probe(struct rte_pci_driver
> *pci_drv __rte_unused,
> 
>  	if (pci_dev->device.devargs) {
>  		retval = rte_eth_devargs_parse(pci_dev->device.devargs-
> >args,
> -				&eth_da);
> -		if (retval)
> +				&eth_da, 1);
> +		if (retval < 0)
>  			return retval;
>  	} else
>  		memset(&eth_da, 0, sizeof(eth_da));
> diff --git a/drivers/net/mlx5/linux/mlx5_os.c
> b/drivers/net/mlx5/linux/mlx5_os.c
> index ae82e1e5d8..17061126d5 100644
> --- a/drivers/net/mlx5/linux/mlx5_os.c
> +++ b/drivers/net/mlx5/linux/mlx5_os.c
> @@ -2733,16 +2733,16 @@ mlx5_os_parse_eth_devargs(struct rte_device
> *dev,
>  	memset(eth_da, 0, sizeof(*eth_da));
>  	/* Parse representor information first from class argument. */
>  	if (dev->devargs->cls_str)
> -		ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da);
> -	if (ret != 0) {
> +		ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da,
> 1);
> +	if (ret < 0) {
>  		DRV_LOG(ERR, "failed to parse device arguments: %s",
>  			dev->devargs->cls_str);
>  		return -rte_errno;
>  	}
>  	if (eth_da->type == RTE_ETH_REPRESENTOR_NONE && dev-
> >devargs->args) {
>  		/* Parse legacy device argument */
> -		ret = rte_eth_devargs_parse(dev->devargs->args, eth_da);
> -		if (ret) {
> +		ret = rte_eth_devargs_parse(dev->devargs->args, eth_da, 1);
> +		if (ret < 0) {
>  			DRV_LOG(ERR, "failed to parse device arguments:
> %s",
>  				dev->devargs->args);
>  			return -rte_errno;
> diff --git a/drivers/net/nfp/flower/nfp_flower_representor.c
> b/drivers/net/nfp/flower/nfp_flower_representor.c
> index 5f7c1fa737..63fe37c8d7 100644
> --- a/drivers/net/nfp/flower/nfp_flower_representor.c
> +++ b/drivers/net/nfp/flower/nfp_flower_representor.c
> @@ -792,8 +792,8 @@ nfp_flower_repr_create(struct nfp_app_fw_flower
> *app_fw_flower)
> 
>  	/* Now parse PCI device args passed for representor info */
>  	if (pci_dev->device.devargs != NULL) {
> -		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da);
> -		if (ret != 0) {
> +		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
> &eth_da, 1);
> +		if (ret < 0) {
>  			PMD_INIT_LOG(ERR, "devarg parse failed");
>  			return -EINVAL;
>  		}
> diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c index
> 6d57b2ba26..0bbcb80365 100644
> --- a/drivers/net/sfc/sfc_ethdev.c
> +++ b/drivers/net/sfc/sfc_ethdev.c
> @@ -3305,8 +3305,8 @@ sfc_parse_rte_devargs(const char *args, struct
> rte_eth_devargs *devargs)
>  	int rc;
> 
>  	if (args != NULL) {
> -		rc = rte_eth_devargs_parse(args, &eth_da);
> -		if (rc != 0) {
> +		rc = rte_eth_devargs_parse(args, &eth_da, 1);
> +		if (rc < 0) {
>  			SFC_GENERIC_LOG(ERR,
>  					"Failed to parse generic devargs '%s'",
>  					args);
> diff --git a/lib/ethdev/ethdev_driver.c b/lib/ethdev/ethdev_driver.c index
> bd917a15fc..4c0d22f838 100644
> --- a/lib/ethdev/ethdev_driver.c
> +++ b/lib/ethdev/ethdev_driver.c
> @@ -2,6 +2,7 @@
>   * Copyright(c) 2022 Intel Corporation
>   */
> 
> +#include <ctype.h>
>  #include <stdlib.h>
>  #include <pthread.h>
> 
> @@ -459,9 +460,26 @@ eth_dev_devargs_tokenise(struct rte_kvargs
> *arglist, const char *str_in)
>  			break;
> 
>  		case 3: /* Parsing list */
> -			if (*letter == ']')
> -				state = 2;
> -			else if (*letter == '\0')
> +			if (*letter == ']') {
> +				/* For devargs having singles lists move to
> state 2 once letter
> +				 * becomes ']' so each can be considered as
> different pair key
> +				 * value. But in nested lists case e.g. multiple
> representors
> +				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete
> nested list should
> +				 * be considered as one pair value, hence
> checking if end of outer
> +				 * list ']' is reached else stay on state 3.
> +				 */
> +				if ((strcmp("representor", pair->key) == 0)
> 	    &&
> +				    (*(letter + 1) != '\0' && *(letter + 2) != '\0'
> &&
> +				     *(letter + 3) != '\0')			    &&
> +				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f')
> ||
> +				     (*(letter + 2) == 'v' && *(letter + 3) == 'f') ||
> +				     (*(letter + 2) == 's' && *(letter + 3) == 'f') ||
> +				     (*(letter + 2) == 'c' && isdigit(*(letter + 3)))
> ||
> +				     (*(letter + 2) == '[' && isdigit(*(letter +
> 3)))))
> +					state = 3;
> +				else
> +					state = 2;
> +			} else if (*letter == '\0')
>  				return -EINVAL;
>  			break;
>  		}
> @@ -469,16 +487,56 @@ eth_dev_devargs_tokenise(struct rte_kvargs
> *arglist, const char *str_in)
>  	}
>  }
> 
> +static int
> +eth_dev_tokenise_representor_list(char *p_val, struct rte_eth_devargs
> *eth_devargs,
> +				  unsigned int nb_da)
> +{
> +	struct rte_eth_devargs *eth_da;
> +	char da_val[BUFSIZ];
> +	char *token, *sptr;
> +	char delim[] = "]";
> +	int devargs = 0;
> +	int result = 0;
> +
> +	token = strtok_r(&p_val[1], delim, &sptr);
> +	while (token != NULL) {
> +		eth_da = &eth_devargs[devargs];
> +		memset(eth_da, 0, sizeof(*eth_da));
> +		snprintf(da_val, BUFSIZ, "%s%c", (token[0] == ',') ? ++token :
> token, ']');
> +		/* Parse the tokenised devarg value */
> +		result = rte_eth_devargs_parse_representor_ports(da_val,
> eth_da);
> +		if (result < 0)
> +			goto parse_cleanup;
> +		devargs++;
> +		if (devargs > (int)nb_da) {
> +			RTE_ETHDEV_LOG_LINE(ERR,
> +					    "Devargs parsed %d > max array
> size %d",
> +					    devargs, nb_da);
> +			result = -1;
> +			goto parse_cleanup;
> +		}
> +		token = strtok_r(NULL, delim, &sptr);
> +	}
> +
> +	result = devargs;
> +
> +parse_cleanup:
> +	return result;
> +
> +}
> +
>  int
> -rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_da)
> +rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs
> *eth_devargs,
> +		      unsigned int nb_da)
>  {
> -	struct rte_kvargs args;
> +	struct rte_eth_devargs *eth_da;
>  	struct rte_kvargs_pair *pair;
> +	struct rte_kvargs args;
> +	static bool dup_rep;
> +	int devargs = 0;
>  	unsigned int i;
>  	int result = 0;
> 
> -	memset(eth_da, 0, sizeof(*eth_da));
> -
>  	result = eth_dev_devargs_tokenise(&args, dargs);
>  	if (result < 0)
>  		goto parse_cleanup;
> @@ -486,18 +544,40 @@ rte_eth_devargs_parse(const char *dargs, struct
> rte_eth_devargs *eth_da)
>  	for (i = 0; i < args.count; i++) {
>  		pair = &args.pairs[i];
>  		if (strcmp("representor", pair->key) == 0) {
> -			if (eth_da->type != RTE_ETH_REPRESENTOR_NONE) {
> -				RTE_ETHDEV_LOG_LINE(ERR, "duplicated
> representor key: %s",
> -					dargs);
> +			if (dup_rep) {
> +				RTE_ETHDEV_LOG_LINE(ERR, "Duplicated
> representor key: %s",
> +						    pair->value);
>  				result = -1;
>  				goto parse_cleanup;
>  			}
> -			result = rte_eth_devargs_parse_representor_ports(
> -					pair->value, eth_da);
> -			if (result < 0)
> -				goto parse_cleanup;
> +
> +			if (pair->value[0] == '[' && !isdigit(pair->value[1])) {
> +				/* Multiple representor list case */
> +				devargs =
> eth_dev_tokenise_representor_list(pair->value,
> +
> eth_devargs, nb_da);
> +				if (devargs < 0)
> +					goto parse_cleanup;
> +			} else {
> +				/* Single representor case */
> +				eth_da = &eth_devargs[devargs];
> +				memset(eth_da, 0, sizeof(*eth_da));
> +				result =
> +
> 	rte_eth_devargs_parse_representor_ports(pair->value,
> +
> 	eth_da);
> +				if (result < 0)
> +					goto parse_cleanup;
> +				devargs++;
> +				if (devargs > (int)nb_da) {
> +					RTE_ETHDEV_LOG_LINE(ERR,
> "Devargs parsed %d > max array size %d",
> +							    devargs, nb_da);
> +					result = -1;
> +					goto parse_cleanup;
> +				}
> +			}
> +			dup_rep = true;
>  		}
>  	}
> +	result = devargs;
> 
>  parse_cleanup:
>  	free(args.str);
> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h index
> b482cd12bb..fd6f404e9a 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -1800,14 +1800,17 @@ rte_eth_representor_id_get(uint16_t port_id,
>   * @param devargs
>   *  device arguments
>   * @param eth_devargs
> - *  parsed ethdev specific arguments.
> + *  contiguous memory populated with parsed ethdev specific arguments.
> + * @param nb_da
> + *  size of eth_devargs array passed
>   *
>   * @return
> - *   Negative errno value on error, 0 on success.
> + *   Negative errno value on error, no of devargs parsed on success.
>   */
>  __rte_internal
>  int
> -rte_eth_devargs_parse(const char *devargs, struct rte_eth_devargs
> *eth_devargs);
> +rte_eth_devargs_parse(const char *devargs, struct rte_eth_devargs
> *eth_devargs,
> +		      unsigned int nb_da);
> 
> 
>  typedef int (*ethdev_init_t)(struct rte_eth_dev *ethdev, void *init_params);
> --
> 2.18.0
  
Ferruh Yigit Jan. 26, 2024, 1:43 p.m. UTC | #5
On 1/21/2024 7:19 PM, Harman Kalra wrote:
> Adding support for parsing multiple representor devargs strings
> passed to a PCI BDF. There may be scenario where port representors
> for various PFs or VFs under PFs are required and all these are
> representor ports shall be backed by single pci device. In such
> case port representors can be created using devargs string:
> <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
> 

This patch is to be able to parse multiple representor device argument,
but I am concerned how it is used.

When there are multiple representor ports backed up by same device,
can't it cause syncronization issues, like if two representor interfaces
used for conflicting configurations. Or if datapath will be supported,
what if two representator used simultaneously.



Meanwhile please check some comments below related to the parser code.

<...>

> @@ -459,9 +460,26 @@ eth_dev_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
>  			break;
>  
>  		case 3: /* Parsing list */
> -			if (*letter == ']')
> -				state = 2;
> -			else if (*letter == '\0')
> +			if (*letter == ']') {
> +				/* For devargs having singles lists move to state 2 once letter
> +				 * becomes ']' so each can be considered as different pair key
> +				 * value. But in nested lists case e.g. multiple representors
> +				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete nested list should
> +				 * be considered as one pair value, hence checking if end of outer
> +				 * list ']' is reached else stay on state 3.
> +				 */
> +				if ((strcmp("representor", pair->key) == 0)	    &&
> +				    (*(letter + 1) != '\0' && *(letter + 2) != '\0' &&
> +				     *(letter + 3) != '\0')			    &&
> +				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f') ||
> +				     (*(letter + 2) == 'v' && *(letter + 3) == 'f') ||
> +				     (*(letter + 2) == 's' && *(letter + 3) == 'f') ||
> +				     (*(letter + 2) == 'c' && isdigit(*(letter + 3))) ||
> +				     (*(letter + 2) == '[' && isdigit(*(letter + 3)))))
>

Above is hard to understand but there are some assumptions in the input,
can we list supported syntax in the comment to make it more clear.

For example following seems not support, can you please check if
intentional:
[vf0,vf1] // I am aware this can be put as vf[0,1] too
[vf[0,1],3]
[vf[0],vf[1]]

I am not saying above should be supported, but syntax should be clear
what is supported what is not.


Also I can't check but is the redundant input verified, like:
[vf[0-3],vf[3,4]]
  
Harman Kalra Jan. 29, 2024, 6:20 p.m. UTC | #6
Hi Ferruh

Thanks for the review
Please find response inline


> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Friday, January 26, 2024 7:13 PM
> To: Harman Kalra <hkalra@marvell.com>; dev@dpdk.org; Thomas Monjalon
> <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
> <ajit.khaparde@broadcom.com>; Somnath Kotur
> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>;
> Hyong Youb Kim <hyonkim@cisco.com>; Yuying Zhang
> <Yuying.Zhang@intel.com>; Beilei Xing <beilei.xing@intel.com>; Qiming Yang
> <qiming.yang@intel.com>; Qi Zhang <qi.z.zhang@intel.com>; Wenjun Wu
> <wenjun1.wu@intel.com>; Dariusz Sosnowski <dsosnowski@nvidia.com>;
> Viacheslav Ovsiienko <viacheslavo@nvidia.com>; Ori Kam
> <orika@nvidia.com>; Suanming Mou <suanmingm@nvidia.com>; Matan
> Azrad <matan@nvidia.com>; Chaoyong He <chaoyong.he@corigine.com>
> Subject: [EXT] Re: [PATCH v4 1/1] ethdev: parsing multiple representor
> devargs string
> 
> External Email
> 
> ----------------------------------------------------------------------
> On 1/21/2024 7:19 PM, Harman Kalra wrote:
> > Adding support for parsing multiple representor devargs strings passed
> > to a PCI BDF. There may be scenario where port representors for
> > various PFs or VFs under PFs are required and all these are
> > representor ports shall be backed by single pci device. In such case
> > port representors can be created using devargs string:
> > <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
> >
> 
> This patch is to be able to parse multiple representor device argument, but I
> am concerned how it is used.

In Marvell CNXK port representor solution all representors are backed by a single 
PCI device (we call it as eswitch device). Eswitch device is not DPDK ethdev device
but an internal device with NIC capabilities and is configured with as many no of
Rxqs and Txqs as port representor required.
Hence each port representor will have dedicated RxQ/TxQ pair to communicate with
respective represented PF or VF. 


> 
> When there are multiple representor ports backed up by same device, can't
> it cause syncronization issues, like if two representor interfaces used for
> conflicting configurations. Or if datapath will be supported, what if two
> representator used simultaneously.

As I mentioned above, each port representor will have dedicated RxQ and TxQ,
worker cores can poll on respective queues without any synchronization issue.
I hope I am able to explain the use case.

> 
> 




> 
> Meanwhile please check some comments below related to the parser code.
> 
> <...>
> 
> > @@ -459,9 +460,26 @@ eth_dev_devargs_tokenise(struct rte_kvargs
> *arglist, const char *str_in)
> >  			break;
> >
> >  		case 3: /* Parsing list */
> > -			if (*letter == ']')
> > -				state = 2;
> > -			else if (*letter == '\0')
> > +			if (*letter == ']') {
> > +				/* For devargs having singles lists move to
> state 2 once letter
> > +				 * becomes ']' so each can be considered as
> different pair key
> > +				 * value. But in nested lists case e.g. multiple
> representors
> > +				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete
> nested list should
> > +				 * be considered as one pair value, hence
> checking if end of outer
> > +				 * list ']' is reached else stay on state 3.
> > +				 */
> > +				if ((strcmp("representor", pair->key) == 0)
> 	    &&
> > +				    (*(letter + 1) != '\0' && *(letter + 2) != '\0'
> &&
> > +				     *(letter + 3) != '\0')			    &&
> > +				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f')
> ||
> > +				     (*(letter + 2) == 'v' && *(letter + 3) == 'f')
> ||
> > +				     (*(letter + 2) == 's' && *(letter + 3) == 'f')
> ||
> > +				     (*(letter + 2) == 'c' && isdigit(*(letter + 3)))
> ||
> > +				     (*(letter + 2) == '[' && isdigit(*(letter +
> 3)))))
> >
> 
> Above is hard to understand but there are some assumptions in the input,
> can we list supported syntax in the comment to make it more clear.
> 
> For example following seems not support, can you please check if
> intentional:
> [vf0,vf1] // I am aware this can be put as vf[0,1] too [vf[0,1],3] [vf[0],vf[1]]

Intention behind above change is just to detect if its nested list i.e. multiple
devargs (constituting lists as well) or a single devarg with a list.

pf0vf[1-4] is a single list devarg example, while [pf[0-3],pfvf[3,4-6]] is
nested list example, where multiple devargs pf[0-3] and pfvf[3,4-6]
(which are also lists) are bind to a list of devargs.

And as I mentioned in the comment, complete "nested list should be considered 
as one pair value", hence entire list i.e. [vf[0,1],3] [vf[0],vf[1]] will be one
value of arglist and later eth_dev_tokenise_representor_list() will tokenize
and feed to rte_eth_devargs_parse_representor_ports().

Whether any format is supported or not should be handled by 
rte_eth_devargs_parse_representor_ports()


> 
> I am not saying above should be supported, but syntax should be clear what
> is supported what is not.
> 
> 
> Also I can't check but is the redundant input verified, like:
> [vf[0-3],vf[3,4]]

IMO, this should be handled by PMD, if any representor already created should
return an error.

Thanks
Harman

>
  
Ferruh Yigit Jan. 30, 2024, 11:09 p.m. UTC | #7
On 1/29/2024 6:20 PM, Harman Kalra wrote:
> Hi Ferruh
> 
> Thanks for the review
> Please find response inline
> 
> 
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@amd.com>
>> Sent: Friday, January 26, 2024 7:13 PM
>> To: Harman Kalra <hkalra@marvell.com>; dev@dpdk.org; Thomas Monjalon
>> <thomas@monjalon.net>; Andrew Rybchenko
>> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
>> <ajit.khaparde@broadcom.com>; Somnath Kotur
>> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>;
>> Hyong Youb Kim <hyonkim@cisco.com>; Yuying Zhang
>> <Yuying.Zhang@intel.com>; Beilei Xing <beilei.xing@intel.com>; Qiming Yang
>> <qiming.yang@intel.com>; Qi Zhang <qi.z.zhang@intel.com>; Wenjun Wu
>> <wenjun1.wu@intel.com>; Dariusz Sosnowski <dsosnowski@nvidia.com>;
>> Viacheslav Ovsiienko <viacheslavo@nvidia.com>; Ori Kam
>> <orika@nvidia.com>; Suanming Mou <suanmingm@nvidia.com>; Matan
>> Azrad <matan@nvidia.com>; Chaoyong He <chaoyong.he@corigine.com>
>> Subject: [EXT] Re: [PATCH v4 1/1] ethdev: parsing multiple representor
>> devargs string
>>
>> External Email
>>
>> ----------------------------------------------------------------------
>> On 1/21/2024 7:19 PM, Harman Kalra wrote:
>>> Adding support for parsing multiple representor devargs strings passed
>>> to a PCI BDF. There may be scenario where port representors for
>>> various PFs or VFs under PFs are required and all these are
>>> representor ports shall be backed by single pci device. In such case
>>> port representors can be created using devargs string:
>>> <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
>>>
>>
>> This patch is to be able to parse multiple representor device argument, but I
>> am concerned how it is used.
> 
> In Marvell CNXK port representor solution all representors are backed by a single 
> PCI device (we call it as eswitch device). Eswitch device is not DPDK ethdev device
> but an internal device with NIC capabilities and is configured with as many no of
> Rxqs and Txqs as port representor required.
> Hence each port representor will have dedicated RxQ/TxQ pair to communicate with
> respective represented PF or VF. 
> 

ack, thanks for clarification.

Just to double check, is the cnxk driver support of new syntax planned
for this release?
It helps if the RFC is out before merging this patch.

> 
>>
>> When there are multiple representor ports backed up by same device, can't
>> it cause syncronization issues, like if two representor interfaces used for
>> conflicting configurations. Or if datapath will be supported, what if two
>> representator used simultaneously.
> 
> As I mentioned above, each port representor will have dedicated RxQ and TxQ,
> worker cores can poll on respective queues without any synchronization issue.
> I hope I am able to explain the use case.
> 

ack

>>
>>
> 
> 
> 
> 
>>
>> Meanwhile please check some comments below related to the parser code.
>>
>> <...>
>>
>>> @@ -459,9 +460,26 @@ eth_dev_devargs_tokenise(struct rte_kvargs
>> *arglist, const char *str_in)
>>>  			break;
>>>
>>>  		case 3: /* Parsing list */
>>> -			if (*letter == ']')
>>> -				state = 2;
>>> -			else if (*letter == '\0')
>>> +			if (*letter == ']') {
>>> +				/* For devargs having singles lists move to
>> state 2 once letter
>>> +				 * becomes ']' so each can be considered as
>> different pair key
>>> +				 * value. But in nested lists case e.g. multiple
>> representors
>>> +				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete
>> nested list should
>>> +				 * be considered as one pair value, hence
>> checking if end of outer
>>> +				 * list ']' is reached else stay on state 3.
>>> +				 */
>>> +				if ((strcmp("representor", pair->key) == 0)
>> 	    &&
>>> +				    (*(letter + 1) != '\0' && *(letter + 2) != '\0'
>> &&
>>> +				     *(letter + 3) != '\0')			    &&
>>> +				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f')
>> ||
>>> +				     (*(letter + 2) == 'v' && *(letter + 3) == 'f')
>> ||
>>> +				     (*(letter + 2) == 's' && *(letter + 3) == 'f')
>> ||
>>> +				     (*(letter + 2) == 'c' && isdigit(*(letter + 3)))
>> ||
>>> +				     (*(letter + 2) == '[' && isdigit(*(letter +
>> 3)))))
>>>
>>
>> Above is hard to understand but there are some assumptions in the input,
>> can we list supported syntax in the comment to make it more clear.
>>
>> For example following seems not support, can you please check if
>> intentional:
>> [vf0,vf1] // I am aware this can be put as vf[0,1] too [vf[0,1],3] [vf[0],vf[1]]
> 
> Intention behind above change is just to detect if its nested list i.e. multiple
> devargs (constituting lists as well) or a single devarg with a list.
> 
> pf0vf[1-4] is a single list devarg example, while [pf[0-3],pfvf[3,4-6]] is
> nested list example, where multiple devargs pf[0-3] and pfvf[3,4-6]
> (which are also lists) are bind to a list of devargs.
> 
> And as I mentioned in the comment, complete "nested list should be considered 
> as one pair value", hence entire list i.e. [vf[0,1],3] [vf[0],vf[1]] will be one
> value of arglist and later eth_dev_tokenise_representor_list() will tokenize
> and feed to rte_eth_devargs_parse_representor_ports().
> 
> Whether any format is supported or not should be handled by 
> rte_eth_devargs_parse_representor_ports()
> 

Agree but this is something user facing, user should know the syntax to
use it but some corner cases are not documented well and not trivial to
grasp from above code.

What do you think about adding some unit tests for parser, it can be
some pointer to the intention of what should be supported and what not,
also increases our confidence to the code?

> 
>>
>> I am not saying above should be supported, but syntax should be clear what
>> is supported what is not.
>>
>>
>> Also I can't check but is the redundant input verified, like:
>> [vf[0-3],vf[3,4]]
> 
> IMO, this should be handled by PMD, if any representor already created should
> return an error.
> 

fair enough
  
Harman Kalra Feb. 1, 2024, 10:10 a.m. UTC | #8
Hi Ferruh

Please find response inline

> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Wednesday, January 31, 2024 4:40 AM
> To: Harman Kalra <hkalra@marvell.com>; dev@dpdk.org; Thomas Monjalon
> <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
> <ajit.khaparde@broadcom.com>; Somnath Kotur
> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>; Hyong
> Youb Kim <hyonkim@cisco.com>; Yuying Zhang <Yuying.Zhang@intel.com>;
> Beilei Xing <beilei.xing@intel.com>; Qiming Yang <qiming.yang@intel.com>; Qi
> Zhang <qi.z.zhang@intel.com>; Wenjun Wu <wenjun1.wu@intel.com>;
> Dariusz Sosnowski <dsosnowski@nvidia.com>; Viacheslav Ovsiienko
> <viacheslavo@nvidia.com>; Ori Kam <orika@nvidia.com>; Suanming Mou
> <suanmingm@nvidia.com>; Matan Azrad <matan@nvidia.com>; Chaoyong
> He <chaoyong.he@corigine.com>
> Subject: Re: [EXT] Re: [PATCH v4 1/1] ethdev: parsing multiple representor
> devargs string
> 
> On 1/29/2024 6:20 PM, Harman Kalra wrote:
> > Hi Ferruh
> >
> > Thanks for the review
> > Please find response inline
> >
> >
> >> -----Original Message-----
> >> From: Ferruh Yigit <ferruh.yigit@amd.com>
> >> Sent: Friday, January 26, 2024 7:13 PM
> >> To: Harman Kalra <hkalra@marvell.com>; dev@dpdk.org; Thomas
> Monjalon
> >> <thomas@monjalon.net>; Andrew Rybchenko
> >> <andrew.rybchenko@oktetlabs.ru>; Ajit Khaparde
> >> <ajit.khaparde@broadcom.com>; Somnath Kotur
> >> <somnath.kotur@broadcom.com>; John Daley <johndale@cisco.com>;
> Hyong
> >> Youb Kim <hyonkim@cisco.com>; Yuying Zhang
> <Yuying.Zhang@intel.com>;
> >> Beilei Xing <beilei.xing@intel.com>; Qiming Yang
> >> <qiming.yang@intel.com>; Qi Zhang <qi.z.zhang@intel.com>; Wenjun Wu
> >> <wenjun1.wu@intel.com>; Dariusz Sosnowski <dsosnowski@nvidia.com>;
> >> Viacheslav Ovsiienko <viacheslavo@nvidia.com>; Ori Kam
> >> <orika@nvidia.com>; Suanming Mou <suanmingm@nvidia.com>; Matan
> Azrad
> >> <matan@nvidia.com>; Chaoyong He <chaoyong.he@corigine.com>
> >> Subject: [EXT] Re: [PATCH v4 1/1] ethdev: parsing multiple
> >> representor devargs string
> >>
> >> External Email
> >>
> >> ---------------------------------------------------------------------
> >> - On 1/21/2024 7:19 PM, Harman Kalra wrote:
> >>> Adding support for parsing multiple representor devargs strings
> >>> passed to a PCI BDF. There may be scenario where port representors
> >>> for various PFs or VFs under PFs are required and all these are
> >>> representor ports shall be backed by single pci device. In such case
> >>> port representors can be created using devargs string:
> >>> <PCI BDF>,representor=[pf[0-1],pf2vf[1,2-3],[4-5]]
> >>>
> >>
> >> This patch is to be able to parse multiple representor device
> >> argument, but I am concerned how it is used.
> >
> > In Marvell CNXK port representor solution all representors are backed
> > by a single PCI device (we call it as eswitch device). Eswitch device
> > is not DPDK ethdev device but an internal device with NIC capabilities
> > and is configured with as many no of Rxqs and Txqs as port representor
> required.
> > Hence each port representor will have dedicated RxQ/TxQ pair to
> > communicate with respective represented PF or VF.
> >
> 
> ack, thanks for clarification.
> 
> Just to double check, is the cnxk driver support of new syntax planned for this
> release?
> It helps if the RFC is out before merging this patch.
 
Yes, it is planned for this release. We have already pushed 2 versions and received
comments. V3 is ready with all V2 comments addressed, I will push by EOD.


> 
> >
> >>
> >> When there are multiple representor ports backed up by same device,
> >> can't it cause syncronization issues, like if two representor
> >> interfaces used for conflicting configurations. Or if datapath will
> >> be supported, what if two representator used simultaneously.
> >
> > As I mentioned above, each port representor will have dedicated RxQ
> > and TxQ, worker cores can poll on respective queues without any
> synchronization issue.
> > I hope I am able to explain the use case.
> >
> 
> ack
> 
> >>
> >>
> >
> >
> >
> >
> >>
> >> Meanwhile please check some comments below related to the parser code.
> >>
> >> <...>
> >>
> >>> @@ -459,9 +460,26 @@ eth_dev_devargs_tokenise(struct rte_kvargs
> >> *arglist, const char *str_in)
> >>>  			break;
> >>>
> >>>  		case 3: /* Parsing list */
> >>> -			if (*letter == ']')
> >>> -				state = 2;
> >>> -			else if (*letter == '\0')
> >>> +			if (*letter == ']') {
> >>> +				/* For devargs having singles lists move to
> >> state 2 once letter
> >>> +				 * becomes ']' so each can be considered as
> >> different pair key
> >>> +				 * value. But in nested lists case e.g. multiple
> >> representors
> >>> +				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete
> >> nested list should
> >>> +				 * be considered as one pair value, hence
> >> checking if end of outer
> >>> +				 * list ']' is reached else stay on state 3.
> >>> +				 */
> >>> +				if ((strcmp("representor", pair->key) == 0)
> >> 	    &&
> >>> +				    (*(letter + 1) != '\0' && *(letter + 2) != '\0'
> >> &&
> >>> +				     *(letter + 3) != '\0')			    &&
> >>> +				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f')
> >> ||
> >>> +				     (*(letter + 2) == 'v' && *(letter + 3) == 'f')
> >> ||
> >>> +				     (*(letter + 2) == 's' && *(letter + 3) == 'f')
> >> ||
> >>> +				     (*(letter + 2) == 'c' && isdigit(*(letter + 3)))
> >> ||
> >>> +				     (*(letter + 2) == '[' && isdigit(*(letter +
> >> 3)))))
> >>>
> >>
> >> Above is hard to understand but there are some assumptions in the
> >> input, can we list supported syntax in the comment to make it more clear.
> >>
> >> For example following seems not support, can you please check if
> >> intentional:
> >> [vf0,vf1] // I am aware this can be put as vf[0,1] too [vf[0,1],3]
> >> [vf[0],vf[1]]
> >
> > Intention behind above change is just to detect if its nested list
> > i.e. multiple devargs (constituting lists as well) or a single devarg with a list.
> >
> > pf0vf[1-4] is a single list devarg example, while
> > [pf[0-3],pfvf[3,4-6]] is nested list example, where multiple devargs
> > pf[0-3] and pfvf[3,4-6] (which are also lists) are bind to a list of devargs.
> >
> > And as I mentioned in the comment, complete "nested list should be
> > considered as one pair value", hence entire list i.e. [vf[0,1],3]
> > [vf[0],vf[1]] will be one value of arglist and later
> > eth_dev_tokenise_representor_list() will tokenize and feed to
> rte_eth_devargs_parse_representor_ports().
> >
> > Whether any format is supported or not should be handled by
> > rte_eth_devargs_parse_representor_ports()
> >
> 
> Agree but this is something user facing, user should know the syntax to
> use it but some corner cases are not documented well and not trivial to
> grasp from above code.
> 
> What do you think about adding some unit tests for parser, it can be
> some pointer to the intention of what should be supported and what not,
> also increases our confidence to the code?

Thanks for the suggestion, I have updated devargs UT with valid/invalid devarg
patterns. Kindly review V5. I tried to cover most of the use case, please let me
know if any important case I missed.

Thanks
Harman


> 
> >
> >>
> >> I am not saying above should be supported, but syntax should be clear
> what
> >> is supported what is not.
> >>
> >>
> >> Also I can't check but is the redundant input verified, like:
> >> [vf[0-3],vf[3,4]]
> >
> > IMO, this should be handled by PMD, if any representor already created
> should
> > return an error.
> >
> 
> fair enough
  

Patch

diff --git a/doc/guides/prog_guide/poll_mode_drv.rst b/doc/guides/prog_guide/poll_mode_drv.rst
index c145a9066c..5008b41c60 100644
--- a/doc/guides/prog_guide/poll_mode_drv.rst
+++ b/doc/guides/prog_guide/poll_mode_drv.rst
@@ -376,7 +376,7 @@  parameters to those ports.
 
 * ``representor`` for a device which supports the creation of representor ports
   this argument allows user to specify which switch ports to enable port
-  representors for. Multiple representors in one device argument is invalid::
+  representors for::
 
    -a DBDF,representor=vf0
    -a DBDF,representor=vf[0,4,6,9]
@@ -389,6 +389,8 @@  parameters to those ports.
    -a DBDF,representor=pf1vf0
    -a DBDF,representor=pf[0-1]sf[0-127]
    -a DBDF,representor=pf1
+   -a DBDF,representor=[pf[0-1],pf2vf[0-2],pf3[3,5-8]]
+   (Multiple representors in one device argument can be represented as a list)
 
 Note: PMDs are not required to support the standard device arguments and users
 should consult the relevant PMD documentation to see support devargs.
diff --git a/doc/guides/prog_guide/switch_representation.rst b/doc/guides/prog_guide/switch_representation.rst
index 6fd7b98bdc..46e0ca85a5 100644
--- a/doc/guides/prog_guide/switch_representation.rst
+++ b/doc/guides/prog_guide/switch_representation.rst
@@ -77,6 +77,7 @@  thought as a software "patch panel" front-end for applications.
    -a pci:dbdf,representor=sf1
    -a pci:dbdf,representor=sf[0-1023]
    -a pci:dbdf,representor=sf[0,2-1023]
+   -a pci:dbdf,representor=[pf[0-1],pf2vf[0-2],pf3[3,5]]
 
 - As virtual devices, they may be more limited than their physical
   counterparts, for instance by exposing only a subset of device
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index acf7e6e46e..5d4f599044 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -6383,8 +6383,8 @@  static int bnxt_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	if (pci_dev->device.devargs) {
 		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
-					    &eth_da);
-		if (ret)
+					    &eth_da, 1);
+		if (ret < 0)
 			return ret;
 	}
 
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index b04b6c9aa1..33d96ec07a 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -1317,8 +1317,8 @@  static int eth_enic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 	ENICPMD_FUNC_TRACE();
 	if (pci_dev->device.devargs) {
 		retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
-				&eth_da);
-		if (retval)
+				&eth_da, 1);
+		if (retval < 0)
 			return retval;
 	}
 	if (eth_da.nb_representor_ports > 0 &&
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 3ca226156b..4d21341382 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -646,8 +646,8 @@  eth_i40e_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	if (pci_dev->device.devargs) {
 		retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
-				&eth_da);
-		if (retval)
+				&eth_da, 1);
+		if (retval < 0)
 			return retval;
 	}
 
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 5d845bba31..0e991fe4b8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -2041,8 +2041,8 @@  eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
 	if (!ice_devargs_check(pci_dev->device.devargs, ICE_DCF_DEVARG_CAP))
 		return 1;
 
-	ret = rte_eth_devargs_parse(pci_dev->device.devargs->args, &eth_da);
-	if (ret)
+	ret = rte_eth_devargs_parse(pci_dev->device.devargs->args, &eth_da, 1);
+	if (ret < 0)
 		return ret;
 
 	ret = rte_eth_dev_pci_generic_probe(pci_dev,
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index d6cf00317e..98e9b8a031 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1765,8 +1765,8 @@  eth_ixgbe_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	if (pci_dev->device.devargs) {
 		retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
-				&eth_da);
-		if (retval)
+				&eth_da, 1);
+		if (retval < 0)
 			return retval;
 	} else
 		memset(&eth_da, 0, sizeof(eth_da));
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index ae82e1e5d8..17061126d5 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -2733,16 +2733,16 @@  mlx5_os_parse_eth_devargs(struct rte_device *dev,
 	memset(eth_da, 0, sizeof(*eth_da));
 	/* Parse representor information first from class argument. */
 	if (dev->devargs->cls_str)
-		ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da);
-	if (ret != 0) {
+		ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da, 1);
+	if (ret < 0) {
 		DRV_LOG(ERR, "failed to parse device arguments: %s",
 			dev->devargs->cls_str);
 		return -rte_errno;
 	}
 	if (eth_da->type == RTE_ETH_REPRESENTOR_NONE && dev->devargs->args) {
 		/* Parse legacy device argument */
-		ret = rte_eth_devargs_parse(dev->devargs->args, eth_da);
-		if (ret) {
+		ret = rte_eth_devargs_parse(dev->devargs->args, eth_da, 1);
+		if (ret < 0) {
 			DRV_LOG(ERR, "failed to parse device arguments: %s",
 				dev->devargs->args);
 			return -rte_errno;
diff --git a/drivers/net/nfp/flower/nfp_flower_representor.c b/drivers/net/nfp/flower/nfp_flower_representor.c
index 5f7c1fa737..63fe37c8d7 100644
--- a/drivers/net/nfp/flower/nfp_flower_representor.c
+++ b/drivers/net/nfp/flower/nfp_flower_representor.c
@@ -792,8 +792,8 @@  nfp_flower_repr_create(struct nfp_app_fw_flower *app_fw_flower)
 
 	/* Now parse PCI device args passed for representor info */
 	if (pci_dev->device.devargs != NULL) {
-		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args, &eth_da);
-		if (ret != 0) {
+		ret = rte_eth_devargs_parse(pci_dev->device.devargs->args, &eth_da, 1);
+		if (ret < 0) {
 			PMD_INIT_LOG(ERR, "devarg parse failed");
 			return -EINVAL;
 		}
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 6d57b2ba26..0bbcb80365 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -3305,8 +3305,8 @@  sfc_parse_rte_devargs(const char *args, struct rte_eth_devargs *devargs)
 	int rc;
 
 	if (args != NULL) {
-		rc = rte_eth_devargs_parse(args, &eth_da);
-		if (rc != 0) {
+		rc = rte_eth_devargs_parse(args, &eth_da, 1);
+		if (rc < 0) {
 			SFC_GENERIC_LOG(ERR,
 					"Failed to parse generic devargs '%s'",
 					args);
diff --git a/lib/ethdev/ethdev_driver.c b/lib/ethdev/ethdev_driver.c
index bd917a15fc..4c0d22f838 100644
--- a/lib/ethdev/ethdev_driver.c
+++ b/lib/ethdev/ethdev_driver.c
@@ -2,6 +2,7 @@ 
  * Copyright(c) 2022 Intel Corporation
  */
 
+#include <ctype.h>
 #include <stdlib.h>
 #include <pthread.h>
 
@@ -459,9 +460,26 @@  eth_dev_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
 			break;
 
 		case 3: /* Parsing list */
-			if (*letter == ']')
-				state = 2;
-			else if (*letter == '\0')
+			if (*letter == ']') {
+				/* For devargs having singles lists move to state 2 once letter
+				 * becomes ']' so each can be considered as different pair key
+				 * value. But in nested lists case e.g. multiple representors
+				 * case i.e. [pf[0-3],pfvf[3,4-6]], complete nested list should
+				 * be considered as one pair value, hence checking if end of outer
+				 * list ']' is reached else stay on state 3.
+				 */
+				if ((strcmp("representor", pair->key) == 0)	    &&
+				    (*(letter + 1) != '\0' && *(letter + 2) != '\0' &&
+				     *(letter + 3) != '\0')			    &&
+				    ((*(letter + 2) == 'p' && *(letter + 3) == 'f') ||
+				     (*(letter + 2) == 'v' && *(letter + 3) == 'f') ||
+				     (*(letter + 2) == 's' && *(letter + 3) == 'f') ||
+				     (*(letter + 2) == 'c' && isdigit(*(letter + 3))) ||
+				     (*(letter + 2) == '[' && isdigit(*(letter + 3)))))
+					state = 3;
+				else
+					state = 2;
+			} else if (*letter == '\0')
 				return -EINVAL;
 			break;
 		}
@@ -469,16 +487,56 @@  eth_dev_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
 	}
 }
 
+static int
+eth_dev_tokenise_representor_list(char *p_val, struct rte_eth_devargs *eth_devargs,
+				  unsigned int nb_da)
+{
+	struct rte_eth_devargs *eth_da;
+	char da_val[BUFSIZ];
+	char *token, *sptr;
+	char delim[] = "]";
+	int devargs = 0;
+	int result = 0;
+
+	token = strtok_r(&p_val[1], delim, &sptr);
+	while (token != NULL) {
+		eth_da = &eth_devargs[devargs];
+		memset(eth_da, 0, sizeof(*eth_da));
+		snprintf(da_val, BUFSIZ, "%s%c", (token[0] == ',') ? ++token : token, ']');
+		/* Parse the tokenised devarg value */
+		result = rte_eth_devargs_parse_representor_ports(da_val, eth_da);
+		if (result < 0)
+			goto parse_cleanup;
+		devargs++;
+		if (devargs > (int)nb_da) {
+			RTE_ETHDEV_LOG_LINE(ERR,
+					    "Devargs parsed %d > max array size %d",
+					    devargs, nb_da);
+			result = -1;
+			goto parse_cleanup;
+		}
+		token = strtok_r(NULL, delim, &sptr);
+	}
+
+	result = devargs;
+
+parse_cleanup:
+	return result;
+
+}
+
 int
-rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_da)
+rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_devargs,
+		      unsigned int nb_da)
 {
-	struct rte_kvargs args;
+	struct rte_eth_devargs *eth_da;
 	struct rte_kvargs_pair *pair;
+	struct rte_kvargs args;
+	static bool dup_rep;
+	int devargs = 0;
 	unsigned int i;
 	int result = 0;
 
-	memset(eth_da, 0, sizeof(*eth_da));
-
 	result = eth_dev_devargs_tokenise(&args, dargs);
 	if (result < 0)
 		goto parse_cleanup;
@@ -486,18 +544,40 @@  rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_da)
 	for (i = 0; i < args.count; i++) {
 		pair = &args.pairs[i];
 		if (strcmp("representor", pair->key) == 0) {
-			if (eth_da->type != RTE_ETH_REPRESENTOR_NONE) {
-				RTE_ETHDEV_LOG_LINE(ERR, "duplicated representor key: %s",
-					dargs);
+			if (dup_rep) {
+				RTE_ETHDEV_LOG_LINE(ERR, "Duplicated representor key: %s",
+						    pair->value);
 				result = -1;
 				goto parse_cleanup;
 			}
-			result = rte_eth_devargs_parse_representor_ports(
-					pair->value, eth_da);
-			if (result < 0)
-				goto parse_cleanup;
+
+			if (pair->value[0] == '[' && !isdigit(pair->value[1])) {
+				/* Multiple representor list case */
+				devargs = eth_dev_tokenise_representor_list(pair->value,
+									    eth_devargs, nb_da);
+				if (devargs < 0)
+					goto parse_cleanup;
+			} else {
+				/* Single representor case */
+				eth_da = &eth_devargs[devargs];
+				memset(eth_da, 0, sizeof(*eth_da));
+				result =
+					rte_eth_devargs_parse_representor_ports(pair->value,
+										eth_da);
+				if (result < 0)
+					goto parse_cleanup;
+				devargs++;
+				if (devargs > (int)nb_da) {
+					RTE_ETHDEV_LOG_LINE(ERR, "Devargs parsed %d > max array size %d",
+							    devargs, nb_da);
+					result = -1;
+					goto parse_cleanup;
+				}
+			}
+			dup_rep = true;
 		}
 	}
+	result = devargs;
 
 parse_cleanup:
 	free(args.str);
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index b482cd12bb..fd6f404e9a 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -1800,14 +1800,17 @@  rte_eth_representor_id_get(uint16_t port_id,
  * @param devargs
  *  device arguments
  * @param eth_devargs
- *  parsed ethdev specific arguments.
+ *  contiguous memory populated with parsed ethdev specific arguments.
+ * @param nb_da
+ *  size of eth_devargs array passed
  *
  * @return
- *   Negative errno value on error, 0 on success.
+ *   Negative errno value on error, no of devargs parsed on success.
  */
 __rte_internal
 int
-rte_eth_devargs_parse(const char *devargs, struct rte_eth_devargs *eth_devargs);
+rte_eth_devargs_parse(const char *devargs, struct rte_eth_devargs *eth_devargs,
+		      unsigned int nb_da);
 
 
 typedef int (*ethdev_init_t)(struct rte_eth_dev *ethdev, void *init_params);