[PATCH v17 00/10] virtio-net: live-TAP local migration

Vladimir Sementsov-Ogievskiy posted 10 patches 2 days, 21 hours ago
Failed in applying to current master (apply log)
hw/core/machine.c                             |   2 +
hw/net/virtio-net.c                           |  89 +++-
include/hw/virtio/virtio-net.h                |   1 +
include/migration/misc.h                      |   2 +
include/migration/vmstate.h                   |   2 +
include/net/net.h                             |   9 +
include/net/tap.h                             |   2 +
migration/options.c                           |  18 +-
net/net.c                                     |  14 +-
net/tap.c                                     | 429 +++++++++++++---
qapi/migration.json                           |  12 +-
qapi/net.json                                 |  20 +-
tests/functional/qemu_test/decorators.py      |  16 +
tests/functional/x86_64/meson.build           |   1 +
tests/functional/x86_64/test_tap_migration.py | 458 ++++++++++++++++++
15 files changed, 986 insertions(+), 89 deletions(-)
create mode 100755 tests/functional/x86_64/test_tap_migration.py
[PATCH v17 00/10] virtio-net: live-TAP local migration
Posted by Vladimir Sementsov-Ogievskiy 2 days, 21 hours ago
Hi all!

Here is a migration for TAP net backend, including its properties and
open fds.

With this new feature, management software doesn't need to initialize
new TAP and do a switch to it. Nothing should be done around
virtio-net in local migration: it just migrates and continues to use
same TAP device. So we avoid extra logic in management software, extra
allocations in kernel (for new TAP), and corresponding extra delay in
migration downtime.

v17: rework interface
02-04: new
07: - drop local-migration parameter for virtio-net and the whole
      code to migrate backends (they should migrate by themselves).
    - drop virtio_net_update_host_features(), and call
      peer_test_vnet_hdr() and virtio_net_get_features() directly
      from post-load handlers
    - drop r-b
08: - add local-migratieon-supported property (instead of
      local-migration that is dropped in 07)
    - register own vmstate
    - add check for being in incoming migration when use incoming-fds
    - drop r-b, a-b
10: only move 'local_migration=local' from virtio-net device
    to 'local-migration-supported": local' in netdev. keep r-bs

Based-on: <20260318113144.15697-1-vsementsov@yandex-team.ru>
    "[PATCH v4 00/13] net: refactoring and fixes"

v17 is pushed to

    https://gitlab.com/vsementsov/qemu.git
      tag: up-tap-fd-migration-with-bk-opt-v17

To run the test, use sudo, as test needs to configure TAP device:

    sudo PYTHONPATH=python:tests/functional \
    QEMU_TEST_QEMU_BINARY=$PWD/build/qemu-system-x86_64 \
    MESON_BUILD_ROOT=$PWD/build \
    ./build/pyvenv/bin/python3 tests/functional/x86_64/test_tap_migration.py

Or, to test the feature by hand, you may follow the instruction:

1. Prerequisites
----------------

    QEMU=/path/to/your/build/qemu-system-x86_64

# download same image as in test

    wget -O /tmp/alpine.iso "https://dl-cdn.alpinelinux.org/alpine/v3.22/releases/x86_64/alpine-standard-3.22.1-x86_64.iso"


# prepare tap device (be careful to not break your own networks)

    sudo ip tuntap add dev tap0 mode tap multi_queue
    sudo ip addr add 192.168.100.1/24 dev tap0
    sudo ip link set tap0 up


2. Start source VM
------------------

Open terminal A, and run:

    $QEMU \
        -name source \
        -machine q35 \
        -accel kvm \
        -m 1G \
        -object memory-backend-file,id=ram0,size=1G,mem-path=/dev/shm/qemu_migration_test,share=on \
        -machine memory-backend=ram0 \
        -drive file=/tmp/alpine.iso,media=cdrom,format=raw \
        -device pcie-pci-bridge,id=pci.1,bus=pcie.0 \
        -netdev tap,id=netdev.1,ifname=tap0,queues=4,vnet_hdr=on,script=no,downscript=no,local-migration-supported=on \
        -device virtio-net-pci,netdev=netdev.1,id=vnet.1,bus=pci.1,mq=on,vectors=18,romfile=,disable-legacy=off \
        -serial stdio \
        -nographic \
        -qmp unix:/tmp/qmp-source.sock,server=on,wait=off

Wait for Alpine to boot.  When you see the login prompt, log in as root
(no password):

    localhost login: root

Configure the guest network:

    ip addr add 192.168.100.2/24 dev eth0
    ip link set eth0 up

Verify connectivity from the guest:

    ping -c 3 192.168.100.1

And from the host (in another terminal):

    ping -c 3 192.168.100.2


3. Start target VM
------------------

Open terminal B.  The target VM uses the same shared memory file and
the same ISO.  The NIC is configured with incoming-fds=on — it will
not open tap0 itself; instead it will receive the TAP file descriptors
from the source over the migration channel.

    $QEMU \
        -name target \
        -machine q35 \
        -accel kvm \
        -m 1G \
        -object memory-backend-file,id=ram0,size=1G,mem-path=/dev/shm/qemu_migration_test,share=on \
        -machine memory-backend=ram0 \
        -drive file=/tmp/alpine.iso,media=cdrom,format=raw \
        -device pcie-pci-bridge,id=pci.1,bus=pcie.0 \
        -netdev tap,id=netdev.1,queues=4,script=no,downscript=no,local-migration-supported=on,incoming-fds=on \
        -device virtio-net-pci,netdev=netdev.1,id=vnet.1,bus=pci.1,mq=on,vectors=18,romfile=,disable-legacy=off \
        -serial stdio \
        -nographic \
        -qmp unix:/tmp/qmp-target.sock,server=on,wait=off \
        -incoming defer


4. Start migration
------------------

Open terminal C and connect to the source QMP socket:

    socat - UNIX-CONNECT:/tmp/qmp-source.sock

Negotiate capabilities and configure migration:

    {"execute": "qmp_capabilities"}

    {"execute": "migrate-set-capabilities", "arguments": {
        "capabilities": [
            {"capability": "events",          "state": true},
            {"capability": "x-ignore-shared", "state": true}
        ]
    }}

    {"execute": "migrate-set-parameters", "arguments": {"local": true}}

Open terminal D and connect to the target QMP socket:

    socat - UNIX-CONNECT:/tmp/qmp-target.sock

Negotiate capabilities and configure migration:

    {"execute": "qmp_capabilities"}

    {"execute": "migrate-set-capabilities", "arguments": {
        "capabilities": [
            {"capability": "events",          "state": true},
            {"capability": "x-ignore-shared", "state": true}
        ]
    }}

    {"execute": "migrate-set-parameters", "arguments": {"local": true}}

Tell the target to listen for the incoming migration (terminal D):

    {"execute": "migrate-incoming",
     "arguments": {"uri": "unix:/tmp/migration.sock"}}

Trigger the migration from the source (terminal C):

    {"execute": "migrate",
     "arguments": {"uri": "unix:/tmp/migration.sock"}}

Poll migration status until it completes (terminal C):

    {"execute": "query-migrate"}
    # repeat until "status" == "completed"

Or just wait for the MIGRATION event that QEMU emits automatically:

    # {"event": "MIGRATION", "data": {"status": "completed"}, ...}

Once the source reports "completed", resume the target VM (terminal D):

    {"execute": "cont"}

The target VM is now running with the migrated state and the TAP file
descriptors that were passed from the source.

Verify that the guest is still reachable from the host:

    ping -c 3 192.168.100.2

And from inside the guest (terminal B, target serial console):

    ping -c 3 192.168.100.1


5. Cleanup
----------

Shut down the target VM (terminal D):

    {"execute": "quit"}

Shut down the source VM (terminal C):

    {"execute": "quit"}

Remove the TAP device:

    sudo ip tuntap del tap0 mode tap multi_queue

Remove the shared memory file:

    rm /dev/shm/qemu_migration_test

Remove leftover sockets if they still exist:

    rm -f /tmp/migration.sock /tmp/qmp-source.sock /tmp/qmp-target.sock 

Vladimir Sementsov-Ogievskiy (10):
  net/tap: move vhost-net open() calls to tap_parse_vhost_fds()
  net/tap: move vhost initialization to tap_setup_vhost()
  net/tap: use container_of instead of DO_UPCAST
  net/tap: QOMify tap backend
  net/tap: add TYPE_VMSTATE_IF interface
  qapi: add local migration parameter
  virtio-net: support local migration of backend
  net/tap: support local migration with virtio-net
  tests/functional: add skipWithoutSudo() decorator
  tests/functional: add test_tap_migration

 hw/core/machine.c                             |   2 +
 hw/net/virtio-net.c                           |  89 +++-
 include/hw/virtio/virtio-net.h                |   1 +
 include/migration/misc.h                      |   2 +
 include/migration/vmstate.h                   |   2 +
 include/net/net.h                             |   9 +
 include/net/tap.h                             |   2 +
 migration/options.c                           |  18 +-
 net/net.c                                     |  14 +-
 net/tap.c                                     | 429 +++++++++++++---
 qapi/migration.json                           |  12 +-
 qapi/net.json                                 |  20 +-
 tests/functional/qemu_test/decorators.py      |  16 +
 tests/functional/x86_64/meson.build           |   1 +
 tests/functional/x86_64/test_tap_migration.py | 458 ++++++++++++++++++
 15 files changed, 986 insertions(+), 89 deletions(-)
 create mode 100755 tests/functional/x86_64/test_tap_migration.py

-- 
2.52.0