xref: /openbmc/qemu/hw/net/vhost_net.c (revision 24602b77f5658ae8377958c15fdef2f44affc743)
16e790746SPaolo Bonzini /*
26e790746SPaolo Bonzini  * vhost-net support
36e790746SPaolo Bonzini  *
46e790746SPaolo Bonzini  * Copyright Red Hat, Inc. 2010
56e790746SPaolo Bonzini  *
66e790746SPaolo Bonzini  * Authors:
76e790746SPaolo Bonzini  *  Michael S. Tsirkin <mst@redhat.com>
86e790746SPaolo Bonzini  *
96e790746SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2.  See
106e790746SPaolo Bonzini  * the COPYING file in the top-level directory.
116e790746SPaolo Bonzini  *
126e790746SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
136e790746SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
146e790746SPaolo Bonzini  */
156e790746SPaolo Bonzini 
16e8d40465SPeter Maydell #include "qemu/osdep.h"
176e790746SPaolo Bonzini #include "net/net.h"
186e790746SPaolo Bonzini #include "net/tap.h"
1903ce5744SNikolay Nikolaev #include "net/vhost-user.h"
20108a6481SCindy Lu #include "net/vhost-vdpa.h"
216e790746SPaolo Bonzini 
2218658a3cSPaolo Bonzini #include "standard-headers/linux/vhost_types.h"
236e790746SPaolo Bonzini #include "hw/virtio/virtio-net.h"
246e790746SPaolo Bonzini #include "net/vhost_net.h"
25a6945f22SKevin Wolf #include "qapi/error.h"
266e790746SPaolo Bonzini #include "qemu/error-report.h"
27db725815SMarkus Armbruster #include "qemu/main-loop.h"
286e790746SPaolo Bonzini 
296e790746SPaolo Bonzini #include <sys/socket.h>
306e790746SPaolo Bonzini #include <net/if.h>
316e790746SPaolo Bonzini #include <netinet/in.h>
326e790746SPaolo Bonzini 
336e790746SPaolo Bonzini 
344fbe0f32SMichael S. Tsirkin #include "standard-headers/linux/virtio_ring.h"
356e790746SPaolo Bonzini #include "hw/virtio/vhost.h"
361c819449SKONRAD Frederic #include "hw/virtio/virtio-bus.h"
3710f8a115SKangjie Xu #include "linux-headers/linux/vhost.h"
386e790746SPaolo Bonzini 
396e790746SPaolo Bonzini 
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 
vhost_net_get_feature_bits(struct vhost_net * net)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 
vhost_net_get_features(struct vhost_net * net,uint64_t features)1249a2ba823SCornelia Huck uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
1256e790746SPaolo Bonzini {
1262e6d46d7SNikolay Nikolaev     return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net),
1272e6d46d7SNikolay Nikolaev             features);
1286e790746SPaolo Bonzini }
vhost_net_get_config(struct vhost_net * net,uint8_t * config,uint32_t config_len)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 }
vhost_net_set_config(struct vhost_net * net,const uint8_t * data,uint32_t offset,uint32_t size,uint32_t flags)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 }
1396e790746SPaolo Bonzini 
vhost_net_ack_features(struct vhost_net * net,uint64_t features)1409a2ba823SCornelia Huck void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
1416e790746SPaolo Bonzini {
142b49ae913SJason Wang     net->dev.acked_features = net->dev.backend_features;
1432e6d46d7SNikolay Nikolaev     vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
1446e790746SPaolo Bonzini }
1456e790746SPaolo Bonzini 
vhost_net_get_max_queues(VHostNetState * net)146e2051e9eSYuanhan Liu uint64_t vhost_net_get_max_queues(VHostNetState *net)
147e2051e9eSYuanhan Liu {
148e2051e9eSYuanhan Liu     return net->dev.max_queues;
149e2051e9eSYuanhan Liu }
150e2051e9eSYuanhan Liu 
vhost_net_get_acked_features(VHostNetState * net)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 
vhost_net_save_acked_features(NetClientState * nc)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(黄勇) 
vhost_net_disable_notifiers_nvhosts(VirtIODevice * dev,NetClientState * ncs,int data_queue_pairs,int nvhosts)1656166799fSzuoboqun static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev,
1666166799fSzuoboqun                 NetClientState *ncs, int data_queue_pairs, int nvhosts)
1676166799fSzuoboqun {
1686166799fSzuoboqun     VirtIONet *n = VIRTIO_NET(dev);
1696166799fSzuoboqun     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
1706166799fSzuoboqun     struct vhost_net *net;
1716166799fSzuoboqun     struct vhost_dev *hdev;
1726166799fSzuoboqun     int r, i, j;
1736166799fSzuoboqun     NetClientState *peer;
1746166799fSzuoboqun 
1756166799fSzuoboqun     /*
1766166799fSzuoboqun      * Batch all the host notifiers in a single transaction to avoid
1776166799fSzuoboqun      * quadratic time complexity in address_space_update_ioeventfds().
1786166799fSzuoboqun      */
1796166799fSzuoboqun     memory_region_transaction_begin();
1806166799fSzuoboqun 
1816166799fSzuoboqun     for (i = 0; i < nvhosts; i++) {
1826166799fSzuoboqun         if (i < data_queue_pairs) {
1836166799fSzuoboqun             peer = qemu_get_peer(ncs, i);
1846166799fSzuoboqun         } else {
1856166799fSzuoboqun             peer = qemu_get_peer(ncs, n->max_queue_pairs);
1866166799fSzuoboqun         }
1876166799fSzuoboqun 
1886166799fSzuoboqun         net = get_vhost_net(peer);
1896166799fSzuoboqun         hdev = &net->dev;
1906166799fSzuoboqun         for (j = 0; j < hdev->nvqs; j++) {
1916166799fSzuoboqun             r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
1926166799fSzuoboqun                                              hdev->vq_index + j,
1936166799fSzuoboqun                                              false);
1946166799fSzuoboqun             if (r < 0) {
1956166799fSzuoboqun                 error_report("vhost %d VQ %d notifier cleanup failed: %d",
1966166799fSzuoboqun                               i, j, -r);
1976166799fSzuoboqun             }
1986166799fSzuoboqun             assert(r >= 0);
1996166799fSzuoboqun         }
2006166799fSzuoboqun     }
2016166799fSzuoboqun     /*
2026166799fSzuoboqun      * The transaction expects the ioeventfds to be open when it
2036166799fSzuoboqun      * commits. Do it now, before the cleanup loop.
2046166799fSzuoboqun      */
2056166799fSzuoboqun     memory_region_transaction_commit();
2066166799fSzuoboqun 
2076166799fSzuoboqun     for (i = 0; i < nvhosts; i++) {
2086166799fSzuoboqun         if (i < data_queue_pairs) {
2096166799fSzuoboqun             peer = qemu_get_peer(ncs, i);
2106166799fSzuoboqun         } else {
2116166799fSzuoboqun             peer = qemu_get_peer(ncs, n->max_queue_pairs);
2126166799fSzuoboqun         }
2136166799fSzuoboqun 
2146166799fSzuoboqun         net = get_vhost_net(peer);
2156166799fSzuoboqun         hdev = &net->dev;
2166166799fSzuoboqun         for (j = 0; j < hdev->nvqs; j++) {
2176166799fSzuoboqun             virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus),
2186166799fSzuoboqun                                              hdev->vq_index + j);
2196166799fSzuoboqun         }
2206166799fSzuoboqun         virtio_device_release_ioeventfd(dev);
2216166799fSzuoboqun     }
2226166799fSzuoboqun }
2236166799fSzuoboqun 
vhost_net_enable_notifiers(VirtIODevice * dev,NetClientState * ncs,int data_queue_pairs,int cvq)2246166799fSzuoboqun static int vhost_net_enable_notifiers(VirtIODevice *dev,
2256166799fSzuoboqun                 NetClientState *ncs, int data_queue_pairs, int cvq)
2266166799fSzuoboqun {
2276166799fSzuoboqun     VirtIONet *n = VIRTIO_NET(dev);
2286166799fSzuoboqun     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
2296166799fSzuoboqun     int nvhosts = data_queue_pairs + cvq;
2306166799fSzuoboqun     struct vhost_net *net;
2316166799fSzuoboqun     struct vhost_dev *hdev;
232*16f6804cSzuoboqun     int r, i, j, k;
2336166799fSzuoboqun     NetClientState *peer;
2346166799fSzuoboqun 
2356166799fSzuoboqun     /*
236*16f6804cSzuoboqun      * We will pass the notifiers to the kernel, make sure that QEMU
237*16f6804cSzuoboqun      * doesn't interfere.
238*16f6804cSzuoboqun      */
239*16f6804cSzuoboqun     for (i = 0; i < nvhosts; i++) {
240*16f6804cSzuoboqun         r = virtio_device_grab_ioeventfd(dev);
241*16f6804cSzuoboqun         if (r < 0) {
242*16f6804cSzuoboqun             error_report("vhost %d binding does not support host notifiers", i);
243*16f6804cSzuoboqun             for (k = 0; k < i; k++) {
244*16f6804cSzuoboqun                 virtio_device_release_ioeventfd(dev);
245*16f6804cSzuoboqun             }
246*16f6804cSzuoboqun             return r;
247*16f6804cSzuoboqun         }
248*16f6804cSzuoboqun     }
249*16f6804cSzuoboqun 
250*16f6804cSzuoboqun     /*
2516166799fSzuoboqun      * Batch all the host notifiers in a single transaction to avoid
2526166799fSzuoboqun      * quadratic time complexity in address_space_update_ioeventfds().
2536166799fSzuoboqun      */
2546166799fSzuoboqun     memory_region_transaction_begin();
2556166799fSzuoboqun 
2566166799fSzuoboqun     for (i = 0; i < nvhosts; i++) {
2576166799fSzuoboqun         if (i < data_queue_pairs) {
2586166799fSzuoboqun             peer = qemu_get_peer(ncs, i);
2596166799fSzuoboqun         } else {
2606166799fSzuoboqun             peer = qemu_get_peer(ncs, n->max_queue_pairs);
2616166799fSzuoboqun         }
2626166799fSzuoboqun 
2636166799fSzuoboqun         net = get_vhost_net(peer);
2646166799fSzuoboqun         hdev = &net->dev;
2656166799fSzuoboqun 
2666166799fSzuoboqun         for (j = 0; j < hdev->nvqs; j++) {
2676166799fSzuoboqun             r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
2686166799fSzuoboqun                                              hdev->vq_index + j,
2696166799fSzuoboqun                                              true);
2706166799fSzuoboqun             if (r < 0) {
2716166799fSzuoboqun                 error_report("vhost %d VQ %d notifier binding failed: %d",
2726166799fSzuoboqun                               i, j, -r);
2736166799fSzuoboqun                 memory_region_transaction_commit();
2746166799fSzuoboqun                 vhost_dev_disable_notifiers_nvqs(hdev, dev, j);
2756166799fSzuoboqun                 goto fail_nvhosts;
2766166799fSzuoboqun             }
2776166799fSzuoboqun         }
2786166799fSzuoboqun     }
2796166799fSzuoboqun 
2806166799fSzuoboqun     memory_region_transaction_commit();
2816166799fSzuoboqun 
2826166799fSzuoboqun     return 0;
2836166799fSzuoboqun fail_nvhosts:
2846166799fSzuoboqun     vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i);
285*16f6804cSzuoboqun     /*
286*16f6804cSzuoboqun      * This for loop starts from i+1, not i, because the i-th ioeventfd
287*16f6804cSzuoboqun      * has already been released in vhost_dev_disable_notifiers_nvqs().
288*16f6804cSzuoboqun      */
289*16f6804cSzuoboqun     for (k = i + 1; k < nvhosts; k++) {
290*16f6804cSzuoboqun         virtio_device_release_ioeventfd(dev);
291*16f6804cSzuoboqun     }
292*16f6804cSzuoboqun 
2936166799fSzuoboqun     return r;
2946166799fSzuoboqun }
2956166799fSzuoboqun 
2966166799fSzuoboqun /*
2976166799fSzuoboqun  * Stop processing guest IO notifications in qemu.
2986166799fSzuoboqun  * Start processing them in vhost in kernel.
2996166799fSzuoboqun  */
vhost_net_disable_notifiers(VirtIODevice * dev,NetClientState * ncs,int data_queue_pairs,int cvq)3006166799fSzuoboqun static void vhost_net_disable_notifiers(VirtIODevice *dev,
3016166799fSzuoboqun                 NetClientState *ncs, int data_queue_pairs, int cvq)
3026166799fSzuoboqun {
3036166799fSzuoboqun     vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs,
3046166799fSzuoboqun                                         data_queue_pairs + cvq);
3056166799fSzuoboqun }
3066166799fSzuoboqun 
vhost_net_get_fd(NetClientState * backend)3076e790746SPaolo Bonzini static int vhost_net_get_fd(NetClientState *backend)
3086e790746SPaolo Bonzini {
3096e790746SPaolo Bonzini     switch (backend->info->type) {
310f394b2e2SEric Blake     case NET_CLIENT_DRIVER_TAP:
3116e790746SPaolo Bonzini         return tap_get_fd(backend);
3126e790746SPaolo Bonzini     default:
3136e790746SPaolo Bonzini         fprintf(stderr, "vhost-net requires tap backend\n");
314af3bba76SPaolo Bonzini         return -ENOSYS;
3156e790746SPaolo Bonzini     }
3166e790746SPaolo Bonzini }
3176e790746SPaolo Bonzini 
vhost_net_init(VhostNetOptions * options)31881647a65SNikolay Nikolaev struct vhost_net *vhost_net_init(VhostNetOptions *options)
3196e790746SPaolo Bonzini {
3206e790746SPaolo Bonzini     int r;
3211a1bfac9SNikolay Nikolaev     bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
322f1a0365bSMarc-André Lureau     struct vhost_net *net = g_new0(struct vhost_net, 1);
323a463215bSMarc-André Lureau     uint64_t features = 0;
324a6945f22SKevin Wolf     Error *local_err = NULL;
32581647a65SNikolay Nikolaev 
32681647a65SNikolay Nikolaev     if (!options->net_backend) {
32781647a65SNikolay Nikolaev         fprintf(stderr, "vhost-net requires net backend to be setup\n");
3286e790746SPaolo Bonzini         goto fail;
3296e790746SPaolo Bonzini     }
330b931bfbfSChangchun Ouyang     net->nc = options->net_backend;
3316a756d14SJason Wang     net->dev.nvqs = options->nvqs;
33281647a65SNikolay Nikolaev 
333e2051e9eSYuanhan Liu     net->dev.max_queues = 1;
334b931bfbfSChangchun Ouyang     net->dev.vqs = net->vqs;
335e2051e9eSYuanhan Liu 
3361a1bfac9SNikolay Nikolaev     if (backend_kernel) {
33781647a65SNikolay Nikolaev         r = vhost_net_get_fd(options->net_backend);
3386e790746SPaolo Bonzini         if (r < 0) {
3396e790746SPaolo Bonzini             goto fail;
3406e790746SPaolo Bonzini         }
3411a1bfac9SNikolay Nikolaev         net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
3429a2ba823SCornelia Huck             ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
3436e790746SPaolo Bonzini         net->backend = r;
344dcb10c00SMichael S. Tsirkin         net->dev.protocol_features = 0;
3451a1bfac9SNikolay Nikolaev     } else {
3461a1bfac9SNikolay Nikolaev         net->dev.backend_features = 0;
347dcb10c00SMichael S. Tsirkin         net->dev.protocol_features = 0;
3481a1bfac9SNikolay Nikolaev         net->backend = -1;
3496e790746SPaolo Bonzini 
350b931bfbfSChangchun Ouyang         /* vhost-user needs vq_index to initiate a specific queue pair */
351b931bfbfSChangchun Ouyang         net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
352b931bfbfSChangchun Ouyang     }
3536e790746SPaolo Bonzini 
35481647a65SNikolay Nikolaev     r = vhost_dev_init(&net->dev, options->opaque,
355a6945f22SKevin Wolf                        options->backend_type, options->busyloop_timeout,
356a6945f22SKevin Wolf                        &local_err);
3576e790746SPaolo Bonzini     if (r < 0) {
358a6945f22SKevin Wolf         error_report_err(local_err);
3596e790746SPaolo Bonzini         goto fail;
3606e790746SPaolo Bonzini     }
361d8e80ae3SDamjan Marion     if (backend_kernel) {
36281647a65SNikolay Nikolaev         if (!qemu_has_vnet_hdr_len(options->net_backend,
3636e790746SPaolo Bonzini                                sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
3649a2ba823SCornelia Huck             net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
3656e790746SPaolo Bonzini         }
3666e790746SPaolo Bonzini         if (~net->dev.features & net->dev.backend_features) {
3671eed051cSIlya Maximets             fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64
3681a1bfac9SNikolay Nikolaev                    " for backend\n",
3696e790746SPaolo Bonzini                    (uint64_t)(~net->dev.features & net->dev.backend_features));
3706e790746SPaolo Bonzini             goto fail;
3716e790746SPaolo Bonzini         }
3721a1bfac9SNikolay Nikolaev     }
373a463215bSMarc-André Lureau 
3746e790746SPaolo Bonzini     /* Set sane init value. Override when guest acks. */
37556f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER
376f394b2e2SEric Blake     if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
377a463215bSMarc-André Lureau         features = vhost_user_get_acked_features(net->nc);
378a463215bSMarc-André Lureau         if (~net->dev.features & features) {
3791eed051cSIlya Maximets             fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64
380a463215bSMarc-André Lureau                     " for backend\n",
381a463215bSMarc-André Lureau                     (uint64_t)(~net->dev.features & features));
382a463215bSMarc-André Lureau             goto fail;
383a463215bSMarc-André Lureau         }
384a463215bSMarc-André Lureau     }
38556f41de7SPaolo Bonzini #endif
386a463215bSMarc-André Lureau 
387a463215bSMarc-André Lureau     vhost_net_ack_features(net, features);
388a463215bSMarc-André Lureau 
3896e790746SPaolo Bonzini     return net;
390f1a0365bSMarc-André Lureau 
3916e790746SPaolo Bonzini fail:
392f1a0365bSMarc-André Lureau     vhost_dev_cleanup(&net->dev);
3936e790746SPaolo Bonzini     g_free(net);
3946e790746SPaolo Bonzini     return NULL;
3956e790746SPaolo Bonzini }
3966e790746SPaolo Bonzini 
vhost_net_set_vq_index(struct vhost_net * net,int vq_index,int vq_index_end)397049eb15bSJason Wang static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index,
398245cf2c2SEugenio Pérez                                    int vq_index_end)
399cd7d1d26SJason Wang {
400cd7d1d26SJason Wang     net->dev.vq_index = vq_index;
401245cf2c2SEugenio Pérez     net->dev.vq_index_end = vq_index_end;
402cd7d1d26SJason Wang }
403cd7d1d26SJason Wang 
vhost_net_start_one(struct vhost_net * net,VirtIODevice * dev)4046e790746SPaolo Bonzini static int vhost_net_start_one(struct vhost_net *net,
405cd7d1d26SJason Wang                                VirtIODevice *dev)
4066e790746SPaolo Bonzini {
4076e790746SPaolo Bonzini     struct vhost_vring_file file = { };
4086e790746SPaolo Bonzini     int r;
4096e790746SPaolo Bonzini 
410eb92b753SEugenio Pérez     if (net->nc->info->start) {
411eb92b753SEugenio Pérez         r = net->nc->info->start(net->nc);
412eb92b753SEugenio Pérez         if (r < 0) {
413eb92b753SEugenio Pérez             return r;
414eb92b753SEugenio Pérez         }
415eb92b753SEugenio Pérez     }
416eb92b753SEugenio Pérez 
4174daa5054SStefano Garzarella     r = vhost_dev_start(&net->dev, dev, false);
4186e790746SPaolo Bonzini     if (r < 0) {
4196e790746SPaolo Bonzini         goto fail_start;
4206e790746SPaolo Bonzini     }
4216e790746SPaolo Bonzini 
422212d69f2SNikolay Nikolaev     if (net->nc->info->poll) {
4236e790746SPaolo Bonzini         net->nc->info->poll(net->nc, false);
424212d69f2SNikolay Nikolaev     }
425212d69f2SNikolay Nikolaev 
426f394b2e2SEric Blake     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
4276e790746SPaolo Bonzini         qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
4286e790746SPaolo Bonzini         file.fd = net->backend;
4296e790746SPaolo Bonzini         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
43023bfaf77SJason Wang             if (!virtio_queue_enabled(dev, net->dev.vq_index +
43123bfaf77SJason Wang                                       file.index)) {
43223bfaf77SJason Wang                 /* Queue might not be ready for start */
43323bfaf77SJason Wang                 continue;
43423bfaf77SJason Wang             }
435950d94baSMarc-André Lureau             r = vhost_net_set_backend(&net->dev, &file);
4366e790746SPaolo Bonzini             if (r < 0) {
4376e790746SPaolo Bonzini                 r = -errno;
4386e790746SPaolo Bonzini                 goto fail;
4396e790746SPaolo Bonzini             }
4406e790746SPaolo Bonzini         }
4411a1bfac9SNikolay Nikolaev     }
442539573c3SEugenio Pérez 
443539573c3SEugenio Pérez     if (net->nc->info->load) {
444539573c3SEugenio Pérez         r = net->nc->info->load(net->nc);
445539573c3SEugenio Pérez         if (r < 0) {
446539573c3SEugenio Pérez             goto fail;
447539573c3SEugenio Pérez         }
448539573c3SEugenio Pérez     }
4496e790746SPaolo Bonzini     return 0;
4506e790746SPaolo Bonzini fail:
4516e790746SPaolo Bonzini     file.fd = -1;
452f394b2e2SEric Blake     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
4536e790746SPaolo Bonzini         while (file.index-- > 0) {
45423bfaf77SJason Wang             if (!virtio_queue_enabled(dev, net->dev.vq_index +
45523bfaf77SJason Wang                                       file.index)) {
45623bfaf77SJason Wang                 /* Queue might not be ready for start */
45723bfaf77SJason Wang                 continue;
45823bfaf77SJason Wang             }
4595d63cb15SThomas Huth             int ret = vhost_net_set_backend(&net->dev, &file);
4605d63cb15SThomas Huth             assert(ret >= 0);
4616e790746SPaolo Bonzini         }
4621a1bfac9SNikolay Nikolaev     }
463212d69f2SNikolay Nikolaev     if (net->nc->info->poll) {
4646e790746SPaolo Bonzini         net->nc->info->poll(net->nc, true);
465212d69f2SNikolay Nikolaev     }
4664daa5054SStefano Garzarella     vhost_dev_stop(&net->dev, dev, false);
4676e790746SPaolo Bonzini fail_start:
4686e790746SPaolo Bonzini     return r;
4696e790746SPaolo Bonzini }
4706e790746SPaolo Bonzini 
vhost_net_stop_one(struct vhost_net * net,VirtIODevice * dev)4716e790746SPaolo Bonzini static void vhost_net_stop_one(struct vhost_net *net,
4726e790746SPaolo Bonzini                                VirtIODevice *dev)
4736e790746SPaolo Bonzini {
4746e790746SPaolo Bonzini     struct vhost_vring_file file = { .fd = -1 };
4756e790746SPaolo Bonzini 
476f394b2e2SEric Blake     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
4776e790746SPaolo Bonzini         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
478950d94baSMarc-André Lureau             int r = vhost_net_set_backend(&net->dev, &file);
4796e790746SPaolo Bonzini             assert(r >= 0);
4806e790746SPaolo Bonzini         }
4811a1bfac9SNikolay Nikolaev     }
482212d69f2SNikolay Nikolaev     if (net->nc->info->poll) {
4836e790746SPaolo Bonzini         net->nc->info->poll(net->nc, true);
484212d69f2SNikolay Nikolaev     }
4854daa5054SStefano Garzarella     vhost_dev_stop(&net->dev, dev, false);
486c5e5269dSEugenio Pérez     if (net->nc->info->stop) {
487c5e5269dSEugenio Pérez         net->nc->info->stop(net->nc);
488c5e5269dSEugenio Pérez     }
4896e790746SPaolo Bonzini }
4906e790746SPaolo Bonzini 
vhost_net_start(VirtIODevice * dev,NetClientState * ncs,int data_queue_pairs,int cvq)4916e790746SPaolo Bonzini int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
49205ba3f63SJason Wang                     int data_queue_pairs, int cvq)
4936e790746SPaolo Bonzini {
4941c819449SKONRAD Frederic     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
4951c819449SKONRAD Frederic     VirtioBusState *vbus = VIRTIO_BUS(qbus);
4961c819449SKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
49705ba3f63SJason Wang     int total_notifiers = data_queue_pairs * 2 + cvq;
49805ba3f63SJason Wang     VirtIONet *n = VIRTIO_NET(dev);
49905ba3f63SJason Wang     int nvhosts = data_queue_pairs + cvq;
50092fbc3e0SCindy Lu     struct vhost_net *net;
50114c81b21SEugenio Pérez     int r, e, i, index_end = data_queue_pairs * 2;
50292fbc3e0SCindy Lu     NetClientState *peer;
5036e790746SPaolo Bonzini 
50414c81b21SEugenio Pérez     if (cvq) {
50514c81b21SEugenio Pérez         index_end += 1;
506049eb15bSJason Wang     }
507049eb15bSJason Wang 
5081c819449SKONRAD Frederic     if (!k->set_guest_notifiers) {
5096e790746SPaolo Bonzini         error_report("binding does not support guest notifiers");
510a4076440SLaurent Vivier         return -ENOSYS;
5116e790746SPaolo Bonzini     }
5126e790746SPaolo Bonzini 
51305ba3f63SJason Wang     for (i = 0; i < nvhosts; i++) {
5145669655aSVictor Kaplansky 
51505ba3f63SJason Wang         if (i < data_queue_pairs) {
51692fbc3e0SCindy Lu             peer = qemu_get_peer(ncs, i);
51705ba3f63SJason Wang         } else { /* Control Virtqueue */
518441537f1SJason Wang             peer = qemu_get_peer(ncs, n->max_queue_pairs);
51905ba3f63SJason Wang         }
52005ba3f63SJason Wang 
52192fbc3e0SCindy Lu         net = get_vhost_net(peer);
52214c81b21SEugenio Pérez         vhost_net_set_vq_index(net, i * 2, index_end);
5235669655aSVictor Kaplansky 
5245669655aSVictor Kaplansky         /* Suppress the masking guest notifiers on vhost user
5255669655aSVictor Kaplansky          * because vhost user doesn't interrupt masking/unmasking
5265669655aSVictor Kaplansky          * properly.
5275669655aSVictor Kaplansky          */
528f394b2e2SEric Blake         if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
5295669655aSVictor Kaplansky             dev->use_guest_notifier_mask = false;
5305669655aSVictor Kaplansky         }
5316e790746SPaolo Bonzini      }
5326e790746SPaolo Bonzini 
5336166799fSzuoboqun     r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq);
5346166799fSzuoboqun     if (r < 0) {
5356166799fSzuoboqun         error_report("Error enabling host notifiers: %d", -r);
5366166799fSzuoboqun         goto err;
5376166799fSzuoboqun     }
5386166799fSzuoboqun 
53905ba3f63SJason Wang     r = k->set_guest_notifiers(qbus->parent, total_notifiers, true);
5406e790746SPaolo Bonzini     if (r < 0) {
5416e790746SPaolo Bonzini         error_report("Error binding guest notifier: %d", -r);
5426166799fSzuoboqun         goto err_host_notifiers;
5436e790746SPaolo Bonzini     }
5446e790746SPaolo Bonzini 
54505ba3f63SJason Wang     for (i = 0; i < nvhosts; i++) {
54605ba3f63SJason Wang         if (i < data_queue_pairs) {
54792fbc3e0SCindy Lu             peer = qemu_get_peer(ncs, i);
54805ba3f63SJason Wang         } else {
549441537f1SJason Wang             peer = qemu_get_peer(ncs, n->max_queue_pairs);
55005ba3f63SJason Wang         }
551bfc6cf31SMarc-André Lureau 
55292fbc3e0SCindy Lu         if (peer->vring_enable) {
553bfc6cf31SMarc-André Lureau             /* restore vring enable state */
55492fbc3e0SCindy Lu             r = vhost_set_vring_enable(peer, peer->vring_enable);
555bfc6cf31SMarc-André Lureau 
556bfc6cf31SMarc-André Lureau             if (r < 0) {
5576166799fSzuoboqun                 goto err_guest_notifiers;
558bfc6cf31SMarc-André Lureau             }
559bfc6cf31SMarc-André Lureau         }
5608b67fe00SYajun Wu 
5618b67fe00SYajun Wu         r = vhost_net_start_one(get_vhost_net(peer), dev);
5628b67fe00SYajun Wu         if (r < 0) {
5636166799fSzuoboqun             goto err_guest_notifiers;
5648b67fe00SYajun Wu         }
565cd7d1d26SJason Wang     }
566cd7d1d26SJason Wang 
5676e790746SPaolo Bonzini     return 0;
5686e790746SPaolo Bonzini 
5696166799fSzuoboqun err_guest_notifiers:
5706e790746SPaolo Bonzini     while (--i >= 0) {
5716f3910b5SSi-Wei Liu         peer = qemu_get_peer(ncs, i < data_queue_pairs ?
5726f3910b5SSi-Wei Liu                                   i : n->max_queue_pairs);
57392fbc3e0SCindy Lu         vhost_net_stop_one(get_vhost_net(peer), dev);
5746e790746SPaolo Bonzini     }
57505ba3f63SJason Wang     e = k->set_guest_notifiers(qbus->parent, total_notifiers, false);
576cd7d1d26SJason Wang     if (e < 0) {
577cd7d1d26SJason Wang         fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
578cd7d1d26SJason Wang         fflush(stderr);
579cd7d1d26SJason Wang     }
5806166799fSzuoboqun err_host_notifiers:
5816166799fSzuoboqun     vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
5823154d1e4SGreg Kurz err:
5836e790746SPaolo Bonzini     return r;
5846e790746SPaolo Bonzini }
5856e790746SPaolo Bonzini 
vhost_net_stop(VirtIODevice * dev,NetClientState * ncs,int data_queue_pairs,int cvq)5866e790746SPaolo Bonzini void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
58705ba3f63SJason Wang                     int data_queue_pairs, int cvq)
5886e790746SPaolo Bonzini {
5891c819449SKONRAD Frederic     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
5901c819449SKONRAD Frederic     VirtioBusState *vbus = VIRTIO_BUS(qbus);
5911c819449SKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
59205ba3f63SJason Wang     VirtIONet *n = VIRTIO_NET(dev);
59305ba3f63SJason Wang     NetClientState *peer;
59405ba3f63SJason Wang     int total_notifiers = data_queue_pairs * 2 + cvq;
59505ba3f63SJason Wang     int nvhosts = data_queue_pairs + cvq;
5966e790746SPaolo Bonzini     int i, r;
5976e790746SPaolo Bonzini 
59805ba3f63SJason Wang     for (i = 0; i < nvhosts; i++) {
59905ba3f63SJason Wang         if (i < data_queue_pairs) {
60005ba3f63SJason Wang             peer = qemu_get_peer(ncs, i);
60105ba3f63SJason Wang         } else {
602441537f1SJason Wang             peer = qemu_get_peer(ncs, n->max_queue_pairs);
60305ba3f63SJason Wang         }
60405ba3f63SJason Wang         vhost_net_stop_one(get_vhost_net(peer), dev);
605cd7d1d26SJason Wang     }
606cd7d1d26SJason Wang 
60705ba3f63SJason Wang     r = k->set_guest_notifiers(qbus->parent, total_notifiers, false);
6086e790746SPaolo Bonzini     if (r < 0) {
6096e790746SPaolo Bonzini         fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
6106e790746SPaolo Bonzini         fflush(stderr);
6116e790746SPaolo Bonzini     }
6126e790746SPaolo Bonzini     assert(r >= 0);
6136166799fSzuoboqun 
6146166799fSzuoboqun     vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
6156e790746SPaolo Bonzini }
6166e790746SPaolo Bonzini 
vhost_net_cleanup(struct vhost_net * net)6176e790746SPaolo Bonzini void vhost_net_cleanup(struct vhost_net *net)
6186e790746SPaolo Bonzini {
6196e790746SPaolo Bonzini     vhost_dev_cleanup(&net->dev);
6206e790746SPaolo Bonzini }
6216e790746SPaolo Bonzini 
vhost_net_notify_migration_done(struct vhost_net * net,char * mac_addr)6223e866365SThibaut Collet int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
6233e866365SThibaut Collet {
6243e866365SThibaut Collet     const VhostOps *vhost_ops = net->dev.vhost_ops;
6253e866365SThibaut Collet 
62651f7aca9SMarc-André Lureau     assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
62751f7aca9SMarc-André Lureau     assert(vhost_ops->vhost_migration_done);
6283e866365SThibaut Collet 
62951f7aca9SMarc-André Lureau     return vhost_ops->vhost_migration_done(&net->dev, mac_addr);
6303e866365SThibaut Collet }
6313e866365SThibaut Collet 
vhost_net_virtqueue_pending(VHostNetState * net,int idx)6326e790746SPaolo Bonzini bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
6336e790746SPaolo Bonzini {
6346e790746SPaolo Bonzini     return vhost_virtqueue_pending(&net->dev, idx);
6356e790746SPaolo Bonzini }
6366e790746SPaolo Bonzini 
vhost_net_virtqueue_mask(VHostNetState * net,VirtIODevice * dev,int idx,bool mask)6376e790746SPaolo Bonzini void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
6386e790746SPaolo Bonzini                               int idx, bool mask)
6396e790746SPaolo Bonzini {
6406e790746SPaolo Bonzini     vhost_virtqueue_mask(&net->dev, dev, idx, mask);
6416e790746SPaolo Bonzini }
642ed8b4afeSNikolay Nikolaev 
vhost_net_config_pending(VHostNetState * net)6438aab0d1dSCindy Lu bool vhost_net_config_pending(VHostNetState *net)
6448aab0d1dSCindy Lu {
6458aab0d1dSCindy Lu     return vhost_config_pending(&net->dev);
6468aab0d1dSCindy Lu }
6478aab0d1dSCindy Lu 
vhost_net_config_mask(VHostNetState * net,VirtIODevice * dev,bool mask)6488aab0d1dSCindy Lu void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask)
6498aab0d1dSCindy Lu {
6508aab0d1dSCindy Lu     vhost_config_mask(&net->dev, dev, mask);
6518aab0d1dSCindy Lu }
get_vhost_net(NetClientState * nc)652ed8b4afeSNikolay Nikolaev VHostNetState *get_vhost_net(NetClientState *nc)
653ed8b4afeSNikolay Nikolaev {
654ed8b4afeSNikolay Nikolaev     VHostNetState *vhost_net = 0;
655ed8b4afeSNikolay Nikolaev 
656ed8b4afeSNikolay Nikolaev     if (!nc) {
657ed8b4afeSNikolay Nikolaev         return 0;
658ed8b4afeSNikolay Nikolaev     }
659ed8b4afeSNikolay Nikolaev 
660ed8b4afeSNikolay Nikolaev     switch (nc->info->type) {
661f394b2e2SEric Blake     case NET_CLIENT_DRIVER_TAP:
662ed8b4afeSNikolay Nikolaev         vhost_net = tap_get_vhost_net(nc);
663ca3fcdeeSAni Sinha         /*
664ca3fcdeeSAni Sinha          * tap_get_vhost_net() can return NULL if a tap net-device backend is
665ca3fcdeeSAni Sinha          * created with 'vhost=off' option, 'vhostforce=off' or no vhost or
666ca3fcdeeSAni Sinha          * vhostforce or vhostfd options at all. Please see net_init_tap_one().
667ca3fcdeeSAni Sinha          * Hence, we omit the assertion here.
668ca3fcdeeSAni Sinha          */
669ed8b4afeSNikolay Nikolaev         break;
67056f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER
671f394b2e2SEric Blake     case NET_CLIENT_DRIVER_VHOST_USER:
67203ce5744SNikolay Nikolaev         vhost_net = vhost_user_get_vhost_net(nc);
6731a5b68ceSMarc-André Lureau         assert(vhost_net);
67403ce5744SNikolay Nikolaev         break;
67556f41de7SPaolo Bonzini #endif
676108a6481SCindy Lu #ifdef CONFIG_VHOST_NET_VDPA
677108a6481SCindy Lu     case NET_CLIENT_DRIVER_VHOST_VDPA:
678108a6481SCindy Lu         vhost_net = vhost_vdpa_get_vhost_net(nc);
679108a6481SCindy Lu         assert(vhost_net);
680108a6481SCindy Lu         break;
681108a6481SCindy Lu #endif
682ed8b4afeSNikolay Nikolaev     default:
683ed8b4afeSNikolay Nikolaev         break;
684ed8b4afeSNikolay Nikolaev     }
685ed8b4afeSNikolay Nikolaev 
686ed8b4afeSNikolay Nikolaev     return vhost_net;
687ed8b4afeSNikolay Nikolaev }
6887263a0adSChangchun Ouyang 
vhost_set_vring_enable(NetClientState * nc,int enable)6897263a0adSChangchun Ouyang int vhost_set_vring_enable(NetClientState *nc, int enable)
6907263a0adSChangchun Ouyang {
6917263a0adSChangchun Ouyang     VHostNetState *net = get_vhost_net(nc);
692bb12e761SMarc-André Lureau     const VhostOps *vhost_ops = net->dev.vhost_ops;
6937263a0adSChangchun Ouyang 
6942c66de61SKevin Wolf     /*
6952c66de61SKevin Wolf      * vhost-vdpa network devices need to enable dataplane virtqueues after
6962c66de61SKevin Wolf      * DRIVER_OK, so they can recover device state before starting dataplane.
6972c66de61SKevin Wolf      * Because of that, we don't enable virtqueues here and leave it to
6982c66de61SKevin Wolf      * net/vhost-vdpa.c.
6992c66de61SKevin Wolf      */
7002c66de61SKevin Wolf     if (nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
7012c66de61SKevin Wolf         return 0;
7022c66de61SKevin Wolf     }
7032c66de61SKevin Wolf 
704bfc6cf31SMarc-André Lureau     nc->vring_enable = enable;
705bfc6cf31SMarc-André Lureau 
706ca10203cSIlya Maximets     if (vhost_ops && vhost_ops->vhost_set_vring_enable) {
70721e70425SMarc-André Lureau         return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
7087263a0adSChangchun Ouyang     }
7097263a0adSChangchun Ouyang 
7107263a0adSChangchun Ouyang     return 0;
7117263a0adSChangchun Ouyang }
7127263a0adSChangchun Ouyang 
vhost_net_set_mtu(struct vhost_net * net,uint16_t mtu)71345a368adSMaxime Coquelin int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
71445a368adSMaxime Coquelin {
71545a368adSMaxime Coquelin     const VhostOps *vhost_ops = net->dev.vhost_ops;
71645a368adSMaxime Coquelin 
71745a368adSMaxime Coquelin     if (!vhost_ops->vhost_net_set_mtu) {
71845a368adSMaxime Coquelin         return 0;
71945a368adSMaxime Coquelin     }
72045a368adSMaxime Coquelin 
72145a368adSMaxime Coquelin     return vhost_ops->vhost_net_set_mtu(&net->dev, mtu);
72245a368adSMaxime Coquelin }
723c2daa08eSKangjie Xu 
vhost_net_virtqueue_reset(VirtIODevice * vdev,NetClientState * nc,int vq_index)724c2daa08eSKangjie Xu void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
725c2daa08eSKangjie Xu                                int vq_index)
726c2daa08eSKangjie Xu {
727c2daa08eSKangjie Xu     VHostNetState *net = get_vhost_net(nc->peer);
728c2daa08eSKangjie Xu     const VhostOps *vhost_ops = net->dev.vhost_ops;
729c2daa08eSKangjie Xu     struct vhost_vring_file file = { .fd = -1 };
730c2daa08eSKangjie Xu     int idx;
731c2daa08eSKangjie Xu 
732c2daa08eSKangjie Xu     /* should only be called after backend is connected */
733c2daa08eSKangjie Xu     assert(vhost_ops);
734c2daa08eSKangjie Xu 
735c2daa08eSKangjie Xu     idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index);
736c2daa08eSKangjie Xu 
737c2daa08eSKangjie Xu     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
738c2daa08eSKangjie Xu         file.index = idx;
739c2daa08eSKangjie Xu         int r = vhost_net_set_backend(&net->dev, &file);
740c2daa08eSKangjie Xu         assert(r >= 0);
741c2daa08eSKangjie Xu     }
742c2daa08eSKangjie Xu 
743c2daa08eSKangjie Xu     vhost_virtqueue_stop(&net->dev,
744c2daa08eSKangjie Xu                          vdev,
745c2daa08eSKangjie Xu                          net->dev.vqs + idx,
746c2daa08eSKangjie Xu                          net->dev.vq_index + idx);
747c2daa08eSKangjie Xu }
74810f8a115SKangjie Xu 
vhost_net_virtqueue_restart(VirtIODevice * vdev,NetClientState * nc,int vq_index)74910f8a115SKangjie Xu int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
75010f8a115SKangjie Xu                                 int vq_index)
75110f8a115SKangjie Xu {
75210f8a115SKangjie Xu     VHostNetState *net = get_vhost_net(nc->peer);
75310f8a115SKangjie Xu     const VhostOps *vhost_ops = net->dev.vhost_ops;
75410f8a115SKangjie Xu     struct vhost_vring_file file = { };
75510f8a115SKangjie Xu     int idx, r;
75610f8a115SKangjie Xu 
75710f8a115SKangjie Xu     if (!net->dev.started) {
75810f8a115SKangjie Xu         return -EBUSY;
75910f8a115SKangjie Xu     }
76010f8a115SKangjie Xu 
76110f8a115SKangjie Xu     /* should only be called after backend is connected */
76210f8a115SKangjie Xu     assert(vhost_ops);
76310f8a115SKangjie Xu 
76410f8a115SKangjie Xu     idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index);
76510f8a115SKangjie Xu 
76610f8a115SKangjie Xu     r = vhost_virtqueue_start(&net->dev,
76710f8a115SKangjie Xu                               vdev,
76810f8a115SKangjie Xu                               net->dev.vqs + idx,
76910f8a115SKangjie Xu                               net->dev.vq_index + idx);
77010f8a115SKangjie Xu     if (r < 0) {
77110f8a115SKangjie Xu         goto err_start;
77210f8a115SKangjie Xu     }
77310f8a115SKangjie Xu 
77410f8a115SKangjie Xu     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
77510f8a115SKangjie Xu         file.index = idx;
77610f8a115SKangjie Xu         file.fd = net->backend;
77710f8a115SKangjie Xu         r = vhost_net_set_backend(&net->dev, &file);
77810f8a115SKangjie Xu         if (r < 0) {
77910f8a115SKangjie Xu             r = -errno;
78010f8a115SKangjie Xu             goto err_start;
78110f8a115SKangjie Xu         }
78210f8a115SKangjie Xu     }
78310f8a115SKangjie Xu 
78410f8a115SKangjie Xu     return 0;
78510f8a115SKangjie Xu 
78610f8a115SKangjie Xu err_start:
78710f8a115SKangjie Xu     error_report("Error when restarting the queue.");
78810f8a115SKangjie Xu 
78910f8a115SKangjie Xu     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
79010f8a115SKangjie Xu         file.fd = VHOST_FILE_UNBIND;
79110f8a115SKangjie Xu         file.index = idx;
7925d63cb15SThomas Huth         int ret = vhost_net_set_backend(&net->dev, &file);
7935d63cb15SThomas Huth         assert(ret >= 0);
79410f8a115SKangjie Xu     }
79510f8a115SKangjie Xu 
7964daa5054SStefano Garzarella     vhost_dev_stop(&net->dev, vdev, false);
79710f8a115SKangjie Xu 
79810f8a115SKangjie Xu     return r;
79910f8a115SKangjie Xu }
800