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) 43*0506889cSLuigi Rizzo * we can access ring->cur, ring->head, ring->tail, etc. 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> 69f0ea3689SLuigi 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. 108f0ea3689SLuigi 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 { 113f0ea3689SLuigi 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 1369225c808SLuigi Rizzo #include <stdio.h> 137f9790aebSLuigi Rizzo #include <sys/time.h> 138f9790aebSLuigi Rizzo #include <sys/mman.h> 139f9790aebSLuigi Rizzo #include <string.h> /* memset */ 140f9790aebSLuigi Rizzo #include <sys/ioctl.h> 141f9790aebSLuigi Rizzo #include <sys/errno.h> /* EINVAL */ 142f9790aebSLuigi Rizzo #include <fcntl.h> /* O_RDWR */ 14317885a7bSLuigi Rizzo #include <unistd.h> /* close() */ 14466015019SLuigi Rizzo #include <signal.h> 14517885a7bSLuigi Rizzo #include <stdlib.h> 146f9790aebSLuigi Rizzo 147f0ea3689SLuigi Rizzo #ifndef ND /* debug macros */ 148f0ea3689SLuigi Rizzo /* debug support */ 149f0ea3689SLuigi Rizzo #define ND(_fmt, ...) do {} while(0) 150f0ea3689SLuigi Rizzo #define D(_fmt, ...) \ 151f0ea3689SLuigi Rizzo do { \ 1524bf50f18SLuigi Rizzo struct timeval _t0; \ 1534bf50f18SLuigi Rizzo gettimeofday(&_t0, NULL); \ 154f0ea3689SLuigi Rizzo fprintf(stderr, "%03d.%06d %s [%d] " _fmt "\n", \ 1554bf50f18SLuigi Rizzo (int)(_t0.tv_sec % 1000), (int)_t0.tv_usec, \ 156f0ea3689SLuigi Rizzo __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 157f0ea3689SLuigi Rizzo } while (0) 158f0ea3689SLuigi Rizzo 159f0ea3689SLuigi Rizzo /* Rate limited version of "D", lps indicates how many per second */ 160f0ea3689SLuigi Rizzo #define RD(lps, format, ...) \ 161f0ea3689SLuigi Rizzo do { \ 1624bf50f18SLuigi Rizzo static int __t0, __cnt; \ 163f0ea3689SLuigi Rizzo struct timeval __xxts; \ 164f0ea3689SLuigi Rizzo gettimeofday(&__xxts, NULL); \ 1654bf50f18SLuigi Rizzo if (__t0 != __xxts.tv_sec) { \ 1664bf50f18SLuigi Rizzo __t0 = __xxts.tv_sec; \ 167f0ea3689SLuigi Rizzo __cnt = 0; \ 168f0ea3689SLuigi Rizzo } \ 169f0ea3689SLuigi Rizzo if (__cnt++ < lps) { \ 170f0ea3689SLuigi Rizzo D(format, ##__VA_ARGS__); \ 171f0ea3689SLuigi Rizzo } \ 172f0ea3689SLuigi Rizzo } while (0) 173f0ea3689SLuigi Rizzo #endif 174f0ea3689SLuigi Rizzo 175f0ea3689SLuigi Rizzo struct nm_pkthdr { /* same as pcap_pkthdr */ 176f9790aebSLuigi Rizzo struct timeval ts; 177f9790aebSLuigi Rizzo uint32_t caplen; 178f9790aebSLuigi Rizzo uint32_t len; 179f9790aebSLuigi Rizzo }; 180f9790aebSLuigi Rizzo 181f0ea3689SLuigi Rizzo struct nm_stat { /* same as pcap_stat */ 18266015019SLuigi Rizzo u_int ps_recv; 18366015019SLuigi Rizzo u_int ps_drop; 18466015019SLuigi Rizzo u_int ps_ifdrop; 18566015019SLuigi Rizzo #ifdef WIN32 18666015019SLuigi Rizzo u_int bs_capt; 18766015019SLuigi Rizzo #endif /* WIN32 */ 18866015019SLuigi Rizzo }; 18966015019SLuigi Rizzo 19066015019SLuigi Rizzo #define NM_ERRBUF_SIZE 512 19166015019SLuigi Rizzo 192f0ea3689SLuigi Rizzo struct nm_desc { 193f0ea3689SLuigi Rizzo struct nm_desc *self; /* point to self if netmap. */ 194f9790aebSLuigi Rizzo int fd; 195f9790aebSLuigi Rizzo void *mem; 1969225c808SLuigi Rizzo uint32_t memsize; 197f0ea3689SLuigi Rizzo int done_mmap; /* set if mem is the result of mmap */ 198f0ea3689SLuigi Rizzo struct netmap_if * const nifp; 19966015019SLuigi Rizzo uint16_t first_tx_ring, last_tx_ring, cur_tx_ring; 20066015019SLuigi Rizzo uint16_t first_rx_ring, last_rx_ring, cur_rx_ring; 20166015019SLuigi Rizzo struct nmreq req; /* also contains the nr_name = ifname */ 202f0ea3689SLuigi Rizzo struct nm_pkthdr hdr; 20366015019SLuigi Rizzo 204f0ea3689SLuigi Rizzo /* 205f0ea3689SLuigi Rizzo * The memory contains netmap_if, rings and then buffers. 206f0ea3689SLuigi Rizzo * Given a pointer (e.g. to nm_inject) we can compare with 207f0ea3689SLuigi Rizzo * mem/buf_start/buf_end to tell if it is a buffer or 208f0ea3689SLuigi Rizzo * some other descriptor in our region. 209f0ea3689SLuigi Rizzo * We also store a pointer to some ring as it helps in the 210f0ea3689SLuigi Rizzo * translation from buffer indexes to addresses. 211f0ea3689SLuigi Rizzo */ 212f0ea3689SLuigi Rizzo struct netmap_ring * const some_ring; 213f0ea3689SLuigi Rizzo void * const buf_start; 214f0ea3689SLuigi Rizzo void * const buf_end; 21566015019SLuigi Rizzo /* parameters from pcap_open_live */ 21666015019SLuigi Rizzo int snaplen; 21766015019SLuigi Rizzo int promisc; 21866015019SLuigi Rizzo int to_ms; 21966015019SLuigi Rizzo char *errbuf; 22066015019SLuigi Rizzo 22166015019SLuigi Rizzo /* save flags so we can restore them on close */ 22266015019SLuigi Rizzo uint32_t if_flags; 22366015019SLuigi Rizzo uint32_t if_reqcap; 22466015019SLuigi Rizzo uint32_t if_curcap; 22566015019SLuigi Rizzo 226f0ea3689SLuigi Rizzo struct nm_stat st; 22766015019SLuigi Rizzo char msg[NM_ERRBUF_SIZE]; 228f9790aebSLuigi Rizzo }; 229f9790aebSLuigi Rizzo 230f9790aebSLuigi Rizzo /* 231f9790aebSLuigi Rizzo * when the descriptor is open correctly, d->self == d 232b82b2211SLuigi Rizzo * Eventually we should also use some magic number. 233f9790aebSLuigi Rizzo */ 234f0ea3689SLuigi Rizzo #define P2NMD(p) ((struct nm_desc *)(p)) 235f0ea3689SLuigi Rizzo #define IS_NETMAP_DESC(d) ((d) && P2NMD(d)->self == P2NMD(d)) 236f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 237f9790aebSLuigi Rizzo 23817885a7bSLuigi Rizzo 23917885a7bSLuigi Rizzo /* 24017885a7bSLuigi Rizzo * this is a slightly optimized copy routine which rounds 24117885a7bSLuigi Rizzo * to multiple of 64 bytes and is often faster than dealing 24217885a7bSLuigi Rizzo * with other odd sizes. We assume there is enough room 24317885a7bSLuigi Rizzo * in the source and destination buffers. 24417885a7bSLuigi Rizzo * 24517885a7bSLuigi Rizzo * XXX only for multiples of 64 bytes, non overlapped. 24617885a7bSLuigi Rizzo */ 24717885a7bSLuigi Rizzo static inline void 248f0ea3689SLuigi Rizzo nm_pkt_copy(const void *_src, void *_dst, int l) 24917885a7bSLuigi Rizzo { 250b82b2211SLuigi Rizzo const uint64_t *src = (const uint64_t *)_src; 251b82b2211SLuigi Rizzo uint64_t *dst = (uint64_t *)_dst; 252b82b2211SLuigi Rizzo 25317885a7bSLuigi Rizzo if (unlikely(l >= 1024)) { 25417885a7bSLuigi Rizzo memcpy(dst, src, l); 25517885a7bSLuigi Rizzo return; 25617885a7bSLuigi Rizzo } 25717885a7bSLuigi Rizzo for (; likely(l > 0); l-=64) { 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 *dst++ = *src++; 26617885a7bSLuigi Rizzo } 26717885a7bSLuigi Rizzo } 26817885a7bSLuigi Rizzo 26917885a7bSLuigi Rizzo 270f9790aebSLuigi Rizzo /* 271f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 272f9790aebSLuigi Rizzo */ 273f0ea3689SLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d); 274f9790aebSLuigi Rizzo 275f9790aebSLuigi Rizzo /* 27617885a7bSLuigi Rizzo *--- the pcap-like API --- 27717885a7bSLuigi Rizzo * 27817885a7bSLuigi Rizzo * nm_open() opens a file descriptor, binds to a port and maps memory. 27917885a7bSLuigi Rizzo * 28017885a7bSLuigi Rizzo * ifname (netmap:foo or vale:foo) is the port name 281f0ea3689SLuigi Rizzo * a suffix can indicate the follwing: 282f0ea3689SLuigi Rizzo * ^ bind the host (sw) ring pair 283f0ea3689SLuigi Rizzo * * bind host and NIC ring pairs (transparent) 284f0ea3689SLuigi Rizzo * -NN bind individual NIC ring pair 285f0ea3689SLuigi Rizzo * {NN bind master side of pipe NN 286f0ea3689SLuigi Rizzo * }NN bind slave side of pipe NN 287f0ea3689SLuigi Rizzo * 288f0ea3689SLuigi Rizzo * req provides the initial values of nmreq before parsing ifname. 289f0ea3689SLuigi Rizzo * Remember that the ifname parsing will override the ring 290f0ea3689SLuigi Rizzo * number in nm_ringid, and part of nm_flags; 291f0ea3689SLuigi Rizzo * flags special functions, normally 0 292f0ea3689SLuigi Rizzo * indicates which fields of *arg are significant 293f0ea3689SLuigi Rizzo * arg special functions, normally NULL 294f0ea3689SLuigi Rizzo * if passed a netmap_desc with mem != NULL, 295f0ea3689SLuigi Rizzo * use that memory instead of mmap. 296f9790aebSLuigi Rizzo */ 29717885a7bSLuigi Rizzo 298f0ea3689SLuigi Rizzo static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req, 299f0ea3689SLuigi Rizzo uint64_t flags, const struct nm_desc *arg); 300f0ea3689SLuigi Rizzo 301f0ea3689SLuigi Rizzo /* 302f0ea3689SLuigi Rizzo * nm_open can import some fields from the parent descriptor. 303f0ea3689SLuigi Rizzo * These flags control which ones. 304f0ea3689SLuigi Rizzo * Also in flags you can specify NETMAP_NO_TX_POLL and NETMAP_DO_RX_POLL, 305f0ea3689SLuigi Rizzo * which set the initial value for these flags. 306f0ea3689SLuigi Rizzo * Note that the 16 low bits of the flags are reserved for data 307f0ea3689SLuigi Rizzo * that may go into the nmreq. 308f0ea3689SLuigi Rizzo */ 309f0ea3689SLuigi Rizzo enum { 310f0ea3689SLuigi Rizzo NM_OPEN_NO_MMAP = 0x040000, /* reuse mmap from parent */ 311f0ea3689SLuigi Rizzo NM_OPEN_IFNAME = 0x080000, /* nr_name, nr_ringid, nr_flags */ 312f0ea3689SLuigi Rizzo NM_OPEN_ARG1 = 0x100000, 313f0ea3689SLuigi Rizzo NM_OPEN_ARG2 = 0x200000, 314f0ea3689SLuigi Rizzo NM_OPEN_ARG3 = 0x400000, 315f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG = 0x800000, /* tx|rx rings|slots */ 316f0ea3689SLuigi Rizzo }; 317f0ea3689SLuigi Rizzo 318f9790aebSLuigi Rizzo 319f9790aebSLuigi Rizzo /* 32017885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 321f9790aebSLuigi Rizzo */ 32217885a7bSLuigi Rizzo 323f0ea3689SLuigi Rizzo static int nm_close(struct nm_desc *); 324f9790aebSLuigi Rizzo 325f9790aebSLuigi Rizzo /* 32617885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 32717885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 32817885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 329f9790aebSLuigi Rizzo */ 33017885a7bSLuigi Rizzo 331f0ea3689SLuigi Rizzo static int nm_inject(struct nm_desc *, const void *, size_t); 332f0ea3689SLuigi Rizzo static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *); 333f0ea3689SLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *); 334f9790aebSLuigi Rizzo 335f9790aebSLuigi Rizzo 336f9790aebSLuigi Rizzo /* 337f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 338f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 339f0ea3689SLuigi Rizzo * You can pass a pointer to a pre-filled nm_desc to add special 340f0ea3689SLuigi Rizzo * parameters. Flags is used as follows 341f0ea3689SLuigi Rizzo * NM_OPEN_NO_MMAP use the memory from arg, only 342f0ea3689SLuigi Rizzo * if the nr_arg2 (memory block) matches. 343f0ea3689SLuigi Rizzo * NM_OPEN_ARG1 use req.nr_arg1 from arg 344f0ea3689SLuigi Rizzo * NM_OPEN_ARG2 use req.nr_arg2 from arg 345f0ea3689SLuigi Rizzo * NM_OPEN_RING_CFG user ring config from arg 346f9790aebSLuigi Rizzo */ 347f0ea3689SLuigi Rizzo static struct nm_desc * 348f0ea3689SLuigi Rizzo nm_open(const char *ifname, const struct nmreq *req, 349f0ea3689SLuigi Rizzo uint64_t new_flags, const struct nm_desc *arg) 350f9790aebSLuigi Rizzo { 351f0ea3689SLuigi Rizzo struct nm_desc *d = NULL; 352f0ea3689SLuigi Rizzo const struct nm_desc *parent = arg; 353f0ea3689SLuigi Rizzo u_int namelen; 354f0ea3689SLuigi Rizzo uint32_t nr_ringid = 0, nr_flags; 355f0ea3689SLuigi Rizzo const char *port = NULL; 356f0ea3689SLuigi Rizzo const char *errmsg = NULL; 357f9790aebSLuigi Rizzo 358f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 359f0ea3689SLuigi Rizzo errno = 0; /* name not recognised, not an error */ 360f9790aebSLuigi Rizzo return NULL; 361f9790aebSLuigi Rizzo } 362f9790aebSLuigi Rizzo if (ifname[0] == 'n') 363f9790aebSLuigi Rizzo ifname += 7; 364f0ea3689SLuigi Rizzo /* scan for a separator */ 365f0ea3689SLuigi Rizzo for (port = ifname; *port && !index("-*^{}", *port); port++) 366f0ea3689SLuigi Rizzo ; 36766015019SLuigi Rizzo namelen = port - ifname; 368f0ea3689SLuigi Rizzo if (namelen >= sizeof(d->req.nr_name)) { 369f0ea3689SLuigi Rizzo errmsg = "name too long"; 370f0ea3689SLuigi Rizzo goto fail; 37166015019SLuigi Rizzo } 372f0ea3689SLuigi Rizzo switch (*port) { 373f0ea3689SLuigi Rizzo default: /* '\0', no suffix */ 374f0ea3689SLuigi Rizzo nr_flags = NR_REG_ALL_NIC; 375f0ea3689SLuigi Rizzo break; 376f0ea3689SLuigi Rizzo case '-': /* one NIC */ 377f0ea3689SLuigi Rizzo nr_flags = NR_REG_ONE_NIC; 378f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 379f0ea3689SLuigi Rizzo break; 380f0ea3689SLuigi Rizzo case '*': /* NIC and SW, ignore port */ 381f0ea3689SLuigi Rizzo nr_flags = NR_REG_NIC_SW; 382f0ea3689SLuigi Rizzo if (port[1]) { 383f0ea3689SLuigi Rizzo errmsg = "invalid port for nic+sw"; 384f0ea3689SLuigi Rizzo goto fail; 385f0ea3689SLuigi Rizzo } 386f0ea3689SLuigi Rizzo break; 387f0ea3689SLuigi Rizzo case '^': /* only sw ring */ 388f0ea3689SLuigi Rizzo nr_flags = NR_REG_SW; 389f0ea3689SLuigi Rizzo if (port[1]) { 390f0ea3689SLuigi Rizzo errmsg = "invalid port for sw ring"; 391f0ea3689SLuigi Rizzo goto fail; 392f0ea3689SLuigi Rizzo } 393f0ea3689SLuigi Rizzo break; 394f0ea3689SLuigi Rizzo case '{': 395f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_MASTER; 396f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 397f0ea3689SLuigi Rizzo break; 398f0ea3689SLuigi Rizzo case '}': 399f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_SLAVE; 400f0ea3689SLuigi Rizzo nr_ringid = atoi(port + 1); 401f0ea3689SLuigi Rizzo break; 402f0ea3689SLuigi Rizzo } 40366015019SLuigi Rizzo 404f0ea3689SLuigi Rizzo if (nr_ringid >= NETMAP_RING_MASK) { 405f0ea3689SLuigi Rizzo errmsg = "invalid ringid"; 406f0ea3689SLuigi Rizzo goto fail; 407f0ea3689SLuigi Rizzo } 408f0ea3689SLuigi Rizzo 409f0ea3689SLuigi Rizzo d = (struct nm_desc *)calloc(1, sizeof(*d)); 410f9790aebSLuigi Rizzo if (d == NULL) { 411f0ea3689SLuigi Rizzo errmsg = "nm_desc alloc failure"; 412f9790aebSLuigi Rizzo errno = ENOMEM; 413f9790aebSLuigi Rizzo return NULL; 414f9790aebSLuigi Rizzo } 415f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 416f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 417f0ea3689SLuigi Rizzo if (d->fd < 0) { 418f0ea3689SLuigi Rizzo errmsg = "cannot open /dev/netmap"; 419f9790aebSLuigi Rizzo goto fail; 420f9790aebSLuigi Rizzo } 421f0ea3689SLuigi Rizzo 422f0ea3689SLuigi Rizzo if (req) 423f0ea3689SLuigi Rizzo d->req = *req; 424f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 425f0ea3689SLuigi Rizzo d->req.nr_ringid &= ~NETMAP_RING_MASK; 426f0ea3689SLuigi Rizzo 427f0ea3689SLuigi Rizzo /* these fields are overridden by ifname and flags processing */ 428f0ea3689SLuigi Rizzo d->req.nr_ringid |= nr_ringid; 429f0ea3689SLuigi Rizzo d->req.nr_flags = nr_flags; 43066015019SLuigi Rizzo memcpy(d->req.nr_name, ifname, namelen); 43166015019SLuigi Rizzo d->req.nr_name[namelen] = '\0'; 432f0ea3689SLuigi Rizzo /* optionally import info from parent */ 433f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && new_flags) { 434f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG1) 435f0ea3689SLuigi Rizzo D("overriding ARG1 %d", parent->req.nr_arg1); 436f0ea3689SLuigi Rizzo d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ? 437f0ea3689SLuigi Rizzo parent->req.nr_arg1 : 4; 438f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG2) 439f0ea3689SLuigi Rizzo D("overriding ARG2 %d", parent->req.nr_arg2); 440f0ea3689SLuigi Rizzo d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ? 441f0ea3689SLuigi Rizzo parent->req.nr_arg2 : 0; 442f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG3) 443f0ea3689SLuigi Rizzo D("overriding ARG3 %d", parent->req.nr_arg3); 444f0ea3689SLuigi Rizzo d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ? 445f0ea3689SLuigi Rizzo parent->req.nr_arg3 : 0; 446f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_RING_CFG) { 447f0ea3689SLuigi Rizzo D("overriding RING_CFG"); 448f0ea3689SLuigi Rizzo d->req.nr_tx_slots = parent->req.nr_tx_slots; 449f0ea3689SLuigi Rizzo d->req.nr_rx_slots = parent->req.nr_rx_slots; 450f0ea3689SLuigi Rizzo d->req.nr_tx_rings = parent->req.nr_tx_rings; 451f0ea3689SLuigi Rizzo d->req.nr_rx_rings = parent->req.nr_rx_rings; 452f0ea3689SLuigi Rizzo } 453f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_IFNAME) { 454f0ea3689SLuigi Rizzo D("overriding ifname %s ringid 0x%x flags 0x%x", 455f0ea3689SLuigi Rizzo parent->req.nr_name, parent->req.nr_ringid, 456f0ea3689SLuigi Rizzo parent->req.nr_flags); 457f0ea3689SLuigi Rizzo memcpy(d->req.nr_name, parent->req.nr_name, 458f0ea3689SLuigi Rizzo sizeof(d->req.nr_name)); 459f0ea3689SLuigi Rizzo d->req.nr_ringid = parent->req.nr_ringid; 460f0ea3689SLuigi Rizzo d->req.nr_flags = parent->req.nr_flags; 461f0ea3689SLuigi Rizzo } 462f0ea3689SLuigi Rizzo } 4639225c808SLuigi Rizzo /* add the *XPOLL flags */ 4649225c808SLuigi Rizzo d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL); 4659225c808SLuigi Rizzo 46666015019SLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) { 467f0ea3689SLuigi Rizzo errmsg = "NIOCREGIF failed"; 468f9790aebSLuigi Rizzo goto fail; 46966015019SLuigi Rizzo } 470f9790aebSLuigi Rizzo 471f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && parent->mem && 472f0ea3689SLuigi Rizzo parent->req.nr_arg2 == d->req.nr_arg2) { 473f0ea3689SLuigi Rizzo /* do not mmap, inherit from parent */ 474f0ea3689SLuigi Rizzo d->memsize = parent->memsize; 475f0ea3689SLuigi Rizzo d->mem = parent->mem; 476f0ea3689SLuigi Rizzo } else { 4779225c808SLuigi Rizzo /* XXX TODO: check if memsize is too large (or there is overflow) */ 478f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 479f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 480f9790aebSLuigi Rizzo d->fd, 0); 4819225c808SLuigi Rizzo if (d->mem == MAP_FAILED) { 482f0ea3689SLuigi Rizzo errmsg = "mmap failed"; 483f9790aebSLuigi Rizzo goto fail; 484f0ea3689SLuigi Rizzo } 485f0ea3689SLuigi Rizzo d->done_mmap = 1; 486f0ea3689SLuigi Rizzo } 487f0ea3689SLuigi Rizzo { 488f0ea3689SLuigi Rizzo struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); 489f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(nifp, ); 490f0ea3689SLuigi Rizzo 491f0ea3689SLuigi Rizzo *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; 492f0ea3689SLuigi Rizzo *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; 493f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); 494f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_end = 495f0ea3689SLuigi Rizzo (char *)d->mem + d->memsize; 496f0ea3689SLuigi Rizzo } 497f0ea3689SLuigi Rizzo 4984bf50f18SLuigi Rizzo if (d->req.nr_flags == NR_REG_SW) { /* host stack */ 49966015019SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings; 50066015019SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings; 5014bf50f18SLuigi Rizzo } else if (d->req.nr_flags == NR_REG_ALL_NIC) { /* only nic */ 502f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 503f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 50466015019SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings - 1; 50566015019SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings - 1; 5064bf50f18SLuigi Rizzo } else if (d->req.nr_flags == NR_REG_NIC_SW) { 507f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 508f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 509f0ea3689SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings; 510f0ea3689SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings; 5114bf50f18SLuigi Rizzo } else if (d->req.nr_flags == NR_REG_ONE_NIC) { 512f0ea3689SLuigi Rizzo /* XXX check validity */ 513f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 5144bf50f18SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_ringid & NETMAP_RING_MASK; 515f0ea3689SLuigi Rizzo } else { /* pipes */ 516f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 0; 517f0ea3689SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = 0; 518f9790aebSLuigi Rizzo } 519f0ea3689SLuigi Rizzo 520f0ea3689SLuigi Rizzo #ifdef DEBUG_NETMAP_USER 521f0ea3689SLuigi Rizzo { /* debugging code */ 522f0ea3689SLuigi Rizzo int i; 523f0ea3689SLuigi Rizzo 524f0ea3689SLuigi Rizzo D("%s tx %d .. %d %d rx %d .. %d %d", ifname, 525f0ea3689SLuigi Rizzo d->first_tx_ring, d->last_tx_ring, d->req.nr_tx_rings, 526f0ea3689SLuigi Rizzo d->first_rx_ring, d->last_rx_ring, d->req.nr_rx_rings); 527f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_tx_rings; i++) { 528f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_TXRING(d->nifp, i); 529f0ea3689SLuigi Rizzo D("TX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 530f0ea3689SLuigi Rizzo } 531f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_rx_rings; i++) { 532f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(d->nifp, i); 533f0ea3689SLuigi Rizzo D("RX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 534f0ea3689SLuigi Rizzo } 535f0ea3689SLuigi Rizzo } 536f0ea3689SLuigi Rizzo #endif /* debugging */ 537f0ea3689SLuigi Rizzo 53866015019SLuigi Rizzo d->cur_tx_ring = d->first_tx_ring; 53966015019SLuigi Rizzo d->cur_rx_ring = d->first_rx_ring; 540f9790aebSLuigi Rizzo return d; 541f9790aebSLuigi Rizzo 542f9790aebSLuigi Rizzo fail: 543f9790aebSLuigi Rizzo nm_close(d); 544f0ea3689SLuigi Rizzo if (errmsg) 545f0ea3689SLuigi Rizzo D("%s %s", errmsg, ifname); 546*0506889cSLuigi Rizzo if (errno == 0) 547f9790aebSLuigi Rizzo errno = EINVAL; 548f9790aebSLuigi Rizzo return NULL; 549f9790aebSLuigi Rizzo } 550f9790aebSLuigi Rizzo 551f9790aebSLuigi Rizzo 552f9790aebSLuigi Rizzo static int 553f0ea3689SLuigi Rizzo nm_close(struct nm_desc *d) 554f9790aebSLuigi Rizzo { 55517885a7bSLuigi Rizzo /* 55617885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 55717885a7bSLuigi Rizzo */ 55817885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 559b82b2211SLuigi Rizzo { (void *)nm_open, (void *)nm_inject, 560b82b2211SLuigi Rizzo (void *)nm_dispatch, (void *)nm_nextpkt } ; 56117885a7bSLuigi Rizzo 562f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 563f9790aebSLuigi Rizzo return EINVAL; 564f0ea3689SLuigi Rizzo if (d->done_mmap && d->mem) 565f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 566f9790aebSLuigi Rizzo if (d->fd != -1) 567f9790aebSLuigi Rizzo close(d->fd); 568f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 569f9790aebSLuigi Rizzo free(d); 570f9790aebSLuigi Rizzo return 0; 571f9790aebSLuigi Rizzo } 572f9790aebSLuigi Rizzo 573f9790aebSLuigi Rizzo 574f9790aebSLuigi Rizzo /* 57517885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 57617885a7bSLuigi Rizzo */ 57717885a7bSLuigi Rizzo static int 578f0ea3689SLuigi Rizzo nm_inject(struct nm_desc *d, const void *buf, size_t size) 57917885a7bSLuigi Rizzo { 58066015019SLuigi Rizzo u_int c, n = d->last_tx_ring - d->first_tx_ring + 1; 58117885a7bSLuigi Rizzo 58217885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 58317885a7bSLuigi Rizzo /* compute current ring to use */ 58417885a7bSLuigi Rizzo struct netmap_ring *ring; 58517885a7bSLuigi Rizzo uint32_t i, idx; 58666015019SLuigi Rizzo uint32_t ri = d->cur_tx_ring + c; 58717885a7bSLuigi Rizzo 58866015019SLuigi Rizzo if (ri > d->last_tx_ring) 58966015019SLuigi Rizzo ri = d->first_tx_ring; 59017885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 59117885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 59217885a7bSLuigi Rizzo continue; 59317885a7bSLuigi Rizzo } 59417885a7bSLuigi Rizzo i = ring->cur; 59517885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 59617885a7bSLuigi Rizzo ring->slot[i].len = size; 597f0ea3689SLuigi Rizzo nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size); 59866015019SLuigi Rizzo d->cur_tx_ring = ri; 59917885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 60017885a7bSLuigi Rizzo return size; 60117885a7bSLuigi Rizzo } 60217885a7bSLuigi Rizzo return 0; /* fail */ 60317885a7bSLuigi Rizzo } 60417885a7bSLuigi Rizzo 60517885a7bSLuigi Rizzo 60617885a7bSLuigi Rizzo /* 607f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 608f9790aebSLuigi Rizzo */ 609f9790aebSLuigi Rizzo static int 610f0ea3689SLuigi Rizzo nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg) 611f9790aebSLuigi Rizzo { 61266015019SLuigi Rizzo int n = d->last_rx_ring - d->first_rx_ring + 1; 61366015019SLuigi Rizzo int c, got = 0, ri = d->cur_rx_ring; 614f9790aebSLuigi Rizzo 615f9790aebSLuigi Rizzo if (cnt == 0) 616f9790aebSLuigi Rizzo cnt = -1; 617f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 618f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 619f9790aebSLuigi Rizzo * so we can omit checking for -1 620f9790aebSLuigi Rizzo */ 621f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 622f9790aebSLuigi Rizzo /* compute current ring to use */ 623f9790aebSLuigi Rizzo struct netmap_ring *ring; 624f9790aebSLuigi Rizzo 62566015019SLuigi Rizzo ri = d->cur_rx_ring + c; 62666015019SLuigi Rizzo if (ri > d->last_rx_ring) 62766015019SLuigi Rizzo ri = d->first_rx_ring; 628f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 62917885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 630f9790aebSLuigi Rizzo u_int i = ring->cur; 631f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 632f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 63366015019SLuigi Rizzo 63466015019SLuigi Rizzo // __builtin_prefetch(buf); 635f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 636f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 637f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 63817885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 639f9790aebSLuigi Rizzo } 640f9790aebSLuigi Rizzo } 64166015019SLuigi Rizzo d->cur_rx_ring = ri; 642f9790aebSLuigi Rizzo return got; 643f9790aebSLuigi Rizzo } 644f9790aebSLuigi Rizzo 645f9790aebSLuigi Rizzo static u_char * 646f0ea3689SLuigi Rizzo nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr) 647f9790aebSLuigi Rizzo { 64866015019SLuigi Rizzo int ri = d->cur_rx_ring; 649f9790aebSLuigi Rizzo 650f9790aebSLuigi Rizzo do { 651f9790aebSLuigi Rizzo /* compute current ring to use */ 652f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 65317885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 654f9790aebSLuigi Rizzo u_int i = ring->cur; 655f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 656f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 65766015019SLuigi Rizzo 65866015019SLuigi Rizzo // __builtin_prefetch(buf); 659f9790aebSLuigi Rizzo hdr->ts = ring->ts; 660f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 66117885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 66217885a7bSLuigi Rizzo /* we could postpone advancing head if we want 66317885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 66417885a7bSLuigi Rizzo * the future. 66517885a7bSLuigi Rizzo */ 66617885a7bSLuigi Rizzo ring->head = ring->cur; 66766015019SLuigi Rizzo d->cur_rx_ring = ri; 668f9790aebSLuigi Rizzo return buf; 669f9790aebSLuigi Rizzo } 670f9790aebSLuigi Rizzo ri++; 67166015019SLuigi Rizzo if (ri > d->last_rx_ring) 67266015019SLuigi Rizzo ri = d->first_rx_ring; 67366015019SLuigi Rizzo } while (ri != d->cur_rx_ring); 674f9790aebSLuigi Rizzo return NULL; /* nothing found */ 675f9790aebSLuigi Rizzo } 676f9790aebSLuigi Rizzo 677f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 678f9790aebSLuigi Rizzo 679f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 680f9790aebSLuigi Rizzo 68168b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 682