diff mbox series

[net-next,v5,3/5] net: dsa: add out-of-band tagging protocol

Message ID 20221021124556.100445-4-maxime.chevallier@bootlin.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: ipqess: introduce Qualcomm IPQESS driver | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 5327 this patch: 5109
netdev/cc_maintainers warning 5 maintainers not CCed: kuba@kernel.org vivien.didelot@gmail.com imagedong@tencent.com edumazet@google.com pabeni@redhat.com
netdev/build_clang fail Errors and warnings before: 1124 this patch: 1015
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 5512 this patch: 5296
netdev/checkpatch warning WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: please write a help paragraph that fully describes the config symbol
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Maxime Chevallier Oct. 21, 2022, 12:45 p.m. UTC
This tagging protocol is designed for the situation where the link
between the MAC and the Switch is designed such that the Destination
Port, which is usually embedded in some part of the Ethernet Header, is
sent out-of-band, and isn't present at all in the Ethernet frame.

This can happen when the MAC and Switch are tightly integrated on an
SoC, as is the case with the Qualcomm IPQ4019 for example, where the DSA
tag is inserted directly into the DMA descriptors. In that case,
the MAC driver is responsible for sending the tag to the switch using
the out-of-band medium. To do so, the MAC driver needs to have the
information of the destination port for that skb.

Add a new tagging protocol based on SKB extensions to convey the
information about the destination port to the MAC driver

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
V4->V5
 - Use SKB extensions to convey the tag
V3->V4 
 - No changes
V3->V2:
 - No changes, as the discussion is ongoing
V1->V2:
 - Reworked the tagging method, putting the tag at skb->head instead
   of putting it into skb->shinfo, as per Andrew, Florian and Vlad's
   reviews

 include/linux/dsa/oob.h | 17 +++++++++
 include/linux/skbuff.h  |  3 ++
 include/net/dsa.h       |  2 ++
 net/core/skbuff.c       | 10 ++++++
 net/dsa/Kconfig         |  8 +++++
 net/dsa/Makefile        |  1 +
 net/dsa/tag_oob.c       | 80 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 121 insertions(+)
 create mode 100644 include/linux/dsa/oob.h
 create mode 100644 net/dsa/tag_oob.c

Comments

Vladimir Oltean Oct. 21, 2022, 2:01 p.m. UTC | #1
On Fri, Oct 21, 2022 at 02:45:54PM +0200, Maxime Chevallier wrote:
> This tagging protocol is designed for the situation where the link
> between the MAC and the Switch is designed such that the Destination
> Port, which is usually embedded in some part of the Ethernet Header, is
> sent out-of-band, and isn't present at all in the Ethernet frame.
> 
> This can happen when the MAC and Switch are tightly integrated on an
> SoC, as is the case with the Qualcomm IPQ4019 for example, where the DSA
> tag is inserted directly into the DMA descriptors. In that case,
> the MAC driver is responsible for sending the tag to the switch using
> the out-of-band medium. To do so, the MAC driver needs to have the
> information of the destination port for that skb.
> 
> Add a new tagging protocol based on SKB extensions to convey the
> information about the destination port to the MAC driver
> 
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
> ---
> V4->V5
>  - Use SKB extensions to convey the tag
> V3->V4 
>  - No changes
> V3->V2:
>  - No changes, as the discussion is ongoing
> V1->V2:
>  - Reworked the tagging method, putting the tag at skb->head instead
>    of putting it into skb->shinfo, as per Andrew, Florian and Vlad's
>    reviews
> 
>  include/linux/dsa/oob.h | 17 +++++++++
>  include/linux/skbuff.h  |  3 ++
>  include/net/dsa.h       |  2 ++
>  net/core/skbuff.c       | 10 ++++++
>  net/dsa/Kconfig         |  8 +++++
>  net/dsa/Makefile        |  1 +
>  net/dsa/tag_oob.c       | 80 +++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 121 insertions(+)
>  create mode 100644 include/linux/dsa/oob.h
>  create mode 100644 net/dsa/tag_oob.c
> 
> diff --git a/include/linux/dsa/oob.h b/include/linux/dsa/oob.h
> new file mode 100644
> index 000000000000..dbb4a6fb1ce4
> --- /dev/null
> +++ b/include/linux/dsa/oob.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-only
> + * Copyright (C) 2022 Maxime Chevallier <maxime.chevallier@bootlin.com>
> + */
> +
> +#ifndef _NET_DSA_OOB_H
> +#define _NET_DSA_OOB_H
> +
> +#include <linux/skbuff.h>
> +
> +struct dsa_oob_tag_info {
> +	u16 proto;

Not needed / not used, please remove.

> +	u16 dp;

Could you please rename "dp" into "port"? The naming convention is that
variables named "dp" have the type "struct dsa_port *".

> +};
> +
> +int dsa_oob_tag_push(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
> +int dsa_oob_tag_pop(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
> +#endif
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 9fcf534f2d92..e387d6795919 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -4571,6 +4571,9 @@ enum skb_ext_id {
>  #endif
>  #if IS_ENABLED(CONFIG_MCTP_FLOWS)
>  	SKB_EXT_MCTP,
> +#endif
> +#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
> +	SKB_EXT_DSA_OOB,
>  #endif
>  	SKB_EXT_NUM, /* must be last */
>  };
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index ee369670e20e..114176efacc9 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -55,6 +55,7 @@ struct phylink_link_state;
>  #define DSA_TAG_PROTO_RTL8_4T_VALUE		25
>  #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE		26
>  #define DSA_TAG_PROTO_LAN937X_VALUE		27
> +#define DSA_TAG_PROTO_OOB_VALUE			28
>  
>  enum dsa_tag_protocol {
>  	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
> @@ -85,6 +86,7 @@ enum dsa_tag_protocol {
>  	DSA_TAG_PROTO_RTL8_4T		= DSA_TAG_PROTO_RTL8_4T_VALUE,
>  	DSA_TAG_PROTO_RZN1_A5PSW	= DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
>  	DSA_TAG_PROTO_LAN937X		= DSA_TAG_PROTO_LAN937X_VALUE,
> +	DSA_TAG_PROTO_OOB		= DSA_TAG_PROTO_OOB_VALUE,
>  };
>  
>  struct dsa_switch;
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 1d9719e72f9d..627b0b9c0b23 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -61,8 +61,12 @@
>  #include <linux/if_vlan.h>
>  #include <linux/mpls.h>
>  #include <linux/kcov.h>
> +#ifdef CONFIG_NET_DSA_TAG_OOB
> +#include <linux/dsa/oob.h>
> +#endif
>  
>  #include <net/protocol.h>
> +#include <net/dsa.h>
>  #include <net/dst.h>
>  #include <net/sock.h>
>  #include <net/checksum.h>
> @@ -4474,6 +4478,9 @@ static const u8 skb_ext_type_len[] = {
>  #if IS_ENABLED(CONFIG_MCTP_FLOWS)
>  	[SKB_EXT_MCTP] = SKB_EXT_CHUNKSIZEOF(struct mctp_flow),
>  #endif
> +#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
> +	[SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
> +#endif
>  };
>  
>  static __always_inline unsigned int skb_ext_total_length(void)
> @@ -4493,6 +4500,9 @@ static __always_inline unsigned int skb_ext_total_length(void)
>  #endif
>  #if IS_ENABLED(CONFIG_MCTP_FLOWS)
>  		skb_ext_type_len[SKB_EXT_MCTP] +
> +#endif
> +#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
> +		skb_ext_type_len[SKB_EXT_DSA_OOB] +
>  #endif
>  		0;
>  }
> diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
> index 3eef72ce99a4..c50508e9f636 100644
> --- a/net/dsa/Kconfig
> +++ b/net/dsa/Kconfig
> @@ -57,6 +57,14 @@ config NET_DSA_TAG_HELLCREEK
>  	  Say Y or M if you want to enable support for tagging frames
>  	  for the Hirschmann Hellcreek TSN switches.
>  
> +config NET_DSA_TAG_OOB
> +	select SKB_EXTENSIONS
> +	tristate "Tag driver for Out-of-band tagging drivers"
> +	help
> +	  Say Y or M if you want to enable support for tagging out-of-band. In
> +	  that case, the MAC driver becomes responsible for sending the tag to
> +	  the switch, outside the inband data.

I suppose at some point you should clarify what this "band" really is.
How about:

	  Say Y or M if you want to enable support for pairs of embedded
	  switches and host MAC drivers which perform demultiplexing and
	  packet steering to ports using out of band metadata processed
	  by the DSA master, rather than tags present in the packets.

Could you also update Documentation/networking/dsa/dsa.rst (the section
"Switch tagging protocols") with some information about how this works?

DSA tags generally support stacking (i.e. a DSA switch port can be a
master for another DSA switch, and so on). Every switch along the path
inserts/extracts its own tag where it expects it to be, and the packet
is steered through all switches in the hierarchy.

It would be good to mention what is the situation with tag stacking when
NET_DSA_TAG_OOB is used. I suppose multiple oob tags don't make sense
for the same skb, and if oob tags are used, they are always for the
switches within the top-most tree. Beyond that, other DSA tags could
still be present in the skb, for downstream switches?

> +
>  config NET_DSA_TAG_GSWIP
>  	tristate "Tag driver for Lantiq / Intel GSWIP switches"
>  	help
> diff --git a/net/dsa/Makefile b/net/dsa/Makefile
> index bf57ef3bce2a..fff657064be4 100644
> --- a/net/dsa/Makefile
> +++ b/net/dsa/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
>  obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o
>  obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
>  obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
> +obj-$(CONFIG_NET_DSA_TAG_OOB) += tag_oob.o

Alphabetic ordering please. Same for the Kconfig entry too, probably.

>  obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
>  obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
>  obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
> diff --git a/net/dsa/tag_oob.c b/net/dsa/tag_oob.c
> new file mode 100644
> index 000000000000..f8fba8406307
> --- /dev/null
> +++ b/net/dsa/tag_oob.c
> @@ -0,0 +1,80 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/* Copyright (c) 2022, Maxime Chevallier <maxime.chevallier@bootlin.com> */
> +
> +#include <linux/bitfield.h>

not needed

> +#include <linux/dsa/oob.h>
> +#include <linux/skbuff.h>
> +
> +#include "dsa_priv.h"
> +
> +#define DSA_OOB_TAG_LEN 4

Not used.

> +
> +int dsa_oob_tag_push(struct sk_buff *skb, struct dsa_oob_tag_info *ti)

const struct dsa_oob_tag_info *

> +{
> +	struct dsa_oob_tag_info *tag_info;
> +
> +	tag_info = skb_ext_add(skb, SKB_EXT_DSA_OOB);

skb_ext_add() can return NULL. The return code for this function is not
really adequate.

> +
> +	tag_info->dp = ti->dp;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(dsa_oob_tag_push);
> +
> +int dsa_oob_tag_pop(struct sk_buff *skb, struct dsa_oob_tag_info *ti)
> +{
> +	struct dsa_oob_tag_info *tag_info;
> +
> +	tag_info = skb_ext_find(skb, SKB_EXT_DSA_OOB);
> +	if (!tag_info)
> +		return -EINVAL;
> +
> +	ti->dp = tag_info->dp;

The function doesn't really "pop" it, despite the name (not clear if
that's even necessary). If we keep the extension in place, can we just
return a pointer to it, rather than make a copy on stack?

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(dsa_oob_tag_pop);

I think these 2 functions can be made "static inline" in <linux/dsa/oob.h>
and this could avoid depending on net/dsa/tag_oob.ko for their other
callers?

> +
> +static struct sk_buff *oob_tag_xmit(struct sk_buff *skb,
> +				    struct net_device *dev)
> +{
> +	struct dsa_port *dp = dsa_slave_to_port(dev);
> +	struct dsa_oob_tag_info tag_info;
> +
> +	tag_info.dp = dp->index;

I would prefer a definition like this:

	struct dsa_oob_tag_info tag_info = {
		.port = dp->index,
	};

here and everywhere else, because if new fields are added to the
structure and are not explicitly present in this initializer, they will
get initialized with zeroes rather than on-stack garbage.

> +
> +	if (dsa_oob_tag_push(skb, &tag_info))
> +		return NULL;
> +
> +	return skb;
> +}
> +
> +static struct sk_buff *oob_tag_rcv(struct sk_buff *skb,
> +				   struct net_device *dev)
> +{
> +	struct dsa_oob_tag_info tag_info;
> +
> +	if (dsa_oob_tag_pop(skb, &tag_info))
> +		return NULL;
> +
> +	skb->dev = dsa_master_find_slave(dev, 0, tag_info.dp);
> +	if (!skb->dev)
> +		return NULL;
> +
> +	return skb;
> +}
> +
> +const struct dsa_device_ops oob_tag_dsa_ops = {
> +	.name	= "oob",
> +	.proto	= DSA_TAG_PROTO_OOB,
> +	.xmit	= oob_tag_xmit,
> +	.rcv	= oob_tag_rcv,
> +};
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("DSA tag driver for out-of-band tagging");
> +MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
> +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OOB);
> +
> +module_dsa_tag_driver(oob_tag_dsa_ops);
> -- 
> 2.37.3
>
Andrew Lunn Oct. 21, 2022, 2:43 p.m. UTC | #2
> @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
>  obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o
>  obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
>  obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
> +obj-$(CONFIG_NET_DSA_TAG_OOB) += tag_oob.o
>  obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
>  obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
>  obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o

This list is roughly in alphabetic order, part from
CONFIG_NET_DSA_TAG_RTL4_A. Please add OOB after OCELOT_8021Q.

Thanks
	Andrew
Andrew Lunn Oct. 21, 2022, 2:46 p.m. UTC | #3
> diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
> index 3eef72ce99a4..c50508e9f636 100644
> --- a/net/dsa/Kconfig
> +++ b/net/dsa/Kconfig
> @@ -57,6 +57,14 @@ config NET_DSA_TAG_HELLCREEK
>  	  Say Y or M if you want to enable support for tagging frames
>  	  for the Hirschmann Hellcreek TSN switches.
>  
> +config NET_DSA_TAG_OOB
> +	select SKB_EXTENSIONS
> +	tristate "Tag driver for Out-of-band tagging drivers"

Here the sorting is based on the tristate. So again, after Ocelot
8021q please.

      Andrew
kernel test robot Oct. 21, 2022, 7:51 p.m. UTC | #4
Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-ipqess-introduce-Qualcomm-IPQESS-driver/20221021-204717
patch link:    https://lore.kernel.org/r/20221021124556.100445-4-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next v5 3/5] net: dsa: add out-of-band tagging protocol
config: sh-allmodconfig
compiler: sh4-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/7d31811b06a4c3d97e0384fcb6acc1e21f22143e
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Maxime-Chevallier/net-ipqess-introduce-Qualcomm-IPQESS-driver/20221021-204717
        git checkout 7d31811b06a4c3d97e0384fcb6acc1e21f22143e
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh SHELL=/bin/bash net/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from include/vdso/const.h:5,
                    from include/linux/const.h:4,
                    from include/linux/list.h:9,
                    from include/linux/module.h:12,
                    from net/core/skbuff.c:37:
>> net/core/skbuff.c:4482:49: error: invalid application of 'sizeof' to incomplete type 'struct dsa_oob_tag_info'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                                                 ^~~~~~
   include/uapi/linux/const.h:32:44: note: in definition of macro '__ALIGN_KERNEL_MASK'
      32 | #define __ALIGN_KERNEL_MASK(x, mask)    (((x) + (mask)) & ~(mask))
         |                                            ^
   include/linux/align.h:8:33: note: in expansion of macro '__ALIGN_KERNEL'
       8 | #define ALIGN(x, a)             __ALIGN_KERNEL((x), (a))
         |                                 ^~~~~~~~~~~~~~
   net/core/skbuff.c:4463:34: note: in expansion of macro 'ALIGN'
    4463 | #define SKB_EXT_CHUNKSIZEOF(x)  (ALIGN((sizeof(x)), SKB_EXT_ALIGN_VALUE) / SKB_EXT_ALIGN_VALUE)
         |                                  ^~~~~
   net/core/skbuff.c:4482:29: note: in expansion of macro 'SKB_EXT_CHUNKSIZEOF'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                             ^~~~~~~~~~~~~~~~~~~
>> net/core/skbuff.c:4482:49: error: invalid application of 'sizeof' to incomplete type 'struct dsa_oob_tag_info'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                                                 ^~~~~~
   include/uapi/linux/const.h:32:50: note: in definition of macro '__ALIGN_KERNEL_MASK'
      32 | #define __ALIGN_KERNEL_MASK(x, mask)    (((x) + (mask)) & ~(mask))
         |                                                  ^~~~
   include/linux/align.h:8:33: note: in expansion of macro '__ALIGN_KERNEL'
       8 | #define ALIGN(x, a)             __ALIGN_KERNEL((x), (a))
         |                                 ^~~~~~~~~~~~~~
   net/core/skbuff.c:4463:34: note: in expansion of macro 'ALIGN'
    4463 | #define SKB_EXT_CHUNKSIZEOF(x)  (ALIGN((sizeof(x)), SKB_EXT_ALIGN_VALUE) / SKB_EXT_ALIGN_VALUE)
         |                                  ^~~~~
   net/core/skbuff.c:4482:29: note: in expansion of macro 'SKB_EXT_CHUNKSIZEOF'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                             ^~~~~~~~~~~~~~~~~~~
>> net/core/skbuff.c:4482:49: error: invalid application of 'sizeof' to incomplete type 'struct dsa_oob_tag_info'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                                                 ^~~~~~
   include/uapi/linux/const.h:32:61: note: in definition of macro '__ALIGN_KERNEL_MASK'
      32 | #define __ALIGN_KERNEL_MASK(x, mask)    (((x) + (mask)) & ~(mask))
         |                                                             ^~~~
   include/linux/align.h:8:33: note: in expansion of macro '__ALIGN_KERNEL'
       8 | #define ALIGN(x, a)             __ALIGN_KERNEL((x), (a))
         |                                 ^~~~~~~~~~~~~~
   net/core/skbuff.c:4463:34: note: in expansion of macro 'ALIGN'
    4463 | #define SKB_EXT_CHUNKSIZEOF(x)  (ALIGN((sizeof(x)), SKB_EXT_ALIGN_VALUE) / SKB_EXT_ALIGN_VALUE)
         |                                  ^~~~~
   net/core/skbuff.c:4482:29: note: in expansion of macro 'SKB_EXT_CHUNKSIZEOF'
    4482 |         [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
         |                             ^~~~~~~~~~~~~~~~~~~


vim +4482 net/core/skbuff.c

  4464	
  4465	static const u8 skb_ext_type_len[] = {
  4466	#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
  4467		[SKB_EXT_BRIDGE_NF] = SKB_EXT_CHUNKSIZEOF(struct nf_bridge_info),
  4468	#endif
  4469	#ifdef CONFIG_XFRM
  4470		[SKB_EXT_SEC_PATH] = SKB_EXT_CHUNKSIZEOF(struct sec_path),
  4471	#endif
  4472	#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
  4473		[TC_SKB_EXT] = SKB_EXT_CHUNKSIZEOF(struct tc_skb_ext),
  4474	#endif
  4475	#if IS_ENABLED(CONFIG_MPTCP)
  4476		[SKB_EXT_MPTCP] = SKB_EXT_CHUNKSIZEOF(struct mptcp_ext),
  4477	#endif
  4478	#if IS_ENABLED(CONFIG_MCTP_FLOWS)
  4479		[SKB_EXT_MCTP] = SKB_EXT_CHUNKSIZEOF(struct mctp_flow),
  4480	#endif
  4481	#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
> 4482		[SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
  4483	#endif
  4484	};
  4485
diff mbox series

Patch

diff --git a/include/linux/dsa/oob.h b/include/linux/dsa/oob.h
new file mode 100644
index 000000000000..dbb4a6fb1ce4
--- /dev/null
+++ b/include/linux/dsa/oob.h
@@ -0,0 +1,17 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (C) 2022 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+
+#ifndef _NET_DSA_OOB_H
+#define _NET_DSA_OOB_H
+
+#include <linux/skbuff.h>
+
+struct dsa_oob_tag_info {
+	u16 proto;
+	u16 dp;
+};
+
+int dsa_oob_tag_push(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
+int dsa_oob_tag_pop(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
+#endif
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9fcf534f2d92..e387d6795919 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4571,6 +4571,9 @@  enum skb_ext_id {
 #endif
 #if IS_ENABLED(CONFIG_MCTP_FLOWS)
 	SKB_EXT_MCTP,
+#endif
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
+	SKB_EXT_DSA_OOB,
 #endif
 	SKB_EXT_NUM, /* must be last */
 };
diff --git a/include/net/dsa.h b/include/net/dsa.h
index ee369670e20e..114176efacc9 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -55,6 +55,7 @@  struct phylink_link_state;
 #define DSA_TAG_PROTO_RTL8_4T_VALUE		25
 #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE		26
 #define DSA_TAG_PROTO_LAN937X_VALUE		27
+#define DSA_TAG_PROTO_OOB_VALUE			28
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -85,6 +86,7 @@  enum dsa_tag_protocol {
 	DSA_TAG_PROTO_RTL8_4T		= DSA_TAG_PROTO_RTL8_4T_VALUE,
 	DSA_TAG_PROTO_RZN1_A5PSW	= DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
 	DSA_TAG_PROTO_LAN937X		= DSA_TAG_PROTO_LAN937X_VALUE,
+	DSA_TAG_PROTO_OOB		= DSA_TAG_PROTO_OOB_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1d9719e72f9d..627b0b9c0b23 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -61,8 +61,12 @@ 
 #include <linux/if_vlan.h>
 #include <linux/mpls.h>
 #include <linux/kcov.h>
+#ifdef CONFIG_NET_DSA_TAG_OOB
+#include <linux/dsa/oob.h>
+#endif
 
 #include <net/protocol.h>
+#include <net/dsa.h>
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/checksum.h>
@@ -4474,6 +4478,9 @@  static const u8 skb_ext_type_len[] = {
 #if IS_ENABLED(CONFIG_MCTP_FLOWS)
 	[SKB_EXT_MCTP] = SKB_EXT_CHUNKSIZEOF(struct mctp_flow),
 #endif
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
+	[SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
+#endif
 };
 
 static __always_inline unsigned int skb_ext_total_length(void)
@@ -4493,6 +4500,9 @@  static __always_inline unsigned int skb_ext_total_length(void)
 #endif
 #if IS_ENABLED(CONFIG_MCTP_FLOWS)
 		skb_ext_type_len[SKB_EXT_MCTP] +
+#endif
+#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
+		skb_ext_type_len[SKB_EXT_DSA_OOB] +
 #endif
 		0;
 }
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 3eef72ce99a4..c50508e9f636 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -57,6 +57,14 @@  config NET_DSA_TAG_HELLCREEK
 	  Say Y or M if you want to enable support for tagging frames
 	  for the Hirschmann Hellcreek TSN switches.
 
+config NET_DSA_TAG_OOB
+	select SKB_EXTENSIONS
+	tristate "Tag driver for Out-of-band tagging drivers"
+	help
+	  Say Y or M if you want to enable support for tagging out-of-band. In
+	  that case, the MAC driver becomes responsible for sending the tag to
+	  the switch, outside the inband data.
+
 config NET_DSA_TAG_GSWIP
 	tristate "Tag driver for Lantiq / Intel GSWIP switches"
 	help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index bf57ef3bce2a..fff657064be4 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -17,6 +17,7 @@  obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
 obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o
 obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
 obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
+obj-$(CONFIG_NET_DSA_TAG_OOB) += tag_oob.o
 obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
 obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
diff --git a/net/dsa/tag_oob.c b/net/dsa/tag_oob.c
new file mode 100644
index 000000000000..f8fba8406307
--- /dev/null
+++ b/net/dsa/tag_oob.c
@@ -0,0 +1,80 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* Copyright (c) 2022, Maxime Chevallier <maxime.chevallier@bootlin.com> */
+
+#include <linux/bitfield.h>
+#include <linux/dsa/oob.h>
+#include <linux/skbuff.h>
+
+#include "dsa_priv.h"
+
+#define DSA_OOB_TAG_LEN 4
+
+int dsa_oob_tag_push(struct sk_buff *skb, struct dsa_oob_tag_info *ti)
+{
+	struct dsa_oob_tag_info *tag_info;
+
+	tag_info = skb_ext_add(skb, SKB_EXT_DSA_OOB);
+
+	tag_info->dp = ti->dp;
+
+	return 0;
+}
+EXPORT_SYMBOL(dsa_oob_tag_push);
+
+int dsa_oob_tag_pop(struct sk_buff *skb, struct dsa_oob_tag_info *ti)
+{
+	struct dsa_oob_tag_info *tag_info;
+
+	tag_info = skb_ext_find(skb, SKB_EXT_DSA_OOB);
+	if (!tag_info)
+		return -EINVAL;
+
+	ti->dp = tag_info->dp;
+
+	return 0;
+}
+EXPORT_SYMBOL(dsa_oob_tag_pop);
+
+static struct sk_buff *oob_tag_xmit(struct sk_buff *skb,
+				    struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	struct dsa_oob_tag_info tag_info;
+
+	tag_info.dp = dp->index;
+
+	if (dsa_oob_tag_push(skb, &tag_info))
+		return NULL;
+
+	return skb;
+}
+
+static struct sk_buff *oob_tag_rcv(struct sk_buff *skb,
+				   struct net_device *dev)
+{
+	struct dsa_oob_tag_info tag_info;
+
+	if (dsa_oob_tag_pop(skb, &tag_info))
+		return NULL;
+
+	skb->dev = dsa_master_find_slave(dev, 0, tag_info.dp);
+	if (!skb->dev)
+		return NULL;
+
+	return skb;
+}
+
+const struct dsa_device_ops oob_tag_dsa_ops = {
+	.name	= "oob",
+	.proto	= DSA_TAG_PROTO_OOB,
+	.xmit	= oob_tag_xmit,
+	.rcv	= oob_tag_rcv,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DSA tag driver for out-of-band tagging");
+MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OOB);
+
+module_dsa_tag_driver(oob_tag_dsa_ops);