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> 69*f0ea3689SLuigi Rizzo #include <sys/socket.h> /* apple needs sockaddr */ 70f9790aebSLuigi Rizzo #include <net/if.h> /* IFNAMSIZ */ 7117885a7bSLuigi Rizzo 7217885a7bSLuigi Rizzo #ifndef likely 7317885a7bSLuigi Rizzo #define likely(x) __builtin_expect(!!(x), 1) 7417885a7bSLuigi Rizzo #define unlikely(x) __builtin_expect(!!(x), 0) 7517885a7bSLuigi Rizzo #endif /* likely and unlikely */ 7617885a7bSLuigi Rizzo 77f9790aebSLuigi Rizzo #include <net/netmap.h> 78f9790aebSLuigi Rizzo 7917885a7bSLuigi Rizzo /* helper macro */ 80104d9fc7SEd Maste #define _NETMAP_OFFSET(type, ptr, offset) \ 81104d9fc7SEd Maste ((type)(void *)((char *)(ptr) + (offset))) 8268b8534bSLuigi Rizzo 8317885a7bSLuigi Rizzo #define NETMAP_IF(_base, _ofs) _NETMAP_OFFSET(struct netmap_if *, _base, _ofs) 8468b8534bSLuigi Rizzo 85104d9fc7SEd Maste #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 86104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index] ) 87104d9fc7SEd Maste 88104d9fc7SEd Maste #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 89104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) 9068b8534bSLuigi Rizzo 9168b8534bSLuigi Rizzo #define NETMAP_BUF(ring, index) \ 925819da83SLuigi Rizzo ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) 9368b8534bSLuigi Rizzo 9464ae02c3SLuigi Rizzo #define NETMAP_BUF_IDX(ring, buf) \ 9564ae02c3SLuigi Rizzo ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ 96a7250582SLuigi Rizzo (ring)->nr_buf_size ) 9764ae02c3SLuigi Rizzo 9868b8534bSLuigi Rizzo 9917885a7bSLuigi Rizzo static inline uint32_t 10017885a7bSLuigi Rizzo nm_ring_next(struct netmap_ring *r, uint32_t i) 10117885a7bSLuigi Rizzo { 10217885a7bSLuigi Rizzo return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1); 10317885a7bSLuigi Rizzo } 10417885a7bSLuigi Rizzo 105a7250582SLuigi Rizzo 10668b8534bSLuigi Rizzo /* 10717885a7bSLuigi Rizzo * Return 1 if we have pending transmissions in the tx ring. 108*f0ea3689SLuigi Rizzo * When everything is complete ring->head = ring->tail + 1 (modulo ring size) 10968b8534bSLuigi Rizzo */ 11017885a7bSLuigi Rizzo static inline int 11117885a7bSLuigi Rizzo nm_tx_pending(struct netmap_ring *r) 11217885a7bSLuigi Rizzo { 113*f0ea3689SLuigi Rizzo return nm_ring_next(r, r->tail) != r->head; 11417885a7bSLuigi Rizzo } 11517885a7bSLuigi Rizzo 11617885a7bSLuigi Rizzo 11717885a7bSLuigi Rizzo static inline uint32_t 11817885a7bSLuigi Rizzo nm_ring_space(struct netmap_ring *ring) 11917885a7bSLuigi Rizzo { 12017885a7bSLuigi Rizzo int ret = ring->tail - ring->cur; 12117885a7bSLuigi Rizzo if (ret < 0) 12217885a7bSLuigi Rizzo ret += ring->num_slots; 12317885a7bSLuigi Rizzo return ret; 12417885a7bSLuigi Rizzo } 12517885a7bSLuigi Rizzo 12668b8534bSLuigi Rizzo 127f9790aebSLuigi Rizzo #ifdef NETMAP_WITH_LIBS 128f9790aebSLuigi Rizzo /* 129f9790aebSLuigi Rizzo * Support for simple I/O libraries. 130f9790aebSLuigi Rizzo * Include other system headers required for compiling this. 131f9790aebSLuigi Rizzo */ 132f9790aebSLuigi Rizzo 133f9790aebSLuigi Rizzo #ifndef HAVE_NETMAP_WITH_LIBS 134f9790aebSLuigi Rizzo #define HAVE_NETMAP_WITH_LIBS 135f9790aebSLuigi Rizzo 136f9790aebSLuigi Rizzo #include <sys/time.h> 137f9790aebSLuigi Rizzo #include <sys/mman.h> 138f9790aebSLuigi Rizzo #include <string.h> /* memset */ 139f9790aebSLuigi Rizzo #include <sys/ioctl.h> 140f9790aebSLuigi Rizzo #include <sys/errno.h> /* EINVAL */ 141f9790aebSLuigi Rizzo #include <fcntl.h> /* O_RDWR */ 14217885a7bSLuigi Rizzo #include <unistd.h> /* close() */ 14366015019SLuigi Rizzo #include <signal.h> 14417885a7bSLuigi Rizzo #include <stdlib.h> 145f9790aebSLuigi Rizzo 146*f0ea3689SLuigi Rizzo #ifndef ND /* debug macros */ 147*f0ea3689SLuigi Rizzo /* debug support */ 148*f0ea3689SLuigi Rizzo #define ND(_fmt, ...) do {} while(0) 149*f0ea3689SLuigi Rizzo #define D(_fmt, ...) \ 150*f0ea3689SLuigi Rizzo do { \ 151*f0ea3689SLuigi Rizzo struct timeval t0; \ 152*f0ea3689SLuigi Rizzo gettimeofday(&t0, NULL); \ 153*f0ea3689SLuigi Rizzo fprintf(stderr, "%03d.%06d %s [%d] " _fmt "\n", \ 154*f0ea3689SLuigi Rizzo (int)(t0.tv_sec % 1000), (int)t0.tv_usec, \ 155*f0ea3689SLuigi Rizzo __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 156*f0ea3689SLuigi Rizzo } while (0) 157*f0ea3689SLuigi Rizzo 158*f0ea3689SLuigi Rizzo /* Rate limited version of "D", lps indicates how many per second */ 159*f0ea3689SLuigi Rizzo #define RD(lps, format, ...) \ 160*f0ea3689SLuigi Rizzo do { \ 161*f0ea3689SLuigi Rizzo static int t0, __cnt; \ 162*f0ea3689SLuigi Rizzo struct timeval __xxts; \ 163*f0ea3689SLuigi Rizzo gettimeofday(&__xxts, NULL); \ 164*f0ea3689SLuigi Rizzo if (t0 != __xxts.tv_sec) { \ 165*f0ea3689SLuigi Rizzo t0 = __xxts.tv_sec; \ 166*f0ea3689SLuigi Rizzo __cnt = 0; \ 167*f0ea3689SLuigi Rizzo } \ 168*f0ea3689SLuigi Rizzo if (__cnt++ < lps) { \ 169*f0ea3689SLuigi Rizzo D(format, ##__VA_ARGS__); \ 170*f0ea3689SLuigi Rizzo } \ 171*f0ea3689SLuigi Rizzo } while (0) 172*f0ea3689SLuigi Rizzo #endif 173*f0ea3689SLuigi Rizzo 174*f0ea3689SLuigi Rizzo struct nm_pkthdr { /* same as pcap_pkthdr */ 175f9790aebSLuigi Rizzo struct timeval ts; 176f9790aebSLuigi Rizzo uint32_t caplen; 177f9790aebSLuigi Rizzo uint32_t len; 178f9790aebSLuigi Rizzo }; 179f9790aebSLuigi Rizzo 180*f0ea3689SLuigi Rizzo struct nm_stat { /* same as pcap_stat */ 18166015019SLuigi Rizzo u_int ps_recv; 18266015019SLuigi Rizzo u_int ps_drop; 18366015019SLuigi Rizzo u_int ps_ifdrop; 18466015019SLuigi Rizzo #ifdef WIN32 18566015019SLuigi Rizzo u_int bs_capt; 18666015019SLuigi Rizzo #endif /* WIN32 */ 18766015019SLuigi Rizzo }; 18866015019SLuigi Rizzo 18966015019SLuigi Rizzo #define NM_ERRBUF_SIZE 512 19066015019SLuigi Rizzo 191*f0ea3689SLuigi Rizzo struct nm_desc { 192*f0ea3689SLuigi Rizzo struct nm_desc *self; /* point to self if netmap. */ 193f9790aebSLuigi Rizzo int fd; 194f9790aebSLuigi Rizzo void *mem; 195f9790aebSLuigi Rizzo int memsize; 196*f0ea3689SLuigi Rizzo int done_mmap; /* set if mem is the result of mmap */ 197*f0ea3689SLuigi Rizzo struct netmap_if * const nifp; 19866015019SLuigi Rizzo uint16_t first_tx_ring, last_tx_ring, cur_tx_ring; 19966015019SLuigi Rizzo uint16_t first_rx_ring, last_rx_ring, cur_rx_ring; 20066015019SLuigi Rizzo struct nmreq req; /* also contains the nr_name = ifname */ 201*f0ea3689SLuigi Rizzo struct nm_pkthdr hdr; 20266015019SLuigi Rizzo 203*f0ea3689SLuigi Rizzo /* 204*f0ea3689SLuigi Rizzo * The memory contains netmap_if, rings and then buffers. 205*f0ea3689SLuigi Rizzo * Given a pointer (e.g. to nm_inject) we can compare with 206*f0ea3689SLuigi Rizzo * mem/buf_start/buf_end to tell if it is a buffer or 207*f0ea3689SLuigi Rizzo * some other descriptor in our region. 208*f0ea3689SLuigi Rizzo * We also store a pointer to some ring as it helps in the 209*f0ea3689SLuigi Rizzo * translation from buffer indexes to addresses. 210*f0ea3689SLuigi Rizzo */ 211*f0ea3689SLuigi Rizzo struct netmap_ring * const some_ring; 212*f0ea3689SLuigi Rizzo void * const buf_start; 213*f0ea3689SLuigi Rizzo void * const buf_end; 21466015019SLuigi Rizzo /* parameters from pcap_open_live */ 21566015019SLuigi Rizzo int snaplen; 21666015019SLuigi Rizzo int promisc; 21766015019SLuigi Rizzo int to_ms; 21866015019SLuigi Rizzo char *errbuf; 21966015019SLuigi Rizzo 22066015019SLuigi Rizzo /* save flags so we can restore them on close */ 22166015019SLuigi Rizzo uint32_t if_flags; 22266015019SLuigi Rizzo uint32_t if_reqcap; 22366015019SLuigi Rizzo uint32_t if_curcap; 22466015019SLuigi Rizzo 225*f0ea3689SLuigi Rizzo struct nm_stat st; 22666015019SLuigi Rizzo char msg[NM_ERRBUF_SIZE]; 227f9790aebSLuigi Rizzo }; 228f9790aebSLuigi Rizzo 229f9790aebSLuigi Rizzo /* 230f9790aebSLuigi Rizzo * when the descriptor is open correctly, d->self == d 231b82b2211SLuigi Rizzo * Eventually we should also use some magic number. 232f9790aebSLuigi Rizzo */ 233*f0ea3689SLuigi Rizzo #define P2NMD(p) ((struct nm_desc *)(p)) 234*f0ea3689SLuigi Rizzo #define IS_NETMAP_DESC(d) ((d) && P2NMD(d)->self == P2NMD(d)) 235f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 236f9790aebSLuigi Rizzo 23717885a7bSLuigi Rizzo 23817885a7bSLuigi Rizzo /* 23917885a7bSLuigi Rizzo * this is a slightly optimized copy routine which rounds 24017885a7bSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 24117885a7bSLuigi Rizzo * with other odd sizes. We assume there is enough room 24217885a7bSLuigi Rizzo * in the source and destination buffers. 24317885a7bSLuigi Rizzo * 24417885a7bSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 24517885a7bSLuigi Rizzo */ 24617885a7bSLuigi Rizzo static inline void 247*f0ea3689SLuigi Rizzo nm_pkt_copy(const void *_src, void *_dst, int l) 24817885a7bSLuigi Rizzo { 249b82b2211SLuigi Rizzo const uint64_t *src = (const uint64_t *)_src; 250b82b2211SLuigi Rizzo uint64_t *dst = (uint64_t *)_dst; 251b82b2211SLuigi Rizzo 25217885a7bSLuigi Rizzo if (unlikely(l >= 1024)) { 25317885a7bSLuigi Rizzo memcpy(dst, src, l); 25417885a7bSLuigi Rizzo return; 25517885a7bSLuigi Rizzo } 25617885a7bSLuigi Rizzo for (; likely(l > 0); l-=64) { 25717885a7bSLuigi Rizzo *dst++ = *src++; 25817885a7bSLuigi Rizzo *dst++ = *src++; 25917885a7bSLuigi Rizzo *dst++ = *src++; 26017885a7bSLuigi Rizzo *dst++ = *src++; 26117885a7bSLuigi Rizzo *dst++ = *src++; 26217885a7bSLuigi Rizzo *dst++ = *src++; 26317885a7bSLuigi Rizzo *dst++ = *src++; 26417885a7bSLuigi Rizzo *dst++ = *src++; 26517885a7bSLuigi Rizzo } 26617885a7bSLuigi Rizzo } 26717885a7bSLuigi Rizzo 26817885a7bSLuigi Rizzo 269f9790aebSLuigi Rizzo /* 270f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 271f9790aebSLuigi Rizzo */ 272*f0ea3689SLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d); 273f9790aebSLuigi Rizzo 274f9790aebSLuigi Rizzo /* 27517885a7bSLuigi Rizzo *--- the pcap-like API --- 27617885a7bSLuigi Rizzo * 27717885a7bSLuigi Rizzo * nm_open() opens a file descriptor, binds to a port and maps memory. 27817885a7bSLuigi Rizzo * 27917885a7bSLuigi Rizzo * ifname (netmap:foo or vale:foo) is the port name 280*f0ea3689SLuigi Rizzo * a suffix can indicate the follwing: 281*f0ea3689SLuigi Rizzo * ^ bind the host (sw) ring pair 282*f0ea3689SLuigi Rizzo * * bind host and NIC ring pairs (transparent) 283*f0ea3689SLuigi Rizzo * -NN bind individual NIC ring pair 284*f0ea3689SLuigi Rizzo * {NN bind master side of pipe NN 285*f0ea3689SLuigi Rizzo * }NN bind slave side of pipe NN 286*f0ea3689SLuigi Rizzo * 287*f0ea3689SLuigi Rizzo * req provides the initial values of nmreq before parsing ifname. 288*f0ea3689SLuigi Rizzo * Remember that the ifname parsing will override the ring 289*f0ea3689SLuigi Rizzo * number in nm_ringid, and part of nm_flags; 290*f0ea3689SLuigi Rizzo * flags special functions, normally 0 291*f0ea3689SLuigi Rizzo * indicates which fields of *arg are significant 292*f0ea3689SLuigi Rizzo * arg special functions, normally NULL 293*f0ea3689SLuigi Rizzo * if passed a netmap_desc with mem != NULL, 294*f0ea3689SLuigi Rizzo * use that memory instead of mmap. 295f9790aebSLuigi Rizzo */ 29617885a7bSLuigi Rizzo 297*f0ea3689SLuigi Rizzo static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req, 298*f0ea3689SLuigi Rizzo uint64_t flags, const struct nm_desc *arg); 299*f0ea3689SLuigi Rizzo 300*f0ea3689SLuigi Rizzo /* 301*f0ea3689SLuigi Rizzo * nm_open can import some fields from the parent descriptor. 302*f0ea3689SLuigi Rizzo * These flags control which ones. 303*f0ea3689SLuigi Rizzo * Also in flags you can specify NETMAP_NO_TX_POLL and NETMAP_DO_RX_POLL, 304*f0ea3689SLuigi Rizzo * which set the initial value for these flags. 305*f0ea3689SLuigi Rizzo * Note that the 16 low bits of the flags are reserved for data 306*f0ea3689SLuigi Rizzo * that may go into the nmreq. 307*f0ea3689SLuigi Rizzo */ 308*f0ea3689SLuigi Rizzo enum { 309*f0ea3689SLuigi Rizzo NM_OPEN_NO_MMAP = 0x040000, /* reuse mmap from parent */ 310*f0ea3689SLuigi Rizzo NM_OPEN_IFNAME = 0x080000, /* nr_name, nr_ringid, nr_flags */ 311*f0ea3689SLuigi Rizzo NM_OPEN_ARG1 = 0x100000, 312*f0ea3689SLuigi Rizzo NM_OPEN_ARG2 = 0x200000, 313*f0ea3689SLuigi Rizzo NM_OPEN_ARG3 = 0x400000, 314*f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG = 0x800000, /* tx|rx rings|slots */ 315*f0ea3689SLuigi Rizzo }; 316*f0ea3689SLuigi Rizzo 317f9790aebSLuigi Rizzo 318f9790aebSLuigi Rizzo /* 31917885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 320f9790aebSLuigi Rizzo */ 32117885a7bSLuigi Rizzo 322*f0ea3689SLuigi Rizzo static int nm_close(struct nm_desc *); 323f9790aebSLuigi Rizzo 324f9790aebSLuigi Rizzo /* 32517885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 32617885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 32717885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 328f9790aebSLuigi Rizzo */ 32917885a7bSLuigi Rizzo 330*f0ea3689SLuigi Rizzo static int nm_inject(struct nm_desc *, const void *, size_t); 331*f0ea3689SLuigi Rizzo static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *); 332*f0ea3689SLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *); 333f9790aebSLuigi Rizzo 334f9790aebSLuigi Rizzo 335f9790aebSLuigi Rizzo /* 336f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 337f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 338*f0ea3689SLuigi Rizzo * You can pass a pointer to a pre-filled nm_desc to add special 339*f0ea3689SLuigi Rizzo * parameters. Flags is used as follows 340*f0ea3689SLuigi Rizzo * NM_OPEN_NO_MMAP use the memory from arg, only 341*f0ea3689SLuigi Rizzo * if the nr_arg2 (memory block) matches. 342*f0ea3689SLuigi Rizzo * NM_OPEN_ARG1 use req.nr_arg1 from arg 343*f0ea3689SLuigi Rizzo * NM_OPEN_ARG2 use req.nr_arg2 from arg 344*f0ea3689SLuigi Rizzo * NM_OPEN_RING_CFG user ring config from arg 345f9790aebSLuigi Rizzo */ 346*f0ea3689SLuigi Rizzo static struct nm_desc * 347*f0ea3689SLuigi Rizzo nm_open(const char *ifname, const struct nmreq *req, 348*f0ea3689SLuigi Rizzo uint64_t new_flags, const struct nm_desc *arg) 349f9790aebSLuigi Rizzo { 350*f0ea3689SLuigi Rizzo struct nm_desc *d = NULL; 351*f0ea3689SLuigi Rizzo const struct nm_desc *parent = arg; 352*f0ea3689SLuigi Rizzo u_int namelen; 353*f0ea3689SLuigi Rizzo uint32_t nr_ringid = 0, nr_flags; 354*f0ea3689SLuigi Rizzo const char *port = NULL; 355*f0ea3689SLuigi Rizzo const char *errmsg = NULL; 356f9790aebSLuigi Rizzo 357f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 358*f0ea3689SLuigi Rizzo errno = 0; /* name not recognised, not an error */ 359f9790aebSLuigi Rizzo return NULL; 360f9790aebSLuigi Rizzo } 361f9790aebSLuigi Rizzo if (ifname[0] == 'n') 362f9790aebSLuigi Rizzo ifname += 7; 363*f0ea3689SLuigi Rizzo /* scan for a separator */ 364*f0ea3689SLuigi Rizzo for (port = ifname; *port && !index("-*^{}", *port); port++) 365*f0ea3689SLuigi Rizzo ; 36666015019SLuigi Rizzo namelen = port - ifname; 367*f0ea3689SLuigi Rizzo if (namelen >= sizeof(d->req.nr_name)) { 368*f0ea3689SLuigi Rizzo errmsg = "name too long"; 369*f0ea3689SLuigi Rizzo goto fail; 37066015019SLuigi Rizzo } 371*f0ea3689SLuigi Rizzo switch (*port) { 372*f0ea3689SLuigi Rizzo default: /* '\0', no suffix */ 373*f0ea3689SLuigi Rizzo nr_flags = NR_REG_ALL_NIC; 374*f0ea3689SLuigi Rizzo break; 375*f0ea3689SLuigi Rizzo case '-': /* one NIC */ 376*f0ea3689SLuigi Rizzo nr_flags = NR_REG_ONE_NIC; 377*f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 378*f0ea3689SLuigi Rizzo break; 379*f0ea3689SLuigi Rizzo case '*': /* NIC and SW, ignore port */ 380*f0ea3689SLuigi Rizzo nr_flags = NR_REG_NIC_SW; 381*f0ea3689SLuigi Rizzo if (port[1]) { 382*f0ea3689SLuigi Rizzo errmsg = "invalid port for nic+sw"; 383*f0ea3689SLuigi Rizzo goto fail; 384*f0ea3689SLuigi Rizzo } 385*f0ea3689SLuigi Rizzo break; 386*f0ea3689SLuigi Rizzo case '^': /* only sw ring */ 387*f0ea3689SLuigi Rizzo nr_flags = NR_REG_SW; 388*f0ea3689SLuigi Rizzo if (port[1]) { 389*f0ea3689SLuigi Rizzo errmsg = "invalid port for sw ring"; 390*f0ea3689SLuigi Rizzo goto fail; 391*f0ea3689SLuigi Rizzo } 392*f0ea3689SLuigi Rizzo break; 393*f0ea3689SLuigi Rizzo case '{': 394*f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_MASTER; 395*f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 396*f0ea3689SLuigi Rizzo break; 397*f0ea3689SLuigi Rizzo case '}': 398*f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_SLAVE; 399*f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 400*f0ea3689SLuigi Rizzo break; 401*f0ea3689SLuigi Rizzo } 40266015019SLuigi Rizzo 403*f0ea3689SLuigi Rizzo if (nr_ringid >= NETMAP_RING_MASK) { 404*f0ea3689SLuigi Rizzo errmsg = "invalid ringid"; 405*f0ea3689SLuigi Rizzo goto fail; 406*f0ea3689SLuigi Rizzo } 407*f0ea3689SLuigi Rizzo /* add the *XPOLL flags */ 408*f0ea3689SLuigi Rizzo nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL); 409*f0ea3689SLuigi Rizzo 410*f0ea3689SLuigi Rizzo d = (struct nm_desc *)calloc(1, sizeof(*d)); 411f9790aebSLuigi Rizzo if (d == NULL) { 412*f0ea3689SLuigi Rizzo errmsg = "nm_desc alloc failure"; 413f9790aebSLuigi Rizzo errno = ENOMEM; 414f9790aebSLuigi Rizzo return NULL; 415f9790aebSLuigi Rizzo } 416f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 417f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 418*f0ea3689SLuigi Rizzo if (d->fd < 0) { 419*f0ea3689SLuigi Rizzo errmsg = "cannot open /dev/netmap"; 420f9790aebSLuigi Rizzo goto fail; 421f9790aebSLuigi Rizzo } 422*f0ea3689SLuigi Rizzo 423*f0ea3689SLuigi Rizzo if (req) 424*f0ea3689SLuigi Rizzo d->req = *req; 425f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 426*f0ea3689SLuigi Rizzo d->req.nr_ringid &= ~NETMAP_RING_MASK; 427*f0ea3689SLuigi Rizzo 428*f0ea3689SLuigi Rizzo /* these fields are overridden by ifname and flags processing */ 429*f0ea3689SLuigi Rizzo d->req.nr_ringid |= nr_ringid; 430*f0ea3689SLuigi Rizzo d->req.nr_flags = nr_flags; 43166015019SLuigi Rizzo memcpy(d->req.nr_name, ifname, namelen); 43266015019SLuigi Rizzo d->req.nr_name[namelen] = '\0'; 433*f0ea3689SLuigi Rizzo /* optionally import info from parent */ 434*f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && new_flags) { 435*f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG1) 436*f0ea3689SLuigi Rizzo D("overriding ARG1 %d", parent->req.nr_arg1); 437*f0ea3689SLuigi Rizzo d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ? 438*f0ea3689SLuigi Rizzo parent->req.nr_arg1 : 4; 439*f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG2) 440*f0ea3689SLuigi Rizzo D("overriding ARG2 %d", parent->req.nr_arg2); 441*f0ea3689SLuigi Rizzo d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ? 442*f0ea3689SLuigi Rizzo parent->req.nr_arg2 : 0; 443*f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG3) 444*f0ea3689SLuigi Rizzo D("overriding ARG3 %d", parent->req.nr_arg3); 445*f0ea3689SLuigi Rizzo d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ? 446*f0ea3689SLuigi Rizzo parent->req.nr_arg3 : 0; 447*f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_RING_CFG) { 448*f0ea3689SLuigi Rizzo D("overriding RING_CFG"); 449*f0ea3689SLuigi Rizzo d->req.nr_tx_slots = parent->req.nr_tx_slots; 450*f0ea3689SLuigi Rizzo d->req.nr_rx_slots = parent->req.nr_rx_slots; 451*f0ea3689SLuigi Rizzo d->req.nr_tx_rings = parent->req.nr_tx_rings; 452*f0ea3689SLuigi Rizzo d->req.nr_rx_rings = parent->req.nr_rx_rings; 453*f0ea3689SLuigi Rizzo } 454*f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_IFNAME) { 455*f0ea3689SLuigi Rizzo D("overriding ifname %s ringid 0x%x flags 0x%x", 456*f0ea3689SLuigi Rizzo parent->req.nr_name, parent->req.nr_ringid, 457*f0ea3689SLuigi Rizzo parent->req.nr_flags); 458*f0ea3689SLuigi Rizzo memcpy(d->req.nr_name, parent->req.nr_name, 459*f0ea3689SLuigi Rizzo sizeof(d->req.nr_name)); 460*f0ea3689SLuigi Rizzo d->req.nr_ringid = parent->req.nr_ringid; 461*f0ea3689SLuigi Rizzo d->req.nr_flags = parent->req.nr_flags; 462*f0ea3689SLuigi Rizzo } 463*f0ea3689SLuigi Rizzo } 46466015019SLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) { 465*f0ea3689SLuigi Rizzo errmsg = "NIOCREGIF failed"; 466f9790aebSLuigi Rizzo goto fail; 46766015019SLuigi Rizzo } 468f9790aebSLuigi Rizzo 469*f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && parent->mem && 470*f0ea3689SLuigi Rizzo parent->req.nr_arg2 == d->req.nr_arg2) { 471*f0ea3689SLuigi Rizzo /* do not mmap, inherit from parent */ 472*f0ea3689SLuigi Rizzo d->memsize = parent->memsize; 473*f0ea3689SLuigi Rizzo d->mem = parent->mem; 474*f0ea3689SLuigi Rizzo } else { 475f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 476f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 477f9790aebSLuigi Rizzo d->fd, 0); 478*f0ea3689SLuigi Rizzo if (d->mem == NULL) { 479*f0ea3689SLuigi Rizzo errmsg = "mmap failed"; 480f9790aebSLuigi Rizzo goto fail; 481*f0ea3689SLuigi Rizzo } 482*f0ea3689SLuigi Rizzo d->done_mmap = 1; 483*f0ea3689SLuigi Rizzo } 484*f0ea3689SLuigi Rizzo { 485*f0ea3689SLuigi Rizzo struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); 486*f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(nifp, ); 487*f0ea3689SLuigi Rizzo 488*f0ea3689SLuigi Rizzo *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; 489*f0ea3689SLuigi Rizzo *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; 490*f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); 491*f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_end = 492*f0ea3689SLuigi Rizzo (char *)d->mem + d->memsize; 493*f0ea3689SLuigi Rizzo } 494*f0ea3689SLuigi Rizzo 495*f0ea3689SLuigi Rizzo if (nr_flags == NR_REG_SW) { /* host stack */ 49666015019SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings; 49766015019SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings; 498*f0ea3689SLuigi Rizzo } else if (nr_flags == NR_REG_ALL_NIC) { /* only nic */ 499*f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 500*f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 50166015019SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings - 1; 50266015019SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings - 1; 503*f0ea3689SLuigi Rizzo } else if (nr_flags == NR_REG_NIC_SW) { 504*f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 505*f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 506*f0ea3689SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings; 507*f0ea3689SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings; 508*f0ea3689SLuigi Rizzo } else if (nr_flags == NR_REG_ONE_NIC) { 509*f0ea3689SLuigi Rizzo /* XXX check validity */ 510*f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 511*f0ea3689SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = nr_ringid; 512*f0ea3689SLuigi Rizzo } else { /* pipes */ 513*f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 0; 514*f0ea3689SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = 0; 515f9790aebSLuigi Rizzo } 516*f0ea3689SLuigi Rizzo 517*f0ea3689SLuigi Rizzo #ifdef DEBUG_NETMAP_USER 518*f0ea3689SLuigi Rizzo { /* debugging code */ 519*f0ea3689SLuigi Rizzo int i; 520*f0ea3689SLuigi Rizzo 521*f0ea3689SLuigi Rizzo D("%s tx %d .. %d %d rx %d .. %d %d", ifname, 522*f0ea3689SLuigi Rizzo d->first_tx_ring, d->last_tx_ring, d->req.nr_tx_rings, 523*f0ea3689SLuigi Rizzo d->first_rx_ring, d->last_rx_ring, d->req.nr_rx_rings); 524*f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_tx_rings; i++) { 525*f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_TXRING(d->nifp, i); 526*f0ea3689SLuigi Rizzo D("TX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 527*f0ea3689SLuigi Rizzo } 528*f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_rx_rings; i++) { 529*f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(d->nifp, i); 530*f0ea3689SLuigi Rizzo D("RX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 531*f0ea3689SLuigi Rizzo } 532*f0ea3689SLuigi Rizzo } 533*f0ea3689SLuigi Rizzo #endif /* debugging */ 534*f0ea3689SLuigi Rizzo 53566015019SLuigi Rizzo d->cur_tx_ring = d->first_tx_ring; 53666015019SLuigi Rizzo d->cur_rx_ring = d->first_rx_ring; 537f9790aebSLuigi Rizzo return d; 538f9790aebSLuigi Rizzo 539f9790aebSLuigi Rizzo fail: 540f9790aebSLuigi Rizzo nm_close(d); 541*f0ea3689SLuigi Rizzo if (errmsg) 542*f0ea3689SLuigi Rizzo D("%s %s", errmsg, ifname); 543f9790aebSLuigi Rizzo errno = EINVAL; 544f9790aebSLuigi Rizzo return NULL; 545f9790aebSLuigi Rizzo } 546f9790aebSLuigi Rizzo 547f9790aebSLuigi Rizzo 548f9790aebSLuigi Rizzo static int 549*f0ea3689SLuigi Rizzo nm_close(struct nm_desc *d) 550f9790aebSLuigi Rizzo { 55117885a7bSLuigi Rizzo /* 55217885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 55317885a7bSLuigi Rizzo */ 55417885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 555b82b2211SLuigi Rizzo { (void *)nm_open, (void *)nm_inject, 556b82b2211SLuigi Rizzo (void *)nm_dispatch, (void *)nm_nextpkt } ; 55717885a7bSLuigi Rizzo 558f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 559f9790aebSLuigi Rizzo return EINVAL; 560*f0ea3689SLuigi Rizzo if (d->done_mmap && d->mem) 561f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 562f9790aebSLuigi Rizzo if (d->fd != -1) 563f9790aebSLuigi Rizzo close(d->fd); 564f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 565f9790aebSLuigi Rizzo free(d); 566f9790aebSLuigi Rizzo return 0; 567f9790aebSLuigi Rizzo } 568f9790aebSLuigi Rizzo 569f9790aebSLuigi Rizzo 570f9790aebSLuigi Rizzo /* 57117885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 57217885a7bSLuigi Rizzo */ 57317885a7bSLuigi Rizzo static int 574*f0ea3689SLuigi Rizzo nm_inject(struct nm_desc *d, const void *buf, size_t size) 57517885a7bSLuigi Rizzo { 57666015019SLuigi Rizzo u_int c, n = d->last_tx_ring - d->first_tx_ring + 1; 57717885a7bSLuigi Rizzo 57817885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 57917885a7bSLuigi Rizzo /* compute current ring to use */ 58017885a7bSLuigi Rizzo struct netmap_ring *ring; 58117885a7bSLuigi Rizzo uint32_t i, idx; 58266015019SLuigi Rizzo uint32_t ri = d->cur_tx_ring + c; 58317885a7bSLuigi Rizzo 58466015019SLuigi Rizzo if (ri > d->last_tx_ring) 58566015019SLuigi Rizzo ri = d->first_tx_ring; 58617885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 58717885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 58817885a7bSLuigi Rizzo continue; 58917885a7bSLuigi Rizzo } 59017885a7bSLuigi Rizzo i = ring->cur; 59117885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 59217885a7bSLuigi Rizzo ring->slot[i].len = size; 593*f0ea3689SLuigi Rizzo nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size); 59466015019SLuigi Rizzo d->cur_tx_ring = ri; 59517885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 59617885a7bSLuigi Rizzo return size; 59717885a7bSLuigi Rizzo } 59817885a7bSLuigi Rizzo return 0; /* fail */ 59917885a7bSLuigi Rizzo } 60017885a7bSLuigi Rizzo 60117885a7bSLuigi Rizzo 60217885a7bSLuigi Rizzo /* 603f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 604f9790aebSLuigi Rizzo */ 605f9790aebSLuigi Rizzo static int 606*f0ea3689SLuigi Rizzo nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg) 607f9790aebSLuigi Rizzo { 60866015019SLuigi Rizzo int n = d->last_rx_ring - d->first_rx_ring + 1; 60966015019SLuigi Rizzo int c, got = 0, ri = d->cur_rx_ring; 610f9790aebSLuigi Rizzo 611f9790aebSLuigi Rizzo if (cnt == 0) 612f9790aebSLuigi Rizzo cnt = -1; 613f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 614f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 615f9790aebSLuigi Rizzo * so we can omit checking for -1 616f9790aebSLuigi Rizzo */ 617f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 618f9790aebSLuigi Rizzo /* compute current ring to use */ 619f9790aebSLuigi Rizzo struct netmap_ring *ring; 620f9790aebSLuigi Rizzo 62166015019SLuigi Rizzo ri = d->cur_rx_ring + c; 62266015019SLuigi Rizzo if (ri > d->last_rx_ring) 62366015019SLuigi Rizzo ri = d->first_rx_ring; 624f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 62517885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 626f9790aebSLuigi Rizzo u_int i = ring->cur; 627f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 628f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 62966015019SLuigi Rizzo 63066015019SLuigi Rizzo // __builtin_prefetch(buf); 631f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 632f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 633f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 63417885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 635f9790aebSLuigi Rizzo } 636f9790aebSLuigi Rizzo } 63766015019SLuigi Rizzo d->cur_rx_ring = ri; 638f9790aebSLuigi Rizzo return got; 639f9790aebSLuigi Rizzo } 640f9790aebSLuigi Rizzo 641f9790aebSLuigi Rizzo static u_char * 642*f0ea3689SLuigi Rizzo nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr) 643f9790aebSLuigi Rizzo { 64466015019SLuigi Rizzo int ri = d->cur_rx_ring; 645f9790aebSLuigi Rizzo 646f9790aebSLuigi Rizzo do { 647f9790aebSLuigi Rizzo /* compute current ring to use */ 648f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 64917885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 650f9790aebSLuigi Rizzo u_int i = ring->cur; 651f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 652f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 65366015019SLuigi Rizzo 65466015019SLuigi Rizzo // __builtin_prefetch(buf); 655f9790aebSLuigi Rizzo hdr->ts = ring->ts; 656f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 65717885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 65817885a7bSLuigi Rizzo /* we could postpone advancing head if we want 65917885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 66017885a7bSLuigi Rizzo * the future. 66117885a7bSLuigi Rizzo */ 66217885a7bSLuigi Rizzo ring->head = ring->cur; 66366015019SLuigi Rizzo d->cur_rx_ring = ri; 664f9790aebSLuigi Rizzo return buf; 665f9790aebSLuigi Rizzo } 666f9790aebSLuigi Rizzo ri++; 66766015019SLuigi Rizzo if (ri > d->last_rx_ring) 66866015019SLuigi Rizzo ri = d->first_rx_ring; 66966015019SLuigi Rizzo } while (ri != d->cur_rx_ring); 670f9790aebSLuigi Rizzo return NULL; /* nothing found */ 671f9790aebSLuigi Rizzo } 672f9790aebSLuigi Rizzo 673f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 674f9790aebSLuigi Rizzo 675f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 676f9790aebSLuigi Rizzo 67768b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 678