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() */ 142*66015019SLuigi Rizzo #include <signal.h> 14317885a7bSLuigi Rizzo #include <stdlib.h> 144f9790aebSLuigi Rizzo 145f9790aebSLuigi Rizzo struct nm_hdr_t { /* same as pcap_pkthdr */ 146f9790aebSLuigi Rizzo struct timeval ts; 147f9790aebSLuigi Rizzo uint32_t caplen; 148f9790aebSLuigi Rizzo uint32_t len; 149f9790aebSLuigi Rizzo }; 150f9790aebSLuigi Rizzo 151*66015019SLuigi Rizzo struct nm_stat_t { // pcap_stat 152*66015019SLuigi Rizzo u_int ps_recv; 153*66015019SLuigi Rizzo u_int ps_drop; 154*66015019SLuigi Rizzo u_int ps_ifdrop; 155*66015019SLuigi Rizzo #ifdef WIN32 156*66015019SLuigi Rizzo u_int bs_capt; 157*66015019SLuigi Rizzo #endif /* WIN32 */ 158*66015019SLuigi Rizzo }; 159*66015019SLuigi Rizzo 160*66015019SLuigi Rizzo #define NM_ERRBUF_SIZE 512 161*66015019SLuigi Rizzo 162f9790aebSLuigi Rizzo struct nm_desc_t { 163f9790aebSLuigi Rizzo struct nm_desc_t *self; 164f9790aebSLuigi Rizzo int fd; 165f9790aebSLuigi Rizzo void *mem; 166f9790aebSLuigi Rizzo int memsize; 167f9790aebSLuigi Rizzo struct netmap_if *nifp; 168*66015019SLuigi Rizzo uint16_t first_tx_ring, last_tx_ring, cur_tx_ring; 169*66015019SLuigi Rizzo uint16_t first_rx_ring, last_rx_ring, cur_rx_ring; 170*66015019SLuigi Rizzo struct nmreq req; /* also contains the nr_name = ifname */ 171f9790aebSLuigi Rizzo struct nm_hdr_t hdr; 172*66015019SLuigi Rizzo 173*66015019SLuigi Rizzo struct netmap_ring *tx, *rx; /* shortcuts to base hw/sw rings */ 174*66015019SLuigi Rizzo 175*66015019SLuigi Rizzo /* parameters from pcap_open_live */ 176*66015019SLuigi Rizzo int snaplen; 177*66015019SLuigi Rizzo int promisc; 178*66015019SLuigi Rizzo int to_ms; 179*66015019SLuigi Rizzo char *errbuf; 180*66015019SLuigi Rizzo 181*66015019SLuigi Rizzo /* save flags so we can restore them on close */ 182*66015019SLuigi Rizzo uint32_t if_flags; 183*66015019SLuigi Rizzo uint32_t if_reqcap; 184*66015019SLuigi Rizzo uint32_t if_curcap; 185*66015019SLuigi Rizzo 186*66015019SLuigi Rizzo struct nm_stat_t st; 187*66015019SLuigi Rizzo char msg[NM_ERRBUF_SIZE]; 188f9790aebSLuigi Rizzo }; 189f9790aebSLuigi Rizzo 190f9790aebSLuigi Rizzo /* 191f9790aebSLuigi Rizzo * when the descriptor is open correctly, d->self == d 192b82b2211SLuigi Rizzo * Eventually we should also use some magic number. 193f9790aebSLuigi Rizzo */ 194f9790aebSLuigi Rizzo #define P2NMD(p) ((struct nm_desc_t *)(p)) 195f9790aebSLuigi Rizzo #define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 196f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 197f9790aebSLuigi Rizzo 19817885a7bSLuigi Rizzo 19917885a7bSLuigi Rizzo /* 20017885a7bSLuigi Rizzo * this is a slightly optimized copy routine which rounds 20117885a7bSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 20217885a7bSLuigi Rizzo * with other odd sizes. We assume there is enough room 20317885a7bSLuigi Rizzo * in the source and destination buffers. 20417885a7bSLuigi Rizzo * 20517885a7bSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 20617885a7bSLuigi Rizzo */ 20717885a7bSLuigi Rizzo static inline void 20817885a7bSLuigi Rizzo pkt_copy(const void *_src, void *_dst, int l) 20917885a7bSLuigi Rizzo { 210b82b2211SLuigi Rizzo const uint64_t *src = (const uint64_t *)_src; 211b82b2211SLuigi Rizzo uint64_t *dst = (uint64_t *)_dst; 212b82b2211SLuigi Rizzo 21317885a7bSLuigi Rizzo if (unlikely(l >= 1024)) { 21417885a7bSLuigi Rizzo memcpy(dst, src, l); 21517885a7bSLuigi Rizzo return; 21617885a7bSLuigi Rizzo } 21717885a7bSLuigi Rizzo for (; likely(l > 0); l-=64) { 21817885a7bSLuigi Rizzo *dst++ = *src++; 21917885a7bSLuigi Rizzo *dst++ = *src++; 22017885a7bSLuigi Rizzo *dst++ = *src++; 22117885a7bSLuigi Rizzo *dst++ = *src++; 22217885a7bSLuigi Rizzo *dst++ = *src++; 22317885a7bSLuigi Rizzo *dst++ = *src++; 22417885a7bSLuigi Rizzo *dst++ = *src++; 22517885a7bSLuigi Rizzo *dst++ = *src++; 22617885a7bSLuigi Rizzo } 22717885a7bSLuigi Rizzo } 22817885a7bSLuigi Rizzo 22917885a7bSLuigi Rizzo 230f9790aebSLuigi Rizzo /* 231f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 232f9790aebSLuigi Rizzo */ 233f9790aebSLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 234f9790aebSLuigi Rizzo 235f9790aebSLuigi Rizzo /* 23617885a7bSLuigi Rizzo *--- the pcap-like API --- 23717885a7bSLuigi Rizzo * 23817885a7bSLuigi Rizzo * nm_open() opens a file descriptor, binds to a port and maps memory. 23917885a7bSLuigi Rizzo * 24017885a7bSLuigi Rizzo * ifname (netmap:foo or vale:foo) is the port name 24117885a7bSLuigi Rizzo * flags can be NETMAP_SW_RING or NETMAP_HW_RING etc. 24217885a7bSLuigi Rizzo * ring_no only used if NETMAP_HW_RING is specified, is interpreted 24317885a7bSLuigi Rizzo * as a string or integer indicating the ring number 24417885a7bSLuigi Rizzo * ring_flags is stored in all ring flags (e.g. for transparent mode) 245f9790aebSLuigi Rizzo * to open. If successful, t opens the fd and maps the memory. 246f9790aebSLuigi Rizzo */ 24717885a7bSLuigi Rizzo 248f9790aebSLuigi Rizzo static struct nm_desc_t *nm_open(const char *ifname, 249f9790aebSLuigi Rizzo const char *ring_no, int flags, int ring_flags); 250f9790aebSLuigi Rizzo 251f9790aebSLuigi Rizzo /* 25217885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 253f9790aebSLuigi Rizzo */ 25417885a7bSLuigi Rizzo 25517885a7bSLuigi Rizzo static int nm_close(struct nm_desc_t *); 256f9790aebSLuigi Rizzo 257f9790aebSLuigi Rizzo /* 25817885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 25917885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 26017885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 261f9790aebSLuigi Rizzo */ 26217885a7bSLuigi Rizzo 26317885a7bSLuigi Rizzo static int nm_inject(struct nm_desc_t *, const void *, size_t); 26417885a7bSLuigi Rizzo static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 26517885a7bSLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc_t *, struct nm_hdr_t *); 266f9790aebSLuigi Rizzo 267f9790aebSLuigi Rizzo 268f9790aebSLuigi Rizzo /* 269f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 270f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 271f9790aebSLuigi Rizzo */ 272f9790aebSLuigi Rizzo static struct nm_desc_t * 273f9790aebSLuigi Rizzo nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 274f9790aebSLuigi Rizzo { 275f9790aebSLuigi Rizzo struct nm_desc_t *d; 276*66015019SLuigi Rizzo u_int n, namelen; 277*66015019SLuigi Rizzo char *port = NULL; 278f9790aebSLuigi Rizzo 279f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 280f9790aebSLuigi Rizzo errno = 0; /* name not recognised */ 281f9790aebSLuigi Rizzo return NULL; 282f9790aebSLuigi Rizzo } 283f9790aebSLuigi Rizzo if (ifname[0] == 'n') 284f9790aebSLuigi Rizzo ifname += 7; 285*66015019SLuigi Rizzo port = strchr(ifname, '-'); 286*66015019SLuigi Rizzo if (!port) { 287*66015019SLuigi Rizzo namelen = strlen(ifname); 288*66015019SLuigi Rizzo } else { 289*66015019SLuigi Rizzo namelen = port - ifname; 290*66015019SLuigi Rizzo flags &= ~(NETMAP_SW_RING | NETMAP_HW_RING | NETMAP_RING_MASK); 291*66015019SLuigi Rizzo if (port[1] == 's') 292*66015019SLuigi Rizzo flags |= NETMAP_SW_RING; 293*66015019SLuigi Rizzo else 294*66015019SLuigi Rizzo ring_name = port; 295*66015019SLuigi Rizzo } 296*66015019SLuigi Rizzo if (namelen >= sizeof(d->req.nr_name)) 297*66015019SLuigi Rizzo namelen = sizeof(d->req.nr_name) - 1; 298*66015019SLuigi Rizzo 299f9790aebSLuigi Rizzo d = (struct nm_desc_t *)calloc(1, sizeof(*d)); 300f9790aebSLuigi Rizzo if (d == NULL) { 301f9790aebSLuigi Rizzo errno = ENOMEM; 302f9790aebSLuigi Rizzo return NULL; 303f9790aebSLuigi Rizzo } 304f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 305f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 306f9790aebSLuigi Rizzo if (d->fd < 0) 307f9790aebSLuigi Rizzo goto fail; 308f9790aebSLuigi Rizzo 309f9790aebSLuigi Rizzo if (flags & NETMAP_SW_RING) { 310f9790aebSLuigi Rizzo d->req.nr_ringid = NETMAP_SW_RING; 311f9790aebSLuigi Rizzo } else { 312f9790aebSLuigi Rizzo u_int r; 313f9790aebSLuigi Rizzo if (flags & NETMAP_HW_RING) /* interpret ring as int */ 314f9790aebSLuigi Rizzo r = (uintptr_t)ring_name; 315f9790aebSLuigi Rizzo else /* interpret ring as numeric string */ 316f9790aebSLuigi Rizzo r = ring_name ? atoi(ring_name) : ~0; 317f9790aebSLuigi Rizzo r = (r < NETMAP_RING_MASK) ? (r | NETMAP_HW_RING) : 0; 318f9790aebSLuigi Rizzo d->req.nr_ringid = r; /* set the ring */ 319f9790aebSLuigi Rizzo } 320f9790aebSLuigi Rizzo d->req.nr_ringid |= (flags & ~NETMAP_RING_MASK); 321f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 322*66015019SLuigi Rizzo memcpy(d->req.nr_name, ifname, namelen); 323*66015019SLuigi Rizzo d->req.nr_name[namelen] = '\0'; 324*66015019SLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) { 325f9790aebSLuigi Rizzo goto fail; 326*66015019SLuigi Rizzo } 327f9790aebSLuigi Rizzo 328f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 329f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 330f9790aebSLuigi Rizzo d->fd, 0); 331f9790aebSLuigi Rizzo if (d->mem == NULL) 332f9790aebSLuigi Rizzo goto fail; 333f9790aebSLuigi Rizzo d->nifp = NETMAP_IF(d->mem, d->req.nr_offset); 334f9790aebSLuigi Rizzo if (d->req.nr_ringid & NETMAP_SW_RING) { 335*66015019SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings; 336*66015019SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings; 337f9790aebSLuigi Rizzo } else if (d->req.nr_ringid & NETMAP_HW_RING) { 338*66015019SLuigi Rizzo /* XXX check validity */ 339*66015019SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 340*66015019SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = 341f9790aebSLuigi Rizzo d->req.nr_ringid & NETMAP_RING_MASK; 342f9790aebSLuigi Rizzo } else { 343*66015019SLuigi Rizzo d->first_tx_ring = d->last_rx_ring = 0; 344*66015019SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings - 1; 345*66015019SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings - 1; 346f9790aebSLuigi Rizzo } 347*66015019SLuigi Rizzo d->tx = NETMAP_TXRING(d->nifp, 0); 348*66015019SLuigi Rizzo d->rx = NETMAP_RXRING(d->nifp, 0); 349*66015019SLuigi Rizzo d->cur_tx_ring = d->first_tx_ring; 350*66015019SLuigi Rizzo d->cur_rx_ring = d->first_rx_ring; 351*66015019SLuigi Rizzo for (n = d->first_tx_ring; n <= d->last_tx_ring; n++) { 352*66015019SLuigi Rizzo d->tx[n].flags |= ring_flags; 353*66015019SLuigi Rizzo } 354*66015019SLuigi Rizzo for (n = d->first_rx_ring; n <= d->last_rx_ring; n++) { 355*66015019SLuigi Rizzo d->rx[n].flags |= ring_flags; 356f9790aebSLuigi Rizzo } 357f9790aebSLuigi Rizzo return d; 358f9790aebSLuigi Rizzo 359f9790aebSLuigi Rizzo fail: 360f9790aebSLuigi Rizzo nm_close(d); 361f9790aebSLuigi Rizzo errno = EINVAL; 362f9790aebSLuigi Rizzo return NULL; 363f9790aebSLuigi Rizzo } 364f9790aebSLuigi Rizzo 365f9790aebSLuigi Rizzo 366f9790aebSLuigi Rizzo static int 367f9790aebSLuigi Rizzo nm_close(struct nm_desc_t *d) 368f9790aebSLuigi Rizzo { 36917885a7bSLuigi Rizzo /* 37017885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 37117885a7bSLuigi Rizzo */ 37217885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 373b82b2211SLuigi Rizzo { (void *)nm_open, (void *)nm_inject, 374b82b2211SLuigi Rizzo (void *)nm_dispatch, (void *)nm_nextpkt } ; 37517885a7bSLuigi Rizzo 376f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 377f9790aebSLuigi Rizzo return EINVAL; 378f9790aebSLuigi Rizzo if (d->mem) 379f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 380f9790aebSLuigi Rizzo if (d->fd != -1) 381f9790aebSLuigi Rizzo close(d->fd); 382f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 383f9790aebSLuigi Rizzo free(d); 384f9790aebSLuigi Rizzo return 0; 385f9790aebSLuigi Rizzo } 386f9790aebSLuigi Rizzo 387f9790aebSLuigi Rizzo 388f9790aebSLuigi Rizzo /* 38917885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 39017885a7bSLuigi Rizzo */ 39117885a7bSLuigi Rizzo static int 39217885a7bSLuigi Rizzo nm_inject(struct nm_desc_t *d, const void *buf, size_t size) 39317885a7bSLuigi Rizzo { 394*66015019SLuigi Rizzo u_int c, n = d->last_tx_ring - d->first_tx_ring + 1; 39517885a7bSLuigi Rizzo 39617885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 39717885a7bSLuigi Rizzo /* compute current ring to use */ 39817885a7bSLuigi Rizzo struct netmap_ring *ring; 39917885a7bSLuigi Rizzo uint32_t i, idx; 400*66015019SLuigi Rizzo uint32_t ri = d->cur_tx_ring + c; 40117885a7bSLuigi Rizzo 402*66015019SLuigi Rizzo if (ri > d->last_tx_ring) 403*66015019SLuigi Rizzo ri = d->first_tx_ring; 40417885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 40517885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 40617885a7bSLuigi Rizzo continue; 40717885a7bSLuigi Rizzo } 40817885a7bSLuigi Rizzo i = ring->cur; 40917885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 41017885a7bSLuigi Rizzo ring->slot[i].len = size; 41117885a7bSLuigi Rizzo pkt_copy(buf, NETMAP_BUF(ring, idx), size); 412*66015019SLuigi Rizzo d->cur_tx_ring = ri; 41317885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 41417885a7bSLuigi Rizzo return size; 41517885a7bSLuigi Rizzo } 41617885a7bSLuigi Rizzo return 0; /* fail */ 41717885a7bSLuigi Rizzo } 41817885a7bSLuigi Rizzo 41917885a7bSLuigi Rizzo 42017885a7bSLuigi Rizzo /* 421f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 422f9790aebSLuigi Rizzo */ 423f9790aebSLuigi Rizzo static int 424f9790aebSLuigi Rizzo nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 425f9790aebSLuigi Rizzo { 426*66015019SLuigi Rizzo int n = d->last_rx_ring - d->first_rx_ring + 1; 427*66015019SLuigi Rizzo int c, got = 0, ri = d->cur_rx_ring; 428f9790aebSLuigi Rizzo 429f9790aebSLuigi Rizzo if (cnt == 0) 430f9790aebSLuigi Rizzo cnt = -1; 431f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 432f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 433f9790aebSLuigi Rizzo * so we can omit checking for -1 434f9790aebSLuigi Rizzo */ 435f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 436f9790aebSLuigi Rizzo /* compute current ring to use */ 437f9790aebSLuigi Rizzo struct netmap_ring *ring; 438f9790aebSLuigi Rizzo 439*66015019SLuigi Rizzo ri = d->cur_rx_ring + c; 440*66015019SLuigi Rizzo if (ri > d->last_rx_ring) 441*66015019SLuigi Rizzo ri = d->first_rx_ring; 442f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 44317885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 444f9790aebSLuigi Rizzo u_int i = ring->cur; 445f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 446f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 447*66015019SLuigi Rizzo 448*66015019SLuigi Rizzo // __builtin_prefetch(buf); 449f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 450f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 451f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 45217885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 453f9790aebSLuigi Rizzo } 454f9790aebSLuigi Rizzo } 455*66015019SLuigi Rizzo d->cur_rx_ring = ri; 456f9790aebSLuigi Rizzo return got; 457f9790aebSLuigi Rizzo } 458f9790aebSLuigi Rizzo 459f9790aebSLuigi Rizzo static u_char * 46017885a7bSLuigi Rizzo nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) 461f9790aebSLuigi Rizzo { 462*66015019SLuigi Rizzo int ri = d->cur_rx_ring; 463f9790aebSLuigi Rizzo 464f9790aebSLuigi Rizzo do { 465f9790aebSLuigi Rizzo /* compute current ring to use */ 466f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 46717885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 468f9790aebSLuigi Rizzo u_int i = ring->cur; 469f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 470f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 471*66015019SLuigi Rizzo 472*66015019SLuigi Rizzo // __builtin_prefetch(buf); 473f9790aebSLuigi Rizzo hdr->ts = ring->ts; 474f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 47517885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 47617885a7bSLuigi Rizzo /* we could postpone advancing head if we want 47717885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 47817885a7bSLuigi Rizzo * the future. 47917885a7bSLuigi Rizzo */ 48017885a7bSLuigi Rizzo ring->head = ring->cur; 481*66015019SLuigi Rizzo d->cur_rx_ring = ri; 482f9790aebSLuigi Rizzo return buf; 483f9790aebSLuigi Rizzo } 484f9790aebSLuigi Rizzo ri++; 485*66015019SLuigi Rizzo if (ri > d->last_rx_ring) 486*66015019SLuigi Rizzo ri = d->first_rx_ring; 487*66015019SLuigi Rizzo } while (ri != d->cur_rx_ring); 488f9790aebSLuigi Rizzo return NULL; /* nothing found */ 489f9790aebSLuigi Rizzo } 490f9790aebSLuigi Rizzo 491f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 492f9790aebSLuigi Rizzo 493f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 494f9790aebSLuigi Rizzo 49568b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 496