]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/net_backends.c
usr.sbin/bhyve: prevent use-after-free in virtio scsi request handling
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / net_backends.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Vincenzo Maffione <vmaffione@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 /*
31  * This file implements multiple network backends (tap, netmap, ...),
32  * to be used by network frontends such as virtio-net and e1000.
33  * The API to access the backend (e.g. send/receive packets, negotiate
34  * features) is exported by net_backends.h.
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/types.h>          /* u_short etc */
41 #ifndef WITHOUT_CAPSICUM
42 #include <sys/capsicum.h>
43 #endif
44 #include <sys/ioctl.h>
45 #include <sys/mman.h>
46 #include <sys/uio.h>
47
48 #include <net/if.h>
49 #include <net/netmap.h>
50 #include <net/netmap_virt.h>
51 #define NETMAP_WITH_LIBS
52 #include <net/netmap_user.h>
53
54 #ifndef WITHOUT_CAPSICUM
55 #include <capsicum_helpers.h>
56 #endif
57 #include <err.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <stdint.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <sysexits.h>
66 #include <assert.h>
67 #include <pthread.h>
68 #include <pthread_np.h>
69 #include <poll.h>
70 #include <assert.h>
71
72
73 #include "iov.h"
74 #include "mevent.h"
75 #include "net_backends.h"
76
77 #include <sys/linker_set.h>
78
79 /*
80  * Each network backend registers a set of function pointers that are
81  * used to implement the net backends API.
82  * This might need to be exposed if we implement backends in separate files.
83  */
84 struct net_backend {
85         const char *prefix;     /* prefix matching this backend */
86
87         /*
88          * Routines used to initialize and cleanup the resources needed
89          * by a backend. The cleanup function is used internally,
90          * and should not be called by the frontend.
91          */
92         int (*init)(struct net_backend *be, const char *devname,
93             net_be_rxeof_t cb, void *param);
94         void (*cleanup)(struct net_backend *be);
95
96         /*
97          * Called to serve a guest transmit request. The scatter-gather
98          * vector provided by the caller has 'iovcnt' elements and contains
99          * the packet to send.
100          */
101         ssize_t (*send)(struct net_backend *be, struct iovec *iov, int iovcnt);
102
103         /*
104          * Called to receive a packet from the backend. When the function
105          * returns a positive value 'len', the scatter-gather vector
106          * provided by the caller contains a packet with such length.
107          * The function returns 0 if the backend doesn't have a new packet to
108          * receive.
109          */
110         ssize_t (*recv)(struct net_backend *be, struct iovec *iov, int iovcnt);
111
112         /*
113          * Ask the backend for the virtio-net features it is able to
114          * support. Possible features are TSO, UFO and checksum offloading
115          * in both rx and tx direction and for both IPv4 and IPv6.
116          */
117         uint64_t (*get_cap)(struct net_backend *be);
118
119         /*
120          * Tell the backend to enable/disable the specified virtio-net
121          * features (capabilities).
122          */
123         int (*set_cap)(struct net_backend *be, uint64_t features,
124             unsigned int vnet_hdr_len);
125
126         struct pci_vtnet_softc *sc;
127         int fd;
128
129         /*
130          * Length of the virtio-net header used by the backend and the
131          * frontend, respectively. A zero value means that the header
132          * is not used.
133          */
134         unsigned int be_vnet_hdr_len;
135         unsigned int fe_vnet_hdr_len;
136
137         /* Size of backend-specific private data. */
138         size_t priv_size;
139
140         /* Room for backend-specific data. */
141         char opaque[0];
142 };
143
144 SET_DECLARE(net_backend_set, struct net_backend);
145
146 #define VNET_HDR_LEN    sizeof(struct virtio_net_rxhdr)
147
148 #define WPRINTF(params) printf params
149
150 /*
151  * The tap backend
152  */
153
154 struct tap_priv {
155         struct mevent *mevp;
156 };
157
158 static void
159 tap_cleanup(struct net_backend *be)
160 {
161         struct tap_priv *priv = (struct tap_priv *)be->opaque;
162
163         if (priv->mevp) {
164                 mevent_delete(priv->mevp);
165         }
166         if (be->fd != -1) {
167                 close(be->fd);
168                 be->fd = -1;
169         }
170 }
171
172 static int
173 tap_init(struct net_backend *be, const char *devname,
174          net_be_rxeof_t cb, void *param)
175 {
176         struct tap_priv *priv = (struct tap_priv *)be->opaque;
177         char tbuf[80];
178         int fd;
179         int opt = 1;
180 #ifndef WITHOUT_CAPSICUM
181         cap_rights_t rights;
182 #endif
183
184         if (cb == NULL) {
185                 WPRINTF(("TAP backend requires non-NULL callback\n"));
186                 return (-1);
187         }
188
189         strcpy(tbuf, "/dev/");
190         strlcat(tbuf, devname, sizeof(tbuf));
191
192         fd = open(tbuf, O_RDWR);
193         if (fd == -1) {
194                 WPRINTF(("open of tap device %s failed\n", tbuf));
195                 goto error;
196         }
197
198         /*
199          * Set non-blocking and register for read
200          * notifications with the event loop
201          */
202         if (ioctl(fd, FIONBIO, &opt) < 0) {
203                 WPRINTF(("tap device O_NONBLOCK failed\n"));
204                 goto error;
205         }
206
207 #ifndef WITHOUT_CAPSICUM
208         cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
209         if (caph_rights_limit(fd, &rights) == -1)
210                 errx(EX_OSERR, "Unable to apply rights for sandbox");
211 #endif
212
213         priv->mevp = mevent_add(fd, EVF_READ, cb, param);
214         if (priv->mevp == NULL) {
215                 WPRINTF(("Could not register event\n"));
216                 goto error;
217         }
218
219         be->fd = fd;
220
221         return (0);
222
223 error:
224         tap_cleanup(be);
225         return (-1);
226 }
227
228 /*
229  * Called to send a buffer chain out to the tap device
230  */
231 static ssize_t
232 tap_send(struct net_backend *be, struct iovec *iov, int iovcnt)
233 {
234         return (writev(be->fd, iov, iovcnt));
235 }
236
237 static ssize_t
238 tap_recv(struct net_backend *be, struct iovec *iov, int iovcnt)
239 {
240         ssize_t ret;
241
242         /* Should never be called without a valid tap fd */
243         assert(be->fd != -1);
244
245         ret = readv(be->fd, iov, iovcnt);
246
247         if (ret < 0 && errno == EWOULDBLOCK) {
248                 return (0);
249         }
250
251         return (ret);
252 }
253
254 static uint64_t
255 tap_get_cap(struct net_backend *be)
256 {
257
258         return (0); /* no capabilities for now */
259 }
260
261 static int
262 tap_set_cap(struct net_backend *be, uint64_t features,
263                 unsigned vnet_hdr_len)
264 {
265
266         return ((features || vnet_hdr_len) ? -1 : 0);
267 }
268
269 static struct net_backend tap_backend = {
270         .prefix = "tap",
271         .priv_size = sizeof(struct tap_priv),
272         .init = tap_init,
273         .cleanup = tap_cleanup,
274         .send = tap_send,
275         .recv = tap_recv,
276         .get_cap = tap_get_cap,
277         .set_cap = tap_set_cap,
278 };
279
280 /* A clone of the tap backend, with a different prefix. */
281 static struct net_backend vmnet_backend = {
282         .prefix = "vmnet",
283         .priv_size = sizeof(struct tap_priv),
284         .init = tap_init,
285         .cleanup = tap_cleanup,
286         .send = tap_send,
287         .recv = tap_recv,
288         .get_cap = tap_get_cap,
289         .set_cap = tap_set_cap,
290 };
291
292 DATA_SET(net_backend_set, tap_backend);
293 DATA_SET(net_backend_set, vmnet_backend);
294
295 /*
296  * The netmap backend
297  */
298
299 /* The virtio-net features supported by netmap. */
300 #define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \
301                 VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \
302                 VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \
303                 VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO)
304
305 struct netmap_priv {
306         char ifname[IFNAMSIZ];
307         struct nm_desc *nmd;
308         uint16_t memid;
309         struct netmap_ring *rx;
310         struct netmap_ring *tx;
311         struct mevent *mevp;
312         net_be_rxeof_t cb;
313         void *cb_param;
314 };
315
316 static void
317 nmreq_init(struct nmreq *req, char *ifname)
318 {
319
320         memset(req, 0, sizeof(*req));
321         strlcpy(req->nr_name, ifname, sizeof(req->nr_name));
322         req->nr_version = NETMAP_API;
323 }
324
325 static int
326 netmap_set_vnet_hdr_len(struct net_backend *be, int vnet_hdr_len)
327 {
328         int err;
329         struct nmreq req;
330         struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
331
332         nmreq_init(&req, priv->ifname);
333         req.nr_cmd = NETMAP_BDG_VNET_HDR;
334         req.nr_arg1 = vnet_hdr_len;
335         err = ioctl(be->fd, NIOCREGIF, &req);
336         if (err) {
337                 WPRINTF(("Unable to set vnet header length %d\n",
338                                 vnet_hdr_len));
339                 return (err);
340         }
341
342         be->be_vnet_hdr_len = vnet_hdr_len;
343
344         return (0);
345 }
346
347 static int
348 netmap_has_vnet_hdr_len(struct net_backend *be, unsigned vnet_hdr_len)
349 {
350         int prev_hdr_len = be->be_vnet_hdr_len;
351         int ret;
352
353         if (vnet_hdr_len == prev_hdr_len) {
354                 return (1);
355         }
356
357         ret = netmap_set_vnet_hdr_len(be, vnet_hdr_len);
358         if (ret) {
359                 return (0);
360         }
361
362         netmap_set_vnet_hdr_len(be, prev_hdr_len);
363
364         return (1);
365 }
366
367 static uint64_t
368 netmap_get_cap(struct net_backend *be)
369 {
370
371         return (netmap_has_vnet_hdr_len(be, VNET_HDR_LEN) ?
372             NETMAP_FEATURES : 0);
373 }
374
375 static int
376 netmap_set_cap(struct net_backend *be, uint64_t features,
377                unsigned vnet_hdr_len)
378 {
379
380         return (netmap_set_vnet_hdr_len(be, vnet_hdr_len));
381 }
382
383 static int
384 netmap_init(struct net_backend *be, const char *devname,
385             net_be_rxeof_t cb, void *param)
386 {
387         struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
388
389         strlcpy(priv->ifname, devname, sizeof(priv->ifname));
390         priv->ifname[sizeof(priv->ifname) - 1] = '\0';
391
392         priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL);
393         if (priv->nmd == NULL) {
394                 WPRINTF(("Unable to nm_open(): interface '%s', errno (%s)\n",
395                         devname, strerror(errno)));
396                 free(priv);
397                 return (-1);
398         }
399
400         priv->memid = priv->nmd->req.nr_arg2;
401         priv->tx = NETMAP_TXRING(priv->nmd->nifp, 0);
402         priv->rx = NETMAP_RXRING(priv->nmd->nifp, 0);
403         priv->cb = cb;
404         priv->cb_param = param;
405         be->fd = priv->nmd->fd;
406
407         priv->mevp = mevent_add(be->fd, EVF_READ, cb, param);
408         if (priv->mevp == NULL) {
409                 WPRINTF(("Could not register event\n"));
410                 return (-1);
411         }
412
413         return (0);
414 }
415
416 static void
417 netmap_cleanup(struct net_backend *be)
418 {
419         struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
420
421         if (priv->mevp) {
422                 mevent_delete(priv->mevp);
423         }
424         if (priv->nmd) {
425                 nm_close(priv->nmd);
426         }
427         be->fd = -1;
428 }
429
430 static ssize_t
431 netmap_send(struct net_backend *be, struct iovec *iov,
432             int iovcnt)
433 {
434         struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
435         struct netmap_ring *ring;
436         ssize_t totlen = 0;
437         int nm_buf_size;
438         int nm_buf_len;
439         uint32_t head;
440         void *nm_buf;
441         int j;
442
443         ring = priv->tx;
444         head = ring->head;
445         if (head == ring->tail) {
446                 WPRINTF(("No space, drop %zu bytes\n", count_iov(iov, iovcnt)));
447                 goto txsync;
448         }
449         nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
450         nm_buf_size = ring->nr_buf_size;
451         nm_buf_len = 0;
452
453         for (j = 0; j < iovcnt; j++) {
454                 int iov_frag_size = iov[j].iov_len;
455                 void *iov_frag_buf = iov[j].iov_base;
456
457                 totlen += iov_frag_size;
458
459                 /*
460                  * Split each iovec fragment over more netmap slots, if
461                  * necessary.
462                  */
463                 for (;;) {
464                         int copylen;
465
466                         copylen = iov_frag_size < nm_buf_size ? iov_frag_size : nm_buf_size;
467                         memcpy(nm_buf, iov_frag_buf, copylen);
468
469                         iov_frag_buf += copylen;
470                         iov_frag_size -= copylen;
471                         nm_buf += copylen;
472                         nm_buf_size -= copylen;
473                         nm_buf_len += copylen;
474
475                         if (iov_frag_size == 0) {
476                                 break;
477                         }
478
479                         ring->slot[head].len = nm_buf_len;
480                         ring->slot[head].flags = NS_MOREFRAG;
481                         head = nm_ring_next(ring, head);
482                         if (head == ring->tail) {
483                                 /*
484                                  * We ran out of netmap slots while
485                                  * splitting the iovec fragments.
486                                  */
487                                 WPRINTF(("No space, drop %zu bytes\n",
488                                    count_iov(iov, iovcnt)));
489                                 goto txsync;
490                         }
491                         nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
492                         nm_buf_size = ring->nr_buf_size;
493                         nm_buf_len = 0;
494                 }
495         }
496
497         /* Complete the last slot, which must not have NS_MOREFRAG set. */
498         ring->slot[head].len = nm_buf_len;
499         ring->slot[head].flags = 0;
500         head = nm_ring_next(ring, head);
501
502         /* Now update ring->head and ring->cur. */
503         ring->head = ring->cur = head;
504 txsync:
505         ioctl(be->fd, NIOCTXSYNC, NULL);
506
507         return (totlen);
508 }
509
510 static ssize_t
511 netmap_recv(struct net_backend *be, struct iovec *iov, int iovcnt)
512 {
513         struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
514         struct netmap_slot *slot = NULL;
515         struct netmap_ring *ring;
516         void *iov_frag_buf;
517         int iov_frag_size;
518         ssize_t totlen = 0;
519         uint32_t head;
520
521         assert(iovcnt);
522
523         ring = priv->rx;
524         head = ring->head;
525         iov_frag_buf = iov->iov_base;
526         iov_frag_size = iov->iov_len;
527
528         do {
529                 int nm_buf_len;
530                 void *nm_buf;
531
532                 if (head == ring->tail) {
533                         return (0);
534                 }
535
536                 slot = ring->slot + head;
537                 nm_buf = NETMAP_BUF(ring, slot->buf_idx);
538                 nm_buf_len = slot->len;
539
540                 for (;;) {
541                         int copylen = nm_buf_len < iov_frag_size ?
542                             nm_buf_len : iov_frag_size;
543
544                         memcpy(iov_frag_buf, nm_buf, copylen);
545                         nm_buf += copylen;
546                         nm_buf_len -= copylen;
547                         iov_frag_buf += copylen;
548                         iov_frag_size -= copylen;
549                         totlen += copylen;
550
551                         if (nm_buf_len == 0) {
552                                 break;
553                         }
554
555                         iov++;
556                         iovcnt--;
557                         if (iovcnt == 0) {
558                                 /* No space to receive. */
559                                 WPRINTF(("Short iov, drop %zd bytes\n",
560                                     totlen));
561                                 return (-ENOSPC);
562                         }
563                         iov_frag_buf = iov->iov_base;
564                         iov_frag_size = iov->iov_len;
565                 }
566
567                 head = nm_ring_next(ring, head);
568
569         } while (slot->flags & NS_MOREFRAG);
570
571         /* Release slots to netmap. */
572         ring->head = ring->cur = head;
573
574         return (totlen);
575 }
576
577 static struct net_backend netmap_backend = {
578         .prefix = "netmap",
579         .priv_size = sizeof(struct netmap_priv),
580         .init = netmap_init,
581         .cleanup = netmap_cleanup,
582         .send = netmap_send,
583         .recv = netmap_recv,
584         .get_cap = netmap_get_cap,
585         .set_cap = netmap_set_cap,
586 };
587
588 /* A clone of the netmap backend, with a different prefix. */
589 static struct net_backend vale_backend = {
590         .prefix = "vale",
591         .priv_size = sizeof(struct netmap_priv),
592         .init = netmap_init,
593         .cleanup = netmap_cleanup,
594         .send = netmap_send,
595         .recv = netmap_recv,
596         .get_cap = netmap_get_cap,
597         .set_cap = netmap_set_cap,
598 };
599
600 DATA_SET(net_backend_set, netmap_backend);
601 DATA_SET(net_backend_set, vale_backend);
602
603 /*
604  * Initialize a backend and attach to the frontend.
605  * This is called during frontend initialization.
606  *  @pbe is a pointer to the backend to be initialized
607  *  @devname is the backend-name as supplied on the command line,
608  *      e.g. -s 2:0,frontend-name,backend-name[,other-args]
609  *  @cb is the receive callback supplied by the frontend,
610  *      and it is invoked in the event loop when a receive
611  *      event is generated in the hypervisor,
612  *  @param is a pointer to the frontend, and normally used as
613  *      the argument for the callback.
614  */
615 int
616 netbe_init(struct net_backend **ret, const char *devname, net_be_rxeof_t cb,
617     void *param)
618 {
619         struct net_backend **pbe, *nbe, *tbe = NULL;
620         int err;
621
622         /*
623          * Find the network backend that matches the user-provided
624          * device name. net_backend_set is built using a linker set.
625          */
626         SET_FOREACH(pbe, net_backend_set) {
627                 if (strncmp(devname, (*pbe)->prefix,
628                     strlen((*pbe)->prefix)) == 0) {
629                         tbe = *pbe;
630                         assert(tbe->init != NULL);
631                         assert(tbe->cleanup != NULL);
632                         assert(tbe->send != NULL);
633                         assert(tbe->recv != NULL);
634                         assert(tbe->get_cap != NULL);
635                         assert(tbe->set_cap != NULL);
636                         break;
637                 }
638         }
639
640         *ret = NULL;
641         if (tbe == NULL)
642                 return (EINVAL);
643         nbe = calloc(1, sizeof(*nbe) + tbe->priv_size);
644         *nbe = *tbe;    /* copy the template */
645         nbe->fd = -1;
646         nbe->sc = param;
647         nbe->be_vnet_hdr_len = 0;
648         nbe->fe_vnet_hdr_len = 0;
649
650         /* Initialize the backend. */
651         err = nbe->init(nbe, devname, cb, param);
652         if (err) {
653                 free(nbe);
654                 return (err);
655         }
656
657         *ret = nbe;
658
659         return (0);
660 }
661
662 void
663 netbe_cleanup(struct net_backend *be)
664 {
665
666         if (be != NULL) {
667                 be->cleanup(be);
668                 free(be);
669         }
670 }
671
672 uint64_t
673 netbe_get_cap(struct net_backend *be)
674 {
675
676         assert(be != NULL);
677         return (be->get_cap(be));
678 }
679
680 int
681 netbe_set_cap(struct net_backend *be, uint64_t features,
682               unsigned vnet_hdr_len)
683 {
684         int ret;
685
686         assert(be != NULL);
687
688         /* There are only three valid lengths, i.e., 0, 10 and 12. */
689         if (vnet_hdr_len && vnet_hdr_len != VNET_HDR_LEN
690                 && vnet_hdr_len != (VNET_HDR_LEN - sizeof(uint16_t)))
691                 return (-1);
692
693         be->fe_vnet_hdr_len = vnet_hdr_len;
694
695         ret = be->set_cap(be, features, vnet_hdr_len);
696         assert(be->be_vnet_hdr_len == 0 ||
697                be->be_vnet_hdr_len == be->fe_vnet_hdr_len);
698
699         return (ret);
700 }
701
702 static __inline struct iovec *
703 iov_trim(struct iovec *iov, int *iovcnt, unsigned int tlen)
704 {
705         struct iovec *riov;
706
707         /* XXX short-cut: assume first segment is >= tlen */
708         assert(iov[0].iov_len >= tlen);
709
710         iov[0].iov_len -= tlen;
711         if (iov[0].iov_len == 0) {
712                 assert(*iovcnt > 1);
713                 *iovcnt -= 1;
714                 riov = &iov[1];
715         } else {
716                 iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen);
717                 riov = &iov[0];
718         }
719
720         return (riov);
721 }
722
723 ssize_t
724 netbe_send(struct net_backend *be, struct iovec *iov, int iovcnt)
725 {
726
727         assert(be != NULL);
728         if (be->be_vnet_hdr_len != be->fe_vnet_hdr_len) {
729                 /*
730                  * The frontend uses a virtio-net header, but the backend
731                  * does not. We ignore it (as it must be all zeroes) and
732                  * strip it.
733                  */
734                 assert(be->be_vnet_hdr_len == 0);
735                 iov = iov_trim(iov, &iovcnt, be->fe_vnet_hdr_len);
736         }
737
738         return (be->send(be, iov, iovcnt));
739 }
740
741 /*
742  * Try to read a packet from the backend, without blocking.
743  * If no packets are available, return 0. In case of success, return
744  * the length of the packet just read. Return -1 in case of errors.
745  */
746 ssize_t
747 netbe_recv(struct net_backend *be, struct iovec *iov, int iovcnt)
748 {
749         /* Length of prepended virtio-net header. */
750         unsigned int hlen = be->fe_vnet_hdr_len;
751         int ret;
752
753         assert(be != NULL);
754
755         if (hlen && hlen != be->be_vnet_hdr_len) {
756                 /*
757                  * The frontend uses a virtio-net header, but the backend
758                  * does not. We need to prepend a zeroed header.
759                  */
760                 struct virtio_net_rxhdr *vh;
761
762                 assert(be->be_vnet_hdr_len == 0);
763
764                 /*
765                  * Get a pointer to the rx header, and use the
766                  * data immediately following it for the packet buffer.
767                  */
768                 vh = iov[0].iov_base;
769                 iov = iov_trim(iov, &iovcnt, hlen);
770
771                 /*
772                  * The only valid field in the rx packet header is the
773                  * number of buffers if merged rx bufs were negotiated.
774                  */
775                 memset(vh, 0, hlen);
776                 if (hlen == VNET_HDR_LEN) {
777                         vh->vrh_bufs = 1;
778                 }
779         }
780
781         ret = be->recv(be, iov, iovcnt);
782         if (ret > 0) {
783                 ret += hlen;
784         }
785
786         return (ret);
787 }
788
789 /*
790  * Read a packet from the backend and discard it.
791  * Returns the size of the discarded packet or zero if no packet was available.
792  * A negative error code is returned in case of read error.
793  */
794 ssize_t
795 netbe_rx_discard(struct net_backend *be)
796 {
797         /*
798          * MP note: the dummybuf is only used to discard frames,
799          * so there is no need for it to be per-vtnet or locked.
800          * We only make it large enough for TSO-sized segment.
801          */
802         static uint8_t dummybuf[65536 + 64];
803         struct iovec iov;
804
805         iov.iov_base = dummybuf;
806         iov.iov_len = sizeof(dummybuf);
807
808         return netbe_recv(be, &iov, 1);
809 }
810