Revision afbaa7b4

b/hw/virtio-net.c
54 54
    uint8_t nouni;
55 55
    uint8_t nobcast;
56 56
    uint8_t vhost_started;
57
    bool vm_running;
57 58
    VMChangeStateEntry *vmstate;
58 59
    struct {
59 60
        int in_use;
......
98 99
    }
99 100
}
100 101

  
102
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
103
{
104
    VirtIONet *n = to_virtio_net(vdev);
105
    if (!n->nic->nc.peer) {
106
        return;
107
    }
108
    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
109
        return;
110
    }
111

  
112
    if (!tap_get_vhost_net(n->nic->nc.peer)) {
113
        return;
114
    }
115
    if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
116
                               (n->status & VIRTIO_NET_S_LINK_UP) &&
117
                               n->vm_running)) {
118
        return;
119
    }
120
    if (!n->vhost_started) {
121
        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
122
        if (r < 0) {
123
            fprintf(stderr, "unable to start vhost net: %d: "
124
                    "falling back on userspace virtio\n", -r);
125
        } else {
126
            n->vhost_started = 1;
127
        }
128
    } else {
129
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
130
        n->vhost_started = 0;
131
    }
132
}
133

  
101 134
static void virtio_net_set_link_status(VLANClientState *nc)
102 135
{
103 136
    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
......
110 143

  
111 144
    if (n->status != old_status)
112 145
        virtio_notify_config(&n->vdev);
146

  
147
    virtio_net_set_status(&n->vdev, n->vdev.status);
113 148
}
114 149

  
115 150
static void virtio_net_reset(VirtIODevice *vdev)
......
123 158
    n->nomulti = 0;
124 159
    n->nouni = 0;
125 160
    n->nobcast = 0;
126
    if (n->vhost_started) {
127
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
128
        n->vhost_started = 0;
129
    }
130 161

  
131 162
    /* Flush any MAC and VLAN filter table state */
132 163
    n->mac_table.in_use = 0;
......
783 814
{
784 815
    VirtIONet *n = opaque;
785 816

  
786
    if (n->vhost_started) {
787
        /* TODO: should we really stop the backend?
788
         * If we don't, it might keep writing to memory. */
789
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
790
        n->vhost_started = 0;
791
    }
817
    /* At this point, backend must be stopped, otherwise
818
     * it might keep writing to memory. */
819
    assert(!n->vhost_started);
792 820
    virtio_save(&n->vdev, f);
793 821

  
794 822
    qemu_put_buffer(f, n->mac, ETH_ALEN);
......
924 952
    .link_status_changed = virtio_net_set_link_status,
925 953
};
926 954

  
927
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
928
{
929
    VirtIONet *n = to_virtio_net(vdev);
930
    if (!n->nic->nc.peer) {
931
        return;
932
    }
933
    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
934
        return;
935
    }
936

  
937
    if (!tap_get_vhost_net(n->nic->nc.peer)) {
938
        return;
939
    }
940
    if (!!n->vhost_started == !!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
941
        return;
942
    }
943
    if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
944
        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), vdev);
945
        if (r < 0) {
946
            fprintf(stderr, "unable to start vhost net: %d: "
947
                    "falling back on userspace virtio\n", -r);
948
        } else {
949
            n->vhost_started = 1;
950
        }
951
    } else {
952
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
953
        n->vhost_started = 0;
954
    }
955
}
956

  
957 955
static void virtio_net_vmstate_change(void *opaque, int running, int reason)
958 956
{
959 957
    VirtIONet *n = opaque;
960
    uint8_t status = running ? VIRTIO_CONFIG_S_DRIVER_OK : 0;
958
    n->vm_running = running;
961 959
    /* This is called when vm is started/stopped,
962
     * it will start/stop vhost backend if * appropriate
960
     * it will start/stop vhost backend if appropriate
963 961
     * e.g. after migration. */
964
    virtio_net_set_status(&n->vdev, n->vdev.status & status);
962
    virtio_net_set_status(&n->vdev, n->vdev.status);
965 963
}
966 964

  
967 965
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
......
1028 1026
    VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
1029 1027
    qemu_del_vm_change_state_handler(n->vmstate);
1030 1028

  
1031
    if (n->vhost_started) {
1032
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
1033
    }
1029
    /* This will stop vhost backend if appropriate. */
1030
    virtio_net_set_status(vdev, 0);
1034 1031

  
1035 1032
    qemu_purge_queued_packets(&n->nic->nc);
1036 1033

  

Also available in: Unified diff