AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/23 20:30 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "HSR"
  ],
  "FocusSymbols": [
    "hsr_forward_skb",
    "hsr_dev_xmit",
    "hsr_handle_frame",
    "dev_disable_gro",
    "netif_disable_gro"
  ],
  "Reasoning": "The patch modifies HSR packet forwarding to handle GSO packets by segmenting them, and disables GRO on HSR slave devices. These are functional changes to reachable network code.",
  "WorthFuzzing": true
}

1/1 2026/07/23 20:30 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 00c8d685932036cc037da84897b1358e1e82f7ea\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Thu Jul 23 20:30:27 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/include/linux/netdevice.h b/include/linux/netdevice.h\nindex 9981d637f8b546..eba2c26a49ba8f 100644\n--- a/include/linux/netdevice.h\n+++ b/include/linux/netdevice.h\n@@ -3434,6 +3434,8 @@ void dev_close(struct net_device *dev);\n void netif_close_many(struct list_head *head, bool unlink);\n void netif_disable_lro(struct net_device *dev);\n void dev_disable_lro(struct net_device *dev);\n+void netif_disable_gro(struct net_device *dev);\n+void dev_disable_gro(struct net_device *dev);\n int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb);\n u16 dev_pick_tx_zero(struct net_device *dev, struct sk_buff *skb,\n \t\t     struct net_device *sb_dev);\ndiff --git a/net/core/dev.c b/net/core/dev.c\nindex 5933c5dab09ee1..a6cf2adc862565 100644\n--- a/net/core/dev.c\n+++ b/net/core/dev.c\n@@ -1840,6 +1840,24 @@ void netif_disable_lro(struct net_device *dev)\n \t}\n }\n \n+void netif_disable_gro(struct net_device *dev)\n+{\n+\tstruct net_device *lower_dev;\n+\tstruct list_head *iter;\n+\n+\tdev-\u003ewanted_features \u0026= ~(NETIF_F_GRO | NETIF_F_GRO_HW);\n+\tnetdev_update_features(dev);\n+\n+\tif (unlikely(dev-\u003efeatures \u0026 (NETIF_F_GRO | NETIF_F_GRO_HW)))\n+\t\tnetdev_WARN(dev, \"failed to disable GRO!\\n\");\n+\n+\tnetdev_for_each_lower_dev(dev, lower_dev, iter) {\n+\t\tnetdev_lock_ops(lower_dev);\n+\t\tnetif_disable_gro(lower_dev);\n+\t\tnetdev_unlock_ops(lower_dev);\n+\t}\n+}\n+\n /**\n  *\tdev_disable_gro_hw - disable HW Generic Receive Offload on a device\n  *\t@dev: device\ndiff --git a/net/core/dev_api.c b/net/core/dev_api.c\nindex 437947dd08ed53..02fb2162951284 100644\n--- a/net/core/dev_api.c\n+++ b/net/core/dev_api.c\n@@ -269,6 +269,22 @@ void dev_disable_lro(struct net_device *dev)\n }\n EXPORT_SYMBOL(dev_disable_lro);\n \n+/**\n+ * dev_disable_gro() - disable Generic Receive Offload on a device\n+ * @dev: device\n+ *\n+ * Disable Generic Receive Offload (GRO) on a net device.  Must be\n+ * called under RTNL.  This is needed if received packets may be\n+ * forwarded to another interface.\n+ */\n+void dev_disable_gro(struct net_device *dev)\n+{\n+\tnetdev_lock_ops(dev);\n+\tnetif_disable_gro(dev);\n+\tnetdev_unlock_ops(dev);\n+}\n+EXPORT_SYMBOL(dev_disable_gro);\n+\n /**\n  * dev_set_promiscuity() - update promiscuity count on a device\n  * @dev: device\ndiff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c\nindex 5555b71ab19b59..248cbb142e21e1 100644\n--- a/net/hsr/hsr_device.c\n+++ b/net/hsr/hsr_device.c\n@@ -232,9 +232,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)\n \t\tskb-\u003edev = master-\u003edev;\n \t\tskb_reset_mac_header(skb);\n \t\tskb_reset_mac_len(skb);\n-\t\tspin_lock_bh(\u0026hsr-\u003eseqnr_lock);\n \t\thsr_forward_skb(skb, master);\n-\t\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n \t} else {\n \t\tdev_core_stats_tx_dropped_inc(dev);\n \t\tdev_kfree_skb_any(skb);\n@@ -335,6 +333,7 @@ static void send_hsr_supervision_frame(struct hsr_port *port,\n \t\thsr_stag-\u003esequence_nr = htons(hsr-\u003esequence_nr);\n \t\thsr-\u003esequence_nr++;\n \t}\n+\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n \n \thsr_stag-\u003etlv.HSR_TLV_type = type;\n \t/* HSRv0 has 6 unused bytes after the MAC */\n@@ -356,14 +355,10 @@ static void send_hsr_supervision_frame(struct hsr_port *port,\n \t\tether_addr_copy(hsr_sp-\u003emacaddress_A, hsr-\u003emacaddress_redbox);\n \t}\n \n-\tif (skb_put_padto(skb, ETH_ZLEN)) {\n-\t\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n+\tif (skb_put_padto(skb, ETH_ZLEN))\n \t\treturn;\n-\t}\n \n \thsr_forward_skb(skb, port);\n-\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n-\treturn;\n }\n \n static void send_prp_supervision_frame(struct hsr_port *master,\n@@ -390,6 +385,7 @@ static void send_prp_supervision_frame(struct hsr_port *master,\n \tspin_lock_bh(\u0026hsr-\u003eseqnr_lock);\n \thsr_stag-\u003esequence_nr = htons(hsr-\u003esup_sequence_nr);\n \thsr-\u003esup_sequence_nr++;\n+\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n \thsr_stag-\u003etlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;\n \thsr_stag-\u003etlv.HSR_TLV_length = sizeof(struct hsr_sup_payload);\n \n@@ -397,13 +393,10 @@ static void send_prp_supervision_frame(struct hsr_port *master,\n \thsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));\n \tether_addr_copy(hsr_sp-\u003emacaddress_A, master-\u003edev-\u003edev_addr);\n \n-\tif (skb_put_padto(skb, ETH_ZLEN)) {\n-\t\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n+\tif (skb_put_padto(skb, ETH_ZLEN))\n \t\treturn;\n-\t}\n \n \thsr_forward_skb(skb, master);\n-\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n }\n \n /* Announce (supervision frame) timer function\n@@ -659,7 +652,7 @@ void hsr_dev_setup(struct net_device *dev)\n \tdev-\u003eneeds_free_netdev = true;\n \n \tdev-\u003ehw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |\n-\t\t\t   NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |\n+\t\t\t   NETIF_F_HW_CSUM |\n \t\t\t   NETIF_F_HW_VLAN_CTAG_TX |\n \t\t\t   NETIF_F_HW_VLAN_CTAG_FILTER;\n \ndiff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c\nindex 0774981a65c164..3fcdbac49c59da 100644\n--- a/net/hsr/hsr_forward.c\n+++ b/net/hsr/hsr_forward.c\n@@ -12,6 +12,7 @@\n #include \u003clinux/skbuff.h\u003e\n #include \u003clinux/etherdevice.h\u003e\n #include \u003clinux/if_vlan.h\u003e\n+#include \u003cnet/gso.h\u003e\n #include \"hsr_main.h\"\n #include \"hsr_framereg.h\"\n \n@@ -621,9 +622,10 @@ static void handle_std_frame(struct sk_buff *skb,\n \tif (port-\u003etype == HSR_PT_MASTER ||\n \t    port-\u003etype == HSR_PT_INTERLINK) {\n \t\t/* Sequence nr for the master/interlink node */\n-\t\tlockdep_assert_held(\u0026hsr-\u003eseqnr_lock);\n+\t\tspin_lock_bh(\u0026hsr-\u003eseqnr_lock);\n \t\tframe-\u003esequence_nr = hsr-\u003esequence_nr;\n \t\thsr-\u003esequence_nr++;\n+\t\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n \t}\n }\n \n@@ -731,7 +733,7 @@ static int fill_frame_info(struct hsr_frame_info *frame,\n }\n \n /* Must be called holding rcu read lock (because of the port parameter) */\n-void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)\n+static void hsr_forward_skb_one(struct sk_buff *skb, struct hsr_port *port)\n {\n \tstruct hsr_frame_info frame;\n \n@@ -760,3 +762,50 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)\n \tport-\u003edev-\u003estats.tx_dropped++;\n \tkfree_skb(skb);\n }\n+\n+/* GSO fan-out funnel: unfold super-packets before per-frame processing so\n+ * each wire frame gets its own HSR/PRP tag and sequence number.\n+ */\n+void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)\n+{\n+\tstruct sk_buff *segs, *next;\n+\n+\tif (likely(!skb_is_gso(skb))) {\n+\t\thsr_forward_skb_one(skb, port);\n+\t\treturn;\n+\t}\n+\n+\t/* Unfold only plain-Ethernet GSO super-packets: locally generated\n+\t * on the master, or arriving untagged from the SAN side on the\n+\t * interlink. A super-packet from a LAN slave may carry per-frame\n+\t * HSR tags / PRP RCT trailers that software segmentation cannot\n+\t * recover; an already-tagged HSR/PRP super-packet violates\n+\t * per-frame wire semantics. Drop both.\n+\t */\n+\tif (port-\u003etype != HSR_PT_MASTER \u0026\u0026 port-\u003etype != HSR_PT_INTERLINK)\n+\t\tgoto drop_gso;\n+\tif (skb-\u003eprotocol == htons(ETH_P_HSR) ||\n+\t    skb-\u003eprotocol == htons(ETH_P_PRP))\n+\t\tgoto drop_gso;\n+\n+\t/* features = 0: request full software segmentation. tx_path is true\n+\t * only for locally generated traffic on the master; ingress from\n+\t * the interlink follows RX checksum semantics.\n+\t */\n+\tsegs = __skb_gso_segment(skb, 0, port-\u003etype == HSR_PT_MASTER);\n+\tif (IS_ERR(segs) || unlikely(!segs))\n+\t\tgoto drop_gso;\n+\n+\tconsume_skb(skb);\n+\twhile (segs) {\n+\t\tnext = segs-\u003enext;\n+\t\tsegs-\u003enext = NULL;\n+\t\thsr_forward_skb_one(segs, port);\n+\t\tsegs = next;\n+\t}\n+\treturn;\n+\n+drop_gso:\n+\tport-\u003edev-\u003estats.tx_dropped++;\n+\tkfree_skb(skb);\n+}\ndiff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c\nindex d9af9e65f72f07..c7fd021f03b1f4 100644\n--- a/net/hsr/hsr_slave.c\n+++ b/net/hsr/hsr_slave.c\n@@ -73,16 +73,7 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)\n \t}\n \tskb_reset_mac_len(skb);\n \n-\t/* Only the frames received over the interlink port will assign a\n-\t * sequence number and require synchronisation vs other sender.\n-\t */\n-\tif (port-\u003etype == HSR_PT_INTERLINK) {\n-\t\tspin_lock_bh(\u0026hsr-\u003eseqnr_lock);\n-\t\thsr_forward_skb(skb, port);\n-\t\tspin_unlock_bh(\u0026hsr-\u003eseqnr_lock);\n-\t} else {\n-\t\thsr_forward_skb(skb, port);\n-\t}\n+\thsr_forward_skb(skb, port);\n \n finish_consume:\n \treturn RX_HANDLER_CONSUMED;\n@@ -170,6 +161,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,\n \tif (res)\n \t\tgoto fail_rx_handler;\n \tdev_disable_lro(dev);\n+\tdev_disable_gro(dev);\n \n \treturn 0;\n \ndiff --git a/tools/testing/selftests/net/hsr/Makefile b/tools/testing/selftests/net/hsr/Makefile\nindex 31fb9326cf533d..0d105476e7c50d 100644\n--- a/tools/testing/selftests/net/hsr/Makefile\n+++ b/tools/testing/selftests/net/hsr/Makefile\n@@ -3,6 +3,7 @@\n top_srcdir = ../../../../..\n \n TEST_PROGS := \\\n+\thsr_gro_superpacket.sh \\\n \thsr_ping.sh \\\n \thsr_redbox.sh \\\n \tlink_faults.sh \\\ndiff --git a/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh b/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh\nnew file mode 100755\nindex 00000000000000..4b0a9ceea1ce59\n--- /dev/null\n+++ b/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh\n@@ -0,0 +1,249 @@\n+#!/bin/bash\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Test HSR handling of GRO/GSO super-packets:\n+#\n+#  1. Enslaving a device to an HSR master disables GRO on it\n+#     (dev_disable_gro()).\n+#  2. The HSR master does not advertise GSO/TSO features.\n+#  3. A TCP stream from a TSO-enabled SAN (which therefore emits GSO\n+#     super-packets) is unfolded at the HSR forward entry and delivered\n+#     per-frame: the transfer completes with zero retransmits.\n+#\n+# Topology (100.64.0.0/24):\n+#\n+#   ns_san                    ns_dut                      ns_peer\n+#  +-----------+  interlink  +---------------+  LAN A/B  +-----------+\n+#  | s0 [0.1]  |-------------| d_il   hsr0   |-----------| hsr1 [0.3]|\n+#  +-----------+             | d_a / d_b     |           | p_a / p_b |\n+#                            +---------------+           +-----------+\n+#\n+# SAN traffic reaches ns_peer only through hsr0's forward path\n+# (interlink RX -\u003e LAN A/B TX), so every SAN frame is tagged and\n+# forwarded by the DUT.\n+\n+source ./hsr_common.sh\n+\n+ns_dut=\"hsr-gro-dut\"\n+ns_san=\"hsr-gro-san\"\n+ns_peer=\"hsr-gro-peer\"\n+san_ip=\"100.64.0.1\"\n+peer_ip=\"100.64.0.3\"\n+iperf_pid=\"\"\n+server_wrapper=\"\"\n+iperf_pidfile=\"/tmp/hsr_gro_iperf.pid\"\n+\n+cleanup()\n+{\n+\tif [ -n \"${iperf_pid}\" ] \u0026\u0026 [[ \"${iperf_pid}\" =~ ^[0-9]+$ ]]; then\n+\t\tkill \"${iperf_pid}\" 2\u003e/dev/null\n+\tfi\n+\tif [ -n \"${server_wrapper}\" ]; then\n+\t\t# the wrapper waits on the server; reap it with a 5s bound so a\n+\t\t# live-but-unpublished server can never hang cleanup\n+\t\tfor _ in $(seq 1 50); do\n+\t\t\tkill -0 \"${server_wrapper}\" 2\u003e/dev/null || break\n+\t\t\tsleep 0.1\n+\t\tdone\n+\t\tkill \"${server_wrapper}\" 2\u003e/dev/null\n+\t\twait \"${server_wrapper}\" 2\u003e/dev/null\n+\t\tserver_wrapper=\"\"\n+\tfi\n+\t# last resort, namespace-scoped only: kill iperf3 processes that\n+\t# actually live in the peer netns. netns != pidns: a blind pkill\n+\t# would scan the host PID space and hit unrelated tests.\n+\tfor _p in $(ip netns pids \"$ns_peer\" 2\u003e/dev/null); do\n+\t\tif [ \"$(cat /proc/$_p/comm 2\u003e/dev/null)\" = \"iperf3\" ]; then\n+\t\t\tkill \"$_p\" 2\u003e/dev/null\n+\t\tfi\n+\tdone\n+\tiperf_pid=\"\"\n+\trm -f \"${iperf_pidfile}\"\n+\tip netns del \"$ns_dut\" 2\u003e/dev/null\n+\tip netns del \"$ns_san\" 2\u003e/dev/null\n+\tip netns del \"$ns_peer\" 2\u003e/dev/null\n+}\n+\n+trap cleanup EXIT\n+\n+check_tool()\n+{\n+\tif ! command -v \"$1\" \u003e /dev/null 2\u003e\u00261; then\n+\t\techo \"SKIP: Could not run test without $1\"\n+\t\texit $ksft_skip\n+\tfi\n+}\n+\n+nsx()\n+{\n+\tip netns exec \"$1\" bash -c \"$2\"\n+}\n+\n+setup_topo()\n+{\n+\tlocal ns\n+\n+\tcleanup\n+\tfor ns in \"$ns_dut\" \"$ns_san\" \"$ns_peer\"; do\n+\t\tip netns add \"$ns\"\n+\tdone\n+\n+\tip link add d_a netns \"$ns_dut\" type veth peer name p_a netns \"$ns_peer\"\n+\tip link add d_b netns \"$ns_dut\" type veth peer name p_b netns \"$ns_peer\"\n+\tip link add d_il netns \"$ns_dut\" type veth peer name s0 netns \"$ns_san\"\n+\n+\t# HSR tags add 6 bytes per frame; give the LAN legs headroom.\n+\tfor iface in d_a d_b; do\n+\t\tnsx \"$ns_dut\" \"ip link set $iface mtu 1600; ip link set $iface up\"\n+\tdone\n+\tfor iface in p_a p_b; do\n+\t\tnsx \"$ns_peer\" \"ip link set $iface mtu 1600; ip link set $iface up\"\n+\tdone\n+\n+\tnsx \"$ns_dut\" \"ip link set d_il up\"\n+\tnsx \"$ns_san\" \"ip link set s0 up; ip addr add $san_ip/24 dev s0\"\n+\n+\tnsx \"$ns_dut\" \"ip link add hsr0 type hsr \\\n+\t\tslave1 d_a slave2 d_b interlink d_il proto 0; \\\n+\t\tip link set hsr0 up\"\n+\tnsx \"$ns_peer\" \"ip link add hsr1 type hsr \\\n+\t\tslave1 p_a slave2 p_b proto 0; \\\n+\t\tip link set hsr1 up; ip addr add $peer_ip/24 dev hsr1\"\n+\n+\t# Let the nodes see each other's supervision frames.\n+\tsleep 2\n+}\n+\n+check_feature()\n+{\n+\tlocal ns=\"$1\"\n+\tlocal iface=\"$2\"\n+\tlocal feature=\"$3\"\n+\tlocal want=\"$4\"\n+\n+\tif nsx \"$ns\" \"ethtool -k $iface\" | grep -q \"^$feature: $want\"; then\n+\t\techo \"INFO: $ns/$iface $feature is $want [ OK ]\"\n+\telse\n+\t\techo \"FAIL: $ns/$iface $feature is not $want\" 1\u003e\u00262\n+\t\tret=1\n+\tfi\n+}\n+\n+do_gro_feature_checks()\n+{\n+\techo \"INFO: Checking that enslavement disabled GRO.\"\n+\tcheck_feature \"$ns_dut\" d_a generic-receive-offload off\n+\tcheck_feature \"$ns_dut\" d_b generic-receive-offload off\n+\tcheck_feature \"$ns_dut\" d_il generic-receive-offload off\n+\tstop_if_error \"GRO not disabled on enslaved devices.\"\n+\n+\techo \"INFO: Checking that enslavement disabled HW-GRO.\"\n+\tcheck_feature \"$ns_dut\" d_a rx-gro-hw off\n+\tcheck_feature \"$ns_dut\" d_b rx-gro-hw off\n+\tcheck_feature \"$ns_dut\" d_il rx-gro-hw off\n+\tstop_if_error \"HW-GRO not disabled on enslaved devices.\"\n+\n+\techo \"INFO: Checking that the HSR master does not advertise GSO/TSO.\"\n+\tcheck_feature \"$ns_dut\" hsr0 generic-segmentation-offload off\n+\tcheck_feature \"$ns_dut\" hsr0 tcp-segmentation-offload off\n+\tstop_if_error \"HSR master still advertises GSO/TSO.\"\n+}\n+\n+start_iperf_server()\n+{\n+\t# One-shot server, no -D: record its exact PID (netns shares the PID\n+\t# namespace). The wrapping shell waits on the server so the script can\n+\t# really wait(1) for the whole tree, on success and failure alike.\n+\trm -f \"${iperf_pidfile}\"\n+\t( nsx \"$ns_peer\" \"iperf3 -s -1 \u003e /dev/null 2\u003e\u00261 \u0026 echo \\$! \u003e ${iperf_pidfile}; wait\" ) \u0026\n+\tserver_wrapper=$!\n+\t# the wrapper writes the pidfile asynchronously; wait for it to\n+\t# appear instead of racing the read\n+\tfor _ in $(seq 1 50); do\n+\t\t[ -s \"${iperf_pidfile}\" ] \u0026\u0026 break\n+\t\tsleep 0.1\n+\tdone\n+\tif [ ! -s \"${iperf_pidfile}\" ]; then\n+\t\techo \"FAIL: iperf3 server did not publish a pid (no pidfile)\" 1\u003e\u00262\n+\t\tret=1\n+\t\treturn 1\n+\tfi\n+\tiperf_pid=$(cat \"${iperf_pidfile}\")\n+\tif ! [[ \"${iperf_pid}\" =~ ^[0-9]+$ ]] || ! kill -0 \"${iperf_pid}\" 2\u003e/dev/null; then\n+\t\techo \"FAIL: iperf3 server pid '${iperf_pid}' invalid or not alive\" 1\u003e\u00262\n+\t\tret=1\n+\t\treturn 1\n+\tfi\n+\tsleep 1\n+\treturn 0\n+}\n+\n+do_tso_stream_test()\n+{\n+\tlocal out sender_retr\n+\n+\techo \"INFO: Enabling TSO/GSO on the SAN interface.\"\n+\tnsx \"$ns_san\" \"ethtool -K s0 tso on gso on\"\n+\tcheck_feature \"$ns_san\" s0 tcp-segmentation-offload on\n+\tstop_if_error \"Could not enable TSO on the SAN interface.\"\n+\n+\techo \"INFO: Running 10s TCP stream SAN -\u003e peer through the HSR DUT.\"\n+\tstart_iperf_server || return\n+\t\t# rate-capped: the discriminator is per-frame unfold (completion with\n+\t# 0 retransmits), not max throughput; uncapped runs flap at VM/CI\n+\t# edge rates without indicating a functional problem.\n+\tout=$(nsx \"$ns_san\" \"timeout 60 iperf3 -c $peer_ip -M 1446 -b 2G -t 10\" 2\u003e\u00261)\n+\tif [ $? -ne 0 ]; then\n+\t\techo \"FAIL: iperf3 client failed:\" 1\u003e\u00262\n+\t\techo \"$out\" 1\u003e\u00262\n+\t\tret=1\n+\t\treturn\n+\tfi\n+\n+\t# success path: the one-shot server exits by itself; really wait for\n+\t# the wrapper to reap it, and check its exit status\n+\twait \"${server_wrapper}\"\n+\tserver_rc=$?\n+\tserver_wrapper=\"\"\n+\tiperf_pid=\"\"\n+\tif [ \"$server_rc\" -ne 0 ]; then\n+\t\techo \"FAIL: iperf3 server exited with rc=$server_rc\" 1\u003e\u00262\n+\t\tret=1\n+\t\treturn\n+\tfi\n+\n+\tsender_retr=$(echo \"$out\" | awk '/sender/ {print $(NF-1)}')\n+\tif [ -z \"$sender_retr\" ] || [ \"$sender_retr\" -ne 0 ]; then\n+\t\techo \"FAIL: retransmits during GSO unfold: ${sender_retr:-unknown}\" 1\u003e\u00262\n+\t\techo \"$out\" 1\u003e\u00262\n+\t\tret=1\n+\t\treturn\n+\tfi\n+\n+\techo \"INFO: TCP stream completed with 0 retransmits [ OK ]\"\n+\techo \"$out\" | grep -E \"sender|receiver\"\n+}\n+\n+check_prerequisites\n+check_tool ethtool\n+check_tool iperf3\n+check_tool timeout\n+\n+# iproute2 must know the HSR interlink syntax.\n+if ! ip link help hsr 2\u003e\u00261 | grep -qi interlink; then\n+\techo \"SKIP: iproute2 has no HSR interlink support\"\n+\texit $ksft_skip\n+fi\n+\n+setup_topo\n+\n+echo \"INFO: Initial validation ping (SAN -\u003e peer through the DUT).\"\n+do_ping \"$ns_san\" \"$peer_ip\"\n+stop_if_error \"Initial validation failed.\"\n+\n+do_gro_feature_checks\n+do_tso_stream_test\n+stop_if_error \"GSO super-packet stream test failed.\"\n+\n+echo \"INFO: All good.\"\n+exit $ret\n"
}

2/1 2026/07/23 20:30 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "HSR"
  ],
  "FocusSymbols": [
    "hsr_forward_skb",
    "hsr_dev_xmit",
    "hsr_handle_frame",
    "dev_disable_gro",
    "netif_disable_gro"
  ],
  "Reasoning": "The patch modifies HSR packet forwarding to handle GSO packets by segmenting them, and disables GRO on HSR slave devices. These are functional changes to reachable network code.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 00c8d685932036cc037da84897b1358e1e82f7ea
Author: syz-cluster <triage@syzkaller.com>
Date:   Thu Jul 23 20:30:27 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b546..eba2c26a49ba8f 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 *newskb);
 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 5933c5dab09ee1..a6cf2adc862565 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1840,6 +1840,24 @@ void netif_disable_lro(struct net_device *dev)
 	}
 }
 
+void netif_disable_gro(struct net_device *dev)
+{
+	struct net_device *lower_dev;
+	struct list_head *iter;
+
+	dev->wanted_features &= ~(NETIF_F_GRO | NETIF_F_GRO_HW);
+	netdev_update_features(dev);
+
+	if (unlikely(dev->features & (NETIF_F_GRO | NETIF_F_GRO_HW)))
+		netdev_WARN(dev, "failed to disable GRO!\n");
+
+	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 437947dd08ed53..02fb2162951284 100644
--- a/net/core/dev_api.c
+++ b/net/core/dev_api.c
@@ -269,6 +269,22 @@ void dev_disable_lro(struct net_device *dev)
 }
 EXPORT_SYMBOL(dev_disable_lro);
 
+/**
+ * dev_disable_gro() - disable Generic Receive Offload on a device
+ * @dev: device
+ *
+ * Disable 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.
+ */
+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_device.c b/net/hsr/hsr_device.c
index 5555b71ab19b59..248cbb142e21e1 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, struct net_device *dev)
 		skb->dev = 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 = htons(hsr->sequence_nr);
 		hsr->sequence_nr++;
 	}
+	spin_unlock_bh(&hsr->seqnr_lock);
 
 	hsr_stag->tlv.HSR_TLV_type = type;
 	/* HSRv0 has 6 unused bytes after the MAC */
@@ -356,14 +355,10 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
 		ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
 	}
 
-	if (skb_put_padto(skb, ETH_ZLEN)) {
-		spin_unlock_bh(&hsr->seqnr_lock);
+	if (skb_put_padto(skb, ETH_ZLEN))
 		return;
-	}
 
 	hsr_forward_skb(skb, port);
-	spin_unlock_bh(&hsr->seqnr_lock);
-	return;
 }
 
 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 = htons(hsr->sup_sequence_nr);
 	hsr->sup_sequence_nr++;
+	spin_unlock_bh(&hsr->seqnr_lock);
 	hsr_stag->tlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
 	hsr_stag->tlv.HSR_TLV_length = sizeof(struct hsr_sup_payload);
 
@@ -397,13 +393,10 @@ static void send_prp_supervision_frame(struct hsr_port *master,
 	hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
 	ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
 
-	if (skb_put_padto(skb, ETH_ZLEN)) {
-		spin_unlock_bh(&hsr->seqnr_lock);
+	if (skb_put_padto(skb, ETH_ZLEN))
 		return;
-	}
 
 	hsr_forward_skb(skb, master);
-	spin_unlock_bh(&hsr->seqnr_lock);
 }
 
 /* Announce (supervision frame) timer function
@@ -659,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 0774981a65c164..3fcdbac49c59da 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -12,6 +12,7 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <net/gso.h>
 #include "hsr_main.h"
 #include "hsr_framereg.h"
 
@@ -621,9 +622,10 @@ static void handle_std_frame(struct sk_buff *skb,
 	if (port->type == HSR_PT_MASTER ||
 	    port->type == 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 = hsr->sequence_nr;
 		hsr->sequence_nr++;
+		spin_unlock_bh(&hsr->seqnr_lock);
 	}
 }
 
@@ -731,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;
 
@@ -760,3 +762,50 @@ 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.
+ */
+void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)
+{
+	struct sk_buff *segs, *next;
+
+	if (likely(!skb_is_gso(skb))) {
+		hsr_forward_skb_one(skb, port);
+		return;
+	}
+
+	/* Unfold only plain-Ethernet GSO super-packets: locally generated
+	 * on the master, or arriving untagged from the SAN side on the
+	 * interlink. A super-packet from a LAN slave may carry per-frame
+	 * HSR tags / PRP RCT trailers that software segmentation cannot
+	 * recover; an already-tagged HSR/PRP super-packet violates
+	 * per-frame wire semantics. Drop both.
+	 */
+	if (port->type != HSR_PT_MASTER && port->type != HSR_PT_INTERLINK)
+		goto drop_gso;
+	if (skb->protocol == htons(ETH_P_HSR) ||
+	    skb->protocol == 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:
+	port->dev->stats.tx_dropped++;
+	kfree_skb(skb);
+}
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index d9af9e65f72f07..c7fd021f03b1f4 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_buff **pskb)
 	}
 	skb_reset_mac_len(skb);
 
-	/* Only the frames received over the interlink port will assign a
-	 * sequence number and require synchronisation vs other sender.
-	 */
-	if (port->type == 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);
 
 finish_consume:
 	return RX_HANDLER_CONSUMED;
@@ -170,6 +161,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,
 	if (res)
 		goto fail_rx_handler;
 	dev_disable_lro(dev);
+	dev_disable_gro(dev);
 
 	return 0;
 
diff --git a/tools/testing/selftests/net/hsr/Makefile b/tools/testing/selftests/net/hsr/Makefile
index 31fb9326cf533d..0d105476e7c50d 100644
--- a/tools/testing/selftests/net/hsr/Makefile
+++ b/tools/testing/selftests/net/hsr/Makefile
@@ -3,6 +3,7 @@
 top_srcdir = ../../../../..
 
 TEST_PROGS := \
+	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 00000000000000..4b0a9ceea1ce59
--- /dev/null
+++ b/tools/testing/selftests/net/hsr/hsr_gro_superpacket.sh
@@ -0,0 +1,249 @@
+#!/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 and delivered
+#     per-frame: the transfer completes with zero retransmits.
+#
+# 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
+
+ns_dut="hsr-gro-dut"
+ns_san="hsr-gro-san"
+ns_peer="hsr-gro-peer"
+san_ip="100.64.0.1"
+peer_ip="100.64.0.3"
+iperf_pid=""
+server_wrapper=""
+iperf_pidfile="/tmp/hsr_gro_iperf.pid"
+
+cleanup()
+{
+	if [ -n "${iperf_pid}" ] && [[ "${iperf_pid}" =~ ^[0-9]+$ ]]; then
+		kill "${iperf_pid}" 2>/dev/null
+	fi
+	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=""
+	fi
+	# last resort, namespace-scoped only: kill iperf3 processes that
+	# actually live in the peer netns. netns != pidns: a blind pkill
+	# would scan the host PID space and hit unrelated tests.
+	for _p in $(ip netns pids "$ns_peer" 2>/dev/null); do
+		if [ "$(cat /proc/$_p/comm 2>/dev/null)" = "iperf3" ]; then
+			kill "$_p" 2>/dev/null
+		fi
+	done
+	iperf_pid=""
+	rm -f "${iperf_pidfile}"
+	ip netns del "$ns_dut" 2>/dev/null
+	ip netns del "$ns_san" 2>/dev/null
+	ip netns del "$ns_peer" 2>/dev/null
+}
+
+trap cleanup EXIT
+
+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"
+}
+
+setup_topo()
+{
+	local ns
+
+	cleanup
+	for ns in "$ns_dut" "$ns_san" "$ns_peer"; do
+		ip netns add "$ns"
+	done
+
+	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="$1"
+	local iface="$2"
+	local feature="$3"
+	local want="$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=1
+	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
+	stop_if_error "HSR master still advertises GSO/TSO."
+}
+
+start_iperf_server()
+{
+	# One-shot server, no -D: record its exact PID (netns shares the PID
+	# namespace). The wrapping shell waits on the server so the script can
+	# really wait(1) for the whole tree, on success and failure alike.
+	rm -f "${iperf_pidfile}"
+	( nsx "$ns_peer" "iperf3 -s -1 > /dev/null 2>&1 & echo \$! > ${iperf_pidfile}; wait" ) &
+	server_wrapper=$!
+	# the wrapper writes the pidfile asynchronously; wait for it to
+	# appear instead of racing the read
+	for _ in $(seq 1 50); do
+		[ -s "${iperf_pidfile}" ] && break
+		sleep 0.1
+	done
+	if [ ! -s "${iperf_pidfile}" ]; then
+		echo "FAIL: iperf3 server did not publish a pid (no pidfile)" 1>&2
+		ret=1
+		return 1
+	fi
+	iperf_pid=$(cat "${iperf_pidfile}")
+	if ! [[ "${iperf_pid}" =~ ^[0-9]+$ ]] || ! kill -0 "${iperf_pid}" 2>/dev/null; then
+		echo "FAIL: iperf3 server pid '${iperf_pid}' invalid or not alive" 1>&2
+		ret=1
+		return 1
+	fi
+	sleep 1
+	return 0
+}
+
+do_tso_stream_test()
+{
+	local out sender_retr
+
+	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 || return
+		# rate-capped: the discriminator is per-frame unfold (completion with
+	# 0 retransmits), not max throughput; uncapped runs flap at VM/CI
+	# edge rates without indicating a functional problem.
+	out=$(nsx "$ns_san" "timeout 60 iperf3 -c $peer_ip -M 1446 -b 2G -t 10" 2>&1)
+	if [ $? -ne 0 ]; then
+		echo "FAIL: iperf3 client failed:" 1>&2
+		echo "$out" 1>&2
+		ret=1
+		return
+	fi
+
+	# success path: the one-shot server exits by itself; really wait for
+	# the wrapper to reap it, and check its exit status
+	wait "${server_wrapper}"
+	server_rc=$?
+	server_wrapper=""
+	iperf_pid=""
+	if [ "$server_rc" -ne 0 ]; then
+		echo "FAIL: iperf3 server exited with rc=$server_rc" 1>&2
+		ret=1
+		return
+	fi
+
+	sender_retr=$(echo "$out" | awk '/sender/ {print $(NF-1)}')
+	if [ -z "$sender_retr" ] || [ "$sender_retr" -ne 0 ]; then
+		echo "FAIL: retransmits during GSO unfold: ${sender_retr:-unknown}" 1>&2
+		echo "$out" 1>&2
+		ret=1
+		return
+	fi
+
+	echo "INFO: TCP stream completed with 0 retransmits [ OK ]"
+	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."
+
+echo "INFO: All good."
+exit $ret

3/2 2026/07/23 20:30 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 8563
							output: 28
							thoughts: 316
						

Thoughts:
**Fuzzing Decision for the Kernel Patch**

Okay, so I need to decide if this patch warrants fuzzing, and it looks like it does. The patch touches a few key areas in the kernel networking stack: `net/core/dev.c`, `net/core/dev_api.c`, and a bunch of HSR-related files (`net/hsr/hsr_device.c`, `net/hsr/hsr_forward.c`, `net/hsr/hsr_slave.c`). It's also adding a selftest, which is a good sign. The additions of `netif_disable_gro` and `dev_disable_gro` functions immediately flag my attention, along with modifications to HSR, specifically disabling GRO on slave devices and introducing GSO fan-out funneling in `hsr_forward_skb`.

The core of the change seems to be around HSR packet forwarding, particularly how it handles Generic Segmentation Offload (GSO) packets with the `hsr_forward_skb` function. This is important. There's also some locking changes around `hsr->seqnr_lock`, so that's something to investigate further.

Now, the crucial question is whether HSR is reachable and can be effectively tested within a fuzzing context. Since HSR is a virtual network device, that means it's definitely accessible. I remember seeing a description of how to create an HSR device via netlink (rtnetlink) in the included selftest: `ip link add hsr0 type hsr slave1 d_a slave2 d_b interlink d_il proto 0`. Excellent. That means we should be able to create HSR devices in a virtualized fuzzing environment, making it a very viable target.

Next step: let's figure out what CONFIG options are involved. I'll do a quick `Kconfig` search for HSR.



4/2 2026/07/23 20:30 tool grepper
0m Args:
{
  "Expression": "config HSR",
  "PathPrefix": "net/hsr/"
}

Results:
{
  "Output": "net/hsr/Kconfig-5-\nnet/hsr/Kconfig:6:config HSR\nnet/hsr/Kconfig-7-\ttristate \"High-availability Seamless Redundancy (HSR \u0026 PRP)\"\n"
}

5/2 2026/07/23 20:30 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9384
							output: 32
							thoughts: 97
						

Thoughts:
Okay, here's my breakdown of what I'm looking at, from my expert perspective:

**HSR Configuration Deep Dive**

Right, so I see `CONFIG_HSR` – that's the central configuration option for High-availability Seamless Redundancy. Time to start digging into the core functionality. I need to get a solid grasp of how this HSR stuff is working.

My initial focus is going to be on a few critical functions, the heart of the HSR process:

*   `hsr_forward_skb`: This is probably the workhorse, handling the forwarding of SKBs.
*   `hsr_dev_xmit`: Likely the device transmit function.
*   `hsr_handle_frame`: Essential for processing incoming frames, the receiver side.
*   `dev_disable_gro` & `netif_disable_gro`: These likely deal with disabling Generic Receive Offload (GRO). We are dealing with real-time requirements, and GRO could be problematic here.

I think I'll start with `hsr_forward_skb`, and it looks like that code is in `net/hsr/hsr_forward.c` based on the file path. Let's see what the forwarding process is like.



6/2 2026/07/23 20:30 tool grepper
0m Args:
{
  "Expression": "hsr_forward_skb",
  "PathPrefix": "net/hsr/"
}

Results:
{
  "Output": "net/hsr/hsr_device.c=224=static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)\n--\nnet/hsr/hsr_device.c-234-\t\tskb_reset_mac_len(skb);\nnet/hsr/hsr_device.c:235:\t\thsr_forward_skb(skb, master);\nnet/hsr/hsr_device.c-236-\t} else {\n--\nnet/hsr/hsr_device.c=291=static void send_hsr_supervision_frame(struct hsr_port *port,\n--\nnet/hsr/hsr_device.c-360-\nnet/hsr/hsr_device.c:361:\thsr_forward_skb(skb, port);\nnet/hsr/hsr_device.c-362-}\n--\nnet/hsr/hsr_device.c=364=static void send_prp_supervision_frame(struct hsr_port *master,\n--\nnet/hsr/hsr_device.c-398-\nnet/hsr/hsr_device.c:399:\thsr_forward_skb(skb, master);\nnet/hsr/hsr_device.c-400-}\n--\nnet/hsr/hsr_forward.c=678=static int fill_frame_info(struct hsr_frame_info *frame,\n--\nnet/hsr/hsr_forward.c-735-/* Must be called holding rcu read lock (because of the port parameter) */\nnet/hsr/hsr_forward.c:736:static void hsr_forward_skb_one(struct sk_buff *skb, struct hsr_port *port)\nnet/hsr/hsr_forward.c-737-{\n--\nnet/hsr/hsr_forward.c-768- */\nnet/hsr/hsr_forward.c:769:void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)\nnet/hsr/hsr_forward.c-770-{\n--\nnet/hsr/hsr_forward.c-773-\tif (likely(!skb_is_gso(skb))) {\nnet/hsr/hsr_forward.c:774:\t\thsr_forward_skb_one(skb, port);\nnet/hsr/hsr_forward.c-775-\t\treturn;\n--\nnet/hsr/hsr_forward.c-802-\t\tsegs-\u003enext = NULL;\nnet/hsr/hsr_forward.c:803:\t\thsr_forward_skb_one(segs, port);\nnet/hsr/hsr_forward.c-804-\t\tsegs = next;\n--\nnet/hsr/hsr_forward.h-15-\nnet/hsr/hsr_forward.h:16:void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port);\nnet/hsr/hsr_forward.h-17-struct sk_buff *prp_create_tagged_frame(struct hsr_frame_info *frame,\n--\nnet/hsr/hsr_slave.c=24=static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)\n--\nnet/hsr/hsr_slave.c-75-\nnet/hsr/hsr_slave.c:76:\thsr_forward_skb(skb, port);\nnet/hsr/hsr_slave.c-77-\n"
}

7/2 2026/07/23 20:30 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10730
							output: 29
							thoughts: 111
						

Thoughts:
**Analyzing the Recent Patch for HSR Forwarding**

Okay, so this patch is introducing some key changes related to HSR (High-availability Seamless Redundancy) forwarding. Specifically, it's adding two new functions, `hsr_forward_skb` and `hsr_forward_skb_one`, which immediately tells me this is about handling SKBs (Socket Buffers) in the HSR context. This is what I expected, given the nature of the issue.

The fact that it also modifies `hsr_dev_xmit` and `hsr_handle_frame` is crucial. Those functions are at the heart of transmitting and receiving frames within the HSR network. Any alteration here warrants close inspection, as performance and reliability hinges on those modules.

Now, the inclusion of `netif_disable_gro` and `dev_disable_gro` in `net/core/dev.c` and `net/core/dev_api.c`, respectively, is what's piquing my interest the most. That’s about Generic Receive Offload, or GRO. I need to understand why GRO is being disabled. This can have significant performance implications if not carefully managed. I'm going to focus in on `dev_disable_gro` in `net/core/dev_api.c`. This could be due to issues with HSR's duplicate frame handling and GRO's aggregation, or perhaps it's a specific incompatibility identified during testing. Disabling GRO is a tradeoff, and I need to understand what the developer’s thinking was, in doing so.



8/2 2026/07/23 20:30 tool grepper
0m Args:
{
  "Expression": "dev_disable_gro",
  "PathPrefix": "net/core/"
}

Results:
{
  "Output": "net/core/dev.c=1843=void netif_disable_gro(struct net_device *dev)\n--\nnet/core/dev.c-1861-/**\nnet/core/dev.c:1862: *\tdev_disable_gro_hw - disable HW Generic Receive Offload on a device\nnet/core/dev.c-1863- *\t@dev: device\n--\nnet/core/dev.c-1868- */\nnet/core/dev.c:1869:static void dev_disable_gro_hw(struct net_device *dev)\nnet/core/dev.c-1870-{\n--\nnet/core/dev.c=6378=static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)\n--\nnet/core/dev.c-6394-\t\t\tnetif_disable_lro(dev);\nnet/core/dev.c:6395:\t\t\tdev_disable_gro_hw(dev);\nnet/core/dev.c-6396-\t\t}\n--\nnet/core/dev_api.c=270=EXPORT_SYMBOL(dev_disable_lro);\n--\nnet/core/dev_api.c-272-/**\nnet/core/dev_api.c:273: * dev_disable_gro() - disable Generic Receive Offload on a device\nnet/core/dev_api.c-274- * @dev: device\n--\nnet/core/dev_api.c-279- */\nnet/core/dev_api.c:280:void dev_disable_gro(struct net_device *dev)\nnet/core/dev_api.c-281-{\n--\nnet/core/dev_api.c-285-}\nnet/core/dev_api.c:286:EXPORT_SYMBOL(dev_disable_gro);\nnet/core/dev_api.c-287-\n"
}

9/2 2026/07/23 20:30 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11706
							output: 23
							thoughts: 106
						

Thoughts:
**My Analysis of the GRO Disabling Patch for HSR**

Okay, so this patch introduces `dev_disable_gro` and `netif_disable_gro`. My understanding is that these functions are specifically invoked when a network device is enslaved under an HSR (High-availability Seamless Redundancy) master. That's a crucial point to remember for context.

I need to make sure this patch is properly documented and easily discoverable. I'm going to add the key functions—`hsr_forward_skb`, `hsr_dev_xmit`, `hsr_handle_frame`, along with these new `dev_disable_gro` and `netif_disable_gro` functions—to the `FocusSymbols` list. This way, any engineer working with HSR will be able to easily find them.

The necessary configuration to enable this functionality is, obviously, `HSR`. I must make that clear in the documentation. However, before I finalize this, it's always a good practice to double-check. I should quickly scan the code to ensure there aren't any other dependent configurations or potential conflicts lurking. This will help prevent future issues and ensure the integration is clean and stable.



10/2 2026/07/23 20:30 tool grepper
0m Args:
{
  "Expression": "config HSR",
  "PathPrefix": ""
}

Results:
{
  "Output": "net/hsr/Kconfig-5-\nnet/hsr/Kconfig:6:config HSR\nnet/hsr/Kconfig-7-\ttristate \"High-availability Seamless Redundancy (HSR \u0026 PRP)\"\n"
}

11/2 2026/07/23 20:30 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12158
							output: 115
							thoughts: 159
						

Thoughts:
**My Assessment of the Patch**

Okay, so there aren't any other configuration files to consider; this is the full picture. Let's get down to brass tacks: does the patch work as advertised? Yes, it does. This thing actually alters how HSR forwards packets, and the key modification is that it correctly handles GSO packets by segmenting them. Plus, it disables Generic Receive Offload (GRO) on the slave devices. That's a functional change, and the code it touches is definitely reachable – a good sign.

Given that it introduces these significant and reachable functional changes to the network code, I'm going to set `WorthFuzzing` to `true`.  We need to put this through its paces. The crucial symbols to focus on are `hsr_forward_skb`, `hsr_dev_xmit`, `hsr_handle_frame`, `dev_disable_gro`, and `netif_disable_gro`.  The only configuration option we need to ensure is enabled is, naturally, `HSR`. The reasoning here is solid: it modifies HSR's forwarding path to address GSO and disables GRO on the slave devices. These are demonstrable, functional changes, within reachable network code, and ripe for fuzzing.



12/2 2026/07/23 20:30 tool set-results
0m Args:
{
  "EnableConfigs": [
    "HSR"
  ],
  "FocusSymbols": [
    "hsr_forward_skb",
    "hsr_dev_xmit",
    "hsr_handle_frame",
    "dev_disable_gro",
    "netif_disable_gro"
  ],
  "Reasoning": "The patch modifies HSR packet forwarding to handle GSO packets by segmenting them, and disables GRO on HSR slave devices. These are functional changes to reachable network code.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "HSR"
  ],
  "FocusSymbols": [
    "hsr_forward_skb",
    "hsr_dev_xmit",
    "hsr_handle_frame",
    "dev_disable_gro",
    "netif_disable_gro"
  ],
  "Reasoning": "The patch modifies HSR packet forwarding to handle GSO packets by segmenting them, and disables GRO on HSR slave devices. These are functional changes to reachable network code.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)