* [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 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.