xref: /qemu/hw/net/vhost_net.c (revision e3e48565c1553f9ab4c34c2388287a013ef30deb)
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 
161422e32dSPaolo Bonzini #include "net/net.h"
17d5970055SMichael S. Tsirkin #include "net/tap.h"
18d5970055SMichael S. Tsirkin 
190d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
200d09e41aSPaolo Bonzini #include "net/vhost_net.h"
211de7afc9SPaolo Bonzini #include "qemu/error-report.h"
22d5970055SMichael S. Tsirkin 
23d5970055SMichael S. Tsirkin #include "config.h"
24d5970055SMichael S. Tsirkin 
25d5970055SMichael S. Tsirkin #ifdef CONFIG_VHOST_NET
26d5970055SMichael S. Tsirkin #include <linux/vhost.h>
27d5970055SMichael S. Tsirkin #include <sys/socket.h>
28d5970055SMichael S. Tsirkin #include <linux/kvm.h>
29d5970055SMichael S. Tsirkin #include <fcntl.h>
30d5970055SMichael S. Tsirkin #include <sys/ioctl.h>
31d5970055SMichael S. Tsirkin #include <linux/virtio_ring.h>
32d5970055SMichael S. Tsirkin #include <netpacket/packet.h>
33d5970055SMichael S. Tsirkin #include <net/ethernet.h>
34d5970055SMichael S. Tsirkin #include <net/if.h>
35d5970055SMichael S. Tsirkin #include <netinet/in.h>
36d5970055SMichael S. Tsirkin 
37d5970055SMichael S. Tsirkin #include <stdio.h>
38d5970055SMichael S. Tsirkin 
390d09e41aSPaolo Bonzini #include "hw/virtio/vhost.h"
401c819449SKONRAD Frederic #include "hw/virtio/virtio-bus.h"
41d5970055SMichael S. Tsirkin 
42d5970055SMichael S. Tsirkin struct vhost_net {
43d5970055SMichael S. Tsirkin     struct vhost_dev dev;
44d5970055SMichael S. Tsirkin     struct vhost_virtqueue vqs[2];
45d5970055SMichael S. Tsirkin     int backend;
4635277d14SStefan Hajnoczi     NetClientState *nc;
47d5970055SMichael S. Tsirkin };
48d5970055SMichael S. Tsirkin 
49d5970055SMichael S. Tsirkin unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
50d5970055SMichael S. Tsirkin {
51d5970055SMichael S. Tsirkin     /* Clear features not supported by host kernel. */
52d5970055SMichael S. Tsirkin     if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
53d5970055SMichael S. Tsirkin         features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
54d5970055SMichael S. Tsirkin     }
55d5970055SMichael S. Tsirkin     if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
56d5970055SMichael S. Tsirkin         features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
57d5970055SMichael S. Tsirkin     }
58bcbabae8SMichael S. Tsirkin     if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
59bcbabae8SMichael S. Tsirkin         features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
60bcbabae8SMichael S. Tsirkin     }
61ca736c8eSMichael S. Tsirkin     if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
625751995aSMichael S. Tsirkin         features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
63ca736c8eSMichael S. Tsirkin     }
64d5970055SMichael S. Tsirkin     return features;
65d5970055SMichael S. Tsirkin }
66d5970055SMichael S. Tsirkin 
67d5970055SMichael S. Tsirkin void vhost_net_ack_features(struct vhost_net *net, unsigned features)
68d5970055SMichael S. Tsirkin {
69d5970055SMichael S. Tsirkin     net->dev.acked_features = net->dev.backend_features;
70d5970055SMichael S. Tsirkin     if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
71d5970055SMichael S. Tsirkin         net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
72d5970055SMichael S. Tsirkin     }
73d5970055SMichael S. Tsirkin     if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
74d5970055SMichael S. Tsirkin         net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
75d5970055SMichael S. Tsirkin     }
76bcbabae8SMichael S. Tsirkin     if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
77bcbabae8SMichael S. Tsirkin         net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
78bcbabae8SMichael S. Tsirkin     }
79ca736c8eSMichael S. Tsirkin     if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
80ca736c8eSMichael S. Tsirkin         net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
81ca736c8eSMichael S. Tsirkin     }
82d5970055SMichael S. Tsirkin }
83d5970055SMichael S. Tsirkin 
844e68f7a0SStefan Hajnoczi static int vhost_net_get_fd(NetClientState *backend)
85d5970055SMichael S. Tsirkin {
86d5970055SMichael S. Tsirkin     switch (backend->info->type) {
872be64a68SLaszlo Ersek     case NET_CLIENT_OPTIONS_KIND_TAP:
88d5970055SMichael S. Tsirkin         return tap_get_fd(backend);
89d5970055SMichael S. Tsirkin     default:
90d5970055SMichael S. Tsirkin         fprintf(stderr, "vhost-net requires tap backend\n");
91d5970055SMichael S. Tsirkin         return -EBADFD;
92d5970055SMichael S. Tsirkin     }
93d5970055SMichael S. Tsirkin }
94d5970055SMichael S. Tsirkin 
954e68f7a0SStefan Hajnoczi struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
965430a28fSmst@redhat.com                                  bool force)
97d5970055SMichael S. Tsirkin {
98d5970055SMichael S. Tsirkin     int r;
997267c094SAnthony Liguori     struct vhost_net *net = g_malloc(sizeof *net);
100d5970055SMichael S. Tsirkin     if (!backend) {
101d5970055SMichael S. Tsirkin         fprintf(stderr, "vhost-net requires backend to be setup\n");
102d5970055SMichael S. Tsirkin         goto fail;
103d5970055SMichael S. Tsirkin     }
104d5970055SMichael S. Tsirkin     r = vhost_net_get_fd(backend);
105d5970055SMichael S. Tsirkin     if (r < 0) {
106d5970055SMichael S. Tsirkin         goto fail;
107d5970055SMichael S. Tsirkin     }
10835277d14SStefan Hajnoczi     net->nc = backend;
109*e3e48565SStefan Hajnoczi     net->dev.backend_features = qemu_has_vnet_hdr(backend) ? 0 :
110d5970055SMichael S. Tsirkin         (1 << VHOST_NET_F_VIRTIO_NET_HDR);
111d5970055SMichael S. Tsirkin     net->backend = r;
112d5970055SMichael S. Tsirkin 
113f56a1247SMichael S. Tsirkin     net->dev.nvqs = 2;
114f56a1247SMichael S. Tsirkin     net->dev.vqs = net->vqs;
115f56a1247SMichael S. Tsirkin 
1161241ed94SStefan Hajnoczi     r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force);
117d5970055SMichael S. Tsirkin     if (r < 0) {
118d5970055SMichael S. Tsirkin         goto fail;
119d5970055SMichael S. Tsirkin     }
120*e3e48565SStefan Hajnoczi     if (!qemu_has_vnet_hdr_len(backend,
121ca736c8eSMichael S. Tsirkin                                sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
122ca736c8eSMichael S. Tsirkin         net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
123ca736c8eSMichael S. Tsirkin     }
124d5970055SMichael S. Tsirkin     if (~net->dev.features & net->dev.backend_features) {
1250bfcd599SBlue Swirl         fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
12629f91781SJes Sorensen                 (uint64_t)(~net->dev.features & net->dev.backend_features));
127d5970055SMichael S. Tsirkin         vhost_dev_cleanup(&net->dev);
128d5970055SMichael S. Tsirkin         goto fail;
129d5970055SMichael S. Tsirkin     }
130d5970055SMichael S. Tsirkin 
131d5970055SMichael S. Tsirkin     /* Set sane init value. Override when guest acks. */
132d5970055SMichael S. Tsirkin     vhost_net_ack_features(net, 0);
133d5970055SMichael S. Tsirkin     return net;
134d5970055SMichael S. Tsirkin fail:
1357267c094SAnthony Liguori     g_free(net);
136d5970055SMichael S. Tsirkin     return NULL;
137d5970055SMichael S. Tsirkin }
138d5970055SMichael S. Tsirkin 
1395430a28fSmst@redhat.com bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
1405430a28fSmst@redhat.com {
1415430a28fSmst@redhat.com     return vhost_dev_query(&net->dev, dev);
1425430a28fSmst@redhat.com }
1435430a28fSmst@redhat.com 
144a9f98bb5SJason Wang static int vhost_net_start_one(struct vhost_net *net,
145a9f98bb5SJason Wang                                VirtIODevice *dev,
146a9f98bb5SJason Wang                                int vq_index)
147d5970055SMichael S. Tsirkin {
148d5970055SMichael S. Tsirkin     struct vhost_vring_file file = { };
149d5970055SMichael S. Tsirkin     int r;
150b0b3db79SMichael S. Tsirkin 
151a9f98bb5SJason Wang     if (net->dev.started) {
152a9f98bb5SJason Wang         return 0;
153a9f98bb5SJason Wang     }
154a9f98bb5SJason Wang 
155a9f98bb5SJason Wang     net->dev.nvqs = 2;
156a9f98bb5SJason Wang     net->dev.vqs = net->vqs;
157a9f98bb5SJason Wang     net->dev.vq_index = vq_index;
158a9f98bb5SJason Wang 
159b0b3db79SMichael S. Tsirkin     r = vhost_dev_enable_notifiers(&net->dev, dev);
160b0b3db79SMichael S. Tsirkin     if (r < 0) {
161b0b3db79SMichael S. Tsirkin         goto fail_notifiers;
162b0b3db79SMichael S. Tsirkin     }
163d5970055SMichael S. Tsirkin 
164d5970055SMichael S. Tsirkin     r = vhost_dev_start(&net->dev, dev);
165d5970055SMichael S. Tsirkin     if (r < 0) {
166b0b3db79SMichael S. Tsirkin         goto fail_start;
167d5970055SMichael S. Tsirkin     }
168d5970055SMichael S. Tsirkin 
16935277d14SStefan Hajnoczi     net->nc->info->poll(net->nc, false);
170d5970055SMichael S. Tsirkin     qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
171d5970055SMichael S. Tsirkin     file.fd = net->backend;
172d5970055SMichael S. Tsirkin     for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
173d5970055SMichael S. Tsirkin         r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
174d5970055SMichael S. Tsirkin         if (r < 0) {
175d5970055SMichael S. Tsirkin             r = -errno;
176d5970055SMichael S. Tsirkin             goto fail;
177d5970055SMichael S. Tsirkin         }
178d5970055SMichael S. Tsirkin     }
179d5970055SMichael S. Tsirkin     return 0;
180d5970055SMichael S. Tsirkin fail:
181d5970055SMichael S. Tsirkin     file.fd = -1;
1826b37c87cSMichael S. Tsirkin     while (file.index-- > 0) {
183d5970055SMichael S. Tsirkin         int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
184d5970055SMichael S. Tsirkin         assert(r >= 0);
185d5970055SMichael S. Tsirkin     }
18635277d14SStefan Hajnoczi     net->nc->info->poll(net->nc, true);
187d5970055SMichael S. Tsirkin     vhost_dev_stop(&net->dev, dev);
188b0b3db79SMichael S. Tsirkin fail_start:
189b0b3db79SMichael S. Tsirkin     vhost_dev_disable_notifiers(&net->dev, dev);
190b0b3db79SMichael S. Tsirkin fail_notifiers:
191d5970055SMichael S. Tsirkin     return r;
192d5970055SMichael S. Tsirkin }
193d5970055SMichael S. Tsirkin 
194a9f98bb5SJason Wang static void vhost_net_stop_one(struct vhost_net *net,
195d5970055SMichael S. Tsirkin                                VirtIODevice *dev)
196d5970055SMichael S. Tsirkin {
197d5970055SMichael S. Tsirkin     struct vhost_vring_file file = { .fd = -1 };
198d5970055SMichael S. Tsirkin 
199a9f98bb5SJason Wang     if (!net->dev.started) {
200a9f98bb5SJason Wang         return;
201a9f98bb5SJason Wang     }
202a9f98bb5SJason Wang 
203d5970055SMichael S. Tsirkin     for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
204d5970055SMichael S. Tsirkin         int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
205d5970055SMichael S. Tsirkin         assert(r >= 0);
206d5970055SMichael S. Tsirkin     }
20735277d14SStefan Hajnoczi     net->nc->info->poll(net->nc, true);
208d5970055SMichael S. Tsirkin     vhost_dev_stop(&net->dev, dev);
209b0b3db79SMichael S. Tsirkin     vhost_dev_disable_notifiers(&net->dev, dev);
210d5970055SMichael S. Tsirkin }
211d5970055SMichael S. Tsirkin 
212a9f98bb5SJason Wang int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
213a9f98bb5SJason Wang                     int total_queues)
214a9f98bb5SJason Wang {
2151c819449SKONRAD Frederic     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
2161c819449SKONRAD Frederic     VirtioBusState *vbus = VIRTIO_BUS(qbus);
2171c819449SKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
218a9f98bb5SJason Wang     int r, i = 0;
219a9f98bb5SJason Wang 
2201c819449SKONRAD Frederic     if (!k->set_guest_notifiers) {
221312fd5f2SMarkus Armbruster         error_report("binding does not support guest notifiers");
222a9f98bb5SJason Wang         r = -ENOSYS;
223a9f98bb5SJason Wang         goto err;
224a9f98bb5SJason Wang     }
225a9f98bb5SJason Wang 
226a9f98bb5SJason Wang     for (i = 0; i < total_queues; i++) {
227a9f98bb5SJason Wang         r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2);
228a9f98bb5SJason Wang 
229a9f98bb5SJason Wang         if (r < 0) {
230a9f98bb5SJason Wang             goto err;
231a9f98bb5SJason Wang         }
232a9f98bb5SJason Wang     }
233a9f98bb5SJason Wang 
2341c819449SKONRAD Frederic     r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
235a9f98bb5SJason Wang     if (r < 0) {
236312fd5f2SMarkus Armbruster         error_report("Error binding guest notifier: %d", -r);
237a9f98bb5SJason Wang         goto err;
238a9f98bb5SJason Wang     }
239a9f98bb5SJason Wang 
240a9f98bb5SJason Wang     return 0;
241a9f98bb5SJason Wang 
242a9f98bb5SJason Wang err:
243a9f98bb5SJason Wang     while (--i >= 0) {
244a9f98bb5SJason Wang         vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
245a9f98bb5SJason Wang     }
246a9f98bb5SJason Wang     return r;
247a9f98bb5SJason Wang }
248a9f98bb5SJason Wang 
249a9f98bb5SJason Wang void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
250a9f98bb5SJason Wang                     int total_queues)
251a9f98bb5SJason Wang {
2521c819449SKONRAD Frederic     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
2531c819449SKONRAD Frederic     VirtioBusState *vbus = VIRTIO_BUS(qbus);
2541c819449SKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
255a9f98bb5SJason Wang     int i, r;
256a9f98bb5SJason Wang 
2571c819449SKONRAD Frederic     r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
258a9f98bb5SJason Wang     if (r < 0) {
259a9f98bb5SJason Wang         fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
260a9f98bb5SJason Wang         fflush(stderr);
261a9f98bb5SJason Wang     }
262a9f98bb5SJason Wang     assert(r >= 0);
263a9f98bb5SJason Wang 
264a9f98bb5SJason Wang     for (i = 0; i < total_queues; i++) {
265a9f98bb5SJason Wang         vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
266a9f98bb5SJason Wang     }
267a9f98bb5SJason Wang }
268a9f98bb5SJason Wang 
269d5970055SMichael S. Tsirkin void vhost_net_cleanup(struct vhost_net *net)
270d5970055SMichael S. Tsirkin {
271d5970055SMichael S. Tsirkin     vhost_dev_cleanup(&net->dev);
2727267c094SAnthony Liguori     g_free(net);
273d5970055SMichael S. Tsirkin }
274f56a1247SMichael S. Tsirkin 
275f56a1247SMichael S. Tsirkin bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
276f56a1247SMichael S. Tsirkin {
277f56a1247SMichael S. Tsirkin     return vhost_virtqueue_pending(&net->dev, idx);
278f56a1247SMichael S. Tsirkin }
279f56a1247SMichael S. Tsirkin 
280f56a1247SMichael S. Tsirkin void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
281f56a1247SMichael S. Tsirkin                               int idx, bool mask)
282f56a1247SMichael S. Tsirkin {
283f56a1247SMichael S. Tsirkin     vhost_virtqueue_mask(&net->dev, dev, idx, mask);
284f56a1247SMichael S. Tsirkin }
285d5970055SMichael S. Tsirkin #else
2864e68f7a0SStefan Hajnoczi struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
2875430a28fSmst@redhat.com                                  bool force)
288d5970055SMichael S. Tsirkin {
28935f75462SMichael Tokarev     error_report("vhost-net support is not compiled in");
290d5970055SMichael S. Tsirkin     return NULL;
291d5970055SMichael S. Tsirkin }
292d5970055SMichael S. Tsirkin 
2935430a28fSmst@redhat.com bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
2945430a28fSmst@redhat.com {
2955430a28fSmst@redhat.com     return false;
2965430a28fSmst@redhat.com }
2975430a28fSmst@redhat.com 
298a9f98bb5SJason Wang int vhost_net_start(VirtIODevice *dev,
299a9f98bb5SJason Wang                     NetClientState *ncs,
300a9f98bb5SJason Wang                     int total_queues)
301d5970055SMichael S. Tsirkin {
302d5970055SMichael S. Tsirkin     return -ENOSYS;
303d5970055SMichael S. Tsirkin }
304a9f98bb5SJason Wang void vhost_net_stop(VirtIODevice *dev,
305a9f98bb5SJason Wang                     NetClientState *ncs,
306a9f98bb5SJason Wang                     int total_queues)
307d5970055SMichael S. Tsirkin {
308d5970055SMichael S. Tsirkin }
309d5970055SMichael S. Tsirkin 
310d5970055SMichael S. Tsirkin void vhost_net_cleanup(struct vhost_net *net)
311d5970055SMichael S. Tsirkin {
312d5970055SMichael S. Tsirkin }
313d5970055SMichael S. Tsirkin 
314d5970055SMichael S. Tsirkin unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
315d5970055SMichael S. Tsirkin {
316d5970055SMichael S. Tsirkin     return features;
317d5970055SMichael S. Tsirkin }
318d5970055SMichael S. Tsirkin void vhost_net_ack_features(struct vhost_net *net, unsigned features)
319d5970055SMichael S. Tsirkin {
320d5970055SMichael S. Tsirkin }
321f56a1247SMichael S. Tsirkin 
322f56a1247SMichael S. Tsirkin bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
323f56a1247SMichael S. Tsirkin {
3244dd72e04SStefan Weil     return false;
325f56a1247SMichael S. Tsirkin }
326f56a1247SMichael S. Tsirkin 
327f56a1247SMichael S. Tsirkin void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
328f56a1247SMichael S. Tsirkin                               int idx, bool mask)
329f56a1247SMichael S. Tsirkin {
330f56a1247SMichael S. Tsirkin }
331d5970055SMichael S. Tsirkin #endif
332