1f9790aebSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. 3f9790aebSLuigi Rizzo * 4f9790aebSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 5f9790aebSLuigi Rizzo * modification, are permitted provided that the following conditions 6f9790aebSLuigi Rizzo * are met: 7f9790aebSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 8f9790aebSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 9f9790aebSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 10f9790aebSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 11f9790aebSLuigi Rizzo * documentation and/or other materials provided with the distribution. 12f9790aebSLuigi Rizzo * 13f9790aebSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14f9790aebSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15f9790aebSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16f9790aebSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17f9790aebSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18f9790aebSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19f9790aebSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20f9790aebSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21f9790aebSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22f9790aebSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23f9790aebSLuigi Rizzo * SUCH DAMAGE. 24f9790aebSLuigi Rizzo */ 25f9790aebSLuigi Rizzo 26f9790aebSLuigi Rizzo /* $FreeBSD$ */ 27f9790aebSLuigi Rizzo 28f9790aebSLuigi Rizzo #include <sys/types.h> 29f9790aebSLuigi Rizzo #include <sys/module.h> 30f9790aebSLuigi Rizzo #include <sys/errno.h> 31f9790aebSLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 32f0ea3689SLuigi Rizzo #include <sys/poll.h> /* POLLIN, POLLOUT */ 33f9790aebSLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 34f9790aebSLuigi Rizzo #include <sys/conf.h> /* DEV_MODULE */ 35f0ea3689SLuigi Rizzo #include <sys/endian.h> 36f9790aebSLuigi Rizzo 37f9790aebSLuigi Rizzo #include <sys/rwlock.h> 38f9790aebSLuigi Rizzo 39f9790aebSLuigi Rizzo #include <vm/vm.h> /* vtophys */ 40f9790aebSLuigi Rizzo #include <vm/pmap.h> /* vtophys */ 41f9790aebSLuigi Rizzo #include <vm/vm_param.h> 42f9790aebSLuigi Rizzo #include <vm/vm_object.h> 43f9790aebSLuigi Rizzo #include <vm/vm_page.h> 44f9790aebSLuigi Rizzo #include <vm/vm_pager.h> 45f9790aebSLuigi Rizzo #include <vm/uma.h> 46f9790aebSLuigi Rizzo 47f9790aebSLuigi Rizzo 48f9790aebSLuigi Rizzo #include <sys/malloc.h> 49f9790aebSLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 50f9790aebSLuigi Rizzo #include <sys/selinfo.h> 51f9790aebSLuigi Rizzo #include <net/if.h> 52f9790aebSLuigi Rizzo #include <net/if_var.h> 534bf50f18SLuigi Rizzo #include <net/if_types.h> /* IFT_ETHER */ 544bf50f18SLuigi Rizzo #include <net/ethernet.h> /* ether_ifdetach */ 554bf50f18SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 56f9790aebSLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 57f0ea3689SLuigi Rizzo #include <netinet/in.h> /* in6_cksum_pseudo() */ 58f0ea3689SLuigi Rizzo #include <machine/in_cksum.h> /* in_pseudo(), in_cksum_hdr() */ 59f9790aebSLuigi Rizzo 60f9790aebSLuigi Rizzo #include <net/netmap.h> 61f9790aebSLuigi Rizzo #include <dev/netmap/netmap_kern.h> 62f9790aebSLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 63f9790aebSLuigi Rizzo 64f9790aebSLuigi Rizzo 65f9790aebSLuigi Rizzo /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */ 66f9790aebSLuigi Rizzo 67e4166283SLuigi Rizzo rawsum_t 68e4166283SLuigi Rizzo nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) 69f0ea3689SLuigi Rizzo { 70f0ea3689SLuigi Rizzo /* TODO XXX please use the FreeBSD implementation for this. */ 71f0ea3689SLuigi Rizzo uint16_t *words = (uint16_t *)data; 72f0ea3689SLuigi Rizzo int nw = len / 2; 73f0ea3689SLuigi Rizzo int i; 74f0ea3689SLuigi Rizzo 75f0ea3689SLuigi Rizzo for (i = 0; i < nw; i++) 76f0ea3689SLuigi Rizzo cur_sum += be16toh(words[i]); 77f0ea3689SLuigi Rizzo 78f0ea3689SLuigi Rizzo if (len & 1) 79f0ea3689SLuigi Rizzo cur_sum += (data[len-1] << 8); 80f0ea3689SLuigi Rizzo 81f0ea3689SLuigi Rizzo return cur_sum; 82f0ea3689SLuigi Rizzo } 83f0ea3689SLuigi Rizzo 84f0ea3689SLuigi Rizzo /* Fold a raw checksum: 'cur_sum' is in host byte order, while the 85f0ea3689SLuigi Rizzo * return value is in network byte order. 86f0ea3689SLuigi Rizzo */ 87e4166283SLuigi Rizzo uint16_t 88e4166283SLuigi Rizzo nm_csum_fold(rawsum_t cur_sum) 89f0ea3689SLuigi Rizzo { 90f0ea3689SLuigi Rizzo /* TODO XXX please use the FreeBSD implementation for this. */ 91f0ea3689SLuigi Rizzo while (cur_sum >> 16) 92f0ea3689SLuigi Rizzo cur_sum = (cur_sum & 0xFFFF) + (cur_sum >> 16); 93f0ea3689SLuigi Rizzo 94f0ea3689SLuigi Rizzo return htobe16((~cur_sum) & 0xFFFF); 95f0ea3689SLuigi Rizzo } 96f0ea3689SLuigi Rizzo 974bf50f18SLuigi Rizzo uint16_t nm_csum_ipv4(struct nm_iphdr *iph) 98f0ea3689SLuigi Rizzo { 99f0ea3689SLuigi Rizzo #if 0 100f0ea3689SLuigi Rizzo return in_cksum_hdr((void *)iph); 101f0ea3689SLuigi Rizzo #else 102f0ea3689SLuigi Rizzo return nm_csum_fold(nm_csum_raw((uint8_t*)iph, sizeof(struct nm_iphdr), 0)); 103f0ea3689SLuigi Rizzo #endif 104f0ea3689SLuigi Rizzo } 105f0ea3689SLuigi Rizzo 106e4166283SLuigi Rizzo void 107e4166283SLuigi Rizzo nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, 108f0ea3689SLuigi Rizzo size_t datalen, uint16_t *check) 109f0ea3689SLuigi Rizzo { 1105a067ae1SLuigi Rizzo #ifdef INET 111f0ea3689SLuigi Rizzo uint16_t pseudolen = datalen + iph->protocol; 112f0ea3689SLuigi Rizzo 113f0ea3689SLuigi Rizzo /* Compute and insert the pseudo-header cheksum. */ 114f0ea3689SLuigi Rizzo *check = in_pseudo(iph->saddr, iph->daddr, 115f0ea3689SLuigi Rizzo htobe16(pseudolen)); 116f0ea3689SLuigi Rizzo /* Compute the checksum on TCP/UDP header + payload 117f0ea3689SLuigi Rizzo * (includes the pseudo-header). 118f0ea3689SLuigi Rizzo */ 119f0ea3689SLuigi Rizzo *check = nm_csum_fold(nm_csum_raw(data, datalen, 0)); 1205a067ae1SLuigi Rizzo #else 1215a067ae1SLuigi Rizzo static int notsupported = 0; 1225a067ae1SLuigi Rizzo if (!notsupported) { 1235a067ae1SLuigi Rizzo notsupported = 1; 1245a067ae1SLuigi Rizzo D("inet4 segmentation not supported"); 1255a067ae1SLuigi Rizzo } 1265a067ae1SLuigi Rizzo #endif 127f0ea3689SLuigi Rizzo } 128f0ea3689SLuigi Rizzo 129e4166283SLuigi Rizzo void 130e4166283SLuigi Rizzo nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, 131f0ea3689SLuigi Rizzo size_t datalen, uint16_t *check) 132f0ea3689SLuigi Rizzo { 133f0ea3689SLuigi Rizzo #ifdef INET6 134f0ea3689SLuigi Rizzo *check = in6_cksum_pseudo((void*)ip6h, datalen, ip6h->nexthdr, 0); 135f0ea3689SLuigi Rizzo *check = nm_csum_fold(nm_csum_raw(data, datalen, 0)); 136f0ea3689SLuigi Rizzo #else 137f0ea3689SLuigi Rizzo static int notsupported = 0; 138f0ea3689SLuigi Rizzo if (!notsupported) { 139f0ea3689SLuigi Rizzo notsupported = 1; 140f0ea3689SLuigi Rizzo D("inet6 segmentation not supported"); 141f0ea3689SLuigi Rizzo } 142f0ea3689SLuigi Rizzo #endif 143f0ea3689SLuigi Rizzo } 144f0ea3689SLuigi Rizzo 145f0ea3689SLuigi Rizzo 146f9790aebSLuigi Rizzo /* 147f9790aebSLuigi Rizzo * Intercept the rx routine in the standard device driver. 148f9790aebSLuigi Rizzo * Second argument is non-zero to intercept, 0 to restore 149f9790aebSLuigi Rizzo */ 150f9790aebSLuigi Rizzo int 151f9790aebSLuigi Rizzo netmap_catch_rx(struct netmap_adapter *na, int intercept) 152f9790aebSLuigi Rizzo { 1534bf50f18SLuigi Rizzo struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na; 154f9790aebSLuigi Rizzo struct ifnet *ifp = na->ifp; 155f9790aebSLuigi Rizzo 156f9790aebSLuigi Rizzo if (intercept) { 157f9790aebSLuigi Rizzo if (gna->save_if_input) { 158f9790aebSLuigi Rizzo D("cannot intercept again"); 159f9790aebSLuigi Rizzo return EINVAL; /* already set */ 160f9790aebSLuigi Rizzo } 161f9790aebSLuigi Rizzo gna->save_if_input = ifp->if_input; 162f9790aebSLuigi Rizzo ifp->if_input = generic_rx_handler; 163f9790aebSLuigi Rizzo } else { 164f9790aebSLuigi Rizzo if (!gna->save_if_input){ 165f9790aebSLuigi Rizzo D("cannot restore"); 166f9790aebSLuigi Rizzo return EINVAL; /* not saved */ 167f9790aebSLuigi Rizzo } 168f9790aebSLuigi Rizzo ifp->if_input = gna->save_if_input; 169f9790aebSLuigi Rizzo gna->save_if_input = NULL; 170f9790aebSLuigi Rizzo } 171f9790aebSLuigi Rizzo 172f9790aebSLuigi Rizzo return 0; 173f9790aebSLuigi Rizzo } 174f9790aebSLuigi Rizzo 17517885a7bSLuigi Rizzo 176f9790aebSLuigi Rizzo /* 177f9790aebSLuigi Rizzo * Intercept the packet steering routine in the tx path, 178f9790aebSLuigi Rizzo * so that we can decide which queue is used for an mbuf. 179f9790aebSLuigi Rizzo * Second argument is non-zero to intercept, 0 to restore. 180f0ea3689SLuigi Rizzo * On freebsd we just intercept if_transmit. 181f9790aebSLuigi Rizzo */ 182f9790aebSLuigi Rizzo void 18317885a7bSLuigi Rizzo netmap_catch_tx(struct netmap_generic_adapter *gna, int enable) 184f9790aebSLuigi Rizzo { 18517885a7bSLuigi Rizzo struct netmap_adapter *na = &gna->up.up; 18617885a7bSLuigi Rizzo struct ifnet *ifp = na->ifp; 18717885a7bSLuigi Rizzo 188f9790aebSLuigi Rizzo if (enable) { 18917885a7bSLuigi Rizzo na->if_transmit = ifp->if_transmit; 19017885a7bSLuigi Rizzo ifp->if_transmit = netmap_transmit; 191f9790aebSLuigi Rizzo } else { 19217885a7bSLuigi Rizzo ifp->if_transmit = na->if_transmit; 193f9790aebSLuigi Rizzo } 194f9790aebSLuigi Rizzo } 195f9790aebSLuigi Rizzo 19617885a7bSLuigi Rizzo 197f0ea3689SLuigi Rizzo /* 198f0ea3689SLuigi Rizzo * Transmit routine used by generic_netmap_txsync(). Returns 0 on success 199f9790aebSLuigi Rizzo * and non-zero on error (which may be packet drops or other errors). 200f9790aebSLuigi Rizzo * addr and len identify the netmap buffer, m is the (preallocated) 201f9790aebSLuigi Rizzo * mbuf to use for transmissions. 202f9790aebSLuigi Rizzo * 203f9790aebSLuigi Rizzo * We should add a reference to the mbuf so the m_freem() at the end 204f9790aebSLuigi Rizzo * of the transmission does not consume resources. 205f9790aebSLuigi Rizzo * 206f9790aebSLuigi Rizzo * On FreeBSD, and on multiqueue cards, we can force the queue using 207f9790aebSLuigi Rizzo * if ((m->m_flags & M_FLOWID) != 0) 208f9790aebSLuigi Rizzo * i = m->m_pkthdr.flowid % adapter->num_queues; 209f9790aebSLuigi Rizzo * else 210f9790aebSLuigi Rizzo * i = curcpu % adapter->num_queues; 211f9790aebSLuigi Rizzo * 212f9790aebSLuigi Rizzo */ 213f9790aebSLuigi Rizzo int 214f9790aebSLuigi Rizzo generic_xmit_frame(struct ifnet *ifp, struct mbuf *m, 215f9790aebSLuigi Rizzo void *addr, u_int len, u_int ring_nr) 216f9790aebSLuigi Rizzo { 217f9790aebSLuigi Rizzo int ret; 218f9790aebSLuigi Rizzo 219e4166283SLuigi Rizzo /* 220e4166283SLuigi Rizzo * The mbuf should be a cluster from our special pool, 221e4166283SLuigi Rizzo * so we do not need to do an m_copyback but just copy 222e4166283SLuigi Rizzo * (and eventually, just reference the netmap buffer) 223e4166283SLuigi Rizzo */ 224f9790aebSLuigi Rizzo 2254bf50f18SLuigi Rizzo if (GET_MBUF_REFCNT(m) != 1) { 226e4166283SLuigi Rizzo D("invalid refcnt %d for %p", 2274bf50f18SLuigi Rizzo GET_MBUF_REFCNT(m), m); 228e4166283SLuigi Rizzo panic("in generic_xmit_frame"); 229e4166283SLuigi Rizzo } 230e4166283SLuigi Rizzo // XXX the ext_size check is unnecessary if we link the netmap buf 231e4166283SLuigi Rizzo if (m->m_ext.ext_size < len) { 232e4166283SLuigi Rizzo RD(5, "size %d < len %d", m->m_ext.ext_size, len); 233e4166283SLuigi Rizzo len = m->m_ext.ext_size; 234e4166283SLuigi Rizzo } 235e4166283SLuigi Rizzo if (0) { /* XXX seems to have negligible benefits */ 236e4166283SLuigi Rizzo m->m_ext.ext_buf = m->m_data = addr; 237e4166283SLuigi Rizzo } else { 238e4166283SLuigi Rizzo bcopy(addr, m->m_data, len); 239e4166283SLuigi Rizzo } 240e4166283SLuigi Rizzo m->m_len = m->m_pkthdr.len = len; 241e4166283SLuigi Rizzo // inc refcount. All ours, we could skip the atomic 2424bf50f18SLuigi Rizzo atomic_fetchadd_int(PNT_MBUF_REFCNT(m), 1); 243f9790aebSLuigi Rizzo m->m_flags |= M_FLOWID; 244f9790aebSLuigi Rizzo m->m_pkthdr.flowid = ring_nr; 245f9790aebSLuigi Rizzo m->m_pkthdr.rcvif = ifp; /* used for tx notification */ 24617885a7bSLuigi Rizzo ret = NA(ifp)->if_transmit(ifp, m); 247f9790aebSLuigi Rizzo return ret; 248f9790aebSLuigi Rizzo } 249f9790aebSLuigi Rizzo 25017885a7bSLuigi Rizzo 2510dc809c0SLuigi Rizzo #if __FreeBSD_version >= 1100005 2520dc809c0SLuigi Rizzo struct netmap_adapter * 2530dc809c0SLuigi Rizzo netmap_getna(if_t ifp) 2540dc809c0SLuigi Rizzo { 2550dc809c0SLuigi Rizzo return (NA((struct ifnet *)ifp)); 2560dc809c0SLuigi Rizzo } 2570dc809c0SLuigi Rizzo #endif /* __FreeBSD_version >= 1100005 */ 2580dc809c0SLuigi Rizzo 259f9790aebSLuigi Rizzo /* 260f9790aebSLuigi Rizzo * The following two functions are empty until we have a generic 261f9790aebSLuigi Rizzo * way to extract the info from the ifp 262f9790aebSLuigi Rizzo */ 263f9790aebSLuigi Rizzo int 264f9790aebSLuigi Rizzo generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx) 265f9790aebSLuigi Rizzo { 266e4166283SLuigi Rizzo D("called, in tx %d rx %d", *tx, *rx); 267f9790aebSLuigi Rizzo return 0; 268f9790aebSLuigi Rizzo } 269f9790aebSLuigi Rizzo 27017885a7bSLuigi Rizzo 271f9790aebSLuigi Rizzo void 272f9790aebSLuigi Rizzo generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq) 273f9790aebSLuigi Rizzo { 274e4166283SLuigi Rizzo D("called, in txq %d rxq %d", *txq, *rxq); 275f0ea3689SLuigi Rizzo *txq = netmap_generic_rings; 276f0ea3689SLuigi Rizzo *rxq = netmap_generic_rings; 277f9790aebSLuigi Rizzo } 278f9790aebSLuigi Rizzo 27917885a7bSLuigi Rizzo 280e4166283SLuigi Rizzo void 2814bf50f18SLuigi Rizzo netmap_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na) 282f9790aebSLuigi Rizzo { 283f9790aebSLuigi Rizzo ND("called"); 284f0ea3689SLuigi Rizzo mit->mit_pending = 0; 2854bf50f18SLuigi Rizzo mit->mit_ring_idx = idx; 286f0ea3689SLuigi Rizzo mit->mit_na = na; 287f9790aebSLuigi Rizzo } 288f9790aebSLuigi Rizzo 289f9790aebSLuigi Rizzo 290e4166283SLuigi Rizzo void 291e4166283SLuigi Rizzo netmap_mitigation_start(struct nm_generic_mit *mit) 292f9790aebSLuigi Rizzo { 293f9790aebSLuigi Rizzo ND("called"); 294f9790aebSLuigi Rizzo } 295f9790aebSLuigi Rizzo 29617885a7bSLuigi Rizzo 297e4166283SLuigi Rizzo void 298e4166283SLuigi Rizzo netmap_mitigation_restart(struct nm_generic_mit *mit) 299f9790aebSLuigi Rizzo { 300f9790aebSLuigi Rizzo ND("called"); 301f9790aebSLuigi Rizzo } 302f9790aebSLuigi Rizzo 30317885a7bSLuigi Rizzo 304e4166283SLuigi Rizzo int 305e4166283SLuigi Rizzo netmap_mitigation_active(struct nm_generic_mit *mit) 306f9790aebSLuigi Rizzo { 307f9790aebSLuigi Rizzo ND("called"); 308f9790aebSLuigi Rizzo return 0; 309f9790aebSLuigi Rizzo } 310f9790aebSLuigi Rizzo 31117885a7bSLuigi Rizzo 312e4166283SLuigi Rizzo void 313e4166283SLuigi Rizzo netmap_mitigation_cleanup(struct nm_generic_mit *mit) 314f9790aebSLuigi Rizzo { 315f9790aebSLuigi Rizzo ND("called"); 316f9790aebSLuigi Rizzo } 317f9790aebSLuigi Rizzo 3184bf50f18SLuigi Rizzo static int 3194bf50f18SLuigi Rizzo nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) 3204bf50f18SLuigi Rizzo { 3214bf50f18SLuigi Rizzo return EINVAL; 3224bf50f18SLuigi Rizzo } 3234bf50f18SLuigi Rizzo 3244bf50f18SLuigi Rizzo static void 3254bf50f18SLuigi Rizzo nm_vi_start(struct ifnet *ifp) 3264bf50f18SLuigi Rizzo { 3274bf50f18SLuigi Rizzo panic("nm_vi_start() must not be called"); 3284bf50f18SLuigi Rizzo } 3294bf50f18SLuigi Rizzo 3304bf50f18SLuigi Rizzo /* 3314bf50f18SLuigi Rizzo * Index manager of persistent virtual interfaces. 3324bf50f18SLuigi Rizzo * It is used to decide the lowest byte of the MAC address. 3334bf50f18SLuigi Rizzo * We use the same algorithm with management of bridge port index. 3344bf50f18SLuigi Rizzo */ 3354bf50f18SLuigi Rizzo #define NM_VI_MAX 255 3364bf50f18SLuigi Rizzo static struct { 3374bf50f18SLuigi Rizzo uint8_t index[NM_VI_MAX]; /* XXX just for a reasonable number */ 3384bf50f18SLuigi Rizzo uint8_t active; 3394bf50f18SLuigi Rizzo struct mtx lock; 3404bf50f18SLuigi Rizzo } nm_vi_indices; 3414bf50f18SLuigi Rizzo 3424bf50f18SLuigi Rizzo void 3434bf50f18SLuigi Rizzo nm_vi_init_index(void) 3444bf50f18SLuigi Rizzo { 3454bf50f18SLuigi Rizzo int i; 3464bf50f18SLuigi Rizzo for (i = 0; i < NM_VI_MAX; i++) 3474bf50f18SLuigi Rizzo nm_vi_indices.index[i] = i; 3484bf50f18SLuigi Rizzo nm_vi_indices.active = 0; 3494bf50f18SLuigi Rizzo mtx_init(&nm_vi_indices.lock, "nm_vi_indices_lock", NULL, MTX_DEF); 3504bf50f18SLuigi Rizzo } 3514bf50f18SLuigi Rizzo 3524bf50f18SLuigi Rizzo /* return -1 if no index available */ 3534bf50f18SLuigi Rizzo static int 3544bf50f18SLuigi Rizzo nm_vi_get_index(void) 3554bf50f18SLuigi Rizzo { 3564bf50f18SLuigi Rizzo int ret; 3574bf50f18SLuigi Rizzo 3584bf50f18SLuigi Rizzo mtx_lock(&nm_vi_indices.lock); 3594bf50f18SLuigi Rizzo ret = nm_vi_indices.active == NM_VI_MAX ? -1 : 3604bf50f18SLuigi Rizzo nm_vi_indices.index[nm_vi_indices.active++]; 3614bf50f18SLuigi Rizzo mtx_unlock(&nm_vi_indices.lock); 3624bf50f18SLuigi Rizzo return ret; 3634bf50f18SLuigi Rizzo } 3644bf50f18SLuigi Rizzo 3654bf50f18SLuigi Rizzo static void 3664bf50f18SLuigi Rizzo nm_vi_free_index(uint8_t val) 3674bf50f18SLuigi Rizzo { 3684bf50f18SLuigi Rizzo int i, lim; 3694bf50f18SLuigi Rizzo 3704bf50f18SLuigi Rizzo mtx_lock(&nm_vi_indices.lock); 3714bf50f18SLuigi Rizzo lim = nm_vi_indices.active; 3724bf50f18SLuigi Rizzo for (i = 0; i < lim; i++) { 3734bf50f18SLuigi Rizzo if (nm_vi_indices.index[i] == val) { 3744bf50f18SLuigi Rizzo /* swap index[lim-1] and j */ 3754bf50f18SLuigi Rizzo int tmp = nm_vi_indices.index[lim-1]; 3764bf50f18SLuigi Rizzo nm_vi_indices.index[lim-1] = val; 3774bf50f18SLuigi Rizzo nm_vi_indices.index[i] = tmp; 3784bf50f18SLuigi Rizzo nm_vi_indices.active--; 3794bf50f18SLuigi Rizzo break; 3804bf50f18SLuigi Rizzo } 3814bf50f18SLuigi Rizzo } 3824bf50f18SLuigi Rizzo if (lim == nm_vi_indices.active) 3834bf50f18SLuigi Rizzo D("funny, index %u didn't found", val); 3844bf50f18SLuigi Rizzo mtx_unlock(&nm_vi_indices.lock); 3854bf50f18SLuigi Rizzo } 3864bf50f18SLuigi Rizzo #undef NM_VI_MAX 3874bf50f18SLuigi Rizzo 3884bf50f18SLuigi Rizzo /* 3894bf50f18SLuigi Rizzo * Implementation of a netmap-capable virtual interface that 3904bf50f18SLuigi Rizzo * registered to the system. 3914bf50f18SLuigi Rizzo * It is based on if_tap.c and ip_fw_log.c in FreeBSD 9. 3924bf50f18SLuigi Rizzo * 3934bf50f18SLuigi Rizzo * Note: Linux sets refcount to 0 on allocation of net_device, 3944bf50f18SLuigi Rizzo * then increments it on registration to the system. 3954bf50f18SLuigi Rizzo * FreeBSD sets refcount to 1 on if_alloc(), and does not 3964bf50f18SLuigi Rizzo * increment this refcount on if_attach(). 3974bf50f18SLuigi Rizzo */ 3984bf50f18SLuigi Rizzo int 3994bf50f18SLuigi Rizzo nm_vi_persist(const char *name, struct ifnet **ret) 4004bf50f18SLuigi Rizzo { 4014bf50f18SLuigi Rizzo struct ifnet *ifp; 4024bf50f18SLuigi Rizzo u_short macaddr_hi; 4034bf50f18SLuigi Rizzo uint32_t macaddr_mid; 4044bf50f18SLuigi Rizzo u_char eaddr[6]; 4054bf50f18SLuigi Rizzo int unit = nm_vi_get_index(); /* just to decide MAC address */ 4064bf50f18SLuigi Rizzo 4074bf50f18SLuigi Rizzo if (unit < 0) 4084bf50f18SLuigi Rizzo return EBUSY; 4094bf50f18SLuigi Rizzo /* 4104bf50f18SLuigi Rizzo * We use the same MAC address generation method with tap 4114bf50f18SLuigi Rizzo * except for the highest octet is 00:be instead of 00:bd 4124bf50f18SLuigi Rizzo */ 4134bf50f18SLuigi Rizzo macaddr_hi = htons(0x00be); /* XXX tap + 1 */ 4144bf50f18SLuigi Rizzo macaddr_mid = (uint32_t) ticks; 4154bf50f18SLuigi Rizzo bcopy(&macaddr_hi, eaddr, sizeof(short)); 4164bf50f18SLuigi Rizzo bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t)); 4174bf50f18SLuigi Rizzo eaddr[5] = (uint8_t)unit; 4184bf50f18SLuigi Rizzo 4194bf50f18SLuigi Rizzo ifp = if_alloc(IFT_ETHER); 4204bf50f18SLuigi Rizzo if (ifp == NULL) { 4214bf50f18SLuigi Rizzo D("if_alloc failed"); 4224bf50f18SLuigi Rizzo return ENOMEM; 4234bf50f18SLuigi Rizzo } 4244bf50f18SLuigi Rizzo if_initname(ifp, name, IF_DUNIT_NONE); 4254bf50f18SLuigi Rizzo ifp->if_mtu = 65536; 4264bf50f18SLuigi Rizzo ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; 4274bf50f18SLuigi Rizzo ifp->if_init = (void *)nm_vi_dummy; 4284bf50f18SLuigi Rizzo ifp->if_ioctl = nm_vi_dummy; 4294bf50f18SLuigi Rizzo ifp->if_start = nm_vi_start; 4304bf50f18SLuigi Rizzo ifp->if_mtu = ETHERMTU; 4314bf50f18SLuigi Rizzo IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 4324bf50f18SLuigi Rizzo ifp->if_capabilities |= IFCAP_LINKSTATE; 4334bf50f18SLuigi Rizzo ifp->if_capenable |= IFCAP_LINKSTATE; 4344bf50f18SLuigi Rizzo 4354bf50f18SLuigi Rizzo ether_ifattach(ifp, eaddr); 4364bf50f18SLuigi Rizzo *ret = ifp; 4374bf50f18SLuigi Rizzo return 0; 4384bf50f18SLuigi Rizzo } 4394bf50f18SLuigi Rizzo /* unregister from the system and drop the final refcount */ 4404bf50f18SLuigi Rizzo void 4414bf50f18SLuigi Rizzo nm_vi_detach(struct ifnet *ifp) 4424bf50f18SLuigi Rizzo { 4434bf50f18SLuigi Rizzo nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]); 4444bf50f18SLuigi Rizzo ether_ifdetach(ifp); 4454bf50f18SLuigi Rizzo if_free(ifp); 4464bf50f18SLuigi Rizzo } 44717885a7bSLuigi Rizzo 448f9790aebSLuigi Rizzo /* 449f9790aebSLuigi Rizzo * In order to track whether pages are still mapped, we hook into 450f9790aebSLuigi Rizzo * the standard cdev_pager and intercept the constructor and 451f9790aebSLuigi Rizzo * destructor. 452f9790aebSLuigi Rizzo */ 453f9790aebSLuigi Rizzo 454f9790aebSLuigi Rizzo struct netmap_vm_handle_t { 455f9790aebSLuigi Rizzo struct cdev *dev; 456f9790aebSLuigi Rizzo struct netmap_priv_d *priv; 457f9790aebSLuigi Rizzo }; 458f9790aebSLuigi Rizzo 45917885a7bSLuigi Rizzo 460f9790aebSLuigi Rizzo static int 461f9790aebSLuigi Rizzo netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, 462f9790aebSLuigi Rizzo vm_ooffset_t foff, struct ucred *cred, u_short *color) 463f9790aebSLuigi Rizzo { 464f9790aebSLuigi Rizzo struct netmap_vm_handle_t *vmh = handle; 465f0ea3689SLuigi Rizzo 466f0ea3689SLuigi Rizzo if (netmap_verbose) 467f9790aebSLuigi Rizzo D("handle %p size %jd prot %d foff %jd", 468f9790aebSLuigi Rizzo handle, (intmax_t)size, prot, (intmax_t)foff); 469*4e93beffSLuigi Rizzo if (color) 470*4e93beffSLuigi Rizzo *color = 0; 471f9790aebSLuigi Rizzo dev_ref(vmh->dev); 472f9790aebSLuigi Rizzo return 0; 473f9790aebSLuigi Rizzo } 474f9790aebSLuigi Rizzo 475f9790aebSLuigi Rizzo 476f9790aebSLuigi Rizzo static void 477f9790aebSLuigi Rizzo netmap_dev_pager_dtor(void *handle) 478f9790aebSLuigi Rizzo { 479f9790aebSLuigi Rizzo struct netmap_vm_handle_t *vmh = handle; 480f9790aebSLuigi Rizzo struct cdev *dev = vmh->dev; 481f9790aebSLuigi Rizzo struct netmap_priv_d *priv = vmh->priv; 482f0ea3689SLuigi Rizzo 483f0ea3689SLuigi Rizzo if (netmap_verbose) 484f9790aebSLuigi Rizzo D("handle %p", handle); 485f9790aebSLuigi Rizzo netmap_dtor(priv); 486f9790aebSLuigi Rizzo free(vmh, M_DEVBUF); 487f9790aebSLuigi Rizzo dev_rel(dev); 488f9790aebSLuigi Rizzo } 489f9790aebSLuigi Rizzo 49017885a7bSLuigi Rizzo 491f9790aebSLuigi Rizzo static int 492f9790aebSLuigi Rizzo netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset, 493f9790aebSLuigi Rizzo int prot, vm_page_t *mres) 494f9790aebSLuigi Rizzo { 495f9790aebSLuigi Rizzo struct netmap_vm_handle_t *vmh = object->handle; 496f9790aebSLuigi Rizzo struct netmap_priv_d *priv = vmh->priv; 497f9790aebSLuigi Rizzo vm_paddr_t paddr; 498f9790aebSLuigi Rizzo vm_page_t page; 499f9790aebSLuigi Rizzo vm_memattr_t memattr; 500f9790aebSLuigi Rizzo vm_pindex_t pidx; 501f9790aebSLuigi Rizzo 502f9790aebSLuigi Rizzo ND("object %p offset %jd prot %d mres %p", 503f9790aebSLuigi Rizzo object, (intmax_t)offset, prot, mres); 504f9790aebSLuigi Rizzo memattr = object->memattr; 505f9790aebSLuigi Rizzo pidx = OFF_TO_IDX(offset); 506f9790aebSLuigi Rizzo paddr = netmap_mem_ofstophys(priv->np_mref, offset); 507f9790aebSLuigi Rizzo if (paddr == 0) 508f9790aebSLuigi Rizzo return VM_PAGER_FAIL; 509f9790aebSLuigi Rizzo 510f9790aebSLuigi Rizzo if (((*mres)->flags & PG_FICTITIOUS) != 0) { 511f9790aebSLuigi Rizzo /* 512f9790aebSLuigi Rizzo * If the passed in result page is a fake page, update it with 513f9790aebSLuigi Rizzo * the new physical address. 514f9790aebSLuigi Rizzo */ 515f9790aebSLuigi Rizzo page = *mres; 516f9790aebSLuigi Rizzo vm_page_updatefake(page, paddr, memattr); 517f9790aebSLuigi Rizzo } else { 518f9790aebSLuigi Rizzo /* 519f9790aebSLuigi Rizzo * Replace the passed in reqpage page with our own fake page and 520f9790aebSLuigi Rizzo * free up the all of the original pages. 521f9790aebSLuigi Rizzo */ 522f9790aebSLuigi Rizzo #ifndef VM_OBJECT_WUNLOCK /* FreeBSD < 10.x */ 523f9790aebSLuigi Rizzo #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK 524f9790aebSLuigi Rizzo #define VM_OBJECT_WLOCK VM_OBJECT_LOCK 525f9790aebSLuigi Rizzo #endif /* VM_OBJECT_WUNLOCK */ 526f9790aebSLuigi Rizzo 527f9790aebSLuigi Rizzo VM_OBJECT_WUNLOCK(object); 528f9790aebSLuigi Rizzo page = vm_page_getfake(paddr, memattr); 529f9790aebSLuigi Rizzo VM_OBJECT_WLOCK(object); 530f9790aebSLuigi Rizzo vm_page_lock(*mres); 531f9790aebSLuigi Rizzo vm_page_free(*mres); 532f9790aebSLuigi Rizzo vm_page_unlock(*mres); 533f9790aebSLuigi Rizzo *mres = page; 534f9790aebSLuigi Rizzo vm_page_insert(page, object, pidx); 535f9790aebSLuigi Rizzo } 536f9790aebSLuigi Rizzo page->valid = VM_PAGE_BITS_ALL; 537f9790aebSLuigi Rizzo return (VM_PAGER_OK); 538f9790aebSLuigi Rizzo } 539f9790aebSLuigi Rizzo 540f9790aebSLuigi Rizzo 541f9790aebSLuigi Rizzo static struct cdev_pager_ops netmap_cdev_pager_ops = { 542f9790aebSLuigi Rizzo .cdev_pg_ctor = netmap_dev_pager_ctor, 543f9790aebSLuigi Rizzo .cdev_pg_dtor = netmap_dev_pager_dtor, 544f9790aebSLuigi Rizzo .cdev_pg_fault = netmap_dev_pager_fault, 545f9790aebSLuigi Rizzo }; 546f9790aebSLuigi Rizzo 547f9790aebSLuigi Rizzo 548f9790aebSLuigi Rizzo static int 549f9790aebSLuigi Rizzo netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff, 550f9790aebSLuigi Rizzo vm_size_t objsize, vm_object_t *objp, int prot) 551f9790aebSLuigi Rizzo { 552f9790aebSLuigi Rizzo int error; 553f9790aebSLuigi Rizzo struct netmap_vm_handle_t *vmh; 554f9790aebSLuigi Rizzo struct netmap_priv_d *priv; 555f9790aebSLuigi Rizzo vm_object_t obj; 556f9790aebSLuigi Rizzo 557f0ea3689SLuigi Rizzo if (netmap_verbose) 558f9790aebSLuigi Rizzo D("cdev %p foff %jd size %jd objp %p prot %d", cdev, 559f9790aebSLuigi Rizzo (intmax_t )*foff, (intmax_t )objsize, objp, prot); 560f9790aebSLuigi Rizzo 561f9790aebSLuigi Rizzo vmh = malloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF, 562f9790aebSLuigi Rizzo M_NOWAIT | M_ZERO); 563f9790aebSLuigi Rizzo if (vmh == NULL) 564f9790aebSLuigi Rizzo return ENOMEM; 565f9790aebSLuigi Rizzo vmh->dev = cdev; 566f9790aebSLuigi Rizzo 567f9790aebSLuigi Rizzo NMG_LOCK(); 568f9790aebSLuigi Rizzo error = devfs_get_cdevpriv((void**)&priv); 569f9790aebSLuigi Rizzo if (error) 570f9790aebSLuigi Rizzo goto err_unlock; 571f9790aebSLuigi Rizzo vmh->priv = priv; 572f9790aebSLuigi Rizzo priv->np_refcount++; 573f9790aebSLuigi Rizzo NMG_UNLOCK(); 574f9790aebSLuigi Rizzo 575f9790aebSLuigi Rizzo error = netmap_get_memory(priv); 576f9790aebSLuigi Rizzo if (error) 577f9790aebSLuigi Rizzo goto err_deref; 578f9790aebSLuigi Rizzo 579f9790aebSLuigi Rizzo obj = cdev_pager_allocate(vmh, OBJT_DEVICE, 580f9790aebSLuigi Rizzo &netmap_cdev_pager_ops, objsize, prot, 581f9790aebSLuigi Rizzo *foff, NULL); 582f9790aebSLuigi Rizzo if (obj == NULL) { 583f9790aebSLuigi Rizzo D("cdev_pager_allocate failed"); 584f9790aebSLuigi Rizzo error = EINVAL; 585f9790aebSLuigi Rizzo goto err_deref; 586f9790aebSLuigi Rizzo } 587f9790aebSLuigi Rizzo 588f9790aebSLuigi Rizzo *objp = obj; 589f9790aebSLuigi Rizzo return 0; 590f9790aebSLuigi Rizzo 591f9790aebSLuigi Rizzo err_deref: 592f9790aebSLuigi Rizzo NMG_LOCK(); 593f9790aebSLuigi Rizzo priv->np_refcount--; 594f9790aebSLuigi Rizzo err_unlock: 595f9790aebSLuigi Rizzo NMG_UNLOCK(); 596f9790aebSLuigi Rizzo // err: 597f9790aebSLuigi Rizzo free(vmh, M_DEVBUF); 598f9790aebSLuigi Rizzo return error; 599f9790aebSLuigi Rizzo } 600f9790aebSLuigi Rizzo 601f9790aebSLuigi Rizzo 602f9790aebSLuigi Rizzo // XXX can we remove this ? 603f9790aebSLuigi Rizzo static int 604f9790aebSLuigi Rizzo netmap_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 605f9790aebSLuigi Rizzo { 606f9790aebSLuigi Rizzo if (netmap_verbose) 607f9790aebSLuigi Rizzo D("dev %p fflag 0x%x devtype %d td %p", 608f9790aebSLuigi Rizzo dev, fflag, devtype, td); 609f9790aebSLuigi Rizzo return 0; 610f9790aebSLuigi Rizzo } 611f9790aebSLuigi Rizzo 612f9790aebSLuigi Rizzo 613f9790aebSLuigi Rizzo static int 614f9790aebSLuigi Rizzo netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 615f9790aebSLuigi Rizzo { 616f9790aebSLuigi Rizzo struct netmap_priv_d *priv; 617f9790aebSLuigi Rizzo int error; 618f9790aebSLuigi Rizzo 619f9790aebSLuigi Rizzo (void)dev; 620f9790aebSLuigi Rizzo (void)oflags; 621f9790aebSLuigi Rizzo (void)devtype; 622f9790aebSLuigi Rizzo (void)td; 623f9790aebSLuigi Rizzo 624f9790aebSLuigi Rizzo // XXX wait or nowait ? 625f9790aebSLuigi Rizzo priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF, 626f9790aebSLuigi Rizzo M_NOWAIT | M_ZERO); 627f9790aebSLuigi Rizzo if (priv == NULL) 628f9790aebSLuigi Rizzo return ENOMEM; 629f9790aebSLuigi Rizzo 630f9790aebSLuigi Rizzo error = devfs_set_cdevpriv(priv, netmap_dtor); 631f9790aebSLuigi Rizzo if (error) 632f9790aebSLuigi Rizzo return error; 633f9790aebSLuigi Rizzo 634f9790aebSLuigi Rizzo priv->np_refcount = 1; 635f9790aebSLuigi Rizzo 636f9790aebSLuigi Rizzo return 0; 637f9790aebSLuigi Rizzo } 638f9790aebSLuigi Rizzo 639f0ea3689SLuigi Rizzo /******************** kqueue support ****************/ 640f0ea3689SLuigi Rizzo 641f0ea3689SLuigi Rizzo /* 642f0ea3689SLuigi Rizzo * The OS_selwakeup also needs to issue a KNOTE_UNLOCKED. 643f0ea3689SLuigi Rizzo * We use a non-zero argument to distinguish the call from the one 644f0ea3689SLuigi Rizzo * in kevent_scan() which instead also needs to run netmap_poll(). 645f0ea3689SLuigi Rizzo * The knote uses a global mutex for the time being. We might 646f0ea3689SLuigi Rizzo * try to reuse the one in the si, but it is not allocated 647f0ea3689SLuigi Rizzo * permanently so it might be a bit tricky. 648f0ea3689SLuigi Rizzo * 649f0ea3689SLuigi Rizzo * The *kqfilter function registers one or another f_event 650f0ea3689SLuigi Rizzo * depending on read or write mode. 651f0ea3689SLuigi Rizzo * In the call to f_event() td_fpop is NULL so any child function 652f0ea3689SLuigi Rizzo * calling devfs_get_cdevpriv() would fail - and we need it in 653f0ea3689SLuigi Rizzo * netmap_poll(). As a workaround we store priv into kn->kn_hook 654f0ea3689SLuigi Rizzo * and pass it as first argument to netmap_poll(), which then 655f0ea3689SLuigi Rizzo * uses the failure to tell that we are called from f_event() 656f0ea3689SLuigi Rizzo * and do not need the selrecord(). 657f0ea3689SLuigi Rizzo */ 658f0ea3689SLuigi Rizzo 659f0ea3689SLuigi Rizzo void freebsd_selwakeup(struct selinfo *si, int pri); 660f0ea3689SLuigi Rizzo 661f0ea3689SLuigi Rizzo void 662f0ea3689SLuigi Rizzo freebsd_selwakeup(struct selinfo *si, int pri) 663f0ea3689SLuigi Rizzo { 664f0ea3689SLuigi Rizzo if (netmap_verbose) 665f0ea3689SLuigi Rizzo D("on knote %p", &si->si_note); 666f0ea3689SLuigi Rizzo selwakeuppri(si, pri); 667f0ea3689SLuigi Rizzo /* use a non-zero hint to tell the notification from the 668f0ea3689SLuigi Rizzo * call done in kqueue_scan() which uses 0 669f0ea3689SLuigi Rizzo */ 670f0ea3689SLuigi Rizzo KNOTE_UNLOCKED(&si->si_note, 0x100 /* notification */); 671f0ea3689SLuigi Rizzo } 672f0ea3689SLuigi Rizzo 673f0ea3689SLuigi Rizzo static void 674f0ea3689SLuigi Rizzo netmap_knrdetach(struct knote *kn) 675f0ea3689SLuigi Rizzo { 676f0ea3689SLuigi Rizzo struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; 677f0ea3689SLuigi Rizzo struct selinfo *si = priv->np_rxsi; 678f0ea3689SLuigi Rizzo 679f0ea3689SLuigi Rizzo D("remove selinfo %p", si); 680f0ea3689SLuigi Rizzo knlist_remove(&si->si_note, kn, 0); 681f0ea3689SLuigi Rizzo } 682f0ea3689SLuigi Rizzo 683f0ea3689SLuigi Rizzo static void 684f0ea3689SLuigi Rizzo netmap_knwdetach(struct knote *kn) 685f0ea3689SLuigi Rizzo { 686f0ea3689SLuigi Rizzo struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; 687f0ea3689SLuigi Rizzo struct selinfo *si = priv->np_txsi; 688f0ea3689SLuigi Rizzo 689f0ea3689SLuigi Rizzo D("remove selinfo %p", si); 690f0ea3689SLuigi Rizzo knlist_remove(&si->si_note, kn, 0); 691f0ea3689SLuigi Rizzo } 692f0ea3689SLuigi Rizzo 693f0ea3689SLuigi Rizzo /* 694f0ea3689SLuigi Rizzo * callback from notifies (generated externally) and our 695f0ea3689SLuigi Rizzo * calls to kevent(). The former we just return 1 (ready) 696f0ea3689SLuigi Rizzo * since we do not know better. 697f0ea3689SLuigi Rizzo * In the latter we call netmap_poll and return 0/1 accordingly. 698f0ea3689SLuigi Rizzo */ 699f0ea3689SLuigi Rizzo static int 700f0ea3689SLuigi Rizzo netmap_knrw(struct knote *kn, long hint, int events) 701f0ea3689SLuigi Rizzo { 702f0ea3689SLuigi Rizzo struct netmap_priv_d *priv; 703f0ea3689SLuigi Rizzo int revents; 704f0ea3689SLuigi Rizzo 705f0ea3689SLuigi Rizzo if (hint != 0) { 706f0ea3689SLuigi Rizzo ND(5, "call from notify"); 707f0ea3689SLuigi Rizzo return 1; /* assume we are ready */ 708f0ea3689SLuigi Rizzo } 709f0ea3689SLuigi Rizzo priv = kn->kn_hook; 710f0ea3689SLuigi Rizzo /* the notification may come from an external thread, 711f0ea3689SLuigi Rizzo * in which case we do not want to run the netmap_poll 712f0ea3689SLuigi Rizzo * This should be filtered above, but check just in case. 713f0ea3689SLuigi Rizzo */ 714f0ea3689SLuigi Rizzo if (curthread != priv->np_td) { /* should not happen */ 715f0ea3689SLuigi Rizzo RD(5, "curthread changed %p %p", curthread, priv->np_td); 716f0ea3689SLuigi Rizzo return 1; 717f0ea3689SLuigi Rizzo } else { 718f0ea3689SLuigi Rizzo revents = netmap_poll((void *)priv, events, curthread); 719f0ea3689SLuigi Rizzo return (events & revents) ? 1 : 0; 720f0ea3689SLuigi Rizzo } 721f0ea3689SLuigi Rizzo } 722f0ea3689SLuigi Rizzo 723f0ea3689SLuigi Rizzo static int 724f0ea3689SLuigi Rizzo netmap_knread(struct knote *kn, long hint) 725f0ea3689SLuigi Rizzo { 726f0ea3689SLuigi Rizzo return netmap_knrw(kn, hint, POLLIN); 727f0ea3689SLuigi Rizzo } 728f0ea3689SLuigi Rizzo 729f0ea3689SLuigi Rizzo static int 730f0ea3689SLuigi Rizzo netmap_knwrite(struct knote *kn, long hint) 731f0ea3689SLuigi Rizzo { 732f0ea3689SLuigi Rizzo return netmap_knrw(kn, hint, POLLOUT); 733f0ea3689SLuigi Rizzo } 734f0ea3689SLuigi Rizzo 735f0ea3689SLuigi Rizzo static struct filterops netmap_rfiltops = { 736f0ea3689SLuigi Rizzo .f_isfd = 1, 737f0ea3689SLuigi Rizzo .f_detach = netmap_knrdetach, 738f0ea3689SLuigi Rizzo .f_event = netmap_knread, 739f0ea3689SLuigi Rizzo }; 740f0ea3689SLuigi Rizzo 741f0ea3689SLuigi Rizzo static struct filterops netmap_wfiltops = { 742f0ea3689SLuigi Rizzo .f_isfd = 1, 743f0ea3689SLuigi Rizzo .f_detach = netmap_knwdetach, 744f0ea3689SLuigi Rizzo .f_event = netmap_knwrite, 745f0ea3689SLuigi Rizzo }; 746f0ea3689SLuigi Rizzo 747f0ea3689SLuigi Rizzo 748f0ea3689SLuigi Rizzo /* 749f0ea3689SLuigi Rizzo * This is called when a thread invokes kevent() to record 750f0ea3689SLuigi Rizzo * a change in the configuration of the kqueue(). 751f0ea3689SLuigi Rizzo * The 'priv' should be the same as in the netmap device. 752f0ea3689SLuigi Rizzo */ 753f0ea3689SLuigi Rizzo static int 754f0ea3689SLuigi Rizzo netmap_kqfilter(struct cdev *dev, struct knote *kn) 755f0ea3689SLuigi Rizzo { 756f0ea3689SLuigi Rizzo struct netmap_priv_d *priv; 757f0ea3689SLuigi Rizzo int error; 758f0ea3689SLuigi Rizzo struct netmap_adapter *na; 759f0ea3689SLuigi Rizzo struct selinfo *si; 760f0ea3689SLuigi Rizzo int ev = kn->kn_filter; 761f0ea3689SLuigi Rizzo 762f0ea3689SLuigi Rizzo if (ev != EVFILT_READ && ev != EVFILT_WRITE) { 763f0ea3689SLuigi Rizzo D("bad filter request %d", ev); 764f0ea3689SLuigi Rizzo return 1; 765f0ea3689SLuigi Rizzo } 766f0ea3689SLuigi Rizzo error = devfs_get_cdevpriv((void**)&priv); 767f0ea3689SLuigi Rizzo if (error) { 768f0ea3689SLuigi Rizzo D("device not yet setup"); 769f0ea3689SLuigi Rizzo return 1; 770f0ea3689SLuigi Rizzo } 771f0ea3689SLuigi Rizzo na = priv->np_na; 772f0ea3689SLuigi Rizzo if (na == NULL) { 773f0ea3689SLuigi Rizzo D("no netmap adapter for this file descriptor"); 774f0ea3689SLuigi Rizzo return 1; 775f0ea3689SLuigi Rizzo } 776f0ea3689SLuigi Rizzo /* the si is indicated in the priv */ 777f0ea3689SLuigi Rizzo si = (ev == EVFILT_WRITE) ? priv->np_txsi : priv->np_rxsi; 778f0ea3689SLuigi Rizzo // XXX lock(priv) ? 779f0ea3689SLuigi Rizzo kn->kn_fop = (ev == EVFILT_WRITE) ? 780f0ea3689SLuigi Rizzo &netmap_wfiltops : &netmap_rfiltops; 781f0ea3689SLuigi Rizzo kn->kn_hook = priv; 782f0ea3689SLuigi Rizzo knlist_add(&si->si_note, kn, 1); 783f0ea3689SLuigi Rizzo // XXX unlock(priv) 784f0ea3689SLuigi Rizzo ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s", 785f0ea3689SLuigi Rizzo na, na->ifp->if_xname, curthread, priv, kn, 786f0ea3689SLuigi Rizzo priv->np_nifp, 787f0ea3689SLuigi Rizzo kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH"); 788f0ea3689SLuigi Rizzo return 0; 789f0ea3689SLuigi Rizzo } 790f9790aebSLuigi Rizzo 791f9790aebSLuigi Rizzo struct cdevsw netmap_cdevsw = { 792f9790aebSLuigi Rizzo .d_version = D_VERSION, 793f9790aebSLuigi Rizzo .d_name = "netmap", 794f9790aebSLuigi Rizzo .d_open = netmap_open, 795f9790aebSLuigi Rizzo .d_mmap_single = netmap_mmap_single, 796f9790aebSLuigi Rizzo .d_ioctl = netmap_ioctl, 797f9790aebSLuigi Rizzo .d_poll = netmap_poll, 798f0ea3689SLuigi Rizzo .d_kqfilter = netmap_kqfilter, 799f9790aebSLuigi Rizzo .d_close = netmap_close, 800f9790aebSLuigi Rizzo }; 801f0ea3689SLuigi Rizzo /*--- end of kqueue support ----*/ 802f9790aebSLuigi Rizzo 803f9790aebSLuigi Rizzo /* 804f9790aebSLuigi Rizzo * Kernel entry point. 805f9790aebSLuigi Rizzo * 806f9790aebSLuigi Rizzo * Initialize/finalize the module and return. 807f9790aebSLuigi Rizzo * 808f9790aebSLuigi Rizzo * Return 0 on success, errno on failure. 809f9790aebSLuigi Rizzo */ 810f9790aebSLuigi Rizzo static int 811f9790aebSLuigi Rizzo netmap_loader(__unused struct module *module, int event, __unused void *arg) 812f9790aebSLuigi Rizzo { 813f9790aebSLuigi Rizzo int error = 0; 814f9790aebSLuigi Rizzo 815f9790aebSLuigi Rizzo switch (event) { 816f9790aebSLuigi Rizzo case MOD_LOAD: 817f9790aebSLuigi Rizzo error = netmap_init(); 818f9790aebSLuigi Rizzo break; 819f9790aebSLuigi Rizzo 820f9790aebSLuigi Rizzo case MOD_UNLOAD: 821f9790aebSLuigi Rizzo netmap_fini(); 822f9790aebSLuigi Rizzo break; 823f9790aebSLuigi Rizzo 824f9790aebSLuigi Rizzo default: 825f9790aebSLuigi Rizzo error = EOPNOTSUPP; 826f9790aebSLuigi Rizzo break; 827f9790aebSLuigi Rizzo } 828f9790aebSLuigi Rizzo 829f9790aebSLuigi Rizzo return (error); 830f9790aebSLuigi Rizzo } 831f9790aebSLuigi Rizzo 832f9790aebSLuigi Rizzo 833f9790aebSLuigi Rizzo DEV_MODULE(netmap, netmap_loader, NULL); 834