pkt-gen.c revision 257529
1227614Sluigi/*
2257529Sluigi * Copyright (C) 2011-2013 Matteo Landi, Luigi Rizzo. All rights reserved.
3227614Sluigi *
4227614Sluigi * Redistribution and use in source and binary forms, with or without
5227614Sluigi * modification, are permitted provided that the following conditions
6227614Sluigi * are met:
7228276Sluigi *   1. Redistributions of source code must retain the above copyright
8228276Sluigi *      notice, this list of conditions and the following disclaimer.
9228276Sluigi *   2. Redistributions in binary form must reproduce the above copyright
10228276Sluigi *      notice, this list of conditions and the following disclaimer in the
11227614Sluigi *    documentation and/or other materials provided with the distribution.
12227614Sluigi *
13227614Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14227614Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227614Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227614Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227614Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227614Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227614Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227614Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227614Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227614Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227614Sluigi * SUCH DAMAGE.
24227614Sluigi */
25227614Sluigi
26227614Sluigi/*
27227614Sluigi * $FreeBSD: head/tools/tools/netmap/pkt-gen.c 257529 2013-11-01 21:21:14Z luigi $
28257529Sluigi * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $
29227614Sluigi *
30227614Sluigi * Example program to show how to build a multithreaded packet
31227614Sluigi * source/sink using the netmap device.
32227614Sluigi *
33227614Sluigi * In this example we create a programmable number of threads
34227614Sluigi * to take care of all the queues of the interface used to
35227614Sluigi * send or receive traffic.
36227614Sluigi *
37227614Sluigi */
38227614Sluigi
39246896Sluigi#include "nm_util.h"
40246896Sluigi
41251426Sluigi#include <ctype.h>	// isprint()
42251426Sluigi
43257529Sluigiconst char *default_payload="netmap pkt-gen DIRECT payload\n"
44227614Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
45227614Sluigi
46257529Sluigiconst char *indirect_payload="netmap pkt-gen indirect payload\n"
47257529Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
48257529Sluigi
49246896Sluigiint time_second;	// support for RD() debugging macro
50227614Sluigi
51227614Sluigiint verbose = 0;
52227614Sluigi
53227614Sluigi#define SKIP_PAYLOAD 1 /* do not check payload. */
54227614Sluigi
55227614Sluigistruct pkt {
56227614Sluigi	struct ether_header eh;
57227614Sluigi	struct ip ip;
58227614Sluigi	struct udphdr udp;
59231198Sluigi	uint8_t body[2048];	// XXX hardwired
60227614Sluigi} __attribute__((__packed__));
61227614Sluigi
62246896Sluigistruct ip_range {
63246896Sluigi	char *name;
64257529Sluigi	uint32_t start, end; /* same as struct in_addr */
65257529Sluigi	uint16_t port0, port1;
66246896Sluigi};
67246896Sluigi
68246896Sluigistruct mac_range {
69246896Sluigi	char *name;
70246896Sluigi	struct ether_addr start, end;
71246896Sluigi};
72246896Sluigi
73227614Sluigi/*
74227614Sluigi * global arguments for all threads
75227614Sluigi */
76246896Sluigi
77227614Sluigistruct glob_arg {
78246896Sluigi	struct ip_range src_ip;
79246896Sluigi	struct ip_range dst_ip;
80246896Sluigi	struct mac_range dst_mac;
81246896Sluigi	struct mac_range src_mac;
82227614Sluigi	int pkt_size;
83227614Sluigi	int burst;
84246896Sluigi	int forever;
85227614Sluigi	int npackets;	/* total packets to send */
86257529Sluigi	int frags;	/* fragments per packet */
87227614Sluigi	int nthreads;
88227614Sluigi	int cpus;
89234956Sluigi	int options;	/* testing */
90234956Sluigi#define OPT_PREFETCH	1
91234956Sluigi#define OPT_ACCESS	2
92234956Sluigi#define OPT_COPY	4
93234956Sluigi#define OPT_MEMCPY	8
94246896Sluigi#define OPT_TS		16	/* add a timestamp */
95251426Sluigi#define OPT_INDIRECT	32	/* use indirect buffers, tx only */
96251426Sluigi#define OPT_DUMP	64	/* dump rx/tx traffic */
97246896Sluigi	int dev_type;
98227614Sluigi	pcap_t *p;
99227614Sluigi
100251132Sluigi	int tx_rate;
101251132Sluigi	struct timespec tx_period;
102251132Sluigi
103246896Sluigi	int affinity;
104246896Sluigi	int main_fd;
105246896Sluigi	int report_interval;
106246896Sluigi	void *(*td_body)(void *);
107246896Sluigi	void *mmap_addr;
108246896Sluigi	int mmap_size;
109246896Sluigi	char *ifname;
110257529Sluigi	char *nmr_config;
111257529Sluigi	int dummy_send;
112227614Sluigi};
113246896Sluigienum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
114227614Sluigi
115246896Sluigi
116227614Sluigi/*
117227614Sluigi * Arguments for a new thread. The same structure is used by
118227614Sluigi * the source and the sink
119227614Sluigi */
120227614Sluigistruct targ {
121227614Sluigi	struct glob_arg *g;
122227614Sluigi	int used;
123227614Sluigi	int completed;
124238165Semaste	int cancel;
125227614Sluigi	int fd;
126227614Sluigi	struct nmreq nmr;
127227614Sluigi	struct netmap_if *nifp;
128227614Sluigi	uint16_t	qfirst, qlast; /* range of queues to scan */
129246896Sluigi	volatile uint64_t count;
130251132Sluigi	struct timespec tic, toc;
131227614Sluigi	int me;
132227614Sluigi	pthread_t thread;
133227614Sluigi	int affinity;
134227614Sluigi
135227614Sluigi	struct pkt pkt;
136227614Sluigi};
137227614Sluigi
138227614Sluigi
139246896Sluigi/*
140246896Sluigi * extract the extremes from a range of ipv4 addresses.
141246896Sluigi * addr_lo[-addr_hi][:port_lo[-port_hi]]
142246896Sluigi */
143246896Sluigistatic void
144246896Sluigiextract_ip_range(struct ip_range *r)
145246896Sluigi{
146257529Sluigi	char *ap, *pp;
147257529Sluigi	struct in_addr a;
148246896Sluigi
149246896Sluigi	D("extract IP range from %s", r->name);
150257529Sluigi	r->port0 = r->port1 = 0;
151257529Sluigi	r->start = r->end = 0;
152257529Sluigi
153257529Sluigi	/* the first - splits start/end of range */
154257529Sluigi	ap = index(r->name, '-');	/* do we have ports ? */
155257529Sluigi	if (ap) {
156257529Sluigi		*ap++ = '\0';
157257529Sluigi	}
158257529Sluigi	/* grab the initial values (mandatory) */
159257529Sluigi	pp = index(r->name, ':');
160257529Sluigi	if (pp) {
161257529Sluigi		*pp++ = '\0';
162257529Sluigi		r->port0 = r->port1 = strtol(pp, NULL, 0);
163257529Sluigi	};
164257529Sluigi	inet_aton(r->name, &a);
165257529Sluigi	r->start = r->end = ntohl(a.s_addr);
166257529Sluigi	if (ap) {
167257529Sluigi		pp = index(ap, ':');
168257529Sluigi		if (pp) {
169257529Sluigi			*pp++ = '\0';
170257529Sluigi			if (*pp)
171257529Sluigi				r->port1 = strtol(pp, NULL, 0);
172246896Sluigi		}
173257529Sluigi		if (*ap) {
174257529Sluigi			inet_aton(ap, &a);
175257529Sluigi			r->end = ntohl(a.s_addr);
176257529Sluigi		}
177246896Sluigi	}
178257529Sluigi	if (r->port0 > r->port1) {
179257529Sluigi		uint16_t tmp = r->port0;
180257529Sluigi		r->port0 = r->port1;
181257529Sluigi		r->port1 = tmp;
182257529Sluigi	}
183257529Sluigi	if (r->start > r->end) {
184257529Sluigi		uint32_t tmp = r->start;
185246896Sluigi		r->start = r->end;
186257529Sluigi		r->end = tmp;
187246896Sluigi	}
188257529Sluigi	{
189257529Sluigi		struct in_addr a;
190257529Sluigi		char buf1[16]; // one ip address
191257529Sluigi
192257529Sluigi		a.s_addr = htonl(r->end);
193257529Sluigi		strncpy(buf1, inet_ntoa(a), sizeof(buf1));
194257529Sluigi		a.s_addr = htonl(r->start);
195257529Sluigi		D("range is %s:%d to %s:%d",
196257529Sluigi			inet_ntoa(a), r->port0, buf1, r->port1);
197257529Sluigi	}
198246896Sluigi}
199246896Sluigi
200246896Sluigistatic void
201246896Sluigiextract_mac_range(struct mac_range *r)
202246896Sluigi{
203246896Sluigi	D("extract MAC range from %s", r->name);
204246896Sluigi	bcopy(ether_aton(r->name), &r->start, 6);
205246896Sluigi	bcopy(ether_aton(r->name), &r->end, 6);
206246896Sluigi#if 0
207246896Sluigi	bcopy(targ->src_mac, eh->ether_shost, 6);
208246896Sluigi	p = index(targ->g->src_mac, '-');
209246896Sluigi	if (p)
210246896Sluigi		targ->src_mac_range = atoi(p+1);
211246896Sluigi
212246896Sluigi	bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6);
213246896Sluigi	bcopy(targ->dst_mac, eh->ether_dhost, 6);
214246896Sluigi	p = index(targ->g->dst_mac, '-');
215246896Sluigi	if (p)
216246896Sluigi		targ->dst_mac_range = atoi(p+1);
217246896Sluigi#endif
218246896Sluigi	D("%s starts at %s", r->name, ether_ntoa(&r->start));
219246896Sluigi}
220246896Sluigi
221227614Sluigistatic struct targ *targs;
222227614Sluigistatic int global_nthreads;
223227614Sluigi
224227614Sluigi/* control-C handler */
225227614Sluigistatic void
226246896Sluigisigint_h(int sig)
227227614Sluigi{
228246896Sluigi	int i;
229246896Sluigi
230246896Sluigi	(void)sig;	/* UNUSED */
231246896Sluigi	for (i = 0; i < global_nthreads; i++) {
232238165Semaste		targs[i].cancel = 1;
233246896Sluigi	}
234227614Sluigi	signal(SIGINT, SIG_DFL);
235227614Sluigi}
236227614Sluigi
237227614Sluigi/* sysctl wrapper to return the number of active CPUs */
238227614Sluigistatic int
239227614Sluigisystem_ncpus(void)
240227614Sluigi{
241246896Sluigi#ifdef __FreeBSD__
242227614Sluigi	int mib[2], ncpus;
243227614Sluigi	size_t len;
244227614Sluigi
245227614Sluigi	mib[0] = CTL_HW;
246227614Sluigi	mib[1] = HW_NCPU;
247227614Sluigi	len = sizeof(mib);
248227614Sluigi	sysctl(mib, 2, &ncpus, &len, NULL, 0);
249227614Sluigi
250227614Sluigi	return (ncpus);
251246896Sluigi#else
252246896Sluigi	return 1;
253246896Sluigi#endif /* !__FreeBSD__ */
254227614Sluigi}
255227614Sluigi
256246896Sluigi#ifdef __linux__
257246896Sluigi#define sockaddr_dl    sockaddr_ll
258246896Sluigi#define sdl_family     sll_family
259246896Sluigi#define AF_LINK        AF_PACKET
260246896Sluigi#define LLADDR(s)      s->sll_addr;
261246896Sluigi#include <linux/if_tun.h>
262246896Sluigi#define TAP_CLONEDEV	"/dev/net/tun"
263246896Sluigi#endif /* __linux__ */
264246896Sluigi
265246896Sluigi#ifdef __FreeBSD__
266246896Sluigi#include <net/if_tun.h>
267246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
268246896Sluigi#endif /* __FreeBSD */
269246896Sluigi
270246896Sluigi#ifdef __APPLE__
271246896Sluigi// #warning TAP not supported on apple ?
272246896Sluigi#include <net/if_utun.h>
273246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
274246896Sluigi#endif /* __APPLE__ */
275246896Sluigi
276246896Sluigi
277227614Sluigi/*
278257529Sluigi * parse the vale configuration in conf and put it in nmr.
279257529Sluigi * The configuration may consist of 0 to 4 numbers separated
280257529Sluigi * by commas: #tx-slots,#rx-slots,#tx-rinzgs,#rx-rings.
281257529Sluigi * Missing numbers or zeroes stand for default values.
282257529Sluigi * As an additional convenience, if exactly one number
283257529Sluigi * is specified, then this is assigned to bot #tx-slots and #rx-slots.
284257529Sluigi * If there is no 4th number, then the 3rd is assigned to bot #tx-rings
285257529Sluigi * and #rx-rings.
286257529Sluigi */
287257529Sluigivoid parse_nmr_config(const char* conf, struct nmreq *nmr)
288257529Sluigi{
289257529Sluigi	char *w, *tok;
290257529Sluigi	int i, v;
291257529Sluigi
292257529Sluigi	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
293257529Sluigi	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
294257529Sluigi	if (conf == NULL || ! *conf)
295257529Sluigi		return;
296257529Sluigi	w = strdup(conf);
297257529Sluigi	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
298257529Sluigi		v = atoi(tok);
299257529Sluigi		switch (i) {
300257529Sluigi		case 0:
301257529Sluigi			nmr->nr_tx_slots = nmr->nr_rx_slots = v;
302257529Sluigi			break;
303257529Sluigi		case 1:
304257529Sluigi			nmr->nr_rx_slots = v;
305257529Sluigi			break;
306257529Sluigi		case 2:
307257529Sluigi			nmr->nr_tx_rings = nmr->nr_rx_rings = v;
308257529Sluigi			break;
309257529Sluigi		case 3:
310257529Sluigi			nmr->nr_rx_rings = v;
311257529Sluigi			break;
312257529Sluigi		default:
313257529Sluigi			D("ignored config: %s", tok);
314257529Sluigi			break;
315257529Sluigi		}
316257529Sluigi	}
317257529Sluigi	D("txr %d txd %d rxr %d rxd %d",
318257529Sluigi			nmr->nr_tx_rings, nmr->nr_tx_slots,
319257529Sluigi			nmr->nr_rx_rings, nmr->nr_rx_slots);
320257529Sluigi	free(w);
321257529Sluigi}
322257529Sluigi
323257529Sluigi
324257529Sluigi/*
325227614Sluigi * locate the src mac address for our interface, put it
326227614Sluigi * into the user-supplied buffer. return 0 if ok, -1 on error.
327227614Sluigi */
328227614Sluigistatic int
329227614Sluigisource_hwaddr(const char *ifname, char *buf)
330227614Sluigi{
331227614Sluigi	struct ifaddrs *ifaphead, *ifap;
332227614Sluigi	int l = sizeof(ifap->ifa_name);
333227614Sluigi
334227614Sluigi	if (getifaddrs(&ifaphead) != 0) {
335227614Sluigi		D("getifaddrs %s failed", ifname);
336227614Sluigi		return (-1);
337227614Sluigi	}
338227614Sluigi
339227614Sluigi	for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
340227614Sluigi		struct sockaddr_dl *sdl =
341227614Sluigi			(struct sockaddr_dl *)ifap->ifa_addr;
342227614Sluigi		uint8_t *mac;
343227614Sluigi
344227614Sluigi		if (!sdl || sdl->sdl_family != AF_LINK)
345227614Sluigi			continue;
346227614Sluigi		if (strncmp(ifap->ifa_name, ifname, l) != 0)
347227614Sluigi			continue;
348227614Sluigi		mac = (uint8_t *)LLADDR(sdl);
349227614Sluigi		sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
350227614Sluigi			mac[0], mac[1], mac[2],
351227614Sluigi			mac[3], mac[4], mac[5]);
352227614Sluigi		if (verbose)
353227614Sluigi			D("source hwaddr %s", buf);
354227614Sluigi		break;
355227614Sluigi	}
356227614Sluigi	freeifaddrs(ifaphead);
357227614Sluigi	return ifap ? 0 : 1;
358227614Sluigi}
359227614Sluigi
360227614Sluigi
361227614Sluigi/* set the thread affinity. */
362227614Sluigistatic int
363227614Sluigisetaffinity(pthread_t me, int i)
364227614Sluigi{
365246896Sluigi#ifdef __FreeBSD__
366227614Sluigi	cpuset_t cpumask;
367227614Sluigi
368227614Sluigi	if (i == -1)
369227614Sluigi		return 0;
370227614Sluigi
371227614Sluigi	/* Set thread affinity affinity.*/
372227614Sluigi	CPU_ZERO(&cpumask);
373227614Sluigi	CPU_SET(i, &cpumask);
374227614Sluigi
375227614Sluigi	if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
376227614Sluigi		D("Unable to set affinity");
377227614Sluigi		return 1;
378227614Sluigi	}
379246896Sluigi#else
380246896Sluigi	(void)me; /* suppress 'unused' warnings */
381246896Sluigi	(void)i;
382246896Sluigi#endif /* __FreeBSD__ */
383227614Sluigi	return 0;
384227614Sluigi}
385227614Sluigi
386227614Sluigi/* Compute the checksum of the given ip header. */
387227614Sluigistatic uint16_t
388246896Sluigichecksum(const void *data, uint16_t len, uint32_t sum)
389227614Sluigi{
390227614Sluigi        const uint8_t *addr = data;
391246896Sluigi	uint32_t i;
392227614Sluigi
393246896Sluigi        /* Checksum all the pairs of bytes first... */
394246896Sluigi        for (i = 0; i < (len & ~1U); i += 2) {
395246896Sluigi                sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
396246896Sluigi                if (sum > 0xFFFF)
397246896Sluigi                        sum -= 0xFFFF;
398227614Sluigi        }
399246896Sluigi	/*
400246896Sluigi	 * If there's a single byte left over, checksum it, too.
401246896Sluigi	 * Network byte order is big-endian, so the remaining byte is
402246896Sluigi	 * the high byte.
403246896Sluigi	 */
404246896Sluigi	if (i < len) {
405246896Sluigi		sum += addr[i] << 8;
406246896Sluigi		if (sum > 0xFFFF)
407246896Sluigi			sum -= 0xFFFF;
408246896Sluigi	}
409246896Sluigi	return sum;
410246896Sluigi}
411227614Sluigi
412246896Sluigistatic u_int16_t
413246896Sluigiwrapsum(u_int32_t sum)
414246896Sluigi{
415246896Sluigi	sum = ~sum & 0xFFFF;
416246896Sluigi	return (htons(sum));
417227614Sluigi}
418227614Sluigi
419251426Sluigi/* Check the payload of the packet for errors (use it for debug).
420251426Sluigi * Look for consecutive ascii representations of the size of the packet.
421251426Sluigi */
422251426Sluigistatic void
423251426Sluigidump_payload(char *p, int len, struct netmap_ring *ring, int cur)
424251426Sluigi{
425251426Sluigi	char buf[128];
426251426Sluigi	int i, j, i0;
427251426Sluigi
428251426Sluigi	/* get the length in ASCII of the length of the packet. */
429251426Sluigi
430257529Sluigi	printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n",
431257529Sluigi		ring, cur, ring->slot[cur].buf_idx,
432257529Sluigi		ring->slot[cur].flags, len);
433251426Sluigi	/* hexdump routine */
434251426Sluigi	for (i = 0; i < len; ) {
435251426Sluigi		memset(buf, sizeof(buf), ' ');
436251426Sluigi		sprintf(buf, "%5d: ", i);
437251426Sluigi		i0 = i;
438251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
439251426Sluigi			sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
440251426Sluigi		i = i0;
441251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
442251426Sluigi			sprintf(buf+7+j + 48, "%c",
443251426Sluigi				isprint(p[i]) ? p[i] : '.');
444251426Sluigi		printf("%s\n", buf);
445251426Sluigi	}
446251426Sluigi}
447251426Sluigi
448227614Sluigi/*
449227614Sluigi * Fill a packet with some payload.
450246896Sluigi * We create a UDP packet so the payload starts at
451246896Sluigi *	14+20+8 = 42 bytes.
452227614Sluigi */
453246896Sluigi#ifdef __linux__
454246896Sluigi#define uh_sport source
455246896Sluigi#define uh_dport dest
456246896Sluigi#define uh_ulen len
457246896Sluigi#define uh_sum check
458246896Sluigi#endif /* linux */
459251426Sluigi
460257529Sluigi/*
461257529Sluigi * increment the addressed in the packet,
462257529Sluigi * starting from the least significant field.
463257529Sluigi *	DST_IP DST_PORT SRC_IP SRC_PORT
464257529Sluigi */
465227614Sluigistatic void
466257529Sluigiupdate_addresses(struct pkt *pkt, struct glob_arg *g)
467257529Sluigi{
468257529Sluigi	uint32_t a;
469257529Sluigi	uint16_t p;
470257529Sluigi	struct ip *ip = &pkt->ip;
471257529Sluigi	struct udphdr *udp = &pkt->udp;
472257529Sluigi
473257529Sluigi	p = ntohs(udp->uh_sport);
474257529Sluigi	if (p < g->src_ip.port1) { /* just inc, no wrap */
475257529Sluigi		udp->uh_sport = htons(p + 1);
476257529Sluigi		return;
477257529Sluigi	}
478257529Sluigi	udp->uh_sport = htons(g->src_ip.port0);
479257529Sluigi
480257529Sluigi	a = ntohl(ip->ip_src.s_addr);
481257529Sluigi	if (a < g->src_ip.end) { /* just inc, no wrap */
482257529Sluigi		ip->ip_src.s_addr = htonl(a + 1);
483257529Sluigi		return;
484257529Sluigi	}
485257529Sluigi	ip->ip_src.s_addr = htonl(g->src_ip.start);
486257529Sluigi
487257529Sluigi	udp->uh_sport = htons(g->src_ip.port0);
488257529Sluigi	p = ntohs(udp->uh_dport);
489257529Sluigi	if (p < g->dst_ip.port1) { /* just inc, no wrap */
490257529Sluigi		udp->uh_dport = htons(p + 1);
491257529Sluigi		return;
492257529Sluigi	}
493257529Sluigi	udp->uh_dport = htons(g->dst_ip.port0);
494257529Sluigi
495257529Sluigi	a = ntohl(ip->ip_dst.s_addr);
496257529Sluigi	if (a < g->dst_ip.end) { /* just inc, no wrap */
497257529Sluigi		ip->ip_dst.s_addr = htonl(a + 1);
498257529Sluigi		return;
499257529Sluigi	}
500257529Sluigi	ip->ip_dst.s_addr = htonl(g->dst_ip.start);
501257529Sluigi
502257529Sluigi}
503257529Sluigi
504257529Sluigi/*
505257529Sluigi * initialize one packet and prepare for the next one.
506257529Sluigi * The copy could be done better instead of repeating it each time.
507257529Sluigi */
508257529Sluigistatic void
509227614Sluigiinitialize_packet(struct targ *targ)
510227614Sluigi{
511227614Sluigi	struct pkt *pkt = &targ->pkt;
512227614Sluigi	struct ether_header *eh;
513227614Sluigi	struct ip *ip;
514227614Sluigi	struct udphdr *udp;
515246896Sluigi	uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip);
516251426Sluigi	const char *payload = targ->g->options & OPT_INDIRECT ?
517257529Sluigi		indirect_payload : default_payload;
518251426Sluigi	int i, l, l0 = strlen(payload);
519227614Sluigi
520257529Sluigi	/* create a nice NUL-terminated string */
521227614Sluigi	for (i = 0; i < paylen;) {
522227614Sluigi		l = min(l0, paylen - i);
523251426Sluigi		bcopy(payload, pkt->body + i, l);
524227614Sluigi		i += l;
525227614Sluigi	}
526227614Sluigi	pkt->body[i-1] = '\0';
527246896Sluigi	ip = &pkt->ip;
528227614Sluigi
529257529Sluigi	/* prepare the headers */
530227614Sluigi        ip->ip_v = IPVERSION;
531227614Sluigi        ip->ip_hl = 5;
532227614Sluigi        ip->ip_id = 0;
533227614Sluigi        ip->ip_tos = IPTOS_LOWDELAY;
534227614Sluigi	ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh));
535227614Sluigi        ip->ip_id = 0;
536227614Sluigi        ip->ip_off = htons(IP_DF); /* Don't fragment */
537227614Sluigi        ip->ip_ttl = IPDEFTTL;
538227614Sluigi	ip->ip_p = IPPROTO_UDP;
539257529Sluigi	ip->ip_dst.s_addr = htonl(targ->g->dst_ip.start);
540257529Sluigi	ip->ip_src.s_addr = htonl(targ->g->src_ip.start);
541246896Sluigi	ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0));
542227614Sluigi
543246896Sluigi
544246896Sluigi	udp = &pkt->udp;
545257529Sluigi        udp->uh_sport = htons(targ->g->src_ip.port0);
546257529Sluigi        udp->uh_dport = htons(targ->g->dst_ip.port0);
547246896Sluigi	udp->uh_ulen = htons(paylen);
548246896Sluigi	/* Magic: taken from sbin/dhclient/packet.c */
549246896Sluigi	udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp),
550246896Sluigi                    checksum(pkt->body,
551246896Sluigi                        paylen - sizeof(*udp),
552246896Sluigi                        checksum(&ip->ip_src, 2 * sizeof(ip->ip_src),
553246896Sluigi                            IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen)
554246896Sluigi                        )
555246896Sluigi                    )
556246896Sluigi                ));
557246896Sluigi
558227614Sluigi	eh = &pkt->eh;
559246896Sluigi	bcopy(&targ->g->src_mac.start, eh->ether_shost, 6);
560246896Sluigi	bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6);
561227614Sluigi	eh->ether_type = htons(ETHERTYPE_IP);
562251426Sluigi	// dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0);
563227614Sluigi}
564227614Sluigi
565227614Sluigi
566227614Sluigi
567227614Sluigi/*
568227614Sluigi * create and enqueue a batch of packets on a ring.
569227614Sluigi * On the last one set NS_REPORT to tell the driver to generate
570227614Sluigi * an interrupt when done.
571227614Sluigi */
572227614Sluigistatic int
573227614Sluigisend_packets(struct netmap_ring *ring, struct pkt *pkt,
574257529Sluigi		struct glob_arg *g, u_int count, int options, u_int nfrags)
575227614Sluigi{
576227614Sluigi	u_int sent, cur = ring->cur;
577257529Sluigi	int fcnt;
578257529Sluigi	int size = g->pkt_size;
579227614Sluigi
580227614Sluigi	if (ring->avail < count)
581227614Sluigi		count = ring->avail;
582257529Sluigi	if (count < nfrags) {
583257529Sluigi		D("truncating packet, no room for frags %d %d",
584257529Sluigi			count, nfrags);
585257529Sluigi	}
586234956Sluigi#if 0
587234956Sluigi	if (options & (OPT_COPY | OPT_PREFETCH) ) {
588234956Sluigi		for (sent = 0; sent < count; sent++) {
589234956Sluigi			struct netmap_slot *slot = &ring->slot[cur];
590234956Sluigi			char *p = NETMAP_BUF(ring, slot->buf_idx);
591234956Sluigi
592234956Sluigi			prefetch(p);
593234956Sluigi			cur = NETMAP_RING_NEXT(ring, cur);
594234956Sluigi		}
595234956Sluigi		cur = ring->cur;
596234956Sluigi	}
597234956Sluigi#endif
598257529Sluigi	for (fcnt = nfrags, sent = 0; sent < count; sent++) {
599227614Sluigi		struct netmap_slot *slot = &ring->slot[cur];
600227614Sluigi		char *p = NETMAP_BUF(ring, slot->buf_idx);
601227614Sluigi
602251426Sluigi		slot->flags = 0;
603251426Sluigi		if (options & OPT_INDIRECT) {
604251426Sluigi			slot->flags |= NS_INDIRECT;
605257529Sluigi			slot->ptr = (uint64_t)pkt;
606257529Sluigi		} else if (options & OPT_COPY) {
607234956Sluigi			pkt_copy(pkt, p, size);
608257529Sluigi			if (fcnt == 1)
609257529Sluigi				update_addresses(pkt, g);
610257529Sluigi		} else if (options & OPT_MEMCPY) {
611227614Sluigi			memcpy(p, pkt, size);
612257529Sluigi			if (fcnt == 1)
613257529Sluigi				update_addresses(pkt, g);
614257529Sluigi		} else if (options & OPT_PREFETCH) {
615234956Sluigi			prefetch(p);
616257529Sluigi		}
617257529Sluigi		if (options & OPT_DUMP)
618257529Sluigi			dump_payload(p, size, ring, cur);
619227614Sluigi		slot->len = size;
620257529Sluigi		if (--fcnt > 0)
621257529Sluigi			slot->flags |= NS_MOREFRAG;
622257529Sluigi		else
623257529Sluigi			fcnt = nfrags;
624257529Sluigi		if (sent == count - 1) {
625257529Sluigi			slot->flags &= ~NS_MOREFRAG;
626227614Sluigi			slot->flags |= NS_REPORT;
627257529Sluigi		}
628227614Sluigi		cur = NETMAP_RING_NEXT(ring, cur);
629227614Sluigi	}
630227614Sluigi	ring->avail -= sent;
631227614Sluigi	ring->cur = cur;
632227614Sluigi
633227614Sluigi	return (sent);
634227614Sluigi}
635227614Sluigi
636246896Sluigi/*
637246896Sluigi * Send a packet, and wait for a response.
638246896Sluigi * The payload (after UDP header, ofs 42) has a 4-byte sequence
639246896Sluigi * followed by a struct timeval (or bintime?)
640246896Sluigi */
641246896Sluigi#define	PAY_OFS	42	/* where in the pkt... */
642246896Sluigi
643227614Sluigistatic void *
644246896Sluigipinger_body(void *data)
645246896Sluigi{
646246896Sluigi	struct targ *targ = (struct targ *) data;
647246896Sluigi	struct pollfd fds[1];
648246896Sluigi	struct netmap_if *nifp = targ->nifp;
649246896Sluigi	int i, rx = 0, n = targ->g->npackets;
650246896Sluigi
651246896Sluigi	fds[0].fd = targ->fd;
652246896Sluigi	fds[0].events = (POLLIN);
653246896Sluigi	static uint32_t sent;
654246896Sluigi	struct timespec ts, now, last_print;
655246896Sluigi	uint32_t count = 0, min = 1000000000, av = 0;
656246896Sluigi
657246896Sluigi	if (targ->g->nthreads > 1) {
658246896Sluigi		D("can only ping with 1 thread");
659246896Sluigi		return NULL;
660246896Sluigi	}
661246896Sluigi
662246896Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &last_print);
663246896Sluigi	while (n == 0 || (int)sent < n) {
664246896Sluigi		struct netmap_ring *ring = NETMAP_TXRING(nifp, 0);
665246896Sluigi		struct netmap_slot *slot;
666246896Sluigi		char *p;
667246896Sluigi	    for (i = 0; i < 1; i++) {
668246896Sluigi		slot = &ring->slot[ring->cur];
669246896Sluigi		slot->len = targ->g->pkt_size;
670246896Sluigi		p = NETMAP_BUF(ring, slot->buf_idx);
671246896Sluigi
672246896Sluigi		if (ring->avail == 0) {
673246896Sluigi			D("-- ouch, cannot send");
674246896Sluigi		} else {
675246896Sluigi			pkt_copy(&targ->pkt, p, targ->g->pkt_size);
676246896Sluigi			clock_gettime(CLOCK_REALTIME_PRECISE, &ts);
677246896Sluigi			bcopy(&sent, p+42, sizeof(sent));
678246896Sluigi			bcopy(&ts, p+46, sizeof(ts));
679246896Sluigi			sent++;
680246896Sluigi			ring->cur = NETMAP_RING_NEXT(ring, ring->cur);
681246896Sluigi			ring->avail--;
682246896Sluigi		}
683246896Sluigi	    }
684246896Sluigi		/* should use a parameter to decide how often to send */
685246896Sluigi		if (poll(fds, 1, 3000) <= 0) {
686246896Sluigi			D("poll error/timeout on queue %d", targ->me);
687246896Sluigi			continue;
688246896Sluigi		}
689246896Sluigi		/* see what we got back */
690246896Sluigi		for (i = targ->qfirst; i < targ->qlast; i++) {
691246896Sluigi			ring = NETMAP_RXRING(nifp, i);
692246896Sluigi			while (ring->avail > 0) {
693246896Sluigi				uint32_t seq;
694246896Sluigi				slot = &ring->slot[ring->cur];
695246896Sluigi				p = NETMAP_BUF(ring, slot->buf_idx);
696246896Sluigi
697246896Sluigi				clock_gettime(CLOCK_REALTIME_PRECISE, &now);
698246896Sluigi				bcopy(p+42, &seq, sizeof(seq));
699246896Sluigi				bcopy(p+46, &ts, sizeof(ts));
700246896Sluigi				ts.tv_sec = now.tv_sec - ts.tv_sec;
701246896Sluigi				ts.tv_nsec = now.tv_nsec - ts.tv_nsec;
702246896Sluigi				if (ts.tv_nsec < 0) {
703246896Sluigi					ts.tv_nsec += 1000000000;
704246896Sluigi					ts.tv_sec--;
705246896Sluigi				}
706246896Sluigi				if (1) D("seq %d/%d delta %d.%09d", seq, sent,
707246896Sluigi					(int)ts.tv_sec, (int)ts.tv_nsec);
708246896Sluigi				if (ts.tv_nsec < (int)min)
709246896Sluigi					min = ts.tv_nsec;
710246896Sluigi				count ++;
711246896Sluigi				av += ts.tv_nsec;
712246896Sluigi				ring->avail--;
713246896Sluigi				ring->cur = NETMAP_RING_NEXT(ring, ring->cur);
714246896Sluigi				rx++;
715246896Sluigi			}
716246896Sluigi		}
717246896Sluigi		//D("tx %d rx %d", sent, rx);
718246896Sluigi		//usleep(100000);
719246896Sluigi		ts.tv_sec = now.tv_sec - last_print.tv_sec;
720246896Sluigi		ts.tv_nsec = now.tv_nsec - last_print.tv_nsec;
721246896Sluigi		if (ts.tv_nsec < 0) {
722246896Sluigi			ts.tv_nsec += 1000000000;
723246896Sluigi			ts.tv_sec--;
724246896Sluigi		}
725246896Sluigi		if (ts.tv_sec >= 1) {
726246896Sluigi			D("count %d min %d av %d",
727246896Sluigi				count, min, av/count);
728246896Sluigi			count = 0;
729246896Sluigi			av = 0;
730246896Sluigi			min = 100000000;
731246896Sluigi			last_print = now;
732246896Sluigi		}
733246896Sluigi	}
734246896Sluigi	return NULL;
735246896Sluigi}
736246896Sluigi
737246896Sluigi
738246896Sluigi/*
739246896Sluigi * reply to ping requests
740246896Sluigi */
741246896Sluigistatic void *
742246896Sluigiponger_body(void *data)
743246896Sluigi{
744246896Sluigi	struct targ *targ = (struct targ *) data;
745246896Sluigi	struct pollfd fds[1];
746246896Sluigi	struct netmap_if *nifp = targ->nifp;
747246896Sluigi	struct netmap_ring *txring, *rxring;
748246896Sluigi	int i, rx = 0, sent = 0, n = targ->g->npackets;
749246896Sluigi	fds[0].fd = targ->fd;
750246896Sluigi	fds[0].events = (POLLIN);
751246896Sluigi
752246896Sluigi	if (targ->g->nthreads > 1) {
753246896Sluigi		D("can only reply ping with 1 thread");
754246896Sluigi		return NULL;
755246896Sluigi	}
756246896Sluigi	D("understood ponger %d but don't know how to do it", n);
757246896Sluigi	while (n == 0 || sent < n) {
758246896Sluigi		uint32_t txcur, txavail;
759246896Sluigi//#define BUSYWAIT
760246896Sluigi#ifdef BUSYWAIT
761246896Sluigi		ioctl(fds[0].fd, NIOCRXSYNC, NULL);
762246896Sluigi#else
763246896Sluigi		if (poll(fds, 1, 1000) <= 0) {
764246896Sluigi			D("poll error/timeout on queue %d", targ->me);
765246896Sluigi			continue;
766246896Sluigi		}
767246896Sluigi#endif
768246896Sluigi		txring = NETMAP_TXRING(nifp, 0);
769246896Sluigi		txcur = txring->cur;
770246896Sluigi		txavail = txring->avail;
771246896Sluigi		/* see what we got back */
772246896Sluigi		for (i = targ->qfirst; i < targ->qlast; i++) {
773246896Sluigi			rxring = NETMAP_RXRING(nifp, i);
774246896Sluigi			while (rxring->avail > 0) {
775246896Sluigi				uint16_t *spkt, *dpkt;
776246896Sluigi				uint32_t cur = rxring->cur;
777246896Sluigi				struct netmap_slot *slot = &rxring->slot[cur];
778246896Sluigi				char *src, *dst;
779246896Sluigi				src = NETMAP_BUF(rxring, slot->buf_idx);
780246896Sluigi				//D("got pkt %p of size %d", src, slot->len);
781246896Sluigi				rxring->avail--;
782246896Sluigi				rxring->cur = NETMAP_RING_NEXT(rxring, cur);
783246896Sluigi				rx++;
784246896Sluigi				if (txavail == 0)
785246896Sluigi					continue;
786246896Sluigi				dst = NETMAP_BUF(txring,
787246896Sluigi				    txring->slot[txcur].buf_idx);
788246896Sluigi				/* copy... */
789246896Sluigi				dpkt = (uint16_t *)dst;
790246896Sluigi				spkt = (uint16_t *)src;
791246896Sluigi				pkt_copy(src, dst, slot->len);
792246896Sluigi				dpkt[0] = spkt[3];
793246896Sluigi				dpkt[1] = spkt[4];
794246896Sluigi				dpkt[2] = spkt[5];
795246896Sluigi				dpkt[3] = spkt[0];
796246896Sluigi				dpkt[4] = spkt[1];
797246896Sluigi				dpkt[5] = spkt[2];
798246896Sluigi				txring->slot[txcur].len = slot->len;
799246896Sluigi				/* XXX swap src dst mac */
800246896Sluigi				txcur = NETMAP_RING_NEXT(txring, txcur);
801246896Sluigi				txavail--;
802246896Sluigi				sent++;
803246896Sluigi			}
804246896Sluigi		}
805246896Sluigi		txring->cur = txcur;
806246896Sluigi		txring->avail = txavail;
807246896Sluigi		targ->count = sent;
808246896Sluigi#ifdef BUSYWAIT
809246896Sluigi		ioctl(fds[0].fd, NIOCTXSYNC, NULL);
810246896Sluigi#endif
811246896Sluigi		//D("tx %d rx %d", sent, rx);
812246896Sluigi	}
813246896Sluigi	return NULL;
814246896Sluigi}
815246896Sluigi
816251132Sluigistatic __inline int
817251132Sluigitimespec_ge(const struct timespec *a, const struct timespec *b)
818251132Sluigi{
819246896Sluigi
820251132Sluigi	if (a->tv_sec > b->tv_sec)
821251132Sluigi		return (1);
822251132Sluigi	if (a->tv_sec < b->tv_sec)
823251132Sluigi		return (0);
824251132Sluigi	if (a->tv_nsec >= b->tv_nsec)
825251132Sluigi		return (1);
826251132Sluigi	return (0);
827251132Sluigi}
828251132Sluigi
829251132Sluigistatic __inline struct timespec
830251132Sluigitimeval2spec(const struct timeval *a)
831251132Sluigi{
832251132Sluigi	struct timespec ts = {
833251132Sluigi		.tv_sec = a->tv_sec,
834251132Sluigi		.tv_nsec = a->tv_usec * 1000
835251132Sluigi	};
836251132Sluigi	return ts;
837251132Sluigi}
838251132Sluigi
839251132Sluigistatic __inline struct timeval
840251132Sluigitimespec2val(const struct timespec *a)
841251132Sluigi{
842251132Sluigi	struct timeval tv = {
843251132Sluigi		.tv_sec = a->tv_sec,
844251132Sluigi		.tv_usec = a->tv_nsec / 1000
845251132Sluigi	};
846251132Sluigi	return tv;
847251132Sluigi}
848251132Sluigi
849251132Sluigi
850251132Sluigistatic int
851251132Sluigiwait_time(struct timespec ts, struct timespec *wakeup_ts, long long *waited)
852251132Sluigi{
853251132Sluigi	struct timespec curtime;
854251132Sluigi
855251132Sluigi	curtime.tv_sec = 0;
856251132Sluigi	curtime.tv_nsec = 0;
857251132Sluigi
858251132Sluigi	if (clock_gettime(CLOCK_REALTIME_PRECISE, &curtime) == -1) {
859251132Sluigi		D("clock_gettime: %s", strerror(errno));
860251132Sluigi		return (-1);
861251132Sluigi	}
862251132Sluigi	while (timespec_ge(&ts, &curtime)) {
863251132Sluigi		if (waited != NULL)
864251132Sluigi			(*waited)++;
865251132Sluigi		if (clock_gettime(CLOCK_REALTIME_PRECISE, &curtime) == -1) {
866251132Sluigi			D("clock_gettime");
867251132Sluigi			return (-1);
868251132Sluigi		}
869251132Sluigi	}
870251132Sluigi	if (wakeup_ts != NULL)
871251132Sluigi		*wakeup_ts = curtime;
872251132Sluigi	return (0);
873251132Sluigi}
874251132Sluigi
875251132Sluigistatic __inline void
876251132Sluigitimespec_add(struct timespec *tsa, struct timespec *tsb)
877251132Sluigi{
878251132Sluigi	tsa->tv_sec += tsb->tv_sec;
879251132Sluigi	tsa->tv_nsec += tsb->tv_nsec;
880251132Sluigi	if (tsa->tv_nsec >= 1000000000) {
881251132Sluigi		tsa->tv_sec++;
882251132Sluigi		tsa->tv_nsec -= 1000000000;
883251132Sluigi	}
884251132Sluigi}
885251132Sluigi
886251132Sluigi
887246896Sluigistatic void *
888227614Sluigisender_body(void *data)
889227614Sluigi{
890227614Sluigi	struct targ *targ = (struct targ *) data;
891246896Sluigi
892227614Sluigi	struct pollfd fds[1];
893227614Sluigi	struct netmap_if *nifp = targ->nifp;
894227614Sluigi	struct netmap_ring *txring;
895246896Sluigi	int i, n = targ->g->npackets / targ->g->nthreads, sent = 0;
896234956Sluigi	int options = targ->g->options | OPT_COPY;
897251132Sluigi	struct timespec tmptime, nexttime = { 0, 0}; // XXX silence compiler
898251132Sluigi	int rate_limit = targ->g->tx_rate;
899251132Sluigi	long long waited = 0;
900251426Sluigi
901251132Sluigi	D("start");
902227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
903227614Sluigi		goto quit;
904228975Suqs	/* setup poll(2) mechanism. */
905227614Sluigi	memset(fds, 0, sizeof(fds));
906227614Sluigi	fds[0].fd = targ->fd;
907227614Sluigi	fds[0].events = (POLLOUT);
908227614Sluigi
909227614Sluigi	/* main loop.*/
910251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
911251132Sluigi	if (rate_limit) {
912251132Sluigi		tmptime.tv_sec = 2;
913251132Sluigi		tmptime.tv_nsec = 0;
914251132Sluigi		timespec_add(&targ->tic, &tmptime);
915251132Sluigi		targ->tic.tv_nsec = 0;
916251132Sluigi		if (wait_time(targ->tic, NULL, NULL) == -1) {
917251132Sluigi			D("wait_time: %s", strerror(errno));
918251132Sluigi			goto quit;
919251132Sluigi		}
920251132Sluigi		nexttime = targ->tic;
921251132Sluigi	}
922246896Sluigi    if (targ->g->dev_type == DEV_PCAP) {
923246896Sluigi	    int size = targ->g->pkt_size;
924246896Sluigi	    void *pkt = &targ->pkt;
925246896Sluigi	    pcap_t *p = targ->g->p;
926246896Sluigi
927246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
928234956Sluigi		if (pcap_inject(p, pkt, size) != -1)
929234956Sluigi			sent++;
930257529Sluigi		update_addresses(pkt, targ->g);
931234956Sluigi		if (i > 10000) {
932234956Sluigi			targ->count = sent;
933234956Sluigi			i = 0;
934234956Sluigi		}
935246896Sluigi	    }
936246896Sluigi    } else if (targ->g->dev_type == DEV_TAP) { /* tap */
937246896Sluigi	    int size = targ->g->pkt_size;
938246896Sluigi	    void *pkt = &targ->pkt;
939246896Sluigi	    D("writing to file desc %d", targ->g->main_fd);
940246896Sluigi
941246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
942246896Sluigi		if (write(targ->g->main_fd, pkt, size) != -1)
943246896Sluigi			sent++;
944257529Sluigi		update_addresses(pkt, targ->g);
945246896Sluigi		if (i > 10000) {
946246896Sluigi			targ->count = sent;
947246896Sluigi			i = 0;
948246896Sluigi		}
949246896Sluigi	    }
950227614Sluigi    } else {
951251132Sluigi	int tosend = 0;
952257529Sluigi	int frags = targ->g->frags;
953257529Sluigi
954246896Sluigi	while (!targ->cancel && (n == 0 || sent < n)) {
955227614Sluigi
956251132Sluigi		if (rate_limit && tosend <= 0) {
957251132Sluigi			tosend = targ->g->burst;
958251132Sluigi			timespec_add(&nexttime, &targ->g->tx_period);
959251132Sluigi			if (wait_time(nexttime, &tmptime, &waited) == -1) {
960251132Sluigi				D("wait_time");
961251132Sluigi				goto quit;
962251132Sluigi			}
963251132Sluigi		}
964251132Sluigi
965227614Sluigi		/*
966227614Sluigi		 * wait for available room in the send queue(s)
967227614Sluigi		 */
968246896Sluigi		if (poll(fds, 1, 2000) <= 0) {
969238165Semaste			if (targ->cancel)
970238165Semaste				break;
971246896Sluigi			D("poll error/timeout on queue %d", targ->me);
972227614Sluigi			goto quit;
973227614Sluigi		}
974227614Sluigi		/*
975227614Sluigi		 * scan our queues and send on those with room
976227614Sluigi		 */
977246896Sluigi		if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) {
978246896Sluigi			D("drop copy");
979234956Sluigi			options &= ~OPT_COPY;
980246896Sluigi		}
981246896Sluigi		for (i = targ->qfirst; i < targ->qlast; i++) {
982251132Sluigi			int m, limit = rate_limit ?  tosend : targ->g->burst;
983246896Sluigi			if (n > 0 && n - sent < limit)
984246896Sluigi				limit = n - sent;
985227614Sluigi			txring = NETMAP_TXRING(nifp, i);
986227614Sluigi			if (txring->avail == 0)
987227614Sluigi				continue;
988257529Sluigi			if (frags > 1)
989257529Sluigi				limit = ((limit + frags - 1) / frags) * frags;
990257529Sluigi
991257529Sluigi			m = send_packets(txring, &targ->pkt, targ->g,
992257529Sluigi					 limit, options, frags);
993257529Sluigi			ND("limit %d avail %d frags %d m %d",
994257529Sluigi				limit, txring->avail, frags, m);
995227614Sluigi			sent += m;
996227614Sluigi			targ->count = sent;
997257529Sluigi			if (rate_limit) {
998257529Sluigi				tosend -= m;
999257529Sluigi				if (tosend <= 0)
1000257529Sluigi					break;
1001257529Sluigi			}
1002227614Sluigi		}
1003227614Sluigi	}
1004234956Sluigi	/* flush any remaining packets */
1005227614Sluigi	ioctl(fds[0].fd, NIOCTXSYNC, NULL);
1006227614Sluigi
1007227614Sluigi	/* final part: wait all the TX queues to be empty. */
1008227614Sluigi	for (i = targ->qfirst; i < targ->qlast; i++) {
1009227614Sluigi		txring = NETMAP_TXRING(nifp, i);
1010227614Sluigi		while (!NETMAP_TX_RING_EMPTY(txring)) {
1011227614Sluigi			ioctl(fds[0].fd, NIOCTXSYNC, NULL);
1012227614Sluigi			usleep(1); /* wait 1 tick */
1013227614Sluigi		}
1014227614Sluigi	}
1015227614Sluigi    }
1016227614Sluigi
1017251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1018227614Sluigi	targ->completed = 1;
1019227614Sluigi	targ->count = sent;
1020227614Sluigi
1021227614Sluigiquit:
1022227614Sluigi	/* reset the ``used`` flag. */
1023227614Sluigi	targ->used = 0;
1024227614Sluigi
1025227614Sluigi	return (NULL);
1026227614Sluigi}
1027227614Sluigi
1028227614Sluigi
1029227614Sluigistatic void
1030246896Sluigireceive_pcap(u_char *user, const struct pcap_pkthdr * h,
1031246896Sluigi	const u_char * bytes)
1032227614Sluigi{
1033227614Sluigi	int *count = (int *)user;
1034246896Sluigi	(void)h;	/* UNUSED */
1035246896Sluigi	(void)bytes;	/* UNUSED */
1036227614Sluigi	(*count)++;
1037227614Sluigi}
1038227614Sluigi
1039227614Sluigistatic int
1040251426Sluigireceive_packets(struct netmap_ring *ring, u_int limit, int dump)
1041227614Sluigi{
1042227614Sluigi	u_int cur, rx;
1043227614Sluigi
1044227614Sluigi	cur = ring->cur;
1045227614Sluigi	if (ring->avail < limit)
1046227614Sluigi		limit = ring->avail;
1047227614Sluigi	for (rx = 0; rx < limit; rx++) {
1048227614Sluigi		struct netmap_slot *slot = &ring->slot[cur];
1049227614Sluigi		char *p = NETMAP_BUF(ring, slot->buf_idx);
1050227614Sluigi
1051251426Sluigi		if (dump)
1052251426Sluigi			dump_payload(p, slot->len, ring, cur);
1053227614Sluigi
1054227614Sluigi		cur = NETMAP_RING_NEXT(ring, cur);
1055227614Sluigi	}
1056227614Sluigi	ring->avail -= rx;
1057227614Sluigi	ring->cur = cur;
1058227614Sluigi
1059227614Sluigi	return (rx);
1060227614Sluigi}
1061227614Sluigi
1062227614Sluigistatic void *
1063227614Sluigireceiver_body(void *data)
1064227614Sluigi{
1065227614Sluigi	struct targ *targ = (struct targ *) data;
1066227614Sluigi	struct pollfd fds[1];
1067227614Sluigi	struct netmap_if *nifp = targ->nifp;
1068227614Sluigi	struct netmap_ring *rxring;
1069246896Sluigi	int i;
1070246896Sluigi	uint64_t received = 0;
1071227614Sluigi
1072227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
1073227614Sluigi		goto quit;
1074227614Sluigi
1075228975Suqs	/* setup poll(2) mechanism. */
1076227614Sluigi	memset(fds, 0, sizeof(fds));
1077227614Sluigi	fds[0].fd = targ->fd;
1078227614Sluigi	fds[0].events = (POLLIN);
1079227614Sluigi
1080227614Sluigi	/* unbounded wait for the first packet. */
1081246896Sluigi	for (;;) {
1082227614Sluigi		i = poll(fds, 1, 1000);
1083227614Sluigi		if (i > 0 && !(fds[0].revents & POLLERR))
1084227614Sluigi			break;
1085227614Sluigi		D("waiting for initial packets, poll returns %d %d", i, fds[0].revents);
1086227614Sluigi	}
1087227614Sluigi
1088227614Sluigi	/* main loop, exit after 1s silence */
1089251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1090246896Sluigi    if (targ->g->dev_type == DEV_PCAP) {
1091238165Semaste	while (!targ->cancel) {
1092246896Sluigi		/* XXX should we poll ? */
1093227614Sluigi		pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL);
1094227614Sluigi	}
1095246896Sluigi    } else if (targ->g->dev_type == DEV_TAP) {
1096246896Sluigi	D("reading from %s fd %d", targ->g->ifname, targ->g->main_fd);
1097246896Sluigi	while (!targ->cancel) {
1098246896Sluigi		char buf[2048];
1099246896Sluigi		/* XXX should we poll ? */
1100246896Sluigi		if (read(targ->g->main_fd, buf, sizeof(buf)) > 0)
1101246896Sluigi			targ->count++;
1102246896Sluigi	}
1103227614Sluigi    } else {
1104251426Sluigi	int dump = targ->g->options & OPT_DUMP;
1105238165Semaste	while (!targ->cancel) {
1106227614Sluigi		/* Once we started to receive packets, wait at most 1 seconds
1107227614Sluigi		   before quitting. */
1108251132Sluigi		if (poll(fds, 1, 1 * 1000) <= 0 && !targ->g->forever) {
1109251132Sluigi			clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1110228975Suqs			targ->toc.tv_sec -= 1; /* Subtract timeout time. */
1111227614Sluigi			break;
1112227614Sluigi		}
1113227614Sluigi
1114227614Sluigi		for (i = targ->qfirst; i < targ->qlast; i++) {
1115227614Sluigi			int m;
1116227614Sluigi
1117227614Sluigi			rxring = NETMAP_RXRING(nifp, i);
1118227614Sluigi			if (rxring->avail == 0)
1119227614Sluigi				continue;
1120227614Sluigi
1121251426Sluigi			m = receive_packets(rxring, targ->g->burst, dump);
1122227614Sluigi			received += m;
1123227614Sluigi		}
1124246896Sluigi		targ->count = received;
1125227614Sluigi
1126227614Sluigi		// tell the card we have read the data
1127227614Sluigi		//ioctl(fds[0].fd, NIOCRXSYNC, NULL);
1128227614Sluigi	}
1129227614Sluigi    }
1130227614Sluigi
1131227614Sluigi	targ->completed = 1;
1132227614Sluigi	targ->count = received;
1133227614Sluigi
1134227614Sluigiquit:
1135227614Sluigi	/* reset the ``used`` flag. */
1136227614Sluigi	targ->used = 0;
1137227614Sluigi
1138227614Sluigi	return (NULL);
1139227614Sluigi}
1140227614Sluigi
1141246896Sluigi/* very crude code to print a number in normalized form.
1142246896Sluigi * Caller has to make sure that the buffer is large enough.
1143246896Sluigi */
1144246896Sluigistatic const char *
1145246896Sluiginorm(char *buf, double val)
1146238170Semaste{
1147246896Sluigi	char *units[] = { "", "K", "M", "G" };
1148246896Sluigi	u_int i;
1149238170Semaste
1150246896Sluigi	for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *); i++)
1151238170Semaste		val /= 1000;
1152246896Sluigi	sprintf(buf, "%.2f %s", val, units[i]);
1153246896Sluigi	return buf;
1154238170Semaste}
1155238170Semaste
1156227614Sluigistatic void
1157227614Sluigitx_output(uint64_t sent, int size, double delta)
1158227614Sluigi{
1159246896Sluigi	double bw, raw_bw, pps;
1160246896Sluigi	char b1[40], b2[80], b3[80];
1161227614Sluigi
1162228276Sluigi	printf("Sent %" PRIu64 " packets, %d bytes each, in %.2f seconds.\n",
1163227614Sluigi	       sent, size, delta);
1164246896Sluigi	if (delta == 0)
1165246896Sluigi		delta = 1e-6;
1166246896Sluigi	if (size < 60)		/* correct for min packet size */
1167246896Sluigi		size = 60;
1168246896Sluigi	pps = sent / delta;
1169246896Sluigi	bw = (8.0 * size * sent) / delta;
1170246896Sluigi	/* raw packets have4 bytes crc + 20 bytes framing */
1171246896Sluigi	raw_bw = (8.0 * (size + 24) * sent) / delta;
1172238170Semaste
1173246896Sluigi	printf("Speed: %spps Bandwidth: %sbps (raw %sbps)\n",
1174246896Sluigi		norm(b1, pps), norm(b2, bw), norm(b3, raw_bw) );
1175227614Sluigi}
1176227614Sluigi
1177227614Sluigi
1178227614Sluigistatic void
1179227614Sluigirx_output(uint64_t received, double delta)
1180227614Sluigi{
1181246896Sluigi	double pps;
1182246896Sluigi	char b1[40];
1183227614Sluigi
1184246896Sluigi	printf("Received %" PRIu64 " packets, in %.2f seconds.\n", received, delta);
1185227614Sluigi
1186246896Sluigi	if (delta == 0)
1187246896Sluigi		delta = 1e-6;
1188246896Sluigi	pps = received / delta;
1189246896Sluigi	printf("Speed: %spps\n", norm(b1, pps));
1190227614Sluigi}
1191227614Sluigi
1192227614Sluigistatic void
1193227614Sluigiusage(void)
1194227614Sluigi{
1195227614Sluigi	const char *cmd = "pkt-gen";
1196227614Sluigi	fprintf(stderr,
1197227614Sluigi		"Usage:\n"
1198227614Sluigi		"%s arguments\n"
1199227614Sluigi		"\t-i interface		interface name\n"
1200246896Sluigi		"\t-f function		tx rx ping pong\n"
1201246896Sluigi		"\t-n count		number of iterations (can be 0)\n"
1202246896Sluigi		"\t-t pkts_to_send		also forces tx mode\n"
1203246896Sluigi		"\t-r pkts_to_receive	also forces rx mode\n"
1204257529Sluigi		"\t-l pkt_size		in bytes excluding CRC\n"
1205257529Sluigi		"\t-d dst_ip[:port[-dst_ip:port]]   single or range\n"
1206257529Sluigi		"\t-s src_ip[:port[-src_ip:port]]   single or range\n"
1207257529Sluigi		"\t-D dst-mac\n"
1208257529Sluigi		"\t-S src-mac\n"
1209246896Sluigi		"\t-a cpu_id		use setaffinity\n"
1210227614Sluigi		"\t-b burst size		testing, mostly\n"
1211227614Sluigi		"\t-c cores		cores to use\n"
1212227614Sluigi		"\t-p threads		processes/threads to use\n"
1213227614Sluigi		"\t-T report_ms		milliseconds between reports\n"
1214257529Sluigi		"\t-P			use libpcap instead of netmap\n"
1215227614Sluigi		"\t-w wait_for_link_time	in seconds\n"
1216257529Sluigi		"\t-R rate		in packets per second\n"
1217257529Sluigi		"\t-X			dump payload\n"
1218227614Sluigi		"",
1219227614Sluigi		cmd);
1220227614Sluigi
1221227614Sluigi	exit(0);
1222227614Sluigi}
1223227614Sluigi
1224246896Sluigistatic void
1225246896Sluigistart_threads(struct glob_arg *g)
1226246896Sluigi{
1227246896Sluigi	int i;
1228227614Sluigi
1229246896Sluigi	targs = calloc(g->nthreads, sizeof(*targs));
1230246896Sluigi	/*
1231246896Sluigi	 * Now create the desired number of threads, each one
1232246896Sluigi	 * using a single descriptor.
1233246896Sluigi 	 */
1234246896Sluigi	for (i = 0; i < g->nthreads; i++) {
1235246896Sluigi		bzero(&targs[i], sizeof(targs[i]));
1236246896Sluigi		targs[i].fd = -1; /* default, with pcap */
1237246896Sluigi		targs[i].g = g;
1238246896Sluigi
1239246896Sluigi	    if (g->dev_type == DEV_NETMAP) {
1240246896Sluigi		struct nmreq tifreq;
1241246896Sluigi		int tfd;
1242246896Sluigi
1243246896Sluigi		/* register interface. */
1244246896Sluigi		tfd = open("/dev/netmap", O_RDWR);
1245246896Sluigi		if (tfd == -1) {
1246246896Sluigi			D("Unable to open /dev/netmap");
1247246896Sluigi			continue;
1248246896Sluigi		}
1249246896Sluigi		targs[i].fd = tfd;
1250246896Sluigi
1251246896Sluigi		bzero(&tifreq, sizeof(tifreq));
1252246896Sluigi		strncpy(tifreq.nr_name, g->ifname, sizeof(tifreq.nr_name));
1253246896Sluigi		tifreq.nr_version = NETMAP_API;
1254246896Sluigi		tifreq.nr_ringid = (g->nthreads > 1) ? (i | NETMAP_HW_RING) : 0;
1255257529Sluigi		parse_nmr_config(g->nmr_config, &tifreq);
1256246896Sluigi
1257246896Sluigi		/*
1258246896Sluigi		 * if we are acting as a receiver only, do not touch the transmit ring.
1259246896Sluigi		 * This is not the default because many apps may use the interface
1260246896Sluigi		 * in both directions, but a pure receiver does not.
1261246896Sluigi		 */
1262246896Sluigi		if (g->td_body == receiver_body) {
1263246896Sluigi			tifreq.nr_ringid |= NETMAP_NO_TX_POLL;
1264246896Sluigi		}
1265246896Sluigi
1266246896Sluigi		if ((ioctl(tfd, NIOCREGIF, &tifreq)) == -1) {
1267246896Sluigi			D("Unable to register %s", g->ifname);
1268246896Sluigi			continue;
1269246896Sluigi		}
1270257529Sluigi		D("memsize is %d MB", tifreq.nr_memsize >> 20);
1271246896Sluigi		targs[i].nmr = tifreq;
1272246896Sluigi		targs[i].nifp = NETMAP_IF(g->mmap_addr, tifreq.nr_offset);
1273257529Sluigi		D("nifp flags 0x%x", targs[i].nifp->ni_flags);
1274246896Sluigi		/* start threads. */
1275246896Sluigi		targs[i].qfirst = (g->nthreads > 1) ? i : 0;
1276246896Sluigi		targs[i].qlast = (g->nthreads > 1) ? i+1 :
1277246896Sluigi			(g->td_body == receiver_body ? tifreq.nr_rx_rings : tifreq.nr_tx_rings);
1278246896Sluigi	    } else {
1279246896Sluigi		targs[i].fd = g->main_fd;
1280246896Sluigi	    }
1281246896Sluigi		targs[i].used = 1;
1282246896Sluigi		targs[i].me = i;
1283246896Sluigi		if (g->affinity >= 0) {
1284246896Sluigi			if (g->affinity < g->cpus)
1285246896Sluigi				targs[i].affinity = g->affinity;
1286246896Sluigi			else
1287246896Sluigi				targs[i].affinity = i % g->cpus;
1288246896Sluigi		} else
1289246896Sluigi			targs[i].affinity = -1;
1290246896Sluigi		/* default, init packets */
1291246896Sluigi		initialize_packet(&targs[i]);
1292246896Sluigi
1293246896Sluigi		if (pthread_create(&targs[i].thread, NULL, g->td_body,
1294246896Sluigi				   &targs[i]) == -1) {
1295246896Sluigi			D("Unable to create thread %d", i);
1296246896Sluigi			targs[i].used = 0;
1297246896Sluigi		}
1298246896Sluigi	}
1299246896Sluigi}
1300246896Sluigi
1301246896Sluigistatic void
1302246896Sluigimain_thread(struct glob_arg *g)
1303246896Sluigi{
1304246896Sluigi	int i;
1305246896Sluigi
1306246896Sluigi	uint64_t prev = 0;
1307246896Sluigi	uint64_t count = 0;
1308246896Sluigi	double delta_t;
1309246896Sluigi	struct timeval tic, toc;
1310246896Sluigi
1311246896Sluigi	gettimeofday(&toc, NULL);
1312246896Sluigi	for (;;) {
1313246896Sluigi		struct timeval now, delta;
1314246896Sluigi		uint64_t pps, usec, my_count, npkts;
1315246896Sluigi		int done = 0;
1316246896Sluigi
1317246896Sluigi		delta.tv_sec = g->report_interval/1000;
1318246896Sluigi		delta.tv_usec = (g->report_interval%1000)*1000;
1319246896Sluigi		select(0, NULL, NULL, NULL, &delta);
1320246896Sluigi		gettimeofday(&now, NULL);
1321246896Sluigi		time_second = now.tv_sec;
1322246896Sluigi		timersub(&now, &toc, &toc);
1323246896Sluigi		my_count = 0;
1324246896Sluigi		for (i = 0; i < g->nthreads; i++) {
1325246896Sluigi			my_count += targs[i].count;
1326246896Sluigi			if (targs[i].used == 0)
1327246896Sluigi				done++;
1328246896Sluigi		}
1329246896Sluigi		usec = toc.tv_sec* 1000000 + toc.tv_usec;
1330246896Sluigi		if (usec < 10000)
1331246896Sluigi			continue;
1332246896Sluigi		npkts = my_count - prev;
1333246896Sluigi		pps = (npkts*1000000 + usec/2) / usec;
1334246896Sluigi		D("%" PRIu64 " pps (%" PRIu64 " pkts in %" PRIu64 " usec)",
1335246896Sluigi			pps, npkts, usec);
1336246896Sluigi		prev = my_count;
1337246896Sluigi		toc = now;
1338246896Sluigi		if (done == g->nthreads)
1339246896Sluigi			break;
1340246896Sluigi	}
1341246896Sluigi
1342246896Sluigi	timerclear(&tic);
1343246896Sluigi	timerclear(&toc);
1344246896Sluigi	for (i = 0; i < g->nthreads; i++) {
1345251132Sluigi		struct timespec t_tic, t_toc;
1346246896Sluigi		/*
1347246896Sluigi		 * Join active threads, unregister interfaces and close
1348246896Sluigi		 * file descriptors.
1349246896Sluigi		 */
1350251132Sluigi		if (targs[i].used)
1351251132Sluigi			pthread_join(targs[i].thread, NULL);
1352246896Sluigi		close(targs[i].fd);
1353246896Sluigi
1354246896Sluigi		if (targs[i].completed == 0)
1355246896Sluigi			D("ouch, thread %d exited with error", i);
1356246896Sluigi
1357246896Sluigi		/*
1358246896Sluigi		 * Collect threads output and extract information about
1359246896Sluigi		 * how long it took to send all the packets.
1360246896Sluigi		 */
1361246896Sluigi		count += targs[i].count;
1362251132Sluigi		t_tic = timeval2spec(&tic);
1363251132Sluigi		t_toc = timeval2spec(&toc);
1364251132Sluigi		if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic))
1365251132Sluigi			tic = timespec2val(&targs[i].tic);
1366251132Sluigi		if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc))
1367251132Sluigi			toc = timespec2val(&targs[i].toc);
1368246896Sluigi	}
1369246896Sluigi
1370246896Sluigi	/* print output. */
1371246896Sluigi	timersub(&toc, &tic, &toc);
1372246896Sluigi	delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
1373246896Sluigi	if (g->td_body == sender_body)
1374246896Sluigi		tx_output(count, g->pkt_size, delta_t);
1375246896Sluigi	else
1376246896Sluigi		rx_output(count, delta_t);
1377246896Sluigi
1378246896Sluigi	if (g->dev_type == DEV_NETMAP) {
1379246896Sluigi		munmap(g->mmap_addr, g->mmap_size);
1380246896Sluigi		close(g->main_fd);
1381246896Sluigi	}
1382246896Sluigi}
1383246896Sluigi
1384246896Sluigi
1385246896Sluigistruct sf {
1386246896Sluigi	char *key;
1387246896Sluigi	void *f;
1388246896Sluigi};
1389246896Sluigi
1390246896Sluigistatic struct sf func[] = {
1391246896Sluigi	{ "tx",	sender_body },
1392246896Sluigi	{ "rx",	receiver_body },
1393246896Sluigi	{ "ping",	pinger_body },
1394246896Sluigi	{ "pong",	ponger_body },
1395246896Sluigi	{ NULL, NULL }
1396246896Sluigi};
1397246896Sluigi
1398246896Sluigistatic int
1399246896Sluigitap_alloc(char *dev)
1400246896Sluigi{
1401246896Sluigi	struct ifreq ifr;
1402246896Sluigi	int fd, err;
1403246896Sluigi	char *clonedev = TAP_CLONEDEV;
1404246896Sluigi
1405246896Sluigi	(void)err;
1406246896Sluigi	(void)dev;
1407246896Sluigi	/* Arguments taken by the function:
1408246896Sluigi	 *
1409246896Sluigi	 * char *dev: the name of an interface (or '\0'). MUST have enough
1410246896Sluigi	 *   space to hold the interface name if '\0' is passed
1411246896Sluigi	 * int flags: interface flags (eg, IFF_TUN etc.)
1412246896Sluigi	 */
1413246896Sluigi
1414246896Sluigi#ifdef __FreeBSD__
1415246896Sluigi	if (dev[3]) { /* tapSomething */
1416246896Sluigi		static char buf[128];
1417246896Sluigi		snprintf(buf, sizeof(buf), "/dev/%s", dev);
1418246896Sluigi		clonedev = buf;
1419246896Sluigi	}
1420246896Sluigi#endif
1421246896Sluigi	/* open the device */
1422246896Sluigi	if( (fd = open(clonedev, O_RDWR)) < 0 ) {
1423246896Sluigi		return fd;
1424246896Sluigi	}
1425246896Sluigi	D("%s open successful", clonedev);
1426246896Sluigi
1427246896Sluigi	/* preparation of the struct ifr, of type "struct ifreq" */
1428246896Sluigi	memset(&ifr, 0, sizeof(ifr));
1429246896Sluigi
1430246896Sluigi#ifdef linux
1431246896Sluigi	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
1432246896Sluigi
1433246896Sluigi	if (*dev) {
1434246896Sluigi		/* if a device name was specified, put it in the structure; otherwise,
1435246896Sluigi		* the kernel will try to allocate the "next" device of the
1436246896Sluigi		* specified type */
1437246896Sluigi		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1438246896Sluigi	}
1439246896Sluigi
1440246896Sluigi	/* try to create the device */
1441246896Sluigi	if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
1442246896Sluigi		D("failed to to a TUNSETIFF");
1443246896Sluigi		close(fd);
1444246896Sluigi		return err;
1445246896Sluigi	}
1446246896Sluigi
1447246896Sluigi	/* if the operation was successful, write back the name of the
1448246896Sluigi	* interface to the variable "dev", so the caller can know
1449246896Sluigi	* it. Note that the caller MUST reserve space in *dev (see calling
1450246896Sluigi	* code below) */
1451246896Sluigi	strcpy(dev, ifr.ifr_name);
1452246896Sluigi	D("new name is %s", dev);
1453246896Sluigi#endif /* linux */
1454246896Sluigi
1455246896Sluigi        /* this is the special file descriptor that the caller will use to talk
1456246896Sluigi         * with the virtual interface */
1457246896Sluigi        return fd;
1458246896Sluigi}
1459246896Sluigi
1460227614Sluigiint
1461227614Sluigimain(int arc, char **argv)
1462227614Sluigi{
1463246896Sluigi	int i;
1464227614Sluigi
1465227614Sluigi	struct glob_arg g;
1466227614Sluigi
1467227614Sluigi	struct nmreq nmr;
1468227614Sluigi	int ch;
1469227614Sluigi	int wait_link = 2;
1470227614Sluigi	int devqueues = 1;	/* how many device queues */
1471227614Sluigi
1472227614Sluigi	bzero(&g, sizeof(g));
1473227614Sluigi
1474246896Sluigi	g.main_fd = -1;
1475246896Sluigi	g.td_body = receiver_body;
1476246896Sluigi	g.report_interval = 1000;	/* report interval */
1477246896Sluigi	g.affinity = -1;
1478246896Sluigi	/* ip addresses can also be a range x.x.x.x-x.x.x.y */
1479246896Sluigi	g.src_ip.name = "10.0.0.1";
1480246896Sluigi	g.dst_ip.name = "10.1.0.1";
1481246896Sluigi	g.dst_mac.name = "ff:ff:ff:ff:ff:ff";
1482246896Sluigi	g.src_mac.name = NULL;
1483227614Sluigi	g.pkt_size = 60;
1484227614Sluigi	g.burst = 512;		// default
1485227614Sluigi	g.nthreads = 1;
1486227614Sluigi	g.cpus = 1;
1487251426Sluigi	g.forever = 1;
1488251132Sluigi	g.tx_rate = 0;
1489257529Sluigi	g.frags = 1;
1490257529Sluigi	g.nmr_config = "";
1491227614Sluigi
1492227614Sluigi	while ( (ch = getopt(arc, argv,
1493257529Sluigi			"a:f:F:n:i:It:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:XC:")) != -1) {
1494246896Sluigi		struct sf *fn;
1495246896Sluigi
1496227614Sluigi		switch(ch) {
1497227614Sluigi		default:
1498227614Sluigi			D("bad option %c %s", ch, optarg);
1499227614Sluigi			usage();
1500227614Sluigi			break;
1501246896Sluigi
1502246896Sluigi		case 'n':
1503246896Sluigi			g.npackets = atoi(optarg);
1504246896Sluigi			break;
1505246896Sluigi
1506257529Sluigi		case 'F':
1507257529Sluigi			i = atoi(optarg);
1508257529Sluigi			if (i < 1 || i > 63) {
1509257529Sluigi				D("invalid frags %d [1..63], ignore", i);
1510257529Sluigi				break;
1511257529Sluigi			}
1512257529Sluigi			g.frags = i;
1513257529Sluigi			break;
1514257529Sluigi
1515246896Sluigi		case 'f':
1516246896Sluigi			for (fn = func; fn->key; fn++) {
1517246896Sluigi				if (!strcmp(fn->key, optarg))
1518246896Sluigi					break;
1519246896Sluigi			}
1520246896Sluigi			if (fn->key)
1521246896Sluigi				g.td_body = fn->f;
1522246896Sluigi			else
1523246896Sluigi				D("unrecognised function %s", optarg);
1524246896Sluigi			break;
1525246896Sluigi
1526246896Sluigi		case 'o':	/* data generation options */
1527234956Sluigi			g.options = atoi(optarg);
1528234956Sluigi			break;
1529246896Sluigi
1530246896Sluigi		case 'a':       /* force affinity */
1531246896Sluigi			g.affinity = atoi(optarg);
1532246896Sluigi			break;
1533246896Sluigi
1534227614Sluigi		case 'i':	/* interface */
1535246896Sluigi			g.ifname = optarg;
1536246896Sluigi			if (!strncmp(optarg, "tap", 3))
1537246896Sluigi				g.dev_type = DEV_TAP;
1538246896Sluigi			else
1539246896Sluigi				g.dev_type = DEV_NETMAP;
1540257529Sluigi			if (!strcmp(g.ifname, "null"))
1541257529Sluigi				g.dummy_send = 1;
1542227614Sluigi			break;
1543246896Sluigi
1544251426Sluigi		case 'I':
1545251426Sluigi			g.options |= OPT_INDIRECT;	/* XXX use indirect buffer */
1546251426Sluigi			break;
1547251426Sluigi
1548246896Sluigi		case 't':	/* send, deprecated */
1549246896Sluigi			D("-t deprecated, please use -f tx -n %s", optarg);
1550246896Sluigi			g.td_body = sender_body;
1551227614Sluigi			g.npackets = atoi(optarg);
1552227614Sluigi			break;
1553246896Sluigi
1554227614Sluigi		case 'r':	/* receive */
1555246896Sluigi			D("-r deprecated, please use -f rx -n %s", optarg);
1556246896Sluigi			g.td_body = receiver_body;
1557227614Sluigi			g.npackets = atoi(optarg);
1558227614Sluigi			break;
1559246896Sluigi
1560227614Sluigi		case 'l':	/* pkt_size */
1561227614Sluigi			g.pkt_size = atoi(optarg);
1562227614Sluigi			break;
1563246896Sluigi
1564227614Sluigi		case 'd':
1565246896Sluigi			g.dst_ip.name = optarg;
1566227614Sluigi			break;
1567246896Sluigi
1568227614Sluigi		case 's':
1569246896Sluigi			g.src_ip.name = optarg;
1570227614Sluigi			break;
1571246896Sluigi
1572227614Sluigi		case 'T':	/* report interval */
1573246896Sluigi			g.report_interval = atoi(optarg);
1574227614Sluigi			break;
1575246896Sluigi
1576227614Sluigi		case 'w':
1577227614Sluigi			wait_link = atoi(optarg);
1578227614Sluigi			break;
1579246896Sluigi
1580251426Sluigi		case 'W': /* XXX changed default */
1581251426Sluigi			g.forever = 0; /* do not exit rx even with no traffic */
1582246896Sluigi			break;
1583246896Sluigi
1584227614Sluigi		case 'b':	/* burst */
1585227614Sluigi			g.burst = atoi(optarg);
1586227614Sluigi			break;
1587227614Sluigi		case 'c':
1588227614Sluigi			g.cpus = atoi(optarg);
1589227614Sluigi			break;
1590227614Sluigi		case 'p':
1591227614Sluigi			g.nthreads = atoi(optarg);
1592227614Sluigi			break;
1593227614Sluigi
1594227614Sluigi		case 'P':
1595246896Sluigi			g.dev_type = DEV_PCAP;
1596227614Sluigi			break;
1597227614Sluigi
1598227614Sluigi		case 'D': /* destination mac */
1599246896Sluigi			g.dst_mac.name = optarg;
1600227614Sluigi			break;
1601246896Sluigi
1602227614Sluigi		case 'S': /* source mac */
1603246896Sluigi			g.src_mac.name = optarg;
1604227614Sluigi			break;
1605227614Sluigi		case 'v':
1606227614Sluigi			verbose++;
1607251132Sluigi			break;
1608251132Sluigi		case 'R':
1609251132Sluigi			g.tx_rate = atoi(optarg);
1610251132Sluigi			break;
1611251426Sluigi		case 'X':
1612251426Sluigi			g.options |= OPT_DUMP;
1613257529Sluigi			break;
1614257529Sluigi		case 'C':
1615257529Sluigi			g.nmr_config = strdup(optarg);
1616227614Sluigi		}
1617227614Sluigi	}
1618227614Sluigi
1619246896Sluigi	if (g.ifname == NULL) {
1620227614Sluigi		D("missing ifname");
1621227614Sluigi		usage();
1622227614Sluigi	}
1623246896Sluigi
1624246896Sluigi	i = system_ncpus();
1625246896Sluigi	if (g.cpus < 0 || g.cpus > i) {
1626246896Sluigi		D("%d cpus is too high, have only %d cpus", g.cpus, i);
1627246896Sluigi		usage();
1628227614Sluigi	}
1629246896Sluigi	if (g.cpus == 0)
1630246896Sluigi		g.cpus = i;
1631246896Sluigi
1632227614Sluigi	if (g.pkt_size < 16 || g.pkt_size > 1536) {
1633227614Sluigi		D("bad pktsize %d\n", g.pkt_size);
1634227614Sluigi		usage();
1635227614Sluigi	}
1636227614Sluigi
1637246896Sluigi	if (g.src_mac.name == NULL) {
1638246896Sluigi		static char mybuf[20] = "00:00:00:00:00:00";
1639234956Sluigi		/* retrieve source mac address. */
1640246896Sluigi		if (source_hwaddr(g.ifname, mybuf) == -1) {
1641234956Sluigi			D("Unable to retrieve source mac");
1642234956Sluigi			// continue, fail later
1643234956Sluigi		}
1644246896Sluigi		g.src_mac.name = mybuf;
1645234956Sluigi	}
1646246896Sluigi	/* extract address ranges */
1647246896Sluigi	extract_ip_range(&g.src_ip);
1648246896Sluigi	extract_ip_range(&g.dst_ip);
1649246896Sluigi	extract_mac_range(&g.src_mac);
1650246896Sluigi	extract_mac_range(&g.dst_mac);
1651234956Sluigi
1652246896Sluigi    if (g.dev_type == DEV_TAP) {
1653246896Sluigi	D("want to use tap %s", g.ifname);
1654246896Sluigi	g.main_fd = tap_alloc(g.ifname);
1655246896Sluigi	if (g.main_fd < 0) {
1656246896Sluigi		D("cannot open tap %s", g.ifname);
1657246896Sluigi		usage();
1658246896Sluigi	}
1659246896Sluigi    } else if (g.dev_type > DEV_NETMAP) {
1660246896Sluigi	char pcap_errbuf[PCAP_ERRBUF_SIZE];
1661246896Sluigi
1662246896Sluigi	D("using pcap on %s", g.ifname);
1663246896Sluigi	pcap_errbuf[0] = '\0'; // init the buffer
1664246896Sluigi	g.p = pcap_open_live(g.ifname, 0, 1, 100, pcap_errbuf);
1665234956Sluigi	if (g.p == NULL) {
1666246896Sluigi		D("cannot open pcap on %s", g.ifname);
1667234956Sluigi		usage();
1668234956Sluigi	}
1669257529Sluigi    } else if (g.dummy_send) {
1670257529Sluigi	D("using a dummy send routine");
1671234956Sluigi    } else {
1672227614Sluigi	bzero(&nmr, sizeof(nmr));
1673232238Sluigi	nmr.nr_version = NETMAP_API;
1674227614Sluigi	/*
1675227614Sluigi	 * Open the netmap device to fetch the number of queues of our
1676227614Sluigi	 * interface.
1677227614Sluigi	 *
1678227614Sluigi	 * The first NIOCREGIF also detaches the card from the
1679227614Sluigi	 * protocol stack and may cause a reset of the card,
1680227614Sluigi	 * which in turn may take some time for the PHY to
1681227614Sluigi	 * reconfigure.
1682227614Sluigi	 */
1683246896Sluigi	g.main_fd = open("/dev/netmap", O_RDWR);
1684246896Sluigi	if (g.main_fd == -1) {
1685227614Sluigi		D("Unable to open /dev/netmap");
1686246896Sluigi		// fail later
1687227614Sluigi	}
1688257529Sluigi	/*
1689257529Sluigi	 * Register the interface on the netmap device: from now on,
1690257529Sluigi	 * we can operate on the network interface without any
1691257529Sluigi	 * interference from the legacy network stack.
1692257529Sluigi	 *
1693257529Sluigi	 * We decide to put the first interface registration here to
1694257529Sluigi	 * give time to cards that take a long time to reset the PHY.
1695257529Sluigi	 */
1696257529Sluigi	bzero(&nmr, sizeof(nmr));
1697257529Sluigi	nmr.nr_version = NETMAP_API;
1698257529Sluigi	strncpy(nmr.nr_name, g.ifname, sizeof(nmr.nr_name));
1699257529Sluigi	nmr.nr_version = NETMAP_API;
1700257529Sluigi	parse_nmr_config(g.nmr_config, &nmr);
1701257529Sluigi	if (ioctl(g.main_fd, NIOCREGIF, &nmr) == -1) {
1702257529Sluigi		D("Unable to register interface %s", g.ifname);
1703257529Sluigi		//continue, fail later
1704257529Sluigi	}
1705257529Sluigi	ND("%s: txr %d txd %d rxr %d rxd %d", g.ifname,
1706257529Sluigi			nmr.nr_tx_rings, nmr.nr_tx_slots,
1707257529Sluigi			nmr.nr_rx_rings, nmr.nr_rx_slots);
1708257529Sluigi	//if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) {
1709257529Sluigi	//	D("Unable to get if info without name");
1710257529Sluigi	//} else {
1711257529Sluigi	//	D("map size is %d Kb", nmr.nr_memsize >> 10);
1712257529Sluigi	//}
1713257529Sluigi	if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) {
1714257529Sluigi		D("Unable to get if info for %s", g.ifname);
1715257529Sluigi	}
1716257529Sluigi	devqueues = nmr.nr_rx_rings;
1717227614Sluigi
1718227614Sluigi	/* validate provided nthreads. */
1719227614Sluigi	if (g.nthreads < 1 || g.nthreads > devqueues) {
1720227614Sluigi		D("bad nthreads %d, have %d queues", g.nthreads, devqueues);
1721227614Sluigi		// continue, fail later
1722227614Sluigi	}
1723227614Sluigi
1724227614Sluigi	/*
1725227614Sluigi	 * Map the netmap shared memory: instead of issuing mmap()
1726227614Sluigi	 * inside the body of the threads, we prefer to keep this
1727227614Sluigi	 * operation here to simplify the thread logic.
1728227614Sluigi	 */
1729246896Sluigi	D("mapping %d Kbytes", nmr.nr_memsize>>10);
1730246896Sluigi	g.mmap_size = nmr.nr_memsize;
1731246896Sluigi	g.mmap_addr = (struct netmap_d *) mmap(0, nmr.nr_memsize,
1732227614Sluigi					    PROT_WRITE | PROT_READ,
1733246896Sluigi					    MAP_SHARED, g.main_fd, 0);
1734246896Sluigi	if (g.mmap_addr == MAP_FAILED) {
1735227614Sluigi		D("Unable to mmap %d KB", nmr.nr_memsize >> 10);
1736227614Sluigi		// continue, fail later
1737227614Sluigi	}
1738227614Sluigi
1739227614Sluigi
1740227614Sluigi
1741227614Sluigi	/* Print some debug information. */
1742227614Sluigi	fprintf(stdout,
1743227614Sluigi		"%s %s: %d queues, %d threads and %d cpus.\n",
1744246896Sluigi		(g.td_body == sender_body) ? "Sending on" : "Receiving from",
1745246896Sluigi		g.ifname,
1746227614Sluigi		devqueues,
1747227614Sluigi		g.nthreads,
1748227614Sluigi		g.cpus);
1749246896Sluigi	if (g.td_body == sender_body) {
1750227614Sluigi		fprintf(stdout, "%s -> %s (%s -> %s)\n",
1751246896Sluigi			g.src_ip.name, g.dst_ip.name,
1752246896Sluigi			g.src_mac.name, g.dst_mac.name);
1753227614Sluigi	}
1754227614Sluigi
1755227614Sluigi	/* Exit if something went wrong. */
1756246896Sluigi	if (g.main_fd < 0) {
1757227614Sluigi		D("aborting");
1758227614Sluigi		usage();
1759227614Sluigi	}
1760234956Sluigi    }
1761227614Sluigi
1762257529Sluigi
1763234956Sluigi	if (g.options) {
1764251426Sluigi		D("--- SPECIAL OPTIONS:%s%s%s%s%s\n",
1765234956Sluigi			g.options & OPT_PREFETCH ? " prefetch" : "",
1766234956Sluigi			g.options & OPT_ACCESS ? " access" : "",
1767234956Sluigi			g.options & OPT_MEMCPY ? " memcpy" : "",
1768251426Sluigi			g.options & OPT_INDIRECT ? " indirect" : "",
1769234956Sluigi			g.options & OPT_COPY ? " copy" : "");
1770234956Sluigi	}
1771257529Sluigi
1772257529Sluigi	g.tx_period.tv_sec = g.tx_period.tv_nsec = 0;
1773257529Sluigi	if (g.tx_rate > 0) {
1774257529Sluigi		/* try to have at least something every second,
1775257529Sluigi		 * reducing the burst size to 0.5s worth of data
1776257529Sluigi		 * (but no less than one full set of fragments)
1777257529Sluigi	 	 */
1778257529Sluigi		if (g.burst > g.tx_rate/2)
1779257529Sluigi			g.burst = g.tx_rate/2;
1780257529Sluigi		if (g.burst < g.frags)
1781257529Sluigi			g.burst = g.frags;
1782251132Sluigi		g.tx_period.tv_nsec = (1e9 / g.tx_rate) * g.burst;
1783257529Sluigi		g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000;
1784257529Sluigi		g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000;
1785251132Sluigi	}
1786257529Sluigi	if (g.td_body == sender_body)
1787257529Sluigi	    D("Sending %d packets every  %ld.%09ld s",
1788257529Sluigi			g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec);
1789227614Sluigi	/* Wait for PHY reset. */
1790227614Sluigi	D("Wait %d secs for phy reset", wait_link);
1791227614Sluigi	sleep(wait_link);
1792227614Sluigi	D("Ready...");
1793227614Sluigi
1794227614Sluigi	/* Install ^C handler. */
1795227614Sluigi	global_nthreads = g.nthreads;
1796227614Sluigi	signal(SIGINT, sigint_h);
1797227614Sluigi
1798246896Sluigi#if 0 // XXX this is not needed, i believe
1799246896Sluigi	if (g.dev_type > DEV_NETMAP) {
1800246896Sluigi		g.p = pcap_open_live(g.ifname, 0, 1, 100, NULL);
1801234956Sluigi		if (g.p == NULL) {
1802246896Sluigi			D("cannot open pcap on %s", g.ifname);
1803234956Sluigi			usage();
1804234956Sluigi		} else
1805246896Sluigi			D("using pcap %p on %s", g.p, g.ifname);
1806227614Sluigi	}
1807246896Sluigi#endif // XXX
1808246896Sluigi	start_threads(&g);
1809246896Sluigi	main_thread(&g);
1810246896Sluigi	return 0;
1811246896Sluigi}
1812227614Sluigi
1813227614Sluigi/* end of file */
1814