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) 430506889cSLuigi 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 287*847bf383SLuigi Rizzo * a suffix starting with + and the following flags, 288*847bf383SLuigi Rizzo * in any order: 289*847bf383SLuigi Rizzo * x exclusive access 290*847bf383SLuigi Rizzo * z zero copy monitor 291*847bf383SLuigi Rizzo * t monitor tx side 292*847bf383SLuigi Rizzo * r monitor rx side 293f0ea3689SLuigi Rizzo * 294f0ea3689SLuigi Rizzo * req provides the initial values of nmreq before parsing ifname. 295f0ea3689SLuigi Rizzo * Remember that the ifname parsing will override the ring 296f0ea3689SLuigi Rizzo * number in nm_ringid, and part of nm_flags; 297f0ea3689SLuigi Rizzo * flags special functions, normally 0 298f0ea3689SLuigi Rizzo * indicates which fields of *arg are significant 299f0ea3689SLuigi Rizzo * arg special functions, normally NULL 300f0ea3689SLuigi Rizzo * if passed a netmap_desc with mem != NULL, 301f0ea3689SLuigi Rizzo * use that memory instead of mmap. 302f9790aebSLuigi Rizzo */ 30317885a7bSLuigi Rizzo 304f0ea3689SLuigi Rizzo static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req, 305f0ea3689SLuigi Rizzo uint64_t flags, const struct nm_desc *arg); 306f0ea3689SLuigi Rizzo 307f0ea3689SLuigi Rizzo /* 308f0ea3689SLuigi Rizzo * nm_open can import some fields from the parent descriptor. 309f0ea3689SLuigi Rizzo * These flags control which ones. 310f0ea3689SLuigi Rizzo * Also in flags you can specify NETMAP_NO_TX_POLL and NETMAP_DO_RX_POLL, 311f0ea3689SLuigi Rizzo * which set the initial value for these flags. 312f0ea3689SLuigi Rizzo * Note that the 16 low bits of the flags are reserved for data 313f0ea3689SLuigi Rizzo * that may go into the nmreq. 314f0ea3689SLuigi Rizzo */ 315f0ea3689SLuigi Rizzo enum { 316f0ea3689SLuigi Rizzo NM_OPEN_NO_MMAP = 0x040000, /* reuse mmap from parent */ 317f0ea3689SLuigi Rizzo NM_OPEN_IFNAME = 0x080000, /* nr_name, nr_ringid, nr_flags */ 318f0ea3689SLuigi Rizzo NM_OPEN_ARG1 = 0x100000, 319f0ea3689SLuigi Rizzo NM_OPEN_ARG2 = 0x200000, 320f0ea3689SLuigi Rizzo NM_OPEN_ARG3 = 0x400000, 321f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG = 0x800000, /* tx|rx rings|slots */ 322f0ea3689SLuigi Rizzo }; 323f0ea3689SLuigi Rizzo 324f9790aebSLuigi Rizzo 325f9790aebSLuigi Rizzo /* 32617885a7bSLuigi Rizzo * nm_close() closes and restores the port to its previous state 327f9790aebSLuigi Rizzo */ 32817885a7bSLuigi Rizzo 329f0ea3689SLuigi Rizzo static int nm_close(struct nm_desc *); 330f9790aebSLuigi Rizzo 331f9790aebSLuigi Rizzo /* 33217885a7bSLuigi Rizzo * nm_inject() is the same as pcap_inject() 33317885a7bSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 33417885a7bSLuigi Rizzo * nm_nextpkt() is the same as pcap_next() 335f9790aebSLuigi Rizzo */ 33617885a7bSLuigi Rizzo 337f0ea3689SLuigi Rizzo static int nm_inject(struct nm_desc *, const void *, size_t); 338f0ea3689SLuigi Rizzo static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *); 339f0ea3689SLuigi Rizzo static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *); 340f9790aebSLuigi Rizzo 341f9790aebSLuigi Rizzo 342f9790aebSLuigi Rizzo /* 343f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 344f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 345f0ea3689SLuigi Rizzo * You can pass a pointer to a pre-filled nm_desc to add special 346f0ea3689SLuigi Rizzo * parameters. Flags is used as follows 347f0ea3689SLuigi Rizzo * NM_OPEN_NO_MMAP use the memory from arg, only 348f0ea3689SLuigi Rizzo * if the nr_arg2 (memory block) matches. 349f0ea3689SLuigi Rizzo * NM_OPEN_ARG1 use req.nr_arg1 from arg 350f0ea3689SLuigi Rizzo * NM_OPEN_ARG2 use req.nr_arg2 from arg 351f0ea3689SLuigi Rizzo * NM_OPEN_RING_CFG user ring config from arg 352f9790aebSLuigi Rizzo */ 353f0ea3689SLuigi Rizzo static struct nm_desc * 354f0ea3689SLuigi Rizzo nm_open(const char *ifname, const struct nmreq *req, 355f0ea3689SLuigi Rizzo uint64_t new_flags, const struct nm_desc *arg) 356f9790aebSLuigi Rizzo { 357f0ea3689SLuigi Rizzo struct nm_desc *d = NULL; 358f0ea3689SLuigi Rizzo const struct nm_desc *parent = arg; 359f0ea3689SLuigi Rizzo u_int namelen; 360*847bf383SLuigi Rizzo uint32_t nr_ringid = 0, nr_flags, nr_reg; 361f0ea3689SLuigi Rizzo const char *port = NULL; 362*847bf383SLuigi Rizzo #define MAXERRMSG 80 363*847bf383SLuigi Rizzo char errmsg[MAXERRMSG] = ""; 364*847bf383SLuigi Rizzo enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK } p_state; 365*847bf383SLuigi Rizzo long num; 366f9790aebSLuigi Rizzo 367f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 368f0ea3689SLuigi Rizzo errno = 0; /* name not recognised, not an error */ 369f9790aebSLuigi Rizzo return NULL; 370f9790aebSLuigi Rizzo } 371f9790aebSLuigi Rizzo if (ifname[0] == 'n') 372f9790aebSLuigi Rizzo ifname += 7; 373f0ea3689SLuigi Rizzo /* scan for a separator */ 374*847bf383SLuigi Rizzo for (port = ifname; *port && !index("-*^{}/", *port); port++) 375f0ea3689SLuigi Rizzo ; 37666015019SLuigi Rizzo namelen = port - ifname; 377f0ea3689SLuigi Rizzo if (namelen >= sizeof(d->req.nr_name)) { 378*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "name too long"); 379f0ea3689SLuigi Rizzo goto fail; 38066015019SLuigi Rizzo } 381*847bf383SLuigi Rizzo p_state = P_START; 382*847bf383SLuigi Rizzo nr_flags = NR_REG_ALL_NIC; /* default for no suffix */ 383*847bf383SLuigi Rizzo while (*port) { 384*847bf383SLuigi Rizzo switch (p_state) { 385*847bf383SLuigi Rizzo case P_START: 386f0ea3689SLuigi Rizzo switch (*port) { 387*847bf383SLuigi Rizzo case '^': /* only SW ring */ 388f0ea3689SLuigi Rizzo nr_flags = NR_REG_SW; 389*847bf383SLuigi Rizzo p_state = P_RNGSFXOK; 390f0ea3689SLuigi Rizzo break; 391*847bf383SLuigi Rizzo case '*': /* NIC and SW */ 392*847bf383SLuigi Rizzo nr_flags = NR_REG_NIC_SW; 393*847bf383SLuigi Rizzo p_state = P_RNGSFXOK; 394*847bf383SLuigi Rizzo break; 395*847bf383SLuigi Rizzo case '-': /* one NIC ring pair */ 396*847bf383SLuigi Rizzo nr_flags = NR_REG_ONE_NIC; 397*847bf383SLuigi Rizzo p_state = P_GETNUM; 398*847bf383SLuigi Rizzo break; 399*847bf383SLuigi Rizzo case '{': /* pipe (master endpoint) */ 400f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_MASTER; 401*847bf383SLuigi Rizzo p_state = P_GETNUM; 402f0ea3689SLuigi Rizzo break; 403*847bf383SLuigi Rizzo case '}': /* pipe (slave endoint) */ 404f0ea3689SLuigi Rizzo nr_flags = NR_REG_PIPE_SLAVE; 405*847bf383SLuigi Rizzo p_state = P_GETNUM; 406f0ea3689SLuigi Rizzo break; 407*847bf383SLuigi Rizzo case '/': /* start of flags */ 408*847bf383SLuigi Rizzo p_state = P_FLAGS; 409*847bf383SLuigi Rizzo break; 410*847bf383SLuigi Rizzo default: 411*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "unknown modifier: '%c'", *port); 412f0ea3689SLuigi Rizzo goto fail; 413f0ea3689SLuigi Rizzo } 414*847bf383SLuigi Rizzo port++; 415*847bf383SLuigi Rizzo break; 416*847bf383SLuigi Rizzo case P_RNGSFXOK: 417*847bf383SLuigi Rizzo switch (*port) { 418*847bf383SLuigi Rizzo case '/': 419*847bf383SLuigi Rizzo p_state = P_FLAGS; 420*847bf383SLuigi Rizzo break; 421*847bf383SLuigi Rizzo default: 422*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "unexpected character: '%c'", *port); 423*847bf383SLuigi Rizzo goto fail; 424*847bf383SLuigi Rizzo } 425*847bf383SLuigi Rizzo port++; 426*847bf383SLuigi Rizzo break; 427*847bf383SLuigi Rizzo case P_GETNUM: 428*847bf383SLuigi Rizzo num = strtol(port, (char **)&port, 10); 429*847bf383SLuigi Rizzo if (num < 0 || num >= NETMAP_RING_MASK) { 430*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "'%ld' out of range [0, %d)", 431*847bf383SLuigi Rizzo num, NETMAP_RING_MASK); 432*847bf383SLuigi Rizzo goto fail; 433*847bf383SLuigi Rizzo } 434*847bf383SLuigi Rizzo nr_ringid = num & NETMAP_RING_MASK; 435*847bf383SLuigi Rizzo p_state = P_RNGSFXOK; 436*847bf383SLuigi Rizzo break; 437*847bf383SLuigi Rizzo case P_FLAGS: 438*847bf383SLuigi Rizzo case P_FLAGSOK: 439*847bf383SLuigi Rizzo switch (*port) { 440*847bf383SLuigi Rizzo case 'x': 441*847bf383SLuigi Rizzo nr_flags |= NR_EXCLUSIVE; 442*847bf383SLuigi Rizzo break; 443*847bf383SLuigi Rizzo case 'z': 444*847bf383SLuigi Rizzo nr_flags |= NR_ZCOPY_MON; 445*847bf383SLuigi Rizzo break; 446*847bf383SLuigi Rizzo case 't': 447*847bf383SLuigi Rizzo nr_flags |= NR_MONITOR_TX; 448*847bf383SLuigi Rizzo break; 449*847bf383SLuigi Rizzo case 'r': 450*847bf383SLuigi Rizzo nr_flags |= NR_MONITOR_RX; 451*847bf383SLuigi Rizzo break; 452*847bf383SLuigi Rizzo default: 453*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "unrecognized flag: '%c'", *port); 454*847bf383SLuigi Rizzo goto fail; 455*847bf383SLuigi Rizzo } 456*847bf383SLuigi Rizzo port++; 457*847bf383SLuigi Rizzo p_state = P_FLAGSOK; 458*847bf383SLuigi Rizzo break; 459*847bf383SLuigi Rizzo } 460*847bf383SLuigi Rizzo } 461*847bf383SLuigi Rizzo if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) { 462*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "unexpected end of port name"); 463*847bf383SLuigi Rizzo goto fail; 464*847bf383SLuigi Rizzo } 465*847bf383SLuigi Rizzo ND("flags: %s %s %s %s", 466*847bf383SLuigi Rizzo (nr_flags & NR_EXCLUSIVE) ? "EXCLUSIVE" : "", 467*847bf383SLuigi Rizzo (nr_flags & NR_ZCOPY_MON) ? "ZCOPY_MON" : "", 468*847bf383SLuigi Rizzo (nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "", 469*847bf383SLuigi Rizzo (nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : ""); 470f0ea3689SLuigi Rizzo d = (struct nm_desc *)calloc(1, sizeof(*d)); 471f9790aebSLuigi Rizzo if (d == NULL) { 472*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "nm_desc alloc failure"); 473f9790aebSLuigi Rizzo errno = ENOMEM; 474f9790aebSLuigi Rizzo return NULL; 475f9790aebSLuigi Rizzo } 476f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 477f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 478f0ea3689SLuigi Rizzo if (d->fd < 0) { 479*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno)); 480f9790aebSLuigi Rizzo goto fail; 481f9790aebSLuigi Rizzo } 482f0ea3689SLuigi Rizzo 483f0ea3689SLuigi Rizzo if (req) 484f0ea3689SLuigi Rizzo d->req = *req; 485f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 486f0ea3689SLuigi Rizzo d->req.nr_ringid &= ~NETMAP_RING_MASK; 487f0ea3689SLuigi Rizzo 488f0ea3689SLuigi Rizzo /* these fields are overridden by ifname and flags processing */ 489f0ea3689SLuigi Rizzo d->req.nr_ringid |= nr_ringid; 490f0ea3689SLuigi Rizzo d->req.nr_flags = nr_flags; 49166015019SLuigi Rizzo memcpy(d->req.nr_name, ifname, namelen); 49266015019SLuigi Rizzo d->req.nr_name[namelen] = '\0'; 493f0ea3689SLuigi Rizzo /* optionally import info from parent */ 494f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && new_flags) { 495f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG1) 496f0ea3689SLuigi Rizzo D("overriding ARG1 %d", parent->req.nr_arg1); 497f0ea3689SLuigi Rizzo d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ? 498f0ea3689SLuigi Rizzo parent->req.nr_arg1 : 4; 499f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG2) 500f0ea3689SLuigi Rizzo D("overriding ARG2 %d", parent->req.nr_arg2); 501f0ea3689SLuigi Rizzo d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ? 502f0ea3689SLuigi Rizzo parent->req.nr_arg2 : 0; 503f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_ARG3) 504f0ea3689SLuigi Rizzo D("overriding ARG3 %d", parent->req.nr_arg3); 505f0ea3689SLuigi Rizzo d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ? 506f0ea3689SLuigi Rizzo parent->req.nr_arg3 : 0; 507f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_RING_CFG) { 508f0ea3689SLuigi Rizzo D("overriding RING_CFG"); 509f0ea3689SLuigi Rizzo d->req.nr_tx_slots = parent->req.nr_tx_slots; 510f0ea3689SLuigi Rizzo d->req.nr_rx_slots = parent->req.nr_rx_slots; 511f0ea3689SLuigi Rizzo d->req.nr_tx_rings = parent->req.nr_tx_rings; 512f0ea3689SLuigi Rizzo d->req.nr_rx_rings = parent->req.nr_rx_rings; 513f0ea3689SLuigi Rizzo } 514f0ea3689SLuigi Rizzo if (new_flags & NM_OPEN_IFNAME) { 515f0ea3689SLuigi Rizzo D("overriding ifname %s ringid 0x%x flags 0x%x", 516f0ea3689SLuigi Rizzo parent->req.nr_name, parent->req.nr_ringid, 517f0ea3689SLuigi Rizzo parent->req.nr_flags); 518f0ea3689SLuigi Rizzo memcpy(d->req.nr_name, parent->req.nr_name, 519f0ea3689SLuigi Rizzo sizeof(d->req.nr_name)); 520f0ea3689SLuigi Rizzo d->req.nr_ringid = parent->req.nr_ringid; 521f0ea3689SLuigi Rizzo d->req.nr_flags = parent->req.nr_flags; 522f0ea3689SLuigi Rizzo } 523f0ea3689SLuigi Rizzo } 5249225c808SLuigi Rizzo /* add the *XPOLL flags */ 5259225c808SLuigi Rizzo d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL); 5269225c808SLuigi Rizzo 52766015019SLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) { 528*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno)); 529f9790aebSLuigi Rizzo goto fail; 53066015019SLuigi Rizzo } 531f9790aebSLuigi Rizzo 532f0ea3689SLuigi Rizzo if (IS_NETMAP_DESC(parent) && parent->mem && 533f0ea3689SLuigi Rizzo parent->req.nr_arg2 == d->req.nr_arg2) { 534f0ea3689SLuigi Rizzo /* do not mmap, inherit from parent */ 535f0ea3689SLuigi Rizzo d->memsize = parent->memsize; 536f0ea3689SLuigi Rizzo d->mem = parent->mem; 537f0ea3689SLuigi Rizzo } else { 5389225c808SLuigi Rizzo /* XXX TODO: check if memsize is too large (or there is overflow) */ 539f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 540f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 541f9790aebSLuigi Rizzo d->fd, 0); 5429225c808SLuigi Rizzo if (d->mem == MAP_FAILED) { 543*847bf383SLuigi Rizzo snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno)); 544f9790aebSLuigi Rizzo goto fail; 545f0ea3689SLuigi Rizzo } 546f0ea3689SLuigi Rizzo d->done_mmap = 1; 547f0ea3689SLuigi Rizzo } 548f0ea3689SLuigi Rizzo { 549f0ea3689SLuigi Rizzo struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); 550f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(nifp, ); 551f0ea3689SLuigi Rizzo 552f0ea3689SLuigi Rizzo *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; 553f0ea3689SLuigi Rizzo *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; 554f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); 555f0ea3689SLuigi Rizzo *(void **)(uintptr_t)&d->buf_end = 556f0ea3689SLuigi Rizzo (char *)d->mem + d->memsize; 557f0ea3689SLuigi Rizzo } 558f0ea3689SLuigi Rizzo 559*847bf383SLuigi Rizzo nr_reg = d->req.nr_flags & NR_REG_MASK; 560*847bf383SLuigi Rizzo 561*847bf383SLuigi Rizzo if (nr_reg == NR_REG_SW) { /* host stack */ 56266015019SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings; 56366015019SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings; 564*847bf383SLuigi Rizzo } else if (nr_reg == NR_REG_ALL_NIC) { /* only nic */ 565f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 566f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 56766015019SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings - 1; 56866015019SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings - 1; 569*847bf383SLuigi Rizzo } else if (nr_reg == NR_REG_NIC_SW) { 570f0ea3689SLuigi Rizzo d->first_tx_ring = 0; 571f0ea3689SLuigi Rizzo d->first_rx_ring = 0; 572f0ea3689SLuigi Rizzo d->last_tx_ring = d->req.nr_tx_rings; 573f0ea3689SLuigi Rizzo d->last_rx_ring = d->req.nr_rx_rings; 574*847bf383SLuigi Rizzo } else if (nr_reg == NR_REG_ONE_NIC) { 575f0ea3689SLuigi Rizzo /* XXX check validity */ 576f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 5774bf50f18SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = d->req.nr_ringid & NETMAP_RING_MASK; 578f0ea3689SLuigi Rizzo } else { /* pipes */ 579f0ea3689SLuigi Rizzo d->first_tx_ring = d->last_tx_ring = 0; 580f0ea3689SLuigi Rizzo d->first_rx_ring = d->last_rx_ring = 0; 581f9790aebSLuigi Rizzo } 582f0ea3689SLuigi Rizzo 583f0ea3689SLuigi Rizzo #ifdef DEBUG_NETMAP_USER 584f0ea3689SLuigi Rizzo { /* debugging code */ 585f0ea3689SLuigi Rizzo int i; 586f0ea3689SLuigi Rizzo 587f0ea3689SLuigi Rizzo D("%s tx %d .. %d %d rx %d .. %d %d", ifname, 588f0ea3689SLuigi Rizzo d->first_tx_ring, d->last_tx_ring, d->req.nr_tx_rings, 589f0ea3689SLuigi Rizzo d->first_rx_ring, d->last_rx_ring, d->req.nr_rx_rings); 590f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_tx_rings; i++) { 591f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_TXRING(d->nifp, i); 592f0ea3689SLuigi Rizzo D("TX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 593f0ea3689SLuigi Rizzo } 594f0ea3689SLuigi Rizzo for (i = 0; i <= d->req.nr_rx_rings; i++) { 595f0ea3689SLuigi Rizzo struct netmap_ring *r = NETMAP_RXRING(d->nifp, i); 596f0ea3689SLuigi Rizzo D("RX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail); 597f0ea3689SLuigi Rizzo } 598f0ea3689SLuigi Rizzo } 599f0ea3689SLuigi Rizzo #endif /* debugging */ 600f0ea3689SLuigi Rizzo 60166015019SLuigi Rizzo d->cur_tx_ring = d->first_tx_ring; 60266015019SLuigi Rizzo d->cur_rx_ring = d->first_rx_ring; 603f9790aebSLuigi Rizzo return d; 604f9790aebSLuigi Rizzo 605f9790aebSLuigi Rizzo fail: 606f9790aebSLuigi Rizzo nm_close(d); 607*847bf383SLuigi Rizzo if (errmsg[0]) 608f0ea3689SLuigi Rizzo D("%s %s", errmsg, ifname); 6090506889cSLuigi Rizzo if (errno == 0) 610f9790aebSLuigi Rizzo errno = EINVAL; 611f9790aebSLuigi Rizzo return NULL; 612f9790aebSLuigi Rizzo } 613f9790aebSLuigi Rizzo 614f9790aebSLuigi Rizzo 615f9790aebSLuigi Rizzo static int 616f0ea3689SLuigi Rizzo nm_close(struct nm_desc *d) 617f9790aebSLuigi Rizzo { 61817885a7bSLuigi Rizzo /* 61917885a7bSLuigi Rizzo * ugly trick to avoid unused warnings 62017885a7bSLuigi Rizzo */ 62117885a7bSLuigi Rizzo static void *__xxzt[] __attribute__ ((unused)) = 622b82b2211SLuigi Rizzo { (void *)nm_open, (void *)nm_inject, 623b82b2211SLuigi Rizzo (void *)nm_dispatch, (void *)nm_nextpkt } ; 62417885a7bSLuigi Rizzo 625f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 626f9790aebSLuigi Rizzo return EINVAL; 627f0ea3689SLuigi Rizzo if (d->done_mmap && d->mem) 628f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 629f9790aebSLuigi Rizzo if (d->fd != -1) 630f9790aebSLuigi Rizzo close(d->fd); 631f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 632f9790aebSLuigi Rizzo free(d); 633f9790aebSLuigi Rizzo return 0; 634f9790aebSLuigi Rizzo } 635f9790aebSLuigi Rizzo 636f9790aebSLuigi Rizzo 637f9790aebSLuigi Rizzo /* 63817885a7bSLuigi Rizzo * Same prototype as pcap_inject(), only need to cast. 63917885a7bSLuigi Rizzo */ 64017885a7bSLuigi Rizzo static int 641f0ea3689SLuigi Rizzo nm_inject(struct nm_desc *d, const void *buf, size_t size) 64217885a7bSLuigi Rizzo { 64366015019SLuigi Rizzo u_int c, n = d->last_tx_ring - d->first_tx_ring + 1; 64417885a7bSLuigi Rizzo 64517885a7bSLuigi Rizzo for (c = 0; c < n ; c++) { 64617885a7bSLuigi Rizzo /* compute current ring to use */ 64717885a7bSLuigi Rizzo struct netmap_ring *ring; 64817885a7bSLuigi Rizzo uint32_t i, idx; 64966015019SLuigi Rizzo uint32_t ri = d->cur_tx_ring + c; 65017885a7bSLuigi Rizzo 65166015019SLuigi Rizzo if (ri > d->last_tx_ring) 65266015019SLuigi Rizzo ri = d->first_tx_ring; 65317885a7bSLuigi Rizzo ring = NETMAP_TXRING(d->nifp, ri); 65417885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 65517885a7bSLuigi Rizzo continue; 65617885a7bSLuigi Rizzo } 65717885a7bSLuigi Rizzo i = ring->cur; 65817885a7bSLuigi Rizzo idx = ring->slot[i].buf_idx; 65917885a7bSLuigi Rizzo ring->slot[i].len = size; 660f0ea3689SLuigi Rizzo nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size); 66166015019SLuigi Rizzo d->cur_tx_ring = ri; 66217885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 66317885a7bSLuigi Rizzo return size; 66417885a7bSLuigi Rizzo } 66517885a7bSLuigi Rizzo return 0; /* fail */ 66617885a7bSLuigi Rizzo } 66717885a7bSLuigi Rizzo 66817885a7bSLuigi Rizzo 66917885a7bSLuigi Rizzo /* 670f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 671f9790aebSLuigi Rizzo */ 672f9790aebSLuigi Rizzo static int 673f0ea3689SLuigi Rizzo nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg) 674f9790aebSLuigi Rizzo { 67566015019SLuigi Rizzo int n = d->last_rx_ring - d->first_rx_ring + 1; 67666015019SLuigi Rizzo int c, got = 0, ri = d->cur_rx_ring; 677f9790aebSLuigi Rizzo 678f9790aebSLuigi Rizzo if (cnt == 0) 679f9790aebSLuigi Rizzo cnt = -1; 680f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 681f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 682f9790aebSLuigi Rizzo * so we can omit checking for -1 683f9790aebSLuigi Rizzo */ 684f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 685f9790aebSLuigi Rizzo /* compute current ring to use */ 686f9790aebSLuigi Rizzo struct netmap_ring *ring; 687f9790aebSLuigi Rizzo 68866015019SLuigi Rizzo ri = d->cur_rx_ring + c; 68966015019SLuigi Rizzo if (ri > d->last_rx_ring) 69066015019SLuigi Rizzo ri = d->first_rx_ring; 691f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 69217885a7bSLuigi Rizzo for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 693f9790aebSLuigi Rizzo u_int i = ring->cur; 694f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 695f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 69666015019SLuigi Rizzo 69766015019SLuigi Rizzo // __builtin_prefetch(buf); 698f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 699f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 700f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 70117885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, i); 702f9790aebSLuigi Rizzo } 703f9790aebSLuigi Rizzo } 70466015019SLuigi Rizzo d->cur_rx_ring = ri; 705f9790aebSLuigi Rizzo return got; 706f9790aebSLuigi Rizzo } 707f9790aebSLuigi Rizzo 708f9790aebSLuigi Rizzo static u_char * 709f0ea3689SLuigi Rizzo nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr) 710f9790aebSLuigi Rizzo { 71166015019SLuigi Rizzo int ri = d->cur_rx_ring; 712f9790aebSLuigi Rizzo 713f9790aebSLuigi Rizzo do { 714f9790aebSLuigi Rizzo /* compute current ring to use */ 715f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 71617885a7bSLuigi Rizzo if (!nm_ring_empty(ring)) { 717f9790aebSLuigi Rizzo u_int i = ring->cur; 718f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 719f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 72066015019SLuigi Rizzo 72166015019SLuigi Rizzo // __builtin_prefetch(buf); 722f9790aebSLuigi Rizzo hdr->ts = ring->ts; 723f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 72417885a7bSLuigi Rizzo ring->cur = nm_ring_next(ring, i); 72517885a7bSLuigi Rizzo /* we could postpone advancing head if we want 72617885a7bSLuigi Rizzo * to hold the buffer. This can be supported in 72717885a7bSLuigi Rizzo * the future. 72817885a7bSLuigi Rizzo */ 72917885a7bSLuigi Rizzo ring->head = ring->cur; 73066015019SLuigi Rizzo d->cur_rx_ring = ri; 731f9790aebSLuigi Rizzo return buf; 732f9790aebSLuigi Rizzo } 733f9790aebSLuigi Rizzo ri++; 73466015019SLuigi Rizzo if (ri > d->last_rx_ring) 73566015019SLuigi Rizzo ri = d->first_rx_ring; 73666015019SLuigi Rizzo } while (ri != d->cur_rx_ring); 737f9790aebSLuigi Rizzo return NULL; /* nothing found */ 738f9790aebSLuigi Rizzo } 739f9790aebSLuigi Rizzo 740f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 741f9790aebSLuigi Rizzo 742f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 743f9790aebSLuigi Rizzo 74468b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 745