diff --git a/tools/tools/netmap/bridge.c b/tools/tools/netmap/bridge.c index a10142e692c3..af8c2847130a 100644 --- a/tools/tools/netmap/bridge.c +++ b/tools/tools/netmap/bridge.c @@ -3,19 +3,19 @@ * * BSD license * - * A netmap client to bridge two network interfaces - * (or one interface and the host stack). + * A netmap application to bridge two network interfaces, + * or one interface and the host stack. * * $FreeBSD$ */ +#include +#include #include #include #include -#include #include #include -#include static int verbose = 0; @@ -32,30 +32,39 @@ sigint_h(int sig) /* - * how many packets on this set of queues ? + * How many slots do we (user application) have on this + * set of queues ? */ static int -pkt_queued(struct nmport_d *d, int tx) +rx_slots_avail(struct nmport_d *d) { u_int i, tot = 0; - if (tx) { - for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) { - tot += nm_ring_space(NETMAP_TXRING(d->nifp, i)); - } - } else { - for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) { - tot += nm_ring_space(NETMAP_RXRING(d->nifp, i)); - } + for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) { + tot += nm_ring_space(NETMAP_RXRING(d->nifp, i)); } + + return tot; +} + +static int +tx_slots_avail(struct nmport_d *d) +{ + u_int i, tot = 0; + + for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) { + tot += nm_ring_space(NETMAP_TXRING(d->nifp, i)); + } + return tot; } /* - * move up to 'limit' pkts from rxring to txring swapping buffers. + * Move up to 'limit' pkts from rxring to txring, swapping buffers + * if zerocopy is possible. Otherwise fall back on packet copying. */ static int -process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, +rings_move(struct netmap_ring *rxring, struct netmap_ring *txring, u_int limit, const char *msg) { u_int j, k, m = 0; @@ -63,7 +72,7 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */ if (rxring->flags || txring->flags) D("%s rxflags %x txflags %x", - msg, rxring->flags, txring->flags); + msg, rxring->flags, txring->flags); j = rxring->head; /* RX */ k = txring->head; /* TX */ m = nm_ring_space(rxring); @@ -79,16 +88,18 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, /* swap packets */ if (ts->buf_idx < 2 || rs->buf_idx < 2) { - RD(5, "wrong index rx[%d] = %d -> tx[%d] = %d", - j, rs->buf_idx, k, ts->buf_idx); + RD(2, "wrong index rxr[%d] = %d -> txr[%d] = %d", + j, rs->buf_idx, k, ts->buf_idx); sleep(2); } /* copy the packet length. */ if (rs->len > rxring->nr_buf_size) { - RD(5, "wrong len %d rx[%d] -> tx[%d]", rs->len, j, k); + RD(2, "%s: invalid len %u, rxr[%d] -> txr[%d]", + msg, rs->len, j, k); rs->len = 0; } else if (verbose > 1) { - D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k); + D("%s: fwd len %u, rx[%d] -> tx[%d]", + msg, rs->len, j, k); } ts->len = rs->len; if (zerocopy) { @@ -111,24 +122,23 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, rxring->head = rxring->cur = j; txring->head = txring->cur = k; if (verbose && m > 0) - D("%s sent %d packets to %p", msg, m, txring); + D("%s fwd %d packets: rxring %u --> txring %u", + msg, m, rxring->ringid, txring->ringid); return (m); } -/* move packts from src to destination */ +/* Move packets from source port to destination port. */ static int -move(struct nmport_d *src, struct nmport_d *dst, u_int limit) +ports_move(struct nmport_d *src, struct nmport_d *dst, u_int limit, + const char *msg) { struct netmap_ring *txring, *rxring; u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring; - const char *msg = (src->reg.nr_flags == NR_REG_SW) ? - "host->net" : "net->host"; while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); - ND("txring %p rxring %p", txring, rxring); if (nm_ring_empty(rxring)) { si++; continue; @@ -137,7 +147,7 @@ move(struct nmport_d *src, struct nmport_d *dst, u_int limit) di++; continue; } - m += process_rings(rxring, txring, limit, msg); + m += rings_move(rxring, txring, limit, msg); } return (m); @@ -149,7 +159,7 @@ usage(void) { fprintf(stderr, "netmap bridge program: forward packets between two " - "network interfaces\n" + "netmap ports\n" " usage(1): bridge [-v] [-i ifa] [-i ifb] [-b burst] " "[-w wait_time] [-L]\n" " usage(2): bridge [-v] [-w wait_time] [-L] " @@ -161,6 +171,11 @@ usage(void) " is not specified, otherwise loopback traffic on ifa.\n" "\n" " example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n" + "\n" + " If ifa and ifb are two interfaces, they must be in\n" + " promiscuous mode. Otherwise, if bridging with the \n" + " host stack, the interface must have the offloads \n" + " disabled.\n" ); exit(1); } @@ -175,13 +190,15 @@ usage(void) int main(int argc, char **argv) { + char msg_a2b[128], msg_b2a[128]; struct pollfd pollfd[2]; - int ch; u_int burst = 1024, wait_link = 4; struct nmport_d *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; char ifabuf[64] = { 0 }; + int pa_sw_rings, pb_sw_rings; int loopback = 0; + int ch; fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__); @@ -281,14 +298,27 @@ main(int argc, char **argv) pa->hdr.nr_name, pa->first_rx_ring, pa->reg.nr_rx_rings, pb->hdr.nr_name, pb->first_rx_ring, pb->reg.nr_rx_rings); + pa_sw_rings = (pa->reg.nr_mode == NR_REG_SW || + pa->reg.nr_mode == NR_REG_ONE_SW); + pb_sw_rings = (pb->reg.nr_mode == NR_REG_SW || + pb->reg.nr_mode == NR_REG_ONE_SW); + + snprintf(msg_a2b, sizeof(msg_a2b), "%s:%s --> %s:%s", + pa->hdr.nr_name, pa_sw_rings ? "host" : "nic", + pb->hdr.nr_name, pb_sw_rings ? "host" : "nic"); + + snprintf(msg_b2a, sizeof(msg_b2a), "%s:%s --> %s:%s", + pb->hdr.nr_name, pb_sw_rings ? "host" : "nic", + pa->hdr.nr_name, pa_sw_rings ? "host" : "nic"); + /* main loop */ signal(SIGINT, sigint_h); while (!do_abort) { int n0, n1, ret; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; - n0 = pkt_queued(pa, 0); - n1 = pkt_queued(pb, 0); + n0 = rx_slots_avail(pa); + n1 = rx_slots_avail(pb); #if defined(_WIN32) || defined(BUSYWAIT) if (n0) { ioctl(pollfd[1].fd, NIOCTXSYNC, NULL); @@ -322,35 +352,37 @@ main(int argc, char **argv) ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, - pkt_queued(pa, 0), + rx_slots_avail(pa), NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->head, - pkt_queued(pa, 1), + tx_slots_avail(pa), pollfd[1].events, pollfd[1].revents, - pkt_queued(pb, 0), + rx_slots_avail(pb), NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->head, - pkt_queued(pb, 1) + tx_slots_avail(pb) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring); D("error on fd0, rx [%d,%d,%d)", - rx->head, rx->cur, rx->tail); + rx->head, rx->cur, rx->tail); } if (pollfd[1].revents & POLLERR) { struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring); D("error on fd1, rx [%d,%d,%d)", - rx->head, rx->cur, rx->tail); + rx->head, rx->cur, rx->tail); } if (pollfd[0].revents & POLLOUT) - move(pb, pa, burst); + ports_move(pb, pa, burst, msg_b2a); if (pollfd[1].revents & POLLOUT) - move(pa, pb, burst); + ports_move(pa, pb, burst, msg_a2b); - /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here, - * kernel will txsync on next poll(). */ + /* + * We don't need ioctl(NIOCTXSYNC) on the two file descriptors. + * here. The kernel will txsync on next poll(). + */ } nmport_close(pb); nmport_close(pa);