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
35*be74aedeSMark Johnston #include <sys/types.h>
360ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
370ff7076bSVincenzo Maffione #include <sys/capsicum.h>
380ff7076bSVincenzo Maffione #endif
390ff7076bSVincenzo Maffione #include <sys/ioctl.h>
400ff7076bSVincenzo Maffione #include <sys/mman.h>
410ff7076bSVincenzo Maffione #include <sys/uio.h>
420ff7076bSVincenzo Maffione
430ff7076bSVincenzo Maffione #include <net/if.h>
4456be282bSBjoern A. Zeeb #include <net/if_tap.h>
450ff7076bSVincenzo Maffione
46*be74aedeSMark Johnston #include <assert.h>
470ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
480ff7076bSVincenzo Maffione #include <capsicum_helpers.h>
490ff7076bSVincenzo Maffione #endif
500ff7076bSVincenzo Maffione #include <err.h>
510ff7076bSVincenzo Maffione #include <errno.h>
520ff7076bSVincenzo Maffione #include <fcntl.h>
53*be74aedeSMark Johnston #include <poll.h>
54*be74aedeSMark Johnston #include <pthread.h>
55*be74aedeSMark Johnston #include <pthread_np.h>
560ff7076bSVincenzo Maffione #include <stdio.h>
570ff7076bSVincenzo Maffione #include <stdlib.h>
580ff7076bSVincenzo Maffione #include <stdint.h>
590ff7076bSVincenzo Maffione #include <string.h>
600ff7076bSVincenzo Maffione #include <sysexits.h>
61*be74aedeSMark Johnston #include <unistd.h>
620ff7076bSVincenzo Maffione
63621b5090SJohn Baldwin #include "config.h"
64332eff95SVincenzo Maffione #include "debug.h"
650ff7076bSVincenzo Maffione #include "iov.h"
660ff7076bSVincenzo Maffione #include "mevent.h"
670ff7076bSVincenzo Maffione #include "net_backends.h"
68*be74aedeSMark Johnston #include "net_backends_priv.h"
69621b5090SJohn Baldwin #include "pci_emul.h"
700ff7076bSVincenzo Maffione
710ced97acSMark Johnston #define NET_BE_SIZE(be) (sizeof(*be) + (be)->priv_size)
720ced97acSMark Johnston
73*be74aedeSMark Johnston void
tap_cleanup(struct net_backend * be)740ff7076bSVincenzo Maffione tap_cleanup(struct net_backend *be)
750ff7076bSVincenzo Maffione {
760ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
770ff7076bSVincenzo Maffione
780ff7076bSVincenzo Maffione if (priv->mevp) {
790ff7076bSVincenzo Maffione mevent_delete(priv->mevp);
800ff7076bSVincenzo Maffione }
810ff7076bSVincenzo Maffione if (be->fd != -1) {
820ff7076bSVincenzo Maffione close(be->fd);
830ff7076bSVincenzo Maffione be->fd = -1;
840ff7076bSVincenzo Maffione }
850ff7076bSVincenzo Maffione }
860ff7076bSVincenzo Maffione
870ff7076bSVincenzo Maffione static int
tap_init(struct net_backend * be,const char * devname,nvlist_t * nvl __unused,net_be_rxeof_t cb,void * param)880ff7076bSVincenzo Maffione tap_init(struct net_backend *be, const char *devname,
8998d920d9SMark Johnston nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
900ff7076bSVincenzo Maffione {
910ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
920ff7076bSVincenzo Maffione char tbuf[80];
93fd8b9c73SJan Bramkamp int opt = 1, up = IFF_UP;
94fd8b9c73SJan Bramkamp
950ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
960ff7076bSVincenzo Maffione cap_rights_t rights;
970ff7076bSVincenzo Maffione #endif
980ff7076bSVincenzo Maffione
990ff7076bSVincenzo Maffione if (cb == NULL) {
100*be74aedeSMark Johnston EPRINTLN("TAP backend requires non-NULL callback");
1010ff7076bSVincenzo Maffione return (-1);
1020ff7076bSVincenzo Maffione }
1030ff7076bSVincenzo Maffione
1040ff7076bSVincenzo Maffione strcpy(tbuf, "/dev/");
1050ff7076bSVincenzo Maffione strlcat(tbuf, devname, sizeof(tbuf));
1060ff7076bSVincenzo Maffione
1072d5fe369SSean Chittenden be->fd = open(tbuf, O_RDWR);
1082d5fe369SSean Chittenden if (be->fd == -1) {
109*be74aedeSMark Johnston EPRINTLN("open of tap device %s failed", tbuf);
1100ff7076bSVincenzo Maffione goto error;
1110ff7076bSVincenzo Maffione }
1120ff7076bSVincenzo Maffione
1130ff7076bSVincenzo Maffione /*
1140ff7076bSVincenzo Maffione * Set non-blocking and register for read
1150ff7076bSVincenzo Maffione * notifications with the event loop
1160ff7076bSVincenzo Maffione */
1172d5fe369SSean Chittenden if (ioctl(be->fd, FIONBIO, &opt) < 0) {
118*be74aedeSMark Johnston EPRINTLN("tap device O_NONBLOCK failed");
1190ff7076bSVincenzo Maffione goto error;
1200ff7076bSVincenzo Maffione }
1210ff7076bSVincenzo Maffione
122f407a72aSGleb Smirnoff if (ioctl(be->fd, VMIO_SIOCSIFFLAGS, up)) {
123*be74aedeSMark Johnston EPRINTLN("tap device link up failed");
12456be282bSBjoern A. Zeeb goto error;
12556be282bSBjoern A. Zeeb }
12656be282bSBjoern A. Zeeb
1270ff7076bSVincenzo Maffione #ifndef WITHOUT_CAPSICUM
1280ff7076bSVincenzo Maffione cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
1292d5fe369SSean Chittenden if (caph_rights_limit(be->fd, &rights) == -1)
1300ff7076bSVincenzo Maffione errx(EX_OSERR, "Unable to apply rights for sandbox");
1310ff7076bSVincenzo Maffione #endif
1320ff7076bSVincenzo Maffione
133f92bb8c1SVincenzo Maffione memset(priv->bbuf, 0, sizeof(priv->bbuf));
134f92bb8c1SVincenzo Maffione priv->bbuflen = 0;
135f92bb8c1SVincenzo Maffione
1363e11768eSVincenzo Maffione priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
1370ff7076bSVincenzo Maffione if (priv->mevp == NULL) {
138*be74aedeSMark Johnston EPRINTLN("Could not register event");
1390ff7076bSVincenzo Maffione goto error;
1400ff7076bSVincenzo Maffione }
1410ff7076bSVincenzo Maffione
1420ff7076bSVincenzo Maffione return (0);
1430ff7076bSVincenzo Maffione
1440ff7076bSVincenzo Maffione error:
1450ff7076bSVincenzo Maffione tap_cleanup(be);
1460ff7076bSVincenzo Maffione return (-1);
1470ff7076bSVincenzo Maffione }
1480ff7076bSVincenzo Maffione
1490ff7076bSVincenzo Maffione /*
1500ff7076bSVincenzo Maffione * Called to send a buffer chain out to the tap device
1510ff7076bSVincenzo Maffione */
152*be74aedeSMark Johnston ssize_t
tap_send(struct net_backend * be,const struct iovec * iov,int iovcnt)15366c662b0SVincenzo Maffione tap_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
1540ff7076bSVincenzo Maffione {
1550ff7076bSVincenzo Maffione return (writev(be->fd, iov, iovcnt));
1560ff7076bSVincenzo Maffione }
1570ff7076bSVincenzo Maffione
158*be74aedeSMark Johnston ssize_t
tap_peek_recvlen(struct net_backend * be)159f92bb8c1SVincenzo Maffione tap_peek_recvlen(struct net_backend *be)
1600ff7076bSVincenzo Maffione {
1610ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
1620ff7076bSVincenzo Maffione ssize_t ret;
1630ff7076bSVincenzo Maffione
164f92bb8c1SVincenzo Maffione if (priv->bbuflen > 0) {
165f92bb8c1SVincenzo Maffione /*
166f92bb8c1SVincenzo Maffione * We already have a packet in the bounce buffer.
167f92bb8c1SVincenzo Maffione * Just return its length.
168f92bb8c1SVincenzo Maffione */
169f92bb8c1SVincenzo Maffione return priv->bbuflen;
170f92bb8c1SVincenzo Maffione }
171f92bb8c1SVincenzo Maffione
172f92bb8c1SVincenzo Maffione /*
173f92bb8c1SVincenzo Maffione * Read the next packet (if any) into the bounce buffer, so
174f92bb8c1SVincenzo Maffione * that we get to know its length and we can return that
175f92bb8c1SVincenzo Maffione * to the caller.
176f92bb8c1SVincenzo Maffione */
177f92bb8c1SVincenzo Maffione ret = read(be->fd, priv->bbuf, sizeof(priv->bbuf));
178f92bb8c1SVincenzo Maffione if (ret < 0 && errno == EWOULDBLOCK) {
179f92bb8c1SVincenzo Maffione return (0);
180f92bb8c1SVincenzo Maffione }
181f92bb8c1SVincenzo Maffione
182f92bb8c1SVincenzo Maffione if (ret > 0)
183f92bb8c1SVincenzo Maffione priv->bbuflen = ret;
184f92bb8c1SVincenzo Maffione
185f92bb8c1SVincenzo Maffione return (ret);
186f92bb8c1SVincenzo Maffione }
187f92bb8c1SVincenzo Maffione
188*be74aedeSMark Johnston ssize_t
tap_recv(struct net_backend * be,const struct iovec * iov,int iovcnt)189f92bb8c1SVincenzo Maffione tap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
190f92bb8c1SVincenzo Maffione {
1910ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
192f92bb8c1SVincenzo Maffione ssize_t ret;
193f92bb8c1SVincenzo Maffione
194f92bb8c1SVincenzo Maffione if (priv->bbuflen > 0) {
195f92bb8c1SVincenzo Maffione /*
196f92bb8c1SVincenzo Maffione * A packet is available in the bounce buffer, so
197f92bb8c1SVincenzo Maffione * we read it from there.
198f92bb8c1SVincenzo Maffione */
199f92bb8c1SVincenzo Maffione ret = buf_to_iov(priv->bbuf, priv->bbuflen,
200f92bb8c1SVincenzo Maffione iov, iovcnt, 0);
201f92bb8c1SVincenzo Maffione
202f92bb8c1SVincenzo Maffione /* Mark the bounce buffer as empty. */
203f92bb8c1SVincenzo Maffione priv->bbuflen = 0;
204f92bb8c1SVincenzo Maffione
205f92bb8c1SVincenzo Maffione return (ret);
206f92bb8c1SVincenzo Maffione }
2070ff7076bSVincenzo Maffione
2080ff7076bSVincenzo Maffione ret = readv(be->fd, iov, iovcnt);
2090ff7076bSVincenzo Maffione if (ret < 0 && errno == EWOULDBLOCK) {
2100ff7076bSVincenzo Maffione return (0);
2110ff7076bSVincenzo Maffione }
2120ff7076bSVincenzo Maffione
2130ff7076bSVincenzo Maffione return (ret);
2140ff7076bSVincenzo Maffione }
2150ff7076bSVincenzo Maffione
216*be74aedeSMark Johnston void
tap_recv_enable(struct net_backend * be)217d12c5ef6SVincenzo Maffione tap_recv_enable(struct net_backend *be)
218d12c5ef6SVincenzo Maffione {
2190ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
220d12c5ef6SVincenzo Maffione
221d12c5ef6SVincenzo Maffione mevent_enable(priv->mevp);
222d12c5ef6SVincenzo Maffione }
223d12c5ef6SVincenzo Maffione
224*be74aedeSMark Johnston void
tap_recv_disable(struct net_backend * be)225d12c5ef6SVincenzo Maffione tap_recv_disable(struct net_backend *be)
226d12c5ef6SVincenzo Maffione {
2270ced97acSMark Johnston struct tap_priv *priv = NET_BE_PRIV(be);
228d12c5ef6SVincenzo Maffione
229d12c5ef6SVincenzo Maffione mevent_disable(priv->mevp);
230d12c5ef6SVincenzo Maffione }
231d12c5ef6SVincenzo Maffione
232*be74aedeSMark Johnston uint64_t
tap_get_cap(struct net_backend * be __unused)23398d920d9SMark Johnston tap_get_cap(struct net_backend *be __unused)
2340ff7076bSVincenzo Maffione {
2350ff7076bSVincenzo Maffione
2360ff7076bSVincenzo Maffione return (0); /* no capabilities for now */
2370ff7076bSVincenzo Maffione }
2380ff7076bSVincenzo Maffione
239*be74aedeSMark Johnston int
tap_set_cap(struct net_backend * be __unused,uint64_t features,unsigned vnet_hdr_len)24098d920d9SMark Johnston tap_set_cap(struct net_backend *be __unused, uint64_t features,
2410ff7076bSVincenzo Maffione unsigned vnet_hdr_len)
2420ff7076bSVincenzo Maffione {
2430ff7076bSVincenzo Maffione
2440ff7076bSVincenzo Maffione return ((features || vnet_hdr_len) ? -1 : 0);
2450ff7076bSVincenzo Maffione }
2460ff7076bSVincenzo Maffione
2470ff7076bSVincenzo Maffione static struct net_backend tap_backend = {
2480ff7076bSVincenzo Maffione .prefix = "tap",
2490ff7076bSVincenzo Maffione .priv_size = sizeof(struct tap_priv),
2500ff7076bSVincenzo Maffione .init = tap_init,
2510ff7076bSVincenzo Maffione .cleanup = tap_cleanup,
2520ff7076bSVincenzo Maffione .send = tap_send,
253f92bb8c1SVincenzo Maffione .peek_recvlen = tap_peek_recvlen,
2540ff7076bSVincenzo Maffione .recv = tap_recv,
255d12c5ef6SVincenzo Maffione .recv_enable = tap_recv_enable,
256d12c5ef6SVincenzo Maffione .recv_disable = tap_recv_disable,
2570ff7076bSVincenzo Maffione .get_cap = tap_get_cap,
2580ff7076bSVincenzo Maffione .set_cap = tap_set_cap,
2590ff7076bSVincenzo Maffione };
2600ff7076bSVincenzo Maffione
2610ff7076bSVincenzo Maffione /* A clone of the tap backend, with a different prefix. */
2620ff7076bSVincenzo Maffione static struct net_backend vmnet_backend = {
2630ff7076bSVincenzo Maffione .prefix = "vmnet",
2640ff7076bSVincenzo Maffione .priv_size = sizeof(struct tap_priv),
2650ff7076bSVincenzo Maffione .init = tap_init,
2660ff7076bSVincenzo Maffione .cleanup = tap_cleanup,
2670ff7076bSVincenzo Maffione .send = tap_send,
268f92bb8c1SVincenzo Maffione .peek_recvlen = tap_peek_recvlen,
2690ff7076bSVincenzo Maffione .recv = tap_recv,
270d12c5ef6SVincenzo Maffione .recv_enable = tap_recv_enable,
271d12c5ef6SVincenzo Maffione .recv_disable = tap_recv_disable,
2720ff7076bSVincenzo Maffione .get_cap = tap_get_cap,
2730ff7076bSVincenzo Maffione .set_cap = tap_set_cap,
2740ff7076bSVincenzo Maffione };
2750ff7076bSVincenzo Maffione
2760ff7076bSVincenzo Maffione DATA_SET(net_backend_set, tap_backend);
2770ff7076bSVincenzo Maffione DATA_SET(net_backend_set, vmnet_backend);
2780ff7076bSVincenzo Maffione
279621b5090SJohn Baldwin int
netbe_legacy_config(nvlist_t * nvl,const char * opts)280621b5090SJohn Baldwin netbe_legacy_config(nvlist_t *nvl, const char *opts)
281621b5090SJohn Baldwin {
282621b5090SJohn Baldwin char *backend, *cp;
283621b5090SJohn Baldwin
284621b5090SJohn Baldwin if (opts == NULL)
285621b5090SJohn Baldwin return (0);
286621b5090SJohn Baldwin
287621b5090SJohn Baldwin cp = strchr(opts, ',');
288621b5090SJohn Baldwin if (cp == NULL) {
289621b5090SJohn Baldwin set_config_value_node(nvl, "backend", opts);
290621b5090SJohn Baldwin return (0);
291621b5090SJohn Baldwin }
292621b5090SJohn Baldwin backend = strndup(opts, cp - opts);
293621b5090SJohn Baldwin set_config_value_node(nvl, "backend", backend);
294621b5090SJohn Baldwin free(backend);
295621b5090SJohn Baldwin return (pci_parse_legacy_config(nvl, cp + 1));
296621b5090SJohn Baldwin }
297621b5090SJohn Baldwin
2980ff7076bSVincenzo Maffione /*
2990ff7076bSVincenzo Maffione * Initialize a backend and attach to the frontend.
3000ff7076bSVincenzo Maffione * This is called during frontend initialization.
301621b5090SJohn Baldwin * @ret is a pointer to the backend to be initialized
3020ff7076bSVincenzo Maffione * @devname is the backend-name as supplied on the command line,
3030ff7076bSVincenzo Maffione * e.g. -s 2:0,frontend-name,backend-name[,other-args]
3040ff7076bSVincenzo Maffione * @cb is the receive callback supplied by the frontend,
3050ff7076bSVincenzo Maffione * and it is invoked in the event loop when a receive
3060ff7076bSVincenzo Maffione * event is generated in the hypervisor,
3070ff7076bSVincenzo Maffione * @param is a pointer to the frontend, and normally used as
3080ff7076bSVincenzo Maffione * the argument for the callback.
3090ff7076bSVincenzo Maffione */
3100ff7076bSVincenzo Maffione int
netbe_init(struct net_backend ** ret,nvlist_t * nvl,net_be_rxeof_t cb,void * param)311621b5090SJohn Baldwin netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb,
3120ff7076bSVincenzo Maffione void *param)
3130ff7076bSVincenzo Maffione {
3140ff7076bSVincenzo Maffione struct net_backend **pbe, *nbe, *tbe = NULL;
315b9c3e544SYan Ka Chiu const char *value, *type;
3165bebe923SAleksandr Fedorov char *devname;
3170ff7076bSVincenzo Maffione int err;
3180ff7076bSVincenzo Maffione
319621b5090SJohn Baldwin value = get_config_value_node(nvl, "backend");
320621b5090SJohn Baldwin if (value == NULL) {
3215bebe923SAleksandr Fedorov return (-1);
3225bebe923SAleksandr Fedorov }
323621b5090SJohn Baldwin devname = strdup(value);
3245bebe923SAleksandr Fedorov
3250ff7076bSVincenzo Maffione /*
326b9c3e544SYan Ka Chiu * Use the type given by configuration if exists; otherwise
327b9c3e544SYan Ka Chiu * use the prefix of the backend as the type.
328b9c3e544SYan Ka Chiu */
329b9c3e544SYan Ka Chiu type = get_config_value_node(nvl, "type");
330b9c3e544SYan Ka Chiu if (type == NULL)
331b9c3e544SYan Ka Chiu type = devname;
332b9c3e544SYan Ka Chiu
333b9c3e544SYan Ka Chiu /*
3340ff7076bSVincenzo Maffione * Find the network backend that matches the user-provided
3350ff7076bSVincenzo Maffione * device name. net_backend_set is built using a linker set.
3360ff7076bSVincenzo Maffione */
3370ff7076bSVincenzo Maffione SET_FOREACH(pbe, net_backend_set) {
338b9c3e544SYan Ka Chiu if (strncmp(type, (*pbe)->prefix,
3390ff7076bSVincenzo Maffione strlen((*pbe)->prefix)) == 0) {
3400ff7076bSVincenzo Maffione tbe = *pbe;
3410ff7076bSVincenzo Maffione assert(tbe->init != NULL);
3420ff7076bSVincenzo Maffione assert(tbe->cleanup != NULL);
3430ff7076bSVincenzo Maffione assert(tbe->send != NULL);
3440ff7076bSVincenzo Maffione assert(tbe->recv != NULL);
3450ff7076bSVincenzo Maffione assert(tbe->get_cap != NULL);
3460ff7076bSVincenzo Maffione assert(tbe->set_cap != NULL);
3470ff7076bSVincenzo Maffione break;
3480ff7076bSVincenzo Maffione }
3490ff7076bSVincenzo Maffione }
3500ff7076bSVincenzo Maffione
3510ff7076bSVincenzo Maffione *ret = NULL;
3525bebe923SAleksandr Fedorov if (tbe == NULL) {
3535bebe923SAleksandr Fedorov free(devname);
3540ff7076bSVincenzo Maffione return (EINVAL);
3555bebe923SAleksandr Fedorov }
3565bebe923SAleksandr Fedorov
3570ced97acSMark Johnston nbe = calloc(1, NET_BE_SIZE(tbe));
3580ff7076bSVincenzo Maffione *nbe = *tbe; /* copy the template */
3590ff7076bSVincenzo Maffione nbe->fd = -1;
3600ff7076bSVincenzo Maffione nbe->sc = param;
3610ff7076bSVincenzo Maffione nbe->be_vnet_hdr_len = 0;
3620ff7076bSVincenzo Maffione nbe->fe_vnet_hdr_len = 0;
3630ff7076bSVincenzo Maffione
3640ff7076bSVincenzo Maffione /* Initialize the backend. */
365621b5090SJohn Baldwin err = nbe->init(nbe, devname, nvl, cb, param);
3660ff7076bSVincenzo Maffione if (err) {
3675bebe923SAleksandr Fedorov free(devname);
3680ff7076bSVincenzo Maffione free(nbe);
3690ff7076bSVincenzo Maffione return (err);
3700ff7076bSVincenzo Maffione }
3710ff7076bSVincenzo Maffione
3720ff7076bSVincenzo Maffione *ret = nbe;
3735bebe923SAleksandr Fedorov free(devname);
3740ff7076bSVincenzo Maffione
3750ff7076bSVincenzo Maffione return (0);
3760ff7076bSVincenzo Maffione }
3770ff7076bSVincenzo Maffione
3780ff7076bSVincenzo Maffione void
netbe_cleanup(struct net_backend * be)3790ff7076bSVincenzo Maffione netbe_cleanup(struct net_backend *be)
3800ff7076bSVincenzo Maffione {
3810ff7076bSVincenzo Maffione
3820ff7076bSVincenzo Maffione if (be != NULL) {
3830ff7076bSVincenzo Maffione be->cleanup(be);
3840ff7076bSVincenzo Maffione free(be);
3850ff7076bSVincenzo Maffione }
3860ff7076bSVincenzo Maffione }
3870ff7076bSVincenzo Maffione
3880ff7076bSVincenzo Maffione uint64_t
netbe_get_cap(struct net_backend * be)3890ff7076bSVincenzo Maffione netbe_get_cap(struct net_backend *be)
3900ff7076bSVincenzo Maffione {
3910ff7076bSVincenzo Maffione
3920ff7076bSVincenzo Maffione assert(be != NULL);
3930ff7076bSVincenzo Maffione return (be->get_cap(be));
3940ff7076bSVincenzo Maffione }
3950ff7076bSVincenzo Maffione
3960ff7076bSVincenzo Maffione int
netbe_set_cap(struct net_backend * be,uint64_t features,unsigned vnet_hdr_len)3970ff7076bSVincenzo Maffione netbe_set_cap(struct net_backend *be, uint64_t features,
3980ff7076bSVincenzo Maffione unsigned vnet_hdr_len)
3990ff7076bSVincenzo Maffione {
4000ff7076bSVincenzo Maffione int ret;
4010ff7076bSVincenzo Maffione
4020ff7076bSVincenzo Maffione assert(be != NULL);
4030ff7076bSVincenzo Maffione
4040ff7076bSVincenzo Maffione /* There are only three valid lengths, i.e., 0, 10 and 12. */
4050ff7076bSVincenzo Maffione if (vnet_hdr_len && vnet_hdr_len != VNET_HDR_LEN
4060ff7076bSVincenzo Maffione && vnet_hdr_len != (VNET_HDR_LEN - sizeof(uint16_t)))
4070ff7076bSVincenzo Maffione return (-1);
4080ff7076bSVincenzo Maffione
4090ff7076bSVincenzo Maffione be->fe_vnet_hdr_len = vnet_hdr_len;
4100ff7076bSVincenzo Maffione
4110ff7076bSVincenzo Maffione ret = be->set_cap(be, features, vnet_hdr_len);
4120ff7076bSVincenzo Maffione assert(be->be_vnet_hdr_len == 0 ||
4130ff7076bSVincenzo Maffione be->be_vnet_hdr_len == be->fe_vnet_hdr_len);
4140ff7076bSVincenzo Maffione
4150ff7076bSVincenzo Maffione return (ret);
4160ff7076bSVincenzo Maffione }
4170ff7076bSVincenzo Maffione
4180ff7076bSVincenzo Maffione ssize_t
netbe_send(struct net_backend * be,const struct iovec * iov,int iovcnt)41966c662b0SVincenzo Maffione netbe_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
4200ff7076bSVincenzo Maffione {
4210ff7076bSVincenzo Maffione
4220ff7076bSVincenzo Maffione return (be->send(be, iov, iovcnt));
4230ff7076bSVincenzo Maffione }
4240ff7076bSVincenzo Maffione
425f92bb8c1SVincenzo Maffione ssize_t
netbe_peek_recvlen(struct net_backend * be)426f92bb8c1SVincenzo Maffione netbe_peek_recvlen(struct net_backend *be)
427f92bb8c1SVincenzo Maffione {
428f92bb8c1SVincenzo Maffione
429f92bb8c1SVincenzo Maffione return (be->peek_recvlen(be));
430f92bb8c1SVincenzo Maffione }
431f92bb8c1SVincenzo Maffione
4320ff7076bSVincenzo Maffione /*
4330ff7076bSVincenzo Maffione * Try to read a packet from the backend, without blocking.
4340ff7076bSVincenzo Maffione * If no packets are available, return 0. In case of success, return
4350ff7076bSVincenzo Maffione * the length of the packet just read. Return -1 in case of errors.
4360ff7076bSVincenzo Maffione */
4370ff7076bSVincenzo Maffione ssize_t
netbe_recv(struct net_backend * be,const struct iovec * iov,int iovcnt)43866c662b0SVincenzo Maffione netbe_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
4390ff7076bSVincenzo Maffione {
4400ff7076bSVincenzo Maffione
44166c662b0SVincenzo Maffione return (be->recv(be, iov, iovcnt));
4420ff7076bSVincenzo Maffione }
4430ff7076bSVincenzo Maffione
4440ff7076bSVincenzo Maffione /*
4450ff7076bSVincenzo Maffione * Read a packet from the backend and discard it.
4460ff7076bSVincenzo Maffione * Returns the size of the discarded packet or zero if no packet was available.
4470ff7076bSVincenzo Maffione * A negative error code is returned in case of read error.
4480ff7076bSVincenzo Maffione */
4490ff7076bSVincenzo Maffione ssize_t
netbe_rx_discard(struct net_backend * be)4500ff7076bSVincenzo Maffione netbe_rx_discard(struct net_backend *be)
4510ff7076bSVincenzo Maffione {
4520ff7076bSVincenzo Maffione /*
4530ff7076bSVincenzo Maffione * MP note: the dummybuf is only used to discard frames,
4540ff7076bSVincenzo Maffione * so there is no need for it to be per-vtnet or locked.
4550ff7076bSVincenzo Maffione * We only make it large enough for TSO-sized segment.
4560ff7076bSVincenzo Maffione */
4570ff7076bSVincenzo Maffione static uint8_t dummybuf[65536 + 64];
4580ff7076bSVincenzo Maffione struct iovec iov;
4590ff7076bSVincenzo Maffione
4600ff7076bSVincenzo Maffione iov.iov_base = dummybuf;
4610ff7076bSVincenzo Maffione iov.iov_len = sizeof(dummybuf);
4620ff7076bSVincenzo Maffione
4630ff7076bSVincenzo Maffione return netbe_recv(be, &iov, 1);
4640ff7076bSVincenzo Maffione }
4650ff7076bSVincenzo Maffione
466d12c5ef6SVincenzo Maffione void
netbe_rx_disable(struct net_backend * be)467d12c5ef6SVincenzo Maffione netbe_rx_disable(struct net_backend *be)
468d12c5ef6SVincenzo Maffione {
469d12c5ef6SVincenzo Maffione
47014d72637SVincenzo Maffione return be->recv_disable(be);
471d12c5ef6SVincenzo Maffione }
472d12c5ef6SVincenzo Maffione
473d12c5ef6SVincenzo Maffione void
netbe_rx_enable(struct net_backend * be)474d12c5ef6SVincenzo Maffione netbe_rx_enable(struct net_backend *be)
475d12c5ef6SVincenzo Maffione {
476d12c5ef6SVincenzo Maffione
47714d72637SVincenzo Maffione return be->recv_enable(be);
478d12c5ef6SVincenzo Maffione }
47966c662b0SVincenzo Maffione
48066c662b0SVincenzo Maffione size_t
netbe_get_vnet_hdr_len(struct net_backend * be)48166c662b0SVincenzo Maffione netbe_get_vnet_hdr_len(struct net_backend *be)
48266c662b0SVincenzo Maffione {
48366c662b0SVincenzo Maffione
48466c662b0SVincenzo Maffione return (be->be_vnet_hdr_len);
48566c662b0SVincenzo Maffione }
486