Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com> --- hw/virtio-net.c | 160 +++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 115 insertions(+), 45 deletions(-)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8c2f460..974af5c 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -862,78 +862,138 @@ static void virtio_net_tx_bh(void *opaque) static void virtio_net_save(QEMUFile *f, void *opaque) { VirtIONet *n = opaque; + Visitor *v = qemu_file_get_visitor(f); + Error *err = NULL; + uint8_t *buf; + int i; /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ assert(!n->vhost_started); + + visit_start_struct(v, NULL, NULL, "virtio_net", 0, &err); + virtio_save(&n->vdev, f); - qemu_put_buffer(f, n->mac, ETH_ALEN); - qemu_put_be32(f, n->tx_waiting); - qemu_put_be32(f, n->mergeable_rx_bufs); - qemu_put_be16(f, n->status); - qemu_put_byte(f, n->promisc); - qemu_put_byte(f, n->allmulti); - qemu_put_be32(f, n->mac_table.in_use); - qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); - qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); - qemu_put_be32(f, n->has_vnet_hdr); - qemu_put_byte(f, n->mac_table.multi_overflow); - qemu_put_byte(f, n->mac_table.uni_overflow); - qemu_put_byte(f, n->alluni); - qemu_put_byte(f, n->nomulti); - qemu_put_byte(f, n->nouni); - qemu_put_byte(f, n->nobcast); - qemu_put_byte(f, n->has_ufo); + visit_start_array(v, NULL, "mac", ETH_ALEN, 1, &err); + for (i = 0; i < ETH_ALEN; i++) { + visit_type_uint8(v, &n->mac[i], NULL, &err); + } + visit_end_array(v, &err); + visit_type_int32(v, &n->tx_waiting, "tx_waiting", &err); + visit_type_int32(v, &n->mergeable_rx_bufs, "mergeable_rx_bufs", &err); + visit_type_uint16(v, &n->status, "status", &err); + visit_type_uint8(v, &n->promisc, "promisc", &err); + visit_type_uint8(v, &n->allmulti, "allmulti", &err); + visit_type_int32(v, &n->mac_table.in_use, "mac_table", &err); + visit_start_array(v, NULL, "mac_tables.macs", + n->mac_table.in_use * ETH_ALEN, 1, &err); + for (i = 0; i < n->mac_table.in_use * ETH_ALEN; i++) { + visit_type_uint8(v, &n->mac_table.macs[i], NULL, &err); + } + visit_end_array(v, &err); + visit_start_array(v, NULL, "vlans", MAX_VLAN >> 3, 1, &err); + buf = (uint8_t *)n->vlans; + for (i = 0; i < MAX_VLAN >> 3; i++) { + visit_type_uint8(v, &buf[i], NULL, &err); + } + visit_end_array(v, &err); + visit_type_uint32(v, &n->has_vnet_hdr, "has_vnet_hdr", &err); + visit_type_uint8(v, &n->mac_table.multi_overflow, + "mac_table.multi_overflow", &err); + visit_type_uint8(v, &n->mac_table.uni_overflow, + "mac_table.uni_overflow", &err); + visit_type_uint8(v, &n->alluni, "alluni", &err); + visit_type_uint8(v, &n->nomulti, "nomulti", &err); + visit_type_uint8(v, &n->nouni, "nouni", &err); + visit_type_uint8(v, &n->nobcast, "nobcast", &err); + visit_type_uint8(v, &n->has_ufo, "has_ufo", &err); + + visit_end_struct(v, &err); + if (err) { + error_report("error loading virtio-net state: %s", error_get_pretty(err)); + error_free(err); + } } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; - int i; + Visitor *v = qemu_file_get_visitor(f); + Error *err = NULL; + uint8_t *buf, tmp, has_ufo; + uint32_t has_vnet_hdr; + int i, ret = 0; + + if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) { + ret = -EINVAL; + goto out; + } - if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) - return -EINVAL; + visit_start_struct(v, NULL, NULL, "virtio_net", 0, &err); virtio_load(&n->vdev, f); - qemu_get_buffer(f, n->mac, ETH_ALEN); - n->tx_waiting = qemu_get_be32(f); - n->mergeable_rx_bufs = qemu_get_be32(f); + visit_start_array(v, NULL, "mac", ETH_ALEN, 1, &err); + for (i = 0; i < ETH_ALEN; i++) { + visit_type_uint8(v, &n->mac[i], NULL, &err); + } + visit_end_array(v, &err); + visit_type_int32(v, &n->tx_waiting, "tx_waiting", &err); + visit_type_int32(v, &n->mergeable_rx_bufs, "mergeable_rx_bufs", &err); - if (version_id >= 3) - n->status = qemu_get_be16(f); + if (version_id >= 3) { + visit_type_uint16(v, &n->status, "status", &err); + } if (version_id >= 4) { if (version_id < 8) { - n->promisc = qemu_get_be32(f); - n->allmulti = qemu_get_be32(f); + visit_type_uint32(v, (uint32_t *)&n->promisc, "promisc", &err); + visit_type_uint32(v, (uint32_t *)&n->allmulti, "allmulti", &err); } else { - n->promisc = qemu_get_byte(f); - n->allmulti = qemu_get_byte(f); + visit_type_uint8(v, (uint8_t *)&n->promisc, "promisc", &err); + visit_type_uint8(v, (uint8_t *)&n->allmulti, "allmulti", &err); } } if (version_id >= 5) { - n->mac_table.in_use = qemu_get_be32(f); + visit_type_int32(v, &n->mac_table.in_use, "mac_table", &err); /* MAC_TABLE_ENTRIES may be different from the saved image */ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { - qemu_get_buffer(f, n->mac_table.macs, - n->mac_table.in_use * ETH_ALEN); + visit_start_array(v, NULL, "mac_tables.macs", + n->mac_table.in_use * ETH_ALEN, 1, &err); + for (i = 0; i < n->mac_table.in_use * ETH_ALEN; i++) { + visit_type_uint8(v, &n->mac_table.macs[i], NULL, &err); + } + visit_end_array(v, &err); } else if (n->mac_table.in_use) { - qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); + /* dummy load */ + visit_start_array(v, NULL, "mac_tables.macs", + n->mac_table.in_use * ETH_ALEN, 1, &err); + for (i = 0; i < n->mac_table.in_use * ETH_ALEN; i++) { + visit_type_uint8(v, &tmp, NULL, &err); + } + visit_end_array(v, &err); n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } } - if (version_id >= 6) - qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); + if (version_id >= 6) { + visit_start_array(v, NULL, "vlans", MAX_VLAN >> 3, 1, &err); + buf = (uint8_t *)n->vlans; + for (i = 0; i < MAX_VLAN >> 3; i++) { + visit_type_uint8(v, &buf[i], NULL, &err); + } + visit_end_array(v, &err); + } if (version_id >= 7) { - if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) { + visit_type_uint32(v, &has_vnet_hdr, "has_vnet_hdr", &err); + if (has_vnet_hdr && !peer_has_vnet_hdr(n)) { error_report("virtio-net: saved image requires vnet_hdr=on"); - return -1; + ret = -1; + goto out; } if (n->has_vnet_hdr) { @@ -948,24 +1008,27 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } if (version_id >= 9) { - n->mac_table.multi_overflow = qemu_get_byte(f); - n->mac_table.uni_overflow = qemu_get_byte(f); + visit_type_uint8(v, &n->mac_table.multi_overflow, "mac_table.multi_overflow", &err); + visit_type_uint8(v, &n->mac_table.uni_overflow, "mac_table.uni_overflow", &err); } if (version_id >= 10) { - n->alluni = qemu_get_byte(f); - n->nomulti = qemu_get_byte(f); - n->nouni = qemu_get_byte(f); - n->nobcast = qemu_get_byte(f); + visit_type_uint8(v, &n->alluni, "alluni", &err); + visit_type_uint8(v, &n->nomulti, "nomulti", &err); + visit_type_uint8(v, &n->nouni, "nouni", &err); + visit_type_uint8(v, &n->nobcast, "nobcast", &err); } if (version_id >= 11) { - if (qemu_get_byte(f) && !peer_has_ufo(n)) { + visit_type_uint8(v, &has_ufo, "has_ufo", &err); + if (has_ufo && !peer_has_ufo(n)) { error_report("virtio-net: saved image requires TUN_F_UFO support"); return -1; } } + visit_end_struct(v, &err); + /* Find the first multicast entry in the saved MAC filter */ for (i = 0; i < n->mac_table.in_use; i++) { if (n->mac_table.macs[i * ETH_ALEN] & 1) { @@ -973,7 +1036,14 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } } n->mac_table.first_multi = i; - return 0; + + if (err) { + error_report("error loading virtio-net state: %s", error_get_pretty(err)); + ret = -EINVAL; + } +out: + error_free(err); + return ret; } static void virtio_net_cleanup(VLANClientState *nc) -- 1.7.4.1