* Re: [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
@ 2026-10-14 15:14 ` Stephen Hemminger
2026-10-14 19:42 ` [PATCH 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
` (5 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2026-10-14 15:14 UTC (permalink / raw)
To: Sandeep Penigalapati; +Cc: dev, Gaetan Rivet, stable
On Wed, 14 Oct 2026 19:42:52 +0000
Sandeep Penigalapati <sandeep.penigalapati@intel.com> wrote:
> This series collects fixes for the fail-safe PMD found while testing
> live migration of a VF-backed sub-device (iavf) paired with a virtio-net
> standby sub-device.
>
> - double release of the sub-device port on hot-unplug;
> - NULL queue-release op on sub-devices that do not implement it;
> - MAC address pool size off-by-one and replay of zeroed MAC slots;
> - unsupported link-status control (-ENOTSUP) treated as fatal;
> - sub-device removal not detected without the RMV interrupt (e.g. VFIO
> device release), now handled through a bus device-event callback.
>
>
> Sandeep Penigalapati (5):
> net/failsafe: fix double release of sub-device port
> net/failsafe: fix queue release without sub-device op
> net/failsafe: fix MAC address pool size and replay
> net/failsafe: ignore unsupported link status update
> net/failsafe: detect sub-device removal via device event
>
> drivers/net/failsafe/failsafe_ether.c | 40 ++++++++++--
> drivers/net/failsafe/failsafe_ops.c | 24 ++++++-
> drivers/net/failsafe/failsafe_private.h | 13 ++--
> drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
> 4 files changed, 62 insertions(+), 98 deletions(-)
>
One related failsafe issue is that today tap is carrying some stubs
only because failsafe doesn't handle ENOTSUP
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
@ 2026-10-14 17:10 ` Stephen Hemminger
2026-10-14 22:16 ` [PATCH v2 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2026-10-14 17:10 UTC (permalink / raw)
To: Sandeep Penigalapati; +Cc: dev, Gaetan Rivet, stable
On Wed, 14 Oct 2026 22:15:59 +0000
Sandeep Penigalapati <sandeep.penigalapati@intel.com> wrote:
> This series collects fixes for the fail-safe PMD found while testing
> live migration of a VF-backed sub-device (iavf) paired with a virtio-net
> standby sub-device.
>
> - double release of the sub-device port on hot-unplug;
> - NULL queue-release op on sub-devices that do not implement it;
> - MAC address pool size off-by-one and replay of zeroed MAC slots;
> - unsupported link-status control (-ENOTSUP) treated as fatal;
> - sub-device removal not detected without the RMV interrupt (e.g. VFIO
> device release), now handled through a bus device-event callback.
>
> v2:
> - patch 2/5: add an explicit ETH(sdev) != NULL check before dereferencing
> in fs_rx_queue_release()/fs_tx_queue_release().
> - patch 5/5: clarify in a comment that a secondary process detects the
> removal via the shared sub_device state checked by fs_rx_unsafe()/
> fs_tx_unsafe() in the burst path.
>
>
> Sandeep Penigalapati (5):
> net/failsafe: fix double release of sub-device port
> net/failsafe: fix queue release without sub-device op
> net/failsafe: fix MAC address pool size and replay
> net/failsafe: ignore unsupported link status update
> net/failsafe: detect sub-device removal via device event
>
> drivers/net/failsafe/failsafe_ether.c | 40 ++++++++++--
> drivers/net/failsafe/failsafe_ops.c | 29 ++++++++-
> drivers/net/failsafe/failsafe_private.h | 13 ++--
> drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
> 4 files changed, 67 insertions(+), 98 deletions(-)
>
More detail semi-automated AI review had some good ideas.
Subject: Re: [PATCH v2 0/5] net/failsafe: hotplug fixes
Series applies to main (eb903f407c) and builds per commit with
-Dwerror=true. Patches 3 and 4 are fine. Comments on 1, 2 and 5.
The most important point is in 5/5: the removal of the safe/fast
burst switching is the real fix for the hot-unplug crash, and it is
mixed with a new feature under the wrong rationale and Fixes tag.
[PATCH v2 1/5] net/failsafe: fix double release of sub-device port
Warning: commit message describes the wrong release path.
For a sub-device in DEV_ACTIVE, the first release is done by
rte_eth_dev_close() (it calls rte_eth_dev_release_port() since
fbd1913561 "ethdev: remove old close behaviour"), not by the bus
remove. The bus remove path only owns release when the sub-device was
DEV_PROBED and never configured. The code change is correct for both.
Also say what actually happens: since 36c46e7381 the first release
sets eth_dev->data = NULL, so the second release dereferences NULL in
eth_dev_fp_ops_reset(rte_eth_fp_ops + eth_dev->data->port_id) and
decrements allocated_ports twice.
Suggested body:
The sub-device port is already released before fs_dev_remove()
calls rte_eth_dev_release_port(): by rte_eth_dev_close() for an
active sub-device, or by the driver remove in rte_dev_remove()
for a probed one. The second release dereferences the NULL
eth_dev->data and crashes.
Remove the redundant call.
With the else branch gone the remaining braces can go too:
if (ret < 0)
ERROR("Bus detach failed for sub_device %u",
SUB_ID(sdev));
[PATCH v2 2/5] net/failsafe: fix queue release without sub-device op
Warning: wrong Fixes tag. The unconditional SUBOPS() call is in the
original driver; 7483341ae553 only changed the callback signature.
Fixes: a46f8d584eb8 ("net/failsafe: add fail-safe PMD")
Info: the v2 ETH(sdev) != NULL test is dead code. sdev_port_id is
set at probe and only reset to RTE_MAX_ETHPORTS in fs_dev_remove()
on the way to DEV_UNDEFINED, so ETH(sdev) is never NULL for a
DEV_ACTIVE sub-device. The other FOREACH_SUBDEV_STATE(..., DEV_ACTIVE)
loops in this file do not check it either. Drop it.
[PATCH v2 5/5] net/failsafe: detect sub-device removal via device event
Warning: two unrelated changes with different stable status; split.
(a) Dropping failsafe_set_burst_fn() and the _fast variants is the
actual crash fix, and the commit message gets the reason wrong. It is
not "no longer needed because removal is now reported reliably". Since
c87d435a4d79 ("ethdev: copy fast-path API into separate structure"),
rte_eth_dev_start() copies dev->rx_pkt_burst/tx_pkt_burst into
rte_eth_fp_ops after dev_ops->dev_start returns. fs_dev_start() ->
fs_switch_dev() -> failsafe_set_burst_fn(dev, 0) installs the _fast
variants, which then get copied. The later switch to the safe
variants in failsafe_eth_rmv_event_callback() only writes
dev->rx_pkt_burst, which the data path no longer reads. So after any
removal, RMV interrupt or not, the application keeps calling
failsafe_rx_burst_fast(), which skips fs_rx_unsafe() and dereferences
ETH(sdev) == NULL once the sub-device is gone.
This part should be its own patch:
net/failsafe: fix Rx/Tx burst after sub-device removal
Since burst functions are copied into rte_eth_fp_ops at start,
replacing dev->rx_pkt_burst/tx_pkt_burst afterwards has no
effect. The fast variants installed at start stay in use after
a sub-device is removed and dereference the removed device.
Remove the fast variants and always use the checked burst path.
Fixes: c87d435a4d79 ("ethdev: copy fast-path API into separate structure")
Cc: stable@dpdk.org
(b) Registering a bus device-event callback for sub-devices without
RMV interrupt is new functionality. It cannot fix a46f8d584eb8; the
rte_dev_event API did not exist when fail-safe was added. No Fixes:,
no Cc: stable.
Info: the device event is raised automatically only for VFIO (via
the req notifier). For UIO sub-devices it comes from the uevent
monitor, which the application must start with
rte_dev_event_monitor_start() and rte_dev_hotplug_handle_enable().
Worth one line in the commit message or in fail_safe.rst.
Info: failsafe_dev_event_callback() can call the RMV callback with 0
as port_id; the argument is __rte_unused and PORT_ID() plus the cast
only adds noise:
if (type == RTE_DEV_EVENT_REMOVE)
failsafe_eth_rmv_event_callback(0, RTE_ETH_EVENT_INTR_RMV,
cb_arg, NULL);
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration
@ 2026-10-14 19:42 Sandeep Penigalapati
2026-10-14 15:14 ` Stephen Hemminger
` (6 more replies)
0 siblings, 7 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
This series collects fixes for the fail-safe PMD found while testing
live migration of a VF-backed sub-device (iavf) paired with a virtio-net
standby sub-device.
- double release of the sub-device port on hot-unplug;
- NULL queue-release op on sub-devices that do not implement it;
- MAC address pool size off-by-one and replay of zeroed MAC slots;
- unsupported link-status control (-ENOTSUP) treated as fatal;
- sub-device removal not detected without the RMV interrupt (e.g. VFIO
device release), now handled through a bus device-event callback.
Sandeep Penigalapati (5):
net/failsafe: fix double release of sub-device port
net/failsafe: fix queue release without sub-device op
net/failsafe: fix MAC address pool size and replay
net/failsafe: ignore unsupported link status update
net/failsafe: detect sub-device removal via device event
drivers/net/failsafe/failsafe_ether.c | 40 ++++++++++--
drivers/net/failsafe/failsafe_ops.c | 24 ++++++-
drivers/net/failsafe/failsafe_private.h | 13 ++--
drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
4 files changed, 62 insertions(+), 98 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/5] net/failsafe: fix double release of sub-device port
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 15:14 ` Stephen Hemminger
@ 2026-10-14 19:42 ` Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
` (4 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
When a sub-device is removed, fs_dev_remove() detaches the underlying
bus device, and that remove path already releases the ethdev port of
the sub-device. The fail-safe code then called
rte_eth_dev_release_port() a second time on the same port, resulting in
a double release of the port during hot-unplug.
Drop the redundant rte_eth_dev_release_port() call and let the bus
remove path own the release of the port.
Fixes: fac0ae546e5f ("net/failsafe: free port by dedicated function")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index f0fd662c7b..4eaa337f55 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -301,8 +301,6 @@ fs_dev_remove(struct sub_device *sdev)
if (ret < 0) {
ERROR("Bus detach failed for sub_device %u",
SUB_ID(sdev));
- } else {
- rte_eth_dev_release_port(ETH(sdev));
}
sdev->state = DEV_PARSED;
/* fallthrough */
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/5] net/failsafe: fix queue release without sub-device op
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 15:14 ` Stephen Hemminger
2026-10-14 19:42 ` [PATCH 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
@ 2026-10-14 19:42 ` Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
` (3 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
fs_rx_queue_release() and fs_tx_queue_release() iterate over the active
sub-devices and call the sub-device Rx/Tx queue release op directly.
Some PMDs do not implement that op, so the function pointer is NULL.
Calling it unconditionally could dereference a NULL pointer and crash
when releasing fail-safe queues.
Check that the sub-device provides the release op before calling it.
Fixes: 7483341ae553 ("ethdev: change queue release callback")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ops.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 8761cb07c3..79aa57cb35 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -398,7 +398,8 @@ fs_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
if (rxq->event_fd >= 0)
close(rxq->event_fd);
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
- if (ETH(sdev)->data->rx_queues != NULL &&
+ if (SUBOPS(sdev, rx_queue_release) != NULL &&
+ ETH(sdev)->data->rx_queues != NULL &&
ETH(sdev)->data->rx_queues[rxq->qid] != NULL)
SUBOPS(sdev, rx_queue_release)(ETH(sdev), rxq->qid);
}
@@ -574,7 +575,8 @@ fs_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
if (fs_lock(dev, 0) != 0)
return;
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
- if (ETH(sdev)->data->tx_queues != NULL &&
+ if (SUBOPS(sdev, tx_queue_release) != NULL &&
+ ETH(sdev)->data->tx_queues != NULL &&
ETH(sdev)->data->tx_queues[txq->qid] != NULL)
SUBOPS(sdev, tx_queue_release)(ETH(sdev), txq->qid);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/5] net/failsafe: fix MAC address pool size and replay
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (2 preceding siblings ...)
2026-10-14 19:42 ` [PATCH 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
@ 2026-10-14 19:42 ` Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
` (2 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
Two issues affect fail-safe MAC address handling:
- fs_mac_addr_add() grew the pool but set nb_mac_addr to the index of
the new entry instead of the entry count (index + 1). The pool size
was off by one and the last added address was dropped when the
configuration was replayed to a sub-device.
- fs_eth_dev_conf_apply() replayed every slot of the MAC address array
to a (re)plugged sub-device, including slots left zeroed by a
previous remove, which made rte_eth_dev_mac_addr_add() fail on the
all-zero address.
Set nb_mac_addr to index + 1 and skip zeroed slots when replaying the
MAC addresses.
Fixes: a46f8d584eb8 ("net/failsafe: add fail-safe PMD")
Fixes: ebea83f899d8 ("net/failsafe: add plug-in support")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 3 +++
drivers/net/failsafe/failsafe_ops.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 4eaa337f55..ea12e2722f 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -177,6 +177,9 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
struct rte_ether_addr *ea;
ea = &dev->data->mac_addrs[i];
+ /* Removed addresses leave a zeroed slot. */
+ if (rte_is_zero_ether_addr(ea))
+ continue;
ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
PRIV(dev)->mac_addr_pool[i]);
if (ret) {
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 79aa57cb35..56c7c884a1 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -1460,7 +1460,7 @@ fs_mac_addr_add(struct rte_eth_dev *dev,
}
if (index >= PRIV(dev)->nb_mac_addr) {
DEBUG("Growing mac_addrs array");
- PRIV(dev)->nb_mac_addr = index;
+ PRIV(dev)->nb_mac_addr = index + 1;
}
PRIV(dev)->mac_addr_pool[index] = vmdq;
fs_unlock(dev, 0);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/5] net/failsafe: ignore unsupported link status update
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (3 preceding siblings ...)
2026-10-14 19:42 ` [PATCH 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
@ 2026-10-14 19:42 ` Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
6 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
When applying the configuration to a sub-device,
fs_eth_dev_conf_apply() forces the link up or down with
rte_eth_dev_set_link_up()/rte_eth_dev_set_link_down(). Sub-devices such
as virtio-net do not support software link control and return -ENOTSUP,
which fail-safe treated as a fatal error and aborted the configuration
apply, preventing plug-in of such sub-devices.
Treat -ENOTSUP from the link control as success; the sub-device link
simply follows its physical state.
Fixes: ebea83f899d8 ("net/failsafe: add plug-in support")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index ea12e2722f..f23580ed37 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -115,7 +115,11 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
else
ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
- if (ret) {
+ if (ret == -ENOTSUP) {
+ /* The sub-device link follows its physical state. */
+ DEBUG("link_status control not supported");
+ ret = 0;
+ } else if (ret) {
ERROR("Failed to apply link_status");
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/5] net/failsafe: detect sub-device removal via device event
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (4 preceding siblings ...)
2026-10-14 19:42 ` [PATCH 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
@ 2026-10-14 19:42 ` Sandeep Penigalapati
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
6 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 19:42 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, stable, Sandeep Penigalapati
Fail-safe relied on the removal (RMV) interrupt and on swapping the
Rx/Tx burst functions to "safe" variants to cope with a disappearing
sub-device. When a sub-device does not support the RMV interrupt (for
example a VFIO device whose removal is only reported by the bus as a
device event on the release request), the removal was not detected:
the burst functions kept polling the gone device and traffic was not
failed over to the other sub-device.
Register a bus device-event callback for sub-devices without RMV
interrupt support and run the existing removal handling from it. The
callback is registered and unregistered by the primary process only:
struct sub_device lives in shared memory, so in a secondary process the
registration flag would read as set and sdev->dev would point into the
primary address space; dereferencing it would crash.
With removal now reported reliably, the per-burst safe/fast function
switching is no longer needed; drop failsafe_set_burst_fn() and the
_fast burst variants and keep a single burst path guarded by an
unlikely() check.
Fixes: a46f8d584eb8 ("net/failsafe: add fail-safe PMD")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 29 ++++++++-
drivers/net/failsafe/failsafe_ops.c | 16 +++++
drivers/net/failsafe/failsafe_private.h | 13 ++--
drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
4 files changed, 49 insertions(+), 92 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index f23580ed37..2a15eb4da5 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -386,6 +386,22 @@ failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev)
" %d", SUB_ID(sdev));
sdev->lsc_callback = 0;
}
+ /*
+ * The bus device-event callback is registered by the primary only
+ * (hotplug is handled there). sub_device is shared memory, so in a
+ * secondary the flag reads as set and sdev->dev holds the primary's
+ * pointer; dereferencing it (rte_dev_name) would crash. Skip it.
+ */
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+ sdev->dev_event_callback) {
+ ret = rte_dev_event_callback_unregister(rte_dev_name(sdev->dev),
+ failsafe_dev_event_callback,
+ sdev);
+ if (ret < 0)
+ WARN("Failed to unregister device event callback for"
+ " sub_device %d", SUB_ID(sdev));
+ sdev->dev_event_callback = 0;
+ }
}
void
@@ -592,8 +608,6 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
return -1;
/* Switch as soon as possible tx_dev. */
fs_switch_dev(fs_dev(sdev), sdev);
- /* Use safe bursts in any case. */
- failsafe_set_burst_fn(fs_dev(sdev), 1);
/*
* Async removal, the sub-PMD will try to unregister
* the callback at the source of the current thread context.
@@ -603,6 +617,17 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
return 0;
}
+void
+failsafe_dev_event_callback(const char *device_name __rte_unused,
+ enum rte_dev_event_type type,
+ void *cb_arg)
+{
+ if (type != RTE_DEV_EVENT_REMOVE)
+ return;
+ failsafe_eth_rmv_event_callback(PORT_ID((struct sub_device *)cb_arg),
+ RTE_ETH_EVENT_INTR_RMV, cb_arg, NULL);
+}
+
int
failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
enum rte_eth_event_type event __rte_unused,
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 56c7c884a1..4916d25d8b 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -82,6 +82,22 @@ fs_dev_configure(struct rte_eth_dev *dev)
else
sdev->rmv_callback = 1;
}
+ /*
+ * Without RMV interrupts, a hot-unplug is only reported by the
+ * bus (e.g. a VFIO device release request) as a device event.
+ */
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+ !rmv_interrupt && sdev->dev != NULL &&
+ sdev->dev_event_callback == 0) {
+ ret = rte_dev_event_callback_register(rte_dev_name(sdev->dev),
+ failsafe_dev_event_callback,
+ sdev);
+ if (ret)
+ WARN("Failed to register device event callback for sub_device %d",
+ SUB_ID(sdev));
+ else
+ sdev->dev_event_callback = 1;
+ }
dev->data->dev_conf.intr_conf.rmv = 0;
if (lsc_interrupt && sdev->lsc_callback == 0) {
ret = rte_eth_dev_callback_register(PORT_ID(sdev),
diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h
index aae091e792..a565ee2fbc 100644
--- a/drivers/net/failsafe/failsafe_private.h
+++ b/drivers/net/failsafe/failsafe_private.h
@@ -138,6 +138,8 @@ struct sub_device {
unsigned int rmv_callback:1;
/* LSC callback registration state */
unsigned int lsc_callback:1;
+ /* Bus device event (removal) callback registration state */
+ unsigned int dev_event_callback:1;
};
/*
@@ -208,18 +210,11 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
/* RX / TX */
-void failsafe_set_burst_fn(struct rte_eth_dev *dev, int force_safe);
-
uint16_t failsafe_rx_burst(void *rxq,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
uint16_t failsafe_tx_burst(void *txq,
struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
-uint16_t failsafe_rx_burst_fast(void *rxq,
- struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
-uint16_t failsafe_tx_burst_fast(void *txq,
- struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
-
/* ARGS */
int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -246,6 +241,9 @@ int failsafe_eth_rmv_event_callback(uint16_t port_id,
int failsafe_eth_lsc_event_callback(uint16_t port_id,
enum rte_eth_event_type event,
void *cb_arg, void *out);
+void failsafe_dev_event_callback(const char *device_name,
+ enum rte_dev_event_type type,
+ void *cb_arg);
int failsafe_eth_new_event_callback(uint16_t port_id,
enum rte_eth_event_type event,
void *cb_arg, void *out);
@@ -487,7 +485,6 @@ fs_switch_dev(struct rte_eth_dev *dev,
} else {
return;
}
- failsafe_set_burst_fn(dev, 0);
rte_wmb();
}
diff --git a/drivers/net/failsafe/failsafe_rxtx.c b/drivers/net/failsafe/failsafe_rxtx.c
index 500483bda3..8d53d9dd40 100644
--- a/drivers/net/failsafe/failsafe_rxtx.c
+++ b/drivers/net/failsafe/failsafe_rxtx.c
@@ -28,39 +28,6 @@ fs_tx_unsafe(struct sub_device *sdev)
(sdev->state != DEV_STARTED);
}
-void
-failsafe_set_burst_fn(struct rte_eth_dev *dev, int force_safe)
-{
- struct sub_device *sdev;
- uint8_t i;
- int need_safe;
- int safe_set;
-
- need_safe = force_safe;
- FOREACH_SUBDEV(sdev, i, dev)
- need_safe |= fs_rx_unsafe(sdev);
- safe_set = (dev->rx_pkt_burst == &failsafe_rx_burst);
- if (need_safe && !safe_set) {
- DEBUG("Using safe RX bursts%s",
- (force_safe ? " (forced)" : ""));
- dev->rx_pkt_burst = &failsafe_rx_burst;
- } else if (!need_safe && safe_set) {
- DEBUG("Using fast RX bursts");
- dev->rx_pkt_burst = &failsafe_rx_burst_fast;
- }
- need_safe = force_safe || fs_tx_unsafe(TX_SUBDEV(dev));
- safe_set = (dev->tx_pkt_burst == &failsafe_tx_burst);
- if (need_safe && !safe_set) {
- DEBUG("Using safe TX bursts%s",
- (force_safe ? " (forced)" : ""));
- dev->tx_pkt_burst = &failsafe_tx_burst;
- } else if (!need_safe && safe_set) {
- DEBUG("Using fast TX bursts");
- dev->tx_pkt_burst = &failsafe_tx_burst_fast;
- }
- rte_wmb();
-}
-
/*
* Override source port in Rx packets.
*
@@ -89,7 +56,7 @@ failsafe_rx_burst(void *queue,
rxq = queue;
sdev = rxq->sdev;
do {
- if (fs_rx_unsafe(sdev)) {
+ if (unlikely(fs_rx_unsafe(sdev))) {
nb_rx = 0;
sdev = sdev->next;
continue;
@@ -108,34 +75,6 @@ failsafe_rx_burst(void *queue,
return nb_rx;
}
-uint16_t
-failsafe_rx_burst_fast(void *queue,
- struct rte_mbuf **rx_pkts,
- uint16_t nb_pkts)
-{
- struct sub_device *sdev;
- struct rxq *rxq;
- void *sub_rxq;
- uint16_t nb_rx;
-
- rxq = queue;
- sdev = rxq->sdev;
- do {
- RTE_ASSERT(!fs_rx_unsafe(sdev));
- sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
- FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
- nb_rx = ETH(sdev)->
- rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
- FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
- sdev = sdev->next;
- } while (nb_rx == 0 && sdev != rxq->sdev);
- rxq->sdev = sdev;
- if (nb_rx)
- failsafe_rx_set_port(rx_pkts, nb_rx,
- rxq->priv->data->port_id);
- return nb_rx;
-}
-
uint16_t
failsafe_tx_burst(void *queue,
struct rte_mbuf **tx_pkts,
@@ -156,23 +95,3 @@ failsafe_tx_burst(void *queue,
FS_ATOMIC_V(txq->refcnt[sdev->sid]);
return nb_tx;
}
-
-uint16_t
-failsafe_tx_burst_fast(void *queue,
- struct rte_mbuf **tx_pkts,
- uint16_t nb_pkts)
-{
- struct sub_device *sdev;
- struct txq *txq;
- void *sub_txq;
- uint16_t nb_tx;
-
- txq = queue;
- sdev = TX_SUBDEV(&rte_eth_devices[txq->priv->data->port_id]);
- RTE_ASSERT(!fs_tx_unsafe(sdev));
- sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
- FS_ATOMIC_P(txq->refcnt[sdev->sid]);
- nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
- FS_ATOMIC_V(txq->refcnt[sdev->sid]);
- return nb_tx;
-}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (5 preceding siblings ...)
2026-10-14 19:42 ` [PATCH 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
@ 2026-10-14 22:15 ` Sandeep Penigalapati
2026-10-14 17:10 ` Stephen Hemminger
` (5 more replies)
6 siblings, 6 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:15 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
This series collects fixes for the fail-safe PMD found while testing
live migration of a VF-backed sub-device (iavf) paired with a virtio-net
standby sub-device.
- double release of the sub-device port on hot-unplug;
- NULL queue-release op on sub-devices that do not implement it;
- MAC address pool size off-by-one and replay of zeroed MAC slots;
- unsupported link-status control (-ENOTSUP) treated as fatal;
- sub-device removal not detected without the RMV interrupt (e.g. VFIO
device release), now handled through a bus device-event callback.
v2:
- patch 2/5: add an explicit ETH(sdev) != NULL check before dereferencing
in fs_rx_queue_release()/fs_tx_queue_release().
- patch 5/5: clarify in a comment that a secondary process detects the
removal via the shared sub_device state checked by fs_rx_unsafe()/
fs_tx_unsafe() in the burst path.
Sandeep Penigalapati (5):
net/failsafe: fix double release of sub-device port
net/failsafe: fix queue release without sub-device op
net/failsafe: fix MAC address pool size and replay
net/failsafe: ignore unsupported link status update
net/failsafe: detect sub-device removal via device event
drivers/net/failsafe/failsafe_ether.c | 40 ++++++++++--
drivers/net/failsafe/failsafe_ops.c | 29 ++++++++-
drivers/net/failsafe/failsafe_private.h | 13 ++--
drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
4 files changed, 67 insertions(+), 98 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/5] net/failsafe: fix double release of sub-device port
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 17:10 ` Stephen Hemminger
@ 2026-10-14 22:16 ` Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
` (3 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:16 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
When a sub-device is removed, fs_dev_remove() detaches the underlying
bus device, and that remove path already releases the ethdev port of
the sub-device. The fail-safe code then called
rte_eth_dev_release_port() a second time on the same port, resulting in
a double release of the port during hot-unplug.
Drop the redundant rte_eth_dev_release_port() call and let the bus
remove path own the release of the port.
Fixes: fac0ae546e5f ("net/failsafe: free port by dedicated function")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index f0fd662c7b..4eaa337f55 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -301,8 +301,6 @@ fs_dev_remove(struct sub_device *sdev)
if (ret < 0) {
ERROR("Bus detach failed for sub_device %u",
SUB_ID(sdev));
- } else {
- rte_eth_dev_release_port(ETH(sdev));
}
sdev->state = DEV_PARSED;
/* fallthrough */
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] net/failsafe: fix queue release without sub-device op
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 17:10 ` Stephen Hemminger
2026-10-14 22:16 ` [PATCH v2 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
@ 2026-10-14 22:16 ` Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
` (2 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:16 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
fs_rx_queue_release() and fs_tx_queue_release() iterate over the active
sub-devices and call the sub-device Rx/Tx queue release op directly.
Some PMDs do not implement that op, so the function pointer is NULL.
Calling it unconditionally could dereference a NULL pointer and crash
when releasing fail-safe queues.
Check that the sub-device provides the release op before calling it.
Fixes: 7483341ae553 ("ethdev: change queue release callback")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
v2:
- Add explicit ETH(sdev) != NULL check before dereferencing.
drivers/net/failsafe/failsafe_ops.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 8761cb07c3..0b025bd122 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -398,7 +398,9 @@ fs_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
if (rxq->event_fd >= 0)
close(rxq->event_fd);
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
- if (ETH(sdev)->data->rx_queues != NULL &&
+ if (ETH(sdev) != NULL &&
+ SUBOPS(sdev, rx_queue_release) != NULL &&
+ ETH(sdev)->data->rx_queues != NULL &&
ETH(sdev)->data->rx_queues[rxq->qid] != NULL)
SUBOPS(sdev, rx_queue_release)(ETH(sdev), rxq->qid);
}
@@ -574,7 +576,9 @@ fs_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
if (fs_lock(dev, 0) != 0)
return;
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
- if (ETH(sdev)->data->tx_queues != NULL &&
+ if (ETH(sdev) != NULL &&
+ SUBOPS(sdev, tx_queue_release) != NULL &&
+ ETH(sdev)->data->tx_queues != NULL &&
ETH(sdev)->data->tx_queues[txq->qid] != NULL)
SUBOPS(sdev, tx_queue_release)(ETH(sdev), txq->qid);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] net/failsafe: fix MAC address pool size and replay
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (2 preceding siblings ...)
2026-10-14 22:16 ` [PATCH v2 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
@ 2026-10-14 22:16 ` Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
5 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:16 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
Two issues affect fail-safe MAC address handling:
- fs_mac_addr_add() grew the pool but set nb_mac_addr to the index of
the new entry instead of the entry count (index + 1). The pool size
was off by one and the last added address was dropped when the
configuration was replayed to a sub-device.
- fs_eth_dev_conf_apply() replayed every slot of the MAC address array
to a (re)plugged sub-device, including slots left zeroed by a
previous remove, which made rte_eth_dev_mac_addr_add() fail on the
all-zero address.
Set nb_mac_addr to index + 1 and skip zeroed slots when replaying the
MAC addresses.
Fixes: a46f8d584eb8 ("net/failsafe: add fail-safe PMD")
Fixes: ebea83f899d8 ("net/failsafe: add plug-in support")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 3 +++
drivers/net/failsafe/failsafe_ops.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 4eaa337f55..ea12e2722f 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -177,6 +177,9 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
struct rte_ether_addr *ea;
ea = &dev->data->mac_addrs[i];
+ /* Removed addresses leave a zeroed slot. */
+ if (rte_is_zero_ether_addr(ea))
+ continue;
ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
PRIV(dev)->mac_addr_pool[i]);
if (ret) {
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 0b025bd122..f0c12dfaa3 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -1462,7 +1462,7 @@ fs_mac_addr_add(struct rte_eth_dev *dev,
}
if (index >= PRIV(dev)->nb_mac_addr) {
DEBUG("Growing mac_addrs array");
- PRIV(dev)->nb_mac_addr = index;
+ PRIV(dev)->nb_mac_addr = index + 1;
}
PRIV(dev)->mac_addr_pool[index] = vmdq;
fs_unlock(dev, 0);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/5] net/failsafe: ignore unsupported link status update
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (3 preceding siblings ...)
2026-10-14 22:16 ` [PATCH v2 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
@ 2026-10-14 22:16 ` Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
5 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:16 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
When applying the configuration to a sub-device,
fs_eth_dev_conf_apply() forces the link up or down with
rte_eth_dev_set_link_up()/rte_eth_dev_set_link_down(). Sub-devices such
as virtio-net do not support software link control and return -ENOTSUP,
which fail-safe treated as a fatal error and aborted the configuration
apply, preventing plug-in of such sub-devices.
Treat -ENOTSUP from the link control as success; the sub-device link
simply follows its physical state.
Fixes: ebea83f899d8 ("net/failsafe: add plug-in support")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
drivers/net/failsafe/failsafe_ether.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index ea12e2722f..f23580ed37 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -115,7 +115,11 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
else
ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
- if (ret) {
+ if (ret == -ENOTSUP) {
+ /* The sub-device link follows its physical state. */
+ DEBUG("link_status control not supported");
+ ret = 0;
+ } else if (ret) {
ERROR("Failed to apply link_status");
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 5/5] net/failsafe: detect sub-device removal via device event
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
` (4 preceding siblings ...)
2026-10-14 22:16 ` [PATCH v2 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
@ 2026-10-14 22:16 ` Sandeep Penigalapati
5 siblings, 0 replies; 14+ messages in thread
From: Sandeep Penigalapati @ 2026-10-14 22:16 UTC (permalink / raw)
To: dev; +Cc: Gaetan Rivet, Stephen Hemminger, stable, Sandeep Penigalapati
Fail-safe relied on the removal (RMV) interrupt and on swapping the
Rx/Tx burst functions to "safe" variants to cope with a disappearing
sub-device. When a sub-device does not support the RMV interrupt (for
example a VFIO device whose removal is only reported by the bus as a
device event on the release request), the removal was not detected:
the burst functions kept polling the gone device and traffic was not
failed over to the other sub-device.
Register a bus device-event callback for sub-devices without RMV
interrupt support and run the existing removal handling from it. The
callback is registered and unregistered by the primary process only:
struct sub_device lives in shared memory, so in a secondary process the
registration flag would read as set and sdev->dev would point into the
primary address space; dereferencing it would crash.
With removal now reported reliably, the per-burst safe/fast function
switching is no longer needed; drop failsafe_set_burst_fn() and the
_fast burst variants and keep a single burst path guarded by an
unlikely() check.
Fixes: a46f8d584eb8 ("net/failsafe: add fail-safe PMD")
Cc: stable@dpdk.org
Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
---
v2:
- Clarify in a comment that a secondary detects removal via the shared
sub_device state checked by fs_rx_unsafe()/fs_tx_unsafe().
drivers/net/failsafe/failsafe_ether.c | 29 ++++++++-
drivers/net/failsafe/failsafe_ops.c | 19 ++++++
drivers/net/failsafe/failsafe_private.h | 13 ++--
drivers/net/failsafe/failsafe_rxtx.c | 83 +------------------------
4 files changed, 52 insertions(+), 92 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index f23580ed37..2a15eb4da5 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -386,6 +386,22 @@ failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev)
" %d", SUB_ID(sdev));
sdev->lsc_callback = 0;
}
+ /*
+ * The bus device-event callback is registered by the primary only
+ * (hotplug is handled there). sub_device is shared memory, so in a
+ * secondary the flag reads as set and sdev->dev holds the primary's
+ * pointer; dereferencing it (rte_dev_name) would crash. Skip it.
+ */
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+ sdev->dev_event_callback) {
+ ret = rte_dev_event_callback_unregister(rte_dev_name(sdev->dev),
+ failsafe_dev_event_callback,
+ sdev);
+ if (ret < 0)
+ WARN("Failed to unregister device event callback for"
+ " sub_device %d", SUB_ID(sdev));
+ sdev->dev_event_callback = 0;
+ }
}
void
@@ -592,8 +608,6 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
return -1;
/* Switch as soon as possible tx_dev. */
fs_switch_dev(fs_dev(sdev), sdev);
- /* Use safe bursts in any case. */
- failsafe_set_burst_fn(fs_dev(sdev), 1);
/*
* Async removal, the sub-PMD will try to unregister
* the callback at the source of the current thread context.
@@ -603,6 +617,17 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
return 0;
}
+void
+failsafe_dev_event_callback(const char *device_name __rte_unused,
+ enum rte_dev_event_type type,
+ void *cb_arg)
+{
+ if (type != RTE_DEV_EVENT_REMOVE)
+ return;
+ failsafe_eth_rmv_event_callback(PORT_ID((struct sub_device *)cb_arg),
+ RTE_ETH_EVENT_INTR_RMV, cb_arg, NULL);
+}
+
int
failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
enum rte_eth_event_type event __rte_unused,
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index f0c12dfaa3..d5b49a39c2 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -82,6 +82,25 @@ fs_dev_configure(struct rte_eth_dev *dev)
else
sdev->rmv_callback = 1;
}
+ /*
+ * Without RMV interrupts, a hot-unplug is only reported by the
+ * bus (e.g. a VFIO device release request) as a device event.
+ * Only the primary registers for it; a secondary learns of the
+ * removal through the shared sub_device state checked by
+ * fs_rx_unsafe()/fs_tx_unsafe() on every burst.
+ */
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+ !rmv_interrupt && sdev->dev != NULL &&
+ sdev->dev_event_callback == 0) {
+ ret = rte_dev_event_callback_register(rte_dev_name(sdev->dev),
+ failsafe_dev_event_callback,
+ sdev);
+ if (ret)
+ WARN("Failed to register device event callback for sub_device %d",
+ SUB_ID(sdev));
+ else
+ sdev->dev_event_callback = 1;
+ }
dev->data->dev_conf.intr_conf.rmv = 0;
if (lsc_interrupt && sdev->lsc_callback == 0) {
ret = rte_eth_dev_callback_register(PORT_ID(sdev),
diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h
index aae091e792..a565ee2fbc 100644
--- a/drivers/net/failsafe/failsafe_private.h
+++ b/drivers/net/failsafe/failsafe_private.h
@@ -138,6 +138,8 @@ struct sub_device {
unsigned int rmv_callback:1;
/* LSC callback registration state */
unsigned int lsc_callback:1;
+ /* Bus device event (removal) callback registration state */
+ unsigned int dev_event_callback:1;
};
/*
@@ -208,18 +210,11 @@ int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev);
/* RX / TX */
-void failsafe_set_burst_fn(struct rte_eth_dev *dev, int force_safe);
-
uint16_t failsafe_rx_burst(void *rxq,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
uint16_t failsafe_tx_burst(void *txq,
struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
-uint16_t failsafe_rx_burst_fast(void *rxq,
- struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
-uint16_t failsafe_tx_burst_fast(void *txq,
- struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
-
/* ARGS */
int failsafe_args_parse(struct rte_eth_dev *dev, const char *params);
@@ -246,6 +241,9 @@ int failsafe_eth_rmv_event_callback(uint16_t port_id,
int failsafe_eth_lsc_event_callback(uint16_t port_id,
enum rte_eth_event_type event,
void *cb_arg, void *out);
+void failsafe_dev_event_callback(const char *device_name,
+ enum rte_dev_event_type type,
+ void *cb_arg);
int failsafe_eth_new_event_callback(uint16_t port_id,
enum rte_eth_event_type event,
void *cb_arg, void *out);
@@ -487,7 +485,6 @@ fs_switch_dev(struct rte_eth_dev *dev,
} else {
return;
}
- failsafe_set_burst_fn(dev, 0);
rte_wmb();
}
diff --git a/drivers/net/failsafe/failsafe_rxtx.c b/drivers/net/failsafe/failsafe_rxtx.c
index 500483bda3..8d53d9dd40 100644
--- a/drivers/net/failsafe/failsafe_rxtx.c
+++ b/drivers/net/failsafe/failsafe_rxtx.c
@@ -28,39 +28,6 @@ fs_tx_unsafe(struct sub_device *sdev)
(sdev->state != DEV_STARTED);
}
-void
-failsafe_set_burst_fn(struct rte_eth_dev *dev, int force_safe)
-{
- struct sub_device *sdev;
- uint8_t i;
- int need_safe;
- int safe_set;
-
- need_safe = force_safe;
- FOREACH_SUBDEV(sdev, i, dev)
- need_safe |= fs_rx_unsafe(sdev);
- safe_set = (dev->rx_pkt_burst == &failsafe_rx_burst);
- if (need_safe && !safe_set) {
- DEBUG("Using safe RX bursts%s",
- (force_safe ? " (forced)" : ""));
- dev->rx_pkt_burst = &failsafe_rx_burst;
- } else if (!need_safe && safe_set) {
- DEBUG("Using fast RX bursts");
- dev->rx_pkt_burst = &failsafe_rx_burst_fast;
- }
- need_safe = force_safe || fs_tx_unsafe(TX_SUBDEV(dev));
- safe_set = (dev->tx_pkt_burst == &failsafe_tx_burst);
- if (need_safe && !safe_set) {
- DEBUG("Using safe TX bursts%s",
- (force_safe ? " (forced)" : ""));
- dev->tx_pkt_burst = &failsafe_tx_burst;
- } else if (!need_safe && safe_set) {
- DEBUG("Using fast TX bursts");
- dev->tx_pkt_burst = &failsafe_tx_burst_fast;
- }
- rte_wmb();
-}
-
/*
* Override source port in Rx packets.
*
@@ -89,7 +56,7 @@ failsafe_rx_burst(void *queue,
rxq = queue;
sdev = rxq->sdev;
do {
- if (fs_rx_unsafe(sdev)) {
+ if (unlikely(fs_rx_unsafe(sdev))) {
nb_rx = 0;
sdev = sdev->next;
continue;
@@ -108,34 +75,6 @@ failsafe_rx_burst(void *queue,
return nb_rx;
}
-uint16_t
-failsafe_rx_burst_fast(void *queue,
- struct rte_mbuf **rx_pkts,
- uint16_t nb_pkts)
-{
- struct sub_device *sdev;
- struct rxq *rxq;
- void *sub_rxq;
- uint16_t nb_rx;
-
- rxq = queue;
- sdev = rxq->sdev;
- do {
- RTE_ASSERT(!fs_rx_unsafe(sdev));
- sub_rxq = ETH(sdev)->data->rx_queues[rxq->qid];
- FS_ATOMIC_P(rxq->refcnt[sdev->sid]);
- nb_rx = ETH(sdev)->
- rx_pkt_burst(sub_rxq, rx_pkts, nb_pkts);
- FS_ATOMIC_V(rxq->refcnt[sdev->sid]);
- sdev = sdev->next;
- } while (nb_rx == 0 && sdev != rxq->sdev);
- rxq->sdev = sdev;
- if (nb_rx)
- failsafe_rx_set_port(rx_pkts, nb_rx,
- rxq->priv->data->port_id);
- return nb_rx;
-}
-
uint16_t
failsafe_tx_burst(void *queue,
struct rte_mbuf **tx_pkts,
@@ -156,23 +95,3 @@ failsafe_tx_burst(void *queue,
FS_ATOMIC_V(txq->refcnt[sdev->sid]);
return nb_tx;
}
-
-uint16_t
-failsafe_tx_burst_fast(void *queue,
- struct rte_mbuf **tx_pkts,
- uint16_t nb_pkts)
-{
- struct sub_device *sdev;
- struct txq *txq;
- void *sub_txq;
- uint16_t nb_tx;
-
- txq = queue;
- sdev = TX_SUBDEV(&rte_eth_devices[txq->priv->data->port_id]);
- RTE_ASSERT(!fs_tx_unsafe(sdev));
- sub_txq = ETH(sdev)->data->tx_queues[txq->qid];
- FS_ATOMIC_P(txq->refcnt[sdev->sid]);
- nb_tx = ETH(sdev)->tx_pkt_burst(sub_txq, tx_pkts, nb_pkts);
- FS_ATOMIC_V(txq->refcnt[sdev->sid]);
- return nb_tx;
-}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-10-14 17:10 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 19:42 [PATCH 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 15:14 ` Stephen Hemminger
2026-10-14 19:42 ` [PATCH 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
2026-10-14 19:42 ` [PATCH 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
2026-10-14 22:15 ` [PATCH v2 0/5] net/failsafe: fixes for sub-device removal and configuration Sandeep Penigalapati
2026-10-14 17:10 ` Stephen Hemminger
2026-10-14 22:16 ` [PATCH v2 1/5] net/failsafe: fix double release of sub-device port Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 2/5] net/failsafe: fix queue release without sub-device op Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 3/5] net/failsafe: fix MAC address pool size and replay Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 4/5] net/failsafe: ignore unsupported link status update Sandeep Penigalapati
2026-10-14 22:16 ` [PATCH v2 5/5] net/failsafe: detect sub-device removal via device event Sandeep Penigalapati
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.