virtio-net: vhost-user: Implement internal migration

Add support of VHOST_USER_PROTOCOL_F_DEVICE_STATE in virtio-net
with vhost-user backend.

Cc: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Message-Id: <20250115135044.799698-3-lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Laurent Vivier 2025-01-15 14:50:44 +01:00 committed by Michael S. Tsirkin
parent 3f65357313
commit 60f543ad91

View file

@ -3337,6 +3337,117 @@ static const VMStateDescription vmstate_virtio_net_rss = {
},
};
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc;
struct vhost_net *net;
if (!n->nic) {
return NULL;
}
nc = qemu_get_queue(n->nic);
if (!nc) {
return NULL;
}
net = get_vhost_net(nc->peer);
if (!net) {
return NULL;
}
return &net->dev;
}
static int vhost_user_net_save_state(QEMUFile *f, void *pv, size_t size,
const VMStateField *field,
JSONWriter *vmdesc)
{
VirtIONet *n = pv;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
Error *local_error = NULL;
int ret;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
error_reportf_err(local_error,
"Error getting vhost back-end of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return -1;
}
ret = vhost_save_backend_state(vhdev, f, &local_error);
if (ret < 0) {
error_reportf_err(local_error,
"Error saving back-end state of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return ret;
}
return 0;
}
static int vhost_user_net_load_state(QEMUFile *f, void *pv, size_t size,
const VMStateField *field)
{
VirtIONet *n = pv;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
Error *local_error = NULL;
int ret;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
error_reportf_err(local_error,
"Error getting vhost back-end of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return -1;
}
ret = vhost_load_backend_state(vhdev, f, &local_error);
if (ret < 0) {
error_reportf_err(local_error,
"Error loading back-end state of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return ret;
}
return 0;
}
static bool vhost_user_net_is_internal_migration(void *opaque)
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
return false;
}
return vhost_supports_device_state(vhdev);
}
static const VMStateDescription vhost_user_net_backend_state = {
.name = "virtio-net-device/backend",
.version_id = 0,
.needed = vhost_user_net_is_internal_migration,
.fields = (const VMStateField[]) {
{
.name = "backend",
.info = &(const VMStateInfo) {
.name = "virtio-net vhost-user backend state",
.get = vhost_user_net_load_state,
.put = vhost_user_net_save_state,
},
},
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_virtio_net_device = {
.name = "virtio-net-device",
.version_id = VIRTIO_NET_VM_VERSION,
@ -3389,6 +3500,7 @@ static const VMStateDescription vmstate_virtio_net_device = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_virtio_net_rss,
&vhost_user_net_backend_state,
NULL
}
};
@ -3950,29 +4062,6 @@ static bool dev_unplug_pending(void *opaque)
return vdc->primary_unplug_pending(dev);
}
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc;
struct vhost_net *net;
if (!n->nic) {
return NULL;
}
nc = qemu_get_queue(n->nic);
if (!nc) {
return NULL;
}
net = get_vhost_net(nc->peer);
if (!net) {
return NULL;
}
return &net->dev;
}
static const VMStateDescription vmstate_virtio_net = {
.name = "virtio-net",
.minimum_version_id = VIRTIO_NET_VM_VERSION,