xref: /freebsd/usr.sbin/bhyve/net_backends.c (revision f407a72a506d2630d60d9096c42058f12dff874e)
10ff7076bSVincenzo Maffione /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
390db4ba9SVincenzo Maffione  *
40ff7076bSVincenzo Maffione  * Copyright (c) 2019 Vincenzo Maffione <vmaffione@FreeBSD.org>
50ff7076bSVincenzo Maffione  *
60ff7076bSVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
70ff7076bSVincenzo Maffione  * modification, are permitted provided that the following conditions
80ff7076bSVincenzo Maffione  * are met:
90ff7076bSVincenzo Maffione  * 1. Redistributions of source code must retain the above copyright
100ff7076bSVincenzo Maffione  *    notice, this list of conditions and the following disclaimer.
110ff7076bSVincenzo Maffione  * 2. Redistributions in binary form must reproduce the above copyright
120ff7076bSVincenzo Maffione  *    notice, this list of conditions and the following disclaimer in the
130ff7076bSVincenzo Maffione  *    documentation and/or other materials provided with the distribution.
140ff7076bSVincenzo Maffione  *
150ff7076bSVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
160ff7076bSVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170ff7076bSVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
180ff7076bSVincenzo Maffione  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
190ff7076bSVincenzo Maffione  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
200ff7076bSVincenzo Maffione  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
210ff7076bSVincenzo Maffione  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
220ff7076bSVincenzo Maffione  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
230ff7076bSVincenzo Maffione  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
240ff7076bSVincenzo Maffione  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
250ff7076bSVincenzo Maffione  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260ff7076bSVincenzo Maffione  */
270ff7076bSVincenzo Maffione 
280ff7076bSVincenzo Maffione /*
290ff7076bSVincenzo Maffione  * This file implements multiple network backends (tap, netmap, ...),
300ff7076bSVincenzo Maffione  * to be used by network frontends such as virtio-net and e1000.
310ff7076bSVincenzo Maffione  * The API to access the backend (e.g. send/receive packets, negotiate
320ff7076bSVincenzo Maffione  * features) is exported by net_backends.h.
330ff7076bSVincenzo Maffione  */
340ff7076bSVincenzo Maffione 
358cd0c1acSVincenzo Maffione #include <sys/cdefs.h>
360ff7076bSVincenzo Maffione #include <sys/types.h>		/* u_short etc */
370ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
380ff7076bSVincenzo Maffione #include <sys/capsicum.h>
390ff7076bSVincenzo Maffione #endif
400ff7076bSVincenzo Maffione #include <sys/ioctl.h>
410ff7076bSVincenzo Maffione #include <sys/mman.h>
420ff7076bSVincenzo Maffione #include <sys/uio.h>
430ff7076bSVincenzo Maffione 
440ff7076bSVincenzo Maffione #include <net/if.h>
4556be282bSBjoern A. Zeeb #include <net/if_tap.h>
460ff7076bSVincenzo Maffione #include <net/netmap.h>
470ff7076bSVincenzo Maffione #include <net/netmap_virt.h>
480ff7076bSVincenzo Maffione #define NETMAP_WITH_LIBS
490ff7076bSVincenzo Maffione #include <net/netmap_user.h>
500ff7076bSVincenzo Maffione 
510ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
520ff7076bSVincenzo Maffione #include <capsicum_helpers.h>
530ff7076bSVincenzo Maffione #endif
540ff7076bSVincenzo Maffione #include <err.h>
550ff7076bSVincenzo Maffione #include <errno.h>
560ff7076bSVincenzo Maffione #include <fcntl.h>
570ff7076bSVincenzo Maffione #include <stdio.h>
580ff7076bSVincenzo Maffione #include <stdlib.h>
590ff7076bSVincenzo Maffione #include <stdint.h>
600ff7076bSVincenzo Maffione #include <string.h>
610ff7076bSVincenzo Maffione #include <unistd.h>
620ff7076bSVincenzo Maffione #include <sysexits.h>
630ff7076bSVincenzo Maffione #include <assert.h>
640ff7076bSVincenzo Maffione #include <pthread.h>
650ff7076bSVincenzo Maffione #include <pthread_np.h>
660ff7076bSVincenzo Maffione #include <poll.h>
670ff7076bSVincenzo Maffione #include <assert.h>
680ff7076bSVincenzo Maffione 
692cd7735dSAleksandr Fedorov #ifdef NETGRAPH
702cd7735dSAleksandr Fedorov #include <sys/param.h>
712cd7735dSAleksandr Fedorov #include <sys/sysctl.h>
722cd7735dSAleksandr Fedorov #include <netgraph.h>
732cd7735dSAleksandr Fedorov #endif
740ff7076bSVincenzo Maffione 
75621b5090SJohn Baldwin #include "config.h"
76332eff95SVincenzo Maffione #include "debug.h"
770ff7076bSVincenzo Maffione #include "iov.h"
780ff7076bSVincenzo Maffione #include "mevent.h"
790ff7076bSVincenzo Maffione #include "net_backends.h"
80621b5090SJohn Baldwin #include "pci_emul.h"
810ff7076bSVincenzo Maffione 
820ff7076bSVincenzo Maffione #include <sys/linker_set.h>
830ff7076bSVincenzo Maffione 
840ff7076bSVincenzo Maffione /*
850ff7076bSVincenzo Maffione  * Each network backend registers a set of function pointers that are
860ff7076bSVincenzo Maffione  * used to implement the net backends API.
870ff7076bSVincenzo Maffione  * This might need to be exposed if we implement backends in separate files.
880ff7076bSVincenzo Maffione  */
890ff7076bSVincenzo Maffione struct net_backend {
900ff7076bSVincenzo Maffione 	const char *prefix;	/* prefix matching this backend */
910ff7076bSVincenzo Maffione 
920ff7076bSVincenzo Maffione 	/*
930ff7076bSVincenzo Maffione 	 * Routines used to initialize and cleanup the resources needed
940ff7076bSVincenzo Maffione 	 * by a backend. The cleanup function is used internally,
950ff7076bSVincenzo Maffione 	 * and should not be called by the frontend.
960ff7076bSVincenzo Maffione 	 */
970ff7076bSVincenzo Maffione 	int (*init)(struct net_backend *be, const char *devname,
98621b5090SJohn Baldwin 	    nvlist_t *nvl, net_be_rxeof_t cb, void *param);
990ff7076bSVincenzo Maffione 	void (*cleanup)(struct net_backend *be);
1000ff7076bSVincenzo Maffione 
1010ff7076bSVincenzo Maffione 	/*
1020ff7076bSVincenzo Maffione 	 * Called to serve a guest transmit request. The scatter-gather
1030ff7076bSVincenzo Maffione 	 * vector provided by the caller has 'iovcnt' elements and contains
1040ff7076bSVincenzo Maffione 	 * the packet to send.
1050ff7076bSVincenzo Maffione 	 */
10666c662b0SVincenzo Maffione 	ssize_t (*send)(struct net_backend *be, const struct iovec *iov,
10766c662b0SVincenzo Maffione 	    int iovcnt);
1080ff7076bSVincenzo Maffione 
1090ff7076bSVincenzo Maffione 	/*
110f92bb8c1SVincenzo Maffione 	 * Get the length of the next packet that can be received from
111f92bb8c1SVincenzo Maffione 	 * the backend. If no packets are currently available, this
112f92bb8c1SVincenzo Maffione 	 * function returns 0.
113f92bb8c1SVincenzo Maffione 	 */
114f92bb8c1SVincenzo Maffione 	ssize_t (*peek_recvlen)(struct net_backend *be);
115f92bb8c1SVincenzo Maffione 
116f92bb8c1SVincenzo Maffione 	/*
1170ff7076bSVincenzo Maffione 	 * Called to receive a packet from the backend. When the function
1180ff7076bSVincenzo Maffione 	 * returns a positive value 'len', the scatter-gather vector
1190ff7076bSVincenzo Maffione 	 * provided by the caller contains a packet with such length.
1200ff7076bSVincenzo Maffione 	 * The function returns 0 if the backend doesn't have a new packet to
1210ff7076bSVincenzo Maffione 	 * receive.
1220ff7076bSVincenzo Maffione 	 */
12366c662b0SVincenzo Maffione 	ssize_t (*recv)(struct net_backend *be, const struct iovec *iov,
12466c662b0SVincenzo Maffione 	    int iovcnt);
1250ff7076bSVincenzo Maffione 
1260ff7076bSVincenzo Maffione 	/*
127d12c5ef6SVincenzo Maffione 	 * Ask the backend to enable or disable receive operation in the
128d12c5ef6SVincenzo Maffione 	 * backend. On return from a disable operation, it is guaranteed
129d12c5ef6SVincenzo Maffione 	 * that the receive callback won't be called until receive is
130d12c5ef6SVincenzo Maffione 	 * enabled again. Note however that it is up to the caller to make
131d12c5ef6SVincenzo Maffione 	 * sure that netbe_recv() is not currently being executed by another
132d12c5ef6SVincenzo Maffione 	 * thread.
133d12c5ef6SVincenzo Maffione 	 */
134d12c5ef6SVincenzo Maffione 	void (*recv_enable)(struct net_backend *be);
135d12c5ef6SVincenzo Maffione 	void (*recv_disable)(struct net_backend *be);
136d12c5ef6SVincenzo Maffione 
137d12c5ef6SVincenzo Maffione 	/*
1380ff7076bSVincenzo Maffione 	 * Ask the backend for the virtio-net features it is able to
1390ff7076bSVincenzo Maffione 	 * support. Possible features are TSO, UFO and checksum offloading
1400ff7076bSVincenzo Maffione 	 * in both rx and tx direction and for both IPv4 and IPv6.
1410ff7076bSVincenzo Maffione 	 */
1420ff7076bSVincenzo Maffione 	uint64_t (*get_cap)(struct net_backend *be);
1430ff7076bSVincenzo Maffione 
1440ff7076bSVincenzo Maffione 	/*
1450ff7076bSVincenzo Maffione 	 * Tell the backend to enable/disable the specified virtio-net
1460ff7076bSVincenzo Maffione 	 * features (capabilities).
1470ff7076bSVincenzo Maffione 	 */
1480ff7076bSVincenzo Maffione 	int (*set_cap)(struct net_backend *be, uint64_t features,
1490ff7076bSVincenzo Maffione 	    unsigned int vnet_hdr_len);
1500ff7076bSVincenzo Maffione 
1510ff7076bSVincenzo Maffione 	struct pci_vtnet_softc *sc;
1520ff7076bSVincenzo Maffione 	int fd;
1530ff7076bSVincenzo Maffione 
1540ff7076bSVincenzo Maffione 	/*
1550ff7076bSVincenzo Maffione 	 * Length of the virtio-net header used by the backend and the
1560ff7076bSVincenzo Maffione 	 * frontend, respectively. A zero value means that the header
1570ff7076bSVincenzo Maffione 	 * is not used.
1580ff7076bSVincenzo Maffione 	 */
1590ff7076bSVincenzo Maffione 	unsigned int be_vnet_hdr_len;
1600ff7076bSVincenzo Maffione 	unsigned int fe_vnet_hdr_len;
1610ff7076bSVincenzo Maffione 
1620ff7076bSVincenzo Maffione 	/* Size of backend-specific private data. */
1630ff7076bSVincenzo Maffione 	size_t priv_size;
1640ff7076bSVincenzo Maffione 
1650ced97acSMark Johnston 	/* Backend-specific private data follows. */
1660ff7076bSVincenzo Maffione };
1670ff7076bSVincenzo Maffione 
1680ced97acSMark Johnston #define	NET_BE_PRIV(be)		((void *)((be) + 1))
1690ced97acSMark Johnston #define	NET_BE_SIZE(be)		(sizeof(*be) + (be)->priv_size)
1700ced97acSMark Johnston 
1710ff7076bSVincenzo Maffione SET_DECLARE(net_backend_set, struct net_backend);
1720ff7076bSVincenzo Maffione 
1730ff7076bSVincenzo Maffione #define VNET_HDR_LEN	sizeof(struct virtio_net_rxhdr)
1740ff7076bSVincenzo Maffione 
175332eff95SVincenzo Maffione #define WPRINTF(params) PRINTLN params
1760ff7076bSVincenzo Maffione 
1770ff7076bSVincenzo Maffione /*
1780ff7076bSVincenzo Maffione  * The tap backend
1790ff7076bSVincenzo Maffione  */
1800ff7076bSVincenzo Maffione 
1810ff7076bSVincenzo Maffione struct tap_priv {
1820ff7076bSVincenzo Maffione 	struct mevent *mevp;
183f92bb8c1SVincenzo Maffione 	/*
184f92bb8c1SVincenzo Maffione 	 * A bounce buffer that allows us to implement the peek_recvlen
185f92bb8c1SVincenzo Maffione 	 * callback. In the future we may get the same information from
186f92bb8c1SVincenzo Maffione 	 * the kevent data.
187f92bb8c1SVincenzo Maffione 	 */
188f92bb8c1SVincenzo Maffione 	char bbuf[1 << 16];
189f92bb8c1SVincenzo Maffione 	ssize_t bbuflen;
1900ff7076bSVincenzo Maffione };
1910ff7076bSVincenzo Maffione 
1920ff7076bSVincenzo Maffione static void
1930ff7076bSVincenzo Maffione tap_cleanup(struct net_backend *be)
1940ff7076bSVincenzo Maffione {
1950ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
1960ff7076bSVincenzo Maffione 
1970ff7076bSVincenzo Maffione 	if (priv->mevp) {
1980ff7076bSVincenzo Maffione 		mevent_delete(priv->mevp);
1990ff7076bSVincenzo Maffione 	}
2000ff7076bSVincenzo Maffione 	if (be->fd != -1) {
2010ff7076bSVincenzo Maffione 		close(be->fd);
2020ff7076bSVincenzo Maffione 		be->fd = -1;
2030ff7076bSVincenzo Maffione 	}
2040ff7076bSVincenzo Maffione }
2050ff7076bSVincenzo Maffione 
2060ff7076bSVincenzo Maffione static int
2070ff7076bSVincenzo Maffione tap_init(struct net_backend *be, const char *devname,
20898d920d9SMark Johnston     nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
2090ff7076bSVincenzo Maffione {
2100ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
2110ff7076bSVincenzo Maffione 	char tbuf[80];
212fd8b9c73SJan Bramkamp 	int opt = 1, up = IFF_UP;
213fd8b9c73SJan Bramkamp 
2140ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
2150ff7076bSVincenzo Maffione 	cap_rights_t rights;
2160ff7076bSVincenzo Maffione #endif
2170ff7076bSVincenzo Maffione 
2180ff7076bSVincenzo Maffione 	if (cb == NULL) {
219332eff95SVincenzo Maffione 		WPRINTF(("TAP backend requires non-NULL callback"));
2200ff7076bSVincenzo Maffione 		return (-1);
2210ff7076bSVincenzo Maffione 	}
2220ff7076bSVincenzo Maffione 
2230ff7076bSVincenzo Maffione 	strcpy(tbuf, "/dev/");
2240ff7076bSVincenzo Maffione 	strlcat(tbuf, devname, sizeof(tbuf));
2250ff7076bSVincenzo Maffione 
2262d5fe369SSean Chittenden 	be->fd = open(tbuf, O_RDWR);
2272d5fe369SSean Chittenden 	if (be->fd == -1) {
228332eff95SVincenzo Maffione 		WPRINTF(("open of tap device %s failed", tbuf));
2290ff7076bSVincenzo Maffione 		goto error;
2300ff7076bSVincenzo Maffione 	}
2310ff7076bSVincenzo Maffione 
2320ff7076bSVincenzo Maffione 	/*
2330ff7076bSVincenzo Maffione 	 * Set non-blocking and register for read
2340ff7076bSVincenzo Maffione 	 * notifications with the event loop
2350ff7076bSVincenzo Maffione 	 */
2362d5fe369SSean Chittenden 	if (ioctl(be->fd, FIONBIO, &opt) < 0) {
237332eff95SVincenzo Maffione 		WPRINTF(("tap device O_NONBLOCK failed"));
2380ff7076bSVincenzo Maffione 		goto error;
2390ff7076bSVincenzo Maffione 	}
2400ff7076bSVincenzo Maffione 
241*f407a72aSGleb Smirnoff 	if (ioctl(be->fd, VMIO_SIOCSIFFLAGS, up)) {
242fd8b9c73SJan Bramkamp 		WPRINTF(("tap device link up failed"));
24356be282bSBjoern A. Zeeb 		goto error;
24456be282bSBjoern A. Zeeb 	}
24556be282bSBjoern A. Zeeb 
2460ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
2470ff7076bSVincenzo Maffione 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
2482d5fe369SSean Chittenden 	if (caph_rights_limit(be->fd, &rights) == -1)
2490ff7076bSVincenzo Maffione 		errx(EX_OSERR, "Unable to apply rights for sandbox");
2500ff7076bSVincenzo Maffione #endif
2510ff7076bSVincenzo Maffione 
252f92bb8c1SVincenzo Maffione 	memset(priv->bbuf, 0, sizeof(priv->bbuf));
253f92bb8c1SVincenzo Maffione 	priv->bbuflen = 0;
254f92bb8c1SVincenzo Maffione 
2553e11768eSVincenzo Maffione 	priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
2560ff7076bSVincenzo Maffione 	if (priv->mevp == NULL) {
257332eff95SVincenzo Maffione 		WPRINTF(("Could not register event"));
2580ff7076bSVincenzo Maffione 		goto error;
2590ff7076bSVincenzo Maffione 	}
2600ff7076bSVincenzo Maffione 
2610ff7076bSVincenzo Maffione 	return (0);
2620ff7076bSVincenzo Maffione 
2630ff7076bSVincenzo Maffione error:
2640ff7076bSVincenzo Maffione 	tap_cleanup(be);
2650ff7076bSVincenzo Maffione 	return (-1);
2660ff7076bSVincenzo Maffione }
2670ff7076bSVincenzo Maffione 
2680ff7076bSVincenzo Maffione /*
2690ff7076bSVincenzo Maffione  * Called to send a buffer chain out to the tap device
2700ff7076bSVincenzo Maffione  */
2710ff7076bSVincenzo Maffione static ssize_t
27266c662b0SVincenzo Maffione tap_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
2730ff7076bSVincenzo Maffione {
2740ff7076bSVincenzo Maffione 	return (writev(be->fd, iov, iovcnt));
2750ff7076bSVincenzo Maffione }
2760ff7076bSVincenzo Maffione 
2770ff7076bSVincenzo Maffione static ssize_t
278f92bb8c1SVincenzo Maffione tap_peek_recvlen(struct net_backend *be)
2790ff7076bSVincenzo Maffione {
2800ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
2810ff7076bSVincenzo Maffione 	ssize_t ret;
2820ff7076bSVincenzo Maffione 
283f92bb8c1SVincenzo Maffione 	if (priv->bbuflen > 0) {
284f92bb8c1SVincenzo Maffione 		/*
285f92bb8c1SVincenzo Maffione 		 * We already have a packet in the bounce buffer.
286f92bb8c1SVincenzo Maffione 		 * Just return its length.
287f92bb8c1SVincenzo Maffione 		 */
288f92bb8c1SVincenzo Maffione 		return priv->bbuflen;
289f92bb8c1SVincenzo Maffione 	}
290f92bb8c1SVincenzo Maffione 
291f92bb8c1SVincenzo Maffione 	/*
292f92bb8c1SVincenzo Maffione 	 * Read the next packet (if any) into the bounce buffer, so
293f92bb8c1SVincenzo Maffione 	 * that we get to know its length and we can return that
294f92bb8c1SVincenzo Maffione 	 * to the caller.
295f92bb8c1SVincenzo Maffione 	 */
296f92bb8c1SVincenzo Maffione 	ret = read(be->fd, priv->bbuf, sizeof(priv->bbuf));
297f92bb8c1SVincenzo Maffione 	if (ret < 0 && errno == EWOULDBLOCK) {
298f92bb8c1SVincenzo Maffione 		return (0);
299f92bb8c1SVincenzo Maffione 	}
300f92bb8c1SVincenzo Maffione 
301f92bb8c1SVincenzo Maffione 	if (ret > 0)
302f92bb8c1SVincenzo Maffione 		priv->bbuflen = ret;
303f92bb8c1SVincenzo Maffione 
304f92bb8c1SVincenzo Maffione 	return (ret);
305f92bb8c1SVincenzo Maffione }
306f92bb8c1SVincenzo Maffione 
307f92bb8c1SVincenzo Maffione static ssize_t
308f92bb8c1SVincenzo Maffione tap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
309f92bb8c1SVincenzo Maffione {
3100ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
311f92bb8c1SVincenzo Maffione 	ssize_t ret;
312f92bb8c1SVincenzo Maffione 
313f92bb8c1SVincenzo Maffione 	if (priv->bbuflen > 0) {
314f92bb8c1SVincenzo Maffione 		/*
315f92bb8c1SVincenzo Maffione 		 * A packet is available in the bounce buffer, so
316f92bb8c1SVincenzo Maffione 		 * we read it from there.
317f92bb8c1SVincenzo Maffione 		 */
318f92bb8c1SVincenzo Maffione 		ret = buf_to_iov(priv->bbuf, priv->bbuflen,
319f92bb8c1SVincenzo Maffione 		    iov, iovcnt, 0);
320f92bb8c1SVincenzo Maffione 
321f92bb8c1SVincenzo Maffione 		/* Mark the bounce buffer as empty. */
322f92bb8c1SVincenzo Maffione 		priv->bbuflen = 0;
323f92bb8c1SVincenzo Maffione 
324f92bb8c1SVincenzo Maffione 		return (ret);
325f92bb8c1SVincenzo Maffione 	}
3260ff7076bSVincenzo Maffione 
3270ff7076bSVincenzo Maffione 	ret = readv(be->fd, iov, iovcnt);
3280ff7076bSVincenzo Maffione 	if (ret < 0 && errno == EWOULDBLOCK) {
3290ff7076bSVincenzo Maffione 		return (0);
3300ff7076bSVincenzo Maffione 	}
3310ff7076bSVincenzo Maffione 
3320ff7076bSVincenzo Maffione 	return (ret);
3330ff7076bSVincenzo Maffione }
3340ff7076bSVincenzo Maffione 
335d12c5ef6SVincenzo Maffione static void
336d12c5ef6SVincenzo Maffione tap_recv_enable(struct net_backend *be)
337d12c5ef6SVincenzo Maffione {
3380ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
339d12c5ef6SVincenzo Maffione 
340d12c5ef6SVincenzo Maffione 	mevent_enable(priv->mevp);
341d12c5ef6SVincenzo Maffione }
342d12c5ef6SVincenzo Maffione 
343d12c5ef6SVincenzo Maffione static void
344d12c5ef6SVincenzo Maffione tap_recv_disable(struct net_backend *be)
345d12c5ef6SVincenzo Maffione {
3460ced97acSMark Johnston 	struct tap_priv *priv = NET_BE_PRIV(be);
347d12c5ef6SVincenzo Maffione 
348d12c5ef6SVincenzo Maffione 	mevent_disable(priv->mevp);
349d12c5ef6SVincenzo Maffione }
350d12c5ef6SVincenzo Maffione 
3510ff7076bSVincenzo Maffione static uint64_t
35298d920d9SMark Johnston tap_get_cap(struct net_backend *be __unused)
3530ff7076bSVincenzo Maffione {
3540ff7076bSVincenzo Maffione 
3550ff7076bSVincenzo Maffione 	return (0); /* no capabilities for now */
3560ff7076bSVincenzo Maffione }
3570ff7076bSVincenzo Maffione 
3580ff7076bSVincenzo Maffione static int
35998d920d9SMark Johnston tap_set_cap(struct net_backend *be __unused, uint64_t features,
3600ff7076bSVincenzo Maffione     unsigned vnet_hdr_len)
3610ff7076bSVincenzo Maffione {
3620ff7076bSVincenzo Maffione 
3630ff7076bSVincenzo Maffione 	return ((features || vnet_hdr_len) ? -1 : 0);
3640ff7076bSVincenzo Maffione }
3650ff7076bSVincenzo Maffione 
3660ff7076bSVincenzo Maffione static struct net_backend tap_backend = {
3670ff7076bSVincenzo Maffione 	.prefix = "tap",
3680ff7076bSVincenzo Maffione 	.priv_size = sizeof(struct tap_priv),
3690ff7076bSVincenzo Maffione 	.init = tap_init,
3700ff7076bSVincenzo Maffione 	.cleanup = tap_cleanup,
3710ff7076bSVincenzo Maffione 	.send = tap_send,
372f92bb8c1SVincenzo Maffione 	.peek_recvlen = tap_peek_recvlen,
3730ff7076bSVincenzo Maffione 	.recv = tap_recv,
374d12c5ef6SVincenzo Maffione 	.recv_enable = tap_recv_enable,
375d12c5ef6SVincenzo Maffione 	.recv_disable = tap_recv_disable,
3760ff7076bSVincenzo Maffione 	.get_cap = tap_get_cap,
3770ff7076bSVincenzo Maffione 	.set_cap = tap_set_cap,
3780ff7076bSVincenzo Maffione };
3790ff7076bSVincenzo Maffione 
3800ff7076bSVincenzo Maffione /* A clone of the tap backend, with a different prefix. */
3810ff7076bSVincenzo Maffione static struct net_backend vmnet_backend = {
3820ff7076bSVincenzo Maffione 	.prefix = "vmnet",
3830ff7076bSVincenzo Maffione 	.priv_size = sizeof(struct tap_priv),
3840ff7076bSVincenzo Maffione 	.init = tap_init,
3850ff7076bSVincenzo Maffione 	.cleanup = tap_cleanup,
3860ff7076bSVincenzo Maffione 	.send = tap_send,
387f92bb8c1SVincenzo Maffione 	.peek_recvlen = tap_peek_recvlen,
3880ff7076bSVincenzo Maffione 	.recv = tap_recv,
389d12c5ef6SVincenzo Maffione 	.recv_enable = tap_recv_enable,
390d12c5ef6SVincenzo Maffione 	.recv_disable = tap_recv_disable,
3910ff7076bSVincenzo Maffione 	.get_cap = tap_get_cap,
3920ff7076bSVincenzo Maffione 	.set_cap = tap_set_cap,
3930ff7076bSVincenzo Maffione };
3940ff7076bSVincenzo Maffione 
3950ff7076bSVincenzo Maffione DATA_SET(net_backend_set, tap_backend);
3960ff7076bSVincenzo Maffione DATA_SET(net_backend_set, vmnet_backend);
3970ff7076bSVincenzo Maffione 
3982cd7735dSAleksandr Fedorov #ifdef NETGRAPH
3992cd7735dSAleksandr Fedorov 
4002cd7735dSAleksandr Fedorov /*
4012cd7735dSAleksandr Fedorov  * Netgraph backend
4022cd7735dSAleksandr Fedorov  */
4032cd7735dSAleksandr Fedorov 
4042cd7735dSAleksandr Fedorov #define NG_SBUF_MAX_SIZE (4 * 1024 * 1024)
4052cd7735dSAleksandr Fedorov 
4062cd7735dSAleksandr Fedorov static int
40798d920d9SMark Johnston ng_init(struct net_backend *be, const char *devname __unused,
408621b5090SJohn Baldwin 	 nvlist_t *nvl, net_be_rxeof_t cb, void *param)
4092cd7735dSAleksandr Fedorov {
4100ced97acSMark Johnston 	struct tap_priv *p = NET_BE_PRIV(be);
4112cd7735dSAleksandr Fedorov 	struct ngm_connect ngc;
412621b5090SJohn Baldwin 	const char *value, *nodename;
4132cd7735dSAleksandr Fedorov 	int sbsz;
4142cd7735dSAleksandr Fedorov 	int ctrl_sock;
4152cd7735dSAleksandr Fedorov 	int flags;
4162cd7735dSAleksandr Fedorov 	unsigned long maxsbsz;
4172cd7735dSAleksandr Fedorov 	size_t msbsz;
4182cd7735dSAleksandr Fedorov #ifndef WITHOUT_CAPSICUM
4192cd7735dSAleksandr Fedorov 	cap_rights_t rights;
4202cd7735dSAleksandr Fedorov #endif
4212cd7735dSAleksandr Fedorov 
4222cd7735dSAleksandr Fedorov 	if (cb == NULL) {
4232cd7735dSAleksandr Fedorov 		WPRINTF(("Netgraph backend requires non-NULL callback"));
4242cd7735dSAleksandr Fedorov 		return (-1);
4252cd7735dSAleksandr Fedorov 	}
4262cd7735dSAleksandr Fedorov 
4272cd7735dSAleksandr Fedorov 	be->fd = -1;
4282cd7735dSAleksandr Fedorov 
4292cd7735dSAleksandr Fedorov 	memset(&ngc, 0, sizeof(ngc));
4302cd7735dSAleksandr Fedorov 
431621b5090SJohn Baldwin 	value = get_config_value_node(nvl, "path");
432621b5090SJohn Baldwin 	if (value == NULL) {
4332cd7735dSAleksandr Fedorov 		WPRINTF(("path must be provided"));
4342cd7735dSAleksandr Fedorov 		return (-1);
4352cd7735dSAleksandr Fedorov 	}
436621b5090SJohn Baldwin 	strncpy(ngc.path, value, NG_PATHSIZ - 1);
4372cd7735dSAleksandr Fedorov 
438621b5090SJohn Baldwin 	value = get_config_value_node(nvl, "hook");
439621b5090SJohn Baldwin 	if (value == NULL)
440621b5090SJohn Baldwin 		value = "vmlink";
441621b5090SJohn Baldwin 	strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1);
442621b5090SJohn Baldwin 
443621b5090SJohn Baldwin 	value = get_config_value_node(nvl, "peerhook");
444621b5090SJohn Baldwin 	if (value == NULL) {
4452cd7735dSAleksandr Fedorov 		WPRINTF(("peer hook must be provided"));
4462cd7735dSAleksandr Fedorov 		return (-1);
4472cd7735dSAleksandr Fedorov 	}
448621b5090SJohn Baldwin 	strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1);
4492cd7735dSAleksandr Fedorov 
450621b5090SJohn Baldwin 	nodename = get_config_value_node(nvl, "socket");
451621b5090SJohn Baldwin 	if (NgMkSockNode(nodename,
4522cd7735dSAleksandr Fedorov 		&ctrl_sock, &be->fd) < 0) {
4532cd7735dSAleksandr Fedorov 		WPRINTF(("can't get Netgraph sockets"));
4542cd7735dSAleksandr Fedorov 		return (-1);
4552cd7735dSAleksandr Fedorov 	}
4562cd7735dSAleksandr Fedorov 
4572cd7735dSAleksandr Fedorov 	if (NgSendMsg(ctrl_sock, ".",
4582cd7735dSAleksandr Fedorov 		NGM_GENERIC_COOKIE,
4592cd7735dSAleksandr Fedorov 		NGM_CONNECT, &ngc, sizeof(ngc)) < 0) {
4602cd7735dSAleksandr Fedorov 		WPRINTF(("can't connect to node"));
4612cd7735dSAleksandr Fedorov 		close(ctrl_sock);
4622cd7735dSAleksandr Fedorov 		goto error;
4632cd7735dSAleksandr Fedorov 	}
4642cd7735dSAleksandr Fedorov 
4652cd7735dSAleksandr Fedorov 	close(ctrl_sock);
4662cd7735dSAleksandr Fedorov 
4672cd7735dSAleksandr Fedorov 	flags = fcntl(be->fd, F_GETFL);
4682cd7735dSAleksandr Fedorov 
4692cd7735dSAleksandr Fedorov 	if (flags < 0) {
4702cd7735dSAleksandr Fedorov 		WPRINTF(("can't get socket flags"));
4712cd7735dSAleksandr Fedorov 		goto error;
4722cd7735dSAleksandr Fedorov 	}
4732cd7735dSAleksandr Fedorov 
4742cd7735dSAleksandr Fedorov 	if (fcntl(be->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
4752cd7735dSAleksandr Fedorov 		WPRINTF(("can't set O_NONBLOCK flag"));
4762cd7735dSAleksandr Fedorov 		goto error;
4772cd7735dSAleksandr Fedorov 	}
4782cd7735dSAleksandr Fedorov 
4792cd7735dSAleksandr Fedorov 	/*
4802cd7735dSAleksandr Fedorov 	 * The default ng_socket(4) buffer's size is too low.
4812cd7735dSAleksandr Fedorov 	 * Calculate the minimum value between NG_SBUF_MAX_SIZE
4822cd7735dSAleksandr Fedorov 	 * and kern.ipc.maxsockbuf.
4832cd7735dSAleksandr Fedorov 	 */
4842cd7735dSAleksandr Fedorov 	msbsz = sizeof(maxsbsz);
4852cd7735dSAleksandr Fedorov 	if (sysctlbyname("kern.ipc.maxsockbuf", &maxsbsz, &msbsz,
4862cd7735dSAleksandr Fedorov 		NULL, 0) < 0) {
4872cd7735dSAleksandr Fedorov 		WPRINTF(("can't get 'kern.ipc.maxsockbuf' value"));
4882cd7735dSAleksandr Fedorov 		goto error;
4892cd7735dSAleksandr Fedorov 	}
4902cd7735dSAleksandr Fedorov 
4912cd7735dSAleksandr Fedorov 	/*
4922cd7735dSAleksandr Fedorov 	 * We can't set the socket buffer size to kern.ipc.maxsockbuf value,
4932cd7735dSAleksandr Fedorov 	 * as it takes into account the mbuf(9) overhead.
4942cd7735dSAleksandr Fedorov 	 */
4952cd7735dSAleksandr Fedorov 	maxsbsz = maxsbsz * MCLBYTES / (MSIZE + MCLBYTES);
4962cd7735dSAleksandr Fedorov 
4972cd7735dSAleksandr Fedorov 	sbsz = MIN(NG_SBUF_MAX_SIZE, maxsbsz);
4982cd7735dSAleksandr Fedorov 
4992cd7735dSAleksandr Fedorov 	if (setsockopt(be->fd, SOL_SOCKET, SO_SNDBUF, &sbsz,
5002cd7735dSAleksandr Fedorov 		sizeof(sbsz)) < 0) {
5012cd7735dSAleksandr Fedorov 		WPRINTF(("can't set TX buffer size"));
5022cd7735dSAleksandr Fedorov 		goto error;
5032cd7735dSAleksandr Fedorov 	}
5042cd7735dSAleksandr Fedorov 
5052cd7735dSAleksandr Fedorov 	if (setsockopt(be->fd, SOL_SOCKET, SO_RCVBUF, &sbsz,
5062cd7735dSAleksandr Fedorov 		sizeof(sbsz)) < 0) {
5072cd7735dSAleksandr Fedorov 		WPRINTF(("can't set RX buffer size"));
5082cd7735dSAleksandr Fedorov 		goto error;
5092cd7735dSAleksandr Fedorov 	}
5102cd7735dSAleksandr Fedorov 
5112cd7735dSAleksandr Fedorov #ifndef WITHOUT_CAPSICUM
5122cd7735dSAleksandr Fedorov 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
5132cd7735dSAleksandr Fedorov 	if (caph_rights_limit(be->fd, &rights) == -1)
5142cd7735dSAleksandr Fedorov 		errx(EX_OSERR, "Unable to apply rights for sandbox");
5152cd7735dSAleksandr Fedorov #endif
5162cd7735dSAleksandr Fedorov 
5172cd7735dSAleksandr Fedorov 	memset(p->bbuf, 0, sizeof(p->bbuf));
5182cd7735dSAleksandr Fedorov 	p->bbuflen = 0;
5192cd7735dSAleksandr Fedorov 
5202cd7735dSAleksandr Fedorov 	p->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
5212cd7735dSAleksandr Fedorov 	if (p->mevp == NULL) {
5222cd7735dSAleksandr Fedorov 		WPRINTF(("Could not register event"));
5232cd7735dSAleksandr Fedorov 		goto error;
5242cd7735dSAleksandr Fedorov 	}
5252cd7735dSAleksandr Fedorov 
5262cd7735dSAleksandr Fedorov 	return (0);
5272cd7735dSAleksandr Fedorov 
5282cd7735dSAleksandr Fedorov error:
5292cd7735dSAleksandr Fedorov 	tap_cleanup(be);
5302cd7735dSAleksandr Fedorov 	return (-1);
5312cd7735dSAleksandr Fedorov }
5322cd7735dSAleksandr Fedorov 
5332cd7735dSAleksandr Fedorov static struct net_backend ng_backend = {
5342cd7735dSAleksandr Fedorov 	.prefix = "netgraph",
5352cd7735dSAleksandr Fedorov 	.priv_size = sizeof(struct tap_priv),
5362cd7735dSAleksandr Fedorov 	.init = ng_init,
5372cd7735dSAleksandr Fedorov 	.cleanup = tap_cleanup,
5382cd7735dSAleksandr Fedorov 	.send = tap_send,
5392cd7735dSAleksandr Fedorov 	.peek_recvlen = tap_peek_recvlen,
5402cd7735dSAleksandr Fedorov 	.recv = tap_recv,
5412cd7735dSAleksandr Fedorov 	.recv_enable = tap_recv_enable,
5422cd7735dSAleksandr Fedorov 	.recv_disable = tap_recv_disable,
5432cd7735dSAleksandr Fedorov 	.get_cap = tap_get_cap,
5442cd7735dSAleksandr Fedorov 	.set_cap = tap_set_cap,
5452cd7735dSAleksandr Fedorov };
5462cd7735dSAleksandr Fedorov 
5472cd7735dSAleksandr Fedorov DATA_SET(net_backend_set, ng_backend);
5482cd7735dSAleksandr Fedorov 
5492cd7735dSAleksandr Fedorov #endif /* NETGRAPH */
5502cd7735dSAleksandr Fedorov 
5510ff7076bSVincenzo Maffione /*
5520ff7076bSVincenzo Maffione  * The netmap backend
5530ff7076bSVincenzo Maffione  */
5540ff7076bSVincenzo Maffione 
5550ff7076bSVincenzo Maffione /* The virtio-net features supported by netmap. */
5560ff7076bSVincenzo Maffione #define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \
5570ff7076bSVincenzo Maffione 		VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \
5580ff7076bSVincenzo Maffione 		VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \
559f92bb8c1SVincenzo Maffione 		VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO)
5600ff7076bSVincenzo Maffione 
5610ff7076bSVincenzo Maffione struct netmap_priv {
5620ff7076bSVincenzo Maffione 	char ifname[IFNAMSIZ];
5630ff7076bSVincenzo Maffione 	struct nm_desc *nmd;
5640ff7076bSVincenzo Maffione 	uint16_t memid;
5650ff7076bSVincenzo Maffione 	struct netmap_ring *rx;
5660ff7076bSVincenzo Maffione 	struct netmap_ring *tx;
5670ff7076bSVincenzo Maffione 	struct mevent *mevp;
5680ff7076bSVincenzo Maffione 	net_be_rxeof_t cb;
5690ff7076bSVincenzo Maffione 	void *cb_param;
5700ff7076bSVincenzo Maffione };
5710ff7076bSVincenzo Maffione 
5720ff7076bSVincenzo Maffione static void
5730ff7076bSVincenzo Maffione nmreq_init(struct nmreq *req, char *ifname)
5740ff7076bSVincenzo Maffione {
5750ff7076bSVincenzo Maffione 
5760ff7076bSVincenzo Maffione 	memset(req, 0, sizeof(*req));
5770ff7076bSVincenzo Maffione 	strlcpy(req->nr_name, ifname, sizeof(req->nr_name));
5780ff7076bSVincenzo Maffione 	req->nr_version = NETMAP_API;
5790ff7076bSVincenzo Maffione }
5800ff7076bSVincenzo Maffione 
5810ff7076bSVincenzo Maffione static int
5820ff7076bSVincenzo Maffione netmap_set_vnet_hdr_len(struct net_backend *be, int vnet_hdr_len)
5830ff7076bSVincenzo Maffione {
5840ff7076bSVincenzo Maffione 	int err;
5850ff7076bSVincenzo Maffione 	struct nmreq req;
5860ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
5870ff7076bSVincenzo Maffione 
5880ff7076bSVincenzo Maffione 	nmreq_init(&req, priv->ifname);
5890ff7076bSVincenzo Maffione 	req.nr_cmd = NETMAP_BDG_VNET_HDR;
5900ff7076bSVincenzo Maffione 	req.nr_arg1 = vnet_hdr_len;
5910ff7076bSVincenzo Maffione 	err = ioctl(be->fd, NIOCREGIF, &req);
5920ff7076bSVincenzo Maffione 	if (err) {
593332eff95SVincenzo Maffione 		WPRINTF(("Unable to set vnet header length %d",
5940ff7076bSVincenzo Maffione 				vnet_hdr_len));
5950ff7076bSVincenzo Maffione 		return (err);
5960ff7076bSVincenzo Maffione 	}
5970ff7076bSVincenzo Maffione 
5980ff7076bSVincenzo Maffione 	be->be_vnet_hdr_len = vnet_hdr_len;
5990ff7076bSVincenzo Maffione 
6000ff7076bSVincenzo Maffione 	return (0);
6010ff7076bSVincenzo Maffione }
6020ff7076bSVincenzo Maffione 
6030ff7076bSVincenzo Maffione static int
6040ff7076bSVincenzo Maffione netmap_has_vnet_hdr_len(struct net_backend *be, unsigned vnet_hdr_len)
6050ff7076bSVincenzo Maffione {
606ed721684SMark Johnston 	unsigned prev_hdr_len = be->be_vnet_hdr_len;
6070ff7076bSVincenzo Maffione 	int ret;
6080ff7076bSVincenzo Maffione 
6090ff7076bSVincenzo Maffione 	if (vnet_hdr_len == prev_hdr_len) {
6100ff7076bSVincenzo Maffione 		return (1);
6110ff7076bSVincenzo Maffione 	}
6120ff7076bSVincenzo Maffione 
6130ff7076bSVincenzo Maffione 	ret = netmap_set_vnet_hdr_len(be, vnet_hdr_len);
6140ff7076bSVincenzo Maffione 	if (ret) {
6150ff7076bSVincenzo Maffione 		return (0);
6160ff7076bSVincenzo Maffione 	}
6170ff7076bSVincenzo Maffione 
6180ff7076bSVincenzo Maffione 	netmap_set_vnet_hdr_len(be, prev_hdr_len);
6190ff7076bSVincenzo Maffione 
6200ff7076bSVincenzo Maffione 	return (1);
6210ff7076bSVincenzo Maffione }
6220ff7076bSVincenzo Maffione 
6230ff7076bSVincenzo Maffione static uint64_t
6240ff7076bSVincenzo Maffione netmap_get_cap(struct net_backend *be)
6250ff7076bSVincenzo Maffione {
6260ff7076bSVincenzo Maffione 
6270ff7076bSVincenzo Maffione 	return (netmap_has_vnet_hdr_len(be, VNET_HDR_LEN) ?
6280ff7076bSVincenzo Maffione 	    NETMAP_FEATURES : 0);
6290ff7076bSVincenzo Maffione }
6300ff7076bSVincenzo Maffione 
6310ff7076bSVincenzo Maffione static int
63298d920d9SMark Johnston netmap_set_cap(struct net_backend *be, uint64_t features __unused,
6330ff7076bSVincenzo Maffione     unsigned vnet_hdr_len)
6340ff7076bSVincenzo Maffione {
6350ff7076bSVincenzo Maffione 
6360ff7076bSVincenzo Maffione 	return (netmap_set_vnet_hdr_len(be, vnet_hdr_len));
6370ff7076bSVincenzo Maffione }
6380ff7076bSVincenzo Maffione 
6390ff7076bSVincenzo Maffione static int
6400ff7076bSVincenzo Maffione netmap_init(struct net_backend *be, const char *devname,
64198d920d9SMark Johnston     nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
6420ff7076bSVincenzo Maffione {
6430ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
6440ff7076bSVincenzo Maffione 
6450ff7076bSVincenzo Maffione 	strlcpy(priv->ifname, devname, sizeof(priv->ifname));
6460ff7076bSVincenzo Maffione 	priv->ifname[sizeof(priv->ifname) - 1] = '\0';
6470ff7076bSVincenzo Maffione 
6480ff7076bSVincenzo Maffione 	priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL);
6490ff7076bSVincenzo Maffione 	if (priv->nmd == NULL) {
650332eff95SVincenzo Maffione 		WPRINTF(("Unable to nm_open(): interface '%s', errno (%s)",
6510ff7076bSVincenzo Maffione 			devname, strerror(errno)));
6520ff7076bSVincenzo Maffione 		return (-1);
6530ff7076bSVincenzo Maffione 	}
6540ff7076bSVincenzo Maffione 
6550ff7076bSVincenzo Maffione 	priv->memid = priv->nmd->req.nr_arg2;
6560ff7076bSVincenzo Maffione 	priv->tx = NETMAP_TXRING(priv->nmd->nifp, 0);
6570ff7076bSVincenzo Maffione 	priv->rx = NETMAP_RXRING(priv->nmd->nifp, 0);
6580ff7076bSVincenzo Maffione 	priv->cb = cb;
6590ff7076bSVincenzo Maffione 	priv->cb_param = param;
6600ff7076bSVincenzo Maffione 	be->fd = priv->nmd->fd;
6610ff7076bSVincenzo Maffione 
6623e11768eSVincenzo Maffione 	priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
6630ff7076bSVincenzo Maffione 	if (priv->mevp == NULL) {
664332eff95SVincenzo Maffione 		WPRINTF(("Could not register event"));
6650ff7076bSVincenzo Maffione 		return (-1);
6660ff7076bSVincenzo Maffione 	}
6670ff7076bSVincenzo Maffione 
6680ff7076bSVincenzo Maffione 	return (0);
6690ff7076bSVincenzo Maffione }
6700ff7076bSVincenzo Maffione 
6710ff7076bSVincenzo Maffione static void
6720ff7076bSVincenzo Maffione netmap_cleanup(struct net_backend *be)
6730ff7076bSVincenzo Maffione {
6740ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
6750ff7076bSVincenzo Maffione 
6760ff7076bSVincenzo Maffione 	if (priv->mevp) {
6770ff7076bSVincenzo Maffione 		mevent_delete(priv->mevp);
6780ff7076bSVincenzo Maffione 	}
6790ff7076bSVincenzo Maffione 	if (priv->nmd) {
6800ff7076bSVincenzo Maffione 		nm_close(priv->nmd);
6810ff7076bSVincenzo Maffione 	}
6820ff7076bSVincenzo Maffione 	be->fd = -1;
6830ff7076bSVincenzo Maffione }
6840ff7076bSVincenzo Maffione 
6850ff7076bSVincenzo Maffione static ssize_t
68666c662b0SVincenzo Maffione netmap_send(struct net_backend *be, const struct iovec *iov,
6870ff7076bSVincenzo Maffione 	    int iovcnt)
6880ff7076bSVincenzo Maffione {
6890ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
6900ff7076bSVincenzo Maffione 	struct netmap_ring *ring;
6910ff7076bSVincenzo Maffione 	ssize_t totlen = 0;
6920ff7076bSVincenzo Maffione 	int nm_buf_size;
6930ff7076bSVincenzo Maffione 	int nm_buf_len;
6940ff7076bSVincenzo Maffione 	uint32_t head;
69503f7ccabSMark Johnston 	uint8_t *nm_buf;
6960ff7076bSVincenzo Maffione 	int j;
6970ff7076bSVincenzo Maffione 
6980ff7076bSVincenzo Maffione 	ring = priv->tx;
6990ff7076bSVincenzo Maffione 	head = ring->head;
7000ff7076bSVincenzo Maffione 	if (head == ring->tail) {
701332eff95SVincenzo Maffione 		WPRINTF(("No space, drop %zu bytes", count_iov(iov, iovcnt)));
7020ff7076bSVincenzo Maffione 		goto txsync;
7030ff7076bSVincenzo Maffione 	}
7040ff7076bSVincenzo Maffione 	nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
7050ff7076bSVincenzo Maffione 	nm_buf_size = ring->nr_buf_size;
7060ff7076bSVincenzo Maffione 	nm_buf_len = 0;
7070ff7076bSVincenzo Maffione 
7080ff7076bSVincenzo Maffione 	for (j = 0; j < iovcnt; j++) {
70963898728SMark Johnston 		uint8_t *iov_frag_buf = iov[j].iov_base;
7100ff7076bSVincenzo Maffione 		int iov_frag_size = iov[j].iov_len;
7110ff7076bSVincenzo Maffione 
7120ff7076bSVincenzo Maffione 		totlen += iov_frag_size;
7130ff7076bSVincenzo Maffione 
7140ff7076bSVincenzo Maffione 		/*
7150ff7076bSVincenzo Maffione 		 * Split each iovec fragment over more netmap slots, if
7160ff7076bSVincenzo Maffione 		 * necessary.
7170ff7076bSVincenzo Maffione 		 */
7180ff7076bSVincenzo Maffione 		for (;;) {
7190ff7076bSVincenzo Maffione 			int copylen;
7200ff7076bSVincenzo Maffione 
7210ff7076bSVincenzo Maffione 			copylen = iov_frag_size < nm_buf_size ? iov_frag_size : nm_buf_size;
7220ff7076bSVincenzo Maffione 			memcpy(nm_buf, iov_frag_buf, copylen);
7230ff7076bSVincenzo Maffione 
7240ff7076bSVincenzo Maffione 			iov_frag_buf += copylen;
7250ff7076bSVincenzo Maffione 			iov_frag_size -= copylen;
7260ff7076bSVincenzo Maffione 			nm_buf += copylen;
7270ff7076bSVincenzo Maffione 			nm_buf_size -= copylen;
7280ff7076bSVincenzo Maffione 			nm_buf_len += copylen;
7290ff7076bSVincenzo Maffione 
7300ff7076bSVincenzo Maffione 			if (iov_frag_size == 0) {
7310ff7076bSVincenzo Maffione 				break;
7320ff7076bSVincenzo Maffione 			}
7330ff7076bSVincenzo Maffione 
7340ff7076bSVincenzo Maffione 			ring->slot[head].len = nm_buf_len;
7350ff7076bSVincenzo Maffione 			ring->slot[head].flags = NS_MOREFRAG;
7360ff7076bSVincenzo Maffione 			head = nm_ring_next(ring, head);
7370ff7076bSVincenzo Maffione 			if (head == ring->tail) {
7380ff7076bSVincenzo Maffione 				/*
7390ff7076bSVincenzo Maffione 				 * We ran out of netmap slots while
7400ff7076bSVincenzo Maffione 				 * splitting the iovec fragments.
7410ff7076bSVincenzo Maffione 				 */
742332eff95SVincenzo Maffione 				WPRINTF(("No space, drop %zu bytes",
7430ff7076bSVincenzo Maffione 				   count_iov(iov, iovcnt)));
7440ff7076bSVincenzo Maffione 				goto txsync;
7450ff7076bSVincenzo Maffione 			}
7460ff7076bSVincenzo Maffione 			nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
7470ff7076bSVincenzo Maffione 			nm_buf_size = ring->nr_buf_size;
7480ff7076bSVincenzo Maffione 			nm_buf_len = 0;
7490ff7076bSVincenzo Maffione 		}
7500ff7076bSVincenzo Maffione 	}
7510ff7076bSVincenzo Maffione 
7520ff7076bSVincenzo Maffione 	/* Complete the last slot, which must not have NS_MOREFRAG set. */
7530ff7076bSVincenzo Maffione 	ring->slot[head].len = nm_buf_len;
7540ff7076bSVincenzo Maffione 	ring->slot[head].flags = 0;
7550ff7076bSVincenzo Maffione 	head = nm_ring_next(ring, head);
7560ff7076bSVincenzo Maffione 
7570ff7076bSVincenzo Maffione 	/* Now update ring->head and ring->cur. */
7580ff7076bSVincenzo Maffione 	ring->head = ring->cur = head;
7590ff7076bSVincenzo Maffione txsync:
7600ff7076bSVincenzo Maffione 	ioctl(be->fd, NIOCTXSYNC, NULL);
7610ff7076bSVincenzo Maffione 
7620ff7076bSVincenzo Maffione 	return (totlen);
7630ff7076bSVincenzo Maffione }
7640ff7076bSVincenzo Maffione 
7650ff7076bSVincenzo Maffione static ssize_t
766f92bb8c1SVincenzo Maffione netmap_peek_recvlen(struct net_backend *be)
767f92bb8c1SVincenzo Maffione {
7680ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
769f92bb8c1SVincenzo Maffione 	struct netmap_ring *ring = priv->rx;
770f92bb8c1SVincenzo Maffione 	uint32_t head = ring->head;
771f92bb8c1SVincenzo Maffione 	ssize_t totlen = 0;
772f92bb8c1SVincenzo Maffione 
773f92bb8c1SVincenzo Maffione 	while (head != ring->tail) {
774f92bb8c1SVincenzo Maffione 		struct netmap_slot *slot = ring->slot + head;
775f92bb8c1SVincenzo Maffione 
776f92bb8c1SVincenzo Maffione 		totlen += slot->len;
777f92bb8c1SVincenzo Maffione 		if ((slot->flags & NS_MOREFRAG) == 0)
778f92bb8c1SVincenzo Maffione 			break;
779f92bb8c1SVincenzo Maffione 		head = nm_ring_next(ring, head);
780f92bb8c1SVincenzo Maffione 	}
781f92bb8c1SVincenzo Maffione 
782f92bb8c1SVincenzo Maffione 	return (totlen);
783f92bb8c1SVincenzo Maffione }
784f92bb8c1SVincenzo Maffione 
785f92bb8c1SVincenzo Maffione static ssize_t
78666c662b0SVincenzo Maffione netmap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
7870ff7076bSVincenzo Maffione {
7880ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
7890ff7076bSVincenzo Maffione 	struct netmap_slot *slot = NULL;
7900ff7076bSVincenzo Maffione 	struct netmap_ring *ring;
79163898728SMark Johnston 	uint8_t *iov_frag_buf;
7920ff7076bSVincenzo Maffione 	int iov_frag_size;
7930ff7076bSVincenzo Maffione 	ssize_t totlen = 0;
7940ff7076bSVincenzo Maffione 	uint32_t head;
7950ff7076bSVincenzo Maffione 
7960ff7076bSVincenzo Maffione 	assert(iovcnt);
7970ff7076bSVincenzo Maffione 
7980ff7076bSVincenzo Maffione 	ring = priv->rx;
7990ff7076bSVincenzo Maffione 	head = ring->head;
8000ff7076bSVincenzo Maffione 	iov_frag_buf = iov->iov_base;
8010ff7076bSVincenzo Maffione 	iov_frag_size = iov->iov_len;
8020ff7076bSVincenzo Maffione 
8030ff7076bSVincenzo Maffione 	do {
80463898728SMark Johnston 		uint8_t *nm_buf;
8050ff7076bSVincenzo Maffione 		int nm_buf_len;
8060ff7076bSVincenzo Maffione 
8070ff7076bSVincenzo Maffione 		if (head == ring->tail) {
8080ff7076bSVincenzo Maffione 			return (0);
8090ff7076bSVincenzo Maffione 		}
8100ff7076bSVincenzo Maffione 
8110ff7076bSVincenzo Maffione 		slot = ring->slot + head;
8120ff7076bSVincenzo Maffione 		nm_buf = NETMAP_BUF(ring, slot->buf_idx);
8130ff7076bSVincenzo Maffione 		nm_buf_len = slot->len;
8140ff7076bSVincenzo Maffione 
8150ff7076bSVincenzo Maffione 		for (;;) {
8160ff7076bSVincenzo Maffione 			int copylen = nm_buf_len < iov_frag_size ?
8170ff7076bSVincenzo Maffione 			    nm_buf_len : iov_frag_size;
8180ff7076bSVincenzo Maffione 
8190ff7076bSVincenzo Maffione 			memcpy(iov_frag_buf, nm_buf, copylen);
8200ff7076bSVincenzo Maffione 			nm_buf += copylen;
8210ff7076bSVincenzo Maffione 			nm_buf_len -= copylen;
8220ff7076bSVincenzo Maffione 			iov_frag_buf += copylen;
8230ff7076bSVincenzo Maffione 			iov_frag_size -= copylen;
8240ff7076bSVincenzo Maffione 			totlen += copylen;
8250ff7076bSVincenzo Maffione 
8260ff7076bSVincenzo Maffione 			if (nm_buf_len == 0) {
8270ff7076bSVincenzo Maffione 				break;
8280ff7076bSVincenzo Maffione 			}
8290ff7076bSVincenzo Maffione 
8300ff7076bSVincenzo Maffione 			iov++;
8310ff7076bSVincenzo Maffione 			iovcnt--;
8320ff7076bSVincenzo Maffione 			if (iovcnt == 0) {
8330ff7076bSVincenzo Maffione 				/* No space to receive. */
834332eff95SVincenzo Maffione 				WPRINTF(("Short iov, drop %zd bytes",
8350ff7076bSVincenzo Maffione 				    totlen));
8360ff7076bSVincenzo Maffione 				return (-ENOSPC);
8370ff7076bSVincenzo Maffione 			}
8380ff7076bSVincenzo Maffione 			iov_frag_buf = iov->iov_base;
8390ff7076bSVincenzo Maffione 			iov_frag_size = iov->iov_len;
8400ff7076bSVincenzo Maffione 		}
8410ff7076bSVincenzo Maffione 
8420ff7076bSVincenzo Maffione 		head = nm_ring_next(ring, head);
8430ff7076bSVincenzo Maffione 
8440ff7076bSVincenzo Maffione 	} while (slot->flags & NS_MOREFRAG);
8450ff7076bSVincenzo Maffione 
8460ff7076bSVincenzo Maffione 	/* Release slots to netmap. */
8470ff7076bSVincenzo Maffione 	ring->head = ring->cur = head;
8480ff7076bSVincenzo Maffione 
8490ff7076bSVincenzo Maffione 	return (totlen);
8500ff7076bSVincenzo Maffione }
8510ff7076bSVincenzo Maffione 
852d12c5ef6SVincenzo Maffione static void
853d12c5ef6SVincenzo Maffione netmap_recv_enable(struct net_backend *be)
854d12c5ef6SVincenzo Maffione {
8550ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
856d12c5ef6SVincenzo Maffione 
857d12c5ef6SVincenzo Maffione 	mevent_enable(priv->mevp);
858d12c5ef6SVincenzo Maffione }
859d12c5ef6SVincenzo Maffione 
860d12c5ef6SVincenzo Maffione static void
861d12c5ef6SVincenzo Maffione netmap_recv_disable(struct net_backend *be)
862d12c5ef6SVincenzo Maffione {
8630ced97acSMark Johnston 	struct netmap_priv *priv = NET_BE_PRIV(be);
864d12c5ef6SVincenzo Maffione 
865d12c5ef6SVincenzo Maffione 	mevent_disable(priv->mevp);
866d12c5ef6SVincenzo Maffione }
867d12c5ef6SVincenzo Maffione 
8680ff7076bSVincenzo Maffione static struct net_backend netmap_backend = {
8690ff7076bSVincenzo Maffione 	.prefix = "netmap",
8700ff7076bSVincenzo Maffione 	.priv_size = sizeof(struct netmap_priv),
8710ff7076bSVincenzo Maffione 	.init = netmap_init,
8720ff7076bSVincenzo Maffione 	.cleanup = netmap_cleanup,
8730ff7076bSVincenzo Maffione 	.send = netmap_send,
874f92bb8c1SVincenzo Maffione 	.peek_recvlen = netmap_peek_recvlen,
8750ff7076bSVincenzo Maffione 	.recv = netmap_recv,
876d12c5ef6SVincenzo Maffione 	.recv_enable = netmap_recv_enable,
877d12c5ef6SVincenzo Maffione 	.recv_disable = netmap_recv_disable,
8780ff7076bSVincenzo Maffione 	.get_cap = netmap_get_cap,
8790ff7076bSVincenzo Maffione 	.set_cap = netmap_set_cap,
8800ff7076bSVincenzo Maffione };
8810ff7076bSVincenzo Maffione 
8820ff7076bSVincenzo Maffione /* A clone of the netmap backend, with a different prefix. */
8830ff7076bSVincenzo Maffione static struct net_backend vale_backend = {
8840ff7076bSVincenzo Maffione 	.prefix = "vale",
8850ff7076bSVincenzo Maffione 	.priv_size = sizeof(struct netmap_priv),
8860ff7076bSVincenzo Maffione 	.init = netmap_init,
8870ff7076bSVincenzo Maffione 	.cleanup = netmap_cleanup,
8880ff7076bSVincenzo Maffione 	.send = netmap_send,
889f92bb8c1SVincenzo Maffione 	.peek_recvlen = netmap_peek_recvlen,
8900ff7076bSVincenzo Maffione 	.recv = netmap_recv,
891d12c5ef6SVincenzo Maffione 	.recv_enable = netmap_recv_enable,
892d12c5ef6SVincenzo Maffione 	.recv_disable = netmap_recv_disable,
8930ff7076bSVincenzo Maffione 	.get_cap = netmap_get_cap,
8940ff7076bSVincenzo Maffione 	.set_cap = netmap_set_cap,
8950ff7076bSVincenzo Maffione };
8960ff7076bSVincenzo Maffione 
8970ff7076bSVincenzo Maffione DATA_SET(net_backend_set, netmap_backend);
8980ff7076bSVincenzo Maffione DATA_SET(net_backend_set, vale_backend);
8990ff7076bSVincenzo Maffione 
900621b5090SJohn Baldwin int
901621b5090SJohn Baldwin netbe_legacy_config(nvlist_t *nvl, const char *opts)
902621b5090SJohn Baldwin {
903621b5090SJohn Baldwin 	char *backend, *cp;
904621b5090SJohn Baldwin 
905621b5090SJohn Baldwin 	if (opts == NULL)
906621b5090SJohn Baldwin 		return (0);
907621b5090SJohn Baldwin 
908621b5090SJohn Baldwin 	cp = strchr(opts, ',');
909621b5090SJohn Baldwin 	if (cp == NULL) {
910621b5090SJohn Baldwin 		set_config_value_node(nvl, "backend", opts);
911621b5090SJohn Baldwin 		return (0);
912621b5090SJohn Baldwin 	}
913621b5090SJohn Baldwin 	backend = strndup(opts, cp - opts);
914621b5090SJohn Baldwin 	set_config_value_node(nvl, "backend", backend);
915621b5090SJohn Baldwin 	free(backend);
916621b5090SJohn Baldwin 	return (pci_parse_legacy_config(nvl, cp + 1));
917621b5090SJohn Baldwin }
918621b5090SJohn Baldwin 
9190ff7076bSVincenzo Maffione /*
9200ff7076bSVincenzo Maffione  * Initialize a backend and attach to the frontend.
9210ff7076bSVincenzo Maffione  * This is called during frontend initialization.
922621b5090SJohn Baldwin  *  @ret is a pointer to the backend to be initialized
9230ff7076bSVincenzo Maffione  *  @devname is the backend-name as supplied on the command line,
9240ff7076bSVincenzo Maffione  * 	e.g. -s 2:0,frontend-name,backend-name[,other-args]
9250ff7076bSVincenzo Maffione  *  @cb is the receive callback supplied by the frontend,
9260ff7076bSVincenzo Maffione  *	and it is invoked in the event loop when a receive
9270ff7076bSVincenzo Maffione  *	event is generated in the hypervisor,
9280ff7076bSVincenzo Maffione  *  @param is a pointer to the frontend, and normally used as
9290ff7076bSVincenzo Maffione  *	the argument for the callback.
9300ff7076bSVincenzo Maffione  */
9310ff7076bSVincenzo Maffione int
932621b5090SJohn Baldwin netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb,
9330ff7076bSVincenzo Maffione     void *param)
9340ff7076bSVincenzo Maffione {
9350ff7076bSVincenzo Maffione 	struct net_backend **pbe, *nbe, *tbe = NULL;
936b9c3e544SYan Ka Chiu 	const char *value, *type;
9375bebe923SAleksandr Fedorov 	char *devname;
9380ff7076bSVincenzo Maffione 	int err;
9390ff7076bSVincenzo Maffione 
940621b5090SJohn Baldwin 	value = get_config_value_node(nvl, "backend");
941621b5090SJohn Baldwin 	if (value == NULL) {
9425bebe923SAleksandr Fedorov 		return (-1);
9435bebe923SAleksandr Fedorov 	}
944621b5090SJohn Baldwin 	devname = strdup(value);
9455bebe923SAleksandr Fedorov 
9460ff7076bSVincenzo Maffione 	/*
947b9c3e544SYan Ka Chiu 	 * Use the type given by configuration if exists; otherwise
948b9c3e544SYan Ka Chiu 	 * use the prefix of the backend as the type.
949b9c3e544SYan Ka Chiu 	 */
950b9c3e544SYan Ka Chiu 	type = get_config_value_node(nvl, "type");
951b9c3e544SYan Ka Chiu 	if (type == NULL)
952b9c3e544SYan Ka Chiu 		type = devname;
953b9c3e544SYan Ka Chiu 
954b9c3e544SYan Ka Chiu 	/*
9550ff7076bSVincenzo Maffione 	 * Find the network backend that matches the user-provided
9560ff7076bSVincenzo Maffione 	 * device name. net_backend_set is built using a linker set.
9570ff7076bSVincenzo Maffione 	 */
9580ff7076bSVincenzo Maffione 	SET_FOREACH(pbe, net_backend_set) {
959b9c3e544SYan Ka Chiu 		if (strncmp(type, (*pbe)->prefix,
9600ff7076bSVincenzo Maffione 		    strlen((*pbe)->prefix)) == 0) {
9610ff7076bSVincenzo Maffione 			tbe = *pbe;
9620ff7076bSVincenzo Maffione 			assert(tbe->init != NULL);
9630ff7076bSVincenzo Maffione 			assert(tbe->cleanup != NULL);
9640ff7076bSVincenzo Maffione 			assert(tbe->send != NULL);
9650ff7076bSVincenzo Maffione 			assert(tbe->recv != NULL);
9660ff7076bSVincenzo Maffione 			assert(tbe->get_cap != NULL);
9670ff7076bSVincenzo Maffione 			assert(tbe->set_cap != NULL);
9680ff7076bSVincenzo Maffione 			break;
9690ff7076bSVincenzo Maffione 		}
9700ff7076bSVincenzo Maffione 	}
9710ff7076bSVincenzo Maffione 
9720ff7076bSVincenzo Maffione 	*ret = NULL;
9735bebe923SAleksandr Fedorov 	if (tbe == NULL) {
9745bebe923SAleksandr Fedorov 		free(devname);
9750ff7076bSVincenzo Maffione 		return (EINVAL);
9765bebe923SAleksandr Fedorov 	}
9775bebe923SAleksandr Fedorov 
9780ced97acSMark Johnston 	nbe = calloc(1, NET_BE_SIZE(tbe));
9790ff7076bSVincenzo Maffione 	*nbe = *tbe;	/* copy the template */
9800ff7076bSVincenzo Maffione 	nbe->fd = -1;
9810ff7076bSVincenzo Maffione 	nbe->sc = param;
9820ff7076bSVincenzo Maffione 	nbe->be_vnet_hdr_len = 0;
9830ff7076bSVincenzo Maffione 	nbe->fe_vnet_hdr_len = 0;
9840ff7076bSVincenzo Maffione 
9850ff7076bSVincenzo Maffione 	/* Initialize the backend. */
986621b5090SJohn Baldwin 	err = nbe->init(nbe, devname, nvl, cb, param);
9870ff7076bSVincenzo Maffione 	if (err) {
9885bebe923SAleksandr Fedorov 		free(devname);
9890ff7076bSVincenzo Maffione 		free(nbe);
9900ff7076bSVincenzo Maffione 		return (err);
9910ff7076bSVincenzo Maffione 	}
9920ff7076bSVincenzo Maffione 
9930ff7076bSVincenzo Maffione 	*ret = nbe;
9945bebe923SAleksandr Fedorov 	free(devname);
9950ff7076bSVincenzo Maffione 
9960ff7076bSVincenzo Maffione 	return (0);
9970ff7076bSVincenzo Maffione }
9980ff7076bSVincenzo Maffione 
9990ff7076bSVincenzo Maffione void
10000ff7076bSVincenzo Maffione netbe_cleanup(struct net_backend *be)
10010ff7076bSVincenzo Maffione {
10020ff7076bSVincenzo Maffione 
10030ff7076bSVincenzo Maffione 	if (be != NULL) {
10040ff7076bSVincenzo Maffione 		be->cleanup(be);
10050ff7076bSVincenzo Maffione 		free(be);
10060ff7076bSVincenzo Maffione 	}
10070ff7076bSVincenzo Maffione }
10080ff7076bSVincenzo Maffione 
10090ff7076bSVincenzo Maffione uint64_t
10100ff7076bSVincenzo Maffione netbe_get_cap(struct net_backend *be)
10110ff7076bSVincenzo Maffione {
10120ff7076bSVincenzo Maffione 
10130ff7076bSVincenzo Maffione 	assert(be != NULL);
10140ff7076bSVincenzo Maffione 	return (be->get_cap(be));
10150ff7076bSVincenzo Maffione }
10160ff7076bSVincenzo Maffione 
10170ff7076bSVincenzo Maffione int
10180ff7076bSVincenzo Maffione netbe_set_cap(struct net_backend *be, uint64_t features,
10190ff7076bSVincenzo Maffione 	      unsigned vnet_hdr_len)
10200ff7076bSVincenzo Maffione {
10210ff7076bSVincenzo Maffione 	int ret;
10220ff7076bSVincenzo Maffione 
10230ff7076bSVincenzo Maffione 	assert(be != NULL);
10240ff7076bSVincenzo Maffione 
10250ff7076bSVincenzo Maffione 	/* There are only three valid lengths, i.e., 0, 10 and 12. */
10260ff7076bSVincenzo Maffione 	if (vnet_hdr_len && vnet_hdr_len != VNET_HDR_LEN
10270ff7076bSVincenzo Maffione 		&& vnet_hdr_len != (VNET_HDR_LEN - sizeof(uint16_t)))
10280ff7076bSVincenzo Maffione 		return (-1);
10290ff7076bSVincenzo Maffione 
10300ff7076bSVincenzo Maffione 	be->fe_vnet_hdr_len = vnet_hdr_len;
10310ff7076bSVincenzo Maffione 
10320ff7076bSVincenzo Maffione 	ret = be->set_cap(be, features, vnet_hdr_len);
10330ff7076bSVincenzo Maffione 	assert(be->be_vnet_hdr_len == 0 ||
10340ff7076bSVincenzo Maffione 	       be->be_vnet_hdr_len == be->fe_vnet_hdr_len);
10350ff7076bSVincenzo Maffione 
10360ff7076bSVincenzo Maffione 	return (ret);
10370ff7076bSVincenzo Maffione }
10380ff7076bSVincenzo Maffione 
10390ff7076bSVincenzo Maffione ssize_t
104066c662b0SVincenzo Maffione netbe_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
10410ff7076bSVincenzo Maffione {
10420ff7076bSVincenzo Maffione 
10430ff7076bSVincenzo Maffione 	return (be->send(be, iov, iovcnt));
10440ff7076bSVincenzo Maffione }
10450ff7076bSVincenzo Maffione 
1046f92bb8c1SVincenzo Maffione ssize_t
1047f92bb8c1SVincenzo Maffione netbe_peek_recvlen(struct net_backend *be)
1048f92bb8c1SVincenzo Maffione {
1049f92bb8c1SVincenzo Maffione 
1050f92bb8c1SVincenzo Maffione 	return (be->peek_recvlen(be));
1051f92bb8c1SVincenzo Maffione }
1052f92bb8c1SVincenzo Maffione 
10530ff7076bSVincenzo Maffione /*
10540ff7076bSVincenzo Maffione  * Try to read a packet from the backend, without blocking.
10550ff7076bSVincenzo Maffione  * If no packets are available, return 0. In case of success, return
10560ff7076bSVincenzo Maffione  * the length of the packet just read. Return -1 in case of errors.
10570ff7076bSVincenzo Maffione  */
10580ff7076bSVincenzo Maffione ssize_t
105966c662b0SVincenzo Maffione netbe_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
10600ff7076bSVincenzo Maffione {
10610ff7076bSVincenzo Maffione 
106266c662b0SVincenzo Maffione 	return (be->recv(be, iov, iovcnt));
10630ff7076bSVincenzo Maffione }
10640ff7076bSVincenzo Maffione 
10650ff7076bSVincenzo Maffione /*
10660ff7076bSVincenzo Maffione  * Read a packet from the backend and discard it.
10670ff7076bSVincenzo Maffione  * Returns the size of the discarded packet or zero if no packet was available.
10680ff7076bSVincenzo Maffione  * A negative error code is returned in case of read error.
10690ff7076bSVincenzo Maffione  */
10700ff7076bSVincenzo Maffione ssize_t
10710ff7076bSVincenzo Maffione netbe_rx_discard(struct net_backend *be)
10720ff7076bSVincenzo Maffione {
10730ff7076bSVincenzo Maffione 	/*
10740ff7076bSVincenzo Maffione 	 * MP note: the dummybuf is only used to discard frames,
10750ff7076bSVincenzo Maffione 	 * so there is no need for it to be per-vtnet or locked.
10760ff7076bSVincenzo Maffione 	 * We only make it large enough for TSO-sized segment.
10770ff7076bSVincenzo Maffione 	 */
10780ff7076bSVincenzo Maffione 	static uint8_t dummybuf[65536 + 64];
10790ff7076bSVincenzo Maffione 	struct iovec iov;
10800ff7076bSVincenzo Maffione 
10810ff7076bSVincenzo Maffione 	iov.iov_base = dummybuf;
10820ff7076bSVincenzo Maffione 	iov.iov_len = sizeof(dummybuf);
10830ff7076bSVincenzo Maffione 
10840ff7076bSVincenzo Maffione 	return netbe_recv(be, &iov, 1);
10850ff7076bSVincenzo Maffione }
10860ff7076bSVincenzo Maffione 
1087d12c5ef6SVincenzo Maffione void
1088d12c5ef6SVincenzo Maffione netbe_rx_disable(struct net_backend *be)
1089d12c5ef6SVincenzo Maffione {
1090d12c5ef6SVincenzo Maffione 
109114d72637SVincenzo Maffione 	return be->recv_disable(be);
1092d12c5ef6SVincenzo Maffione }
1093d12c5ef6SVincenzo Maffione 
1094d12c5ef6SVincenzo Maffione void
1095d12c5ef6SVincenzo Maffione netbe_rx_enable(struct net_backend *be)
1096d12c5ef6SVincenzo Maffione {
1097d12c5ef6SVincenzo Maffione 
109814d72637SVincenzo Maffione 	return be->recv_enable(be);
1099d12c5ef6SVincenzo Maffione }
110066c662b0SVincenzo Maffione 
110166c662b0SVincenzo Maffione size_t
110266c662b0SVincenzo Maffione netbe_get_vnet_hdr_len(struct net_backend *be)
110366c662b0SVincenzo Maffione {
110466c662b0SVincenzo Maffione 
110566c662b0SVincenzo Maffione 	return (be->be_vnet_hdr_len);
110666c662b0SVincenzo Maffione }
1107