]> CyberLeo.Net >> Repos - FreeBSD/releng/9.1.git/blob - tools/tools/netmap/bridge.c
Copy stable/9 to releng/9.1 as part of the 9.1-RELEASE release process.
[FreeBSD/releng/9.1.git] / tools / tools / netmap / bridge.c
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 <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 */
19
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
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
37 int verbose = 0;
38
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)
49
50
51 char *version = "$Id: bridge.c 10857 2012-04-06 12:18:22Z luigi $";
52
53 static int do_abort = 0;
54
55 /*
56  * info on a ring we handle
57  */
58 struct 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
73 static void
74 sigint_h(__unused int sig)
75 {
76         do_abort = 1;
77         signal(SIGINT, SIG_DFL);
78 }
79
80
81 static int
82 do_ioctl(struct my_ring *me, int 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 %d", 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 /*
123  * open a device. if me->mem is null then do an mmap.
124  */
125 static int
126 netmap_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);
183 error:
184         close(me->fd);
185         return -1;
186 }
187
188
189 static int
190 netmap_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  */
204 static int
205 process_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
210         /* print a warning if any of the ring flags is set (e.g. NM_REINIT) */
211         if (rxring->flags || txring->flags)
212                 D("%s rxflags %x txflags %x",
213                         msg, rxring->flags, txring->flags);
214         j = rxring->cur; /* RX */
215         k = txring->cur; /* TX */
216         if (rxring->avail < limit)
217                 limit = rxring->avail;
218         if (txring->avail < limit)
219                 limit = txring->avail;
220         m = limit;
221         while (limit-- > 0) {
222                 struct netmap_slot *rs = &rxring->slot[j];
223                 struct netmap_slot *ts = &txring->slot[k];
224                 uint32_t pkt;
225
226                 /* swap packets */
227                 if (ts->buf_idx < 2 || rs->buf_idx < 2) {
228                         D("wrong index rx[%d] = %d  -> tx[%d] = %d",
229                                 j, rs->buf_idx, k, ts->buf_idx);
230                         sleep(2);
231                 }
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)
240                         D("send len %d rx[%d] -> tx[%d]", 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)
254                 D("sent %d packets to %p", m, txring);
255
256         return (m);
257 }
258
259 /* move packts from src to destination */
260 static int
261 move(struct my_ring *src, struct my_ring *dst, u_int limit)
262 {
263         struct netmap_ring *txring, *rxring;
264         u_int m = 0, si = src->begin, di = dst->begin;
265         const char *msg = (src->queueid & NETMAP_SW_RING) ?
266                 "host->net" : "net->host";
267
268         while (si < src->end && di < dst->end) {
269                 rxring = NETMAP_RXRING(src->nifp, si);
270                 txring = NETMAP_TXRING(dst->nifp, di);
271                 ND("txring %p rxring %p", txring, rxring);
272                 if (rxring->avail == 0) {
273                         si++;
274                         continue;
275                 }
276                 if (txring->avail == 0) {
277                         di++;
278                         continue;
279                 }
280                 m += process_rings(rxring, txring, limit, msg);
281         }
282
283         return (m);
284 }
285
286 /*
287  * how many packets on this set of queues ?
288  */
289 static int
290 howmany(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;
299         }
300         if (0 && verbose && tot && !tx)
301                 D("ring %s %s %s has %d avail at %d",
302                         me->ifname, tx ? "tx": "rx",
303                         me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ?
304                                 "host":"net",
305                         tot, NETMAP_TXRING(me->nifp, me->begin)->cur);
306         return tot;
307 }
308
309 static void
310 usage(void)
311 {
312         fprintf(stderr,
313             "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [iface]\n");
314         exit(1);
315 }
316
317 /*
318  * bridge [-v] if1 [if2]
319  *
320  * If only one name, or the two interfaces are the same,
321  * bridges userland and the adapter. Otherwise bridge
322  * two intefaces.
323  */
324 int
325 main(int argc, char **argv)
326 {
327         struct pollfd pollfd[2];
328         int i, ch;
329         u_int burst = 1024, wait_link = 4;
330         struct my_ring me[2];
331         char *ifa = NULL, *ifb = NULL;
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) {
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)
348                                 ifa = optarg;
349                         else if (ifb == NULL)
350                                 ifb = optarg;
351                         else
352                                 D("%s ignored, already have 2 interfaces",
353                                         optarg);
354                         break;
355                 case 'v':
356                         verbose++;
357                         break;
358                 case 'w':
359                         wait_link = atoi(optarg);
360                         break;
361                 }
362
363         }
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)
372                 burst = atoi(argv[3]);
373         if (!ifb)
374                 ifb = ifa;
375         if (!ifa) {
376                 D("missing interface");
377                 usage();
378         }
379         if (burst < 1 || burst > 8192) {
380                 D("invalid burst %d, set to 1024", burst);
381                 burst = 1024;
382         }
383         if (wait_link > 100) {
384                 D("invalid wait_link %d, set to 4", wait_link);
385                 wait_link = 4;
386         }
387         /* setup netmap interface #1. */
388         me[0].ifname = ifa;
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         }
397         if (netmap_open(me, i))
398                 return (1);
399         me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */
400         if (netmap_open(me+1, 0))
401                 return (1);
402
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;
454                 n0 = howmany(me, 0);
455                 n1 = howmany(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,
471                                 howmany(me, 0),
472                                 me[0].rx->cur,
473                                 howmany(me, 1),
474                                 pollfd[1].events,
475                                 pollfd[1].revents,
476                                 howmany(me+1, 0),
477                                 me[1].rx->cur,
478                                 howmany(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) {
487                         D("error on fd1, rxcur %d@%d",
488                                 me[1].rx->avail, me[1].rx->cur);
489                 }
490                 if (pollfd[0].revents & POLLOUT) {
491                         move(me + 1, me, burst);
492                         // XXX we don't need the ioctl */
493                         // ioctl(me[0].fd, NIOCTXSYNC, NULL);
494                 }
495                 if (pollfd[1].revents & POLLOUT) {
496                         move(me, me + 1, burst);
497                         // XXX we don't need the ioctl */
498                         // ioctl(me[1].fd, NIOCTXSYNC, NULL);
499                 }
500         }
501         D("exiting");
502         netmap_close(me + 1);
503         netmap_close(me + 0);
504
505         return (0);
506 }