HSR/PRP require per-wire-frame tags and sequence numbers. Treating a GSO skb as one frame breaks those semantics. Classify GSO skbs at the forward entry by effective protocol rather than ingress port. Segment plain aggregates and process every segment normally, preserving local delivery and forwarding. Drop ETH_P_HSR, ETH_P_PRP and unreadable aggregates because their per-frame metadata cannot be rebuilt. HSR supports one 802.1Q C-tag, so unsupported stacked or S-tag GSO input is rejected before segmentation. In-tree software GRO does not merge PRP RCT frames because its IPv4 and IPv6 length checks reject trailing bytes. This guarantee does not cover device-specific fixed-on GRO_HW output. Also remove GSO features from the HSR master's hw_features when possible. This patch depends on patch 2 and the sparse-bitmap duplicate discard in 7.0 and newer; older trees require an adapted backport. Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)") Cc: # 7.0.x Signed-off-by: Xin Xie --- net/hsr/hsr_device.c | 2 +- net/hsr/hsr_forward.c | 102 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 3fd1762d8916..248cbb142e21 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -652,7 +652,7 @@ void hsr_dev_setup(struct net_device *dev) dev->needs_free_netdev = true; dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER; diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 87cd72a1dc65..f42694cf4309 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "hsr_main.h" #include "hsr_framereg.h" @@ -732,7 +733,7 @@ static int fill_frame_info(struct hsr_frame_info *frame, } /* Must be called holding rcu read lock (because of the port parameter) */ -void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) +static void hsr_forward_skb_one(struct sk_buff *skb, struct hsr_port *port) { struct hsr_frame_info frame; @@ -761,3 +762,102 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) DEV_STATS_INC(port->dev, tx_dropped); kfree_skb(skb); } + +/* GSO fan-out funnel: unfold super-packets before per-frame processing so + * each wire frame gets its own HSR/PRP tag and sequence number. + */ +/* Effective frame protocol of a (possibly VLAN-tagged) skb, or 0 when + * it cannot be determined or the tagging exceeds what HSR supports. + * HSR supports one 802.1Q C-tag only, matching fill_frame_info(): an + * accelerated tag must be a C-tag with a non-VLAN inner protocol; an + * in-band tag is unwrapped exactly once and a residual VLAN EtherType + * is rejected. Read-only; no state is kept beyond the immediate + * protocol value. + */ +static __be16 hsr_gso_effective_proto(const struct sk_buff *skb) +{ + struct ethhdr eh; + struct vlan_hdr vh; + const struct ethhdr *eth; + const struct vlan_hdr *vhdr; + __be16 proto; + + if (skb_vlan_tag_present(skb)) { + /* HSR supports one 802.1Q C-tag only. */ + if (skb->vlan_proto != htons(ETH_P_8021Q)) + return 0; + if (eth_type_vlan(skb->protocol)) + return 0; + return skb->protocol; + } + + eth = skb_header_pointer(skb, 0, sizeof(eh), &eh); + if (!eth) + return 0; + + proto = eth->h_proto; + if (!eth_type_vlan(proto)) + return proto; + if (proto != htons(ETH_P_8021Q)) + return 0; + + vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(vh), &vh); + if (!vhdr) + return 0; + + proto = vhdr->h_vlan_encapsulated_proto; + if (eth_type_vlan(proto)) + return 0; + + return proto; +} + +void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) +{ + struct sk_buff *segs, *next; + __be16 proto; + + if (likely(!skb_is_gso(skb))) { + hsr_forward_skb_one(skb, port); + return; + } + + /* Conforming plain-protocol GSO super-packets carry trailer-free + * sender payload and are segmented here: each segment is delivered + * or forwarded as its own wire frame, on any ingress role. + * + * The gate is content-based, not port-based. An aggregate whose + * effective protocol is ETH_P_HSR or ETH_P_PRP cannot be safely + * segmented and is dropped, as is any skb whose header cannot be + * read or whose tagging exceeds the single 802.1Q C-tag HSR + * supports. With NETIF_F_HW_HSR_TAG_RM the lower has already + * stripped the tag, so such aggregates arrive plain and are + * segmented. + */ + proto = hsr_gso_effective_proto(skb); + if (!proto) + goto drop_gso; /* classification failure, fail-safe */ + if (proto == htons(ETH_P_HSR) || proto == htons(ETH_P_PRP)) + goto drop_gso; + + /* features = 0: request full software segmentation. tx_path is true + * only for locally generated traffic on the master; ingress from + * the interlink follows RX checksum semantics. + */ + segs = __skb_gso_segment(skb, 0, port->type == HSR_PT_MASTER); + if (IS_ERR(segs) || unlikely(!segs)) + goto drop_gso; + + consume_skb(skb); + while (segs) { + next = segs->next; + segs->next = NULL; + hsr_forward_skb_one(segs, port); + segs = next; + } + return; + +drop_gso: + DEV_STATS_INC(port->dev, tx_dropped); + kfree_skb(skb); +} -- 2.43.0