2 * (C) 2011 Luigi Rizzo, Matteo Landi
6 * A netmap client to bridge two network interfaces
7 * (or one interface and the host stack).
13 #include <signal.h> /* signal */
16 #include <string.h> /* strcmp */
17 #include <fcntl.h> /* open */
18 #include <unistd.h> /* close */
20 #include <sys/endian.h> /* le64toh */
21 #include <sys/mman.h> /* PROT_* */
22 #include <sys/ioctl.h> /* ioctl */
23 #include <machine/param.h>
25 #include <sys/socket.h> /* sockaddr.. */
26 #include <arpa/inet.h> /* ntohs */
28 #include <net/if.h> /* ifreq */
29 #include <net/ethernet.h>
30 #include <net/netmap.h>
31 #include <net/netmap_user.h>
33 #include <netinet/in.h> /* sockaddr_in */
35 #define MIN(a, b) ((a) < (b) ? (a) : (b))
40 #define ND(format, ...) {}
41 #define D(format, ...) do { \
42 if (!verbose) break; \
43 struct timeval _xxts; \
44 gettimeofday(&_xxts, NULL); \
45 fprintf(stderr, "%03d.%06d %s [%d] " format "\n", \
46 (int)_xxts.tv_sec %1000, (int)_xxts.tv_usec, \
47 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
51 char *version = "$Id: bridge.c 9642 2011-11-07 21:39:47Z luigi $";
53 static int do_abort = 0;
56 * info on a ring we handle
61 char *mem; /* userspace mmap address */
64 u_int begin, end; /* first..last+1 rings to check */
65 struct netmap_if *nifp;
66 struct netmap_ring *tx, *rx; /* shortcuts */
74 sigint_h(__unused int sig)
77 signal(SIGINT, SIG_DFL);
82 do_ioctl(struct my_ring *me, int what)
87 bzero(&ifr, sizeof(ifr));
88 strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name));
91 ifr.ifr_flagshigh = me->if_flags >> 16;
92 ifr.ifr_flags = me->if_flags & 0xffff;
95 ifr.ifr_reqcap = me->if_reqcap;
96 ifr.ifr_curcap = me->if_curcap;
99 error = ioctl(me->fd, what, &ifr);
101 D("ioctl error %d", what);
106 me->if_flags = (ifr.ifr_flagshigh << 16) |
107 (0xffff & ifr.ifr_flags);
109 D("flags are 0x%x", me->if_flags);
113 me->if_reqcap = ifr.ifr_reqcap;
114 me->if_curcap = ifr.ifr_curcap;
116 D("curcap are 0x%x", me->if_curcap);
123 * open a device. if me->mem is null then do an mmap.
126 netmap_open(struct my_ring *me, int ringid)
131 me->fd = fd = open("/dev/netmap", O_RDWR);
133 D("Unable to open /dev/netmap");
136 bzero(&req, sizeof(req));
137 strncpy(req.nr_name, me->ifname, sizeof(req.nr_name));
138 req.nr_ringid = ringid;
139 err = ioctl(fd, NIOCGINFO, &req);
141 D("cannot get info on %s", me->ifname);
144 me->memsize = l = req.nr_memsize;
146 D("memsize is %d MB", l>>20);
147 err = ioctl(fd, NIOCREGIF, &req);
149 D("Unable to register %s", me->ifname);
153 if (me->mem == NULL) {
154 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
155 if (me->mem == MAP_FAILED) {
162 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
163 me->queueid = ringid;
164 if (ringid & NETMAP_SW_RING) {
165 me->begin = req.nr_numrings;
166 me->end = me->begin + 1;
167 } else if (ringid & NETMAP_HW_RING) {
168 me->begin = ringid & NETMAP_RING_MASK;
169 me->end = me->begin + 1;
172 me->end = req.nr_numrings;
174 me->tx = NETMAP_TXRING(me->nifp, me->begin);
175 me->rx = NETMAP_RXRING(me->nifp, me->begin);
184 netmap_close(struct my_ring *me)
188 munmap(me->mem, me->memsize);
189 ioctl(me->fd, NIOCUNREGIF, NULL);
196 * move up to 'limit' pkts from rxring to txring swapping buffers.
199 process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
200 u_int limit, const char *msg)
204 /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */
205 if (rxring->flags || txring->flags)
206 D("%s rxflags %x txflags %x",
207 msg, rxring->flags, txring->flags);
208 j = rxring->cur; /* RX */
209 k = txring->cur; /* TX */
210 if (rxring->avail < limit)
211 limit = rxring->avail;
212 if (txring->avail < limit)
213 limit = txring->avail;
215 while (limit-- > 0) {
216 struct netmap_slot *rs = &rxring->slot[j];
217 struct netmap_slot *ts = &txring->slot[k];
221 if (ts->buf_idx < 2 || rs->buf_idx < 2) {
222 D("wrong index rx[%d] = %d -> tx[%d] = %d",
223 j, rs->buf_idx, k, ts->buf_idx);
227 ts->buf_idx = rs->buf_idx;
230 /* copy the packet length. */
231 if (rs->len < 14 || rs->len > 2048)
232 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
233 else if (verbose > 1)
234 D("send len %d rx[%d] -> tx[%d]", rs->len, j, k);
237 /* report the buffer change. */
238 ts->flags |= NS_BUF_CHANGED;
239 rs->flags |= NS_BUF_CHANGED;
240 j = NETMAP_RING_NEXT(rxring, j);
241 k = NETMAP_RING_NEXT(txring, k);
247 if (verbose && m > 0)
248 D("sent %d packets to %p", m, txring);
253 /* move packts from src to destination */
255 move(struct my_ring *src, struct my_ring *dst, u_int limit)
257 struct netmap_ring *txring, *rxring;
258 u_int m = 0, si = src->begin, di = dst->begin;
259 const char *msg = (src->queueid & NETMAP_SW_RING) ?
260 "host->net" : "net->host";
262 while (si < src->end && di < dst->end) {
263 rxring = NETMAP_RXRING(src->nifp, si);
264 txring = NETMAP_TXRING(dst->nifp, di);
265 ND("txring %p rxring %p", txring, rxring);
266 if (rxring->avail == 0) {
270 if (txring->avail == 0) {
274 m += process_rings(rxring, txring, limit, msg);
281 * how many packets on this set of queues ?
284 howmany(struct my_ring *me, int tx)
288 ND("me %p begin %d end %d", me, me->begin, me->end);
289 for (i = me->begin; i < me->end; i++) {
290 struct netmap_ring *ring = tx ?
291 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
294 if (0 && verbose && tot && !tx)
295 D("ring %s %s %s has %d avail at %d",
296 me->ifname, tx ? "tx": "rx",
297 me->end > me->nifp->ni_num_queues ?
299 tot, NETMAP_TXRING(me->nifp, me->begin)->cur);
304 * bridge [-v] if1 [if2]
306 * If only one name, or the two interfaces are the same,
307 * bridges userland and the adapter. Otherwise bridge
311 main(int argc, char **argv)
313 struct pollfd pollfd[2];
316 struct my_ring me[2];
318 fprintf(stderr, "%s %s built %s %s\n",
319 argv[0], version, __DATE__, __TIME__);
321 bzero(me, sizeof(me));
323 while (argc > 1 && !strcmp(argv[1], "-v")) {
329 if (argc < 2 || argc > 4) {
330 D("Usage: %s IFNAME1 [IFNAME2 [BURST]]", argv[0]);
334 /* setup netmap interface #1. */
335 me[0].ifname = argv[1];
336 if (argc == 2 || !strcmp(argv[1], argv[2])) {
337 D("same interface, endpoint 0 goes to host");
339 me[1].ifname = argv[1];
341 /* two different interfaces. Take all rings on if1 */
342 i = 0; // all hw rings
343 me[1].ifname = argv[2];
345 if (netmap_open(me, i))
347 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */
348 if (netmap_open(me+1, 0))
351 /* if bridging two interfaces, set promisc mode */
352 if (i != NETMAP_SW_RING) {
353 do_ioctl(me, SIOCGIFFLAGS);
354 if ((me[0].if_flags & IFF_UP) == 0) {
355 D("%s is down, bringing up...", me[0].ifname);
356 me[0].if_flags |= IFF_UP;
358 me[0].if_flags |= IFF_PPROMISC;
359 do_ioctl(me, SIOCSIFFLAGS);
361 do_ioctl(me+1, SIOCGIFFLAGS);
362 me[1].if_flags |= IFF_PPROMISC;
363 do_ioctl(me+1, SIOCSIFFLAGS);
365 /* also disable checksums etc. */
366 do_ioctl(me, SIOCGIFCAP);
367 me[0].if_reqcap = me[0].if_curcap;
368 me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
369 do_ioctl(me+0, SIOCSIFCAP);
371 do_ioctl(me+1, SIOCGIFFLAGS);
372 if ((me[1].if_flags & IFF_UP) == 0) {
373 D("%s is down, bringing up...", me[1].ifname);
374 me[1].if_flags |= IFF_UP;
376 do_ioctl(me+1, SIOCSIFFLAGS);
378 do_ioctl(me+1, SIOCGIFCAP);
379 me[1].if_reqcap = me[1].if_curcap;
380 me[1].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
381 do_ioctl(me+1, SIOCSIFCAP);
383 burst = atoi(argv[3]); /* packets burst size. */
385 /* setup poll(2) variables. */
386 memset(pollfd, 0, sizeof(pollfd));
387 for (i = 0; i < 2; i++) {
388 pollfd[i].fd = me[i].fd;
389 pollfd[i].events = (POLLIN);
392 D("Wait 2 secs for link to come up...");
394 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
395 me[0].ifname, me[0].queueid, me[0].nifp->ni_num_queues,
396 me[1].ifname, me[1].queueid, me[1].nifp->ni_num_queues);
399 signal(SIGINT, sigint_h);
402 pollfd[0].events = pollfd[1].events = 0;
403 pollfd[0].revents = pollfd[1].revents = 0;
405 n1 = howmany(me + 1, 0);
407 pollfd[1].events |= POLLOUT;
409 pollfd[0].events |= POLLIN;
411 pollfd[0].events |= POLLOUT;
413 pollfd[1].events |= POLLIN;
414 ret = poll(pollfd, 2, 2500);
415 if (ret <= 0 || verbose)
416 D("poll %s [0] ev %x %x rx %d@%d tx %d,"
417 " [1] ev %x %x rx %d@%d tx %d",
418 ret <= 0 ? "timeout" : "ok",
432 if (pollfd[0].revents & POLLERR) {
433 D("error on fd0, rxcur %d@%d",
434 me[0].rx->avail, me[0].rx->cur);
436 if (pollfd[1].revents & POLLERR) {
437 D("error on fd1, rxcur %d@%d",
438 me[1].rx->avail, me[1].rx->cur);
440 if (pollfd[0].revents & POLLOUT) {
441 move(me + 1, me, burst);
442 // XXX we don't need the ioctl */
443 // ioctl(me[0].fd, NIOCTXSYNC, NULL);
445 if (pollfd[1].revents & POLLOUT) {
446 move(me, me + 1, burst);
447 // XXX we don't need the ioctl */
448 // ioctl(me[1].fd, NIOCTXSYNC, NULL);
452 netmap_close(me + 1);
453 netmap_close(me + 0);