1227614Sluigi/*
2260368Sluigi * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
3341457Svmaffione * Copyright (C) 2013-2015 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: stable/11/tools/tools/netmap/pkt-gen.c 344918 2019-03-08 08:27:33Z vmaffione $
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
40261909Sluigi#define _GNU_SOURCE	/* for CPU_SET() */
41261909Sluigi#include <stdio.h>
42261909Sluigi#define NETMAP_WITH_LIBS
43261909Sluigi#include <net/netmap_user.h>
44246896Sluigi
45261909Sluigi
46251426Sluigi#include <ctype.h>	// isprint()
47261909Sluigi#include <unistd.h>	// sysconf()
48261909Sluigi#include <sys/poll.h>
49261909Sluigi#include <arpa/inet.h>	/* ntohs */
50341457Svmaffione#ifndef _WIN32
51261909Sluigi#include <sys/sysctl.h>	/* sysctl */
52341457Svmaffione#endif
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>
58341457Svmaffione#include <netinet/ip6.h>
59341457Svmaffione#ifdef linux
60341457Svmaffione#define IPV6_VERSION	0x60
61341457Svmaffione#define IPV6_DEFHLIM	64
62341457Svmaffione#endif
63341457Svmaffione#include <assert.h>
64341457Svmaffione#include <math.h>
65251426Sluigi
66261909Sluigi#include <pthread.h>
67261909Sluigi
68260700Sluigi#ifndef NO_PCAP
69260700Sluigi#include <pcap/pcap.h>
70260700Sluigi#endif
71261909Sluigi
72341457Svmaffione#include "ctrs.h"
73341457Svmaffione
74341457Svmaffionestatic void usage(int);
75341457Svmaffione
76341457Svmaffione#ifdef _WIN32
77341457Svmaffione#define cpuset_t        DWORD_PTR   //uint64_t
78341457Svmaffionestatic inline void CPU_ZERO(cpuset_t *p)
79341457Svmaffione{
80341457Svmaffione	*p = 0;
81341457Svmaffione}
82341457Svmaffione
83341457Svmaffionestatic inline void CPU_SET(uint32_t i, cpuset_t *p)
84341457Svmaffione{
85341457Svmaffione	*p |= 1<< (i & 0x3f);
86341457Svmaffione}
87341457Svmaffione
88341457Svmaffione#define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c)    //((void)a, 0)
89341457Svmaffione#define TAP_CLONEDEV	"/dev/tap"
90341457Svmaffione#define AF_LINK	18	//defined in winsocks.h
91341457Svmaffione#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME
92341457Svmaffione#include <net/if_dl.h>
93341457Svmaffione
94341457Svmaffione/*
95341457Svmaffione * Convert an ASCII representation of an ethernet address to
96341457Svmaffione * binary form.
97341457Svmaffione */
98341457Svmaffionestruct ether_addr *
99341457Svmaffioneether_aton(const char *a)
100341457Svmaffione{
101341457Svmaffione	int i;
102341457Svmaffione	static struct ether_addr o;
103341457Svmaffione	unsigned int o0, o1, o2, o3, o4, o5;
104341457Svmaffione
105341457Svmaffione	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
106341457Svmaffione
107341457Svmaffione	if (i != 6)
108341457Svmaffione		return (NULL);
109341457Svmaffione
110341457Svmaffione	o.octet[0]=o0;
111341457Svmaffione	o.octet[1]=o1;
112341457Svmaffione	o.octet[2]=o2;
113341457Svmaffione	o.octet[3]=o3;
114341457Svmaffione	o.octet[4]=o4;
115341457Svmaffione	o.octet[5]=o5;
116341457Svmaffione
117341457Svmaffione	return ((struct ether_addr *)&o);
118341457Svmaffione}
119341457Svmaffione
120341457Svmaffione/*
121341457Svmaffione * Convert a binary representation of an ethernet address to
122341457Svmaffione * an ASCII string.
123341457Svmaffione */
124341457Svmaffionechar *
125341457Svmaffioneether_ntoa(const struct ether_addr *n)
126341457Svmaffione{
127341457Svmaffione	int i;
128341457Svmaffione	static char a[18];
129341457Svmaffione
130341457Svmaffione	i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x",
131341457Svmaffione	    n->octet[0], n->octet[1], n->octet[2],
132341457Svmaffione	    n->octet[3], n->octet[4], n->octet[5]);
133341457Svmaffione	return (i < 17 ? NULL : (char *)&a);
134341457Svmaffione}
135341457Svmaffione#endif /* _WIN32 */
136341457Svmaffione
137261909Sluigi#ifdef linux
138261909Sluigi
139261909Sluigi#define cpuset_t        cpu_set_t
140261909Sluigi
141261909Sluigi#define ifr_flagshigh  ifr_flags        /* only the low 16 bits here */
142261909Sluigi#define IFF_PPROMISC   IFF_PROMISC      /* IFF_PPROMISC does not exist */
143261909Sluigi#include <linux/ethtool.h>
144261909Sluigi#include <linux/sockios.h>
145261909Sluigi
146261909Sluigi#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME
147261909Sluigi#include <netinet/ether.h>      /* ether_aton */
148261909Sluigi#include <linux/if_packet.h>    /* sockaddr_ll */
149261909Sluigi#endif  /* linux */
150261909Sluigi
151261909Sluigi#ifdef __FreeBSD__
152261909Sluigi#include <sys/endian.h> /* le64toh */
153261909Sluigi#include <machine/param.h>
154261909Sluigi
155261909Sluigi#include <pthread_np.h> /* pthread w/ affinity */
156261909Sluigi#include <sys/cpuset.h> /* cpu_set */
157261909Sluigi#include <net/if_dl.h>  /* LLADDR */
158261909Sluigi#endif  /* __FreeBSD__ */
159261909Sluigi
160261909Sluigi#ifdef __APPLE__
161261909Sluigi
162261909Sluigi#define cpuset_t        uint64_t        // XXX
163261909Sluigistatic inline void CPU_ZERO(cpuset_t *p)
164261909Sluigi{
165341457Svmaffione	*p = 0;
166261909Sluigi}
167261909Sluigi
168261909Sluigistatic inline void CPU_SET(uint32_t i, cpuset_t *p)
169261909Sluigi{
170341457Svmaffione	*p |= 1<< (i & 0x3f);
171261909Sluigi}
172261909Sluigi
173261909Sluigi#define pthread_setaffinity_np(a, b, c) ((void)a, 0)
174261909Sluigi
175261909Sluigi#define ifr_flagshigh  ifr_flags        // XXX
176261909Sluigi#define IFF_PPROMISC   IFF_PROMISC
177261909Sluigi#include <net/if_dl.h>  /* LLADDR */
178261909Sluigi#define clock_gettime(a,b)      \
179341457Svmaffione	do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
180261909Sluigi#endif  /* __APPLE__ */
181261909Sluigi
182257529Sluigiconst char *default_payload="netmap pkt-gen DIRECT payload\n"
183227614Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
184227614Sluigi
185257529Sluigiconst char *indirect_payload="netmap pkt-gen indirect payload\n"
186257529Sluigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
187257529Sluigi
188227614Sluigiint verbose = 0;
189341457Svmaffioneint normalize = 1;
190227614Sluigi
191260368Sluigi#define VIRT_HDR_1	10	/* length of a base vnet-hdr */
192260368Sluigi#define VIRT_HDR_2	12	/* length of the extenede vnet-hdr */
193260368Sluigi#define VIRT_HDR_MAX	VIRT_HDR_2
194260368Sluigistruct virt_header {
195260368Sluigi	uint8_t fields[VIRT_HDR_MAX];
196260368Sluigi};
197260368Sluigi
198342035Svmaffione#define MAX_BODYSIZE	65536
199270063Sluigi
200227614Sluigistruct pkt {
201260368Sluigi	struct virt_header vh;
202227614Sluigi	struct ether_header eh;
203341457Svmaffione	union {
204341457Svmaffione		struct {
205341457Svmaffione			struct ip ip;
206341457Svmaffione			struct udphdr udp;
207341457Svmaffione			uint8_t body[MAX_BODYSIZE];	/* hardwired */
208341457Svmaffione		} ipv4;
209341457Svmaffione		struct {
210341457Svmaffione			struct ip6_hdr ip;
211341457Svmaffione			struct udphdr udp;
212341457Svmaffione			uint8_t body[MAX_BODYSIZE];	/* hardwired */
213341457Svmaffione		} ipv6;
214341457Svmaffione	};
215227614Sluigi} __attribute__((__packed__));
216227614Sluigi
217341457Svmaffione#define	PKT(p, f, af)	\
218341457Svmaffione    ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f)
219341457Svmaffione
220246896Sluigistruct ip_range {
221246896Sluigi	char *name;
222341457Svmaffione	union {
223341457Svmaffione		struct {
224341457Svmaffione			uint32_t start, end; /* same as struct in_addr */
225341457Svmaffione		} ipv4;
226341457Svmaffione		struct {
227341457Svmaffione			struct in6_addr start, end;
228341457Svmaffione			uint8_t sgroup, egroup;
229341457Svmaffione		} ipv6;
230341457Svmaffione	};
231257529Sluigi	uint16_t port0, port1;
232246896Sluigi};
233246896Sluigi
234246896Sluigistruct mac_range {
235246896Sluigi	char *name;
236246896Sluigi	struct ether_addr start, end;
237246896Sluigi};
238246896Sluigi
239261909Sluigi/* ifname can be netmap:foo-xxxx */
240261909Sluigi#define MAX_IFNAMELEN	64	/* our buffer for ifname */
241270063Sluigi#define MAX_PKTSIZE	MAX_BODYSIZE	/* XXX: + IP_HDR + ETH_HDR */
242270063Sluigi
243270063Sluigi/* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
244270063Sluigistruct tstamp {
245270063Sluigi	uint32_t sec;
246270063Sluigi	uint32_t nsec;
247270063Sluigi};
248270063Sluigi
249227614Sluigi/*
250227614Sluigi * global arguments for all threads
251227614Sluigi */
252246896Sluigi
253227614Sluigistruct glob_arg {
254341457Svmaffione	int af;		/* address family AF_INET/AF_INET6 */
255246896Sluigi	struct ip_range src_ip;
256246896Sluigi	struct ip_range dst_ip;
257246896Sluigi	struct mac_range dst_mac;
258246896Sluigi	struct mac_range src_mac;
259227614Sluigi	int pkt_size;
260341457Svmaffione	int pkt_min_size;
261227614Sluigi	int burst;
262246896Sluigi	int forever;
263341457Svmaffione	uint64_t npackets;	/* total packets to send */
264341457Svmaffione	int frags;		/* fragments per packet */
265342035Svmaffione	u_int frag_size;	/* size of each fragment */
266227614Sluigi	int nthreads;
267341457Svmaffione	int cpus;	/* cpus used for running */
268341457Svmaffione	int system_cpus;	/* cpus on the system */
269341457Svmaffione
270234956Sluigi	int options;	/* testing */
271234956Sluigi#define OPT_PREFETCH	1
272234956Sluigi#define OPT_ACCESS	2
273234956Sluigi#define OPT_COPY	4
274234956Sluigi#define OPT_MEMCPY	8
275246896Sluigi#define OPT_TS		16	/* add a timestamp */
276251426Sluigi#define OPT_INDIRECT	32	/* use indirect buffers, tx only */
277251426Sluigi#define OPT_DUMP	64	/* dump rx/tx traffic */
278341457Svmaffione#define OPT_RUBBISH	256	/* send wathever the buffers contain */
279281746Sadrian#define OPT_RANDOM_SRC  512
280281746Sadrian#define OPT_RANDOM_DST  1024
281341457Svmaffione#define OPT_PPS_STATS   2048
282246896Sluigi	int dev_type;
283260700Sluigi#ifndef NO_PCAP
284227614Sluigi	pcap_t *p;
285260700Sluigi#endif
286227614Sluigi
287251132Sluigi	int tx_rate;
288251132Sluigi	struct timespec tx_period;
289251132Sluigi
290246896Sluigi	int affinity;
291246896Sluigi	int main_fd;
292261909Sluigi	struct nm_desc *nmd;
293260700Sluigi	int report_interval;		/* milliseconds between prints */
294246896Sluigi	void *(*td_body)(void *);
295341457Svmaffione	int td_type;
296246896Sluigi	void *mmap_addr;
297261909Sluigi	char ifname[MAX_IFNAMELEN];
298257529Sluigi	char *nmr_config;
299257529Sluigi	int dummy_send;
300260368Sluigi	int virt_header;	/* send also the virt_header */
301272962Sgnn	char *packet_file;	/* -P option */
302341457Svmaffione#define	STATS_WIN	15
303341457Svmaffione	int win_idx;
304341457Svmaffione	int64_t win[STATS_WIN];
305341457Svmaffione	int wait_link;
306341457Svmaffione	int framing;		/* #bits of framing (for bw output) */
307227614Sluigi};
308246896Sluigienum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
309227614Sluigi
310342035Svmaffioneenum {
311342035Svmaffione	TD_TYPE_SENDER = 1,
312342035Svmaffione	TD_TYPE_RECEIVER,
313342035Svmaffione	TD_TYPE_OTHER,
314342035Svmaffione};
315246896Sluigi
316227614Sluigi/*
317227614Sluigi * Arguments for a new thread. The same structure is used by
318227614Sluigi * the source and the sink
319227614Sluigi */
320227614Sluigistruct targ {
321227614Sluigi	struct glob_arg *g;
322227614Sluigi	int used;
323227614Sluigi	int completed;
324238165Semaste	int cancel;
325227614Sluigi	int fd;
326261909Sluigi	struct nm_desc *nmd;
327341457Svmaffione	/* these ought to be volatile, but they are
328341457Svmaffione	 * only sampled and errors should not accumulate
329341457Svmaffione	 */
330341457Svmaffione	struct my_ctrs ctr;
331341457Svmaffione
332251132Sluigi	struct timespec tic, toc;
333227614Sluigi	int me;
334227614Sluigi	pthread_t thread;
335227614Sluigi	int affinity;
336227614Sluigi
337227614Sluigi	struct pkt pkt;
338272962Sgnn	void *frame;
339341457Svmaffione	uint16_t seed[3];
340341457Svmaffione	u_int frags;
341341457Svmaffione	u_int frag_size;
342227614Sluigi};
343227614Sluigi
344341457Svmaffionestatic __inline uint16_t
345341457Svmaffionecksum_add(uint16_t sum, uint16_t a)
346341457Svmaffione{
347341457Svmaffione	uint16_t res;
348227614Sluigi
349341457Svmaffione	res = sum + a;
350341457Svmaffione	return (res + (res < a));
351341457Svmaffione}
352341457Svmaffione
353341457Svmaffionestatic void
354341457Svmaffioneextract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port)
355341457Svmaffione{
356341457Svmaffione	struct in_addr a;
357341457Svmaffione	char *pp;
358341457Svmaffione
359341457Svmaffione	pp = strchr(name, ':');
360341457Svmaffione	if (pp != NULL) {	/* do we have ports ? */
361341457Svmaffione		*pp++ = '\0';
362341457Svmaffione		*port = (uint16_t)strtol(pp, NULL, 0);
363341457Svmaffione	}
364341457Svmaffione
365341457Svmaffione	inet_pton(AF_INET, name, &a);
366341457Svmaffione	*addr = ntohl(a.s_addr);
367341457Svmaffione}
368341457Svmaffione
369341457Svmaffionestatic void
370341457Svmaffioneextract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port,
371341457Svmaffione    uint8_t *group)
372341457Svmaffione{
373341457Svmaffione	char *pp;
374341457Svmaffione
375341457Svmaffione	/*
376341457Svmaffione	 * We accept IPv6 address in the following form:
377341457Svmaffione	 *  group@[2001:DB8::1001]:port	(w/ brackets and port)
378341457Svmaffione	 *  group@[2001:DB8::1]		(w/ brackets and w/o port)
379341457Svmaffione	 *  group@2001:DB8::1234	(w/o brackets and w/o port)
380341457Svmaffione	 */
381341457Svmaffione	pp = strchr(name, '@');
382341457Svmaffione	if (pp != NULL) {
383341457Svmaffione		*pp++ = '\0';
384341457Svmaffione		*group = (uint8_t)strtol(name, NULL, 0);
385341457Svmaffione		if (*group > 7)
386341457Svmaffione			*group = 7;
387341457Svmaffione		name = pp;
388341457Svmaffione	}
389341457Svmaffione	if (name[0] == '[')
390341457Svmaffione		name++;
391341457Svmaffione	pp = strchr(name, ']');
392341457Svmaffione	if (pp != NULL)
393341457Svmaffione		*pp++ = '\0';
394341457Svmaffione	if (pp != NULL && *pp != ':')
395341457Svmaffione		pp = NULL;
396341457Svmaffione	if (pp != NULL) {	/* do we have ports ? */
397341457Svmaffione		*pp++ = '\0';
398341457Svmaffione		*port = (uint16_t)strtol(pp, NULL, 0);
399341457Svmaffione	}
400341457Svmaffione	inet_pton(AF_INET6, name, addr);
401341457Svmaffione}
402246896Sluigi/*
403246896Sluigi * extract the extremes from a range of ipv4 addresses.
404246896Sluigi * addr_lo[-addr_hi][:port_lo[-port_hi]]
405246896Sluigi */
406341457Svmaffionestatic int
407341457Svmaffioneextract_ip_range(struct ip_range *r, int af)
408246896Sluigi{
409341457Svmaffione	char *name, *ap, start[INET6_ADDRSTRLEN];
410341457Svmaffione	char end[INET6_ADDRSTRLEN];
411257529Sluigi	struct in_addr a;
412341457Svmaffione	uint32_t tmp;
413246896Sluigi
414260368Sluigi	if (verbose)
415260368Sluigi		D("extract IP range from %s", r->name);
416257529Sluigi
417341457Svmaffione	name = strdup(r->name);
418341457Svmaffione	if (name == NULL) {
419341457Svmaffione		D("strdup failed");
420341457Svmaffione		usage(-1);
421341457Svmaffione	}
422257529Sluigi	/* the first - splits start/end of range */
423341457Svmaffione	ap = strchr(name, '-');
424341457Svmaffione	if (ap != NULL)
425257529Sluigi		*ap++ = '\0';
426341457Svmaffione	r->port0 = 1234;	/* default port */
427341457Svmaffione	if (af == AF_INET6) {
428341457Svmaffione		r->ipv6.sgroup = 7; /* default group */
429341457Svmaffione		extract_ipv6_addr(name, &r->ipv6.start, &r->port0,
430341457Svmaffione		    &r->ipv6.sgroup);
431341457Svmaffione	} else
432341457Svmaffione		extract_ipv4_addr(name, &r->ipv4.start, &r->port0);
433341457Svmaffione
434341457Svmaffione	r->port1 = r->port0;
435341457Svmaffione	if (af == AF_INET6) {
436341457Svmaffione		if (ap != NULL) {
437341457Svmaffione			r->ipv6.egroup = r->ipv6.sgroup;
438341457Svmaffione			extract_ipv6_addr(ap, &r->ipv6.end, &r->port1,
439341457Svmaffione			    &r->ipv6.egroup);
440341457Svmaffione		} else {
441341457Svmaffione			r->ipv6.end = r->ipv6.start;
442341457Svmaffione			r->ipv6.egroup = r->ipv6.sgroup;
443246896Sluigi		}
444341457Svmaffione	} else {
445341457Svmaffione		if (ap != NULL) {
446341457Svmaffione			extract_ipv4_addr(ap, &r->ipv4.end, &r->port1);
447341457Svmaffione			if (r->ipv4.start > r->ipv4.end) {
448341457Svmaffione				tmp = r->ipv4.end;
449341457Svmaffione				r->ipv4.end = r->ipv4.start;
450341457Svmaffione				r->ipv4.start = tmp;
451341457Svmaffione			}
452341457Svmaffione		} else
453341457Svmaffione			r->ipv4.end = r->ipv4.start;
454246896Sluigi	}
455341457Svmaffione
456257529Sluigi	if (r->port0 > r->port1) {
457341457Svmaffione		tmp = r->port0;
458257529Sluigi		r->port0 = r->port1;
459257529Sluigi		r->port1 = tmp;
460257529Sluigi	}
461341457Svmaffione	if (af == AF_INET) {
462341457Svmaffione		a.s_addr = htonl(r->ipv4.start);
463341457Svmaffione		inet_ntop(af, &a, start, sizeof(start));
464341457Svmaffione		a.s_addr = htonl(r->ipv4.end);
465341457Svmaffione		inet_ntop(af, &a, end, sizeof(end));
466341457Svmaffione	} else {
467341457Svmaffione		inet_ntop(af, &r->ipv6.start, start, sizeof(start));
468341457Svmaffione		inet_ntop(af, &r->ipv6.end, end, sizeof(end));
469246896Sluigi	}
470341457Svmaffione	if (af == AF_INET)
471341457Svmaffione		D("range is %s:%d to %s:%d", start, r->port0, end, r->port1);
472341457Svmaffione	else
473341457Svmaffione		D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup,
474341457Svmaffione		    start, r->port0, r->ipv6.egroup, end, r->port1);
475257529Sluigi
476341457Svmaffione	free(name);
477341457Svmaffione	if (r->port0 != r->port1 ||
478341457Svmaffione	    (af == AF_INET && r->ipv4.start != r->ipv4.end) ||
479341457Svmaffione	    (af == AF_INET6 &&
480341457Svmaffione		!IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end)))
481341457Svmaffione		return (OPT_COPY);
482341457Svmaffione	return (0);
483246896Sluigi}
484246896Sluigi
485341457Svmaffionestatic int
486246896Sluigiextract_mac_range(struct mac_range *r)
487246896Sluigi{
488341457Svmaffione	struct ether_addr *e;
489260368Sluigi	if (verbose)
490260368Sluigi	    D("extract MAC range from %s", r->name);
491341457Svmaffione
492341457Svmaffione	e = ether_aton(r->name);
493341457Svmaffione	if (e == NULL) {
494341457Svmaffione		D("invalid MAC address '%s'", r->name);
495341457Svmaffione		return 1;
496341457Svmaffione	}
497341457Svmaffione	bcopy(e, &r->start, 6);
498341457Svmaffione	bcopy(e, &r->end, 6);
499246896Sluigi#if 0
500246896Sluigi	bcopy(targ->src_mac, eh->ether_shost, 6);
501246896Sluigi	p = index(targ->g->src_mac, '-');
502246896Sluigi	if (p)
503246896Sluigi		targ->src_mac_range = atoi(p+1);
504246896Sluigi
505246896Sluigi	bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6);
506246896Sluigi	bcopy(targ->dst_mac, eh->ether_dhost, 6);
507246896Sluigi	p = index(targ->g->dst_mac, '-');
508246896Sluigi	if (p)
509246896Sluigi		targ->dst_mac_range = atoi(p+1);
510246896Sluigi#endif
511260368Sluigi	if (verbose)
512260368Sluigi		D("%s starts at %s", r->name, ether_ntoa(&r->start));
513341457Svmaffione	return 0;
514246896Sluigi}
515246896Sluigi
516342035Svmaffionestatic int
517342035Svmaffioneget_if_mtu(const struct glob_arg *g)
518342035Svmaffione{
519342035Svmaffione	char ifname[IFNAMSIZ];
520342035Svmaffione	struct ifreq ifreq;
521342035Svmaffione	int s, ret;
522342035Svmaffione
523342035Svmaffione	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{')
524342035Svmaffione			&& !strchr(g->ifname, '}')) {
525342035Svmaffione		/* Parse the interface name and ask the kernel for the
526342035Svmaffione		 * MTU value. */
527342035Svmaffione		strncpy(ifname, g->ifname+7, IFNAMSIZ-1);
528342035Svmaffione		ifname[strcspn(ifname, "-*^{}/@")] = '\0';
529342035Svmaffione
530342035Svmaffione		s = socket(AF_INET, SOCK_DGRAM, 0);
531342035Svmaffione		if (s < 0) {
532342035Svmaffione			D("socket() failed: %s", strerror(errno));
533342035Svmaffione			return s;
534342035Svmaffione		}
535342035Svmaffione
536342035Svmaffione		memset(&ifreq, 0, sizeof(ifreq));
537342035Svmaffione		strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
538342035Svmaffione
539342035Svmaffione		ret = ioctl(s, SIOCGIFMTU, &ifreq);
540342035Svmaffione		if (ret) {
541342035Svmaffione			D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
542342035Svmaffione		}
543342035Svmaffione
544342035Svmaffione		return ifreq.ifr_mtu;
545342035Svmaffione	}
546342035Svmaffione
547342035Svmaffione	/* This is a pipe or a VALE port, where the MTU is very large,
548342035Svmaffione	 * so we use some practical limit. */
549342035Svmaffione	return 65536;
550342035Svmaffione}
551342035Svmaffione
552227614Sluigistatic struct targ *targs;
553227614Sluigistatic int global_nthreads;
554227614Sluigi
555227614Sluigi/* control-C handler */
556227614Sluigistatic void
557246896Sluigisigint_h(int sig)
558227614Sluigi{
559246896Sluigi	int i;
560246896Sluigi
561246896Sluigi	(void)sig;	/* UNUSED */
562341457Svmaffione	D("received control-C on thread %p", (void *)pthread_self());
563246896Sluigi	for (i = 0; i < global_nthreads; i++) {
564238165Semaste		targs[i].cancel = 1;
565246896Sluigi	}
566227614Sluigi}
567227614Sluigi
568227614Sluigi/* sysctl wrapper to return the number of active CPUs */
569227614Sluigistatic int
570227614Sluigisystem_ncpus(void)
571227614Sluigi{
572261909Sluigi	int ncpus;
573261909Sluigi#if defined (__FreeBSD__)
574261909Sluigi	int mib[2] = { CTL_HW, HW_NCPU };
575261909Sluigi	size_t len = sizeof(mib);
576227614Sluigi	sysctl(mib, 2, &ncpus, &len, NULL, 0);
577261909Sluigi#elif defined(linux)
578261909Sluigi	ncpus = sysconf(_SC_NPROCESSORS_ONLN);
579341457Svmaffione#elif defined(_WIN32)
580341457Svmaffione	{
581341457Svmaffione		SYSTEM_INFO sysinfo;
582341457Svmaffione		GetSystemInfo(&sysinfo);
583341457Svmaffione		ncpus = sysinfo.dwNumberOfProcessors;
584341457Svmaffione	}
585261909Sluigi#else /* others */
586261909Sluigi	ncpus = 1;
587261909Sluigi#endif /* others */
588227614Sluigi	return (ncpus);
589227614Sluigi}
590227614Sluigi
591246896Sluigi#ifdef __linux__
592246896Sluigi#define sockaddr_dl    sockaddr_ll
593246896Sluigi#define sdl_family     sll_family
594246896Sluigi#define AF_LINK        AF_PACKET
595246896Sluigi#define LLADDR(s)      s->sll_addr;
596246896Sluigi#include <linux/if_tun.h>
597246896Sluigi#define TAP_CLONEDEV	"/dev/net/tun"
598246896Sluigi#endif /* __linux__ */
599246896Sluigi
600246896Sluigi#ifdef __FreeBSD__
601246896Sluigi#include <net/if_tun.h>
602246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
603246896Sluigi#endif /* __FreeBSD */
604246896Sluigi
605246896Sluigi#ifdef __APPLE__
606246896Sluigi// #warning TAP not supported on apple ?
607246896Sluigi#include <net/if_utun.h>
608246896Sluigi#define TAP_CLONEDEV	"/dev/tap"
609246896Sluigi#endif /* __APPLE__ */
610246896Sluigi
611246896Sluigi
612227614Sluigi/*
613257529Sluigi * parse the vale configuration in conf and put it in nmr.
614261909Sluigi * Return the flag set if necessary.
615341457Svmaffione * The configuration may consist of 1 to 4 numbers separated
616257906Shiren * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings.
617257529Sluigi * Missing numbers or zeroes stand for default values.
618257529Sluigi * As an additional convenience, if exactly one number
619257906Shiren * is specified, then this is assigned to both #tx-slots and #rx-slots.
620261909Sluigi * If there is no 4th number, then the 3rd is assigned to both #tx-rings
621257529Sluigi * and #rx-rings.
622257529Sluigi */
623261909Sluigiint
624261909Sluigiparse_nmr_config(const char* conf, struct nmreq *nmr)
625257529Sluigi{
626257529Sluigi	char *w, *tok;
627257529Sluigi	int i, v;
628257529Sluigi
629344918Svmaffione	if (conf == NULL || ! *conf)
630344918Svmaffione		return 0;
631257529Sluigi	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
632257529Sluigi	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
633257529Sluigi	w = strdup(conf);
634257529Sluigi	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
635257529Sluigi		v = atoi(tok);
636257529Sluigi		switch (i) {
637257529Sluigi		case 0:
638257529Sluigi			nmr->nr_tx_slots = nmr->nr_rx_slots = v;
639257529Sluigi			break;
640257529Sluigi		case 1:
641257529Sluigi			nmr->nr_rx_slots = v;
642257529Sluigi			break;
643257529Sluigi		case 2:
644257529Sluigi			nmr->nr_tx_rings = nmr->nr_rx_rings = v;
645257529Sluigi			break;
646257529Sluigi		case 3:
647257529Sluigi			nmr->nr_rx_rings = v;
648257529Sluigi			break;
649257529Sluigi		default:
650257529Sluigi			D("ignored config: %s", tok);
651257529Sluigi			break;
652257529Sluigi		}
653257529Sluigi	}
654257529Sluigi	D("txr %d txd %d rxr %d rxd %d",
655257529Sluigi			nmr->nr_tx_rings, nmr->nr_tx_slots,
656257529Sluigi			nmr->nr_rx_rings, nmr->nr_rx_slots);
657257529Sluigi	free(w);
658261909Sluigi	return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
659341457Svmaffione		nmr->nr_rx_rings || nmr->nr_rx_slots) ?
660261909Sluigi		NM_OPEN_RING_CFG : 0;
661257529Sluigi}
662257529Sluigi
663257529Sluigi
664257529Sluigi/*
665227614Sluigi * locate the src mac address for our interface, put it
666227614Sluigi * into the user-supplied buffer. return 0 if ok, -1 on error.
667227614Sluigi */
668227614Sluigistatic int
669227614Sluigisource_hwaddr(const char *ifname, char *buf)
670227614Sluigi{
671227614Sluigi	struct ifaddrs *ifaphead, *ifap;
672227614Sluigi
673227614Sluigi	if (getifaddrs(&ifaphead) != 0) {
674227614Sluigi		D("getifaddrs %s failed", ifname);
675227614Sluigi		return (-1);
676227614Sluigi	}
677227614Sluigi
678227614Sluigi	for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
679227614Sluigi		struct sockaddr_dl *sdl =
680227614Sluigi			(struct sockaddr_dl *)ifap->ifa_addr;
681227614Sluigi		uint8_t *mac;
682227614Sluigi
683227614Sluigi		if (!sdl || sdl->sdl_family != AF_LINK)
684227614Sluigi			continue;
685341457Svmaffione		if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0)
686227614Sluigi			continue;
687227614Sluigi		mac = (uint8_t *)LLADDR(sdl);
688227614Sluigi		sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
689227614Sluigi			mac[0], mac[1], mac[2],
690227614Sluigi			mac[3], mac[4], mac[5]);
691227614Sluigi		if (verbose)
692227614Sluigi			D("source hwaddr %s", buf);
693227614Sluigi		break;
694227614Sluigi	}
695227614Sluigi	freeifaddrs(ifaphead);
696227614Sluigi	return ifap ? 0 : 1;
697227614Sluigi}
698227614Sluigi
699227614Sluigi
700227614Sluigi/* set the thread affinity. */
701227614Sluigistatic int
702227614Sluigisetaffinity(pthread_t me, int i)
703227614Sluigi{
704227614Sluigi	cpuset_t cpumask;
705227614Sluigi
706227614Sluigi	if (i == -1)
707227614Sluigi		return 0;
708227614Sluigi
709227614Sluigi	/* Set thread affinity affinity.*/
710227614Sluigi	CPU_ZERO(&cpumask);
711227614Sluigi	CPU_SET(i, &cpumask);
712227614Sluigi
713227614Sluigi	if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
714260368Sluigi		D("Unable to set affinity: %s", strerror(errno));
715227614Sluigi		return 1;
716227614Sluigi	}
717227614Sluigi	return 0;
718227614Sluigi}
719227614Sluigi
720341457Svmaffione
721227614Sluigi/* Compute the checksum of the given ip header. */
722341457Svmaffionestatic uint32_t
723246896Sluigichecksum(const void *data, uint16_t len, uint32_t sum)
724227614Sluigi{
725341457Svmaffione	const uint8_t *addr = data;
726246896Sluigi	uint32_t i;
727227614Sluigi
728341457Svmaffione	/* Checksum all the pairs of bytes first... */
729341457Svmaffione	for (i = 0; i < (len & ~1U); i += 2) {
730341457Svmaffione		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
731341457Svmaffione		if (sum > 0xFFFF)
732341457Svmaffione			sum -= 0xFFFF;
733341457Svmaffione	}
734246896Sluigi	/*
735246896Sluigi	 * If there's a single byte left over, checksum it, too.
736246896Sluigi	 * Network byte order is big-endian, so the remaining byte is
737246896Sluigi	 * the high byte.
738246896Sluigi	 */
739246896Sluigi	if (i < len) {
740246896Sluigi		sum += addr[i] << 8;
741246896Sluigi		if (sum > 0xFFFF)
742246896Sluigi			sum -= 0xFFFF;
743246896Sluigi	}
744246896Sluigi	return sum;
745246896Sluigi}
746227614Sluigi
747341457Svmaffionestatic uint16_t
748341457Svmaffionewrapsum(uint32_t sum)
749246896Sluigi{
750246896Sluigi	sum = ~sum & 0xFFFF;
751246896Sluigi	return (htons(sum));
752227614Sluigi}
753227614Sluigi
754251426Sluigi/* Check the payload of the packet for errors (use it for debug).
755251426Sluigi * Look for consecutive ascii representations of the size of the packet.
756251426Sluigi */
757251426Sluigistatic void
758341457Svmaffionedump_payload(const char *_p, int len, struct netmap_ring *ring, int cur)
759251426Sluigi{
760251426Sluigi	char buf[128];
761251426Sluigi	int i, j, i0;
762341457Svmaffione	const unsigned char *p = (const unsigned char *)_p;
763251426Sluigi
764251426Sluigi	/* get the length in ASCII of the length of the packet. */
765261909Sluigi
766257529Sluigi	printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n",
767257529Sluigi		ring, cur, ring->slot[cur].buf_idx,
768257529Sluigi		ring->slot[cur].flags, len);
769251426Sluigi	/* hexdump routine */
770251426Sluigi	for (i = 0; i < len; ) {
771341457Svmaffione		memset(buf, ' ', sizeof(buf));
772251426Sluigi		sprintf(buf, "%5d: ", i);
773251426Sluigi		i0 = i;
774251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
775251426Sluigi			sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
776251426Sluigi		i = i0;
777251426Sluigi		for (j=0; j < 16 && i < len; i++, j++)
778251426Sluigi			sprintf(buf+7+j + 48, "%c",
779251426Sluigi				isprint(p[i]) ? p[i] : '.');
780251426Sluigi		printf("%s\n", buf);
781251426Sluigi	}
782251426Sluigi}
783251426Sluigi
784227614Sluigi/*
785227614Sluigi * Fill a packet with some payload.
786246896Sluigi * We create a UDP packet so the payload starts at
787246896Sluigi *	14+20+8 = 42 bytes.
788227614Sluigi */
789246896Sluigi#ifdef __linux__
790246896Sluigi#define uh_sport source
791246896Sluigi#define uh_dport dest
792246896Sluigi#define uh_ulen len
793246896Sluigi#define uh_sum check
794246896Sluigi#endif /* linux */
795251426Sluigi
796227614Sluigistatic void
797341457Svmaffioneupdate_ip(struct pkt *pkt, struct targ *t)
798257529Sluigi{
799341457Svmaffione	struct glob_arg *g = t->g;
800341457Svmaffione	struct ip ip;
801341457Svmaffione	struct udphdr udp;
802341457Svmaffione	uint32_t oaddr, naddr;
803341457Svmaffione	uint16_t oport, nport;
804341457Svmaffione	uint16_t ip_sum, udp_sum;
805257529Sluigi
806341457Svmaffione	memcpy(&ip, &pkt->ipv4.ip, sizeof(ip));
807341457Svmaffione	memcpy(&udp, &pkt->ipv4.udp, sizeof(udp));
808341457Svmaffione	do {
809341457Svmaffione		ip_sum = udp_sum = 0;
810341457Svmaffione		naddr = oaddr = ntohl(ip.ip_src.s_addr);
811341457Svmaffione		nport = oport = ntohs(udp.uh_sport);
812341457Svmaffione		if (g->options & OPT_RANDOM_SRC) {
813341457Svmaffione			ip.ip_src.s_addr = nrand48(t->seed);
814341457Svmaffione			udp.uh_sport = nrand48(t->seed);
815341457Svmaffione			naddr = ntohl(ip.ip_src.s_addr);
816341457Svmaffione			nport = ntohs(udp.uh_sport);
817281746Sadrian			break;
818281746Sadrian		}
819341457Svmaffione		if (oport < g->src_ip.port1) {
820341457Svmaffione			nport = oport + 1;
821341457Svmaffione			udp.uh_sport = htons(nport);
822281746Sadrian			break;
823281746Sadrian		}
824341457Svmaffione		nport = g->src_ip.port0;
825341457Svmaffione		udp.uh_sport = htons(nport);
826341457Svmaffione		if (oaddr < g->src_ip.ipv4.end) {
827341457Svmaffione			naddr = oaddr + 1;
828341457Svmaffione			ip.ip_src.s_addr = htonl(naddr);
829341457Svmaffione			break;
830341457Svmaffione		}
831341457Svmaffione		naddr = g->src_ip.ipv4.start;
832341457Svmaffione		ip.ip_src.s_addr = htonl(naddr);
833341457Svmaffione	} while (0);
834341457Svmaffione	/* update checksums if needed */
835341457Svmaffione	if (oaddr != naddr) {
836341457Svmaffione		ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
837341457Svmaffione		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
838341457Svmaffione		ip_sum = cksum_add(ip_sum, naddr >> 16);
839341457Svmaffione		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
840257529Sluigi	}
841341457Svmaffione	if (oport != nport) {
842341457Svmaffione		udp_sum = cksum_add(udp_sum, ~oport);
843341457Svmaffione		udp_sum = cksum_add(udp_sum, nport);
844341457Svmaffione	}
845341457Svmaffione	do {
846341457Svmaffione		naddr = oaddr = ntohl(ip.ip_dst.s_addr);
847341457Svmaffione		nport = oport = ntohs(udp.uh_dport);
848341457Svmaffione		if (g->options & OPT_RANDOM_DST) {
849341457Svmaffione			ip.ip_dst.s_addr = nrand48(t->seed);
850341457Svmaffione			udp.uh_dport = nrand48(t->seed);
851341457Svmaffione			naddr = ntohl(ip.ip_dst.s_addr);
852341457Svmaffione			nport = ntohs(udp.uh_dport);
853281746Sadrian			break;
854281746Sadrian		}
855341457Svmaffione		if (oport < g->dst_ip.port1) {
856341457Svmaffione			nport = oport + 1;
857341457Svmaffione			udp.uh_dport = htons(nport);
858281746Sadrian			break;
859281746Sadrian		}
860341457Svmaffione		nport = g->dst_ip.port0;
861341457Svmaffione		udp.uh_dport = htons(nport);
862341457Svmaffione		if (oaddr < g->dst_ip.ipv4.end) {
863341457Svmaffione			naddr = oaddr + 1;
864341457Svmaffione			ip.ip_dst.s_addr = htonl(naddr);
865341457Svmaffione			break;
866341457Svmaffione		}
867341457Svmaffione		naddr = g->dst_ip.ipv4.start;
868341457Svmaffione		ip.ip_dst.s_addr = htonl(naddr);
869341457Svmaffione	} while (0);
870341457Svmaffione	/* update checksums */
871341457Svmaffione	if (oaddr != naddr) {
872341457Svmaffione		ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
873341457Svmaffione		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
874341457Svmaffione		ip_sum = cksum_add(ip_sum, naddr >> 16);
875341457Svmaffione		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
876257529Sluigi	}
877341457Svmaffione	if (oport != nport) {
878341457Svmaffione		udp_sum = cksum_add(udp_sum, ~oport);
879341457Svmaffione		udp_sum = cksum_add(udp_sum, nport);
880341457Svmaffione	}
881341457Svmaffione	if (udp_sum != 0)
882341457Svmaffione		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum));
883341457Svmaffione	if (ip_sum != 0) {
884341457Svmaffione		ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum));
885341457Svmaffione		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum));
886341457Svmaffione	}
887341457Svmaffione	memcpy(&pkt->ipv4.ip, &ip, sizeof(ip));
888341457Svmaffione	memcpy(&pkt->ipv4.udp, &udp, sizeof(udp));
889257529Sluigi}
890257529Sluigi
891341457Svmaffione#ifndef s6_addr16
892341457Svmaffione#define	s6_addr16	__u6_addr.__u6_addr16
893341457Svmaffione#endif
894341457Svmaffionestatic void
895341457Svmaffioneupdate_ip6(struct pkt *pkt, struct targ *t)
896341457Svmaffione{
897341457Svmaffione	struct glob_arg *g = t->g;
898341457Svmaffione	struct ip6_hdr ip6;
899341457Svmaffione	struct udphdr udp;
900341457Svmaffione	uint16_t udp_sum;
901341457Svmaffione	uint16_t oaddr, naddr;
902341457Svmaffione	uint16_t oport, nport;
903341457Svmaffione	uint8_t group;
904341457Svmaffione
905341457Svmaffione	memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6));
906341457Svmaffione	memcpy(&udp, &pkt->ipv6.udp, sizeof(udp));
907341457Svmaffione	do {
908341457Svmaffione		udp_sum = 0;
909341457Svmaffione		group = g->src_ip.ipv6.sgroup;
910341457Svmaffione		naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]);
911341457Svmaffione		nport = oport = ntohs(udp.uh_sport);
912341457Svmaffione		if (g->options & OPT_RANDOM_SRC) {
913341457Svmaffione			ip6.ip6_src.s6_addr16[group] = nrand48(t->seed);
914341457Svmaffione			udp.uh_sport = nrand48(t->seed);
915341457Svmaffione			naddr = ntohs(ip6.ip6_src.s6_addr16[group]);
916341457Svmaffione			nport = ntohs(udp.uh_sport);
917341457Svmaffione			break;
918341457Svmaffione		}
919341457Svmaffione		if (oport < g->src_ip.port1) {
920341457Svmaffione			nport = oport + 1;
921341457Svmaffione			udp.uh_sport = htons(nport);
922341457Svmaffione			break;
923341457Svmaffione		}
924341457Svmaffione		nport = g->src_ip.port0;
925341457Svmaffione		udp.uh_sport = htons(nport);
926341457Svmaffione		if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) {
927341457Svmaffione			naddr = oaddr + 1;
928341457Svmaffione			ip6.ip6_src.s6_addr16[group] = htons(naddr);
929341457Svmaffione			break;
930341457Svmaffione		}
931341457Svmaffione		naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]);
932341457Svmaffione		ip6.ip6_src.s6_addr16[group] = htons(naddr);
933341457Svmaffione	} while (0);
934341457Svmaffione	/* update checksums if needed */
935341457Svmaffione	if (oaddr != naddr)
936341457Svmaffione		udp_sum = cksum_add(~oaddr, naddr);
937341457Svmaffione	if (oport != nport)
938341457Svmaffione		udp_sum = cksum_add(udp_sum,
939341457Svmaffione		    cksum_add(~oport, nport));
940341457Svmaffione	do {
941341457Svmaffione		group = g->dst_ip.ipv6.egroup;
942341457Svmaffione		naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
943341457Svmaffione		nport = oport = ntohs(udp.uh_dport);
944341457Svmaffione		if (g->options & OPT_RANDOM_DST) {
945341457Svmaffione			ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed);
946341457Svmaffione			udp.uh_dport = nrand48(t->seed);
947341457Svmaffione			naddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
948341457Svmaffione			nport = ntohs(udp.uh_dport);
949341457Svmaffione			break;
950341457Svmaffione		}
951341457Svmaffione		if (oport < g->dst_ip.port1) {
952341457Svmaffione			nport = oport + 1;
953341457Svmaffione			udp.uh_dport = htons(nport);
954341457Svmaffione			break;
955341457Svmaffione		}
956341457Svmaffione		nport = g->dst_ip.port0;
957341457Svmaffione		udp.uh_dport = htons(nport);
958341457Svmaffione		if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) {
959341457Svmaffione			naddr = oaddr + 1;
960341457Svmaffione			ip6.ip6_dst.s6_addr16[group] = htons(naddr);
961341457Svmaffione			break;
962341457Svmaffione		}
963341457Svmaffione		naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]);
964341457Svmaffione		ip6.ip6_dst.s6_addr16[group] = htons(naddr);
965341457Svmaffione	} while (0);
966341457Svmaffione	/* update checksums */
967341457Svmaffione	if (oaddr != naddr)
968341457Svmaffione		udp_sum = cksum_add(udp_sum,
969341457Svmaffione		    cksum_add(~oaddr, naddr));
970341457Svmaffione	if (oport != nport)
971341457Svmaffione		udp_sum = cksum_add(udp_sum,
972341457Svmaffione		    cksum_add(~oport, nport));
973341457Svmaffione	if (udp_sum != 0)
974341457Svmaffione		udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum);
975341457Svmaffione	memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6));
976341457Svmaffione	memcpy(&pkt->ipv6.udp, &udp, sizeof(udp));
977341457Svmaffione}
978341457Svmaffione
979341457Svmaffionestatic void
980341457Svmaffioneupdate_addresses(struct pkt *pkt, struct targ *t)
981341457Svmaffione{
982341457Svmaffione
983341457Svmaffione	if (t->g->af == AF_INET)
984341457Svmaffione		update_ip(pkt, t);
985341457Svmaffione	else
986341457Svmaffione		update_ip6(pkt, t);
987341457Svmaffione}
988257529Sluigi/*
989257529Sluigi * initialize one packet and prepare for the next one.
990257529Sluigi * The copy could be done better instead of repeating it each time.
991257529Sluigi */
992257529Sluigistatic void
993227614Sluigiinitialize_packet(struct targ *targ)
994227614Sluigi{
995227614Sluigi	struct pkt *pkt = &targ->pkt;
996227614Sluigi	struct ether_header *eh;
997341457Svmaffione	struct ip6_hdr ip6;
998341457Svmaffione	struct ip ip;
999341457Svmaffione	struct udphdr udp;
1000341457Svmaffione	void *udp_ptr;
1001341457Svmaffione	uint16_t paylen;
1002341457Svmaffione	uint32_t csum = 0;
1003251426Sluigi	const char *payload = targ->g->options & OPT_INDIRECT ?
1004257529Sluigi		indirect_payload : default_payload;
1005260700Sluigi	int i, l0 = strlen(payload);
1006227614Sluigi
1007341457Svmaffione#ifndef NO_PCAP
1008272962Sgnn	char errbuf[PCAP_ERRBUF_SIZE];
1009272962Sgnn	pcap_t *file;
1010272962Sgnn	struct pcap_pkthdr *header;
1011272962Sgnn	const unsigned char *packet;
1012341457Svmaffione
1013272962Sgnn	/* Read a packet from a PCAP file if asked. */
1014272962Sgnn	if (targ->g->packet_file != NULL) {
1015272962Sgnn		if ((file = pcap_open_offline(targ->g->packet_file,
1016272962Sgnn			    errbuf)) == NULL)
1017272962Sgnn			D("failed to open pcap file %s",
1018272962Sgnn			    targ->g->packet_file);
1019272962Sgnn		if (pcap_next_ex(file, &header, &packet) < 0)
1020272962Sgnn			D("failed to read packet from %s",
1021272962Sgnn			    targ->g->packet_file);
1022272962Sgnn		if ((targ->frame = malloc(header->caplen)) == NULL)
1023272962Sgnn			D("out of memory");
1024272962Sgnn		bcopy(packet, (unsigned char *)targ->frame, header->caplen);
1025272962Sgnn		targ->g->pkt_size = header->caplen;
1026272962Sgnn		pcap_close(file);
1027272962Sgnn		return;
1028272962Sgnn	}
1029341457Svmaffione#endif
1030272962Sgnn
1031341457Svmaffione	paylen = targ->g->pkt_size - sizeof(*eh) -
1032341457Svmaffione	    (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6));
1033341457Svmaffione
1034257529Sluigi	/* create a nice NUL-terminated string */
1035260700Sluigi	for (i = 0; i < paylen; i += l0) {
1036260700Sluigi		if (l0 > paylen - i)
1037260700Sluigi			l0 = paylen - i; // last round
1038341457Svmaffione		bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0);
1039227614Sluigi	}
1040341457Svmaffione	PKT(pkt, body, targ->g->af)[i - 1] = '\0';
1041227614Sluigi
1042257529Sluigi	/* prepare the headers */
1043227614Sluigi	eh = &pkt->eh;
1044246896Sluigi	bcopy(&targ->g->src_mac.start, eh->ether_shost, 6);
1045246896Sluigi	bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6);
1046260368Sluigi
1047341457Svmaffione	if (targ->g->af == AF_INET) {
1048341457Svmaffione		eh->ether_type = htons(ETHERTYPE_IP);
1049341457Svmaffione		memcpy(&ip, &pkt->ipv4.ip, sizeof(ip));
1050341457Svmaffione		udp_ptr = &pkt->ipv4.udp;
1051341457Svmaffione		ip.ip_v = IPVERSION;
1052341457Svmaffione		ip.ip_hl = sizeof(ip) >> 2;
1053341457Svmaffione		ip.ip_id = 0;
1054341457Svmaffione		ip.ip_tos = IPTOS_LOWDELAY;
1055341457Svmaffione		ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh));
1056341457Svmaffione		ip.ip_id = 0;
1057341457Svmaffione		ip.ip_off = htons(IP_DF); /* Don't fragment */
1058341457Svmaffione		ip.ip_ttl = IPDEFTTL;
1059341457Svmaffione		ip.ip_p = IPPROTO_UDP;
1060341457Svmaffione		ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start);
1061341457Svmaffione		ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start);
1062341457Svmaffione		ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0));
1063341457Svmaffione		memcpy(&pkt->ipv4.ip, &ip, sizeof(ip));
1064341457Svmaffione	} else {
1065341457Svmaffione		eh->ether_type = htons(ETHERTYPE_IPV6);
1066341457Svmaffione		memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6));
1067341457Svmaffione		udp_ptr = &pkt->ipv6.udp;
1068341457Svmaffione		ip6.ip6_flow = 0;
1069341457Svmaffione		ip6.ip6_plen = htons(paylen);
1070341457Svmaffione		ip6.ip6_vfc = IPV6_VERSION;
1071341457Svmaffione		ip6.ip6_nxt = IPPROTO_UDP;
1072341457Svmaffione		ip6.ip6_hlim = IPV6_DEFHLIM;
1073341457Svmaffione		ip6.ip6_src = targ->g->src_ip.ipv6.start;
1074341457Svmaffione		ip6.ip6_dst = targ->g->dst_ip.ipv6.start;
1075341457Svmaffione	}
1076341457Svmaffione	memcpy(&udp, udp_ptr, sizeof(udp));
1077341457Svmaffione
1078341457Svmaffione	udp.uh_sport = htons(targ->g->src_ip.port0);
1079341457Svmaffione	udp.uh_dport = htons(targ->g->dst_ip.port0);
1080341457Svmaffione	udp.uh_ulen = htons(paylen);
1081341457Svmaffione	if (targ->g->af == AF_INET) {
1082341457Svmaffione		/* Magic: taken from sbin/dhclient/packet.c */
1083341457Svmaffione		udp.uh_sum = wrapsum(
1084341457Svmaffione		    checksum(&udp, sizeof(udp),	/* udp header */
1085341457Svmaffione		    checksum(pkt->ipv4.body,	/* udp payload */
1086341457Svmaffione		    paylen - sizeof(udp),
1087341457Svmaffione		    checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */
1088341457Svmaffione			2 * sizeof(pkt->ipv4.ip.ip_src),
1089341457Svmaffione			IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen)))));
1090341457Svmaffione		memcpy(&pkt->ipv4.ip, &ip, sizeof(ip));
1091341457Svmaffione	} else {
1092341457Svmaffione		/* Save part of pseudo header checksum into csum */
1093341457Svmaffione		csum = IPPROTO_UDP << 24;
1094341457Svmaffione		csum = checksum(&csum, sizeof(csum), paylen);
1095341457Svmaffione		udp.uh_sum = wrapsum(
1096341457Svmaffione		    checksum(udp_ptr, sizeof(udp),	/* udp header */
1097341457Svmaffione		    checksum(pkt->ipv6.body,	/* udp payload */
1098341457Svmaffione		    paylen - sizeof(udp),
1099341457Svmaffione		    checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */
1100341457Svmaffione			2 * sizeof(pkt->ipv6.ip.ip6_src), csum))));
1101341457Svmaffione		memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6));
1102341457Svmaffione	}
1103341457Svmaffione	memcpy(udp_ptr, &udp, sizeof(udp));
1104341457Svmaffione
1105260368Sluigi	bzero(&pkt->vh, sizeof(pkt->vh));
1106251426Sluigi	// dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0);
1107227614Sluigi}
1108227614Sluigi
1109270063Sluigistatic void
1110341457Svmaffioneget_vnet_hdr_len(struct glob_arg *g)
1111270063Sluigi{
1112270063Sluigi	struct nmreq req;
1113341457Svmaffione	int err;
1114227614Sluigi
1115341457Svmaffione	memset(&req, 0, sizeof(req));
1116341457Svmaffione	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
1117341457Svmaffione	req.nr_version = NETMAP_API;
1118341457Svmaffione	req.nr_cmd = NETMAP_VNET_HDR_GET;
1119341457Svmaffione	err = ioctl(g->main_fd, NIOCREGIF, &req);
1120341457Svmaffione	if (err) {
1121341457Svmaffione		D("Unable to get virtio-net header length");
1122341457Svmaffione		return;
1123341457Svmaffione	}
1124341457Svmaffione
1125341457Svmaffione	g->virt_header = req.nr_arg1;
1126341457Svmaffione	if (g->virt_header) {
1127341457Svmaffione		D("Port requires virtio-net header, length = %d",
1128341457Svmaffione		  g->virt_header);
1129341457Svmaffione	}
1130341457Svmaffione}
1131341457Svmaffione
1132341457Svmaffionestatic void
1133341457Svmaffioneset_vnet_hdr_len(struct glob_arg *g)
1134341457Svmaffione{
1135341457Svmaffione	int err, l = g->virt_header;
1136341457Svmaffione	struct nmreq req;
1137341457Svmaffione
1138270063Sluigi	if (l == 0)
1139270063Sluigi		return;
1140227614Sluigi
1141270063Sluigi	memset(&req, 0, sizeof(req));
1142341457Svmaffione	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
1143270063Sluigi	req.nr_version = NETMAP_API;
1144270063Sluigi	req.nr_cmd = NETMAP_BDG_VNET_HDR;
1145270063Sluigi	req.nr_arg1 = l;
1146341457Svmaffione	err = ioctl(g->main_fd, NIOCREGIF, &req);
1147270063Sluigi	if (err) {
1148341457Svmaffione		D("Unable to set virtio-net header length %d", l);
1149270063Sluigi	}
1150270063Sluigi}
1151270063Sluigi
1152227614Sluigi/*
1153227614Sluigi * create and enqueue a batch of packets on a ring.
1154227614Sluigi * On the last one set NS_REPORT to tell the driver to generate
1155227614Sluigi * an interrupt when done.
1156227614Sluigi */
1157227614Sluigistatic int
1158260368Sluigisend_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
1159341457Svmaffione		int size, struct targ *t, u_int count, int options)
1160227614Sluigi{
1161344918Svmaffione	u_int n, sent, head = ring->head;
1162341457Svmaffione	u_int frags = t->frags;
1163341457Svmaffione	u_int frag_size = t->frag_size;
1164344918Svmaffione	struct netmap_slot *slot = &ring->slot[head];
1165227614Sluigi
1166260368Sluigi	n = nm_ring_space(ring);
1167234956Sluigi#if 0
1168234956Sluigi	if (options & (OPT_COPY | OPT_PREFETCH) ) {
1169234956Sluigi		for (sent = 0; sent < count; sent++) {
1170344918Svmaffione			struct netmap_slot *slot = &ring->slot[head];
1171234956Sluigi			char *p = NETMAP_BUF(ring, slot->buf_idx);
1172234956Sluigi
1173260700Sluigi			__builtin_prefetch(p);
1174344918Svmaffione			head = nm_ring_next(ring, head);
1175234956Sluigi		}
1176344918Svmaffione		head = ring->head;
1177234956Sluigi	}
1178234956Sluigi#endif
1179341457Svmaffione	for (sent = 0; sent < count && n >= frags; sent++, n--) {
1180341457Svmaffione		char *p;
1181341457Svmaffione		int buf_changed;
1182341457Svmaffione		u_int tosend = size;
1183227614Sluigi
1184344918Svmaffione		slot = &ring->slot[head];
1185341457Svmaffione		p = NETMAP_BUF(ring, slot->buf_idx);
1186341457Svmaffione		buf_changed = slot->flags & NS_BUF_CHANGED;
1187341457Svmaffione
1188251426Sluigi		slot->flags = 0;
1189341457Svmaffione		if (options & OPT_RUBBISH) {
1190341457Svmaffione			/* do nothing */
1191341457Svmaffione		} else if (options & OPT_INDIRECT) {
1192251426Sluigi			slot->flags |= NS_INDIRECT;
1193341457Svmaffione			slot->ptr = (uint64_t)((uintptr_t)frame);
1194341457Svmaffione		} else if (frags > 1) {
1195341457Svmaffione			u_int i;
1196341457Svmaffione			const char *f = frame;
1197341457Svmaffione			char *fp = p;
1198341457Svmaffione			for (i = 0; i < frags - 1; i++) {
1199341457Svmaffione				memcpy(fp, f, frag_size);
1200341457Svmaffione				slot->len = frag_size;
1201341457Svmaffione				slot->flags = NS_MOREFRAG;
1202341457Svmaffione				if (options & OPT_DUMP)
1203344918Svmaffione					dump_payload(fp, frag_size, ring, head);
1204341457Svmaffione				tosend -= frag_size;
1205341457Svmaffione				f += frag_size;
1206344918Svmaffione				head = nm_ring_next(ring, head);
1207344918Svmaffione				slot = &ring->slot[head];
1208341457Svmaffione				fp = NETMAP_BUF(ring, slot->buf_idx);
1209341457Svmaffione			}
1210341457Svmaffione			n -= (frags - 1);
1211341457Svmaffione			p = fp;
1212341457Svmaffione			slot->flags = 0;
1213341457Svmaffione			memcpy(p, f, tosend);
1214341457Svmaffione			update_addresses(pkt, t);
1215341457Svmaffione		} else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) {
1216341457Svmaffione			if (options & OPT_COPY)
1217341457Svmaffione				nm_pkt_copy(frame, p, size);
1218341457Svmaffione			else
1219341457Svmaffione				memcpy(p, frame, size);
1220341457Svmaffione			update_addresses(pkt, t);
1221257529Sluigi		} else if (options & OPT_PREFETCH) {
1222260700Sluigi			__builtin_prefetch(p);
1223257529Sluigi		}
1224341457Svmaffione		slot->len = tosend;
1225257529Sluigi		if (options & OPT_DUMP)
1226344918Svmaffione			dump_payload(p, tosend, ring, head);
1227344918Svmaffione		head = nm_ring_next(ring, head);
1228227614Sluigi	}
1229341457Svmaffione	if (sent) {
1230341457Svmaffione		slot->flags |= NS_REPORT;
1231344918Svmaffione		ring->head = ring->cur = head;
1232341457Svmaffione	}
1233341457Svmaffione	if (sent < count) {
1234341457Svmaffione		/* tell netmap that we need more slots */
1235341457Svmaffione		ring->cur = ring->tail;
1236341457Svmaffione	}
1237227614Sluigi
1238227614Sluigi	return (sent);
1239227614Sluigi}
1240227614Sluigi
1241246896Sluigi/*
1242341457Svmaffione * Index of the highest bit set
1243341457Svmaffione */
1244341457Svmaffioneuint32_t
1245341457Svmaffionemsb64(uint64_t x)
1246341457Svmaffione{
1247341457Svmaffione	uint64_t m = 1ULL << 63;
1248341457Svmaffione	int i;
1249341457Svmaffione
1250341457Svmaffione	for (i = 63; i >= 0; i--, m >>=1)
1251341457Svmaffione		if (m & x)
1252341457Svmaffione			return i;
1253341457Svmaffione	return 0;
1254341457Svmaffione}
1255341457Svmaffione
1256341457Svmaffione/*
1257341457Svmaffione * wait until ts, either busy or sleeping if more than 1ms.
1258341457Svmaffione * Return wakeup time.
1259341457Svmaffione */
1260341457Svmaffionestatic struct timespec
1261341457Svmaffionewait_time(struct timespec ts)
1262341457Svmaffione{
1263341457Svmaffione	for (;;) {
1264341457Svmaffione		struct timespec w, cur;
1265341457Svmaffione		clock_gettime(CLOCK_REALTIME_PRECISE, &cur);
1266341457Svmaffione		w = timespec_sub(ts, cur);
1267341457Svmaffione		if (w.tv_sec < 0)
1268341457Svmaffione			return cur;
1269341457Svmaffione		else if (w.tv_sec > 0 || w.tv_nsec > 1000000)
1270341457Svmaffione			poll(NULL, 0, 1);
1271341457Svmaffione	}
1272341457Svmaffione}
1273341457Svmaffione
1274341457Svmaffione/*
1275246896Sluigi * Send a packet, and wait for a response.
1276246896Sluigi * The payload (after UDP header, ofs 42) has a 4-byte sequence
1277246896Sluigi * followed by a struct timeval (or bintime?)
1278246896Sluigi */
1279246896Sluigi
1280227614Sluigistatic void *
1281341457Svmaffioneping_body(void *data)
1282246896Sluigi{
1283246896Sluigi	struct targ *targ = (struct targ *) data;
1284261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
1285261909Sluigi	struct netmap_if *nifp = targ->nmd->nifp;
1286341457Svmaffione	int i, m, rx = 0;
1287260368Sluigi	void *frame;
1288260368Sluigi	int size;
1289261909Sluigi	struct timespec ts, now, last_print;
1290341457Svmaffione	struct timespec nexttime = {0, 0}; /* silence compiler */
1291341457Svmaffione	uint64_t sent = 0, n = targ->g->npackets;
1292341457Svmaffione	uint64_t count = 0, t_cur, t_min = ~0, av = 0;
1293341457Svmaffione	uint64_t g_min = ~0, g_av = 0;
1294341457Svmaffione	uint64_t buckets[64];	/* bins for delays, ns */
1295341457Svmaffione	int rate_limit = targ->g->tx_rate, tosend = 0;
1296246896Sluigi
1297341457Svmaffione	frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header;
1298260368Sluigi	size = targ->g->pkt_size + targ->g->virt_header;
1299260368Sluigi
1300341457Svmaffione
1301246896Sluigi	if (targ->g->nthreads > 1) {
1302246896Sluigi		D("can only ping with 1 thread");
1303246896Sluigi		return NULL;
1304246896Sluigi	}
1305246896Sluigi
1306341457Svmaffione	bzero(&buckets, sizeof(buckets));
1307246896Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &last_print);
1308260368Sluigi	now = last_print;
1309341457Svmaffione	if (rate_limit) {
1310341457Svmaffione		targ->tic = timespec_add(now, (struct timespec){2,0});
1311341457Svmaffione		targ->tic.tv_nsec = 0;
1312341457Svmaffione		wait_time(targ->tic);
1313341457Svmaffione		nexttime = targ->tic;
1314341457Svmaffione	}
1315341457Svmaffione	while (!targ->cancel && (n == 0 || sent < n)) {
1316341457Svmaffione		struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
1317246896Sluigi		struct netmap_slot *slot;
1318246896Sluigi		char *p;
1319341457Svmaffione		int rv;
1320341457Svmaffione		uint64_t limit, event = 0;
1321246896Sluigi
1322341457Svmaffione		if (rate_limit && tosend <= 0) {
1323341457Svmaffione			tosend = targ->g->burst;
1324341457Svmaffione			nexttime = timespec_add(nexttime, targ->g->tx_period);
1325341457Svmaffione			wait_time(nexttime);
1326246896Sluigi		}
1327341457Svmaffione
1328341457Svmaffione		limit = rate_limit ? tosend : targ->g->burst;
1329341457Svmaffione		if (n > 0 && n - sent < limit)
1330341457Svmaffione			limit = n - sent;
1331341457Svmaffione		for (m = 0; (unsigned)m < limit; m++) {
1332344918Svmaffione			slot = &ring->slot[ring->head];
1333341457Svmaffione			slot->len = size;
1334341457Svmaffione			p = NETMAP_BUF(ring, slot->buf_idx);
1335341457Svmaffione
1336341457Svmaffione			if (nm_ring_empty(ring)) {
1337341457Svmaffione				D("-- ouch, cannot send");
1338341457Svmaffione				break;
1339341457Svmaffione			} else {
1340341457Svmaffione				struct tstamp *tp;
1341341457Svmaffione				nm_pkt_copy(frame, p, size);
1342341457Svmaffione				clock_gettime(CLOCK_REALTIME_PRECISE, &ts);
1343341457Svmaffione				bcopy(&sent, p+42, sizeof(sent));
1344341457Svmaffione				tp = (struct tstamp *)(p+46);
1345341457Svmaffione				tp->sec = (uint32_t)ts.tv_sec;
1346341457Svmaffione				tp->nsec = (uint32_t)ts.tv_nsec;
1347341457Svmaffione				sent++;
1348344918Svmaffione				ring->head = ring->cur = nm_ring_next(ring, ring->head);
1349341457Svmaffione			}
1350341457Svmaffione		}
1351341457Svmaffione		if (m > 0)
1352341457Svmaffione			event++;
1353341457Svmaffione		targ->ctr.pkts = sent;
1354341457Svmaffione		targ->ctr.bytes = sent*size;
1355341457Svmaffione		targ->ctr.events = event;
1356341457Svmaffione		if (rate_limit)
1357341457Svmaffione			tosend -= m;
1358341457Svmaffione#ifdef BUSYWAIT
1359341457Svmaffione		rv = ioctl(pfd.fd, NIOCTXSYNC, NULL);
1360341457Svmaffione		if (rv < 0) {
1361341457Svmaffione			D("TXSYNC error on queue %d: %s", targ->me,
1362341457Svmaffione				strerror(errno));
1363341457Svmaffione		}
1364341457Svmaffione	again:
1365341457Svmaffione		ioctl(pfd.fd, NIOCRXSYNC, NULL);
1366341457Svmaffione#else
1367246896Sluigi		/* should use a parameter to decide how often to send */
1368341457Svmaffione		if ( (rv = poll(&pfd, 1, 3000)) <= 0) {
1369341457Svmaffione			D("poll error on queue %d: %s", targ->me,
1370341457Svmaffione				(rv ? strerror(errno) : "timeout"));
1371246896Sluigi			continue;
1372246896Sluigi		}
1373341457Svmaffione#endif /* BUSYWAIT */
1374246896Sluigi		/* see what we got back */
1375341457Svmaffione		rx = 0;
1376341457Svmaffione		for (i = targ->nmd->first_rx_ring;
1377341457Svmaffione			i <= targ->nmd->last_rx_ring; i++) {
1378246896Sluigi			ring = NETMAP_RXRING(nifp, i);
1379260368Sluigi			while (!nm_ring_empty(ring)) {
1380246896Sluigi				uint32_t seq;
1381270063Sluigi				struct tstamp *tp;
1382341457Svmaffione				int pos;
1383341457Svmaffione
1384344918Svmaffione				slot = &ring->slot[ring->head];
1385246896Sluigi				p = NETMAP_BUF(ring, slot->buf_idx);
1386246896Sluigi
1387246896Sluigi				clock_gettime(CLOCK_REALTIME_PRECISE, &now);
1388246896Sluigi				bcopy(p+42, &seq, sizeof(seq));
1389270063Sluigi				tp = (struct tstamp *)(p+46);
1390270063Sluigi				ts.tv_sec = (time_t)tp->sec;
1391270063Sluigi				ts.tv_nsec = (long)tp->nsec;
1392246896Sluigi				ts.tv_sec = now.tv_sec - ts.tv_sec;
1393246896Sluigi				ts.tv_nsec = now.tv_nsec - ts.tv_nsec;
1394246896Sluigi				if (ts.tv_nsec < 0) {
1395246896Sluigi					ts.tv_nsec += 1000000000;
1396246896Sluigi					ts.tv_sec--;
1397246896Sluigi				}
1398341457Svmaffione				if (0) D("seq %d/%llu delta %d.%09d", seq,
1399341457Svmaffione					(unsigned long long)sent,
1400246896Sluigi					(int)ts.tv_sec, (int)ts.tv_nsec);
1401341457Svmaffione				t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec;
1402341457Svmaffione				if (t_cur < t_min)
1403341457Svmaffione					t_min = t_cur;
1404246896Sluigi				count ++;
1405341457Svmaffione				av += t_cur;
1406341457Svmaffione				pos = msb64(t_cur);
1407341457Svmaffione				buckets[pos]++;
1408341457Svmaffione				/* now store it in a bucket */
1409344918Svmaffione				ring->head = ring->cur = nm_ring_next(ring, ring->head);
1410246896Sluigi				rx++;
1411246896Sluigi			}
1412246896Sluigi		}
1413246896Sluigi		//D("tx %d rx %d", sent, rx);
1414246896Sluigi		//usleep(100000);
1415246896Sluigi		ts.tv_sec = now.tv_sec - last_print.tv_sec;
1416246896Sluigi		ts.tv_nsec = now.tv_nsec - last_print.tv_nsec;
1417246896Sluigi		if (ts.tv_nsec < 0) {
1418246896Sluigi			ts.tv_nsec += 1000000000;
1419246896Sluigi			ts.tv_sec--;
1420246896Sluigi		}
1421246896Sluigi		if (ts.tv_sec >= 1) {
1422341457Svmaffione			D("count %d RTT: min %d av %d ns",
1423341457Svmaffione				(int)count, (int)t_min, (int)(av/count));
1424341457Svmaffione			int k, j, kmin, off;
1425341457Svmaffione			char buf[512];
1426341457Svmaffione
1427341457Svmaffione			for (kmin = 0; kmin < 64; kmin ++)
1428341457Svmaffione				if (buckets[kmin])
1429341457Svmaffione					break;
1430341457Svmaffione			for (k = 63; k >= kmin; k--)
1431341457Svmaffione				if (buckets[k])
1432341457Svmaffione					break;
1433341457Svmaffione			buf[0] = '\0';
1434341457Svmaffione			off = 0;
1435341457Svmaffione			for (j = kmin; j <= k; j++) {
1436341457Svmaffione				off += sprintf(buf + off, " %5d", (int)buckets[j]);
1437341457Svmaffione			}
1438341457Svmaffione			D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf);
1439341457Svmaffione			bzero(&buckets, sizeof(buckets));
1440246896Sluigi			count = 0;
1441341457Svmaffione			g_av += av;
1442246896Sluigi			av = 0;
1443341457Svmaffione			if (t_min < g_min)
1444341457Svmaffione				g_min = t_min;
1445341457Svmaffione			t_min = ~0;
1446246896Sluigi			last_print = now;
1447246896Sluigi		}
1448341457Svmaffione#ifdef BUSYWAIT
1449341457Svmaffione		if (rx < m && ts.tv_sec <= 3 && !targ->cancel)
1450341457Svmaffione			goto again;
1451341457Svmaffione#endif /* BUSYWAIT */
1452246896Sluigi	}
1453341457Svmaffione
1454341457Svmaffione	if (sent > 0) {
1455341457Svmaffione		D("RTT over %llu packets: min %d av %d ns",
1456341457Svmaffione			(long long unsigned)sent, (int)g_min,
1457341457Svmaffione			(int)((double)g_av/sent));
1458341457Svmaffione	}
1459341457Svmaffione	targ->completed = 1;
1460341457Svmaffione
1461341457Svmaffione	/* reset the ``used`` flag. */
1462341457Svmaffione	targ->used = 0;
1463341457Svmaffione
1464246896Sluigi	return NULL;
1465246896Sluigi}
1466246896Sluigi
1467246896Sluigi
1468246896Sluigi/*
1469246896Sluigi * reply to ping requests
1470246896Sluigi */
1471246896Sluigistatic void *
1472341457Svmaffionepong_body(void *data)
1473246896Sluigi{
1474246896Sluigi	struct targ *targ = (struct targ *) data;
1475261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
1476261909Sluigi	struct netmap_if *nifp = targ->nmd->nifp;
1477246896Sluigi	struct netmap_ring *txring, *rxring;
1478341457Svmaffione	int i, rx = 0;
1479341457Svmaffione	uint64_t sent = 0, n = targ->g->npackets;
1480246896Sluigi
1481246896Sluigi	if (targ->g->nthreads > 1) {
1482246896Sluigi		D("can only reply ping with 1 thread");
1483246896Sluigi		return NULL;
1484246896Sluigi	}
1485341457Svmaffione	if (n > 0)
1486341457Svmaffione		D("understood ponger %llu but don't know how to do it",
1487341457Svmaffione			(unsigned long long)n);
1488341457Svmaffione	while (!targ->cancel && (n == 0 || sent < n)) {
1489344918Svmaffione		uint32_t txhead, txavail;
1490246896Sluigi//#define BUSYWAIT
1491246896Sluigi#ifdef BUSYWAIT
1492261909Sluigi		ioctl(pfd.fd, NIOCRXSYNC, NULL);
1493246896Sluigi#else
1494341457Svmaffione		int rv;
1495341457Svmaffione		if ( (rv = poll(&pfd, 1, 1000)) <= 0) {
1496341457Svmaffione			D("poll error on queue %d: %s", targ->me,
1497341457Svmaffione				rv ? strerror(errno) : "timeout");
1498246896Sluigi			continue;
1499246896Sluigi		}
1500246896Sluigi#endif
1501341457Svmaffione		txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
1502344918Svmaffione		txhead = txring->head;
1503260368Sluigi		txavail = nm_ring_space(txring);
1504246896Sluigi		/* see what we got back */
1505261909Sluigi		for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) {
1506246896Sluigi			rxring = NETMAP_RXRING(nifp, i);
1507260368Sluigi			while (!nm_ring_empty(rxring)) {
1508246896Sluigi				uint16_t *spkt, *dpkt;
1509344918Svmaffione				uint32_t head = rxring->head;
1510344918Svmaffione				struct netmap_slot *slot = &rxring->slot[head];
1511246896Sluigi				char *src, *dst;
1512246896Sluigi				src = NETMAP_BUF(rxring, slot->buf_idx);
1513246896Sluigi				//D("got pkt %p of size %d", src, slot->len);
1514344918Svmaffione				rxring->head = rxring->cur = nm_ring_next(rxring, head);
1515246896Sluigi				rx++;
1516246896Sluigi				if (txavail == 0)
1517246896Sluigi					continue;
1518246896Sluigi				dst = NETMAP_BUF(txring,
1519344918Svmaffione				    txring->slot[txhead].buf_idx);
1520246896Sluigi				/* copy... */
1521246896Sluigi				dpkt = (uint16_t *)dst;
1522246896Sluigi				spkt = (uint16_t *)src;
1523261909Sluigi				nm_pkt_copy(src, dst, slot->len);
1524341457Svmaffione				/* swap source and destination MAC */
1525246896Sluigi				dpkt[0] = spkt[3];
1526246896Sluigi				dpkt[1] = spkt[4];
1527246896Sluigi				dpkt[2] = spkt[5];
1528246896Sluigi				dpkt[3] = spkt[0];
1529246896Sluigi				dpkt[4] = spkt[1];
1530246896Sluigi				dpkt[5] = spkt[2];
1531344918Svmaffione				txring->slot[txhead].len = slot->len;
1532344918Svmaffione				txhead = nm_ring_next(txring, txhead);
1533246896Sluigi				txavail--;
1534246896Sluigi				sent++;
1535246896Sluigi			}
1536246896Sluigi		}
1537344918Svmaffione		txring->head = txring->cur = txhead;
1538341457Svmaffione		targ->ctr.pkts = sent;
1539246896Sluigi#ifdef BUSYWAIT
1540261909Sluigi		ioctl(pfd.fd, NIOCTXSYNC, NULL);
1541246896Sluigi#endif
1542246896Sluigi		//D("tx %d rx %d", sent, rx);
1543246896Sluigi	}
1544246896Sluigi
1545341457Svmaffione	targ->completed = 1;
1546246896Sluigi
1547341457Svmaffione	/* reset the ``used`` flag. */
1548341457Svmaffione	targ->used = 0;
1549251132Sluigi
1550341457Svmaffione	return NULL;
1551251132Sluigi}
1552251132Sluigi
1553251132Sluigi
1554246896Sluigistatic void *
1555227614Sluigisender_body(void *data)
1556227614Sluigi{
1557227614Sluigi	struct targ *targ = (struct targ *) data;
1558261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT };
1559270063Sluigi	struct netmap_if *nifp;
1560341457Svmaffione	struct netmap_ring *txring = NULL;
1561341457Svmaffione	int i;
1562341457Svmaffione	uint64_t n = targ->g->npackets / targ->g->nthreads;
1563341457Svmaffione	uint64_t sent = 0;
1564341457Svmaffione	uint64_t event = 0;
1565234956Sluigi	int options = targ->g->options | OPT_COPY;
1566260368Sluigi	struct timespec nexttime = { 0, 0}; // XXX silence compiler
1567251132Sluigi	int rate_limit = targ->g->tx_rate;
1568260368Sluigi	struct pkt *pkt = &targ->pkt;
1569260368Sluigi	void *frame;
1570260368Sluigi	int size;
1571251426Sluigi
1572272962Sgnn	if (targ->frame == NULL) {
1573341457Svmaffione		frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header;
1574272962Sgnn		size = targ->g->pkt_size + targ->g->virt_header;
1575272962Sgnn	} else {
1576272962Sgnn		frame = targ->frame;
1577272962Sgnn		size = targ->g->pkt_size;
1578272962Sgnn	}
1579341457Svmaffione
1580270063Sluigi	D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd);
1581227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
1582227614Sluigi		goto quit;
1583227614Sluigi
1584227614Sluigi	/* main loop.*/
1585251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1586251132Sluigi	if (rate_limit) {
1587260368Sluigi		targ->tic = timespec_add(targ->tic, (struct timespec){2,0});
1588251132Sluigi		targ->tic.tv_nsec = 0;
1589260368Sluigi		wait_time(targ->tic);
1590251132Sluigi		nexttime = targ->tic;
1591251132Sluigi	}
1592341457Svmaffione	if (targ->g->dev_type == DEV_TAP) {
1593260700Sluigi	    D("writing to file desc %d", targ->g->main_fd);
1594246896Sluigi
1595246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
1596260700Sluigi		if (write(targ->g->main_fd, frame, size) != -1)
1597234956Sluigi			sent++;
1598341457Svmaffione		update_addresses(pkt, targ);
1599234956Sluigi		if (i > 10000) {
1600341457Svmaffione			targ->ctr.pkts = sent;
1601341457Svmaffione			targ->ctr.bytes = sent*size;
1602341457Svmaffione			targ->ctr.events = sent;
1603234956Sluigi			i = 0;
1604234956Sluigi		}
1605246896Sluigi	    }
1606260700Sluigi#ifndef NO_PCAP
1607260700Sluigi    } else if (targ->g->dev_type == DEV_PCAP) {
1608260700Sluigi	    pcap_t *p = targ->g->p;
1609246896Sluigi
1610246896Sluigi	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
1611260700Sluigi		if (pcap_inject(p, frame, size) != -1)
1612246896Sluigi			sent++;
1613341457Svmaffione		update_addresses(pkt, targ);
1614246896Sluigi		if (i > 10000) {
1615341457Svmaffione			targ->ctr.pkts = sent;
1616341457Svmaffione			targ->ctr.bytes = sent*size;
1617341457Svmaffione			targ->ctr.events = sent;
1618246896Sluigi			i = 0;
1619246896Sluigi		}
1620246896Sluigi	    }
1621260700Sluigi#endif /* NO_PCAP */
1622227614Sluigi    } else {
1623251132Sluigi	int tosend = 0;
1624342035Svmaffione	u_int bufsz, frag_size = targ->g->frag_size;
1625257529Sluigi
1626341457Svmaffione	nifp = targ->nmd->nifp;
1627341457Svmaffione	txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
1628341457Svmaffione	bufsz = txring->nr_buf_size;
1629342035Svmaffione	if (bufsz < frag_size)
1630342035Svmaffione		frag_size = bufsz;
1631341457Svmaffione	targ->frag_size = targ->g->pkt_size / targ->frags;
1632342035Svmaffione	if (targ->frag_size > frag_size) {
1633342035Svmaffione		targ->frags = targ->g->pkt_size / frag_size;
1634342035Svmaffione		targ->frag_size = frag_size;
1635342035Svmaffione		if (targ->g->pkt_size % frag_size != 0)
1636341457Svmaffione			targ->frags++;
1637341457Svmaffione	}
1638341457Svmaffione	D("frags %u frag_size %u", targ->frags, targ->frag_size);
1639246896Sluigi	while (!targ->cancel && (n == 0 || sent < n)) {
1640341457Svmaffione		int rv;
1641227614Sluigi
1642251132Sluigi		if (rate_limit && tosend <= 0) {
1643251132Sluigi			tosend = targ->g->burst;
1644260368Sluigi			nexttime = timespec_add(nexttime, targ->g->tx_period);
1645260368Sluigi			wait_time(nexttime);
1646251132Sluigi		}
1647251132Sluigi
1648227614Sluigi		/*
1649227614Sluigi		 * wait for available room in the send queue(s)
1650227614Sluigi		 */
1651341457Svmaffione#ifdef BUSYWAIT
1652341457Svmaffione		(void)rv;
1653341457Svmaffione		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
1654341457Svmaffione			D("ioctl error on queue %d: %s", targ->me,
1655341457Svmaffione					strerror(errno));
1656341457Svmaffione			goto quit;
1657341457Svmaffione		}
1658341457Svmaffione#else /* !BUSYWAIT */
1659341457Svmaffione		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
1660238165Semaste			if (targ->cancel)
1661238165Semaste				break;
1662341457Svmaffione			D("poll error on queue %d: %s", targ->me,
1663341457Svmaffione				rv ? strerror(errno) : "timeout");
1664261909Sluigi			// goto quit;
1665227614Sluigi		}
1666261909Sluigi		if (pfd.revents & POLLERR) {
1667341457Svmaffione			D("poll error on %d ring %d-%d", pfd.fd,
1668341457Svmaffione				targ->nmd->first_tx_ring, targ->nmd->last_tx_ring);
1669260368Sluigi			goto quit;
1670260368Sluigi		}
1671341457Svmaffione#endif /* !BUSYWAIT */
1672227614Sluigi		/*
1673227614Sluigi		 * scan our queues and send on those with room
1674227614Sluigi		 */
1675246896Sluigi		if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) {
1676246896Sluigi			D("drop copy");
1677234956Sluigi			options &= ~OPT_COPY;
1678246896Sluigi		}
1679261909Sluigi		for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
1680341457Svmaffione			int m;
1681341457Svmaffione			uint64_t limit = rate_limit ?  tosend : targ->g->burst;
1682341457Svmaffione
1683341457Svmaffione			if (n > 0 && n == sent)
1684341457Svmaffione				break;
1685341457Svmaffione
1686246896Sluigi			if (n > 0 && n - sent < limit)
1687246896Sluigi				limit = n - sent;
1688227614Sluigi			txring = NETMAP_TXRING(nifp, i);
1689260368Sluigi			if (nm_ring_empty(txring))
1690227614Sluigi				continue;
1691261909Sluigi
1692341457Svmaffione			if (targ->g->pkt_min_size > 0) {
1693341457Svmaffione				size = nrand48(targ->seed) %
1694341457Svmaffione					(targ->g->pkt_size - targ->g->pkt_min_size) +
1695341457Svmaffione					targ->g->pkt_min_size;
1696341457Svmaffione			}
1697341457Svmaffione			m = send_packets(txring, pkt, frame, size, targ,
1698341457Svmaffione					 limit, options);
1699341457Svmaffione			ND("limit %lu tail %d m %d",
1700341457Svmaffione				limit, txring->tail, m);
1701227614Sluigi			sent += m;
1702341457Svmaffione			if (m > 0) //XXX-ste: can m be 0?
1703341457Svmaffione				event++;
1704341457Svmaffione			targ->ctr.pkts = sent;
1705341457Svmaffione			targ->ctr.bytes += m*size;
1706341457Svmaffione			targ->ctr.events = event;
1707257529Sluigi			if (rate_limit) {
1708257529Sluigi				tosend -= m;
1709257529Sluigi				if (tosend <= 0)
1710257529Sluigi					break;
1711257529Sluigi			}
1712227614Sluigi		}
1713227614Sluigi	}
1714234956Sluigi	/* flush any remaining packets */
1715341457Svmaffione	if (txring != NULL) {
1716341457Svmaffione		D("flush tail %d head %d on thread %p",
1717341457Svmaffione			txring->tail, txring->head,
1718341457Svmaffione			(void *)pthread_self());
1719341457Svmaffione		ioctl(pfd.fd, NIOCTXSYNC, NULL);
1720341457Svmaffione	}
1721227614Sluigi
1722227614Sluigi	/* final part: wait all the TX queues to be empty. */
1723261909Sluigi	for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
1724227614Sluigi		txring = NETMAP_TXRING(nifp, i);
1725341457Svmaffione		while (!targ->cancel && nm_tx_pending(txring)) {
1726270063Sluigi			RD(5, "pending tx tail %d head %d on ring %d",
1727270063Sluigi				txring->tail, txring->head, i);
1728261909Sluigi			ioctl(pfd.fd, NIOCTXSYNC, NULL);
1729227614Sluigi			usleep(1); /* wait 1 tick */
1730227614Sluigi		}
1731227614Sluigi	}
1732260700Sluigi    } /* end DEV_NETMAP */
1733227614Sluigi
1734251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1735227614Sluigi	targ->completed = 1;
1736341457Svmaffione	targ->ctr.pkts = sent;
1737341457Svmaffione	targ->ctr.bytes = sent*size;
1738341457Svmaffione	targ->ctr.events = event;
1739227614Sluigiquit:
1740227614Sluigi	/* reset the ``used`` flag. */
1741227614Sluigi	targ->used = 0;
1742227614Sluigi
1743227614Sluigi	return (NULL);
1744227614Sluigi}
1745227614Sluigi
1746227614Sluigi
1747260700Sluigi#ifndef NO_PCAP
1748227614Sluigistatic void
1749246896Sluigireceive_pcap(u_char *user, const struct pcap_pkthdr * h,
1750246896Sluigi	const u_char * bytes)
1751227614Sluigi{
1752341457Svmaffione	struct my_ctrs *ctr = (struct my_ctrs *)user;
1753246896Sluigi	(void)bytes;	/* UNUSED */
1754341457Svmaffione	ctr->bytes += h->len;
1755341457Svmaffione	ctr->pkts++;
1756227614Sluigi}
1757260700Sluigi#endif /* !NO_PCAP */
1758227614Sluigi
1759341457Svmaffione
1760227614Sluigistatic int
1761341457Svmaffionereceive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes)
1762227614Sluigi{
1763344918Svmaffione	u_int head, rx, n;
1764341457Svmaffione	uint64_t b = 0;
1765341457Svmaffione	u_int complete = 0;
1766227614Sluigi
1767341457Svmaffione	if (bytes == NULL)
1768341457Svmaffione		bytes = &b;
1769341457Svmaffione
1770344918Svmaffione	head = ring->head;
1771260368Sluigi	n = nm_ring_space(ring);
1772260368Sluigi	if (n < limit)
1773260368Sluigi		limit = n;
1774227614Sluigi	for (rx = 0; rx < limit; rx++) {
1775344918Svmaffione		struct netmap_slot *slot = &ring->slot[head];
1776227614Sluigi		char *p = NETMAP_BUF(ring, slot->buf_idx);
1777227614Sluigi
1778341457Svmaffione		*bytes += slot->len;
1779251426Sluigi		if (dump)
1780344918Svmaffione			dump_payload(p, slot->len, ring, head);
1781341457Svmaffione		if (!(slot->flags & NS_MOREFRAG))
1782341457Svmaffione			complete++;
1783227614Sluigi
1784344918Svmaffione		head = nm_ring_next(ring, head);
1785227614Sluigi	}
1786344918Svmaffione	ring->head = ring->cur = head;
1787227614Sluigi
1788341457Svmaffione	return (complete);
1789227614Sluigi}
1790227614Sluigi
1791227614Sluigistatic void *
1792227614Sluigireceiver_body(void *data)
1793227614Sluigi{
1794227614Sluigi	struct targ *targ = (struct targ *) data;
1795261909Sluigi	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
1796270063Sluigi	struct netmap_if *nifp;
1797227614Sluigi	struct netmap_ring *rxring;
1798246896Sluigi	int i;
1799341457Svmaffione	struct my_ctrs cur;
1800227614Sluigi
1801341457Svmaffione	memset(&cur, 0, sizeof(cur));
1802341457Svmaffione
1803227614Sluigi	if (setaffinity(targ->thread, targ->affinity))
1804227614Sluigi		goto quit;
1805227614Sluigi
1806270063Sluigi	D("reading from %s fd %d main_fd %d",
1807270063Sluigi		targ->g->ifname, targ->fd, targ->g->main_fd);
1808227614Sluigi	/* unbounded wait for the first packet. */
1809270063Sluigi	for (;!targ->cancel;) {
1810261909Sluigi		i = poll(&pfd, 1, 1000);
1811261909Sluigi		if (i > 0 && !(pfd.revents & POLLERR))
1812227614Sluigi			break;
1813341457Svmaffione		if (i < 0) {
1814341457Svmaffione			D("poll() error: %s", strerror(errno));
1815341457Svmaffione			goto quit;
1816341457Svmaffione		}
1817341457Svmaffione		if (pfd.revents & POLLERR) {
1818341457Svmaffione			D("fd error");
1819341457Svmaffione			goto quit;
1820341457Svmaffione		}
1821261909Sluigi		RD(1, "waiting for initial packets, poll returns %d %d",
1822261909Sluigi			i, pfd.revents);
1823227614Sluigi	}
1824227614Sluigi	/* main loop, exit after 1s silence */
1825251132Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1826260700Sluigi    if (targ->g->dev_type == DEV_TAP) {
1827246896Sluigi	while (!targ->cancel) {
1828270063Sluigi		char buf[MAX_BODYSIZE];
1829246896Sluigi		/* XXX should we poll ? */
1830341457Svmaffione		i = read(targ->g->main_fd, buf, sizeof(buf));
1831341457Svmaffione		if (i > 0) {
1832341457Svmaffione			targ->ctr.pkts++;
1833341457Svmaffione			targ->ctr.bytes += i;
1834341457Svmaffione			targ->ctr.events++;
1835341457Svmaffione		}
1836246896Sluigi	}
1837260700Sluigi#ifndef NO_PCAP
1838260700Sluigi    } else if (targ->g->dev_type == DEV_PCAP) {
1839260700Sluigi	while (!targ->cancel) {
1840260700Sluigi		/* XXX should we poll ? */
1841270063Sluigi		pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap,
1842341457Svmaffione			(u_char *)&targ->ctr);
1843341457Svmaffione		targ->ctr.events++;
1844260700Sluigi	}
1845260700Sluigi#endif /* !NO_PCAP */
1846227614Sluigi    } else {
1847251426Sluigi	int dump = targ->g->options & OPT_DUMP;
1848270063Sluigi
1849341457Svmaffione	nifp = targ->nmd->nifp;
1850238165Semaste	while (!targ->cancel) {
1851227614Sluigi		/* Once we started to receive packets, wait at most 1 seconds
1852227614Sluigi		   before quitting. */
1853341457Svmaffione#ifdef BUSYWAIT
1854341457Svmaffione		if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) {
1855341457Svmaffione			D("ioctl error on queue %d: %s", targ->me,
1856341457Svmaffione					strerror(errno));
1857341457Svmaffione			goto quit;
1858341457Svmaffione		}
1859341457Svmaffione#else /* !BUSYWAIT */
1860261909Sluigi		if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) {
1861251132Sluigi			clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1862228975Suqs			targ->toc.tv_sec -= 1; /* Subtract timeout time. */
1863261909Sluigi			goto out;
1864227614Sluigi		}
1865227614Sluigi
1866261909Sluigi		if (pfd.revents & POLLERR) {
1867260368Sluigi			D("poll err");
1868260368Sluigi			goto quit;
1869260368Sluigi		}
1870341457Svmaffione#endif /* !BUSYWAIT */
1871341457Svmaffione		uint64_t cur_space = 0;
1872261909Sluigi		for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) {
1873227614Sluigi			int m;
1874227614Sluigi
1875227614Sluigi			rxring = NETMAP_RXRING(nifp, i);
1876341457Svmaffione			/* compute free space in the ring */
1877341457Svmaffione			m = rxring->head + rxring->num_slots - rxring->tail;
1878341457Svmaffione			if (m >= (int) rxring->num_slots)
1879341457Svmaffione				m -= rxring->num_slots;
1880341457Svmaffione			cur_space += m;
1881260368Sluigi			if (nm_ring_empty(rxring))
1882227614Sluigi				continue;
1883227614Sluigi
1884341457Svmaffione			m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes);
1885341457Svmaffione			cur.pkts += m;
1886341457Svmaffione			if (m > 0)
1887341457Svmaffione				cur.events++;
1888227614Sluigi		}
1889341457Svmaffione		cur.min_space = targ->ctr.min_space;
1890341457Svmaffione		if (cur_space < cur.min_space)
1891341457Svmaffione			cur.min_space = cur_space;
1892341457Svmaffione		targ->ctr = cur;
1893227614Sluigi	}
1894227614Sluigi    }
1895227614Sluigi
1896261909Sluigi	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
1897261909Sluigi
1898341457Svmaffione#if !defined(BUSYWAIT)
1899261909Sluigiout:
1900341457Svmaffione#endif
1901227614Sluigi	targ->completed = 1;
1902341457Svmaffione	targ->ctr = cur;
1903227614Sluigi
1904227614Sluigiquit:
1905227614Sluigi	/* reset the ``used`` flag. */
1906227614Sluigi	targ->used = 0;
1907227614Sluigi
1908227614Sluigi	return (NULL);
1909227614Sluigi}
1910227614Sluigi
1911341457Svmaffionestatic void *
1912341457Svmaffionetxseq_body(void *data)
1913238170Semaste{
1914341457Svmaffione	struct targ *targ = (struct targ *) data;
1915341457Svmaffione	struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT };
1916341457Svmaffione	struct netmap_ring *ring;
1917341457Svmaffione	int64_t sent = 0;
1918341457Svmaffione	uint64_t event = 0;
1919341457Svmaffione	int options = targ->g->options | OPT_COPY;
1920341457Svmaffione	struct timespec nexttime = {0, 0};
1921341457Svmaffione	int rate_limit = targ->g->tx_rate;
1922341457Svmaffione	struct pkt *pkt = &targ->pkt;
1923341457Svmaffione	int frags = targ->g->frags;
1924341457Svmaffione	uint32_t sequence = 0;
1925341457Svmaffione	int budget = 0;
1926341457Svmaffione	void *frame;
1927341457Svmaffione	int size;
1928238170Semaste
1929341457Svmaffione	if (targ->g->nthreads > 1) {
1930341457Svmaffione		D("can only txseq ping with 1 thread");
1931341457Svmaffione		return NULL;
1932341457Svmaffione	}
1933341457Svmaffione
1934341457Svmaffione	if (targ->g->npackets > 0) {
1935341457Svmaffione		D("Ignoring -n argument");
1936341457Svmaffione	}
1937341457Svmaffione
1938341457Svmaffione	frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header;
1939341457Svmaffione	size = targ->g->pkt_size + targ->g->virt_header;
1940341457Svmaffione
1941341457Svmaffione	D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd);
1942341457Svmaffione	if (setaffinity(targ->thread, targ->affinity))
1943341457Svmaffione		goto quit;
1944341457Svmaffione
1945341457Svmaffione	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
1946341457Svmaffione	if (rate_limit) {
1947341457Svmaffione		targ->tic = timespec_add(targ->tic, (struct timespec){2,0});
1948341457Svmaffione		targ->tic.tv_nsec = 0;
1949341457Svmaffione		wait_time(targ->tic);
1950341457Svmaffione		nexttime = targ->tic;
1951341457Svmaffione	}
1952341457Svmaffione
1953341457Svmaffione	/* Only use the first queue. */
1954341457Svmaffione	ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring);
1955341457Svmaffione
1956341457Svmaffione	while (!targ->cancel) {
1957341457Svmaffione		int64_t limit;
1958341457Svmaffione		unsigned int space;
1959341457Svmaffione		unsigned int head;
1960341457Svmaffione		int fcnt;
1961341457Svmaffione		uint16_t sum = 0;
1962341457Svmaffione		int rv;
1963341457Svmaffione
1964341457Svmaffione		if (!rate_limit) {
1965341457Svmaffione			budget = targ->g->burst;
1966341457Svmaffione
1967341457Svmaffione		} else if (budget <= 0) {
1968341457Svmaffione			budget = targ->g->burst;
1969341457Svmaffione			nexttime = timespec_add(nexttime, targ->g->tx_period);
1970341457Svmaffione			wait_time(nexttime);
1971341457Svmaffione		}
1972341457Svmaffione
1973341457Svmaffione		/* wait for available room in the send queue */
1974341457Svmaffione#ifdef BUSYWAIT
1975341457Svmaffione		(void)rv;
1976341457Svmaffione		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
1977341457Svmaffione			D("ioctl error on queue %d: %s", targ->me,
1978341457Svmaffione					strerror(errno));
1979341457Svmaffione			goto quit;
1980341457Svmaffione		}
1981341457Svmaffione#else /* !BUSYWAIT */
1982341457Svmaffione		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
1983341457Svmaffione			if (targ->cancel)
1984341457Svmaffione				break;
1985341457Svmaffione			D("poll error on queue %d: %s", targ->me,
1986341457Svmaffione				rv ? strerror(errno) : "timeout");
1987341457Svmaffione			// goto quit;
1988341457Svmaffione		}
1989341457Svmaffione		if (pfd.revents & POLLERR) {
1990341457Svmaffione			D("poll error on %d ring %d-%d", pfd.fd,
1991341457Svmaffione				targ->nmd->first_tx_ring, targ->nmd->last_tx_ring);
1992341457Svmaffione			goto quit;
1993341457Svmaffione		}
1994341457Svmaffione#endif /* !BUSYWAIT */
1995341457Svmaffione
1996341457Svmaffione		/* If no room poll() again. */
1997341457Svmaffione		space = nm_ring_space(ring);
1998341457Svmaffione		if (!space) {
1999341457Svmaffione			continue;
2000341457Svmaffione		}
2001341457Svmaffione
2002341457Svmaffione		limit = budget;
2003341457Svmaffione
2004341457Svmaffione		if (space < limit) {
2005341457Svmaffione			limit = space;
2006341457Svmaffione		}
2007341457Svmaffione
2008341457Svmaffione		/* Cut off ``limit`` to make sure is multiple of ``frags``. */
2009341457Svmaffione		if (frags > 1) {
2010341457Svmaffione			limit = (limit / frags) * frags;
2011341457Svmaffione		}
2012341457Svmaffione
2013341457Svmaffione		limit = sent + limit; /* Convert to absolute. */
2014341457Svmaffione
2015341457Svmaffione		for (fcnt = frags, head = ring->head;
2016341457Svmaffione				sent < limit; sent++, sequence++) {
2017341457Svmaffione			struct netmap_slot *slot = &ring->slot[head];
2018341457Svmaffione			char *p = NETMAP_BUF(ring, slot->buf_idx);
2019341457Svmaffione			uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t;
2020341457Svmaffione
2021341457Svmaffione			memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum));
2022341457Svmaffione
2023341457Svmaffione			slot->flags = 0;
2024341457Svmaffione			t = *w;
2025341457Svmaffione			PKT(pkt, body, targ->g->af)[0] = sequence >> 24;
2026341457Svmaffione			PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff;
2027341457Svmaffione			sum = ~cksum_add(~sum, cksum_add(~t, *w));
2028341457Svmaffione			t = *++w;
2029341457Svmaffione			PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff;
2030341457Svmaffione			PKT(pkt, body, targ->g->af)[3] = sequence & 0xff;
2031341457Svmaffione			sum = ~cksum_add(~sum, cksum_add(~t, *w));
2032341457Svmaffione			memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum));
2033341457Svmaffione			nm_pkt_copy(frame, p, size);
2034341457Svmaffione			if (fcnt == frags) {
2035341457Svmaffione				update_addresses(pkt, targ);
2036341457Svmaffione			}
2037341457Svmaffione
2038341457Svmaffione			if (options & OPT_DUMP) {
2039341457Svmaffione				dump_payload(p, size, ring, head);
2040341457Svmaffione			}
2041341457Svmaffione
2042341457Svmaffione			slot->len = size;
2043341457Svmaffione
2044341457Svmaffione			if (--fcnt > 0) {
2045341457Svmaffione				slot->flags |= NS_MOREFRAG;
2046341457Svmaffione			} else {
2047341457Svmaffione				fcnt = frags;
2048341457Svmaffione			}
2049341457Svmaffione
2050341457Svmaffione			if (sent == limit - 1) {
2051341457Svmaffione				/* Make sure we don't push an incomplete
2052341457Svmaffione				 * packet. */
2053341457Svmaffione				assert(!(slot->flags & NS_MOREFRAG));
2054341457Svmaffione				slot->flags |= NS_REPORT;
2055341457Svmaffione			}
2056341457Svmaffione
2057341457Svmaffione			head = nm_ring_next(ring, head);
2058341457Svmaffione			if (rate_limit) {
2059341457Svmaffione				budget--;
2060341457Svmaffione			}
2061341457Svmaffione		}
2062341457Svmaffione
2063341457Svmaffione		ring->cur = ring->head = head;
2064341457Svmaffione
2065341457Svmaffione		event ++;
2066341457Svmaffione		targ->ctr.pkts = sent;
2067341457Svmaffione		targ->ctr.bytes = sent * size;
2068341457Svmaffione		targ->ctr.events = event;
2069341457Svmaffione	}
2070341457Svmaffione
2071341457Svmaffione	/* flush any remaining packets */
2072341457Svmaffione	D("flush tail %d head %d on thread %p",
2073341457Svmaffione		ring->tail, ring->head,
2074341457Svmaffione		(void *)pthread_self());
2075341457Svmaffione	ioctl(pfd.fd, NIOCTXSYNC, NULL);
2076341457Svmaffione
2077341457Svmaffione	/* final part: wait the TX queues to become empty. */
2078341457Svmaffione	while (!targ->cancel && nm_tx_pending(ring)) {
2079341457Svmaffione		RD(5, "pending tx tail %d head %d on ring %d",
2080341457Svmaffione				ring->tail, ring->head, targ->nmd->first_tx_ring);
2081341457Svmaffione		ioctl(pfd.fd, NIOCTXSYNC, NULL);
2082341457Svmaffione		usleep(1); /* wait 1 tick */
2083341457Svmaffione	}
2084341457Svmaffione
2085341457Svmaffione	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
2086341457Svmaffione	targ->completed = 1;
2087341457Svmaffione	targ->ctr.pkts = sent;
2088341457Svmaffione	targ->ctr.bytes = sent * size;
2089341457Svmaffione	targ->ctr.events = event;
2090341457Svmaffionequit:
2091341457Svmaffione	/* reset the ``used`` flag. */
2092341457Svmaffione	targ->used = 0;
2093341457Svmaffione
2094341457Svmaffione	return (NULL);
2095238170Semaste}
2096238170Semaste
2097341457Svmaffione
2098341457Svmaffionestatic char *
2099341457Svmaffionemulti_slot_to_string(struct netmap_ring *ring, unsigned int head,
2100341457Svmaffione		     unsigned int nfrags, char *strbuf, size_t strbuflen)
2101227614Sluigi{
2102341457Svmaffione	unsigned int f;
2103341457Svmaffione	char *ret = strbuf;
2104227614Sluigi
2105341457Svmaffione	for (f = 0; f < nfrags; f++) {
2106341457Svmaffione		struct netmap_slot *slot = &ring->slot[head];
2107341457Svmaffione		int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len,
2108341457Svmaffione				 slot->flags);
2109341457Svmaffione		if (m >= (int)strbuflen) {
2110341457Svmaffione			break;
2111341457Svmaffione		}
2112341457Svmaffione		strbuf += m;
2113341457Svmaffione		strbuflen -= m;
2114238170Semaste
2115341457Svmaffione		head = nm_ring_next(ring, head);
2116341457Svmaffione	}
2117341457Svmaffione
2118341457Svmaffione	return ret;
2119227614Sluigi}
2120227614Sluigi
2121341457Svmaffionestatic void *
2122341457Svmaffionerxseq_body(void *data)
2123341457Svmaffione{
2124341457Svmaffione	struct targ *targ = (struct targ *) data;
2125341457Svmaffione	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
2126341457Svmaffione	int dump = targ->g->options & OPT_DUMP;
2127341457Svmaffione	struct netmap_ring *ring;
2128341457Svmaffione	unsigned int frags_exp = 1;
2129341457Svmaffione	struct my_ctrs cur;
2130341457Svmaffione	unsigned int frags = 0;
2131341457Svmaffione	int first_packet = 1;
2132341457Svmaffione	int first_slot = 1;
2133341457Svmaffione	int i, j, af, nrings;
2134341457Svmaffione	uint32_t seq, *seq_exp = NULL;
2135227614Sluigi
2136341457Svmaffione	memset(&cur, 0, sizeof(cur));
2137341457Svmaffione
2138341457Svmaffione	if (setaffinity(targ->thread, targ->affinity))
2139341457Svmaffione		goto quit;
2140341457Svmaffione
2141341457Svmaffione	nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1;
2142341457Svmaffione	seq_exp = calloc(nrings, sizeof(uint32_t));
2143341457Svmaffione	if (seq_exp == NULL) {
2144341457Svmaffione		D("failed to allocate seq array");
2145341457Svmaffione		goto quit;
2146341457Svmaffione	}
2147341457Svmaffione
2148341457Svmaffione	D("reading from %s fd %d main_fd %d",
2149341457Svmaffione		targ->g->ifname, targ->fd, targ->g->main_fd);
2150341457Svmaffione	/* unbounded wait for the first packet. */
2151341457Svmaffione	for (;!targ->cancel;) {
2152341457Svmaffione		i = poll(&pfd, 1, 1000);
2153341457Svmaffione		if (i > 0 && !(pfd.revents & POLLERR))
2154341457Svmaffione			break;
2155341457Svmaffione		RD(1, "waiting for initial packets, poll returns %d %d",
2156341457Svmaffione			i, pfd.revents);
2157341457Svmaffione	}
2158341457Svmaffione
2159341457Svmaffione	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
2160341457Svmaffione
2161341457Svmaffione
2162341457Svmaffione	while (!targ->cancel) {
2163341457Svmaffione		unsigned int head;
2164341457Svmaffione		int limit;
2165341457Svmaffione
2166341457Svmaffione#ifdef BUSYWAIT
2167341457Svmaffione		if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) {
2168341457Svmaffione			D("ioctl error on queue %d: %s", targ->me,
2169341457Svmaffione					strerror(errno));
2170341457Svmaffione			goto quit;
2171341457Svmaffione		}
2172341457Svmaffione#else /* !BUSYWAIT */
2173341457Svmaffione		if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) {
2174341457Svmaffione			clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
2175341457Svmaffione			targ->toc.tv_sec -= 1; /* Subtract timeout time. */
2176341457Svmaffione			goto out;
2177341457Svmaffione		}
2178341457Svmaffione
2179341457Svmaffione		if (pfd.revents & POLLERR) {
2180341457Svmaffione			D("poll err");
2181341457Svmaffione			goto quit;
2182341457Svmaffione		}
2183341457Svmaffione#endif /* !BUSYWAIT */
2184341457Svmaffione
2185341457Svmaffione		for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) {
2186341457Svmaffione			ring = NETMAP_RXRING(targ->nmd->nifp, j);
2187341457Svmaffione			if (nm_ring_empty(ring))
2188341457Svmaffione				continue;
2189341457Svmaffione
2190341457Svmaffione			limit = nm_ring_space(ring);
2191341457Svmaffione			if (limit > targ->g->burst)
2192341457Svmaffione				limit = targ->g->burst;
2193341457Svmaffione
2194341457Svmaffione#if 0
2195341457Svmaffione			/* Enable this if
2196341457Svmaffione			 *     1) we remove the early-return optimization from
2197341457Svmaffione			 *        the netmap poll implementation, or
2198341457Svmaffione			 *     2) pipes get NS_MOREFRAG support.
2199341457Svmaffione			 * With the current netmap implementation, an experiment like
2200341457Svmaffione			 *    pkt-gen -i vale:1{1 -f txseq -F 9
2201341457Svmaffione			 *    pkt-gen -i vale:1}1 -f rxseq
2202341457Svmaffione			 * would get stuck as soon as we find nm_ring_space(ring) < 9,
2203341457Svmaffione			 * since here limit is rounded to 0 and
2204341457Svmaffione			 * pipe rxsync is not called anymore by the poll() of this loop.
2205341457Svmaffione			 */
2206341457Svmaffione			if (frags_exp > 1) {
2207341457Svmaffione				int o = limit;
2208341457Svmaffione				/* Cut off to the closest smaller multiple. */
2209341457Svmaffione				limit = (limit / frags_exp) * frags_exp;
2210341457Svmaffione				RD(2, "LIMIT %d --> %d", o, limit);
2211341457Svmaffione			}
2212341457Svmaffione#endif
2213341457Svmaffione
2214341457Svmaffione			for (head = ring->head, i = 0; i < limit; i++) {
2215341457Svmaffione				struct netmap_slot *slot = &ring->slot[head];
2216341457Svmaffione				char *p = NETMAP_BUF(ring, slot->buf_idx);
2217341457Svmaffione				int len = slot->len;
2218341457Svmaffione				struct pkt *pkt;
2219341457Svmaffione
2220341457Svmaffione				if (dump) {
2221341457Svmaffione					dump_payload(p, slot->len, ring, head);
2222341457Svmaffione				}
2223341457Svmaffione
2224341457Svmaffione				frags++;
2225341457Svmaffione				if (!(slot->flags & NS_MOREFRAG)) {
2226341457Svmaffione					if (first_packet) {
2227341457Svmaffione						first_packet = 0;
2228341457Svmaffione					} else if (frags != frags_exp) {
2229341457Svmaffione						char prbuf[512];
2230341457Svmaffione						RD(1, "Received packets with %u frags, "
2231341457Svmaffione								"expected %u, '%s'", frags, frags_exp,
2232341457Svmaffione								multi_slot_to_string(ring, head-frags+1,
2233341457Svmaffione							       	frags,
2234341457Svmaffione									prbuf, sizeof(prbuf)));
2235341457Svmaffione					}
2236341457Svmaffione					first_packet = 0;
2237341457Svmaffione					frags_exp = frags;
2238341457Svmaffione					frags = 0;
2239341457Svmaffione				}
2240341457Svmaffione
2241341457Svmaffione				p -= sizeof(pkt->vh) - targ->g->virt_header;
2242341457Svmaffione				len += sizeof(pkt->vh) - targ->g->virt_header;
2243341457Svmaffione				pkt = (struct pkt *)p;
2244341457Svmaffione				if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP)
2245341457Svmaffione					af = AF_INET;
2246341457Svmaffione				else
2247341457Svmaffione					af = AF_INET6;
2248341457Svmaffione
2249341457Svmaffione				if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) +
2250341457Svmaffione						sizeof(seq)) {
2251341457Svmaffione					RD(1, "%s: packet too small (len=%u)", __func__,
2252341457Svmaffione							slot->len);
2253341457Svmaffione				} else {
2254341457Svmaffione					seq = (PKT(pkt, body, af)[0] << 24) |
2255341457Svmaffione						(PKT(pkt, body, af)[1] << 16) |
2256341457Svmaffione						(PKT(pkt, body, af)[2] << 8) |
2257341457Svmaffione						PKT(pkt, body, af)[3];
2258341457Svmaffione					if (first_slot) {
2259341457Svmaffione						/* Grab the first one, whatever it
2260341457Svmaffione						   is. */
2261341457Svmaffione						seq_exp[j] = seq;
2262341457Svmaffione						first_slot = 0;
2263341457Svmaffione					} else if (seq != seq_exp[j]) {
2264341457Svmaffione						uint32_t delta = seq - seq_exp[j];
2265341457Svmaffione
2266341457Svmaffione						if (delta < (0xFFFFFFFF >> 1)) {
2267341457Svmaffione							RD(2, "Sequence GAP: exp %u found %u",
2268341457Svmaffione									seq_exp[j], seq);
2269341457Svmaffione						} else {
2270341457Svmaffione							RD(2, "Sequence OUT OF ORDER: "
2271341457Svmaffione									"exp %u found %u", seq_exp[j], seq);
2272341457Svmaffione						}
2273341457Svmaffione						seq_exp[j] = seq;
2274341457Svmaffione					}
2275341457Svmaffione					seq_exp[j]++;
2276341457Svmaffione				}
2277341457Svmaffione
2278341457Svmaffione				cur.bytes += slot->len;
2279341457Svmaffione				head = nm_ring_next(ring, head);
2280341457Svmaffione				cur.pkts++;
2281341457Svmaffione			}
2282341457Svmaffione
2283341457Svmaffione			ring->cur = ring->head = head;
2284341457Svmaffione
2285341457Svmaffione			cur.events++;
2286341457Svmaffione			targ->ctr = cur;
2287341457Svmaffione		}
2288341457Svmaffione	}
2289341457Svmaffione	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
2290341457Svmaffione
2291341457Svmaffione#ifndef BUSYWAIT
2292341457Svmaffioneout:
2293341457Svmaffione#endif /* !BUSYWAIT */
2294341457Svmaffione	targ->completed = 1;
2295341457Svmaffione	targ->ctr = cur;
2296341457Svmaffione
2297341457Svmaffionequit:
2298341457Svmaffione	if (seq_exp != NULL)
2299341457Svmaffione		free(seq_exp);
2300341457Svmaffione	/* reset the ``used`` flag. */
2301341457Svmaffione	targ->used = 0;
2302341457Svmaffione
2303341457Svmaffione	return (NULL);
2304341457Svmaffione}
2305341457Svmaffione
2306341457Svmaffione
2307227614Sluigistatic void
2308341457Svmaffionetx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg)
2309227614Sluigi{
2310341457Svmaffione	double bw, raw_bw, pps, abs;
2311341457Svmaffione	char b1[40], b2[80], b3[80];
2312341457Svmaffione	int size;
2313227614Sluigi
2314341457Svmaffione	if (cur->pkts == 0) {
2315341457Svmaffione		printf("%s nothing.\n", msg);
2316341457Svmaffione		return;
2317341457Svmaffione	}
2318227614Sluigi
2319341457Svmaffione	size = (int)(cur->bytes / cur->pkts);
2320341457Svmaffione
2321341457Svmaffione	printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n",
2322341457Svmaffione		msg,
2323341457Svmaffione		(unsigned long long)cur->pkts,
2324341457Svmaffione		(unsigned long long)cur->bytes,
2325341457Svmaffione		(unsigned long long)cur->events, size, delta);
2326246896Sluigi	if (delta == 0)
2327246896Sluigi		delta = 1e-6;
2328341457Svmaffione	if (size < 60)		/* correct for min packet size */
2329341457Svmaffione		size = 60;
2330341457Svmaffione	pps = cur->pkts / delta;
2331341457Svmaffione	bw = (8.0 * cur->bytes) / delta;
2332341457Svmaffione	raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta;
2333341457Svmaffione	abs = cur->pkts / (double)(cur->events);
2334341457Svmaffione
2335341457Svmaffione	printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n",
2336341457Svmaffione		norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs);
2337227614Sluigi}
2338227614Sluigi
2339227614Sluigistatic void
2340341457Svmaffioneusage(int errcode)
2341227614Sluigi{
2342341457Svmaffione/* This usage is generated from the pkt-gen man page:
2343341457Svmaffione *   $ man pkt-gen > x
2344341457Svmaffione * and pasted here adding the string terminators and endlines with simple
2345341457Svmaffione * regular expressions. */
2346227614Sluigi	const char *cmd = "pkt-gen";
2347227614Sluigi	fprintf(stderr,
2348227614Sluigi		"Usage:\n"
2349227614Sluigi		"%s arguments\n"
2350341457Svmaffione"     -h      Show program usage and exit.\n"
2351341457Svmaffione"\n"
2352341457Svmaffione"     -i interface\n"
2353341457Svmaffione"             Name of the network interface that pkt-gen operates on.  It can be a system network interface\n"
2354341457Svmaffione"             (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n"
2355341457Svmaffione"             monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n"
2356341457Svmaffione"             mented in netmap(4) (NIOCREGIF section).\n"
2357341457Svmaffione"\n"
2358341457Svmaffione"     -f function\n"
2359341457Svmaffione"             The function to be executed by pkt-gen.  Specify tx for transmission, rx for reception, ping\n"
2360341457Svmaffione"             for client-side ping-pong operation, and pong for server-side ping-pong operation.\n"
2361341457Svmaffione"\n"
2362341457Svmaffione"     -n count\n"
2363341457Svmaffione"             Number of iterations of the pkt-gen function, with 0 meaning infinite).  In case of tx or rx,\n"
2364341457Svmaffione"             count is the number of packets to receive or transmit.  In case of ping or pong, count is the\n"
2365341457Svmaffione"             number of ping-pong transactions.\n"
2366341457Svmaffione"\n"
2367341457Svmaffione"     -l pkt_size\n"
2368341457Svmaffione"             Packet size in bytes excluding CRC.  If passed a second time, use random sizes larger or\n"
2369341457Svmaffione"             equal than the second one and lower than the first one.\n"
2370341457Svmaffione"\n"
2371341457Svmaffione"     -b burst_size\n"
2372341457Svmaffione"             Transmit or receive up to burst_size packets at a time.\n"
2373341457Svmaffione"\n"
2374341457Svmaffione"     -4      Use IPv4 addresses.\n"
2375341457Svmaffione"\n"
2376341457Svmaffione"     -6      Use IPv6 addresses.\n"
2377341457Svmaffione"\n"
2378341457Svmaffione"     -d dst_ip[:port[-dst_ip:port]]\n"
2379341457Svmaffione"             Destination IPv4/IPv6 address and port, single or range.\n"
2380341457Svmaffione"\n"
2381341457Svmaffione"     -s src_ip[:port[-src_ip:port]]\n"
2382341457Svmaffione"             Source IPv4/IPv6 address and port, single or range.\n"
2383341457Svmaffione"\n"
2384341457Svmaffione"     -D dst_mac\n"
2385341457Svmaffione"             Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n"
2386341457Svmaffione"\n"
2387341457Svmaffione"     -S src_mac\n"
2388341457Svmaffione"             Source MAC address in colon notation.\n"
2389341457Svmaffione"\n"
2390341457Svmaffione"     -a cpu_id\n"
2391341457Svmaffione"             Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3).  If more\n"
2392341457Svmaffione"             threads are used, they are pinned to the subsequent CPUs, one per thread.\n"
2393341457Svmaffione"\n"
2394341457Svmaffione"     -c cpus\n"
2395341457Svmaffione"             Maximum number of CPUs to use (0 means to use all the available ones).\n"
2396341457Svmaffione"\n"
2397341457Svmaffione"     -p threads\n"
2398341457Svmaffione"             Number of threads to use.  By default, only a single thread is used to handle all the netmap\n"
2399341457Svmaffione"             rings.  If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n"
2400341457Svmaffione"             single RX ring (in rx mode), or a TX/RX ring couple.  The number of threads must be less or\n"
2401341457Svmaffione"             equal than the number of TX (or RX) ring available in the device specified by interface.\n"
2402341457Svmaffione"\n"
2403341457Svmaffione"     -T report_ms\n"
2404341457Svmaffione"             Number of milliseconds between reports.\n"
2405341457Svmaffione"\n"
2406341457Svmaffione"     -w wait_for_link_time\n"
2407341457Svmaffione"             Number of seconds to wait before starting the pkt-gen function, useuful to make sure that the\n"
2408341457Svmaffione"             network link is up.  A network device driver may take some time to enter netmap mode, or to\n"
2409341457Svmaffione"             create a new transmit/receive ring pair when netmap(4) requests one.\n"
2410341457Svmaffione"\n"
2411341457Svmaffione"     -R rate\n"
2412341457Svmaffione"             Packet transmission rate.  Not setting the packet transmission rate tells pkt-gen to transmit\n"
2413341457Svmaffione"             packets as quickly as possible.  On servers from 2010 on-wards netmap(4) is able to com-\n"
2414341457Svmaffione"             pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n"
2415341457Svmaffione"             your intention is to saturate the link.\n"
2416341457Svmaffione"\n"
2417341457Svmaffione"     -X      Dump payload of each packet transmitted or received.\n"
2418341457Svmaffione"\n"
2419341457Svmaffione"     -H len  Add empty virtio-net-header with size 'len'.  Valid sizes are 0, 10 and 12.  This option is\n"
2420341457Svmaffione"             only used with Virtual Machine technologies that use virtio as a network interface.\n"
2421341457Svmaffione"\n"
2422341457Svmaffione"     -P file\n"
2423341457Svmaffione"             Load the packet to be transmitted from a pcap file rather than constructing it within\n"
2424341457Svmaffione"             pkt-gen.\n"
2425341457Svmaffione"\n"
2426341457Svmaffione"     -z      Use random IPv4/IPv6 src address/port.\n"
2427341457Svmaffione"\n"
2428341457Svmaffione"     -Z      Use random IPv4/IPv6 dst address/port.\n"
2429341457Svmaffione"\n"
2430341457Svmaffione"     -N      Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n"
2431341457Svmaffione"\n"
2432341457Svmaffione"     -F num_frags\n"
2433341457Svmaffione"             Send multi-slot packets, each one with num_frags fragments.  A multi-slot packet is repre-\n"
2434341457Svmaffione"             sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n"
2435341457Svmaffione"             last slot).  This is useful to transmit or receive packets larger than the netmap buffer\n"
2436341457Svmaffione"             size.\n"
2437341457Svmaffione"\n"
2438341457Svmaffione"     -M frag_size\n"
2439341457Svmaffione"             In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n"
2440341457Svmaffione"             length divided by num_frags.\n"
2441341457Svmaffione"\n"
2442341457Svmaffione"     -I      Use indirect buffers.  It is only valid for transmitting on VALE ports, and it is implemented\n"
2443341457Svmaffione"             by setting the NS_INDIRECT flag in the netmap slots.\n"
2444341457Svmaffione"\n"
2445341457Svmaffione"     -W      Exit immediately if all the RX rings are empty the first time they are examined.\n"
2446341457Svmaffione"\n"
2447341457Svmaffione"     -v      Increase the verbosity level.\n"
2448341457Svmaffione"\n"
2449341457Svmaffione"     -r      In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n"
2450341457Svmaffione"             netmap buffers is (rubbish mode).\n"
2451341457Svmaffione"\n"
2452341457Svmaffione"     -A      Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n"
2453341457Svmaffione"\n"
2454341457Svmaffione"     -B      Take Ethernet framing and CRC into account when computing the average bps.  This adds 4 bytes\n"
2455341457Svmaffione"             of CRC and 20 bytes of framing to each packet.\n"
2456341457Svmaffione"\n"
2457341457Svmaffione"     -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n"
2458341457Svmaffione"             Configuration in terms of number of rings and slots to be used when opening the netmap port.\n"
2459341457Svmaffione"             Such configuration has effect on software ports created on the fly, such as VALE ports and\n"
2460341457Svmaffione"             netmap pipes.  The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n"
2461341457Svmaffione"             rx_slots, tx_rings, rx_rings.  Missing numbers or zeroes stand for default values.  As an\n"
2462341457Svmaffione"             additional convenience, if exactly one number is specified, then this is assigned to both\n"
2463341457Svmaffione"             tx_slots and rx_slots.  If there is no fourth number, then the third one is assigned to both\n"
2464341457Svmaffione"             tx_rings and rx_rings.\n"
2465341457Svmaffione"\n"
2466341457Svmaffione"     -o options		data generation options (parsed using atoi)\n"
2467341457Svmaffione"				OPT_PREFETCH	1\n"
2468341457Svmaffione"				OPT_ACCESS	2\n"
2469341457Svmaffione"				OPT_COPY	4\n"
2470341457Svmaffione"				OPT_MEMCPY	8\n"
2471341457Svmaffione"				OPT_TS		16 (add a timestamp)\n"
2472341457Svmaffione"				OPT_INDIRECT	32 (use indirect buffers)\n"
2473341457Svmaffione"				OPT_DUMP	64 (dump rx/tx traffic)\n"
2474341457Svmaffione"				OPT_RUBBISH	256\n"
2475341457Svmaffione"					(send wathever the buffers contain)\n"
2476341457Svmaffione"				OPT_RANDOM_SRC  512\n"
2477341457Svmaffione"				OPT_RANDOM_DST  1024\n"
2478341457Svmaffione"				OPT_PPS_STATS   2048\n"
2479341457Svmaffione		     "",
2480227614Sluigi		cmd);
2481341457Svmaffione	exit(errcode);
2482227614Sluigi}
2483227614Sluigi
2484246896Sluigistatic void
2485341457Svmaffionestart_threads(struct glob_arg *g) {
2486246896Sluigi	int i;
2487227614Sluigi
2488246896Sluigi	targs = calloc(g->nthreads, sizeof(*targs));
2489341457Svmaffione	struct targ *t;
2490246896Sluigi	/*
2491246896Sluigi	 * Now create the desired number of threads, each one
2492246896Sluigi	 * using a single descriptor.
2493341457Svmaffione	 */
2494246896Sluigi	for (i = 0; i < g->nthreads; i++) {
2495341457Svmaffione		uint64_t seed = time(0) | (time(0) << 32);
2496341457Svmaffione		t = &targs[i];
2497246896Sluigi
2498261909Sluigi		bzero(t, sizeof(*t));
2499261909Sluigi		t->fd = -1; /* default, with pcap */
2500261909Sluigi		t->g = g;
2501341457Svmaffione		memcpy(t->seed, &seed, sizeof(t->seed));
2502261909Sluigi
2503341457Svmaffione		if (g->dev_type == DEV_NETMAP) {
2504341457Svmaffione			struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */
2505341457Svmaffione			uint64_t nmd_flags = 0;
2506341457Svmaffione			nmd.self = &nmd;
2507246896Sluigi
2508341457Svmaffione			if (i > 0) {
2509341457Svmaffione				/* the first thread uses the fd opened by the main
2510341457Svmaffione				 * thread, the other threads re-open /dev/netmap
2511341457Svmaffione				 */
2512341457Svmaffione				if (g->nthreads > 1) {
2513341457Svmaffione					nmd.req.nr_flags =
2514341457Svmaffione						g->nmd->req.nr_flags & ~NR_REG_MASK;
2515341457Svmaffione					nmd.req.nr_flags |= NR_REG_ONE_NIC;
2516341457Svmaffione					nmd.req.nr_ringid = i;
2517341457Svmaffione				}
2518341457Svmaffione				/* Only touch one of the rings (rx is already ok) */
2519341457Svmaffione				if (g->td_type == TD_TYPE_RECEIVER)
2520341457Svmaffione					nmd_flags |= NETMAP_NO_TX_POLL;
2521341457Svmaffione
2522341457Svmaffione				/* register interface. Override ifname and ringid etc. */
2523341457Svmaffione				t->nmd = nm_open(t->g->ifname, NULL, nmd_flags |
2524341457Svmaffione						NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd);
2525341457Svmaffione				if (t->nmd == NULL) {
2526341457Svmaffione					D("Unable to open %s: %s",
2527341457Svmaffione							t->g->ifname, strerror(errno));
2528341457Svmaffione					continue;
2529341457Svmaffione				}
2530341457Svmaffione			} else {
2531341457Svmaffione				t->nmd = g->nmd;
2532261909Sluigi			}
2533341457Svmaffione			t->fd = t->nmd->fd;
2534341457Svmaffione			t->frags = g->frags;
2535341457Svmaffione		} else {
2536341457Svmaffione			targs[i].fd = g->main_fd;
2537246896Sluigi		}
2538261909Sluigi		t->used = 1;
2539261909Sluigi		t->me = i;
2540246896Sluigi		if (g->affinity >= 0) {
2541341457Svmaffione			t->affinity = (g->affinity + i) % g->cpus;
2542261909Sluigi		} else {
2543261909Sluigi			t->affinity = -1;
2544261909Sluigi		}
2545246896Sluigi		/* default, init packets */
2546261909Sluigi		initialize_packet(t);
2547341457Svmaffione	}
2548341457Svmaffione	/* Wait for PHY reset. */
2549341457Svmaffione	D("Wait %d secs for phy reset", g->wait_link);
2550341457Svmaffione	sleep(g->wait_link);
2551341457Svmaffione	D("Ready...");
2552246896Sluigi
2553341457Svmaffione	for (i = 0; i < g->nthreads; i++) {
2554341457Svmaffione		t = &targs[i];
2555261909Sluigi		if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) {
2556260368Sluigi			D("Unable to create thread %d: %s", i, strerror(errno));
2557261909Sluigi			t->used = 0;
2558246896Sluigi		}
2559246896Sluigi	}
2560246896Sluigi}
2561246896Sluigi
2562246896Sluigistatic void
2563246896Sluigimain_thread(struct glob_arg *g)
2564246896Sluigi{
2565246896Sluigi	int i;
2566246896Sluigi
2567341457Svmaffione	struct my_ctrs prev, cur;
2568246896Sluigi	double delta_t;
2569246896Sluigi	struct timeval tic, toc;
2570246896Sluigi
2571341457Svmaffione	prev.pkts = prev.bytes = prev.events = 0;
2572341457Svmaffione	gettimeofday(&prev.t, NULL);
2573246896Sluigi	for (;;) {
2574341457Svmaffione		char b1[40], b2[40], b3[40], b4[100];
2575341457Svmaffione		uint64_t pps, usec;
2576341457Svmaffione		struct my_ctrs x;
2577341457Svmaffione		double abs;
2578246896Sluigi		int done = 0;
2579246896Sluigi
2580341457Svmaffione		usec = wait_for_next_report(&prev.t, &cur.t,
2581341457Svmaffione				g->report_interval);
2582341457Svmaffione
2583341457Svmaffione		cur.pkts = cur.bytes = cur.events = 0;
2584341457Svmaffione		cur.min_space = 0;
2585341457Svmaffione		if (usec < 10000) /* too short to be meaningful */
2586341457Svmaffione			continue;
2587341457Svmaffione		/* accumulate counts for all threads */
2588246896Sluigi		for (i = 0; i < g->nthreads; i++) {
2589341457Svmaffione			cur.pkts += targs[i].ctr.pkts;
2590341457Svmaffione			cur.bytes += targs[i].ctr.bytes;
2591341457Svmaffione			cur.events += targs[i].ctr.events;
2592341457Svmaffione			cur.min_space += targs[i].ctr.min_space;
2593341457Svmaffione			targs[i].ctr.min_space = 99999;
2594246896Sluigi			if (targs[i].used == 0)
2595246896Sluigi				done++;
2596246896Sluigi		}
2597341457Svmaffione		x.pkts = cur.pkts - prev.pkts;
2598341457Svmaffione		x.bytes = cur.bytes - prev.bytes;
2599341457Svmaffione		x.events = cur.events - prev.events;
2600341457Svmaffione		pps = (x.pkts*1000000 + usec/2) / usec;
2601341457Svmaffione		abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0;
2602341457Svmaffione
2603341457Svmaffione		if (!(g->options & OPT_PPS_STATS)) {
2604341457Svmaffione			strcpy(b4, "");
2605341457Svmaffione		} else {
2606341457Svmaffione			/* Compute some pps stats using a sliding window. */
2607341457Svmaffione			double ppsavg = 0.0, ppsdev = 0.0;
2608341457Svmaffione			int nsamples = 0;
2609341457Svmaffione
2610341457Svmaffione			g->win[g->win_idx] = pps;
2611341457Svmaffione			g->win_idx = (g->win_idx + 1) % STATS_WIN;
2612341457Svmaffione
2613341457Svmaffione			for (i = 0; i < STATS_WIN; i++) {
2614341457Svmaffione				ppsavg += g->win[i];
2615341457Svmaffione				if (g->win[i]) {
2616341457Svmaffione					nsamples ++;
2617341457Svmaffione				}
2618341457Svmaffione			}
2619341457Svmaffione			ppsavg /= nsamples;
2620341457Svmaffione
2621341457Svmaffione			for (i = 0; i < STATS_WIN; i++) {
2622341457Svmaffione				if (g->win[i] == 0) {
2623341457Svmaffione					continue;
2624341457Svmaffione				}
2625341457Svmaffione				ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg);
2626341457Svmaffione			}
2627341457Svmaffione			ppsdev /= nsamples;
2628341457Svmaffione			ppsdev = sqrt(ppsdev);
2629341457Svmaffione
2630341457Svmaffione			snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]",
2631341457Svmaffione				 norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize));
2632341457Svmaffione		}
2633341457Svmaffione
2634341457Svmaffione		D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space",
2635341457Svmaffione			norm(b1, pps, normalize), b4,
2636341457Svmaffione			norm(b2, (double)x.pkts, normalize),
2637341457Svmaffione			norm(b3, (double)x.bytes*8+(double)x.pkts*g->framing, normalize),
2638341457Svmaffione			(unsigned long long)usec,
2639341457Svmaffione			abs, (int)cur.min_space);
2640341457Svmaffione		prev = cur;
2641341457Svmaffione
2642246896Sluigi		if (done == g->nthreads)
2643246896Sluigi			break;
2644246896Sluigi	}
2645246896Sluigi
2646246896Sluigi	timerclear(&tic);
2647246896Sluigi	timerclear(&toc);
2648341457Svmaffione	cur.pkts = cur.bytes = cur.events = 0;
2649341457Svmaffione	/* final round */
2650246896Sluigi	for (i = 0; i < g->nthreads; i++) {
2651251132Sluigi		struct timespec t_tic, t_toc;
2652246896Sluigi		/*
2653246896Sluigi		 * Join active threads, unregister interfaces and close
2654246896Sluigi		 * file descriptors.
2655246896Sluigi		 */
2656251132Sluigi		if (targs[i].used)
2657341457Svmaffione			pthread_join(targs[i].thread, NULL); /* blocking */
2658341457Svmaffione		if (g->dev_type == DEV_NETMAP) {
2659341457Svmaffione			nm_close(targs[i].nmd);
2660341457Svmaffione			targs[i].nmd = NULL;
2661341457Svmaffione		} else {
2662341457Svmaffione			close(targs[i].fd);
2663341457Svmaffione		}
2664246896Sluigi
2665246896Sluigi		if (targs[i].completed == 0)
2666246896Sluigi			D("ouch, thread %d exited with error", i);
2667246896Sluigi
2668246896Sluigi		/*
2669246896Sluigi		 * Collect threads output and extract information about
2670246896Sluigi		 * how long it took to send all the packets.
2671246896Sluigi		 */
2672341457Svmaffione		cur.pkts += targs[i].ctr.pkts;
2673341457Svmaffione		cur.bytes += targs[i].ctr.bytes;
2674341457Svmaffione		cur.events += targs[i].ctr.events;
2675341457Svmaffione		/* collect the largest start (tic) and end (toc) times,
2676341457Svmaffione		 * XXX maybe we should do the earliest tic, or do a weighted
2677341457Svmaffione		 * average ?
2678341457Svmaffione		 */
2679251132Sluigi		t_tic = timeval2spec(&tic);
2680251132Sluigi		t_toc = timeval2spec(&toc);
2681251132Sluigi		if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic))
2682251132Sluigi			tic = timespec2val(&targs[i].tic);
2683251132Sluigi		if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc))
2684251132Sluigi			toc = timespec2val(&targs[i].toc);
2685246896Sluigi	}
2686246896Sluigi
2687246896Sluigi	/* print output. */
2688246896Sluigi	timersub(&toc, &tic, &toc);
2689246896Sluigi	delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
2690341457Svmaffione	if (g->td_type == TD_TYPE_SENDER)
2691341457Svmaffione		tx_output(g, &cur, delta_t, "Sent");
2692341457Svmaffione	else if (g->td_type == TD_TYPE_RECEIVER)
2693341457Svmaffione		tx_output(g, &cur, delta_t, "Received");
2694246896Sluigi}
2695246896Sluigi
2696341457Svmaffionestruct td_desc {
2697341457Svmaffione	int ty;
2698246896Sluigi	char *key;
2699246896Sluigi	void *f;
2700341457Svmaffione	int default_burst;
2701246896Sluigi};
2702246896Sluigi
2703341457Svmaffionestatic struct td_desc func[] = {
2704341457Svmaffione	{ TD_TYPE_RECEIVER,	"rx",		receiver_body,	512},	/* default */
2705341457Svmaffione	{ TD_TYPE_SENDER,	"tx",		sender_body,	512 },
2706341457Svmaffione	{ TD_TYPE_OTHER,	"ping",		ping_body,	1 },
2707341457Svmaffione	{ TD_TYPE_OTHER,	"pong",		pong_body,	1 },
2708341457Svmaffione	{ TD_TYPE_SENDER,	"txseq",	txseq_body,	512 },
2709341457Svmaffione	{ TD_TYPE_RECEIVER,	"rxseq",	rxseq_body,	512 },
2710341457Svmaffione	{ 0,			NULL,		NULL, 		0 }
2711246896Sluigi};
2712246896Sluigi
2713246896Sluigistatic int
2714246896Sluigitap_alloc(char *dev)
2715246896Sluigi{
2716246896Sluigi	struct ifreq ifr;
2717246896Sluigi	int fd, err;
2718246896Sluigi	char *clonedev = TAP_CLONEDEV;
2719246896Sluigi
2720246896Sluigi	(void)err;
2721246896Sluigi	(void)dev;
2722246896Sluigi	/* Arguments taken by the function:
2723246896Sluigi	 *
2724246896Sluigi	 * char *dev: the name of an interface (or '\0'). MUST have enough
2725246896Sluigi	 *   space to hold the interface name if '\0' is passed
2726246896Sluigi	 * int flags: interface flags (eg, IFF_TUN etc.)
2727246896Sluigi	 */
2728246896Sluigi
2729246896Sluigi#ifdef __FreeBSD__
2730246896Sluigi	if (dev[3]) { /* tapSomething */
2731246896Sluigi		static char buf[128];
2732246896Sluigi		snprintf(buf, sizeof(buf), "/dev/%s", dev);
2733246896Sluigi		clonedev = buf;
2734246896Sluigi	}
2735246896Sluigi#endif
2736246896Sluigi	/* open the device */
2737246896Sluigi	if( (fd = open(clonedev, O_RDWR)) < 0 ) {
2738246896Sluigi		return fd;
2739246896Sluigi	}
2740246896Sluigi	D("%s open successful", clonedev);
2741246896Sluigi
2742246896Sluigi	/* preparation of the struct ifr, of type "struct ifreq" */
2743246896Sluigi	memset(&ifr, 0, sizeof(ifr));
2744246896Sluigi
2745246896Sluigi#ifdef linux
2746246896Sluigi	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
2747246896Sluigi
2748246896Sluigi	if (*dev) {
2749246896Sluigi		/* if a device name was specified, put it in the structure; otherwise,
2750246896Sluigi		* the kernel will try to allocate the "next" device of the
2751246896Sluigi		* specified type */
2752341457Svmaffione		size_t len = strlen(dev);
2753341457Svmaffione		if (len > IFNAMSIZ) {
2754341457Svmaffione			D("%s too long", dev);
2755341457Svmaffione			return -1;
2756341457Svmaffione		}
2757341457Svmaffione		memcpy(ifr.ifr_name, dev, len);
2758246896Sluigi	}
2759246896Sluigi
2760246896Sluigi	/* try to create the device */
2761246896Sluigi	if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
2762260368Sluigi		D("failed to to a TUNSETIFF: %s", strerror(errno));
2763246896Sluigi		close(fd);
2764246896Sluigi		return err;
2765246896Sluigi	}
2766246896Sluigi
2767246896Sluigi	/* if the operation was successful, write back the name of the
2768246896Sluigi	* interface to the variable "dev", so the caller can know
2769246896Sluigi	* it. Note that the caller MUST reserve space in *dev (see calling
2770246896Sluigi	* code below) */
2771246896Sluigi	strcpy(dev, ifr.ifr_name);
2772246896Sluigi	D("new name is %s", dev);
2773246896Sluigi#endif /* linux */
2774246896Sluigi
2775341457Svmaffione	/* this is the special file descriptor that the caller will use to talk
2776341457Svmaffione	 * with the virtual interface */
2777341457Svmaffione	return fd;
2778246896Sluigi}
2779246896Sluigi
2780227614Sluigiint
2781227614Sluigimain(int arc, char **argv)
2782227614Sluigi{
2783246896Sluigi	int i;
2784341457Svmaffione	struct sigaction sa;
2785341457Svmaffione	sigset_t ss;
2786227614Sluigi
2787227614Sluigi	struct glob_arg g;
2788227614Sluigi
2789227614Sluigi	int ch;
2790227614Sluigi	int devqueues = 1;	/* how many device queues */
2791341457Svmaffione	int wait_link_arg = 0;
2792227614Sluigi
2793341457Svmaffione	int pkt_size_done = 0;
2794341457Svmaffione
2795341457Svmaffione	struct td_desc *fn = func;
2796341457Svmaffione
2797227614Sluigi	bzero(&g, sizeof(g));
2798227614Sluigi
2799246896Sluigi	g.main_fd = -1;
2800341457Svmaffione	g.td_body = fn->f;
2801341457Svmaffione	g.td_type = fn->ty;
2802246896Sluigi	g.report_interval = 1000;	/* report interval */
2803246896Sluigi	g.affinity = -1;
2804246896Sluigi	/* ip addresses can also be a range x.x.x.x-x.x.x.y */
2805341457Svmaffione	g.af = AF_INET;		/* default */
2806246896Sluigi	g.src_ip.name = "10.0.0.1";
2807246896Sluigi	g.dst_ip.name = "10.1.0.1";
2808246896Sluigi	g.dst_mac.name = "ff:ff:ff:ff:ff:ff";
2809246896Sluigi	g.src_mac.name = NULL;
2810227614Sluigi	g.pkt_size = 60;
2811341457Svmaffione	g.pkt_min_size = 0;
2812227614Sluigi	g.nthreads = 1;
2813341457Svmaffione	g.cpus = 1;		/* default */
2814251426Sluigi	g.forever = 1;
2815251132Sluigi	g.tx_rate = 0;
2816342035Svmaffione	g.frags = 1;
2817342035Svmaffione	g.frag_size = (u_int)-1;	/* use the netmap buffer size by default */
2818257529Sluigi	g.nmr_config = "";
2819260368Sluigi	g.virt_header = 0;
2820341457Svmaffione	g.wait_link = 2;	/* wait 2 seconds for physical ports */
2821227614Sluigi
2822341457Svmaffione	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
2823341457Svmaffione	    "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) {
2824246896Sluigi
2825227614Sluigi		switch(ch) {
2826227614Sluigi		default:
2827227614Sluigi			D("bad option %c %s", ch, optarg);
2828341457Svmaffione			usage(-1);
2829227614Sluigi			break;
2830246896Sluigi
2831341457Svmaffione		case 'h':
2832341457Svmaffione			usage(0);
2833341457Svmaffione			break;
2834341457Svmaffione
2835341457Svmaffione		case '4':
2836341457Svmaffione			g.af = AF_INET;
2837341457Svmaffione			break;
2838341457Svmaffione
2839341457Svmaffione		case '6':
2840341457Svmaffione			g.af = AF_INET6;
2841341457Svmaffione			break;
2842341457Svmaffione
2843341457Svmaffione		case 'N':
2844341457Svmaffione			normalize = 0;
2845341457Svmaffione			break;
2846341457Svmaffione
2847246896Sluigi		case 'n':
2848341457Svmaffione			g.npackets = strtoull(optarg, NULL, 10);
2849246896Sluigi			break;
2850246896Sluigi
2851257529Sluigi		case 'F':
2852257529Sluigi			i = atoi(optarg);
2853257529Sluigi			if (i < 1 || i > 63) {
2854257529Sluigi				D("invalid frags %d [1..63], ignore", i);
2855257529Sluigi				break;
2856257529Sluigi			}
2857257529Sluigi			g.frags = i;
2858257529Sluigi			break;
2859257529Sluigi
2860341457Svmaffione		case 'M':
2861342035Svmaffione			g.frag_size = atoi(optarg);
2862341457Svmaffione			break;
2863341457Svmaffione
2864246896Sluigi		case 'f':
2865246896Sluigi			for (fn = func; fn->key; fn++) {
2866246896Sluigi				if (!strcmp(fn->key, optarg))
2867246896Sluigi					break;
2868246896Sluigi			}
2869341457Svmaffione			if (fn->key) {
2870246896Sluigi				g.td_body = fn->f;
2871341457Svmaffione				g.td_type = fn->ty;
2872341457Svmaffione			} else {
2873246896Sluigi				D("unrecognised function %s", optarg);
2874341457Svmaffione			}
2875246896Sluigi			break;
2876246896Sluigi
2877246896Sluigi		case 'o':	/* data generation options */
2878341457Svmaffione			g.options |= atoi(optarg);
2879234956Sluigi			break;
2880246896Sluigi
2881246896Sluigi		case 'a':       /* force affinity */
2882246896Sluigi			g.affinity = atoi(optarg);
2883246896Sluigi			break;
2884246896Sluigi
2885227614Sluigi		case 'i':	/* interface */
2886260700Sluigi			/* a prefix of tap: netmap: or pcap: forces the mode.
2887260700Sluigi			 * otherwise we guess
2888260700Sluigi			 */
2889260700Sluigi			D("interface is %s", optarg);
2890261909Sluigi			if (strlen(optarg) > MAX_IFNAMELEN - 8) {
2891261909Sluigi				D("ifname too long %s", optarg);
2892261909Sluigi				break;
2893261909Sluigi			}
2894261909Sluigi			strcpy(g.ifname, optarg);
2895260700Sluigi			if (!strcmp(optarg, "null")) {
2896260700Sluigi				g.dev_type = DEV_NETMAP;
2897260700Sluigi				g.dummy_send = 1;
2898260700Sluigi			} else if (!strncmp(optarg, "tap:", 4)) {
2899246896Sluigi				g.dev_type = DEV_TAP;
2900261909Sluigi				strcpy(g.ifname, optarg + 4);
2901260700Sluigi			} else if (!strncmp(optarg, "pcap:", 5)) {
2902260700Sluigi				g.dev_type = DEV_PCAP;
2903261909Sluigi				strcpy(g.ifname, optarg + 5);
2904261909Sluigi			} else if (!strncmp(optarg, "netmap:", 7) ||
2905261909Sluigi				   !strncmp(optarg, "vale", 4)) {
2906246896Sluigi				g.dev_type = DEV_NETMAP;
2907260700Sluigi			} else if (!strncmp(optarg, "tap", 3)) {
2908260700Sluigi				g.dev_type = DEV_TAP;
2909261909Sluigi			} else { /* prepend netmap: */
2910260700Sluigi				g.dev_type = DEV_NETMAP;
2911261909Sluigi				sprintf(g.ifname, "netmap:%s", optarg);
2912260700Sluigi			}
2913227614Sluigi			break;
2914246896Sluigi
2915251426Sluigi		case 'I':
2916341457Svmaffione			g.options |= OPT_INDIRECT;	/* use indirect buffers */
2917251426Sluigi			break;
2918251426Sluigi
2919227614Sluigi		case 'l':	/* pkt_size */
2920341457Svmaffione			if (pkt_size_done) {
2921341457Svmaffione				g.pkt_min_size = atoi(optarg);
2922341457Svmaffione			} else {
2923341457Svmaffione				g.pkt_size = atoi(optarg);
2924341457Svmaffione				pkt_size_done = 1;
2925341457Svmaffione			}
2926227614Sluigi			break;
2927246896Sluigi
2928227614Sluigi		case 'd':
2929246896Sluigi			g.dst_ip.name = optarg;
2930227614Sluigi			break;
2931246896Sluigi
2932227614Sluigi		case 's':
2933246896Sluigi			g.src_ip.name = optarg;
2934227614Sluigi			break;
2935246896Sluigi
2936227614Sluigi		case 'T':	/* report interval */
2937246896Sluigi			g.report_interval = atoi(optarg);
2938227614Sluigi			break;
2939246896Sluigi
2940227614Sluigi		case 'w':
2941341457Svmaffione			g.wait_link = atoi(optarg);
2942341457Svmaffione			wait_link_arg = 1;
2943227614Sluigi			break;
2944246896Sluigi
2945341457Svmaffione		case 'W':
2946341457Svmaffione			g.forever = 0; /* exit RX with no traffic */
2947246896Sluigi			break;
2948246896Sluigi
2949227614Sluigi		case 'b':	/* burst */
2950227614Sluigi			g.burst = atoi(optarg);
2951227614Sluigi			break;
2952227614Sluigi		case 'c':
2953227614Sluigi			g.cpus = atoi(optarg);
2954227614Sluigi			break;
2955227614Sluigi		case 'p':
2956227614Sluigi			g.nthreads = atoi(optarg);
2957227614Sluigi			break;
2958227614Sluigi
2959227614Sluigi		case 'D': /* destination mac */
2960246896Sluigi			g.dst_mac.name = optarg;
2961227614Sluigi			break;
2962246896Sluigi
2963227614Sluigi		case 'S': /* source mac */
2964246896Sluigi			g.src_mac.name = optarg;
2965227614Sluigi			break;
2966227614Sluigi		case 'v':
2967227614Sluigi			verbose++;
2968251132Sluigi			break;
2969251132Sluigi		case 'R':
2970251132Sluigi			g.tx_rate = atoi(optarg);
2971251132Sluigi			break;
2972251426Sluigi		case 'X':
2973251426Sluigi			g.options |= OPT_DUMP;
2974257529Sluigi			break;
2975257529Sluigi		case 'C':
2976257529Sluigi			g.nmr_config = strdup(optarg);
2977260368Sluigi			break;
2978260368Sluigi		case 'H':
2979260368Sluigi			g.virt_header = atoi(optarg);
2980260700Sluigi			break;
2981272962Sgnn		case 'P':
2982272962Sgnn			g.packet_file = strdup(optarg);
2983272962Sgnn			break;
2984341457Svmaffione		case 'r':
2985341457Svmaffione			g.options |= OPT_RUBBISH;
2986341457Svmaffione			break;
2987281746Sadrian		case 'z':
2988281746Sadrian			g.options |= OPT_RANDOM_SRC;
2989281746Sadrian			break;
2990281746Sadrian		case 'Z':
2991281746Sadrian			g.options |= OPT_RANDOM_DST;
2992281746Sadrian			break;
2993341457Svmaffione		case 'A':
2994341457Svmaffione			g.options |= OPT_PPS_STATS;
2995341457Svmaffione			break;
2996341457Svmaffione		case 'B':
2997341457Svmaffione			/* raw packets have4 bytes crc + 20 bytes framing */
2998341457Svmaffione			// XXX maybe add an option to pass the IFG
2999341457Svmaffione			g.framing = 24 * 8;
3000341457Svmaffione			break;
3001227614Sluigi		}
3002227614Sluigi	}
3003227614Sluigi
3004278641Sgnn	if (strlen(g.ifname) <=0 ) {
3005227614Sluigi		D("missing ifname");
3006341457Svmaffione		usage(-1);
3007227614Sluigi	}
3008246896Sluigi
3009341457Svmaffione	if (g.burst == 0) {
3010341457Svmaffione		g.burst = fn->default_burst;
3011341457Svmaffione		D("using default burst size: %d", g.burst);
3012341457Svmaffione	}
3013341457Svmaffione
3014341457Svmaffione	g.system_cpus = i = system_ncpus();
3015246896Sluigi	if (g.cpus < 0 || g.cpus > i) {
3016246896Sluigi		D("%d cpus is too high, have only %d cpus", g.cpus, i);
3017341457Svmaffione		usage(-1);
3018227614Sluigi	}
3019341457Svmaffione	D("running on %d cpus (have %d)", g.cpus, i);
3020246896Sluigi	if (g.cpus == 0)
3021246896Sluigi		g.cpus = i;
3022246896Sluigi
3023341457Svmaffione	if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) {
3024341457Svmaffione		g.wait_link = 0;
3025341457Svmaffione	}
3026341457Svmaffione
3027270063Sluigi	if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) {
3028270063Sluigi		D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE);
3029341457Svmaffione		usage(-1);
3030227614Sluigi	}
3031227614Sluigi
3032341457Svmaffione	if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) {
3033341457Svmaffione		D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size);
3034341457Svmaffione		usage(-1);
3035341457Svmaffione	}
3036341457Svmaffione
3037246896Sluigi	if (g.src_mac.name == NULL) {
3038246896Sluigi		static char mybuf[20] = "00:00:00:00:00:00";
3039234956Sluigi		/* retrieve source mac address. */
3040246896Sluigi		if (source_hwaddr(g.ifname, mybuf) == -1) {
3041234956Sluigi			D("Unable to retrieve source mac");
3042234956Sluigi			// continue, fail later
3043234956Sluigi		}
3044246896Sluigi		g.src_mac.name = mybuf;
3045234956Sluigi	}
3046246896Sluigi	/* extract address ranges */
3047341457Svmaffione	if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac))
3048341457Svmaffione		usage(-1);
3049341457Svmaffione	g.options |= extract_ip_range(&g.src_ip, g.af);
3050341457Svmaffione	g.options |= extract_ip_range(&g.dst_ip, g.af);
3051234956Sluigi
3052260368Sluigi	if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1
3053260368Sluigi			&& g.virt_header != VIRT_HDR_2) {
3054260368Sluigi		D("bad virtio-net-header length");
3055341457Svmaffione		usage(-1);
3056260368Sluigi	}
3057260368Sluigi
3058246896Sluigi    if (g.dev_type == DEV_TAP) {
3059246896Sluigi	D("want to use tap %s", g.ifname);
3060246896Sluigi	g.main_fd = tap_alloc(g.ifname);
3061246896Sluigi	if (g.main_fd < 0) {
3062246896Sluigi		D("cannot open tap %s", g.ifname);
3063341457Svmaffione		usage(-1);
3064246896Sluigi	}
3065260700Sluigi#ifndef NO_PCAP
3066260700Sluigi    } else if (g.dev_type == DEV_PCAP) {
3067246896Sluigi	char pcap_errbuf[PCAP_ERRBUF_SIZE];
3068246896Sluigi
3069246896Sluigi	pcap_errbuf[0] = '\0'; // init the buffer
3070270063Sluigi	g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf);
3071234956Sluigi	if (g.p == NULL) {
3072246896Sluigi		D("cannot open pcap on %s", g.ifname);
3073341457Svmaffione		usage(-1);
3074234956Sluigi	}
3075270063Sluigi	g.main_fd = pcap_fileno(g.p);
3076270063Sluigi	D("using pcap on %s fileno %d", g.ifname, g.main_fd);
3077260700Sluigi#endif /* !NO_PCAP */
3078260700Sluigi    } else if (g.dummy_send) { /* but DEV_NETMAP */
3079257529Sluigi	D("using a dummy send routine");
3080234956Sluigi    } else {
3081341457Svmaffione	struct nm_desc base_nmd;
3082341457Svmaffione	char errmsg[MAXERRMSG];
3083341457Svmaffione	u_int flags;
3084261909Sluigi
3085261909Sluigi	bzero(&base_nmd, sizeof(base_nmd));
3086261909Sluigi
3087341457Svmaffione	parse_nmr_config(g.nmr_config, &base_nmd.req);
3088341457Svmaffione
3089341457Svmaffione	base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
3090341457Svmaffione
3091341457Svmaffione	if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) {
3092341457Svmaffione		D("Invalid name '%s': %s", g.ifname, errmsg);
3093341457Svmaffione		goto out;
3094261909Sluigi	}
3095261909Sluigi
3096227614Sluigi	/*
3097261909Sluigi	 * Open the netmap device using nm_open().
3098227614Sluigi	 *
3099227614Sluigi	 * protocol stack and may cause a reset of the card,
3100227614Sluigi	 * which in turn may take some time for the PHY to
3101261909Sluigi	 * reconfigure. We do the open here to have time to reset.
3102227614Sluigi	 */
3103341457Svmaffione	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
3104341457Svmaffione		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
3105341457Svmaffione	if (g.nthreads > 1) {
3106341457Svmaffione		base_nmd.req.nr_flags &= ~NR_REG_MASK;
3107341457Svmaffione		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
3108341457Svmaffione		base_nmd.req.nr_ringid = 0;
3109341457Svmaffione	}
3110341457Svmaffione	g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd);
3111261909Sluigi	if (g.nmd == NULL) {
3112261909Sluigi		D("Unable to open %s: %s", g.ifname, strerror(errno));
3113261909Sluigi		goto out;
3114227614Sluigi	}
3115261909Sluigi	g.main_fd = g.nmd->fd;
3116341457Svmaffione	D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
3117341457Svmaffione				g.nmd->mem);
3118227614Sluigi
3119341457Svmaffione	if (g.virt_header) {
3120341457Svmaffione		/* Set the virtio-net header length, since the user asked
3121341457Svmaffione		 * for it explicitely. */
3122341457Svmaffione		set_vnet_hdr_len(&g);
3123341457Svmaffione	} else {
3124341457Svmaffione		/* Check whether the netmap port we opened requires us to send
3125341457Svmaffione		 * and receive frames with virtio-net header. */
3126341457Svmaffione		get_vnet_hdr_len(&g);
3127341457Svmaffione	}
3128341457Svmaffione
3129341457Svmaffione	/* get num of queues in tx or rx */
3130341457Svmaffione	if (g.td_type == TD_TYPE_SENDER)
3131270063Sluigi		devqueues = g.nmd->req.nr_tx_rings;
3132341457Svmaffione	else
3133270063Sluigi		devqueues = g.nmd->req.nr_rx_rings;
3134261909Sluigi
3135227614Sluigi	/* validate provided nthreads. */
3136227614Sluigi	if (g.nthreads < 1 || g.nthreads > devqueues) {
3137227614Sluigi		D("bad nthreads %d, have %d queues", g.nthreads, devqueues);
3138227614Sluigi		// continue, fail later
3139227614Sluigi	}
3140227614Sluigi
3141342035Svmaffione	if (g.td_type == TD_TYPE_SENDER) {
3142342035Svmaffione		int mtu = get_if_mtu(&g);
3143342035Svmaffione
3144342035Svmaffione		if (mtu > 0 && g.pkt_size > mtu) {
3145342035Svmaffione			D("pkt_size (%d) must be <= mtu (%d)",
3146342035Svmaffione				g.pkt_size, mtu);
3147342035Svmaffione			return -1;
3148342035Svmaffione		}
3149342035Svmaffione	}
3150342035Svmaffione
3151260700Sluigi	if (verbose) {
3152261909Sluigi		struct netmap_if *nifp = g.nmd->nifp;
3153261909Sluigi		struct nmreq *req = &g.nmd->req;
3154227614Sluigi
3155261909Sluigi		D("nifp at offset %d, %d tx %d rx region %d",
3156261909Sluigi		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
3157261909Sluigi		    req->nr_arg2);
3158261909Sluigi		for (i = 0; i <= req->nr_tx_rings; i++) {
3159270063Sluigi			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
3160341457Svmaffione			D("   TX%d at 0x%p slots %d", i,
3161341457Svmaffione			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
3162260700Sluigi		}
3163261909Sluigi		for (i = 0; i <= req->nr_rx_rings; i++) {
3164270063Sluigi			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
3165341457Svmaffione			D("   RX%d at 0x%p slots %d", i,
3166341457Svmaffione			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
3167260700Sluigi		}
3168260700Sluigi	}
3169227614Sluigi
3170227614Sluigi	/* Print some debug information. */
3171227614Sluigi	fprintf(stdout,
3172227614Sluigi		"%s %s: %d queues, %d threads and %d cpus.\n",
3173341457Svmaffione		(g.td_type == TD_TYPE_SENDER) ? "Sending on" :
3174341457Svmaffione			((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" :
3175341457Svmaffione			"Working on"),
3176246896Sluigi		g.ifname,
3177227614Sluigi		devqueues,
3178227614Sluigi		g.nthreads,
3179227614Sluigi		g.cpus);
3180341457Svmaffione	if (g.td_type == TD_TYPE_SENDER) {
3181227614Sluigi		fprintf(stdout, "%s -> %s (%s -> %s)\n",
3182246896Sluigi			g.src_ip.name, g.dst_ip.name,
3183246896Sluigi			g.src_mac.name, g.dst_mac.name);
3184227614Sluigi	}
3185261909Sluigi
3186261909Sluigiout:
3187227614Sluigi	/* Exit if something went wrong. */
3188246896Sluigi	if (g.main_fd < 0) {
3189227614Sluigi		D("aborting");
3190341457Svmaffione		usage(-1);
3191227614Sluigi	}
3192234956Sluigi    }
3193227614Sluigi
3194261909Sluigi
3195234956Sluigi	if (g.options) {
3196341457Svmaffione		D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n",
3197234956Sluigi			g.options & OPT_PREFETCH ? " prefetch" : "",
3198234956Sluigi			g.options & OPT_ACCESS ? " access" : "",
3199234956Sluigi			g.options & OPT_MEMCPY ? " memcpy" : "",
3200251426Sluigi			g.options & OPT_INDIRECT ? " indirect" : "",
3201341457Svmaffione			g.options & OPT_COPY ? " copy" : "",
3202341457Svmaffione			g.options & OPT_RUBBISH ? " rubbish " : "");
3203234956Sluigi	}
3204257529Sluigi
3205257529Sluigi	g.tx_period.tv_sec = g.tx_period.tv_nsec = 0;
3206257529Sluigi	if (g.tx_rate > 0) {
3207257529Sluigi		/* try to have at least something every second,
3208260368Sluigi		 * reducing the burst size to some 0.01s worth of data
3209257529Sluigi		 * (but no less than one full set of fragments)
3210257529Sluigi	 	 */
3211260368Sluigi		uint64_t x;
3212260368Sluigi		int lim = (g.tx_rate)/300;
3213260368Sluigi		if (g.burst > lim)
3214260368Sluigi			g.burst = lim;
3215341457Svmaffione		if (g.burst == 0)
3216341457Svmaffione			g.burst = 1;
3217260368Sluigi		x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate;
3218260368Sluigi		g.tx_period.tv_nsec = x;
3219257529Sluigi		g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000;
3220257529Sluigi		g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000;
3221251132Sluigi	}
3222341457Svmaffione	if (g.td_type == TD_TYPE_SENDER)
3223257529Sluigi	    D("Sending %d packets every  %ld.%09ld s",
3224257529Sluigi			g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec);
3225227614Sluigi	/* Install ^C handler. */
3226227614Sluigi	global_nthreads = g.nthreads;
3227341457Svmaffione	sigemptyset(&ss);
3228341457Svmaffione	sigaddset(&ss, SIGINT);
3229341457Svmaffione	/* block SIGINT now, so that all created threads will inherit the mask */
3230341457Svmaffione	if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) {
3231341457Svmaffione		D("failed to block SIGINT: %s", strerror(errno));
3232341457Svmaffione	}
3233341457Svmaffione	start_threads(&g);
3234341457Svmaffione	/* Install the handler and re-enable SIGINT for the main thread */
3235341457Svmaffione	memset(&sa, 0, sizeof(sa));
3236341457Svmaffione	sa.sa_handler = sigint_h;
3237341457Svmaffione	if (sigaction(SIGINT, &sa, NULL) < 0) {
3238341457Svmaffione		D("failed to install ^C handler: %s", strerror(errno));
3239341457Svmaffione	}
3240227614Sluigi
3241341457Svmaffione	if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) {
3242341457Svmaffione		D("failed to re-enable SIGINT: %s", strerror(errno));
3243341457Svmaffione	}
3244246896Sluigi	main_thread(&g);
3245341457Svmaffione	free(targs);
3246246896Sluigi	return 0;
3247246896Sluigi}
3248227614Sluigi
3249227614Sluigi/* end of file */
3250