netmap_user.h (259412) | netmap_user.h (260368) |
---|---|
1/* | 1/* |
2 * Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved. 3 * Copyright (C) 2013 Universita` di Pisa | 2 * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved. |
4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright --- 9 unchanged lines hidden (view full) --- 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* | 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright --- 9 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* |
29 * $FreeBSD: head/sys/net/netmap_user.h 259412 2013-12-15 08:37:24Z luigi $ | 28 * $FreeBSD: head/sys/net/netmap_user.h 260368 2014-01-06 12:53:15Z luigi $ |
30 * | 29 * |
31 * This header contains the macros used to manipulate netmap structures 32 * and packets in userspace. See netmap(4) for more information. | 30 * Functions and macros to manipulate netmap structures and packets 31 * in userspace. See netmap(4) for more information. |
33 * 34 * The address of the struct netmap_if, say nifp, is computed from the 35 * value returned from ioctl(.., NIOCREG, ...) and the mmap region: 36 * ioctl(fd, NIOCREG, &req); 37 * mem = mmap(0, ... ); 38 * nifp = NETMAP_IF(mem, req.nr_nifp); 39 * (so simple, we could just do it manually) 40 * 41 * From there: 42 * struct netmap_ring *NETMAP_TXRING(nifp, index) 43 * struct netmap_ring *NETMAP_RXRING(nifp, index) 44 * we can access ring->nr_cur, ring->nr_avail, ring->nr_flags 45 * 46 * ring->slot[i] gives us the i-th slot (we can access | 32 * 33 * The address of the struct netmap_if, say nifp, is computed from the 34 * value returned from ioctl(.., NIOCREG, ...) and the mmap region: 35 * ioctl(fd, NIOCREG, &req); 36 * mem = mmap(0, ... ); 37 * nifp = NETMAP_IF(mem, req.nr_nifp); 38 * (so simple, we could just do it manually) 39 * 40 * From there: 41 * struct netmap_ring *NETMAP_TXRING(nifp, index) 42 * struct netmap_ring *NETMAP_RXRING(nifp, index) 43 * we can access ring->nr_cur, ring->nr_avail, ring->nr_flags 44 * 45 * ring->slot[i] gives us the i-th slot (we can access |
47 * directly plen, flags, bufindex) | 46 * directly len, flags, buf_idx) |
48 * 49 * char *buf = NETMAP_BUF(ring, x) returns a pointer to 50 * the buffer numbered x 51 * | 47 * 48 * char *buf = NETMAP_BUF(ring, x) returns a pointer to 49 * the buffer numbered x 50 * |
52 * Since rings are circular, we have macros to compute the next index 53 * i = NETMAP_RING_NEXT(ring, i); | 51 * All ring indexes (head, cur, tail) should always move forward. 52 * To compute the next index in a circular ring you can use 53 * i = nm_ring_next(ring, i); |
54 * 55 * To ease porting apps from pcap to netmap we supply a few fuctions | 54 * 55 * To ease porting apps from pcap to netmap we supply a few fuctions |
56 * that can be called to open, close and read from netmap in a way 57 * similar to libpcap. | 56 * that can be called to open, close, read and write on netmap in a way 57 * similar to libpcap. Note that the read/write function depend on 58 * an ioctl()/select()/poll() being issued to refill rings or push 59 * packets out. |
58 * 59 * In order to use these, include #define NETMAP_WITH_LIBS 60 * in the source file that invokes these functions. 61 */ 62 63#ifndef _NET_NETMAP_USER_H_ 64#define _NET_NETMAP_USER_H_ 65 66#include <stdint.h> 67#include <net/if.h> /* IFNAMSIZ */ | 60 * 61 * In order to use these, include #define NETMAP_WITH_LIBS 62 * in the source file that invokes these functions. 63 */ 64 65#ifndef _NET_NETMAP_USER_H_ 66#define _NET_NETMAP_USER_H_ 67 68#include <stdint.h> 69#include <net/if.h> /* IFNAMSIZ */ |
70 71#ifndef likely 72#define likely(x) __builtin_expect(!!(x), 1) 73#define unlikely(x) __builtin_expect(!!(x), 0) 74#endif /* likely and unlikely */ 75 |
|
68#include <net/netmap.h> 69 | 76#include <net/netmap.h> 77 |
78/* helper macro */ |
|
70#define _NETMAP_OFFSET(type, ptr, offset) \ 71 ((type)(void *)((char *)(ptr) + (offset))) 72 | 79#define _NETMAP_OFFSET(type, ptr, offset) \ 80 ((type)(void *)((char *)(ptr) + (offset))) 81 |
73#define NETMAP_IF(b, o) _NETMAP_OFFSET(struct netmap_if *, b, o) | 82#define NETMAP_IF(_base, _ofs) _NETMAP_OFFSET(struct netmap_if *, _base, _ofs) |
74 75#define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 76 nifp, (nifp)->ring_ofs[index] ) 77 78#define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 79 nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) 80 81#define NETMAP_BUF(ring, index) \ 82 ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) 83 84#define NETMAP_BUF_IDX(ring, buf) \ 85 ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ 86 (ring)->nr_buf_size ) 87 | 83 84#define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 85 nifp, (nifp)->ring_ofs[index] ) 86 87#define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 88 nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) 89 90#define NETMAP_BUF(ring, index) \ 91 ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) 92 93#define NETMAP_BUF_IDX(ring, buf) \ 94 ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ 95 (ring)->nr_buf_size ) 96 |
88#define NETMAP_RING_NEXT(r, i) \ 89 ((i)+1 == (r)->num_slots ? 0 : (i) + 1 ) | |
90 | 97 |
91#define NETMAP_RING_FIRST_RESERVED(r) \ 92 ( (r)->cur < (r)->reserved ? \ 93 (r)->cur + (r)->num_slots - (r)->reserved : \ 94 (r)->cur - (r)->reserved ) | 98static inline uint32_t 99nm_ring_next(struct netmap_ring *r, uint32_t i) 100{ 101 return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1); 102} |
95 | 103 |
104 |
|
96/* | 105/* |
97 * Return 1 if the given tx ring is empty. | 106 * Return 1 if we have pending transmissions in the tx ring. 107 * When everything is complete ring->cur = ring->tail + 1 (modulo ring size) |
98 */ | 108 */ |
99#define NETMAP_TX_RING_EMPTY(r) ((r)->avail >= (r)->num_slots - 1) | 109static inline int 110nm_tx_pending(struct netmap_ring *r) 111{ 112 return nm_ring_next(r, r->tail) != r->cur; 113} |
100 | 114 |
115 116static inline uint32_t 117nm_ring_space(struct netmap_ring *ring) 118{ 119 int ret = ring->tail - ring->cur; 120 if (ret < 0) 121 ret += ring->num_slots; 122 return ret; 123} 124 125 |
|
101#ifdef NETMAP_WITH_LIBS 102/* 103 * Support for simple I/O libraries. 104 * Include other system headers required for compiling this. 105 */ 106 107#ifndef HAVE_NETMAP_WITH_LIBS 108#define HAVE_NETMAP_WITH_LIBS 109 110#include <sys/time.h> 111#include <sys/mman.h> 112#include <string.h> /* memset */ 113#include <sys/ioctl.h> 114#include <sys/errno.h> /* EINVAL */ 115#include <fcntl.h> /* O_RDWR */ | 126#ifdef NETMAP_WITH_LIBS 127/* 128 * Support for simple I/O libraries. 129 * Include other system headers required for compiling this. 130 */ 131 132#ifndef HAVE_NETMAP_WITH_LIBS 133#define HAVE_NETMAP_WITH_LIBS 134 135#include <sys/time.h> 136#include <sys/mman.h> 137#include <string.h> /* memset */ 138#include <sys/ioctl.h> 139#include <sys/errno.h> /* EINVAL */ 140#include <fcntl.h> /* O_RDWR */ |
116#include <malloc.h> | 141#include <unistd.h> /* close() */ 142#ifdef __FreeBSD__ 143#include <stdlib.h> 144#else 145#include <malloc.h> /* on FreeBSD it is stdlib.h */ 146#endif |
117 118struct nm_hdr_t { /* same as pcap_pkthdr */ 119 struct timeval ts; 120 uint32_t caplen; 121 uint32_t len; 122}; 123 124struct nm_desc_t { --- 9 unchanged lines hidden (view full) --- 134 135/* 136 * when the descriptor is open correctly, d->self == d 137 */ 138#define P2NMD(p) ((struct nm_desc_t *)(p)) 139#define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 140#define NETMAP_FD(d) (P2NMD(d)->fd) 141 | 147 148struct nm_hdr_t { /* same as pcap_pkthdr */ 149 struct timeval ts; 150 uint32_t caplen; 151 uint32_t len; 152}; 153 154struct nm_desc_t { --- 9 unchanged lines hidden (view full) --- 164 165/* 166 * when the descriptor is open correctly, d->self == d 167 */ 168#define P2NMD(p) ((struct nm_desc_t *)(p)) 169#define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 170#define NETMAP_FD(d) (P2NMD(d)->fd) 171 |
172 |
|
142/* | 173/* |
174 * this is a slightly optimized copy routine which rounds 175 * to multiple of 64 bytes and is often faster than dealing 176 * with other odd sizes. We assume there is enough room 177 * in the source and destination buffers. 178 * 179 * XXX only for multiples of 64 bytes, non overlapped. 180 */ 181static inline void 182pkt_copy(const void *_src, void *_dst, int l) 183{ 184 const uint64_t *src = _src; 185 uint64_t *dst = _dst; 186 if (unlikely(l >= 1024)) { 187 memcpy(dst, src, l); 188 return; 189 } 190 for (; likely(l > 0); l-=64) { 191 *dst++ = *src++; 192 *dst++ = *src++; 193 *dst++ = *src++; 194 *dst++ = *src++; 195 *dst++ = *src++; 196 *dst++ = *src++; 197 *dst++ = *src++; 198 *dst++ = *src++; 199 } 200} 201 202 203/* |
|
143 * The callback, invoked on each received packet. Same as libpcap 144 */ 145typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 146 147/* | 204 * The callback, invoked on each received packet. Same as libpcap 205 */ 206typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 207 208/* |
148 * The open routine accepts an ifname (netmap:foo or vale:foo) and 149 * optionally a second (string) argument indicating the ring number | 209 *--- the pcap-like API --- 210 * 211 * nm_open() opens a file descriptor, binds to a port and maps memory. 212 * 213 * ifname (netmap:foo or vale:foo) is the port name 214 * flags can be NETMAP_SW_RING or NETMAP_HW_RING etc. 215 * ring_no only used if NETMAP_HW_RING is specified, is interpreted 216 * as a string or integer indicating the ring number 217 * ring_flags is stored in all ring flags (e.g. for transparent mode) |
150 * to open. If successful, t opens the fd and maps the memory. 151 */ | 218 * to open. If successful, t opens the fd and maps the memory. 219 */ |
220 |
|
152static struct nm_desc_t *nm_open(const char *ifname, 153 const char *ring_no, int flags, int ring_flags); 154 155/* | 221static struct nm_desc_t *nm_open(const char *ifname, 222 const char *ring_no, int flags, int ring_flags); 223 224/* |
156 * nm_dispatch() is the same as pcap_dispatch() 157 * nm_next() is the same as pcap_next() | 225 * nm_close() closes and restores the port to its previous state |
158 */ | 226 */ |
159static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 160static u_char *nm_next(struct nm_desc_t *, struct nm_hdr_t *); | |
161 | 227 |
228static int nm_close(struct nm_desc_t *); 229 |
|
162/* | 230/* |
163 * unmap memory, close file descriptor and free the descriptor. | 231 * nm_inject() is the same as pcap_inject() 232 * nm_dispatch() is the same as pcap_dispatch() 233 * nm_nextpkt() is the same as pcap_next() |
164 */ | 234 */ |
165static int nm_close(struct nm_desc_t *); | |
166 | 235 |
236static int nm_inject(struct nm_desc_t *, const void *, size_t); 237static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 238static u_char *nm_nextpkt(struct nm_desc_t *, struct nm_hdr_t *); |
|
167 | 239 |
240 |
|
168/* 169 * Try to open, return descriptor if successful, NULL otherwise. 170 * An invalid netmap name will return errno = 0; 171 */ 172static struct nm_desc_t * 173nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 174{ 175 struct nm_desc_t *d; --- 59 unchanged lines hidden (view full) --- 235 errno = EINVAL; 236 return NULL; 237} 238 239 240static int 241nm_close(struct nm_desc_t *d) 242{ | 241/* 242 * Try to open, return descriptor if successful, NULL otherwise. 243 * An invalid netmap name will return errno = 0; 244 */ 245static struct nm_desc_t * 246nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 247{ 248 struct nm_desc_t *d; --- 59 unchanged lines hidden (view full) --- 308 errno = EINVAL; 309 return NULL; 310} 311 312 313static int 314nm_close(struct nm_desc_t *d) 315{ |
316 /* 317 * ugly trick to avoid unused warnings 318 */ 319 static void *__xxzt[] __attribute__ ((unused)) = 320 { nm_open, nm_inject, nm_dispatch, nm_nextpkt } ; 321 |
|
243 if (d == NULL || d->self != d) 244 return EINVAL; 245 if (d->mem) 246 munmap(d->mem, d->memsize); 247 if (d->fd != -1) 248 close(d->fd); 249 bzero(d, sizeof(*d)); 250 free(d); 251 return 0; 252} 253 254 255/* | 322 if (d == NULL || d->self != d) 323 return EINVAL; 324 if (d->mem) 325 munmap(d->mem, d->memsize); 326 if (d->fd != -1) 327 close(d->fd); 328 bzero(d, sizeof(*d)); 329 free(d); 330 return 0; 331} 332 333 334/* |
335 * Same prototype as pcap_inject(), only need to cast. 336 */ 337static int 338nm_inject(struct nm_desc_t *d, const void *buf, size_t size) 339{ 340 u_int c, n = d->last_ring - d->first_ring + 1; 341 342 if (0) fprintf(stderr, "%s rings %d %d %d\n", __FUNCTION__, 343 d->first_ring, d->cur_ring, d->last_ring); 344 for (c = 0; c < n ; c++) { 345 /* compute current ring to use */ 346 struct netmap_ring *ring; 347 uint32_t i, idx; 348 uint32_t ri = d->cur_ring + c; 349 350 if (ri > d->last_ring) 351 ri = d->first_ring; 352 ring = NETMAP_TXRING(d->nifp, ri); 353 if (nm_ring_empty(ring)) { 354 if (0) fprintf(stderr, "%s ring %d cur %d tail %d\n", 355 __FUNCTION__, 356 ri, ring->cur, ring->tail); 357 continue; 358 } 359 i = ring->cur; 360 idx = ring->slot[i].buf_idx; 361 ring->slot[i].len = size; 362 pkt_copy(buf, NETMAP_BUF(ring, idx), size); 363 d->cur_ring = ri; 364 ring->head = ring->cur = nm_ring_next(ring, i); 365 return size; 366 } 367 return 0; /* fail */ 368} 369 370 371/* |
|
256 * Same prototype as pcap_dispatch(), only need to cast. 257 */ | 372 * Same prototype as pcap_dispatch(), only need to cast. 373 */ |
258inline /* not really, but disable unused warnings */ | |
259static int 260nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 261{ 262 int n = d->last_ring - d->first_ring + 1; 263 int c, got = 0, ri = d->cur_ring; 264 265 if (cnt == 0) 266 cnt = -1; --- 4 unchanged lines hidden (view full) --- 271 for (c=0; c < n && cnt != got; c++) { 272 /* compute current ring to use */ 273 struct netmap_ring *ring; 274 275 ri = d->cur_ring + c; 276 if (ri > d->last_ring) 277 ri = d->first_ring; 278 ring = NETMAP_RXRING(d->nifp, ri); | 374static int 375nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 376{ 377 int n = d->last_ring - d->first_ring + 1; 378 int c, got = 0, ri = d->cur_ring; 379 380 if (cnt == 0) 381 cnt = -1; --- 4 unchanged lines hidden (view full) --- 386 for (c=0; c < n && cnt != got; c++) { 387 /* compute current ring to use */ 388 struct netmap_ring *ring; 389 390 ri = d->cur_ring + c; 391 if (ri > d->last_ring) 392 ri = d->first_ring; 393 ring = NETMAP_RXRING(d->nifp, ri); |
279 for ( ; ring->avail > 0 && cnt != got; got++) { | 394 for ( ; !nm_ring_empty(ring) && cnt != got; got++) { |
280 u_int i = ring->cur; 281 u_int idx = ring->slot[i].buf_idx; 282 u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 283 // XXX should check valid buf 284 // prefetch(buf); 285 d->hdr.len = d->hdr.caplen = ring->slot[i].len; 286 d->hdr.ts = ring->ts; 287 cb(arg, &d->hdr, buf); | 395 u_int i = ring->cur; 396 u_int idx = ring->slot[i].buf_idx; 397 u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 398 // XXX should check valid buf 399 // prefetch(buf); 400 d->hdr.len = d->hdr.caplen = ring->slot[i].len; 401 d->hdr.ts = ring->ts; 402 cb(arg, &d->hdr, buf); |
288 ring->cur = NETMAP_RING_NEXT(ring, i); 289 ring->avail--; | 403 ring->head = ring->cur = nm_ring_next(ring, i); |
290 } 291 } 292 d->cur_ring = ri; 293 return got; 294} 295 | 404 } 405 } 406 d->cur_ring = ri; 407 return got; 408} 409 |
296inline /* not really, but disable unused warnings */ | |
297static u_char * | 410static u_char * |
298nm_next(struct nm_desc_t *d, struct nm_hdr_t *hdr) | 411nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) |
299{ 300 int ri = d->cur_ring; 301 302 do { 303 /* compute current ring to use */ 304 struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); | 412{ 413 int ri = d->cur_ring; 414 415 do { 416 /* compute current ring to use */ 417 struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); |
305 if (ring->avail > 0) { | 418 if (!nm_ring_empty(ring)) { |
306 u_int i = ring->cur; 307 u_int idx = ring->slot[i].buf_idx; 308 u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 309 // XXX should check valid buf 310 // prefetch(buf); 311 hdr->ts = ring->ts; 312 hdr->len = hdr->caplen = ring->slot[i].len; | 419 u_int i = ring->cur; 420 u_int idx = ring->slot[i].buf_idx; 421 u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 422 // XXX should check valid buf 423 // prefetch(buf); 424 hdr->ts = ring->ts; 425 hdr->len = hdr->caplen = ring->slot[i].len; |
313 ring->cur = NETMAP_RING_NEXT(ring, i); 314 ring->avail--; | 426 ring->cur = nm_ring_next(ring, i); 427 /* we could postpone advancing head if we want 428 * to hold the buffer. This can be supported in 429 * the future. 430 */ 431 ring->head = ring->cur; |
315 d->cur_ring = ri; 316 return buf; 317 } 318 ri++; 319 if (ri > d->last_ring) 320 ri = d->first_ring; 321 } while (ri != d->cur_ring); 322 return NULL; /* nothing found */ 323} 324 325#endif /* !HAVE_NETMAP_WITH_LIBS */ 326 327#endif /* NETMAP_WITH_LIBS */ 328 329#endif /* _NET_NETMAP_USER_H_ */ | 432 d->cur_ring = ri; 433 return buf; 434 } 435 ri++; 436 if (ri > d->last_ring) 437 ri = d->first_ring; 438 } while (ri != d->cur_ring); 439 return NULL; /* nothing found */ 440} 441 442#endif /* !HAVE_NETMAP_WITH_LIBS */ 443 444#endif /* NETMAP_WITH_LIBS */ 445 446#endif /* _NET_NETMAP_USER_H_ */ |