1b97eb69luigi/*
241068e3luigi * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
3cdb8056luigi * Copyright (C) 2013-2015 Universita` di Pisa. All rights reserved.
4b97eb69luigi *
5b97eb69luigi * Redistribution and use in source and binary forms, with or without
6b97eb69luigi * modification, are permitted provided that the following conditions
7b97eb69luigi * are met:
8298ffdeluigi *   1. Redistributions of source code must retain the above copyright
9298ffdeluigi *      notice, this list of conditions and the following disclaimer.
10298ffdeluigi *   2. Redistributions in binary form must reproduce the above copyright
11298ffdeluigi *      notice, this list of conditions and the following disclaimer in the
12b97eb69luigi *    documentation and/or other materials provided with the distribution.
13b97eb69luigi *
14b97eb69luigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b97eb69luigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b97eb69luigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b97eb69luigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b97eb69luigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b97eb69luigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b97eb69luigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b97eb69luigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b97eb69luigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b97eb69luigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b97eb69luigi * SUCH DAMAGE.
25b97eb69luigi */
26b97eb69luigi
27b97eb69luigi/*
28b97eb69luigi * $FreeBSD$
2941bc3f2luigi * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $
30b97eb69luigi *
31b97eb69luigi * Example program to show how to build a multithreaded packet
32b97eb69luigi * source/sink using the netmap device.
33b97eb69luigi *
34b97eb69luigi * In this example we create a programmable number of threads
35b97eb69luigi * to take care of all the queues of the interface used to
36b97eb69luigi * send or receive traffic.
37b97eb69luigi *
38b97eb69luigi */
39b97eb69luigi
4051f5fa4luigi#define _GNU_SOURCE	/* for CPU_SET() */
4151f5fa4luigi#include <stdio.h>
4251f5fa4luigi#define NETMAP_WITH_LIBS
4351f5fa4luigi#include <net/netmap_user.h>
4451f5fa4luigi
451a47ce1luigi
46018a784luigi#include <ctype.h>	// isprint()
4751f5fa4luigi#include <unistd.h>	// sysconf()
4851f5fa4luigi#include <sys/poll.h>
4951f5fa4luigi#include <arpa/inet.h>	/* ntohs */
50cdb8056luigi#ifndef _WIN32
5151f5fa4luigi#include <sys/sysctl.h>	/* sysctl */
52cdb8056luigi#endif
5351f5fa4luigi#include <ifaddrs.h>	/* getifaddrs */
5451f5fa4luigi#include <net/ethernet.h>
5551f5fa4luigi#include <netinet/in.h>
5651f5fa4luigi#include <netinet/ip.h>
5751f5fa4luigi#include <netinet/udp.h>
5804d6605vmaffione#include <netinet/ip6.h>
5904d6605vmaffione#ifdef linux
6004d6605vmaffione#define IPV6_VERSION	0x60
6104d6605vmaffione#define IPV6_DEFHLIM	64
6204d6605vmaffione#endif
63cdb8056luigi#include <assert.h>
64cdb8056luigi#include <math.h>
6551f5fa4luigi
6651f5fa4luigi#include <pthread.h>
67018a784luigi
68f11710fluigi#ifndef NO_PCAP
69f11710fluigi#include <pcap/pcap.h>
70f11710fluigi#endif
7151f5fa4luigi
72cdb8056luigi#include "ctrs.h"
73cdb8056luigi
7404d6605vmaffionestatic void usage(int);
7504d6605vmaffione
76cdb8056luigi#ifdef _WIN32
77cdb8056luigi#define cpuset_t        DWORD_PTR   //uint64_t
78cdb8056luigistatic inline void CPU_ZERO(cpuset_t *p)
79cdb8056luigi{
8004d6605vmaffione	*p = 0;
81cdb8056luigi}
82cdb8056luigi
83cdb8056luigistatic inline void CPU_SET(uint32_t i, cpuset_t *p)
84cdb8056luigi{
8504d6605vmaffione	*p |= 1<< (i & 0x3f);
86cdb8056luigi}
87cdb8056luigi
88cdb8056luigi#define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c)    //((void)a, 0)
89cdb8056luigi#define TAP_CLONEDEV	"/dev/tap"
90cdb8056luigi#define AF_LINK	18	//defined in winsocks.h
91cdb8056luigi#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME
92cdb8056luigi#include <net/if_dl.h>
93cdb8056luigi
94cdb8056luigi/*
95cdb8056luigi * Convert an ASCII representation of an ethernet address to
96cdb8056luigi * binary form.
97cdb8056luigi */
98cdb8056luigistruct ether_addr *
99cdb8056luigiether_aton(const char *a)
100cdb8056luigi{
101cdb8056luigi	int i;
102cdb8056luigi	static struct ether_addr o;
103cdb8056luigi	unsigned int o0, o1, o2, o3, o4, o5;
104cdb8056luigi
105cdb8056luigi	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
106cdb8056luigi
107cdb8056luigi	if (i != 6)
108cdb8056luigi		return (NULL);
109cdb8056luigi
110cdb8056luigi	o.octet[0]=o0;
111cdb8056luigi	o.octet[1]=o1;
112cdb8056luigi	o.octet[2]=o2;
113cdb8056luigi	o.octet[3]=o3;
114cdb8056luigi	o.octet[4]=o4;
115cdb8056luigi	o.octet[5]=o5;
116cdb8056luigi
117cdb8056luigi	return ((struct ether_addr *)&o);
118cdb8056luigi}
119cdb8056luigi
120cdb8056luigi/*
121cdb8056luigi * Convert a binary representation of an ethernet address to
122cdb8056luigi * an ASCII string.
123cdb8056luigi */
124cdb8056luigichar *
125cdb8056luigiether_ntoa(const struct ether_addr *n)
126cdb8056luigi{
127cdb8056luigi	int i;
128cdb8056luigi	static char a[18];
129cdb8056luigi
130cdb8056luigi	i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x",
131cdb8056luigi	    n->octet[0], n->octet[1], n->octet[2],
132cdb8056luigi	    n->octet[3], n->octet[4], n->octet[5]);
133cdb8056luigi	return (i < 17 ? NULL : (char *)&a);
134cdb8056luigi}
135cdb8056luigi#endif /* _WIN32 */
136cdb8056luigi
13751f5fa4luigi#ifdef linux
13851f5fa4luigi
13951f5fa4luigi#define cpuset_t        cpu_set_t
14051f5fa4luigi
14151f5fa4luigi#define ifr_flagshigh  ifr_flags        /* only the low 16 bits here */
14251f5fa4luigi#define IFF_PPROMISC   IFF_PROMISC      /* IFF_PPROMISC does not exist */
14351f5fa4luigi#include <linux/ethtool.h>
14451f5fa4luigi#include <linux/sockios.h>
14551f5fa4luigi
14651f5fa4luigi#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME
14751f5fa4luigi#include <netinet/ether.h>      /* ether_aton */
14851f5fa4luigi#include <linux/if_packet.h>    /* sockaddr_ll */
14951f5fa4luigi#endif  /* linux */
15051f5fa4luigi
15151f5fa4luigi#ifdef __FreeBSD__
15251f5fa4luigi#include <sys/endian.h> /* le64toh */
15351f5fa4luigi#include <machine/param.h>
15451f5fa4luigi
15551f5fa4luigi#include <pthread_np.h> /* pthread w/ affinity */
15651f5fa4luigi#include <sys/cpuset.h> /* cpu_set */
15751f5fa4luigi#include <net/if_dl.h>  /* LLADDR */
15851f5fa4luigi#endif  /* __FreeBSD__ */
15951f5fa4luigi
16051f5fa4luigi#ifdef __APPLE__
16151f5fa4luigi
16251f5fa4luigi#define cpuset_t        uint64_t        // XXX
16351f5fa4luigistatic inline void CPU_ZERO(cpuset_t *p)
16451f5fa4luigi{
16504d6605vmaffione	*p = 0;
16651f5fa4luigi}
16751f5fa4luigi
16851f5fa4luigistatic inline void CPU_SET(uint32_t i, cpuset_t *p)
16951f5fa4luigi{
17004d6605vmaffione	*p |= 1<< (i & 0x3f);
17151f5fa4luigi}
17251f5fa4luigi
17351f5fa4luigi#define pthread_setaffinity_np(a, b, c) ((void)a, 0)
17451f5fa4luigi
17551f5fa4luigi#define ifr_flagshigh  ifr_flags        // XXX
17651f5fa4luigi#define IFF_PPROMISC   IFF_PROMISC
17751f5fa4luigi#include <net/if_dl.h>  /* LLADDR */
17851f5fa4luigi#define clock_gettime(a,b)      \
17904d6605vmaffione	do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
18051f5fa4luigi#endif  /* __APPLE__ */
18151f5fa4luigi
18241bc3f2luigiconst char *default_payload="netmap pkt-gen DIRECT payload\n"
18341bc3f2luigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
18441bc3f2luigi
18541bc3f2luigiconst char *indirect_payload="netmap pkt-gen indirect payload\n"
186b97eb69luigi	"http://info.iet.unipi.it/~luigi/netmap/ ";
187b97eb69luigi
188b97eb69luigiint verbose = 0;
18904d6605vmaffioneint normalize = 1;
19041068e3luigi
19141068e3luigi#define VIRT_HDR_1	10	/* length of a base vnet-hdr */
19241068e3luigi#define VIRT_HDR_2	12	/* length of the extenede vnet-hdr */
19341068e3luigi#define VIRT_HDR_MAX	VIRT_HDR_2
19441068e3luigistruct virt_header {
19541068e3luigi	uint8_t fields[VIRT_HDR_MAX];
19641068e3luigi};
19741068e3luigi
19843ef1e7vmaffione#define MAX_BODYSIZE	65536
1993ab69a2luigi
200b97eb69luigistruct pkt {
20141068e3luigi	struct virt_header vh;
202b97eb69luigi	struct ether_header eh;
20304d6605vmaffione	union {
20404d6605vmaffione		struct {
20504d6605vmaffione			struct ip ip;
20604d6605vmaffione			struct udphdr udp;
20704d6605vmaffione			uint8_t body[MAX_BODYSIZE];	/* hardwired */
20804d6605vmaffione		} ipv4;
20904d6605vmaffione		struct {
21004d6605vmaffione			struct ip6_hdr ip;
21104d6605vmaffione			struct udphdr udp;
21204d6605vmaffione			uint8_t body[MAX_BODYSIZE];	/* hardwired */
21304d6605vmaffione		} ipv6;
21404d6605vmaffione	};
215b97eb69luigi} __attribute__((__packed__));
216b97eb69luigi
21704d6605vmaffione#define	PKT(p, f, af)	\
21804d6605vmaffione    ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f)
21904d6605vmaffione
2201a47ce1luigistruct ip_range {
2211a47ce1luigi	char *name;
22204d6605vmaffione	union {
22304d6605vmaffione		struct {
22404d6605vmaffione			uint32_t start, end; /* same as struct in_addr */
22504d6605vmaffione		} ipv4;
22604d6605vmaffione		struct {
22704d6605vmaffione			struct in6_addr start, end;
22804d6605vmaffione			uint8_t sgroup, egroup;
22904d6605vmaffione		} ipv6;
23004d6605vmaffione	};
23141bc3f2luigi	uint16_t port0, port1;
2321a47ce1luigi};
2331a47ce1luigi
2341a47ce1luigistruct mac_range {
2351a47ce1luigi	char *name;
2361a47ce1luigi	struct ether_addr start, end;
2371a47ce1luigi};
2381a47ce1luigi
23951f5fa4luigi/* ifname can be netmap:foo-xxxx */
24051f5fa4luigi#define MAX_IFNAMELEN	64	/* our buffer for ifname */
2413ab69a2luigi#define MAX_PKTSIZE	MAX_BODYSIZE	/* XXX: + IP_HDR + ETH_HDR */
2423ab69a2luigi
2433ab69a2luigi/* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
2443ab69a2luigistruct tstamp {
2453ab69a2luigi	uint32_t sec;
2463ab69a2luigi	uint32_t nsec;
2473ab69a2luigi};
2483ab69a2luigi
249b97eb69luigi/*
250b97eb69luigi * global arguments for all threads
251b97eb69luigi */
2521a47ce1luigi
253b97eb69luigistruct glob_arg {
25404d6605vmaffione	int af;		/* address family AF_INET/AF_INET6 */
2551a47ce1luigi	struct ip_range src_ip;
2561a47ce1luigi	struct ip_range dst_ip;
2571a47ce1luigi	struct mac_range dst_mac;
2581a47ce1luigi	struct mac_range src_mac;
259b97eb69luigi	int pkt_size;
26004d6605vmaffione	int pkt_min_size;
261b97eb69luigi	int burst;
2621a47ce1luigi	int forever;
263cdb8056luigi	uint64_t npackets;	/* total packets to send */
26404d6605vmaffione	int frags;		/* fragments per packet */
26543ef1e7vmaffione	u_int frag_size;	/* size of each fragment */
266b97eb69luigi	int nthreads;
267cdb8056luigi	int cpus;	/* cpus used for running */
268cdb8056luigi	int system_cpus;	/* cpus on the system */
269cdb8056luigi
2705561327luigi	int options;	/* testing */
2715561327luigi#define OPT_PREFETCH	1
2725561327luigi#define OPT_ACCESS	2
2735561327luigi#define OPT_COPY	4
2745561327luigi#define OPT_MEMCPY	8
2751a47ce1luigi#define OPT_TS		16	/* add a timestamp */
276018a784luigi#define OPT_INDIRECT	32	/* use indirect buffers, tx only */
277018a784luigi#define OPT_DUMP	64	/* dump rx/tx traffic */
278cdb8056luigi#define OPT_RUBBISH	256	/* send wathever the buffers contain */
279fcf33fcadrian#define OPT_RANDOM_SRC  512
280fcf33fcadrian#define OPT_RANDOM_DST  1024
281cdb8056luigi#define OPT_PPS_STATS   2048
2821a47ce1luigi	int dev_type;
283f11710fluigi#ifndef NO_PCAP
284b97eb69luigi	pcap_t *p;
285f11710fluigi#endif
286b97eb69luigi
2873136540luigi	int tx_rate;
2883136540luigi	struct timespec tx_period;
2893136540luigi
2901a47ce1luigi	int affinity;
2911a47ce1luigi	int main_fd;
29251f5fa4luigi	struct nm_desc *nmd;
293f11710fluigi	int report_interval;		/* milliseconds between prints */
2941a47ce1luigi	void *(*td_body)(void *);
295cdb8056luigi	int td_type;
2961a47ce1luigi	void *mmap_addr;
29751f5fa4luigi	char ifname[MAX_IFNAMELEN];
29841bc3f2luigi	char *nmr_config;
29941bc3f2luigi	int dummy_send;
30041068e3luigi	int virt_header;	/* send also the virt_header */
3013dea4f4gnn	char *packet_file;	/* -P option */
302cdb8056luigi#define	STATS_WIN	15
303cdb8056luigi	int win_idx;
304cdb8056luigi	int64_t win[STATS_WIN];
30504d6605vmaffione	int wait_link;
30604d6605vmaffione	int framing;		/* #bits of framing (for bw output) */
307