* [PATCH iwl-next] ixgbe: use ktime_get_real_ns() in ixgbe_ptp_reset()
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Jacob Keller, Marcin Szycik
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
Replace ktime_to_ns(ktime_get_real()) with the direct equivalent
ktime_get_real_ns() in ixgbe_ptp_reset(). Using the combined helper
avoids the unnecessary intermediate ktime_t variable and makes the
intent clearer.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 6885d23..a7d1635 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1347,7 +1347,7 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
spin_lock_irqsave(&adapter->tmreg_lock, flags);
timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
- ktime_to_ns(ktime_get_real()));
+ ktime_get_real_ns());
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
adapter->last_overflow_check = jiffies;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: remove ixgbe_ping_all_vfs() from watchdog link-up handler
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Sebastian Basierski <sebastianx.basierski@intel.com>
When multiple VFs are brought up simultaneously, a VF can receive a
CTS (Clear To Send) mailbox message instead of the expected RESET |
(N)ACK response, because the watchdog is sending a gratuitous ping
right as the VF mailbox transaction is in progress.
Remove the ixgbe_ping_all_vfs() call from ixgbe_watchdog_link_is_up().
Link-state changes are already communicated to VFs through the normal
mailbox protocol; the extra ping here is redundant and races with VF
initialization.
Signed-off-by: Sebastian Basierski <sebastianx.basierski@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1885fe8..52f0cdc 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -8163,9 +8163,6 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
/* update the default user priority for VFs */
ixgbe_update_default_up(adapter);
-
- /* ping all the active vfs to let them know link has changed */
- ixgbe_ping_all_vfs(adapter);
}
/**
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: clean up adaptive interrupt moderation algorithm
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
Improve the adaptive interrupt throttle (ITR) algorithm in several ways:
- Lower IXGBE_ITR_ADAPTIVE_MAX_USECS from 126 to 84 us (12K interrupts/s
minimum in bulk mode) to prevent RX starvation in full-blown bulk
scenarios.
- Add ixgbe_container_is_rx() helper to split the Rx vs Tx logic in
ixgbe_update_itr(); Rx uses a latency-favouring path for small bursts
(< 24 packets and < 12112 bytes), targeting 8x throughput growth per
step.
- Limit the ITR decrease in latency mode to at most 2 us per update so
ACK workloads do not overdrive the moderation and starve TCP senders.
- Add IXGBE_ITR_ADAPTIVE_MASK_USECS (= IXGBE_ITR_ADAPTIVE_LATENCY - 1
= 0x7F) to mask out the mode flag bit 7 in ixgbe_set_itr(), replacing
the open-coded ~IXGBE_ITR_ADAPTIVE_LATENCY.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 4 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 78 +++++++++++--------
2 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 59a1cee4..c704cc6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -475,9 +475,10 @@ static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
#define IXGBE_ITR_ADAPTIVE_MIN_INC 2
#define IXGBE_ITR_ADAPTIVE_MIN_USECS 10
-#define IXGBE_ITR_ADAPTIVE_MAX_USECS 126
+#define IXGBE_ITR_ADAPTIVE_MAX_USECS 84
#define IXGBE_ITR_ADAPTIVE_LATENCY 0x80
#define IXGBE_ITR_ADAPTIVE_BULK 0x00
+#define IXGBE_ITR_ADAPTIVE_MASK_USECS (IXGBE_ITR_ADAPTIVE_LATENCY - 1)
struct ixgbe_ring_container {
struct ixgbe_ring *ring; /* pointer to linked list of rings */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 0bc806a..1885fe8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2711,6 +2711,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
}
+static inline bool ixgbe_container_is_rx(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring_container *rc)
+{
+ return &q_vector->rx == rc;
+}
+
/**
* ixgbe_update_itr - update the dynamic ITR value based on statistics
* @q_vector: structure containing interrupt and ring information
@@ -2747,35 +2753,24 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
goto clear_counts;
packets = ring_container->total_packets;
-
- /* We have no packets to actually measure against. This means
- * either one of the other queues on this vector is active or
- * we are a Tx queue doing TSO with too high of an interrupt rate.
- *
- * When this occurs just tick up our delay by the minimum value
- * and hope that this extra delay will prevent us from being called
- * without any work on our queue.
- */
- if (!packets) {
- itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
- if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
- itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
- itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
- goto clear_counts;
- }
-
bytes = ring_container->total_bytes;
- /* If packets are less than 4 or bytes are less than 9000 assume
- * insufficient data to use bulk rate limiting approach. We are
- * likely latency driven.
- */
- if (packets < 4 && bytes < 9000) {
- itr = IXGBE_ITR_ADAPTIVE_LATENCY;
- goto adjust_by_size;
+ if (ixgbe_container_is_rx(q_vector, ring_container)) {
+ /* If Rx and there are 1 to 23 packets and bytes are less than
+ * 12112 assume insufficient data to use bulk rate limiting
+ * approach. Instead we will focus on simply trying to target
+ * receiving 8 times as much data in the next interrupt.
+ */
+ if (packets && packets < 24 && bytes < 12112) {
+ itr = IXGBE_ITR_ADAPTIVE_LATENCY;
+ avg_wire_size = (bytes + packets * 24) * 2;
+ avg_wire_size = clamp_t(unsigned int,
+ avg_wire_size, 2560, 12800);
+ goto adjust_for_speed;
+ }
}
- /* Between 4 and 48 we can assume that our current interrupt delay
+ /* Less than 48 packets we can assume that our current interrupt delay
* is only slightly too low. As such we should increase it by a small
* fixed amount.
*/
@@ -2783,6 +2778,20 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
+
+ /* If sample size is 0 - 7 we should probably switch
+ * to latency mode instead of trying to control
+ * things as though we are in bulk.
+ *
+ * Otherwise if the number of packets is less than 48
+ * we should maintain whatever mode we are currently
+ * in. The range between 8 and 48 is the cross-over
+ * point between latency and bulk traffic.
+ */
+ if (packets < 8)
+ itr += IXGBE_ITR_ADAPTIVE_LATENCY;
+ else
+ itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
goto clear_counts;
}
@@ -2813,7 +2822,6 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
*/
itr = IXGBE_ITR_ADAPTIVE_BULK;
-adjust_by_size:
/* If packet counts are 256 or greater we can assume we have a gross
* overestimation of what the rate should be. Instead of trying to fine
* tune it just use the formula below to try and dial in an exact value
@@ -2856,12 +2864,7 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
avg_wire_size = 32256;
}
- /* If we are in low latency mode half our delay which doubles the rate
- * to somewhere between 100K to 16K ints/sec
- */
- if (itr & IXGBE_ITR_ADAPTIVE_LATENCY)
- avg_wire_size >>= 1;
-
+adjust_for_speed:
/* Resultant value is 256 times larger than it needs to be. This
* gives us room to adjust the value as needed to either increase
* or decrease the value based on link speeds of 10G, 2.5G, 1G, etc.
@@ -2888,6 +2891,15 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
break;
}
+ /* In the case of a latency specific workload only allow us to
+ * reduce the ITR by at most 2us. By doing this we should dial
+ * in so that our number of interrupts is no more than 2x the number
+ * of packets for the least busy workload. So for example in the case
+ * of a TCP workload the ACK packets being received would set the
+ * interrupt rate as they are a latency specific workload.
+ */
+ if ((itr & IXGBE_ITR_ADAPTIVE_LATENCY) && itr < ring_container->itr)
+ itr = ring_container->itr - IXGBE_ITR_ADAPTIVE_MIN_INC;
clear_counts:
/* write back value */
ring_container->itr = itr;
@@ -2948,7 +2960,7 @@ static void ixgbe_set_itr(struct ixgbe_q_vector *q_vector)
new_itr = min(q_vector->rx.itr, q_vector->tx.itr);
/* Clear latency flag if set, shift into correct position */
- new_itr &= ~IXGBE_ITR_ADAPTIVE_LATENCY;
+ new_itr &= IXGBE_ITR_ADAPTIVE_MASK_USECS;
new_itr <<= 2;
if (new_itr != q_vector->itr) {
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: add bounds check for debugfs register access
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Paul Greenwalt
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Paul Greenwalt <paul.greenwalt@intel.com>
Prevent out-of-bounds MMIO accesses triggered through user-controlled
register offsets. IXGBE_HFDR (0x15FE8) is the highest valid MMIO
register in the ixgbe register map; any offset beyond it would address
unmapped memory.
Add a defense-in-depth check at two levels:
1. ixgbe_read_reg() -- the noinline register read accessor. A
WARN_ON_ONCE() guard here catches any future code path (including
ioctl extensions) that might inadvertently pass an out-of-range
offset without relying on higher layers to catch it first.
ixgbe_write_reg() is a static inline called from the TX/RX hot path;
adding WARN_ON_ONCE there would inline the check at every call site,
so only the read path gets this guard.
2. ixgbe_dbg_reg_ops_write() -- the debugfs 'reg_ops' interface is the
only current path where a raw, user-supplied offset enters the driver.
Gating it before invoking the register accessors provides a clean,
user-visible failure (silent ignore with no kernel splat) for
deliberately malformed debugfs writes.
Add a reg <= IXGBE_HFDR guard to both the read and write paths in
ixgbe_dbg_reg_ops_write(), and a WARN_ON_ONCE + early-return guard to
ixgbe_read_reg().
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c | 6 ++++--
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 ++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
index 5b1cf49d..a6a19c0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
@@ -86,7 +86,8 @@ static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
u32 reg, value;
int cnt;
cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", ®, &value);
- if (cnt == 2) {
+ /* check format and bounds check register access */
+ if (cnt == 2 && reg <= IXGBE_HFDR) {
IXGBE_WRITE_REG(&adapter->hw, reg, value);
value = IXGBE_READ_REG(&adapter->hw, reg);
e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
@@ -97,7 +98,8 @@ static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
u32 reg, value;
int cnt;
cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", ®);
- if (cnt == 1) {
+ /* check format and bounds check register access */
+ if (cnt == 1 && reg <= IXGBE_HFDR) {
value = IXGBE_READ_REG(&adapter->hw, reg);
e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
} else {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..4a1f3c2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -354,4 +354,6 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
if (ixgbe_removed(reg_addr))
return IXGBE_FAILED_READ_REG;
+ if (WARN_ON_ONCE(reg > IXGBE_HFDR))
+ return IXGBE_FAILED_READ_REG;
if (unlikely(hw->phy.nw_mng_if_sel &
IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE)) {
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: increase SWFW semaphore timeout for X550 FW updates
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
From: Soumen Karmakar <soumen.karmakar@intel.com>
According to FW documentation, the most time-consuming part of continuous
FW activity is Shadow RAM (SR) dump which takes up to 3.2 seconds. For
X550 devices, the module-update FW command can take over 4.5 s. Increase
the max Software/Firmware (SW/FW) semaphore wait time from the default
200 ms to 5 s for X550 to avoid spurious semaphore timeout failures
during FW update operations.
Signed-off-by: Soumen Karmakar <soumen.karmakar@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index e67e2fe..85047ef 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -577,6 +577,9 @@ int ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
swmask |= swi2c_mask;
fwmask |= swi2c_mask << 2;
+ if (hw->mac.type == ixgbe_mac_X550)
+ timeout = 1000;
+
for (i = 0; i < timeout; i++) {
/* SW NVM semaphore bit is used for access to all
* SW_FW_SYNC bits (not just NVM)
--
2.52.0
^ permalink raw reply related
* Re: [PATCH net v3 09/11] rxrpc: Fix keyring reference count leak in rxrpc_setsockopt()
From: David Howells @ 2026-03-27 7:24 UTC (permalink / raw)
To: Anderson Nascimento
Cc: dhowells, netdev, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <CAPhRvkw8eopbCei6XQY3Fi-nDk+FyuXUWs8ToQyHE9J229_v0Q@mail.gmail.com>
Anderson Nascimento <anderson@allelesecurity.com> wrote:
> To make the logic more coherent, what if we check if (rx->key ||
> rx->securities) in both options and remove the rx->securities check from
> rxrpc_request_key()?
You're allowed to have both a keyring (server) and a key (client). You can
issue client calls on a server socket. The in-kernel kafs filesystem does
this, for example - though it normally sets the outgoing key on individual
calls.
To parallel the kernel example, it might be worth my while adding a CMSG tag
to take a key ID or key description so the rxrpc_sendmsg() can do a
request_key() when setting up a call (the AF_RXRPC socket allows a different
key with each call dispatched), though the AFS command line tools tend only to
talk to a single cell at a time (you only need one key for comms with an
entire cell).
Davod
^ permalink raw reply
* [PATCH net] ice: use READ_ONCE() to access cached PHC time
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Sergey Temerkhanov
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@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>
---
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 8b0530b..2ea4dbc 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -350,7 +350,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.52.0
^ permalink raw reply related
* [PATCH net] ice: stop DCBNL requests during driver unload
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Dave Ertman
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Dave Ertman <david.m.ertman@intel.com>
With a chatty lldpad, DCB configuration requests can arrive through
the DCBNL API while the driver is tearing down PF resources, leading
to use-after-free and NULL dereference crashes.
Set ICE_SHUTTING_DOWN in pf->state at the start of ice_remove() and
check this bit at the beginning of every DCBNL callback that accesses
resources freed during the remove path.
Fixes: b94b013eb626 ("ice: Implement DCBNL support")
Cc: stable@vger.kernel.org
Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice.h | 1 +
drivers/net/ethernet/intel/ice/ice_dcb_nl.c | 46 +++++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_main.c | 1 +
3 files changed, 48 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 2b2b22a..052c310 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -283,6 +283,7 @@ enum ice_pf_state {
ICE_EMPR_RECV, /* set by OICR handler */
ICE_SUSPENDED, /* set on module remove path */
ICE_RESET_FAILED, /* set by reset/rebuild */
+ ICE_SHUTTING_DOWN, /* set on module remove path, before releasing resources */
/* When checking for the PF to be in a nominal operating state, the
* bits that are grouped at the beginning of the list need to be
* checked. Bits occurring before ICE_STATE_NOMINAL_CHECK_BITS will
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
index a10c1c8d..4a30129 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
@@ -15,6 +15,8 @@ static void ice_dcbnl_devreset(struct net_device *netdev)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
while (ice_is_reset_in_progress(pf->state))
usleep_range(1000, 2000);
@@ -35,6 +37,8 @@ static int ice_dcbnl_getets(struct net_device *netdev, struct ieee_ets *ets)
struct ice_pf *pf;
pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
dcbxcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
ets->willing = dcbxcfg->etscfg.willing;
@@ -66,6 +70,8 @@ static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets)
int bwcfg = 0, bwrec = 0;
int err, i;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
@@ -135,6 +141,8 @@ ice_dcbnl_getnumtcs(struct net_device *dev, int __always_unused tcid, u8 *num)
if (!test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags))
return -EINVAL;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
*num = pf->hw.func_caps.common_cap.maxtc;
return 0;
@@ -148,6 +156,8 @@ static u8 ice_dcbnl_getdcbx(struct net_device *netdev)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return 0;
return pf->dcbx_cap;
}
@@ -161,6 +171,8 @@ static u8 ice_dcbnl_setdcbx(struct net_device *netdev, u8 mode)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_qos_cfg *qos_cfg;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return 0;
/* if FW LLDP agent is running, DCBNL not allowed to change mode */
if (test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags))
return ICE_DCB_NO_HW_CHG;
@@ -208,6 +220,8 @@ static void ice_dcbnl_get_perm_hw_addr(struct net_device *netdev, u8 *perm_addr)
struct ice_port_info *pi = pf->hw.port_info;
int i, j;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
memset(perm_addr, 0xff, MAX_ADDR_LEN);
for (i = 0; i < netdev->addr_len; i++)
@@ -242,6 +256,8 @@ static int ice_dcbnl_getpfc(struct net_device *netdev, struct ieee_pfc *pfc)
struct ice_dcbx_cfg *dcbxcfg;
int i;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
dcbxcfg = &pi->qos_cfg.local_dcbx_cfg;
pfc->pfc_cap = dcbxcfg->pfc.pfccap;
pfc->pfc_en = dcbxcfg->pfc.pfcena;
@@ -267,6 +283,8 @@ static int ice_dcbnl_setpfc(struct net_device *netdev, struct ieee_pfc *pfc)
struct ice_dcbx_cfg *new_cfg;
int err;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
@@ -308,6 +326,8 @@ ice_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, u8 *setting)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_port_info *pi = pf->hw.port_info;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -331,6 +351,8 @@ static void ice_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, u8 set)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_dcbx_cfg *new_cfg;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -364,6 +386,8 @@ static u8 ice_dcbnl_getpfcstate(struct net_device *netdev)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_port_info *pi = pf->hw.port_info;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return 0;
/* Return enabled if any UP enabled for PFC */
if (pi->qos_cfg.local_dcbx_cfg.pfc.pfcena)
return 1;
@@ -395,6 +419,8 @@ static u8 ice_dcbnl_setstate(struct net_device *netdev, u8 state)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return ICE_DCB_NO_HW_CHG;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return ICE_DCB_NO_HW_CHG;
@@ -469,6 +495,8 @@ ice_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
struct ice_dcbx_cfg *new_cfg;
int i;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -504,6 +532,8 @@ ice_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 *bw_pct)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_port_info *pi = pf->hw.port_info;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -528,6 +558,8 @@ ice_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 bw_pct)
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_dcbx_cfg *new_cfg;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -609,6 +641,8 @@ ice_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int __always_unused pgid,
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return;
@@ -643,6 +677,8 @@ static u8 ice_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return ICE_DCB_NO_HW_CHG;
if (!(test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags)))
return ICE_DCB_NO_HW_CHG;
@@ -695,6 +731,8 @@ static int ice_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
.protocol = id,
};
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return -EINVAL;
@@ -738,6 +776,8 @@ static int ice_dcbnl_setapp(struct net_device *netdev, struct dcb_app *app)
u8 max_tc;
int ret;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
/* ONLY DSCP APP TLVs have operational significance */
if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)
return -EINVAL;
@@ -871,6 +911,8 @@ static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app)
unsigned int i, j;
int ret = 0;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return -EBUSY;
if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) {
netdev_err(netdev, "can't delete DSCP netlink app when FW DCB agent is active\n");
return -EINVAL;
@@ -978,6 +1020,8 @@ static u8 ice_dcbnl_cee_set_all(struct net_device *netdev)
struct ice_dcbx_cfg *new_cfg;
int err;
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return ICE_DCB_NO_HW_CHG;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return ICE_DCB_NO_HW_CHG;
@@ -1048,6 +1092,8 @@ void ice_dcbnl_set_all(struct ice_vsi *vsi)
return;
pf = ice_netdev_to_pf(netdev);
+ if (test_bit(ICE_SHUTTING_DOWN, pf->state))
+ return;
pi = pf->hw.port_info;
/* SW DCB taken care of by SW Default Config */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 685c9618..eff48bd 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5424,6 +5424,7 @@ static void ice_remove(struct pci_dev *pdev)
struct ice_pf *pf = pci_get_drvdata(pdev);
int i;
+ set_bit(ICE_SHUTTING_DOWN, pf->state);
for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
if (!ice_is_reset_in_progress(pf->state))
break;
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix netdev bring-up and bring-down in self-test
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Konstantin Ilichev, Grzegorz Nitka
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Konstantin Ilichev <konstantin.ilichev@intel.com>
When an offline self-test is initiated with ethtool -t, any ongoing
traffic could get stuck because ice_stop() and ice_open() are called
without letting the OS know about state transitions. In most cases
a write() system call would block.
Fix this by calling dev_change_flags() to bring the netdev up and
down, which ensures ndo_open()/ndo_stop() are called and all watchers
are notified correctly.
Fixes: 0e674aeb0b77 ("ice: Add handler for ethtool selftest")
Cc: stable@vger.kernel.org
Co-developed-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Signed-off-by: Konstantin Ilichev <konstantin.ilichev@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_ethtool.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 96d95af..2a4f06f 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1416,7 +1416,7 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
/* If the device is online then take it offline */
if (if_running)
/* indicate we're in test mode */
- ice_stop(netdev);
+ dev_change_flags(netdev, netdev->flags & ~IFF_UP, NULL);
data[ICE_ETH_TEST_LINK] = ice_link_test(netdev);
data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev);
@@ -1434,10 +1434,12 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
clear_bit(ICE_TESTING, pf->state);
if (if_running) {
- int status = ice_open(netdev);
+ int status = dev_change_flags(netdev,
+ netdev->flags | IFF_UP,
+ NULL);
if (status) {
- dev_err(dev, "Could not open device %s, err %d\n",
+ dev_err(dev, "Could not bring up device %s, err %d\n",
pf->int_name, status);
}
}
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix ice_init_link() error return preventing probe
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Paul Greenwalt
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Paul Greenwalt <paul.greenwalt@intel.com>
ice_init_link() can return an error status from ice_update_link_info()
or ice_init_phy_user_cfg(), causing probe to fail.
An incorrect NVM update procedure can result in link/PHY errors, and
the recommended resolution is to update the NVM using the correct
procedure. If the driver fails probe due to link errors, the user
cannot update the NVM to recover. The link/PHY errors logged are
non-fatal: they are already annotated as 'not a fatal error if this
fails'.
Since none of the errors inside ice_init_link() should prevent probe
from completing, convert it to void and remove the error check in the
caller. All failures are already logged; callers have no meaningful
recovery path for link init errors.
Fixes: 5b246e533d01 ("ice: split probe into smaller functions")
Cc: stable@vger.kernel.org
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_main.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index cf116bb..a6b0c09 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4856,16 +4856,14 @@ static void ice_init_wakeup(struct ice_pf *pf)
device_set_wakeup_enable(ice_pf_to_dev(pf), false);
}
-static int ice_init_link(struct ice_pf *pf)
+static void ice_init_link(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
int err;
err = ice_init_link_events(pf->hw.port_info);
- if (err) {
+ if (err)
dev_err(dev, "ice_init_link_events failed: %d\n", err);
- return err;
- }
/* not a fatal error if this fails */
err = ice_init_nvm_phy_type(pf->hw.port_info);
@@ -4899,8 +4897,6 @@ static int ice_init_link(struct ice_pf *pf)
} else {
set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
}
-
- return err;
}
static int ice_init_pf_sw(struct ice_pf *pf)
@@ -5043,9 +5039,7 @@ static int ice_init(struct ice_pf *pf)
ice_init_wakeup(pf);
- err = ice_init_link(pf);
- if (err)
- goto err_init_link;
+ ice_init_link(pf);
err = ice_send_version(pf);
if (err)
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix setting promisc mode while adding VID filter
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Marcin Szycik
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Marcin Szycik <marcin.szycik@intel.com>
There are at least two paths through which VSI promiscuous mode can be
independently configured via ice_fltr_set_vsi_promisc():
- ice_vlan_rx_add_vid() (netdev op)
- ice_service_task() -> ... -> ice_set_promisc()
Both paths may try to program promiscuous mode concurrently. One such
scenario is:
1. Add ice netdev to bond
2. Add the bond netdev to bridge
3. ice netdev enters allmulticast mode (IFF_ALLMULTI)
4. Service task programs promisc mode filter
5. Bridge -> bond calls ice_vlan_rx_add_vid()
Crucially, ice_vlan_rx_add_vid() fails if ice_fltr_set_vsi_promisc()
returns any error, including -EEXIST. This causes VLAN filtering setup
to fail on the bond interface. ice_set_promisc() already handles -EEXIST
correctly.
Fix by adding the same -EEXIST check to ice_vlan_rx_add_vid(): if the
promisc filter is already programmed, continue without returning error.
Fixes: 1273f89578f2 ("ice: Fix broken IFF_ALLMULTI handling")
Cc: stable@vger.kernel.org
Signed-off-by: Marcin Szycik <marcin.szycik@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 8896805..cf116bb 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3755,7 +3755,7 @@ int ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
ICE_MCAST_VLAN_PROMISC_BITS,
vid);
- if (ret)
+ if (ret && ret != -EEXIST)
goto finish;
}
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix PTP hang for E825C devices
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Grzegorz Nitka
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Grzegorz Nitka <grzegorz.nitka@intel.com>
Change the order of PTP reconfiguration when port goes down or up
(ice_down and ice_up calls) to be more graceful and consistent from
timestamp interrupts processing perspective.
For both calls (ice_up and ice_down), accompanying ice_ptp_link_change
is called which starts/stops PTP timer. This patch changes the order:
- while link goes down: disable net device Tx first (netif_carrier_off,
netif_tx_disable), then call ice_ptp_link_change
- while link goes up: ice_ptp_link_change called first, then re-enable
net device Tx (netif_tx_start_all_queues)
Otherwise, there is a narrow window in which PTP timestamp request has
been triggered and timestamp processing occurs when PTP timer is not
enabled yet (up case) or already disabled (down case). This may lead to
undefined behavior and receiving invalid timestamps. This case was
observed on E825C devices only.
Fixes: 6b1ff5d39228 ("ice: always call ice_ptp_link_change and make it void")
Cc: stable@vger.kernel.org
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index e7308e3..8896805 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -6797,10 +6797,10 @@ static int ice_up_complete(struct ice_vsi *vsi)
(vsi->port_info->phy.link_info.link_info & ICE_AQ_LINK_UP) &&
((vsi->netdev && (vsi->type == ICE_VSI_PF ||
vsi->type == ICE_VSI_SF)))) {
+ ice_ptp_link_change(pf, true);
ice_print_link_msg(vsi, true);
netif_tx_start_all_queues(vsi->netdev);
netif_carrier_on(vsi->netdev);
- ice_ptp_link_change(pf, true);
}
/* Perform an initial read of the statistics registers now to
@@ -7328,9 +7328,9 @@ int ice_down(struct ice_vsi *vsi)
if (vsi->netdev) {
vlan_err = ice_vsi_del_vlan_zero(vsi);
- ice_ptp_link_change(vsi->back, false);
netif_carrier_off(vsi->netdev);
netif_tx_disable(vsi->netdev);
+ ice_ptp_link_change(vsi->back, false);
}
ice_vsi_dis_irq(vsi);
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix PTP Call Trace during PTP release
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Paul Greenwalt
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@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>
---
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 094e962..6848b1c 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -3041,6 +3041,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.52.0
^ permalink raw reply related
* [PATCH net] ice: fix locking around wait_event_interruptible_locked_irq
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Jacob Keller, Jakub Kicinski
In-Reply-To: <20260327072332.130320-1-aleksandr.loktionov@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
Commit 50327223a8bb ("ice: add lock to protect low latency interface")
introduced a wait queue used to protect the low latency timer interface.
The queue is used with the wait_event_interruptible_locked_irq macro, which
unlocks the wait queue lock while sleeping. The irq variant uses
spin_lock_irq and spin_unlock_irq to manage this. The wait queue lock was
previously locked using spin_lock_irqsave. This difference in lock variants
could lead to issues, since wait_event would unlock the wait queue and
restore interrupts while sleeping.
The ice_read_phy_tstamp_ll_e810() function is ultimately called through
ice_read_phy_tstamp, which is called from ice_ptp_process_tx_tstamp or
ice_ptp_clear_unexpected_tx_ready. The former is called through the
miscellaneous IRQ thread function, while the latter is called from the
service task work queue thread. Neither of these functions has interrupts
disabled, so use spin_lock_irq instead of spin_lock_irqsave.
Fixes: 50327223a8bb ("ice: add lock to protect low latency interface")
Cc: stable@vger.kernel.org
Reported-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/netdev/20250109181823.77f44c69@kernel.org/
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 61c0a0d..1f73d72 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -4323,18 +4323,17 @@ static int
ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
{
struct ice_e810_params *params = &hw->ptp.phy.e810;
- unsigned long flags;
u32 val;
int err;
- spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
+ spin_lock_irq(¶ms->atqbal_wq.lock);
/* Wait for any pending in-progress low latency interrupt */
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
!(params->atqbal_flags &
ATQBAL_FLAGS_INTR_IN_PROGRESS));
if (err) {
- spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
+ spin_unlock_irq(¶ms->atqbal_wq.lock);
return err;
}
@@ -4349,7 +4348,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
REG_LL_PROXY_H);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
- spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
+ spin_unlock_irq(¶ms->atqbal_wq.lock);
return err;
}
@@ -4359,7 +4358,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
/* Read the low 32 bit value and set the TS valid bit */
*lo = rd32(hw, REG_LL_PROXY_L) | TS_VALID;
- spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
+ spin_unlock_irq(¶ms->atqbal_wq.lock);
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH net] ice: fix null-ptr dereference on false-positive tx timeout
From: Aleksandr Loktionov @ 2026-03-27 7:23 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
From: Michal Kubiak <michal.kubiak@intel.com>
Due to some kernel bugs the Tx timeout event may be false-positive.
For example, the kernel commit 95ecba62e2fd ("net: fix races in
netdev_tx_sent_queue()/dev_watchdog()") fixes race conditions that can
also occur during the ice driver initialization.
In case of such false-positive Tx timeouts there can be no real Tx
transaction started, so the SKB pointer can be NULL. Therefore, the call
devlink_fmsg_dump_skb() can crash because of NULL-ptr dereference.
Fix that by checking the SKB pointer before dereferencing it.
Fixes: 2a82874a3b7b ("ice: add Tx hang devlink health reporter")
Cc: stable@vger.kernel.org
Signed-off-by: Michal Kubiak <michal.kubiak@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/devlink/health.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c
index 8e9a8a8..4275329 100644
--- a/drivers/net/ethernet/intel/ice/devlink/health.c
+++ b/drivers/net/ethernet/intel/ice/devlink/health.c
@@ -409,7 +409,8 @@ static int ice_tx_hang_reporter_dump(struct devlink_health_reporter *reporter,
ice_fmsg_put_ptr(fmsg, "skb-ptr", skb);
devlink_fmsg_binary_pair_put(fmsg, "desc", event->tx_ring->desc,
event->tx_ring->count * sizeof(struct ice_tx_desc));
- devlink_fmsg_dump_skb(fmsg, skb);
+ if (skb)
+ devlink_fmsg_dump_skb(fmsg, skb);
devlink_fmsg_obj_nest_end(fmsg);
return 0;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ice: fix AQ error code comparison in ice_set_pauseparam()
From: Aleksandr Loktionov @ 2026-03-27 7:22 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Lukasz Czapnik
In-Reply-To: <20260327072236.129802-1-aleksandr.loktionov@intel.com>
From: Lukasz Czapnik <lukasz.czapnik@intel.com>
Fix unreachable code: the conditionals in ice_set_pauseparam() used
the bitwise-AND operator suggesting aq_failures is a bitmap, but it
is actually an enum, making the third condition logically unreachable.
Replace the if-else ladder with a switch statement. Also move the
aq_failures initialization to the variable declaration and remove the
redundant zeroing from ice_set_fc().
Fixes: fcea6f3da546 ("ice: Add stats and ethtool support")
Signed-off-by: Lukasz Czapnik <lukasz.czapnik@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_common.c | 1 -
drivers/net/ethernet/intel/ice/ice_ethtool.c | 12 ++++++++----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index f1a6601..6dad7d4 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -3883,7 +3883,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
if (!pi || !aq_failures)
return -EINVAL;
- *aq_failures = 0;
hw = pi->hw;
pcaps = kzalloc_obj(*pcaps);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 2a4f06f..0cf064c 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -3501,7 +3501,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
struct ice_vsi *vsi = np->vsi;
struct ice_hw *hw = &pf->hw;
struct ice_port_info *pi;
- u8 aq_failures;
+ u8 aq_failures = 0;
bool link_up;
u32 is_an;
int err;
@@ -3572,18 +3572,22 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
/* Set the FC mode and only restart AN if link is up */
err = ice_set_fc(pi, &aq_failures, link_up);
- if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) {
+ switch (aq_failures) {
+ case ICE_SET_FC_AQ_FAIL_GET:
netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
- } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) {
+ break;
+ case ICE_SET_FC_AQ_FAIL_SET:
netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
- } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) {
+ break;
+ case ICE_SET_FC_AQ_FAIL_UPDATE:
netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
+ break;
}
return err;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ice: call netif_keep_dst() once when entering switchdev mode
From: Aleksandr Loktionov @ 2026-03-27 7:22 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Marcin Szycik
In-Reply-To: <20260327072236.129802-1-aleksandr.loktionov@intel.com>
From: Marcin Szycik <marcin.szycik@intel.com>
netif_keep_dst() only needs to be called once for the uplink VSI, not
once for each port representor. Move it from ice_eswitch_setup_repr()
to ice_eswitch_enable_switchdev().
Fixes: defd52455aee ("ice: do Tx through PF netdev in slow-path")
Signed-off-by: Marcin Szycik <marcin.szycik@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_eswitch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index 2e4f096..c30e27b 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -117,8 +117,6 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
if (!repr->dst)
return -ENOMEM;
- netif_keep_dst(uplink_vsi->netdev);
-
dst = repr->dst;
dst->u.port_info.port_id = vsi->vsi_num;
dst->u.port_info.lower_dev = uplink_vsi->netdev;
@@ -312,6 +310,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
if (ice_eswitch_br_offloads_init(pf))
goto err_br_offloads;
+ netif_keep_dst(uplink_vsi->netdev);
+
pf->eswitch.is_running = true;
return 0;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ice: check cross-timestamp timeout bits
From: Aleksandr Loktionov @ 2026-03-27 7:22 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327072236.129802-1-aleksandr.loktionov@intel.com>
From: Karol Kolacinski <karol.kolacinski@intel.com>
Polling for cross-timestamp active bit depends on HW scheduling and
actual timeout may happen before the driver finishes polling.
Check cross-timestamp timeout bits to ensure that the driver finishes
the operation earlier when HW indicates timeout.
Fixes: 92456e795ac6 ("ice: Add unified ice_capture_crosststamp")
Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_hw_autogen.h | 3 +++
drivers/net/ethernet/intel/ice/ice_ptp.c | 12 ++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index 082ad33..8b4884e 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -499,6 +499,8 @@
#define PRTRPB_RDPC 0x000AC260
#define GLHH_ART_CTL 0x000A41D4
#define GLHH_ART_CTL_ACTIVE_M BIT(0)
+#define GLHH_ART_CTL_TIME_OUT1_M BIT(1)
+#define GLHH_ART_CTL_TIME_OUT2_M BIT(2)
#define GLHH_ART_TIME_H 0x000A41D8
#define GLHH_ART_TIME_L 0x000A41DC
#define GLTSYN_AUX_IN_0(_i) (0x000889D8 + ((_i) * 4))
@@ -564,6 +566,7 @@
#define E830_PRTTSYN_TXTIME_L(_i) (0x001E5000 + ((_i) * 32))
#define E830_GLPTM_ART_CTL 0x00088B50
#define E830_GLPTM_ART_CTL_ACTIVE_M BIT(0)
+#define E830_GLPTM_ART_CTL_TIME_OUT_M BIT(1)
#define E830_GLPTM_ART_TIME_H 0x00088B54
#define E830_GLPTM_ART_TIME_L 0x00088B58
#define E830_GLTSYN_PTMTIME_H(_i) (0x00088B48 + ((_i) * 4))
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 6848b1c..8b0530b 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2011,6 +2011,7 @@ static int ice_ptp_adjtime(struct ptp_clock_info *info, s64 delta)
* @lock_busy: Bit in the semaphore lock indicating the lock is busy
* @ctl_reg: The hardware register to request cross timestamp
* @ctl_active: Bit in the control register to request cross timestamp
+ * @ctl_timeout: Bits in the control register to indicate HW timeout
* @art_time_l: Lower 32-bits of ART system time
* @art_time_h: Upper 32-bits of ART system time
* @dev_time_l: Lower 32-bits of device time (per timer index)
@@ -2024,6 +2025,7 @@ struct ice_crosststamp_cfg {
/* Capture control register */
u32 ctl_reg;
u32 ctl_active;
+ u32 ctl_timeout;
/* Time storage */
u32 art_time_l;
@@ -2037,6 +2039,7 @@ static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e82x = {
.lock_busy = PFHH_SEM_BUSY_M,
.ctl_reg = GLHH_ART_CTL,
.ctl_active = GLHH_ART_CTL_ACTIVE_M,
+ .ctl_timeout = GLHH_ART_CTL_TIME_OUT1_M | GLHH_ART_CTL_TIME_OUT2_M,
.art_time_l = GLHH_ART_TIME_L,
.art_time_h = GLHH_ART_TIME_H,
.dev_time_l[0] = GLTSYN_HHTIME_L(0),
@@ -2051,6 +2054,7 @@ static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e830 = {
.lock_busy = E830_PFPTM_SEM_BUSY_M,
.ctl_reg = E830_GLPTM_ART_CTL,
.ctl_active = E830_GLPTM_ART_CTL_ACTIVE_M,
+ .ctl_timeout = E830_GLPTM_ART_CTL_TIME_OUT_M,
.art_time_l = E830_GLPTM_ART_TIME_L,
.art_time_h = E830_GLPTM_ART_TIME_H,
.dev_time_l[0] = E830_GLTSYN_PTMTIME_L(0),
@@ -2123,9 +2127,13 @@ static int ice_capture_crosststamp(ktime_t *device,
ctl |= cfg->ctl_active;
wr32(hw, cfg->ctl_reg, ctl);
- /* Poll until hardware completes the capture */
- err = rd32_poll_timeout(hw, cfg->ctl_reg, ctl, !(ctl & cfg->ctl_active),
+ /* Poll until hardware completes the capture or timeout occurs */
+ err = rd32_poll_timeout(hw, cfg->ctl_reg, ctl,
+ !(ctl & cfg->ctl_active) ||
+ (ctl & cfg->ctl_timeout),
5, 20 * USEC_PER_MSEC);
+ if (ctl & cfg->ctl_timeout)
+ err = -ETIMEDOUT;
if (err)
goto err_timeout;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ice: do not reset MDD counters on VF reset
From: Aleksandr Loktionov @ 2026-03-27 7:22 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327072236.129802-1-aleksandr.loktionov@intel.com>
From: Mark Rustad <mark.d.rustad@intel.com>
Do not clear MDD event counters on VF reset, to be consistent with
how VF statistics are not reset either. This allows accumulation of
MDD events across resets so that persistent misbehavior can be
tracked and reported more accurately.
Fixes: 12bb018c538c ("ice: Refactor VF reset")
Signed-off-by: Mark Rustad <mark.d.rustad@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_vf_lib.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 7d33f09..9bcc739 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -227,8 +227,6 @@ static void ice_vf_clear_counters(struct ice_vf *vf)
vf->num_mac = 0;
vf->num_mac_lldp = 0;
- memset(&vf->mdd_tx_events, 0, sizeof(vf->mdd_tx_events));
- memset(&vf->mdd_rx_events, 0, sizeof(vf->mdd_rx_events));
}
/**
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ice: fix FDIR CTRL VSI resource leak in ice_reset_all_vfs()
From: Aleksandr Loktionov @ 2026-03-27 7:22 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Dawid Osuchowski
From: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
Resetting all VFs causes resource leak on VFs with FDIR filters
enabled as CTRL VSIs are only invalidated and not freed. Fix by using
ice_vf_ctrl_vsi_release() instead of ice_vf_ctrl_invalidate_vsi() which
aligns behavior with the ice_reset_vf() function.
Reproduction:
echo 1 > /sys/class/net/$pf/device/sriov_numvfs
ethtool -N $vf flow-type ether proto 0x9000 action 0
echo 1 > /sys/class/net/$pf/device/reset
Fixes: da62c5ff9dcd ("ice: Add support for per VF ctrl VSI enabling")
Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_vf_lib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index c8bc952f..7d33f09 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -801,7 +801,7 @@ void ice_reset_all_vfs(struct ice_pf *pf)
* setup only when VF creates its first FDIR rule.
*/
if (vf->ctrl_vsi_idx != ICE_NO_VSI)
- ice_vf_ctrl_invalidate_vsi(vf);
+ ice_vf_ctrl_vsi_release(vf);
ice_vf_pre_vsi_rebuild(vf);
ice_vf_rebuild_vsi(vf);
--
2.52.0
^ permalink raw reply related
* Re: [PATCH net-next] net/dst: improve dst_ops refcounting with per-dst bit
From: xietangxin @ 2026-03-27 7:05 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet
In-Reply-To: <CANn89iL1cex3LK824Wke0URGqRv+fD16vUdM0y=dvdPgPqgdhA@mail.gmail.com>
On 3/27/2026 11:51 AM, Eric Dumazet wrote:
> On Tue, Mar 24, 2026 at 8:42 PM xietangxin <xietangxin@yeah.net> wrote:
>>
>
>> Hi Eric,
>>
>> I tested your patch with my reproduction script, but the UAF still occurs
>> with a warning in dst_entries_destroy() just before the crash.
>>
>> The reason is that for IPv6, dst_entries on the rt6_uncached_list are
>> handled by rt6_uncached_list_flush_dev() during netns destruction,
>> which bypasses dst_dev_put().
>>
>> I tested add changes like dst_dev_put() inside rt6_uncached_list_flush_dev(),
>> the UAF is gone and the dst_entries_destroy warning no longer appears.
>
>
> Could you share the incremental patch you added on top of mine ?
>
> Thanks.
Hi Eric,
Sure. Here is the incremental patch that I added on top of your patch.
---
diff --git a/include/net/dst.h b/include/net/dst.h
index 793f38452bf4..393cc84b6aa5 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -401,6 +401,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
struct net_device *dev, int initial_obsolete,
unsigned short flags);
void dst_dev_put(struct dst_entry *dst);
+void dst_count_dec(struct dst_entry *dst);
static inline void dst_confirm(struct dst_entry *dst)
{
diff --git a/net/core/dst.c b/net/core/dst.c
index d1efd3e7c44e..b5c5e04e10c1 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -139,7 +139,7 @@ static void dst_destroy_rcu(struct rcu_head *head)
dst_destroy(dst);
}
-static void dst_count_dec(struct dst_entry *dst)
+void dst_count_dec(struct dst_entry *dst)
{
struct dst_ops *ops = READ_ONCE(dst->ops);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 658c0f742e45..9744a8e2fdc8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -173,6 +173,7 @@ static void rt6_uncached_list_flush_dev(struct net_device *dev)
struct inet6_dev *rt_idev = rt->rt6i_idev;
struct net_device *rt_dev = rt->dst.dev;
bool handled = false;
+ struct dst_entry *dst = &rt->dst;
if (rt_idev && rt_idev->dev == dev) {
rt->rt6i_idev = in6_dev_get(blackhole_netdev);
@@ -181,14 +182,16 @@ static void rt6_uncached_list_flush_dev(struct net_device *dev)
}
if (rt_dev == dev) {
- rt->dst.dev = blackhole_netdev;
+ dst->dev = blackhole_netdev;
+ dst_count_dec(dst);
+ WRITE_ONCE(dst->ops, dst->ops->template);
netdev_ref_replace(rt_dev, blackhole_netdev,
- &rt->dst.dev_tracker,
+ &dst->dev_tracker,
GFP_ATOMIC);
handled = true;
}
if (handled)
- list_del_init(&rt->dst.rt_uncached);
+ list_del_init(&dst->rt_uncached);
}
spin_unlock_bh(&ul->lock);
}
--
Best regards,
Tangxin Xie
^ permalink raw reply related
* Re: [PATCH v3 4/7] net/sched: fix packet loop on netem when duplicate is on
From: William Liu @ 2026-03-27 7:00 UTC (permalink / raw)
To: Stephen Hemminger
Cc: netdev, Jamal Hadi Salim, Savino Dicanosa, Victor Nogueira,
Jiri Pirko, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-kernel
In-Reply-To: <20260326181701.308275-5-stephen@networkplumber.org>
Reviewed-by: William Liu <will@willsroot.io>
On Thursday, March 26th, 2026 at 6:17 PM, Stephen Hemminger <stephen@networkplumber.org> wrote:
> From: Jamal Hadi Salim <jhs@mojatatu.com>
>
> When netem duplicates a packet it re-enqueues the copy at the root qdisc.
> If another netem sits in the tree the copy can be duplicated
> again, recursing until the stack or memory is exhausted.
>
> The original duplication guard temporarily zeroed q->duplicate around
> the re-enqueue, but that does not cover all cases because it is
> per-qdisc state shared across all concurrent enqueue paths
> and is not safe without additional locking.
>
> Use the skb tc_depth field introduced in an earlier patch:
> - increment it on the duplicate before re-enqueue
> - skip duplication for any skb whose tc_depth is already non-zero.
>
> This marks the packet itself rather than mutating qdisc state,
> therefore it is safe regardless of tree topology or concurrency.
>
> Fixes: 0afb51e72855 ("[PKT_SCHED]: netem: reinsert for duplication")
> Reported-by: William Liu <will@willsroot.io>
> Reported-by: Savino Dicanosa <savy@syst3mfailure.io>
> Closes: https://lore.kernel.org/netdev/8DuRWwfqjoRDLDmBMlIfbrsZg9Gx50DHJc1ilxsEBNe2D6NMoigR_eIRIG0LOjMc3r10nUUZtArXx4oZBIdUfZQrwjcQhdinnMis_0G7VEk=@willsroot.io/
> Co-developed-by: Victor Nogueira <victor@mojatatu.com>
> Signed-off-by: Victor Nogueira <victor@mojatatu.com>
> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> net/sched/sch_netem.c | 7 +++----
> 1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
> index 0ccf74a9cb82..6086700eb1e7 100644
> --- a/net/sched/sch_netem.c
> +++ b/net/sched/sch_netem.c
> @@ -461,7 +461,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
> skb->prev = NULL;
>
> /* Random duplication */
> - if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng))
> + if (q->duplicate && skb->tc_depth == 0 &&
> + q->duplicate >= get_crandom(&q->dup_cor, &q->prng))
> ++count;
>
> /* Drop packet? */
> @@ -539,11 +540,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
> */
> if (skb2) {
> struct Qdisc *rootq = qdisc_root_bh(sch);
> - u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
>
> - q->duplicate = 0;
> + skb2->tc_depth++; /* prevent duplicating a dup... */
> rootq->enqueue(skb2, rootq, to_free);
> - q->duplicate = dupsave;
> skb2 = NULL;
> }
>
> --
> 2.53.0
>
>
^ permalink raw reply
* [PATCH net v2 3/3] selftests/tc-testing: add tests for cls_fw and cls_flow on shared blocks
From: Xiang Mei @ 2026-03-27 6:55 UTC (permalink / raw)
To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
Xiang Mei
In-Reply-To: <20260327065548.3191115-1-xmei5@asu.edu>
Regression tests for the shared-block NULL derefs fixed in the previous
two patches:
- fw: attach an empty fw filter to a shared block and send traffic.
- flow: create a flow filter on a shared block without a baseclass.
Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
v2: Correct 3/3 selftest case
.../tc-testing/tc-tests/infra/filter.json | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
index 8d10042b489b..b82a48ab9e79 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
@@ -22,5 +22,51 @@
"teardown": [
"$TC qdisc del dev $DUMMY root handle 1: htb default 1"
]
+ },
+ {
+ "id": "b7e3",
+ "name": "Empty fw filter on shared block - no NULL deref in fw_classify",
+ "category": [
+ "filter",
+ "fw"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set lo up",
+ "$TC qdisc add dev lo egress_block 1 clsact",
+ "$TC filter add block 1 protocol ip prio 1 fw"
+ ],
+ "cmdUnderTest": "python3 -c 'import socket; s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.setsockopt(socket.SOL_SOCKET, socket.SO_MARK, 0x10000); s.sendto(b\"A\", (\"127.0.0.1\", 9)); s.close()'",
+ "expExitCode": "0",
+ "verifyCmd": "$TC qdisc show dev lo",
+ "matchPattern": "clsact",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev lo clsact"
+ ]
+ },
+ {
+ "id": "c8f4",
+ "name": "Flow filter on shared block without baseclass - no NULL deref in flow_change",
+ "category": [
+ "filter",
+ "flow"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$TC qdisc add dev $DEV1 ingress_block 1 clsact"
+ ],
+ "cmdUnderTest": "$TC filter add block 1 protocol ip prio 1 handle 1 flow map key dst",
+ "expExitCode": "2",
+ "verifyCmd": "$TC filter show block 1",
+ "matchPattern": "flow",
+ "matchCount": "0",
+ "teardown": [
+ "$TC qdisc del dev $DEV1 clsact"
+ ]
}
]
--
2.43.0
^ permalink raw reply related
* [PATCH net v2 2/3] net/sched: cls_flow: fix NULL pointer dereference on shared blocks
From: Xiang Mei @ 2026-03-27 6:55 UTC (permalink / raw)
To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
Xiang Mei
In-Reply-To: <20260327065548.3191115-1-xmei5@asu.edu>
flow_change() calls tcf_block_q() and dereferences q->handle to derive
a default baseclass. Shared blocks leave block->q NULL, causing a NULL
deref when a flow filter without a fully qualified baseclass is created
on a shared block.
Check tcf_block_shared() before accessing block->q and return -EINVAL
for shared blocks. This avoids the null-deref shown below:
=======================================================================
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
RIP: 0010:flow_change (net/sched/cls_flow.c:508)
Call Trace:
tc_new_tfilter (net/sched/cls_api.c:2432)
rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
[...]
=======================================================================
Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
v2: Correct 3/3 selftest case
net/sched/cls_flow.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 339c664beff6..26077681c9b6 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -503,8 +503,13 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
}
if (TC_H_MAJ(baseclass) == 0) {
- struct Qdisc *q = tcf_block_q(tp->chain->block);
+ struct tcf_block *block = tp->chain->block;
+ struct Qdisc *q;
+ if (tcf_block_shared(block))
+ goto err2;
+
+ q = tcf_block_q(block);
baseclass = TC_H_MAKE(q->handle, baseclass);
}
if (TC_H_MIN(baseclass) == 0)
--
2.43.0
^ permalink raw reply related
* [PATCH net v2 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
From: Xiang Mei @ 2026-03-27 6:55 UTC (permalink / raw)
To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
Xiang Mei
The old-method path in fw_classify() calls tcf_block_q() and
dereferences q->handle. Shared blocks leave block->q NULL, causing a
NULL deref when an empty cls_fw filter is attached to a shared block
and a packet with a nonzero major skb mark is classified.
Check tcf_block_shared() before accessing block->q and return -1 (no
match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
The fixed null-ptr-deref calling stack:
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
Call Trace:
tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
tc_run (net/core/dev.c:4401)
__dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
v2: Correct 3/3 selftest case
net/sched/cls_fw.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index be81c108179d..caf17ab3be87 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -74,9 +74,14 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb,
}
}
} else {
- struct Qdisc *q = tcf_block_q(tp->chain->block);
+ struct tcf_block *block = tp->chain->block;
+ struct Qdisc *q;
+
+ if (tcf_block_shared(block))
+ return -1;
/* Old method: classify the packet using its skb mark. */
+ q = tcf_block_q(block);
if (id && (TC_H_MAJ(id) == 0 ||
!(TC_H_MAJ(id ^ q->handle)))) {
res->classid = id;
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox