168b8534bSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved. 368b8534bSLuigi Rizzo * 468b8534bSLuigi 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: 768b8534bSLuigi Rizzo * 868b8534bSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 968b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 1068b8534bSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 1168b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 12f9790aebSLuigi Rizzo * documentation and/or other materials provided with the distribution. 1368b8534bSLuigi Rizzo * 14f9790aebSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1568b8534bSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f9790aebSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f9790aebSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f9790aebSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f9790aebSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f9790aebSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f9790aebSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f9790aebSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f9790aebSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f9790aebSLuigi Rizzo * SUCH DAMAGE. 2568b8534bSLuigi Rizzo */ 2668b8534bSLuigi Rizzo 2768b8534bSLuigi Rizzo /* 2868b8534bSLuigi Rizzo * $FreeBSD$ 2968b8534bSLuigi Rizzo * 3017885a7bSLuigi Rizzo * Functions and macros to manipulate netmap structures and packets 3117885a7bSLuigi Rizzo * in userspace. See netmap(4) for more information. 3268b8534bSLuigi Rizzo * 3364ae02c3SLuigi Rizzo * The address of the struct netmap_if, say nifp, is computed from the 3464ae02c3SLuigi Rizzo * value returned from ioctl(.., NIOCREG, ...) and the mmap region: 3568b8534bSLuigi Rizzo * ioctl(fd, NIOCREG, &req); 3668b8534bSLuigi Rizzo * mem = mmap(0, ... ); 3768b8534bSLuigi Rizzo * nifp = NETMAP_IF(mem, req.nr_nifp); 3868b8534bSLuigi Rizzo * (so simple, we could just do it manually) 3968b8534bSLuigi Rizzo * 4068b8534bSLuigi Rizzo * From there: 4168b8534bSLuigi Rizzo * struct netmap_ring *NETMAP_TXRING(nifp, index) 4268b8534bSLuigi Rizzo * struct netmap_ring *NETMAP_RXRING(nifp, index) 4368b8534bSLuigi Rizzo * we can access ring->nr_cur, ring->nr_avail, ring->nr_flags 4468b8534bSLuigi Rizzo * 4568b8534bSLuigi Rizzo * ring->slot[i] gives us the i-th slot (we can access 4617885a7bSLuigi Rizzo * directly len, flags, buf_idx) 4768b8534bSLuigi Rizzo * 4827892e02SLuigi Rizzo * char *buf = NETMAP_BUF(ring, x) returns a pointer to 4927892e02SLuigi Rizzo * the buffer numbered x 5068b8534bSLuigi Rizzo * 5117885a7bSLuigi Rizzo * All ring indexes (head, cur, tail) should always move forward. 5217885a7bSLuigi Rizzo * To compute the next index in a circular ring you can use 5317885a7bSLuigi Rizzo * i = nm_ring_next(ring, i); 54f9790aebSLuigi Rizzo * 55f9790aebSLuigi Rizzo * To ease porting apps from pcap to netmap we supply a few fuctions 5617885a7bSLuigi Rizzo * that can be called to open, close, read and write on netmap in a way 5717885a7bSLuigi Rizzo * similar to libpcap. Note that the read/write function depend on 5817885a7bSLuigi Rizzo * an ioctl()/select()/poll() being issued to refill rings or push 5917885a7bSLuigi Rizzo * packets out. 60f9790aebSLuigi Rizzo * 61f9790aebSLuigi Rizzo * In order to use these, include #define NETMAP_WITH_LIBS 62f9790aebSLuigi Rizzo * in the source file that invokes these functions. 6368b8534bSLuigi Rizzo */ 6468b8534bSLuigi Rizzo 6568b8534bSLuigi Rizzo #ifndef _NET_NETMAP_USER_H_ 6668b8534bSLuigi Rizzo #define _NET_NETMAP_USER_H_ 6768b8534bSLuigi Rizzo 68f9790aebSLuigi Rizzo #include <stdint.h> 69f9790aebSLuigi Rizzo #include <net/if.h> /* IFNAMSIZ */ 7017885a7bSLuigi Rizzo 7117885a7bSLuigi Rizzo #ifndef likely 7217885a7bSLuigi Rizzo #define likely(x) __builtin_expect(!!(x), 1) 7317885a7bSLuigi Rizzo #define unlikely(x) __builtin_expect(!!(x), 0) 7417885a7bSLuigi Rizzo #endif /* likely and unlikely */ 7517885a7bSLuigi Rizzo 76f9790aebSLuigi Rizzo #include <net/netmap.h> 77f9790aebSLuigi Rizzo 7817885a7bSLuigi Rizzo /* helper macro */ 79104d9fc7SEd Maste #define _NETMAP_OFFSET(type, ptr, offset) \ 80104d9fc7SEd Maste ((type)(void *)((char *)(ptr) + (offset))) 8168b8534bSLuigi Rizzo 8217885a7bSLuigi Rizzo #define NETMAP_IF(_base, _ofs) _NETMAP_OFFSET(struct netmap_if *, _base, _ofs) 8368b8534bSLuigi Rizzo 84104d9fc7SEd Maste #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 85104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index] ) 86104d9fc7SEd Maste 87104d9fc7SEd Maste #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 88104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) 8968b8534bSLuigi Rizzo 9068b8534bSLuigi Rizzo #define NETMAP_BUF(ring, index) \ 915819da83SLuigi Rizzo ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) 9268b8534bSLuigi Rizzo 9364ae02c3SLuigi Rizzo #define NETMAP_BUF_IDX(ring, buf) \ 9464ae02c3SLuigi Rizzo ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ 95a7250582SLuigi Rizzo (ring)->nr_buf_size ) 9664ae02c3SLuigi Rizzo 9768b8534bSLuigi Rizzo 9817885a7bSLuigi Rizzo static inline uint32_t 9917885a7bSLuigi Rizzo nm_ring_next(struct netmap_ring *r, uint32_t i) 10017885a7bSLuigi Rizzo { 10117885a7bSLuigi Rizzo return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1); 10217885a7bSLuigi Rizzo } 10317885a7bSLuigi Rizzo 104a7250582SLuigi Rizzo 10568b8534bSLuigi Rizzo /* 10617885a7bSLuigi Rizzo * Return 1 if we have pending transmissions in the tx ring. 10717885a7bSLuigi Rizzo * When everything is complete ring->cur = ring->tail + 1 (modulo ring size) 10868b8534bSLuigi Rizzo */ 10917885a7bSLuigi Rizzo static inline int 11017885a7bSLuigi Rizzo nm_tx_pending(struct netmap_ring *r) 11117885a7bSLuigi Rizzo { 11217885a7bSLuigi Rizzo return nm_ring_next(r, r->tail) != r->cur; 11317885a7bSLuigi Rizzo } 11417885a7bSLuigi Rizzo 11517885a7bSLuigi Rizzo 11617885a7bSLuigi Rizzo static inline uint32_t 11717885a7bSLuigi Rizzo nm_ring_space(struct netmap_ring *ring) 11817885a7bSLuigi Rizzo { 11917885a7bSLuigi Rizzo int ret = ring->tail - ring->cur; 12017885a7bSLuigi Rizzo if (ret < 0) 12117885a7bSLuigi Rizzo ret += ring->num_slots; 12217885a7bSLuigi Rizzo return ret; 12317885a7bSLuigi Rizzo } 12417885a7bSLuigi Rizzo 12568b8534bSLuigi Rizzo 126f9790aebSLuigi Rizzo #ifdef NETMAP_WITH_LIBS 127f9790aebSLuigi Rizzo /* 128f9790aebSLuigi Rizzo * Support for simple I/O libraries. 129f9790aebSLuigi Rizzo * Include other system headers required for compiling this. 130f9790aebSLuigi Rizzo */ 131f9790aebSLuigi Rizzo 132f9790aebSLuigi Rizzo #ifndef HAVE_NETMAP_WITH_LIBS 133f9790aebSLuigi Rizzo #define HAVE_NETMAP_WITH_LIBS 134f9790aebSLuigi Rizzo 135f9790aebSLuigi Rizzo #include <sys/time.h> 136f9790aebSLuigi Rizzo #include <sys/mman.h> 137f9790aebSLuigi Rizzo #include <string.h> /* memset */ 138f9790aebSLuigi Rizzo #include <sys/ioctl.h> 139f9790aebSLuigi Rizzo #include <sys/errno.h> /* EINVAL */ 140f9790aebSLuigi Rizzo #include <fcntl.h> /* O_RDWR */ 14117885a7bSLuigi Rizzo #include <unistd.h> /* close() */ 14217885a7bSLuigi Rizzo #ifdef __FreeBSD__ 14317885a7bSLuigi Rizzo #include <stdlib.h> 14417885a7bSLuigi Rizzo #else 14517885a7bSLuigi Rizzo #include <malloc.h> /* on FreeBSD it is stdlib.h */ 14617885a7bSLuigi Rizzo #endif 147f9790aebSLuigi Rizzo 148f9790aebSLuigi Rizzo struct nm_hdr_t { /* same as pcap_pkthdr */ 149f9790aebSLuigi Rizzo struct timeval ts; 150f9790aebSLuigi Rizzo uint32_t caplen; 151f9790aebSLuigi Rizzo uint32_t len; 152f9790aebSLuigi Rizzo }; 153f9790aebSLuigi Rizzo 154f9790aebSLuigi Rizzo struct nm_desc_t { 155f9790aebSLuigi Rizzo struct nm_desc_t *self; 156f9790aebSLuigi Rizzo int fd; 157f9790aebSLuigi Rizzo void *mem; 158f9790aebSLuigi Rizzo int memsize; 159f9790aebSLuigi Rizzo struct netmap_if *nifp; 160f9790aebSLuigi Rizzo uint16_t first_ring, last_ring, cur_ring; 161f9790aebSLuigi Rizzo struct nmreq req; 162f9790aebSLuigi Rizzo struct nm_hdr_t hdr; 163f9790aebSLuigi Rizzo }; 164f9790aebSLuigi Rizzo 165f9790aebSLuigi Rizzo /* 166f9790aebSLuigi Rizzo * when the descriptor is open correctly, d->self == d 167*b82b2211SLuigi Rizzo * Eventually we should also use some magic number. 168f9790aebSLuigi Rizzo */ 169f9790aebSLuigi Rizzo #define P2NMD(p) ((struct nm_desc_t *)(p)) 170f9790aebSLuigi Rizzo #define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 171f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 172f9790aebSLuigi Rizzo 17317885a7bSLuigi Rizzo 17417885a7bSLuigi Rizzo /* 17517885a7bSLuigi Rizzo * this is a slightly optimized copy routine which rounds 17617885a7bSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 17717885a7bSLuigi Rizzo * with other odd sizes. We assume there is enough room 17817885a7bSLuigi Rizzo * in the source and destination buffers. 17917885a7bSLuigi Rizzo * 18017885a7bSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 18117885a7bSLuigi Rizzo */ 18217885a7bSLuigi Rizzo static inline void 18317885a7bSLuigi Rizzo pkt_copy(const void *_src, void *_dst, int l) 18417885a7bSLuigi Rizzo { 185*b82b2211SLuigi Rizzo const uint64_t *src = (const uint64_t *)_src; 186*b82b2211SLuigi Rizzo uint64_t *dst = (uint64_t *)_dst; 187*b82b2211SLuigi Rizzo 18817885a7bSLuigi Rizzo if (unlikely(l >= 1024)) { 18917885a7bSLuigi Rizzo memcpy(dst, src, l); 19017885a7bSLuigi Rizzo return; 19117885a7bSLuigi Rizzo } 19217885a7bSLuigi Rizzo for (; likely(l > 0); l-=64) { 19317885a7bSLuigi Rizzo *dst++ = *src++; 19417885a7bSLuigi Rizzo *dst++ = *src++; 19517885a7bSLuigi Rizzo *dst++ = *src++; 19617885a7bSLuigi Rizzo *dst++ = *src++; 19717885a7bSLuigi Rizzo *dst++ = *src++; 19817885a7bSLuigi Rizzo *dst++ = *src++; 19917885a7bSLuigi Rizzo *dst++ = *src++; 20017885a7bSLuigi Rizzo *dst++ = *src++; 20117885a7bSLuigi Rizzo } 20217885a7bSLuigi Rizzo } 20317885a7bSLuigi Rizzo 20417885a7bSLuigi Rizzo 205f9790aebSLuigi Rizzo /* 206f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 207f9790aebSLuigi Rizzo */ 208f9790aebSLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 209f9790aebSLuigi Rizzo 210f9790aebSLuigi Rizzo /* 21117885a7bSLuigi Rizzo *--- the pcap-like API --- 21217885a7bSLuigi Rizzo * 21317885a7bSLuigi Rizzo * nm_open() opens a file descriptor, binds to a port and maps memory. 21417885a7bSLuigi Rizzo * 21517885a7bSLuigi Rizzo * ifname (netmap:foo or vale:foo) is the port name 21617885a7bSLuigi Rizzo * flags can be NETMAP_SW_RING or NETMAP_HW_RING etc. 21717885a7bSLuigi Rizzo * ring_no only used if NETMAP_HW_RING is specified, is interpreted 21817885a7bSLuigi Rizzo * as a string or integer indicating the ring number 21917885a7bSLuigi Rizzo * ring_flags is stored in all ring flags (e.g. for transparent mode) 220f9790aebSLuigi Rizzo * to open. If successful, t opens the fd and maps the memory. 221f9790aebSLuigi Rizzo */ 22217885a7bSLuigi Rizzo 223f9790aebSLuigi Rizzo static struct nm_desc_t *nm_open(const char *ifname, 224f9790aebSLuigi Rizzo const char *ring_no, int flags, int ring_flags); 225f9790aebSLuigi Rizzo 226f9790aebSLuigi Rizzo /* 22717885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 228f9790aebSLuigi Rizzo */ 22917885a7bSLuigi Rizzo 23017885a7bSLuigi Rizzo static int nm_close(struct nm_desc_t *); 231f9790aebSLuigi Rizzo 232f9790aebSLuigi Rizzo /* 23317885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 23417885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 23517885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 236f9790aebSLuigi Rizzo */ 23717885a7bSLuigi Rizzo 23817885a7bSLuigi Rizzo static int nm_inject(struct nm_desc_t *, const void *, size_t); 23917885a7bSLuigi Rizzo static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 24017885a7bSLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc_t *, struct nm_hdr_t *); 241f9790aebSLuigi Rizzo 242f9790aebSLuigi Rizzo 243f9790aebSLuigi Rizzo /* 244f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 245f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 246f9790aebSLuigi Rizzo */ 247f9790aebSLuigi Rizzo static struct nm_desc_t * 248f9790aebSLuigi Rizzo nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 249f9790aebSLuigi Rizzo { 250f9790aebSLuigi Rizzo struct nm_desc_t *d; 251f9790aebSLuigi Rizzo u_int n; 252f9790aebSLuigi Rizzo 253f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 254f9790aebSLuigi Rizzo errno = 0; /* name not recognised */ 255f9790aebSLuigi Rizzo return NULL; 256f9790aebSLuigi Rizzo } 257f9790aebSLuigi Rizzo if (ifname[0] == 'n') 258f9790aebSLuigi Rizzo ifname += 7; 259f9790aebSLuigi Rizzo d = (struct nm_desc_t *)calloc(1, sizeof(*d)); 260f9790aebSLuigi Rizzo if (d == NULL) { 261f9790aebSLuigi Rizzo errno = ENOMEM; 262f9790aebSLuigi Rizzo return NULL; 263f9790aebSLuigi Rizzo } 264f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 265f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 266f9790aebSLuigi Rizzo if (d->fd < 0) 267f9790aebSLuigi Rizzo goto fail; 268f9790aebSLuigi Rizzo 269f9790aebSLuigi Rizzo if (flags & NETMAP_SW_RING) { 270f9790aebSLuigi Rizzo d->req.nr_ringid = NETMAP_SW_RING; 271f9790aebSLuigi Rizzo } else { 272f9790aebSLuigi Rizzo u_int r; 273f9790aebSLuigi Rizzo if (flags & NETMAP_HW_RING) /* interpret ring as int */ 274f9790aebSLuigi Rizzo r = (uintptr_t)ring_name; 275f9790aebSLuigi Rizzo else /* interpret ring as numeric string */ 276f9790aebSLuigi Rizzo r = ring_name ? atoi(ring_name) : ~0; 277f9790aebSLuigi Rizzo r = (r < NETMAP_RING_MASK) ? (r | NETMAP_HW_RING) : 0; 278f9790aebSLuigi Rizzo d->req.nr_ringid = r; /* set the ring */ 279f9790aebSLuigi Rizzo } 280f9790aebSLuigi Rizzo d->req.nr_ringid |= (flags & ~NETMAP_RING_MASK); 281f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 282f9790aebSLuigi Rizzo strncpy(d->req.nr_name, ifname, sizeof(d->req.nr_name)); 283f9790aebSLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) 284f9790aebSLuigi Rizzo goto fail; 285f9790aebSLuigi Rizzo 286f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 287f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 288f9790aebSLuigi Rizzo d->fd, 0); 289f9790aebSLuigi Rizzo if (d->mem == NULL) 290f9790aebSLuigi Rizzo goto fail; 291f9790aebSLuigi Rizzo d->nifp = NETMAP_IF(d->mem, d->req.nr_offset); 292f9790aebSLuigi Rizzo if (d->req.nr_ringid & NETMAP_SW_RING) { 293f9790aebSLuigi Rizzo d->first_ring = d->last_ring = d->req.nr_rx_rings; 294f9790aebSLuigi Rizzo } else if (d->req.nr_ringid & NETMAP_HW_RING) { 295f9790aebSLuigi Rizzo d->first_ring = d->last_ring = 296f9790aebSLuigi Rizzo d->req.nr_ringid & NETMAP_RING_MASK; 297f9790aebSLuigi Rizzo } else { 298f9790aebSLuigi Rizzo d->first_ring = 0; 299f9790aebSLuigi Rizzo d->last_ring = d->req.nr_rx_rings - 1; 300f9790aebSLuigi Rizzo } 301f9790aebSLuigi Rizzo d->cur_ring = d->first_ring; 302f9790aebSLuigi Rizzo for (n = d->first_ring; n <= d->last_ring; n++) { 303f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, n); 304f9790aebSLuigi Rizzo ring->flags |= ring_flags; 305f9790aebSLuigi Rizzo } 306f9790aebSLuigi Rizzo return d; 307f9790aebSLuigi Rizzo 308f9790aebSLuigi Rizzo fail: 309f9790aebSLuigi Rizzo nm_close(d); 310f9790aebSLuigi Rizzo errno = EINVAL; 311f9790aebSLuigi Rizzo return NULL; 312f9790aebSLuigi Rizzo } 313f9790aebSLuigi Rizzo 314f9790aebSLuigi Rizzo 315f9790aebSLuigi Rizzo static int 316f9790aebSLuigi Rizzo nm_close(struct nm_desc_t *d) 317f9790aebSLuigi Rizzo { 31817885a7bSLuigi Rizzo /* 31917885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 32017885a7bSLuigi Rizzo */ 32117885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 322*b82b2211SLuigi Rizzo { (void *)nm_open, (void *)nm_inject, 323*b82b2211SLuigi Rizzo (void *)nm_dispatch, (void *)nm_nextpkt } ; 32417885a7bSLuigi Rizzo 325f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 326f9790aebSLuigi Rizzo return EINVAL; 327f9790aebSLuigi Rizzo if (d->mem) 328f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 329f9790aebSLuigi Rizzo if (d->fd != -1) 330f9790aebSLuigi Rizzo close(d->fd); 331f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 332f9790aebSLuigi Rizzo free(d); 333f9790aebSLuigi Rizzo return 0; 334f9790aebSLuigi Rizzo } 335f9790aebSLuigi Rizzo 336f9790aebSLuigi Rizzo 337f9790aebSLuigi Rizzo /* 33817885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 33917885a7bSLuigi Rizzo */ 34017885a7bSLuigi Rizzo static int 34117885a7bSLuigi Rizzo nm_inject(struct nm_desc_t *d, const void *buf, size_t size) 34217885a7bSLuigi Rizzo { 34317885a7bSLuigi Rizzo u_int c, n = d->last_ring - d->first_ring + 1; 34417885a7bSLuigi Rizzo 34517885a7bSLuigi Rizzo if (0) fprintf(stderr, "%s rings %d %d %d\n", __FUNCTION__, 34617885a7bSLuigi Rizzo d->first_ring, d->cur_ring, d->last_ring); 34717885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 34817885a7bSLuigi Rizzo /* compute current ring to use */ 34917885a7bSLuigi Rizzo struct netmap_ring *ring; 35017885a7bSLuigi Rizzo uint32_t i, idx; 35117885a7bSLuigi Rizzo uint32_t ri = d->cur_ring + c; 35217885a7bSLuigi Rizzo 35317885a7bSLuigi Rizzo if (ri > d->last_ring) 35417885a7bSLuigi Rizzo ri = d->first_ring; 35517885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 35617885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 35717885a7bSLuigi Rizzo if (0) fprintf(stderr, "%s ring %d cur %d tail %d\n", 35817885a7bSLuigi Rizzo __FUNCTION__, 35917885a7bSLuigi Rizzo ri, ring->cur, ring->tail); 36017885a7bSLuigi Rizzo continue; 36117885a7bSLuigi Rizzo } 36217885a7bSLuigi Rizzo i = ring->cur; 36317885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 36417885a7bSLuigi Rizzo ring->slot[i].len = size; 36517885a7bSLuigi Rizzo pkt_copy(buf, NETMAP_BUF(ring, idx), size); 36617885a7bSLuigi Rizzo d->cur_ring = ri; 36717885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 36817885a7bSLuigi Rizzo return size; 36917885a7bSLuigi Rizzo } 37017885a7bSLuigi Rizzo return 0; /* fail */ 37117885a7bSLuigi Rizzo } 37217885a7bSLuigi Rizzo 37317885a7bSLuigi Rizzo 37417885a7bSLuigi Rizzo /* 375f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 376f9790aebSLuigi Rizzo */ 377f9790aebSLuigi Rizzo static int 378f9790aebSLuigi Rizzo nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 379f9790aebSLuigi Rizzo { 380f9790aebSLuigi Rizzo int n = d->last_ring - d->first_ring + 1; 381f9790aebSLuigi Rizzo int c, got = 0, ri = d->cur_ring; 382f9790aebSLuigi Rizzo 383f9790aebSLuigi Rizzo if (cnt == 0) 384f9790aebSLuigi Rizzo cnt = -1; 385f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 386f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 387f9790aebSLuigi Rizzo * so we can omit checking for -1 388f9790aebSLuigi Rizzo */ 389f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 390f9790aebSLuigi Rizzo /* compute current ring to use */ 391f9790aebSLuigi Rizzo struct netmap_ring *ring; 392f9790aebSLuigi Rizzo 393f9790aebSLuigi Rizzo ri = d->cur_ring + c; 394f9790aebSLuigi Rizzo if (ri > d->last_ring) 395f9790aebSLuigi Rizzo ri = d->first_ring; 396f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 39717885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 398f9790aebSLuigi Rizzo u_int i = ring->cur; 399f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 400f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 401f9790aebSLuigi Rizzo // XXX should check valid buf 402f9790aebSLuigi Rizzo // prefetch(buf); 403f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 404f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 405f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 40617885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 407f9790aebSLuigi Rizzo } 408f9790aebSLuigi Rizzo } 409f9790aebSLuigi Rizzo d->cur_ring = ri; 410f9790aebSLuigi Rizzo return got; 411f9790aebSLuigi Rizzo } 412f9790aebSLuigi Rizzo 413f9790aebSLuigi Rizzo static u_char * 41417885a7bSLuigi Rizzo nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) 415f9790aebSLuigi Rizzo { 416f9790aebSLuigi Rizzo int ri = d->cur_ring; 417f9790aebSLuigi Rizzo 418f9790aebSLuigi Rizzo do { 419f9790aebSLuigi Rizzo /* compute current ring to use */ 420f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 42117885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 422f9790aebSLuigi Rizzo u_int i = ring->cur; 423f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 424f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 425f9790aebSLuigi Rizzo // XXX should check valid buf 426f9790aebSLuigi Rizzo // prefetch(buf); 427f9790aebSLuigi Rizzo hdr->ts = ring->ts; 428f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 42917885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 43017885a7bSLuigi Rizzo /* we could postpone advancing head if we want 43117885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 43217885a7bSLuigi Rizzo * the future. 43317885a7bSLuigi Rizzo */ 43417885a7bSLuigi Rizzo ring->head = ring->cur; 435f9790aebSLuigi Rizzo d->cur_ring = ri; 436f9790aebSLuigi Rizzo return buf; 437f9790aebSLuigi Rizzo } 438f9790aebSLuigi Rizzo ri++; 439f9790aebSLuigi Rizzo if (ri > d->last_ring) 440f9790aebSLuigi Rizzo ri = d->first_ring; 441f9790aebSLuigi Rizzo } while (ri != d->cur_ring); 442f9790aebSLuigi Rizzo return NULL; /* nothing found */ 443f9790aebSLuigi Rizzo } 444f9790aebSLuigi Rizzo 445f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 446f9790aebSLuigi Rizzo 447f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 448f9790aebSLuigi Rizzo 44968b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 450