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