]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - tools/tools/netmap/pkt-gen.c
MFC: import netmap core files into RELENG_9.
[FreeBSD/stable/9.git] / tools / tools / netmap / pkt-gen.c
1 /*
2  * Copyright (C) 2011 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 9827 2011-12-05 11:29:34Z 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 const char *default_payload="netmap pkt-gen Luigi Rizzo and Matteo Landi\n"
40         "http://info.iet.unipi.it/~luigi/netmap/ ";
41
42 #include <errno.h>
43 #include <pthread.h>    /* pthread_* */
44 #include <pthread_np.h> /* pthread w/ affinity */
45 #include <signal.h>     /* signal */
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <inttypes.h>   /* PRI* macros */
49 #include <string.h>     /* strcmp */
50 #include <fcntl.h>      /* open */
51 #include <unistd.h>     /* close */
52 #include <ifaddrs.h>    /* getifaddrs */
53
54 #include <sys/mman.h>   /* PROT_* */
55 #include <sys/ioctl.h>  /* ioctl */
56 #include <sys/poll.h>
57 #include <sys/socket.h> /* sockaddr.. */
58 #include <arpa/inet.h>  /* ntohs */
59 #include <sys/param.h>
60 #include <sys/cpuset.h> /* cpu_set */
61 #include <sys/sysctl.h> /* sysctl */
62 #include <sys/time.h>   /* timersub */
63
64 #include <net/ethernet.h>
65 #include <net/if.h>     /* ifreq */
66 #include <net/if_dl.h>  /* LLADDR */
67
68 #include <netinet/in.h>
69 #include <netinet/ip.h>
70 #include <netinet/udp.h>
71
72 #include <net/netmap.h>
73 #include <net/netmap_user.h>
74 #include <pcap/pcap.h>
75
76
77 static inline int min(int a, int b) { return a < b ? a : b; }
78
79 /* debug support */
80 #define D(format, ...)                          \
81         fprintf(stderr, "%s [%d] " format "\n",         \
82         __FUNCTION__, __LINE__, ##__VA_ARGS__)
83
84 #ifndef EXPERIMENTAL
85 #define EXPERIMENTAL 0
86 #endif
87
88 int verbose = 0;
89 #define MAX_QUEUES 64   /* no need to limit */
90
91 #define SKIP_PAYLOAD 1 /* do not check payload. */
92
93 #if EXPERIMENTAL
94 /* Wrapper around `rdtsc' to take reliable timestamps flushing the pipeline */ 
95 #define netmap_rdtsc(t) \
96         do { \
97                 u_int __regs[4];                                        \
98                                                                         \
99                 do_cpuid(0, __regs);                                    \
100                 (t) = rdtsc();                                          \
101         } while (0)
102
103 static __inline void
104 do_cpuid(u_int ax, u_int *p)
105 {
106         __asm __volatile("cpuid"
107                          : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
108                          :  "0" (ax));
109 }
110
111 static __inline uint64_t
112 rdtsc(void)
113 {
114         uint64_t rv;
115
116         __asm __volatile("rdtsc" : "=A" (rv));
117         return (rv);
118 }
119 #define MAX_SAMPLES 100000
120 #endif /* EXPERIMENTAL */
121
122
123 struct pkt {
124         struct ether_header eh;
125         struct ip ip;
126         struct udphdr udp;
127         uint8_t body[2048];     // XXX hardwired
128 } __attribute__((__packed__));
129
130 /*
131  * global arguments for all threads
132  */
133 struct glob_arg {
134         const char *src_ip;
135         const char *dst_ip;
136         const char *src_mac;
137         const char *dst_mac;
138         int pkt_size;
139         int burst;
140         int npackets;   /* total packets to send */
141         int nthreads;
142         int cpus;
143         int use_pcap;
144         pcap_t *p;
145 };
146
147 struct mystat {
148         uint64_t containers[8];
149 };
150
151 /*
152  * Arguments for a new thread. The same structure is used by
153  * the source and the sink
154  */
155 struct targ {
156         struct glob_arg *g;
157         int used;
158         int completed;
159         int fd;
160         struct nmreq nmr;
161         struct netmap_if *nifp;
162         uint16_t        qfirst, qlast; /* range of queues to scan */
163         uint64_t count;
164         struct timeval tic, toc;
165         int me;
166         pthread_t thread;
167         int affinity;
168
169         uint8_t dst_mac[6];
170         uint8_t src_mac[6];
171         u_int dst_mac_range;
172         u_int src_mac_range;
173         uint32_t dst_ip;
174         uint32_t src_ip;
175         u_int dst_ip_range;
176         u_int src_ip_range;
177
178         struct pkt pkt;
179 };
180
181
182 static struct targ *targs;
183 static int global_nthreads;
184
185 /* control-C handler */
186 static void
187 sigint_h(__unused int sig)
188 {
189         for (int i = 0; i < global_nthreads; i++) {
190                 /* cancel active threads. */
191                 if (targs[i].used == 0)
192                         continue;
193
194                 D("Cancelling thread #%d\n", i);
195                 pthread_cancel(targs[i].thread);
196                 targs[i].used = 0;
197         }
198
199         signal(SIGINT, SIG_DFL);
200 }
201
202
203 /* sysctl wrapper to return the number of active CPUs */
204 static int
205 system_ncpus(void)
206 {
207         int mib[2], ncpus;
208         size_t len;
209
210         mib[0] = CTL_HW;
211         mib[1] = HW_NCPU;
212         len = sizeof(mib);
213         sysctl(mib, 2, &ncpus, &len, NULL, 0);
214
215         return (ncpus);
216 }
217
218 /*
219  * locate the src mac address for our interface, put it
220  * into the user-supplied buffer. return 0 if ok, -1 on error.
221  */
222 static int
223 source_hwaddr(const char *ifname, char *buf)
224 {
225         struct ifaddrs *ifaphead, *ifap;
226         int l = sizeof(ifap->ifa_name);
227
228         if (getifaddrs(&ifaphead) != 0) {
229                 D("getifaddrs %s failed", ifname);
230                 return (-1);
231         }
232
233         for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
234                 struct sockaddr_dl *sdl =
235                         (struct sockaddr_dl *)ifap->ifa_addr;
236                 uint8_t *mac;
237
238                 if (!sdl || sdl->sdl_family != AF_LINK)
239                         continue;
240                 if (strncmp(ifap->ifa_name, ifname, l) != 0)
241                         continue;
242                 mac = (uint8_t *)LLADDR(sdl);
243                 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
244                         mac[0], mac[1], mac[2],
245                         mac[3], mac[4], mac[5]);
246                 if (verbose)
247                         D("source hwaddr %s", buf);
248                 break;
249         }
250         freeifaddrs(ifaphead);
251         return ifap ? 0 : 1;
252 }
253
254
255 /* set the thread affinity. */
256 static int
257 setaffinity(pthread_t me, int i)
258 {
259         cpuset_t cpumask;
260
261         if (i == -1)
262                 return 0;
263
264         /* Set thread affinity affinity.*/
265         CPU_ZERO(&cpumask);
266         CPU_SET(i, &cpumask);
267
268         if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
269                 D("Unable to set affinity");
270                 return 1;
271         }
272         return 0;
273 }
274
275 /* Compute the checksum of the given ip header. */
276 static uint16_t
277 checksum(const void *data, uint16_t len)
278 {
279         const uint8_t *addr = data;
280         uint32_t sum = 0;
281
282         while (len > 1) {
283                 sum += addr[0] * 256 + addr[1];
284                 addr += 2;
285                 len -= 2;
286         }
287
288         if (len == 1)
289                 sum += *addr * 256;
290
291         sum = (sum >> 16) + (sum & 0xffff);
292         sum += (sum >> 16);
293
294         sum = htons(sum);
295
296         return ~sum;
297 }
298
299 /*
300  * Fill a packet with some payload.
301  */
302 static void
303 initialize_packet(struct targ *targ)
304 {
305         struct pkt *pkt = &targ->pkt;
306         struct ether_header *eh;
307         struct ip *ip;
308         struct udphdr *udp;
309         uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(*ip);
310         int i, l, l0 = strlen(default_payload);
311         char *p;
312
313         for (i = 0; i < paylen;) {
314                 l = min(l0, paylen - i);
315                 bcopy(default_payload, pkt->body + i, l);
316                 i += l;
317         }
318         pkt->body[i-1] = '\0';
319
320         udp = &pkt->udp;
321         udp->uh_sport = htons(1234);
322         udp->uh_dport = htons(4321);
323         udp->uh_ulen = htons(paylen);
324         udp->uh_sum = 0; // checksum(udp, sizeof(*udp));
325
326         ip = &pkt->ip;
327         ip->ip_v = IPVERSION;
328         ip->ip_hl = 5;
329         ip->ip_id = 0;
330         ip->ip_tos = IPTOS_LOWDELAY;
331         ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh));
332         ip->ip_id = 0;
333         ip->ip_off = htons(IP_DF); /* Don't fragment */
334         ip->ip_ttl = IPDEFTTL;
335         ip->ip_p = IPPROTO_UDP;
336         inet_aton(targ->g->src_ip, (struct in_addr *)&ip->ip_src);
337         inet_aton(targ->g->dst_ip, (struct in_addr *)&ip->ip_dst);
338         targ->dst_ip = ip->ip_dst.s_addr;
339         targ->src_ip = ip->ip_src.s_addr;
340         p = index(targ->g->src_ip, '-');
341         if (p) {
342                 targ->dst_ip_range = atoi(p+1);
343                 D("dst-ip sweep %d addresses", targ->dst_ip_range);
344         }
345         ip->ip_sum = checksum(ip, sizeof(*ip));
346
347         eh = &pkt->eh;
348         bcopy(ether_aton(targ->g->src_mac), targ->src_mac, 6);
349         bcopy(targ->src_mac, eh->ether_shost, 6);
350         p = index(targ->g->src_mac, '-');
351         if (p)
352                 targ->src_mac_range = atoi(p+1);
353
354         bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6);
355         bcopy(targ->dst_mac, eh->ether_dhost, 6);
356         p = index(targ->g->dst_mac, '-');
357         if (p)
358                 targ->dst_mac_range = atoi(p+1);
359         eh->ether_type = htons(ETHERTYPE_IP);
360 }
361
362 /* Check the payload of the packet for errors (use it for debug).
363  * Look for consecutive ascii representations of the size of the packet.
364  */
365 static void
366 check_payload(char *p, int psize)
367 {
368         char temp[64];
369         int n_read, size, sizelen;
370
371         /* get the length in ASCII of the length of the packet. */
372         sizelen = sprintf(temp, "%d", psize) + 1; // include a whitespace
373
374         /* dummy payload. */
375         p += 14; /* skip packet header. */
376         n_read = 14;
377         while (psize - n_read >= sizelen) {
378                 sscanf(p, "%d", &size);
379                 if (size != psize) {
380                         D("Read %d instead of %d", size, psize);
381                         break;
382                 }
383
384                 p += sizelen;
385                 n_read += sizelen;
386         }
387 }
388
389
390 /*
391  * create and enqueue a batch of packets on a ring.
392  * On the last one set NS_REPORT to tell the driver to generate
393  * an interrupt when done.
394  */
395 static int
396 send_packets(struct netmap_ring *ring, struct pkt *pkt, 
397                 int size, u_int count, int fill_all)
398 {
399         u_int sent, cur = ring->cur;
400
401         if (ring->avail < count)
402                 count = ring->avail;
403
404         for (sent = 0; sent < count; sent++) {
405                 struct netmap_slot *slot = &ring->slot[cur];
406                 char *p = NETMAP_BUF(ring, slot->buf_idx);
407
408                 if (fill_all)
409                         memcpy(p, pkt, size);
410
411                 slot->len = size;
412                 if (sent == count - 1)
413                         slot->flags |= NS_REPORT;
414                 cur = NETMAP_RING_NEXT(ring, cur);
415         }
416         ring->avail -= sent;
417         ring->cur = cur;
418
419         return (sent);
420 }
421
422 static void *
423 sender_body(void *data)
424 {
425         struct targ *targ = (struct targ *) data;
426
427         struct pollfd fds[1];
428         struct netmap_if *nifp = targ->nifp;
429         struct netmap_ring *txring;
430         int i, n = targ->g->npackets / targ->g->nthreads, sent = 0;
431         int fill_all = 1;
432
433         if (setaffinity(targ->thread, targ->affinity))
434                 goto quit;
435         /* setup poll(2) mechanism. */
436         memset(fds, 0, sizeof(fds));
437         fds[0].fd = targ->fd;
438         fds[0].events = (POLLOUT);
439
440         /* main loop.*/
441         gettimeofday(&targ->tic, NULL);
442     if (targ->g->use_pcap) {
443         int size = targ->g->pkt_size;
444         void *pkt = &targ->pkt;
445         pcap_t *p = targ->g->p;
446
447         for (; sent < n; sent++) {
448                 if (pcap_inject(p, pkt, size) == -1)
449                         break;
450         }
451     } else {
452         while (sent < n) {
453
454                 /*
455                  * wait for available room in the send queue(s)
456                  */
457                 if (poll(fds, 1, 2000) <= 0) {
458                         D("poll error/timeout on queue %d\n", targ->me);
459                         goto quit;
460                 }
461                 /*
462                  * scan our queues and send on those with room
463                  */
464                 if (sent > 100000)
465                         fill_all = 0;
466                 for (i = targ->qfirst; i < targ->qlast; i++) {
467                         int m, limit = MIN(n - sent, targ->g->burst);
468
469                         txring = NETMAP_TXRING(nifp, i);
470                         if (txring->avail == 0)
471                                 continue;
472                         m = send_packets(txring, &targ->pkt, targ->g->pkt_size,
473                                          limit, fill_all);
474                         sent += m;
475                         targ->count = sent;
476                 }
477         }
478         /* Tell the interface that we have new packets. */
479         ioctl(fds[0].fd, NIOCTXSYNC, NULL);
480
481         /* final part: wait all the TX queues to be empty. */
482         for (i = targ->qfirst; i < targ->qlast; i++) {
483                 txring = NETMAP_TXRING(nifp, i);
484                 while (!NETMAP_TX_RING_EMPTY(txring)) {
485                         ioctl(fds[0].fd, NIOCTXSYNC, NULL);
486                         usleep(1); /* wait 1 tick */
487                 }
488         }
489     }
490
491         gettimeofday(&targ->toc, NULL);
492         targ->completed = 1;
493         targ->count = sent;
494
495 quit:
496         /* reset the ``used`` flag. */
497         targ->used = 0;
498
499         return (NULL);
500 }
501
502
503 static void
504 receive_pcap(u_char *user, __unused const struct pcap_pkthdr * h,
505         __unused const u_char * bytes)
506 {
507         int *count = (int *)user;
508         (*count)++;
509 }
510
511 static int
512 receive_packets(struct netmap_ring *ring, u_int limit, int skip_payload)
513 {
514         u_int cur, rx;
515
516         cur = ring->cur;
517         if (ring->avail < limit)
518                 limit = ring->avail;
519         for (rx = 0; rx < limit; rx++) {
520                 struct netmap_slot *slot = &ring->slot[cur];
521                 char *p = NETMAP_BUF(ring, slot->buf_idx);
522
523                 if (!skip_payload)
524                         check_payload(p, slot->len);
525
526                 cur = NETMAP_RING_NEXT(ring, cur);
527         }
528         ring->avail -= rx;
529         ring->cur = cur;
530
531         return (rx);
532 }
533
534 static void *
535 receiver_body(void *data)
536 {
537         struct targ *targ = (struct targ *) data;
538         struct pollfd fds[1];
539         struct netmap_if *nifp = targ->nifp;
540         struct netmap_ring *rxring;
541         int i, received = 0;
542
543         if (setaffinity(targ->thread, targ->affinity))
544                 goto quit;
545
546         /* setup poll(2) mechanism. */
547         memset(fds, 0, sizeof(fds));
548         fds[0].fd = targ->fd;
549         fds[0].events = (POLLIN);
550
551         /* unbounded wait for the first packet. */
552         for (;;) {
553                 i = poll(fds, 1, 1000);
554                 if (i > 0 && !(fds[0].revents & POLLERR))
555                         break;
556                 D("waiting for initial packets, poll returns %d %d", i, fds[0].revents);
557         }
558
559         /* main loop, exit after 1s silence */
560         gettimeofday(&targ->tic, NULL);
561     if (targ->g->use_pcap) {
562         for (;;) {
563                 pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL);
564         }
565     } else {
566         while (1) {
567                 /* Once we started to receive packets, wait at most 1 seconds
568                    before quitting. */
569                 if (poll(fds, 1, 1 * 1000) <= 0) {
570                         gettimeofday(&targ->toc, NULL);
571                         targ->toc.tv_sec -= 1; /* Subtract timeout time. */
572                         break;
573                 }
574
575                 for (i = targ->qfirst; i < targ->qlast; i++) {
576                         int m;
577
578                         rxring = NETMAP_RXRING(nifp, i);
579                         if (rxring->avail == 0)
580                                 continue;
581
582                         m = receive_packets(rxring, targ->g->burst,
583                                         SKIP_PAYLOAD);
584                         received += m;
585                         targ->count = received;
586                 }
587
588                 // tell the card we have read the data
589                 //ioctl(fds[0].fd, NIOCRXSYNC, NULL);
590         }
591     }
592
593         targ->completed = 1;
594         targ->count = received;
595
596 quit:
597         /* reset the ``used`` flag. */
598         targ->used = 0;
599
600         return (NULL);
601 }
602
603 static void
604 tx_output(uint64_t sent, int size, double delta)
605 {
606         double amount = 8.0 * (1.0 * size * sent) / delta;
607         double pps = sent / delta;
608         char units[4] = { '\0', 'K', 'M', 'G' };
609         int aunit = 0, punit = 0;
610
611         while (amount >= 1000) {
612                 amount /= 1000;
613                 aunit += 1;
614         }
615         while (pps >= 1000) {
616                 pps /= 1000;
617                 punit += 1;
618         }
619
620         printf("Sent %" PRIu64 " packets, %d bytes each, in %.2f seconds.\n",
621                sent, size, delta);
622         printf("Speed: %.2f%cpps. Bandwidth: %.2f%cbps.\n",
623                pps, units[punit], amount, units[aunit]);
624 }
625
626
627 static void
628 rx_output(uint64_t received, double delta)
629 {
630
631         double pps = received / delta;
632         char units[4] = { '\0', 'K', 'M', 'G' };
633         int punit = 0;
634
635         while (pps >= 1000) {
636                 pps /= 1000;
637                 punit += 1;
638         }
639
640         printf("Received %" PRIu64 " packets, in %.2f seconds.\n", received, delta);
641         printf("Speed: %.2f%cpps.\n", pps, units[punit]);
642 }
643
644 static void
645 usage(void)
646 {
647         const char *cmd = "pkt-gen";
648         fprintf(stderr,
649                 "Usage:\n"
650                 "%s arguments\n"
651                 "\t-i interface         interface name\n"
652                 "\t-t pkts_to_send      also forces send mode\n"
653                 "\t-r pkts_to_receive   also forces receive mode\n"
654                 "\t-l pkts_size         in bytes excluding CRC\n"
655                 "\t-d dst-ip            end with %%n to sweep n addresses\n"
656                 "\t-s src-ip            end with %%n to sweep n addresses\n"
657                 "\t-D dst-mac           end with %%n to sweep n addresses\n"
658                 "\t-S src-mac           end with %%n to sweep n addresses\n"
659                 "\t-b burst size                testing, mostly\n"
660                 "\t-c cores             cores to use\n"
661                 "\t-p threads           processes/threads to use\n"
662                 "\t-T report_ms         milliseconds between reports\n"
663                 "\t-w wait_for_link_time        in seconds\n"
664                 "",
665                 cmd);
666
667         exit(0);
668 }
669
670
671 int
672 main(int arc, char **argv)
673 {
674         int i, fd;
675
676         struct glob_arg g;
677
678         struct nmreq nmr;
679         void *mmap_addr;                /* the mmap address */
680         void *(*td_body)(void *) = receiver_body;
681         int ch;
682         int report_interval = 1000;     /* report interval */
683         char *ifname = NULL;
684         int wait_link = 2;
685         int devqueues = 1;      /* how many device queues */
686
687         bzero(&g, sizeof(g));
688
689         g.src_ip = "10.0.0.1";
690         g.dst_ip = "10.1.0.1";
691         g.dst_mac = "ff:ff:ff:ff:ff:ff";
692         g.src_mac = NULL;
693         g.pkt_size = 60;
694         g.burst = 512;          // default
695         g.nthreads = 1;
696         g.cpus = 1;
697
698         while ( (ch = getopt(arc, argv,
699                         "i:t:r:l:d:s:D:S:b:c:p:T:w:v")) != -1) {
700                 switch(ch) {
701                 default:
702                         D("bad option %c %s", ch, optarg);
703                         usage();
704                         break;
705                 case 'i':       /* interface */
706                         ifname = optarg;
707                         break;
708                 case 't':       /* send */
709                         td_body = sender_body;
710                         g.npackets = atoi(optarg);
711                         break;
712                 case 'r':       /* receive */
713                         td_body = receiver_body;
714                         g.npackets = atoi(optarg);
715                         break;
716                 case 'l':       /* pkt_size */
717                         g.pkt_size = atoi(optarg);
718                         break;
719                 case 'd':
720                         g.dst_ip = optarg;
721                         break;
722                 case 's':
723                         g.src_ip = optarg;
724                         break;
725                 case 'T':       /* report interval */
726                         report_interval = atoi(optarg);
727                         break;
728                 case 'w':
729                         wait_link = atoi(optarg);
730                         break;
731                 case 'b':       /* burst */
732                         g.burst = atoi(optarg);
733                         break;
734                 case 'c':
735                         g.cpus = atoi(optarg);
736                         break;
737                 case 'p':
738                         g.nthreads = atoi(optarg);
739                         break;
740
741                 case 'P':
742                         g.use_pcap = 1;
743                         break;
744
745                 case 'D': /* destination mac */
746                         g.dst_mac = optarg;
747         {
748                 struct ether_addr *mac = ether_aton(g.dst_mac);
749                 D("ether_aton(%s) gives %p", g.dst_mac, mac);
750         }
751                         break;
752                 case 'S': /* source mac */
753                         g.src_mac = optarg;
754                         break;
755                 case 'v':
756                         verbose++;
757                 }
758         }
759
760         if (ifname == NULL) {
761                 D("missing ifname");
762                 usage();
763         }
764         {
765                 int n = system_ncpus();
766                 if (g.cpus < 0 || g.cpus > n) {
767                         D("%d cpus is too high, have only %d cpus", g.cpus, n);
768                         usage();
769                 }
770                 if (g.cpus == 0)
771                         g.cpus = n;
772         }
773         if (g.pkt_size < 16 || g.pkt_size > 1536) {
774                 D("bad pktsize %d\n", g.pkt_size);
775                 usage();
776         }
777
778         bzero(&nmr, sizeof(nmr));
779         /*
780          * Open the netmap device to fetch the number of queues of our
781          * interface.
782          *
783          * The first NIOCREGIF also detaches the card from the
784          * protocol stack and may cause a reset of the card,
785          * which in turn may take some time for the PHY to
786          * reconfigure.
787          */
788         fd = open("/dev/netmap", O_RDWR);
789         if (fd == -1) {
790                 D("Unable to open /dev/netmap");
791                 // fail later
792         } else {
793                 if ((ioctl(fd, NIOCGINFO, &nmr)) == -1) {
794                         D("Unable to get if info without name");
795                 } else {
796                         D("map size is %d Kb", nmr.nr_memsize >> 10);
797                 }
798                 bzero(&nmr, sizeof(nmr));
799                 strncpy(nmr.nr_name, ifname, sizeof(nmr.nr_name));
800                 if ((ioctl(fd, NIOCGINFO, &nmr)) == -1) {
801                         D("Unable to get if info for %s", ifname);
802                 }
803                 devqueues = nmr.nr_numrings;
804         }
805
806         /* validate provided nthreads. */
807         if (g.nthreads < 1 || g.nthreads > devqueues) {
808                 D("bad nthreads %d, have %d queues", g.nthreads, devqueues);
809                 // continue, fail later
810         }
811
812         if (td_body == sender_body && g.src_mac == NULL) {
813                 static char mybuf[20] = "ff:ff:ff:ff:ff:ff";
814                 /* retrieve source mac address. */
815                 if (source_hwaddr(ifname, mybuf) == -1) {
816                         D("Unable to retrieve source mac");
817                         // continue, fail later
818                 }
819                 g.src_mac = mybuf;
820         }
821
822         /*
823          * Map the netmap shared memory: instead of issuing mmap()
824          * inside the body of the threads, we prefer to keep this
825          * operation here to simplify the thread logic.
826          */
827         D("mmapping %d Kbytes", nmr.nr_memsize>>10);
828         mmap_addr = (struct netmap_d *) mmap(0, nmr.nr_memsize,
829                                             PROT_WRITE | PROT_READ,
830                                             MAP_SHARED, fd, 0);
831         if (mmap_addr == MAP_FAILED) {
832                 D("Unable to mmap %d KB", nmr.nr_memsize >> 10);
833                 // continue, fail later
834         }
835
836         /*
837          * Register the interface on the netmap device: from now on,
838          * we can operate on the network interface without any
839          * interference from the legacy network stack.
840          *
841          * We decide to put the first interface registration here to
842          * give time to cards that take a long time to reset the PHY.
843          */
844         if (ioctl(fd, NIOCREGIF, &nmr) == -1) {
845                 D("Unable to register interface %s", ifname);
846                 //continue, fail later
847         }
848
849
850         /* Print some debug information. */
851         fprintf(stdout,
852                 "%s %s: %d queues, %d threads and %d cpus.\n",
853                 (td_body == sender_body) ? "Sending on" : "Receiving from",
854                 ifname,
855                 devqueues,
856                 g.nthreads,
857                 g.cpus);
858         if (td_body == sender_body) {
859                 fprintf(stdout, "%s -> %s (%s -> %s)\n",
860                         g.src_ip, g.dst_ip,
861                         g.src_mac, g.dst_mac);
862         }
863                         
864         /* Exit if something went wrong. */
865         if (fd < 0) {
866                 D("aborting");
867                 usage();
868         }
869
870
871         /* Wait for PHY reset. */
872         D("Wait %d secs for phy reset", wait_link);
873         sleep(wait_link);
874         D("Ready...");
875
876         /* Install ^C handler. */
877         global_nthreads = g.nthreads;
878         signal(SIGINT, sigint_h);
879
880         if (g.use_pcap) {
881                 // XXX g.p = pcap_open_live(..);
882         }
883
884         targs = calloc(g.nthreads, sizeof(*targs));
885         /*
886          * Now create the desired number of threads, each one
887          * using a single descriptor.
888          */
889         for (i = 0; i < g.nthreads; i++) {
890                 struct netmap_if *tnifp;
891                 struct nmreq tifreq;
892                 int tfd;
893
894             if (g.use_pcap) {
895                 tfd = -1;
896                 tnifp = NULL;
897             } else {
898                 /* register interface. */
899                 tfd = open("/dev/netmap", O_RDWR);
900                 if (tfd == -1) {
901                         D("Unable to open /dev/netmap");
902                         continue;
903                 }
904
905                 bzero(&tifreq, sizeof(tifreq));
906                 strncpy(tifreq.nr_name, ifname, sizeof(tifreq.nr_name));
907                 tifreq.nr_ringid = (g.nthreads > 1) ? (i | NETMAP_HW_RING) : 0;
908
909                 /*
910                  * if we are acting as a receiver only, do not touch the transmit ring.
911                  * This is not the default because many apps may use the interface
912                  * in both directions, but a pure receiver does not.
913                  */
914                 if (td_body == receiver_body) {
915                         tifreq.nr_ringid |= NETMAP_NO_TX_POLL;
916                 }
917
918                 if ((ioctl(tfd, NIOCREGIF, &tifreq)) == -1) {
919                         D("Unable to register %s", ifname);
920                         continue;
921                 }
922                 tnifp = NETMAP_IF(mmap_addr, tifreq.nr_offset);
923             }
924                 /* start threads. */
925                 bzero(&targs[i], sizeof(targs[i]));
926                 targs[i].g = &g;
927                 targs[i].used = 1;
928                 targs[i].completed = 0;
929                 targs[i].fd = tfd;
930                 targs[i].nmr = tifreq;
931                 targs[i].nifp = tnifp;
932                 targs[i].qfirst = (g.nthreads > 1) ? i : 0;
933                 targs[i].qlast = (g.nthreads > 1) ? i+1 : tifreq.nr_numrings;
934                 targs[i].me = i;
935                 targs[i].affinity = g.cpus ? i % g.cpus : -1;
936                 if (td_body == sender_body) {
937                         /* initialize the packet to send. */
938                         initialize_packet(&targs[i]);
939                 }
940
941                 if (pthread_create(&targs[i].thread, NULL, td_body,
942                                    &targs[i]) == -1) {
943                         D("Unable to create thread %d", i);
944                         targs[i].used = 0;
945                 }
946         }
947
948     {
949         uint64_t my_count = 0, prev = 0;
950         uint64_t count = 0;
951         double delta_t;
952         struct timeval tic, toc;
953
954         gettimeofday(&toc, NULL);
955         for (;;) {
956                 struct timeval now, delta;
957                 uint64_t pps;
958                 int done = 0;
959
960                 delta.tv_sec = report_interval/1000;
961                 delta.tv_usec = (report_interval%1000)*1000;
962                 select(0, NULL, NULL, NULL, &delta);
963                 gettimeofday(&now, NULL);
964                 timersub(&now, &toc, &toc);
965                 my_count = 0;
966                 for (i = 0; i < g.nthreads; i++) {
967                         my_count += targs[i].count;
968                         if (targs[i].used == 0)
969                                 done++;
970                 }
971                 pps = toc.tv_sec* 1000000 + toc.tv_usec;
972                 if (pps < 10000)
973                         continue;
974                 pps = (my_count - prev)*1000000 / pps;
975                 D("%" PRIu64 " pps", pps);
976                 prev = my_count;
977                 toc = now;
978                 if (done == g.nthreads)
979                         break;
980         }
981
982         timerclear(&tic);
983         timerclear(&toc);
984         for (i = 0; i < g.nthreads; i++) {
985                 /*
986                  * Join active threads, unregister interfaces and close
987                  * file descriptors.
988                  */
989                 pthread_join(targs[i].thread, NULL);
990                 ioctl(targs[i].fd, NIOCUNREGIF, &targs[i].nmr);
991                 close(targs[i].fd);
992
993                 if (targs[i].completed == 0)
994                         continue;
995
996                 /*
997                  * Collect threads output and extract information about
998                  * how long it took to send all the packets.
999                  */
1000                 count += targs[i].count;
1001                 if (!timerisset(&tic) || timercmp(&targs[i].tic, &tic, <))
1002                         tic = targs[i].tic;
1003                 if (!timerisset(&toc) || timercmp(&targs[i].toc, &toc, >))
1004                         toc = targs[i].toc;
1005         }
1006
1007         /* print output. */
1008         timersub(&toc, &tic, &toc);
1009         delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
1010         if (td_body == sender_body)
1011                 tx_output(count, g.pkt_size, delta_t);
1012         else
1013                 rx_output(count, delta_t);
1014     }
1015
1016         ioctl(fd, NIOCUNREGIF, &nmr);
1017         munmap(mmap_addr, nmr.nr_memsize);
1018         close(fd);
1019
1020         return (0);
1021 }
1022 /* end of file */