2 * (C) 2011-2014 Luigi Rizzo, Matteo Landi
6 * A netmap client to bridge two network interfaces
7 * (or one interface and the host stack).
13 #define NETMAP_WITH_LIBS
14 #include <net/netmap_user.h>
19 static int do_abort = 0;
20 static int zerocopy = 1; /* enable zerocopy if possible */
25 (void)sig; /* UNUSED */
27 signal(SIGINT, SIG_DFL);
32 * how many packets on this set of queues ?
35 pkt_queued(struct nm_desc *d, int tx)
40 for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
41 tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
44 for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
45 tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
52 * move up to 'limit' pkts from rxring to txring swapping buffers.
55 process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
56 u_int limit, const char *msg)
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);
69 m = nm_ring_space(txring);
74 struct netmap_slot *rs = &rxring->slot[j];
75 struct netmap_slot *ts = &txring->slot[k];
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);
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);
87 } else if (verbose > 1) {
88 D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k);
92 uint32_t pkt = ts->buf_idx;
93 ts->buf_idx = rs->buf_idx;
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);
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);
105 j = nm_ring_next(rxring, j);
106 k = nm_ring_next(txring, k);
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);
116 /* move packts from src to destination */
118 move(struct nm_desc *src, struct nm_desc *dst, u_int limit)
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";
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)) {
133 if (nm_ring_empty(txring)) {
137 m += process_rings(rxring, txring, limit, msg);
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"
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"
160 " example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n"
166 * bridge [-v] if1 [if2]
168 * If only one name, or the two interfaces are the same,
169 * bridges userland and the adapter. Otherwise bridge
173 main(int argc, char **argv)
175 struct pollfd pollfd[2];
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 };
183 fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
185 while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) {
188 D("bad option %c %s", ch, optarg);
193 case 'b': /* burst */
194 burst = atoi(optarg);
196 case 'i': /* interface */
199 else if (ifb == NULL)
202 D("%s ignored, already have 2 interfaces",
206 zerocopy = 0; /* do not zerocopy */
212 wait_link = atoi(optarg);
229 burst = atoi(argv[2]);
233 D("missing interface");
236 if (burst < 1 || burst > 8192) {
237 D("invalid burst %d, set to 1024", burst);
240 if (wait_link > 100) {
241 D("invalid wait_link %d, set to 4", wait_link);
244 if (!strcmp(ifa, ifb)) {
246 D("same interface, endpoint 0 goes to host");
247 snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa);
250 D("same interface, loopbacking traffic");
253 /* two different interfaces. Take all rings on if1 */
255 pa = nm_open(ifa, NULL, 0, NULL);
257 D("cannot open %s", ifa);
260 /* try to reuse the mmap() of the first interface, if possible */
261 pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa);
263 D("cannot open %s", ifb);
267 zerocopy = zerocopy && (pa->mem == pb->mem);
268 D("------- zerocopy %ssupported", zerocopy ? "" : "NOT ");
270 /* setup poll(2) array */
271 memset(pollfd, 0, sizeof(pollfd));
272 pollfd[0].fd = pa->fd;
273 pollfd[1].fd = pb->fd;
275 D("Wait %d secs for link to come up...", 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);
282 signal(SIGINT, sigint_h);
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)
291 ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
292 pollfd[1].revents = POLLOUT;
294 ioctl(pollfd[0].fd, NIOCRXSYNC, NULL);
297 ioctl(pollfd[0].fd, NIOCTXSYNC, NULL);
298 pollfd[0].revents = POLLOUT;
300 ioctl(pollfd[1].fd, NIOCRXSYNC, NULL);
305 pollfd[1].events |= POLLOUT;
307 pollfd[0].events |= POLLIN;
309 pollfd[0].events |= POLLOUT;
311 pollfd[1].events |= POLLIN;
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",
323 NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->cur,
328 NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->cur,
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);
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);
343 if (pollfd[0].revents & POLLOUT)
346 if (pollfd[1].revents & POLLOUT)
349 /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here,
350 * kernel will txsync on next poll(). */