]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/tools/netmap/pkt-gen.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / tools / tools / netmap / pkt-gen.c
1 /*
2  * Copyright (C) 2011-2012 Matteo Landi, Luigi Rizzo. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *   1. Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *   2. Redistributions in binary form must reproduce the above copyright
10  *      notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * $FreeBSD$
28  * $Id: pkt-gen.c 12024 2013-01-25 05:41:51Z luigi $
29  *
30  * Example program to show how to build a multithreaded packet
31  * source/sink using the netmap device.
32  *
33  * In this example we create a programmable number of threads
34  * to take care of all the queues of the interface used to
35  * send or receive traffic.
36  *
37  */
38
39 #include "nm_util.h"
40
41 const char *default_payload="netmap pkt-gen payload\n"
42         "http://info.iet.unipi.it/~luigi/netmap/ ";
43
44 int time_second;        // support for RD() debugging macro
45
46 int verbose = 0;
47
48 #define SKIP_PAYLOAD 1 /* do not check payload. */
49
50 struct pkt {
51         struct ether_header eh;
52         struct ip ip;
53         struct udphdr udp;
54         uint8_t body[2048];     // XXX hardwired
55 } __attribute__((__packed__));
56
57 struct ip_range {
58         char *name;
59         struct in_addr start, end, cur;
60         uint16_t port0, port1, cur_p;
61 };
62
63 struct mac_range {
64         char *name;
65         struct ether_addr start, end;
66 };
67
68 /*
69  * global arguments for all threads
70  */
71
72 struct glob_arg {
73         struct ip_range src_ip;
74         struct ip_range dst_ip;
75         struct mac_range dst_mac;
76         struct mac_range src_mac;
77         int pkt_size;
78         int burst;
79         int forever;
80         int npackets;   /* total packets to send */
81         int nthreads;
82         int cpus;
83         int options;    /* testing */
84 #define OPT_PREFETCH    1
85 #define OPT_ACCESS      2
86 #define OPT_COPY        4
87 #define OPT_MEMCPY      8
88 #define OPT_TS          16      /* add a timestamp */
89         int dev_type;
90         pcap_t *p;
91
92         int affinity;
93         int main_fd;
94         int report_interval;
95         void *(*td_body)(void *);
96         void *mmap_addr;
97         int mmap_size;
98         char *ifname;
99 };
100 enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
101
102
103 /*
104  * Arguments for a new thread. The same structure is used by
105  * the source and the sink
106  */
107 struct targ {
108         struct glob_arg *g;
109         int used;
110         int completed;
111         int cancel;
112         int fd;
113         struct nmreq nmr;
114         struct netmap_if *nifp;
115         uint16_t        qfirst, qlast; /* range of queues to scan */
116         volatile uint64_t count;
117         struct timeval tic, toc;
118         int me;
119         pthread_t thread;
120         int affinity;
121
122         struct pkt pkt;
123 };
124
125
126 /*
127  * extract the extremes from a range of ipv4 addresses.
128  * addr_lo[-addr_hi][:port_lo[-port_hi]]
129  */
130 static void
131 extract_ip_range(struct ip_range *r)
132 {
133         char *p_lo, *p_hi;
134         char buf1[16]; // one ip address
135
136         D("extract IP range from %s", r->name);
137         p_lo = index(r->name, ':');     /* do we have ports ? */
138         if (p_lo) {
139                 D(" found ports at %s", p_lo);
140                 *p_lo++ = '\0';
141                 p_hi = index(p_lo, '-');
142                 if (p_hi)
143                         *p_hi++ = '\0';
144                 else
145                         p_hi = p_lo;
146                 r->port0 = strtol(p_lo, NULL, 0);
147                 r->port1 = strtol(p_hi, NULL, 0);
148                 if (r->port1 < r->port0) {
149                         r->cur_p = r->port0;
150                         r->port0 = r->port1;
151                         r->port1 = r->cur_p;
152                 }
153                 r->cur_p = r->port0;
154                 D("ports are %d to %d", r->port0, r->port1);
155         }
156         p_hi = index(r->name, '-');     /* do we have upper ip ? */
157         if (p_hi) {
158                 *p_hi++ = '\0';
159         } else
160                 p_hi = r->name;
161         inet_aton(r->name, &r->start);
162         inet_aton(p_hi, &r->end);
163         if (r->start.s_addr > r->end.s_addr) {
164                 r->cur = r->start;
165                 r->start = r->end;
166                 r->end = r->cur;
167         }
168         r->cur = r->start;
169         strncpy(buf1, inet_ntoa(r->end), sizeof(buf1));
170         D("range is %s %d to %s %d", inet_ntoa(r->start), r->port0,
171                 buf1, r->port1);
172 }
173
174 static void
175 extract_mac_range(struct mac_range *r)
176 {
177         D("extract MAC range from %s", r->name);
178         bcopy(ether_aton(r->name), &r->start, 6);
179         bcopy(ether_aton(r->name), &r->end, 6);
180 #if 0
181         bcopy(targ->src_mac, eh->ether_shost, 6);
182         p = index(targ->g->src_mac, '-');
183         if (p)
184                 targ->src_mac_range = atoi(p+1);
185
186         bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6);
187         bcopy(targ->dst_mac, eh->ether_dhost, 6);
188         p = index(targ->g->dst_mac, '-');
189         if (p)
190                 targ->dst_mac_range = atoi(p+1);
191 #endif
192         D("%s starts at %s", r->name, ether_ntoa(&r->start));
193 }
194
195 static struct targ *targs;
196 static int global_nthreads;
197
198 /* control-C handler */
199 static void
200 sigint_h(int sig)
201 {
202         int i;
203
204         (void)sig;      /* UNUSED */
205         for (i = 0; i < global_nthreads; i++) {
206                 targs[i].cancel = 1;
207         }
208         signal(SIGINT, SIG_DFL);
209 }
210
211 /* sysctl wrapper to return the number of active CPUs */
212 static int
213 system_ncpus(void)
214 {
215 #ifdef __FreeBSD__
216         int mib[2], ncpus;
217         size_t len;
218
219         mib[0] = CTL_HW;
220         mib[1] = HW_NCPU;
221         len = sizeof(mib);
222         sysctl(mib, 2, &ncpus, &len, NULL, 0);
223
224         return (ncpus);
225 #else
226         return 1;
227 #endif /* !__FreeBSD__ */
228 }
229
230 #ifdef __linux__
231 #define sockaddr_dl    sockaddr_ll
232 #define sdl_family     sll_family
233 #define AF_LINK        AF_PACKET
234 #define LLADDR(s)      s->sll_addr;
235 #include <linux/if_tun.h>
236 #define TAP_CLONEDEV    "/dev/net/tun"
237 #endif /* __linux__ */
238
239 #ifdef __FreeBSD__
240 #include <net/if_tun.h>
241 #define TAP_CLONEDEV    "/dev/tap"
242 #endif /* __FreeBSD */
243
244 #ifdef __APPLE__
245 // #warning TAP not supported on apple ?
246 #include <net/if_utun.h>
247 #define TAP_CLONEDEV    "/dev/tap"
248 #endif /* __APPLE__ */
249
250
251 /*
252  * locate the src mac address for our interface, put it
253  * into the user-supplied buffer. return 0 if ok, -1 on error.
254  */
255 static int
256 source_hwaddr(const char *ifname, char *buf)
257 {
258         struct ifaddrs *ifaphead, *ifap;
259         int l = sizeof(ifap->ifa_name);
260
261         if (getifaddrs(&ifaphead) != 0) {
262                 D("getifaddrs %s failed", ifname);
263                 return (-1);
264         }
265
266         for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
267                 struct sockaddr_dl *sdl =
268                         (struct sockaddr_dl *)ifap->ifa_addr;
269                 uint8_t *mac;
270
271                 if (!sdl || sdl->sdl_family != AF_LINK)
272                         continue;
273                 if (strncmp(ifap->ifa_name, ifname, l) != 0)
274                         continue;
275                 mac = (uint8_t *)LLADDR(sdl);
276                 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
277                         mac[0], mac[1], mac[2],
278                         mac[3], mac[4], mac[5]);
279                 if (verbose)
280                         D("source hwaddr %s", buf);
281                 break;
282         }
283         freeifaddrs(ifaphead);
284         return ifap ? 0 : 1;
285 }
286
287
288 /* set the thread affinity. */
289 static int
290 setaffinity(pthread_t me, int i)
291 {
292 #ifdef __FreeBSD__
293         cpuset_t cpumask;
294
295         if (i == -1)
296                 return 0;
297
298         /* Set thread affinity affinity.*/
299         CPU_ZERO(&cpumask);
300         CPU_SET(i, &cpumask);
301
302         if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
303                 D("Unable to set affinity");
304                 return 1;
305         }
306 #else
307         (void)me; /* suppress 'unused' warnings */
308         (void)i;
309 #endif /* __FreeBSD__ */
310         return 0;
311 }
312
313 /* Compute the checksum of the given ip header. */
314 static uint16_t
315 checksum(const void *data, uint16_t len, uint32_t sum)
316 {
317         const uint8_t *addr = data;
318         uint32_t i;
319
320         /* Checksum all the pairs of bytes first... */
321         for (i = 0; i < (len & ~1U); i += 2) {
322                 sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
323                 if (sum > 0xFFFF)
324                         sum -= 0xFFFF;
325         }
326         /*
327          * If there's a single byte left over, checksum it, too.
328          * Network byte order is big-endian, so the remaining byte is
329          * the high byte.
330          */
331         if (i < len) {
332                 sum += addr[i] << 8;
333                 if (sum > 0xFFFF)
334                         sum -= 0xFFFF;
335         }
336         return sum;
337 }
338
339 static u_int16_t
340 wrapsum(u_int32_t sum)
341 {
342         sum = ~sum & 0xFFFF;
343         return (htons(sum));
344 }
345
346 /*
347  * Fill a packet with some payload.
348  * We create a UDP packet so the payload starts at
349  *      14+20+8 = 42 bytes.
350  */
351 #ifdef __linux__
352 #define uh_sport source
353 #define uh_dport dest
354 #define uh_ulen len
355 #define uh_sum check
356 #endif /* linux */
357 static void
358 initialize_packet(struct targ *targ)
359 {
360         struct pkt *pkt = &targ->pkt;
361         struct ether_header *eh;
362         struct ip *ip;
363         struct udphdr *udp;
364         uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip);
365         int i, l, l0 = strlen(default_payload);
366
367         for (i = 0; i < paylen;) {
368                 l = min(l0, paylen - i);
369                 bcopy(default_payload, pkt->body + i, l);
370                 i += l;
371         }
372         pkt->body[i-1] = '\0';
373         ip = &pkt->ip;
374
375         ip->ip_v = IPVERSION;
376         ip->ip_hl = 5;
377         ip->ip_id = 0;
378         ip->ip_tos = IPTOS_LOWDELAY;
379         ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh));
380         ip->ip_id = 0;
381         ip->ip_off = htons(IP_DF); /* Don't fragment */
382         ip->ip_ttl = IPDEFTTL;
383         ip->ip_p = IPPROTO_UDP;
384         ip->ip_dst.s_addr = targ->g->dst_ip.cur.s_addr;
385         if (++targ->g->dst_ip.cur.s_addr > targ->g->dst_ip.end.s_addr)
386                 targ->g->dst_ip.cur.s_addr = targ->g->dst_ip.start.s_addr;
387         ip->ip_src.s_addr = targ->g->src_ip.cur.s_addr;
388         if (++targ->g->src_ip.cur.s_addr > targ->g->src_ip.end.s_addr)
389                 targ->g->src_ip.cur.s_addr = targ->g->src_ip.start.s_addr;
390         ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0));
391
392
393         udp = &pkt->udp;
394         udp->uh_sport = htons(targ->g->src_ip.cur_p);
395         if (++targ->g->src_ip.cur_p > targ->g->src_ip.port1)
396                 targ->g->src_ip.cur_p = targ->g->src_ip.port0;
397         udp->uh_dport = htons(targ->g->dst_ip.cur_p);
398         if (++targ->g->dst_ip.cur_p > targ->g->dst_ip.port1)
399                 targ->g->dst_ip.cur_p = targ->g->dst_ip.port0;
400         udp->uh_ulen = htons(paylen);
401         /* Magic: taken from sbin/dhclient/packet.c */
402         udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp),
403                     checksum(pkt->body,
404                         paylen - sizeof(*udp),
405                         checksum(&ip->ip_src, 2 * sizeof(ip->ip_src),
406                             IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen)
407                         )
408                     )
409                 ));
410
411         eh = &pkt->eh;
412         bcopy(&targ->g->src_mac.start, eh->ether_shost, 6);
413         bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6);
414         eh->ether_type = htons(ETHERTYPE_IP);
415 }
416
417 /* Check the payload of the packet for errors (use it for debug).
418  * Look for consecutive ascii representations of the size of the packet.
419  */
420 static void
421 check_payload(char *p, int psize)
422 {
423         char temp[64];
424         int n_read, size, sizelen;
425
426         /* get the length in ASCII of the length of the packet. */
427         sizelen = sprintf(temp, "%d", psize) + 1; // include a whitespace
428
429         /* dummy payload. */
430         p += 14; /* skip packet header. */
431         n_read = 14;
432         while (psize - n_read >= sizelen) {
433                 sscanf(p, "%d", &size);
434                 if (size != psize) {
435                         D("Read %d instead of %d", size, psize);
436                         break;
437                 }
438
439                 p += sizelen;
440                 n_read += sizelen;
441         }
442 }
443
444
445 /*
446  * create and enqueue a batch of packets on a ring.
447  * On the last one set NS_REPORT to tell the driver to generate
448  * an interrupt when done.
449  */
450 static int
451 send_packets(struct netmap_ring *ring, struct pkt *pkt, 
452                 int size, u_int count, int options)
453 {
454         u_int sent, cur = ring->cur;
455
456         if (ring->avail < count)
457                 count = ring->avail;
458
459 #if 0
460         if (options & (OPT_COPY | OPT_PREFETCH) ) {
461                 for (sent = 0; sent < count; sent++) {
462                         struct netmap_slot *slot = &ring->slot[cur];
463                         char *p = NETMAP_BUF(ring, slot->buf_idx);
464
465                         prefetch(p);
466                         cur = NETMAP_RING_NEXT(ring, cur);
467                 }
468                 cur = ring->cur;
469         }
470 #endif
471         for (sent = 0; sent < count; sent++) {
472                 struct netmap_slot *slot = &ring->slot[cur];
473                 char *p = NETMAP_BUF(ring, slot->buf_idx);
474
475                 if (options & OPT_COPY)
476                         pkt_copy(pkt, p, size);
477                 else if (options & OPT_MEMCPY)
478                         memcpy(p, pkt, size);
479                 else if (options & OPT_PREFETCH)
480                         prefetch(p);
481                 slot->len = size;
482                 if (sent == count - 1)
483                         slot->flags |= NS_REPORT;
484                 cur = NETMAP_RING_NEXT(ring, cur);
485         }
486         ring->avail -= sent;
487         ring->cur = cur;
488
489         return (sent);
490 }
491
492 /*
493  * Send a packet, and wait for a response.
494  * The payload (after UDP header, ofs 42) has a 4-byte sequence
495  * followed by a struct timeval (or bintime?)
496  */
497 #define PAY_OFS 42      /* where in the pkt... */
498
499 static void *
500 pinger_body(void *data)
501 {
502         struct targ *targ = (struct targ *) data;
503         struct pollfd fds[1];
504         struct netmap_if *nifp = targ->nifp;
505         int i, rx = 0, n = targ->g->npackets;
506
507         fds[0].fd = targ->fd;
508         fds[0].events = (POLLIN);
509         static uint32_t sent;
510         struct timespec ts, now, last_print;
511         uint32_t count = 0, min = 1000000000, av = 0;
512
513         if (targ->g->nthreads > 1) {
514                 D("can only ping with 1 thread");
515                 return NULL;
516         }
517
518         clock_gettime(CLOCK_REALTIME_PRECISE, &last_print);
519         while (n == 0 || (int)sent < n) {
520                 struct netmap_ring *ring = NETMAP_TXRING(nifp, 0);
521                 struct netmap_slot *slot;
522                 char *p;
523             for (i = 0; i < 1; i++) {
524                 slot = &ring->slot[ring->cur];
525                 slot->len = targ->g->pkt_size;
526                 p = NETMAP_BUF(ring, slot->buf_idx);
527
528                 if (ring->avail == 0) {
529                         D("-- ouch, cannot send");
530                 } else {
531                         pkt_copy(&targ->pkt, p, targ->g->pkt_size);
532                         clock_gettime(CLOCK_REALTIME_PRECISE, &ts);
533                         bcopy(&sent, p+42, sizeof(sent));
534                         bcopy(&ts, p+46, sizeof(ts));
535                         sent++;
536                         ring->cur = NETMAP_RING_NEXT(ring, ring->cur);
537                         ring->avail--;
538                 }
539             }
540                 /* should use a parameter to decide how often to send */
541                 if (poll(fds, 1, 3000) <= 0) {
542                         D("poll error/timeout on queue %d", targ->me);
543                         continue;
544                 }
545                 /* see what we got back */
546                 for (i = targ->qfirst; i < targ->qlast; i++) {
547                         ring = NETMAP_RXRING(nifp, i);
548                         while (ring->avail > 0) {
549                                 uint32_t seq;
550                                 slot = &ring->slot[ring->cur];
551                                 p = NETMAP_BUF(ring, slot->buf_idx);
552
553                                 clock_gettime(CLOCK_REALTIME_PRECISE, &now);
554                                 bcopy(p+42, &seq, sizeof(seq));
555                                 bcopy(p+46, &ts, sizeof(ts));
556                                 ts.tv_sec = now.tv_sec - ts.tv_sec;
557                                 ts.tv_nsec = now.tv_nsec - ts.tv_nsec;
558                                 if (ts.tv_nsec < 0) {
559                                         ts.tv_nsec += 1000000000;
560                                         ts.tv_sec--;
561                                 }
562                                 if (1) D("seq %d/%d delta %d.%09d", seq, sent,
563                                         (int)ts.tv_sec, (int)ts.tv_nsec);
564                                 if (ts.tv_nsec < (int)min)
565                                         min = ts.tv_nsec;
566                                 count ++;
567                                 av += ts.tv_nsec;
568                                 ring->avail--;
569                                 ring->cur = NETMAP_RING_NEXT(ring, ring->cur);
570                                 rx++;
571                         }
572                 }
573                 //D("tx %d rx %d", sent, rx);
574                 //usleep(100000);
575                 ts.tv_sec = now.tv_sec - last_print.tv_sec;
576                 ts.tv_nsec = now.tv_nsec - last_print.tv_nsec;
577                 if (ts.tv_nsec < 0) {
578                         ts.tv_nsec += 1000000000;
579                         ts.tv_sec--;
580                 }
581                 if (ts.tv_sec >= 1) {
582                         D("count %d min %d av %d",
583                                 count, min, av/count);
584                         count = 0;
585                         av = 0;
586                         min = 100000000;
587                         last_print = now;
588                 }
589         }
590         return NULL;
591 }
592
593
594 /*
595  * reply to ping requests
596  */
597 static void *
598 ponger_body(void *data)
599 {
600         struct targ *targ = (struct targ *) data;
601         struct pollfd fds[1];
602         struct netmap_if *nifp = targ->nifp;
603         struct netmap_ring *txring, *rxring;
604         int i, rx = 0, sent = 0, n = targ->g->npackets;
605         fds[0].fd = targ->fd;
606         fds[0].events = (POLLIN);
607
608         if (targ->g->nthreads > 1) {
609                 D("can only reply ping with 1 thread");
610                 return NULL;
611         }
612         D("understood ponger %d but don't know how to do it", n);
613         while (n == 0 || sent < n) {
614                 uint32_t txcur, txavail;
615 //#define BUSYWAIT
616 #ifdef BUSYWAIT
617                 ioctl(fds[0].fd, NIOCRXSYNC, NULL);
618 #else
619                 if (poll(fds, 1, 1000) <= 0) {
620                         D("poll error/timeout on queue %d", targ->me);
621                         continue;
622                 }
623 #endif
624                 txring = NETMAP_TXRING(nifp, 0);
625                 txcur = txring->cur;
626                 txavail = txring->avail;
627                 /* see what we got back */
628                 for (i = targ->qfirst; i < targ->qlast; i++) {
629                         rxring = NETMAP_RXRING(nifp, i);
630                         while (rxring->avail > 0) {
631                                 uint16_t *spkt, *dpkt;
632                                 uint32_t cur = rxring->cur;
633                                 struct netmap_slot *slot = &rxring->slot[cur];
634                                 char *src, *dst;
635                                 src = NETMAP_BUF(rxring, slot->buf_idx);
636                                 //D("got pkt %p of size %d", src, slot->len);
637                                 rxring->avail--;
638                                 rxring->cur = NETMAP_RING_NEXT(rxring, cur);
639                                 rx++;
640                                 if (txavail == 0)
641                                         continue;
642                                 dst = NETMAP_BUF(txring,
643                                     txring->slot[txcur].buf_idx);
644                                 /* copy... */
645                                 dpkt = (uint16_t *)dst;
646                                 spkt = (uint16_t *)src;
647                                 pkt_copy(src, dst, slot->len);
648                                 dpkt[0] = spkt[3];
649                                 dpkt[1] = spkt[4];
650                                 dpkt[2] = spkt[5];
651                                 dpkt[3] = spkt[0];
652                                 dpkt[4] = spkt[1];
653                                 dpkt[5] = spkt[2];
654                                 txring->slot[txcur].len = slot->len;
655                                 /* XXX swap src dst mac */
656                                 txcur = NETMAP_RING_NEXT(txring, txcur);
657                                 txavail--;
658                                 sent++;
659                         }
660                 }
661                 txring->cur = txcur;
662                 txring->avail = txavail;
663                 targ->count = sent;
664 #ifdef BUSYWAIT
665                 ioctl(fds[0].fd, NIOCTXSYNC, NULL);
666 #endif
667                 //D("tx %d rx %d", sent, rx);
668         }
669         return NULL;
670 }
671
672
673 static void *
674 sender_body(void *data)
675 {
676         struct targ *targ = (struct targ *) data;
677
678         struct pollfd fds[1];
679         struct netmap_if *nifp = targ->nifp;
680         struct netmap_ring *txring;
681         int i, n = targ->g->npackets / targ->g->nthreads, sent = 0;
682         int options = targ->g->options | OPT_COPY;
683 D("start");
684         if (setaffinity(targ->thread, targ->affinity))
685                 goto quit;
686         /* setup poll(2) mechanism. */
687         memset(fds, 0, sizeof(fds));
688         fds[0].fd = targ->fd;
689         fds[0].events = (POLLOUT);
690
691         /* main loop.*/
692         gettimeofday(&targ->tic, NULL);
693
694     if (targ->g->dev_type == DEV_PCAP) {
695             int size = targ->g->pkt_size;
696             void *pkt = &targ->pkt;
697             pcap_t *p = targ->g->p;
698
699             for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
700                 if (pcap_inject(p, pkt, size) != -1)
701                         sent++;
702                 if (i > 10000) {
703                         targ->count = sent;
704                         i = 0;
705                 }
706             }
707     } else if (targ->g->dev_type == DEV_TAP) { /* tap */
708             int size = targ->g->pkt_size;
709             void *pkt = &targ->pkt;
710             D("writing to file desc %d", targ->g->main_fd);
711
712             for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
713                 if (write(targ->g->main_fd, pkt, size) != -1)
714                         sent++;
715                 if (i > 10000) {
716                         targ->count = sent;
717                         i = 0;
718                 }
719             }
720     } else {
721         while (!targ->cancel && (n == 0 || sent < n)) {
722
723                 /*
724                  * wait for available room in the send queue(s)
725                  */
726                 if (poll(fds, 1, 2000) <= 0) {
727                         if (targ->cancel)
728                                 break;
729                         D("poll error/timeout on queue %d", targ->me);
730                         goto quit;
731                 }
732                 /*
733                  * scan our queues and send on those with room
734                  */
735                 if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) {
736                         D("drop copy");
737                         options &= ~OPT_COPY;
738                 }
739                 for (i = targ->qfirst; i < targ->qlast; i++) {
740                         int m, limit = targ->g->burst;
741                         if (n > 0 && n - sent < limit)
742                                 limit = n - sent;
743                         txring = NETMAP_TXRING(nifp, i);
744                         if (txring->avail == 0)
745                                 continue;
746                         m = send_packets(txring, &targ->pkt, targ->g->pkt_size,
747                                          limit, options);
748                         sent += m;
749                         targ->count = sent;
750                 }
751         }
752         /* flush any remaining packets */
753         ioctl(fds[0].fd, NIOCTXSYNC, NULL);
754
755         /* final part: wait all the TX queues to be empty. */
756         for (i = targ->qfirst; i < targ->qlast; i++) {
757                 txring = NETMAP_TXRING(nifp, i);
758                 while (!NETMAP_TX_RING_EMPTY(txring)) {
759                         ioctl(fds[0].fd, NIOCTXSYNC, NULL);
760                         usleep(1); /* wait 1 tick */
761                 }
762         }
763     }
764
765         gettimeofday(&targ->toc, NULL);
766         targ->completed = 1;
767         targ->count = sent;
768
769 quit:
770         /* reset the ``used`` flag. */
771         targ->used = 0;
772
773         return (NULL);
774 }
775
776
777 static void
778 receive_pcap(u_char *user, const struct pcap_pkthdr * h,
779         const u_char * bytes)
780 {
781         int *count = (int *)user;
782         (void)h;        /* UNUSED */
783         (void)bytes;    /* UNUSED */
784         (*count)++;
785 }
786
787 static int
788 receive_packets(struct netmap_ring *ring, u_int limit, int skip_payload)
789 {
790         u_int cur, rx;
791
792         cur = ring->cur;
793         if (ring->avail < limit)
794                 limit = ring->avail;
795         for (rx = 0; rx < limit; rx++) {
796                 struct netmap_slot *slot = &ring->slot[cur];
797                 char *p = NETMAP_BUF(ring, slot->buf_idx);
798
799                 if (!skip_payload)
800                         check_payload(p, slot->len);
801
802                 cur = NETMAP_RING_NEXT(ring, cur);
803         }
804         ring->avail -= rx;
805         ring->cur = cur;
806
807         return (rx);
808 }
809
810 static void *
811 receiver_body(void *data)
812 {
813         struct targ *targ = (struct targ *) data;
814         struct pollfd fds[1];
815         struct netmap_if *nifp = targ->nifp;
816         struct netmap_ring *rxring;
817         int i;
818         uint64_t received = 0;
819
820         if (setaffinity(targ->thread, targ->affinity))
821                 goto quit;
822
823         /* setup poll(2) mechanism. */
824         memset(fds, 0, sizeof(fds));
825         fds[0].fd = targ->fd;
826         fds[0].events = (POLLIN);
827
828         /* unbounded wait for the first packet. */
829         for (;;) {
830                 i = poll(fds, 1, 1000);
831                 if (i > 0 && !(fds[0].revents & POLLERR))
832                         break;
833                 D("waiting for initial packets, poll returns %d %d", i, fds[0].revents);
834         }
835
836         /* main loop, exit after 1s silence */
837         gettimeofday(&targ->tic, NULL);
838     if (targ->g->dev_type == DEV_PCAP) {
839         while (!targ->cancel) {
840                 /* XXX should we poll ? */
841                 pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL);
842         }
843     } else if (targ->g->dev_type == DEV_TAP) {
844         D("reading from %s fd %d", targ->g->ifname, targ->g->main_fd);
845         while (!targ->cancel) {
846                 char buf[2048];
847                 /* XXX should we poll ? */
848                 if (read(targ->g->main_fd, buf, sizeof(buf)) > 0)
849                         targ->count++;
850         }
851     } else {
852         while (!targ->cancel) {
853                 /* Once we started to receive packets, wait at most 1 seconds
854                    before quitting. */
855                 if (poll(fds, 1, 1 * 1000) <= 0 && targ->g->forever == 0) {
856                         gettimeofday(&targ->toc, NULL);
857                         targ->toc.tv_sec -= 1; /* Subtract timeout time. */
858                         break;
859                 }
860
861                 for (i = targ->qfirst; i < targ->qlast; i++) {
862                         int m;
863
864                         rxring = NETMAP_RXRING(nifp, i);
865                         if (rxring->avail == 0)
866                                 continue;
867
868                         m = receive_packets(rxring, targ->g->burst,
869                                         SKIP_PAYLOAD);
870                         received += m;
871                 }
872                 targ->count = received;
873
874                 // tell the card we have read the data
875                 //ioctl(fds[0].fd, NIOCRXSYNC, NULL);
876         }
877     }
878
879         targ->completed = 1;
880         targ->count = received;
881
882 quit:
883         /* reset the ``used`` flag. */
884         targ->used = 0;
885
886         return (NULL);
887 }
888
889 /* very crude code to print a number in normalized form.
890  * Caller has to make sure that the buffer is large enough.
891  */
892 static const char *
893 norm(char *buf, double val)
894 {
895         char *units[] = { "", "K", "M", "G" };
896         u_int i;
897
898         for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *); i++)
899                 val /= 1000;
900         sprintf(buf, "%.2f %s", val, units[i]);
901         return buf;
902 }
903
904 static void
905 tx_output(uint64_t sent, int size, double delta)
906 {
907         double bw, raw_bw, pps;
908         char b1[40], b2[80], b3[80];
909
910         printf("Sent %" PRIu64 " packets, %d bytes each, in %.2f seconds.\n",
911                sent, size, delta);
912         if (delta == 0)
913                 delta = 1e-6;
914         if (size < 60)          /* correct for min packet size */
915                 size = 60;
916         pps = sent / delta;
917         bw = (8.0 * size * sent) / delta;
918         /* raw packets have4 bytes crc + 20 bytes framing */
919         raw_bw = (8.0 * (size + 24) * sent) / delta;
920
921         printf("Speed: %spps Bandwidth: %sbps (raw %sbps)\n",
922                 norm(b1, pps), norm(b2, bw), norm(b3, raw_bw) );
923 }
924
925
926 static void
927 rx_output(uint64_t received, double delta)
928 {
929         double pps;
930         char b1[40];
931
932         printf("Received %" PRIu64 " packets, in %.2f seconds.\n", received, delta);
933
934         if (delta == 0)
935                 delta = 1e-6;
936         pps = received / delta;
937         printf("Speed: %spps\n", norm(b1, pps));
938 }
939
940 static void
941 usage(void)
942 {
943         const char *cmd = "pkt-gen";
944         fprintf(stderr,
945                 "Usage:\n"
946                 "%s arguments\n"
947                 "\t-i interface         interface name\n"
948                 "\t-f function          tx rx ping pong\n"
949                 "\t-n count             number of iterations (can be 0)\n"
950                 "\t-t pkts_to_send              also forces tx mode\n"
951                 "\t-r pkts_to_receive   also forces rx mode\n"
952                 "\t-l pkts_size         in bytes excluding CRC\n"
953                 "\t-d dst-ip            end with %%n to sweep n addresses\n"
954                 "\t-s src-ip            end with %%n to sweep n addresses\n"
955                 "\t-D dst-mac           end with %%n to sweep n addresses\n"
956                 "\t-S src-mac           end with %%n to sweep n addresses\n"
957                 "\t-a cpu_id            use setaffinity\n"
958                 "\t-b burst size                testing, mostly\n"
959                 "\t-c cores             cores to use\n"
960                 "\t-p threads           processes/threads to use\n"
961                 "\t-T report_ms         milliseconds between reports\n"
962                 "\t-P                           use libpcap instead of netmap\n"
963                 "\t-w wait_for_link_time        in seconds\n"
964                 "",
965                 cmd);
966
967         exit(0);
968 }
969
970 static void
971 start_threads(struct glob_arg *g)
972 {
973         int i;
974
975         targs = calloc(g->nthreads, sizeof(*targs));
976         /*
977          * Now create the desired number of threads, each one
978          * using a single descriptor.
979          */
980         for (i = 0; i < g->nthreads; i++) {
981                 bzero(&targs[i], sizeof(targs[i]));
982                 targs[i].fd = -1; /* default, with pcap */
983                 targs[i].g = g;
984
985             if (g->dev_type == DEV_NETMAP) {
986                 struct nmreq tifreq;
987                 int tfd;
988
989                 /* register interface. */
990                 tfd = open("/dev/netmap", O_RDWR);
991                 if (tfd == -1) {
992                         D("Unable to open /dev/netmap");
993                         continue;
994                 }
995                 targs[i].fd = tfd;
996
997                 bzero(&tifreq, sizeof(tifreq));
998                 strncpy(tifreq.nr_name, g->ifname, sizeof(tifreq.nr_name));
999                 tifreq.nr_version = NETMAP_API;
1000                 tifreq.nr_ringid = (g->nthreads > 1) ? (i | NETMAP_HW_RING) : 0;
1001
1002                 /*
1003                  * if we are acting as a receiver only, do not touch the transmit ring.
1004                  * This is not the default because many apps may use the interface
1005                  * in both directions, but a pure receiver does not.
1006                  */
1007                 if (g->td_body == receiver_body) {
1008                         tifreq.nr_ringid |= NETMAP_NO_TX_POLL;
1009                 }
1010
1011                 if ((ioctl(tfd, NIOCREGIF, &tifreq)) == -1) {
1012                         D("Unable to register %s", g->ifname);
1013                         continue;
1014                 }
1015                 targs[i].nmr = tifreq;
1016                 targs[i].nifp = NETMAP_IF(g->mmap_addr, tifreq.nr_offset);
1017                 /* start threads. */
1018                 targs[i].qfirst = (g->nthreads > 1) ? i : 0;
1019                 targs[i].qlast = (g->nthreads > 1) ? i+1 :
1020                         (g->td_body == receiver_body ? tifreq.nr_rx_rings : tifreq.nr_tx_rings);
1021             } else {
1022                 targs[i].fd = g->main_fd;
1023             }
1024                 targs[i].used = 1;
1025                 targs[i].me = i;
1026                 if (g->affinity >= 0) {
1027                         if (g->affinity < g->cpus)
1028                                 targs[i].affinity = g->affinity;
1029                         else
1030                                 targs[i].affinity = i % g->cpus;
1031                 } else
1032                         targs[i].affinity = -1;
1033                 /* default, init packets */
1034                 initialize_packet(&targs[i]);
1035
1036                 if (pthread_create(&targs[i].thread, NULL, g->td_body,
1037                                    &targs[i]) == -1) {
1038                         D("Unable to create thread %d", i);
1039                         targs[i].used = 0;
1040                 }
1041         }
1042 }
1043
1044 static void
1045 main_thread(struct glob_arg *g)
1046 {
1047         int i;
1048
1049         uint64_t prev = 0;
1050         uint64_t count = 0;
1051         double delta_t;
1052         struct timeval tic, toc;
1053
1054         gettimeofday(&toc, NULL);
1055         for (;;) {
1056                 struct timeval now, delta;
1057                 uint64_t pps, usec, my_count, npkts;
1058                 int done = 0;
1059
1060                 delta.tv_sec = g->report_interval/1000;
1061                 delta.tv_usec = (g->report_interval%1000)*1000;
1062                 select(0, NULL, NULL, NULL, &delta);
1063                 gettimeofday(&now, NULL);
1064                 time_second = now.tv_sec;
1065                 timersub(&now, &toc, &toc);
1066                 my_count = 0;
1067                 for (i = 0; i < g->nthreads; i++) {
1068                         my_count += targs[i].count;
1069                         if (targs[i].used == 0)
1070                                 done++;
1071                 }
1072                 usec = toc.tv_sec* 1000000 + toc.tv_usec;
1073                 if (usec < 10000)
1074                         continue;
1075                 npkts = my_count - prev;
1076                 pps = (npkts*1000000 + usec/2) / usec;
1077                 D("%" PRIu64 " pps (%" PRIu64 " pkts in %" PRIu64 " usec)",
1078                         pps, npkts, usec);
1079                 prev = my_count;
1080                 toc = now;
1081                 if (done == g->nthreads)
1082                         break;
1083         }
1084
1085         timerclear(&tic);
1086         timerclear(&toc);
1087         for (i = 0; i < g->nthreads; i++) {
1088                 /*
1089                  * Join active threads, unregister interfaces and close
1090                  * file descriptors.
1091                  */
1092                 pthread_join(targs[i].thread, NULL);
1093                 close(targs[i].fd);
1094
1095                 if (targs[i].completed == 0)
1096                         D("ouch, thread %d exited with error", i);
1097
1098                 /*
1099                  * Collect threads output and extract information about
1100                  * how long it took to send all the packets.
1101                  */
1102                 count += targs[i].count;
1103                 if (!timerisset(&tic) || timercmp(&targs[i].tic, &tic, <))
1104                         tic = targs[i].tic;
1105                 if (!timerisset(&toc) || timercmp(&targs[i].toc, &toc, >))
1106                         toc = targs[i].toc;
1107         }
1108
1109         /* print output. */
1110         timersub(&toc, &tic, &toc);
1111         delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
1112         if (g->td_body == sender_body)
1113                 tx_output(count, g->pkt_size, delta_t);
1114         else
1115                 rx_output(count, delta_t);
1116
1117         if (g->dev_type == DEV_NETMAP) {
1118                 ioctl(g->main_fd, NIOCUNREGIF, NULL); // XXX deprecated
1119                 munmap(g->mmap_addr, g->mmap_size);
1120                 close(g->main_fd);
1121         }
1122 }
1123
1124
1125 struct sf {
1126         char *key;
1127         void *f;
1128 };
1129
1130 static struct sf func[] = {
1131         { "tx", sender_body },
1132         { "rx", receiver_body },
1133         { "ping",       pinger_body },
1134         { "pong",       ponger_body },
1135         { NULL, NULL }
1136 };
1137
1138 static int
1139 tap_alloc(char *dev)
1140 {
1141         struct ifreq ifr;
1142         int fd, err;
1143         char *clonedev = TAP_CLONEDEV;
1144
1145         (void)err;
1146         (void)dev;
1147         /* Arguments taken by the function:
1148          *
1149          * char *dev: the name of an interface (or '\0'). MUST have enough
1150          *   space to hold the interface name if '\0' is passed
1151          * int flags: interface flags (eg, IFF_TUN etc.)
1152          */
1153
1154 #ifdef __FreeBSD__
1155         if (dev[3]) { /* tapSomething */
1156                 static char buf[128];
1157                 snprintf(buf, sizeof(buf), "/dev/%s", dev);
1158                 clonedev = buf;
1159         }
1160 #endif
1161         /* open the device */
1162         if( (fd = open(clonedev, O_RDWR)) < 0 ) {
1163                 return fd;
1164         }
1165         D("%s open successful", clonedev);
1166
1167         /* preparation of the struct ifr, of type "struct ifreq" */
1168         memset(&ifr, 0, sizeof(ifr));
1169
1170 #ifdef linux
1171         ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
1172
1173         if (*dev) {
1174                 /* if a device name was specified, put it in the structure; otherwise,
1175                 * the kernel will try to allocate the "next" device of the
1176                 * specified type */
1177                 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1178         }
1179
1180         /* try to create the device */
1181         if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
1182                 D("failed to to a TUNSETIFF");
1183                 close(fd);
1184                 return err;
1185         }
1186
1187         /* if the operation was successful, write back the name of the
1188         * interface to the variable "dev", so the caller can know
1189         * it. Note that the caller MUST reserve space in *dev (see calling
1190         * code below) */
1191         strcpy(dev, ifr.ifr_name);
1192         D("new name is %s", dev);
1193 #endif /* linux */
1194
1195         /* this is the special file descriptor that the caller will use to talk
1196          * with the virtual interface */
1197         return fd;
1198 }
1199
1200 int
1201 main(int arc, char **argv)
1202 {
1203         int i;
1204
1205         struct glob_arg g;
1206
1207         struct nmreq nmr;
1208         int ch;
1209         int wait_link = 2;
1210         int devqueues = 1;      /* how many device queues */
1211
1212         bzero(&g, sizeof(g));
1213
1214         g.main_fd = -1;
1215         g.td_body = receiver_body;
1216         g.report_interval = 1000;       /* report interval */
1217         g.affinity = -1;
1218         /* ip addresses can also be a range x.x.x.x-x.x.x.y */
1219         g.src_ip.name = "10.0.0.1";
1220         g.dst_ip.name = "10.1.0.1";
1221         g.dst_mac.name = "ff:ff:ff:ff:ff:ff";
1222         g.src_mac.name = NULL;
1223         g.pkt_size = 60;
1224         g.burst = 512;          // default
1225         g.nthreads = 1;
1226         g.cpus = 1;
1227
1228         while ( (ch = getopt(arc, argv,
1229                         "a:f:n:i:t:r:l:d:s:D:S:b:c:o:p:PT:w:Wv")) != -1) {
1230                 struct sf *fn;
1231
1232                 switch(ch) {
1233                 default:
1234                         D("bad option %c %s", ch, optarg);
1235                         usage();
1236                         break;
1237
1238                 case 'n':
1239                         g.npackets = atoi(optarg);
1240                         break;
1241
1242                 case 'f':
1243                         for (fn = func; fn->key; fn++) {
1244                                 if (!strcmp(fn->key, optarg))
1245                                         break;
1246                         }
1247                         if (fn->key)
1248                                 g.td_body = fn->f;
1249                         else
1250                                 D("unrecognised function %s", optarg);
1251                         break;
1252
1253                 case 'o':       /* data generation options */
1254                         g.options = atoi(optarg);
1255                         break;
1256
1257                 case 'a':       /* force affinity */
1258                         g.affinity = atoi(optarg);
1259                         break;
1260
1261                 case 'i':       /* interface */
1262                         g.ifname = optarg;
1263                         if (!strncmp(optarg, "tap", 3))
1264                                 g.dev_type = DEV_TAP;
1265                         else
1266                                 g.dev_type = DEV_NETMAP;
1267                         break;
1268
1269                 case 't':       /* send, deprecated */
1270                         D("-t deprecated, please use -f tx -n %s", optarg);
1271                         g.td_body = sender_body;
1272                         g.npackets = atoi(optarg);
1273                         break;
1274
1275                 case 'r':       /* receive */
1276                         D("-r deprecated, please use -f rx -n %s", optarg);
1277                         g.td_body = receiver_body;
1278                         g.npackets = atoi(optarg);
1279                         break;
1280
1281                 case 'l':       /* pkt_size */
1282                         g.pkt_size = atoi(optarg);
1283                         break;
1284
1285                 case 'd':
1286                         g.dst_ip.name = optarg;
1287                         break;
1288
1289                 case 's':
1290                         g.src_ip.name = optarg;
1291                         break;
1292
1293                 case 'T':       /* report interval */
1294                         g.report_interval = atoi(optarg);
1295                         break;
1296
1297                 case 'w':
1298                         wait_link = atoi(optarg);
1299                         break;
1300
1301                 case 'W':
1302                         g.forever = 1; /* do not exit rx even with no traffic */
1303                         break;
1304
1305                 case 'b':       /* burst */
1306                         g.burst = atoi(optarg);
1307                         break;
1308                 case 'c':
1309                         g.cpus = atoi(optarg);
1310                         break;
1311                 case 'p':
1312                         g.nthreads = atoi(optarg);
1313                         break;
1314
1315                 case 'P':
1316                         g.dev_type = DEV_PCAP;
1317                         break;
1318
1319                 case 'D': /* destination mac */
1320                         g.dst_mac.name = optarg;
1321                         break;
1322
1323                 case 'S': /* source mac */
1324                         g.src_mac.name = optarg;
1325                         break;
1326                 case 'v':
1327                         verbose++;
1328                 }
1329         }
1330
1331         if (g.ifname == NULL) {
1332                 D("missing ifname");
1333                 usage();
1334         }
1335
1336         i = system_ncpus();
1337         if (g.cpus < 0 || g.cpus > i) {
1338                 D("%d cpus is too high, have only %d cpus", g.cpus, i);
1339                 usage();
1340         }
1341         if (g.cpus == 0)
1342                 g.cpus = i;
1343
1344         if (g.pkt_size < 16 || g.pkt_size > 1536) {
1345                 D("bad pktsize %d\n", g.pkt_size);
1346                 usage();
1347         }
1348
1349         if (g.src_mac.name == NULL) {
1350                 static char mybuf[20] = "00:00:00:00:00:00";
1351                 /* retrieve source mac address. */
1352                 if (source_hwaddr(g.ifname, mybuf) == -1) {
1353                         D("Unable to retrieve source mac");
1354                         // continue, fail later
1355                 }
1356                 g.src_mac.name = mybuf;
1357         }
1358         /* extract address ranges */
1359         extract_ip_range(&g.src_ip);
1360         extract_ip_range(&g.dst_ip);
1361         extract_mac_range(&g.src_mac);
1362         extract_mac_range(&g.dst_mac);
1363
1364     if (g.dev_type == DEV_TAP) {
1365         D("want to use tap %s", g.ifname);
1366         g.main_fd = tap_alloc(g.ifname);
1367         if (g.main_fd < 0) {
1368                 D("cannot open tap %s", g.ifname);
1369                 usage();
1370         }
1371     } else if (g.dev_type > DEV_NETMAP) {
1372         char pcap_errbuf[PCAP_ERRBUF_SIZE];
1373
1374         D("using pcap on %s", g.ifname);
1375         pcap_errbuf[0] = '\0'; // init the buffer
1376         g.p = pcap_open_live(g.ifname, 0, 1, 100, pcap_errbuf);
1377         if (g.p == NULL) {
1378                 D("cannot open pcap on %s", g.ifname);
1379                 usage();
1380         }
1381     } else {
1382         bzero(&nmr, sizeof(nmr));
1383         nmr.nr_version = NETMAP_API;
1384         /*
1385          * Open the netmap device to fetch the number of queues of our
1386          * interface.
1387          *
1388          * The first NIOCREGIF also detaches the card from the
1389          * protocol stack and may cause a reset of the card,
1390          * which in turn may take some time for the PHY to
1391          * reconfigure.
1392          */
1393         g.main_fd = open("/dev/netmap", O_RDWR);
1394         if (g.main_fd == -1) {
1395                 D("Unable to open /dev/netmap");
1396                 // fail later
1397         } else {
1398                 if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) {
1399                         D("Unable to get if info without name");
1400                 } else {
1401                         D("map size is %d Kb", nmr.nr_memsize >> 10);
1402                 }
1403                 bzero(&nmr, sizeof(nmr));
1404                 nmr.nr_version = NETMAP_API;
1405                 strncpy(nmr.nr_name, g.ifname, sizeof(nmr.nr_name));
1406                 if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) {
1407                         D("Unable to get if info for %s", g.ifname);
1408                 }
1409                 devqueues = nmr.nr_rx_rings;
1410         }
1411
1412         /* validate provided nthreads. */
1413         if (g.nthreads < 1 || g.nthreads > devqueues) {
1414                 D("bad nthreads %d, have %d queues", g.nthreads, devqueues);
1415                 // continue, fail later
1416         }
1417
1418         /*
1419          * Map the netmap shared memory: instead of issuing mmap()
1420          * inside the body of the threads, we prefer to keep this
1421          * operation here to simplify the thread logic.
1422          */
1423         D("mapping %d Kbytes", nmr.nr_memsize>>10);
1424         g.mmap_size = nmr.nr_memsize;
1425         g.mmap_addr = (struct netmap_d *) mmap(0, nmr.nr_memsize,
1426                                             PROT_WRITE | PROT_READ,
1427                                             MAP_SHARED, g.main_fd, 0);
1428         if (g.mmap_addr == MAP_FAILED) {
1429                 D("Unable to mmap %d KB", nmr.nr_memsize >> 10);
1430                 // continue, fail later
1431         }
1432
1433         /*
1434          * Register the interface on the netmap device: from now on,
1435          * we can operate on the network interface without any
1436          * interference from the legacy network stack.
1437          *
1438          * We decide to put the first interface registration here to
1439          * give time to cards that take a long time to reset the PHY.
1440          */
1441         nmr.nr_version = NETMAP_API;
1442         if (ioctl(g.main_fd, NIOCREGIF, &nmr) == -1) {
1443                 D("Unable to register interface %s", g.ifname);
1444                 //continue, fail later
1445         }
1446
1447
1448         /* Print some debug information. */
1449         fprintf(stdout,
1450                 "%s %s: %d queues, %d threads and %d cpus.\n",
1451                 (g.td_body == sender_body) ? "Sending on" : "Receiving from",
1452                 g.ifname,
1453                 devqueues,
1454                 g.nthreads,
1455                 g.cpus);
1456         if (g.td_body == sender_body) {
1457                 fprintf(stdout, "%s -> %s (%s -> %s)\n",
1458                         g.src_ip.name, g.dst_ip.name,
1459                         g.src_mac.name, g.dst_mac.name);
1460         }
1461                         
1462         /* Exit if something went wrong. */
1463         if (g.main_fd < 0) {
1464                 D("aborting");
1465                 usage();
1466         }
1467     }
1468
1469         if (g.options) {
1470                 D("special options:%s%s%s%s\n",
1471                         g.options & OPT_PREFETCH ? " prefetch" : "",
1472                         g.options & OPT_ACCESS ? " access" : "",
1473                         g.options & OPT_MEMCPY ? " memcpy" : "",
1474                         g.options & OPT_COPY ? " copy" : "");
1475         }
1476         /* Wait for PHY reset. */
1477         D("Wait %d secs for phy reset", wait_link);
1478         sleep(wait_link);
1479         D("Ready...");
1480
1481         /* Install ^C handler. */
1482         global_nthreads = g.nthreads;
1483         signal(SIGINT, sigint_h);
1484
1485 #if 0 // XXX this is not needed, i believe
1486         if (g.dev_type > DEV_NETMAP) {
1487                 g.p = pcap_open_live(g.ifname, 0, 1, 100, NULL);
1488                 if (g.p == NULL) {
1489                         D("cannot open pcap on %s", g.ifname);
1490                         usage();
1491                 } else
1492                         D("using pcap %p on %s", g.p, g.ifname);
1493         }
1494 #endif // XXX
1495         start_threads(&g);
1496         main_thread(&g);
1497         return 0;
1498 }
1499
1500 /* end of file */