1d5970055SMichael S. Tsirkin /* 2d5970055SMichael S. Tsirkin * vhost-net support 3d5970055SMichael S. Tsirkin * 4d5970055SMichael S. Tsirkin * Copyright Red Hat, Inc. 2010 5d5970055SMichael S. Tsirkin * 6d5970055SMichael S. Tsirkin * Authors: 7d5970055SMichael S. Tsirkin * Michael S. Tsirkin <mst@redhat.com> 8d5970055SMichael S. Tsirkin * 9d5970055SMichael S. Tsirkin * This work is licensed under the terms of the GNU GPL, version 2. See 10d5970055SMichael S. Tsirkin * the COPYING file in the top-level directory. 116b620ca3SPaolo Bonzini * 126b620ca3SPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the 136b620ca3SPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version. 14d5970055SMichael S. Tsirkin */ 15d5970055SMichael S. Tsirkin 16e8d40465SPeter Maydell #include "qemu/osdep.h" 171422e32dSPaolo Bonzini #include "net/net.h" 18d5970055SMichael S. Tsirkin #include "net/tap.h" 1903ce5744SNikolay Nikolaev #include "net/vhost-user.h" 20108a6481SCindy Lu #include "net/vhost-vdpa.h" 21d5970055SMichael S. Tsirkin 2218658a3cSPaolo Bonzini #include "standard-headers/linux/vhost_types.h" 230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h" 240d09e41aSPaolo Bonzini #include "net/vhost_net.h" 25a6945f22SKevin Wolf #include "qapi/error.h" 261de7afc9SPaolo Bonzini #include "qemu/error-report.h" 27db725815SMarkus Armbruster #include "qemu/main-loop.h" 28d5970055SMichael S. Tsirkin 29d5970055SMichael S. Tsirkin #include <sys/socket.h> 30d5970055SMichael S. Tsirkin #include <net/if.h> 31d5970055SMichael S. Tsirkin #include <netinet/in.h> 32d5970055SMichael S. Tsirkin 33d5970055SMichael S. Tsirkin 344fbe0f32SMichael S. Tsirkin #include "standard-headers/linux/virtio_ring.h" 350d09e41aSPaolo Bonzini #include "hw/virtio/vhost.h" 361c819449SKONRAD Frederic #include "hw/virtio/virtio-bus.h" 3710f8a115SKangjie Xu #include "linux-headers/linux/vhost.h" 38d5970055SMichael S. Tsirkin 39d5970055SMichael S. Tsirkin 402e6d46d7SNikolay Nikolaev /* Features supported by host kernel. */ 412e6d46d7SNikolay Nikolaev static const int kernel_feature_bits[] = { 422e6d46d7SNikolay Nikolaev VIRTIO_F_NOTIFY_ON_EMPTY, 432e6d46d7SNikolay Nikolaev VIRTIO_RING_F_INDIRECT_DESC, 442e6d46d7SNikolay Nikolaev VIRTIO_RING_F_EVENT_IDX, 452e6d46d7SNikolay Nikolaev VIRTIO_NET_F_MRG_RXBUF, 46b1506132SMichael S. Tsirkin VIRTIO_F_VERSION_1, 4745a368adSMaxime Coquelin VIRTIO_NET_F_MTU, 48c471ad0eSJason Wang VIRTIO_F_IOMMU_PLATFORM, 49dfea7930SJason Wang VIRTIO_F_RING_PACKED, 502a3552baSKangjie Xu VIRTIO_F_RING_RESET, 51c03213fdSJonah Palmer VIRTIO_F_IN_ORDER, 52b937fa89SJonah Palmer VIRTIO_F_NOTIFICATION_DATA, 53f8e09b97SAkihiko Odaki VIRTIO_NET_F_RSC_EXT, 540145c393SAndrew Melnychenko VIRTIO_NET_F_HASH_REPORT, 552e6d46d7SNikolay Nikolaev VHOST_INVALID_FEATURE_BIT 562e6d46d7SNikolay Nikolaev }; 572e6d46d7SNikolay Nikolaev 585f4c01caSNikolay Nikolaev /* Features supported by others. */ 59d122f1a2SStefan Weil static const int user_feature_bits[] = { 605f4c01caSNikolay Nikolaev VIRTIO_F_NOTIFY_ON_EMPTY, 61b937fa89SJonah Palmer VIRTIO_F_NOTIFICATION_DATA, 625f4c01caSNikolay Nikolaev VIRTIO_RING_F_INDIRECT_DESC, 635f4c01caSNikolay Nikolaev VIRTIO_RING_F_EVENT_IDX, 645f4c01caSNikolay Nikolaev 655f4c01caSNikolay Nikolaev VIRTIO_F_ANY_LAYOUT, 66b1506132SMichael S. Tsirkin VIRTIO_F_VERSION_1, 675f4c01caSNikolay Nikolaev VIRTIO_NET_F_CSUM, 685f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_CSUM, 695f4c01caSNikolay Nikolaev VIRTIO_NET_F_GSO, 705f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_TSO4, 715f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_TSO6, 725f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_ECN, 735f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_UFO, 745f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_TSO4, 755f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_TSO6, 765f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_ECN, 775f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_UFO, 785f4c01caSNikolay Nikolaev VIRTIO_NET_F_MRG_RXBUF, 7945a368adSMaxime Coquelin VIRTIO_NET_F_MTU, 806dcdd06eSMaxime Coquelin VIRTIO_F_IOMMU_PLATFORM, 81dfea7930SJason Wang VIRTIO_F_RING_PACKED, 82562a7d23SStefano Garzarella VIRTIO_F_RING_RESET, 83c03213fdSJonah Palmer VIRTIO_F_IN_ORDER, 840145c393SAndrew Melnychenko VIRTIO_NET_F_RSS, 85f8e09b97SAkihiko Odaki VIRTIO_NET_F_RSC_EXT, 860145c393SAndrew Melnychenko VIRTIO_NET_F_HASH_REPORT, 879da16849SAndrew Melnychenko VIRTIO_NET_F_GUEST_USO4, 889da16849SAndrew Melnychenko VIRTIO_NET_F_GUEST_USO6, 899da16849SAndrew Melnychenko VIRTIO_NET_F_HOST_USO, 905f4c01caSNikolay Nikolaev 9172018d1eSMichael S. Tsirkin /* This bit implies RARP isn't sent by QEMU out of band */ 92f6f56291SThibaut Collet VIRTIO_NET_F_GUEST_ANNOUNCE, 93f6f56291SThibaut Collet 945f4c01caSNikolay Nikolaev VIRTIO_NET_F_MQ, 955f4c01caSNikolay Nikolaev 965f4c01caSNikolay Nikolaev VHOST_INVALID_FEATURE_BIT 975f4c01caSNikolay Nikolaev }; 985f4c01caSNikolay Nikolaev 992e6d46d7SNikolay Nikolaev static const int *vhost_net_get_feature_bits(struct vhost_net *net) 1002e6d46d7SNikolay Nikolaev { 1012e6d46d7SNikolay Nikolaev const int *feature_bits = 0; 1022e6d46d7SNikolay Nikolaev 1032e6d46d7SNikolay Nikolaev switch (net->nc->info->type) { 104f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 1052e6d46d7SNikolay Nikolaev feature_bits = kernel_feature_bits; 1062e6d46d7SNikolay Nikolaev break; 107f394b2e2SEric Blake case NET_CLIENT_DRIVER_VHOST_USER: 1085f4c01caSNikolay Nikolaev feature_bits = user_feature_bits; 1095f4c01caSNikolay Nikolaev break; 110108a6481SCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 111108a6481SCindy Lu case NET_CLIENT_DRIVER_VHOST_VDPA: 112108a6481SCindy Lu feature_bits = vdpa_feature_bits; 113108a6481SCindy Lu break; 114108a6481SCindy Lu #endif 1152e6d46d7SNikolay Nikolaev default: 1162e6d46d7SNikolay Nikolaev error_report("Feature bits not defined for this type: %d", 1172e6d46d7SNikolay Nikolaev net->nc->info->type); 1182e6d46d7SNikolay Nikolaev break; 1192e6d46d7SNikolay Nikolaev } 1202e6d46d7SNikolay Nikolaev 1212e6d46d7SNikolay Nikolaev return feature_bits; 1222e6d46d7SNikolay Nikolaev } 1232e6d46d7SNikolay Nikolaev 1249a2ba823SCornelia Huck uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) 125d5970055SMichael S. Tsirkin { 1262e6d46d7SNikolay Nikolaev return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net), 1272e6d46d7SNikolay Nikolaev features); 128d5970055SMichael S. Tsirkin } 12938140cc4SCindy Lu int vhost_net_get_config(struct vhost_net *net, uint8_t *config, 13038140cc4SCindy Lu uint32_t config_len) 13138140cc4SCindy Lu { 13250de5138SKevin Wolf return vhost_dev_get_config(&net->dev, config, config_len, NULL); 13338140cc4SCindy Lu } 13438140cc4SCindy Lu int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, 13538140cc4SCindy Lu uint32_t offset, uint32_t size, uint32_t flags) 13638140cc4SCindy Lu { 13738140cc4SCindy Lu return vhost_dev_set_config(&net->dev, data, offset, size, flags); 13838140cc4SCindy Lu } 139d5970055SMichael S. Tsirkin 1409a2ba823SCornelia Huck void vhost_net_ack_features(struct vhost_net *net, uint64_t features) 141d5970055SMichael S. Tsirkin { 142b49ae913SJason Wang net->dev.acked_features = net->dev.backend_features; 1432e6d46d7SNikolay Nikolaev vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features); 144d5970055SMichael S. Tsirkin } 145d5970055SMichael S. Tsirkin 146e2051e9eSYuanhan Liu uint64_t vhost_net_get_max_queues(VHostNetState *net) 147e2051e9eSYuanhan Liu { 148e2051e9eSYuanhan Liu return net->dev.max_queues; 149e2051e9eSYuanhan Liu } 150e2051e9eSYuanhan Liu 151a463215bSMarc-André Lureau uint64_t vhost_net_get_acked_features(VHostNetState *net) 152a463215bSMarc-André Lureau { 153a463215bSMarc-André Lureau return net->dev.acked_features; 154a463215bSMarc-André Lureau } 155a463215bSMarc-André Lureau 156c9bdc449SHyman Huang(黄勇) void vhost_net_save_acked_features(NetClientState *nc) 157c9bdc449SHyman Huang(黄勇) { 158c9bdc449SHyman Huang(黄勇) #ifdef CONFIG_VHOST_NET_USER 159c9bdc449SHyman Huang(黄勇) if (nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 160c9bdc449SHyman Huang(黄勇) vhost_user_save_acked_features(nc); 161c9bdc449SHyman Huang(黄勇) } 162c9bdc449SHyman Huang(黄勇) #endif 163c9bdc449SHyman Huang(黄勇) } 164c9bdc449SHyman Huang(黄勇) 165*6166799fSzuoboqun static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev, 166*6166799fSzuoboqun NetClientState *ncs, int data_queue_pairs, int nvhosts) 167*6166799fSzuoboqun { 168*6166799fSzuoboqun VirtIONet *n = VIRTIO_NET(dev); 169*6166799fSzuoboqun BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 170*6166799fSzuoboqun struct vhost_net *net; 171*6166799fSzuoboqun struct vhost_dev *hdev; 172*6166799fSzuoboqun int r, i, j; 173*6166799fSzuoboqun NetClientState *peer; 174*6166799fSzuoboqun 175*6166799fSzuoboqun /* 176*6166799fSzuoboqun * Batch all the host notifiers in a single transaction to avoid 177*6166799fSzuoboqun * quadratic time complexity in address_space_update_ioeventfds(). 178*6166799fSzuoboqun */ 179*6166799fSzuoboqun memory_region_transaction_begin(); 180*6166799fSzuoboqun 181*6166799fSzuoboqun for (i = 0; i < nvhosts; i++) { 182*6166799fSzuoboqun if (i < data_queue_pairs) { 183*6166799fSzuoboqun peer = qemu_get_peer(ncs, i); 184*6166799fSzuoboqun } else { 185*6166799fSzuoboqun peer = qemu_get_peer(ncs, n->max_queue_pairs); 186*6166799fSzuoboqun } 187*6166799fSzuoboqun 188*6166799fSzuoboqun net = get_vhost_net(peer); 189*6166799fSzuoboqun hdev = &net->dev; 190*6166799fSzuoboqun for (j = 0; j < hdev->nvqs; j++) { 191*6166799fSzuoboqun r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 192*6166799fSzuoboqun hdev->vq_index + j, 193*6166799fSzuoboqun false); 194*6166799fSzuoboqun if (r < 0) { 195*6166799fSzuoboqun error_report("vhost %d VQ %d notifier cleanup failed: %d", 196*6166799fSzuoboqun i, j, -r); 197*6166799fSzuoboqun } 198*6166799fSzuoboqun assert(r >= 0); 199*6166799fSzuoboqun } 200*6166799fSzuoboqun } 201*6166799fSzuoboqun /* 202*6166799fSzuoboqun * The transaction expects the ioeventfds to be open when it 203*6166799fSzuoboqun * commits. Do it now, before the cleanup loop. 204*6166799fSzuoboqun */ 205*6166799fSzuoboqun memory_region_transaction_commit(); 206*6166799fSzuoboqun 207*6166799fSzuoboqun for (i = 0; i < nvhosts; i++) { 208*6166799fSzuoboqun if (i < data_queue_pairs) { 209*6166799fSzuoboqun peer = qemu_get_peer(ncs, i); 210*6166799fSzuoboqun } else { 211*6166799fSzuoboqun peer = qemu_get_peer(ncs, n->max_queue_pairs); 212*6166799fSzuoboqun } 213*6166799fSzuoboqun 214*6166799fSzuoboqun net = get_vhost_net(peer); 215*6166799fSzuoboqun hdev = &net->dev; 216*6166799fSzuoboqun for (j = 0; j < hdev->nvqs; j++) { 217*6166799fSzuoboqun virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), 218*6166799fSzuoboqun hdev->vq_index + j); 219*6166799fSzuoboqun } 220*6166799fSzuoboqun virtio_device_release_ioeventfd(dev); 221*6166799fSzuoboqun } 222*6166799fSzuoboqun } 223*6166799fSzuoboqun 224*6166799fSzuoboqun static int vhost_net_enable_notifiers(VirtIODevice *dev, 225*6166799fSzuoboqun NetClientState *ncs, int data_queue_pairs, int cvq) 226*6166799fSzuoboqun { 227*6166799fSzuoboqun VirtIONet *n = VIRTIO_NET(dev); 228*6166799fSzuoboqun BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 229*6166799fSzuoboqun int nvhosts = data_queue_pairs + cvq; 230*6166799fSzuoboqun struct vhost_net *net; 231*6166799fSzuoboqun struct vhost_dev *hdev; 232*6166799fSzuoboqun int r, i, j; 233*6166799fSzuoboqun NetClientState *peer; 234*6166799fSzuoboqun 235*6166799fSzuoboqun /* 236*6166799fSzuoboqun * Batch all the host notifiers in a single transaction to avoid 237*6166799fSzuoboqun * quadratic time complexity in address_space_update_ioeventfds(). 238*6166799fSzuoboqun */ 239*6166799fSzuoboqun memory_region_transaction_begin(); 240*6166799fSzuoboqun 241*6166799fSzuoboqun for (i = 0; i < nvhosts; i++) { 242*6166799fSzuoboqun if (i < data_queue_pairs) { 243*6166799fSzuoboqun peer = qemu_get_peer(ncs, i); 244*6166799fSzuoboqun } else { 245*6166799fSzuoboqun peer = qemu_get_peer(ncs, n->max_queue_pairs); 246*6166799fSzuoboqun } 247*6166799fSzuoboqun 248*6166799fSzuoboqun net = get_vhost_net(peer); 249*6166799fSzuoboqun hdev = &net->dev; 250*6166799fSzuoboqun /* 251*6166799fSzuoboqun * We will pass the notifiers to the kernel, make sure that QEMU 252*6166799fSzuoboqun * doesn't interfere. 253*6166799fSzuoboqun */ 254*6166799fSzuoboqun r = virtio_device_grab_ioeventfd(dev); 255*6166799fSzuoboqun if (r < 0) { 256*6166799fSzuoboqun error_report("binding does not support host notifiers"); 257*6166799fSzuoboqun memory_region_transaction_commit(); 258*6166799fSzuoboqun goto fail_nvhosts; 259*6166799fSzuoboqun } 260*6166799fSzuoboqun 261*6166799fSzuoboqun for (j = 0; j < hdev->nvqs; j++) { 262*6166799fSzuoboqun r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 263*6166799fSzuoboqun hdev->vq_index + j, 264*6166799fSzuoboqun true); 265*6166799fSzuoboqun if (r < 0) { 266*6166799fSzuoboqun error_report("vhost %d VQ %d notifier binding failed: %d", 267*6166799fSzuoboqun i, j, -r); 268*6166799fSzuoboqun memory_region_transaction_commit(); 269*6166799fSzuoboqun vhost_dev_disable_notifiers_nvqs(hdev, dev, j); 270*6166799fSzuoboqun goto fail_nvhosts; 271*6166799fSzuoboqun } 272*6166799fSzuoboqun } 273*6166799fSzuoboqun } 274*6166799fSzuoboqun 275*6166799fSzuoboqun memory_region_transaction_commit(); 276*6166799fSzuoboqun 277*6166799fSzuoboqun return 0; 278*6166799fSzuoboqun fail_nvhosts: 279*6166799fSzuoboqun vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i); 280*6166799fSzuoboqun return r; 281*6166799fSzuoboqun } 282*6166799fSzuoboqun 283*6166799fSzuoboqun /* 284*6166799fSzuoboqun * Stop processing guest IO notifications in qemu. 285*6166799fSzuoboqun * Start processing them in vhost in kernel. 286*6166799fSzuoboqun */ 287*6166799fSzuoboqun static void vhost_net_disable_notifiers(VirtIODevice *dev, 288*6166799fSzuoboqun NetClientState *ncs, int data_queue_pairs, int cvq) 289*6166799fSzuoboqun { 290*6166799fSzuoboqun vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, 291*6166799fSzuoboqun data_queue_pairs + cvq); 292*6166799fSzuoboqun } 293*6166799fSzuoboqun 2944e68f7a0SStefan Hajnoczi static int vhost_net_get_fd(NetClientState *backend) 295d5970055SMichael S. Tsirkin { 296d5970055SMichael S. Tsirkin switch (backend->info->type) { 297f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 298d5970055SMichael S. Tsirkin return tap_get_fd(backend); 299d5970055SMichael S. Tsirkin default: 300d5970055SMichael S. Tsirkin fprintf(stderr, "vhost-net requires tap backend\n"); 301af3bba76SPaolo Bonzini return -ENOSYS; 302d5970055SMichael S. Tsirkin } 303d5970055SMichael S. Tsirkin } 304d5970055SMichael S. Tsirkin 30581647a65SNikolay Nikolaev struct vhost_net *vhost_net_init(VhostNetOptions *options) 306d5970055SMichael S. Tsirkin { 307d5970055SMichael S. Tsirkin int r; 3081a1bfac9SNikolay Nikolaev bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL; 309f1a0365bSMarc-André Lureau struct vhost_net *net = g_new0(struct vhost_net, 1); 310a463215bSMarc-André Lureau uint64_t features = 0; 311a6945f22SKevin Wolf Error *local_err = NULL; 31281647a65SNikolay Nikolaev 31381647a65SNikolay Nikolaev if (!options->net_backend) { 31481647a65SNikolay Nikolaev fprintf(stderr, "vhost-net requires net backend to be setup\n"); 315d5970055SMichael S. Tsirkin goto fail; 316d5970055SMichael S. Tsirkin } 317b931bfbfSChangchun Ouyang net->nc = options->net_backend; 3186a756d14SJason Wang net->dev.nvqs = options->nvqs; 31981647a65SNikolay Nikolaev 320e2051e9eSYuanhan Liu net->dev.max_queues = 1; 321b931bfbfSChangchun Ouyang net->dev.vqs = net->vqs; 322e2051e9eSYuanhan Liu 3231a1bfac9SNikolay Nikolaev if (backend_kernel) { 32481647a65SNikolay Nikolaev r = vhost_net_get_fd(options->net_backend); 325d5970055SMichael S. Tsirkin if (r < 0) { 326d5970055SMichael S. Tsirkin goto fail; 327d5970055SMichael S. Tsirkin } 3281a1bfac9SNikolay Nikolaev net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend) 3299a2ba823SCornelia Huck ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR); 330d5970055SMichael S. Tsirkin net->backend = r; 331dcb10c00SMichael S. Tsirkin net->dev.protocol_features = 0; 3321a1bfac9SNikolay Nikolaev } else { 3331a1bfac9SNikolay Nikolaev net->dev.backend_features = 0; 334dcb10c00SMichael S. Tsirkin net->dev.protocol_features = 0; 3351a1bfac9SNikolay Nikolaev net->backend = -1; 336d5970055SMichael S. Tsirkin 337b931bfbfSChangchun Ouyang /* vhost-user needs vq_index to initiate a specific queue pair */ 338b931bfbfSChangchun Ouyang net->dev.vq_index = net->nc->queue_index * net->dev.nvqs; 339b931bfbfSChangchun Ouyang } 340f56a1247SMichael S. Tsirkin 34181647a65SNikolay Nikolaev r = vhost_dev_init(&net->dev, options->opaque, 342a6945f22SKevin Wolf options->backend_type, options->busyloop_timeout, 343a6945f22SKevin Wolf &local_err); 344d5970055SMichael S. Tsirkin if (r < 0) { 345a6945f22SKevin Wolf error_report_err(local_err); 346d5970055SMichael S. Tsirkin goto fail; 347d5970055SMichael S. Tsirkin } 348d8e80ae3SDamjan Marion if (backend_kernel) { 34981647a65SNikolay Nikolaev if (!qemu_has_vnet_hdr_len(options->net_backend, 350ca736c8eSMichael S. Tsirkin sizeof(struct virtio_net_hdr_mrg_rxbuf))) { 3519a2ba823SCornelia Huck net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); 352ca736c8eSMichael S. Tsirkin } 353d5970055SMichael S. Tsirkin if (~net->dev.features & net->dev.backend_features) { 3541eed051cSIlya Maximets fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 3551a1bfac9SNikolay Nikolaev " for backend\n", 35629f91781SJes Sorensen (uint64_t)(~net->dev.features & net->dev.backend_features)); 357d5970055SMichael S. Tsirkin goto fail; 358d5970055SMichael S. Tsirkin } 3591a1bfac9SNikolay Nikolaev } 360a463215bSMarc-André Lureau 361d5970055SMichael S. Tsirkin /* Set sane init value. Override when guest acks. */ 36256f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 363f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 364a463215bSMarc-André Lureau features = vhost_user_get_acked_features(net->nc); 365a463215bSMarc-André Lureau if (~net->dev.features & features) { 3661eed051cSIlya Maximets fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 367a463215bSMarc-André Lureau " for backend\n", 368a463215bSMarc-André Lureau (uint64_t)(~net->dev.features & features)); 369a463215bSMarc-André Lureau goto fail; 370a463215bSMarc-André Lureau } 371a463215bSMarc-André Lureau } 37256f41de7SPaolo Bonzini #endif 373a463215bSMarc-André Lureau 374a463215bSMarc-André Lureau vhost_net_ack_features(net, features); 375a463215bSMarc-André Lureau 376d5970055SMichael S. Tsirkin return net; 377f1a0365bSMarc-André Lureau 378d5970055SMichael S. Tsirkin fail: 379f1a0365bSMarc-André Lureau vhost_dev_cleanup(&net->dev); 3807267c094SAnthony Liguori g_free(net); 381d5970055SMichael S. Tsirkin return NULL; 382d5970055SMichael S. Tsirkin } 383d5970055SMichael S. Tsirkin 384049eb15bSJason Wang static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index, 385245cf2c2SEugenio Pérez int vq_index_end) 386cd7d1d26SJason Wang { 387cd7d1d26SJason Wang net->dev.vq_index = vq_index; 388245cf2c2SEugenio Pérez net->dev.vq_index_end = vq_index_end; 389cd7d1d26SJason Wang } 390cd7d1d26SJason Wang 391a9f98bb5SJason Wang static int vhost_net_start_one(struct vhost_net *net, 392cd7d1d26SJason Wang VirtIODevice *dev) 393d5970055SMichael S. Tsirkin { 394d5970055SMichael S. Tsirkin struct vhost_vring_file file = { }; 395d5970055SMichael S. Tsirkin int r; 396b0b3db79SMichael S. Tsirkin 397eb92b753SEugenio Pérez if (net->nc->info->start) { 398eb92b753SEugenio Pérez r = net->nc->info->start(net->nc); 399eb92b753SEugenio Pérez if (r < 0) { 400eb92b753SEugenio Pérez return r; 401eb92b753SEugenio Pérez } 402eb92b753SEugenio Pérez } 403eb92b753SEugenio Pérez 4044daa5054SStefano Garzarella r = vhost_dev_start(&net->dev, dev, false); 405d5970055SMichael S. Tsirkin if (r < 0) { 406b0b3db79SMichael S. Tsirkin goto fail_start; 407d5970055SMichael S. Tsirkin } 408d5970055SMichael S. Tsirkin 409212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 41035277d14SStefan Hajnoczi net->nc->info->poll(net->nc, false); 411212d69f2SNikolay Nikolaev } 412212d69f2SNikolay Nikolaev 413f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 414d5970055SMichael S. Tsirkin qemu_set_fd_handler(net->backend, NULL, NULL, NULL); 415d5970055SMichael S. Tsirkin file.fd = net->backend; 416d5970055SMichael S. Tsirkin for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 41723bfaf77SJason Wang if (!virtio_queue_enabled(dev, net->dev.vq_index + 41823bfaf77SJason Wang file.index)) { 41923bfaf77SJason Wang /* Queue might not be ready for start */ 42023bfaf77SJason Wang continue; 42123bfaf77SJason Wang } 422950d94baSMarc-André Lureau r = vhost_net_set_backend(&net->dev, &file); 423d5970055SMichael S. Tsirkin if (r < 0) { 424d5970055SMichael S. Tsirkin r = -errno; 425d5970055SMichael S. Tsirkin goto fail; 426d5970055SMichael S. Tsirkin } 427d5970055SMichael S. Tsirkin } 4281a1bfac9SNikolay Nikolaev } 429539573c3SEugenio Pérez 430539573c3SEugenio Pérez if (net->nc->info->load) { 431539573c3SEugenio Pérez r = net->nc->info->load(net->nc); 432539573c3SEugenio Pérez if (r < 0) { 433539573c3SEugenio Pérez goto fail; 434539573c3SEugenio Pérez } 435539573c3SEugenio Pérez } 436d5970055SMichael S. Tsirkin return 0; 437d5970055SMichael S. Tsirkin fail: 438d5970055SMichael S. Tsirkin file.fd = -1; 439f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 4406b37c87cSMichael S. Tsirkin while (file.index-- > 0) { 44123bfaf77SJason Wang if (!virtio_queue_enabled(dev, net->dev.vq_index + 44223bfaf77SJason Wang file.index)) { 44323bfaf77SJason Wang /* Queue might not be ready for start */ 44423bfaf77SJason Wang continue; 44523bfaf77SJason Wang } 4465d63cb15SThomas Huth int ret = vhost_net_set_backend(&net->dev, &file); 4475d63cb15SThomas Huth assert(ret >= 0); 448d5970055SMichael S. Tsirkin } 4491a1bfac9SNikolay Nikolaev } 450212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 45135277d14SStefan Hajnoczi net->nc->info->poll(net->nc, true); 452212d69f2SNikolay Nikolaev } 4534daa5054SStefano Garzarella vhost_dev_stop(&net->dev, dev, false); 454b0b3db79SMichael S. Tsirkin fail_start: 455d5970055SMichael S. Tsirkin return r; 456d5970055SMichael S. Tsirkin } 457d5970055SMichael S. Tsirkin 458a9f98bb5SJason Wang static void vhost_net_stop_one(struct vhost_net *net, 459d5970055SMichael S. Tsirkin VirtIODevice *dev) 460d5970055SMichael S. Tsirkin { 461d5970055SMichael S. Tsirkin struct vhost_vring_file file = { .fd = -1 }; 462d5970055SMichael S. Tsirkin 463f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 464d5970055SMichael S. Tsirkin for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 465950d94baSMarc-André Lureau int r = vhost_net_set_backend(&net->dev, &file); 466d5970055SMichael S. Tsirkin assert(r >= 0); 467d5970055SMichael S. Tsirkin } 4681a1bfac9SNikolay Nikolaev } 469212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 47035277d14SStefan Hajnoczi net->nc->info->poll(net->nc, true); 471212d69f2SNikolay Nikolaev } 4724daa5054SStefano Garzarella vhost_dev_stop(&net->dev, dev, false); 473c5e5269dSEugenio Pérez if (net->nc->info->stop) { 474c5e5269dSEugenio Pérez net->nc->info->stop(net->nc); 475c5e5269dSEugenio Pérez } 476d5970055SMichael S. Tsirkin } 477d5970055SMichael S. Tsirkin 478a9f98bb5SJason Wang int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, 47905ba3f63SJason Wang int data_queue_pairs, int cvq) 480a9f98bb5SJason Wang { 4811c819449SKONRAD Frederic BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 4821c819449SKONRAD Frederic VirtioBusState *vbus = VIRTIO_BUS(qbus); 4831c819449SKONRAD Frederic VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); 48405ba3f63SJason Wang int total_notifiers = data_queue_pairs * 2 + cvq; 48505ba3f63SJason Wang VirtIONet *n = VIRTIO_NET(dev); 48605ba3f63SJason Wang int nvhosts = data_queue_pairs + cvq; 48792fbc3e0SCindy Lu struct vhost_net *net; 48814c81b21SEugenio Pérez int r, e, i, index_end = data_queue_pairs * 2; 48992fbc3e0SCindy Lu NetClientState *peer; 490a9f98bb5SJason Wang 49114c81b21SEugenio Pérez if (cvq) { 49214c81b21SEugenio Pérez index_end += 1; 493049eb15bSJason Wang } 494049eb15bSJason Wang 4951c819449SKONRAD Frederic if (!k->set_guest_notifiers) { 496312fd5f2SMarkus Armbruster error_report("binding does not support guest notifiers"); 497a4076440SLaurent Vivier return -ENOSYS; 498a9f98bb5SJason Wang } 499a9f98bb5SJason Wang 50005ba3f63SJason Wang for (i = 0; i < nvhosts; i++) { 5015669655aSVictor Kaplansky 50205ba3f63SJason Wang if (i < data_queue_pairs) { 50392fbc3e0SCindy Lu peer = qemu_get_peer(ncs, i); 50405ba3f63SJason Wang } else { /* Control Virtqueue */ 505441537f1SJason Wang peer = qemu_get_peer(ncs, n->max_queue_pairs); 50605ba3f63SJason Wang } 50705ba3f63SJason Wang 50892fbc3e0SCindy Lu net = get_vhost_net(peer); 50914c81b21SEugenio Pérez vhost_net_set_vq_index(net, i * 2, index_end); 5105669655aSVictor Kaplansky 5115669655aSVictor Kaplansky /* Suppress the masking guest notifiers on vhost user 5125669655aSVictor Kaplansky * because vhost user doesn't interrupt masking/unmasking 5135669655aSVictor Kaplansky * properly. 5145669655aSVictor Kaplansky */ 515f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 5165669655aSVictor Kaplansky dev->use_guest_notifier_mask = false; 5175669655aSVictor Kaplansky } 518a9f98bb5SJason Wang } 519a9f98bb5SJason Wang 520*6166799fSzuoboqun r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq); 521*6166799fSzuoboqun if (r < 0) { 522*6166799fSzuoboqun error_report("Error enabling host notifiers: %d", -r); 523*6166799fSzuoboqun goto err; 524*6166799fSzuoboqun } 525*6166799fSzuoboqun 52605ba3f63SJason Wang r = k->set_guest_notifiers(qbus->parent, total_notifiers, true); 527a9f98bb5SJason Wang if (r < 0) { 528312fd5f2SMarkus Armbruster error_report("Error binding guest notifier: %d", -r); 529*6166799fSzuoboqun goto err_host_notifiers; 530a9f98bb5SJason Wang } 531a9f98bb5SJason Wang 53205ba3f63SJason Wang for (i = 0; i < nvhosts; i++) { 53305ba3f63SJason Wang if (i < data_queue_pairs) { 53492fbc3e0SCindy Lu peer = qemu_get_peer(ncs, i); 53505ba3f63SJason Wang } else { 536441537f1SJason Wang peer = qemu_get_peer(ncs, n->max_queue_pairs); 53705ba3f63SJason Wang } 538bfc6cf31SMarc-André Lureau 53992fbc3e0SCindy Lu if (peer->vring_enable) { 540bfc6cf31SMarc-André Lureau /* restore vring enable state */ 54192fbc3e0SCindy Lu r = vhost_set_vring_enable(peer, peer->vring_enable); 542bfc6cf31SMarc-André Lureau 543bfc6cf31SMarc-André Lureau if (r < 0) { 544*6166799fSzuoboqun goto err_guest_notifiers; 545bfc6cf31SMarc-André Lureau } 546bfc6cf31SMarc-André Lureau } 5478b67fe00SYajun Wu 5488b67fe00SYajun Wu r = vhost_net_start_one(get_vhost_net(peer), dev); 5498b67fe00SYajun Wu if (r < 0) { 550*6166799fSzuoboqun goto err_guest_notifiers; 5518b67fe00SYajun Wu } 552cd7d1d26SJason Wang } 553cd7d1d26SJason Wang 554a9f98bb5SJason Wang return 0; 555a9f98bb5SJason Wang 556*6166799fSzuoboqun err_guest_notifiers: 557a9f98bb5SJason Wang while (--i >= 0) { 5586f3910b5SSi-Wei Liu peer = qemu_get_peer(ncs, i < data_queue_pairs ? 5596f3910b5SSi-Wei Liu i : n->max_queue_pairs); 56092fbc3e0SCindy Lu vhost_net_stop_one(get_vhost_net(peer), dev); 561a9f98bb5SJason Wang } 56205ba3f63SJason Wang e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); 563cd7d1d26SJason Wang if (e < 0) { 564cd7d1d26SJason Wang fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); 565cd7d1d26SJason Wang fflush(stderr); 566cd7d1d26SJason Wang } 567*6166799fSzuoboqun err_host_notifiers: 568*6166799fSzuoboqun vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); 5693154d1e4SGreg Kurz err: 570a9f98bb5SJason Wang return r; 571a9f98bb5SJason Wang } 572a9f98bb5SJason Wang 573a9f98bb5SJason Wang void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, 57405ba3f63SJason Wang int data_queue_pairs, int cvq) 575a9f98bb5SJason Wang { 5761c819449SKONRAD Frederic BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 5771c819449SKONRAD Frederic VirtioBusState *vbus = VIRTIO_BUS(qbus); 5781c819449SKONRAD Frederic VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); 57905ba3f63SJason Wang VirtIONet *n = VIRTIO_NET(dev); 58005ba3f63SJason Wang NetClientState *peer; 58105ba3f63SJason Wang int total_notifiers = data_queue_pairs * 2 + cvq; 58205ba3f63SJason Wang int nvhosts = data_queue_pairs + cvq; 583a9f98bb5SJason Wang int i, r; 584a9f98bb5SJason Wang 58505ba3f63SJason Wang for (i = 0; i < nvhosts; i++) { 58605ba3f63SJason Wang if (i < data_queue_pairs) { 58705ba3f63SJason Wang peer = qemu_get_peer(ncs, i); 58805ba3f63SJason Wang } else { 589441537f1SJason Wang peer = qemu_get_peer(ncs, n->max_queue_pairs); 59005ba3f63SJason Wang } 59105ba3f63SJason Wang vhost_net_stop_one(get_vhost_net(peer), dev); 592cd7d1d26SJason Wang } 593cd7d1d26SJason Wang 59405ba3f63SJason Wang r = k->set_guest_notifiers(qbus->parent, total_notifiers, false); 595a9f98bb5SJason Wang if (r < 0) { 596a9f98bb5SJason Wang fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); 597a9f98bb5SJason Wang fflush(stderr); 598a9f98bb5SJason Wang } 599a9f98bb5SJason Wang assert(r >= 0); 600*6166799fSzuoboqun 601*6166799fSzuoboqun vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); 602a9f98bb5SJason Wang } 603a9f98bb5SJason Wang 604d5970055SMichael S. Tsirkin void vhost_net_cleanup(struct vhost_net *net) 605d5970055SMichael S. Tsirkin { 606d5970055SMichael S. Tsirkin vhost_dev_cleanup(&net->dev); 607d5970055SMichael S. Tsirkin } 608f56a1247SMichael S. Tsirkin 6093e866365SThibaut Collet int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) 6103e866365SThibaut Collet { 6113e866365SThibaut Collet const VhostOps *vhost_ops = net->dev.vhost_ops; 6123e866365SThibaut Collet 61351f7aca9SMarc-André Lureau assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 61451f7aca9SMarc-André Lureau assert(vhost_ops->vhost_migration_done); 6153e866365SThibaut Collet 61651f7aca9SMarc-André Lureau return vhost_ops->vhost_migration_done(&net->dev, mac_addr); 6173e866365SThibaut Collet } 6183e866365SThibaut Collet 619f56a1247SMichael S. Tsirkin bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) 620f56a1247SMichael S. Tsirkin { 621f56a1247SMichael S. Tsirkin return vhost_virtqueue_pending(&net->dev, idx); 622f56a1247SMichael S. Tsirkin } 623f56a1247SMichael S. Tsirkin 624f56a1247SMichael S. Tsirkin void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, 625f56a1247SMichael S. Tsirkin int idx, bool mask) 626f56a1247SMichael S. Tsirkin { 627f56a1247SMichael S. Tsirkin vhost_virtqueue_mask(&net->dev, dev, idx, mask); 628f56a1247SMichael S. Tsirkin } 629ed8b4afeSNikolay Nikolaev 6308aab0d1dSCindy Lu bool vhost_net_config_pending(VHostNetState *net) 6318aab0d1dSCindy Lu { 6328aab0d1dSCindy Lu return vhost_config_pending(&net->dev); 6338aab0d1dSCindy Lu } 6348aab0d1dSCindy Lu 6358aab0d1dSCindy Lu void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) 6368aab0d1dSCindy Lu { 6378aab0d1dSCindy Lu vhost_config_mask(&net->dev, dev, mask); 6388aab0d1dSCindy Lu } 639ed8b4afeSNikolay Nikolaev VHostNetState *get_vhost_net(NetClientState *nc) 640ed8b4afeSNikolay Nikolaev { 641ed8b4afeSNikolay Nikolaev VHostNetState *vhost_net = 0; 642ed8b4afeSNikolay Nikolaev 643ed8b4afeSNikolay Nikolaev if (!nc) { 644ed8b4afeSNikolay Nikolaev return 0; 645ed8b4afeSNikolay Nikolaev } 646ed8b4afeSNikolay Nikolaev 647ed8b4afeSNikolay Nikolaev switch (nc->info->type) { 648f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 649ed8b4afeSNikolay Nikolaev vhost_net = tap_get_vhost_net(nc); 650ca3fcdeeSAni Sinha /* 651ca3fcdeeSAni Sinha * tap_get_vhost_net() can return NULL if a tap net-device backend is 652ca3fcdeeSAni Sinha * created with 'vhost=off' option, 'vhostforce=off' or no vhost or 653ca3fcdeeSAni Sinha * vhostforce or vhostfd options at all. Please see net_init_tap_one(). 654ca3fcdeeSAni Sinha * Hence, we omit the assertion here. 655ca3fcdeeSAni Sinha */ 656ed8b4afeSNikolay Nikolaev break; 65756f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 658f394b2e2SEric Blake case NET_CLIENT_DRIVER_VHOST_USER: 65903ce5744SNikolay Nikolaev vhost_net = vhost_user_get_vhost_net(nc); 6601a5b68ceSMarc-André Lureau assert(vhost_net); 66103ce5744SNikolay Nikolaev break; 66256f41de7SPaolo Bonzini #endif 663108a6481SCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 664108a6481SCindy Lu case NET_CLIENT_DRIVER_VHOST_VDPA: 665108a6481SCindy Lu vhost_net = vhost_vdpa_get_vhost_net(nc); 666108a6481SCindy Lu assert(vhost_net); 667108a6481SCindy Lu break; 668108a6481SCindy Lu #endif 669ed8b4afeSNikolay Nikolaev default: 670ed8b4afeSNikolay Nikolaev break; 671ed8b4afeSNikolay Nikolaev } 672ed8b4afeSNikolay Nikolaev 673ed8b4afeSNikolay Nikolaev return vhost_net; 674ed8b4afeSNikolay Nikolaev } 6757263a0adSChangchun Ouyang 6767263a0adSChangchun Ouyang int vhost_set_vring_enable(NetClientState *nc, int enable) 6777263a0adSChangchun Ouyang { 6787263a0adSChangchun Ouyang VHostNetState *net = get_vhost_net(nc); 679bb12e761SMarc-André Lureau const VhostOps *vhost_ops = net->dev.vhost_ops; 6807263a0adSChangchun Ouyang 6812c66de61SKevin Wolf /* 6822c66de61SKevin Wolf * vhost-vdpa network devices need to enable dataplane virtqueues after 6832c66de61SKevin Wolf * DRIVER_OK, so they can recover device state before starting dataplane. 6842c66de61SKevin Wolf * Because of that, we don't enable virtqueues here and leave it to 6852c66de61SKevin Wolf * net/vhost-vdpa.c. 6862c66de61SKevin Wolf */ 6872c66de61SKevin Wolf if (nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { 6882c66de61SKevin Wolf return 0; 6892c66de61SKevin Wolf } 6902c66de61SKevin Wolf 691bfc6cf31SMarc-André Lureau nc->vring_enable = enable; 692bfc6cf31SMarc-André Lureau 693ca10203cSIlya Maximets if (vhost_ops && vhost_ops->vhost_set_vring_enable) { 69421e70425SMarc-André Lureau return vhost_ops->vhost_set_vring_enable(&net->dev, enable); 6957263a0adSChangchun Ouyang } 6967263a0adSChangchun Ouyang 6977263a0adSChangchun Ouyang return 0; 6987263a0adSChangchun Ouyang } 6997263a0adSChangchun Ouyang 70045a368adSMaxime Coquelin int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) 70145a368adSMaxime Coquelin { 70245a368adSMaxime Coquelin const VhostOps *vhost_ops = net->dev.vhost_ops; 70345a368adSMaxime Coquelin 70445a368adSMaxime Coquelin if (!vhost_ops->vhost_net_set_mtu) { 70545a368adSMaxime Coquelin return 0; 70645a368adSMaxime Coquelin } 70745a368adSMaxime Coquelin 70845a368adSMaxime Coquelin return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); 70945a368adSMaxime Coquelin } 710c2daa08eSKangjie Xu 711c2daa08eSKangjie Xu void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc, 712c2daa08eSKangjie Xu int vq_index) 713c2daa08eSKangjie Xu { 714c2daa08eSKangjie Xu VHostNetState *net = get_vhost_net(nc->peer); 715c2daa08eSKangjie Xu const VhostOps *vhost_ops = net->dev.vhost_ops; 716c2daa08eSKangjie Xu struct vhost_vring_file file = { .fd = -1 }; 717c2daa08eSKangjie Xu int idx; 718c2daa08eSKangjie Xu 719c2daa08eSKangjie Xu /* should only be called after backend is connected */ 720c2daa08eSKangjie Xu assert(vhost_ops); 721c2daa08eSKangjie Xu 722c2daa08eSKangjie Xu idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); 723c2daa08eSKangjie Xu 724c2daa08eSKangjie Xu if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 725c2daa08eSKangjie Xu file.index = idx; 726c2daa08eSKangjie Xu int r = vhost_net_set_backend(&net->dev, &file); 727c2daa08eSKangjie Xu assert(r >= 0); 728c2daa08eSKangjie Xu } 729c2daa08eSKangjie Xu 730c2daa08eSKangjie Xu vhost_virtqueue_stop(&net->dev, 731c2daa08eSKangjie Xu vdev, 732c2daa08eSKangjie Xu net->dev.vqs + idx, 733c2daa08eSKangjie Xu net->dev.vq_index + idx); 734c2daa08eSKangjie Xu } 73510f8a115SKangjie Xu 73610f8a115SKangjie Xu int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc, 73710f8a115SKangjie Xu int vq_index) 73810f8a115SKangjie Xu { 73910f8a115SKangjie Xu VHostNetState *net = get_vhost_net(nc->peer); 74010f8a115SKangjie Xu const VhostOps *vhost_ops = net->dev.vhost_ops; 74110f8a115SKangjie Xu struct vhost_vring_file file = { }; 74210f8a115SKangjie Xu int idx, r; 74310f8a115SKangjie Xu 74410f8a115SKangjie Xu if (!net->dev.started) { 74510f8a115SKangjie Xu return -EBUSY; 74610f8a115SKangjie Xu } 74710f8a115SKangjie Xu 74810f8a115SKangjie Xu /* should only be called after backend is connected */ 74910f8a115SKangjie Xu assert(vhost_ops); 75010f8a115SKangjie Xu 75110f8a115SKangjie Xu idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); 75210f8a115SKangjie Xu 75310f8a115SKangjie Xu r = vhost_virtqueue_start(&net->dev, 75410f8a115SKangjie Xu vdev, 75510f8a115SKangjie Xu net->dev.vqs + idx, 75610f8a115SKangjie Xu net->dev.vq_index + idx); 75710f8a115SKangjie Xu if (r < 0) { 75810f8a115SKangjie Xu goto err_start; 75910f8a115SKangjie Xu } 76010f8a115SKangjie Xu 76110f8a115SKangjie Xu if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 76210f8a115SKangjie Xu file.index = idx; 76310f8a115SKangjie Xu file.fd = net->backend; 76410f8a115SKangjie Xu r = vhost_net_set_backend(&net->dev, &file); 76510f8a115SKangjie Xu if (r < 0) { 76610f8a115SKangjie Xu r = -errno; 76710f8a115SKangjie Xu goto err_start; 76810f8a115SKangjie Xu } 76910f8a115SKangjie Xu } 77010f8a115SKangjie Xu 77110f8a115SKangjie Xu return 0; 77210f8a115SKangjie Xu 77310f8a115SKangjie Xu err_start: 77410f8a115SKangjie Xu error_report("Error when restarting the queue."); 77510f8a115SKangjie Xu 77610f8a115SKangjie Xu if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 77710f8a115SKangjie Xu file.fd = VHOST_FILE_UNBIND; 77810f8a115SKangjie Xu file.index = idx; 7795d63cb15SThomas Huth int ret = vhost_net_set_backend(&net->dev, &file); 7805d63cb15SThomas Huth assert(ret >= 0); 78110f8a115SKangjie Xu } 78210f8a115SKangjie Xu 7834daa5054SStefano Garzarella vhost_dev_stop(&net->dev, vdev, false); 78410f8a115SKangjie Xu 78510f8a115SKangjie Xu return r; 78610f8a115SKangjie Xu } 787