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