hw/net/virtio-net.c | 135 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 23 deletions(-)
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>
---
hw/net/virtio-net.c | 135 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 112 insertions(+), 23 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6e8c51a2dbce..b4d9e96dc0d7 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -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,
--
2.47.1
I tested this patch with virtio-net regression tests,everything works fine. Tested-by: Lei Yang <leiyang@redhat.com> On Wed, Dec 18, 2024 at 10:36 PM Laurent Vivier <lvivier@redhat.com> wrote: > > 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> > --- > hw/net/virtio-net.c | 135 ++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 112 insertions(+), 23 deletions(-) > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index 6e8c51a2dbce..b4d9e96dc0d7 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -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, > -- > 2.47.1 > >
© 2016 - 2024 Red Hat, Inc.