Add a PF-level "x-vf-migration" boolean property (default off) that,
when enabled, causes each emulated VF to advertise a vendor-specific
PCI capability in its config space. The variant driver igb-vfio-pci
probes for this capability at bind time and uses its presence to
enable migration support.

The capability is a 16-byte vendor-specific capability (PCI_CAP_ID_VNDR)
containing a magic value ("MIGB"), the BAR index where the migration
region will be mapped, and feature flags indicating which migration
features are supported.

Assisted-by: Claude
Suggested-by: Alex Williamson <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
 MAINTAINERS                           |  6 +++
 docs/system/device-emulation.rst      |  1 +
 docs/system/devices/igb-migration.rst | 20 ++++++++
 docs/system/devices/igb.rst           |  6 +++
 hw/net/igb_migration.h                | 43 ++++++++++++++++
 hw/net/igb.c                          | 12 +++++
 hw/net/igb_migration.c                | 72 +++++++++++++++++++++++++++
 hw/net/igbvf.c                        | 11 ++++
 hw/net/meson.build                    |  2 +-
 hw/net/trace-events                   |  1 +
 10 files changed, 173 insertions(+), 1 deletion(-)
 create mode 100644 docs/system/devices/igb-migration.rst
 create mode 100644 hw/net/igb_migration.h
 create mode 100644 hw/net/igb_migration.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a28935c89866..6d29b905c47c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2765,6 +2765,12 @@ F: tests/functional/x86_64/test_netdev_ethtool.py
 F: tests/qtest/igb-test.c
 F: tests/qtest/libqos/igb.c
 
+igb VF migration
+M: Cédric Le Goater <[email protected]>
+S: Maintained
+F: hw/net/igb_migration.*
+F: docs/system/devices/igb-migration.rst
+
 eepro100
 M: Stefan Weil <[email protected]>
 S: Maintained
diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst
index 40054bb7dfcc..75f423b795cd 100644
--- a/docs/system/device-emulation.rst
+++ b/docs/system/device-emulation.rst
@@ -90,6 +90,7 @@ Emulated Devices
    devices/cxl.rst
    devices/emmc.rst
    devices/igb.rst
+   devices/igb-migration.rst
    devices/ivshmem-flat.rst
    devices/ivshmem.rst
    devices/keyboard.rst
diff --git a/docs/system/devices/igb-migration.rst 
b/docs/system/devices/igb-migration.rst
new file mode 100644
index 000000000000..017b47c4544e
--- /dev/null
+++ b/docs/system/devices/igb-migration.rst
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+.. _igb-migration:
+
+igb VF Migration
+----------------
+
+The igb device supports an experimental VF migration interface that allows
+the ``igb-vfio-pci`` variant driver to migrate VF state during live
+migration. This is enabled with the ``x-vf-migration`` property::
+
+  -device igb,x-vf-migration=on,...
+
+When enabled, each emulated VF advertises a vendor-specific PCI capability
+(cap id 0x09) with a magic signature (``0x4D494742`` / "MIGB") that the
+variant driver probes at bind time. The capability contains an interface
+version number, the BAR index hosting the migration register region, and
+feature flags indicating which migration features are supported.
+
+This feature is experimental and the ``x-`` prefix indicates the interface
+may change.
diff --git a/docs/system/devices/igb.rst b/docs/system/devices/igb.rst
index 50f625fd77e4..00271dbc92c3 100644
--- a/docs/system/devices/igb.rst
+++ b/docs/system/devices/igb.rst
@@ -64,6 +64,12 @@ command:
 
   pyvenv/bin/meson test --suite thorough func-x86_64-netdev_ethtool
 
+VF Migration (experimental)
+===========================
+
+See :ref:`igb-migration` for details on the experimental VF live migration
+interface.
+
 References
 ==========
 
diff --git a/hw/net/igb_migration.h b/hw/net/igb_migration.h
new file mode 100644
index 000000000000..e79892436b21
--- /dev/null
+++ b/hw/net/igb_migration.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU Intel 82576 SR/IOV VF Migration Support
+ *
+ * Copyright (c) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef IGB_MIGRATION_H
+#define IGB_MIGRATION_H
+
+#include "hw/pci/pci_device.h"
+
+/* Migration BAR definitions */
+#define IGB_MIG_BAR_IDX   (2)
+#define IGB_MIG_BAR_SIZE  (64 * 1024)
+
+/*
+ * Vendor-specific PCI capability for migration discovery.
+ *
+ * The igb-vfio-pci variant driver probes for this at bind time.
+ * If present, the driver knows the emulated VF supports migration.
+ */
+#define IGB_MIG_CAP_MAGIC    0x4D494742  /* "MIGB" */
+#define IGB_MIG_CAP_VERSION  1
+
+#define IGB_MIG_CAP_F_STATE  (1u << 0)   /* device state serialization */
+#define IGB_MIG_CAP_F_DIRTY  (1u << 1)   /* dirty page tracking */
+
+#define IGB_MIG_CAP_SIZE     16
+#define IGB_MIG_CAP_OFF_MAGIC  4    /* offset within cap for magic field */
+#define IGB_MIG_CAP_OFF_BARID  8    /* offset within cap for BAR id */
+#define IGB_MIG_CAP_OFF_FLAGS  12   /* offset within cap for feature flags */
+
+typedef struct IgbVfMigState {
+    bool migration_cap;
+    MemoryRegion mig_bar;
+} IgbVfMigState;
+
+void igb_pf_init_migration_bar(PCIDevice *dev);
+bool igbvf_add_migration_cap(PCIDevice *dev, Error **errp);
+
+#endif
diff --git a/hw/net/igb.c b/hw/net/igb.c
index c076807e7110..b43235996db2 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -57,6 +57,7 @@
 
 #include "igb_common.h"
 #include "igb_core.h"
+#include "igb_migration.h"
 
 #include "trace.h"
 #include "qapi/error.h"
@@ -69,6 +70,7 @@ struct IGBState {
     PCIDevice parent_obj;
     NICState *nic;
     NICConf conf;
+    bool vf_migration;
 
     MemoryRegion mmio;
     MemoryRegion flash;
@@ -459,6 +461,15 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error 
**errp)
     pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MSIX_BAR_IDX,
         PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
         IGBVF_MSIX_SIZE);
+    /*
+     * When VF migration support is enabled, register an additional VF
+     * BAR for the migration register region. The variant driver
+     * discovers this via a vendor-specific PCI capability that points
+     * to this BAR.
+     */
+    if (s->vf_migration) {
+        igb_pf_init_migration_bar(pci_dev);
+    }
 
     igb_init_net_peer(s, pci_dev, macaddr);
 
@@ -597,6 +608,7 @@ static const VMStateDescription igb_vmstate = {
 static const Property igb_properties[] = {
     DEFINE_NIC_PROPERTIES(IGBState, conf),
     DEFINE_PROP_BOOL("x-pcie-flr-init", IGBState, has_flr, true),
+    DEFINE_PROP_BOOL("x-vf-migration", IGBState, vf_migration, false),
 };
 
 static void igb_class_init(ObjectClass *class, const void *data)
diff --git a/hw/net/igb_migration.c b/hw/net/igb_migration.c
new file mode 100644
index 000000000000..794f1217d3e5
--- /dev/null
+++ b/hw/net/igb_migration.c
@@ -0,0 +1,72 @@
+/*
+ * QEMU Intel 82576 SR/IOV VF Migration Support
+ *
+ * Copyright (c) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/pcie.h"
+#include "igb_common.h"
+#include "igb_migration.h"
+#include "trace.h"
+
+
+
+/*
+ * 32-bit prefetchable BAR. A 64-bit BAR2 would consume BAR2+BAR3, but
+ * BAR3 is already used for MSI-X (IGBVF_MSIX_BAR_IDX = 3).
+ *
+ *   BAR   Index       Type            Size   Purpose
+ *   BAR0  0+1    64-bit prefetchable  16 KB  MMIO registers
+ *   BAR2  2      32-bit prefetchable  64 KB  Migration
+ *   BAR3  3+4    64-bit prefetchable  16 KB  MSI-X table + PBA
+ *   BAR5  5      -                    -      Unused
+ */
+void igb_pf_init_migration_bar(PCIDevice *dev)
+{
+    pcie_sriov_pf_init_vf_bar(dev, IGB_MIG_BAR_IDX,
+                              PCI_BASE_ADDRESS_MEM_PREFETCH,
+                              IGB_MIG_BAR_SIZE);
+}
+
+/*
+ * Add vendor-specific PCI capability that the variant driver probes for.
+ *
+ * Layout (16 bytes):
+ *   [0]  cap_id      (PCI_CAP_ID_VNDR = 0x09)
+ *   [1]  next_cap
+ *   [2]  cap_len     (16)
+ *   [3]  version     (IGB_MIG_CAP_VERSION)
+ *   [4-7]  magic     (IGB_MIG_CAP_MAGIC, little-endian)
+ *   [8-11] bar_id    (IGB_MIG_BAR_IDX, little-endian)
+ *   [12-15] flags    (feature flags, little-endian)
+ */
+bool igbvf_add_migration_cap(PCIDevice *dev, Error **errp)
+{
+    int offset;
+
+    offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0,
+                                IGB_MIG_CAP_SIZE, errp);
+    if (offset < 0) {
+        return false;
+    }
+
+    /* Length and version in the standard cap flags word */
+    pci_set_byte(dev->config + offset + PCI_CAP_FLAGS,
+                 IGB_MIG_CAP_SIZE);
+    pci_set_byte(dev->config + offset + PCI_CAP_FLAGS + 1,
+                 IGB_MIG_CAP_VERSION);
+
+    pci_set_long(dev->config + offset + IGB_MIG_CAP_OFF_MAGIC,
+                 IGB_MIG_CAP_MAGIC);
+    pci_set_long(dev->config + offset + IGB_MIG_CAP_OFF_BARID,
+                 IGB_MIG_BAR_IDX);
+    pci_set_long(dev->config + offset + IGB_MIG_CAP_OFF_FLAGS,
+                 IGB_MIG_CAP_F_STATE);
+
+    trace_igbvf_mig_cap_add(pcie_sriov_vf_number(dev), offset);
+    return true;
+}
diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
index 9a165c7063ee..94c9739cd58c 100644
--- a/hw/net/igbvf.c
+++ b/hw/net/igbvf.c
@@ -47,6 +47,7 @@
 #include "net/net.h"
 #include "igb_common.h"
 #include "igb_core.h"
+#include "igb_migration.h"
 #include "trace.h"
 #include "qapi/error.h"
 
@@ -57,6 +58,8 @@ struct IgbVfState {
 
     MemoryRegion mmio;
     MemoryRegion msix;
+
+    IgbVfMigState mig;
 };
 
 static hwaddr vf_to_pf_addr(hwaddr addr, uint16_t vfn, bool write)
@@ -272,6 +275,14 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
         hw_error("Failed to initialize PCIe capability");
     }
 
+    s->mig.migration_cap = 
object_property_get_bool(OBJECT(pcie_sriov_get_pf(dev)),
+                                                "x-vf-migration", 
&error_abort);
+    if (s->mig.migration_cap) {
+        if (!igbvf_add_migration_cap(dev, errp)) {
+            return;
+        }
+    }
+
     if (object_property_get_bool(OBJECT(pcie_sriov_get_pf(dev)),
                                  "x-pcie-flr-init", &error_abort)) {
         pcie_cap_flr_init(dev);
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 84f142df222a..bb4b449b25ba 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -11,7 +11,7 @@ system_ss.add(when: 'CONFIG_E1000_PCI', if_true: 
files('e1000.c', 'e1000x_common
 system_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: 
files('net_tx_pkt.c', 'net_rx_pkt.c'))
 system_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('e1000e.c', 
'e1000e_core.c', 'e1000x_common.c'))
 system_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 
'net_rx_pkt.c'))
-system_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 
'igbvf.c', 'igb_core.c'))
+system_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 
'igbvf.c', 'igb_core.c', 'igb_migration.c'))
 system_ss.add(when: 'CONFIG_RTL8139_PCI', if_true: files('rtl8139.c'))
 system_ss.add(when: 'CONFIG_TULIP', if_true: files('tulip.c'))
 system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('net_tx_pkt.c', 
'net_rx_pkt.c'))
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 001a20b0e2ac..06d8848023e5 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -294,6 +294,7 @@ igb_wrn_rx_desc_modes_not_supp(int desc_type) "Not 
supported descriptor type: %d
 
 # igbvf.c
 igbvf_wrn_io_addr_unknown(uint64_t addr) "IO unknown register 0x%"PRIx64
+igbvf_mig_cap_add(uint16_t vfn, int offset) "VF%u: added migration vendor cap 
at config offset 0x%x"
 
 # spapr_llan.c
 spapr_vlan_get_rx_bd_from_pool_found(int pool, int32_t count, uint32_t 
rx_bufs) "pool=%d count=%"PRId32" rxbufs=%"PRIu32
-- 
2.55.0


Reply via email to