From nobody Tue Sep 29 09:46:20 2026 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 282AC3C109C for ; Sun, 9 Aug 2026 12:15:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277702; cv=none; b=XWnhdt2rthXzHtm+evoKNz0Amwwf8VMYof5ogWVDConffFijPB6Qgt/QBsR7wlfMyf1zR2jB1jcDGgMGG+tGuCrSAPa/LWewHnJRgtM4bI/nYXcNUwot0xy/o/MPbq5wooa3Iqo8A94Xv28seaoikJIENFHVEwthsE4Lqf0nZWM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277702; c=relaxed/simple; bh=nUOVeBFFUPO0EXBKrcOK+AXygJbNMgByifpoRqFKklY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AXcaIHRXiIuCeCePA4oIBGU5L/HUDG0tLIx8ytyqCgsaId/dr+5x6tQSEUGobqr8EJgojJHZerih6sV5k3d2tl2UJSNZJx9FvAHSDyRjgTy1e8qkN6WiXpA7sYMwa80AW/a5sbZ9k8JctpoOyqVZLk3ITXHp7Hqq5tqlgmSO3bI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=rpFVWZVL; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="rpFVWZVL" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-47fe45db360so119545f8f.2 for ; Sun, 09 Aug 2026 05:15:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786277698; x=1786882498; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Tjt5VhvveBeVhJ7gVkQsZLN+QtuDGPYHnEEQcH//h8s=; b=rpFVWZVLH3wwUN0P/t6fs6jFdpeP9LNUcUVSNpK04vDbyeKwUZ0CeSAVHswpA4yEJY pv4P0mRJ6Yd7Mhg6Nu5xoxwHpHcu0DBtg2d7Oyfy8S2tA6n5MRIG/hglnAYaalxT92jw +n71l5NpbtmPyTBXpVhv3faUBOOFumjhjP0cNe3+6bLcB5DWFhtaJhmqar0carvqkhDS uSMn8qYHq2LT4ZsdAknkDsWbZTWD4LDN8GHo37gjOyylJ9tACzU+xnsc5A0Lkyt0vGvJ 6EAyCMWlaYoryDnMiiEFdL56rJbg/jlizLkmgc7+A63waBOxIj+2s6elGO4IG/UFkQ0O F9Fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786277698; x=1786882498; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Tjt5VhvveBeVhJ7gVkQsZLN+QtuDGPYHnEEQcH//h8s=; b=QI2aq5s/mlG2NheebjuaiUZl1FBbdaxoWZepnFlIvbD6zXBZZsJW9D4C6zhTyJFxaT ZV400eKCt4pktygblcUwsA1zWj+Zc2FfdHrAioxsjhAVOQoBWVL1LGNTgA+lwMsmT4UV 0UtvEmKUHj73HLzBawf/OfutMzlZizKCmzhe8S+U8gSAoLfw8nrezKMJ3tRF5A25qpYD bwVr2ta1FkcOPeOeBC2Ghtzzeg6VNenQx+WlmyZEIRn+QhWOIlwoTajFxHvLtT+JZAtr W+mj4nAPgLasPFV7ENMZb/Dtz35eD/PLKZmnBXYz00zxM4f89RJHjcDeSFMiJ7qCAqbT glqg== X-Forwarded-Encrypted: i=1; AHgh+RrJdGKY7uCJU7UQTP3szvHt3gfl+79taIslS9THPQjkDoLZBpn/lzi2woz/g/nMWHhK8+u5dj68WL9b2fw=@vger.kernel.org X-Gm-Message-State: AOJu0YwMVapQdlS5gJP0nHnJEX+xbMr42bdhMPx4EqZ4RrPiUH3ntU8p x2jNESPjlzGE5NxWN5RhTedaXzMAJgeaxESyHP3UbS3G6V7MSS5Dw4RO X-Gm-Gg: AR+sD100NFdWGZa5Ky0STy0PhuyuO6rlBCgaF9VY10FkoEmDH/45RW9YQTsJrIQR4pw a2f1tb5bxLTo8+JqI+vxd2W60EM62LhIqbymSa29t0bdmVMHtMXMHUJ8dXePCpSH1gEIQM/jkHX ELjAI1Jvtv3qqd1ocFDennCs9/dmIo7AwBKHWYFKioQkxpztHEevb9rZ73isuOrsptkpr2tiPGt 1LzN2bE32SG9N0QU8z7R6AfvgUil5F3aDt1rf0aqZYFCvmpsNoGr6r0ZZMlmZ4NAijTeOMeh5p6 041aIFUlZr6jNTkl0uPhZHRvrIPeUjdk6QBP52b2TjiB7g6PbxH2wCtN+DOYcTQBdmwcA5DdIG8 udg1QIqoZ1Hae9uj461Fy2fx6XUGl23l9cPNz0U0gRB8K2ZmElON5rhSe87SNHjtBxZ0n6i9O3M iyvyl6nWzAehJijozWxF9bjVzRCD+KgqwjtoyOBUJVp0Jz4XS9Df3LCqEAQi99t+Ne43++IA8yr E6+FsgPkGBCMk+GBwhHQRXT5QDqmpGkt/zMZvr6+Cxd+mRArK4iHLkNyHkoLpv+LB6s9FRDHTxH wsfmG7f3De+BqGTog+2b X-Received: by 2002:a05:600c:1d10:b0:498:8e6:d463 with SMTP id 5b1f17b1804b1-4994e79b14emr243848055e9.1.1786277698245; Sun, 09 Aug 2026 05:14:58 -0700 (PDT) Received: from L-022584.energy.envision.com (dynamic-077-012-133-135.77.12.pool.telefonica.de. [77.12.133.135]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-480021e7b3fsm25158434f8f.20.2026.08.09.05.14.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Aug 2026 05:14:57 -0700 (PDT) From: Xin Xie To: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch, shuah@kernel.org, kees@kernel.org, petr.wozniak@gmail.com, qingfang.deng@linux.dev, fmaurer@redhat.com, luka.gejak@linux.dev, bigeasy@linutronix.de, xiaoliang.yang_1@nxp.com, skhawaja@google.com, liuhangbin@gmail.com, stable@vger.kernel.org, sdf.kernel@gmail.com, Xin Xie Subject: [PATCH 1/4] net: hsr: fix packet drops caused by GRO superpackets Date: Sun, 9 Aug 2026 14:14:51 +0200 Message-ID: <20260809121455.1745-2-xiexinet@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260809121455.1745-1-xiexinet@gmail.com> References: <20260809121455.1745-1-xiexinet@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" HSR/PRP process each wire frame separately for tagging and duplicate discard. GRO on a lower device hides multiple frames in one skb, which cannot be forwarded with valid per-frame metadata. Disable GRO and GRO_HW when a lower device is enslaved, matching the existing LRO handling. This is best effort because GRO may be re-enabled and some devices cannot disable GRO_HW. The forward-entry segmentation fix handles plain, trailer-free GSO skbs that still arrive; device-specific fixed-on GRO_HW output is outside this guarantee. Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamle= ss Redundancy protocol (HSRv0)") Cc: stable@vger.kernel.org Signed-off-by: Xin Xie --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 15 +++++++++++++++ net/core/dev_api.c | 21 +++++++++++++++++++++ net/hsr/hsr_slave.c | 5 +++++ 4 files changed, 43 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9981d637f8b5..eba2c26a49ba 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3434,6 +3434,8 @@ void dev_close(struct net_device *dev); void netif_close_many(struct list_head *head, bool unlink); void netif_disable_lro(struct net_device *dev); void dev_disable_lro(struct net_device *dev); +void netif_disable_gro(struct net_device *dev); +void dev_disable_gro(struct net_device *dev); int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *ne= wskb); u16 dev_pick_tx_zero(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev); diff --git a/net/core/dev.c b/net/core/dev.c index 5933c5dab09e..f20d5ab0cf72 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1840,6 +1840,21 @@ void netif_disable_lro(struct net_device *dev) } } =20 +void netif_disable_gro(struct net_device *dev) +{ + struct net_device *lower_dev; + struct list_head *iter; + + dev->wanted_features &=3D ~(NETIF_F_GRO | NETIF_F_GRO_HW); + netdev_update_features(dev); + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + netdev_lock_ops(lower_dev); + netif_disable_gro(lower_dev); + netdev_unlock_ops(lower_dev); + } +} + /** * dev_disable_gro_hw - disable HW Generic Receive Offload on a device * @dev: device diff --git a/net/core/dev_api.c b/net/core/dev_api.c index 437947dd08ed..3ca2515ad048 100644 --- a/net/core/dev_api.c +++ b/net/core/dev_api.c @@ -269,6 +269,27 @@ void dev_disable_lro(struct net_device *dev) } EXPORT_SYMBOL(dev_disable_lro); =20 +/** + * dev_disable_gro() - disable Generic Receive Offload on a device + * @dev: device + * + * Best-effort disable of Generic Receive Offload (GRO) on a net + * device. Must be called under RTNL. This is needed if received + * packets may be forwarded to another interface. + * + * The disable is best-effort: a device with a fixed-on feature (for + * example GRO_HW on a virtio-net device negotiated without + * VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) keeps it enabled. Callers that + * need a hard guarantee must inspect the resulting feature state. + */ +void dev_disable_gro(struct net_device *dev) +{ + netdev_lock_ops(dev); + netif_disable_gro(dev); + netdev_unlock_ops(dev); +} +EXPORT_SYMBOL(dev_disable_gro); + /** * dev_set_promiscuity() - update promiscuity count on a device * @dev: device diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 01c73b4b50dd..bb2182a169a3 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -171,6 +171,11 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, str= uct net_device *dev, goto fail_rx_handler; dev_disable_lro(dev); =20 + /* GRO disabling is best-effort: fixed-on GRO_HW cannot be + * forced off, and GRO may be re-enabled later via ethtool. + */ + dev_disable_gro(dev); + return 0; =20 fail_rx_handler: --=20 2.43.0 From nobody Tue Sep 29 09:46:20 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 86FED3CF942 for ; Sun, 9 Aug 2026 12:15:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277705; cv=none; b=djuYSv2ZXM44/ZMbalj6/9bBDdU+AEMQ0v92/T+FCVXuZGzbq/0QKYpstGGW96zVD3nipJT1zVooH77zlhJZZYJa7l+DDF9H4MTQTkJ+33XsSveVqVCQTK5L3i3FEIluR+w6bSsZfLkbt45se3XjZTrhQAj+0am47Cr+P+Kv7SU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277705; c=relaxed/simple; bh=uacT/jei5dgba42+Tsf6fcoe45L0FIC0Fpqbwa8RlWs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oM7+TccIt4dtsc2e4ulCH5OVhbSACopQb2Y6CrmIP5kPkjgguXgdk5QCl9qQCSxkiscNnuH5DamQmFaNGlok1qKP2HEnSQeJgZ4vGOwlfgAxx12ZOpFb7uFHzIdfZ4P7LF0hG2qBjnIPeZgqK7/xNF+pd41m9tE5cyRfHPcCI1I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=R0ll42kZ; arc=none smtp.client-ip=209.85.128.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="R0ll42kZ" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-4957739c22fso207355e9.3 for ; Sun, 09 Aug 2026 05:15:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786277700; x=1786882500; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=QTUwYlCoLFw4wVzo6jM7Q/KRvDXTLX460FJlpDvikKk=; b=R0ll42kZXuVmbJXoWrTzcwH2M6oHcn74Qs4x/MpIbFDPgqjClEjCqZA8oEumUMAY2D FLO8j3JY/7LpDvqIXdEGl9TosNItsoPtIQVmjsx9JO3D6F/LxDQixYxLuMEUCG6nEpX3 mmTeHQ76lNblm7Rscm/aHnyhjJyvpVf6agogCKm4ze2lxPTrRl0KG6eLTHNLjv1T47QE 2HKujjKWucH7JMCJHe3qDpG1atqTvYvxXPEkzu3edENTvBNwwS/7FbT5Kf1PqpctYyEU CvweAzvRcfemeMshhMxZoulokaS9HRy6zdUoGo5g+PyLSoJfb0EhiVUv4MFAsVqd3X53 edyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786277700; x=1786882500; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=QTUwYlCoLFw4wVzo6jM7Q/KRvDXTLX460FJlpDvikKk=; b=q1KgP/hmJjOiWfp+wDqJf8jMt3xIdex2kT54wEF3V+moVlnaU4eTGd7X33qidpruig rzSxaCYJ0kvjbUkAJRtuc/QXB7/yWys4mbFX3EH5tD/baHCjVkqNbchrC5P0vlru/jrb Ud0oVfQbBGY0DadN5qIeSUe/jmfFa2NthVotHIf4hUMlrfAsL9tFeDZ8dPKMBm/F4gbM UV0DEe7qAqTvqjfLO+8p7S6oeTqSVoUhRF8JSxq23SK+cHaUuTd0gBdgw+WNPQmTkqE7 acobT6EnwOH0Pal4zADvYlKtu2+FoDc/SjCYEGFRUi5+Y0lDATWuq8YZ8Y0q9MqSXRHN 3pQQ== X-Forwarded-Encrypted: i=1; AHgh+RpXi+kBL4aTQ2Coa2e1KmdKza7+MoG/e//5h/Xg3ldM67o7VbFWB0n1K3nsHoiMDRJw+04VW9GdYrZGiAw=@vger.kernel.org X-Gm-Message-State: AOJu0Yyx9ytteD3DAyeAXe28Ck9MWF0hEjuvuR8Xu45CGuB7bdPn16Ae 6QDdThEIRsnPKdGB9iDEzeTlel088e1x6Y0TTBLpEAYxeeOiCxncH2IP X-Gm-Gg: AR+sD11ft8NHAFeiI36sqIjKj62tRLnxa6YZM6Q3zODyhP62xcqNpoeGxvjILBnAFEd vlfCZoK8CEv7WBW8TUMJq72GnQtHeeKhAxQjsO3fMx4178NVYnqP2b2zmU5Wdey+auy0i0aAs7A oko3eZiQ7DNjT5DVh5WgZNil/DJeWveWNhxg6Qju+HiCyihM/8eF4VEdVNuVZzTIRITtz8jlugY yjNWTxiTFHhPy4XANFQiJFoCMjqhLuW6q3il5feulOvv+rzZXS40hOwl654bsgpApy7jcqYEdwQ cNzspJoLedF/UbYT3m97QAOSCxXcNPI/Qrz1zTCKZ6L7WhJWnKQ1kUccm2HNA0ibAVrNSX2lw1Z 3m7zxwCN8Go38+Lm3gkrhPhRTpz6aiNnHl0212MkJmZxf6ppjItTeGS3kCDGmV30mIJviJl1ZOA sINbP8ifkqXyCCZLhJJSRf0l+xoL8cHJ0xPVrcgfZlSqO1aiKmhTOA3k+/Q3BrNbFB+HNYutrOz +jnq/jZ1pQUpd5Tr026FOboiba4ILVsWQEiuskwEknPzl+P4iNEK9PKV+k9aiV3WUNoXAfIbrfF ZAa1vTNK2fcUe+4XROWYag== X-Received: by 2002:a05:600c:1393:b0:495:650b:4c61 with SMTP id 5b1f17b1804b1-4994e7d0166mr247269495e9.3.1786277699563; Sun, 09 Aug 2026 05:14:59 -0700 (PDT) Received: from L-022584.energy.envision.com (dynamic-077-012-133-135.77.12.pool.telefonica.de. [77.12.133.135]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-480021e7b3fsm25158434f8f.20.2026.08.09.05.14.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Aug 2026 05:14:59 -0700 (PDT) From: Xin Xie To: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch, shuah@kernel.org, kees@kernel.org, petr.wozniak@gmail.com, qingfang.deng@linux.dev, fmaurer@redhat.com, luka.gejak@linux.dev, bigeasy@linutronix.de, xiaoliang.yang_1@nxp.com, skhawaja@google.com, liuhangbin@gmail.com, stable@vger.kernel.org, sdf.kernel@gmail.com, Xin Xie , syzbot+fbf74291c3b7e753b481@syzkaller.appspotmail.com Subject: [PATCH 2/4] net: hsr: shrink seqnr_lock to sequence counter updates Date: Sun, 9 Aug 2026 14:14:52 +0200 Message-ID: <20260809121455.1745-3-xiexinet@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260809121455.1745-1-xiexinet@gmail.com> References: <20260809121455.1745-1-xiexinet@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Commit 06afd2c31d33 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.") and commit 430d67bdcb04 ("net: hsr: Use the seqnr lock for frames received via interlink port.") hold seqnr_lock across the whole forwarding path. Transmitting while holding the lock can create lock-dependency issues when HSR devices are stacked with other net devices, up to a real deadlock (see Reported-by/Closes). Since commit aae9d6b616b5 ("hsr: Implement more robust duplicate discard for HSR"), duplicate discard is order-independent (sparse bitmaps), so only the sequence counter updates need serialization. Limit seqnr_lock to the counter updates in handle_std_frame(); the master TX path (hsr_dev_xmit()) and the interlink RX path (hsr_handle_frame()) drop their outer lock, and the supervision frame builders release it right after their counter update. Concurrent forwarding may emit frames out of allocation order, which sparse-bitmap discard tolerates. The master/interlink tx statistics are no longer serialized; consistent per-cpu/per-queue statistics for all HSR paths are handled in a separate series. Fixes: 06afd2c31d33 ("hsr: Synchronize sending frames to have always increm= ented outgoing seq nr.") Fixes: 430d67bdcb04 ("net: hsr: Use the seqnr lock for frames received via = interlink port.") Reported-by: syzbot+fbf74291c3b7e753b481@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3Dfbf74291c3b7e753b481 Cc: # aae9d6b616b5: hsr: Implement more robust dup= licate discard for HSR Signed-off-by: Xin Xie Reported-by/Closes). Reviewed-by: Hangbin Liu --- net/hsr/hsr_device.c | 15 ++++----------- net/hsr/hsr_forward.c | 3 ++- net/hsr/hsr_slave.c | 11 +---------- 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 5555b71ab19b..3fd1762d8916 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -232,9 +232,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, st= ruct net_device *dev) skb->dev =3D master->dev; skb_reset_mac_header(skb); skb_reset_mac_len(skb); - spin_lock_bh(&hsr->seqnr_lock); hsr_forward_skb(skb, master); - spin_unlock_bh(&hsr->seqnr_lock); } else { dev_core_stats_tx_dropped_inc(dev); dev_kfree_skb_any(skb); @@ -335,6 +333,7 @@ static void send_hsr_supervision_frame(struct hsr_port = *port, hsr_stag->sequence_nr =3D htons(hsr->sequence_nr); hsr->sequence_nr++; } + spin_unlock_bh(&hsr->seqnr_lock); =20 hsr_stag->tlv.HSR_TLV_type =3D type; /* HSRv0 has 6 unused bytes after the MAC */ @@ -356,14 +355,10 @@ static void send_hsr_supervision_frame(struct hsr_por= t *port, ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox); } =20 - if (skb_put_padto(skb, ETH_ZLEN)) { - spin_unlock_bh(&hsr->seqnr_lock); + if (skb_put_padto(skb, ETH_ZLEN)) return; - } =20 hsr_forward_skb(skb, port); - spin_unlock_bh(&hsr->seqnr_lock); - return; } =20 static void send_prp_supervision_frame(struct hsr_port *master, @@ -390,6 +385,7 @@ static void send_prp_supervision_frame(struct hsr_port = *master, spin_lock_bh(&hsr->seqnr_lock); hsr_stag->sequence_nr =3D htons(hsr->sup_sequence_nr); hsr->sup_sequence_nr++; + spin_unlock_bh(&hsr->seqnr_lock); hsr_stag->tlv.HSR_TLV_type =3D PRP_TLV_LIFE_CHECK_DD; hsr_stag->tlv.HSR_TLV_length =3D sizeof(struct hsr_sup_payload); =20 @@ -397,13 +393,10 @@ static void send_prp_supervision_frame(struct hsr_por= t *master, hsr_sp =3D skb_put(skb, sizeof(struct hsr_sup_payload)); ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); =20 - if (skb_put_padto(skb, ETH_ZLEN)) { - spin_unlock_bh(&hsr->seqnr_lock); + if (skb_put_padto(skb, ETH_ZLEN)) return; - } =20 hsr_forward_skb(skb, master); - spin_unlock_bh(&hsr->seqnr_lock); } =20 /* Announce (supervision frame) timer function diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 0774981a65c1..8e4158a9b57c 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -621,9 +621,10 @@ static void handle_std_frame(struct sk_buff *skb, if (port->type =3D=3D HSR_PT_MASTER || port->type =3D=3D HSR_PT_INTERLINK) { /* Sequence nr for the master/interlink node */ - lockdep_assert_held(&hsr->seqnr_lock); + spin_lock_bh(&hsr->seqnr_lock); frame->sequence_nr =3D hsr->sequence_nr; hsr->sequence_nr++; + spin_unlock_bh(&hsr->seqnr_lock); } } =20 diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index bb2182a169a3..8b96eafe15b3 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -73,16 +73,7 @@ static rx_handler_result_t hsr_handle_frame(struct sk_bu= ff **pskb) } skb_reset_mac_len(skb); =20 - /* Only the frames received over the interlink port will assign a - * sequence number and require synchronisation vs other sender. - */ - if (port->type =3D=3D HSR_PT_INTERLINK) { - spin_lock_bh(&hsr->seqnr_lock); - hsr_forward_skb(skb, port); - spin_unlock_bh(&hsr->seqnr_lock); - } else { - hsr_forward_skb(skb, port); - } + hsr_forward_skb(skb, port); =20 finish_consume: return RX_HANDLER_CONSUMED; --=20 2.43.0 From nobody Tue Sep 29 09:46:20 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C79043D1A9A for ; Sun, 9 Aug 2026 12:15:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277710; cv=none; b=ee+XE4J6dzqtPcymrDTkd2Jhwx7caU/588kJxcRAWr+E1yB/Wsx63fa1H2wzIxL67ZRRRPRYSJF7mHKofBH/Xh6yuVzU/FJ2ygPkiOxazj5n5RaO35B4ZFodC1PIIbgrGaMzOVdsfSZwyuPIj/XpbllWA376zUiLmLnIDwkQWF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277710; c=relaxed/simple; bh=v2IOzHAE8P7e7RPtUYejuCgStYNSB6rjJrtbYCdnJjI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=abS1mAFiDbsN/dc1p94HOKnUetGuR5/nGaDkE3xqtYI9hLkLCwrwihhW2N86WZMFK+yB12wiF4tgF8hvE1BrZjhk22YtQgEubOzpBEDXYyVvuryCQBTYL4RH4n9Z+KodtZInypY+8zhxkYPpeAjjjXl65+gi9nRL7wN1/iOx+VM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jaxRpvxp; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jaxRpvxp" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-473987fc217so26685f8f.0 for ; Sun, 09 Aug 2026 05:15:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786277701; x=1786882501; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=tK5etVjV8isZ+EPgOl8b6oOCjBS1RkzIoG5Pe4Znpcs=; b=jaxRpvxp0+bYmTbQuUsag8eEDCxNEzgqanm0XvuzVSn+sTWBP88Jkh4FXmNy5t7mz8 KbYNwlorwXWySIDuVP4MMWVZfPlXD5sh8HtbWO0mCWdmOGKSmCeVVjfheZbihHL7svER Ga8eHizLOtzHO+RR3sNQwqbU6RQ+EIEny/XTeqMsi4FFsfrFq6y1RtLlyeWDXORQ8uQk Ya7ea/dQ88bbES/bHkRqRIk2S3QOf0BSjaWRuzICqxSxeXM2vbYdAHNH0paz9N70T6Cw q2ekAFuPzcB3JOp/eu7fGtOnPolB1lBb1DS8R1o7a8Jz8zXP52YvLA0nbJgNkar4Ujgr Rdaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786277701; x=1786882501; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=tK5etVjV8isZ+EPgOl8b6oOCjBS1RkzIoG5Pe4Znpcs=; b=Rmh18gvpDInPlgJFea0+g+hAtAgdJSRxink7Bmh7CcaACjm0Ajz9CSBxxRbxyvknDV wSOmdjRz2a6JLv/0D+PbJOPmdNjyFIUf2rDbaXSsdADic8Ridi9slmsr1qCvZtNHaN1U LcnAxlmmqBjbb+Ziwq8DfuvkWxMRtRma8s2G6rRgKYM95oRVreAH1pn0Vja2Hf+IEXov 5AxRcHUsOi2ELl945qLiv8ZYUo7LFK1JKzKtfcyBC2e0+PnLMITUPRZFtDCKKTJHVg4z Bga/3kbpesrCy3ugU4F5inA/5AOiyLj1Mkil5ZcBt3LXhJAjZSQmTcgr/D0mparTPFe2 GinA== X-Forwarded-Encrypted: i=1; AHgh+RrSM7tUAmeuP31S2RE+v9C26bxXHelarvOlTdbFONwx+CmMiYdI8v2+rTapQ0KQ3d6zx+b/XNWLCCmBSYk=@vger.kernel.org X-Gm-Message-State: AOJu0Ywd1UJeUwEsDtQm7LdKOpCCO8n0PUMdse5mLOSXtk2pvQLximQq 1X/pVNltp/owC/NwHs46f1yl+5E/QDaYL2hg8PCLlXztEUB/WP5uEL09 X-Gm-Gg: AR+sD10tZez4XhZp5m3BJvSTfMFyJqQi5dDMSJWJIuLZImidNoTymaHbRpTR68tSQG4 L7HAQTZUJS7z8eiioaekfROuaVFgT5wRU3hxip6c6Q68pnybyq8qOCsmLr/FKS2aJEChj9mRbrf F2Vp9sbai2MjgwuC0mIbYOCbMZJ4ncixpOQM/3I/ffnyZ9igoCX0vparqTi86AQTCcJx2L/CmkE F7+FZRpaMDXeUY1E8cqNNYp+SBUpTF18Jj1Z/9xtpsjQvnSvAiiKxIc0C4gPP692lNx0AlbJ+ee su9zP59SHJ7a4f45c55WGZUn8XL7XTi+IKSdqX64vMGXZa808gJe6i5xFFA+VMzh9oZW0KsHRlb 1gXWA2y1frZVrrjlBJd1rx1ORLY5pCb+dK4F/HL2aC8c4PyNY3nj7p5TWMuQ9sJmk9KrcvogtR+ yklGrUiVxKaOUpzByTaHUMxWuo2bhAY6g5JNKes0JbxWRCKFSQHdgUr8TkIcpOdl8UsBD3lZuhX jukOsmTtUYLxRY8yeazEi1kblDRHHh3aYS1DozHNTcxDWYoBPp4QZ/1iojMjpdFy1bm4Zj6EAPV mop6b+KUDkPGmirDp1LAcmJp9FWEDKo= X-Received: by 2002:a5d:5c82:0:b0:481:3db3:8eb with SMTP id ffacd0b85a97d-4813db3093fmr3525985f8f.1.1786277700954; Sun, 09 Aug 2026 05:15:00 -0700 (PDT) Received: from L-022584.energy.envision.com (dynamic-077-012-133-135.77.12.pool.telefonica.de. [77.12.133.135]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-480021e7b3fsm25158434f8f.20.2026.08.09.05.14.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Aug 2026 05:15:00 -0700 (PDT) From: Xin Xie To: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch, shuah@kernel.org, kees@kernel.org, petr.wozniak@gmail.com, qingfang.deng@linux.dev, fmaurer@redhat.com, luka.gejak@linux.dev, bigeasy@linutronix.de, xiaoliang.yang_1@nxp.com, skhawaja@google.com, liuhangbin@gmail.com, stable@vger.kernel.org, sdf.kernel@gmail.com, Xin Xie Subject: [PATCH 3/4] net: hsr: unfold GSO super-packets at the forward entry Date: Sun, 9 Aug 2026 14:14:53 +0200 Message-ID: <20260809121455.1745-4-xiexinet@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260809121455.1745-1-xiexinet@gmail.com> References: <20260809121455.1745-1-xiexinet@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 each segment normally, preserving local delivery and forwarding. Drop ETH_P_HSR and ETH_P_PRP aggregates (per-frame metadata cannot be rebuilt), classification failures (unreadable header, stacked or S-tag tagging), and aggregates with unreadable net_iov (device-memory) fragments: their payload is not host-readable, and segmentation would leave the segment payload uninitialized, silently dropped at transmit or exposed where netmem transmit is enabled. In-tree software GRO does not merge PRP RCT frames (its IPv4/IPv6 length checks reject trailing bytes); fixed-on GRO_HW output is outside this guarantee. Also remove the GSO_MASK member types from the HSR master's hw_features: local traffic is segmented by the core before the forward path, so the master funnel branch sees single frames, and TSO and the other GSO_MASK offloads can no longer be enabled on the master; generic-segmentation-offload stays changeable and is cleared at runtime. This patch depends on patch 2 ("net: hsr: shrink seqnr_lock to sequence counter updates") and the sparse-bitmap duplicate discard introduced by commit aae9d6b616b5 ("hsr: Implement more robust duplicate discard for HSR"); older trees require an adapted backport. Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamle= ss Redundancy protocol (HSRv0)") Cc: # aae9d6b616b5: hsr: Implement more robust dup= licate discard for HSR Signed-off-by: Xin Xie --- net/hsr/hsr_device.c | 2 +- net/hsr/hsr_forward.c | 106 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 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 =3D true; =20 dev->hw_features =3D 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; =20 diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 8e4158a9b57c..ae49c2d74ace 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" =20 @@ -732,7 +733,7 @@ static int fill_frame_info(struct hsr_frame_info *frame, } =20 /* 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; =20 @@ -761,3 +762,106 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_= port *port) port->dev->stats.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: 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 !=3D htons(ETH_P_8021Q)) + return 0; + if (eth_type_vlan(skb->protocol)) + return 0; + return skb->protocol; + } + + eth =3D skb_header_pointer(skb, 0, sizeof(eh), &eh); + if (!eth) + return 0; + + proto =3D eth->h_proto; + if (!eth_type_vlan(proto)) + return proto; + if (proto !=3D htons(ETH_P_8021Q)) + return 0; + + vhdr =3D skb_header_pointer(skb, ETH_HLEN, sizeof(vh), &vh); + if (!vhdr) + return 0; + + proto =3D 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, whose tagging exceeds the single 802.1Q C-tag HSR + * supports, or whose fragments are unreadable net_iov + * (device-memory) pages: software segmentation cannot read their + * payload, so each segment would inherit the unreadable flag and + * carry uninitialized data. With NETIF_F_HW_HSR_TAG_RM the lower + * has already stripped the tag, so such aggregates arrive plain + * and are segmented. + */ + proto =3D hsr_gso_effective_proto(skb); + if (!proto) + goto drop_gso; /* classification failure, fail-safe */ + if (proto =3D=3D htons(ETH_P_HSR) || proto =3D=3D htons(ETH_P_PRP)) + goto drop_gso; + if (!skb_frags_readable(skb)) + goto drop_gso; /* net_iov (device-memory) frags are not host-readable */ + + /* features =3D 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 =3D __skb_gso_segment(skb, 0, port->type =3D=3D HSR_PT_MASTER); + if (IS_ERR(segs) || unlikely(!segs)) + goto drop_gso; + + consume_skb(skb); + while (segs) { + next =3D segs->next; + segs->next =3D NULL; + hsr_forward_skb_one(segs, port); + segs =3D next; + } + return; + +drop_gso: + port->dev->stats.tx_dropped++; + kfree_skb(skb); +} --=20 2.43.0 From nobody Tue Sep 29 09:46:20 2026 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7447B3D1CCA for ; Sun, 9 Aug 2026 12:15:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277726; cv=none; b=MKqjvg8H4kRCgPT3bEQlbpE7y/gju4Trfoxw0wYDoKXbRrw1iWoGwTz9DQFWQuf914ezuPcCuvTIl7uXWD10NZClMirMpB9fMW+BBx+WbH/3QyOTSW1ay2ziB+wHxTwZyGa4a7J+Fy6IhimYwL722sdyQwMPbag9cwjJlS2Vsc4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786277726; c=relaxed/simple; bh=ZgSKxeusZoIfDoSLLk2Zo1ETS1qWVUcSeg223Orvo9o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hEoXROIG+AMi1sCxsmqlTX9nw1V5CugluRZh7mSEPySi7seBhYz9TwsCIcUrANxW06BVoGeWrUgx9P0w1k2xsvwpg66FH1opD0VhV+Cf6OnzFISq+6pJ9IqSJNa0Fssd7qaQnZyr+kPtPzSv0RQphL/ltHDIM8eQ/P8FxvcoRzk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=YoSv1OqP; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YoSv1OqP" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-4765eec32e1so87287f8f.1 for ; Sun, 09 Aug 2026 05:15:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786277703; x=1786882503; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=MZe84lDz46c2ldUAlcnI7KUozWN91rFTqvrE5PlfiJA=; b=YoSv1OqPaUrOjeDpqIEjj/z4F1TCb+dvA9o4rTyRHBli9X5cWjb7kT8yCQMVD5uazQ /UZ7ugPHVJo1pwF3vblJLbD5UIW3CWgq/uXVLcVBGm4SvOqh4qfbI4QFabKa+Yp7MY9P yiHLbZ3P4Z6CqTjogrmi0AtDvIccphjJ6rdQ9Qt1+Itd1cxuHZB34uR6Z4AbHT309zDA RRPT3z+ocw/hqgMIcaDUwadBs6EAddBv6AZ8CvH45/NHzGH+rOWxVIMaZzqpoUoQMEDH 0H258eg4IHSFD9v9PjUVDlkDBKCKMRABZqnwYC4rqdyveRYDfPyZW6Qm9INFO66qgUor oVYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786277703; x=1786882503; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=MZe84lDz46c2ldUAlcnI7KUozWN91rFTqvrE5PlfiJA=; b=IF/1Nw22Qc5qtyFpdZpGiWhYnDVSH6Mw5Mouf0QNSRa7LJZCpcVHnHsviO+hEmj4mY 3NmF0tyAnPmD8Sgor/JCGLQIChfvRHv8Qz0eQvKyvz3/UekEG7SMgaFKqJknDv0jYr0z F6ML/7lzzCtJSvceIQQvzc99nFFsRa1P+xRfNvcWzUiNyg/ZrvD8OrZWn6hBmYh52Pcu FSgBiDgpWjC6A2SsU1risyxZRERzrpfTkUFm+GM0nLUNMRtZVLaMxPofSCZ6TzlwQkQR fjopcYnnP45rq+u3XITF2BY8Ty2NHX9zmmeSfckcqSq8EMi2s4MoCbCRmTXof0ZOWBv2 haew== X-Forwarded-Encrypted: i=1; AHgh+Rr0TQIlK+z7iQhzWR4OZjdMoN3GiFEOfABxedn1HTeAfCHnMPP9WucmfcB1Qj1z8ZoTQWxgYfk+zM1nwto=@vger.kernel.org X-Gm-Message-State: AOJu0YycM2Ntf6UCYaKM+qI5WIgzEoTCcZdvAm6PFxfwIOMqKTURgHB5 3tuAs7azuH7OSkwZJOj7Jf4wHUX709ElxkBqEKC5S5FY3AfW+Gx5rCWG X-Gm-Gg: AR+sD10s0YtzTBTDSzoz2WLBLjjbecyjp0SxQW/BHZahX7I7eO/WXpOvWOEEZH9eTeS J2UojU28GP6WDuISLC0oEc/fIDkJ7VHgZ6d1VdtYoiVRrjf5/Ew7GyuZosD9XfzEycu95IaSTvB qitQrm0ccm5aAK78tZtVxhIFxQoqbynrpIoFmv8m+RMVmnsfuW1jrdaoQwkecgZMdiLuJ7uvgGC V7M/8xoF+p7Aib7+FV5PzS08ZfNKuf8Gz3f5p9ycnyke5dPofb+ersyvs/fE7sMVVOB9szzcngP huYNmbJyUFnYyDeFRGmhx0dhw0KKYHXyl8+qMO7kfa8ZqBVC0Ai/neE0+7xaPVv14c0DtEFzVOE HGZXf7efY6W/Qf48j/bUJ7S55ZYES9FlbEWcaN0Tl6+X/KqRSeyIwzIQvsEmtVl5Xt8pCHt0qlH dWwXPQ9SbYlZkNsNpyDUY90RFoWB/gGiOQ4ngKTtfhzm3fjJ2prgWZ7/z9RzYyX/zfqyAgEs+RQ OAArqBx/Mk6cmLHTZb/eezvapkGgGwgSxmX/XNqALD0SnJrxdAwYOM7WpNWjYrHEO/qu7uxCLR2 LrwChItYJjLAMpdaJDoV X-Received: by 2002:a05:600c:1387:b0:495:3eb4:3c6d with SMTP id 5b1f17b1804b1-4994e7b810bmr225744885e9.2.1786277702240; Sun, 09 Aug 2026 05:15:02 -0700 (PDT) Received: from L-022584.energy.envision.com (dynamic-077-012-133-135.77.12.pool.telefonica.de. [77.12.133.135]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-480021e7b3fsm25158434f8f.20.2026.08.09.05.15.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Aug 2026 05:15:01 -0700 (PDT) From: Xin Xie To: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch, shuah@kernel.org, kees@kernel.org, petr.wozniak@gmail.com, qingfang.deng@linux.dev, fmaurer@redhat.com, luka.gejak@linux.dev, bigeasy@linutronix.de, xiaoliang.yang_1@nxp.com, skhawaja@google.com, liuhangbin@gmail.com, stable@vger.kernel.org, sdf.kernel@gmail.com, Xin Xie Subject: [PATCH 4/4] selftests: net: hsr: cover GSO super-packets on PRP slave ingress Date: Sun, 9 Aug 2026 14:14:54 +0200 Message-ID: <20260809121455.1745-5-xiexinet@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260809121455.1745-1-xiexinet@gmail.com> References: <20260809121455.1745-1-xiexinet@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add a new always-run HSR/PRP kselftest (hsr_gro_superpacket.sh) covering the GRO/GRO_HW state on enslaved devices, the HSR master's GSO/TSO feature advertisement, a TSO stream through the forward path, and a PRP LAN-slave plain-GSO regression in which aggregates are segmented at the forward entry and delivered locally to the master. The test asserts that plain aggregates are unfolded per-frame on any ingress role and that local delivery and forwarding are preserved; interface-counter deltas are the evidence. Server readiness and reap waits are bounded, and the tool dependencies (ethtool, iperf3, timeout) are enforced via check_tool(). Signed-off-by: Xin Xie --- tools/testing/selftests/net/hsr/Makefile | 1 + .../selftests/net/hsr/hsr_gro_superpacket.sh | 678 ++++++++++++++++++ 2 files changed, 679 insertions(+) create mode 100755 tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh diff --git a/tools/testing/selftests/net/hsr/Makefile b/tools/testing/selft= ests/net/hsr/Makefile index 31fb9326cf53..0d105476e7c5 100644 --- a/tools/testing/selftests/net/hsr/Makefile +++ b/tools/testing/selftests/net/hsr/Makefile @@ -3,6 +3,7 @@ top_srcdir =3D ../../../../.. =20 TEST_PROGS :=3D \ + hsr_gro_superpacket.sh \ hsr_ping.sh \ hsr_redbox.sh \ link_faults.sh \ diff --git a/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh b/tools= /testing/selftests/net/hsr/hsr_gro_superpacket.sh new file mode 100755 index 000000000000..d2b34f6f37a7 --- /dev/null +++ b/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh @@ -0,0 +1,678 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test HSR handling of GRO/GSO super-packets: +# +# 1. Enslaving a device to an HSR master disables GRO on it +# (dev_disable_gro()). +# 2. The HSR master does not advertise GSO/TSO features. +# 3. A TCP stream from a TSO-enabled SAN (which therefore emits GSO +# super-packets) is unfolded at the HSR forward entry. Evidence: +# interface-counter deltas show super-packet-sized frames leaving +# the SAN and per-frame-sized traffic leaving the DUT's LAN ports. +# 4. PRP LAN-slave plain-GSO regression: a plain SAN aggregate +# entering a PRP LAN slave (ns_ls over the d_pa/ls_a and d_pb/ls_p +# veth pairs) is segmented at the forward entry and delivered +# locally to the PRP master (prp0), not dropped. Oracles: the SAN +# TX average proves aggregates left the SAN; the prp0 RX volume and +# per-frame average prove local delivery of the segmented stream. +# +# Topology (100.64.0.0/24): +# +# ns_san ns_dut ns_peer +# +-----------+ interlink +---------------+ LAN A/B +-----------+ +# | s0 [0.1] |-------------| d_il hsr0 |-----------| hsr1 [0.3]| +# +-----------+ | d_a / d_b | | p_a / p_b | +# +---------------+ +-----------+ +# +# SAN traffic reaches ns_peer only through hsr0's forward path +# (interlink RX -> LAN A/B TX), so every SAN frame is tagged and +# forwarded by the DUT. + +source ./hsr_common.sh + +san_ip=3D"100.64.0.1" +peer_ip=3D"100.64.0.3" + +# Aggregate counter thresholds for the stream test (bytes/packets): +# SAN_AVG_MIN proves GSO super-packets left the SAN; LAN_AVG_MAX is a +# guard with margin, not the protocol maximum (see do_tso_stream_test). +SAN_AVG_MIN=3D2048 +LAN_AVG_MAX=3D1514 +# Master-RX per-frame bound for the LAN-slave test: prp0 RX counts +# recv_len after skb_pull(ETH_HLEN), so per-frame payload is at most +# 1500. Same guard-with-margin shape as LAN_AVG_MAX, but a different +# quantity (see do_lansan_gso_test). +MASTER_RX_AVG_MAX=3D1514 + +iperf_pid=3D"" +server_wrapper=3D"" +active_srv_ns=3D"" +workdir=3D"" +pidfile=3D"" +ns_dut=3D"" +ns_san=3D"" +ns_peer=3D"" +ns_ls=3D"" +rcfile=3D"" + +# Delete the per-server private work directory and reset its +# variables. Called after a successful reap and from the EXIT +# trap (all normal failure paths; runner-timeout INT/TERM signals +# exit via the same trap). +cleanup_workdir() +{ + # remove only the known non-empty private directory + if [ -n "${workdir}" ] && [ -d "${workdir}" ]; then + rm -rf "${workdir}" + fi + workdir=3D"" + pidfile=3D"" + rcfile=3D"" +} + +cleanup() +{ + # Server cleanup targets only the namespace of the currently + # active server (recorded by start_iperf_server); after a + # successful reap nothing is active. + if [ -n "${active_srv_ns}" ]; then + # exact-PID kill only after RE-validating identity (guards + # against PID reuse between publication and cleanup) + if [ -n "${iperf_pid}" ] && valid_server_pid "${active_srv_ns}" "${iperf= _pid}"; then + kill "${iperf_pid}" 2>/dev/null + fi + iperf_pid=3D"" + if [ -n "${server_wrapper}" ]; then + # the wrapper waits on the server; reap it with a 5s + # bound so a live-but-unpublished server can never + # hang cleanup + for _ in $(seq 1 50); do + kill -0 "${server_wrapper}" 2>/dev/null || break + sleep 0.1 + done + kill "${server_wrapper}" 2>/dev/null + wait "${server_wrapper}" 2>/dev/null + server_wrapper=3D"" + fi + # last resort, namespace-scoped only: TERM the iperf3 + # processes that actually live in the active server netns, + # poll for bounded exit, then SIGKILL any survivor before + # touching the namespace name. A blind pkill would scan + # the host PID space and hit unrelated tests. + local _p _still + for _p in $(ip netns pids "${active_srv_ns}" 2>/dev/null); do + if is_iperf3_pid "$_p"; then + kill "$_p" 2>/dev/null + fi + done + for _ in $(seq 1 50); do + _still=3D0 + for _p in $(ip netns pids "${active_srv_ns}" 2>/dev/null); do + if is_iperf3_pid "$_p"; then + _still=3D1 + break + fi + done + [ "$_still" -eq 0 ] && break + sleep 0.1 + done + for _p in $(ip netns pids "${active_srv_ns}" 2>/dev/null); do + if is_iperf3_pid "$_p"; then + kill -9 "$_p" 2>/dev/null + fi + done + fi + active_srv_ns=3D"" + cleanup_workdir + cleanup_all_ns +} + +trap cleanup EXIT +# INT/TERM (e.g. a runner timeout) must not leave the workdir, +# server or namespaces behind: exit 143 (128+SIGTERM) via the EXIT +# trap so cleanup runs exactly once. Do not use a shared +# 'trap cleanup EXIT INT TERM': the trap would return and the +# script would keep running after cleanup. +trap 'exit 143' INT TERM + +check_tool() +{ + if ! command -v "$1" > /dev/null 2>&1; then + echo "SKIP: Could not run test without $1" + exit $ksft_skip + fi +} + +nsx() +{ + ip netns exec "$1" bash -c "$2" +} + +is_iperf3_pid() +{ + [ "$(cat /proc/"$1"/comm 2>/dev/null)" =3D "iperf3" ] +} + +# Bounded reap of the one-shot server: wait at most 5s for it to +# exit, then reap the wrapper and REQUIRE the rcfile with its real +# status. A stuck server can never hang the script. The wrapper writes +# the rcfile only after iperf3 has exited, so polling the rcfile has no +# PID-reuse ambiguity (a kill -0 poll on the non-child PID could +# spuriously match a recycled PID). +reap_iperf_server() +{ + local server_rc + + for _ in $(seq 1 50); do + [ -s "${rcfile}" ] && break + sleep 0.1 + done + if [ ! -s "${rcfile}" ]; then + echo "FAIL: iperf3 server did not exit within 5s" 1>&2 + ret=3D1 + return 1 + fi + wait "${server_wrapper}" + server_wrapper=3D"" + if [ ! -s "${rcfile}" ]; then + echo "FAIL: iperf3 server status file missing (${rcfile})" 1>&2 + ret=3D1 + return 1 + fi + server_rc=3D$(cat "${rcfile}") + if ! [[ "$server_rc" =3D~ ^[0-9]+$ ]] || [ "$server_rc" -ne 0 ]; then + echo "FAIL: iperf3 server exited with rc=3D'${server_rc}'" 1>&2 + ret=3D1 + return 1 + fi + iperf_pid=3D"" + cleanup_workdir + active_srv_ns=3D"" + return 0 +} + +# Decimal-counter validation for the snapshot blocks: every value must +# be a plain decimal number. A parse failure in read_tx_counters yields +# empty/garbled fields, which this check turns into an immediate FAIL. +valid_decimals() +{ + local v + + for v in "$@"; do + [[ "$v" =3D~ ^[0-9]+$ ]] || return 1 + done + return 0 +} + +setup_topo() +{ + setup_ns ns_dut ns_san ns_peer || exit $? + + ip link add d_a netns "$ns_dut" type veth peer name p_a netns "$ns_peer" + ip link add d_b netns "$ns_dut" type veth peer name p_b netns "$ns_peer" + ip link add d_il netns "$ns_dut" type veth peer name s0 netns "$ns_san" + + # HSR tags add 6 bytes per frame; give the LAN legs headroom. + for iface in d_a d_b; do + nsx "$ns_dut" "ip link set $iface mtu 1600; \ + ip link set $iface up" + done + for iface in p_a p_b; do + nsx "$ns_peer" "ip link set $iface mtu 1600; \ + ip link set $iface up" + done + + nsx "$ns_dut" "ip link set d_il up" + nsx "$ns_san" "ip link set s0 up; ip addr add $san_ip/24 dev s0" + + nsx "$ns_dut" "ip link add hsr0 type hsr \ + slave1 d_a slave2 d_b interlink d_il proto 0; \ + ip link set hsr0 up" + nsx "$ns_peer" "ip link add hsr1 type hsr \ + slave1 p_a slave2 p_b proto 0; \ + ip link set hsr1 up; ip addr add $peer_ip/24 dev hsr1" + + # Let the nodes see each other's supervision frames. + sleep 2 +} + +check_feature() +{ + local ns=3D"$1" + local iface=3D"$2" + local feature=3D"$3" + local want=3D"$4" + + if nsx "$ns" "ethtool -k $iface" | grep -q "^$feature: $want"; then + echo "INFO: $ns/$iface $feature is $want [ OK ]" + else + echo "FAIL: $ns/$iface $feature is not $want" 1>&2 + ret=3D1 + fi +} + +# Off-or-absent variant: fails only when the feature is present AND on, +# so devices that simply do not list the feature do not fail it. +check_feature_not_on() +{ + local ns=3D"$1" + local iface=3D"$2" + local feature=3D"$3" + + if nsx "$ns" "ethtool -k $iface" | grep -q "^$feature: on"; then + echo "FAIL: $ns/$iface $feature is on" 1>&2 + ret=3D1 + else + echo "INFO: $ns/$iface $feature not on [ OK ]" + fi +} + +do_gro_feature_checks() +{ + echo "INFO: Checking that enslavement disabled GRO." + check_feature "$ns_dut" d_a generic-receive-offload off + check_feature "$ns_dut" d_b generic-receive-offload off + check_feature "$ns_dut" d_il generic-receive-offload off + stop_if_error "GRO not disabled on enslaved devices." + + echo "INFO: Checking that enslavement disabled HW-GRO." + check_feature "$ns_dut" d_a rx-gro-hw off + check_feature "$ns_dut" d_b rx-gro-hw off + check_feature "$ns_dut" d_il rx-gro-hw off + stop_if_error "HW-GRO not disabled on enslaved devices." + + echo "INFO: Checking that the HSR master does not advertise GSO/TSO." + check_feature "$ns_dut" hsr0 generic-segmentation-offload off + check_feature "$ns_dut" hsr0 tcp-segmentation-offload off + check_feature_not_on "$ns_dut" hsr0 tx-udp-segmentation + check_feature_not_on "$ns_dut" hsr0 tx-gso-list + stop_if_error "HSR master still advertises GSO-family features." +} + +alloc_workdir() +{ + # Allocated only here, long after the initial topology cleanup, so + # cleanup() at setup_topo() time can never remove it. mktemp failure + # is a hard test failure. + workdir=3D$(mktemp -d /tmp/hsr_gro_test.XXXXXX) || { + echo "FAIL: mktemp -d failed" 1>&2 + exit 1 + } + chmod 700 "${workdir}" + pidfile=3D"${workdir}/iperf.pid" + rcfile=3D"${workdir}/iperf.rc" +} + +# Numeric, alive, comm =3D=3D iperf3, and really owned by the given netns. +valid_server_pid() +{ + local pns=3D"$1" p=3D"$2" + + [[ "$p" =3D~ ^[0-9]+$ ]] || return 1 + kill -0 "$p" 2>/dev/null || return 1 + [ "$(cat /proc/"$p"/comm 2>/dev/null)" =3D "iperf3" ] || return 1 + ip netns pids "$pns" 2>/dev/null | grep -qx "$p" +} + +start_iperf_server() +{ + local srv_ns=3D"$1" + local srv_ip=3D"${2:-}" + local candidate_pid + + # One-shot server, no -D: the wrapper records its exact PID and its + # real exit status (netns shares the PID namespace and the host fs). + alloc_workdir + # record the server namespace for cleanup() before + # anything can fail with the server running + active_srv_ns=3D"$srv_ns" + ( nsx "$srv_ns" "iperf3 -s -1 ${srv_ip:+-B $srv_ip} > /dev/null 2>&1 & \ + echo \$! > ${pidfile}; \ + wait \$!; \ + echo \$? > ${rcfile}" ) & + server_wrapper=3D$! + # the wrapper writes the pidfile asynchronously; wait for it to + # appear instead of racing the read + for _ in $(seq 1 50); do + [ -s "${pidfile}" ] && break + sleep 0.1 + done + if [ ! -s "${pidfile}" ]; then + echo "FAIL: iperf3 server did not publish a pid" \ + "(no pidfile)" 1>&2 + ret=3D1 + return 1 + fi + candidate_pid=3D$(<"${pidfile}") + # The pidfile is written between fork() and execve(), when comm is + # still "bash". Retry for up to 5s so that transient state cannot + # fail a server that is starting normally; a genuinely dead or + # never-execed server still fails at expiry. + for _ in $(seq 1 50); do + valid_server_pid "$srv_ns" "${candidate_pid}" && break + sleep 0.1 + done + if ! valid_server_pid "$srv_ns" "${candidate_pid}"; then + echo "FAIL: iperf3 server pid '${candidate_pid}'" \ + "failed validation" 1>&2 + ret=3D1 + return 1 + fi + # publish only after full validation + iperf_pid=3D"${candidate_pid}" + # Bounded listen() readiness poll: the pidfile proves the process + # started, not that bind()+listen() completed; on a loaded CI the + # client can otherwise hit "Connection refused" while the kernel + # behaves correctly. The server netns is freshly created and + # private, so a :5201 listener there is ours. If ss is unavailable + # in a minimal environment, keep the old fixed wait as last resort. + if command -v ss > /dev/null 2>&1; then + for _ in $(seq 1 50); do + nsx "$srv_ns" "ss -ltn" | grep -q ':5201' && break + sleep 0.1 + done + if ! nsx "$srv_ns" "ss -ltn" | grep -q ':5201'; then + echo "FAIL: iperf3 server did not listen on :5201 within 5s" 1>&2 + ret=3D1 + return 1 + fi + else + sleep 1 + fi + return 0 +} + +# Print " " for exactly one TX record of ns/dev; anything +# else (missing, duplicated, non-numeric) is a hard FAIL. +read_tx_counters() +{ + local ns=3D"$1" dev=3D"$2" + local out cnt + + out=3D$(nsx "$ns" "ip -s link show $dev" | \ + awk '/^ +TX:/{getline; print $1, $2}') + cnt=3D$(echo "$out" | grep -c '^[0-9]* [0-9]*$') + if [ "$cnt" -ne 1 ]; then + echo "FAIL: cannot parse TX counters of $ns/$dev" \ + "(records=3D$cnt)" 1>&2 + return 1 + fi + echo "$out" + return 0 +} + +# Print " " for exactly one RX record of ns/dev; the +# same single-record discipline as read_tx_counters. +read_rx_counters() +{ + local ns=3D"$1" dev=3D"$2" + local out cnt + + out=3D$(nsx "$ns" "ip -s link show $dev" | \ + awk '/^ +RX:/{getline; print $1, $2}') + cnt=3D$(echo "$out" | grep -c '^[0-9]* [0-9]*$') + if [ "$cnt" -ne 1 ]; then + echo "FAIL: cannot parse RX counters of $ns/$dev" \ + "(records=3D$cnt)" 1>&2 + return 1 + fi + echo "$out" + return 0 +} + +eval_counter_delta() +{ + local name=3D"$1" b0=3D"$2" p0=3D"$3" b1=3D"$4" p1=3D"$5" op=3D"$6" limit= =3D"$7" + local bd pd + + if ! [[ "$b0" =3D~ ^[0-9]+$ && "$b1" =3D~ ^[0-9]+$ && \ + "$p0" =3D~ ^[0-9]+$ && "$p1" =3D~ ^[0-9]+$ ]]; then + echo "FAIL: non-numeric counter input for $name" 1>&2 + ret=3D1 + return 1 + fi + bd=3D$((b1 - b0)) + pd=3D$((p1 - p0)) + if [ "$bd" -lt 0 ] || [ "$pd" -le 0 ]; then + echo "FAIL: counter delta invalid for $name" \ + "(bytes=3D$bd pkts=3D$pd)" 1>&2 + ret=3D1 + return 1 + fi + if [ "$op" =3D "gt" ]; then + if [ "$bd" -le $((pd * limit)) ]; then + echo "FAIL: $name bytes/packets $bd/$pd <=3D $limit" 1>&2 + ret=3D1 + return 1 + fi + else + if [ "$bd" -gt $((pd * limit)) ]; then + echo "FAIL: $name bytes/packets $bd/$pd > $limit" 1>&2 + ret=3D1 + return 1 + fi + fi + echo "INFO: $name counter delta bytes=3D$bd packets=3D$pd" \ + "(op $op limit $limit) [ OK ]" + return 0 +} + +# LAN-slave plain-GSO regression: a plain SAN aggregate entering a PRP +# LAN slave must be segmented at the forward entry, not dropped. PRP +# drops slave-to-slave forwarding by design (prp_drop_frame), so the +# consumer of LAN-slave SAN traffic is local delivery to the master. +# Two independent oracles: the SAN-side proof that aggregates really +# arrived at the DUT, and the volume + per-frame shape of the local +# delivery. On the broken gate the aggregates are dropped and TCP +# crawls on retransmitted single segments, separating the kernels by +# an order of magnitude in delivered bytes. +do_lansan_gso_test() +{ + local prp_ip=3D"10.99.1.1" ls_ip=3D"10.99.1.10" + local out san_b0 san_p0 san_b1 san_p1 + local a_b0 a_p0 a_b1 a_p1 r_b0 r_p0 r_b1 r_p1 + + setup_ns ns_ls || exit $? + + ip link add d_pa netns "$ns_dut" type veth peer name ls_a netns "$ns_ls" + ip link add d_pb netns "$ns_dut" type veth peer name ls_p netns "$ns_ls" + + nsx "$ns_dut" "ip link set d_pa mtu 1600 up" + nsx "$ns_dut" "ip link set d_pb mtu 1600 up" + nsx "$ns_ls" "ip link set ls_a mtu 1600 up; \ + ip link set ls_p mtu 1600 up; ip addr add $ls_ip/24 dev ls_a" + + # PRP DUT with the SAN on a LAN slave: plain SAN aggregates are + # valid traffic on a PRP LAN and must not be dropped. + nsx "$ns_dut" "ip link add prp0 type hsr \ + slave1 d_pa slave2 d_pb proto 1; \ + ip link set prp0 up; ip addr add $prp_ip/24 dev prp0" + + # Let supervision frames converge. + sleep 2 + + echo "INFO: Enabling TSO/GSO on the LAN-side SAN interface." + nsx "$ns_ls" "ethtool -K ls_a tso on gso on" + check_feature "$ns_ls" ls_a tcp-segmentation-offload on + stop_if_error "Could not enable TSO on the LAN-side SAN interface." + + start_iperf_server "$ns_dut" "$prp_ip" || return + + read -r r_b0 r_p0 <&2 + ret=3D1 + return 1 + fi + + if ! out=3D$(nsx "$ns_ls" "timeout 60 iperf3 -c $prp_ip -M 1446 \ + -b 2G -t 10" 2>&1); then + echo "FAIL: LAN-slave GSO local-delivery stream failed:" 1>&2 + echo "$out" 1>&2 + ret=3D1 + return + fi + + read -r r_b1 r_p1 <&2 + ret=3D1 + return 1 + fi + + # Oracle 1 - aggregates really arrived: the SAN emitted + # super-packets toward the DUT. + eval_counter_delta "SAN ls_a TX" "$san_b0" "$san_p0" \ + "$san_b1" "$san_p1" gt "$SAN_AVG_MIN" + [ "${ret:-0}" -eq 0 ] || return + + # Oracle 2 - local delivery of those aggregates: volume and + # per-frame shape on the PRP master. The volume gate separates + # full delivery from the retransmit crawl the broken gate leaves; + # the average gate proves the bytes arrived per-frame. + if [ $((r_b1 - r_b0)) -lt 100000000 ]; then + echo "FAIL: LAN-slave local delivery degraded" \ + "(prp0 RX delta $((r_b1 - r_b0)) bytes < 100000000)" 1>&2 + ret=3D1 + return + fi + if [ $((r_b1 - r_b0)) -gt $(( (r_p1 - r_p0) * MASTER_RX_AVG_MAX )) ]; then + echo "FAIL: local delivery not per-frame" \ + "(avg $(( (r_b1 - r_b0) / (r_p1 - r_p0) )) > $MASTER_RX_AVG_MAX)" 1>&2 + ret=3D1 + return + fi + echo "INFO: LAN-slave local delivery prp0 RX delta" \ + "$((r_b1 - r_b0)) bytes / $((r_p1 - r_p0)) pkts [ OK ]" + reap_iperf_server || return + echo "INFO: LAN-slave plain-GSO regression [ OK ]" +} + +do_tso_stream_test() +{ + local out sender_retr + local san_b0 san_p0 san_b1 san_p1 + local a_b0 a_p0 a_b1 a_p1 b_b0 b_p0 b_b1 b_p1 + + echo "INFO: Enabling TSO/GSO on the SAN interface." + nsx "$ns_san" "ethtool -K s0 tso on gso on" + check_feature "$ns_san" s0 tcp-segmentation-offload on + stop_if_error "Could not enable TSO on the SAN interface." + + echo "INFO: Running 10s TCP stream SAN -> peer through the HSR DUT." + start_iperf_server "$ns_peer" || return + + # Counter snapshots around the stream window. The SAN-side average + # must exceed SAN_AVG_MIN (aggregate proof that GSO super-packets + # really left the SAN); each DUT LAN leg must stay under LAN_AVG_MAX + # (aggregate proof that bulk output was segmented per-frame). These + # are aggregate discriminators, not a per-frame maximum proof. + san_b0=3D0; san_p0=3D0; a_b0=3D0; a_p0=3D0; b_b0=3D0; b_p0=3D0 + read -r san_b0 san_p0 <&2 + ret=3D1 + return 1 + fi + + # rate-capped: the PRIMARY discriminator is the counter inequality + # above, not max throughput; retransmits are informational only. + # Uncapped runs flap at VM/CI edge rates without indicating a + # functional problem. + if ! out=3D$(nsx "$ns_san" "timeout 60 iperf3 -c $peer_ip -M 1446 \ + -b 2G -t 10" 2>&1); then + echo "FAIL: iperf3 client failed:" 1>&2 + echo "$out" 1>&2 + ret=3D1 + return + fi + + read -r san_b1 san_p1 <&2 + ret=3D1 + return 1 + fi + + eval_counter_delta "SAN s0 TX" "$san_b0" "$san_p0" "$san_b1" "$san_p1" \ + gt "$SAN_AVG_MIN" + eval_counter_delta "DUT d_a TX" "$a_b0" "$a_p0" "$a_b1" "$a_p1" \ + le "$LAN_AVG_MAX" + eval_counter_delta "DUT d_b TX" "$b_b0" "$b_p0" "$b_b1" "$b_p1" \ + le "$LAN_AVG_MAX" + [ "${ret:-0}" -eq 0 ] || return + + # success path: bounded reap with the server's real status + reap_iperf_server || return + + # secondary health signal only: anchored, single-match, numeric =E2=80=94 + # any parse anomaly is a loud FAIL, but the value itself no longer + # gates (the counter inequalities above are the primary evidence). + sender_retr=3D$(echo "$out" | awk '/sec .* sender$/ {print $(NF-1)}') + if [ "$(echo "$sender_retr" | grep -Ec '^[0-9]+$')" -ne 1 ]; then + echo "FAIL: cannot parse sender retransmits reliably" 1>&2 + echo "$out" 1>&2 + ret=3D1 + return + fi + echo "INFO: TCP stream done;" \ + "sender retransmits=3D$sender_retr (secondary signal)" + echo "$out" | grep -E "sender|receiver" +} + +check_prerequisites +check_tool ethtool +check_tool iperf3 +check_tool timeout + +# iproute2 must know the HSR interlink syntax. +if ! ip link help hsr 2>&1 | grep -qi interlink; then + echo "SKIP: iproute2 has no HSR interlink support" + exit $ksft_skip +fi + +setup_topo + +echo "INFO: Initial validation ping (SAN -> peer through the DUT)." +do_ping "$ns_san" "$peer_ip" +stop_if_error "Initial validation failed." + +do_gro_feature_checks +do_tso_stream_test +stop_if_error "GSO super-packet stream test failed." + +do_lansan_gso_test +stop_if_error "LAN-slave plain-GSO regression failed." + +echo "INFO: All good." +cleanup +exit $ret --=20 2.43.0