Revision afbaa7b4 hw/virtio-net.c
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