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 10857 2012-04-06 12:18:22Z 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 req.nr_version = NETMAP_API;
140 err = ioctl(fd, NIOCGINFO, &req);
142 D("cannot get info on %s", me->ifname);
145 me->memsize = l = req.nr_memsize;
147 D("memsize is %d MB", l>>20);
148 err = ioctl(fd, NIOCREGIF, &req);
150 D("Unable to register %s", me->ifname);
154 if (me->mem == NULL) {
155 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
156 if (me->mem == MAP_FAILED) {
163 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
164 me->queueid = ringid;
165 if (ringid & NETMAP_SW_RING) {
166 me->begin = req.nr_rx_rings;
167 me->end = me->begin + 1;
168 me->tx = NETMAP_TXRING(me->nifp, req.nr_tx_rings);
169 me->rx = NETMAP_RXRING(me->nifp, req.nr_rx_rings);
170 } else if (ringid & NETMAP_HW_RING) {
171 D("XXX check multiple threads");
172 me->begin = ringid & NETMAP_RING_MASK;
173 me->end = me->begin + 1;
174 me->tx = NETMAP_TXRING(me->nifp, me->begin);
175 me->rx = NETMAP_RXRING(me->nifp, me->begin);
178 me->end = req.nr_rx_rings; // XXX max of the two
179 me->tx = NETMAP_TXRING(me->nifp, 0);
180 me->rx = NETMAP_RXRING(me->nifp, 0);
190 netmap_close(struct my_ring *me)
194 munmap(me->mem, me->memsize);
195 ioctl(me->fd, NIOCUNREGIF, NULL);
202 * move up to 'limit' pkts from rxring to txring swapping buffers.
205 process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
206 u_int limit, const char *msg)
210 /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */
211 if (rxring->flags || txring->flags)
212 D("%s rxflags %x txflags %x",
213 msg, rxring->flags, txring->flags);
214 j = rxring->cur; /* RX */
215 k = txring->cur; /* TX */
216 if (rxring->avail < limit)
217 limit = rxring->avail;
218 if (txring->avail < limit)
219 limit = txring->avail;
221 while (limit-- > 0) {
222 struct netmap_slot *rs = &rxring->slot[j];
223 struct netmap_slot *ts = &txring->slot[k];
227 if (ts->buf_idx < 2 || rs->buf_idx < 2) {
228 D("wrong index rx[%d] = %d -> tx[%d] = %d",
229 j, rs->buf_idx, k, ts->buf_idx);
233 ts->buf_idx = rs->buf_idx;
236 /* copy the packet length. */
237 if (rs->len < 14 || rs->len > 2048)
238 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
239 else if (verbose > 1)
240 D("send len %d rx[%d] -> tx[%d]", rs->len, j, k);
243 /* report the buffer change. */
244 ts->flags |= NS_BUF_CHANGED;
245 rs->flags |= NS_BUF_CHANGED;
246 j = NETMAP_RING_NEXT(rxring, j);
247 k = NETMAP_RING_NEXT(txring, k);
253 if (verbose && m > 0)
254 D("sent %d packets to %p", m, txring);
259 /* move packts from src to destination */
261 move(struct my_ring *src, struct my_ring *dst, u_int limit)
263 struct netmap_ring *txring, *rxring;
264 u_int m = 0, si = src->begin, di = dst->begin;
265 const char *msg = (src->queueid & NETMAP_SW_RING) ?
266 "host->net" : "net->host";
268 while (si < src->end && di < dst->end) {
269 rxring = NETMAP_RXRING(src->nifp, si);
270 txring = NETMAP_TXRING(dst->nifp, di);
271 ND("txring %p rxring %p", txring, rxring);
272 if (rxring->avail == 0) {
276 if (txring->avail == 0) {
280 m += process_rings(rxring, txring, limit, msg);
287 * how many packets on this set of queues ?
290 howmany(struct my_ring *me, int tx)
294 ND("me %p begin %d end %d", me, me->begin, me->end);
295 for (i = me->begin; i < me->end; i++) {
296 struct netmap_ring *ring = tx ?
297 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
300 if (0 && verbose && tot && !tx)
301 D("ring %s %s %s has %d avail at %d",
302 me->ifname, tx ? "tx": "rx",
303 me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ?
305 tot, NETMAP_TXRING(me->nifp, me->begin)->cur);
313 "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [iface]\n");
318 * bridge [-v] if1 [if2]
320 * If only one name, or the two interfaces are the same,
321 * bridges userland and the adapter. Otherwise bridge
325 main(int argc, char **argv)
327 struct pollfd pollfd[2];
329 u_int burst = 1024, wait_link = 4;
330 struct my_ring me[2];
331 char *ifa = NULL, *ifb = NULL;
333 fprintf(stderr, "%s %s built %s %s\n",
334 argv[0], version, __DATE__, __TIME__);
336 bzero(me, sizeof(me));
338 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) {
340 D("bad option %c %s", ch, optarg);
343 case 'b': /* burst */
344 burst = atoi(optarg);
346 case 'i': /* interface */
349 else if (ifb == NULL)
352 D("%s ignored, already have 2 interfaces",
359 wait_link = atoi(optarg);
372 burst = atoi(argv[3]);
376 D("missing interface");
379 if (burst < 1 || burst > 8192) {
380 D("invalid burst %d, set to 1024", burst);
383 if (wait_link > 100) {
384 D("invalid wait_link %d, set to 4", wait_link);
387 /* setup netmap interface #1. */
390 if (!strcmp(ifa, ifb)) {
391 D("same interface, endpoint 0 goes to host");
394 /* two different interfaces. Take all rings on if1 */
395 i = 0; // all hw rings
397 if (netmap_open(me, i))
399 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */
400 if (netmap_open(me+1, 0))
403 /* if bridging two interfaces, set promisc mode */
404 if (i != NETMAP_SW_RING) {
405 do_ioctl(me, SIOCGIFFLAGS);
406 if ((me[0].if_flags & IFF_UP) == 0) {
407 D("%s is down, bringing up...", me[0].ifname);
408 me[0].if_flags |= IFF_UP;
410 me[0].if_flags |= IFF_PPROMISC;
411 do_ioctl(me, SIOCSIFFLAGS);
413 do_ioctl(me+1, SIOCGIFFLAGS);
414 me[1].if_flags |= IFF_PPROMISC;
415 do_ioctl(me+1, SIOCSIFFLAGS);
417 /* also disable checksums etc. */
418 do_ioctl(me, SIOCGIFCAP);
419 me[0].if_reqcap = me[0].if_curcap;
420 me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
421 do_ioctl(me+0, SIOCSIFCAP);
423 do_ioctl(me+1, SIOCGIFFLAGS);
424 if ((me[1].if_flags & IFF_UP) == 0) {
425 D("%s is down, bringing up...", me[1].ifname);
426 me[1].if_flags |= IFF_UP;
428 do_ioctl(me+1, SIOCSIFFLAGS);
430 do_ioctl(me+1, SIOCGIFCAP);
431 me[1].if_reqcap = me[1].if_curcap;
432 me[1].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
433 do_ioctl(me+1, SIOCSIFCAP);
435 /* setup poll(2) variables. */
436 memset(pollfd, 0, sizeof(pollfd));
437 for (i = 0; i < 2; i++) {
438 pollfd[i].fd = me[i].fd;
439 pollfd[i].events = (POLLIN);
442 D("Wait %d secs for link to come up...", wait_link);
444 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
445 me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings,
446 me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings);
449 signal(SIGINT, sigint_h);
452 pollfd[0].events = pollfd[1].events = 0;
453 pollfd[0].revents = pollfd[1].revents = 0;
455 n1 = howmany(me + 1, 0);
457 pollfd[1].events |= POLLOUT;
459 pollfd[0].events |= POLLIN;
461 pollfd[0].events |= POLLOUT;
463 pollfd[1].events |= POLLIN;
464 ret = poll(pollfd, 2, 2500);
465 if (ret <= 0 || verbose)
466 D("poll %s [0] ev %x %x rx %d@%d tx %d,"
467 " [1] ev %x %x rx %d@%d tx %d",
468 ret <= 0 ? "timeout" : "ok",
482 if (pollfd[0].revents & POLLERR) {
483 D("error on fd0, rxcur %d@%d",
484 me[0].rx->avail, me[0].rx->cur);
486 if (pollfd[1].revents & POLLERR) {
487 D("error on fd1, rxcur %d@%d",
488 me[1].rx->avail, me[1].rx->cur);
490 if (pollfd[0].revents & POLLOUT) {
491 move(me + 1, me, burst);
492 // XXX we don't need the ioctl */
493 // ioctl(me[0].fd, NIOCTXSYNC, NULL);
495 if (pollfd[1].revents & POLLOUT) {
496 move(me, me + 1, burst);
497 // XXX we don't need the ioctl */
498 // ioctl(me[1].fd, NIOCTXSYNC, NULL);
502 netmap_close(me + 1);
503 netmap_close(me + 0);