* [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* 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
* [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
* 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 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 a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox