]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/netmap/bridge.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 "nm_util.h"
13
14
15 int verbose = 0;
16
17 char *version = "$Id$";
18
19 static int do_abort = 0;
20
21 static void
22 sigint_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  */
33 static int
34 process_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 */
98 static int
99 move(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  */
127 static int
128 pkt_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
147 static void
148 usage(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  */
162 int
163 main(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 }