Netdev List
 help / color / mirror / Atom feed
* [PATCH net v6 0/3] tipc: fix NULL deref in tipc_named_node_up() on empty publication list
From: Weiming Shi @ 2026-07-17 18:56 UTC (permalink / raw)
  To: Jon Maloy, Tung Nguyen, netdev, tipc-discussion; +Cc: Xiang Mei, Weiming Shi

This series continues the fix for the NULL dereference in
tipc_named_node_up() on an empty publication list.

Patch 1/3 carries Tung Nguyen's defer-to-workqueue approach, suggested
by Jon Maloy on the thread as the replacement for the item-less bulk
from v2. Tung's RFC only exists as an inline diff in the thread, so I
folded it into this series with his Signed-off-by kept. I tested it in
our two-node QEMU setup (veth pair, UDP bearers, node-id addressing),
both with an unprivileged user namespace and as root: the unpatched
kernel panics on the first run of the same reproducer, the patched one
distributes normally with a non-empty list.

While testing we found two residual issues in the approach, fixed by
patches 2/3 and 3/3.

Patch 2/3: tipc_net_finalize() does not check the return value of
tipc_nametbl_publish(). If the publish fails, for example on a
GFP_ATOMIC allocation failure, the node is finalized but cluster_scope
stays empty. The deferred worker then calls named_distribute() with
an empty list and hits the same NULL dereference, this time on the
workqueue. With this patch the worker re-checks the list and skips
cleanly, no crash and no link flap. The tail stamp in
named_distribute() also gets an empty-queue guard.

Patch 3/3: a repeated NODE_UP while the bulk work is pending takes a
node reference that is never dropped, because schedule_work() returns
false when the work is already queued. Found by flapping the bearer
during the defer window. One reference is leaked per repeated
NODE_UP.

Changes in v6:
 - Make the series self-contained: fold Tung Nguyen's base patch into
   the series (1/3), keeping his Signed-off-by. The version sent as
   v5 only carried the two follow-ups and depended on his patch from
   the thread; the code changes in 2/3 and 3/3 are unchanged from
   that version.

Changes in v5:
 - Replace the item-less bulk approach with Tung Nguyen's
   defer-to-workqueue RFC, which fixes the reported bug in our
   testing.
 - Fix two residual issues found during testing (patches 2/3, 3/3).

Weiming Shi (3):
  tipc: fix NULL deref in tipc_named_node_up() on empty publication list
  tipc: fix NULL deref in deferred bulk distribution on publish failure
  tipc: fix node reference leak when defer work is already pending

 net/tipc/core.c       |  1 +
 net/tipc/core.h       |  2 ++
 net/tipc/name_distr.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++----
 net/tipc/name_distr.h |  3 ++-
 net/tipc/net.c        |  5 ++++-
 net/tipc/node.c       | 35 ++++++++++++++++++++++++++++--
 6 files changed, 97 insertions(+), 8 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH net 13/13] iavf: validate num_vsis in VIRTCHNL_OP_GET_VF_RESOURCES response
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Junrui Luo, anthony.l.nguyen, przemyslaw.kitszel, Yuhao Jiang,
	stable, Aleksandr Loktionov, Simon Horman, Rafal Romanowski
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Junrui Luo <moonafterrain@outlook.com>

The VF allocates a fixed-size buffer for IAVF_MAX_VF_VSI (3) VSI
entries when processing a VIRTCHNL_OP_GET_VF_RESOURCES response from
the PF. However, num_vsis from the PF response is used unchecked as
the loop bound when iterating over vsi_res[] in multiple functions.

A PF sending num_vsis greater than IAVF_MAX_VF_VSI, or the received
message is shorter than num_vsis claims leads to out-of-bounds accesses
on the vsi_res[] array.

Clamp num_vsis based on the actual bytes copied from the PF response.

Fixes: 5eae00c57f5e ("i40evf: main driver core")
Reported-by: Yuhao Jiang <danisjiang@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 .../net/ethernet/intel/iavf/iavf_virtchnl.c   | 26 +++++++++++++++----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index ec234cc8bd9d..c4039d2b24a4 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -248,12 +248,28 @@ int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter)
 /**
  * iavf_validate_num_queues
  * @adapter: adapter structure
+ * @msglen: length of the received VF resource message
  *
- * Validate that the number of queues the PF has sent in
- * VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle.
+ * Validate the VIRTCHNL_OP_GET_VF_RESOURCES response from the PF. Ensure
+ * num_vsis does not exceed what the message length can cover, and cap
+ * num_queue_pairs to the VF maximum.
  **/
-static void iavf_validate_num_queues(struct iavf_adapter *adapter)
+static void iavf_validate_num_queues(struct iavf_adapter *adapter, u16 msglen)
 {
+	u16 max_vsis;
+
+	if (msglen < sizeof(struct virtchnl_vf_resource))
+		max_vsis = 0;
+	else
+		max_vsis = (msglen - sizeof(struct virtchnl_vf_resource)) /
+			   sizeof(struct virtchnl_vsi_resource);
+
+	if (adapter->vf_res->num_vsis > max_vsis) {
+		dev_info(&adapter->pdev->dev, "Received %d VSIs, but message can only cover %d\n",
+			 adapter->vf_res->num_vsis, max_vsis);
+		adapter->vf_res->num_vsis = max_vsis;
+	}
+
 	if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
 		struct virtchnl_vsi_resource *vsi_res;
 		int i;
@@ -300,7 +316,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter)
 	 * we aren't getting too many queues
 	 */
 	if (!err)
-		iavf_validate_num_queues(adapter);
+		iavf_validate_num_queues(adapter, min(event.msg_len, len));
 	iavf_vf_parse_hw_config(hw, adapter->vf_res);
 
 	kfree(event.msg_buf);
@@ -2578,7 +2594,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
 		u16 len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE;
 
 		memcpy(adapter->vf_res, msg, min(msglen, len));
-		iavf_validate_num_queues(adapter);
+		iavf_validate_num_queues(adapter, min(msglen, len));
 		iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res);
 		if (is_zero_ether_addr(adapter->hw.mac.addr)) {
 			/* restore current mac address */
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 12/13] idpf: fix max_vport related crash on allocation error during init
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Emil Tantilov, anthony.l.nguyen, willemb, Madhu Chittim,
	Aleksandr Loktionov, Simon Horman, Samuel Salin
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

Set adapter->max_vports only after successful allocation of vports, netdevs
and  vport_config buffers. This fixes possible crashes on reset or rmmod,
following failed allocation on init

[  305.981402] idpf 0000:83:00.0: enabling device (0100 -> 0102)
[  305.994464] idpf 0000:83:00.0: Device HW Reset initiated
[  320.416872] BUG: kernel NULL pointer dereference, address: 0000000000000000
[  320.416918] #PF: supervisor read access in kernel mode
[  320.416942] #PF: error_code(0x0000) - not-present page
[  320.416963] PGD 2099657067 P4D 0
[  320.416983] Oops: Oops: 0000 [#1] SMP NOPTI
...
[  320.417093] RIP: 0010:idpf_remove+0x118/0x200 [idpf]
[  320.417130] Code: 8b bb 98 09 00 00 e8 17 0f 5b e5 48 8b bb e8 08 00 00 e8 0b 0f 5b e5 66 83 bb 28 06 00 00 00 48 8b bb 20 06 00 00 74 49 31 ed <48> 8b 04 ef 48 85 c0 74 2f 48 8b 78 20 e8 66 58 91 e5 48 8b 83 20
[  320.417183] RSP: 0018:ff7322212903fdb8 EFLAGS: 00010246
[  320.417205] RAX: 0000000000000000 RBX: ff4463de40300000 RCX: ff7322212903fd4c
[  320.417228] RDX: 0000000000000001 RSI: ffffffffa7f7d100 RDI: 0000000000000000
[  320.417250] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000
[  320.417272] R10: 0000000000000001 R11: ff4463de3a638f58 R12: ff4463be89ac7000
[  320.417294] R13: ff4463be89ac7198 R14: ff4463be94fc7198 R15: ffffffffc0f10f20
[  320.417317] FS:  00007f963c0e6740(0000) GS:ff4463fdd65d8000(0000) knlGS:0000000000000000
[  320.417342] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  320.417362] CR2: 0000000000000000 CR3: 00000020ba674002 CR4: 0000000000773ef0
[  320.417385] PKRU: 55555554
[  320.417398] Call Trace:
[  320.417412]  <TASK>
[  320.417429]  pci_device_remove+0x42/0xb0
[  320.417459]  device_release_driver_internal+0x1a9/0x210
[  320.417492]  driver_detach+0x4b/0x90
[  320.417516]  bus_remove_driver+0x70/0x100
[  320.417539]  pci_unregister_driver+0x2e/0xb0
[  320.417564]  __do_sys_delete_module.constprop.0+0x190/0x2f0
[  320.417592]  ? kmem_cache_free+0x31e/0x550
[  320.417619]  ? lockdep_hardirqs_on_prepare+0xde/0x190
[  320.417644]  ? do_syscall_64+0x38/0x6b0
[  320.417665]  do_syscall_64+0xc8/0x6b0
[  320.417683]  ? clear_bhb_loop+0x30/0x80
[  320.417706]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  320.417727] RIP: 0033:0x7f963bb30beb

Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration")
Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Samuel Salin <Samuel.salin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index be66f9b2e101..dc5ad784f456 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -3555,7 +3555,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
 
 	pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter));
 	num_max_vports = idpf_get_max_vports(adapter);
-	adapter->max_vports = num_max_vports;
 	adapter->vports = kzalloc_objs(*adapter->vports, num_max_vports);
 	if (!adapter->vports)
 		return -ENOMEM;
@@ -3576,6 +3575,12 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
 		goto err_netdev_alloc;
 	}
 
+	/* Set max_vports only after vports, netdevs and vport_config buffers
+	 * are allocated to make sure max_vport bound loops don't end up
+	 * crashing, following allocation errors on init.
+	 */
+	adapter->max_vports = num_max_vports;
+
 	/* Start the mailbox task before requesting vectors. This will ensure
 	 * vector information response from mailbox is handled
 	 */
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 11/13] ice: reject out-of-range ptype in ice_parser_profile_init
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Aleksandr Loktionov, anthony.l.nguyen, horms, stable,
	Marcin Szycik, Rafal Romanowski
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Aleksandr Loktionov <aleksandr.loktionov@intel.com>

set_bit(rslt->ptype, prof->ptypes) operates on a DECLARE_BITMAP of
ICE_FLOW_PTYPE_MAX (1024) bits. Nothing prevents a malicious VF from
providing ptype >= 1024 through VIRTCHNL, resulting in a write past
the end of the bitmap and a kernel page fault.

Reproduced with a custom kernel module injecting a crafted
VIRTCHNL_OP_ADD_RSS_CFG on E810-C QSFP (8086:1592),
FW 4.91 0x800214af 1.3909.0, ICE COMMS DDP 1.3.53.0,
kernel 7.1.0-rc1.

crash_parser: ice_parser_profile_init @ ffffffffc0d61b60
crash_parser: setting ptype=0xffff (max valid=1023)
crash_parser: calling ice_parser_profile_init -- expect OOB crash!
BUG: kernel NULL pointer dereference, address: 0000000000000000
Oops: Oops: 0002 [#1] SMP NOPTI
CPU: 56 UID: 0 PID: 165011 Comm: insmod Kdump: loaded Tainted: G S U OE 7.1.0-rc1 #1
Hardware name: Intel Corporation S2600BPB/S2600BPB
RIP: 0010:ice_parser_profile_init+0x2d/0x1d0 [ice]
Call Trace:
 <TASK>
 ? __pfx_ice_parser_profile_init+0x10/0x10 [ice]
 crash_init+0x127/0xff0 [crash_parser]
 do_one_initcall+0x45/0x310
 do_init_module+0x64/0x270
 init_module_from_file+0xcc/0xf0
 idempotent_init_module+0x17b/0x280
 __x64_sys_finit_module+0x6e/0xe0

Bail out early with -EINVAL when ptype is out of range.

Fixes: e312b3a1e209 ("ice: add API for parser profile initialization")
Cc: stable@vger.kernel.org
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_parser.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/intel/ice/ice_parser.c b/drivers/net/ethernet/intel/ice/ice_parser.c
index f8e69630fb72..3ede4c1a5a8a 100644
--- a/drivers/net/ethernet/intel/ice/ice_parser.c
+++ b/drivers/net/ethernet/intel/ice/ice_parser.c
@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_parser_result *rslt,
 	u16 proto_off = 0;
 	u16 off;
 
+	if (rslt->ptype >= ICE_FLOW_PTYPE_MAX)
+		return -EINVAL;
+
 	memset(prof, 0, sizeof(*prof));
 	set_bit(rslt->ptype, prof->ptypes);
 	if (blk == ICE_BLK_SW) {
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 10/13] ice: prevent tstamp ring allocation for non-PF VSI types
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Paul Greenwalt, anthony.l.nguyen, Przemek Kitszel,
	Aleksandr Loktionov, Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Paul Greenwalt <paul.greenwalt@intel.com>

The pf->txtime_txqs bitmap tracks which Tx queues have ETF (Earliest
TxTime First) offload enabled. This bitmap is indexed by queue number
and is set by ice_offload_txtime(), which only operates on PF VSI
queues.

However, ice_is_txtime_ena() does not check the VSI type before
consulting the bitmap. When ETF offload is enabled on PF Tx queue 0,
bit 0 is set in pf->txtime_txqs. During a subsequent PCI reset
rebuild, the CTRL VSI's Tx queue 0 is reconfigured and
ice_is_txtime_ena() is called for that ring. Since it only checks
pf->txtime_txqs by queue index without distinguishing VSI type, it
finds bit 0 set and returns true, matching the PF VSI's ETF queue,
not the CTRL VSI's. This causes ice_vsi_cfg_txq() to spuriously
allocate a tstamp_ring for the CTRL VSI ring.

Since CTRL VSI rings have no associated netdev, ice_clean_tx_ring()
takes an early return at the !netdev check before reaching
ice_free_tx_tstamp_ring(), leaking the allocation. Each PCI reset
leaks one 64-byte tstamp_ring.

Fix this by restricting ice_is_txtime_ena() to return true only for
PF VSI rings, since txtime_txqs is only meaningful for PF VSI queues.

Fixes: ccde82e90946 ("ice: add E830 Earliest TxTime First Offload support")
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index f72bb1aa4067..fc91b6665f90 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -767,6 +767,9 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
 	struct ice_vsi *vsi = ring->vsi;
 	struct ice_pf *pf = vsi->back;
 
+	if (vsi->type != ICE_VSI_PF)
+		return false;
+
 	return test_bit(ring->q_index,  pf->txtime_txqs);
 }
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 09/13] ice: fix PTP Call Trace during PTP release
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Paul Greenwalt, anthony.l.nguyen, horms, richardcochran,
	jacob.e.keller, stable, Aleksandr Loktionov, Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Paul Greenwalt <paul.greenwalt@intel.com>

If a PF reset occurs when the PTP state is ICE_PTP_UNINIT, then
ice_ptp_rebuild() will update the state to ICE_PTP_ERROR. This will
result in the following PTP release call trace during driver unload:

    kernel BUG at lib/list_debug.c:52!
    ice_ptp_release+0x332/0x3c0 [ice]
    ice_deinit_features.part.0+0x10e/0x120 [ice]
    ice_remove+0x100/0x220 [ice]

This was observed when passing PF1 through to a VM. ice_ptp_init()
fails because ctrl_pf is NULL and sets the state to ICE_PTP_UNINIT.

Fix by detecting the ICE_PTP_UNINIT state in ice_ptp_rebuild() and
returning without error, preventing the invalid state transition to
ICE_PTP_ERROR. The only valid path to ICE_PTP_ERROR is from
ICE_PTP_RESETTING after a failed rebuild.

Fixes: 8293e4cb2ff5 ("ice: introduce PTP state machine")
Cc: stable@vger.kernel.org
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_ptp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 1469038bc895..eaec36ab6ae3 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -3037,6 +3037,11 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
 	struct ice_ptp *ptp = &pf->ptp;
 	int err;
 
+	if (ptp->state == ICE_PTP_UNINIT) {
+		dev_dbg(ice_pf_to_dev(pf), "PTP was not initialized, skipping rebuild\n");
+		return;
+	}
+
 	if (ptp->state == ICE_PTP_READY) {
 		ice_ptp_prepare_for_reset(pf, reset_type);
 	} else if (ptp->state != ICE_PTP_RESETTING) {
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 08/13] ice: use READ_ONCE() to access cached PHC time
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Sergey Temerkhanov, anthony.l.nguyen, richardcochran,
	jacob.e.keller, stable, Aleksandr Loktionov, Simon Horman,
	Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Sergey Temerkhanov <sergey.temerkhanov@intel.com>

ptp.cached_phc_time is a 64-bit value updated by a periodic work item
on one CPU and read locklessly on another.  On 32-bit or non-atomic
architectures this can result in a torn read.  Use READ_ONCE() to
enforce a single atomic load.

Fixes: 77a781155a65 ("ice: enable receive hardware timestamping")
Cc: stable@vger.kernel.org
Signed-off-by: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index ec3d89d8d4d3..1469038bc895 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -346,7 +346,7 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
 		return 0;
 	}
 
-	return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
+	return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time),
 				     (in_tstamp >> 8) & mask);
 }
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 07/13] ice: support SBQ posted writes with non-posted support for CGU
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Karol Kolacinski, richardcochran, jacob.e.keller,
	Przemyslaw Korba, Aleksandr Loktionov, Arkadiusz Kubalewski,
	Simon Horman, Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Karol Kolacinski <karol.kolacinski@intel.com>

Sideband queue (SBQ) is a HW queue with very short completion time. All
SBQ writes were posted by default, which means that the driver did not
have to wait for completion from the neighbor device, because there was
none. This introduced unnecessary delays, where only those delays were
"ensuring" that the command is "completed" and this was a potential race
condition.

Add the possibility to perform non-posted writes where it's necessary to
wait for completion, instead of relying on fake completion from the FW,
where only the delays are guarding the writes.

Flush the SBQ by reading address 0 from the PHY 0 before issuing SYNC
command to ensure that writes to all PHYs were completed and skip SBQ
message completion if it's posted.

E810 only supports opcode 0x01, but its FW always sends completion
responses for this opcode, so the driver waits for each write to complete.
This makes E810 writes synchronous and eliminates the need for SBQ flush.

To analyze if delays are gone, look for and compare time spent in
ice_sq_send_cmd - posted writes should return immediately after the wr32.
That can be done for example by adjusting phc time with phc_ctl on E830
device, for less than 2 seconds to use this new mechanism. Without it,
command below will fail.

Reproduction steps:
phc_ctl eth13 adj 1
phc_ctl[4478170.994]: adjusted clock by 1.000000 seconds

Check trace for timing for comparisons:
echo ice_sbq_send_cmd > /sys/kernel/debug/tracing/set_ftrace_filter
echo function_graph > /sys/kernel/debug/tracing/current_tracer
cat /sys/kernel/debug/tracing/trace

Fixes: 8f5ee3c477a8 ("ice: add support for sideband messages")
Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
Signed-off-by: Przemyslaw Korba <przemyslaw.korba@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_common.c   | 25 ++++++++--
 drivers/net/ethernet/intel/ice/ice_controlq.c |  4 ++
 drivers/net/ethernet/intel/ice/ice_controlq.h |  1 +
 drivers/net/ethernet/intel/ice/ice_ptp_hw.c   | 47 +++++++++++++------
 drivers/net/ethernet/intel/ice/ice_sbq_cmd.h  |  2 +-
 5 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index ef1ce106f81b..53974ebaaffa 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1762,6 +1762,7 @@ int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in, u16 flags)
 {
 	struct ice_sbq_cmd_desc desc = {0};
 	struct ice_sbq_msg_req msg = {0};
+	struct ice_sq_cd cd = {};
 	u16 msg_len;
 	int status;
 
@@ -1774,19 +1775,33 @@ int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in, u16 flags)
 	msg.msg_addr_low = cpu_to_le16(in->msg_addr_low);
 	msg.msg_addr_high = cpu_to_le32(in->msg_addr_high);
 
-	if (in->opcode)
+	switch (in->opcode) {
+	case ice_sbq_msg_wr_p:
+	case ice_sbq_msg_wr_np:
 		msg.data = cpu_to_le32(in->data);
-	else
+		/* E810 FW only supports opcode 0x01, convert non-posted to posted */
+		if (hw->mac_type == ICE_MAC_E810)
+			msg.opcode = ice_sbq_msg_wr_p;
+		break;
+	case ice_sbq_msg_rd:
 		/* data read comes back in completion, so shorten the struct by
 		 * sizeof(msg.data)
 		 */
 		msg_len -= sizeof(msg.data);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* E810 doesn't support posted mode, always wait for completion */
+	cd.posted = in->opcode == ice_sbq_msg_wr_p &&
+		    hw->mac_type != ICE_MAC_E810;
 
 	desc.flags = cpu_to_le16(flags);
 	desc.opcode = cpu_to_le16(ice_sbq_opc_neigh_dev_req);
 	desc.param0.cmd_len = cpu_to_le16(msg_len);
-	status = ice_sbq_send_cmd(hw, &desc, &msg, msg_len, NULL);
-	if (!status && !in->opcode)
+	status = ice_sbq_send_cmd(hw, &desc, &msg, msg_len, &cd);
+	if (!status && in->opcode == ice_sbq_msg_rd)
 		in->data = le32_to_cpu
 			(((struct ice_sbq_msg_cmpl *)&msg)->data);
 	return status;
@@ -6547,7 +6562,7 @@ int ice_write_cgu_reg(struct ice_hw *hw, u32 addr, u32 val)
 {
 	struct ice_sbq_msg_input cgu_msg = {
 		.dest_dev = ice_get_dest_cgu(hw),
-		.opcode = ice_sbq_msg_wr,
+		.opcode = ice_sbq_msg_wr_np,
 		.msg_addr_low = addr,
 		.data = val
 	};
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c
index dcb837cadd18..a6008dc77fa4 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -1086,6 +1086,10 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
 	wr32(hw, cq->sq.tail, cq->sq.next_to_use);
 	ice_flush(hw);
 
+	/* If the message is posted, don't wait for completion. */
+	if (cd && cd->posted)
+		goto sq_send_command_error;
+
 	/* Wait for the command to complete. If it finishes within the
 	 * timeout, copy the descriptor back to temp.
 	 */
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index 788040dd662e..c50d6fcbacba 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -77,6 +77,7 @@ struct ice_ctl_q_ring {
 /* sq transaction details */
 struct ice_sq_cd {
 	struct libie_aq_desc *wb_desc;
+	u8 posted : 1;
 };
 
 /* rq event information */
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 8e5f97835954..c6049097f49d 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -352,6 +352,20 @@ void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
 static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
 {
 	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
+	struct ice_sbq_msg_input msg = {
+		.dest_dev = ice_sbq_dev_phy_0,
+		.opcode = ice_sbq_msg_rd,
+	};
+	int err;
+
+	/* Flush SBQ to ensure posted writes complete before SYNC command.
+	 * Skip for E810 - FW always sends completions, so writes are synchronous.
+	 */
+	if (hw->mac_type != ICE_MAC_E810) {
+		err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
+		if (err)
+			dev_warn(ice_hw_to_dev(hw), "Failed to flush SBQ: %d\n", err);
+	}
 
 	if (!ice_is_primary(hw))
 		hw = ice_get_primary_hw(pf);
@@ -442,7 +456,7 @@ static int ice_write_phy_eth56g(struct ice_hw *hw, u8 port, u32 addr, u32 val)
 {
 	struct ice_sbq_msg_input msg = {
 		.dest_dev = ice_ptp_get_dest_dev_e825(hw, port),
-		.opcode = ice_sbq_msg_wr,
+		.opcode = ice_sbq_msg_wr_p,
 		.msg_addr_low = lower_16_bits(addr),
 		.msg_addr_high = upper_16_bits(addr),
 		.data = val
@@ -2614,16 +2628,18 @@ ice_read_64b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
  * @val: The value to write to the register
  *
  * Write a PHY register for the given port over the device sideband queue.
+ * Uses posted writes - requires SBQ flush before SYNC_EXEC_CMD.
  */
 static int
 ice_write_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 val)
 {
-	struct ice_sbq_msg_input msg = {0};
+	struct ice_sbq_msg_input msg = {
+		.opcode = ice_sbq_msg_wr_p,
+		.data = val
+	};
 	int err;
 
 	ice_fill_phy_msg_e82x(hw, &msg, port, offset);
-	msg.opcode = ice_sbq_msg_wr;
-	msg.data = val;
 
 	err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
 	if (err) {
@@ -2811,16 +2827,16 @@ ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
 int
 ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
 {
-	struct ice_sbq_msg_input msg = {0};
+	struct ice_sbq_msg_input msg = {
+		.opcode = ice_sbq_msg_wr_p,
+		.data = val
+	};
 	int err;
 
 	err = ice_fill_quad_msg_e82x(hw, &msg, quad, offset);
 	if (err)
 		return err;
 
-	msg.opcode = ice_sbq_msg_wr;
-	msg.data = val;
-
 	err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
 	if (err) {
 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
@@ -4514,18 +4530,19 @@ static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
  * @val: the value to write to the PHY
  *
  * Write a value to a register of the external PHY on the E810 device.
+ * E810 FW sends completions for opcode 0x01, making writes synchronous.
  */
 static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
 {
-	struct ice_sbq_msg_input msg = {0};
+	struct ice_sbq_msg_input msg = {
+		.dest_dev = ice_sbq_dev_phy_0,
+		.opcode = ice_sbq_msg_wr_p,
+		.msg_addr_low = lower_16_bits(addr),
+		.msg_addr_high = upper_16_bits(addr),
+		.data = val
+	};
 	int err;
 
-	msg.msg_addr_low = lower_16_bits(addr);
-	msg.msg_addr_high = upper_16_bits(addr);
-	msg.opcode = ice_sbq_msg_wr;
-	msg.dest_dev = ice_sbq_dev_phy_0;
-	msg.data = val;
-
 	err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
 	if (err) {
 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
diff --git a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
index 226243d32968..eedcd2481a59 100644
--- a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
@@ -55,7 +55,7 @@ enum ice_sbq_dev_id {
 
 enum ice_sbq_msg_opcode {
 	ice_sbq_msg_rd		= 0x00,
-	ice_sbq_msg_wr		= 0x01,
+	ice_sbq_msg_wr_p	= 0x01,
 	ice_sbq_msg_wr_np	= 0x02
 };
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 05/13] ice: use NETIF_F_HW_CSUM instead of IP/IPV6
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Michal Swiatkowski, anthony.l.nguyen, horms, jramaseu, willemb,
	benoit.monin, Przemek Kitszel, Aleksandr Loktionov,
	Alexander Nowlin
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>

The hardware is capable of calculating checksum for IPV6 packets with
extension header. To not drop such packets switch from IP/IPV6 checksum
to HW_CSUM.

HW_CSUM is also used in previous generation (i40e).

Previously HW_CSUM was used to indicate that hardware supports general
checksum. Drop it assuming that if the hardware supports it, it is used.

Disabling offload for E830 in case of TSO isn't needed anymore as the
check for TSO is done in Tx path just before preparation of the special
GCS descriptor.

The commit from Fixes didn't introduce a bug, it just shown that the
driver is doing sth wrong with the checksum features.

Suggested-by: Jakub Ramaseuski <jramaseu@redhat.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Fixes: 04c20a9356f2 ("net: skip offload for NETIF_F_IPV6_CSUM if ipv6 header contains extension")
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_main.c | 21 +--------------------
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index e2fd2dab03e3..8b439e217e02 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3491,9 +3491,8 @@ void ice_set_netdev_features(struct net_device *netdev)
 			NETIF_F_RXHASH;
 
 	csumo_features = NETIF_F_RXCSUM	  |
-			 NETIF_F_IP_CSUM  |
 			 NETIF_F_SCTP_CRC |
-			 NETIF_F_IPV6_CSUM;
+			 NETIF_F_HW_CSUM;
 
 	vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |
 			 NETIF_F_HW_VLAN_CTAG_TX     |
@@ -3555,12 +3554,6 @@ void ice_set_netdev_features(struct net_device *netdev)
 	/* Allow core to manage IRQs affinity */
 	netif_set_affinity_auto(netdev);
 
-	/* Mutual exclusivity for TSO and GCS is enforced by the set features
-	 * ndo callback.
-	 */
-	if (ice_is_feature_supported(pf, ICE_F_GCS))
-		netdev->hw_features |= NETIF_F_HW_CSUM;
-
 	netif_set_tso_max_size(netdev, ICE_MAX_TSO_SIZE);
 }
 
@@ -6500,18 +6493,6 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
 	if (changed & NETIF_F_LOOPBACK)
 		ret = ice_set_loopback(vsi, !!(features & NETIF_F_LOOPBACK));
 
-	/* Due to E830 hardware limitations, TSO (NETIF_F_ALL_TSO) with GCS
-	 * (NETIF_F_HW_CSUM) is not supported.
-	 */
-	if (ice_is_feature_supported(pf, ICE_F_GCS) &&
-	    ((features & NETIF_F_HW_CSUM) && (features & NETIF_F_ALL_TSO))) {
-		if (netdev->features & NETIF_F_HW_CSUM)
-			dev_err(ice_pf_to_dev(pf), "To enable TSO, you must first disable HW checksum.\n");
-		else
-			dev_err(ice_pf_to_dev(pf), "To enable HW checksum, you must first disable TSO.\n");
-		return -EIO;
-	}
-
 	return ret;
 }
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 06/13] ice: fix LAG recipe to profile association
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Marcin Szycik, anthony.l.nguyen, daniel.machon,
	Michal Swiatkowski, Aleksandr Loktionov, Dave Ertman,
	Simon Horman, Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Marcin Szycik <marcin.szycik@linux.intel.com>

ice_init_lag() associates recipes to profiles, assuming that Link
Aggregation-related profiles will always have profile ID lower than 70
(ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER). This value seems arbitrary and
might not always be valid for some versions of DDP package, i.e. LAG
profiles may have profile ID greater than 70. This would lead to
misconfigured switch and LAG not working properly.

Fix it by checking up to maximum profile ID.

Fixes: 1e0f9881ef79 ("ice: Flesh out implementation of support for SRIOV on bonded interface")
Signed-off-by: Marcin Szycik <marcin.szycik@linux.intel.com>
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Dave Ertman <david.m.ertman@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_lag.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index 310e8fe2925c..08a17ded0ad5 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -2623,7 +2623,7 @@ int ice_init_lag(struct ice_pf *pf)
 		goto  free_lport_res;
 
 	/* associate recipes to profiles */
-	for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) {
+	for (n = 0; n < ICE_MAX_NUM_PROFILES; n++) {
 		err = ice_aq_get_recipe_to_profile(&pf->hw, n,
 						   &recipe_bits, NULL);
 		if (err)
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 02/13] ice: remove redundant switchdev check in ice_eswitch_attach_vf()
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Vincent Chen, anthony.l.nguyen, michal.swiatkowski, horms,
	Aleksandr Loktionov, Rafal Romanowski
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Vincent Chen <vincent.chen@sifive.com>

All callers of ice_eswitch_attach_vf() check the switchdev mode before
calling the function, the internal switchdev mode check in
ice_eswitch_attach_vf() is redundant. Remove this check to align with
the design pattern used for ice_eswitch_attach_sf(), where the caller is
responsible for checking switchdev mode before attachment.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_eswitch.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index c30e27bbfe6e..b069e6c514fb 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -512,9 +512,6 @@ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
 	struct ice_repr *repr;
 	int err;
 
-	if (!ice_is_eswitch_mode_switchdev(pf))
-		return 0;
-
 	repr = ice_repr_create_vf(vf);
 	if (IS_ERR(repr))
 		return PTR_ERR(repr);
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 03/13] ice: pass the return value of skb_checksum_help()
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Michal Swiatkowski, anthony.l.nguyen, horms, jramaseu,
	Aleksandr Loktionov, Rinitha S
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>

skb_checksum_help() can fail. Pass its return value back to the caller.

Commonize this software path in goto.

Instead of just returning error try calculating software checksum first.
There is a check for TSO in checksum_sw_fb.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_txrx.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 4ca1a0602307..c04c5856dad6 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1654,7 +1654,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 			ret = ipv6_skip_exthdr(skb, exthdr - skb->data,
 					       &l4_proto, &frag_off);
 			if (ret < 0)
-				return -1;
+				goto checksum_sw_fb;
 		}
 
 		/* define outer transport */
@@ -1673,11 +1673,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 			l4.hdr = skb_inner_network_header(skb);
 			break;
 		default:
-			if (first->tx_flags & ICE_TX_FLAGS_TSO)
-				return -1;
-
-			skb_checksum_help(skb);
-			return 0;
+			goto checksum_sw_fb;
 		}
 
 		/* compute outer L3 header size */
@@ -1736,7 +1732,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 			ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_proto,
 					 &frag_off);
 	} else {
-		return -1;
+		goto checksum_sw_fb;
 	}
 
 	/* compute inner L3 header size */
@@ -1789,15 +1785,17 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 		break;
 
 	default:
-		if (first->tx_flags & ICE_TX_FLAGS_TSO)
-			return -1;
-		skb_checksum_help(skb);
-		return 0;
+		goto checksum_sw_fb;
 	}
 
 	off->td_cmd |= cmd;
 	off->td_offset |= offset;
 	return 1;
+
+checksum_sw_fb:
+	if (first->tx_flags & ICE_TX_FLAGS_TSO)
+		return -1;
+	return skb_checksum_help(skb);
 }
 
 /**
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 04/13] ice: always do GCS if hardware supports it
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Michal Swiatkowski, anthony.l.nguyen, horms, jramaseu,
	Przemek Kitszel, Aleksandr Loktionov, Alexander Nowlin
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>

There is no need to check for NETIF_HW_CSUM. If the code reach
calculating checksum it means that correct checksum flags are set,
because kernel is checking that when setting ip->summed.

Instead of netdev feature flag use Tx ring flag to check if the hardware
can use special descriptor for checksum calculating.

Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_lib.c  | 4 ++++
 drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
 drivers/net/ethernet/intel/ice/ice_txrx.h | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 8cdc4fda89e9..fc9d4e0fa755 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1415,6 +1415,10 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
 			set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
 		else
 			set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
+
+		if (ice_is_feature_supported(pf, ICE_F_GCS))
+			set_bit(ICE_TX_RING_FLAGS_GCS, ring->flags);
+
 		WRITE_ONCE(vsi->tx_rings[i], ring);
 	}
 
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index c04c5856dad6..b2063a54d6d8 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1739,7 +1739,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 	l3_len = l4.hdr - ip.hdr;
 	offset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;
 
-	if ((tx_ring->netdev->features & NETIF_F_HW_CSUM) &&
+	if (test_bit(ICE_TX_RING_FLAGS_GCS, tx_ring->flags) &&
 	    !(first->tx_flags & ICE_TX_FLAGS_TSO) &&
 	    !skb_csum_is_sctp(skb)) {
 		/* Set GCS */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index 5e517f219379..15dbd5100912 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -217,6 +217,7 @@ enum ice_tx_ring_flags {
 	ICE_TX_RING_FLAGS_VLAN_L2TAG1,
 	ICE_TX_RING_FLAGS_VLAN_L2TAG2,
 	ICE_TX_RING_FLAGS_TXTIME,
+	ICE_TX_RING_FLAGS_GCS,
 	ICE_TX_RING_FLAGS_NBITS,
 };
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 01/13] ice: allow creating VFs when !CONFIG_ICE_SWITCHDEV
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Vincent Chen, anthony.l.nguyen, michal.swiatkowski, horms,
	Aleksandr Loktionov, Rafal Romanowski
In-Reply-To: <20260717185340.3595286-1-anthony.l.nguyen@intel.com>

From: Vincent Chen <vincent.chen@sifive.com>

Currently ice_eswitch_attach_vf() is called unconditionally in
ice_start_vfs(), which causes VF creation to fail when CONFIG_ICE_SWITCHDEV
is not defined.

Fix this by adding switchdev mode checks at the call sites before
calling ice_eswitch_attach_vf(), consistent with how
ice_eswitch_attach_sf() is already handled in ice_devlink_port_new().
This is similar to commit aacca7a83b97 ("ice: allow creating VFs for
!CONFIG_NET_SWITCHDEV") which fixed the same issue for the previous
ice_eswitch_configure() API.

Fixes: 415db8399d06 ("ice: make representor code generic")
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_sriov.c  | 14 ++++++++------
 drivers/net/ethernet/intel/ice/ice_vf_lib.c |  3 ++-
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 7e00e091756d..e04de0215596 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -484,12 +484,14 @@ static int ice_start_vfs(struct ice_pf *pf)
 			goto teardown;
 		}
 
-		retval = ice_eswitch_attach_vf(pf, vf);
-		if (retval) {
-			dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
-				vf->vf_id, retval);
-			ice_vf_vsi_release(vf);
-			goto teardown;
+		if (ice_is_eswitch_mode_switchdev(pf)) {
+			retval = ice_eswitch_attach_vf(pf, vf);
+			if (retval) {
+				dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
+					vf->vf_id, retval);
+				ice_vf_vsi_release(vf);
+				goto teardown;
+			}
 		}
 
 		set_bit(ICE_VF_STATE_INIT, vf->vf_states);
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 27e4acb1620f..9052e71e9c99 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -812,7 +812,8 @@ void ice_reset_all_vfs(struct ice_pf *pf)
 		}
 		ice_vf_post_vsi_rebuild(vf);
 
-		ice_eswitch_attach_vf(pf, vf);
+		if (ice_is_eswitch_mode_switchdev(pf))
+			ice_eswitch_attach_vf(pf, vf);
 
 		mutex_unlock(&vf->cfg_lock);
 	}
-- 
2.47.1


^ permalink raw reply related

* [PATCH net 00/13][pull request] Intel Wired LAN Driver Updates 2026-07-17 (ice, idpf, iavf)
From: Tony Nguyen @ 2026-07-17 18:53 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev; +Cc: Tony Nguyen

For ice:
Vincent Chen fixes issue preventing VF creation when switchdev is not
enabled in the configuration.

Michal fixes issue with checksum advertisement and handling with
extension headers.

Additional details:
https://lore.kernel.org/intel-wired-lan/20260428070647.777141-1-michal.swiatkowski@linux.intel.com/

Marcin corrects iteration value for profile association that was
truncating profiles.

Karol bypasses, unnecessary, waiting on sideband queue PTP writes which
can cause failures with phc_ctl program.

Sergey adds READ_ONCE() to access of PHC time to prevent torn read on
32-bit systems.

Paul adds a check for uninitialized PTP state before attempting to
rebuild it and restricts check of TxTime to be for PF VSI only.

Alex adds bounds check on PTYPE to prevent possible out-of-bounds write.

For idpf:
Emil defers setting of adapter max_vports value to prevent inadvertent
use if interim allocation errors are encountered.

For iavf:
Junrui Luo checks and clamps VSI size from virtchnl to prevent
out-of-bounds accesses.

The following are changes since commit 56d96fededd61192cd7cc8d2b0f36adfd59036c3:
  mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue 100GbE

Aleksandr Loktionov (1):
  ice: reject out-of-range ptype in ice_parser_profile_init

Emil Tantilov (1):
  idpf: fix max_vport related crash on allocation error during init

Junrui Luo (1):
  iavf: validate num_vsis in VIRTCHNL_OP_GET_VF_RESOURCES response

Karol Kolacinski (1):
  ice: support SBQ posted writes with non-posted support for CGU

Marcin Szycik (1):
  ice: fix LAG recipe to profile association

Michal Swiatkowski (3):
  ice: pass the return value of skb_checksum_help()
  ice: always do GCS if hardware supports it
  ice: use NETIF_F_HW_CSUM instead of IP/IPV6

Paul Greenwalt (2):
  ice: fix PTP Call Trace during PTP release
  ice: prevent tstamp ring allocation for non-PF VSI types

Sergey Temerkhanov (1):
  ice: use READ_ONCE() to access cached PHC time

Vincent Chen (2):
  ice: allow creating VFs when !CONFIG_ICE_SWITCHDEV
  ice: remove redundant switchdev check in ice_eswitch_attach_vf()

 .../net/ethernet/intel/iavf/iavf_virtchnl.c   | 26 ++++++++--
 drivers/net/ethernet/intel/ice/ice.h          |  3 ++
 drivers/net/ethernet/intel/ice/ice_common.c   | 25 ++++++++--
 drivers/net/ethernet/intel/ice/ice_controlq.c |  4 ++
 drivers/net/ethernet/intel/ice/ice_controlq.h |  1 +
 drivers/net/ethernet/intel/ice/ice_eswitch.c  |  3 --
 drivers/net/ethernet/intel/ice/ice_lag.c      |  2 +-
 drivers/net/ethernet/intel/ice/ice_lib.c      |  4 ++
 drivers/net/ethernet/intel/ice/ice_main.c     | 21 +--------
 drivers/net/ethernet/intel/ice/ice_parser.c   |  3 ++
 drivers/net/ethernet/intel/ice/ice_ptp.c      |  7 ++-
 drivers/net/ethernet/intel/ice/ice_ptp_hw.c   | 47 +++++++++++++------
 drivers/net/ethernet/intel/ice/ice_sbq_cmd.h  |  2 +-
 drivers/net/ethernet/intel/ice/ice_sriov.c    | 14 +++---
 drivers/net/ethernet/intel/ice/ice_txrx.c     | 22 ++++-----
 drivers/net/ethernet/intel/ice/ice_txrx.h     |  1 +
 drivers/net/ethernet/intel/ice/ice_vf_lib.c   |  3 +-
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   |  7 ++-
 18 files changed, 124 insertions(+), 71 deletions(-)

-- 
2.47.1


^ permalink raw reply

* Re: [PATCH net v4 2/2] tipc: fix NULL deref in tipc_named_node_up() on empty publication list
From: Weiming Shi @ 2026-07-17 18:34 UTC (permalink / raw)
  To: Tung Quang Nguyen
  Cc: netdev@vger.kernel.org, tipc-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, xmei5@asu.edu, Jon Maloy,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
In-Reply-To: <GV1P189MB1988F91A48BC981B816C2700C6C62@GV1P189MB1988.EURP189.PROD.OUTLOOK.COM>

Tung Quang Nguyen <tung.quang.nguyen@est.tech> 于2026年7月17日周五 17:48写道:
>
> >Subject: [PATCH net v4 2/2] tipc: fix NULL deref in tipc_named_node_up() on
> >empty publication list
> >
> >named_distribute() ends by stamping the last_bulk flag on the tail skb via
> >buf_msg(skb_peek_tail(list)). When the publication list is empty no skb is
> >enqueued, skb_peek_tail() returns NULL, and buf_msg(NULL) is dereferenced.
> >
> >tipc_named_node_up() runs this on &nt->cluster_scope. With a node-id
> >configuration cluster_scope is populated only later by tipc_net_finalize(), so a
> >peer link that comes up first reaches named_distribute() with an empty list. It
> >is reachable by an unprivileged user (TIPC genl ops use
> >GENL_UNS_ADMIN_PERM) over a UDP bearer in a user+net namespace:
> >
> > KASAN: null-ptr-deref in range [0x00000000000000d8-0x00000000000000df]
> > RIP: 0010:tipc_named_node_up (net/tipc/name_distr.c:196)
> >  tipc_named_node_up (net/tipc/name_distr.c:196 net/tipc/name_distr.c:221)
> >  tipc_node_write_unlock (net/tipc/node.c:428)
> >  tipc_rcv (net/tipc/node.c:2185)
> >  tipc_udp_recv (net/tipc/udp_media.c:392)  Kernel panic - not syncing: Fatal
> >exception in interrupt
> >
> >The peer holds back this node's later name updates until it sees a bulk with the
> >last_bulk flag, so simply skipping the send would stall it. Emit an item-less bulk
> >when the publication list is empty, so the peer still receives the last_bulk flag
> >and opens.
> >
> >Fixes: cad2929dc432 ("tipc: update a binding service via broadcast")
> >Reported-by: Xiang Mei <xmei5@asu.edu>
> >Assisted-by: Claude:claude-opus-4-8
> >Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> >---
> > net/tipc/name_distr.c | 14 ++++++++++++++
> > 1 file changed, 14 insertions(+)
> >
> >diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index
> >ba4f4906e13b..a8bb7bd101ea 100644
> >--- a/net/tipc/name_distr.c
> >+++ b/net/tipc/name_distr.c
> >@@ -192,6 +192,20 @@ static void named_distribute(struct net *net, struct
> >sk_buff_head *list,
> >               skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem));
> >               __skb_queue_tail(list, skb);
> >       }
> >+
> >+      if (skb_queue_empty(list)) {
> >+              skb = named_prepare_buf(net, PUBLICATION, 0, dnode);
> >+              if (!skb) {
> >+                      pr_warn("Bulk publication failure\n");
> >+                      return;
> >+              }
> >+              hdr = buf_msg(skb);
> >+              msg_set_bc_ack_invalid(hdr, true);
> >+              msg_set_bulk(hdr);
> >+              msg_set_non_legacy(hdr);
> >+              __skb_queue_tail(list, skb);
> >+      }
> As I explained before, this approach is wrong because
> 1. It does not handle memory allocation failure.
> 2. It breaks receiving peer by  sending non-data message to that peer in case skb is not NULL.
>
> Could you please test below patch to see if it fixes the NULL dereference issue you reported ?

Hi ,
Tested your patch, it fixes the NULL dereference I reported. No more
panic with an empty cluster_scope .

One new bug found during testing: if tipc_nametbl_publish() fails in
tipc_net_finalize(), the node is
still marked finalized, so the deferred worker wakes up and calls
named_distribute() with an empty list,
hitting the same NULL dereference.

I have the fix ready and sent it out:

https://lore.kernel.org/all/20260717183047.2725959-1-bestswngs@gmail.com/
https://lore.kernel.org/all/20260717183047.2725959-2-bestswngs@gmail.com/
https://lore.kernel.org/all/20260717183047.2725959-3-bestswngs@gmail.com/

Thanks,
Weiming Shi

>
> ---
>  net/tipc/core.c       |  1 +
>  net/tipc/core.h       |  2 ++
>  net/tipc/name_distr.c | 48 +++++++++++++++++++++++++++++++++++++++----
>  net/tipc/name_distr.h |  3 ++-
>  net/tipc/net.c        |  2 ++
>  net/tipc/node.c       | 34 ++++++++++++++++++++++++++++--
>  6 files changed, 83 insertions(+), 7 deletions(-)
>
> diff --git a/net/tipc/core.c b/net/tipc/core.c
> index 315975c3be81..9e81be4f01cf 100644
> --- a/net/tipc/core.c
> +++ b/net/tipc/core.c
> @@ -61,6 +61,7 @@ static int __net_init tipc_init_net(struct net *net)
>         tn->trial_addr = 0;
>         tn->addr_trial_end = 0;
>         tn->capabilities = TIPC_NODE_CAPABILITIES;
> +       atomic_set(&tn->finalized, 0);
>         INIT_WORK(&tn->work, tipc_net_finalize_work);
>         memset(tn->node_id, 0, sizeof(tn->node_id));
>         memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
> diff --git a/net/tipc/core.h b/net/tipc/core.h
> index 9ce5f9ff6cc0..76768844c808 100644
> --- a/net/tipc/core.h
> +++ b/net/tipc/core.h
> @@ -145,6 +145,8 @@ struct tipc_net {
>         struct work_struct work;
>         /* The numbers of work queues in schedule */
>         atomic_t wq_count;
> +       /* flag to indicate work has finished */
> +       atomic_t finalized;
>  };
>
>  static inline struct tipc_net *tipc_net(struct net *net)
> diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
> index ba5f4906e13b..8a1692dbd243 100644
> --- a/net/tipc/name_distr.c
> +++ b/net/tipc/name_distr.c
> @@ -147,7 +147,7 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
>   * @pls: linked list of publication items to be packed into buffer chain
>   * @seqno: sequence number for this message
>   */
> -static void named_distribute(struct net *net, struct sk_buff_head *list,
> +static int named_distribute(struct net *net, struct sk_buff_head *list,
>                              u32 dnode, struct list_head *pls, u16 seqno)
>  {
>         struct publication *publ;
> @@ -164,8 +164,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
>                         skb = named_prepare_buf(net, PUBLICATION, msg_rem,
>                                                 dnode);
>                         if (!skb) {
> +                               __skb_queue_purge(list);
>                                 pr_warn("Bulk publication failure\n");
> -                               return;
> +                               return 1;
>                         }
>                         hdr = buf_msg(skb);
>                         msg_set_bc_ack_invalid(hdr, true);
> @@ -195,6 +196,8 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
>         hdr = buf_msg(skb_peek_tail(list));
>         msg_set_last_bulk(hdr);
>         msg_set_named_seqno(hdr, seqno);
> +
> +       return 0;
>  }
>
>  /**
> @@ -203,7 +206,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
>   * @dnode: destination node
>   * @capabilities: peer node's capabilities
>   */
> -void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
> +int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
>  {
>         struct name_table *nt = tipc_name_table(net);
>         struct tipc_net *tn = tipc_net(net);
> @@ -218,9 +221,46 @@ void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
>         spin_unlock_bh(&tn->nametbl_lock);
>
>         read_lock_bh(&nt->cluster_scope_lock);
> -       named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);
> +       /* tipc_net_finalize_work() has not finished inserting self address to
> +         * name table yet.
> +         */
> +       if (unlikely(list_empty(&nt->cluster_scope))) {
> +               read_unlock_bh(&nt->cluster_scope_lock);
> +               return 1;
> +       }
> +
> +       if (named_distribute(net, &head, dnode, &nt->cluster_scope, seqno)) {
> +               read_unlock_bh(&nt->cluster_scope_lock);
> +               return -ENOBUFS;
> +       }
> +
>         tipc_node_xmit(net, &head, dnode, 0);
>         read_unlock_bh(&nt->cluster_scope_lock);
> +       return 0;
> +}
> +
> +int tipc_named_dist_cluster_scope(struct net *net, u32 dnode)
> +{
> +       struct name_table *nt = tipc_name_table(net);
> +       struct tipc_net *tn = tipc_net(net);
> +       struct sk_buff_head head;
> +       u16 seqno;
> +
> +       __skb_queue_head_init(&head);
> +       wait_var_event(&tn->finalized, atomic_read(&tn->finalized));
> +       spin_lock_bh(&tn->nametbl_lock);
> +       seqno = nt->snd_nxt;
> +       spin_unlock_bh(&tn->nametbl_lock);
> +
> +       read_lock_bh(&nt->cluster_scope_lock);
> +       if (named_distribute(net, &head, dnode, &nt->cluster_scope, seqno)) {
> +               read_unlock_bh(&nt->cluster_scope_lock);
> +               return -ENOBUFS;
> +       }
> +       tipc_node_xmit(net, &head, dnode, 0);
> +       read_unlock_bh(&nt->cluster_scope_lock);
> +
> +       return 0;
>  }
>
>  /**
> diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
> index c677f6f082df..cadf4e8c3e66 100644
> --- a/net/tipc/name_distr.h
> +++ b/net/tipc/name_distr.h
> @@ -69,7 +69,8 @@ struct distr_item {
>
>  struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);
>  struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);
> -void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
> +int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
> +int tipc_named_dist_cluster_scope(struct net *net, u32 dnode);
>  void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,
>                     u16 *rcv_nxt, bool *open);
>  void tipc_named_reinit(struct net *net);
> diff --git a/net/tipc/net.c b/net/tipc/net.c
> index 7e65d0b0c4a8..4c144e720ac1 100644
> --- a/net/tipc/net.c
> +++ b/net/tipc/net.c
> @@ -139,6 +139,8 @@ static void tipc_net_finalize(struct net *net, u32 addr)
>         tipc_sk_reinit(net);
>         tipc_mon_reinit_self(net);
>         tipc_nametbl_publish(net, &ua, &sk, addr);
> +       atomic_inc(&tn->finalized);
> +       wake_up_var(&tn->finalized);
>  }
>
>  void tipc_net_finalize_work(struct work_struct *work)
> diff --git a/net/tipc/node.c b/net/tipc/node.c
> index 8e4ef2630ae4..c5b0a98324c3 100644
> --- a/net/tipc/node.c
> +++ b/net/tipc/node.c
> @@ -145,6 +145,8 @@ struct tipc_node {
>  #ifdef CONFIG_TIPC_CRYPTO
>         struct tipc_crypto *crypto_rx;
>  #endif
> +       /* Work item for bulk distribution of cluster scope publications */
> +       struct work_struct work;
>  };
>
>  /* Node FSM states and events:
> @@ -303,6 +305,7 @@ static void tipc_node_free(struct rcu_head *rp)
>  #ifdef CONFIG_TIPC_CRYPTO
>         tipc_crypto_stop(&n->crypto_rx);
>  #endif
> +       cancel_work_sync(&n->work);
>         kfree(n);
>  }
>
> @@ -393,6 +396,19 @@ static void tipc_node_write_unlock_fast(struct tipc_node *n)
>         write_unlock_bh(&n->lock);
>  }
>
> +static void tipc_node_dist_bulk(struct work_struct *work)
> +{
> +       struct tipc_node *node = container_of(work, struct tipc_node, work);
> +
> +       if (tipc_named_dist_cluster_scope(node->net, node->addr) < 0) {
> +               u32 bearer_id = node->link_id & 0xffff;
> +
> +               tipc_node_link_down(node, bearer_id, false);
> +       }
> +
> +       tipc_node_put(node);
> +}
> +
> static void tipc_node_write_unlock(struct tipc_node *n)
>         __releases(n->lock)
>  {
> @@ -424,8 +440,21 @@ static void tipc_node_write_unlock(struct tipc_node *n)
>         if (flags & TIPC_NOTIFY_NODE_DOWN)
>                 tipc_publ_notify(net, publ_list, node, n->capabilities);
>
> -       if (flags & TIPC_NOTIFY_NODE_UP)
> -               tipc_named_node_up(net, node, n->capabilities);
> +       if (flags & TIPC_NOTIFY_NODE_UP) {
> +               int rc = 0;
> +
> +               rc = tipc_named_node_up(net, node, n->capabilities);
> +               /* Defer bulk distribution to work queue */
> +               if (rc > 0) {
> +                       tipc_node_get(n);
> +                       schedule_work(&n->work);
> +               } else if (rc < 0) {
> +                       /* Bring the link down to start over bulk distribution
> +                        * when the link is up again.
> +                        */
> +                       tipc_node_link_down(n, bearer_id, false);
> +               }
> +       }
>
>         if (flags & TIPC_NOTIFY_LINK_UP) {
>                 tipc_mon_peer_up(net, node, bearer_id);
> @@ -564,6 +593,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
>         INIT_LIST_HEAD(&n->list);
>         INIT_LIST_HEAD(&n->publ_list);
>         INIT_LIST_HEAD(&n->conn_sks);
> +       INIT_WORK(&n->work, tipc_node_dist_bulk);
>         skb_queue_head_init(&n->bc_entry.namedq);
>         skb_queue_head_init(&n->bc_entry.inputq1);
>         __skb_queue_head_init(&n->bc_entry.arrvq);

^ permalink raw reply

* [PATCH net v5 2/2] tipc: fix node reference leak when defer work is already pending
From: Weiming Shi @ 2026-07-17 18:30 UTC (permalink / raw)
  To: Jon Maloy, Tung Nguyen, netdev, tipc-discussion
  Cc: Xiang Mei, Weiming Shi, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel
In-Reply-To: <20260717183047.2725959-1-bestswngs@gmail.com>

In tipc_node_write_unlock(), TIPC_NOTIFY_NODE_UP with an empty
cluster_scope takes a node reference and schedules n->work. If the
link flaps down and up while that work is still pending, the next
NODE_UP takes another reference, but schedule_work() returns false
and the extra reference is never dropped. The tipc_node structure
leaks.

Verified by flapping the bearer while the work is pending: one
reference is leaked per repeated NODE_UP, while the work is put only
once when it finally runs.

Drop the reference when the work was already queued.

Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
 net/tipc/node.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/tipc/node.c b/net/tipc/node.c
index b545a47d6ccb..428c4eacd02f 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -447,7 +447,8 @@ static void tipc_node_write_unlock(struct tipc_node *n)
 		/* Defer bulk distribution to work queue */
 		if (rc > 0) {
 			tipc_node_get(n);
-			schedule_work(&n->work);
+			if (!schedule_work(&n->work))
+				tipc_node_put(n);
 		} else if (rc < 0) {
 			/* Bring the link down to start over bulk distribution
 			 * when the link is up again.
-- 
2.43.0


^ permalink raw reply related

* [PATCH net v5 1/2] tipc: fix NULL deref in tipc_named_node_up() on empty publication list
From: Weiming Shi @ 2026-07-17 18:30 UTC (permalink / raw)
  To: Jon Maloy, Tung Nguyen, netdev, tipc-discussion
  Cc: Xiang Mei, Weiming Shi, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Hoang Huu Le,
	kernel test robot, linux-kernel
In-Reply-To: <20260717183047.2725959-1-bestswngs@gmail.com>

tipc_net_finalize() does not check the return value of
tipc_nametbl_publish(). If the publish fails, for example on a
GFP_ATOMIC allocation failure, the node state name never lands in
cluster_scope, but tn->finalized is still set. A worker deferred by
tipc_named_node_up() then wakes and calls named_distribute() with an
empty list and hits the same NULL dereference in
buf_msg(skb_peek_tail(list)) as the original bug, this time on the
tipc_node_dist_bulk workqueue. The reported crash:

 KASAN: null-ptr-deref in range [0x00000000000000d8-0x00000000000000df]
 RIP: 0010:tipc_named_node_up (net/tipc/name_distr.c:196)
  tipc_named_node_up (net/tipc/name_distr.c:196 net/tipc/name_distr.c:221)
  tipc_node_write_unlock (net/tipc/node.c:428)
  tipc_rcv (net/tipc/node.c:2185)
  tipc_udp_recv (net/tipc/udp_media.c:392)
 Kernel panic - not syncing: Fatal exception in interrupt

Check the publish result and warn on failure, but still set finalized,
otherwise deferred workers would sleep forever. In
tipc_named_dist_cluster_scope() re-check cluster_scope after the wait
and skip the distribution when it is empty. This is a permanent
condition, so return 0 instead of an error, otherwise the link would
be bounced forever. Also guard the tail stamp in named_distribute()
itself, so a caller that misses the precondition gets a warning and a
link reset through the existing -ENOBUFS path instead of a crash.

Reproducing this needs an allocation failure during finalize, so I
verified it by stubbing out the publish call: both nodes log the
failure, the workers skip the distribution, no crash, no link flap.
The normal path is unchanged with the same two-node test.

Fixes: cad2929dc432 ("tipc: update a binding service via broadcast")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
 net/tipc/name_distr.c | 11 +++++++++++
 net/tipc/net.c        |  3 ++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index b764274df758..5b0fb09226fc 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -193,6 +193,10 @@ static int named_distribute(struct net *net, struct sk_buff_head *list,
 		skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem));
 		__skb_queue_tail(list, skb);
 	}
+	if (skb_queue_empty(list)) {
+		pr_warn("Bulk publication list empty, nothing to distribute\n");
+		return 1;
+	}
 	hdr = buf_msg(skb_peek_tail(list));
 	msg_set_last_bulk(hdr);
 	msg_set_named_seqno(hdr, seqno);
@@ -253,6 +257,13 @@ int tipc_named_dist_cluster_scope(struct net *net, u32 dnode)
 	spin_unlock_bh(&tn->nametbl_lock);
 
 	read_lock_bh(&nt->cluster_scope_lock);
+	if (unlikely(list_empty(&nt->cluster_scope))) {
+		/* finalize is done but nothing was published (publish
+		 * failed): a permanent state, nothing to synchronize.
+		 */
+		read_unlock_bh(&nt->cluster_scope_lock);
+		return 0;
+	}
 	if (named_distribute(net, &head, dnode, &nt->cluster_scope, seqno)) {
 		read_unlock_bh(&nt->cluster_scope_lock);
 		return -ENOBUFS;
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 4c144e720ac1..2aa8812c551a 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -138,7 +138,8 @@ static void tipc_net_finalize(struct net *net, u32 addr)
 	tipc_named_reinit(net);
 	tipc_sk_reinit(net);
 	tipc_mon_reinit_self(net);
-	tipc_nametbl_publish(net, &ua, &sk, addr);
+	if (!tipc_nametbl_publish(net, &ua, &sk, addr))
+		pr_warn("Failed to publish own node state\n");
 	atomic_inc(&tn->finalized);
 	wake_up_var(&tn->finalized);
 }
-- 
2.43.0


^ permalink raw reply related

* [PATCH net v5 0/2] tipc: fix NULL deref in tipc_named_node_up() on empty publication list
From: Weiming Shi @ 2026-07-17 18:30 UTC (permalink / raw)
  To: Jon Maloy, Tung Nguyen, netdev, tipc-discussion; +Cc: Xiang Mei, Weiming Shi

This series continues the fix for the NULL dereference in
tipc_named_node_up() on an empty publication list, on top of Tung
Nguyen's RFC that defers bulk distribution to a workqueue. Jon asked
us to test that approach. It fixes the reported bug in our two-node
QEMU setup (veth pair, UDP bearers, node-id addressing), both with an
unprivileged user namespace and as root.

These two patches fix two issues found during that testing.

Patch 1/2: tipc_net_finalize() does not check the return value of
tipc_nametbl_publish(). If the publish fails, for example on a
GFP_ATOMIC allocation failure, the node is finalized but cluster_scope
stays empty. The deferred worker then calls named_distribute() with an
empty list and hits the same NULL dereference, this time on the
workqueue. With this patch the worker re-checks the list and skips
cleanly, no crash and no link flap. The tail stamp in
named_distribute() also gets an empty-queue guard.

Patch 2/2: a repeated NODE_UP while the bulk work is pending takes a
node reference that is never dropped, because schedule_work() returns
false when the work is already queued. Found by flapping the bearer
during the defer window. One reference is leaked per repeated
NODE_UP.

Changes in v5:
 - Replace the item-less bulk approach with Tung's defer-to-workqueue
   approach, which Jon asked us to test and which fixes the reported
   bug in our testing.
 - Patch 1/2: handle tipc_nametbl_publish() failure in finalize, and
   guard the tail stamp in named_distribute() against an empty list.
 - Patch 2/2: fix the node reference leak when the defer work is
   already pending.

Note: this series applies on top of Tung Nguyen's RFC "tipc: fix
NULL deref in tipc_named_node_up() on empty publication list".
Tested against eb3f4b7426cf plus the RFC.

Weiming Shi (2):
  tipc: fix NULL deref in tipc_named_node_up() on empty publication list
  tipc: fix node reference leak when defer work is already pending

 net/tipc/name_distr.c | 11 +++++++++++
 net/tipc/net.c        |  3 ++-
 net/tipc/node.c       |  3 ++-
 3 files changed, 15 insertions(+), 2 deletions(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH net v3] sctp: socket: remove unused 'err' parameter from sctp_skb_recv_datagram
From: David Laight @ 2026-07-17 18:19 UTC (permalink / raw)
  To: Xin Long
  Cc: luoqing, jedrzej.jagielski, davem, edumazet, horms, kuba,
	linux-kernel, linux-sctp, luoqing, marcelo.leitner, netdev,
	pabeni
In-Reply-To: <CADvbK_dHFt6cceHQ5BwPMWbF1j4i8BtYZ4Su067SvMeiiD6Rcw@mail.gmail.com>

On Fri, 17 Jul 2026 11:10:21 -0400
Xin Long <lucien.xin@gmail.com> wrote:

> On Fri, Jul 17, 2026 at 4:21 AM luoqing <l1138897701@163.com> wrote:
> >
> > From: luoqing <luoqing@kylinos.cn>
> >
> > The 'err' parameter in sctp_skb_recv_datagram() is never used by any
> > of its callers. Both sctp_recvmsg() and sctp_ulpevent_read_nxtinfo()
> > pass the address of a local variable but never check its value after
> > the function returns, rendering the parameter completely useless.
> >
> > Remove the unused parameter to simplify the function signature and
> > eliminate dead code.
> >
> > Signed-off-by: luoqing <luoqing@kylinos.cn>
> > ---
> >  include/net/sctp/sctp.h |  2 +-
> >  net/sctp/socket.c       | 10 +++-------
> >  net/sctp/ulpevent.c     |  3 +--
> >  3 files changed, 5 insertions(+), 10 deletions(-)
> >
> > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> > index d50c27812504..b86d50d6b146 100644
> > --- a/include/net/sctp/sctp.h
> > +++ b/include/net/sctp/sctp.h
> > @@ -97,7 +97,7 @@ void sctp_sock_rfree(struct sk_buff *skb);
> >
> >  extern struct percpu_counter sctp_sockets_allocated;
> >  int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
> > -struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int *);
> > +struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags);
> >
> >  typedef int (*sctp_callback_t)(struct sctp_endpoint *, struct sctp_transport *, void *);
> >  void sctp_transport_walk_start(struct rhashtable_iter *iter);
> > diff --git a/net/sctp/socket.c b/net/sctp/socket.c
> > index c7b9e325ec1c..3804382d78e0 100644
> > --- a/net/sctp/socket.c
> > +++ b/net/sctp/socket.c
> > @@ -2123,7 +2123,7 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
> >                 goto out;
> >         }
> >
> > -       skb = sctp_skb_recv_datagram(sk, flags, &err);
> > +       skb = sctp_skb_recv_datagram(sk, flags);
> >         if (!skb)
> >                 goto out;
> >
> > @@ -9082,7 +9082,7 @@ static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p)
> >   * Note: This is pretty much the same routine as in core/datagram.c
> >   * with a few changes to make lksctp work.
> >   */
> > -struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int *err)
> > +struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags)
> >  {
> >         int error;
> >         struct sk_buff *skb;
> > @@ -9120,17 +9120,13 @@ struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int *err)
> >                 if (sk->sk_shutdown & RCV_SHUTDOWN)
> >                         break;
> >
> > -
> >                 /* User doesn't want to wait.  */
> >                 error = -EAGAIN;
> >                 if (!timeo)
> >                         goto no_packet;
> > -       } while (sctp_wait_for_packet(sk, err, &timeo) == 0);
> > -
> > -       return NULL;
> > +       } while (sctp_wait_for_packet(sk, &error, &timeo) == 0);
> >
> >  no_packet:
> > -       *err = error;
> >         return NULL;
> >  }
> >
> > diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> > index 8920ca92a011..8ed51a15c3a4 100644
> > --- a/net/sctp/ulpevent.c
> > +++ b/net/sctp/ulpevent.c
> > @@ -1061,9 +1061,8 @@ void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
> >                                 struct sock *sk)
> >  {
> >         struct sk_buff *skb;
> > -       int err;
> >
> > -       skb = sctp_skb_recv_datagram(sk, MSG_PEEK | MSG_DONTWAIT, &err);
> > +       skb = sctp_skb_recv_datagram(sk, MSG_PEEK | MSG_DONTWAIT);
> >         if (skb != NULL) {
> >                 __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb),
> >                                              msghdr, skb);
> > --
> > 2.25.1
> >  
> I think it's used at [1] in sctp_recvmsg():
> 
>         skb = sctp_skb_recv_datagram(sk, flags, &err);
>         if (!skb)
>                 goto out;

Would it make more sense to ERR_PTR() etc ?

	David

> ...
> 
> out:
>         release_sock(sk);
>         return err;   <------ [1]
> 
> Thanks.
> 


^ permalink raw reply

* Re: [PATCH net-next v3] selftests/net: Skip srv6_end_dt46_l3vpn_test if iproute2 too old
From: Andrea Mayer @ 2026-07-17 17:49 UTC (permalink / raw)
  To: Alessio Faina
  Cc: netdev, linux-kselftest, Po-Hsu Lin, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern,
	Simon Horman, Shuah Khan, stefano.salsano, Andrea Mayer
In-Reply-To: <20260715122859.36177-1-alessio.faina@canonical.com>

On Wed, 15 Jul 2026 14:28:59 +0200
Alessio Faina <alessio.faina@canonical.com> wrote:

> In case iproute2 is older than version 5.14.0, released ~Sept 1, 2021,
> the End.DT46 support is not available and the host_vpn_tests test contained
> in the srv6_end_dt46_l3vpn_test.sh file is failing in some kernel backports.
> This is the result of those tests:
>
> ################################################################################
> TEST SECTION: SRv6 VPN connectivity test among hosts in the same tenant
> ################################################################################
>
>     TEST: IPv6 Hosts connectivity: hs-t100-1 -> hs-t100-2 (tenant 100)  [ FAIL ]
>
>     TEST: IPv4 Hosts connectivity: hs-t100-1 -> hs-t100-2 (tenant 100)  [ FAIL ]
>
>     TEST: IPv6 Hosts connectivity: hs-t100-2 -> hs-t100-1 (tenant 100)  [ FAIL ]
>
>     TEST: IPv4 Hosts connectivity: hs-t100-2 -> hs-t100-1 (tenant 100)  [ FAIL ]
>
>     TEST: IPv6 Hosts connectivity: hs-t200-3 -> hs-t200-4 (tenant 200)  [ FAIL ]
>
>     TEST: IPv4 Hosts connectivity: hs-t200-3 -> hs-t200-4 (tenant 200)  [ FAIL ]
>
>     TEST: IPv6 Hosts connectivity: hs-t200-4 -> hs-t200-3 (tenant 200)  [ FAIL ]
>
>     TEST: IPv4 Hosts connectivity: hs-t200-4 -> hs-t200-3 (tenant 200)  [ FAIL ]
>
> To amend this, check the current running iproute2 supports the required
> feature and, if not, just skip the entire test to avoid a failure.
>
> Signed-off-by: Alessio Faina <alessio.faina@canonical.com>
> ---
> v3:
>  -  fix indentation in test_iproute2_supp_or_ksft_skip()
>  -  fix subject to reflect full test suite skip
>  -  https://lore.kernel.org/netdev/20260713095750.2671173-1-alessio.faina@canonical.com/
> v2:
>     - skip entire test suite if iproute2 is too old
> v1: https://lore.kernel.org/netdev/20260708152745.2430714-1-alessio.faina@canonical.com/
>
>  .../testing/selftests/net/srv6_end_dt46_l3vpn_test.sh  | 10 ++++++++++
>  1 file changed, 10 insertions(+)

Hi Alessio,

Thanks for the v3, both points are addressed.

About the check flagged by Sashiko: "ip route add help" is fine.
iproute2 catches the "help" word and prints the usage before it parses it as a
prefix, so the grep works.
As a small nit, the other srv6 selftests use "ip route help" without "add".
This is not blocking, and I don't think it is worth spinning a v4 just to
remove the "add".

Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>

Ciao
Andrea

^ permalink raw reply

* Re: [PATCH net 8/9] ipvs: fix more places with wrong ipv6 transport offsets
From: Julian Anastasov @ 2026-07-17 17:41 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: Florian Westphal, netdev, David S. Miller, Eric Dumazet,
	Jakub Kicinski, netfilter-devel, pablo
In-Reply-To: <e7ed31d3-a3aa-427a-8e82-aa65b4388368@redhat.com>


	Hello,

On Fri, 17 Jul 2026, Paolo Abeni wrote:

> Hi,
> 
> On 7/10/26 4:37 PM, Florian Westphal wrote:
> > From: Julian Anastasov <ja@ssi.bg>
> > 
> > Sashiko reports for more incorrect IPv6 transport offsets.
> > 
> > The app code for TCP was assuming IPv4 network header
> > even after the ipvsh argument was provided. This can
> > cause problems with apps over IPv6. As for the only
> > official app in the kernel tree (FTP) this problem is
> > harmless because we use Netfilter to mangle the FTP
> > ports and we do not adjust the TCP seq numbers.
> > 
> > Also, provide correct offset of the ICMPV6 header in
> > ip_vs_out_icmp_v6() for correct checksum checks when
> > the IPv6 packet has extension headers.
> > 
> > Fixes: d12e12299a69 ("ipvs: add ipv6 support to ftp")
> > Fixes: 2a3b791e6e11 ("IPVS: Add/adjust Netfilter hook functions and helpers for v6")
> > Cc: stable@vger.kernel.org
> > Link: https://sashiko.dev/#/patchset/20260706101624.69471-1-zhaoyz24%40mails.tsinghua.edu.cn
> > Signed-off-by: Julian Anastasov <ja@ssi.bg>
> > Signed-off-by: Florian Westphal <fw@strlen.de>
> > ---
> >  net/netfilter/ipvs/ip_vs_app.c  | 10 ++++------
> >  net/netfilter/ipvs/ip_vs_core.c |  3 +--
> >  2 files changed, 5 insertions(+), 8 deletions(-)
> > 
> > diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
> > index d54d7da58334..b0e00be85cb1 100644
> > --- a/net/netfilter/ipvs/ip_vs_app.c
> > +++ b/net/netfilter/ipvs/ip_vs_app.c
> > @@ -361,14 +361,13 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
> >  				  struct ip_vs_iphdr *ipvsh)
> >  {
> >  	int diff;
> > -	const unsigned int tcp_offset = ip_hdrlen(skb);
> >  	struct tcphdr *th;
> >  	__u32 seq;
> >  
> > -	if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
> > +	if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
> >  		return 0;
> >  
> > -	th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
> > +	th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
> 
> Beyond the usual set of pre-existing issues, sashiko-gemini noted this
> patch may need a follow-up:
> 
> https://sashiko.dev/#/patchset/20260710143733.29741-2-fw%40strlen.de

	I'll provide fix to continue supporting non-zero
network offset but I already don't remember what is the use
case. As for the handle_response_icmp() checksum validation
problem I'm still working on the patch.

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply

* Re: [PATCH RFC net-next 3/6] bpf: Allow skb extensions to survive packet scrubbing
From: Jason Xing @ 2026-07-17 17:30 UTC (permalink / raw)
  To: Jakub Sitnicki
  Cc: Stanislav Fomichev, Daniel Borkmann, John Fastabend, netdev, bpf,
	kernel-team, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <CAL+tcoB4fwO5WxAcnW3QRErSQCnMBVMh6mfhFfG_dZhL+=MA6Q@mail.gmail.com>

On Thu, Jul 16, 2026 at 5:06 PM Jason Xing <kerneljasonxing@gmail.com> wrote:
>
> On Thu, Jul 16, 2026 at 3:00 PM Jakub Sitnicki <jakub@cloudflare.com> wrote:
> >
> > On Thu, Jul 16, 2026 at 05:11 AM -07, Stanislav Fomichev wrote:
> > > On 07/14, Jakub Sitnicki wrote:
> > >> skb_scrub_packet() drops all skb extensions unconditionally via
> > >> skb_ext_reset(). It runs on tunnel encap/decap (ip_tunnel_rcv,
> > >> vxlan_rcv, etc.) and cross-netns forwarding (dev_forward_skb).
> > >>
> > >> This makes it impossible for a BPF program to pass metadata via
> > >> bpf_skb_ext through a tunnel or across a netns boundary. The extension
> > >> is always lost at the scrub point.
> > >>
> > >> Introduce skb_ext_scrub() which consults each active extension before
> > >> discarding it. Extensions that request preservation are kept while the
> > >> rest are torn down. When the extension slab is shared with clones, COW
> > >> ensures isolation. Replace the skb_ext_reset() call in
> > >> skb_scrub_packet() with skb_ext_scrub().
> > >>
> > >> Expose the opt-in mechanism to BPF via the BPF_SKB_EXT_F_NO_SCRUB flag
> > >> for bpf_dynptr_from_skb_ext(). A program that sets this flag when
> > >> creating the extension signals that its metadata should survive
> > >> scrubbing.
> > >>
> > >> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
> > >> ---
> > >>  include/linux/bpf.h      |  1 +
> > >>  include/linux/skbuff.h   |  2 ++
> > >>  include/uapi/linux/bpf.h |  3 +-
> > >>  net/core/filter.c        | 11 +++++--
> > >>  net/core/skbuff.c        | 82 ++++++++++++++++++++++++++++++++++++++++++------
> > >>  net/ipv4/udp.c           |  2 +-
> > >>  6 files changed, 86 insertions(+), 15 deletions(-)
> > >>
> > >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > >> index 6b918a5b61bf..a46ca53c5b27 100644
> > >> --- a/include/linux/bpf.h
> > >> +++ b/include/linux/bpf.h
> > >> @@ -4214,6 +4214,7 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
> > >>  #ifdef CONFIG_BPF_SKB_EXT
> > >>
> > >>  struct bpf_skb_ext {
> > >> +    u64 flags;
> > >>      u8 buf[CONFIG_BPF_SKB_EXT_SIZE] __aligned(8);
> > >>  };
> > >>
> > >> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > >> index 584d8440d352..66afa5489007 100644
> > >> --- a/include/linux/skbuff.h
> > >> +++ b/include/linux/skbuff.h
> > >> @@ -5063,6 +5063,7 @@ void *__skb_ext_set(struct sk_buff *skb, enum skb_ext_id id,
> > >>  void *skb_ext_add(struct sk_buff *skb, enum skb_ext_id id);
> > >>  void __skb_ext_del(struct sk_buff *skb, enum skb_ext_id id);
> > >>  void __skb_ext_put(struct skb_ext *ext);
> > >> +void skb_ext_scrub(struct sk_buff *skb);
> > >>
> > >>  static inline void skb_ext_put(struct sk_buff *skb)
> > >>  {
> > >> @@ -5132,6 +5133,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
> > >>  static inline void __skb_ext_put(struct skb_ext *ext) {}
> > >>  static inline void skb_ext_put(struct sk_buff *skb) {}
> > >>  static inline void skb_ext_reset(struct sk_buff *skb) {}
> > >> +static inline void skb_ext_scrub(struct sk_buff *skb) {}
> > >>  static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
> > >>  static inline void __skb_ext_copy(struct sk_buff *d, const struct sk_buff *s) {}
> > >>  static inline void skb_ext_copy(struct sk_buff *dst, const struct sk_buff *s) {}
> > >> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> > >> index 3eee4467422d..02da170205de 100644
> > >> --- a/include/uapi/linux/bpf.h
> > >> +++ b/include/uapi/linux/bpf.h
> > >> @@ -7734,7 +7734,8 @@ struct bpf_insn_array_value {
> > >>
> > >>  /* Flags to control bpf_dynptr_from_skb_ext() behavior. */
> > >>  enum {
> > >> -    BPF_SKB_EXT_F_CREATE = (1ULL << 0),
> > >> +    BPF_SKB_EXT_F_CREATE    = (1ULL << 0),
> > >> +    BPF_SKB_EXT_F_NO_SCRUB  = (1ULL << 1),
> > >
> > > Do I understand correctly that you do prefer the NO_SCRUB mode? Any reason
> > > we need to have scrub mode? If it's all produced/consumed by bpf, maybe
> > > we can just carry this data unconditionally instead of having a SCRUB/NO_SCRUB
> > > option?

After giving it more thought, I vote for only no_scrub mode because I
don't see any reason why we still use scrub mode. But it's just my
opinion.

My question is if we in the future really need the scrub mode, it's
still possible to add this option, right?

Thanks,
Jason

> >
> > Yes, that's correct. We definitely need NO_SCRUB but I don't have a use
> > case that relies on metadata scrubbing. I believe Kuniyuki also would
> > like the no-scrub to be the only/default behavior for Google's egress
> > use case.
> >
> > I've made it an opt-out mostly because that the existing metadata
> > (skb->mark, skb->data_meta) gets scrubbed. Although as Jakub K has
> > pointed out to me - you can circumvent it by using bpf_redirect into the
> > target netns. So I guess we have a precendent?
> >
> > I could use input from folks operating in K8S-like environments, if
>
> Sorry, I don't quite follow it here. Why don't we need the NO_SCRUB
> here? The crucial point here is to allow skb traverse across different
> containers, which is also what I expect. We do need to support this
> case to make this feature standalone, which means it is independent
> and not affected by other components.
>
> And one part of what I'm doing for BPF timestamping v2 is to address
> the issue in the container scenario as well, FYI.
>
> Thanks,
> Jason
>
> > no-scrub-only mode would be acceptable there? Daniel, John, any opinion?
> >
> >

^ permalink raw reply

* [PATCH 6.12.y 5/9] af_unix/scm: fix whitespace errors
From: Heiko Stuebner @ 2026-07-17 17:29 UTC (permalink / raw)
  To: stable
  Cc: heiko, quentin.schulz, kuniyu, kuniyu, Alexander Mikhalitsyn,
	linux-kernel, netdev, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Leon Romanovsky,
	Arnd Bergmann, Christian Brauner, Lennart Poettering,
	Luca Boccassi, David Rheinsberg, Heiko Stuebner
In-Reply-To: <20260717172922.3398851-1-heiko@sntech.de>

From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>

[ Upstream commit 2b9996417e4ec231c91818f9ea8107ae62ef75ad ]

Fix whitespace/formatting errors.

Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: David S. Miller <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Kuniyuki Iwashima <kuniyu@google.com>
Cc: Lennart Poettering <mzxreary@0pointer.de>
Cc: Luca Boccassi <bluca@debian.org>
Cc: David Rheinsberg <david@readahead.eu>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Link: https://lore.kernel.org/20250703222314.309967-5-aleksandr.mikhalitsyn@canonical.com
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
---
 include/net/scm.h  | 4 ++--
 net/unix/af_unix.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/net/scm.h b/include/net/scm.h
index 0d35c7c77a74..ea85f7427a19 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -69,7 +69,7 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co
 static __inline__ void scm_set_cred(struct scm_cookie *scm,
 				    struct pid *pid, kuid_t uid, kgid_t gid)
 {
-	scm->pid  = get_pid(pid);
+	scm->pid = get_pid(pid);
 	scm->creds.pid = pid_vnr(pid);
 	scm->creds.uid = uid;
 	scm->creds.gid = gid;
@@ -78,7 +78,7 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
 static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
 {
 	put_pid(scm->pid);
-	scm->pid  = NULL;
+	scm->pid = NULL;
 }
 
 static __inline__ void scm_destroy(struct scm_cookie *scm)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1d426f5b2580..c64d8ee0ede4 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1887,7 +1887,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
 	struct scm_cookie scm;
 
 	memset(&scm, 0, sizeof(scm));
-	scm.pid  = UNIXCB(skb).pid;
+	scm.pid = UNIXCB(skb).pid;
 	if (UNIXCB(skb).fp)
 		unix_detach_fds(&scm, skb);
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] compiler_types: Introduce inline_for_performance
From: Nick Desaulniers @ 2026-07-17 16:56 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Laight, Andrew Morton, linux-kernel, netdev, Jakub Kicinski,
	Eric Dumazet, Paolo Abeni, Nicolas Pitre, nathan, ajordanr
In-Reply-To: <CANn89iJVQe=wedLheJmjZjOTJsWHijT0jZs=iRxKssJZbjAxHw@mail.gmail.com>

On Mon, Jan 19, 2026 at 11:33:29AM +0100, Eric Dumazet wrote:
> > Many __always_inline came because of clang's reluctance to inline
> > small things, even if the resulting code size is bigger and slower.
> >
> > It is a bit unclear, this seems to happen when callers are 'big
> > enough'.

Haha, yes, and I've read LLVM's inline cost model before and "a bit
unclear" is how I feel about it.  At this point, some of your Google
compatriots have even resorted to AI for inlining.

https://arxiv.org/pdf/2101.04808

> > noinstr (callers) functions are also a problem.
> >
> > Let's take the list_add() call from dev_gro_receive() : clang does not
> > inline it, for some reason.
> >
> > After adding __always_inline to list_add() and __list_add() we have
> > smaller and more efficient code,
> > for real workloads, not only benchmarks.

Yeah, ChromeOS is hitting this now, too.  They're deploying AutoFDO
where you collect traces with LBR (x86) / ETM,TRBE,BRBE,SPE (ARM) then
feed that back into the compiler.  Then they're getting modpost warnings
from section mismatches when constant propagation sinks addresses of
initdata globals into specialized copies of list_add that are then not
inlined (so not placed in .init).

https://github.com/ClangBuiltLinux/linux/issues/2173

I think list_add, __list_add, and probably __list_del_entry_valid should
be always_inline, possibly except for the different definitions when
CONFIG_LIST_HARDENED is set.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox