From 2e4193f3cfa23f6c85f479ef10bf779406538f3c Mon Sep 17 00:00:00 2001 From: Matthew Hagan Date: Sun, 26 Sep 2021 11:23:27 +0000 Subject: [PATCH] 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 --- ...t-skb-offload_fwd_mark-when-not-offl.patch | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 target/linux/generic/backport-5.10/794-v5.15-net-dsa-don-t-set-skb-offload_fwd_mark-when-not-offl.patch diff --git a/target/linux/generic/backport-5.10/794-v5.15-net-dsa-don-t-set-skb-offload_fwd_mark-when-not-offl.patch b/target/linux/generic/backport-5.10/794-v5.15-net-dsa-don-t-set-skb-offload_fwd_mark-when-not-offl.patch new file mode 100644 index 00000000000..ab4fdf85093 --- /dev/null +++ b/target/linux/generic/backport-5.10/794-v5.15-net-dsa-don-t-set-skb-offload_fwd_mark-when-not-offl.patch @@ -0,0 +1,138 @@ +From bea7907837c57a0aaac009931eb14efb056dafab Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +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 +Reviewed-by: Tobias Waldekranz +Signed-off-by: David S. Miller +--- + 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; + }