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