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