kernel: 5.10: dsa: don't set skb->offload_fwd_mark when not offloading bridge
Add Vladimir Oltean's "net: dsa: don't set skb->offload_fwd_mark when not offloading the bridge" This covers cases where packets received by an upstream switch must be forwarded back on the same port, which skb->offload_fwd_mark normally prevents. Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						Rafał Miłecki
					
				
			
			
				
	
			
			
			
						parent
						
							b2cfed48f6
						
					
				
				
					commit
					2e4193f3cf
				
			@@ -0,0 +1,138 @@
 | 
			
		||||
From bea7907837c57a0aaac009931eb14efb056dafab Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
 | 
			
		||||
Date: Thu, 29 Jul 2021 17:56:00 +0300
 | 
			
		||||
Subject: [PATCH] net: dsa: don't set skb->offload_fwd_mark when not offloading
 | 
			
		||||
 the bridge
 | 
			
		||||
 | 
			
		||||
DSA has gained the recent ability to deal gracefully with upper
 | 
			
		||||
interfaces it cannot offload, such as the bridge, bonding or team
 | 
			
		||||
drivers. When such uppers exist, the ports are still in standalone mode
 | 
			
		||||
as far as the hardware is concerned.
 | 
			
		||||
 | 
			
		||||
But when we deliver packets to the software bridge in order for that to
 | 
			
		||||
do the forwarding, there is an unpleasant surprise in that the bridge
 | 
			
		||||
will refuse to forward them. This is because we unconditionally set
 | 
			
		||||
skb->offload_fwd_mark = true, meaning that the bridge thinks the frames
 | 
			
		||||
were already forwarded in hardware by us.
 | 
			
		||||
 | 
			
		||||
Since dp->bridge_dev is populated only when there is hardware offload
 | 
			
		||||
for it, but not in the software fallback case, let's introduce a new
 | 
			
		||||
helper that can be called from the tagger data path which sets the
 | 
			
		||||
skb->offload_fwd_mark accordingly to zero when there is no hardware
 | 
			
		||||
offload for bridging. This lets the bridge forward packets back to other
 | 
			
		||||
interfaces of our switch, if needed.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
 | 
			
		||||
Reviewed-by: Tobias Waldekranz <tobias@waldekranz.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 net/dsa/dsa_priv.h         | 14 ++++++++++++++
 | 
			
		||||
 net/dsa/tag_brcm.c         |  4 ++--
 | 
			
		||||
 net/dsa/tag_dsa.c          | 15 +++++++++++----
 | 
			
		||||
 net/dsa/tag_ksz.c          |  2 +-
 | 
			
		||||
 net/dsa/tag_lan9303.c      |  3 ++-
 | 
			
		||||
 net/dsa/tag_mtk.c          |  2 +-
 | 
			
		||||
 net/dsa/tag_ocelot.c       |  2 +-
 | 
			
		||||
 net/dsa/tag_rtl4_a.c       |  2 +-
 | 
			
		||||
 net/dsa/tag_sja1105.c      | 20 ++++++++++++++------
 | 
			
		||||
 9 files changed, 47 insertions(+), 17 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/net/dsa/dsa_priv.h
 | 
			
		||||
+++ b/net/dsa/dsa_priv.h
 | 
			
		||||
@@ -266,6 +266,20 @@ static inline struct sk_buff *dsa_untag_
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/* If the ingress port offloads the bridge, we mark the frame as autonomously
 | 
			
		||||
+ * forwarded by hardware, so the software bridge doesn't forward in twice, back
 | 
			
		||||
+ * to us, because we already did. However, if we're in fallback mode and we do
 | 
			
		||||
+ * software bridging, we are not offloading it, therefore the dp->bridge_dev
 | 
			
		||||
+ * pointer is not populated, and flooding needs to be done by software (we are
 | 
			
		||||
+ * effectively operating in standalone ports mode).
 | 
			
		||||
+ */
 | 
			
		||||
+static inline void dsa_default_offload_fwd_mark(struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct dsa_port *dp = dsa_slave_to_port(skb->dev);
 | 
			
		||||
+
 | 
			
		||||
+	skb->offload_fwd_mark = !!(dp->bridge_dev);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* switch.c */
 | 
			
		||||
 int dsa_switch_register_notifier(struct dsa_switch *ds);
 | 
			
		||||
 void dsa_switch_unregister_notifier(struct dsa_switch *ds);
 | 
			
		||||
--- a/net/dsa/tag_brcm.c
 | 
			
		||||
+++ b/net/dsa/tag_brcm.c
 | 
			
		||||
@@ -166,7 +166,7 @@ static struct sk_buff *brcm_tag_rcv_ll(s
 | 
			
		||||
 	/* Remove Broadcom tag and update checksum */
 | 
			
		||||
 	skb_pull_rcsum(skb, BRCM_TAG_LEN);
 | 
			
		||||
 
 | 
			
		||||
-	skb->offload_fwd_mark = 1;
 | 
			
		||||
+	dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
@@ -270,7 +270,7 @@ static struct sk_buff *brcm_leg_tag_rcv(
 | 
			
		||||
 	/* Remove Broadcom tag and update checksum */
 | 
			
		||||
 	skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN);
 | 
			
		||||
 
 | 
			
		||||
-	skb->offload_fwd_mark = 1;
 | 
			
		||||
+	dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	/* Move the Ethernet DA and SA */
 | 
			
		||||
 	memmove(skb->data - ETH_HLEN,
 | 
			
		||||
--- a/net/dsa/tag_ksz.c
 | 
			
		||||
+++ b/net/dsa/tag_ksz.c
 | 
			
		||||
@@ -24,7 +24,7 @@ static struct sk_buff *ksz_common_rcv(st
 | 
			
		||||
 
 | 
			
		||||
 	pskb_trim_rcsum(skb, skb->len - len);
 | 
			
		||||
 
 | 
			
		||||
-	skb->offload_fwd_mark = true;
 | 
			
		||||
+	dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
--- a/net/dsa/tag_lan9303.c
 | 
			
		||||
+++ b/net/dsa/tag_lan9303.c
 | 
			
		||||
@@ -115,7 +115,8 @@ static struct sk_buff *lan9303_rcv(struc
 | 
			
		||||
 	skb_pull_rcsum(skb, 2 + 2);
 | 
			
		||||
 	memmove(skb->data - ETH_HLEN, skb->data - (ETH_HLEN + LAN9303_TAG_LEN),
 | 
			
		||||
 		2 * ETH_ALEN);
 | 
			
		||||
-	skb->offload_fwd_mark = !(lan9303_tag1 & LAN9303_TAG_RX_TRAPPED_TO_CPU);
 | 
			
		||||
+	if (!(lan9303_tag1 & LAN9303_TAG_RX_TRAPPED_TO_CPU))
 | 
			
		||||
+		dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
--- a/net/dsa/tag_mtk.c
 | 
			
		||||
+++ b/net/dsa/tag_mtk.c
 | 
			
		||||
@@ -104,7 +104,7 @@ static struct sk_buff *mtk_tag_rcv(struc
 | 
			
		||||
 
 | 
			
		||||
 	/* Only unicast or broadcast frames are offloaded */
 | 
			
		||||
 	if (likely(!is_multicast_skb))
 | 
			
		||||
-		skb->offload_fwd_mark = 1;
 | 
			
		||||
+		dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
--- a/net/dsa/tag_ocelot.c
 | 
			
		||||
+++ b/net/dsa/tag_ocelot.c
 | 
			
		||||
@@ -225,7 +225,7 @@ static struct sk_buff *ocelot_rcv(struct
 | 
			
		||||
 		 */
 | 
			
		||||
 		return NULL;
 | 
			
		||||
 
 | 
			
		||||
-	skb->offload_fwd_mark = 1;
 | 
			
		||||
+	dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 	skb->priority = qos_class;
 | 
			
		||||
 
 | 
			
		||||
 	/* Ocelot switches copy frames unmodified to the CPU. However, it is
 | 
			
		||||
--- a/net/dsa/tag_rtl4_a.c
 | 
			
		||||
+++ b/net/dsa/tag_rtl4_a.c
 | 
			
		||||
@@ -115,7 +115,7 @@ static struct sk_buff *rtl4a_tag_rcv(str
 | 
			
		||||
 		skb->data - ETH_HLEN - RTL4_A_HDR_LEN,
 | 
			
		||||
 		2 * ETH_ALEN);
 | 
			
		||||
 
 | 
			
		||||
-	skb->offload_fwd_mark = 1;
 | 
			
		||||
+	dsa_default_offload_fwd_mark(skb);
 | 
			
		||||
 
 | 
			
		||||
 	return skb;
 | 
			
		||||
 }
 | 
			
		||||
		Reference in New Issue
	
	Block a user