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" 251de7afc9SPaolo Bonzini #include "qemu/error-report.h" 26db725815SMarkus Armbruster #include "qemu/main-loop.h" 27d5970055SMichael S. Tsirkin 28d5970055SMichael S. Tsirkin #include <sys/socket.h> 29d5970055SMichael S. Tsirkin #include <net/if.h> 30d5970055SMichael S. Tsirkin #include <netinet/in.h> 31d5970055SMichael S. Tsirkin 32d5970055SMichael S. Tsirkin 334fbe0f32SMichael S. Tsirkin #include "standard-headers/linux/virtio_ring.h" 340d09e41aSPaolo Bonzini #include "hw/virtio/vhost.h" 351c819449SKONRAD Frederic #include "hw/virtio/virtio-bus.h" 36d5970055SMichael S. Tsirkin 37d5970055SMichael S. Tsirkin 382e6d46d7SNikolay Nikolaev /* Features supported by host kernel. */ 392e6d46d7SNikolay Nikolaev static const int kernel_feature_bits[] = { 402e6d46d7SNikolay Nikolaev VIRTIO_F_NOTIFY_ON_EMPTY, 412e6d46d7SNikolay Nikolaev VIRTIO_RING_F_INDIRECT_DESC, 422e6d46d7SNikolay Nikolaev VIRTIO_RING_F_EVENT_IDX, 432e6d46d7SNikolay Nikolaev VIRTIO_NET_F_MRG_RXBUF, 44b1506132SMichael S. Tsirkin VIRTIO_F_VERSION_1, 4545a368adSMaxime Coquelin VIRTIO_NET_F_MTU, 46c471ad0eSJason Wang VIRTIO_F_IOMMU_PLATFORM, 47dfea7930SJason Wang VIRTIO_F_RING_PACKED, 48*0145c393SAndrew Melnychenko VIRTIO_NET_F_HASH_REPORT, 492e6d46d7SNikolay Nikolaev VHOST_INVALID_FEATURE_BIT 502e6d46d7SNikolay Nikolaev }; 512e6d46d7SNikolay Nikolaev 525f4c01caSNikolay Nikolaev /* Features supported by others. */ 53d122f1a2SStefan Weil static const int user_feature_bits[] = { 545f4c01caSNikolay Nikolaev VIRTIO_F_NOTIFY_ON_EMPTY, 555f4c01caSNikolay Nikolaev VIRTIO_RING_F_INDIRECT_DESC, 565f4c01caSNikolay Nikolaev VIRTIO_RING_F_EVENT_IDX, 575f4c01caSNikolay Nikolaev 585f4c01caSNikolay Nikolaev VIRTIO_F_ANY_LAYOUT, 59b1506132SMichael S. Tsirkin VIRTIO_F_VERSION_1, 605f4c01caSNikolay Nikolaev VIRTIO_NET_F_CSUM, 615f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_CSUM, 625f4c01caSNikolay Nikolaev VIRTIO_NET_F_GSO, 635f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_TSO4, 645f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_TSO6, 655f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_ECN, 665f4c01caSNikolay Nikolaev VIRTIO_NET_F_GUEST_UFO, 675f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_TSO4, 685f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_TSO6, 695f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_ECN, 705f4c01caSNikolay Nikolaev VIRTIO_NET_F_HOST_UFO, 715f4c01caSNikolay Nikolaev VIRTIO_NET_F_MRG_RXBUF, 7245a368adSMaxime Coquelin VIRTIO_NET_F_MTU, 736dcdd06eSMaxime Coquelin VIRTIO_F_IOMMU_PLATFORM, 74dfea7930SJason Wang VIRTIO_F_RING_PACKED, 75*0145c393SAndrew Melnychenko VIRTIO_NET_F_RSS, 76*0145c393SAndrew Melnychenko VIRTIO_NET_F_HASH_REPORT, 775f4c01caSNikolay Nikolaev 7872018d1eSMichael S. Tsirkin /* This bit implies RARP isn't sent by QEMU out of band */ 79f6f56291SThibaut Collet VIRTIO_NET_F_GUEST_ANNOUNCE, 80f6f56291SThibaut Collet 815f4c01caSNikolay Nikolaev VIRTIO_NET_F_MQ, 825f4c01caSNikolay Nikolaev 835f4c01caSNikolay Nikolaev VHOST_INVALID_FEATURE_BIT 845f4c01caSNikolay Nikolaev }; 855f4c01caSNikolay Nikolaev 862e6d46d7SNikolay Nikolaev static const int *vhost_net_get_feature_bits(struct vhost_net *net) 872e6d46d7SNikolay Nikolaev { 882e6d46d7SNikolay Nikolaev const int *feature_bits = 0; 892e6d46d7SNikolay Nikolaev 902e6d46d7SNikolay Nikolaev switch (net->nc->info->type) { 91f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 922e6d46d7SNikolay Nikolaev feature_bits = kernel_feature_bits; 932e6d46d7SNikolay Nikolaev break; 94f394b2e2SEric Blake case NET_CLIENT_DRIVER_VHOST_USER: 955f4c01caSNikolay Nikolaev feature_bits = user_feature_bits; 965f4c01caSNikolay Nikolaev break; 97108a6481SCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 98108a6481SCindy Lu case NET_CLIENT_DRIVER_VHOST_VDPA: 99108a6481SCindy Lu feature_bits = vdpa_feature_bits; 100108a6481SCindy Lu break; 101108a6481SCindy Lu #endif 1022e6d46d7SNikolay Nikolaev default: 1032e6d46d7SNikolay Nikolaev error_report("Feature bits not defined for this type: %d", 1042e6d46d7SNikolay Nikolaev net->nc->info->type); 1052e6d46d7SNikolay Nikolaev break; 1062e6d46d7SNikolay Nikolaev } 1072e6d46d7SNikolay Nikolaev 1082e6d46d7SNikolay Nikolaev return feature_bits; 1092e6d46d7SNikolay Nikolaev } 1102e6d46d7SNikolay Nikolaev 1119a2ba823SCornelia Huck uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) 112d5970055SMichael S. Tsirkin { 1132e6d46d7SNikolay Nikolaev return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net), 1142e6d46d7SNikolay Nikolaev features); 115d5970055SMichael S. Tsirkin } 11638140cc4SCindy Lu int vhost_net_get_config(struct vhost_net *net, uint8_t *config, 11738140cc4SCindy Lu uint32_t config_len) 11838140cc4SCindy Lu { 11938140cc4SCindy Lu return vhost_dev_get_config(&net->dev, config, config_len); 12038140cc4SCindy Lu } 12138140cc4SCindy Lu int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, 12238140cc4SCindy Lu uint32_t offset, uint32_t size, uint32_t flags) 12338140cc4SCindy Lu { 12438140cc4SCindy Lu return vhost_dev_set_config(&net->dev, data, offset, size, flags); 12538140cc4SCindy Lu } 126d5970055SMichael S. Tsirkin 1279a2ba823SCornelia Huck void vhost_net_ack_features(struct vhost_net *net, uint64_t features) 128d5970055SMichael S. Tsirkin { 129b49ae913SJason Wang net->dev.acked_features = net->dev.backend_features; 1302e6d46d7SNikolay Nikolaev vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features); 131d5970055SMichael S. Tsirkin } 132d5970055SMichael S. Tsirkin 133e2051e9eSYuanhan Liu uint64_t vhost_net_get_max_queues(VHostNetState *net) 134e2051e9eSYuanhan Liu { 135e2051e9eSYuanhan Liu return net->dev.max_queues; 136e2051e9eSYuanhan Liu } 137e2051e9eSYuanhan Liu 138a463215bSMarc-André Lureau uint64_t vhost_net_get_acked_features(VHostNetState *net) 139a463215bSMarc-André Lureau { 140a463215bSMarc-André Lureau return net->dev.acked_features; 141a463215bSMarc-André Lureau } 142a463215bSMarc-André Lureau 1434e68f7a0SStefan Hajnoczi static int vhost_net_get_fd(NetClientState *backend) 144d5970055SMichael S. Tsirkin { 145d5970055SMichael S. Tsirkin switch (backend->info->type) { 146f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 147d5970055SMichael S. Tsirkin return tap_get_fd(backend); 148d5970055SMichael S. Tsirkin default: 149d5970055SMichael S. Tsirkin fprintf(stderr, "vhost-net requires tap backend\n"); 150af3bba76SPaolo Bonzini return -ENOSYS; 151d5970055SMichael S. Tsirkin } 152d5970055SMichael S. Tsirkin } 153d5970055SMichael S. Tsirkin 15481647a65SNikolay Nikolaev struct vhost_net *vhost_net_init(VhostNetOptions *options) 155d5970055SMichael S. Tsirkin { 156d5970055SMichael S. Tsirkin int r; 1571a1bfac9SNikolay Nikolaev bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL; 158f1a0365bSMarc-André Lureau struct vhost_net *net = g_new0(struct vhost_net, 1); 159a463215bSMarc-André Lureau uint64_t features = 0; 16081647a65SNikolay Nikolaev 16181647a65SNikolay Nikolaev if (!options->net_backend) { 16281647a65SNikolay Nikolaev fprintf(stderr, "vhost-net requires net backend to be setup\n"); 163d5970055SMichael S. Tsirkin goto fail; 164d5970055SMichael S. Tsirkin } 165b931bfbfSChangchun Ouyang net->nc = options->net_backend; 16681647a65SNikolay Nikolaev 167e2051e9eSYuanhan Liu net->dev.max_queues = 1; 168b931bfbfSChangchun Ouyang net->dev.nvqs = 2; 169b931bfbfSChangchun Ouyang net->dev.vqs = net->vqs; 170e2051e9eSYuanhan Liu 1711a1bfac9SNikolay Nikolaev if (backend_kernel) { 17281647a65SNikolay Nikolaev r = vhost_net_get_fd(options->net_backend); 173d5970055SMichael S. Tsirkin if (r < 0) { 174d5970055SMichael S. Tsirkin goto fail; 175d5970055SMichael S. Tsirkin } 1761a1bfac9SNikolay Nikolaev net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend) 1779a2ba823SCornelia Huck ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR); 178d5970055SMichael S. Tsirkin net->backend = r; 179dcb10c00SMichael S. Tsirkin net->dev.protocol_features = 0; 1801a1bfac9SNikolay Nikolaev } else { 1811a1bfac9SNikolay Nikolaev net->dev.backend_features = 0; 182dcb10c00SMichael S. Tsirkin net->dev.protocol_features = 0; 1831a1bfac9SNikolay Nikolaev net->backend = -1; 184d5970055SMichael S. Tsirkin 185b931bfbfSChangchun Ouyang /* vhost-user needs vq_index to initiate a specific queue pair */ 186b931bfbfSChangchun Ouyang net->dev.vq_index = net->nc->queue_index * net->dev.nvqs; 187b931bfbfSChangchun Ouyang } 188f56a1247SMichael S. Tsirkin 18981647a65SNikolay Nikolaev r = vhost_dev_init(&net->dev, options->opaque, 19069e87b32SJason Wang options->backend_type, options->busyloop_timeout); 191d5970055SMichael S. Tsirkin if (r < 0) { 192d5970055SMichael S. Tsirkin goto fail; 193d5970055SMichael S. Tsirkin } 194d8e80ae3SDamjan Marion if (backend_kernel) { 19581647a65SNikolay Nikolaev if (!qemu_has_vnet_hdr_len(options->net_backend, 196ca736c8eSMichael S. Tsirkin sizeof(struct virtio_net_hdr_mrg_rxbuf))) { 1979a2ba823SCornelia Huck net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); 198ca736c8eSMichael S. Tsirkin } 199d5970055SMichael S. Tsirkin if (~net->dev.features & net->dev.backend_features) { 2001a1bfac9SNikolay Nikolaev fprintf(stderr, "vhost lacks feature mask %" PRIu64 2011a1bfac9SNikolay Nikolaev " for backend\n", 20229f91781SJes Sorensen (uint64_t)(~net->dev.features & net->dev.backend_features)); 203d5970055SMichael S. Tsirkin goto fail; 204d5970055SMichael S. Tsirkin } 2051a1bfac9SNikolay Nikolaev } 206a463215bSMarc-André Lureau 207d5970055SMichael S. Tsirkin /* Set sane init value. Override when guest acks. */ 20856f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 209f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 210a463215bSMarc-André Lureau features = vhost_user_get_acked_features(net->nc); 211a463215bSMarc-André Lureau if (~net->dev.features & features) { 212a463215bSMarc-André Lureau fprintf(stderr, "vhost lacks feature mask %" PRIu64 213a463215bSMarc-André Lureau " for backend\n", 214a463215bSMarc-André Lureau (uint64_t)(~net->dev.features & features)); 215a463215bSMarc-André Lureau goto fail; 216a463215bSMarc-André Lureau } 217a463215bSMarc-André Lureau } 21856f41de7SPaolo Bonzini #endif 219a463215bSMarc-André Lureau 220a463215bSMarc-André Lureau vhost_net_ack_features(net, features); 221a463215bSMarc-André Lureau 222d5970055SMichael S. Tsirkin return net; 223f1a0365bSMarc-André Lureau 224d5970055SMichael S. Tsirkin fail: 225f1a0365bSMarc-André Lureau vhost_dev_cleanup(&net->dev); 2267267c094SAnthony Liguori g_free(net); 227d5970055SMichael S. Tsirkin return NULL; 228d5970055SMichael S. Tsirkin } 229d5970055SMichael S. Tsirkin 230cd7d1d26SJason Wang static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index) 231cd7d1d26SJason Wang { 232cd7d1d26SJason Wang net->dev.vq_index = vq_index; 233cd7d1d26SJason Wang } 234cd7d1d26SJason Wang 235a9f98bb5SJason Wang static int vhost_net_start_one(struct vhost_net *net, 236cd7d1d26SJason Wang VirtIODevice *dev) 237d5970055SMichael S. Tsirkin { 238d5970055SMichael S. Tsirkin struct vhost_vring_file file = { }; 239d5970055SMichael S. Tsirkin int r; 240b0b3db79SMichael S. Tsirkin 241a9f98bb5SJason Wang net->dev.nvqs = 2; 242a9f98bb5SJason Wang net->dev.vqs = net->vqs; 243a9f98bb5SJason Wang 244b0b3db79SMichael S. Tsirkin r = vhost_dev_enable_notifiers(&net->dev, dev); 245b0b3db79SMichael S. Tsirkin if (r < 0) { 246b0b3db79SMichael S. Tsirkin goto fail_notifiers; 247b0b3db79SMichael S. Tsirkin } 248d5970055SMichael S. Tsirkin 249d5970055SMichael S. Tsirkin r = vhost_dev_start(&net->dev, dev); 250d5970055SMichael S. Tsirkin if (r < 0) { 251b0b3db79SMichael S. Tsirkin goto fail_start; 252d5970055SMichael S. Tsirkin } 253d5970055SMichael S. Tsirkin 254212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 25535277d14SStefan Hajnoczi net->nc->info->poll(net->nc, false); 256212d69f2SNikolay Nikolaev } 257212d69f2SNikolay Nikolaev 258f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 259d5970055SMichael S. Tsirkin qemu_set_fd_handler(net->backend, NULL, NULL, NULL); 260d5970055SMichael S. Tsirkin file.fd = net->backend; 261d5970055SMichael S. Tsirkin for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 26223bfaf77SJason Wang if (!virtio_queue_enabled(dev, net->dev.vq_index + 26323bfaf77SJason Wang file.index)) { 26423bfaf77SJason Wang /* Queue might not be ready for start */ 26523bfaf77SJason Wang continue; 26623bfaf77SJason Wang } 267950d94baSMarc-André Lureau r = vhost_net_set_backend(&net->dev, &file); 268d5970055SMichael S. Tsirkin if (r < 0) { 269d5970055SMichael S. Tsirkin r = -errno; 270d5970055SMichael S. Tsirkin goto fail; 271d5970055SMichael S. Tsirkin } 272d5970055SMichael S. Tsirkin } 2731a1bfac9SNikolay Nikolaev } 274d5970055SMichael S. Tsirkin return 0; 275d5970055SMichael S. Tsirkin fail: 276d5970055SMichael S. Tsirkin file.fd = -1; 277f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 2786b37c87cSMichael S. Tsirkin while (file.index-- > 0) { 27923bfaf77SJason Wang if (!virtio_queue_enabled(dev, net->dev.vq_index + 28023bfaf77SJason Wang file.index)) { 28123bfaf77SJason Wang /* Queue might not be ready for start */ 28223bfaf77SJason Wang continue; 28323bfaf77SJason Wang } 284950d94baSMarc-André Lureau int r = vhost_net_set_backend(&net->dev, &file); 285d5970055SMichael S. Tsirkin assert(r >= 0); 286d5970055SMichael S. Tsirkin } 2871a1bfac9SNikolay Nikolaev } 288212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 28935277d14SStefan Hajnoczi net->nc->info->poll(net->nc, true); 290212d69f2SNikolay Nikolaev } 291d5970055SMichael S. Tsirkin vhost_dev_stop(&net->dev, dev); 292b0b3db79SMichael S. Tsirkin fail_start: 293b0b3db79SMichael S. Tsirkin vhost_dev_disable_notifiers(&net->dev, dev); 294b0b3db79SMichael S. Tsirkin fail_notifiers: 295d5970055SMichael S. Tsirkin return r; 296d5970055SMichael S. Tsirkin } 297d5970055SMichael S. Tsirkin 298a9f98bb5SJason Wang static void vhost_net_stop_one(struct vhost_net *net, 299d5970055SMichael S. Tsirkin VirtIODevice *dev) 300d5970055SMichael S. Tsirkin { 301d5970055SMichael S. Tsirkin struct vhost_vring_file file = { .fd = -1 }; 302d5970055SMichael S. Tsirkin 303f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { 304d5970055SMichael S. Tsirkin for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 305950d94baSMarc-André Lureau int r = vhost_net_set_backend(&net->dev, &file); 306d5970055SMichael S. Tsirkin assert(r >= 0); 307d5970055SMichael S. Tsirkin } 3081a1bfac9SNikolay Nikolaev } 309212d69f2SNikolay Nikolaev if (net->nc->info->poll) { 31035277d14SStefan Hajnoczi net->nc->info->poll(net->nc, true); 311212d69f2SNikolay Nikolaev } 312d5970055SMichael S. Tsirkin vhost_dev_stop(&net->dev, dev); 313b0b3db79SMichael S. Tsirkin vhost_dev_disable_notifiers(&net->dev, dev); 314d5970055SMichael S. Tsirkin } 315d5970055SMichael S. Tsirkin 316a9f98bb5SJason Wang int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, 317a9f98bb5SJason Wang int total_queues) 318a9f98bb5SJason Wang { 3191c819449SKONRAD Frederic BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 3201c819449SKONRAD Frederic VirtioBusState *vbus = VIRTIO_BUS(qbus); 3211c819449SKONRAD Frederic VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); 32292fbc3e0SCindy Lu struct vhost_net *net; 3233154d1e4SGreg Kurz int r, e, i; 32492fbc3e0SCindy Lu NetClientState *peer; 325a9f98bb5SJason Wang 3261c819449SKONRAD Frederic if (!k->set_guest_notifiers) { 327312fd5f2SMarkus Armbruster error_report("binding does not support guest notifiers"); 328a4076440SLaurent Vivier return -ENOSYS; 329a9f98bb5SJason Wang } 330a9f98bb5SJason Wang 3313154d1e4SGreg Kurz for (i = 0; i < total_queues; i++) { 3325669655aSVictor Kaplansky 33392fbc3e0SCindy Lu peer = qemu_get_peer(ncs, i); 33492fbc3e0SCindy Lu net = get_vhost_net(peer); 3355669655aSVictor Kaplansky vhost_net_set_vq_index(net, i * 2); 3365669655aSVictor Kaplansky 3375669655aSVictor Kaplansky /* Suppress the masking guest notifiers on vhost user 3385669655aSVictor Kaplansky * because vhost user doesn't interrupt masking/unmasking 3395669655aSVictor Kaplansky * properly. 3405669655aSVictor Kaplansky */ 341f394b2e2SEric Blake if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 3425669655aSVictor Kaplansky dev->use_guest_notifier_mask = false; 3435669655aSVictor Kaplansky } 344a9f98bb5SJason Wang } 345a9f98bb5SJason Wang 3461c819449SKONRAD Frederic r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true); 347a9f98bb5SJason Wang if (r < 0) { 348312fd5f2SMarkus Armbruster error_report("Error binding guest notifier: %d", -r); 3493154d1e4SGreg Kurz goto err; 350a9f98bb5SJason Wang } 351a9f98bb5SJason Wang 352cd7d1d26SJason Wang for (i = 0; i < total_queues; i++) { 35392fbc3e0SCindy Lu peer = qemu_get_peer(ncs, i); 35492fbc3e0SCindy Lu r = vhost_net_start_one(get_vhost_net(peer), dev); 355cd7d1d26SJason Wang 356cd7d1d26SJason Wang if (r < 0) { 357cd7d1d26SJason Wang goto err_start; 358cd7d1d26SJason Wang } 359bfc6cf31SMarc-André Lureau 36092fbc3e0SCindy Lu if (peer->vring_enable) { 361bfc6cf31SMarc-André Lureau /* restore vring enable state */ 36292fbc3e0SCindy Lu r = vhost_set_vring_enable(peer, peer->vring_enable); 363bfc6cf31SMarc-André Lureau 364bfc6cf31SMarc-André Lureau if (r < 0) { 365bfc6cf31SMarc-André Lureau goto err_start; 366bfc6cf31SMarc-André Lureau } 367bfc6cf31SMarc-André Lureau } 368cd7d1d26SJason Wang } 369cd7d1d26SJason Wang 370a9f98bb5SJason Wang return 0; 371a9f98bb5SJason Wang 372cd7d1d26SJason Wang err_start: 373a9f98bb5SJason Wang while (--i >= 0) { 37492fbc3e0SCindy Lu peer = qemu_get_peer(ncs , i); 37592fbc3e0SCindy Lu vhost_net_stop_one(get_vhost_net(peer), dev); 376a9f98bb5SJason Wang } 377cd7d1d26SJason Wang e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false); 378cd7d1d26SJason Wang if (e < 0) { 379cd7d1d26SJason Wang fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); 380cd7d1d26SJason Wang fflush(stderr); 381cd7d1d26SJason Wang } 3823154d1e4SGreg Kurz err: 383a9f98bb5SJason Wang return r; 384a9f98bb5SJason Wang } 385a9f98bb5SJason Wang 386a9f98bb5SJason Wang void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, 387a9f98bb5SJason Wang int total_queues) 388a9f98bb5SJason Wang { 3891c819449SKONRAD Frederic BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); 3901c819449SKONRAD Frederic VirtioBusState *vbus = VIRTIO_BUS(qbus); 3911c819449SKONRAD Frederic VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); 392a9f98bb5SJason Wang int i, r; 393a9f98bb5SJason Wang 394cd7d1d26SJason Wang for (i = 0; i < total_queues; i++) { 395cd7d1d26SJason Wang vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev); 396cd7d1d26SJason Wang } 397cd7d1d26SJason Wang 3981c819449SKONRAD Frederic r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false); 399a9f98bb5SJason Wang if (r < 0) { 400a9f98bb5SJason Wang fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); 401a9f98bb5SJason Wang fflush(stderr); 402a9f98bb5SJason Wang } 403a9f98bb5SJason Wang assert(r >= 0); 404a9f98bb5SJason Wang } 405a9f98bb5SJason Wang 406d5970055SMichael S. Tsirkin void vhost_net_cleanup(struct vhost_net *net) 407d5970055SMichael S. Tsirkin { 408d5970055SMichael S. Tsirkin vhost_dev_cleanup(&net->dev); 409d5970055SMichael S. Tsirkin } 410f56a1247SMichael S. Tsirkin 4113e866365SThibaut Collet int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) 4123e866365SThibaut Collet { 4133e866365SThibaut Collet const VhostOps *vhost_ops = net->dev.vhost_ops; 4143e866365SThibaut Collet 41551f7aca9SMarc-André Lureau assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 41651f7aca9SMarc-André Lureau assert(vhost_ops->vhost_migration_done); 4173e866365SThibaut Collet 41851f7aca9SMarc-André Lureau return vhost_ops->vhost_migration_done(&net->dev, mac_addr); 4193e866365SThibaut Collet } 4203e866365SThibaut Collet 421f56a1247SMichael S. Tsirkin bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) 422f56a1247SMichael S. Tsirkin { 423f56a1247SMichael S. Tsirkin return vhost_virtqueue_pending(&net->dev, idx); 424f56a1247SMichael S. Tsirkin } 425f56a1247SMichael S. Tsirkin 426f56a1247SMichael S. Tsirkin void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, 427f56a1247SMichael S. Tsirkin int idx, bool mask) 428f56a1247SMichael S. Tsirkin { 429f56a1247SMichael S. Tsirkin vhost_virtqueue_mask(&net->dev, dev, idx, mask); 430f56a1247SMichael S. Tsirkin } 431ed8b4afeSNikolay Nikolaev 432ed8b4afeSNikolay Nikolaev VHostNetState *get_vhost_net(NetClientState *nc) 433ed8b4afeSNikolay Nikolaev { 434ed8b4afeSNikolay Nikolaev VHostNetState *vhost_net = 0; 435ed8b4afeSNikolay Nikolaev 436ed8b4afeSNikolay Nikolaev if (!nc) { 437ed8b4afeSNikolay Nikolaev return 0; 438ed8b4afeSNikolay Nikolaev } 439ed8b4afeSNikolay Nikolaev 440ed8b4afeSNikolay Nikolaev switch (nc->info->type) { 441f394b2e2SEric Blake case NET_CLIENT_DRIVER_TAP: 442ed8b4afeSNikolay Nikolaev vhost_net = tap_get_vhost_net(nc); 443ed8b4afeSNikolay Nikolaev break; 44456f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 445f394b2e2SEric Blake case NET_CLIENT_DRIVER_VHOST_USER: 44603ce5744SNikolay Nikolaev vhost_net = vhost_user_get_vhost_net(nc); 4471a5b68ceSMarc-André Lureau assert(vhost_net); 44803ce5744SNikolay Nikolaev break; 44956f41de7SPaolo Bonzini #endif 450108a6481SCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 451108a6481SCindy Lu case NET_CLIENT_DRIVER_VHOST_VDPA: 452108a6481SCindy Lu vhost_net = vhost_vdpa_get_vhost_net(nc); 453108a6481SCindy Lu assert(vhost_net); 454108a6481SCindy Lu break; 455108a6481SCindy Lu #endif 456ed8b4afeSNikolay Nikolaev default: 457ed8b4afeSNikolay Nikolaev break; 458ed8b4afeSNikolay Nikolaev } 459ed8b4afeSNikolay Nikolaev 460ed8b4afeSNikolay Nikolaev return vhost_net; 461ed8b4afeSNikolay Nikolaev } 4627263a0adSChangchun Ouyang 4637263a0adSChangchun Ouyang int vhost_set_vring_enable(NetClientState *nc, int enable) 4647263a0adSChangchun Ouyang { 4657263a0adSChangchun Ouyang VHostNetState *net = get_vhost_net(nc); 466bb12e761SMarc-André Lureau const VhostOps *vhost_ops = net->dev.vhost_ops; 4677263a0adSChangchun Ouyang 468bfc6cf31SMarc-André Lureau nc->vring_enable = enable; 469bfc6cf31SMarc-André Lureau 470ca10203cSIlya Maximets if (vhost_ops && vhost_ops->vhost_set_vring_enable) { 47121e70425SMarc-André Lureau return vhost_ops->vhost_set_vring_enable(&net->dev, enable); 4727263a0adSChangchun Ouyang } 4737263a0adSChangchun Ouyang 4747263a0adSChangchun Ouyang return 0; 4757263a0adSChangchun Ouyang } 4767263a0adSChangchun Ouyang 47745a368adSMaxime Coquelin int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) 47845a368adSMaxime Coquelin { 47945a368adSMaxime Coquelin const VhostOps *vhost_ops = net->dev.vhost_ops; 48045a368adSMaxime Coquelin 48145a368adSMaxime Coquelin if (!vhost_ops->vhost_net_set_mtu) { 48245a368adSMaxime Coquelin return 0; 48345a368adSMaxime Coquelin } 48445a368adSMaxime Coquelin 48545a368adSMaxime Coquelin return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); 48645a368adSMaxime Coquelin } 487