Deleted Added
full compact
bridge.c (243281) bridge.c (250458)
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 *
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: stable/9/tools/tools/netmap/bridge.c 243281 2012-11-19 15:24:19Z emaste $
9 * $FreeBSD: stable/9/tools/tools/netmap/bridge.c 250458 2013-05-10 16:16:33Z luigi $
10 */
11
10 */
11
12#include <errno.h>
13#include <signal.h> /* signal */
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h> /* strcmp */
17#include <fcntl.h> /* open */
18#include <unistd.h> /* close */
12#include "nm_util.h"
19
13
20#include <sys/endian.h> /* le64toh */
21#include <sys/mman.h> /* PROT_* */
22#include <sys/ioctl.h> /* ioctl */
23#include <machine/param.h>
24#include <sys/poll.h>
25#include <sys/socket.h> /* sockaddr.. */
26#include <arpa/inet.h> /* ntohs */
27
14
28#include <net/if.h> /* ifreq */
29#include <net/ethernet.h>
30#include <net/netmap.h>
31#include <net/netmap_user.h>
32
33#include <netinet/in.h> /* sockaddr_in */
34
35#define MIN(a, b) ((a) < (b) ? (a) : (b))
36
37int verbose = 0;
38
15int verbose = 0;
16
39/* debug support */
40#define ND(format, ...) {}
41#define D(format, ...) do { \
42 if (!verbose) break; \
43 struct timeval _xxts; \
44 gettimeofday(&_xxts, NULL); \
45 fprintf(stderr, "%03d.%06d %s [%d] " format "\n", \
46 (int)_xxts.tv_sec %1000, (int)_xxts.tv_usec, \
47 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
48 } while (0)
17char *version = "$Id: bridge.c 12016 2013-01-23 17:24:22Z luigi $";
49
18
50
51char *version = "$Id: bridge.c 10857 2012-04-06 12:18:22Z luigi $";
52
53static int do_abort = 0;
54
19static int do_abort = 0;
20
55/*
56 * info on a ring we handle
57 */
58struct my_ring {
59 const char *ifname;
60 int fd;
61 char *mem; /* userspace mmap address */
62 u_int memsize;
63 u_int queueid;
64 u_int begin, end; /* first..last+1 rings to check */
65 struct netmap_if *nifp;
66 struct netmap_ring *tx, *rx; /* shortcuts */
67
68 uint32_t if_flags;
69 uint32_t if_reqcap;
70 uint32_t if_curcap;
71};
72
73static void
21static void
74sigint_h(__unused int sig)
22sigint_h(int sig)
75{
23{
24 (void)sig; /* UNUSED */
76 do_abort = 1;
77 signal(SIGINT, SIG_DFL);
78}
79
80
25 do_abort = 1;
26 signal(SIGINT, SIG_DFL);
27}
28
29
81static int
82do_ioctl(struct my_ring *me, unsigned long what)
83{
84 struct ifreq ifr;
85 int error;
86
87 bzero(&ifr, sizeof(ifr));
88 strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name));
89 switch (what) {
90 case SIOCSIFFLAGS:
91 ifr.ifr_flagshigh = me->if_flags >> 16;
92 ifr.ifr_flags = me->if_flags & 0xffff;
93 break;
94 case SIOCSIFCAP:
95 ifr.ifr_reqcap = me->if_reqcap;
96 ifr.ifr_curcap = me->if_curcap;
97 break;
98 }
99 error = ioctl(me->fd, what, &ifr);
100 if (error) {
101 D("ioctl error 0x%lx", what);
102 return error;
103 }
104 switch (what) {
105 case SIOCGIFFLAGS:
106 me->if_flags = (ifr.ifr_flagshigh << 16) |
107 (0xffff & ifr.ifr_flags);
108 if (verbose)
109 D("flags are 0x%x", me->if_flags);
110 break;
111
112 case SIOCGIFCAP:
113 me->if_reqcap = ifr.ifr_reqcap;
114 me->if_curcap = ifr.ifr_curcap;
115 if (verbose)
116 D("curcap are 0x%x", me->if_curcap);
117 break;
118 }
119 return 0;
120}
121
122/*
30/*
123 * open a device. if me->mem is null then do an mmap.
124 */
125static int
126netmap_open(struct my_ring *me, int ringid)
127{
128 int fd, err, l;
129 struct nmreq req;
130
131 me->fd = fd = open("/dev/netmap", O_RDWR);
132 if (fd < 0) {
133 D("Unable to open /dev/netmap");
134 return (-1);
135 }
136 bzero(&req, sizeof(req));
137 strncpy(req.nr_name, me->ifname, sizeof(req.nr_name));
138 req.nr_ringid = ringid;
139 req.nr_version = NETMAP_API;
140 err = ioctl(fd, NIOCGINFO, &req);
141 if (err) {
142 D("cannot get info on %s", me->ifname);
143 goto error;
144 }
145 me->memsize = l = req.nr_memsize;
146 if (verbose)
147 D("memsize is %d MB", l>>20);
148 err = ioctl(fd, NIOCREGIF, &req);
149 if (err) {
150 D("Unable to register %s", me->ifname);
151 goto error;
152 }
153
154 if (me->mem == NULL) {
155 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
156 if (me->mem == MAP_FAILED) {
157 D("Unable to mmap");
158 me->mem = NULL;
159 goto error;
160 }
161 }
162
163 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
164 me->queueid = ringid;
165 if (ringid & NETMAP_SW_RING) {
166 me->begin = req.nr_rx_rings;
167 me->end = me->begin + 1;
168 me->tx = NETMAP_TXRING(me->nifp, req.nr_tx_rings);
169 me->rx = NETMAP_RXRING(me->nifp, req.nr_rx_rings);
170 } else if (ringid & NETMAP_HW_RING) {
171 D("XXX check multiple threads");
172 me->begin = ringid & NETMAP_RING_MASK;
173 me->end = me->begin + 1;
174 me->tx = NETMAP_TXRING(me->nifp, me->begin);
175 me->rx = NETMAP_RXRING(me->nifp, me->begin);
176 } else {
177 me->begin = 0;
178 me->end = req.nr_rx_rings; // XXX max of the two
179 me->tx = NETMAP_TXRING(me->nifp, 0);
180 me->rx = NETMAP_RXRING(me->nifp, 0);
181 }
182 return (0);
183error:
184 close(me->fd);
185 return -1;
186}
187
188
189static int
190netmap_close(struct my_ring *me)
191{
192 D("");
193 if (me->mem)
194 munmap(me->mem, me->memsize);
195 ioctl(me->fd, NIOCUNREGIF, NULL);
196 close(me->fd);
197 return (0);
198}
199
200
201/*
202 * move up to 'limit' pkts from rxring to txring swapping buffers.
203 */
204static int
205process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
206 u_int limit, const char *msg)
207{
208 u_int j, k, m = 0;
209

--- 22 unchanged lines hidden (view full) ---

232 pkt = ts->buf_idx;
233 ts->buf_idx = rs->buf_idx;
234 rs->buf_idx = pkt;
235
236 /* copy the packet length. */
237 if (rs->len < 14 || rs->len > 2048)
238 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
239 else if (verbose > 1)
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

--- 22 unchanged lines hidden (view full) ---

61 pkt = ts->buf_idx;
62 ts->buf_idx = rs->buf_idx;
63 rs->buf_idx = pkt;
64
65 /* copy the packet length. */
66 if (rs->len < 14 || rs->len > 2048)
67 D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
68 else if (verbose > 1)
240 D("send len %d rx[%d] -> tx[%d]", rs->len, j, k);
69 D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k);
241 ts->len = rs->len;
242
243 /* report the buffer change. */
244 ts->flags |= NS_BUF_CHANGED;
245 rs->flags |= NS_BUF_CHANGED;
246 j = NETMAP_RING_NEXT(rxring, j);
247 k = NETMAP_RING_NEXT(txring, k);
248 }
249 rxring->avail -= m;
250 txring->avail -= m;
251 rxring->cur = j;
252 txring->cur = k;
253 if (verbose && m > 0)
70 ts->len = rs->len;
71
72 /* report the buffer change. */
73 ts->flags |= NS_BUF_CHANGED;
74 rs->flags |= NS_BUF_CHANGED;
75 j = NETMAP_RING_NEXT(rxring, j);
76 k = NETMAP_RING_NEXT(txring, k);
77 }
78 rxring->avail -= m;
79 txring->avail -= m;
80 rxring->cur = j;
81 txring->cur = k;
82 if (verbose && m > 0)
254 D("sent %d packets to %p", m, txring);
83 D("%s sent %d packets to %p", msg, m, txring);
255
256 return (m);
257}
258
259/* move packts from src to destination */
260static int
261move(struct my_ring *src, struct my_ring *dst, u_int limit)
262{

--- 19 unchanged lines hidden (view full) ---

282
283 return (m);
284}
285
286/*
287 * how many packets on this set of queues ?
288 */
289static int
84
85 return (m);
86}
87
88/* move packts from src to destination */
89static int
90move(struct my_ring *src, struct my_ring *dst, u_int limit)
91{

--- 19 unchanged lines hidden (view full) ---

111
112 return (m);
113}
114
115/*
116 * how many packets on this set of queues ?
117 */
118static int
290howmany(struct my_ring *me, int tx)
119pkt_queued(struct my_ring *me, int tx)
291{
292 u_int i, tot = 0;
293
294 ND("me %p begin %d end %d", me, me->begin, me->end);
295 for (i = me->begin; i < me->end; i++) {
296 struct netmap_ring *ring = tx ?
297 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
298 tot += ring->avail;

--- 33 unchanged lines hidden (view full) ---

332
333 fprintf(stderr, "%s %s built %s %s\n",
334 argv[0], version, __DATE__, __TIME__);
335
336 bzero(me, sizeof(me));
337
338 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) {
339 switch (ch) {
120{
121 u_int i, tot = 0;
122
123 ND("me %p begin %d end %d", me, me->begin, me->end);
124 for (i = me->begin; i < me->end; i++) {
125 struct netmap_ring *ring = tx ?
126 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
127 tot += ring->avail;

--- 33 unchanged lines hidden (view full) ---

161
162 fprintf(stderr, "%s %s built %s %s\n",
163 argv[0], version, __DATE__, __TIME__);
164
165 bzero(me, sizeof(me));
166
167 while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) {
168 switch (ch) {
169 default:
340 D("bad option %c %s", ch, optarg);
341 usage();
342 break;
343 case 'b': /* burst */
344 burst = atoi(optarg);
345 break;
346 case 'i': /* interface */
347 if (ifa == NULL)

--- 8 unchanged lines hidden (view full) ---

356 verbose++;
357 break;
358 case 'w':
359 wait_link = atoi(optarg);
360 break;
361 }
362
363 }
170 D("bad option %c %s", ch, optarg);
171 usage();
172 break;
173 case 'b': /* burst */
174 burst = atoi(optarg);
175 break;
176 case 'i': /* interface */
177 if (ifa == NULL)

--- 8 unchanged lines hidden (view full) ---

186 verbose++;
187 break;
188 case 'w':
189 wait_link = atoi(optarg);
190 break;
191 }
192
193 }
194
364 argc -= optind;
365 argv += optind;
366
367 if (argc > 1)
368 ifa = argv[1];
369 if (argc > 2)
370 ifb = argv[2];
371 if (argc > 3)

--- 17 unchanged lines hidden (view full) ---

389 me[1].ifname = ifb;
390 if (!strcmp(ifa, ifb)) {
391 D("same interface, endpoint 0 goes to host");
392 i = NETMAP_SW_RING;
393 } else {
394 /* two different interfaces. Take all rings on if1 */
395 i = 0; // all hw rings
396 }
195 argc -= optind;
196 argv += optind;
197
198 if (argc > 1)
199 ifa = argv[1];
200 if (argc > 2)
201 ifb = argv[2];
202 if (argc > 3)

--- 17 unchanged lines hidden (view full) ---

220 me[1].ifname = ifb;
221 if (!strcmp(ifa, ifb)) {
222 D("same interface, endpoint 0 goes to host");
223 i = NETMAP_SW_RING;
224 } else {
225 /* two different interfaces. Take all rings on if1 */
226 i = 0; // all hw rings
227 }
397 if (netmap_open(me, i))
228 if (netmap_open(me, i, 1))
398 return (1);
399 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */
229 return (1);
230 me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */
400 if (netmap_open(me+1, 0))
231 if (netmap_open(me+1, 0, 1))
401 return (1);
402
232 return (1);
233
403 /* if bridging two interfaces, set promisc mode */
404 if (i != NETMAP_SW_RING) {
405 do_ioctl(me, SIOCGIFFLAGS);
406 if ((me[0].if_flags & IFF_UP) == 0) {
407 D("%s is down, bringing up...", me[0].ifname);
408 me[0].if_flags |= IFF_UP;
409 }
410 me[0].if_flags |= IFF_PPROMISC;
411 do_ioctl(me, SIOCSIFFLAGS);
412
413 do_ioctl(me+1, SIOCGIFFLAGS);
414 me[1].if_flags |= IFF_PPROMISC;
415 do_ioctl(me+1, SIOCSIFFLAGS);
416
417 /* also disable checksums etc. */
418 do_ioctl(me, SIOCGIFCAP);
419 me[0].if_reqcap = me[0].if_curcap;
420 me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
421 do_ioctl(me+0, SIOCSIFCAP);
422 }
423 do_ioctl(me+1, SIOCGIFFLAGS);
424 if ((me[1].if_flags & IFF_UP) == 0) {
425 D("%s is down, bringing up...", me[1].ifname);
426 me[1].if_flags |= IFF_UP;
427 }
428 do_ioctl(me+1, SIOCSIFFLAGS);
429
430 do_ioctl(me+1, SIOCGIFCAP);
431 me[1].if_reqcap = me[1].if_curcap;
432 me[1].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
433 do_ioctl(me+1, SIOCSIFCAP);
434
435 /* setup poll(2) variables. */
436 memset(pollfd, 0, sizeof(pollfd));
437 for (i = 0; i < 2; i++) {
438 pollfd[i].fd = me[i].fd;
439 pollfd[i].events = (POLLIN);
440 }
441
442 D("Wait %d secs for link to come up...", wait_link);
443 sleep(wait_link);
444 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
445 me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings,
446 me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings);
447
448 /* main loop */
449 signal(SIGINT, sigint_h);
450 while (!do_abort) {
451 int n0, n1, ret;
452 pollfd[0].events = pollfd[1].events = 0;
453 pollfd[0].revents = pollfd[1].revents = 0;
234 /* setup poll(2) variables. */
235 memset(pollfd, 0, sizeof(pollfd));
236 for (i = 0; i < 2; i++) {
237 pollfd[i].fd = me[i].fd;
238 pollfd[i].events = (POLLIN);
239 }
240
241 D("Wait %d secs for link to come up...", wait_link);
242 sleep(wait_link);
243 D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
244 me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings,
245 me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings);
246
247 /* main loop */
248 signal(SIGINT, sigint_h);
249 while (!do_abort) {
250 int n0, n1, ret;
251 pollfd[0].events = pollfd[1].events = 0;
252 pollfd[0].revents = pollfd[1].revents = 0;
454 n0 = howmany(me, 0);
455 n1 = howmany(me + 1, 0);
253 n0 = pkt_queued(me, 0);
254 n1 = pkt_queued(me + 1, 0);
456 if (n0)
457 pollfd[1].events |= POLLOUT;
458 else
459 pollfd[0].events |= POLLIN;
460 if (n1)
461 pollfd[0].events |= POLLOUT;
462 else
463 pollfd[1].events |= POLLIN;
464 ret = poll(pollfd, 2, 2500);
465 if (ret <= 0 || verbose)
466 D("poll %s [0] ev %x %x rx %d@%d tx %d,"
467 " [1] ev %x %x rx %d@%d tx %d",
468 ret <= 0 ? "timeout" : "ok",
469 pollfd[0].events,
470 pollfd[0].revents,
255 if (n0)
256 pollfd[1].events |= POLLOUT;
257 else
258 pollfd[0].events |= POLLIN;
259 if (n1)
260 pollfd[0].events |= POLLOUT;
261 else
262 pollfd[1].events |= POLLIN;
263 ret = poll(pollfd, 2, 2500);
264 if (ret <= 0 || verbose)
265 D("poll %s [0] ev %x %x rx %d@%d tx %d,"
266 " [1] ev %x %x rx %d@%d tx %d",
267 ret <= 0 ? "timeout" : "ok",
268 pollfd[0].events,
269 pollfd[0].revents,
471 howmany(me, 0),
270 pkt_queued(me, 0),
472 me[0].rx->cur,
271 me[0].rx->cur,
473 howmany(me, 1),
272 pkt_queued(me, 1),
474 pollfd[1].events,
475 pollfd[1].revents,
273 pollfd[1].events,
274 pollfd[1].revents,
476 howmany(me+1, 0),
275 pkt_queued(me+1, 0),
477 me[1].rx->cur,
276 me[1].rx->cur,
478 howmany(me+1, 1)
277 pkt_queued(me+1, 1)
479 );
480 if (ret < 0)
481 continue;
482 if (pollfd[0].revents & POLLERR) {
483 D("error on fd0, rxcur %d@%d",
484 me[0].rx->avail, me[0].rx->cur);
485 }
486 if (pollfd[1].revents & POLLERR) {

--- 20 unchanged lines hidden ---
278 );
279 if (ret < 0)
280 continue;
281 if (pollfd[0].revents & POLLERR) {
282 D("error on fd0, rxcur %d@%d",
283 me[0].rx->avail, me[0].rx->cur);
284 }
285 if (pollfd[1].revents & POLLERR) {

--- 20 unchanged lines hidden ---