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$ 10 */ 11 12 #include <stdio.h> 13 #define NETMAP_WITH_LIBS 14 #include <net/netmap_user.h> 15 #include <sys/poll.h> 16 17 int verbose = 0; 18 19 static int do_abort = 0; 20 static int zerocopy = 1; /* enable zerocopy if possible */ 21 22 static void 23 sigint_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 */ 34 int 35 pkt_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 */ 54 static int 55 process_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 RD(5, "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 > rxring->nr_buf_size) { 85 RD(5, "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 /* copy the NS_MOREFRAG */ 99 rs->flags = (rs->flags & ~NS_MOREFRAG) | (ts->flags & NS_MOREFRAG); 100 } else { 101 char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); 102 char *txbuf = NETMAP_BUF(txring, ts->buf_idx); 103 nm_pkt_copy(rxbuf, txbuf, ts->len); 104 } 105 j = nm_ring_next(rxring, j); 106 k = nm_ring_next(txring, k); 107 } 108 rxring->head = rxring->cur = j; 109 txring->head = txring->cur = k; 110 if (verbose && m > 0) 111 D("%s sent %d packets to %p", msg, m, txring); 112 113 return (m); 114 } 115 116 /* move packts from src to destination */ 117 static int 118 move(struct nm_desc *src, struct nm_desc *dst, u_int limit) 119 { 120 struct netmap_ring *txring, *rxring; 121 u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring; 122 const char *msg = (src->req.nr_flags == NR_REG_SW) ? 123 "host->net" : "net->host"; 124 125 while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { 126 rxring = NETMAP_RXRING(src->nifp, si); 127 txring = NETMAP_TXRING(dst->nifp, di); 128 ND("txring %p rxring %p", txring, rxring); 129 if (nm_ring_empty(rxring)) { 130 si++; 131 continue; 132 } 133 if (nm_ring_empty(txring)) { 134 di++; 135 continue; 136 } 137 m += process_rings(rxring, txring, limit, msg); 138 } 139 140 return (m); 141 } 142 143 144 static void 145 usage(void) 146 { 147 fprintf(stderr, 148 "netmap bridge program: forward packets between two " 149 "network interfaces\n" 150 " usage(1): bridge [-v] [-i ifa] [-i ifb] [-b burst] " 151 "[-w wait_time] [-L]\n" 152 " usage(2): bridge [-v] [-w wait_time] [-L] " 153 "[ifa [ifb [burst]]]\n" 154 "\n" 155 " ifa and ifb are specified using the nm_open() syntax.\n" 156 " When ifb is missing (or is equal to ifa), bridge will\n" 157 " forward between between ifa and the host stack if -L\n" 158 " is not specified, otherwise loopback traffic on ifa.\n" 159 "\n" 160 " example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n" 161 ); 162 exit(1); 163 } 164 165 /* 166 * bridge [-v] if1 [if2] 167 * 168 * If only one name, or the two interfaces are the same, 169 * bridges userland and the adapter. Otherwise bridge 170 * two intefaces. 171 */ 172 int 173 main(int argc, char **argv) 174 { 175 struct pollfd pollfd[2]; 176 int ch; 177 u_int burst = 1024, wait_link = 4; 178 struct nm_desc *pa = NULL, *pb = NULL; 179 char *ifa = NULL, *ifb = NULL; 180 char ifabuf[64] = { 0 }; 181 int loopback = 0; 182 183 fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__); 184 185 while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) { 186 switch (ch) { 187 default: 188 D("bad option %c %s", ch, optarg); 189 /* fallthrough */ 190 case 'h': 191 usage(); 192 break; 193 case 'b': /* burst */ 194 burst = atoi(optarg); 195 break; 196 case 'i': /* interface */ 197 if (ifa == NULL) 198 ifa = optarg; 199 else if (ifb == NULL) 200 ifb = optarg; 201 else 202 D("%s ignored, already have 2 interfaces", 203 optarg); 204 break; 205 case 'c': 206 zerocopy = 0; /* do not zerocopy */ 207 break; 208 case 'v': 209 verbose++; 210 break; 211 case 'w': 212 wait_link = atoi(optarg); 213 break; 214 case 'L': 215 loopback = 1; 216 break; 217 } 218 219 } 220 221 argc -= optind; 222 argv += optind; 223 224 if (argc > 0) 225 ifa = argv[0]; 226 if (argc > 1) 227 ifb = argv[1]; 228 if (argc > 2) 229 burst = atoi(argv[2]); 230 if (!ifb) 231 ifb = ifa; 232 if (!ifa) { 233 D("missing interface"); 234 usage(); 235 } 236 if (burst < 1 || burst > 8192) { 237 D("invalid burst %d, set to 1024", burst); 238 burst = 1024; 239 } 240 if (wait_link > 100) { 241 D("invalid wait_link %d, set to 4", wait_link); 242 wait_link = 4; 243 } 244 if (!strcmp(ifa, ifb)) { 245 if (!loopback) { 246 D("same interface, endpoint 0 goes to host"); 247 snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa); 248 ifa = ifabuf; 249 } else { 250 D("same interface, loopbacking traffic"); 251 } 252 } else { 253 /* two different interfaces. Take all rings on if1 */ 254 } 255 pa = nm_open(ifa, NULL, 0, NULL); 256 if (pa == NULL) { 257 D("cannot open %s", ifa); 258 return (1); 259 } 260 /* try to reuse the mmap() of the first interface, if possible */ 261 pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa); 262 if (pb == NULL) { 263 D("cannot open %s", ifb); 264 nm_close(pa); 265 return (1); 266 } 267 zerocopy = zerocopy && (pa->mem == pb->mem); 268 D("------- zerocopy %ssupported", zerocopy ? "" : "NOT "); 269 270 /* setup poll(2) array */ 271 memset(pollfd, 0, sizeof(pollfd)); 272 pollfd[0].fd = pa->fd; 273 pollfd[1].fd = pb->fd; 274 275 D("Wait %d secs for link to come up...", wait_link); 276 sleep(wait_link); 277 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.", 278 pa->req.nr_name, pa->first_rx_ring, pa->req.nr_rx_rings, 279 pb->req.nr_name, pb->first_rx_ring, pb->req.nr_rx_rings); 280 281 /* main loop */ 282 signal(SIGINT, sigint_h); 283 while (!do_abort) { 284 int n0, n1, ret; 285 pollfd[0].events = pollfd[1].events = 0; 286 pollfd[0].revents = pollfd[1].revents = 0; 287 n0 = pkt_queued(pa, 0); 288 n1 = pkt_queued(pb, 0); 289 #if defined(_WIN32) || defined(BUSYWAIT) 290 if (n0) { 291 ioctl(pollfd[1].fd, NIOCTXSYNC, NULL); 292 pollfd[1].revents = POLLOUT; 293 } else { 294 ioctl(pollfd[0].fd, NIOCRXSYNC, NULL); 295 } 296 if (n1) { 297 ioctl(pollfd[0].fd, NIOCTXSYNC, NULL); 298 pollfd[0].revents = POLLOUT; 299 } else { 300 ioctl(pollfd[1].fd, NIOCRXSYNC, NULL); 301 } 302 ret = 1; 303 #else 304 if (n0) 305 pollfd[1].events |= POLLOUT; 306 else 307 pollfd[0].events |= POLLIN; 308 if (n1) 309 pollfd[0].events |= POLLOUT; 310 else 311 pollfd[1].events |= POLLIN; 312 313 /* poll() also cause kernel to txsync/rxsync the NICs */ 314 ret = poll(pollfd, 2, 2500); 315 #endif /* defined(_WIN32) || defined(BUSYWAIT) */ 316 if (ret <= 0 || verbose) 317 D("poll %s [0] ev %x %x rx %d@%d tx %d," 318 " [1] ev %x %x rx %d@%d tx %d", 319 ret <= 0 ? "timeout" : "ok", 320 pollfd[0].events, 321 pollfd[0].revents, 322 pkt_queued(pa, 0), 323 NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->cur, 324 pkt_queued(pa, 1), 325 pollfd[1].events, 326 pollfd[1].revents, 327 pkt_queued(pb, 0), 328 NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->cur, 329 pkt_queued(pb, 1) 330 ); 331 if (ret < 0) 332 continue; 333 if (pollfd[0].revents & POLLERR) { 334 struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring); 335 D("error on fd0, rx [%d,%d,%d)", 336 rx->head, rx->cur, rx->tail); 337 } 338 if (pollfd[1].revents & POLLERR) { 339 struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring); 340 D("error on fd1, rx [%d,%d,%d)", 341 rx->head, rx->cur, rx->tail); 342 } 343 if (pollfd[0].revents & POLLOUT) 344 move(pb, pa, burst); 345 346 if (pollfd[1].revents & POLLOUT) 347 move(pa, pb, burst); 348 349 /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here, 350 * kernel will txsync on next poll(). */ 351 } 352 nm_close(pb); 353 nm_close(pa); 354 355 return (0); 356 } 357