2 * (C) 2011-2014 Luigi Rizzo, Matteo Landi
6 * A netmap application to bridge two network interfaces,
7 * or one interface and the host stack.
12 #include <libnetmap.h>
16 #include <sys/ioctl.h>
20 static int verbose = 0;
22 static int do_abort = 0;
23 static int zerocopy = 1; /* enable zerocopy if possible */
28 (void)sig; /* UNUSED */
30 signal(SIGINT, SIG_DFL);
35 * How many slots do we (user application) have on this
39 rx_slots_avail(struct nmport_d *d)
43 for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
44 tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
51 tx_slots_avail(struct nmport_d *d)
55 for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
56 tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
63 * Move up to 'limit' pkts from rxring to txring, swapping buffers
64 * if zerocopy is possible. Otherwise fall back on packet copying.
67 rings_move(struct netmap_ring *rxring, struct netmap_ring *txring,
68 u_int limit, const char *msg)
72 /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */
73 if (rxring->flags || txring->flags)
74 D("%s rxflags %x txflags %x",
75 msg, rxring->flags, txring->flags);
76 j = rxring->head; /* RX */
77 k = txring->head; /* TX */
78 m = nm_ring_space(rxring);
81 m = nm_ring_space(txring);
86 struct netmap_slot *rs = &rxring->slot[j];
87 struct netmap_slot *ts = &txring->slot[k];
90 if (ts->buf_idx < 2 || rs->buf_idx < 2) {
91 RD(2, "wrong index rxr[%d] = %d -> txr[%d] = %d",
92 j, rs->buf_idx, k, ts->buf_idx);
95 /* copy the packet length. */
96 if (rs->len > rxring->nr_buf_size) {
97 RD(2, "%s: invalid len %u, rxr[%d] -> txr[%d]",
100 } else if (verbose > 1) {
101 D("%s: fwd len %u, rx[%d] -> tx[%d]",
106 uint32_t pkt = ts->buf_idx;
107 ts->buf_idx = rs->buf_idx;
109 /* report the buffer change. */
110 ts->flags |= NS_BUF_CHANGED;
111 rs->flags |= NS_BUF_CHANGED;
112 /* copy the NS_MOREFRAG */
113 rs->flags = (rs->flags & ~NS_MOREFRAG) | (ts->flags & NS_MOREFRAG);
115 char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx);
116 char *txbuf = NETMAP_BUF(txring, ts->buf_idx);
117 nm_pkt_copy(rxbuf, txbuf, ts->len);
119 j = nm_ring_next(rxring, j);
120 k = nm_ring_next(txring, k);
122 rxring->head = rxring->cur = j;
123 txring->head = txring->cur = k;
124 if (verbose && m > 0)
125 D("%s fwd %d packets: rxring %u --> txring %u",
126 msg, m, rxring->ringid, txring->ringid);
131 /* Move packets from source port to destination port. */
133 ports_move(struct nmport_d *src, struct nmport_d *dst, u_int limit,
136 struct netmap_ring *txring, *rxring;
137 u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring;
139 while (si <= src->last_rx_ring && di <= dst->last_tx_ring) {
140 rxring = NETMAP_RXRING(src->nifp, si);
141 txring = NETMAP_TXRING(dst->nifp, di);
142 if (nm_ring_empty(rxring)) {
146 if (nm_ring_empty(txring)) {
150 m += rings_move(rxring, txring, limit, msg);
161 "netmap bridge program: forward packets between two "
163 " usage(1): bridge [-v] [-i ifa] [-i ifb] [-b burst] "
164 "[-w wait_time] [-L]\n"
165 " usage(2): bridge [-v] [-w wait_time] [-L] "
166 "[ifa [ifb [burst]]]\n"
168 " ifa and ifb are specified using the nm_open() syntax.\n"
169 " When ifb is missing (or is equal to ifa), bridge will\n"
170 " forward between between ifa and the host stack if -L\n"
171 " is not specified, otherwise loopback traffic on ifa.\n"
173 " example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n"
175 " If ifa and ifb are two interfaces, they must be in\n"
176 " promiscuous mode. Otherwise, if bridging with the \n"
177 " host stack, the interface must have the offloads \n"
184 * bridge [-v] if1 [if2]
186 * If only one name, or the two interfaces are the same,
187 * bridges userland and the adapter. Otherwise bridge
191 main(int argc, char **argv)
193 char msg_a2b[128], msg_b2a[128];
194 struct pollfd pollfd[2];
195 u_int burst = 1024, wait_link = 4;
196 struct nmport_d *pa = NULL, *pb = NULL;
197 char *ifa = NULL, *ifb = NULL;
198 char ifabuf[64] = { 0 };
199 int pa_sw_rings, pb_sw_rings;
203 fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
205 while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) {
208 D("bad option %c %s", ch, optarg);
213 case 'b': /* burst */
214 burst = atoi(optarg);
216 case 'i': /* interface */
219 else if (ifb == NULL)
222 D("%s ignored, already have 2 interfaces",
226 zerocopy = 0; /* do not zerocopy */
232 wait_link = atoi(optarg);
249 burst = atoi(argv[2]);
253 D("missing interface");
256 if (burst < 1 || burst > 8192) {
257 D("invalid burst %d, set to 1024", burst);
260 if (wait_link > 100) {
261 D("invalid wait_link %d, set to 4", wait_link);
264 if (!strcmp(ifa, ifb)) {
266 D("same interface, endpoint 0 goes to host");
267 snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa);
270 D("same interface, loopbacking traffic");
273 /* two different interfaces. Take all rings on if1 */
275 pa = nmport_open(ifa);
277 D("cannot open %s", ifa);
280 /* try to reuse the mmap() of the first interface, if possible */
281 pb = nmport_open(ifb);
283 D("cannot open %s", ifb);
287 zerocopy = zerocopy && (pa->mem == pb->mem);
288 D("------- zerocopy %ssupported", zerocopy ? "" : "NOT ");
290 /* setup poll(2) array */
291 memset(pollfd, 0, sizeof(pollfd));
292 pollfd[0].fd = pa->fd;
293 pollfd[1].fd = pb->fd;
295 D("Wait %d secs for link to come up...", wait_link);
297 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
298 pa->hdr.nr_name, pa->first_rx_ring, pa->reg.nr_rx_rings,
299 pb->hdr.nr_name, pb->first_rx_ring, pb->reg.nr_rx_rings);
301 pa_sw_rings = (pa->reg.nr_mode == NR_REG_SW ||
302 pa->reg.nr_mode == NR_REG_ONE_SW);
303 pb_sw_rings = (pb->reg.nr_mode == NR_REG_SW ||
304 pb->reg.nr_mode == NR_REG_ONE_SW);
306 snprintf(msg_a2b, sizeof(msg_a2b), "%s:%s --> %s:%s",
307 pa->hdr.nr_name, pa_sw_rings ? "host" : "nic",
308 pb->hdr.nr_name, pb_sw_rings ? "host" : "nic");
310 snprintf(msg_b2a, sizeof(msg_b2a), "%s:%s --> %s:%s",
311 pb->hdr.nr_name, pb_sw_rings ? "host" : "nic",
312 pa->hdr.nr_name, pa_sw_rings ? "host" : "nic");
315 signal(SIGINT, sigint_h);
318 pollfd[0].events = pollfd[1].events = 0;
319 pollfd[0].revents = pollfd[1].revents = 0;
320 n0 = rx_slots_avail(pa);
321 n1 = rx_slots_avail(pb);
322 #if defined(_WIN32) || defined(BUSYWAIT)
324 ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
325 pollfd[1].revents = POLLOUT;
327 ioctl(pollfd[0].fd, NIOCRXSYNC, NULL);
330 ioctl(pollfd[0].fd, NIOCTXSYNC, NULL);
331 pollfd[0].revents = POLLOUT;
333 ioctl(pollfd[1].fd, NIOCRXSYNC, NULL);
338 pollfd[1].events |= POLLOUT;
340 pollfd[0].events |= POLLIN;
342 pollfd[0].events |= POLLOUT;
344 pollfd[1].events |= POLLIN;
346 /* poll() also cause kernel to txsync/rxsync the NICs */
347 ret = poll(pollfd, 2, 2500);
348 #endif /* defined(_WIN32) || defined(BUSYWAIT) */
349 if (ret <= 0 || verbose)
350 D("poll %s [0] ev %x %x rx %d@%d tx %d,"
351 " [1] ev %x %x rx %d@%d tx %d",
352 ret <= 0 ? "timeout" : "ok",
356 NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->head,
361 NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->head,
366 if (pollfd[0].revents & POLLERR) {
367 struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring);
368 D("error on fd0, rx [%d,%d,%d)",
369 rx->head, rx->cur, rx->tail);
371 if (pollfd[1].revents & POLLERR) {
372 struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring);
373 D("error on fd1, rx [%d,%d,%d)",
374 rx->head, rx->cur, rx->tail);
376 if (pollfd[0].revents & POLLOUT)
377 ports_move(pb, pa, burst, msg_b2a);
379 if (pollfd[1].revents & POLLOUT)
380 ports_move(pa, pb, burst, msg_a2b);
383 * We don't need ioctl(NIOCTXSYNC) on the two file descriptors.
384 * here. The kernel will txsync on next poll().