168b8534bSLuigi Rizzo /* 2*17885a7bSLuigi 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 * 30*17885a7bSLuigi Rizzo * Functions and macros to manipulate netmap structures and packets 31*17885a7bSLuigi 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 46*17885a7bSLuigi 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 * 51*17885a7bSLuigi Rizzo * All ring indexes (head, cur, tail) should always move forward. 52*17885a7bSLuigi Rizzo * To compute the next index in a circular ring you can use 53*17885a7bSLuigi Rizzo * i = nm_ring_next(ring, i); 54f9790aebSLuigi Rizzo * 55f9790aebSLuigi Rizzo * To ease porting apps from pcap to netmap we supply a few fuctions 56*17885a7bSLuigi Rizzo * that can be called to open, close, read and write on netmap in a way 57*17885a7bSLuigi Rizzo * similar to libpcap. Note that the read/write function depend on 58*17885a7bSLuigi Rizzo * an ioctl()/select()/poll() being issued to refill rings or push 59*17885a7bSLuigi 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 */ 70*17885a7bSLuigi Rizzo 71*17885a7bSLuigi Rizzo #ifndef likely 72*17885a7bSLuigi Rizzo #define likely(x) __builtin_expect(!!(x), 1) 73*17885a7bSLuigi Rizzo #define unlikely(x) __builtin_expect(!!(x), 0) 74*17885a7bSLuigi Rizzo #endif /* likely and unlikely */ 75*17885a7bSLuigi Rizzo 76f9790aebSLuigi Rizzo #include <net/netmap.h> 77f9790aebSLuigi Rizzo 78*17885a7bSLuigi Rizzo /* helper macro */ 79104d9fc7SEd Maste #define _NETMAP_OFFSET(type, ptr, offset) \ 80104d9fc7SEd Maste ((type)(void *)((char *)(ptr) + (offset))) 8168b8534bSLuigi Rizzo 82*17885a7bSLuigi 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 98*17885a7bSLuigi Rizzo static inline uint32_t 99*17885a7bSLuigi Rizzo nm_ring_next(struct netmap_ring *r, uint32_t i) 100*17885a7bSLuigi Rizzo { 101*17885a7bSLuigi Rizzo return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1); 102*17885a7bSLuigi Rizzo } 103*17885a7bSLuigi Rizzo 104a7250582SLuigi Rizzo 10568b8534bSLuigi Rizzo /* 106*17885a7bSLuigi Rizzo * Return 1 if we have pending transmissions in the tx ring. 107*17885a7bSLuigi Rizzo * When everything is complete ring->cur = ring->tail + 1 (modulo ring size) 10868b8534bSLuigi Rizzo */ 109*17885a7bSLuigi Rizzo static inline int 110*17885a7bSLuigi Rizzo nm_tx_pending(struct netmap_ring *r) 111*17885a7bSLuigi Rizzo { 112*17885a7bSLuigi Rizzo return nm_ring_next(r, r->tail) != r->cur; 113*17885a7bSLuigi Rizzo } 114*17885a7bSLuigi Rizzo 115*17885a7bSLuigi Rizzo 116*17885a7bSLuigi Rizzo static inline uint32_t 117*17885a7bSLuigi Rizzo nm_ring_space(struct netmap_ring *ring) 118*17885a7bSLuigi Rizzo { 119*17885a7bSLuigi Rizzo int ret = ring->tail - ring->cur; 120*17885a7bSLuigi Rizzo if (ret < 0) 121*17885a7bSLuigi Rizzo ret += ring->num_slots; 122*17885a7bSLuigi Rizzo return ret; 123*17885a7bSLuigi Rizzo } 124*17885a7bSLuigi 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 */ 141*17885a7bSLuigi Rizzo #include <unistd.h> /* close() */ 142*17885a7bSLuigi Rizzo #ifdef __FreeBSD__ 143*17885a7bSLuigi Rizzo #include <stdlib.h> 144*17885a7bSLuigi Rizzo #else 145*17885a7bSLuigi Rizzo #include <malloc.h> /* on FreeBSD it is stdlib.h */ 146*17885a7bSLuigi 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 167f9790aebSLuigi Rizzo */ 168f9790aebSLuigi Rizzo #define P2NMD(p) ((struct nm_desc_t *)(p)) 169f9790aebSLuigi Rizzo #define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 170f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 171f9790aebSLuigi Rizzo 172*17885a7bSLuigi Rizzo 173*17885a7bSLuigi Rizzo /* 174*17885a7bSLuigi Rizzo * this is a slightly optimized copy routine which rounds 175*17885a7bSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 176*17885a7bSLuigi Rizzo * with other odd sizes. We assume there is enough room 177*17885a7bSLuigi Rizzo * in the source and destination buffers. 178*17885a7bSLuigi Rizzo * 179*17885a7bSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 180*17885a7bSLuigi Rizzo */ 181*17885a7bSLuigi Rizzo static inline void 182*17885a7bSLuigi Rizzo pkt_copy(const void *_src, void *_dst, int l) 183*17885a7bSLuigi Rizzo { 184*17885a7bSLuigi Rizzo const uint64_t *src = _src; 185*17885a7bSLuigi Rizzo uint64_t *dst = _dst; 186*17885a7bSLuigi Rizzo if (unlikely(l >= 1024)) { 187*17885a7bSLuigi Rizzo memcpy(dst, src, l); 188*17885a7bSLuigi Rizzo return; 189*17885a7bSLuigi Rizzo } 190*17885a7bSLuigi Rizzo for (; likely(l > 0); l-=64) { 191*17885a7bSLuigi Rizzo *dst++ = *src++; 192*17885a7bSLuigi Rizzo *dst++ = *src++; 193*17885a7bSLuigi Rizzo *dst++ = *src++; 194*17885a7bSLuigi Rizzo *dst++ = *src++; 195*17885a7bSLuigi Rizzo *dst++ = *src++; 196*17885a7bSLuigi Rizzo *dst++ = *src++; 197*17885a7bSLuigi Rizzo *dst++ = *src++; 198*17885a7bSLuigi Rizzo *dst++ = *src++; 199*17885a7bSLuigi Rizzo } 200*17885a7bSLuigi Rizzo } 201*17885a7bSLuigi Rizzo 202*17885a7bSLuigi Rizzo 203f9790aebSLuigi Rizzo /* 204f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 205f9790aebSLuigi Rizzo */ 206f9790aebSLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 207f9790aebSLuigi Rizzo 208f9790aebSLuigi Rizzo /* 209*17885a7bSLuigi Rizzo *--- the pcap-like API --- 210*17885a7bSLuigi Rizzo * 211*17885a7bSLuigi Rizzo * nm_open() opens a file descriptor, binds to a port and maps memory. 212*17885a7bSLuigi Rizzo * 213*17885a7bSLuigi Rizzo * ifname (netmap:foo or vale:foo) is the port name 214*17885a7bSLuigi Rizzo * flags can be NETMAP_SW_RING or NETMAP_HW_RING etc. 215*17885a7bSLuigi Rizzo * ring_no only used if NETMAP_HW_RING is specified, is interpreted 216*17885a7bSLuigi Rizzo * as a string or integer indicating the ring number 217*17885a7bSLuigi Rizzo * ring_flags is stored in all ring flags (e.g. for transparent mode) 218f9790aebSLuigi Rizzo * to open. If successful, t opens the fd and maps the memory. 219f9790aebSLuigi Rizzo */ 220*17885a7bSLuigi Rizzo 221f9790aebSLuigi Rizzo static struct nm_desc_t *nm_open(const char *ifname, 222f9790aebSLuigi Rizzo const char *ring_no, int flags, int ring_flags); 223f9790aebSLuigi Rizzo 224f9790aebSLuigi Rizzo /* 225*17885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 226f9790aebSLuigi Rizzo */ 227*17885a7bSLuigi Rizzo 228*17885a7bSLuigi Rizzo static int nm_close(struct nm_desc_t *); 229f9790aebSLuigi Rizzo 230f9790aebSLuigi Rizzo /* 231*17885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 232*17885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 233*17885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 234f9790aebSLuigi Rizzo */ 235*17885a7bSLuigi Rizzo 236*17885a7bSLuigi Rizzo static int nm_inject(struct nm_desc_t *, const void *, size_t); 237*17885a7bSLuigi Rizzo static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 238*17885a7bSLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc_t *, struct nm_hdr_t *); 239f9790aebSLuigi Rizzo 240f9790aebSLuigi Rizzo 241f9790aebSLuigi Rizzo /* 242f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 243f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 244f9790aebSLuigi Rizzo */ 245f9790aebSLuigi Rizzo static struct nm_desc_t * 246f9790aebSLuigi Rizzo nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 247f9790aebSLuigi Rizzo { 248f9790aebSLuigi Rizzo struct nm_desc_t *d; 249f9790aebSLuigi Rizzo u_int n; 250f9790aebSLuigi Rizzo 251f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 252f9790aebSLuigi Rizzo errno = 0; /* name not recognised */ 253f9790aebSLuigi Rizzo return NULL; 254f9790aebSLuigi Rizzo } 255f9790aebSLuigi Rizzo if (ifname[0] == 'n') 256f9790aebSLuigi Rizzo ifname += 7; 257f9790aebSLuigi Rizzo d = (struct nm_desc_t *)calloc(1, sizeof(*d)); 258f9790aebSLuigi Rizzo if (d == NULL) { 259f9790aebSLuigi Rizzo errno = ENOMEM; 260f9790aebSLuigi Rizzo return NULL; 261f9790aebSLuigi Rizzo } 262f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 263f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 264f9790aebSLuigi Rizzo if (d->fd < 0) 265f9790aebSLuigi Rizzo goto fail; 266f9790aebSLuigi Rizzo 267f9790aebSLuigi Rizzo if (flags & NETMAP_SW_RING) { 268f9790aebSLuigi Rizzo d->req.nr_ringid = NETMAP_SW_RING; 269f9790aebSLuigi Rizzo } else { 270f9790aebSLuigi Rizzo u_int r; 271f9790aebSLuigi Rizzo if (flags & NETMAP_HW_RING) /* interpret ring as int */ 272f9790aebSLuigi Rizzo r = (uintptr_t)ring_name; 273f9790aebSLuigi Rizzo else /* interpret ring as numeric string */ 274f9790aebSLuigi Rizzo r = ring_name ? atoi(ring_name) : ~0; 275f9790aebSLuigi Rizzo r = (r < NETMAP_RING_MASK) ? (r | NETMAP_HW_RING) : 0; 276f9790aebSLuigi Rizzo d->req.nr_ringid = r; /* set the ring */ 277f9790aebSLuigi Rizzo } 278f9790aebSLuigi Rizzo d->req.nr_ringid |= (flags & ~NETMAP_RING_MASK); 279f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 280f9790aebSLuigi Rizzo strncpy(d->req.nr_name, ifname, sizeof(d->req.nr_name)); 281f9790aebSLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) 282f9790aebSLuigi Rizzo goto fail; 283f9790aebSLuigi Rizzo 284f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 285f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 286f9790aebSLuigi Rizzo d->fd, 0); 287f9790aebSLuigi Rizzo if (d->mem == NULL) 288f9790aebSLuigi Rizzo goto fail; 289f9790aebSLuigi Rizzo d->nifp = NETMAP_IF(d->mem, d->req.nr_offset); 290f9790aebSLuigi Rizzo if (d->req.nr_ringid & NETMAP_SW_RING) { 291f9790aebSLuigi Rizzo d->first_ring = d->last_ring = d->req.nr_rx_rings; 292f9790aebSLuigi Rizzo } else if (d->req.nr_ringid & NETMAP_HW_RING) { 293f9790aebSLuigi Rizzo d->first_ring = d->last_ring = 294f9790aebSLuigi Rizzo d->req.nr_ringid & NETMAP_RING_MASK; 295f9790aebSLuigi Rizzo } else { 296f9790aebSLuigi Rizzo d->first_ring = 0; 297f9790aebSLuigi Rizzo d->last_ring = d->req.nr_rx_rings - 1; 298f9790aebSLuigi Rizzo } 299f9790aebSLuigi Rizzo d->cur_ring = d->first_ring; 300f9790aebSLuigi Rizzo for (n = d->first_ring; n <= d->last_ring; n++) { 301f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, n); 302f9790aebSLuigi Rizzo ring->flags |= ring_flags; 303f9790aebSLuigi Rizzo } 304f9790aebSLuigi Rizzo return d; 305f9790aebSLuigi Rizzo 306f9790aebSLuigi Rizzo fail: 307f9790aebSLuigi Rizzo nm_close(d); 308f9790aebSLuigi Rizzo errno = EINVAL; 309f9790aebSLuigi Rizzo return NULL; 310f9790aebSLuigi Rizzo } 311f9790aebSLuigi Rizzo 312f9790aebSLuigi Rizzo 313f9790aebSLuigi Rizzo static int 314f9790aebSLuigi Rizzo nm_close(struct nm_desc_t *d) 315f9790aebSLuigi Rizzo { 316*17885a7bSLuigi Rizzo /* 317*17885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 318*17885a7bSLuigi Rizzo */ 319*17885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 320*17885a7bSLuigi Rizzo { nm_open, nm_inject, nm_dispatch, nm_nextpkt } ; 321*17885a7bSLuigi Rizzo 322f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 323f9790aebSLuigi Rizzo return EINVAL; 324f9790aebSLuigi Rizzo if (d->mem) 325f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 326f9790aebSLuigi Rizzo if (d->fd != -1) 327f9790aebSLuigi Rizzo close(d->fd); 328f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 329f9790aebSLuigi Rizzo free(d); 330f9790aebSLuigi Rizzo return 0; 331f9790aebSLuigi Rizzo } 332f9790aebSLuigi Rizzo 333f9790aebSLuigi Rizzo 334f9790aebSLuigi Rizzo /* 335*17885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 336*17885a7bSLuigi Rizzo */ 337*17885a7bSLuigi Rizzo static int 338*17885a7bSLuigi Rizzo nm_inject(struct nm_desc_t *d, const void *buf, size_t size) 339*17885a7bSLuigi Rizzo { 340*17885a7bSLuigi Rizzo u_int c, n = d->last_ring - d->first_ring + 1; 341*17885a7bSLuigi Rizzo 342*17885a7bSLuigi Rizzo if (0) fprintf(stderr, "%s rings %d %d %d\n", __FUNCTION__, 343*17885a7bSLuigi Rizzo d->first_ring, d->cur_ring, d->last_ring); 344*17885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 345*17885a7bSLuigi Rizzo /* compute current ring to use */ 346*17885a7bSLuigi Rizzo struct netmap_ring *ring; 347*17885a7bSLuigi Rizzo uint32_t i, idx; 348*17885a7bSLuigi Rizzo uint32_t ri = d->cur_ring + c; 349*17885a7bSLuigi Rizzo 350*17885a7bSLuigi Rizzo if (ri > d->last_ring) 351*17885a7bSLuigi Rizzo ri = d->first_ring; 352*17885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 353*17885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 354*17885a7bSLuigi Rizzo if (0) fprintf(stderr, "%s ring %d cur %d tail %d\n", 355*17885a7bSLuigi Rizzo __FUNCTION__, 356*17885a7bSLuigi Rizzo ri, ring->cur, ring->tail); 357*17885a7bSLuigi Rizzo continue; 358*17885a7bSLuigi Rizzo } 359*17885a7bSLuigi Rizzo i = ring->cur; 360*17885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 361*17885a7bSLuigi Rizzo ring->slot[i].len = size; 362*17885a7bSLuigi Rizzo pkt_copy(buf, NETMAP_BUF(ring, idx), size); 363*17885a7bSLuigi Rizzo d->cur_ring = ri; 364*17885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 365*17885a7bSLuigi Rizzo return size; 366*17885a7bSLuigi Rizzo } 367*17885a7bSLuigi Rizzo return 0; /* fail */ 368*17885a7bSLuigi Rizzo } 369*17885a7bSLuigi Rizzo 370*17885a7bSLuigi Rizzo 371*17885a7bSLuigi Rizzo /* 372f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 373f9790aebSLuigi Rizzo */ 374f9790aebSLuigi Rizzo static int 375f9790aebSLuigi Rizzo nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 376f9790aebSLuigi Rizzo { 377f9790aebSLuigi Rizzo int n = d->last_ring - d->first_ring + 1; 378f9790aebSLuigi Rizzo int c, got = 0, ri = d->cur_ring; 379f9790aebSLuigi Rizzo 380f9790aebSLuigi Rizzo if (cnt == 0) 381f9790aebSLuigi Rizzo cnt = -1; 382f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 383f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 384f9790aebSLuigi Rizzo * so we can omit checking for -1 385f9790aebSLuigi Rizzo */ 386f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 387f9790aebSLuigi Rizzo /* compute current ring to use */ 388f9790aebSLuigi Rizzo struct netmap_ring *ring; 389f9790aebSLuigi Rizzo 390f9790aebSLuigi Rizzo ri = d->cur_ring + c; 391f9790aebSLuigi Rizzo if (ri > d->last_ring) 392f9790aebSLuigi Rizzo ri = d->first_ring; 393f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 394*17885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 395f9790aebSLuigi Rizzo u_int i = ring->cur; 396f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 397f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 398f9790aebSLuigi Rizzo // XXX should check valid buf 399f9790aebSLuigi Rizzo // prefetch(buf); 400f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 401f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 402f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 403*17885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 404f9790aebSLuigi Rizzo } 405f9790aebSLuigi Rizzo } 406f9790aebSLuigi Rizzo d->cur_ring = ri; 407f9790aebSLuigi Rizzo return got; 408f9790aebSLuigi Rizzo } 409f9790aebSLuigi Rizzo 410f9790aebSLuigi Rizzo static u_char * 411*17885a7bSLuigi Rizzo nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) 412f9790aebSLuigi Rizzo { 413f9790aebSLuigi Rizzo int ri = d->cur_ring; 414f9790aebSLuigi Rizzo 415f9790aebSLuigi Rizzo do { 416f9790aebSLuigi Rizzo /* compute current ring to use */ 417f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 418*17885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 419f9790aebSLuigi Rizzo u_int i = ring->cur; 420f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 421f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 422f9790aebSLuigi Rizzo // XXX should check valid buf 423f9790aebSLuigi Rizzo // prefetch(buf); 424f9790aebSLuigi Rizzo hdr->ts = ring->ts; 425f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 426*17885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 427*17885a7bSLuigi Rizzo /* we could postpone advancing head if we want 428*17885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 429*17885a7bSLuigi Rizzo * the future. 430*17885a7bSLuigi Rizzo */ 431*17885a7bSLuigi Rizzo ring->head = ring->cur; 432f9790aebSLuigi Rizzo d->cur_ring = ri; 433f9790aebSLuigi Rizzo return buf; 434f9790aebSLuigi Rizzo } 435f9790aebSLuigi Rizzo ri++; 436f9790aebSLuigi Rizzo if (ri > d->last_ring) 437f9790aebSLuigi Rizzo ri = d->first_ring; 438f9790aebSLuigi Rizzo } while (ri != d->cur_ring); 439f9790aebSLuigi Rizzo return NULL; /* nothing found */ 440f9790aebSLuigi Rizzo } 441f9790aebSLuigi Rizzo 442f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 443f9790aebSLuigi Rizzo 444f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 445f9790aebSLuigi Rizzo 44668b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 447