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