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$ 10 */ 11 12#include "nm_util.h" 13 14 15int verbose = 0; 16 17char *version = "$Id$"; 18 19static int do_abort = 0; 20 21static void 22sigint_h(int sig) 23{ 24 (void)sig; /* UNUSED */ 25 do_abort = 1; 26 signal(SIGINT, SIG_DFL); 27} 28 29 30/* 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 39 /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */ 40 if (rxring->flags || txring->flags) 41 D("%s rxflags %x txflags %x", 42 msg, rxring->flags, txring->flags); 43 j = rxring->cur; /* RX */ 44 k = txring->cur; /* TX */ 45 if (rxring->avail < limit) 46 limit = rxring->avail; 47 if (txring->avail < limit) 48 limit = txring->avail; 49 m = limit; 50 while (limit-- > 0) { 51 struct netmap_slot *rs = &rxring->slot[j]; 52 struct netmap_slot *ts = &txring->slot[k]; 53#ifdef NO_SWAP 54 char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); 55 char *txbuf = NETMAP_BUF(txring, ts->buf_idx); 56#else 57 uint32_t pkt; 58#endif 59 60 /* swap packets */ 61 if (ts->buf_idx < 2 || rs->buf_idx < 2) { 62 D("wrong index rx[%d] = %d -> tx[%d] = %d", 63 j, rs->buf_idx, k, ts->buf_idx); 64 sleep(2); 65 } 66#ifndef NO_SWAP 67 pkt = ts->buf_idx; 68 ts->buf_idx = rs->buf_idx; 69 rs->buf_idx = pkt; 70#endif 71 /* copy the packet length. */ 72 if (rs->len < 14 || rs->len > 2048) 73 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k); 74 else if (verbose > 1) 75 D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k); 76 ts->len = rs->len; 77#ifdef NO_SWAP 78 pkt_copy(rxbuf, txbuf, ts->len); 79#else 80 /* report the buffer change. */ 81 ts->flags |= NS_BUF_CHANGED; 82 rs->flags |= NS_BUF_CHANGED; 83#endif /* NO_SWAP */ 84 j = NETMAP_RING_NEXT(rxring, j); 85 k = NETMAP_RING_NEXT(txring, k); 86 } 87 rxring->avail -= m; 88 txring->avail -= m; 89 rxring->cur = j; 90 txring->cur = k; 91 if (verbose && m > 0) 92 D("%s sent %d packets to %p", msg, m, txring); 93 94 return (m); 95} 96 97/* move packts from src to destination */ 98static int 99move(struct my_ring *src, struct my_ring *dst, u_int limit) 100{ 101 struct netmap_ring *txring, *rxring; 102 u_int m = 0, si = src->begin, di = dst->begin; 103 const char *msg = (src->queueid & NETMAP_SW_RING) ? 104 "host->net" : "net->host"; 105 106 while (si < src->end && di < dst->end) { 107 rxring = NETMAP_RXRING(src->nifp, si); 108 txring = NETMAP_TXRING(dst->nifp, di); 109 ND("txring %p rxring %p", txring, rxring); 110 if (rxring->avail == 0) { 111 si++; 112 continue; 113 } 114 if (txring->avail == 0) { 115 di++; 116 continue; 117 } 118 m += process_rings(rxring, txring, limit, msg); 119 } 120 121 return (m); 122} 123 124/* 125 * how many packets on this set of queues ? 126 */ 127static int 128pkt_queued(struct my_ring *me, int tx) 129{ 130 u_int i, tot = 0; 131 132 ND("me %p begin %d end %d", me, me->begin, me->end); 133 for (i = me->begin; i < me->end; i++) { 134 struct netmap_ring *ring = tx ? 135 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); 136 tot += ring->avail; 137 } 138 if (0 && verbose && tot && !tx) 139 D("ring %s %s %s has %d avail at %d", 140 me->ifname, tx ? "tx": "rx", 141 me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ? 142 "host":"net", 143 tot, NETMAP_TXRING(me->nifp, me->begin)->cur); 144 return tot; 145} 146 147static void 148usage(void) 149{ 150 fprintf(stderr, 151 "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [iface]\n"); 152 exit(1); 153} 154 155/* 156 * bridge [-v] if1 [if2] 157 * 158 * If only one name, or the two interfaces are the same, 159 * bridges userland and the adapter. Otherwise bridge 160 * two intefaces. 161 */ 162int 163main(int argc, char **argv) 164{ 165 struct pollfd pollfd[2]; 166 int i, ch; 167 u_int burst = 1024, wait_link = 4; 168 struct my_ring me[2]; 169 char *ifa = NULL, *ifb = NULL; 170 171 fprintf(stderr, "%s %s built %s %s\n", 172 argv[0], version, __DATE__, __TIME__); 173 174 bzero(me, sizeof(me)); 175 176 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) { 177 switch (ch) { 178 default: 179 D("bad option %c %s", ch, optarg); 180 usage(); 181 break; 182 case 'b': /* burst */ 183 burst = atoi(optarg); 184 break; 185 case 'i': /* interface */ 186 if (ifa == NULL) 187 ifa = optarg; 188 else if (ifb == NULL) 189 ifb = optarg; 190 else 191 D("%s ignored, already have 2 interfaces", 192 optarg); 193 break; 194 case 'v': 195 verbose++; 196 break; 197 case 'w': 198 wait_link = atoi(optarg); 199 break; 200 } 201 202 } 203 204 argc -= optind; 205 argv += optind; 206 207 if (argc > 1) 208 ifa = argv[1]; 209 if (argc > 2) 210 ifb = argv[2]; 211 if (argc > 3) 212 burst = atoi(argv[3]); 213 if (!ifb) 214 ifb = ifa; 215 if (!ifa) { 216 D("missing interface"); 217 usage(); 218 } 219 if (burst < 1 || burst > 8192) { 220 D("invalid burst %d, set to 1024", burst); 221 burst = 1024; 222 } 223 if (wait_link > 100) { 224 D("invalid wait_link %d, set to 4", wait_link); 225 wait_link = 4; 226 } 227 /* setup netmap interface #1. */ 228 me[0].ifname = ifa; 229 me[1].ifname = ifb; 230 if (!strcmp(ifa, ifb)) { 231 D("same interface, endpoint 0 goes to host"); 232 i = NETMAP_SW_RING; 233 } else { 234 /* two different interfaces. Take all rings on if1 */ 235 i = 0; // all hw rings 236 } 237 if (netmap_open(me, i, 1)) 238 return (1); 239 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ 240 if (netmap_open(me+1, 0, 1)) 241 return (1); 242 243 /* setup poll(2) variables. */ 244 memset(pollfd, 0, sizeof(pollfd)); 245 for (i = 0; i < 2; i++) { 246 pollfd[i].fd = me[i].fd; 247 pollfd[i].events = (POLLIN); 248 } 249 250 D("Wait %d secs for link to come up...", wait_link); 251 sleep(wait_link); 252 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.", 253 me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings, 254 me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings); 255 256 /* main loop */ 257 signal(SIGINT, sigint_h); 258 while (!do_abort) { 259 int n0, n1, ret; 260 pollfd[0].events = pollfd[1].events = 0; 261 pollfd[0].revents = pollfd[1].revents = 0; 262 n0 = pkt_queued(me, 0); 263 n1 = pkt_queued(me + 1, 0); 264 if (n0) 265 pollfd[1].events |= POLLOUT; 266 else 267 pollfd[0].events |= POLLIN; 268 if (n1) 269 pollfd[0].events |= POLLOUT; 270 else 271 pollfd[1].events |= POLLIN; 272 ret = poll(pollfd, 2, 2500); 273 if (ret <= 0 || verbose) 274 D("poll %s [0] ev %x %x rx %d@%d tx %d," 275 " [1] ev %x %x rx %d@%d tx %d", 276 ret <= 0 ? "timeout" : "ok", 277 pollfd[0].events, 278 pollfd[0].revents, 279 pkt_queued(me, 0), 280 me[0].rx->cur, 281 pkt_queued(me, 1), 282 pollfd[1].events, 283 pollfd[1].revents, 284 pkt_queued(me+1, 0), 285 me[1].rx->cur, 286 pkt_queued(me+1, 1) 287 ); 288 if (ret < 0) 289 continue; 290 if (pollfd[0].revents & POLLERR) { 291 D("error on fd0, rxcur %d@%d", 292 me[0].rx->avail, me[0].rx->cur); 293 } 294 if (pollfd[1].revents & POLLERR) { 295 D("error on fd1, rxcur %d@%d", 296 me[1].rx->avail, me[1].rx->cur); 297 } 298 if (pollfd[0].revents & POLLOUT) { 299 move(me + 1, me, burst); 300 // XXX we don't need the ioctl */ 301 // ioctl(me[0].fd, NIOCTXSYNC, NULL); 302 } 303 if (pollfd[1].revents & POLLOUT) { 304 move(me, me + 1, burst); 305 // XXX we don't need the ioctl */ 306 // ioctl(me[1].fd, NIOCTXSYNC, NULL); 307 } 308 } 309 D("exiting"); 310 netmap_close(me + 1); 311 netmap_close(me + 0); 312 313 return (0); 314} 315