xref: /illumos-gate/usr/src/cmd/bhyve/net_backends.c (revision 32640292)
184659b24SMichael Zeller /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
384659b24SMichael Zeller  *
484659b24SMichael Zeller  * Copyright (c) 2019 Vincenzo Maffione <vmaffione@FreeBSD.org>
584659b24SMichael Zeller  *
684659b24SMichael Zeller  * Redistribution and use in source and binary forms, with or without
784659b24SMichael Zeller  * modification, are permitted provided that the following conditions
884659b24SMichael Zeller  * are met:
984659b24SMichael Zeller  * 1. Redistributions of source code must retain the above copyright
1084659b24SMichael Zeller  *    notice, this list of conditions and the following disclaimer.
1184659b24SMichael Zeller  * 2. Redistributions in binary form must reproduce the above copyright
1284659b24SMichael Zeller  *    notice, this list of conditions and the following disclaimer in the
1384659b24SMichael Zeller  *    documentation and/or other materials provided with the distribution.
1484659b24SMichael Zeller  *
1584659b24SMichael Zeller  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
1684659b24SMichael Zeller  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1784659b24SMichael Zeller  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1884659b24SMichael Zeller  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
1984659b24SMichael Zeller  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
2084659b24SMichael Zeller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
2184659b24SMichael Zeller  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2284659b24SMichael Zeller  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2384659b24SMichael Zeller  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2484659b24SMichael Zeller  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2584659b24SMichael Zeller  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2684659b24SMichael Zeller  */
2784659b24SMichael Zeller 
2884659b24SMichael Zeller /*
2984659b24SMichael Zeller  * This file implements multiple network backends (tap, netmap, ...),
3084659b24SMichael Zeller  * to be used by network frontends such as virtio-net and e1000.
3184659b24SMichael Zeller  * The API to access the backend (e.g. send/receive packets, negotiate
3284659b24SMichael Zeller  * features) is exported by net_backends.h.
3384659b24SMichael Zeller  */
3484659b24SMichael Zeller 
3584659b24SMichael Zeller #include <sys/cdefs.h>
3684659b24SMichael Zeller 
3784659b24SMichael Zeller #include <sys/types.h>		/* u_short etc */
3884659b24SMichael Zeller #ifndef WITHOUT_CAPSICUM
3984659b24SMichael Zeller #include <sys/capsicum.h>
4084659b24SMichael Zeller #endif
4184659b24SMichael Zeller #include <sys/ioctl.h>
4284659b24SMichael Zeller #include <sys/mman.h>
4384659b24SMichael Zeller #include <sys/uio.h>
4484659b24SMichael Zeller 
4584659b24SMichael Zeller #include <net/if.h>
46069b2ef0SAndy Fiddaman #ifdef __FreeBSD__
47b0de25cbSAndy Fiddaman #if defined(INET6) || defined(INET)
48b0de25cbSAndy Fiddaman #include <net/if_tap.h>
49b0de25cbSAndy Fiddaman #endif
5084659b24SMichael Zeller #include <net/netmap.h>
5184659b24SMichael Zeller #include <net/netmap_virt.h>
5284659b24SMichael Zeller #define NETMAP_WITH_LIBS
5384659b24SMichael Zeller #include <net/netmap_user.h>
54b0de25cbSAndy Fiddaman #endif /* __FreeBSD__ */
5584659b24SMichael Zeller 
5684659b24SMichael Zeller #ifndef WITHOUT_CAPSICUM
5784659b24SMichael Zeller #include <capsicum_helpers.h>
5884659b24SMichael Zeller #endif
5984659b24SMichael Zeller #include <err.h>
6084659b24SMichael Zeller #include <errno.h>
6184659b24SMichael Zeller #include <fcntl.h>
6284659b24SMichael Zeller #include <stdio.h>
6384659b24SMichael Zeller #include <stdlib.h>
6484659b24SMichael Zeller #include <stdint.h>
6584659b24SMichael Zeller #include <string.h>
6684659b24SMichael Zeller #include <unistd.h>
6784659b24SMichael Zeller #include <sysexits.h>
6884659b24SMichael Zeller #include <assert.h>
6984659b24SMichael Zeller #include <pthread.h>
7084659b24SMichael Zeller #include <pthread_np.h>
7184659b24SMichael Zeller #include <poll.h>
7284659b24SMichael Zeller #include <assert.h>
7384659b24SMichael Zeller 
74154972afSPatrick Mooney #ifdef NETGRAPH
75154972afSPatrick Mooney #include <sys/param.h>
76154972afSPatrick Mooney #include <sys/sysctl.h>
77154972afSPatrick Mooney #include <netgraph.h>
78154972afSPatrick Mooney #endif
7984659b24SMichael Zeller 
80069b2ef0SAndy Fiddaman #ifndef __FreeBSD__
81069b2ef0SAndy Fiddaman #include <libdlpi.h>
82069b2ef0SAndy Fiddaman #include <net/ethernet.h>
83069b2ef0SAndy Fiddaman #endif
84069b2ef0SAndy Fiddaman 
852b948146SAndy Fiddaman #include "config.h"
86154972afSPatrick Mooney #include "debug.h"
8784659b24SMichael Zeller #include "iov.h"
8884659b24SMichael Zeller #include "mevent.h"
8984659b24SMichael Zeller #include "net_backends.h"
902b948146SAndy Fiddaman #include "pci_emul.h"
9184659b24SMichael Zeller 
9284659b24SMichael Zeller #include <sys/linker_set.h>
9384659b24SMichael Zeller 
9484659b24SMichael Zeller /*
9584659b24SMichael Zeller  * Each network backend registers a set of function pointers that are
9684659b24SMichael Zeller  * used to implement the net backends API.
9784659b24SMichael Zeller  * This might need to be exposed if we implement backends in separate files.
9884659b24SMichael Zeller  */
9984659b24SMichael Zeller struct net_backend {
10084659b24SMichael Zeller 	const char *prefix;	/* prefix matching this backend */
10184659b24SMichael Zeller 
10284659b24SMichael Zeller 	/*
10384659b24SMichael Zeller 	 * Routines used to initialize and cleanup the resources needed
10484659b24SMichael Zeller 	 * by a backend. The cleanup function is used internally,
10584659b24SMichael Zeller 	 * and should not be called by the frontend.
10684659b24SMichael Zeller 	 */
10784659b24SMichael Zeller 	int (*init)(struct net_backend *be, const char *devname,
1082b948146SAndy Fiddaman 	    nvlist_t *nvl, net_be_rxeof_t cb, void *param);
10984659b24SMichael Zeller 	void (*cleanup)(struct net_backend *be);
11084659b24SMichael Zeller 
11184659b24SMichael Zeller 	/*
11284659b24SMichael Zeller 	 * Called to serve a guest transmit request. The scatter-gather
11384659b24SMichael Zeller 	 * vector provided by the caller has 'iovcnt' elements and contains
11484659b24SMichael Zeller 	 * the packet to send.
11584659b24SMichael Zeller 	 */
116154972afSPatrick Mooney 	ssize_t (*send)(struct net_backend *be, const struct iovec *iov,
117154972afSPatrick Mooney 	    int iovcnt);
118154972afSPatrick Mooney 
119154972afSPatrick Mooney 	/*
120154972afSPatrick Mooney 	 * Get the length of the next packet that can be received from
121154972afSPatrick Mooney 	 * the backend. If no packets are currently available, this
122154972afSPatrick Mooney 	 * function returns 0.
123154972afSPatrick Mooney 	 */
124154972afSPatrick Mooney 	ssize_t (*peek_recvlen)(struct net_backend *be);
12584659b24SMichael Zeller 
12684659b24SMichael Zeller 	/*
12784659b24SMichael Zeller 	 * Called to receive a packet from the backend. When the function
12884659b24SMichael Zeller 	 * returns a positive value 'len', the scatter-gather vector
12984659b24SMichael Zeller 	 * provided by the caller contains a packet with such length.
13084659b24SMichael Zeller 	 * The function returns 0 if the backend doesn't have a new packet to
13184659b24SMichael Zeller 	 * receive.
13284659b24SMichael Zeller 	 */
133154972afSPatrick Mooney 	ssize_t (*recv)(struct net_backend *be, const struct iovec *iov,
134154972afSPatrick Mooney 	    int iovcnt);
135154972afSPatrick Mooney 
136154972afSPatrick Mooney 	/*
137154972afSPatrick Mooney 	 * Ask the backend to enable or disable receive operation in the
138154972afSPatrick Mooney 	 * backend. On return from a disable operation, it is guaranteed
139154972afSPatrick Mooney 	 * that the receive callback won't be called until receive is
140154972afSPatrick Mooney 	 * enabled again. Note however that it is up to the caller to make
141154972afSPatrick Mooney 	 * sure that netbe_recv() is not currently being executed by another
142154972afSPatrick Mooney 	 * thread.
143154972afSPatrick Mooney 	 */
144154972afSPatrick Mooney 	void (*recv_enable)(struct net_backend *be);
145154972afSPatrick Mooney 	void (*recv_disable)(struct net_backend *be);
14684659b24SMichael Zeller 
14784659b24SMichael Zeller 	/*
14884659b24SMichael Zeller 	 * Ask the backend for the virtio-net features it is able to
14984659b24SMichael Zeller 	 * support. Possible features are TSO, UFO and checksum offloading
15084659b24SMichael Zeller 	 * in both rx and tx direction and for both IPv4 and IPv6.
15184659b24SMichael Zeller 	 */
15284659b24SMichael Zeller 	uint64_t (*get_cap)(struct net_backend *be);
15384659b24SMichael Zeller 
15484659b24SMichael Zeller 	/*
15584659b24SMichael Zeller 	 * Tell the backend to enable/disable the specified virtio-net
15684659b24SMichael Zeller 	 * features (capabilities).
15784659b24SMichael Zeller 	 */
15884659b24SMichael Zeller 	int (*set_cap)(struct net_backend *be, uint64_t features,
15984659b24SMichael Zeller 	    unsigned int vnet_hdr_len);
16084659b24SMichael Zeller 
161069b2ef0SAndy Fiddaman #ifndef __FreeBSD__
162069b2ef0SAndy Fiddaman 	int (*get_mac)(struct net_backend *be, void *, size_t *);
163069b2ef0SAndy Fiddaman #endif
164069b2ef0SAndy Fiddaman 
16584659b24SMichael Zeller 	struct pci_vtnet_softc *sc;
16684659b24SMichael Zeller 	int fd;
16784659b24SMichael Zeller 
16884659b24SMichael Zeller 	/*
16984659b24SMichael Zeller 	 * Length of the virtio-net header used by the backend and the
17084659b24SMichael Zeller 	 * frontend, respectively. A zero value means that the header
17184659b24SMichael Zeller 	 * is not used.
17284659b24SMichael Zeller 	 */
17384659b24SMichael Zeller 	unsigned int be_vnet_hdr_len;
17484659b24SMichael Zeller 	unsigned int fe_vnet_hdr_len;
17584659b24SMichael Zeller 
17684659b24SMichael Zeller 	/* Size of backend-specific private data. */
17784659b24SMichael Zeller 	size_t priv_size;
17884659b24SMichael Zeller 
17959d65d31SAndy Fiddaman 	/* Backend-specific private data follows. */
18084659b24SMichael Zeller };
18184659b24SMichael Zeller 
18259d65d31SAndy Fiddaman #define	NET_BE_PRIV(be)		((void *)((be) + 1))
18359d65d31SAndy Fiddaman #define	NET_BE_SIZE(be)		(sizeof(*be) + (be)->priv_size)
18459d65d31SAndy Fiddaman 
18584659b24SMichael Zeller SET_DECLARE(net_backend_set, struct net_backend);
18684659b24SMichael Zeller 
18784659b24SMichael Zeller #define VNET_HDR_LEN	sizeof(struct virtio_net_rxhdr)
18884659b24SMichael Zeller 
189154972afSPatrick Mooney #define WPRINTF(params) PRINTLN params
19084659b24SMichael Zeller 
191069b2ef0SAndy Fiddaman #ifdef __FreeBSD__
192069b2ef0SAndy Fiddaman 
19384659b24SMichael Zeller /*
19484659b24SMichael Zeller  * The tap backend
19584659b24SMichael Zeller  */
19684659b24SMichael Zeller 
197b0de25cbSAndy Fiddaman #if defined(INET6) || defined(INET)
1984f3f3e9aSAndy Fiddaman static const int pf_list[] = {
199b0de25cbSAndy Fiddaman #if defined(INET6)
200b0de25cbSAndy Fiddaman 	PF_INET6,
201b0de25cbSAndy Fiddaman #endif
202b0de25cbSAndy Fiddaman #if defined(INET)
203b0de25cbSAndy Fiddaman 	PF_INET,
204b0de25cbSAndy Fiddaman #endif
205b0de25cbSAndy Fiddaman };
206b0de25cbSAndy Fiddaman #endif
207b0de25cbSAndy Fiddaman 
20884659b24SMichael Zeller struct tap_priv {
20984659b24SMichael Zeller 	struct mevent *mevp;
210154972afSPatrick Mooney 	/*
211154972afSPatrick Mooney 	 * A bounce buffer that allows us to implement the peek_recvlen
212154972afSPatrick Mooney 	 * callback. In the future we may get the same information from
213154972afSPatrick Mooney 	 * the kevent data.
214154972afSPatrick Mooney 	 */
215154972afSPatrick Mooney 	char bbuf[1 << 16];
216154972afSPatrick Mooney 	ssize_t bbuflen;
21784659b24SMichael Zeller };
21884659b24SMichael Zeller 
21984659b24SMichael Zeller static void
tap_cleanup(struct net_backend * be)22084659b24SMichael Zeller tap_cleanup(struct net_backend *be)
22184659b24SMichael Zeller {
22259d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
22384659b24SMichael Zeller 
22484659b24SMichael Zeller 	if (priv->mevp) {
22584659b24SMichael Zeller 		mevent_delete(priv->mevp);
22684659b24SMichael Zeller 	}
22784659b24SMichael Zeller 	if (be->fd != -1) {
22884659b24SMichael Zeller 		close(be->fd);
22984659b24SMichael Zeller 		be->fd = -1;
23084659b24SMichael Zeller 	}
23184659b24SMichael Zeller }
23284659b24SMichael Zeller 
23384659b24SMichael Zeller static int
tap_init(struct net_backend * be,const char * devname,nvlist_t * nvl __unused,net_be_rxeof_t cb,void * param)23484659b24SMichael Zeller tap_init(struct net_backend *be, const char *devname,
23559d65d31SAndy Fiddaman     nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
23684659b24SMichael Zeller {
23759d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
23884659b24SMichael Zeller 	char tbuf[80];
23984659b24SMichael Zeller 	int opt = 1;
240b0de25cbSAndy Fiddaman #if defined(INET6) || defined(INET)
241b0de25cbSAndy Fiddaman 	struct ifreq ifrq;
24259d65d31SAndy Fiddaman 	int s;
243b0de25cbSAndy Fiddaman #endif
24484659b24SMichael Zeller #ifndef WITHOUT_CAPSICUM
24584659b24SMichael Zeller 	cap_rights_t rights;
24684659b24SMichael Zeller #endif
24784659b24SMichael Zeller 
24884659b24SMichael Zeller 	if (cb == NULL) {
249154972afSPatrick Mooney 		WPRINTF(("TAP backend requires non-NULL callback"));
25084659b24SMichael Zeller 		return (-1);
25184659b24SMichael Zeller 	}
25284659b24SMichael Zeller 
25384659b24SMichael Zeller 	strcpy(tbuf, "/dev/");
25484659b24SMichael Zeller 	strlcat(tbuf, devname, sizeof(tbuf));
25584659b24SMichael Zeller 
25684659b24SMichael Zeller 	be->fd = open(tbuf, O_RDWR);
25784659b24SMichael Zeller 	if (be->fd == -1) {
258154972afSPatrick Mooney 		WPRINTF(("open of tap device %s failed", tbuf));
25984659b24SMichael Zeller 		goto error;
26084659b24SMichael Zeller 	}
26184659b24SMichael Zeller 
26284659b24SMichael Zeller 	/*
26384659b24SMichael Zeller 	 * Set non-blocking and register for read
26484659b24SMichael Zeller 	 * notifications with the event loop
26584659b24SMichael Zeller 	 */
26684659b24SMichael Zeller 	if (ioctl(be->fd, FIONBIO, &opt) < 0) {
267154972afSPatrick Mooney 		WPRINTF(("tap device O_NONBLOCK failed"));
26884659b24SMichael Zeller 		goto error;
26984659b24SMichael Zeller 	}
27084659b24SMichael Zeller 
271b0de25cbSAndy Fiddaman #if defined(INET6) || defined(INET)
272b0de25cbSAndy Fiddaman 	/*
273b0de25cbSAndy Fiddaman 	 * Try to UP the interface rather than relying on
274b0de25cbSAndy Fiddaman 	 * net.link.tap.up_on_open.
275b0de25cbSAndy Fiddaman 	  */
276b0de25cbSAndy Fiddaman 	bzero(&ifrq, sizeof(ifrq));
277b0de25cbSAndy Fiddaman 	if (ioctl(be->fd, TAPGIFNAME, &ifrq) < 0) {
278b0de25cbSAndy Fiddaman 		WPRINTF(("Could not get interface name"));
279b0de25cbSAndy Fiddaman 		goto error;
280b0de25cbSAndy Fiddaman 	}
281b0de25cbSAndy Fiddaman 
282b0de25cbSAndy Fiddaman 	s = -1;
28359d65d31SAndy Fiddaman 	for (size_t i = 0; s == -1 && i < nitems(pf_list); i++)
284b0de25cbSAndy Fiddaman 		s = socket(pf_list[i], SOCK_DGRAM, 0);
285b0de25cbSAndy Fiddaman 	if (s == -1) {
286b0de25cbSAndy Fiddaman 		WPRINTF(("Could open socket"));
287b0de25cbSAndy Fiddaman 		goto error;
288b0de25cbSAndy Fiddaman 	}
289b0de25cbSAndy Fiddaman 
290b0de25cbSAndy Fiddaman 	if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
291b0de25cbSAndy Fiddaman 		(void)close(s);
292b0de25cbSAndy Fiddaman 		WPRINTF(("Could not get interface flags"));
293b0de25cbSAndy Fiddaman 		goto error;
294b0de25cbSAndy Fiddaman 	}
295b0de25cbSAndy Fiddaman 	ifrq.ifr_flags |= IFF_UP;
296b0de25cbSAndy Fiddaman 	if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
297b0de25cbSAndy Fiddaman 		(void)close(s);
298b0de25cbSAndy Fiddaman 		WPRINTF(("Could not set interface flags"));
299b0de25cbSAndy Fiddaman 		goto error;
300b0de25cbSAndy Fiddaman 	}
301b0de25cbSAndy Fiddaman 	(void)close(s);
302b0de25cbSAndy Fiddaman #endif
303b0de25cbSAndy Fiddaman 
30484659b24SMichael Zeller #ifndef WITHOUT_CAPSICUM
30584659b24SMichael Zeller 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
30684659b24SMichael Zeller 	if (caph_rights_limit(be->fd, &rights) == -1)
30784659b24SMichael Zeller 		errx(EX_OSERR, "Unable to apply rights for sandbox");
30884659b24SMichael Zeller #endif
30984659b24SMichael Zeller 
310154972afSPatrick Mooney 	memset(priv->bbuf, 0, sizeof(priv->bbuf));
311154972afSPatrick Mooney 	priv->bbuflen = 0;
312154972afSPatrick Mooney 
313154972afSPatrick Mooney 	priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
31484659b24SMichael Zeller 	if (priv->mevp == NULL) {
315154972afSPatrick Mooney 		WPRINTF(("Could not register event"));
31684659b24SMichael Zeller 		goto error;
31784659b24SMichael Zeller 	}
31884659b24SMichael Zeller 
31984659b24SMichael Zeller 	return (0);
32084659b24SMichael Zeller 
32184659b24SMichael Zeller error:
32284659b24SMichael Zeller 	tap_cleanup(be);
32384659b24SMichael Zeller 	return (-1);
32484659b24SMichael Zeller }
32584659b24SMichael Zeller 
32684659b24SMichael Zeller /*
32784659b24SMichael Zeller  * Called to send a buffer chain out to the tap device
32884659b24SMichael Zeller  */
32984659b24SMichael Zeller static ssize_t
tap_send(struct net_backend * be,const struct iovec * iov,int iovcnt)330154972afSPatrick Mooney tap_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
33184659b24SMichael Zeller {
33284659b24SMichael Zeller 	return (writev(be->fd, iov, iovcnt));
33384659b24SMichael Zeller }
33484659b24SMichael Zeller 
33584659b24SMichael Zeller static ssize_t
tap_peek_recvlen(struct net_backend * be)336154972afSPatrick Mooney tap_peek_recvlen(struct net_backend *be)
33784659b24SMichael Zeller {
33859d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
33984659b24SMichael Zeller 	ssize_t ret;
34084659b24SMichael Zeller 
341154972afSPatrick Mooney 	if (priv->bbuflen > 0) {
342154972afSPatrick Mooney 		/*
343154972afSPatrick Mooney 		 * We already have a packet in the bounce buffer.
344154972afSPatrick Mooney 		 * Just return its length.
345154972afSPatrick Mooney 		 */
346154972afSPatrick Mooney 		return priv->bbuflen;
347154972afSPatrick Mooney 	}
34884659b24SMichael Zeller 
349154972afSPatrick Mooney 	/*
350154972afSPatrick Mooney 	 * Read the next packet (if any) into the bounce buffer, so
351154972afSPatrick Mooney 	 * that we get to know its length and we can return that
352154972afSPatrick Mooney 	 * to the caller.
353154972afSPatrick Mooney 	 */
354154972afSPatrick Mooney 	ret = read(be->fd, priv->bbuf, sizeof(priv->bbuf));
355154972afSPatrick Mooney 	if (ret < 0 && errno == EWOULDBLOCK) {
356154972afSPatrick Mooney 		return (0);
357154972afSPatrick Mooney 	}
358154972afSPatrick Mooney 
359154972afSPatrick Mooney 	if (ret > 0)
360154972afSPatrick Mooney 		priv->bbuflen = ret;
361154972afSPatrick Mooney 
362154972afSPatrick Mooney 	return (ret);
363154972afSPatrick Mooney }
364154972afSPatrick Mooney 
365154972afSPatrick Mooney static ssize_t
tap_recv(struct net_backend * be,const struct iovec * iov,int iovcnt)366154972afSPatrick Mooney tap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
367154972afSPatrick Mooney {
36859d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
369154972afSPatrick Mooney 	ssize_t ret;
370154972afSPatrick Mooney 
371154972afSPatrick Mooney 	if (priv->bbuflen > 0) {
372154972afSPatrick Mooney 		/*
373154972afSPatrick Mooney 		 * A packet is available in the bounce buffer, so
374154972afSPatrick Mooney 		 * we read it from there.
375154972afSPatrick Mooney 		 */
376154972afSPatrick Mooney 		ret = buf_to_iov(priv->bbuf, priv->bbuflen,
377154972afSPatrick Mooney 		    iov, iovcnt, 0);
378154972afSPatrick Mooney 
379154972afSPatrick Mooney 		/* Mark the bounce buffer as empty. */
380154972afSPatrick Mooney 		priv->bbuflen = 0;
381154972afSPatrick Mooney 
382154972afSPatrick Mooney 		return (ret);
383154972afSPatrick Mooney 	}
38484659b24SMichael Zeller 
385154972afSPatrick Mooney 	ret = readv(be->fd, iov, iovcnt);
38684659b24SMichael Zeller 	if (ret < 0 && errno == EWOULDBLOCK) {
38784659b24SMichael Zeller 		return (0);
38884659b24SMichael Zeller 	}
38984659b24SMichael Zeller 
39084659b24SMichael Zeller 	return (ret);
39184659b24SMichael Zeller }
39284659b24SMichael Zeller 
393154972afSPatrick Mooney static void
tap_recv_enable(struct net_backend * be)394154972afSPatrick Mooney tap_recv_enable(struct net_backend *be)
395154972afSPatrick Mooney {
39659d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
397154972afSPatrick Mooney 
398154972afSPatrick Mooney 	mevent_enable(priv->mevp);
399154972afSPatrick Mooney }
400154972afSPatrick Mooney 
401154972afSPatrick Mooney static void
tap_recv_disable(struct net_backend * be)402154972afSPatrick Mooney tap_recv_disable(struct net_backend *be)
403154972afSPatrick Mooney {
40459d65d31SAndy Fiddaman 	struct tap_priv *priv = NET_BE_PRIV(be);
405154972afSPatrick Mooney 
406154972afSPatrick Mooney 	mevent_disable(priv->mevp);
407154972afSPatrick Mooney }
408154972afSPatrick Mooney 
40984659b24SMichael Zeller static uint64_t
tap_get_cap(struct net_backend * be __unused)41059d65d31SAndy Fiddaman tap_get_cap(struct net_backend *be __unused)
41184659b24SMichael Zeller {
41284659b24SMichael Zeller 
41384659b24SMichael Zeller 	return (0); /* no capabilities for now */
41484659b24SMichael Zeller }
41584659b24SMichael Zeller 
41684659b24SMichael Zeller static int
tap_set_cap(struct net_backend * be __unused,uint64_t features,unsigned vnet_hdr_len)41759d65d31SAndy Fiddaman tap_set_cap(struct net_backend *be __unused, uint64_t features,
41859d65d31SAndy Fiddaman     unsigned vnet_hdr_len)
41984659b24SMichael Zeller {
42084659b24SMichael Zeller 
42184659b24SMichael Zeller 	return ((features || vnet_hdr_len) ? -1 : 0);
42284659b24SMichael Zeller }
42384659b24SMichael Zeller 
42484659b24SMichael Zeller static struct net_backend tap_backend = {
42584659b24SMichael Zeller 	.prefix = "tap",
42684659b24SMichael Zeller 	.priv_size = sizeof(struct tap_priv),
42784659b24SMichael Zeller 	.init = tap_init,
42884659b24SMichael Zeller 	.cleanup = tap_cleanup,
42984659b24SMichael Zeller 	.send = tap_send,
430154972afSPatrick Mooney 	.peek_recvlen = tap_peek_recvlen,
43184659b24SMichael Zeller 	.recv = tap_recv,
432154972afSPatrick Mooney 	.recv_enable = tap_recv_enable,
433154972afSPatrick Mooney 	.recv_disable = tap_recv_disable,
43484659b24SMichael Zeller 	.get_cap = tap_get_cap,
43584659b24SMichael Zeller 	.set_cap = tap_set_cap,
43684659b24SMichael Zeller };
43784659b24SMichael Zeller 
43884659b24SMichael Zeller /* A clone of the tap backend, with a different prefix. */
43984659b24SMichael Zeller static struct net_backend vmnet_backend = {
44084659b24SMichael Zeller 	.prefix = "vmnet",
44184659b24SMichael Zeller 	.priv_size = sizeof(struct tap_priv),
44284659b24SMichael Zeller 	.init = tap_init,
44384659b24SMichael Zeller 	.cleanup = tap_cleanup,
44484659b24SMichael Zeller 	.send = tap_send,
445154972afSPatrick Mooney 	.peek_recvlen = tap_peek_recvlen,
44684659b24SMichael Zeller 	.recv = tap_recv,
447154972afSPatrick Mooney 	.recv_enable = tap_recv_enable,
448154972afSPatrick Mooney 	.recv_disable = tap_recv_disable,
44984659b24SMichael Zeller 	.get_cap = tap_get_cap,
45084659b24SMichael Zeller 	.set_cap = tap_set_cap,
45184659b24SMichael Zeller };
45284659b24SMichael Zeller 
45384659b24SMichael Zeller DATA_SET(net_backend_set, tap_backend);
45484659b24SMichael Zeller DATA_SET(net_backend_set, vmnet_backend);
45584659b24SMichael Zeller 
456154972afSPatrick Mooney #ifdef NETGRAPH
457154972afSPatrick Mooney 
458154972afSPatrick Mooney /*
459154972afSPatrick Mooney  * Netgraph backend
460154972afSPatrick Mooney  */
461154972afSPatrick Mooney 
462154972afSPatrick Mooney #define NG_SBUF_MAX_SIZE (4 * 1024 * 1024)
463154972afSPatrick Mooney 
464154972afSPatrick Mooney static int
ng_init(struct net_backend * be,const char * devname __unused,nvlist_t * nvl,net_be_rxeof_t cb,void * param)46559d65d31SAndy Fiddaman ng_init(struct net_backend *be, const char *devname __unused,
4662b948146SAndy Fiddaman 	 nvlist_t *nvl, net_be_rxeof_t cb, void *param)
467154972afSPatrick Mooney {
46859d65d31SAndy Fiddaman 	struct tap_priv *p = NET_BE_PRIV(be);
469154972afSPatrick Mooney 	struct ngm_connect ngc;
4702b948146SAndy Fiddaman 	const char *value, *nodename;
471154972afSPatrick Mooney 	int sbsz;
472154972afSPatrick Mooney 	int ctrl_sock;
473154972afSPatrick Mooney 	int flags;
474154972afSPatrick Mooney 	unsigned long maxsbsz;
475154972afSPatrick Mooney 	size_t msbsz;
476154972afSPatrick Mooney #ifndef WITHOUT_CAPSICUM
477154972afSPatrick Mooney 	cap_rights_t rights;
478154972afSPatrick Mooney #endif
479154972afSPatrick Mooney 
480154972afSPatrick Mooney 	if (cb == NULL) {
481154972afSPatrick Mooney 		WPRINTF(("Netgraph backend requires non-NULL callback"));
482154972afSPatrick Mooney 		return (-1);
483154972afSPatrick Mooney 	}
484154972afSPatrick Mooney 
485154972afSPatrick Mooney 	be->fd = -1;
486154972afSPatrick Mooney 
487154972afSPatrick Mooney 	memset(&ngc, 0, sizeof(ngc));
488154972afSPatrick Mooney 
4892b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "path");
4902b948146SAndy Fiddaman 	if (value == NULL) {
491154972afSPatrick Mooney 		WPRINTF(("path must be provided"));
492154972afSPatrick Mooney 		return (-1);
493154972afSPatrick Mooney 	}
4942b948146SAndy Fiddaman 	strncpy(ngc.path, value, NG_PATHSIZ - 1);
495154972afSPatrick Mooney 
4962b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "hook");
4972b948146SAndy Fiddaman 	if (value == NULL)
4982b948146SAndy Fiddaman 		value = "vmlink";
4992b948146SAndy Fiddaman 	strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1);
5002b948146SAndy Fiddaman 
5012b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "peerhook");
5022b948146SAndy Fiddaman 	if (value == NULL) {
503154972afSPatrick Mooney 		WPRINTF(("peer hook must be provided"));
504154972afSPatrick Mooney 		return (-1);
505154972afSPatrick Mooney 	}
5062b948146SAndy Fiddaman 	strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1);
507154972afSPatrick Mooney 
5082b948146SAndy Fiddaman 	nodename = get_config_value_node(nvl, "socket");
5092b948146SAndy Fiddaman 	if (NgMkSockNode(nodename,
510154972afSPatrick Mooney 		&ctrl_sock, &be->fd) < 0) {
511154972afSPatrick Mooney 		WPRINTF(("can't get Netgraph sockets"));
512154972afSPatrick Mooney 		return (-1);
513154972afSPatrick Mooney 	}
514154972afSPatrick Mooney 
515154972afSPatrick Mooney 	if (NgSendMsg(ctrl_sock, ".",
516154972afSPatrick Mooney 		NGM_GENERIC_COOKIE,
517154972afSPatrick Mooney 		NGM_CONNECT, &ngc, sizeof(ngc)) < 0) {
518154972afSPatrick Mooney 		WPRINTF(("can't connect to node"));
519154972afSPatrick Mooney 		close(ctrl_sock);
520154972afSPatrick Mooney 		goto error;
521154972afSPatrick Mooney 	}
522154972afSPatrick Mooney 
523154972afSPatrick Mooney 	close(ctrl_sock);
524154972afSPatrick Mooney 
525154972afSPatrick Mooney 	flags = fcntl(be->fd, F_GETFL);
526154972afSPatrick Mooney 
527154972afSPatrick Mooney 	if (flags < 0) {
528154972afSPatrick Mooney 		WPRINTF(("can't get socket flags"));
529154972afSPatrick Mooney 		goto error;
530154972afSPatrick Mooney 	}
531154972afSPatrick Mooney 
532154972afSPatrick Mooney 	if (fcntl(be->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
533154972afSPatrick Mooney 		WPRINTF(("can't set O_NONBLOCK flag"));
534154972afSPatrick Mooney 		goto error;
535154972afSPatrick Mooney 	}
536154972afSPatrick Mooney 
537154972afSPatrick Mooney 	/*
538154972afSPatrick Mooney 	 * The default ng_socket(4) buffer's size is too low.
539154972afSPatrick Mooney 	 * Calculate the minimum value between NG_SBUF_MAX_SIZE
5406dc98349SAndy Fiddaman 	 * and kern.ipc.maxsockbuf.
541154972afSPatrick Mooney 	 */
542154972afSPatrick Mooney 	msbsz = sizeof(maxsbsz);
543154972afSPatrick Mooney 	if (sysctlbyname("kern.ipc.maxsockbuf", &maxsbsz, &msbsz,
544154972afSPatrick Mooney 		NULL, 0) < 0) {
545154972afSPatrick Mooney 		WPRINTF(("can't get 'kern.ipc.maxsockbuf' value"));
546154972afSPatrick Mooney 		goto error;
547154972afSPatrick Mooney 	}
548154972afSPatrick Mooney 
549154972afSPatrick Mooney 	/*
550154972afSPatrick Mooney 	 * We can't set the socket buffer size to kern.ipc.maxsockbuf value,
551154972afSPatrick Mooney 	 * as it takes into account the mbuf(9) overhead.
552154972afSPatrick Mooney 	 */
553154972afSPatrick Mooney 	maxsbsz = maxsbsz * MCLBYTES / (MSIZE + MCLBYTES);
554154972afSPatrick Mooney 
555154972afSPatrick Mooney 	sbsz = MIN(NG_SBUF_MAX_SIZE, maxsbsz);
556154972afSPatrick Mooney 
557154972afSPatrick Mooney 	if (setsockopt(be->fd, SOL_SOCKET, SO_SNDBUF, &sbsz,
558154972afSPatrick Mooney 		sizeof(sbsz)) < 0) {
559154972afSPatrick Mooney 		WPRINTF(("can't set TX buffer size"));
560154972afSPatrick Mooney 		goto error;
561154972afSPatrick Mooney 	}
562154972afSPatrick Mooney 
563154972afSPatrick Mooney 	if (setsockopt(be->fd, SOL_SOCKET, SO_RCVBUF, &sbsz,
564154972afSPatrick Mooney 		sizeof(sbsz)) < 0) {
565154972afSPatrick Mooney 		WPRINTF(("can't set RX buffer size"));
566154972afSPatrick Mooney 		goto error;
567154972afSPatrick Mooney 	}
568154972afSPatrick Mooney 
569154972afSPatrick Mooney #ifndef WITHOUT_CAPSICUM
570154972afSPatrick Mooney 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
571154972afSPatrick Mooney 	if (caph_rights_limit(be->fd, &rights) == -1)
572154972afSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
573154972afSPatrick Mooney #endif
574154972afSPatrick Mooney 
575154972afSPatrick Mooney 	memset(p->bbuf, 0, sizeof(p->bbuf));
576154972afSPatrick Mooney 	p->bbuflen = 0;
577154972afSPatrick Mooney 
578154972afSPatrick Mooney 	p->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
579154972afSPatrick Mooney 	if (p->mevp == NULL) {
580154972afSPatrick Mooney 		WPRINTF(("Could not register event"));
581154972afSPatrick Mooney 		goto error;
582154972afSPatrick Mooney 	}
583154972afSPatrick Mooney 
584154972afSPatrick Mooney 	return (0);
585154972afSPatrick Mooney 
586154972afSPatrick Mooney error:
587154972afSPatrick Mooney 	tap_cleanup(be);
588154972afSPatrick Mooney 	return (-1);
589154972afSPatrick Mooney }
590154972afSPatrick Mooney 
591154972afSPatrick Mooney static struct net_backend ng_backend = {
592154972afSPatrick Mooney 	.prefix = "netgraph",
593154972afSPatrick Mooney 	.priv_size = sizeof(struct tap_priv),
594154972afSPatrick Mooney 	.init = ng_init,
595154972afSPatrick Mooney 	.cleanup = tap_cleanup,
596154972afSPatrick Mooney 	.send = tap_send,
597154972afSPatrick Mooney 	.peek_recvlen = tap_peek_recvlen,
598154972afSPatrick Mooney 	.recv = tap_recv,
599154972afSPatrick Mooney 	.recv_enable = tap_recv_enable,
600154972afSPatrick Mooney 	.recv_disable = tap_recv_disable,
601154972afSPatrick Mooney 	.get_cap = tap_get_cap,
602154972afSPatrick Mooney 	.set_cap = tap_set_cap,
603154972afSPatrick Mooney };
604154972afSPatrick Mooney 
605154972afSPatrick Mooney DATA_SET(net_backend_set, ng_backend);
606154972afSPatrick Mooney 
607154972afSPatrick Mooney #endif /* NETGRAPH */
608154972afSPatrick Mooney 
60984659b24SMichael Zeller /*
61084659b24SMichael Zeller  * The netmap backend
61184659b24SMichael Zeller  */
61284659b24SMichael Zeller 
61384659b24SMichael Zeller /* The virtio-net features supported by netmap. */
61484659b24SMichael Zeller #define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \
61584659b24SMichael Zeller 		VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \
61684659b24SMichael Zeller 		VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \
61784659b24SMichael Zeller 		VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO)
61884659b24SMichael Zeller 
61984659b24SMichael Zeller struct netmap_priv {
62084659b24SMichael Zeller 	char ifname[IFNAMSIZ];
62184659b24SMichael Zeller 	struct nm_desc *nmd;
62284659b24SMichael Zeller 	uint16_t memid;
62384659b24SMichael Zeller 	struct netmap_ring *rx;
62484659b24SMichael Zeller 	struct netmap_ring *tx;
62584659b24SMichael Zeller 	struct mevent *mevp;
62684659b24SMichael Zeller 	net_be_rxeof_t cb;
62784659b24SMichael Zeller 	void *cb_param;
62884659b24SMichael Zeller };
62984659b24SMichael Zeller 
63084659b24SMichael Zeller static void
nmreq_init(struct nmreq * req,char * ifname)63184659b24SMichael Zeller nmreq_init(struct nmreq *req, char *ifname)
63284659b24SMichael Zeller {
63384659b24SMichael Zeller 
63484659b24SMichael Zeller 	memset(req, 0, sizeof(*req));
63584659b24SMichael Zeller 	strlcpy(req->nr_name, ifname, sizeof(req->nr_name));
63684659b24SMichael Zeller 	req->nr_version = NETMAP_API;
63784659b24SMichael Zeller }
63884659b24SMichael Zeller 
63984659b24SMichael Zeller static int
netmap_set_vnet_hdr_len(struct net_backend * be,int vnet_hdr_len)64084659b24SMichael Zeller netmap_set_vnet_hdr_len(struct net_backend *be, int vnet_hdr_len)
64184659b24SMichael Zeller {
64284659b24SMichael Zeller 	int err;
64384659b24SMichael Zeller 	struct nmreq req;
64459d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
64584659b24SMichael Zeller 
64684659b24SMichael Zeller 	nmreq_init(&req, priv->ifname);
64784659b24SMichael Zeller 	req.nr_cmd = NETMAP_BDG_VNET_HDR;
64884659b24SMichael Zeller 	req.nr_arg1 = vnet_hdr_len;
64984659b24SMichael Zeller 	err = ioctl(be->fd, NIOCREGIF, &req);
65084659b24SMichael Zeller 	if (err) {
651154972afSPatrick Mooney 		WPRINTF(("Unable to set vnet header length %d",
65284659b24SMichael Zeller 				vnet_hdr_len));
65384659b24SMichael Zeller 		return (err);
65484659b24SMichael Zeller 	}
65584659b24SMichael Zeller 
65684659b24SMichael Zeller 	be->be_vnet_hdr_len = vnet_hdr_len;
65784659b24SMichael Zeller 
65884659b24SMichael Zeller 	return (0);
65984659b24SMichael Zeller }
66084659b24SMichael Zeller 
66184659b24SMichael Zeller static int
netmap_has_vnet_hdr_len(struct net_backend * be,unsigned vnet_hdr_len)66284659b24SMichael Zeller netmap_has_vnet_hdr_len(struct net_backend *be, unsigned vnet_hdr_len)
66384659b24SMichael Zeller {
66459d65d31SAndy Fiddaman 	unsigned prev_hdr_len = be->be_vnet_hdr_len;
66584659b24SMichael Zeller 	int ret;
66684659b24SMichael Zeller 
66784659b24SMichael Zeller 	if (vnet_hdr_len == prev_hdr_len) {
66884659b24SMichael Zeller 		return (1);
66984659b24SMichael Zeller 	}
67084659b24SMichael Zeller 
67184659b24SMichael Zeller 	ret = netmap_set_vnet_hdr_len(be, vnet_hdr_len);
67284659b24SMichael Zeller 	if (ret) {
67384659b24SMichael Zeller 		return (0);
67484659b24SMichael Zeller 	}
67584659b24SMichael Zeller 
67684659b24SMichael Zeller 	netmap_set_vnet_hdr_len(be, prev_hdr_len);
67784659b24SMichael Zeller 
67884659b24SMichael Zeller 	return (1);
67984659b24SMichael Zeller }
68084659b24SMichael Zeller 
68184659b24SMichael Zeller static uint64_t
netmap_get_cap(struct net_backend * be)68284659b24SMichael Zeller netmap_get_cap(struct net_backend *be)
68384659b24SMichael Zeller {
68484659b24SMichael Zeller 
68584659b24SMichael Zeller 	return (netmap_has_vnet_hdr_len(be, VNET_HDR_LEN) ?
68684659b24SMichael Zeller 	    NETMAP_FEATURES : 0);
68784659b24SMichael Zeller }
68884659b24SMichael Zeller 
68984659b24SMichael Zeller static int
netmap_set_cap(struct net_backend * be,uint64_t features __unused,unsigned vnet_hdr_len)69059d65d31SAndy Fiddaman netmap_set_cap(struct net_backend *be, uint64_t features __unused,
69159d65d31SAndy Fiddaman     unsigned vnet_hdr_len)
69284659b24SMichael Zeller {
69384659b24SMichael Zeller 
69484659b24SMichael Zeller 	return (netmap_set_vnet_hdr_len(be, vnet_hdr_len));
69584659b24SMichael Zeller }
69684659b24SMichael Zeller 
69784659b24SMichael Zeller static int
netmap_init(struct net_backend * be,const char * devname,nvlist_t * nvl __unused,net_be_rxeof_t cb,void * param)69884659b24SMichael Zeller netmap_init(struct net_backend *be, const char *devname,
69959d65d31SAndy Fiddaman     nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
70084659b24SMichael Zeller {
70159d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
70284659b24SMichael Zeller 
70384659b24SMichael Zeller 	strlcpy(priv->ifname, devname, sizeof(priv->ifname));
70484659b24SMichael Zeller 	priv->ifname[sizeof(priv->ifname) - 1] = '\0';
70584659b24SMichael Zeller 
70684659b24SMichael Zeller 	priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL);
70784659b24SMichael Zeller 	if (priv->nmd == NULL) {
708154972afSPatrick Mooney 		WPRINTF(("Unable to nm_open(): interface '%s', errno (%s)",
70984659b24SMichael Zeller 			devname, strerror(errno)));
71084659b24SMichael Zeller 		return (-1);
71184659b24SMichael Zeller 	}
71284659b24SMichael Zeller 
71384659b24SMichael Zeller 	priv->memid = priv->nmd->req.nr_arg2;
71484659b24SMichael Zeller 	priv->tx = NETMAP_TXRING(priv->nmd->nifp, 0);
71584659b24SMichael Zeller 	priv->rx = NETMAP_RXRING(priv->nmd->nifp, 0);
71684659b24SMichael Zeller 	priv->cb = cb;
71784659b24SMichael Zeller 	priv->cb_param = param;
71884659b24SMichael Zeller 	be->fd = priv->nmd->fd;
71984659b24SMichael Zeller 
720154972afSPatrick Mooney 	priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
72184659b24SMichael Zeller 	if (priv->mevp == NULL) {
722154972afSPatrick Mooney 		WPRINTF(("Could not register event"));
72384659b24SMichael Zeller 		return (-1);
72484659b24SMichael Zeller 	}
72584659b24SMichael Zeller 
72684659b24SMichael Zeller 	return (0);
72784659b24SMichael Zeller }
72884659b24SMichael Zeller 
72984659b24SMichael Zeller static void
netmap_cleanup(struct net_backend * be)73084659b24SMichael Zeller netmap_cleanup(struct net_backend *be)
73184659b24SMichael Zeller {
73259d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
73384659b24SMichael Zeller 
73484659b24SMichael Zeller 	if (priv->mevp) {
73584659b24SMichael Zeller 		mevent_delete(priv->mevp);
73684659b24SMichael Zeller 	}
73784659b24SMichael Zeller 	if (priv->nmd) {
73884659b24SMichael Zeller 		nm_close(priv->nmd);
73984659b24SMichael Zeller 	}
74084659b24SMichael Zeller 	be->fd = -1;
74184659b24SMichael Zeller }
74284659b24SMichael Zeller 
74384659b24SMichael Zeller static ssize_t
netmap_send(struct net_backend * be,const struct iovec * iov,int iovcnt)744154972afSPatrick Mooney netmap_send(struct net_backend *be, const struct iovec *iov,
74584659b24SMichael Zeller 	    int iovcnt)
74684659b24SMichael Zeller {
74759d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
74884659b24SMichael Zeller 	struct netmap_ring *ring;
74984659b24SMichael Zeller 	ssize_t totlen = 0;
75084659b24SMichael Zeller 	int nm_buf_size;
75184659b24SMichael Zeller 	int nm_buf_len;
75284659b24SMichael Zeller 	uint32_t head;
75359d65d31SAndy Fiddaman 	uint8_t *nm_buf;
75484659b24SMichael Zeller 	int j;
75584659b24SMichael Zeller 
75684659b24SMichael Zeller 	ring = priv->tx;
75784659b24SMichael Zeller 	head = ring->head;
75884659b24SMichael Zeller 	if (head == ring->tail) {
759154972afSPatrick Mooney 		WPRINTF(("No space, drop %zu bytes", count_iov(iov, iovcnt)));
76084659b24SMichael Zeller 		goto txsync;
76184659b24SMichael Zeller 	}
76284659b24SMichael Zeller 	nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
76384659b24SMichael Zeller 	nm_buf_size = ring->nr_buf_size;
76484659b24SMichael Zeller 	nm_buf_len = 0;
76584659b24SMichael Zeller 
76684659b24SMichael Zeller 	for (j = 0; j < iovcnt; j++) {
76759d65d31SAndy Fiddaman 		uint8_t *iov_frag_buf = iov[j].iov_base;
76884659b24SMichael Zeller 		int iov_frag_size = iov[j].iov_len;
76984659b24SMichael Zeller 
77084659b24SMichael Zeller 		totlen += iov_frag_size;
77184659b24SMichael Zeller 
77284659b24SMichael Zeller 		/*
77384659b24SMichael Zeller 		 * Split each iovec fragment over more netmap slots, if
77484659b24SMichael Zeller 		 * necessary.
77584659b24SMichael Zeller 		 */
77684659b24SMichael Zeller 		for (;;) {
77784659b24SMichael Zeller 			int copylen;
77884659b24SMichael Zeller 
77984659b24SMichael Zeller 			copylen = iov_frag_size < nm_buf_size ? iov_frag_size : nm_buf_size;
78084659b24SMichael Zeller 			memcpy(nm_buf, iov_frag_buf, copylen);
78184659b24SMichael Zeller 
78284659b24SMichael Zeller 			iov_frag_buf += copylen;
78384659b24SMichael Zeller 			iov_frag_size -= copylen;
78484659b24SMichael Zeller 			nm_buf += copylen;
78584659b24SMichael Zeller 			nm_buf_size -= copylen;
78684659b24SMichael Zeller 			nm_buf_len += copylen;
78784659b24SMichael Zeller 
78884659b24SMichael Zeller 			if (iov_frag_size == 0) {
78984659b24SMichael Zeller 				break;
79084659b24SMichael Zeller 			}
79184659b24SMichael Zeller 
79284659b24SMichael Zeller 			ring->slot[head].len = nm_buf_len;
79384659b24SMichael Zeller 			ring->slot[head].flags = NS_MOREFRAG;
79484659b24SMichael Zeller 			head = nm_ring_next(ring, head);
79584659b24SMichael Zeller 			if (head == ring->tail) {
79684659b24SMichael Zeller 				/*
79784659b24SMichael Zeller 				 * We ran out of netmap slots while
79884659b24SMichael Zeller 				 * splitting the iovec fragments.
79984659b24SMichael Zeller 				 */
800154972afSPatrick Mooney 				WPRINTF(("No space, drop %zu bytes",
80184659b24SMichael Zeller 				   count_iov(iov, iovcnt)));
80284659b24SMichael Zeller 				goto txsync;
80384659b24SMichael Zeller 			}
80484659b24SMichael Zeller 			nm_buf = NETMAP_BUF(ring, ring->slot[head].buf_idx);
80584659b24SMichael Zeller 			nm_buf_size = ring->nr_buf_size;
80684659b24SMichael Zeller 			nm_buf_len = 0;
80784659b24SMichael Zeller 		}
80884659b24SMichael Zeller 	}
80984659b24SMichael Zeller 
81084659b24SMichael Zeller 	/* Complete the last slot, which must not have NS_MOREFRAG set. */
81184659b24SMichael Zeller 	ring->slot[head].len = nm_buf_len;
81284659b24SMichael Zeller 	ring->slot[head].flags = 0;
81384659b24SMichael Zeller 	head = nm_ring_next(ring, head);
81484659b24SMichael Zeller 
81584659b24SMichael Zeller 	/* Now update ring->head and ring->cur. */
81684659b24SMichael Zeller 	ring->head = ring->cur = head;
81784659b24SMichael Zeller txsync:
81884659b24SMichael Zeller 	ioctl(be->fd, NIOCTXSYNC, NULL);
81984659b24SMichael Zeller 
82084659b24SMichael Zeller 	return (totlen);
82184659b24SMichael Zeller }
82284659b24SMichael Zeller 
82384659b24SMichael Zeller static ssize_t
netmap_peek_recvlen(struct net_backend * be)824154972afSPatrick Mooney netmap_peek_recvlen(struct net_backend *be)
825154972afSPatrick Mooney {
82659d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
827154972afSPatrick Mooney 	struct netmap_ring *ring = priv->rx;
828154972afSPatrick Mooney 	uint32_t head = ring->head;
829154972afSPatrick Mooney 	ssize_t totlen = 0;
830154972afSPatrick Mooney 
831154972afSPatrick Mooney 	while (head != ring->tail) {
832154972afSPatrick Mooney 		struct netmap_slot *slot = ring->slot + head;
833154972afSPatrick Mooney 
834154972afSPatrick Mooney 		totlen += slot->len;
835154972afSPatrick Mooney 		if ((slot->flags & NS_MOREFRAG) == 0)
836154972afSPatrick Mooney 			break;
837154972afSPatrick Mooney 		head = nm_ring_next(ring, head);
838154972afSPatrick Mooney 	}
839154972afSPatrick Mooney 
840154972afSPatrick Mooney 	return (totlen);
841154972afSPatrick Mooney }
842154972afSPatrick Mooney 
843154972afSPatrick Mooney static ssize_t
netmap_recv(struct net_backend * be,const struct iovec * iov,int iovcnt)844154972afSPatrick Mooney netmap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
84584659b24SMichael Zeller {
84659d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
84784659b24SMichael Zeller 	struct netmap_slot *slot = NULL;
84884659b24SMichael Zeller 	struct netmap_ring *ring;
84959d65d31SAndy Fiddaman 	uint8_t *iov_frag_buf;
85084659b24SMichael Zeller 	int iov_frag_size;
85184659b24SMichael Zeller 	ssize_t totlen = 0;
85284659b24SMichael Zeller 	uint32_t head;
85384659b24SMichael Zeller 
85484659b24SMichael Zeller 	assert(iovcnt);
85584659b24SMichael Zeller 
85684659b24SMichael Zeller 	ring = priv->rx;
85784659b24SMichael Zeller 	head = ring->head;
85884659b24SMichael Zeller 	iov_frag_buf = iov->iov_base;
85984659b24SMichael Zeller 	iov_frag_size = iov->iov_len;
86084659b24SMichael Zeller 
86184659b24SMichael Zeller 	do {
86259d65d31SAndy Fiddaman 		uint8_t *nm_buf;
86384659b24SMichael Zeller 		int nm_buf_len;
86484659b24SMichael Zeller 
86584659b24SMichael Zeller 		if (head == ring->tail) {
86684659b24SMichael Zeller 			return (0);
86784659b24SMichael Zeller 		}
86884659b24SMichael Zeller 
86984659b24SMichael Zeller 		slot = ring->slot + head;
87084659b24SMichael Zeller 		nm_buf = NETMAP_BUF(ring, slot->buf_idx);
87184659b24SMichael Zeller 		nm_buf_len = slot->len;
87284659b24SMichael Zeller 
87384659b24SMichael Zeller 		for (;;) {
87484659b24SMichael Zeller 			int copylen = nm_buf_len < iov_frag_size ?
87584659b24SMichael Zeller 			    nm_buf_len : iov_frag_size;
87684659b24SMichael Zeller 
87784659b24SMichael Zeller 			memcpy(iov_frag_buf, nm_buf, copylen);
87884659b24SMichael Zeller 			nm_buf += copylen;
87984659b24SMichael Zeller 			nm_buf_len -= copylen;
88084659b24SMichael Zeller 			iov_frag_buf += copylen;
88184659b24SMichael Zeller 			iov_frag_size -= copylen;
88284659b24SMichael Zeller 			totlen += copylen;
88384659b24SMichael Zeller 
88484659b24SMichael Zeller 			if (nm_buf_len == 0) {
88584659b24SMichael Zeller 				break;
88684659b24SMichael Zeller 			}
88784659b24SMichael Zeller 
88884659b24SMichael Zeller 			iov++;
88984659b24SMichael Zeller 			iovcnt--;
89084659b24SMichael Zeller 			if (iovcnt == 0) {
89184659b24SMichael Zeller 				/* No space to receive. */
892154972afSPatrick Mooney 				WPRINTF(("Short iov, drop %zd bytes",
89384659b24SMichael Zeller 				    totlen));
89484659b24SMichael Zeller 				return (-ENOSPC);
89584659b24SMichael Zeller 			}
89684659b24SMichael Zeller 			iov_frag_buf = iov->iov_base;
89784659b24SMichael Zeller 			iov_frag_size = iov->iov_len;
89884659b24SMichael Zeller 		}
89984659b24SMichael Zeller 
90084659b24SMichael Zeller 		head = nm_ring_next(ring, head);
90184659b24SMichael Zeller 
90284659b24SMichael Zeller 	} while (slot->flags & NS_MOREFRAG);
90384659b24SMichael Zeller 
90484659b24SMichael Zeller 	/* Release slots to netmap. */
90584659b24SMichael Zeller 	ring->head = ring->cur = head;
90684659b24SMichael Zeller 
90784659b24SMichael Zeller 	return (totlen);
90884659b24SMichael Zeller }
90984659b24SMichael Zeller 
910154972afSPatrick Mooney static void
netmap_recv_enable(struct net_backend * be)911154972afSPatrick Mooney netmap_recv_enable(struct net_backend *be)
912154972afSPatrick Mooney {
91359d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
914154972afSPatrick Mooney 
915154972afSPatrick Mooney 	mevent_enable(priv->mevp);
916154972afSPatrick Mooney }
917154972afSPatrick Mooney 
918154972afSPatrick Mooney static void
netmap_recv_disable(struct net_backend * be)919154972afSPatrick Mooney netmap_recv_disable(struct net_backend *be)
920154972afSPatrick Mooney {
92159d65d31SAndy Fiddaman 	struct netmap_priv *priv = NET_BE_PRIV(be);
922154972afSPatrick Mooney 
923154972afSPatrick Mooney 	mevent_disable(priv->mevp);
924154972afSPatrick Mooney }
925154972afSPatrick Mooney 
92684659b24SMichael Zeller static struct net_backend netmap_backend = {
92784659b24SMichael Zeller 	.prefix = "netmap",
92884659b24SMichael Zeller 	.priv_size = sizeof(struct netmap_priv),
92984659b24SMichael Zeller 	.init = netmap_init,
93084659b24SMichael Zeller 	.cleanup = netmap_cleanup,
93184659b24SMichael Zeller 	.send = netmap_send,
932154972afSPatrick Mooney 	.peek_recvlen = netmap_peek_recvlen,
93384659b24SMichael Zeller 	.recv = netmap_recv,
934154972afSPatrick Mooney 	.recv_enable = netmap_recv_enable,
935154972afSPatrick Mooney 	.recv_disable = netmap_recv_disable,
93684659b24SMichael Zeller 	.get_cap = netmap_get_cap,
93784659b24SMichael Zeller 	.set_cap = netmap_set_cap,
93884659b24SMichael Zeller };
93984659b24SMichael Zeller 
94084659b24SMichael Zeller /* A clone of the netmap backend, with a different prefix. */
94184659b24SMichael Zeller static struct net_backend vale_backend = {
94284659b24SMichael Zeller 	.prefix = "vale",
94384659b24SMichael Zeller 	.priv_size = sizeof(struct netmap_priv),
94484659b24SMichael Zeller 	.init = netmap_init,
94584659b24SMichael Zeller 	.cleanup = netmap_cleanup,
94684659b24SMichael Zeller 	.send = netmap_send,
947154972afSPatrick Mooney 	.peek_recvlen = netmap_peek_recvlen,
94884659b24SMichael Zeller 	.recv = netmap_recv,
949154972afSPatrick Mooney 	.recv_enable = netmap_recv_enable,
950154972afSPatrick Mooney 	.recv_disable = netmap_recv_disable,
95184659b24SMichael Zeller 	.get_cap = netmap_get_cap,
95284659b24SMichael Zeller 	.set_cap = netmap_set_cap,
95384659b24SMichael Zeller };
95484659b24SMichael Zeller 
95584659b24SMichael Zeller DATA_SET(net_backend_set, netmap_backend);
95684659b24SMichael Zeller DATA_SET(net_backend_set, vale_backend);
95784659b24SMichael Zeller 
958069b2ef0SAndy Fiddaman #else /* __FreeBSD__ */
959069b2ef0SAndy Fiddaman 
960069b2ef0SAndy Fiddaman /*
961069b2ef0SAndy Fiddaman  * The illumos dlpi backend
962069b2ef0SAndy Fiddaman  */
963069b2ef0SAndy Fiddaman 
964069b2ef0SAndy Fiddaman /*
965069b2ef0SAndy Fiddaman  * The size of the bounce buffer used to implement the peek callback.
966069b2ef0SAndy Fiddaman  * This value should be big enough to accommodate the largest of all possible
967069b2ef0SAndy Fiddaman  * frontend packet lengths. The value here matches the definition of
968069b2ef0SAndy Fiddaman  * VTNET_MAX_PKT_LEN in pci_virtio_net.c
969069b2ef0SAndy Fiddaman  */
970069b2ef0SAndy Fiddaman #define	DLPI_BBUF_SIZE (65536 + 64)
971069b2ef0SAndy Fiddaman 
972069b2ef0SAndy Fiddaman typedef struct be_dlpi_priv {
973069b2ef0SAndy Fiddaman 	dlpi_handle_t bdp_dhp;
974069b2ef0SAndy Fiddaman 	struct mevent *bdp_mevp;
975069b2ef0SAndy Fiddaman 	/*
976069b2ef0SAndy Fiddaman 	 * A bounce buffer that allows us to implement the peek_recvlen
977069b2ef0SAndy Fiddaman 	 * callback. Each structure is only used by a single thread so
978069b2ef0SAndy Fiddaman 	 * one is enough.
979069b2ef0SAndy Fiddaman 	 */
980069b2ef0SAndy Fiddaman 	uint8_t bdp_bbuf[DLPI_BBUF_SIZE];
981069b2ef0SAndy Fiddaman 	ssize_t bdp_bbuflen;
982069b2ef0SAndy Fiddaman } be_dlpi_priv_t;
983069b2ef0SAndy Fiddaman 
984069b2ef0SAndy Fiddaman static void
be_dlpi_cleanup(net_backend_t * be)985069b2ef0SAndy Fiddaman be_dlpi_cleanup(net_backend_t *be)
986069b2ef0SAndy Fiddaman {
98759d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
988069b2ef0SAndy Fiddaman 
989069b2ef0SAndy Fiddaman 	if (priv->bdp_dhp != NULL)
990069b2ef0SAndy Fiddaman 		dlpi_close(priv->bdp_dhp);
991069b2ef0SAndy Fiddaman 	priv->bdp_dhp = NULL;
992069b2ef0SAndy Fiddaman 
993069b2ef0SAndy Fiddaman 	if (priv->bdp_mevp != NULL)
994069b2ef0SAndy Fiddaman 		mevent_delete(priv->bdp_mevp);
995069b2ef0SAndy Fiddaman 	priv->bdp_mevp = NULL;
996069b2ef0SAndy Fiddaman 
997069b2ef0SAndy Fiddaman 	priv->bdp_bbuflen = 0;
998069b2ef0SAndy Fiddaman 	be->fd = -1;
999069b2ef0SAndy Fiddaman }
1000069b2ef0SAndy Fiddaman 
1001069b2ef0SAndy Fiddaman static void
be_dlpi_err(int ret,const char * dev,char * msg)1002069b2ef0SAndy Fiddaman be_dlpi_err(int ret, const char *dev, char *msg)
1003069b2ef0SAndy Fiddaman {
1004069b2ef0SAndy Fiddaman 	WPRINTF(("%s: %s (%s)", dev, msg, dlpi_strerror(ret)));
1005069b2ef0SAndy Fiddaman }
1006069b2ef0SAndy Fiddaman 
1007069b2ef0SAndy Fiddaman static int
be_dlpi_init(net_backend_t * be,const char * devname __unused,nvlist_t * nvl,net_be_rxeof_t cb,void * param)1008069b2ef0SAndy Fiddaman be_dlpi_init(net_backend_t *be, const char *devname __unused,
1009069b2ef0SAndy Fiddaman      nvlist_t *nvl, net_be_rxeof_t cb, void *param)
1010069b2ef0SAndy Fiddaman {
101159d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1012069b2ef0SAndy Fiddaman 	const char *vnic;
1013069b2ef0SAndy Fiddaman 	int ret;
1014069b2ef0SAndy Fiddaman 
1015069b2ef0SAndy Fiddaman 	if (cb == NULL) {
1016069b2ef0SAndy Fiddaman 		WPRINTF(("dlpi backend requires non-NULL callback"));
1017069b2ef0SAndy Fiddaman 		return (-1);
1018069b2ef0SAndy Fiddaman 	}
1019069b2ef0SAndy Fiddaman 
1020069b2ef0SAndy Fiddaman 	vnic = get_config_value_node(nvl, "vnic");
1021069b2ef0SAndy Fiddaman 	if (vnic == NULL) {
1022069b2ef0SAndy Fiddaman 		WPRINTF(("dlpi backend requires a VNIC"));
1023069b2ef0SAndy Fiddaman 		return (-1);
1024069b2ef0SAndy Fiddaman 	}
1025069b2ef0SAndy Fiddaman 
1026069b2ef0SAndy Fiddaman 	priv->bdp_bbuflen = 0;
1027069b2ef0SAndy Fiddaman 
1028069b2ef0SAndy Fiddaman 	ret = dlpi_open(vnic, &priv->bdp_dhp, DLPI_RAW);
1029069b2ef0SAndy Fiddaman 
1030069b2ef0SAndy Fiddaman 	if (ret != DLPI_SUCCESS) {
1031069b2ef0SAndy Fiddaman 		be_dlpi_err(ret, vnic, "open failed");
1032069b2ef0SAndy Fiddaman 		goto error;
1033069b2ef0SAndy Fiddaman 	}
1034069b2ef0SAndy Fiddaman 
1035069b2ef0SAndy Fiddaman 	if ((ret = dlpi_bind(priv->bdp_dhp, DLPI_ANY_SAP, NULL)) !=
1036069b2ef0SAndy Fiddaman 	    DLPI_SUCCESS) {
1037069b2ef0SAndy Fiddaman 		be_dlpi_err(ret, vnic, "bind failed");
1038069b2ef0SAndy Fiddaman 		goto error;
1039069b2ef0SAndy Fiddaman 	}
1040069b2ef0SAndy Fiddaman 
1041069b2ef0SAndy Fiddaman 	if (get_config_bool_node_default(nvl, "promiscrxonly", true)) {
1042069b2ef0SAndy Fiddaman 		if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_RX_ONLY)) !=
1043069b2ef0SAndy Fiddaman 		    DLPI_SUCCESS) {
1044069b2ef0SAndy Fiddaman 			be_dlpi_err(ret, vnic,
1045069b2ef0SAndy Fiddaman 			    "enable promiscuous mode(rxonly) failed");
1046069b2ef0SAndy Fiddaman 			goto error;
1047069b2ef0SAndy Fiddaman 		}
1048069b2ef0SAndy Fiddaman 	}
1049069b2ef0SAndy Fiddaman 	if (get_config_bool_node_default(nvl, "promiscphys", false)) {
1050069b2ef0SAndy Fiddaman 		if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_PHYS)) !=
1051069b2ef0SAndy Fiddaman 		    DLPI_SUCCESS) {
1052069b2ef0SAndy Fiddaman 			be_dlpi_err(ret, vnic,
1053069b2ef0SAndy Fiddaman 			    "enable promiscuous mode(physical) failed");
1054069b2ef0SAndy Fiddaman 			goto error;
1055069b2ef0SAndy Fiddaman 		}
1056069b2ef0SAndy Fiddaman 	}
1057069b2ef0SAndy Fiddaman 	if (get_config_bool_node_default(nvl, "promiscsap", true)) {
1058069b2ef0SAndy Fiddaman 		if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_SAP)) !=
1059069b2ef0SAndy Fiddaman 		    DLPI_SUCCESS) {
1060069b2ef0SAndy Fiddaman 			be_dlpi_err(ret, vnic,
1061069b2ef0SAndy Fiddaman 			    "enable promiscuous mode(SAP) failed");
1062069b2ef0SAndy Fiddaman 			goto error;
1063069b2ef0SAndy Fiddaman 		}
1064069b2ef0SAndy Fiddaman 	}
1065069b2ef0SAndy Fiddaman 	if (get_config_bool_node_default(nvl, "promiscmulti", true)) {
1066069b2ef0SAndy Fiddaman 		if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_MULTI)) !=
1067069b2ef0SAndy Fiddaman 		    DLPI_SUCCESS) {
1068069b2ef0SAndy Fiddaman 			be_dlpi_err(ret, vnic,
1069069b2ef0SAndy Fiddaman 			    "enable promiscuous mode(muticast) failed");
1070069b2ef0SAndy Fiddaman 			goto error;
1071069b2ef0SAndy Fiddaman 		}
1072069b2ef0SAndy Fiddaman 	}
1073069b2ef0SAndy Fiddaman 
1074069b2ef0SAndy Fiddaman         be->fd = dlpi_fd(priv->bdp_dhp);
1075069b2ef0SAndy Fiddaman 
1076069b2ef0SAndy Fiddaman         if (fcntl(be->fd, F_SETFL, O_NONBLOCK) < 0) {
1077069b2ef0SAndy Fiddaman                 WPRINTF(("%s: enable O_NONBLOCK failed", vnic));
1078069b2ef0SAndy Fiddaman 		goto error;
1079069b2ef0SAndy Fiddaman         }
1080069b2ef0SAndy Fiddaman 
1081069b2ef0SAndy Fiddaman 	priv->bdp_mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
1082069b2ef0SAndy Fiddaman 	if (priv->bdp_mevp == NULL) {
1083069b2ef0SAndy Fiddaman 		WPRINTF(("Could not register event"));
1084069b2ef0SAndy Fiddaman 		goto error;
1085069b2ef0SAndy Fiddaman 	}
1086069b2ef0SAndy Fiddaman 
1087069b2ef0SAndy Fiddaman 	return (0);
1088069b2ef0SAndy Fiddaman 
1089069b2ef0SAndy Fiddaman error:
1090069b2ef0SAndy Fiddaman 	be_dlpi_cleanup(be);
1091069b2ef0SAndy Fiddaman 	return (-1);
1092069b2ef0SAndy Fiddaman }
1093069b2ef0SAndy Fiddaman 
1094069b2ef0SAndy Fiddaman /*
1095069b2ef0SAndy Fiddaman  * Called to send a buffer chain out to the dlpi device
1096069b2ef0SAndy Fiddaman  */
1097069b2ef0SAndy Fiddaman static ssize_t
be_dlpi_send(net_backend_t * be,const struct iovec * iov,int iovcnt)1098069b2ef0SAndy Fiddaman be_dlpi_send(net_backend_t *be, const struct iovec *iov, int iovcnt)
1099069b2ef0SAndy Fiddaman {
110059d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1101069b2ef0SAndy Fiddaman 	ssize_t len = 0;
1102069b2ef0SAndy Fiddaman 	int ret;
1103069b2ef0SAndy Fiddaman 
1104069b2ef0SAndy Fiddaman 	if (iovcnt == 1) {
1105069b2ef0SAndy Fiddaman 		len = iov[0].iov_len;
1106069b2ef0SAndy Fiddaman 		ret = dlpi_send(priv->bdp_dhp, NULL, 0, iov[0].iov_base, len,
1107069b2ef0SAndy Fiddaman 		    NULL);
1108069b2ef0SAndy Fiddaman 	} else {
1109069b2ef0SAndy Fiddaman 		void *buf = NULL;
1110069b2ef0SAndy Fiddaman 
1111069b2ef0SAndy Fiddaman 		len = iov_to_buf(iov, iovcnt, &buf);
1112069b2ef0SAndy Fiddaman 
1113069b2ef0SAndy Fiddaman 		if (len <= 0 || buf == NULL)
1114069b2ef0SAndy Fiddaman 			return (-1);
1115069b2ef0SAndy Fiddaman 
1116069b2ef0SAndy Fiddaman 		ret = dlpi_send(priv->bdp_dhp, NULL, 0, buf, len, NULL);
1117069b2ef0SAndy Fiddaman 		free(buf);
1118069b2ef0SAndy Fiddaman 	}
1119069b2ef0SAndy Fiddaman 
1120069b2ef0SAndy Fiddaman 	if (ret != DLPI_SUCCESS)
1121069b2ef0SAndy Fiddaman 		return (-1);
1122069b2ef0SAndy Fiddaman 
1123069b2ef0SAndy Fiddaman 	return (len);
1124069b2ef0SAndy Fiddaman }
1125069b2ef0SAndy Fiddaman 
1126069b2ef0SAndy Fiddaman static ssize_t
be_dlpi_peek_recvlen(net_backend_t * be)1127069b2ef0SAndy Fiddaman be_dlpi_peek_recvlen(net_backend_t *be)
1128069b2ef0SAndy Fiddaman {
112959d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1130069b2ef0SAndy Fiddaman 	dlpi_recvinfo_t recv;
1131069b2ef0SAndy Fiddaman 	size_t len;
1132069b2ef0SAndy Fiddaman 	int ret;
1133069b2ef0SAndy Fiddaman 
1134069b2ef0SAndy Fiddaman 	/*
1135069b2ef0SAndy Fiddaman 	 * We already have a packet in the bounce buffer.
1136069b2ef0SAndy Fiddaman 	 * Just return its length.
1137069b2ef0SAndy Fiddaman 	 */
1138069b2ef0SAndy Fiddaman 	if (priv->bdp_bbuflen > 0)
1139069b2ef0SAndy Fiddaman 		return (priv->bdp_bbuflen);
1140069b2ef0SAndy Fiddaman 
1141069b2ef0SAndy Fiddaman 	/*
1142069b2ef0SAndy Fiddaman 	 * Read the next packet (if any) into the bounce buffer, so
1143069b2ef0SAndy Fiddaman 	 * that we get to know its length and we can return that
1144069b2ef0SAndy Fiddaman 	 * to the caller.
1145069b2ef0SAndy Fiddaman 	 */
1146069b2ef0SAndy Fiddaman 	len = sizeof (priv->bdp_bbuf);
1147069b2ef0SAndy Fiddaman 	ret = dlpi_recv(priv->bdp_dhp, NULL, NULL, priv->bdp_bbuf, &len,
1148069b2ef0SAndy Fiddaman 	    0, &recv);
1149069b2ef0SAndy Fiddaman 	if (ret == DL_SYSERR) {
1150069b2ef0SAndy Fiddaman 		if (errno == EWOULDBLOCK)
1151069b2ef0SAndy Fiddaman 			return (0);
1152069b2ef0SAndy Fiddaman 		return (-1);
1153069b2ef0SAndy Fiddaman 	} else if (ret == DLPI_ETIMEDOUT) {
1154069b2ef0SAndy Fiddaman 		return (0);
1155069b2ef0SAndy Fiddaman 	} else if (ret != DLPI_SUCCESS) {
1156069b2ef0SAndy Fiddaman 		return (-1);
1157069b2ef0SAndy Fiddaman 	}
1158069b2ef0SAndy Fiddaman 
1159069b2ef0SAndy Fiddaman 	if (recv.dri_totmsglen > sizeof (priv->bdp_bbuf)) {
1160069b2ef0SAndy Fiddaman 		EPRINTLN("DLPI bounce buffer was too small! - needed %x bytes",
1161069b2ef0SAndy Fiddaman 		    recv.dri_totmsglen);
1162069b2ef0SAndy Fiddaman 	}
1163069b2ef0SAndy Fiddaman 
1164069b2ef0SAndy Fiddaman 	priv->bdp_bbuflen = len;
1165069b2ef0SAndy Fiddaman 
1166069b2ef0SAndy Fiddaman 	return (len);
1167069b2ef0SAndy Fiddaman }
1168069b2ef0SAndy Fiddaman 
1169069b2ef0SAndy Fiddaman static ssize_t
be_dlpi_recv(net_backend_t * be,const struct iovec * iov,int iovcnt)1170069b2ef0SAndy Fiddaman be_dlpi_recv(net_backend_t *be, const struct iovec *iov, int iovcnt)
1171069b2ef0SAndy Fiddaman {
117259d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1173069b2ef0SAndy Fiddaman 	size_t len;
1174069b2ef0SAndy Fiddaman 	int ret;
1175069b2ef0SAndy Fiddaman 
1176069b2ef0SAndy Fiddaman 	if (priv->bdp_bbuflen > 0) {
1177069b2ef0SAndy Fiddaman 		/*
1178069b2ef0SAndy Fiddaman 		 * A packet is available in the bounce buffer, so
1179069b2ef0SAndy Fiddaman 		 * we read it from there.
1180069b2ef0SAndy Fiddaman 		 */
1181069b2ef0SAndy Fiddaman 		len = buf_to_iov(priv->bdp_bbuf, priv->bdp_bbuflen,
1182069b2ef0SAndy Fiddaman 		    iov, iovcnt, 0);
1183069b2ef0SAndy Fiddaman 
1184069b2ef0SAndy Fiddaman 		/* Mark the bounce buffer as empty. */
1185069b2ef0SAndy Fiddaman 		priv->bdp_bbuflen = 0;
1186069b2ef0SAndy Fiddaman 
1187069b2ef0SAndy Fiddaman 		return (len);
1188069b2ef0SAndy Fiddaman 	}
1189069b2ef0SAndy Fiddaman 
1190069b2ef0SAndy Fiddaman 	len = iov[0].iov_len;
1191069b2ef0SAndy Fiddaman 	ret = dlpi_recv(priv->bdp_dhp, NULL, NULL,
1192069b2ef0SAndy Fiddaman 	    (uint8_t *)iov[0].iov_base, &len, 0, NULL);
1193069b2ef0SAndy Fiddaman 	if (ret == DL_SYSERR) {
1194069b2ef0SAndy Fiddaman 		if (errno == EWOULDBLOCK)
1195069b2ef0SAndy Fiddaman 			return (0);
1196069b2ef0SAndy Fiddaman 		return (-1);
1197069b2ef0SAndy Fiddaman 	} else if (ret == DLPI_ETIMEDOUT) {
1198069b2ef0SAndy Fiddaman 		return (0);
1199069b2ef0SAndy Fiddaman 	} else if (ret != DLPI_SUCCESS) {
1200069b2ef0SAndy Fiddaman 		return (-1);
1201069b2ef0SAndy Fiddaman 	}
1202069b2ef0SAndy Fiddaman 
1203069b2ef0SAndy Fiddaman 	return (len);
1204069b2ef0SAndy Fiddaman }
1205069b2ef0SAndy Fiddaman 
1206069b2ef0SAndy Fiddaman static void
be_dlpi_recv_enable(net_backend_t * be)1207069b2ef0SAndy Fiddaman be_dlpi_recv_enable(net_backend_t *be)
1208069b2ef0SAndy Fiddaman {
120959d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1210069b2ef0SAndy Fiddaman 
1211069b2ef0SAndy Fiddaman 	mevent_enable(priv->bdp_mevp);
1212069b2ef0SAndy Fiddaman }
1213069b2ef0SAndy Fiddaman 
1214069b2ef0SAndy Fiddaman static void
be_dlpi_recv_disable(net_backend_t * be)1215069b2ef0SAndy Fiddaman be_dlpi_recv_disable(net_backend_t *be)
1216069b2ef0SAndy Fiddaman {
121759d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1218069b2ef0SAndy Fiddaman 
1219069b2ef0SAndy Fiddaman 	mevent_disable(priv->bdp_mevp);
1220069b2ef0SAndy Fiddaman }
1221069b2ef0SAndy Fiddaman 
1222069b2ef0SAndy Fiddaman static uint64_t
be_dlpi_get_cap(net_backend_t * be)1223069b2ef0SAndy Fiddaman be_dlpi_get_cap(net_backend_t *be)
1224069b2ef0SAndy Fiddaman {
1225069b2ef0SAndy Fiddaman 	return (0); /* no capabilities for now */
1226069b2ef0SAndy Fiddaman }
1227069b2ef0SAndy Fiddaman 
1228069b2ef0SAndy Fiddaman static int
be_dlpi_set_cap(net_backend_t * be,uint64_t features,unsigned vnet_hdr_len)1229069b2ef0SAndy Fiddaman be_dlpi_set_cap(net_backend_t *be, uint64_t features,
1230069b2ef0SAndy Fiddaman     unsigned vnet_hdr_len)
1231069b2ef0SAndy Fiddaman {
1232069b2ef0SAndy Fiddaman 	return ((features || vnet_hdr_len) ? -1 : 0);
1233069b2ef0SAndy Fiddaman }
1234069b2ef0SAndy Fiddaman 
1235069b2ef0SAndy Fiddaman static int
be_dlpi_get_mac(net_backend_t * be,void * buf,size_t * buflen)1236069b2ef0SAndy Fiddaman be_dlpi_get_mac(net_backend_t *be, void *buf, size_t *buflen)
1237069b2ef0SAndy Fiddaman {
123859d65d31SAndy Fiddaman 	be_dlpi_priv_t *priv = NET_BE_PRIV(be);
1239069b2ef0SAndy Fiddaman 	uchar_t physaddr[DLPI_PHYSADDR_MAX];
1240069b2ef0SAndy Fiddaman 	size_t physaddrlen = DLPI_PHYSADDR_MAX;
1241069b2ef0SAndy Fiddaman 	int ret;
1242069b2ef0SAndy Fiddaman 
1243069b2ef0SAndy Fiddaman 	if ((ret = dlpi_get_physaddr(priv->bdp_dhp, DL_CURR_PHYS_ADDR,
1244069b2ef0SAndy Fiddaman 	    physaddr, &physaddrlen)) != DLPI_SUCCESS) {
1245069b2ef0SAndy Fiddaman 		be_dlpi_err(ret, dlpi_linkname(priv->bdp_dhp),
1246069b2ef0SAndy Fiddaman 		    "read MAC address failed");
1247069b2ef0SAndy Fiddaman 		return (EINVAL);
1248069b2ef0SAndy Fiddaman 	}
1249069b2ef0SAndy Fiddaman 
1250069b2ef0SAndy Fiddaman 	if (physaddrlen != ETHERADDRL) {
1251069b2ef0SAndy Fiddaman 		WPRINTF(("%s: bad MAC address len %d",
1252069b2ef0SAndy Fiddaman 		    dlpi_linkname(priv->bdp_dhp), physaddrlen));
1253069b2ef0SAndy Fiddaman 		return (EINVAL);
1254069b2ef0SAndy Fiddaman 	}
1255069b2ef0SAndy Fiddaman 
1256069b2ef0SAndy Fiddaman 	if (physaddrlen > *buflen) {
1257069b2ef0SAndy Fiddaman 		WPRINTF(("%s: MAC address too long (%d bytes required)",
1258069b2ef0SAndy Fiddaman 		    dlpi_linkname(priv->bdp_dhp), physaddrlen));
1259069b2ef0SAndy Fiddaman 		return (ENOMEM);
1260069b2ef0SAndy Fiddaman 	}
1261069b2ef0SAndy Fiddaman 
1262069b2ef0SAndy Fiddaman 	*buflen = physaddrlen;
1263069b2ef0SAndy Fiddaman 	memcpy(buf, physaddr, *buflen);
1264069b2ef0SAndy Fiddaman 
1265069b2ef0SAndy Fiddaman 	return (0);
1266069b2ef0SAndy Fiddaman }
1267069b2ef0SAndy Fiddaman 
1268069b2ef0SAndy Fiddaman static struct net_backend dlpi_backend = {
1269069b2ef0SAndy Fiddaman 	.prefix = "dlpi",
1270069b2ef0SAndy Fiddaman 	.priv_size = sizeof(struct be_dlpi_priv),
1271069b2ef0SAndy Fiddaman 	.init = be_dlpi_init,
1272069b2ef0SAndy Fiddaman 	.cleanup = be_dlpi_cleanup,
1273069b2ef0SAndy Fiddaman 	.send = be_dlpi_send,
1274069b2ef0SAndy Fiddaman 	.peek_recvlen = be_dlpi_peek_recvlen,
1275069b2ef0SAndy Fiddaman 	.recv = be_dlpi_recv,
1276069b2ef0SAndy Fiddaman 	.recv_enable = be_dlpi_recv_enable,
1277069b2ef0SAndy Fiddaman 	.recv_disable = be_dlpi_recv_disable,
1278069b2ef0SAndy Fiddaman 	.get_cap = be_dlpi_get_cap,
1279069b2ef0SAndy Fiddaman 	.set_cap = be_dlpi_set_cap,
1280069b2ef0SAndy Fiddaman 	.get_mac = be_dlpi_get_mac,
1281069b2ef0SAndy Fiddaman };
1282069b2ef0SAndy Fiddaman 
1283069b2ef0SAndy Fiddaman DATA_SET(net_backend_set, dlpi_backend);
1284069b2ef0SAndy Fiddaman 
1285069b2ef0SAndy Fiddaman #endif /* __FreeBSD__ */
1286069b2ef0SAndy Fiddaman 
1287069b2ef0SAndy Fiddaman #ifdef __FreeBSD__
12882b948146SAndy Fiddaman int
netbe_legacy_config(nvlist_t * nvl,const char * opts)12892b948146SAndy Fiddaman netbe_legacy_config(nvlist_t *nvl, const char *opts)
12902b948146SAndy Fiddaman {
12912b948146SAndy Fiddaman 	char *backend, *cp;
12922b948146SAndy Fiddaman 
12932b948146SAndy Fiddaman 	if (opts == NULL)
12942b948146SAndy Fiddaman 		return (0);
12952b948146SAndy Fiddaman 
12962b948146SAndy Fiddaman 	cp = strchr(opts, ',');
12972b948146SAndy Fiddaman 	if (cp == NULL) {
12982b948146SAndy Fiddaman 		set_config_value_node(nvl, "backend", opts);
12992b948146SAndy Fiddaman 		return (0);
13002b948146SAndy Fiddaman 	}
13012b948146SAndy Fiddaman 	backend = strndup(opts, cp - opts);
13022b948146SAndy Fiddaman 	set_config_value_node(nvl, "backend", backend);
13032b948146SAndy Fiddaman 	free(backend);
13042b948146SAndy Fiddaman 	return (pci_parse_legacy_config(nvl, cp + 1));
13052b948146SAndy Fiddaman }
1306069b2ef0SAndy Fiddaman #else
1307069b2ef0SAndy Fiddaman int
netbe_legacy_config(nvlist_t * nvl,const char * opts)1308069b2ef0SAndy Fiddaman netbe_legacy_config(nvlist_t *nvl, const char *opts)
1309069b2ef0SAndy Fiddaman {
1310069b2ef0SAndy Fiddaman 	char *config, *name, *tofree, *value;
1311069b2ef0SAndy Fiddaman 
1312069b2ef0SAndy Fiddaman 	if (opts == NULL)
1313069b2ef0SAndy Fiddaman 		return (0);
1314069b2ef0SAndy Fiddaman 
1315069b2ef0SAndy Fiddaman 	/* Default to the 'dlpi' backend - can still be overridden by opts */
1316069b2ef0SAndy Fiddaman 	set_config_value_node(nvl, "backend", "dlpi");
13174f3f3e9aSAndy Fiddaman 	set_config_value_node(nvl, "type", "dlpi");
1318069b2ef0SAndy Fiddaman 
1319069b2ef0SAndy Fiddaman 	config = tofree = strdup(opts);
1320069b2ef0SAndy Fiddaman 	if (config == NULL)
1321069b2ef0SAndy Fiddaman 		err(4, "netbe_legacy_config strdup()");
1322069b2ef0SAndy Fiddaman 	while ((name = strsep(&config, ",")) != NULL) {
1323069b2ef0SAndy Fiddaman 		value = strchr(name, '=');
1324069b2ef0SAndy Fiddaman 		if (value != NULL) {
1325069b2ef0SAndy Fiddaman 			*value++ = '\0';
1326069b2ef0SAndy Fiddaman 			set_config_value_node(nvl, name, value);
1327069b2ef0SAndy Fiddaman 		} else {
1328069b2ef0SAndy Fiddaman 			set_config_value_node(nvl, "vnic", name);
1329069b2ef0SAndy Fiddaman 		}
1330069b2ef0SAndy Fiddaman 	}
1331069b2ef0SAndy Fiddaman 	free(tofree);
1332069b2ef0SAndy Fiddaman 
1333069b2ef0SAndy Fiddaman 	return (0);
1334069b2ef0SAndy Fiddaman }
1335069b2ef0SAndy Fiddaman #endif
13362b948146SAndy Fiddaman 
133784659b24SMichael Zeller /*
133884659b24SMichael Zeller  * Initialize a backend and attach to the frontend.
133984659b24SMichael Zeller  * This is called during frontend initialization.
13402b948146SAndy Fiddaman  *  @ret is a pointer to the backend to be initialized
134184659b24SMichael Zeller  *  @devname is the backend-name as supplied on the command line,
134284659b24SMichael Zeller  * 	e.g. -s 2:0,frontend-name,backend-name[,other-args]
134384659b24SMichael Zeller  *  @cb is the receive callback supplied by the frontend,
134484659b24SMichael Zeller  *	and it is invoked in the event loop when a receive
134584659b24SMichael Zeller  *	event is generated in the hypervisor,
134684659b24SMichael Zeller  *  @param is a pointer to the frontend, and normally used as
134784659b24SMichael Zeller  *	the argument for the callback.
134884659b24SMichael Zeller  */
134984659b24SMichael Zeller int
netbe_init(struct net_backend ** ret,nvlist_t * nvl,net_be_rxeof_t cb,void * param)13502b948146SAndy Fiddaman netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb,
135184659b24SMichael Zeller     void *param)
135284659b24SMichael Zeller {
135384659b24SMichael Zeller 	struct net_backend **pbe, *nbe, *tbe = NULL;
13544f3f3e9aSAndy Fiddaman 	const char *value, *type;
1355154972afSPatrick Mooney 	char *devname;
135684659b24SMichael Zeller 	int err;
135784659b24SMichael Zeller 
13582b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "backend");
13592b948146SAndy Fiddaman 	if (value == NULL) {
1360154972afSPatrick Mooney 		return (-1);
1361154972afSPatrick Mooney 	}
13622b948146SAndy Fiddaman 	devname = strdup(value);
1363154972afSPatrick Mooney 
13644f3f3e9aSAndy Fiddaman 	/*
13654f3f3e9aSAndy Fiddaman 	 * Use the type given by configuration if exists; otherwise
13664f3f3e9aSAndy Fiddaman 	 * use the prefix of the backend as the type.
13674f3f3e9aSAndy Fiddaman 	 */
13684f3f3e9aSAndy Fiddaman 	type = get_config_value_node(nvl, "type");
13694f3f3e9aSAndy Fiddaman 	if (type == NULL)
13704f3f3e9aSAndy Fiddaman 		type = devname;
13714f3f3e9aSAndy Fiddaman 
137284659b24SMichael Zeller 	/*
137384659b24SMichael Zeller 	 * Find the network backend that matches the user-provided
137484659b24SMichael Zeller 	 * device name. net_backend_set is built using a linker set.
137584659b24SMichael Zeller 	 */
137684659b24SMichael Zeller 	SET_FOREACH(pbe, net_backend_set) {
13774f3f3e9aSAndy Fiddaman 		if (strncmp(type, (*pbe)->prefix,
137884659b24SMichael Zeller 		    strlen((*pbe)->prefix)) == 0) {
137984659b24SMichael Zeller 			tbe = *pbe;
138084659b24SMichael Zeller 			assert(tbe->init != NULL);
138184659b24SMichael Zeller 			assert(tbe->cleanup != NULL);
138284659b24SMichael Zeller 			assert(tbe->send != NULL);
138384659b24SMichael Zeller 			assert(tbe->recv != NULL);
138484659b24SMichael Zeller 			assert(tbe->get_cap != NULL);
138584659b24SMichael Zeller 			assert(tbe->set_cap != NULL);
138684659b24SMichael Zeller 			break;
138784659b24SMichael Zeller 		}
138884659b24SMichael Zeller 	}
138984659b24SMichael Zeller 
139084659b24SMichael Zeller 	*ret = NULL;
1391154972afSPatrick Mooney 	if (tbe == NULL) {
1392154972afSPatrick Mooney 		free(devname);
139384659b24SMichael Zeller 		return (EINVAL);
1394154972afSPatrick Mooney 	}
1395154972afSPatrick Mooney 
139659d65d31SAndy Fiddaman 	nbe = calloc(1, NET_BE_SIZE(tbe));
139784659b24SMichael Zeller 	*nbe = *tbe;	/* copy the template */
139884659b24SMichael Zeller 	nbe->fd = -1;
139984659b24SMichael Zeller 	nbe->sc = param;
140084659b24SMichael Zeller 	nbe->be_vnet_hdr_len = 0;
140184659b24SMichael Zeller 	nbe->fe_vnet_hdr_len = 0;
140284659b24SMichael Zeller 
140384659b24SMichael Zeller 	/* Initialize the backend. */
14042b948146SAndy Fiddaman 	err = nbe->init(nbe, devname, nvl, cb, param);
140584659b24SMichael Zeller 	if (err) {
1406154972afSPatrick Mooney 		free(devname);
140784659b24SMichael Zeller 		free(nbe);
140884659b24SMichael Zeller 		return (err);
140984659b24SMichael Zeller 	}
141084659b24SMichael Zeller 
141184659b24SMichael Zeller 	*ret = nbe;
1412154972afSPatrick Mooney 	free(devname);
141384659b24SMichael Zeller 
141484659b24SMichael Zeller 	return (0);
141584659b24SMichael Zeller }
141684659b24SMichael Zeller 
141784659b24SMichael Zeller void
netbe_cleanup(struct net_backend * be)141884659b24SMichael Zeller netbe_cleanup(struct net_backend *be)
141984659b24SMichael Zeller {
142084659b24SMichael Zeller 
142184659b24SMichael Zeller 	if (be != NULL) {
142284659b24SMichael Zeller 		be->cleanup(be);
142384659b24SMichael Zeller 		free(be);
142484659b24SMichael Zeller 	}
142584659b24SMichael Zeller }
142684659b24SMichael Zeller 
142784659b24SMichael Zeller uint64_t
netbe_get_cap(struct net_backend * be)142884659b24SMichael Zeller netbe_get_cap(struct net_backend *be)
142984659b24SMichael Zeller {
143084659b24SMichael Zeller 
143184659b24SMichael Zeller 	assert(be != NULL);
143284659b24SMichael Zeller 	return (be->get_cap(be));
143384659b24SMichael Zeller }
143484659b24SMichael Zeller 
143584659b24SMichael Zeller int
netbe_set_cap(struct net_backend * be,uint64_t features,unsigned vnet_hdr_len)143684659b24SMichael Zeller netbe_set_cap(struct net_backend *be, uint64_t features,
143784659b24SMichael Zeller 	      unsigned vnet_hdr_len)
143884659b24SMichael Zeller {
143984659b24SMichael Zeller 	int ret;
144084659b24SMichael Zeller 
144184659b24SMichael Zeller 	assert(be != NULL);
144284659b24SMichael Zeller 
144384659b24SMichael Zeller 	/* There are only three valid lengths, i.e., 0, 10 and 12. */
144484659b24SMichael Zeller 	if (vnet_hdr_len && vnet_hdr_len != VNET_HDR_LEN
144584659b24SMichael Zeller 		&& vnet_hdr_len != (VNET_HDR_LEN - sizeof(uint16_t)))
144684659b24SMichael Zeller 		return (-1);
144784659b24SMichael Zeller 
144884659b24SMichael Zeller 	be->fe_vnet_hdr_len = vnet_hdr_len;
144984659b24SMichael Zeller 
145084659b24SMichael Zeller 	ret = be->set_cap(be, features, vnet_hdr_len);
145184659b24SMichael Zeller 	assert(be->be_vnet_hdr_len == 0 ||
145284659b24SMichael Zeller 	       be->be_vnet_hdr_len == be->fe_vnet_hdr_len);
145384659b24SMichael Zeller 
145484659b24SMichael Zeller 	return (ret);
145584659b24SMichael Zeller }
145684659b24SMichael Zeller 
1457154972afSPatrick Mooney ssize_t
netbe_send(struct net_backend * be,const struct iovec * iov,int iovcnt)1458154972afSPatrick Mooney netbe_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
145984659b24SMichael Zeller {
146084659b24SMichael Zeller 
1461154972afSPatrick Mooney 	return (be->send(be, iov, iovcnt));
146284659b24SMichael Zeller }
146384659b24SMichael Zeller 
146484659b24SMichael Zeller ssize_t
netbe_peek_recvlen(struct net_backend * be)1465154972afSPatrick Mooney netbe_peek_recvlen(struct net_backend *be)
146684659b24SMichael Zeller {
146784659b24SMichael Zeller 
1468154972afSPatrick Mooney 	return (be->peek_recvlen(be));
146984659b24SMichael Zeller }
147084659b24SMichael Zeller 
147184659b24SMichael Zeller /*
147284659b24SMichael Zeller  * Try to read a packet from the backend, without blocking.
147384659b24SMichael Zeller  * If no packets are available, return 0. In case of success, return
147484659b24SMichael Zeller  * the length of the packet just read. Return -1 in case of errors.
147584659b24SMichael Zeller  */
147684659b24SMichael Zeller ssize_t
netbe_recv(struct net_backend * be,const struct iovec * iov,int iovcnt)1477154972afSPatrick Mooney netbe_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
147884659b24SMichael Zeller {
147984659b24SMichael Zeller 
1480154972afSPatrick Mooney 	return (be->recv(be, iov, iovcnt));
148184659b24SMichael Zeller }
148284659b24SMichael Zeller 
148384659b24SMichael Zeller /*
148484659b24SMichael Zeller  * Read a packet from the backend and discard it.
148584659b24SMichael Zeller  * Returns the size of the discarded packet or zero if no packet was available.
148684659b24SMichael Zeller  * A negative error code is returned in case of read error.
148784659b24SMichael Zeller  */
148884659b24SMichael Zeller ssize_t
netbe_rx_discard(struct net_backend * be)148984659b24SMichael Zeller netbe_rx_discard(struct net_backend *be)
149084659b24SMichael Zeller {
149184659b24SMichael Zeller 	/*
149284659b24SMichael Zeller 	 * MP note: the dummybuf is only used to discard frames,
149384659b24SMichael Zeller 	 * so there is no need for it to be per-vtnet or locked.
149484659b24SMichael Zeller 	 * We only make it large enough for TSO-sized segment.
149584659b24SMichael Zeller 	 */
149684659b24SMichael Zeller 	static uint8_t dummybuf[65536 + 64];
149784659b24SMichael Zeller 	struct iovec iov;
149884659b24SMichael Zeller 
1499069b2ef0SAndy Fiddaman #ifdef __FreeBSD__
150084659b24SMichael Zeller 	iov.iov_base = dummybuf;
1501069b2ef0SAndy Fiddaman #else
1502069b2ef0SAndy Fiddaman 	iov.iov_base = (caddr_t)dummybuf;
1503069b2ef0SAndy Fiddaman #endif
150484659b24SMichael Zeller 	iov.iov_len = sizeof(dummybuf);
150584659b24SMichael Zeller 
150684659b24SMichael Zeller 	return netbe_recv(be, &iov, 1);
150784659b24SMichael Zeller }
150884659b24SMichael Zeller 
1509154972afSPatrick Mooney void
netbe_rx_disable(struct net_backend * be)1510154972afSPatrick Mooney netbe_rx_disable(struct net_backend *be)
1511154972afSPatrick Mooney {
1512154972afSPatrick Mooney 
1513154972afSPatrick Mooney 	return be->recv_disable(be);
1514154972afSPatrick Mooney }
1515154972afSPatrick Mooney 
1516154972afSPatrick Mooney void
netbe_rx_enable(struct net_backend * be)1517154972afSPatrick Mooney netbe_rx_enable(struct net_backend *be)
1518154972afSPatrick Mooney {
1519154972afSPatrick Mooney 
1520154972afSPatrick Mooney 	return be->recv_enable(be);
1521154972afSPatrick Mooney }
1522154972afSPatrick Mooney 
1523154972afSPatrick Mooney size_t
netbe_get_vnet_hdr_len(struct net_backend * be)1524154972afSPatrick Mooney netbe_get_vnet_hdr_len(struct net_backend *be)
1525154972afSPatrick Mooney {
1526154972afSPatrick Mooney 
1527154972afSPatrick Mooney 	return (be->be_vnet_hdr_len);
1528154972afSPatrick Mooney }
1529069b2ef0SAndy Fiddaman 
1530069b2ef0SAndy Fiddaman #ifndef __FreeBSD__
1531069b2ef0SAndy Fiddaman int
netbe_get_mac(net_backend_t * be,void * buf,size_t * buflen)1532069b2ef0SAndy Fiddaman netbe_get_mac(net_backend_t *be, void *buf, size_t *buflen)
1533069b2ef0SAndy Fiddaman {
1534069b2ef0SAndy Fiddaman 	if (be->get_mac == NULL)
1535069b2ef0SAndy Fiddaman 		return (ENOTSUP);
1536069b2ef0SAndy Fiddaman 	return (be->get_mac(be, buf, buflen));
1537069b2ef0SAndy Fiddaman }
1538069b2ef0SAndy Fiddaman #endif
1539