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