]> git.proxmox.com Git - mirror_qemu.git/blame - hw/net/vhost_net.c
Merge tag 'pull-ppc-20230918' of https://gitlab.com/danielhb/qemu into staging
[mirror_qemu.git] / hw / net / vhost_net.c
CommitLineData
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. */
41static 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 56static 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 93static 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 118uint64_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
123int 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}
128int 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 134void 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
140uint64_t vhost_net_get_max_queues(VHostNetState *net)
141{
142 return net->dev.max_queues;
143}
144
a463215b
MAL
145uint64_t vhost_net_get_acked_features(VHostNetState *net)
146{
147 return net->dev.acked_features;
148}
149
c9bdc449
HH
150void 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 159static 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 170struct 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 243fail:
f1a0365b 244 vhost_dev_cleanup(&net->dev);
7267c094 245 g_free(net);
d5970055
MT
246 return NULL;
247}
248
049eb15b 249static 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 256static 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;
307fail:
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
324fail_start:
325 vhost_dev_disable_notifiers(&net->dev, dev);
326fail_notifiers:
d5970055
MT
327 return r;
328}
329
a9f98bb5
JW
330static 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 351int 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 423err_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 434err:
a9f98bb5
JW
435 return r;
436}
437
438void 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
467void vhost_net_cleanup(struct vhost_net *net)
468{
469 vhost_dev_cleanup(&net->dev);
d5970055 470}
f56a1247 471
3e866365
TC
472int 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
482bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
483{
484 return vhost_virtqueue_pending(&net->dev, idx);
485}
486
487void 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
493bool vhost_net_config_pending(VHostNetState *net)
494{
495 return vhost_config_pending(&net->dev);
496}
497
498void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask)
499{
500 vhost_config_mask(&net->dev, dev, mask);
501}
ed8b4afe
NN
502VHostNetState *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
539int 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
553int 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
564void 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
589int 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
626err_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}