]>
Commit | Line | Data |
---|---|---|
d5970055 MT |
1 | /* |
2 | * vhost-net support | |
3 | * | |
4 | * Copyright Red Hat, Inc. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Michael S. Tsirkin <mst@redhat.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
6b620ca3 PB |
11 | * |
12 | * Contributions after 2012-01-13 are licensed under the terms of the | |
13 | * GNU GPL, version 2 or (at your option) any later version. | |
d5970055 MT |
14 | */ |
15 | ||
e8d40465 | 16 | #include "qemu/osdep.h" |
1422e32d | 17 | #include "net/net.h" |
d5970055 | 18 | #include "net/tap.h" |
03ce5744 | 19 | #include "net/vhost-user.h" |
108a6481 | 20 | #include "net/vhost-vdpa.h" |
d5970055 | 21 | |
18658a3c | 22 | #include "standard-headers/linux/vhost_types.h" |
0d09e41a PB |
23 | #include "hw/virtio/virtio-net.h" |
24 | #include "net/vhost_net.h" | |
a6945f22 | 25 | #include "qapi/error.h" |
1de7afc9 | 26 | #include "qemu/error-report.h" |
db725815 | 27 | #include "qemu/main-loop.h" |
d5970055 | 28 | |
d5970055 | 29 | #include <sys/socket.h> |
d5970055 MT |
30 | #include <net/if.h> |
31 | #include <netinet/in.h> | |
32 | ||
d5970055 | 33 | |
4fbe0f32 | 34 | #include "standard-headers/linux/virtio_ring.h" |
0d09e41a | 35 | #include "hw/virtio/vhost.h" |
1c819449 | 36 | #include "hw/virtio/virtio-bus.h" |
10f8a115 | 37 | #include "linux-headers/linux/vhost.h" |
d5970055 | 38 | |
d5970055 | 39 | |
2e6d46d7 NN |
40 | /* Features supported by host kernel. */ |
41 | static const int kernel_feature_bits[] = { | |
42 | VIRTIO_F_NOTIFY_ON_EMPTY, | |
43 | VIRTIO_RING_F_INDIRECT_DESC, | |
44 | VIRTIO_RING_F_EVENT_IDX, | |
45 | VIRTIO_NET_F_MRG_RXBUF, | |
b1506132 | 46 | VIRTIO_F_VERSION_1, |
45a368ad | 47 | VIRTIO_NET_F_MTU, |
c471ad0e | 48 | VIRTIO_F_IOMMU_PLATFORM, |
dfea7930 | 49 | VIRTIO_F_RING_PACKED, |
2a3552ba | 50 | VIRTIO_F_RING_RESET, |
0145c393 | 51 | VIRTIO_NET_F_HASH_REPORT, |
2e6d46d7 NN |
52 | VHOST_INVALID_FEATURE_BIT |
53 | }; | |
54 | ||
5f4c01ca | 55 | /* Features supported by others. */ |
d122f1a2 | 56 | static const int user_feature_bits[] = { |
5f4c01ca NN |
57 | VIRTIO_F_NOTIFY_ON_EMPTY, |
58 | VIRTIO_RING_F_INDIRECT_DESC, | |
59 | VIRTIO_RING_F_EVENT_IDX, | |
60 | ||
61 | VIRTIO_F_ANY_LAYOUT, | |
b1506132 | 62 | VIRTIO_F_VERSION_1, |
5f4c01ca NN |
63 | VIRTIO_NET_F_CSUM, |
64 | VIRTIO_NET_F_GUEST_CSUM, | |
65 | VIRTIO_NET_F_GSO, | |
66 | VIRTIO_NET_F_GUEST_TSO4, | |
67 | VIRTIO_NET_F_GUEST_TSO6, | |
68 | VIRTIO_NET_F_GUEST_ECN, | |
69 | VIRTIO_NET_F_GUEST_UFO, | |
70 | VIRTIO_NET_F_HOST_TSO4, | |
71 | VIRTIO_NET_F_HOST_TSO6, | |
72 | VIRTIO_NET_F_HOST_ECN, | |
73 | VIRTIO_NET_F_HOST_UFO, | |
74 | VIRTIO_NET_F_MRG_RXBUF, | |
45a368ad | 75 | VIRTIO_NET_F_MTU, |
6dcdd06e | 76 | VIRTIO_F_IOMMU_PLATFORM, |
dfea7930 | 77 | VIRTIO_F_RING_PACKED, |
562a7d23 | 78 | VIRTIO_F_RING_RESET, |
0145c393 AM |
79 | VIRTIO_NET_F_RSS, |
80 | VIRTIO_NET_F_HASH_REPORT, | |
9da16849 AM |
81 | VIRTIO_NET_F_GUEST_USO4, |
82 | VIRTIO_NET_F_GUEST_USO6, | |
83 | VIRTIO_NET_F_HOST_USO, | |
5f4c01ca | 84 | |
72018d1e | 85 | /* This bit implies RARP isn't sent by QEMU out of band */ |
f6f56291 TC |
86 | VIRTIO_NET_F_GUEST_ANNOUNCE, |
87 | ||
5f4c01ca NN |
88 | VIRTIO_NET_F_MQ, |
89 | ||
90 | VHOST_INVALID_FEATURE_BIT | |
91 | }; | |
92 | ||
2e6d46d7 | 93 | static const int *vhost_net_get_feature_bits(struct vhost_net *net) |
d5970055 | 94 | { |
2e6d46d7 NN |
95 | const int *feature_bits = 0; |
96 | ||
97 | switch (net->nc->info->type) { | |
f394b2e2 | 98 | case NET_CLIENT_DRIVER_TAP: |
2e6d46d7 NN |
99 | feature_bits = kernel_feature_bits; |
100 | break; | |
f394b2e2 | 101 | case NET_CLIENT_DRIVER_VHOST_USER: |
5f4c01ca NN |
102 | feature_bits = user_feature_bits; |
103 | break; | |
108a6481 CL |
104 | #ifdef CONFIG_VHOST_NET_VDPA |
105 | case NET_CLIENT_DRIVER_VHOST_VDPA: | |
106 | feature_bits = vdpa_feature_bits; | |
107 | break; | |
108 | #endif | |
2e6d46d7 NN |
109 | default: |
110 | error_report("Feature bits not defined for this type: %d", | |
111 | net->nc->info->type); | |
112 | break; | |
ca736c8e | 113 | } |
2e6d46d7 NN |
114 | |
115 | return feature_bits; | |
116 | } | |
117 | ||
9a2ba823 | 118 | uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) |
2e6d46d7 NN |
119 | { |
120 | return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net), | |
121 | features); | |
d5970055 | 122 | } |
38140cc4 CL |
123 | int vhost_net_get_config(struct vhost_net *net, uint8_t *config, |
124 | uint32_t config_len) | |
125 | { | |
50de5138 | 126 | return vhost_dev_get_config(&net->dev, config, config_len, NULL); |
38140cc4 CL |
127 | } |
128 | int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, | |
129 | uint32_t offset, uint32_t size, uint32_t flags) | |
130 | { | |
131 | return vhost_dev_set_config(&net->dev, data, offset, size, flags); | |
132 | } | |
d5970055 | 133 | |
9a2ba823 | 134 | void vhost_net_ack_features(struct vhost_net *net, uint64_t features) |
d5970055 | 135 | { |
b49ae913 | 136 | net->dev.acked_features = net->dev.backend_features; |
2e6d46d7 | 137 | vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features); |
d5970055 MT |
138 | } |
139 | ||
e2051e9e YL |
140 | uint64_t vhost_net_get_max_queues(VHostNetState *net) |
141 | { | |
142 | return net->dev.max_queues; | |
143 | } | |
144 | ||
a463215b MAL |
145 | uint64_t vhost_net_get_acked_features(VHostNetState *net) |
146 | { | |
147 | return net->dev.acked_features; | |
148 | } | |
149 | ||
c9bdc449 HH |
150 | void vhost_net_save_acked_features(NetClientState *nc) |
151 | { | |
152 | #ifdef CONFIG_VHOST_NET_USER | |
153 | if (nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { | |
154 | vhost_user_save_acked_features(nc); | |
155 | } | |
156 | #endif | |
157 | } | |
158 | ||
4e68f7a0 | 159 | static int vhost_net_get_fd(NetClientState *backend) |
d5970055 MT |
160 | { |
161 | switch (backend->info->type) { | |
f394b2e2 | 162 | case NET_CLIENT_DRIVER_TAP: |
d5970055 MT |
163 | return tap_get_fd(backend); |
164 | default: | |
165 | fprintf(stderr, "vhost-net requires tap backend\n"); | |
af3bba76 | 166 | return -ENOSYS; |
d5970055 MT |
167 | } |
168 | } | |
169 | ||
81647a65 | 170 | struct vhost_net *vhost_net_init(VhostNetOptions *options) |
d5970055 MT |
171 | { |
172 | int r; | |
1a1bfac9 | 173 | bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL; |
f1a0365b | 174 | struct vhost_net *net = g_new0(struct vhost_net, 1); |
a463215b | 175 | uint64_t features = 0; |
a6945f22 | 176 | Error *local_err = NULL; |
81647a65 NN |
177 | |
178 | if (!options->net_backend) { | |
179 | fprintf(stderr, "vhost-net requires net backend to be setup\n"); | |
d5970055 MT |
180 | goto fail; |
181 | } | |
b931bfbf | 182 | net->nc = options->net_backend; |
6a756d14 | 183 | net->dev.nvqs = options->nvqs; |
81647a65 | 184 | |
e2051e9e | 185 | net->dev.max_queues = 1; |
b931bfbf | 186 | net->dev.vqs = net->vqs; |
e2051e9e | 187 | |
1a1bfac9 NN |
188 | if (backend_kernel) { |
189 | r = vhost_net_get_fd(options->net_backend); | |
190 | if (r < 0) { | |
191 | goto fail; | |
192 | } | |
193 | net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend) | |
9a2ba823 | 194 | ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR); |
1a1bfac9 | 195 | net->backend = r; |
dcb10c00 | 196 | net->dev.protocol_features = 0; |
1a1bfac9 NN |
197 | } else { |
198 | net->dev.backend_features = 0; | |
dcb10c00 | 199 | net->dev.protocol_features = 0; |
1a1bfac9 | 200 | net->backend = -1; |
d5970055 | 201 | |
b931bfbf CO |
202 | /* vhost-user needs vq_index to initiate a specific queue pair */ |
203 | net->dev.vq_index = net->nc->queue_index * net->dev.nvqs; | |
204 | } | |
f56a1247 | 205 | |
81647a65 | 206 | r = vhost_dev_init(&net->dev, options->opaque, |
a6945f22 KW |
207 | options->backend_type, options->busyloop_timeout, |
208 | &local_err); | |
d5970055 | 209 | if (r < 0) { |
a6945f22 | 210 | error_report_err(local_err); |
d5970055 MT |
211 | goto fail; |
212 | } | |
1a1bfac9 | 213 | if (backend_kernel) { |
d8e80ae3 DM |
214 | if (!qemu_has_vnet_hdr_len(options->net_backend, |
215 | sizeof(struct virtio_net_hdr_mrg_rxbuf))) { | |
9a2ba823 | 216 | net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); |
d8e80ae3 | 217 | } |
1a1bfac9 | 218 | if (~net->dev.features & net->dev.backend_features) { |
1eed051c | 219 | fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 |
1a1bfac9 NN |
220 | " for backend\n", |
221 | (uint64_t)(~net->dev.features & net->dev.backend_features)); | |
1a1bfac9 NN |
222 | goto fail; |
223 | } | |
d5970055 | 224 | } |
a463215b | 225 | |
d5970055 | 226 | /* Set sane init value. Override when guest acks. */ |
56f41de7 | 227 | #ifdef CONFIG_VHOST_NET_USER |
f394b2e2 | 228 | if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { |
a463215b MAL |
229 | features = vhost_user_get_acked_features(net->nc); |
230 | if (~net->dev.features & features) { | |
1eed051c | 231 | fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 |
a463215b MAL |
232 | " for backend\n", |
233 | (uint64_t)(~net->dev.features & features)); | |
a463215b MAL |
234 | goto fail; |
235 | } | |
236 | } | |
56f41de7 | 237 | #endif |
a463215b MAL |
238 | |
239 | vhost_net_ack_features(net, features); | |
240 | ||
d5970055 | 241 | return net; |
f1a0365b | 242 | |
d5970055 | 243 | fail: |
f1a0365b | 244 | vhost_dev_cleanup(&net->dev); |
7267c094 | 245 | g_free(net); |
d5970055 MT |
246 | return NULL; |
247 | } | |
248 | ||
049eb15b | 249 | static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index, |
245cf2c2 | 250 | int vq_index_end) |
cd7d1d26 JW |
251 | { |
252 | net->dev.vq_index = vq_index; | |
245cf2c2 | 253 | net->dev.vq_index_end = vq_index_end; |
cd7d1d26 JW |
254 | } |
255 | ||
a9f98bb5 | 256 | static int vhost_net_start_one(struct vhost_net *net, |
cd7d1d26 | 257 | VirtIODevice *dev) |
d5970055 MT |
258 | { |
259 | struct vhost_vring_file file = { }; | |
260 | int r; | |
b0b3db79 | 261 | |
eb92b753 EP |
262 | if (net->nc->info->start) { |
263 | r = net->nc->info->start(net->nc); | |
264 | if (r < 0) { | |
265 | return r; | |
266 | } | |
267 | } | |
268 | ||
b0b3db79 MT |
269 | r = vhost_dev_enable_notifiers(&net->dev, dev); |
270 | if (r < 0) { | |
271 | goto fail_notifiers; | |
272 | } | |
d5970055 | 273 | |
4daa5054 | 274 | r = vhost_dev_start(&net->dev, dev, false); |
d5970055 | 275 | if (r < 0) { |
b0b3db79 | 276 | goto fail_start; |
d5970055 MT |
277 | } |
278 | ||
212d69f2 NN |
279 | if (net->nc->info->poll) { |
280 | net->nc->info->poll(net->nc, false); | |
281 | } | |
282 | ||
f394b2e2 | 283 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { |
1a1bfac9 NN |
284 | qemu_set_fd_handler(net->backend, NULL, NULL, NULL); |
285 | file.fd = net->backend; | |
286 | for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { | |
23bfaf77 JW |
287 | if (!virtio_queue_enabled(dev, net->dev.vq_index + |
288 | file.index)) { | |
289 | /* Queue might not be ready for start */ | |
290 | continue; | |
291 | } | |
950d94ba | 292 | r = vhost_net_set_backend(&net->dev, &file); |
1a1bfac9 NN |
293 | if (r < 0) { |
294 | r = -errno; | |
295 | goto fail; | |
296 | } | |
d5970055 MT |
297 | } |
298 | } | |
539573c3 EP |
299 | |
300 | if (net->nc->info->load) { | |
301 | r = net->nc->info->load(net->nc); | |
302 | if (r < 0) { | |
303 | goto fail; | |
304 | } | |
305 | } | |
d5970055 MT |
306 | return 0; |
307 | fail: | |
308 | file.fd = -1; | |
f394b2e2 | 309 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { |
1a1bfac9 | 310 | while (file.index-- > 0) { |
23bfaf77 JW |
311 | if (!virtio_queue_enabled(dev, net->dev.vq_index + |
312 | file.index)) { | |
313 | /* Queue might not be ready for start */ | |
314 | continue; | |
315 | } | |
950d94ba | 316 | int r = vhost_net_set_backend(&net->dev, &file); |
1a1bfac9 NN |
317 | assert(r >= 0); |
318 | } | |
d5970055 | 319 | } |
212d69f2 NN |
320 | if (net->nc->info->poll) { |
321 | net->nc->info->poll(net->nc, true); | |
322 | } | |
4daa5054 | 323 | vhost_dev_stop(&net->dev, dev, false); |
b0b3db79 MT |
324 | fail_start: |
325 | vhost_dev_disable_notifiers(&net->dev, dev); | |
326 | fail_notifiers: | |
d5970055 MT |
327 | return r; |
328 | } | |
329 | ||
a9f98bb5 JW |
330 | static void vhost_net_stop_one(struct vhost_net *net, |
331 | VirtIODevice *dev) | |
d5970055 MT |
332 | { |
333 | struct vhost_vring_file file = { .fd = -1 }; | |
334 | ||
f394b2e2 | 335 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { |
1a1bfac9 | 336 | for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { |
950d94ba | 337 | int r = vhost_net_set_backend(&net->dev, &file); |
1a1bfac9 NN |
338 | assert(r >= 0); |
339 | } | |
d5970055 | 340 | } |
212d69f2 NN |
341 | if (net->nc->info->poll) { |
342 | net->nc->info->poll(net->nc, true); | |
343 | } | |
4daa5054 | 344 | vhost_dev_stop(&net->dev, dev, false); |
c5e5269d EP |
345 | if (net->nc->info->stop) { |
346 | net->nc->info->stop(net->nc); | |
347 | } | |
b0b3db79 | 348 | vhost_dev_disable_notifiers(&net->dev, dev); |
d5970055 MT |
349 | } |
350 | ||
a9f98bb5 | 351 | int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, |
05ba3f63 | 352 | int data_queue_pairs, int cvq) |
a9f98bb5 | 353 | { |
1c819449 FK |
354 | BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); |
355 | VirtioBusState *vbus = VIRTIO_BUS(qbus); | |
356 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); | |
05ba3f63 JW |
357 | int total_notifiers = data_queue_pairs * 2 + cvq; |
358 | VirtIONet *n = VIRTIO_NET(dev); | |
359 | int nvhosts = data_queue_pairs + cvq; | |
92fbc3e0 | 360 | struct vhost_net *net; |
14c81b21 | 361 | int r, e, i, index_end = data_queue_pairs * 2; |
92fbc3e0 | 362 | NetClientState *peer; |
a9f98bb5 | 363 | |
14c81b21 EP |
364 | if (cvq) { |
365 | index_end += 1; | |
049eb15b JW |
366 | } |
367 | ||
1c819449 | 368 | if (!k->set_guest_notifiers) { |
312fd5f2 | 369 | error_report("binding does not support guest notifiers"); |
a4076440 | 370 | return -ENOSYS; |
a9f98bb5 JW |
371 | } |
372 | ||
05ba3f63 JW |
373 | for (i = 0; i < nvhosts; i++) { |
374 | ||
375 | if (i < data_queue_pairs) { | |
376 | peer = qemu_get_peer(ncs, i); | |
377 | } else { /* Control Virtqueue */ | |
441537f1 | 378 | peer = qemu_get_peer(ncs, n->max_queue_pairs); |
05ba3f63 | 379 | } |
5669655a | 380 | |
92fbc3e0 | 381 | net = get_vhost_net(peer); |
14c81b21 | 382 | vhost_net_set_vq_index(net, i * 2, index_end); |
5669655a VK |
383 | |
384 | /* Suppress the masking guest notifiers on vhost user | |
385 | * because vhost user doesn't interrupt masking/unmasking | |
386 | * properly. | |
387 | */ | |
f394b2e2 | 388 | if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { |
01edc230 | 389 | dev->use_guest_notifier_mask = false; |
5669655a VK |
390 | } |
391 | } | |
a9f98bb5 | 392 | |
05ba3f63 | 393 | r = k->set_guest_notifiers(qbus->parent, total_notifiers, true); |
a9f98bb5 | 394 | if (r < 0) { |
312fd5f2 | 395 | error_report("Error binding guest notifier: %d", -r); |
3154d1e4 | 396 | goto err; |
a9f98bb5 JW |
397 | } |
398 | ||
05ba3f63 JW |
399 | for (i = 0; i < nvhosts; i++) { |
400 | if (i < data_queue_pairs) { | |
401 | peer = qemu_get_peer(ncs, i); | |
402 | } else { | |
441537f1 | 403 | peer = qemu_get_peer(ncs, n->max_queue_pairs); |
05ba3f63 | 404 | } |
bfc6cf31 | 405 | |
92fbc3e0 | 406 | if (peer->vring_enable) { |
bfc6cf31 | 407 | /* restore vring enable state */ |
92fbc3e0 | 408 | r = vhost_set_vring_enable(peer, peer->vring_enable); |
bfc6cf31 MAL |
409 | |
410 | if (r < 0) { | |
411 | goto err_start; | |
412 | } | |
413 | } | |
8b67fe00 YW |
414 | |
415 | r = vhost_net_start_one(get_vhost_net(peer), dev); | |
416 | if (r < 0) { | |
417 | goto err_start; | |
418 | } | |
cd7d1d26 JW |
419 | } |
420 | ||
a9f98bb5 JW |
421 | return 0; |
422 | ||
cd7d1d26 | 423 | err_start: |
a9f98bb5 | 424 | while (--i >= 0) { |
6f3910b5 SWL |
425 | peer = qemu_get_peer(ncs, i < data_queue_pairs ? |
426 | i : n->max_queue_pairs); | |
92fbc3e0 | 427 | vhost_net_stop_one(get_vhost_net(peer), dev); |
a9f98bb5 | 428 | } |
05ba3f63 | 429 | e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); |
cd7d1d26 JW |
430 | if (e < 0) { |
431 | fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); | |
432 | fflush(stderr); | |
433 | } | |
3154d1e4 | 434 | err: |
a9f98bb5 JW |
435 | return r; |
436 | } | |
437 | ||
438 | void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, | |
05ba3f63 | 439 | int data_queue_pairs, int cvq) |
a9f98bb5 | 440 | { |
1c819449 FK |
441 | BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); |
442 | VirtioBusState *vbus = VIRTIO_BUS(qbus); | |
443 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); | |
05ba3f63 JW |
444 | VirtIONet *n = VIRTIO_NET(dev); |
445 | NetClientState *peer; | |
446 | int total_notifiers = data_queue_pairs * 2 + cvq; | |
447 | int nvhosts = data_queue_pairs + cvq; | |
a9f98bb5 JW |
448 | int i, r; |
449 | ||
05ba3f63 JW |
450 | for (i = 0; i < nvhosts; i++) { |
451 | if (i < data_queue_pairs) { | |
452 | peer = qemu_get_peer(ncs, i); | |
453 | } else { | |
441537f1 | 454 | peer = qemu_get_peer(ncs, n->max_queue_pairs); |
05ba3f63 JW |
455 | } |
456 | vhost_net_stop_one(get_vhost_net(peer), dev); | |
cd7d1d26 JW |
457 | } |
458 | ||
05ba3f63 | 459 | r = k->set_guest_notifiers(qbus->parent, total_notifiers, false); |
a9f98bb5 JW |
460 | if (r < 0) { |
461 | fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); | |
462 | fflush(stderr); | |
463 | } | |
464 | assert(r >= 0); | |
a9f98bb5 JW |
465 | } |
466 | ||
d5970055 MT |
467 | void vhost_net_cleanup(struct vhost_net *net) |
468 | { | |
469 | vhost_dev_cleanup(&net->dev); | |
d5970055 | 470 | } |
f56a1247 | 471 | |
3e866365 TC |
472 | int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) |
473 | { | |
474 | const VhostOps *vhost_ops = net->dev.vhost_ops; | |
3e866365 | 475 | |
51f7aca9 MAL |
476 | assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); |
477 | assert(vhost_ops->vhost_migration_done); | |
3e866365 | 478 | |
51f7aca9 | 479 | return vhost_ops->vhost_migration_done(&net->dev, mac_addr); |
3e866365 TC |
480 | } |
481 | ||
f56a1247 MT |
482 | bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) |
483 | { | |
484 | return vhost_virtqueue_pending(&net->dev, idx); | |
485 | } | |
486 | ||
487 | void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, | |
488 | int idx, bool mask) | |
489 | { | |
490 | vhost_virtqueue_mask(&net->dev, dev, idx, mask); | |
491 | } | |
ed8b4afe | 492 | |
8aab0d1d CL |
493 | bool vhost_net_config_pending(VHostNetState *net) |
494 | { | |
495 | return vhost_config_pending(&net->dev); | |
496 | } | |
497 | ||
498 | void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) | |
499 | { | |
500 | vhost_config_mask(&net->dev, dev, mask); | |
501 | } | |
ed8b4afe NN |
502 | VHostNetState *get_vhost_net(NetClientState *nc) |
503 | { | |
504 | VHostNetState *vhost_net = 0; | |
505 | ||
506 | if (!nc) { | |
507 | return 0; | |
508 | } | |
509 | ||
510 | switch (nc->info->type) { | |
f394b2e2 | 511 | case NET_CLIENT_DRIVER_TAP: |
ed8b4afe | 512 | vhost_net = tap_get_vhost_net(nc); |
ca3fcdee AS |
513 | /* |
514 | * tap_get_vhost_net() can return NULL if a tap net-device backend is | |
515 | * created with 'vhost=off' option, 'vhostforce=off' or no vhost or | |
516 | * vhostforce or vhostfd options at all. Please see net_init_tap_one(). | |
517 | * Hence, we omit the assertion here. | |
518 | */ | |
ed8b4afe | 519 | break; |
56f41de7 | 520 | #ifdef CONFIG_VHOST_NET_USER |
f394b2e2 | 521 | case NET_CLIENT_DRIVER_VHOST_USER: |
03ce5744 | 522 | vhost_net = vhost_user_get_vhost_net(nc); |
1a5b68ce | 523 | assert(vhost_net); |
03ce5744 | 524 | break; |
108a6481 CL |
525 | #endif |
526 | #ifdef CONFIG_VHOST_NET_VDPA | |
527 | case NET_CLIENT_DRIVER_VHOST_VDPA: | |
528 | vhost_net = vhost_vdpa_get_vhost_net(nc); | |
529 | assert(vhost_net); | |
530 | break; | |
56f41de7 | 531 | #endif |
ed8b4afe NN |
532 | default: |
533 | break; | |
534 | } | |
535 | ||
536 | return vhost_net; | |
537 | } | |
7263a0ad CO |
538 | |
539 | int vhost_set_vring_enable(NetClientState *nc, int enable) | |
540 | { | |
541 | VHostNetState *net = get_vhost_net(nc); | |
bb12e761 | 542 | const VhostOps *vhost_ops = net->dev.vhost_ops; |
72b65f92 | 543 | |
bfc6cf31 MAL |
544 | nc->vring_enable = enable; |
545 | ||
ca10203c | 546 | if (vhost_ops && vhost_ops->vhost_set_vring_enable) { |
21e70425 | 547 | return vhost_ops->vhost_set_vring_enable(&net->dev, enable); |
7263a0ad CO |
548 | } |
549 | ||
550 | return 0; | |
551 | } | |
552 | ||
45a368ad MC |
553 | int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) |
554 | { | |
555 | const VhostOps *vhost_ops = net->dev.vhost_ops; | |
556 | ||
557 | if (!vhost_ops->vhost_net_set_mtu) { | |
558 | return 0; | |
559 | } | |
560 | ||
561 | return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); | |
562 | } | |
c2daa08e KX |
563 | |
564 | void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc, | |
565 | int vq_index) | |
566 | { | |
567 | VHostNetState *net = get_vhost_net(nc->peer); | |
568 | const VhostOps *vhost_ops = net->dev.vhost_ops; | |
569 | struct vhost_vring_file file = { .fd = -1 }; | |
570 | int idx; | |
571 | ||
572 | /* should only be called after backend is connected */ | |
573 | assert(vhost_ops); | |
574 | ||
575 | idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); | |
576 | ||
577 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { | |
578 | file.index = idx; | |
579 | int r = vhost_net_set_backend(&net->dev, &file); | |
580 | assert(r >= 0); | |
581 | } | |
582 | ||
583 | vhost_virtqueue_stop(&net->dev, | |
584 | vdev, | |
585 | net->dev.vqs + idx, | |
586 | net->dev.vq_index + idx); | |
587 | } | |
10f8a115 KX |
588 | |
589 | int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc, | |
590 | int vq_index) | |
591 | { | |
592 | VHostNetState *net = get_vhost_net(nc->peer); | |
593 | const VhostOps *vhost_ops = net->dev.vhost_ops; | |
594 | struct vhost_vring_file file = { }; | |
595 | int idx, r; | |
596 | ||
597 | if (!net->dev.started) { | |
598 | return -EBUSY; | |
599 | } | |
600 | ||
601 | /* should only be called after backend is connected */ | |
602 | assert(vhost_ops); | |
603 | ||
604 | idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); | |
605 | ||
606 | r = vhost_virtqueue_start(&net->dev, | |
607 | vdev, | |
608 | net->dev.vqs + idx, | |
609 | net->dev.vq_index + idx); | |
610 | if (r < 0) { | |
611 | goto err_start; | |
612 | } | |
613 | ||
614 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { | |
615 | file.index = idx; | |
616 | file.fd = net->backend; | |
617 | r = vhost_net_set_backend(&net->dev, &file); | |
618 | if (r < 0) { | |
619 | r = -errno; | |
620 | goto err_start; | |
621 | } | |
622 | } | |
623 | ||
624 | return 0; | |
625 | ||
626 | err_start: | |
627 | error_report("Error when restarting the queue."); | |
628 | ||
629 | if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { | |
630 | file.fd = VHOST_FILE_UNBIND; | |
631 | file.index = idx; | |
632 | int r = vhost_net_set_backend(&net->dev, &file); | |
633 | assert(r >= 0); | |
634 | } | |
635 | ||
4daa5054 | 636 | vhost_dev_stop(&net->dev, vdev, false); |
10f8a115 KX |
637 | |
638 | return r; | |
639 | } |