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