2 * Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved.
3 * Copyright (C) 2013 Universita` di Pisa
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
31 * This header contains the macros used to manipulate netmap structures
32 * and packets in userspace. See netmap(4) for more information.
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)
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
46 * ring->slot[i] gives us the i-th slot (we can access
47 * directly plen, flags, bufindex)
49 * char *buf = NETMAP_BUF(ring, x) returns a pointer to
50 * the buffer numbered x
52 * Since rings are circular, we have macros to compute the next index
53 * i = NETMAP_RING_NEXT(ring, i);
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
59 * In order to use these, include #define NETMAP_WITH_LIBS
60 * in the source file that invokes these functions.
63 #ifndef _NET_NETMAP_USER_H_
64 #define _NET_NETMAP_USER_H_
67 #include <net/if.h> /* IFNAMSIZ */
68 #include <net/netmap.h>
70 #define _NETMAP_OFFSET(type, ptr, offset) \
71 ((type)(void *)((char *)(ptr) + (offset)))
73 #define NETMAP_IF(b, o) _NETMAP_OFFSET(struct netmap_if *, b, o)
75 #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
76 nifp, (nifp)->ring_ofs[index] )
78 #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
79 nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
81 #define NETMAP_BUF(ring, index) \
82 ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
84 #define NETMAP_BUF_IDX(ring, buf) \
85 ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
88 #define NETMAP_RING_NEXT(r, i) \
89 ((i)+1 == (r)->num_slots ? 0 : (i) + 1 )
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 )
97 * Return 1 if the given tx ring is empty.
99 #define NETMAP_TX_RING_EMPTY(r) ((r)->avail >= (r)->num_slots - 1)
101 #ifdef NETMAP_WITH_LIBS
103 * Support for simple I/O libraries.
104 * Include other system headers required for compiling this.
107 #ifndef HAVE_NETMAP_WITH_LIBS
108 #define HAVE_NETMAP_WITH_LIBS
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 */
118 struct nm_hdr_t
{ /* same as pcap_pkthdr */
125 struct nm_desc_t
*self
;
129 struct netmap_if
*nifp
;
130 uint16_t first_ring
, last_ring
, cur_ring
;
136 * when the descriptor is open correctly, d->self == d
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)
143 * The callback, invoked on each received packet. Same as libpcap
145 typedef void (*nm_cb_t
)(u_char
*, const struct nm_hdr_t
*, const u_char
*d
);
148 * The open routine accepts an ifname (netmap:foo or vale:foo) and
149 * optionally a second (string) argument indicating the ring number
150 * to open. If successful, t opens the fd and maps the memory.
152 static struct nm_desc_t
*nm_open(const char *ifname
,
153 const char *ring_no
, int flags
, int ring_flags
);
156 * nm_dispatch() is the same as pcap_dispatch()
157 * nm_next() is the same as pcap_next()
159 static int nm_dispatch(struct nm_desc_t
*, int, nm_cb_t
, u_char
*);
160 static u_char
*nm_next(struct nm_desc_t
*, struct nm_hdr_t
*);
163 * unmap memory, close file descriptor and free the descriptor.
165 static int nm_close(struct nm_desc_t
*);
169 * Try to open, return descriptor if successful, NULL otherwise.
170 * An invalid netmap name will return errno = 0;
172 static struct nm_desc_t
*
173 nm_open(const char *ifname
, const char *ring_name
, int flags
, int ring_flags
)
178 if (strncmp(ifname
, "netmap:", 7) && strncmp(ifname
, "vale", 4)) {
179 errno
= 0; /* name not recognised */
182 if (ifname
[0] == 'n')
184 d
= (struct nm_desc_t
*)calloc(1, sizeof(*d
));
189 d
->self
= d
; /* set this early so nm_close() works */
190 d
->fd
= open("/dev/netmap", O_RDWR
);
194 if (flags
& NETMAP_SW_RING
) {
195 d
->req
.nr_ringid
= NETMAP_SW_RING
;
198 if (flags
& NETMAP_HW_RING
) /* interpret ring as int */
199 r
= (uintptr_t)ring_name
;
200 else /* interpret ring as numeric string */
201 r
= ring_name
? atoi(ring_name
) : ~0;
202 r
= (r
< NETMAP_RING_MASK
) ? (r
| NETMAP_HW_RING
) : 0;
203 d
->req
.nr_ringid
= r
; /* set the ring */
205 d
->req
.nr_ringid
|= (flags
& ~NETMAP_RING_MASK
);
206 d
->req
.nr_version
= NETMAP_API
;
207 strncpy(d
->req
.nr_name
, ifname
, sizeof(d
->req
.nr_name
));
208 if (ioctl(d
->fd
, NIOCREGIF
, &d
->req
))
211 d
->memsize
= d
->req
.nr_memsize
;
212 d
->mem
= mmap(0, d
->memsize
, PROT_WRITE
| PROT_READ
, MAP_SHARED
,
216 d
->nifp
= NETMAP_IF(d
->mem
, d
->req
.nr_offset
);
217 if (d
->req
.nr_ringid
& NETMAP_SW_RING
) {
218 d
->first_ring
= d
->last_ring
= d
->req
.nr_rx_rings
;
219 } else if (d
->req
.nr_ringid
& NETMAP_HW_RING
) {
220 d
->first_ring
= d
->last_ring
=
221 d
->req
.nr_ringid
& NETMAP_RING_MASK
;
224 d
->last_ring
= d
->req
.nr_rx_rings
- 1;
226 d
->cur_ring
= d
->first_ring
;
227 for (n
= d
->first_ring
; n
<= d
->last_ring
; n
++) {
228 struct netmap_ring
*ring
= NETMAP_RXRING(d
->nifp
, n
);
229 ring
->flags
|= ring_flags
;
241 nm_close(struct nm_desc_t
*d
)
243 if (d
== NULL
|| d
->self
!= d
)
246 munmap(d
->mem
, d
->memsize
);
249 bzero(d
, sizeof(*d
));
256 * Same prototype as pcap_dispatch(), only need to cast.
258 inline /* not really, but disable unused warnings */
260 nm_dispatch(struct nm_desc_t
*d
, int cnt
, nm_cb_t cb
, u_char
*arg
)
262 int n
= d
->last_ring
- d
->first_ring
+ 1;
263 int c
, got
= 0, ri
= d
->cur_ring
;
267 /* cnt == -1 means infinite, but rings have a finite amount
268 * of buffers and the int is large enough that we never wrap,
269 * so we can omit checking for -1
271 for (c
=0; c
< n
&& cnt
!= got
; c
++) {
272 /* compute current ring to use */
273 struct netmap_ring
*ring
;
275 ri
= d
->cur_ring
+ c
;
276 if (ri
> d
->last_ring
)
278 ring
= NETMAP_RXRING(d
->nifp
, ri
);
279 for ( ; ring
->avail
> 0 && cnt
!= got
; got
++) {
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
285 d
->hdr
.len
= d
->hdr
.caplen
= ring
->slot
[i
].len
;
286 d
->hdr
.ts
= ring
->ts
;
287 cb(arg
, &d
->hdr
, buf
);
288 ring
->cur
= NETMAP_RING_NEXT(ring
, i
);
296 inline /* not really, but disable unused warnings */
298 nm_next(struct nm_desc_t
*d
, struct nm_hdr_t
*hdr
)
300 int ri
= d
->cur_ring
;
303 /* compute current ring to use */
304 struct netmap_ring
*ring
= NETMAP_RXRING(d
->nifp
, ri
);
305 if (ring
->avail
> 0) {
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
312 hdr
->len
= hdr
->caplen
= ring
->slot
[i
].len
;
313 ring
->cur
= NETMAP_RING_NEXT(ring
, i
);
319 if (ri
> d
->last_ring
)
321 } while (ri
!= d
->cur_ring
);
322 return NULL
; /* nothing found */
325 #endif /* !HAVE_NETMAP_WITH_LIBS */
327 #endif /* NETMAP_WITH_LIBS */
329 #endif /* _NET_NETMAP_USER_H_ */