pkt-gen.c revision 272962
1227614Sluigi/*
2260368Sluigi * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
3260368Sluigi * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
4227614Sluigi *
5227614Sluigi * Redistribution and use in source and binary forms, with or without
6227614Sluigi * modification, are permitted provided that the following conditions
7227614Sluigi * are met:
8228276Sluigi *   1. Redistributions of source code must retain the above copyright
9228276Sluigi *      notice, this list of conditions and the following disclaimer.
10228276Sluigi *   2. Redistributions in binary form must reproduce the above copyright
11228276Sluigi *      notice, this list of conditions and the following disclaimer in the
12227614Sluigi *    documentation and/or other materials provided with the distribution.
13227614Sluigi *
14227614Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15227614Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16227614Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17227614Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18227614Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19227614Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20227614Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21227614Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22227614Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23227614Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24227614Sluigi * SUCH DAMAGE.
25227614Sluigi */
26227614Sluigi
27227614Sluigi/*
28227614Sluigi * $FreeBSD: head/tools/tools/netmap/pkt-gen.c 272962 2014-10-11 21:43:05Z gnn $
29257529Sluigi * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $
30227614Sluigi *
31227614Sluigi * Example program to show how to build a multithreaded packet
32227614Sluigi * source/sink using the netmap device.
33227614Sluigi *
34227614Sluigi * In this example we create a programmable number of threads
35227614Sluigi * to take care of all the queues of the interface used to
36227614Sluigi * send or receive traffic.
37227614Sluigi *
38227614Sluigi */
39227614Sluigi
40270063Sluigi// #define TRASH_VHOST_HDR
41270063Sluigi
42261909Sluigi#define _GNU_SOURCE	/* for CPU_SET() */
43261909Sluigi#include <stdio.h>
44261909Sluigi#define NETMAP_WITH_LIBS
45261909Sluigi#include <net/netmap_user.h>
46246896Sluigi
47261909Sluigi
48251426Sluigi#include <ctype.h>	// isprint()
49261909Sluigi#include <unistd.h>	// sysconf()
50261909Sluigi#include <sys/poll.h>
51261909Sluigi#include <arpa/inet.h>	/* ntohs */
52261909Sluigi#include <sys/sysctl.h>	/* sysctl */
53261909Sluigi#include <ifaddrs.h>	/* getifaddrs */
54261909Sluigi#include <net/ethernet.h>
55261909Sluigi#include <netinet/in.h>
56261909Sluigi#include <netinet/ip.h>
57261909Sluigi#include <netinet/udp.h>
58251426Sluigi
59261909Sluigi#include <pthread.h>
60261909Sluigi
61260700Sluigi#ifndef NO_PCAP
62260700Sluigi#include <pcap/pcap.h>
63260700Sluigi#endif
64261909Sluigi
65261909Sluigi#ifdef linux
66261909Sluigi
67261909Sluigi#define cpuset_t        cpu_set_t
68261909Sluigi
69261909Sluigi#define ifr_flagshigh  ifr_flags        /* only the low 16 bits here */
70261909Sluigi#define IFF_PPROMISC   IFF_PROMISC      /* IFF_PPROMISC does not exist */
71261909Sluigi#include <linux/ethtool.h>
72261909Sluigi#include <linux/sockios.h>
73261909Sluigi
74261909Sluigi#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME
75261909Sluigi#include <netinet/ether.h>      /* ether_aton */
76261909Sluigi#include <linux/if_packet.h>    /* sockaddr_ll */
77261909Sluigi#endif  /* linux */
78261909Sluigi
79261909Sluigi#ifdef __FreeBSD__
80261909Sluigi#include <sys/endian.h> /* le64toh */
81261909Sluigi#include <machine/param.h>
82261909Sluigi
83261909Sluigi#include <pthread_np.h> /* pthread w/ affinity */
84261909Sluigi#include <sys/cpuset.h> /* cpu_set */
85261909Sluigi#include <net/if_dl.h>  /* LLADDR */
86261909Sluigi#endif  /* __FreeBSD__ */
87261909Sluigi
88261909Sluigi#ifdef __APPLE__
89261909Sluigi
90261909Sluigi#define cpuset_t        uint64_t        // XXX
91261909Sluigistatic inline void CPU_ZERO(cpuset_t *p)
92261909Sluigi{
93261909Sluigi        *p = 0;
94261909Sluigi}
95261909Sluigi
96261909Sluigistatic inline void CPU_SET(uint32_t i, cpuset_t *p)
97261909Sluigi{
98261909Sluigi        *p |= 1<< (i & 0x3f);
99261909Sluigi}
100261909Sluigi
101261909Sluigi#define pthread_setaffinity_np(a, b, c) ((void)a, 0)
102261909Sluigi
103261909Sluigi#define ifr_flagshigh  ifr_flags        // XXX
104261909Sluigi#define IFF_PPROMISC   IFF_PROMISC
105261909Sluigi#include <net/if_dl.h>  /* LLADDR */
106261909Sluigi#define clock_gettime(a,b)      \
107261909Sluigi        do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
108261909Sluigi#endif  /* __APPLE__ */
109261909Sluigi
110257529Sluigiconst char *default_payload="netmap pkt-gen DIRECT payload\n"
111227614Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
112227614Sluigi
113257529Sluigiconst char *indirect_payload="netmap pkt-gen indirect payload\n"
114257529Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
115257529Sluigi
116227614Sluigiint verbose = 0;
117227614Sluigi
118261909Sluigi#define SKIP_PAYLOAD 1 /* do not check payload. XXX unused */
119227614Sluigi
120260368Sluigi
121260368Sluigi#define VIRT_HDR_1	10	/* length of a base vnet-hdr */
122260368Sluigi#define VIRT_HDR_2	12	/* length of the extenede vnet-hdr */
123260368Sluigi#define VIRT_HDR_MAX	VIRT_HDR_2
124260368Sluigistruct virt_header {
125260368Sluigi	uint8_t fields[VIRT_HDR_MAX];
126260368Sluigi};
127260368Sluigi
128270063Sluigi#define MAX_BODYSIZE	16384
129270063Sluigi
130227614Sluigistruct pkt {
131260368Sluigi	struct virt_header vh;
132227614Sluigi	struct ether_header eh;
133227614Sluigi	struct ip ip;
134227614Sluigi	struct udphdr udp;
135270063Sluigi	uint8_t body[MAX_BODYSIZE];	// XXX hardwired
136227614Sluigi} __attribute__((__packed__));
137227614Sluigi
138246896Sluigistruct ip_range {
139246896Sluigi	char *name;
140257529Sluigi	uint32_t start, end; /* same as struct in_addr */
141257529Sluigi	uint16_t port0, port1;
142246896Sluigi};
143246896Sluigi
144246896Sluigistruct mac_range {
145246896Sluigi	char *name;
146246896Sluigi	struct ether_addr start, end;
147246896Sluigi};
148246896Sluigi
149261909Sluigi/* ifname can be netmap:foo-xxxx */
150261909Sluigi#define MAX_IFNAMELEN	64	/* our buffer for ifname */
151270063Sluigi//#define MAX_PKTSIZE	1536
152270063Sluigi#define MAX_PKTSIZE	MAX_BODYSIZE	/* XXX: + IP_HDR + ETH_HDR */
153270063Sluigi
154270063Sluigi/* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
155270063Sluigistruct tstamp {
156270063Sluigi	uint32_t sec;
157270063Sluigi	uint32_t nsec;
158270063Sluigi};
159270063Sluigi
160227614Sluigi/*
161227614Sluigi * global arguments for all threads
162227614Sluigi */
163246896Sluigi
164227614Sluigistruct glob_arg {
165246896Sluigi	struct ip_range src_ip;
166246896Sluigi	struct ip_range dst_ip;
167246896Sluigi	struct mac_range dst_mac;
168246896Sluigi	struct mac_range src_mac;
169227614Sluigi	int pkt_size;
170227614Sluigi	int burst;
171246896Sluigi	int forever;
172227614Sluigi	int npackets;	/* total packets to send */
173257529Sluigi	int frags;	/* fragments per packet */
174227614Sluigi	int nthreads;
175227614Sluigi	int cpus;
176234956Sluigi	int options;	/* testing */
177234956Sluigi#define OPT_PREFETCH	1
178234956Sluigi#define OPT_ACCESS	2
179234956Sluigi#define OPT_COPY	4
180234956Sluigi#define OPT_MEMCPY	8
181246896Sluigi#define OPT_TS		16	/* add a timestamp */
182251426Sluigi#define OPT_INDIRECT	32	/* use indirect buffers, tx only */
183251426Sluigi#define OPT_DUMP	64	/* dump rx/tx traffic */
184270063Sluigi#define OPT_MONITOR_TX  128
185270063Sluigi#define OPT_MONITOR_RX  256
186246896Sluigi	int dev_type;
187260700Sluigi#ifndef NO_PCAP
188227614Sluigi	pcap_t *p;
189260700Sluigi#endif
190227614Sluigi
191251132Sluigi	int tx_rate;
192251132Sluigi	struct timespec tx_period;
193251132Sluigi
194246896Sluigi	int affinity;
195246896Sluigi	int main_fd;
196261909Sluigi	struct nm_desc *nmd;
197260700Sluigi	int report_interval;		/* milliseconds between prints */
198246896Sluigi	void *(*td_body)(void *);
199246896Sluigi	void *mmap_addr;
200261909Sluigi	char ifname[MAX_IFNAMELEN];
201257529Sluigi	char *nmr_config;
202257529Sluigi	int dummy_send;
203260368Sluigi	int virt_header;	/* send also the virt_header */
204261909Sluigi	int extra_bufs;		/* goes in nr_arg3 */
205272962Sgnn	char *packet_file;	/* -P option */
206227614Sluigi};
207246896Sluigienum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
208227614Sluigi
209246896Sluigi
210227614Sluigi/*
211227614Sluigi * Arguments for a new thread. The same structure is used by
212227614Sluigi * the source and the sink
213227614Sluigi */
214227614Sluigistruct targ {
215227614Sluigi	struct glob_arg *g;
216227614Sluigi	int used;
217227614Sluigi	int completed;
218238165Semaste	int cancel;
219227614Sluigi	int fd;
220261909Sluigi	struct nm_desc *nmd;
221246896Sluigi	volatile uint64_t count;
222251132Sluigi	struct timespec tic, toc;
223227614Sluigi	int me;
224227614Sluigi	pthread_t thread;
225227614Sluigi	int affinity;
226227614Sluigi
227227614Sluigi	struct pkt pkt;
228272962Sgnn	void *frame;
229227614Sluigi};
230227614Sluigi
231227614Sluigi
232246896Sluigi/*
233246896Sluigi * extract the extremes from a range of ipv4 addresses.
234246896Sluigi * addr_lo[-addr_hi][:port_lo[-port_hi]]
235246896Sluigi */
236246896Sluigistatic void
237246896Sluigiextract_ip_range(struct ip_range *r)
238246896Sluigi{
239257529Sluigi	char *ap, *pp;
240257529Sluigi	struct in_addr a;
241246896Sluigi
242260368Sluigi	if (verbose)
243260368Sluigi		D("extract IP range from %s", r->name);
244257529Sluigi	r->port0 = r->port1 = 0;
245257529Sluigi	r->start = r->end = 0;
246257529Sluigi
247257529Sluigi	/* the first - splits start/end of range */
248257529Sluigi	ap = index(r->name, '-');	/* do we have ports ? */
249257529Sluigi	if (ap) {
250257529Sluigi		*ap++ = '\0';
251257529Sluigi	}
252257529Sluigi	/* grab the initial values (mandatory) */
253257529Sluigi	pp = index(r->name, ':');
254257529Sluigi	if (pp) {
255257529Sluigi		*pp++ = '\0';
256257529Sluigi		r->port0 = r->port1 = strtol(pp, NULL, 0);
257257529Sluigi	};
258257529Sluigi	inet_aton(r->name, &a);
259257529Sluigi	r->start = r->end = ntohl(a.s_addr);
260257529Sluigi	if (ap) {
261257529Sluigi		pp = index(ap, ':');
262257529Sluigi		if (pp) {
263257529Sluigi			*pp++ = '\0';
264261909Sluigi			if (*pp)
265257529Sluigi				r->port1 = strtol(pp, NULL, 0);
266246896Sluigi		}
267257529Sluigi		if (*ap) {
268257529Sluigi			inet_aton(ap, &a);
269257529Sluigi			r->end = ntohl(a.s_addr);
270257529Sluigi		}
271246896Sluigi	}
272257529Sluigi	if (r->port0 > r->port1) {
273257529Sluigi		uint16_t tmp = r->port0;
274257529Sluigi		r->port0 = r->port1;
275257529Sluigi		r->port1 = tmp;
276257529Sluigi	}
277257529Sluigi	if (r->start > r->end) {
278257529Sluigi		uint32_t tmp = r->start;
279246896Sluigi		r->start = r->end;
280257529Sluigi		r->end = tmp;
281246896Sluigi	}
282257529Sluigi	{
283257529Sluigi		struct in_addr a;
284257529Sluigi		char buf1[16]; // one ip address
285257529Sluigi
286257529Sluigi		a.s_addr = htonl(r->end);
287257529Sluigi		strncpy(buf1, inet_ntoa(a), sizeof(buf1));
288257529Sluigi		a.s_addr = htonl(r->start);
289260368Sluigi		if (1)
290260368Sluigi		    D("range is %s:%d to %s:%d",
291257529Sluigi			inet_ntoa(a), r->port0, buf1, r->port1);
292257529Sluigi	}
293246896Sluigi}
294246896Sluigi
295246896Sluigistatic void
296246896Sluigiextract_mac_range(struct mac_range *r)
297246896Sluigi{
298260368Sluigi	if (verbose)
299260368Sluigi	    D("extract MAC range from %s", r->name);
300246896Sluigi	bcopy(ether_aton(r->name), &r->start, 6);
301246896Sluigi	bcopy(ether_aton(r->name), &r->end, 6);
302246896Sluigi#if 0
303246896Sluigi	bcopy(targ->src_mac, eh->ether_shost, 6);
304246896Sluigi	p = index(targ->g->src_mac, '-');
305246896Sluigi	if (p)
306246896Sluigi		targ->src_mac_range = atoi(p+1);
307246896Sluigi
308246896Sluigi	bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6);
309246896Sluigi	bcopy(targ->dst_mac, eh->ether_dhost, 6);
310246896Sluigi	p = index(targ->g->dst_mac, '-');
311246896Sluigi	if (p)
312246896Sluigi		targ->dst_mac_range = atoi(p+1);
313246896Sluigi#endif
314260368Sluigi	if (verbose)
315260368Sluigi		D("%s starts at %s", r->name, ether_ntoa(&r->start));
316246896Sluigi}
317246896Sluigi
318227614Sluigistatic struct targ *targs;
319227614Sluigistatic int global_nthreads;
320227614Sluigi
321227614Sluigi/* control-C handler */
322227614Sluigistatic void
323246896Sluigisigint_h(int sig)
324227614Sluigi{
325246896Sluigi	int i;
326246896Sluigi
327246896Sluigi	(void)sig;	/* UNUSED */
328270063Sluigi	D("received control-C on thread %p", pthread_self());
329246896Sluigi	for (i = 0; i < global_nthreads; i++) {
330238165Semaste		targs[i].cancel = 1;
331246896Sluigi	}
332227614Sluigi	signal(SIGINT, SIG_DFL);
333227614Sluigi}
334227614Sluigi
335227614Sluigi/* sysctl wrapper to return the number of active CPUs */
336227614Sluigistatic int
337227614Sluigisystem_ncpus(void)
338227614Sluigi{
339261909Sluigi	int ncpus;
340261909Sluigi#if defined (__FreeBSD__)
341261909Sluigi	int mib[2] = { CTL_HW, HW_NCPU };
342261909Sluigi	size_t len = sizeof(mib);
343227614Sluigi	sysctl(mib, 2, &ncpus, &len, NULL, 0);
344261909Sluigi#elif defined(linux)
345261909Sluigi	ncpus = sysconf(_SC_NPROCESSORS_ONLN);
346261909Sluigi#else /* others */
347261909Sluigi	ncpus = 1;
348261909Sluigi#endif /* others */
349227614Sluigi	return (ncpus);
350227614Sluigi}
351227614Sluigi
352246896Sluigi#ifdef __linux__
353246896Sluigi#define sockaddr_dl    sockaddr_ll
354246896Sluigi#define sdl_family     sll_family
355246896Sluigi#define AF_LINK        AF_PACKET
356246896Sluigi#define LLADDR(s)      s->sll_addr;
357246896Sluigi#include <linux/if_tun.h>
358246896Sluigi#define TAP_CLONEDEV	"/dev/net/tun"
359246896Sluigi#endif /* __linux__ */
360246896Sluigi
361246896Sluigi#ifdef __FreeBSD__
362246896Sluigi#include <net/if_tun.h>
363246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
364246896Sluigi#endif /* __FreeBSD */
365246896Sluigi
366246896Sluigi#ifdef __APPLE__
367246896Sluigi// #warning TAP not supported on apple ?
368246896Sluigi#include <net/if_utun.h>
369246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
370246896Sluigi#endif /* __APPLE__ */
371246896Sluigi
372246896Sluigi
373227614Sluigi/*
374257529Sluigi * parse the vale configuration in conf and put it in nmr.
375261909Sluigi * Return the flag set if necessary.
376257529Sluigi * The configuration may consist of 0 to 4 numbers separated
377257906Shiren * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings.
378257529Sluigi * Missing numbers or zeroes stand for default values.
379257529Sluigi * As an additional convenience, if exactly one number
380257906Shiren * is specified, then this is assigned to both #tx-slots and #rx-slots.
381261909Sluigi * If there is no 4th number, then the 3rd is assigned to both #tx-rings
382257529Sluigi * and #rx-rings.
383257529Sluigi */
384261909Sluigiint
385261909Sluigiparse_nmr_config(const char* conf, struct nmreq *nmr)
386257529Sluigi{
387257529Sluigi	char *w, *tok;
388257529Sluigi	int i, v;
389257529Sluigi
390257529Sluigi	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
391257529Sluigi	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
392257529Sluigi	if (conf == NULL || ! *conf)
393261909Sluigi		return 0;
394257529Sluigi	w = strdup(conf);
395257529Sluigi	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
396257529Sluigi		v = atoi(tok);
397257529Sluigi		switch (i) {
398257529Sluigi		case 0:
399257529Sluigi			nmr->nr_tx_slots = nmr->nr_rx_slots = v;
400257529Sluigi			break;
401257529Sluigi		case 1:
402257529Sluigi			nmr->nr_rx_slots = v;
403257529Sluigi			break;
404257529Sluigi		case 2:
405257529Sluigi			nmr->nr_tx_rings = nmr->nr_rx_rings = v;
406257529Sluigi			break;
407257529Sluigi		case 3:
408257529Sluigi			nmr->nr_rx_rings = v;
409257529Sluigi			break;
410257529Sluigi		default:
411257529Sluigi			D("ignored config: %s", tok);
412257529Sluigi			break;
413257529Sluigi		}
414257529Sluigi	}
415257529Sluigi	D("txr %d txd %d rxr %d rxd %d",
416257529Sluigi			nmr->nr_tx_rings, nmr->nr_tx_slots,
417257529Sluigi			nmr->nr_rx_rings, nmr->nr_rx_slots);
418257529Sluigi	free(w);
419261909Sluigi	return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
420261909Sluigi                        nmr->nr_rx_rings || nmr->nr_rx_slots) ?
421261909Sluigi		NM_OPEN_RING_CFG : 0;
422257529Sluigi}
423257529Sluigi
424257529Sluigi
425257529Sluigi/*
426227614Sluigi * locate the src mac address for our interface, put it
427227614Sluigi * into the user-supplied buffer. return 0 if ok, -1 on error.
428227614Sluigi */
429227614Sluigistatic int
430227614Sluigisource_hwaddr(const char *ifname, char *buf)
431227614Sluigi{
432227614Sluigi	struct ifaddrs *ifaphead, *ifap;
433227614Sluigi	int l = sizeof(ifap->ifa_name);
434227614Sluigi
435227614Sluigi	if (getifaddrs(&ifaphead) != 0) {
436227614Sluigi		D("getifaddrs %s failed", ifname);
437227614Sluigi		return (-1);
438227614Sluigi	}
439227614Sluigi
440227614Sluigi	for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
441227614Sluigi		struct sockaddr_dl *sdl =
442227614Sluigi			(struct sockaddr_dl *)ifap->ifa_addr;
443227614Sluigi		uint8_t *mac;
444227614Sluigi
445227614Sluigi		if (!sdl || sdl->sdl_family != AF_LINK)
446227614Sluigi			continue;
447227614Sluigi		if (strncmp(ifap->ifa_name, ifname, l) != 0)
448227614Sluigi			continue;
449227614Sluigi		mac = (uint8_t *)LLADDR(sdl);
450227614Sluigi		sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
451227614Sluigi			mac[0], mac[1], mac[2],
452227614Sluigi			mac[3], mac[4], mac[5]);
453227614Sluigi		if (verbose)
454227614Sluigi			D("source hwaddr %s", buf);
455227614Sluigi		break;
456227614Sluigi	}
457227614Sluigi	freeifaddrs(ifaphead);
458227614Sluigi	return ifap ? 0 : 1;
459227614Sluigi}
460227614Sluigi
461227614Sluigi
462227614Sluigi/* set the thread affinity. */
463227614Sluigistatic int
464227614Sluigisetaffinity(pthread_t me, int i)
465227614Sluigi{
466227614Sluigi	cpuset_t cpumask;
467227614Sluigi
468227614Sluigi	if (i == -1)
469227614Sluigi		return 0;
470227614Sluigi
471227614Sluigi	/* Set thread affinity affinity.*/
472227614Sluigi	CPU_ZERO(&cpumask);
473227614Sluigi	CPU_SET(i, &cpumask);
474227614Sluigi
475227614Sluigi	if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
476260368Sluigi		D("Unable to set affinity: %s", strerror(errno));
477227614Sluigi		return 1;
478227614Sluigi	}
479227614Sluigi	return 0;
480227614Sluigi}
481227614Sluigi
482227614Sluigi/* Compute the checksum of the given ip header. */
483227614Sluigistatic uint16_t
484246896Sluigichecksum(const void *data, uint16_t len, uint32_t sum)
485227614Sluigi{
486227614Sluigi        const uint8_t *addr = data;
487246896Sluigi	uint32_t i;
488227614Sluigi
489246896Sluigi        /* Checksum all the pairs of bytes first... */
490246896Sluigi        for (i = 0; i < (len & ~1U); i += 2) {
491246896Sluigi                sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
492246896Sluigi                if (sum > 0xFFFF)
493246896Sluigi                        sum -= 0xFFFF;
494227614Sluigi        }
495246896Sluigi	/*
496246896Sluigi	 * If there's a single byte left over, checksum it, too.
497246896Sluigi	 * Network byte order is big-endian, so the remaining byte is
498246896Sluigi	 * the high byte.
499246896Sluigi	 */
500246896Sluigi	if (i < len) {
501246896Sluigi		sum += addr[i] << 8;
502246896Sluigi		if (sum > 0xFFFF)
503246896Sluigi			sum -= 0xFFFF;
504246896Sluigi	}
505246896Sluigi	return sum;
506246896Sluigi}
507227614Sluigi
508246896Sluigistatic u_int16_t
509246896Sluigiwrapsum(u_int32_t sum)
510246896Sluigi{
511246896Sluigi	sum = ~sum & 0xFFFF;
512246896Sluigi	return (htons(sum));
513227614Sluigi}
514227614Sluigi
515251426Sluigi/* Check the payload of the packet for errors (use it for debug).
516251426Sluigi * Look for consecutive ascii representations of the size of the packet.
517251426Sluigi */
518251426Sluigistatic void
519251426Sluigidump_payload(char *p, int len, struct netmap_ring *ring, int cur)
520251426Sluigi{
521251426Sluigi	char buf[128];
522251426Sluigi	int i, j, i0;
523251426Sluigi
524251426Sluigi	/* get the length in ASCII of the length of the packet. */
525261909Sluigi
526257529Sluigi	printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n",
527257529Sluigi		ring, cur, ring->slot[cur].buf_idx,
528257529Sluigi		ring->slot[cur].flags, len);
529251426Sluigi	/* hexdump routine */
530251426Sluigi	for (i = 0; i < len; ) {
531251426Sluigi		memset(buf, sizeof(buf), ' ');
532251426Sluigi		sprintf(buf, "%5d: ", i);
533251426Sluigi		i0 = i;
534251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
535251426Sluigi			sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
536251426Sluigi		i = i0;
537251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
538251426Sluigi			sprintf(buf+7+j + 48, "%c",
539251426Sluigi				isprint(p[i]) ? p[i] : '.');
540251426Sluigi		printf("%s\n", buf);
541251426Sluigi	}
542251426Sluigi}
543251426Sluigi
544227614Sluigi/*
545227614Sluigi * Fill a packet with some payload.
546246896Sluigi * We create a UDP packet so the payload starts at
547246896Sluigi *	14+20+8 = 42 bytes.
548227614Sluigi */
549246896Sluigi#ifdef __linux__
550246896Sluigi#define uh_sport source
551246896Sluigi#define uh_dport dest
552246896Sluigi#define uh_ulen len
553246896Sluigi#define uh_sum check
554246896Sluigi#endif /* linux */
555251426Sluigi
556257529Sluigi/*
557257529Sluigi * increment the addressed in the packet,
558257529Sluigi * starting from the least significant field.
559257529Sluigi *	DST_IP DST_PORT SRC_IP SRC_PORT
560257529Sluigi */
561227614Sluigistatic void
562257529Sluigiupdate_addresses(struct pkt *pkt, struct glob_arg *g)
563257529Sluigi{
564257529Sluigi	uint32_t a;
565257529Sluigi	uint16_t p;
566257529Sluigi	struct ip *ip = &pkt->ip;
567257529Sluigi	struct udphdr *udp = &pkt->udp;
568257529Sluigi
569260700Sluigi    do {
570257529Sluigi	p = ntohs(udp->uh_sport);
571257529Sluigi	if (p < g->src_ip.port1) { /* just inc, no wrap */
572257529Sluigi		udp->uh_sport = htons(p + 1);
573260700Sluigi		break;
574257529Sluigi	}
575257529Sluigi	udp->uh_sport = htons(g->src_ip.port0);
576257529Sluigi
577257529Sluigi	a = ntohl(ip->ip_src.s_addr);
578257529Sluigi	if (a < g->src_ip.end) { /* just inc, no wrap */
579257529Sluigi		ip->ip_src.s_addr = htonl(a + 1);
580260700Sluigi		break;
581257529Sluigi	}
582257529Sluigi	ip->ip_src.s_addr = htonl(g->src_ip.start);
583257529Sluigi
584257529Sluigi	udp->uh_sport = htons(g->src_ip.port0);
585257529Sluigi	p = ntohs(udp->uh_dport);
586257529Sluigi	if (p < g->dst_ip.port1) { /* just inc, no wrap */
587257529Sluigi		udp->uh_dport = htons(p + 1);
588260700Sluigi		break;
589257529Sluigi	}
590257529Sluigi	udp->uh_dport = htons(g->dst_ip.port0);
591257529Sluigi
592257529Sluigi	a = ntohl(ip->ip_dst.s_addr);
593257529Sluigi	if (a < g->dst_ip.end) { /* just inc, no wrap */
594257529Sluigi		ip->ip_dst.s_addr = htonl(a + 1);
595260700Sluigi		break;
596257529Sluigi	}
597257529Sluigi	ip->ip_dst.s_addr = htonl(g->dst_ip.start);
598260700Sluigi    } while (0);
599260700Sluigi    // update checksum
600257529Sluigi}
601257529Sluigi
602257529Sluigi/*
603257529Sluigi * initialize one packet and prepare for the next one.
604257529Sluigi * The copy could be done better instead of repeating it each time.
605257529Sluigi */
606257529Sluigistatic void
607227614Sluigiinitialize_packet(struct targ *targ)
608227614Sluigi{
609227614Sluigi	struct pkt *pkt = &targ->pkt;
610227614Sluigi	struct ether_header *eh;
611227614Sluigi	struct ip *ip;
612227614Sluigi	struct udphdr *udp;
613246896Sluigi	uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip);
614251426Sluigi	const char *payload = targ->g->options & OPT_INDIRECT ?
615257529Sluigi		indirect_payload : default_payload;
616260700Sluigi	int i, l0 = strlen(payload);
617227614Sluigi
618272962Sgnn	char errbuf[PCAP_ERRBUF_SIZE];
619272962Sgnn	pcap_t *file;
620272962Sgnn	struct pcap_pkthdr *header;
621272962Sgnn	const unsigned char *packet;
622272962Sgnn
623272962Sgnn	/* Read a packet from a PCAP file if asked. */
624272962Sgnn	if (targ->g->packet_file != NULL) {
625272962Sgnn		if ((file = pcap_open_offline(targ->g->packet_file,
626272962Sgnn			    errbuf)) == NULL)
627272962Sgnn			D("failed to open pcap file %s",
628272962Sgnn			    targ->g->packet_file);
629272962Sgnn		if (pcap_next_ex(file, &header, &packet) < 0)
630272962Sgnn			D("failed to read packet from %s",
631272962Sgnn			    targ->g->packet_file);
632272962Sgnn		if ((targ->frame = malloc(header->caplen)) == NULL)
633272962Sgnn			D("out of memory");
634272962Sgnn		bcopy(packet, (unsigned char *)targ->frame, header->caplen);
635272962Sgnn		targ->g->pkt_size = header->caplen;
636272962Sgnn		pcap_close(file);
637272962Sgnn		return;
638272962Sgnn	}
639272962Sgnn
640257529Sluigi	/* create a nice NUL-terminated string */
641260700Sluigi	for (i = 0; i < paylen; i += l0) {
642260700Sluigi		if (l0 > paylen - i)
643260700Sluigi			l0 = paylen - i; // last round
644260700Sluigi		bcopy(payload, pkt->body + i, l0);
645227614Sluigi	}
646227614Sluigi	pkt->body[i-1] = '\0';
647246896Sluigi	ip = &pkt->ip;
648227614Sluigi
649257529Sluigi	/* prepare the headers */
650227614Sluigi        ip->ip_v = IPVERSION;
651227614Sluigi        ip->ip_hl = 5;
652227614Sluigi        ip->ip_id = 0;
653227614Sluigi        ip->ip_tos = IPTOS_LOWDELAY;
654227614Sluigi	ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh));
655227614Sluigi        ip->ip_id = 0;
656227614Sluigi        ip->ip_off = htons(IP_DF); /* Don't fragment */
657227614Sluigi        ip->ip_ttl = IPDEFTTL;
658227614Sluigi	ip->ip_p = IPPROTO_UDP;
659257529Sluigi	ip->ip_dst.s_addr = htonl(targ->g->dst_ip.start);
660257529Sluigi	ip->ip_src.s_addr = htonl(targ->g->src_ip.start);
661246896Sluigi	ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0));
662227614Sluigi
663246896Sluigi
664246896Sluigi	udp = &pkt->udp;
665257529Sluigi        udp->uh_sport = htons(targ->g->src_ip.port0);
666257529Sluigi        udp->uh_dport = htons(targ->g->dst_ip.port0);
667246896Sluigi	udp->uh_ulen = htons(paylen);
668246896Sluigi	/* Magic: taken from sbin/dhclient/packet.c */
669246896Sluigi	udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp),
670246896Sluigi                    checksum(pkt->body,
671246896Sluigi                        paylen - sizeof(*udp),
672246896Sluigi                        checksum(&ip->ip_src, 2 * sizeof(ip->ip_src),
673246896Sluigi                            IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen)
674246896Sluigi                        )
675246896Sluigi                    )
676246896Sluigi                ));
677246896Sluigi
678227614Sluigi	eh = &pkt->eh;
679246896Sluigi	bcopy(&targ->g->src_mac.start, eh->ether_shost, 6);
680246896Sluigi	bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6);
681227614Sluigi	eh->ether_type = htons(ETHERTYPE_IP);
682260368Sluigi
683260368Sluigi	bzero(&pkt->vh, sizeof(pkt->vh));
684270063Sluigi#ifdef TRASH_VHOST_HDR
685270063Sluigi	/* set bogus content */
686270063Sluigi	pkt->vh.fields[0] = 0xff;
687270063Sluigi	pkt->vh.fields[1] = 0xff;
688270063Sluigi	pkt->vh.fields[2] = 0xff;
689270063Sluigi	pkt->vh.fields[3] = 0xff;
690270063Sluigi	pkt->vh.fields[4] = 0xff;
691270063Sluigi	pkt->vh.fields[5] = 0xff;
692270063Sluigi#endif /* TRASH_VHOST_HDR */
693251426Sluigi	// dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0);
694227614Sluigi}
695227614Sluigi
696270063Sluigistatic void
697270063Sluigiset_vnet_hdr_len(struct targ *t)
698270063Sluigi{
699270063Sluigi	int err, l = t->g->virt_header;
700270063Sluigi	struct nmreq req;
701227614Sluigi
702270063Sluigi	if (l == 0)
703270063Sluigi		return;
704227614Sluigi
705270063Sluigi	memset(&req, 0, sizeof(req));
706270063Sluigi	bcopy(t->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
707270063Sluigi	req.nr_version = NETMAP_API;
708270063Sluigi	req.nr_cmd = NETMAP_BDG_VNET_HDR;
709270063Sluigi	req.nr_arg1 = l;
710270063Sluigi	err = ioctl(t->fd, NIOCREGIF, &req);
711270063Sluigi	if (err) {
712270063Sluigi		D("Unable to set vnet header length %d", l);
713270063Sluigi	}
714270063Sluigi}
715270063Sluigi
716270063Sluigi
717227614Sluigi/*
718227614Sluigi * create and enqueue a batch of packets on a ring.
719227614Sluigi * On the last one set NS_REPORT to tell the driver to generate
720227614Sluigi * an interrupt when done.
721227614Sluigi */
722227614Sluigistatic int
723260368Sluigisend_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
724260368Sluigi		int size, struct glob_arg *g, u_int count, int options,
725260368Sluigi		u_int nfrags)
726227614Sluigi{
727260368Sluigi	u_int n, sent, cur = ring->cur;
728260700Sluigi	u_int fcnt;
729227614Sluigi
730260368Sluigi	n = nm_ring_space(ring);
731260368Sluigi	if (n < count)
732260368Sluigi		count = n;
733257529Sluigi	if (count < nfrags) {
734257529Sluigi		D("truncating packet, no room for frags %d %d",
735260368Sluigi				count, nfrags);
736257529Sluigi	}
737234956Sluigi#if 0
738234956Sluigi	if (options & (OPT_COPY | OPT_PREFETCH) ) {
739234956Sluigi		for (sent = 0; sent < count; sent++) {
740234956Sluigi			struct netmap_slot *slot = &ring->slot[cur];
741234956Sluigi			char *p = NETMAP_BUF(ring, slot->buf_idx);
742234956Sluigi
743260700Sluigi			__builtin_prefetch(p);
744260368Sluigi			cur = nm_ring_next(ring, cur);
745234956Sluigi		}
746234956Sluigi		cur = ring->cur;
747234956Sluigi	}
748234956Sluigi#endif
749257529Sluigi	for (fcnt = nfrags, sent = 0; sent < count; sent++) {
750227614Sluigi		struct netmap_slot *slot = &ring->slot[cur];
751227614Sluigi		char *p = NETMAP_BUF(ring, slot->buf_idx);
752227614Sluigi
753251426Sluigi		slot->flags = 0;
754251426Sluigi		if (options & OPT_INDIRECT) {
755251426Sluigi			slot->flags |= NS_INDIRECT;
756260368Sluigi			slot->ptr = (uint64_t)frame;
757257529Sluigi		} else if (options & OPT_COPY) {
758261909Sluigi			nm_pkt_copy(frame, p, size);
759260700Sluigi			if (fcnt == nfrags)
760257529Sluigi				update_addresses(pkt, g);
761257529Sluigi		} else if (options & OPT_MEMCPY) {
762260368Sluigi			memcpy(p, frame, size);
763260700Sluigi			if (fcnt == nfrags)
764257529Sluigi				update_addresses(pkt, g);
765257529Sluigi		} else if (options & OPT_PREFETCH) {
766260700Sluigi			__builtin_prefetch(p);
767257529Sluigi		}
768257529Sluigi		if (options & OPT_DUMP)
769257529Sluigi			dump_payload(p, size, ring, cur);
770227614Sluigi		slot->len = size;
771257529Sluigi		if (--fcnt > 0)
772257529Sluigi			slot->flags |= NS_MOREFRAG;
773257529Sluigi		else
774257529Sluigi			fcnt = nfrags;
775257529Sluigi		if (sent == count - 1) {
776257529Sluigi			slot->flags &= ~NS_MOREFRAG;
777227614Sluigi			slot->flags |= NS_REPORT;
778257529Sluigi		}
779260368Sluigi		cur = nm_ring_next(ring, cur);
780227614Sluigi	}
781260368Sluigi	ring->head = ring->cur = cur;
782227614Sluigi
783227614Sluigi	return (sent);
784227614Sluigi}
785227614Sluigi
786246896Sluigi/*
787246896Sluigi * Send a packet, and wait for a response.
788246896Sluigi * The payload (after UDP header, ofs 42) has a 4-byte sequence
789246896Sluigi * followed by a struct timeval (or bintime?)
790246896Sluigi */
791246896Sluigi#define	PAY_OFS	42	/* where in the pkt... */
792246896Sluigi
793227614Sluigistatic void *
794246896Sluigipinger_body(void *data)
795246896Sluigi{
796246896Sluigi	struct targ *targ = (struct targ *) data;
797261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
798261909Sluigi	struct netmap_if *nifp = targ->nmd->nifp;
799246896Sluigi	int i, rx = 0, n = targ->g->npackets;
800260368Sluigi	void *frame;
801260368Sluigi	int size;
802261909Sluigi	uint32_t sent = 0;
803261909Sluigi	struct timespec ts, now, last_print;
804261909Sluigi	uint32_t count = 0, min = 1000000000, av = 0;
805246896Sluigi
806260368Sluigi	frame = &targ->pkt;
807260368Sluigi	frame += sizeof(targ->pkt.vh) - targ->g->virt_header;
808260368Sluigi	size = targ->g->pkt_size + targ->g->virt_header;
809260368Sluigi
810246896Sluigi	if (targ->g->nthreads > 1) {
811246896Sluigi		D("can only ping with 1 thread");
812246896Sluigi		return NULL;
813246896Sluigi	}
814246896Sluigi
815246896Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &last_print);
816260368Sluigi	now = last_print;
817246896Sluigi	while (n == 0 || (int)sent < n) {
818246896Sluigi		struct netmap_ring *ring = NETMAP_TXRING(nifp, 0);
819246896Sluigi		struct netmap_slot *slot;
820246896Sluigi		char *p;
821260368Sluigi	    for (i = 0; i < 1; i++) { /* XXX why the loop for 1 pkt ? */
822246896Sluigi		slot = &ring->slot[ring->cur];
823260368Sluigi		slot->len = size;
824246896Sluigi		p = NETMAP_BUF(ring, slot->buf_idx);
825246896Sluigi
826260368Sluigi		if (nm_ring_empty(ring)) {
827246896Sluigi			D("-- ouch, cannot send");
828246896Sluigi		} else {
829270063Sluigi			struct tstamp *tp;
830261909Sluigi			nm_pkt_copy(frame, p, size);
831246896Sluigi			clock_gettime(CLOCK_REALTIME_PRECISE, &ts);
832246896Sluigi			bcopy(&sent, p+42, sizeof(sent));
833270063Sluigi			tp = (struct tstamp *)(p+46);
834270063Sluigi			tp->sec = (uint32_t)ts.tv_sec;
835270063Sluigi			tp->nsec = (uint32_t)ts.tv_nsec;
836246896Sluigi			sent++;
837260368Sluigi			ring->head = ring->cur = nm_ring_next(ring, ring->cur);
838246896Sluigi		}
839246896Sluigi	    }
840246896Sluigi		/* should use a parameter to decide how often to send */
841261909Sluigi		if (poll(&pfd, 1, 3000) <= 0) {
842260368Sluigi			D("poll error/timeout on queue %d: %s", targ->me,
843260368Sluigi				strerror(errno));
844246896Sluigi			continue;
845246896Sluigi		}
846246896Sluigi		/* see what we got back */
847261909Sluigi		for (i = targ->nmd->first_tx_ring;
848261909Sluigi			i <= targ->nmd->last_tx_ring; i++) {
849246896Sluigi			ring = NETMAP_RXRING(nifp, i);
850260368Sluigi			while (!nm_ring_empty(ring)) {
851246896Sluigi				uint32_t seq;
852270063Sluigi				struct tstamp *tp;
853246896Sluigi				slot = &ring->slot[ring->cur];
854246896Sluigi				p = NETMAP_BUF(ring, slot->buf_idx);
855246896Sluigi
856246896Sluigi				clock_gettime(CLOCK_REALTIME_PRECISE, &now);
857246896Sluigi				bcopy(p+42, &seq, sizeof(seq));
858270063Sluigi				tp = (struct tstamp *)(p+46);
859270063Sluigi				ts.tv_sec = (time_t)tp->sec;
860270063Sluigi				ts.tv_nsec = (long)tp->nsec;
861246896Sluigi				ts.tv_sec = now.tv_sec - ts.tv_sec;
862246896Sluigi				ts.tv_nsec = now.tv_nsec - ts.tv_nsec;
863246896Sluigi				if (ts.tv_nsec < 0) {
864246896Sluigi					ts.tv_nsec += 1000000000;
865246896Sluigi					ts.tv_sec--;
866246896Sluigi				}
867246896Sluigi				if (1) D("seq %d/%d delta %d.%09d", seq, sent,
868246896Sluigi					(int)ts.tv_sec, (int)ts.tv_nsec);
869246896Sluigi				if (ts.tv_nsec < (int)min)
870246896Sluigi					min = ts.tv_nsec;
871246896Sluigi				count ++;
872246896Sluigi				av += ts.tv_nsec;
873260368Sluigi				ring->head = ring->cur = nm_ring_next(ring, ring->cur);
874246896Sluigi				rx++;
875246896Sluigi			}
876246896Sluigi		}
877246896Sluigi		//D("tx %d rx %d", sent, rx);
878246896Sluigi		//usleep(100000);
879246896Sluigi		ts.tv_sec = now.tv_sec - last_print.tv_sec;
880246896Sluigi		ts.tv_nsec = now.tv_nsec - last_print.tv_nsec;
881246896Sluigi		if (ts.tv_nsec < 0) {
882246896Sluigi			ts.tv_nsec += 1000000000;
883246896Sluigi			ts.tv_sec--;
884246896Sluigi		}
885246896Sluigi		if (ts.tv_sec >= 1) {
886246896Sluigi			D("count %d min %d av %d",
887246896Sluigi				count, min, av/count);
888246896Sluigi			count = 0;
889246896Sluigi			av = 0;
890246896Sluigi			min = 100000000;
891246896Sluigi			last_print = now;
892246896Sluigi		}
893246896Sluigi	}
894246896Sluigi	return NULL;
895246896Sluigi}
896246896Sluigi
897246896Sluigi
898246896Sluigi/*
899246896Sluigi * reply to ping requests
900246896Sluigi */
901246896Sluigistatic void *
902246896Sluigiponger_body(void *data)
903246896Sluigi{
904246896Sluigi	struct targ *targ = (struct targ *) data;
905261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
906261909Sluigi	struct netmap_if *nifp = targ->nmd->nifp;
907246896Sluigi	struct netmap_ring *txring, *rxring;
908246896Sluigi	int i, rx = 0, sent = 0, n = targ->g->npackets;
909246896Sluigi
910246896Sluigi	if (targ->g->nthreads > 1) {
911246896Sluigi		D("can only reply ping with 1 thread");
912246896Sluigi		return NULL;
913246896Sluigi	}
914246896Sluigi	D("understood ponger %d but don't know how to do it", n);
915246896Sluigi	while (n == 0 || sent < n) {
916246896Sluigi		uint32_t txcur, txavail;
917246896Sluigi//#define BUSYWAIT
918246896Sluigi#ifdef BUSYWAIT
919261909Sluigi		ioctl(pfd.fd, NIOCRXSYNC, NULL);
920246896Sluigi#else
921261909Sluigi		if (poll(&pfd, 1, 1000) <= 0) {
922260368Sluigi			D("poll error/timeout on queue %d: %s", targ->me,
923260368Sluigi				strerror(errno));
924246896Sluigi			continue;
925246896Sluigi		}
926246896Sluigi#endif
927246896Sluigi		txring = NETMAP_TXRING(nifp, 0);
928246896Sluigi		txcur = txring->cur;
929260368Sluigi		txavail = nm_ring_space(txring);
930246896Sluigi		/* see what we got back */
931261909Sluigi		for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) {
932246896Sluigi			rxring = NETMAP_RXRING(nifp, i);
933260368Sluigi			while (!nm_ring_empty(rxring)) {
934246896Sluigi				uint16_t *spkt, *dpkt;
935246896Sluigi				uint32_t cur = rxring->cur;
936246896Sluigi				struct netmap_slot *slot = &rxring->slot[cur];
937246896Sluigi				char *src, *dst;
938246896Sluigi				src = NETMAP_BUF(rxring, slot->buf_idx);
939246896Sluigi				//D("got pkt %p of size %d", src, slot->len);
940260368Sluigi				rxring->head = rxring->cur = nm_ring_next(rxring, cur);
941246896Sluigi				rx++;
942246896Sluigi				if (txavail == 0)
943246896Sluigi					continue;
944246896Sluigi				dst = NETMAP_BUF(txring,
945246896Sluigi				    txring->slot[txcur].buf_idx);
946246896Sluigi				/* copy... */
947246896Sluigi				dpkt = (uint16_t *)dst;
948246896Sluigi				spkt = (uint16_t *)src;
949261909Sluigi				nm_pkt_copy(src, dst, slot->len);
950246896Sluigi				dpkt[0] = spkt[3];
951246896Sluigi				dpkt[1] = spkt[4];
952246896Sluigi				dpkt[2] = spkt[5];
953246896Sluigi				dpkt[3] = spkt[0];
954246896Sluigi				dpkt[4] = spkt[1];
955246896Sluigi				dpkt[5] = spkt[2];
956246896Sluigi				txring->slot[txcur].len = slot->len;
957246896Sluigi				/* XXX swap src dst mac */
958260368Sluigi				txcur = nm_ring_next(txring, txcur);
959246896Sluigi				txavail--;
960246896Sluigi				sent++;
961246896Sluigi			}
962246896Sluigi		}
963260368Sluigi		txring->head = txring->cur = txcur;
964246896Sluigi		targ->count = sent;
965246896Sluigi#ifdef BUSYWAIT
966261909Sluigi		ioctl(pfd.fd, NIOCTXSYNC, NULL);
967246896Sluigi#endif
968246896Sluigi		//D("tx %d rx %d", sent, rx);
969246896Sluigi	}
970246896Sluigi	return NULL;
971246896Sluigi}
972246896Sluigi
973251132Sluigistatic __inline int
974251132Sluigitimespec_ge(const struct timespec *a, const struct timespec *b)
975251132Sluigi{
976246896Sluigi
977251132Sluigi	if (a->tv_sec > b->tv_sec)
978251132Sluigi		return (1);
979251132Sluigi	if (a->tv_sec < b->tv_sec)
980251132Sluigi		return (0);
981251132Sluigi	if (a->tv_nsec >= b->tv_nsec)
982251132Sluigi		return (1);
983251132Sluigi	return (0);
984251132Sluigi}
985251132Sluigi
986251132Sluigistatic __inline struct timespec
987251132Sluigitimeval2spec(const struct timeval *a)
988251132Sluigi{
989251132Sluigi	struct timespec ts = {
990251132Sluigi		.tv_sec = a->tv_sec,
991251132Sluigi		.tv_nsec = a->tv_usec * 1000
992251132Sluigi	};
993251132Sluigi	return ts;
994251132Sluigi}
995251132Sluigi
996251132Sluigistatic __inline struct timeval
997251132Sluigitimespec2val(const struct timespec *a)
998251132Sluigi{
999251132Sluigi	struct timeval tv = {
1000251132Sluigi		.tv_sec = a->tv_sec,
1001251132Sluigi		.tv_usec = a->tv_nsec / 1000
1002251132Sluigi	};
1003251132Sluigi	return tv;
1004251132Sluigi}
1005251132Sluigi
1006251132Sluigi
1007260368Sluigistatic __inline struct timespec
1008260368Sluigitimespec_add(struct timespec a, struct timespec b)
1009251132Sluigi{
1010260368Sluigi	struct timespec ret = { a.tv_sec + b.tv_sec, a.tv_nsec + b.tv_nsec };
1011260368Sluigi	if (ret.tv_nsec >= 1000000000) {
1012260368Sluigi		ret.tv_sec++;
1013260368Sluigi		ret.tv_nsec -= 1000000000;
1014260368Sluigi	}
1015260368Sluigi	return ret;
1016260368Sluigi}
1017251132Sluigi
1018260368Sluigistatic __inline struct timespec
1019260368Sluigitimespec_sub(struct timespec a, struct timespec b)
1020260368Sluigi{
1021260368Sluigi	struct timespec ret = { a.tv_sec - b.tv_sec, a.tv_nsec - b.tv_nsec };
1022260368Sluigi	if (ret.tv_nsec < 0) {
1023260368Sluigi		ret.tv_sec--;
1024260368Sluigi		ret.tv_nsec += 1000000000;
1025251132Sluigi	}
1026260368Sluigi	return ret;
1027251132Sluigi}
1028251132Sluigi
1029260368Sluigi
1030260368Sluigi/*
1031260368Sluigi * wait until ts, either busy or sleeping if more than 1ms.
1032260368Sluigi * Return wakeup time.
1033260368Sluigi */
1034260368Sluigistatic struct timespec
1035260368Sluigiwait_time(struct timespec ts)
1036251132Sluigi{
1037260368Sluigi	for (;;) {
1038260368Sluigi		struct timespec w, cur;
1039260368Sluigi		clock_gettime(CLOCK_REALTIME_PRECISE, &cur);
1040260368Sluigi		w = timespec_sub(ts, cur);
1041260368Sluigi		if (w.tv_sec < 0)
1042260368Sluigi			return cur;
1043260368Sluigi		else if (w.tv_sec > 0 || w.tv_nsec > 1000000)
1044260368Sluigi			poll(NULL, 0, 1);
1045251132Sluigi	}
1046251132Sluigi}
1047251132Sluigi
1048246896Sluigistatic void *
1049227614Sluigisender_body(void *data)
1050227614Sluigi{
1051227614Sluigi	struct targ *targ = (struct targ *) data;
1052261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT };
1053270063Sluigi	struct netmap_if *nifp;
1054227614Sluigi	struct netmap_ring *txring;
1055261909Sluigi	int i, n = targ->g->npackets / targ->g->nthreads;
1056261909Sluigi	int64_t sent = 0;
1057234956Sluigi	int options = targ->g->options | OPT_COPY;
1058260368Sluigi	struct timespec nexttime = { 0, 0}; // XXX silence compiler
1059251132Sluigi	int rate_limit = targ->g->tx_rate;
1060260368Sluigi	struct pkt *pkt = &targ->pkt;
1061260368Sluigi	void *frame;
1062260368Sluigi	int size;
1063251426Sluigi
1064272962Sgnn	if (targ->frame == NULL) {
1065272962Sgnn		frame = pkt;
1066272962Sgnn		frame += sizeof(pkt->vh) - targ->g->virt_header;
1067272962Sgnn		size = targ->g->pkt_size + targ->g->virt_header;
1068272962Sgnn	} else {
1069272962Sgnn		frame = targ->frame;
1070272962Sgnn		size = targ->g->pkt_size;
1071272962Sgnn	}
1072272962Sgnn
1073270063Sluigi	D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd);
1074227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
1075227614Sluigi		goto quit;
1076227614Sluigi
1077227614Sluigi	/* main loop.*/
1078251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1079251132Sluigi	if (rate_limit) {
1080260368Sluigi		targ->tic = timespec_add(targ->tic, (struct timespec){2,0});
1081251132Sluigi		targ->tic.tv_nsec = 0;
1082260368Sluigi		wait_time(targ->tic);
1083251132Sluigi		nexttime = targ->tic;
1084251132Sluigi	}
1085261909Sluigi        if (targ->g->dev_type == DEV_TAP) {
1086260700Sluigi	    D("writing to file desc %d", targ->g->main_fd);
1087246896Sluigi
1088246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
1089260700Sluigi		if (write(targ->g->main_fd, frame, size) != -1)
1090234956Sluigi			sent++;
1091257529Sluigi		update_addresses(pkt, targ->g);
1092234956Sluigi		if (i > 10000) {
1093234956Sluigi			targ->count = sent;
1094234956Sluigi			i = 0;
1095234956Sluigi		}
1096246896Sluigi	    }
1097260700Sluigi#ifndef NO_PCAP
1098260700Sluigi    } else if (targ->g->dev_type == DEV_PCAP) {
1099260700Sluigi	    pcap_t *p = targ->g->p;
1100246896Sluigi
1101246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
1102260700Sluigi		if (pcap_inject(p, frame, size) != -1)
1103246896Sluigi			sent++;
1104257529Sluigi		update_addresses(pkt, targ->g);
1105246896Sluigi		if (i > 10000) {
1106246896Sluigi			targ->count = sent;
1107246896Sluigi			i = 0;
1108246896Sluigi		}
1109246896Sluigi	    }
1110260700Sluigi#endif /* NO_PCAP */
1111227614Sluigi    } else {
1112251132Sluigi	int tosend = 0;
1113257529Sluigi	int frags = targ->g->frags;
1114257529Sluigi
1115270063Sluigi        nifp = targ->nmd->nifp;
1116246896Sluigi	while (!targ->cancel && (n == 0 || sent < n)) {
1117227614Sluigi
1118251132Sluigi		if (rate_limit && tosend <= 0) {
1119251132Sluigi			tosend = targ->g->burst;
1120260368Sluigi			nexttime = timespec_add(nexttime, targ->g->tx_period);
1121260368Sluigi			wait_time(nexttime);
1122251132Sluigi		}
1123251132Sluigi
1124227614Sluigi		/*
1125227614Sluigi		 * wait for available room in the send queue(s)
1126227614Sluigi		 */
1127261909Sluigi		if (poll(&pfd, 1, 2000) <= 0) {
1128238165Semaste			if (targ->cancel)
1129238165Semaste				break;
1130260368Sluigi			D("poll error/timeout on queue %d: %s", targ->me,
1131260368Sluigi				strerror(errno));
1132261909Sluigi			// goto quit;
1133227614Sluigi		}
1134261909Sluigi		if (pfd.revents & POLLERR) {
1135260368Sluigi			D("poll error");
1136260368Sluigi			goto quit;
1137260368Sluigi		}
1138227614Sluigi		/*
1139227614Sluigi		 * scan our queues and send on those with room
1140227614Sluigi		 */
1141246896Sluigi		if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) {
1142246896Sluigi			D("drop copy");
1143234956Sluigi			options &= ~OPT_COPY;
1144246896Sluigi		}
1145261909Sluigi		for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
1146251132Sluigi			int m, limit = rate_limit ?  tosend : targ->g->burst;
1147246896Sluigi			if (n > 0 && n - sent < limit)
1148246896Sluigi				limit = n - sent;
1149227614Sluigi			txring = NETMAP_TXRING(nifp, i);
1150260368Sluigi			if (nm_ring_empty(txring))
1151227614Sluigi				continue;
1152257529Sluigi			if (frags > 1)
1153257529Sluigi				limit = ((limit + frags - 1) / frags) * frags;
1154261909Sluigi
1155260368Sluigi			m = send_packets(txring, pkt, frame, size, targ->g,
1156257529Sluigi					 limit, options, frags);
1157261909Sluigi			ND("limit %d tail %d frags %d m %d",
1158260700Sluigi				limit, txring->tail, frags, m);
1159227614Sluigi			sent += m;
1160227614Sluigi			targ->count = sent;
1161257529Sluigi			if (rate_limit) {
1162257529Sluigi				tosend -= m;
1163257529Sluigi				if (tosend <= 0)
1164257529Sluigi					break;
1165257529Sluigi			}
1166227614Sluigi		}
1167227614Sluigi	}
1168234956Sluigi	/* flush any remaining packets */
1169270063Sluigi	D("flush tail %d head %d on thread %p",
1170270063Sluigi		txring->tail, txring->head,
1171270063Sluigi		pthread_self());
1172261909Sluigi	ioctl(pfd.fd, NIOCTXSYNC, NULL);
1173227614Sluigi
1174227614Sluigi	/* final part: wait all the TX queues to be empty. */
1175261909Sluigi	for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
1176227614Sluigi		txring = NETMAP_TXRING(nifp, i);
1177260368Sluigi		while (nm_tx_pending(txring)) {
1178270063Sluigi			RD(5, "pending tx tail %d head %d on ring %d",
1179270063Sluigi				txring->tail, txring->head, i);
1180261909Sluigi			ioctl(pfd.fd, NIOCTXSYNC, NULL);
1181227614Sluigi			usleep(1); /* wait 1 tick */
1182227614Sluigi		}
1183227614Sluigi	}
1184260700Sluigi    } /* end DEV_NETMAP */
1185227614Sluigi
1186251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1187227614Sluigi	targ->completed = 1;
1188227614Sluigi	targ->count = sent;
1189227614Sluigi
1190227614Sluigiquit:
1191227614Sluigi	/* reset the ``used`` flag. */
1192227614Sluigi	targ->used = 0;
1193227614Sluigi
1194227614Sluigi	return (NULL);
1195227614Sluigi}
1196227614Sluigi
1197227614Sluigi
1198260700Sluigi#ifndef NO_PCAP
1199227614Sluigistatic void
1200246896Sluigireceive_pcap(u_char *user, const struct pcap_pkthdr * h,
1201246896Sluigi	const u_char * bytes)
1202227614Sluigi{
1203227614Sluigi	int *count = (int *)user;
1204246896Sluigi	(void)h;	/* UNUSED */
1205246896Sluigi	(void)bytes;	/* UNUSED */
1206227614Sluigi	(*count)++;
1207227614Sluigi}
1208260700Sluigi#endif /* !NO_PCAP */
1209227614Sluigi
1210227614Sluigistatic int
1211251426Sluigireceive_packets(struct netmap_ring *ring, u_int limit, int dump)
1212227614Sluigi{
1213260368Sluigi	u_int cur, rx, n;
1214227614Sluigi
1215227614Sluigi	cur = ring->cur;
1216260368Sluigi	n = nm_ring_space(ring);
1217260368Sluigi	if (n < limit)
1218260368Sluigi		limit = n;
1219227614Sluigi	for (rx = 0; rx < limit; rx++) {
1220227614Sluigi		struct netmap_slot *slot = &ring->slot[cur];
1221227614Sluigi		char *p = NETMAP_BUF(ring, slot->buf_idx);
1222227614Sluigi
1223251426Sluigi		if (dump)
1224251426Sluigi			dump_payload(p, slot->len, ring, cur);
1225227614Sluigi
1226260368Sluigi		cur = nm_ring_next(ring, cur);
1227227614Sluigi	}
1228260368Sluigi	ring->head = ring->cur = cur;
1229227614Sluigi
1230227614Sluigi	return (rx);
1231227614Sluigi}
1232227614Sluigi
1233227614Sluigistatic void *
1234227614Sluigireceiver_body(void *data)
1235227614Sluigi{
1236227614Sluigi	struct targ *targ = (struct targ *) data;
1237261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
1238270063Sluigi	struct netmap_if *nifp;
1239227614Sluigi	struct netmap_ring *rxring;
1240246896Sluigi	int i;
1241246896Sluigi	uint64_t received = 0;
1242227614Sluigi
1243227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
1244227614Sluigi		goto quit;
1245227614Sluigi
1246270063Sluigi	D("reading from %s fd %d main_fd %d",
1247270063Sluigi		targ->g->ifname, targ->fd, targ->g->main_fd);
1248227614Sluigi	/* unbounded wait for the first packet. */
1249270063Sluigi	for (;!targ->cancel;) {
1250261909Sluigi		i = poll(&pfd, 1, 1000);
1251261909Sluigi		if (i > 0 && !(pfd.revents & POLLERR))
1252227614Sluigi			break;
1253261909Sluigi		RD(1, "waiting for initial packets, poll returns %d %d",
1254261909Sluigi			i, pfd.revents);
1255227614Sluigi	}
1256227614Sluigi	/* main loop, exit after 1s silence */
1257251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1258260700Sluigi    if (targ->g->dev_type == DEV_TAP) {
1259246896Sluigi	while (!targ->cancel) {
1260270063Sluigi		char buf[MAX_BODYSIZE];
1261246896Sluigi		/* XXX should we poll ? */
1262246896Sluigi		if (read(targ->g->main_fd, buf, sizeof(buf)) > 0)
1263246896Sluigi			targ->count++;
1264246896Sluigi	}
1265260700Sluigi#ifndef NO_PCAP
1266260700Sluigi    } else if (targ->g->dev_type == DEV_PCAP) {
1267260700Sluigi	while (!targ->cancel) {
1268260700Sluigi		/* XXX should we poll ? */
1269270063Sluigi		pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap,
1270270063Sluigi			(u_char *)&targ->count);
1271260700Sluigi	}
1272260700Sluigi#endif /* !NO_PCAP */
1273227614Sluigi    } else {
1274251426Sluigi	int dump = targ->g->options & OPT_DUMP;
1275270063Sluigi
1276270063Sluigi        nifp = targ->nmd->nifp;
1277238165Semaste	while (!targ->cancel) {
1278227614Sluigi		/* Once we started to receive packets, wait at most 1 seconds
1279227614Sluigi		   before quitting. */
1280261909Sluigi		if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) {
1281251132Sluigi			clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1282228975Suqs			targ->toc.tv_sec -= 1; /* Subtract timeout time. */
1283261909Sluigi			goto out;
1284227614Sluigi		}
1285227614Sluigi
1286261909Sluigi		if (pfd.revents & POLLERR) {
1287260368Sluigi			D("poll err");
1288260368Sluigi			goto quit;
1289260368Sluigi		}
1290260368Sluigi
1291261909Sluigi		for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) {
1292227614Sluigi			int m;
1293227614Sluigi
1294227614Sluigi			rxring = NETMAP_RXRING(nifp, i);
1295260368Sluigi			if (nm_ring_empty(rxring))
1296227614Sluigi				continue;
1297227614Sluigi
1298251426Sluigi			m = receive_packets(rxring, targ->g->burst, dump);
1299227614Sluigi			received += m;
1300227614Sluigi		}
1301246896Sluigi		targ->count = received;
1302227614Sluigi	}
1303227614Sluigi    }
1304227614Sluigi
1305261909Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1306261909Sluigi
1307261909Sluigiout:
1308227614Sluigi	targ->completed = 1;
1309227614Sluigi	targ->count = received;
1310227614Sluigi
1311227614Sluigiquit:
1312227614Sluigi	/* reset the ``used`` flag. */
1313227614Sluigi	targ->used = 0;
1314227614Sluigi
1315227614Sluigi	return (NULL);
1316227614Sluigi}
1317227614Sluigi
1318246896Sluigi/* very crude code to print a number in normalized form.
1319246896Sluigi * Caller has to make sure that the buffer is large enough.
1320246896Sluigi */
1321246896Sluigistatic const char *
1322246896Sluiginorm(char *buf, double val)
1323238170Semaste{
1324261909Sluigi	char *units[] = { "", "K", "M", "G", "T" };
1325246896Sluigi	u_int i;
1326238170Semaste
1327261909Sluigi	for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++)
1328238170Semaste		val /= 1000;
1329246896Sluigi	sprintf(buf, "%.2f %s", val, units[i]);
1330246896Sluigi	return buf;
1331238170Semaste}
1332238170Semaste
1333227614Sluigistatic void
1334227614Sluigitx_output(uint64_t sent, int size, double delta)
1335227614Sluigi{
1336246896Sluigi	double bw, raw_bw, pps;
1337246896Sluigi	char b1[40], b2[80], b3[80];
1338227614Sluigi
1339261909Sluigi	printf("Sent %llu packets, %d bytes each, in %.2f seconds.\n",
1340261909Sluigi	       (unsigned long long)sent, size, delta);
1341246896Sluigi	if (delta == 0)
1342246896Sluigi		delta = 1e-6;
1343246896Sluigi	if (size < 60)		/* correct for min packet size */
1344246896Sluigi		size = 60;
1345246896Sluigi	pps = sent / delta;
1346246896Sluigi	bw = (8.0 * size * sent) / delta;
1347246896Sluigi	/* raw packets have4 bytes crc + 20 bytes framing */
1348246896Sluigi	raw_bw = (8.0 * (size + 24) * sent) / delta;
1349238170Semaste
1350246896Sluigi	printf("Speed: %spps Bandwidth: %sbps (raw %sbps)\n",
1351246896Sluigi		norm(b1, pps), norm(b2, bw), norm(b3, raw_bw) );
1352227614Sluigi}
1353227614Sluigi
1354227614Sluigi
1355227614Sluigistatic void
1356227614Sluigirx_output(uint64_t received, double delta)
1357227614Sluigi{
1358246896Sluigi	double pps;
1359246896Sluigi	char b1[40];
1360227614Sluigi
1361261909Sluigi	printf("Received %llu packets, in %.2f seconds.\n",
1362261909Sluigi		(unsigned long long) received, delta);
1363227614Sluigi
1364246896Sluigi	if (delta == 0)
1365246896Sluigi		delta = 1e-6;
1366246896Sluigi	pps = received / delta;
1367246896Sluigi	printf("Speed: %spps\n", norm(b1, pps));
1368227614Sluigi}
1369227614Sluigi
1370227614Sluigistatic void
1371227614Sluigiusage(void)
1372227614Sluigi{
1373227614Sluigi	const char *cmd = "pkt-gen";
1374227614Sluigi	fprintf(stderr,
1375227614Sluigi		"Usage:\n"
1376227614Sluigi		"%s arguments\n"
1377227614Sluigi		"\t-i interface		interface name\n"
1378246896Sluigi		"\t-f function		tx rx ping pong\n"
1379246896Sluigi		"\t-n count		number of iterations (can be 0)\n"
1380246896Sluigi		"\t-t pkts_to_send		also forces tx mode\n"
1381246896Sluigi		"\t-r pkts_to_receive	also forces rx mode\n"
1382257529Sluigi		"\t-l pkt_size		in bytes excluding CRC\n"
1383257529Sluigi		"\t-d dst_ip[:port[-dst_ip:port]]   single or range\n"
1384257529Sluigi		"\t-s src_ip[:port[-src_ip:port]]   single or range\n"
1385257529Sluigi		"\t-D dst-mac\n"
1386257529Sluigi		"\t-S src-mac\n"
1387246896Sluigi		"\t-a cpu_id		use setaffinity\n"
1388227614Sluigi		"\t-b burst size		testing, mostly\n"
1389227614Sluigi		"\t-c cores		cores to use\n"
1390227614Sluigi		"\t-p threads		processes/threads to use\n"
1391227614Sluigi		"\t-T report_ms		milliseconds between reports\n"
1392257529Sluigi		"\t-P			use libpcap instead of netmap\n"
1393227614Sluigi		"\t-w wait_for_link_time	in seconds\n"
1394257529Sluigi		"\t-R rate		in packets per second\n"
1395257529Sluigi		"\t-X			dump payload\n"
1396260368Sluigi		"\t-H len		add empty virtio-net-header with size 'len'\n"
1397272962Sgnn	        "\t-P file		load packet from pcap file"
1398227614Sluigi		"",
1399227614Sluigi		cmd);
1400227614Sluigi
1401227614Sluigi	exit(0);
1402227614Sluigi}
1403227614Sluigi
1404246896Sluigistatic void
1405246896Sluigistart_threads(struct glob_arg *g)
1406246896Sluigi{
1407246896Sluigi	int i;
1408227614Sluigi
1409246896Sluigi	targs = calloc(g->nthreads, sizeof(*targs));
1410246896Sluigi	/*
1411246896Sluigi	 * Now create the desired number of threads, each one
1412246896Sluigi	 * using a single descriptor.
1413246896Sluigi 	 */
1414246896Sluigi	for (i = 0; i < g->nthreads; i++) {
1415261909Sluigi		struct targ *t = &targs[i];
1416246896Sluigi
1417261909Sluigi		bzero(t, sizeof(*t));
1418261909Sluigi		t->fd = -1; /* default, with pcap */
1419261909Sluigi		t->g = g;
1420261909Sluigi
1421246896Sluigi	    if (g->dev_type == DEV_NETMAP) {
1422261909Sluigi		struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */
1423270063Sluigi		uint64_t nmd_flags = 0;
1424270063Sluigi		nmd.self = &nmd;
1425246896Sluigi
1426261909Sluigi		if (g->nthreads > 1) {
1427261909Sluigi			if (nmd.req.nr_flags != NR_REG_ALL_NIC) {
1428261909Sluigi				D("invalid nthreads mode %d", nmd.req.nr_flags);
1429261909Sluigi				continue;
1430261909Sluigi			}
1431261909Sluigi			nmd.req.nr_flags = NR_REG_ONE_NIC;
1432261909Sluigi			nmd.req.nr_ringid = i;
1433246896Sluigi		}
1434261909Sluigi		/* Only touch one of the rings (rx is already ok) */
1435261909Sluigi		if (g->td_body == receiver_body)
1436270063Sluigi			nmd_flags |= NETMAP_NO_TX_POLL;
1437246896Sluigi
1438261909Sluigi		/* register interface. Override ifname and ringid etc. */
1439270063Sluigi		if (g->options & OPT_MONITOR_TX)
1440270063Sluigi			nmd.req.nr_flags |= NR_MONITOR_TX;
1441270063Sluigi		if (g->options & OPT_MONITOR_RX)
1442270063Sluigi			nmd.req.nr_flags |= NR_MONITOR_RX;
1443246896Sluigi
1444270063Sluigi		t->nmd = nm_open(t->g->ifname, NULL, nmd_flags |
1445270063Sluigi			NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd);
1446261909Sluigi		if (t->nmd == NULL) {
1447261909Sluigi			D("Unable to open %s: %s",
1448261909Sluigi				t->g->ifname, strerror(errno));
1449261909Sluigi			continue;
1450246896Sluigi		}
1451261909Sluigi		t->fd = t->nmd->fd;
1452270063Sluigi		set_vnet_hdr_len(t);
1453246896Sluigi
1454246896Sluigi	    } else {
1455246896Sluigi		targs[i].fd = g->main_fd;
1456246896Sluigi	    }
1457261909Sluigi		t->used = 1;
1458261909Sluigi		t->me = i;
1459246896Sluigi		if (g->affinity >= 0) {
1460246896Sluigi			if (g->affinity < g->cpus)
1461261909Sluigi				t->affinity = g->affinity;
1462246896Sluigi			else
1463261909Sluigi				t->affinity = i % g->cpus;
1464261909Sluigi		} else {
1465261909Sluigi			t->affinity = -1;
1466261909Sluigi		}
1467246896Sluigi		/* default, init packets */
1468261909Sluigi		initialize_packet(t);
1469246896Sluigi
1470261909Sluigi		if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) {
1471260368Sluigi			D("Unable to create thread %d: %s", i, strerror(errno));
1472261909Sluigi			t->used = 0;
1473246896Sluigi		}
1474246896Sluigi	}
1475246896Sluigi}
1476246896Sluigi
1477246896Sluigistatic void
1478246896Sluigimain_thread(struct glob_arg *g)
1479246896Sluigi{
1480246896Sluigi	int i;
1481246896Sluigi
1482246896Sluigi	uint64_t prev = 0;
1483246896Sluigi	uint64_t count = 0;
1484246896Sluigi	double delta_t;
1485246896Sluigi	struct timeval tic, toc;
1486246896Sluigi
1487246896Sluigi	gettimeofday(&toc, NULL);
1488246896Sluigi	for (;;) {
1489246896Sluigi		struct timeval now, delta;
1490246896Sluigi		uint64_t pps, usec, my_count, npkts;
1491246896Sluigi		int done = 0;
1492246896Sluigi
1493246896Sluigi		delta.tv_sec = g->report_interval/1000;
1494246896Sluigi		delta.tv_usec = (g->report_interval%1000)*1000;
1495246896Sluigi		select(0, NULL, NULL, NULL, &delta);
1496246896Sluigi		gettimeofday(&now, NULL);
1497246896Sluigi		timersub(&now, &toc, &toc);
1498246896Sluigi		my_count = 0;
1499246896Sluigi		for (i = 0; i < g->nthreads; i++) {
1500246896Sluigi			my_count += targs[i].count;
1501246896Sluigi			if (targs[i].used == 0)
1502246896Sluigi				done++;
1503246896Sluigi		}
1504246896Sluigi		usec = toc.tv_sec* 1000000 + toc.tv_usec;
1505246896Sluigi		if (usec < 10000)
1506246896Sluigi			continue;
1507246896Sluigi		npkts = my_count - prev;
1508246896Sluigi		pps = (npkts*1000000 + usec/2) / usec;
1509261909Sluigi		D("%llu pps (%llu pkts in %llu usec)",
1510261909Sluigi			(unsigned long long)pps,
1511261909Sluigi			(unsigned long long)npkts,
1512261909Sluigi			(unsigned long long)usec);
1513246896Sluigi		prev = my_count;
1514246896Sluigi		toc = now;
1515246896Sluigi		if (done == g->nthreads)
1516246896Sluigi			break;
1517246896Sluigi	}
1518246896Sluigi
1519246896Sluigi	timerclear(&tic);
1520246896Sluigi	timerclear(&toc);
1521246896Sluigi	for (i = 0; i < g->nthreads; i++) {
1522251132Sluigi		struct timespec t_tic, t_toc;
1523246896Sluigi		/*
1524246896Sluigi		 * Join active threads, unregister interfaces and close
1525246896Sluigi		 * file descriptors.
1526246896Sluigi		 */
1527251132Sluigi		if (targs[i].used)
1528251132Sluigi			pthread_join(targs[i].thread, NULL);
1529246896Sluigi		close(targs[i].fd);
1530246896Sluigi
1531246896Sluigi		if (targs[i].completed == 0)
1532246896Sluigi			D("ouch, thread %d exited with error", i);
1533246896Sluigi
1534246896Sluigi		/*
1535246896Sluigi		 * Collect threads output and extract information about
1536246896Sluigi		 * how long it took to send all the packets.
1537246896Sluigi		 */
1538246896Sluigi		count += targs[i].count;
1539251132Sluigi		t_tic = timeval2spec(&tic);
1540251132Sluigi		t_toc = timeval2spec(&toc);
1541251132Sluigi		if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic))
1542251132Sluigi			tic = timespec2val(&targs[i].tic);
1543251132Sluigi		if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc))
1544251132Sluigi			toc = timespec2val(&targs[i].toc);
1545246896Sluigi	}
1546246896Sluigi
1547246896Sluigi	/* print output. */
1548246896Sluigi	timersub(&toc, &tic, &toc);
1549246896Sluigi	delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
1550246896Sluigi	if (g->td_body == sender_body)
1551246896Sluigi		tx_output(count, g->pkt_size, delta_t);
1552246896Sluigi	else
1553246896Sluigi		rx_output(count, delta_t);
1554246896Sluigi
1555246896Sluigi	if (g->dev_type == DEV_NETMAP) {
1556261909Sluigi		munmap(g->nmd->mem, g->nmd->req.nr_memsize);
1557246896Sluigi		close(g->main_fd);
1558246896Sluigi	}
1559246896Sluigi}
1560246896Sluigi
1561246896Sluigi
1562246896Sluigistruct sf {
1563246896Sluigi	char *key;
1564246896Sluigi	void *f;
1565246896Sluigi};
1566246896Sluigi
1567246896Sluigistatic struct sf func[] = {
1568246896Sluigi	{ "tx",	sender_body },
1569246896Sluigi	{ "rx",	receiver_body },
1570246896Sluigi	{ "ping",	pinger_body },
1571246896Sluigi	{ "pong",	ponger_body },
1572246896Sluigi	{ NULL, NULL }
1573246896Sluigi};
1574246896Sluigi
1575246896Sluigistatic int
1576246896Sluigitap_alloc(char *dev)
1577246896Sluigi{
1578246896Sluigi	struct ifreq ifr;
1579246896Sluigi	int fd, err;
1580246896Sluigi	char *clonedev = TAP_CLONEDEV;
1581246896Sluigi
1582246896Sluigi	(void)err;
1583246896Sluigi	(void)dev;
1584246896Sluigi	/* Arguments taken by the function:
1585246896Sluigi	 *
1586246896Sluigi	 * char *dev: the name of an interface (or '\0'). MUST have enough
1587246896Sluigi	 *   space to hold the interface name if '\0' is passed
1588246896Sluigi	 * int flags: interface flags (eg, IFF_TUN etc.)
1589246896Sluigi	 */
1590246896Sluigi
1591246896Sluigi#ifdef __FreeBSD__
1592246896Sluigi	if (dev[3]) { /* tapSomething */
1593246896Sluigi		static char buf[128];
1594246896Sluigi		snprintf(buf, sizeof(buf), "/dev/%s", dev);
1595246896Sluigi		clonedev = buf;
1596246896Sluigi	}
1597246896Sluigi#endif
1598246896Sluigi	/* open the device */
1599246896Sluigi	if( (fd = open(clonedev, O_RDWR)) < 0 ) {
1600246896Sluigi		return fd;
1601246896Sluigi	}
1602246896Sluigi	D("%s open successful", clonedev);
1603246896Sluigi
1604246896Sluigi	/* preparation of the struct ifr, of type "struct ifreq" */
1605246896Sluigi	memset(&ifr, 0, sizeof(ifr));
1606246896Sluigi
1607246896Sluigi#ifdef linux
1608246896Sluigi	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
1609246896Sluigi
1610246896Sluigi	if (*dev) {
1611246896Sluigi		/* if a device name was specified, put it in the structure; otherwise,
1612246896Sluigi		* the kernel will try to allocate the "next" device of the
1613246896Sluigi		* specified type */
1614246896Sluigi		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1615246896Sluigi	}
1616246896Sluigi
1617246896Sluigi	/* try to create the device */
1618246896Sluigi	if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
1619260368Sluigi		D("failed to to a TUNSETIFF: %s", strerror(errno));
1620246896Sluigi		close(fd);
1621246896Sluigi		return err;
1622246896Sluigi	}
1623246896Sluigi
1624246896Sluigi	/* if the operation was successful, write back the name of the
1625246896Sluigi	* interface to the variable "dev", so the caller can know
1626246896Sluigi	* it. Note that the caller MUST reserve space in *dev (see calling
1627246896Sluigi	* code below) */
1628246896Sluigi	strcpy(dev, ifr.ifr_name);
1629246896Sluigi	D("new name is %s", dev);
1630246896Sluigi#endif /* linux */
1631246896Sluigi
1632246896Sluigi        /* this is the special file descriptor that the caller will use to talk
1633246896Sluigi         * with the virtual interface */
1634246896Sluigi        return fd;
1635246896Sluigi}
1636246896Sluigi
1637227614Sluigiint
1638227614Sluigimain(int arc, char **argv)
1639227614Sluigi{
1640246896Sluigi	int i;
1641227614Sluigi
1642227614Sluigi	struct glob_arg g;
1643227614Sluigi
1644227614Sluigi	int ch;
1645227614Sluigi	int wait_link = 2;
1646227614Sluigi	int devqueues = 1;	/* how many device queues */
1647227614Sluigi
1648227614Sluigi	bzero(&g, sizeof(g));
1649227614Sluigi
1650246896Sluigi	g.main_fd = -1;
1651246896Sluigi	g.td_body = receiver_body;
1652246896Sluigi	g.report_interval = 1000;	/* report interval */
1653246896Sluigi	g.affinity = -1;
1654246896Sluigi	/* ip addresses can also be a range x.x.x.x-x.x.x.y */
1655246896Sluigi	g.src_ip.name = "10.0.0.1";
1656246896Sluigi	g.dst_ip.name = "10.1.0.1";
1657246896Sluigi	g.dst_mac.name = "ff:ff:ff:ff:ff:ff";
1658246896Sluigi	g.src_mac.name = NULL;
1659227614Sluigi	g.pkt_size = 60;
1660227614Sluigi	g.burst = 512;		// default
1661227614Sluigi	g.nthreads = 1;
1662227614Sluigi	g.cpus = 1;
1663251426Sluigi	g.forever = 1;
1664251132Sluigi	g.tx_rate = 0;
1665257529Sluigi	g.frags = 1;
1666257529Sluigi	g.nmr_config = "";
1667260368Sluigi	g.virt_header = 0;
1668227614Sluigi
1669227614Sluigi	while ( (ch = getopt(arc, argv,
1670272962Sgnn			"a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:m:P:")) != -1) {
1671246896Sluigi		struct sf *fn;
1672246896Sluigi
1673227614Sluigi		switch(ch) {
1674227614Sluigi		default:
1675227614Sluigi			D("bad option %c %s", ch, optarg);
1676227614Sluigi			usage();
1677227614Sluigi			break;
1678246896Sluigi
1679246896Sluigi		case 'n':
1680246896Sluigi			g.npackets = atoi(optarg);
1681246896Sluigi			break;
1682246896Sluigi
1683257529Sluigi		case 'F':
1684257529Sluigi			i = atoi(optarg);
1685257529Sluigi			if (i < 1 || i > 63) {
1686257529Sluigi				D("invalid frags %d [1..63], ignore", i);
1687257529Sluigi				break;
1688257529Sluigi			}
1689257529Sluigi			g.frags = i;
1690257529Sluigi			break;
1691257529Sluigi
1692246896Sluigi		case 'f':
1693246896Sluigi			for (fn = func; fn->key; fn++) {
1694246896Sluigi				if (!strcmp(fn->key, optarg))
1695246896Sluigi					break;
1696246896Sluigi			}
1697246896Sluigi			if (fn->key)
1698246896Sluigi				g.td_body = fn->f;
1699246896Sluigi			else
1700246896Sluigi				D("unrecognised function %s", optarg);
1701246896Sluigi			break;
1702246896Sluigi
1703246896Sluigi		case 'o':	/* data generation options */
1704234956Sluigi			g.options = atoi(optarg);
1705234956Sluigi			break;
1706246896Sluigi
1707246896Sluigi		case 'a':       /* force affinity */
1708246896Sluigi			g.affinity = atoi(optarg);
1709246896Sluigi			break;
1710246896Sluigi
1711227614Sluigi		case 'i':	/* interface */
1712260700Sluigi			/* a prefix of tap: netmap: or pcap: forces the mode.
1713260700Sluigi			 * otherwise we guess
1714260700Sluigi			 */
1715260700Sluigi			D("interface is %s", optarg);
1716261909Sluigi			if (strlen(optarg) > MAX_IFNAMELEN - 8) {
1717261909Sluigi				D("ifname too long %s", optarg);
1718261909Sluigi				break;
1719261909Sluigi			}
1720261909Sluigi			strcpy(g.ifname, optarg);
1721260700Sluigi			if (!strcmp(optarg, "null")) {
1722260700Sluigi				g.dev_type = DEV_NETMAP;
1723260700Sluigi				g.dummy_send = 1;
1724260700Sluigi			} else if (!strncmp(optarg, "tap:", 4)) {
1725246896Sluigi				g.dev_type = DEV_TAP;
1726261909Sluigi				strcpy(g.ifname, optarg + 4);
1727260700Sluigi			} else if (!strncmp(optarg, "pcap:", 5)) {
1728260700Sluigi				g.dev_type = DEV_PCAP;
1729261909Sluigi				strcpy(g.ifname, optarg + 5);
1730261909Sluigi			} else if (!strncmp(optarg, "netmap:", 7) ||
1731261909Sluigi				   !strncmp(optarg, "vale", 4)) {
1732246896Sluigi				g.dev_type = DEV_NETMAP;
1733260700Sluigi			} else if (!strncmp(optarg, "tap", 3)) {
1734260700Sluigi				g.dev_type = DEV_TAP;
1735261909Sluigi			} else { /* prepend netmap: */
1736260700Sluigi				g.dev_type = DEV_NETMAP;
1737261909Sluigi				sprintf(g.ifname, "netmap:%s", optarg);
1738260700Sluigi			}
1739227614Sluigi			break;
1740246896Sluigi
1741251426Sluigi		case 'I':
1742251426Sluigi			g.options |= OPT_INDIRECT;	/* XXX use indirect buffer */
1743251426Sluigi			break;
1744251426Sluigi
1745227614Sluigi		case 'l':	/* pkt_size */
1746227614Sluigi			g.pkt_size = atoi(optarg);
1747227614Sluigi			break;
1748246896Sluigi
1749227614Sluigi		case 'd':
1750246896Sluigi			g.dst_ip.name = optarg;
1751227614Sluigi			break;
1752246896Sluigi
1753227614Sluigi		case 's':
1754246896Sluigi			g.src_ip.name = optarg;
1755227614Sluigi			break;
1756246896Sluigi
1757227614Sluigi		case 'T':	/* report interval */
1758246896Sluigi			g.report_interval = atoi(optarg);
1759227614Sluigi			break;
1760246896Sluigi
1761227614Sluigi		case 'w':
1762227614Sluigi			wait_link = atoi(optarg);
1763227614Sluigi			break;
1764246896Sluigi
1765251426Sluigi		case 'W': /* XXX changed default */
1766251426Sluigi			g.forever = 0; /* do not exit rx even with no traffic */
1767246896Sluigi			break;
1768246896Sluigi
1769227614Sluigi		case 'b':	/* burst */
1770227614Sluigi			g.burst = atoi(optarg);
1771227614Sluigi			break;
1772227614Sluigi		case 'c':
1773227614Sluigi			g.cpus = atoi(optarg);
1774227614Sluigi			break;
1775227614Sluigi		case 'p':
1776227614Sluigi			g.nthreads = atoi(optarg);
1777227614Sluigi			break;
1778227614Sluigi
1779227614Sluigi		case 'D': /* destination mac */
1780246896Sluigi			g.dst_mac.name = optarg;
1781227614Sluigi			break;
1782246896Sluigi
1783227614Sluigi		case 'S': /* source mac */
1784246896Sluigi			g.src_mac.name = optarg;
1785227614Sluigi			break;
1786227614Sluigi		case 'v':
1787227614Sluigi			verbose++;
1788251132Sluigi			break;
1789251132Sluigi		case 'R':
1790251132Sluigi			g.tx_rate = atoi(optarg);
1791251132Sluigi			break;
1792251426Sluigi		case 'X':
1793251426Sluigi			g.options |= OPT_DUMP;
1794257529Sluigi			break;
1795257529Sluigi		case 'C':
1796257529Sluigi			g.nmr_config = strdup(optarg);
1797260368Sluigi			break;
1798260368Sluigi		case 'H':
1799260368Sluigi			g.virt_header = atoi(optarg);
1800260700Sluigi			break;
1801261909Sluigi		case 'e': /* extra bufs */
1802261909Sluigi			g.extra_bufs = atoi(optarg);
1803260700Sluigi			break;
1804270063Sluigi		case 'm':
1805270063Sluigi			if (strcmp(optarg, "tx") == 0) {
1806270063Sluigi				g.options |= OPT_MONITOR_TX;
1807270063Sluigi			} else if (strcmp(optarg, "rx") == 0) {
1808270063Sluigi				g.options |= OPT_MONITOR_RX;
1809270063Sluigi			} else {
1810270063Sluigi				D("unrecognized monitor mode %s", optarg);
1811270063Sluigi			}
1812270063Sluigi			break;
1813272962Sgnn		case 'P':
1814272962Sgnn			g.packet_file = strdup(optarg);
1815272962Sgnn			break;
1816227614Sluigi		}
1817272962Sgnn
1818227614Sluigi	}
1819227614Sluigi
1820246896Sluigi	if (g.ifname == NULL) {
1821227614Sluigi		D("missing ifname");
1822227614Sluigi		usage();
1823227614Sluigi	}
1824246896Sluigi
1825246896Sluigi	i = system_ncpus();
1826246896Sluigi	if (g.cpus < 0 || g.cpus > i) {
1827246896Sluigi		D("%d cpus is too high, have only %d cpus", g.cpus, i);
1828246896Sluigi		usage();
1829227614Sluigi	}
1830246896Sluigi	if (g.cpus == 0)
1831246896Sluigi		g.cpus = i;
1832246896Sluigi
1833270063Sluigi	if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) {
1834270063Sluigi		D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE);
1835227614Sluigi		usage();
1836227614Sluigi	}
1837227614Sluigi
1838246896Sluigi	if (g.src_mac.name == NULL) {
1839246896Sluigi		static char mybuf[20] = "00:00:00:00:00:00";
1840234956Sluigi		/* retrieve source mac address. */
1841246896Sluigi		if (source_hwaddr(g.ifname, mybuf) == -1) {
1842234956Sluigi			D("Unable to retrieve source mac");
1843234956Sluigi			// continue, fail later
1844234956Sluigi		}
1845246896Sluigi		g.src_mac.name = mybuf;
1846234956Sluigi	}
1847246896Sluigi	/* extract address ranges */
1848246896Sluigi	extract_ip_range(&g.src_ip);
1849246896Sluigi	extract_ip_range(&g.dst_ip);
1850246896Sluigi	extract_mac_range(&g.src_mac);
1851246896Sluigi	extract_mac_range(&g.dst_mac);
1852234956Sluigi
1853260700Sluigi	if (g.src_ip.start != g.src_ip.end ||
1854260700Sluigi	    g.src_ip.port0 != g.src_ip.port1 ||
1855260700Sluigi	    g.dst_ip.start != g.dst_ip.end ||
1856260700Sluigi	    g.dst_ip.port0 != g.dst_ip.port1)
1857260700Sluigi		g.options |= OPT_COPY;
1858260700Sluigi
1859260368Sluigi	if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1
1860260368Sluigi			&& g.virt_header != VIRT_HDR_2) {
1861260368Sluigi		D("bad virtio-net-header length");
1862260368Sluigi		usage();
1863260368Sluigi	}
1864260368Sluigi
1865246896Sluigi    if (g.dev_type == DEV_TAP) {
1866246896Sluigi	D("want to use tap %s", g.ifname);
1867246896Sluigi	g.main_fd = tap_alloc(g.ifname);
1868246896Sluigi	if (g.main_fd < 0) {
1869246896Sluigi		D("cannot open tap %s", g.ifname);
1870246896Sluigi		usage();
1871246896Sluigi	}
1872260700Sluigi#ifndef NO_PCAP
1873260700Sluigi    } else if (g.dev_type == DEV_PCAP) {
1874246896Sluigi	char pcap_errbuf[PCAP_ERRBUF_SIZE];
1875246896Sluigi
1876246896Sluigi	pcap_errbuf[0] = '\0'; // init the buffer
1877270063Sluigi	g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf);
1878234956Sluigi	if (g.p == NULL) {
1879246896Sluigi		D("cannot open pcap on %s", g.ifname);
1880234956Sluigi		usage();
1881234956Sluigi	}
1882270063Sluigi	g.main_fd = pcap_fileno(g.p);
1883270063Sluigi	D("using pcap on %s fileno %d", g.ifname, g.main_fd);
1884260700Sluigi#endif /* !NO_PCAP */
1885260700Sluigi    } else if (g.dummy_send) { /* but DEV_NETMAP */
1886257529Sluigi	D("using a dummy send routine");
1887234956Sluigi    } else {
1888270063Sluigi	struct nmreq base_nmd;
1889261909Sluigi
1890261909Sluigi	bzero(&base_nmd, sizeof(base_nmd));
1891261909Sluigi
1892270063Sluigi	parse_nmr_config(g.nmr_config, &base_nmd);
1893261909Sluigi	if (g.extra_bufs) {
1894270063Sluigi		base_nmd.nr_arg3 = g.extra_bufs;
1895261909Sluigi	}
1896261909Sluigi
1897227614Sluigi	/*
1898261909Sluigi	 * Open the netmap device using nm_open().
1899227614Sluigi	 *
1900227614Sluigi	 * protocol stack and may cause a reset of the card,
1901227614Sluigi	 * which in turn may take some time for the PHY to
1902261909Sluigi	 * reconfigure. We do the open here to have time to reset.
1903227614Sluigi	 */
1904270063Sluigi	g.nmd = nm_open(g.ifname, &base_nmd, 0, NULL);
1905261909Sluigi	if (g.nmd == NULL) {
1906261909Sluigi		D("Unable to open %s: %s", g.ifname, strerror(errno));
1907261909Sluigi		goto out;
1908227614Sluigi	}
1909261909Sluigi	g.main_fd = g.nmd->fd;
1910261909Sluigi	D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
1911227614Sluigi
1912270063Sluigi	/* get num of queues in tx or rx */
1913270063Sluigi	if (g.td_body == sender_body)
1914270063Sluigi		devqueues = g.nmd->req.nr_tx_rings;
1915270063Sluigi	else
1916270063Sluigi		devqueues = g.nmd->req.nr_rx_rings;
1917261909Sluigi
1918227614Sluigi	/* validate provided nthreads. */
1919227614Sluigi	if (g.nthreads < 1 || g.nthreads > devqueues) {
1920227614Sluigi		D("bad nthreads %d, have %d queues", g.nthreads, devqueues);
1921227614Sluigi		// continue, fail later
1922227614Sluigi	}
1923227614Sluigi
1924260700Sluigi	if (verbose) {
1925261909Sluigi		struct netmap_if *nifp = g.nmd->nifp;
1926261909Sluigi		struct nmreq *req = &g.nmd->req;
1927227614Sluigi
1928261909Sluigi		D("nifp at offset %d, %d tx %d rx region %d",
1929261909Sluigi		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
1930261909Sluigi		    req->nr_arg2);
1931261909Sluigi		for (i = 0; i <= req->nr_tx_rings; i++) {
1932270063Sluigi			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
1933270063Sluigi			D("   TX%d at 0x%lx slots %d", i,
1934270063Sluigi			    (char *)ring - (char *)nifp, ring->num_slots);
1935260700Sluigi		}
1936261909Sluigi		for (i = 0; i <= req->nr_rx_rings; i++) {
1937270063Sluigi			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
1938270063Sluigi			D("   RX%d at 0x%lx slots %d", i,
1939270063Sluigi			    (char *)ring - (char *)nifp, ring->num_slots);
1940260700Sluigi		}
1941260700Sluigi	}
1942227614Sluigi
1943227614Sluigi	/* Print some debug information. */
1944227614Sluigi	fprintf(stdout,
1945227614Sluigi		"%s %s: %d queues, %d threads and %d cpus.\n",
1946246896Sluigi		(g.td_body == sender_body) ? "Sending on" : "Receiving from",
1947246896Sluigi		g.ifname,
1948227614Sluigi		devqueues,
1949227614Sluigi		g.nthreads,
1950227614Sluigi		g.cpus);
1951246896Sluigi	if (g.td_body == sender_body) {
1952227614Sluigi		fprintf(stdout, "%s -> %s (%s -> %s)\n",
1953246896Sluigi			g.src_ip.name, g.dst_ip.name,
1954246896Sluigi			g.src_mac.name, g.dst_mac.name);
1955227614Sluigi	}
1956261909Sluigi
1957261909Sluigiout:
1958227614Sluigi	/* Exit if something went wrong. */
1959246896Sluigi	if (g.main_fd < 0) {
1960227614Sluigi		D("aborting");
1961227614Sluigi		usage();
1962227614Sluigi	}
1963234956Sluigi    }
1964227614Sluigi
1965261909Sluigi
1966234956Sluigi	if (g.options) {
1967251426Sluigi		D("--- SPECIAL OPTIONS:%s%s%s%s%s\n",
1968234956Sluigi			g.options & OPT_PREFETCH ? " prefetch" : "",
1969234956Sluigi			g.options & OPT_ACCESS ? " access" : "",
1970234956Sluigi			g.options & OPT_MEMCPY ? " memcpy" : "",
1971251426Sluigi			g.options & OPT_INDIRECT ? " indirect" : "",
1972234956Sluigi			g.options & OPT_COPY ? " copy" : "");
1973234956Sluigi	}
1974257529Sluigi
1975257529Sluigi	g.tx_period.tv_sec = g.tx_period.tv_nsec = 0;
1976257529Sluigi	if (g.tx_rate > 0) {
1977257529Sluigi		/* try to have at least something every second,
1978260368Sluigi		 * reducing the burst size to some 0.01s worth of data
1979257529Sluigi		 * (but no less than one full set of fragments)
1980257529Sluigi	 	 */
1981260368Sluigi		uint64_t x;
1982260368Sluigi		int lim = (g.tx_rate)/300;
1983260368Sluigi		if (g.burst > lim)
1984260368Sluigi			g.burst = lim;
1985257529Sluigi		if (g.burst < g.frags)
1986257529Sluigi			g.burst = g.frags;
1987260368Sluigi		x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate;
1988260368Sluigi		g.tx_period.tv_nsec = x;
1989257529Sluigi		g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000;
1990257529Sluigi		g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000;
1991251132Sluigi	}
1992257529Sluigi	if (g.td_body == sender_body)
1993257529Sluigi	    D("Sending %d packets every  %ld.%09ld s",
1994257529Sluigi			g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec);
1995227614Sluigi	/* Wait for PHY reset. */
1996227614Sluigi	D("Wait %d secs for phy reset", wait_link);
1997227614Sluigi	sleep(wait_link);
1998227614Sluigi	D("Ready...");
1999227614Sluigi
2000227614Sluigi	/* Install ^C handler. */
2001227614Sluigi	global_nthreads = g.nthreads;
2002227614Sluigi	signal(SIGINT, sigint_h);
2003227614Sluigi
2004246896Sluigi	start_threads(&g);
2005246896Sluigi	main_thread(&g);
2006246896Sluigi	return 0;
2007246896Sluigi}
2008227614Sluigi
2009227614Sluigi/* end of file */
2010