lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
 <PAXPR04MB851027E5F830F08F3395083888D22@PAXPR04MB8510.eurprd04.prod.outlook.com>
Date: Fri, 14 Mar 2025 13:48:21 +0000
From: Wei Fang <wei.fang@....com>
To: Vladimir Oltean <vladimir.oltean@....com>
CC: Claudiu Manoil <claudiu.manoil@....com>, Clark Wang
	<xiaoning.wang@....com>, "andrew+netdev@...n.ch" <andrew+netdev@...n.ch>,
	"davem@...emloft.net" <davem@...emloft.net>, "edumazet@...gle.com"
	<edumazet@...gle.com>, "kuba@...nel.org" <kuba@...nel.org>,
	"pabeni@...hat.com" <pabeni@...hat.com>, "christophe.leroy@...roup.eu"
	<christophe.leroy@...roup.eu>, "netdev@...r.kernel.org"
	<netdev@...r.kernel.org>, "linux-kernel@...r.kernel.org"
	<linux-kernel@...r.kernel.org>, "imx@...ts.linux.dev" <imx@...ts.linux.dev>,
	"linuxppc-dev@...ts.ozlabs.org" <linuxppc-dev@...ts.ozlabs.org>,
	"linux-arm-kernel@...ts.infradead.org" <linux-arm-kernel@...ts.infradead.org>
Subject: RE: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver
 to support NTMP



Best Regards,
Wei Fang

> -----Original Message-----
> From: Vladimir Oltean <vladimir.oltean@....com>
> On Fri, Mar 14, 2025 at 05:38:18AM +0200, Wei Fang wrote:
> > > > +	__le16 update_act;
> > > > +	u8 dbg_opt;
> > > > +	u8 tblv_qact;
> > > > +#define NTMP_QUERY_ACT		GENMASK(3, 0)
> > > > +#define NTMP_TBL_VER		GENMASK(7, 0)
> > > > +#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> > > > +				 ((a) & NTMP_QUERY_ACT))
> > >
> > > Can you please move #define macros out of structure definitions?
> >
> > No, I think these macros in the structure can better reflect the specific
> > meaning of these members. We can intuitively see what the bits of
> > these members represent, rather than finding the definition of these
> > bits in RM or elsewhere.
> 
> I mean, I was just suggesting to group the macros with the macros, and
> the struct fields with the struct fields. Mixing them together looks a
> bit messy to me. Even worse in the definition of "union netc_cbd" which
> IMO needs to be reconsidered a bit (a hint given below).

I think this is a matter of personal preference. I was inspired by some
of Intel's structure definitions. I think this method allows me to quickly
understand what fields the member consists of and what bits each field
occupies.

> 
> But you mention "intuitive" definitions without having to go to the RM.
> If I look just at the definitions, I see that NTMP_QUERY_ACT and
> NTMP_TBL_VER
> overlap, and that NTMP_TBLV_QACT() just ORs them together. How does that
> work?
> Shouldn't NTMP_TBL_VER() have been GENMASK(7, 4)? If I do open the RM

I must admit that it is my fault, so yes, NTMP_TBL_VER should be GENMASK(7, 4).
I will fix it, thanks for pointing this.

> and go to the "Generic NTMP Request Data Buffer Format" section, that
> table does seem to agree with me.
> 
> The "normal" way to give more meaning to struct fields is to define them
> as enum values. That doesn't work with "packed" field definitions as you
> have here, which I agree is a challenge. But it is one of the reasons
> why I tried to develop an API together with Jacob Keller which tries to
> address this, by allowing you to define the structures in an "unpacked"
> format, and have a separate data structure which informs the CPU how
> that structure maps over the buffer layout.
> 
> Below is an example to illustrate this for the case of NTMP request buffers.
> Note that the example is incomplete and doesn't even compile, because I
> haven't even converted all ntmp_fill_crd_eid() callers - I don't want to
> waste too much time doing that in case you disagree, but it's still
> enough to show what I'm talking about. Disclaimer: I didn't even _try_
> to compile it - it may contain bugs.
> 
> -- >8 --
> diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig
> b/drivers/net/ethernet/freescale/enetc/Kconfig
> index c8efbb6f2055..35d5cf21f6f4 100644
> --- a/drivers/net/ethernet/freescale/enetc/Kconfig
> +++ b/drivers/net/ethernet/freescale/enetc/Kconfig
> @@ -17,6 +17,7 @@ config NXP_ENETC_PF_COMMON
> 
>  config NXP_NETC_LIB
>  	tristate
> +	select PACKING
>  	help
>  	  This module provides common functionalities for both ENETC and NETC
>  	  Switch, such as NETC Table Management Protocol (NTMP) 2.0,
> common tc
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c
> b/drivers/net/ethernet/freescale/enetc/ntmp.c
> index df10f2f310c1..f96cfca92a1c 100644
> --- a/drivers/net/ethernet/freescale/enetc/ntmp.c
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
> @@ -180,7 +180,7 @@ static int netc_xmit_ntmp_cmd(struct netc_cbdrs
> *cbdrs, union netc_cbd *cbd)
>  	return err;
>  }
> 
> -static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void
> **buf_align)
> +static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data,
> ntmp_common_req_msg_data_buf *buf_align)
>  {
>  	void *buf;
> 
> @@ -221,18 +221,24 @@ static void ntmp_fill_request_headr(union netc_cbd
> *cbd, dma_addr_t dma,
>  	cbd->req_hdr.npf = cpu_to_le32(NTMP_NPF);
>  }
> 
> -static void ntmp_fill_crd(struct common_req_data *crd,
> -			  u8 tblv, u8 qa, u16 ua)
> +static const struct packed_field_u8 ntmp_common_req_fields[] = {
> +	PACKED_FIELD(31, 28, struct ntmp_common_req_data, table_version),
> +	PACKED_FIELD(27, 24, struct ntmp_common_req_data, query_actions),
> +	PACKED_FIELD(15, 0, struct ntmp_common_req_data, update_actions),
> +};
> +
> +static void ntmp_fill_crd(ntmp_common_req_msg_data_buf *buf,
> +			  const struct common_req_data *crd)
>  {
> -	crd->update_act = cpu_to_le16(ua);
> -	crd->tblv_qact = NTMP_TBLV_QACT(tblv, qa);
> +	pack_fields(buf, sizeof(*buf), crd, ntmp_common_req_fields,
> +		    QUIRK_LITTLE_ENDIAN);
>  }
> 
> -static void ntmp_fill_crd_eid(struct ntmp_req_by_eid *rbe, u8 tblv,
> -			      u8 qa, u16 ua, u32 entry_id)
> +static void ntmp_fill_crd_eid(struct ntmp_common_req_msg_data_buf *buf,
> +			      const struct ntmp_req_by_eid *rbe)
>  {
> -	ntmp_fill_crd(&rbe->crd, tblv, qa, ua);
> -	rbe->entry_id = cpu_to_le32(entry_id);
> +	ntmp_fill_crd(buf, &rbe->crd);
> +	pack(buf + 1, rbe->entry_id, 31, 0);
>  }
> 
>  static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> @@ -240,7 +246,13 @@ static int ntmp_delete_entry_by_id(struct
> netc_cbdrs *cbdrs, int tbl_id,
>  				   u32 resp_len)
>  {
>  	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> -	struct ntmp_req_by_eid *req;
> +	struct ntmp_req_by_eid req = {
> +		.crd = {
> +			.table_version = tbl_ver,
> +		},
> +		.entry_id = entry_id,
> +	};
> +	ntmp_common_req_msg_data_buf buf;
>  	union netc_cbd cbd;
>  	u32 len;
>  	int err;
> @@ -255,7 +267,7 @@ static int ntmp_delete_entry_by_id(struct netc_cbdrs
> *cbdrs, int tbl_id,
>  		req_len = sizeof(*req);
> 
>  	data.size = req_len >= resp_len ? req_len : resp_len;
> -	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	err = ntmp_alloc_data_mem(&data, &buf);
>  	if (err)
>  		return err;
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> index 45e4d083ab0a..e68b2a060176 100644
> --- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> @@ -16,14 +16,14 @@ struct ntmp_dma_buf {
>  	dma_addr_t dma;
>  };
> 
> -struct common_req_data {
> -	__le16 update_act;
> -	u8 dbg_opt;
> -	u8 tblv_qact;
> -#define NTMP_QUERY_ACT		GENMASK(3, 0)
> -#define NTMP_TBL_VER		GENMASK(7, 0)
> -#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> -				 ((a) & NTMP_QUERY_ACT))
> +#define NTMP_COMMON_REQ_MSG_DATA_BUFSZ	4
> +
> +typedef struct __packed { u8
> buf[NTMP_COMMON_REQ_MSG_DATA_BUFSZ]; }
> ntmp_common_req_msg_data_buf;
> +
> +struct ntmp_common_req_data {
> +	u16 update_actions;
> +	u8 query_actions;
> +	u8 table_version;
>  };
> 
>  struct common_resp_query {
> @@ -36,8 +36,8 @@ struct common_resp_nq {
> 
>  /* Generic structure for request data by entry ID  */
>  struct ntmp_req_by_eid {
> -	struct common_req_data crd;
> -	__le32 entry_id;
> +	struct ntmp_common_req_data crd;
> +	u32 entry_id;
>  };
> 
>  /* MAC Address Filter Table Request Data Buffer Format of Add action */
> -- >8 --
> 
> Some remarks:
>  - The fact that struct ntmp_common_req_data is an unpacked structure
>    now means that the layout of fields is completely decoupled from the
>    layout of the data buffer. You can make each field an enum type if
>    you want, which I didn't do here.
>  - You don't have to access its fields with le32_to_cpu() and friends,
>    it's implicitly in CPU endianness.
>  - The API is tolerant of the case where the CPU is in a different
>    endianness from ENETC.
>  - The API protects you against overlapping PACKED_FIELD() definitions,
>    and gives a compile-time error if it detects an overlap.
>  - The API allows you to define buffers of any size you want, and the
>    bit field ranges vary according to the buffer size you chose. Notice
>    how you are grouping two fields within the "u8 tblv_qact" field, and
>    their offsets are 7-4 and 3-0, respectively, within that u8, but in
>    the PACKED_FIELD() definition you can make them 31-28 and 27-24, just
>    like in the RM.
>  - struct ntmp_req_by_eid and struct ntmp_common_req_data don't have to
>    be distinct structures. You can call pack_fields() and pack only a
>    subset of the fields of an unpacked structure. Then pack the rest
>    with explicit pack() calls, or not pack them at all.
> 
> I just want to present this alternative because I believe it offers some
> distinct advantages which may be useful here. But note that just
> "QUIRK_LITTLE_ENDIAN" may be wrong for NTMP. You need to see whether
> you
> also need QUIRK_LSW32_IS_FIRST or not. For buffers up to 32 bits,
> QUIRK_LSW32_IS_FIRST makes no difference, only for buffers larger than that.
> 

Thanks, but we have added fully NTMP support in downstream, it's a great
challenge for me to convert it to the 'packing' method. I don't think I have
too much time to do this conversion. And I also need some time to figure
out how to use it and whether it is worth doing so.

> > > The question pertains to everything else that is exported to
> > > include/linux/fsl/ntmp.h - what the API consumer sees. Is there a real
> > > reason to export it? For many structures and macros, the answer seems no.
> > >
> > > Even for cases like struct maft_keye_data which are only used by debugfs,
> > > it still seems preferable to keep data encapsulation and offer a helper
> > > function to retrieve a pointer to the MAC address from the MAFT entry.
> > > Then, "struct maft_keye_data;" can simply be declared, without exposing
> > > its full definition.
> >
> > ntmp_private.h is only used for ntmp driver, I don't want it to be included
> > by any enetc files. ntmp.h is used for both enetc and switch drivers, so we
> > need to add full definitions of the table data.
> 
> And I agree with you, I also don't want ntmp_private.h to be exposed to
> the NTMP API consumers, and I wasn't suggesting that. I just want the
> NTMP API to spare consumer drivers of the gory details, like for example
> the buffer layout of a MAC filtering entry, reserved fields, things like
> that. What I was saying is to keep the buffer layout private to
> ntmp_private.h, and expose a more abstract data structure to API
> consumers.
> 

Sorry, I don't fully understand, for example, if we place the definition
of "struct maft_keye_data" in ntmp_private.h, how does the debugfs
get the information from "struct maft_keye_data"? Add a helper function
in the NTMP driver and export it to enetc driver? And how does
enetc4_pf_add_si_mac_exact_filter() to set the mac address to "struct
maft_keye_data", add another helper? If so, I think it is more complicated.

> > > > +struct ntmp_priv {
> > >
> > > Would it be better to name this "struct ntmp_client"? I don't really
> > > understand the way in which it is "private".
> >
> > It refers to some private data of NTMP of different devices (enetc or
> > switches). Since the current patch is only a small part of NTMP, many
> > members have not been added to the structure. The following is the
> > definition in our downstream.
> >
> > struct ntmp_priv {
> > 	enum netc_dev_type dev_type;
> > 	struct netc_cbdrs cbdrs;
> > 	u32 errata;
> >
> > 	struct ntmp_caps caps;
> > 	/* bitmap of table entry ID */
> > 	unsigned long *ist_eid_bitmap;
> > 	unsigned long *rpt_eid_bitmap;
> > 	unsigned long *sgit_eid_bitmap;
> > 	unsigned long *isct_eid_bitmap;
> > 	unsigned long *sgclt_word_bitmap;
> > 	unsigned long *ett_eid_bitmap;
> > 	unsigned long *ect_eid_bitmap;
> > 	u32 ett_bitmap_size;
> > 	u32 ect_bitmap_size;
> >
> > 	struct hlist_head flower_list;
> > 	struct mutex flower_lock; /* flower_list lock */
> >
> > 	u64 (*adjust_base_time)(struct ntmp_priv *priv, u64 bt, u32 ct);
> > 	u32 (*get_tgst_free_words)(struct ntmp_priv *priv);
> > };
> 
> Thank you for posting the downstream layout of struct ntmp_priv which I
> was already aware of. What I was saying is that the word "private" means
> an aspect of the implementation which is hidden from other code layers.
> There's nothing "private" here if the NTMP layer has access to the
> definition of this structure. I was asking whether you agree that it's
> more adequate to name this structure "ntmp_client", since it represents
> the data associated with a consumer of the NTMP API - a NETC SI or (in
> the future) the switch. Or some other name. But the word "private" seems
> misused.
> 

Okay, it seems to make you feel confused, let me rename it later, how about
"ntmp_user"?

> > > What's the idea with the null entry ID? Why special-case it?
> > >
> >
> > Some functions are configured by multiple tables. If a table is
> > not needed in the current configuration, we may set its entry
> > id to NTMP_NULL_ENTRY_ID, indicating that the table is bypassed.
> > For the current patch, this condition can be removed.
> 
> Ok, thank you.
> 
> > > > +	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];
> > >
> > > I think you need to be in a "preemption disabled" / "migration disable"
> > > calling context for smp_processor_id() to be reliable. Otherwise, the
> > > task can migrate to another CPU as soon as this function returns.
> > >
> >
> > It does not matter, we just want to select a command BD ring when all
> > command BD rings are busy. So smp_processor_id() is just a parameter,
> > we can also use a random number.
> 
> Ok.
> 
> > > Can you place this dma_wmb() right next to the "*cur_cbd = *cbd" line,
> > > to make it obvious that updating the producer index has nothing to do
> > > with it? Or is there another reason for this ordering?
> > >
> >
> > No special reason for this ordering, I will move it after "*cur_cbd = *cbd".
> 
> Thanks, I appreciate it.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ