bridge.c (243281) | bridge.c (250458) |
---|---|
1/* 2 * (C) 2011 Luigi Rizzo, Matteo Landi 3 * 4 * BSD license 5 * 6 * A netmap client to bridge two network interfaces 7 * (or one interface and the host stack). 8 * | 1/* 2 * (C) 2011 Luigi Rizzo, Matteo Landi 3 * 4 * BSD license 5 * 6 * A netmap client to bridge two network interfaces 7 * (or one interface and the host stack). 8 * |
9 * $FreeBSD: stable/9/tools/tools/netmap/bridge.c 243281 2012-11-19 15:24:19Z emaste $ | 9 * $FreeBSD: stable/9/tools/tools/netmap/bridge.c 250458 2013-05-10 16:16:33Z luigi $ |
10 */ 11 | 10 */ 11 |
12#include <errno.h> 13#include <signal.h> /* signal */ 14#include <stdlib.h> 15#include <stdio.h> 16#include <string.h> /* strcmp */ 17#include <fcntl.h> /* open */ 18#include <unistd.h> /* close */ | 12#include "nm_util.h" |
19 | 13 |
20#include <sys/endian.h> /* le64toh */ 21#include <sys/mman.h> /* PROT_* */ 22#include <sys/ioctl.h> /* ioctl */ 23#include <machine/param.h> 24#include <sys/poll.h> 25#include <sys/socket.h> /* sockaddr.. */ 26#include <arpa/inet.h> /* ntohs */ | |
27 | 14 |
28#include <net/if.h> /* ifreq */ 29#include <net/ethernet.h> 30#include <net/netmap.h> 31#include <net/netmap_user.h> 32 33#include <netinet/in.h> /* sockaddr_in */ 34 35#define MIN(a, b) ((a) < (b) ? (a) : (b)) 36 | |
37int verbose = 0; 38 | 15int verbose = 0; 16 |
39/* debug support */ 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__); \ 48 } while (0) | 17char *version = "$Id: bridge.c 12016 2013-01-23 17:24:22Z luigi $"; |
49 | 18 |
50 51char *version = "$Id: bridge.c 10857 2012-04-06 12:18:22Z luigi $"; 52 | |
53static int do_abort = 0; 54 | 19static int do_abort = 0; 20 |
55/* 56 * info on a ring we handle 57 */ 58struct my_ring { 59 const char *ifname; 60 int fd; 61 char *mem; /* userspace mmap address */ 62 u_int memsize; 63 u_int queueid; 64 u_int begin, end; /* first..last+1 rings to check */ 65 struct netmap_if *nifp; 66 struct netmap_ring *tx, *rx; /* shortcuts */ 67 68 uint32_t if_flags; 69 uint32_t if_reqcap; 70 uint32_t if_curcap; 71}; 72 | |
73static void | 21static void |
74sigint_h(__unused int sig) | 22sigint_h(int sig) |
75{ | 23{ |
24 (void)sig; /* UNUSED */ |
|
76 do_abort = 1; 77 signal(SIGINT, SIG_DFL); 78} 79 80 | 25 do_abort = 1; 26 signal(SIGINT, SIG_DFL); 27} 28 29 |
81static int 82do_ioctl(struct my_ring *me, unsigned long what) 83{ 84 struct ifreq ifr; 85 int error; 86 87 bzero(&ifr, sizeof(ifr)); 88 strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name)); 89 switch (what) { 90 case SIOCSIFFLAGS: 91 ifr.ifr_flagshigh = me->if_flags >> 16; 92 ifr.ifr_flags = me->if_flags & 0xffff; 93 break; 94 case SIOCSIFCAP: 95 ifr.ifr_reqcap = me->if_reqcap; 96 ifr.ifr_curcap = me->if_curcap; 97 break; 98 } 99 error = ioctl(me->fd, what, &ifr); 100 if (error) { 101 D("ioctl error 0x%lx", what); 102 return error; 103 } 104 switch (what) { 105 case SIOCGIFFLAGS: 106 me->if_flags = (ifr.ifr_flagshigh << 16) | 107 (0xffff & ifr.ifr_flags); 108 if (verbose) 109 D("flags are 0x%x", me->if_flags); 110 break; 111 112 case SIOCGIFCAP: 113 me->if_reqcap = ifr.ifr_reqcap; 114 me->if_curcap = ifr.ifr_curcap; 115 if (verbose) 116 D("curcap are 0x%x", me->if_curcap); 117 break; 118 } 119 return 0; 120} 121 | |
122/* | 30/* |
123 * open a device. if me->mem is null then do an mmap. 124 */ 125static int 126netmap_open(struct my_ring *me, int ringid) 127{ 128 int fd, err, l; 129 struct nmreq req; 130 131 me->fd = fd = open("/dev/netmap", O_RDWR); 132 if (fd < 0) { 133 D("Unable to open /dev/netmap"); 134 return (-1); 135 } 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); 141 if (err) { 142 D("cannot get info on %s", me->ifname); 143 goto error; 144 } 145 me->memsize = l = req.nr_memsize; 146 if (verbose) 147 D("memsize is %d MB", l>>20); 148 err = ioctl(fd, NIOCREGIF, &req); 149 if (err) { 150 D("Unable to register %s", me->ifname); 151 goto error; 152 } 153 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) { 157 D("Unable to mmap"); 158 me->mem = NULL; 159 goto error; 160 } 161 } 162 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); 176 } else { 177 me->begin = 0; 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); 181 } 182 return (0); 183error: 184 close(me->fd); 185 return -1; 186} 187 188 189static int 190netmap_close(struct my_ring *me) 191{ 192 D(""); 193 if (me->mem) 194 munmap(me->mem, me->memsize); 195 ioctl(me->fd, NIOCUNREGIF, NULL); 196 close(me->fd); 197 return (0); 198} 199 200 201/* | |
202 * move up to 'limit' pkts from rxring to txring swapping buffers. 203 */ 204static int 205process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, 206 u_int limit, const char *msg) 207{ 208 u_int j, k, m = 0; 209 --- 22 unchanged lines hidden (view full) --- 232 pkt = ts->buf_idx; 233 ts->buf_idx = rs->buf_idx; 234 rs->buf_idx = pkt; 235 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) | 31 * move up to 'limit' pkts from rxring to txring swapping buffers. 32 */ 33static int 34process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, 35 u_int limit, const char *msg) 36{ 37 u_int j, k, m = 0; 38 --- 22 unchanged lines hidden (view full) --- 61 pkt = ts->buf_idx; 62 ts->buf_idx = rs->buf_idx; 63 rs->buf_idx = pkt; 64 65 /* copy the packet length. */ 66 if (rs->len < 14 || rs->len > 2048) 67 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k); 68 else if (verbose > 1) |
240 D("send len %d rx[%d] -> tx[%d]", rs->len, j, k); | 69 D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k); |
241 ts->len = rs->len; 242 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); 248 } 249 rxring->avail -= m; 250 txring->avail -= m; 251 rxring->cur = j; 252 txring->cur = k; 253 if (verbose && m > 0) | 70 ts->len = rs->len; 71 72 /* report the buffer change. */ 73 ts->flags |= NS_BUF_CHANGED; 74 rs->flags |= NS_BUF_CHANGED; 75 j = NETMAP_RING_NEXT(rxring, j); 76 k = NETMAP_RING_NEXT(txring, k); 77 } 78 rxring->avail -= m; 79 txring->avail -= m; 80 rxring->cur = j; 81 txring->cur = k; 82 if (verbose && m > 0) |
254 D("sent %d packets to %p", m, txring); | 83 D("%s sent %d packets to %p", msg, m, txring); |
255 256 return (m); 257} 258 259/* move packts from src to destination */ 260static int 261move(struct my_ring *src, struct my_ring *dst, u_int limit) 262{ --- 19 unchanged lines hidden (view full) --- 282 283 return (m); 284} 285 286/* 287 * how many packets on this set of queues ? 288 */ 289static int | 84 85 return (m); 86} 87 88/* move packts from src to destination */ 89static int 90move(struct my_ring *src, struct my_ring *dst, u_int limit) 91{ --- 19 unchanged lines hidden (view full) --- 111 112 return (m); 113} 114 115/* 116 * how many packets on this set of queues ? 117 */ 118static int |
290howmany(struct my_ring *me, int tx) | 119pkt_queued(struct my_ring *me, int tx) |
291{ 292 u_int i, tot = 0; 293 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); 298 tot += ring->avail; --- 33 unchanged lines hidden (view full) --- 332 333 fprintf(stderr, "%s %s built %s %s\n", 334 argv[0], version, __DATE__, __TIME__); 335 336 bzero(me, sizeof(me)); 337 338 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) { 339 switch (ch) { | 120{ 121 u_int i, tot = 0; 122 123 ND("me %p begin %d end %d", me, me->begin, me->end); 124 for (i = me->begin; i < me->end; i++) { 125 struct netmap_ring *ring = tx ? 126 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); 127 tot += ring->avail; --- 33 unchanged lines hidden (view full) --- 161 162 fprintf(stderr, "%s %s built %s %s\n", 163 argv[0], version, __DATE__, __TIME__); 164 165 bzero(me, sizeof(me)); 166 167 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) { 168 switch (ch) { |
169 default: |
|
340 D("bad option %c %s", ch, optarg); 341 usage(); 342 break; 343 case 'b': /* burst */ 344 burst = atoi(optarg); 345 break; 346 case 'i': /* interface */ 347 if (ifa == NULL) --- 8 unchanged lines hidden (view full) --- 356 verbose++; 357 break; 358 case 'w': 359 wait_link = atoi(optarg); 360 break; 361 } 362 363 } | 170 D("bad option %c %s", ch, optarg); 171 usage(); 172 break; 173 case 'b': /* burst */ 174 burst = atoi(optarg); 175 break; 176 case 'i': /* interface */ 177 if (ifa == NULL) --- 8 unchanged lines hidden (view full) --- 186 verbose++; 187 break; 188 case 'w': 189 wait_link = atoi(optarg); 190 break; 191 } 192 193 } |
194 |
|
364 argc -= optind; 365 argv += optind; 366 367 if (argc > 1) 368 ifa = argv[1]; 369 if (argc > 2) 370 ifb = argv[2]; 371 if (argc > 3) --- 17 unchanged lines hidden (view full) --- 389 me[1].ifname = ifb; 390 if (!strcmp(ifa, ifb)) { 391 D("same interface, endpoint 0 goes to host"); 392 i = NETMAP_SW_RING; 393 } else { 394 /* two different interfaces. Take all rings on if1 */ 395 i = 0; // all hw rings 396 } | 195 argc -= optind; 196 argv += optind; 197 198 if (argc > 1) 199 ifa = argv[1]; 200 if (argc > 2) 201 ifb = argv[2]; 202 if (argc > 3) --- 17 unchanged lines hidden (view full) --- 220 me[1].ifname = ifb; 221 if (!strcmp(ifa, ifb)) { 222 D("same interface, endpoint 0 goes to host"); 223 i = NETMAP_SW_RING; 224 } else { 225 /* two different interfaces. Take all rings on if1 */ 226 i = 0; // all hw rings 227 } |
397 if (netmap_open(me, i)) | 228 if (netmap_open(me, i, 1)) |
398 return (1); 399 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ | 229 return (1); 230 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ |
400 if (netmap_open(me+1, 0)) | 231 if (netmap_open(me+1, 0, 1)) |
401 return (1); 402 | 232 return (1); 233 |
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; 409 } 410 me[0].if_flags |= IFF_PPROMISC; 411 do_ioctl(me, SIOCSIFFLAGS); 412 413 do_ioctl(me+1, SIOCGIFFLAGS); 414 me[1].if_flags |= IFF_PPROMISC; 415 do_ioctl(me+1, SIOCSIFFLAGS); 416 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); 422 } 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; 427 } 428 do_ioctl(me+1, SIOCSIFFLAGS); 429 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); 434 | |
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); 440 } 441 442 D("Wait %d secs for link to come up...", wait_link); 443 sleep(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); 447 448 /* main loop */ 449 signal(SIGINT, sigint_h); 450 while (!do_abort) { 451 int n0, n1, ret; 452 pollfd[0].events = pollfd[1].events = 0; 453 pollfd[0].revents = pollfd[1].revents = 0; | 234 /* setup poll(2) variables. */ 235 memset(pollfd, 0, sizeof(pollfd)); 236 for (i = 0; i < 2; i++) { 237 pollfd[i].fd = me[i].fd; 238 pollfd[i].events = (POLLIN); 239 } 240 241 D("Wait %d secs for link to come up...", wait_link); 242 sleep(wait_link); 243 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.", 244 me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings, 245 me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings); 246 247 /* main loop */ 248 signal(SIGINT, sigint_h); 249 while (!do_abort) { 250 int n0, n1, ret; 251 pollfd[0].events = pollfd[1].events = 0; 252 pollfd[0].revents = pollfd[1].revents = 0; |
454 n0 = howmany(me, 0); 455 n1 = howmany(me + 1, 0); | 253 n0 = pkt_queued(me, 0); 254 n1 = pkt_queued(me + 1, 0); |
456 if (n0) 457 pollfd[1].events |= POLLOUT; 458 else 459 pollfd[0].events |= POLLIN; 460 if (n1) 461 pollfd[0].events |= POLLOUT; 462 else 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", 469 pollfd[0].events, 470 pollfd[0].revents, | 255 if (n0) 256 pollfd[1].events |= POLLOUT; 257 else 258 pollfd[0].events |= POLLIN; 259 if (n1) 260 pollfd[0].events |= POLLOUT; 261 else 262 pollfd[1].events |= POLLIN; 263 ret = poll(pollfd, 2, 2500); 264 if (ret <= 0 || verbose) 265 D("poll %s [0] ev %x %x rx %d@%d tx %d," 266 " [1] ev %x %x rx %d@%d tx %d", 267 ret <= 0 ? "timeout" : "ok", 268 pollfd[0].events, 269 pollfd[0].revents, |
471 howmany(me, 0), | 270 pkt_queued(me, 0), |
472 me[0].rx->cur, | 271 me[0].rx->cur, |
473 howmany(me, 1), | 272 pkt_queued(me, 1), |
474 pollfd[1].events, 475 pollfd[1].revents, | 273 pollfd[1].events, 274 pollfd[1].revents, |
476 howmany(me+1, 0), | 275 pkt_queued(me+1, 0), |
477 me[1].rx->cur, | 276 me[1].rx->cur, |
478 howmany(me+1, 1) | 277 pkt_queued(me+1, 1) |
479 ); 480 if (ret < 0) 481 continue; 482 if (pollfd[0].revents & POLLERR) { 483 D("error on fd0, rxcur %d@%d", 484 me[0].rx->avail, me[0].rx->cur); 485 } 486 if (pollfd[1].revents & POLLERR) { --- 20 unchanged lines hidden --- | 278 ); 279 if (ret < 0) 280 continue; 281 if (pollfd[0].revents & POLLERR) { 282 D("error on fd0, rxcur %d@%d", 283 me[0].rx->avail, me[0].rx->cur); 284 } 285 if (pollfd[1].revents & POLLERR) { --- 20 unchanged lines hidden --- |