168b8534bSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. 337e3a6d3SLuigi Rizzo * Copyright (C) 2013-2015 Universita` di Pisa. All rights reserved. 468b8534bSLuigi Rizzo * 568b8534bSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 668b8534bSLuigi Rizzo * modification, are permitted provided that the following conditions 768b8534bSLuigi Rizzo * are met: 868b8534bSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 968b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 1068b8534bSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 1168b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 1268b8534bSLuigi Rizzo * documentation and/or other materials provided with the distribution. 1368b8534bSLuigi Rizzo * 1468b8534bSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1568b8534bSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1668b8534bSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1768b8534bSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1868b8534bSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1968b8534bSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2068b8534bSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2168b8534bSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2268b8534bSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2368b8534bSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2468b8534bSLuigi Rizzo * SUCH DAMAGE. 2568b8534bSLuigi Rizzo */ 2668b8534bSLuigi Rizzo 2768b8534bSLuigi Rizzo /* 2868b8534bSLuigi Rizzo * $FreeBSD$ 29ce3ee1e7SLuigi Rizzo * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $ 3068b8534bSLuigi Rizzo * 3168b8534bSLuigi Rizzo * Example program to show how to build a multithreaded packet 3268b8534bSLuigi Rizzo * source/sink using the netmap device. 3368b8534bSLuigi Rizzo * 3468b8534bSLuigi Rizzo * In this example we create a programmable number of threads 3568b8534bSLuigi Rizzo * to take care of all the queues of the interface used to 3668b8534bSLuigi Rizzo * send or receive traffic. 3768b8534bSLuigi Rizzo * 3868b8534bSLuigi Rizzo */ 3968b8534bSLuigi Rizzo 40f0ea3689SLuigi Rizzo #define _GNU_SOURCE /* for CPU_SET() */ 41f0ea3689SLuigi Rizzo #include <arpa/inet.h> /* ntohs */ 424bfe1a4fSVincenzo Maffione #include <assert.h> 434bfe1a4fSVincenzo Maffione #include <ctype.h> // isprint() 444bfe1a4fSVincenzo Maffione #include <errno.h> 454bfe1a4fSVincenzo Maffione #include <fcntl.h> 46f0ea3689SLuigi Rizzo #include <ifaddrs.h> /* getifaddrs */ 474bfe1a4fSVincenzo Maffione #include <libnetmap.h> 484bfe1a4fSVincenzo Maffione #include <math.h> 49f0ea3689SLuigi Rizzo #include <net/ethernet.h> 50f0ea3689SLuigi Rizzo #include <netinet/in.h> 51f0ea3689SLuigi Rizzo #include <netinet/ip.h> 5280ad548dSVincenzo Maffione #include <netinet/ip6.h> 534bfe1a4fSVincenzo Maffione #include <netinet/udp.h> 544bfe1a4fSVincenzo Maffione #ifndef NO_PCAP 554bfe1a4fSVincenzo Maffione #include <pcap/pcap.h> 564bfe1a4fSVincenzo Maffione #endif 574bfe1a4fSVincenzo Maffione #include <pthread.h> 584bfe1a4fSVincenzo Maffione #include <signal.h> 594bfe1a4fSVincenzo Maffione #include <stdio.h> 604bfe1a4fSVincenzo Maffione #include <stdlib.h> 614bfe1a4fSVincenzo Maffione #include <string.h> 624bfe1a4fSVincenzo Maffione #include <sys/ioctl.h> 634bfe1a4fSVincenzo Maffione #include <sys/poll.h> 644bfe1a4fSVincenzo Maffione #include <sys/stat.h> 654bfe1a4fSVincenzo Maffione #if !defined(_WIN32) && !defined(linux) 664bfe1a4fSVincenzo Maffione #include <sys/sysctl.h> /* sysctl */ 674bfe1a4fSVincenzo Maffione #endif 684bfe1a4fSVincenzo Maffione #include <sys/types.h> 694bfe1a4fSVincenzo Maffione #include <unistd.h> // sysconf() 7080ad548dSVincenzo Maffione #ifdef linux 7180ad548dSVincenzo Maffione #define IPV6_VERSION 0x60 7280ad548dSVincenzo Maffione #define IPV6_DEFHLIM 64 7380ad548dSVincenzo Maffione #endif 74f0ea3689SLuigi Rizzo 7537e3a6d3SLuigi Rizzo #include "ctrs.h" 7637e3a6d3SLuigi Rizzo 7780ad548dSVincenzo Maffione static void usage(int); 7880ad548dSVincenzo Maffione 7937e3a6d3SLuigi Rizzo #ifdef _WIN32 8037e3a6d3SLuigi Rizzo #define cpuset_t DWORD_PTR //uint64_t 8137e3a6d3SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 8237e3a6d3SLuigi Rizzo { 8337e3a6d3SLuigi Rizzo *p = 0; 8437e3a6d3SLuigi Rizzo } 8537e3a6d3SLuigi Rizzo 8637e3a6d3SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 8737e3a6d3SLuigi Rizzo { 8837e3a6d3SLuigi Rizzo *p |= 1<< (i & 0x3f); 8937e3a6d3SLuigi Rizzo } 9037e3a6d3SLuigi Rizzo 9137e3a6d3SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c) //((void)a, 0) 9237e3a6d3SLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 9337e3a6d3SLuigi Rizzo #define AF_LINK 18 //defined in winsocks.h 9437e3a6d3SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 9537e3a6d3SLuigi Rizzo #include <net/if_dl.h> 9637e3a6d3SLuigi Rizzo 9737e3a6d3SLuigi Rizzo /* 9837e3a6d3SLuigi Rizzo * Convert an ASCII representation of an ethernet address to 9937e3a6d3SLuigi Rizzo * binary form. 10037e3a6d3SLuigi Rizzo */ 10137e3a6d3SLuigi Rizzo struct ether_addr * 10237e3a6d3SLuigi Rizzo ether_aton(const char *a) 10337e3a6d3SLuigi Rizzo { 10437e3a6d3SLuigi Rizzo int i; 10537e3a6d3SLuigi Rizzo static struct ether_addr o; 10637e3a6d3SLuigi Rizzo unsigned int o0, o1, o2, o3, o4, o5; 10737e3a6d3SLuigi Rizzo 10837e3a6d3SLuigi Rizzo i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); 10937e3a6d3SLuigi Rizzo 11037e3a6d3SLuigi Rizzo if (i != 6) 11137e3a6d3SLuigi Rizzo return (NULL); 11237e3a6d3SLuigi Rizzo 11337e3a6d3SLuigi Rizzo o.octet[0]=o0; 11437e3a6d3SLuigi Rizzo o.octet[1]=o1; 11537e3a6d3SLuigi Rizzo o.octet[2]=o2; 11637e3a6d3SLuigi Rizzo o.octet[3]=o3; 11737e3a6d3SLuigi Rizzo o.octet[4]=o4; 11837e3a6d3SLuigi Rizzo o.octet[5]=o5; 11937e3a6d3SLuigi Rizzo 12037e3a6d3SLuigi Rizzo return ((struct ether_addr *)&o); 12137e3a6d3SLuigi Rizzo } 12237e3a6d3SLuigi Rizzo 12337e3a6d3SLuigi Rizzo /* 12437e3a6d3SLuigi Rizzo * Convert a binary representation of an ethernet address to 12537e3a6d3SLuigi Rizzo * an ASCII string. 12637e3a6d3SLuigi Rizzo */ 12737e3a6d3SLuigi Rizzo char * 12837e3a6d3SLuigi Rizzo ether_ntoa(const struct ether_addr *n) 12937e3a6d3SLuigi Rizzo { 13037e3a6d3SLuigi Rizzo int i; 13137e3a6d3SLuigi Rizzo static char a[18]; 13237e3a6d3SLuigi Rizzo 13337e3a6d3SLuigi Rizzo i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", 13437e3a6d3SLuigi Rizzo n->octet[0], n->octet[1], n->octet[2], 13537e3a6d3SLuigi Rizzo n->octet[3], n->octet[4], n->octet[5]); 13637e3a6d3SLuigi Rizzo return (i < 17 ? NULL : (char *)&a); 13737e3a6d3SLuigi Rizzo } 13837e3a6d3SLuigi Rizzo #endif /* _WIN32 */ 13937e3a6d3SLuigi Rizzo 140f0ea3689SLuigi Rizzo #ifdef linux 141f0ea3689SLuigi Rizzo 142f0ea3689SLuigi Rizzo #define cpuset_t cpu_set_t 143f0ea3689SLuigi Rizzo 144f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags /* only the low 16 bits here */ 145f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ 146f0ea3689SLuigi Rizzo #include <linux/ethtool.h> 147f0ea3689SLuigi Rizzo #include <linux/sockios.h> 148f0ea3689SLuigi Rizzo 149f0ea3689SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 150f0ea3689SLuigi Rizzo #include <netinet/ether.h> /* ether_aton */ 151f0ea3689SLuigi Rizzo #include <linux/if_packet.h> /* sockaddr_ll */ 152f0ea3689SLuigi Rizzo #endif /* linux */ 153f0ea3689SLuigi Rizzo 154f0ea3689SLuigi Rizzo #ifdef __FreeBSD__ 155f0ea3689SLuigi Rizzo #include <sys/endian.h> /* le64toh */ 156f0ea3689SLuigi Rizzo #include <machine/param.h> 157f0ea3689SLuigi Rizzo 158f0ea3689SLuigi Rizzo #include <pthread_np.h> /* pthread w/ affinity */ 159f0ea3689SLuigi Rizzo #include <sys/cpuset.h> /* cpu_set */ 160f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 161f0ea3689SLuigi Rizzo #endif /* __FreeBSD__ */ 162f0ea3689SLuigi Rizzo 163f0ea3689SLuigi Rizzo #ifdef __APPLE__ 164f0ea3689SLuigi Rizzo 165f0ea3689SLuigi Rizzo #define cpuset_t uint64_t // XXX 166f0ea3689SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 167f0ea3689SLuigi Rizzo { 168f0ea3689SLuigi Rizzo *p = 0; 169f0ea3689SLuigi Rizzo } 170f0ea3689SLuigi Rizzo 171f0ea3689SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 172f0ea3689SLuigi Rizzo { 173f0ea3689SLuigi Rizzo *p |= 1<< (i & 0x3f); 174f0ea3689SLuigi Rizzo } 175f0ea3689SLuigi Rizzo 176f0ea3689SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) ((void)a, 0) 177f0ea3689SLuigi Rizzo 178f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags // XXX 179f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC 180f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 181f0ea3689SLuigi Rizzo #define clock_gettime(a,b) \ 182f0ea3689SLuigi Rizzo do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) 183f0ea3689SLuigi Rizzo #endif /* __APPLE__ */ 184f0ea3689SLuigi Rizzo 1857eb32dc8SVincenzo Maffione static const char *default_payload = "netmap pkt-gen DIRECT payload\n" 186ce3ee1e7SLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 187ce3ee1e7SLuigi Rizzo 1887eb32dc8SVincenzo Maffione static const char *indirect_payload = "netmap pkt-gen indirect payload\n" 18968b8534bSLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 19068b8534bSLuigi Rizzo 1917eb32dc8SVincenzo Maffione static int verbose = 0; 1927eb32dc8SVincenzo Maffione static int normalize = 1; 19317885a7bSLuigi Rizzo 19417885a7bSLuigi Rizzo #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ 19517885a7bSLuigi Rizzo #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ 19617885a7bSLuigi Rizzo #define VIRT_HDR_MAX VIRT_HDR_2 19717885a7bSLuigi Rizzo struct virt_header { 19817885a7bSLuigi Rizzo uint8_t fields[VIRT_HDR_MAX]; 19917885a7bSLuigi Rizzo }; 20017885a7bSLuigi Rizzo 2019e53f3bdSVincenzo Maffione #define MAX_BODYSIZE 65536 2024bf50f18SLuigi Rizzo 20368b8534bSLuigi Rizzo struct pkt { 20417885a7bSLuigi Rizzo struct virt_header vh; 20568b8534bSLuigi Rizzo struct ether_header eh; 20680ad548dSVincenzo Maffione union { 20780ad548dSVincenzo Maffione struct { 20868b8534bSLuigi Rizzo struct ip ip; 20968b8534bSLuigi Rizzo struct udphdr udp; 21080ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 21180ad548dSVincenzo Maffione } ipv4; 21280ad548dSVincenzo Maffione struct { 21380ad548dSVincenzo Maffione struct ip6_hdr ip; 21480ad548dSVincenzo Maffione struct udphdr udp; 21580ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 21680ad548dSVincenzo Maffione } ipv6; 21780ad548dSVincenzo Maffione }; 21868b8534bSLuigi Rizzo } __attribute__((__packed__)); 21968b8534bSLuigi Rizzo 22080ad548dSVincenzo Maffione #define PKT(p, f, af) \ 22180ad548dSVincenzo Maffione ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f) 22280ad548dSVincenzo Maffione 223f8e4e36aSLuigi Rizzo struct ip_range { 2247eb32dc8SVincenzo Maffione const char *name; 22580ad548dSVincenzo Maffione union { 22680ad548dSVincenzo Maffione struct { 227ce3ee1e7SLuigi Rizzo uint32_t start, end; /* same as struct in_addr */ 22880ad548dSVincenzo Maffione } ipv4; 22980ad548dSVincenzo Maffione struct { 23080ad548dSVincenzo Maffione struct in6_addr start, end; 23180ad548dSVincenzo Maffione uint8_t sgroup, egroup; 23280ad548dSVincenzo Maffione } ipv6; 23380ad548dSVincenzo Maffione }; 234ce3ee1e7SLuigi Rizzo uint16_t port0, port1; 235f8e4e36aSLuigi Rizzo }; 236f8e4e36aSLuigi Rizzo 237f8e4e36aSLuigi Rizzo struct mac_range { 2387eb32dc8SVincenzo Maffione const char *name; 239f8e4e36aSLuigi Rizzo struct ether_addr start, end; 240f8e4e36aSLuigi Rizzo }; 241f8e4e36aSLuigi Rizzo 242f0ea3689SLuigi Rizzo /* ifname can be netmap:foo-xxxx */ 2434bfe1a4fSVincenzo Maffione #define MAX_IFNAMELEN 512 /* our buffer for ifname */ 2444bfe1a4fSVincenzo Maffione //#define MAX_PKTSIZE 1536 2454bf50f18SLuigi Rizzo #define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ 2464bf50f18SLuigi Rizzo 2474bf50f18SLuigi Rizzo /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ 2484bf50f18SLuigi Rizzo struct tstamp { 2494bf50f18SLuigi Rizzo uint32_t sec; 2504bf50f18SLuigi Rizzo uint32_t nsec; 2514bf50f18SLuigi Rizzo }; 2524bf50f18SLuigi Rizzo 25368b8534bSLuigi Rizzo /* 25468b8534bSLuigi Rizzo * global arguments for all threads 25568b8534bSLuigi Rizzo */ 256f8e4e36aSLuigi Rizzo 25768b8534bSLuigi Rizzo struct glob_arg { 25880ad548dSVincenzo Maffione int af; /* address family AF_INET/AF_INET6 */ 259f8e4e36aSLuigi Rizzo struct ip_range src_ip; 260f8e4e36aSLuigi Rizzo struct ip_range dst_ip; 261f8e4e36aSLuigi Rizzo struct mac_range dst_mac; 262f8e4e36aSLuigi Rizzo struct mac_range src_mac; 26368b8534bSLuigi Rizzo int pkt_size; 26480ad548dSVincenzo Maffione int pkt_min_size; 26568b8534bSLuigi Rizzo int burst; 266f8e4e36aSLuigi Rizzo int forever; 26737e3a6d3SLuigi Rizzo uint64_t npackets; /* total packets to send */ 268ce3ee1e7SLuigi Rizzo int frags; /* fragments per packet */ 2699e53f3bdSVincenzo Maffione u_int frag_size; /* size of each fragment */ 27068b8534bSLuigi Rizzo int nthreads; 27137e3a6d3SLuigi Rizzo int cpus; /* cpus used for running */ 27237e3a6d3SLuigi Rizzo int system_cpus; /* cpus on the system */ 27337e3a6d3SLuigi Rizzo 27499fb123fSLuigi Rizzo int options; /* testing */ 27599fb123fSLuigi Rizzo #define OPT_PREFETCH 1 27699fb123fSLuigi Rizzo #define OPT_ACCESS 2 27799fb123fSLuigi Rizzo #define OPT_COPY 4 27899fb123fSLuigi Rizzo #define OPT_MEMCPY 8 279f8e4e36aSLuigi Rizzo #define OPT_TS 16 /* add a timestamp */ 280b303f675SLuigi Rizzo #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ 281b303f675SLuigi Rizzo #define OPT_DUMP 64 /* dump rx/tx traffic */ 282ed188a7eSVincenzo Maffione #define OPT_RUBBISH 256 /* send whatever the buffers contain */ 28356717743SAdrian Chadd #define OPT_RANDOM_SRC 512 28456717743SAdrian Chadd #define OPT_RANDOM_DST 1024 28537e3a6d3SLuigi Rizzo #define OPT_PPS_STATS 2048 286f8e4e36aSLuigi Rizzo int dev_type; 287f2637526SLuigi Rizzo #ifndef NO_PCAP 28868b8534bSLuigi Rizzo pcap_t *p; 289f2637526SLuigi Rizzo #endif 29068b8534bSLuigi Rizzo 2911cb4c501SLuigi Rizzo int tx_rate; 2921cb4c501SLuigi Rizzo struct timespec tx_period; 2931cb4c501SLuigi Rizzo 294f8e4e36aSLuigi Rizzo int affinity; 295f8e4e36aSLuigi Rizzo int main_fd; 2964bfe1a4fSVincenzo Maffione struct nmport_d *nmd; 2974bfe1a4fSVincenzo Maffione uint32_t orig_mode; 298f2637526SLuigi Rizzo int report_interval; /* milliseconds between prints */ 299f8e4e36aSLuigi Rizzo void *(*td_body)(void *); 30037e3a6d3SLuigi Rizzo int td_type; 301f8e4e36aSLuigi Rizzo void *mmap_addr; 302f0ea3689SLuigi Rizzo char ifname[MAX_IFNAMELEN]; 3037eb32dc8SVincenzo Maffione const char *nmr_config; 304ce3ee1e7SLuigi Rizzo int dummy_send; 30517885a7bSLuigi Rizzo int virt_header; /* send also the virt_header */ 306f284c737SGeorge V. Neville-Neil char *packet_file; /* -P option */ 30737e3a6d3SLuigi Rizzo #define STATS_WIN 15 30837e3a6d3SLuigi Rizzo int win_idx; 30937e3a6d3SLuigi Rizzo int64_t win[STATS_WIN]; 31080ad548dSVincenzo Maffione int wait_link; 31180ad548dSVincenzo Maffione int framing; /* #bits of framing (for bw output) */ 31268b8534bSLuigi Rizzo }; 313f8e4e36aSLuigi Rizzo enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; 314f8e4e36aSLuigi Rizzo 3159e53f3bdSVincenzo Maffione enum { 3169e53f3bdSVincenzo Maffione TD_TYPE_SENDER = 1, 3179e53f3bdSVincenzo Maffione TD_TYPE_RECEIVER, 3189e53f3bdSVincenzo Maffione TD_TYPE_OTHER, 3199e53f3bdSVincenzo Maffione }; 32068b8534bSLuigi Rizzo 32168b8534bSLuigi Rizzo /* 32268b8534bSLuigi Rizzo * Arguments for a new thread. The same structure is used by 32368b8534bSLuigi Rizzo * the source and the sink 32468b8534bSLuigi Rizzo */ 32568b8534bSLuigi Rizzo struct targ { 32668b8534bSLuigi Rizzo struct glob_arg *g; 32768b8534bSLuigi Rizzo int used; 32868b8534bSLuigi Rizzo int completed; 3293fe77e68SEd Maste int cancel; 33068b8534bSLuigi Rizzo int fd; 3314bfe1a4fSVincenzo Maffione struct nmport_d *nmd; 33237e3a6d3SLuigi Rizzo /* these ought to be volatile, but they are 33337e3a6d3SLuigi Rizzo * only sampled and errors should not accumulate 33437e3a6d3SLuigi Rizzo */ 33537e3a6d3SLuigi Rizzo struct my_ctrs ctr; 33637e3a6d3SLuigi Rizzo 3371cb4c501SLuigi Rizzo struct timespec tic, toc; 33868b8534bSLuigi Rizzo int me; 33968b8534bSLuigi Rizzo pthread_t thread; 34068b8534bSLuigi Rizzo int affinity; 34168b8534bSLuigi Rizzo 34268b8534bSLuigi Rizzo struct pkt pkt; 343f284c737SGeorge V. Neville-Neil void *frame; 34480ad548dSVincenzo Maffione uint16_t seed[3]; 34580ad548dSVincenzo Maffione u_int frags; 34680ad548dSVincenzo Maffione u_int frag_size; 34768b8534bSLuigi Rizzo }; 34868b8534bSLuigi Rizzo 34980ad548dSVincenzo Maffione static __inline uint16_t 35080ad548dSVincenzo Maffione cksum_add(uint16_t sum, uint16_t a) 35180ad548dSVincenzo Maffione { 35280ad548dSVincenzo Maffione uint16_t res; 35368b8534bSLuigi Rizzo 35480ad548dSVincenzo Maffione res = sum + a; 35580ad548dSVincenzo Maffione return (res + (res < a)); 35680ad548dSVincenzo Maffione } 35780ad548dSVincenzo Maffione 35880ad548dSVincenzo Maffione static void 35980ad548dSVincenzo Maffione extract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port) 36080ad548dSVincenzo Maffione { 36180ad548dSVincenzo Maffione struct in_addr a; 36280ad548dSVincenzo Maffione char *pp; 36380ad548dSVincenzo Maffione 36480ad548dSVincenzo Maffione pp = strchr(name, ':'); 36580ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 36680ad548dSVincenzo Maffione *pp++ = '\0'; 36780ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 36880ad548dSVincenzo Maffione } 36980ad548dSVincenzo Maffione 37080ad548dSVincenzo Maffione inet_pton(AF_INET, name, &a); 37180ad548dSVincenzo Maffione *addr = ntohl(a.s_addr); 37280ad548dSVincenzo Maffione } 37380ad548dSVincenzo Maffione 37480ad548dSVincenzo Maffione static void 37580ad548dSVincenzo Maffione extract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port, 37680ad548dSVincenzo Maffione uint8_t *group) 37780ad548dSVincenzo Maffione { 37880ad548dSVincenzo Maffione char *pp; 37980ad548dSVincenzo Maffione 38080ad548dSVincenzo Maffione /* 38180ad548dSVincenzo Maffione * We accept IPv6 address in the following form: 38280ad548dSVincenzo Maffione * group@[2001:DB8::1001]:port (w/ brackets and port) 38380ad548dSVincenzo Maffione * group@[2001:DB8::1] (w/ brackets and w/o port) 38480ad548dSVincenzo Maffione * group@2001:DB8::1234 (w/o brackets and w/o port) 38580ad548dSVincenzo Maffione */ 38680ad548dSVincenzo Maffione pp = strchr(name, '@'); 38780ad548dSVincenzo Maffione if (pp != NULL) { 38880ad548dSVincenzo Maffione *pp++ = '\0'; 38980ad548dSVincenzo Maffione *group = (uint8_t)strtol(name, NULL, 0); 39080ad548dSVincenzo Maffione if (*group > 7) 39180ad548dSVincenzo Maffione *group = 7; 39280ad548dSVincenzo Maffione name = pp; 39380ad548dSVincenzo Maffione } 39480ad548dSVincenzo Maffione if (name[0] == '[') 39580ad548dSVincenzo Maffione name++; 39680ad548dSVincenzo Maffione pp = strchr(name, ']'); 39780ad548dSVincenzo Maffione if (pp != NULL) 39880ad548dSVincenzo Maffione *pp++ = '\0'; 39980ad548dSVincenzo Maffione if (pp != NULL && *pp != ':') 40080ad548dSVincenzo Maffione pp = NULL; 40180ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 40280ad548dSVincenzo Maffione *pp++ = '\0'; 40380ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 40480ad548dSVincenzo Maffione } 40580ad548dSVincenzo Maffione inet_pton(AF_INET6, name, addr); 40680ad548dSVincenzo Maffione } 407f8e4e36aSLuigi Rizzo /* 408f8e4e36aSLuigi Rizzo * extract the extremes from a range of ipv4 addresses. 409f8e4e36aSLuigi Rizzo * addr_lo[-addr_hi][:port_lo[-port_hi]] 410f8e4e36aSLuigi Rizzo */ 41180ad548dSVincenzo Maffione static int 41280ad548dSVincenzo Maffione extract_ip_range(struct ip_range *r, int af) 413f8e4e36aSLuigi Rizzo { 41480ad548dSVincenzo Maffione char *name, *ap, start[INET6_ADDRSTRLEN]; 41580ad548dSVincenzo Maffione char end[INET6_ADDRSTRLEN]; 416ce3ee1e7SLuigi Rizzo struct in_addr a; 41780ad548dSVincenzo Maffione uint32_t tmp; 418f8e4e36aSLuigi Rizzo 41917885a7bSLuigi Rizzo if (verbose) 420f8e4e36aSLuigi Rizzo D("extract IP range from %s", r->name); 421ce3ee1e7SLuigi Rizzo 42280ad548dSVincenzo Maffione name = strdup(r->name); 42380ad548dSVincenzo Maffione if (name == NULL) { 42480ad548dSVincenzo Maffione D("strdup failed"); 42580ad548dSVincenzo Maffione usage(-1); 42680ad548dSVincenzo Maffione } 427ce3ee1e7SLuigi Rizzo /* the first - splits start/end of range */ 42880ad548dSVincenzo Maffione ap = strchr(name, '-'); 42980ad548dSVincenzo Maffione if (ap != NULL) 430ce3ee1e7SLuigi Rizzo *ap++ = '\0'; 43180ad548dSVincenzo Maffione r->port0 = 1234; /* default port */ 43280ad548dSVincenzo Maffione if (af == AF_INET6) { 43380ad548dSVincenzo Maffione r->ipv6.sgroup = 7; /* default group */ 43480ad548dSVincenzo Maffione extract_ipv6_addr(name, &r->ipv6.start, &r->port0, 43580ad548dSVincenzo Maffione &r->ipv6.sgroup); 43680ad548dSVincenzo Maffione } else 43780ad548dSVincenzo Maffione extract_ipv4_addr(name, &r->ipv4.start, &r->port0); 43880ad548dSVincenzo Maffione 43980ad548dSVincenzo Maffione r->port1 = r->port0; 44080ad548dSVincenzo Maffione if (af == AF_INET6) { 44180ad548dSVincenzo Maffione if (ap != NULL) { 44280ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 44380ad548dSVincenzo Maffione extract_ipv6_addr(ap, &r->ipv6.end, &r->port1, 44480ad548dSVincenzo Maffione &r->ipv6.egroup); 44580ad548dSVincenzo Maffione } else { 44680ad548dSVincenzo Maffione r->ipv6.end = r->ipv6.start; 44780ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 448ce3ee1e7SLuigi Rizzo } 44980ad548dSVincenzo Maffione } else { 45080ad548dSVincenzo Maffione if (ap != NULL) { 45180ad548dSVincenzo Maffione extract_ipv4_addr(ap, &r->ipv4.end, &r->port1); 45280ad548dSVincenzo Maffione if (r->ipv4.start > r->ipv4.end) { 45380ad548dSVincenzo Maffione tmp = r->ipv4.end; 45480ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 45580ad548dSVincenzo Maffione r->ipv4.start = tmp; 456ce3ee1e7SLuigi Rizzo } 45780ad548dSVincenzo Maffione } else 45880ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 459ce3ee1e7SLuigi Rizzo } 46080ad548dSVincenzo Maffione 461ce3ee1e7SLuigi Rizzo if (r->port0 > r->port1) { 46280ad548dSVincenzo Maffione tmp = r->port0; 463f8e4e36aSLuigi Rizzo r->port0 = r->port1; 464ce3ee1e7SLuigi Rizzo r->port1 = tmp; 465f8e4e36aSLuigi Rizzo } 46680ad548dSVincenzo Maffione if (af == AF_INET) { 46780ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.start); 46880ad548dSVincenzo Maffione inet_ntop(af, &a, start, sizeof(start)); 46980ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.end); 47080ad548dSVincenzo Maffione inet_ntop(af, &a, end, sizeof(end)); 47180ad548dSVincenzo Maffione } else { 47280ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.start, start, sizeof(start)); 47380ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.end, end, sizeof(end)); 474f8e4e36aSLuigi Rizzo } 47580ad548dSVincenzo Maffione if (af == AF_INET) 47680ad548dSVincenzo Maffione D("range is %s:%d to %s:%d", start, r->port0, end, r->port1); 47780ad548dSVincenzo Maffione else 47880ad548dSVincenzo Maffione D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup, 47980ad548dSVincenzo Maffione start, r->port0, r->ipv6.egroup, end, r->port1); 480ce3ee1e7SLuigi Rizzo 48180ad548dSVincenzo Maffione free(name); 48280ad548dSVincenzo Maffione if (r->port0 != r->port1 || 48380ad548dSVincenzo Maffione (af == AF_INET && r->ipv4.start != r->ipv4.end) || 48480ad548dSVincenzo Maffione (af == AF_INET6 && 48580ad548dSVincenzo Maffione !IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end))) 48680ad548dSVincenzo Maffione return (OPT_COPY); 48780ad548dSVincenzo Maffione return (0); 488f8e4e36aSLuigi Rizzo } 489f8e4e36aSLuigi Rizzo 49080ad548dSVincenzo Maffione static int 491f8e4e36aSLuigi Rizzo extract_mac_range(struct mac_range *r) 492f8e4e36aSLuigi Rizzo { 49380ad548dSVincenzo Maffione struct ether_addr *e; 49417885a7bSLuigi Rizzo if (verbose) 495f8e4e36aSLuigi Rizzo D("extract MAC range from %s", r->name); 49680ad548dSVincenzo Maffione 49780ad548dSVincenzo Maffione e = ether_aton(r->name); 49880ad548dSVincenzo Maffione if (e == NULL) { 49980ad548dSVincenzo Maffione D("invalid MAC address '%s'", r->name); 50080ad548dSVincenzo Maffione return 1; 50180ad548dSVincenzo Maffione } 50280ad548dSVincenzo Maffione bcopy(e, &r->start, 6); 50380ad548dSVincenzo Maffione bcopy(e, &r->end, 6); 504f8e4e36aSLuigi Rizzo #if 0 505f8e4e36aSLuigi Rizzo bcopy(targ->src_mac, eh->ether_shost, 6); 506f8e4e36aSLuigi Rizzo p = index(targ->g->src_mac, '-'); 507f8e4e36aSLuigi Rizzo if (p) 508f8e4e36aSLuigi Rizzo targ->src_mac_range = atoi(p+1); 509f8e4e36aSLuigi Rizzo 510f8e4e36aSLuigi Rizzo bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6); 511f8e4e36aSLuigi Rizzo bcopy(targ->dst_mac, eh->ether_dhost, 6); 512f8e4e36aSLuigi Rizzo p = index(targ->g->dst_mac, '-'); 513f8e4e36aSLuigi Rizzo if (p) 514f8e4e36aSLuigi Rizzo targ->dst_mac_range = atoi(p+1); 515f8e4e36aSLuigi Rizzo #endif 51617885a7bSLuigi Rizzo if (verbose) 517f8e4e36aSLuigi Rizzo D("%s starts at %s", r->name, ether_ntoa(&r->start)); 51880ad548dSVincenzo Maffione return 0; 519f8e4e36aSLuigi Rizzo } 520f8e4e36aSLuigi Rizzo 5219e53f3bdSVincenzo Maffione static int 5229e53f3bdSVincenzo Maffione get_if_mtu(const struct glob_arg *g) 5239e53f3bdSVincenzo Maffione { 5249e53f3bdSVincenzo Maffione struct ifreq ifreq; 5259e53f3bdSVincenzo Maffione int s, ret; 5264bfe1a4fSVincenzo Maffione const char *ifname = g->nmd->hdr.nr_name; 5274bfe1a4fSVincenzo Maffione size_t len; 5289e53f3bdSVincenzo Maffione 5294bfe1a4fSVincenzo Maffione if (!strncmp(g->ifname, "netmap:", 7) && !strchr(ifname, '{') 5304bfe1a4fSVincenzo Maffione && !strchr(ifname, '}')) { 5314bfe1a4fSVincenzo Maffione 5324bfe1a4fSVincenzo Maffione len = strlen(ifname); 5334bfe1a4fSVincenzo Maffione 5344bfe1a4fSVincenzo Maffione if (len > IFNAMSIZ) { 5354bfe1a4fSVincenzo Maffione D("'%s' too long, cannot ask for MTU", ifname); 5364bfe1a4fSVincenzo Maffione return -1; 5374bfe1a4fSVincenzo Maffione } 5389e53f3bdSVincenzo Maffione 5399e53f3bdSVincenzo Maffione s = socket(AF_INET, SOCK_DGRAM, 0); 5409e53f3bdSVincenzo Maffione if (s < 0) { 5419e53f3bdSVincenzo Maffione D("socket() failed: %s", strerror(errno)); 5429e53f3bdSVincenzo Maffione return s; 5439e53f3bdSVincenzo Maffione } 5449e53f3bdSVincenzo Maffione 5459e53f3bdSVincenzo Maffione memset(&ifreq, 0, sizeof(ifreq)); 5464bfe1a4fSVincenzo Maffione memcpy(ifreq.ifr_name, ifname, len); 5479e53f3bdSVincenzo Maffione 5489e53f3bdSVincenzo Maffione ret = ioctl(s, SIOCGIFMTU, &ifreq); 5499e53f3bdSVincenzo Maffione if (ret) { 5509e53f3bdSVincenzo Maffione D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno)); 5519e53f3bdSVincenzo Maffione } 5529e53f3bdSVincenzo Maffione 5534bfe1a4fSVincenzo Maffione close(s); 5544bfe1a4fSVincenzo Maffione 5559e53f3bdSVincenzo Maffione return ifreq.ifr_mtu; 5569e53f3bdSVincenzo Maffione } 5579e53f3bdSVincenzo Maffione 5589e53f3bdSVincenzo Maffione /* This is a pipe or a VALE port, where the MTU is very large, 5599e53f3bdSVincenzo Maffione * so we use some practical limit. */ 5609e53f3bdSVincenzo Maffione return 65536; 5619e53f3bdSVincenzo Maffione } 5629e53f3bdSVincenzo Maffione 56368b8534bSLuigi Rizzo static struct targ *targs; 56468b8534bSLuigi Rizzo static int global_nthreads; 56568b8534bSLuigi Rizzo 56668b8534bSLuigi Rizzo /* control-C handler */ 56768b8534bSLuigi Rizzo static void 568f8e4e36aSLuigi Rizzo sigint_h(int sig) 56968b8534bSLuigi Rizzo { 570f8e4e36aSLuigi Rizzo int i; 57168b8534bSLuigi Rizzo 572f8e4e36aSLuigi Rizzo (void)sig; /* UNUSED */ 57337e3a6d3SLuigi Rizzo D("received control-C on thread %p", (void *)pthread_self()); 574f8e4e36aSLuigi Rizzo for (i = 0; i < global_nthreads; i++) { 575f8e4e36aSLuigi Rizzo targs[i].cancel = 1; 576f8e4e36aSLuigi Rizzo } 57768b8534bSLuigi Rizzo } 57868b8534bSLuigi Rizzo 57968b8534bSLuigi Rizzo /* sysctl wrapper to return the number of active CPUs */ 58068b8534bSLuigi Rizzo static int 58168b8534bSLuigi Rizzo system_ncpus(void) 58268b8534bSLuigi Rizzo { 583f0ea3689SLuigi Rizzo int ncpus; 584f0ea3689SLuigi Rizzo #if defined (__FreeBSD__) 585f0ea3689SLuigi Rizzo int mib[2] = { CTL_HW, HW_NCPU }; 586f0ea3689SLuigi Rizzo size_t len = sizeof(mib); 58768b8534bSLuigi Rizzo sysctl(mib, 2, &ncpus, &len, NULL, 0); 588f0ea3689SLuigi Rizzo #elif defined(linux) 589f0ea3689SLuigi Rizzo ncpus = sysconf(_SC_NPROCESSORS_ONLN); 59037e3a6d3SLuigi Rizzo #elif defined(_WIN32) 59137e3a6d3SLuigi Rizzo { 59237e3a6d3SLuigi Rizzo SYSTEM_INFO sysinfo; 59337e3a6d3SLuigi Rizzo GetSystemInfo(&sysinfo); 59437e3a6d3SLuigi Rizzo ncpus = sysinfo.dwNumberOfProcessors; 59537e3a6d3SLuigi Rizzo } 596f0ea3689SLuigi Rizzo #else /* others */ 597f0ea3689SLuigi Rizzo ncpus = 1; 598f0ea3689SLuigi Rizzo #endif /* others */ 59968b8534bSLuigi Rizzo return (ncpus); 60068b8534bSLuigi Rizzo } 60168b8534bSLuigi Rizzo 602f8e4e36aSLuigi Rizzo #ifdef __linux__ 603f8e4e36aSLuigi Rizzo #define sockaddr_dl sockaddr_ll 604f8e4e36aSLuigi Rizzo #define sdl_family sll_family 605f8e4e36aSLuigi Rizzo #define AF_LINK AF_PACKET 606f8e4e36aSLuigi Rizzo #define LLADDR(s) s->sll_addr; 607f8e4e36aSLuigi Rizzo #include <linux/if_tun.h> 608f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/net/tun" 609f8e4e36aSLuigi Rizzo #endif /* __linux__ */ 610f8e4e36aSLuigi Rizzo 611f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 612f8e4e36aSLuigi Rizzo #include <net/if_tun.h> 613f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 614f8e4e36aSLuigi Rizzo #endif /* __FreeBSD */ 615f8e4e36aSLuigi Rizzo 616f8e4e36aSLuigi Rizzo #ifdef __APPLE__ 617f8e4e36aSLuigi Rizzo // #warning TAP not supported on apple ? 618f8e4e36aSLuigi Rizzo #include <net/if_utun.h> 619f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 620f8e4e36aSLuigi Rizzo #endif /* __APPLE__ */ 621f8e4e36aSLuigi Rizzo 622f8e4e36aSLuigi Rizzo 62368b8534bSLuigi Rizzo /* 624ce3ee1e7SLuigi Rizzo * parse the vale configuration in conf and put it in nmr. 625f0ea3689SLuigi Rizzo * Return the flag set if necessary. 62680ad548dSVincenzo Maffione * The configuration may consist of 1 to 4 numbers separated 627fc6eb28bSHiren Panchasara * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. 628ce3ee1e7SLuigi Rizzo * Missing numbers or zeroes stand for default values. 629ce3ee1e7SLuigi Rizzo * As an additional convenience, if exactly one number 630fc6eb28bSHiren Panchasara * is specified, then this is assigned to both #tx-slots and #rx-slots. 631fc6eb28bSHiren Panchasara * If there is no 4th number, then the 3rd is assigned to both #tx-rings 632ce3ee1e7SLuigi Rizzo * and #rx-rings. 633ce3ee1e7SLuigi Rizzo */ 6347eb32dc8SVincenzo Maffione static int 6354bfe1a4fSVincenzo Maffione parse_nmr_config(const char* conf, struct nmreq_register *nmr) 636ce3ee1e7SLuigi Rizzo { 637ce3ee1e7SLuigi Rizzo char *w, *tok; 638ce3ee1e7SLuigi Rizzo int i, v; 639ce3ee1e7SLuigi Rizzo 640ce3ee1e7SLuigi Rizzo if (conf == NULL || ! *conf) 641f0ea3689SLuigi Rizzo return 0; 642406e7723SVincenzo Maffione nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 643406e7723SVincenzo Maffione nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 644ce3ee1e7SLuigi Rizzo w = strdup(conf); 645ce3ee1e7SLuigi Rizzo for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 646ce3ee1e7SLuigi Rizzo v = atoi(tok); 647ce3ee1e7SLuigi Rizzo switch (i) { 648ce3ee1e7SLuigi Rizzo case 0: 649ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = v; 650ce3ee1e7SLuigi Rizzo break; 651ce3ee1e7SLuigi Rizzo case 1: 652ce3ee1e7SLuigi Rizzo nmr->nr_rx_slots = v; 653ce3ee1e7SLuigi Rizzo break; 654ce3ee1e7SLuigi Rizzo case 2: 655ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = v; 656ce3ee1e7SLuigi Rizzo break; 657ce3ee1e7SLuigi Rizzo case 3: 658ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings = v; 659ce3ee1e7SLuigi Rizzo break; 660ce3ee1e7SLuigi Rizzo default: 661ce3ee1e7SLuigi Rizzo D("ignored config: %s", tok); 662ce3ee1e7SLuigi Rizzo break; 663ce3ee1e7SLuigi Rizzo } 664ce3ee1e7SLuigi Rizzo } 665ce3ee1e7SLuigi Rizzo D("txr %d txd %d rxr %d rxd %d", 666ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings, nmr->nr_tx_slots, 667ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings, nmr->nr_rx_slots); 668ce3ee1e7SLuigi Rizzo free(w); 6694bfe1a4fSVincenzo Maffione return 0; 670ce3ee1e7SLuigi Rizzo } 671ce3ee1e7SLuigi Rizzo 672ce3ee1e7SLuigi Rizzo 673ce3ee1e7SLuigi Rizzo /* 67468b8534bSLuigi Rizzo * locate the src mac address for our interface, put it 67568b8534bSLuigi Rizzo * into the user-supplied buffer. return 0 if ok, -1 on error. 67668b8534bSLuigi Rizzo */ 67768b8534bSLuigi Rizzo static int 67868b8534bSLuigi Rizzo source_hwaddr(const char *ifname, char *buf) 67968b8534bSLuigi Rizzo { 68068b8534bSLuigi Rizzo struct ifaddrs *ifaphead, *ifap; 68168b8534bSLuigi Rizzo 68268b8534bSLuigi Rizzo if (getifaddrs(&ifaphead) != 0) { 68368b8534bSLuigi Rizzo D("getifaddrs %s failed", ifname); 68468b8534bSLuigi Rizzo return (-1); 68568b8534bSLuigi Rizzo } 68668b8534bSLuigi Rizzo 68768b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 68868b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 68968b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 69068b8534bSLuigi Rizzo uint8_t *mac; 69168b8534bSLuigi Rizzo 69268b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 69368b8534bSLuigi Rizzo continue; 69480ad548dSVincenzo Maffione if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) 69568b8534bSLuigi Rizzo continue; 69668b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 69768b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 69868b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 69968b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 70068b8534bSLuigi Rizzo if (verbose) 70168b8534bSLuigi Rizzo D("source hwaddr %s", buf); 70268b8534bSLuigi Rizzo break; 70368b8534bSLuigi Rizzo } 70468b8534bSLuigi Rizzo freeifaddrs(ifaphead); 70568b8534bSLuigi Rizzo return ifap ? 0 : 1; 70668b8534bSLuigi Rizzo } 70768b8534bSLuigi Rizzo 70868b8534bSLuigi Rizzo 70968b8534bSLuigi Rizzo /* set the thread affinity. */ 71068b8534bSLuigi Rizzo static int 71168b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 71268b8534bSLuigi Rizzo { 71368b8534bSLuigi Rizzo cpuset_t cpumask; 71468b8534bSLuigi Rizzo 71568b8534bSLuigi Rizzo if (i == -1) 71668b8534bSLuigi Rizzo return 0; 71768b8534bSLuigi Rizzo 71868b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 71968b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 72068b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 72168b8534bSLuigi Rizzo 72268b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 72317885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 72468b8534bSLuigi Rizzo return 1; 72568b8534bSLuigi Rizzo } 72668b8534bSLuigi Rizzo return 0; 72768b8534bSLuigi Rizzo } 72868b8534bSLuigi Rizzo 72980ad548dSVincenzo Maffione 73068b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 73180ad548dSVincenzo Maffione static uint32_t 732f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 73368b8534bSLuigi Rizzo { 73468b8534bSLuigi Rizzo const uint8_t *addr = data; 735f8e4e36aSLuigi Rizzo uint32_t i; 73668b8534bSLuigi Rizzo 737f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 738f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 7397eb32dc8SVincenzo Maffione sum += (uint16_t)ntohs(*((const uint16_t *)(addr + i))); 740f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 741f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 742f8e4e36aSLuigi Rizzo } 743f8e4e36aSLuigi Rizzo /* 744f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 745f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 746f8e4e36aSLuigi Rizzo * the high byte. 747f8e4e36aSLuigi Rizzo */ 748f8e4e36aSLuigi Rizzo if (i < len) { 749f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 750f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 751f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 752f8e4e36aSLuigi Rizzo } 753f8e4e36aSLuigi Rizzo return sum; 75468b8534bSLuigi Rizzo } 75568b8534bSLuigi Rizzo 75680ad548dSVincenzo Maffione static uint16_t 75780ad548dSVincenzo Maffione wrapsum(uint32_t sum) 758f8e4e36aSLuigi Rizzo { 759f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 760f8e4e36aSLuigi Rizzo return (htons(sum)); 76168b8534bSLuigi Rizzo } 76268b8534bSLuigi Rizzo 763b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 764b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 765b303f675SLuigi Rizzo */ 766b303f675SLuigi Rizzo static void 76737e3a6d3SLuigi Rizzo dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) 768b303f675SLuigi Rizzo { 769b303f675SLuigi Rizzo char buf[128]; 770b303f675SLuigi Rizzo int i, j, i0; 77137e3a6d3SLuigi Rizzo const unsigned char *p = (const unsigned char *)_p; 772b303f675SLuigi Rizzo 773b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 774b303f675SLuigi Rizzo 775ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 776ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 777ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 778b303f675SLuigi Rizzo /* hexdump routine */ 779b303f675SLuigi Rizzo for (i = 0; i < len; ) { 780b797f66cSConrad Meyer memset(buf, ' ', sizeof(buf)); 781b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 782b303f675SLuigi Rizzo i0 = i; 783b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 784b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 785b303f675SLuigi Rizzo i = i0; 786b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 787b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 788b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 789b303f675SLuigi Rizzo printf("%s\n", buf); 790b303f675SLuigi Rizzo } 791b303f675SLuigi Rizzo } 792b303f675SLuigi Rizzo 79368b8534bSLuigi Rizzo /* 79468b8534bSLuigi Rizzo * Fill a packet with some payload. 795f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 796f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 79768b8534bSLuigi Rizzo */ 798f8e4e36aSLuigi Rizzo #ifdef __linux__ 799f8e4e36aSLuigi Rizzo #define uh_sport source 800f8e4e36aSLuigi Rizzo #define uh_dport dest 801f8e4e36aSLuigi Rizzo #define uh_ulen len 802f8e4e36aSLuigi Rizzo #define uh_sum check 803f8e4e36aSLuigi Rizzo #endif /* linux */ 804b303f675SLuigi Rizzo 80527bf5dd3SVincenzo Maffione static uint16_t 80627bf5dd3SVincenzo Maffione new_ip_sum(uint16_t ip_sum, uint32_t oaddr, uint32_t naddr) 80727bf5dd3SVincenzo Maffione { 80827bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 80927bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 81027bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 81127bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 81227bf5dd3SVincenzo Maffione return ip_sum; 81327bf5dd3SVincenzo Maffione } 81427bf5dd3SVincenzo Maffione 81527bf5dd3SVincenzo Maffione static uint16_t 81627bf5dd3SVincenzo Maffione new_udp_sum(uint16_t udp_sum, uint16_t oport, uint16_t nport) 81727bf5dd3SVincenzo Maffione { 81827bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 81927bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 82027bf5dd3SVincenzo Maffione return udp_sum; 82127bf5dd3SVincenzo Maffione } 82227bf5dd3SVincenzo Maffione 82327bf5dd3SVincenzo Maffione 824ce3ee1e7SLuigi Rizzo static void 82580ad548dSVincenzo Maffione update_ip(struct pkt *pkt, struct targ *t) 826ce3ee1e7SLuigi Rizzo { 82780ad548dSVincenzo Maffione struct glob_arg *g = t->g; 82880ad548dSVincenzo Maffione struct ip ip; 82980ad548dSVincenzo Maffione struct udphdr udp; 83080ad548dSVincenzo Maffione uint32_t oaddr, naddr; 83180ad548dSVincenzo Maffione uint16_t oport, nport; 83227bf5dd3SVincenzo Maffione uint16_t ip_sum = 0, udp_sum = 0; 833ce3ee1e7SLuigi Rizzo 83480ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 83580ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); 836f2637526SLuigi Rizzo do { 83780ad548dSVincenzo Maffione ip_sum = udp_sum = 0; 83880ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_src.s_addr); 83980ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 84056717743SAdrian Chadd if (g->options & OPT_RANDOM_SRC) { 84180ad548dSVincenzo Maffione ip.ip_src.s_addr = nrand48(t->seed); 84280ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 84380ad548dSVincenzo Maffione naddr = ntohl(ip.ip_src.s_addr); 84480ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 84527bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 84627bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 84727bf5dd3SVincenzo Maffione } else { 84880ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 84980ad548dSVincenzo Maffione nport = oport + 1; 85080ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 85127bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 852f2637526SLuigi Rizzo break; 853ce3ee1e7SLuigi Rizzo } 85480ad548dSVincenzo Maffione nport = g->src_ip.port0; 85580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 85680ad548dSVincenzo Maffione if (oaddr < g->src_ip.ipv4.end) { 85780ad548dSVincenzo Maffione naddr = oaddr + 1; 85880ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 85927bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 860f2637526SLuigi Rizzo break; 861ce3ee1e7SLuigi Rizzo } 86280ad548dSVincenzo Maffione naddr = g->src_ip.ipv4.start; 86380ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 86427bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 86580ad548dSVincenzo Maffione } 86627bf5dd3SVincenzo Maffione 86780ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_dst.s_addr); 86880ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 86980ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 87080ad548dSVincenzo Maffione ip.ip_dst.s_addr = nrand48(t->seed); 87180ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 87280ad548dSVincenzo Maffione naddr = ntohl(ip.ip_dst.s_addr); 87380ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 87427bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 87527bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 87627bf5dd3SVincenzo Maffione } else { 87780ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 87880ad548dSVincenzo Maffione nport = oport + 1; 87980ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88027bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 88180ad548dSVincenzo Maffione break; 88280ad548dSVincenzo Maffione } 88380ad548dSVincenzo Maffione nport = g->dst_ip.port0; 88480ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88580ad548dSVincenzo Maffione if (oaddr < g->dst_ip.ipv4.end) { 88680ad548dSVincenzo Maffione naddr = oaddr + 1; 88780ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 88827bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 88980ad548dSVincenzo Maffione break; 89080ad548dSVincenzo Maffione } 89180ad548dSVincenzo Maffione naddr = g->dst_ip.ipv4.start; 89280ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 89327bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 89427bf5dd3SVincenzo Maffione } 89580ad548dSVincenzo Maffione } while (0); 89680ad548dSVincenzo Maffione /* update checksums */ 89780ad548dSVincenzo Maffione if (udp_sum != 0) 89880ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); 89980ad548dSVincenzo Maffione if (ip_sum != 0) { 90080ad548dSVincenzo Maffione ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); 90180ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); 90280ad548dSVincenzo Maffione } 90380ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 90480ad548dSVincenzo Maffione memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); 905ce3ee1e7SLuigi Rizzo } 906ce3ee1e7SLuigi Rizzo 90780ad548dSVincenzo Maffione #ifndef s6_addr16 90880ad548dSVincenzo Maffione #define s6_addr16 __u6_addr.__u6_addr16 90980ad548dSVincenzo Maffione #endif 91080ad548dSVincenzo Maffione static void 91180ad548dSVincenzo Maffione update_ip6(struct pkt *pkt, struct targ *t) 91280ad548dSVincenzo Maffione { 91380ad548dSVincenzo Maffione struct glob_arg *g = t->g; 91480ad548dSVincenzo Maffione struct ip6_hdr ip6; 91580ad548dSVincenzo Maffione struct udphdr udp; 91680ad548dSVincenzo Maffione uint16_t udp_sum; 91780ad548dSVincenzo Maffione uint16_t oaddr, naddr; 91880ad548dSVincenzo Maffione uint16_t oport, nport; 91980ad548dSVincenzo Maffione uint8_t group; 92080ad548dSVincenzo Maffione 92180ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); 92280ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); 92380ad548dSVincenzo Maffione do { 92480ad548dSVincenzo Maffione udp_sum = 0; 92580ad548dSVincenzo Maffione group = g->src_ip.ipv6.sgroup; 92680ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); 92780ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 92880ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_SRC) { 92980ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = nrand48(t->seed); 93080ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 93180ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_src.s6_addr16[group]); 93280ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 93380ad548dSVincenzo Maffione break; 93480ad548dSVincenzo Maffione } 93580ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 93680ad548dSVincenzo Maffione nport = oport + 1; 93780ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 93880ad548dSVincenzo Maffione break; 93980ad548dSVincenzo Maffione } 94080ad548dSVincenzo Maffione nport = g->src_ip.port0; 94180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 94280ad548dSVincenzo Maffione if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { 94380ad548dSVincenzo Maffione naddr = oaddr + 1; 94480ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 94580ad548dSVincenzo Maffione break; 94680ad548dSVincenzo Maffione } 94780ad548dSVincenzo Maffione naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); 94880ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 94927bf5dd3SVincenzo Maffione 95080ad548dSVincenzo Maffione /* update checksums if needed */ 95180ad548dSVincenzo Maffione if (oaddr != naddr) 95280ad548dSVincenzo Maffione udp_sum = cksum_add(~oaddr, naddr); 95380ad548dSVincenzo Maffione if (oport != nport) 95480ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 95580ad548dSVincenzo Maffione cksum_add(~oport, nport)); 95627bf5dd3SVincenzo Maffione 95780ad548dSVincenzo Maffione group = g->dst_ip.ipv6.egroup; 95880ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 95980ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 96080ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 96180ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed); 96280ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 96380ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 96480ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 96580ad548dSVincenzo Maffione break; 96680ad548dSVincenzo Maffione } 96780ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 96880ad548dSVincenzo Maffione nport = oport + 1; 96980ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97080ad548dSVincenzo Maffione break; 97180ad548dSVincenzo Maffione } 97280ad548dSVincenzo Maffione nport = g->dst_ip.port0; 97380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97480ad548dSVincenzo Maffione if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { 97580ad548dSVincenzo Maffione naddr = oaddr + 1; 97680ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 97780ad548dSVincenzo Maffione break; 97880ad548dSVincenzo Maffione } 97980ad548dSVincenzo Maffione naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); 98080ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 98180ad548dSVincenzo Maffione } while (0); 98280ad548dSVincenzo Maffione /* update checksums */ 98380ad548dSVincenzo Maffione if (oaddr != naddr) 98480ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 98580ad548dSVincenzo Maffione cksum_add(~oaddr, naddr)); 98680ad548dSVincenzo Maffione if (oport != nport) 98780ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 98880ad548dSVincenzo Maffione cksum_add(~oport, nport)); 98980ad548dSVincenzo Maffione if (udp_sum != 0) 99080ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); 99180ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 99280ad548dSVincenzo Maffione memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); 99380ad548dSVincenzo Maffione } 99480ad548dSVincenzo Maffione 99580ad548dSVincenzo Maffione static void 99680ad548dSVincenzo Maffione update_addresses(struct pkt *pkt, struct targ *t) 99780ad548dSVincenzo Maffione { 99880ad548dSVincenzo Maffione 99980ad548dSVincenzo Maffione if (t->g->af == AF_INET) 100080ad548dSVincenzo Maffione update_ip(pkt, t); 100180ad548dSVincenzo Maffione else 100280ad548dSVincenzo Maffione update_ip6(pkt, t); 100380ad548dSVincenzo Maffione } 1004ce3ee1e7SLuigi Rizzo /* 1005ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 1006ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 1007ce3ee1e7SLuigi Rizzo */ 100868b8534bSLuigi Rizzo static void 100968b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 101068b8534bSLuigi Rizzo { 101168b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 101268b8534bSLuigi Rizzo struct ether_header *eh; 101380ad548dSVincenzo Maffione struct ip6_hdr ip6; 101480ad548dSVincenzo Maffione struct ip ip; 101580ad548dSVincenzo Maffione struct udphdr udp; 101680ad548dSVincenzo Maffione void *udp_ptr; 101780ad548dSVincenzo Maffione uint16_t paylen; 101880ad548dSVincenzo Maffione uint32_t csum = 0; 1019b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 1020ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 1021f2637526SLuigi Rizzo int i, l0 = strlen(payload); 102268b8534bSLuigi Rizzo 102337e3a6d3SLuigi Rizzo #ifndef NO_PCAP 1024f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 1025f284c737SGeorge V. Neville-Neil pcap_t *file; 1026f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 1027f284c737SGeorge V. Neville-Neil const unsigned char *packet; 1028f284c737SGeorge V. Neville-Neil 1029f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 1030f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 1031f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 1032f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 1033f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 1034f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1035f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 1036f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 1037f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1038f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 1039f284c737SGeorge V. Neville-Neil D("out of memory"); 1040f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 1041f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 1042f284c737SGeorge V. Neville-Neil pcap_close(file); 1043f284c737SGeorge V. Neville-Neil return; 1044f284c737SGeorge V. Neville-Neil } 104537e3a6d3SLuigi Rizzo #endif 1046f284c737SGeorge V. Neville-Neil 104780ad548dSVincenzo Maffione paylen = targ->g->pkt_size - sizeof(*eh) - 104880ad548dSVincenzo Maffione (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); 104980ad548dSVincenzo Maffione 1050ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 1051f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 1052f2637526SLuigi Rizzo if (l0 > paylen - i) 1053f2637526SLuigi Rizzo l0 = paylen - i; // last round 105480ad548dSVincenzo Maffione bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0); 105568b8534bSLuigi Rizzo } 105680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[i - 1] = '\0'; 1057f8e4e36aSLuigi Rizzo 1058ce3ee1e7SLuigi Rizzo /* prepare the headers */ 105968b8534bSLuigi Rizzo eh = &pkt->eh; 1060f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 1061f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 106280ad548dSVincenzo Maffione 106380ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 106468b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 106580ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 106680ad548dSVincenzo Maffione udp_ptr = &pkt->ipv4.udp; 106780ad548dSVincenzo Maffione ip.ip_v = IPVERSION; 106880ad548dSVincenzo Maffione ip.ip_hl = sizeof(ip) >> 2; 106980ad548dSVincenzo Maffione ip.ip_id = 0; 107080ad548dSVincenzo Maffione ip.ip_tos = IPTOS_LOWDELAY; 107180ad548dSVincenzo Maffione ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); 107280ad548dSVincenzo Maffione ip.ip_id = 0; 107380ad548dSVincenzo Maffione ip.ip_off = htons(IP_DF); /* Don't fragment */ 107480ad548dSVincenzo Maffione ip.ip_ttl = IPDEFTTL; 107580ad548dSVincenzo Maffione ip.ip_p = IPPROTO_UDP; 107680ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); 107780ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); 107880ad548dSVincenzo Maffione ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); 107980ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 108080ad548dSVincenzo Maffione } else { 108180ad548dSVincenzo Maffione eh->ether_type = htons(ETHERTYPE_IPV6); 108280ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); 108380ad548dSVincenzo Maffione udp_ptr = &pkt->ipv6.udp; 108480ad548dSVincenzo Maffione ip6.ip6_flow = 0; 108580ad548dSVincenzo Maffione ip6.ip6_plen = htons(paylen); 108680ad548dSVincenzo Maffione ip6.ip6_vfc = IPV6_VERSION; 108780ad548dSVincenzo Maffione ip6.ip6_nxt = IPPROTO_UDP; 108880ad548dSVincenzo Maffione ip6.ip6_hlim = IPV6_DEFHLIM; 108980ad548dSVincenzo Maffione ip6.ip6_src = targ->g->src_ip.ipv6.start; 109080ad548dSVincenzo Maffione ip6.ip6_dst = targ->g->dst_ip.ipv6.start; 109180ad548dSVincenzo Maffione } 109280ad548dSVincenzo Maffione memcpy(&udp, udp_ptr, sizeof(udp)); 109380ad548dSVincenzo Maffione 109480ad548dSVincenzo Maffione udp.uh_sport = htons(targ->g->src_ip.port0); 109580ad548dSVincenzo Maffione udp.uh_dport = htons(targ->g->dst_ip.port0); 109680ad548dSVincenzo Maffione udp.uh_ulen = htons(paylen); 109780ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 109880ad548dSVincenzo Maffione /* Magic: taken from sbin/dhclient/packet.c */ 109980ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 110080ad548dSVincenzo Maffione checksum(&udp, sizeof(udp), /* udp header */ 110180ad548dSVincenzo Maffione checksum(pkt->ipv4.body, /* udp payload */ 110280ad548dSVincenzo Maffione paylen - sizeof(udp), 110380ad548dSVincenzo Maffione checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 110480ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv4.ip.ip_src), 110580ad548dSVincenzo Maffione IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); 110680ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 110780ad548dSVincenzo Maffione } else { 110880ad548dSVincenzo Maffione /* Save part of pseudo header checksum into csum */ 110980ad548dSVincenzo Maffione csum = IPPROTO_UDP << 24; 111080ad548dSVincenzo Maffione csum = checksum(&csum, sizeof(csum), paylen); 111180ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 111280ad548dSVincenzo Maffione checksum(udp_ptr, sizeof(udp), /* udp header */ 111380ad548dSVincenzo Maffione checksum(pkt->ipv6.body, /* udp payload */ 111480ad548dSVincenzo Maffione paylen - sizeof(udp), 111580ad548dSVincenzo Maffione checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 111680ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); 111780ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 111880ad548dSVincenzo Maffione } 111980ad548dSVincenzo Maffione memcpy(udp_ptr, &udp, sizeof(udp)); 112017885a7bSLuigi Rizzo 112117885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 1122b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 112368b8534bSLuigi Rizzo } 112468b8534bSLuigi Rizzo 11254bf50f18SLuigi Rizzo static void 112637e3a6d3SLuigi Rizzo get_vnet_hdr_len(struct glob_arg *g) 11274bf50f18SLuigi Rizzo { 11284bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11294bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 113037e3a6d3SLuigi Rizzo int err; 113137e3a6d3SLuigi Rizzo 11324bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11334bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET; 11344bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11354bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11364bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11374bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 113837e3a6d3SLuigi Rizzo if (err) { 113937e3a6d3SLuigi Rizzo D("Unable to get virtio-net header length"); 114037e3a6d3SLuigi Rizzo return; 114137e3a6d3SLuigi Rizzo } 114237e3a6d3SLuigi Rizzo 11434bfe1a4fSVincenzo Maffione g->virt_header = ph.nr_hdr_len; 114437e3a6d3SLuigi Rizzo if (g->virt_header) { 114537e3a6d3SLuigi Rizzo D("Port requires virtio-net header, length = %d", 114637e3a6d3SLuigi Rizzo g->virt_header); 114737e3a6d3SLuigi Rizzo } 114837e3a6d3SLuigi Rizzo } 114937e3a6d3SLuigi Rizzo 115037e3a6d3SLuigi Rizzo static void 115137e3a6d3SLuigi Rizzo set_vnet_hdr_len(struct glob_arg *g) 115237e3a6d3SLuigi Rizzo { 115337e3a6d3SLuigi Rizzo int err, l = g->virt_header; 11544bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11554bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 11564bf50f18SLuigi Rizzo 11574bf50f18SLuigi Rizzo if (l == 0) 11584bf50f18SLuigi Rizzo return; 11594bf50f18SLuigi Rizzo 11604bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11614bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET; 11624bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11634bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11644bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11654bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 11664bf50f18SLuigi Rizzo if (err) { 116737e3a6d3SLuigi Rizzo D("Unable to set virtio-net header length %d", l); 11684bf50f18SLuigi Rizzo } 11694bf50f18SLuigi Rizzo } 117068b8534bSLuigi Rizzo 117168b8534bSLuigi Rizzo /* 117268b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 117368b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 117468b8534bSLuigi Rizzo * an interrupt when done. 117568b8534bSLuigi Rizzo */ 117668b8534bSLuigi Rizzo static int 117717885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 117880ad548dSVincenzo Maffione int size, struct targ *t, u_int count, int options) 117968b8534bSLuigi Rizzo { 1180406e7723SVincenzo Maffione u_int n, sent, head = ring->head; 118180ad548dSVincenzo Maffione u_int frags = t->frags; 118280ad548dSVincenzo Maffione u_int frag_size = t->frag_size; 1183406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 118468b8534bSLuigi Rizzo 118517885a7bSLuigi Rizzo n = nm_ring_space(ring); 118699fb123fSLuigi Rizzo #if 0 118799fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 118868b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 1189406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 119068b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 119168b8534bSLuigi Rizzo 1192f2637526SLuigi Rizzo __builtin_prefetch(p); 1193406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 119499fb123fSLuigi Rizzo } 1195406e7723SVincenzo Maffione head = ring->head; 119699fb123fSLuigi Rizzo } 119799fb123fSLuigi Rizzo #endif 119880ad548dSVincenzo Maffione for (sent = 0; sent < count && n >= frags; sent++, n--) { 119980ad548dSVincenzo Maffione char *p; 120080ad548dSVincenzo Maffione int buf_changed; 120180ad548dSVincenzo Maffione u_int tosend = size; 120280ad548dSVincenzo Maffione 1203406e7723SVincenzo Maffione slot = &ring->slot[head]; 120480ad548dSVincenzo Maffione p = NETMAP_BUF(ring, slot->buf_idx); 120580ad548dSVincenzo Maffione buf_changed = slot->flags & NS_BUF_CHANGED; 120699fb123fSLuigi Rizzo 1207b303f675SLuigi Rizzo slot->flags = 0; 120837e3a6d3SLuigi Rizzo if (options & OPT_RUBBISH) { 120937e3a6d3SLuigi Rizzo /* do nothing */ 121037e3a6d3SLuigi Rizzo } else if (options & OPT_INDIRECT) { 1211b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 121237e3a6d3SLuigi Rizzo slot->ptr = (uint64_t)((uintptr_t)frame); 121380ad548dSVincenzo Maffione } else if (frags > 1) { 121480ad548dSVincenzo Maffione u_int i; 121580ad548dSVincenzo Maffione const char *f = frame; 121680ad548dSVincenzo Maffione char *fp = p; 121780ad548dSVincenzo Maffione for (i = 0; i < frags - 1; i++) { 121880ad548dSVincenzo Maffione memcpy(fp, f, frag_size); 121980ad548dSVincenzo Maffione slot->len = frag_size; 122080ad548dSVincenzo Maffione slot->flags = NS_MOREFRAG; 122180ad548dSVincenzo Maffione if (options & OPT_DUMP) 1222406e7723SVincenzo Maffione dump_payload(fp, frag_size, ring, head); 122380ad548dSVincenzo Maffione tosend -= frag_size; 122480ad548dSVincenzo Maffione f += frag_size; 1225406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 1226406e7723SVincenzo Maffione slot = &ring->slot[head]; 122780ad548dSVincenzo Maffione fp = NETMAP_BUF(ring, slot->buf_idx); 122880ad548dSVincenzo Maffione } 122980ad548dSVincenzo Maffione n -= (frags - 1); 123080ad548dSVincenzo Maffione p = fp; 123180ad548dSVincenzo Maffione slot->flags = 0; 123280ad548dSVincenzo Maffione memcpy(p, f, tosend); 123380ad548dSVincenzo Maffione update_addresses(pkt, t); 123480ad548dSVincenzo Maffione } else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) { 123580ad548dSVincenzo Maffione if (options & OPT_COPY) 1236f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 123780ad548dSVincenzo Maffione else 123817885a7bSLuigi Rizzo memcpy(p, frame, size); 123980ad548dSVincenzo Maffione update_addresses(pkt, t); 1240ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 1241f2637526SLuigi Rizzo __builtin_prefetch(p); 1242ce3ee1e7SLuigi Rizzo } 124380ad548dSVincenzo Maffione slot->len = tosend; 1244ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 1245406e7723SVincenzo Maffione dump_payload(p, tosend, ring, head); 1246406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 124768b8534bSLuigi Rizzo } 124880ad548dSVincenzo Maffione if (sent) { 124980ad548dSVincenzo Maffione slot->flags |= NS_REPORT; 1250406e7723SVincenzo Maffione ring->head = ring->cur = head; 125180ad548dSVincenzo Maffione } 125280ad548dSVincenzo Maffione if (sent < count) { 125380ad548dSVincenzo Maffione /* tell netmap that we need more slots */ 125480ad548dSVincenzo Maffione ring->cur = ring->tail; 125580ad548dSVincenzo Maffione } 125668b8534bSLuigi Rizzo 125768b8534bSLuigi Rizzo return (sent); 125868b8534bSLuigi Rizzo } 125968b8534bSLuigi Rizzo 1260f8e4e36aSLuigi Rizzo /* 126137e3a6d3SLuigi Rizzo * Index of the highest bit set 126237e3a6d3SLuigi Rizzo */ 12637eb32dc8SVincenzo Maffione static uint32_t 126437e3a6d3SLuigi Rizzo msb64(uint64_t x) 126537e3a6d3SLuigi Rizzo { 126637e3a6d3SLuigi Rizzo uint64_t m = 1ULL << 63; 126737e3a6d3SLuigi Rizzo int i; 126837e3a6d3SLuigi Rizzo 126937e3a6d3SLuigi Rizzo for (i = 63; i >= 0; i--, m >>=1) 127037e3a6d3SLuigi Rizzo if (m & x) 127137e3a6d3SLuigi Rizzo return i; 127237e3a6d3SLuigi Rizzo return 0; 127337e3a6d3SLuigi Rizzo } 127437e3a6d3SLuigi Rizzo 127537e3a6d3SLuigi Rizzo /* 127680ad548dSVincenzo Maffione * wait until ts, either busy or sleeping if more than 1ms. 127780ad548dSVincenzo Maffione * Return wakeup time. 127880ad548dSVincenzo Maffione */ 127980ad548dSVincenzo Maffione static struct timespec 128080ad548dSVincenzo Maffione wait_time(struct timespec ts) 128180ad548dSVincenzo Maffione { 128280ad548dSVincenzo Maffione for (;;) { 128380ad548dSVincenzo Maffione struct timespec w, cur; 128480ad548dSVincenzo Maffione clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 128580ad548dSVincenzo Maffione w = timespec_sub(ts, cur); 128680ad548dSVincenzo Maffione if (w.tv_sec < 0) 128780ad548dSVincenzo Maffione return cur; 128880ad548dSVincenzo Maffione else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 128980ad548dSVincenzo Maffione poll(NULL, 0, 1); 129080ad548dSVincenzo Maffione } 129180ad548dSVincenzo Maffione } 129280ad548dSVincenzo Maffione 129380ad548dSVincenzo Maffione /* 1294f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 1295f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 1296f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 1297f8e4e36aSLuigi Rizzo */ 1298f8e4e36aSLuigi Rizzo 129968b8534bSLuigi Rizzo static void * 130080ad548dSVincenzo Maffione ping_body(void *data) 130168b8534bSLuigi Rizzo { 130268b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1303f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1304f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 130580ad548dSVincenzo Maffione int i, m, rx = 0; 130617885a7bSLuigi Rizzo void *frame; 130717885a7bSLuigi Rizzo int size; 1308f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 130980ad548dSVincenzo Maffione struct timespec nexttime = {0, 0}; /* silence compiler */ 131037e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 131137e3a6d3SLuigi Rizzo uint64_t count = 0, t_cur, t_min = ~0, av = 0; 131280ad548dSVincenzo Maffione uint64_t g_min = ~0, g_av = 0; 131337e3a6d3SLuigi Rizzo uint64_t buckets[64]; /* bins for delays, ns */ 131480ad548dSVincenzo Maffione int rate_limit = targ->g->tx_rate, tosend = 0; 131517885a7bSLuigi Rizzo 131680ad548dSVincenzo Maffione frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header; 131717885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1318e5ecae38SEd Maste 131937e3a6d3SLuigi Rizzo 1320f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1321f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 1322f8e4e36aSLuigi Rizzo return NULL; 1323f95a30bdSEd Maste } 1324f8e4e36aSLuigi Rizzo 13259a7abd93SVincenzo Maffione if (targ->g->af == AF_INET6) { 13269a7abd93SVincenzo Maffione D("Warning: ping-pong with IPv6 not supported"); 13279a7abd93SVincenzo Maffione } 13289a7abd93SVincenzo Maffione 132937e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1330f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 133117885a7bSLuigi Rizzo now = last_print; 133280ad548dSVincenzo Maffione if (rate_limit) { 133380ad548dSVincenzo Maffione targ->tic = timespec_add(now, (struct timespec){2,0}); 133480ad548dSVincenzo Maffione targ->tic.tv_nsec = 0; 133580ad548dSVincenzo Maffione wait_time(targ->tic); 133680ad548dSVincenzo Maffione nexttime = targ->tic; 133780ad548dSVincenzo Maffione } 133837e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 133980ad548dSVincenzo Maffione struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1340f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 1341f8e4e36aSLuigi Rizzo char *p; 134280ad548dSVincenzo Maffione int rv; 134380ad548dSVincenzo Maffione uint64_t limit, event = 0; 134480ad548dSVincenzo Maffione 134580ad548dSVincenzo Maffione if (rate_limit && tosend <= 0) { 134680ad548dSVincenzo Maffione tosend = targ->g->burst; 134780ad548dSVincenzo Maffione nexttime = timespec_add(nexttime, targ->g->tx_period); 134880ad548dSVincenzo Maffione wait_time(nexttime); 134980ad548dSVincenzo Maffione } 135080ad548dSVincenzo Maffione 135180ad548dSVincenzo Maffione limit = rate_limit ? tosend : targ->g->burst; 135280ad548dSVincenzo Maffione if (n > 0 && n - sent < limit) 135380ad548dSVincenzo Maffione limit = n - sent; 135480ad548dSVincenzo Maffione for (m = 0; (unsigned)m < limit; m++) { 1355406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 135617885a7bSLuigi Rizzo slot->len = size; 1357f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1358f8e4e36aSLuigi Rizzo 135917885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 1360f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 136180ad548dSVincenzo Maffione break; 1362f8e4e36aSLuigi Rizzo } else { 13634bf50f18SLuigi Rizzo struct tstamp *tp; 1364f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 1365f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 1366f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 13674bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13684bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 13694bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 1370f8e4e36aSLuigi Rizzo sent++; 1371406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1372f8e4e36aSLuigi Rizzo } 1373f8e4e36aSLuigi Rizzo } 137480ad548dSVincenzo Maffione if (m > 0) 137580ad548dSVincenzo Maffione event++; 137680ad548dSVincenzo Maffione targ->ctr.pkts = sent; 137780ad548dSVincenzo Maffione targ->ctr.bytes = sent*size; 137880ad548dSVincenzo Maffione targ->ctr.events = event; 137980ad548dSVincenzo Maffione if (rate_limit) 138080ad548dSVincenzo Maffione tosend -= m; 138180ad548dSVincenzo Maffione #ifdef BUSYWAIT 138280ad548dSVincenzo Maffione rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); 138380ad548dSVincenzo Maffione if (rv < 0) { 138480ad548dSVincenzo Maffione D("TXSYNC error on queue %d: %s", targ->me, 138517885a7bSLuigi Rizzo strerror(errno)); 138680ad548dSVincenzo Maffione } 138780ad548dSVincenzo Maffione again: 138880ad548dSVincenzo Maffione ioctl(pfd.fd, NIOCRXSYNC, NULL); 138980ad548dSVincenzo Maffione #else 139080ad548dSVincenzo Maffione /* should use a parameter to decide how often to send */ 139180ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 3000)) <= 0) { 139280ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 139380ad548dSVincenzo Maffione (rv ? strerror(errno) : "timeout")); 1394f8e4e36aSLuigi Rizzo continue; 1395f8e4e36aSLuigi Rizzo } 139680ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1397f8e4e36aSLuigi Rizzo /* see what we got back */ 139880ad548dSVincenzo Maffione rx = 0; 139980ad548dSVincenzo Maffione for (i = targ->nmd->first_rx_ring; 140080ad548dSVincenzo Maffione i <= targ->nmd->last_rx_ring; i++) { 1401f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 140217885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 1403f8e4e36aSLuigi Rizzo uint32_t seq; 14044bf50f18SLuigi Rizzo struct tstamp *tp; 140537e3a6d3SLuigi Rizzo int pos; 140637e3a6d3SLuigi Rizzo 1407406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 1408f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1409f8e4e36aSLuigi Rizzo 1410f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 1411f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 14124bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 14134bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 14144bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 1415f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 1416f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 1417f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1418f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1419f8e4e36aSLuigi Rizzo ts.tv_sec--; 1420f8e4e36aSLuigi Rizzo } 142180ad548dSVincenzo Maffione if (0) D("seq %d/%llu delta %d.%09d", seq, 142280ad548dSVincenzo Maffione (unsigned long long)sent, 1423f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 142437e3a6d3SLuigi Rizzo t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; 142537e3a6d3SLuigi Rizzo if (t_cur < t_min) 142637e3a6d3SLuigi Rizzo t_min = t_cur; 1427f8e4e36aSLuigi Rizzo count ++; 142837e3a6d3SLuigi Rizzo av += t_cur; 142937e3a6d3SLuigi Rizzo pos = msb64(t_cur); 143037e3a6d3SLuigi Rizzo buckets[pos]++; 143137e3a6d3SLuigi Rizzo /* now store it in a bucket */ 1432406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1433f8e4e36aSLuigi Rizzo rx++; 1434f8e4e36aSLuigi Rizzo } 1435f8e4e36aSLuigi Rizzo } 1436f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1437f8e4e36aSLuigi Rizzo //usleep(100000); 1438f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 1439f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 1440f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1441f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1442f8e4e36aSLuigi Rizzo ts.tv_sec--; 1443f8e4e36aSLuigi Rizzo } 1444f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 144537e3a6d3SLuigi Rizzo D("count %d RTT: min %d av %d ns", 144637e3a6d3SLuigi Rizzo (int)count, (int)t_min, (int)(av/count)); 144780ad548dSVincenzo Maffione int k, j, kmin, off; 144837e3a6d3SLuigi Rizzo char buf[512]; 144937e3a6d3SLuigi Rizzo 145037e3a6d3SLuigi Rizzo for (kmin = 0; kmin < 64; kmin ++) 145137e3a6d3SLuigi Rizzo if (buckets[kmin]) 145237e3a6d3SLuigi Rizzo break; 145337e3a6d3SLuigi Rizzo for (k = 63; k >= kmin; k--) 145437e3a6d3SLuigi Rizzo if (buckets[k]) 145537e3a6d3SLuigi Rizzo break; 145637e3a6d3SLuigi Rizzo buf[0] = '\0'; 145780ad548dSVincenzo Maffione off = 0; 145880ad548dSVincenzo Maffione for (j = kmin; j <= k; j++) { 145980ad548dSVincenzo Maffione off += sprintf(buf + off, " %5d", (int)buckets[j]); 146080ad548dSVincenzo Maffione } 146137e3a6d3SLuigi Rizzo D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf); 146237e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1463f8e4e36aSLuigi Rizzo count = 0; 146480ad548dSVincenzo Maffione g_av += av; 1465f8e4e36aSLuigi Rizzo av = 0; 146680ad548dSVincenzo Maffione if (t_min < g_min) 146780ad548dSVincenzo Maffione g_min = t_min; 146837e3a6d3SLuigi Rizzo t_min = ~0; 1469f8e4e36aSLuigi Rizzo last_print = now; 1470f8e4e36aSLuigi Rizzo } 147180ad548dSVincenzo Maffione #ifdef BUSYWAIT 147280ad548dSVincenzo Maffione if (rx < m && ts.tv_sec <= 3 && !targ->cancel) 147380ad548dSVincenzo Maffione goto again; 147480ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1475f8e4e36aSLuigi Rizzo } 147637e3a6d3SLuigi Rizzo 147780ad548dSVincenzo Maffione if (sent > 0) { 147880ad548dSVincenzo Maffione D("RTT over %llu packets: min %d av %d ns", 147980ad548dSVincenzo Maffione (long long unsigned)sent, (int)g_min, 148080ad548dSVincenzo Maffione (int)((double)g_av/sent)); 148180ad548dSVincenzo Maffione } 148280ad548dSVincenzo Maffione targ->completed = 1; 148380ad548dSVincenzo Maffione 148437e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 148537e3a6d3SLuigi Rizzo targ->used = 0; 148637e3a6d3SLuigi Rizzo 1487f8e4e36aSLuigi Rizzo return NULL; 1488f8e4e36aSLuigi Rizzo } 1489f8e4e36aSLuigi Rizzo 1490f8e4e36aSLuigi Rizzo 1491f8e4e36aSLuigi Rizzo /* 1492f8e4e36aSLuigi Rizzo * reply to ping requests 1493f8e4e36aSLuigi Rizzo */ 1494f8e4e36aSLuigi Rizzo static void * 149580ad548dSVincenzo Maffione pong_body(void *data) 1496f8e4e36aSLuigi Rizzo { 1497f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1498f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1499f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 1500f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 150137e3a6d3SLuigi Rizzo int i, rx = 0; 150237e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 1503f8e4e36aSLuigi Rizzo 1504f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1505f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 1506f8e4e36aSLuigi Rizzo return NULL; 1507f8e4e36aSLuigi Rizzo } 150880ad548dSVincenzo Maffione if (n > 0) 150980ad548dSVincenzo Maffione D("understood ponger %llu but don't know how to do it", 151080ad548dSVincenzo Maffione (unsigned long long)n); 15119a7abd93SVincenzo Maffione 15129a7abd93SVincenzo Maffione if (targ->g->af == AF_INET6) { 15139a7abd93SVincenzo Maffione D("Warning: ping-pong with IPv6 not supported"); 15149a7abd93SVincenzo Maffione } 15159a7abd93SVincenzo Maffione 151637e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 1517406e7723SVincenzo Maffione uint32_t txhead, txavail; 1518f8e4e36aSLuigi Rizzo //#define BUSYWAIT 1519f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1520f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 1521f8e4e36aSLuigi Rizzo #else 152280ad548dSVincenzo Maffione int rv; 152380ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 1000)) <= 0) { 152480ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 152580ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1526f8e4e36aSLuigi Rizzo continue; 1527f8e4e36aSLuigi Rizzo } 1528f8e4e36aSLuigi Rizzo #endif 152980ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1530406e7723SVincenzo Maffione txhead = txring->head; 153117885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 1532f8e4e36aSLuigi Rizzo /* see what we got back */ 1533f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 1534f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 153517885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 1536f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 1537406e7723SVincenzo Maffione uint32_t head = rxring->head; 1538406e7723SVincenzo Maffione struct netmap_slot *slot = &rxring->slot[head]; 1539f8e4e36aSLuigi Rizzo char *src, *dst; 1540f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 1541f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 1542406e7723SVincenzo Maffione rxring->head = rxring->cur = nm_ring_next(rxring, head); 1543f8e4e36aSLuigi Rizzo rx++; 1544f8e4e36aSLuigi Rizzo if (txavail == 0) 1545f8e4e36aSLuigi Rizzo continue; 1546f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 1547406e7723SVincenzo Maffione txring->slot[txhead].buf_idx); 1548f8e4e36aSLuigi Rizzo /* copy... */ 1549f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 1550f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 1551f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 155280ad548dSVincenzo Maffione /* swap source and destination MAC */ 1553f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 1554f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 1555f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 1556f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 1557f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 1558f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 15599a7abd93SVincenzo Maffione /* swap source and destination IPv4 */ 15609a7abd93SVincenzo Maffione if (spkt[6] == htons(ETHERTYPE_IP)) { 15619a7abd93SVincenzo Maffione dpkt[13] = spkt[15]; 15629a7abd93SVincenzo Maffione dpkt[14] = spkt[16]; 15639a7abd93SVincenzo Maffione dpkt[15] = spkt[13]; 15649a7abd93SVincenzo Maffione dpkt[16] = spkt[14]; 15659a7abd93SVincenzo Maffione } 1566406e7723SVincenzo Maffione txring->slot[txhead].len = slot->len; 15679a7abd93SVincenzo Maffione //dump_payload(dst, slot->len, txring, txhead); 1568406e7723SVincenzo Maffione txhead = nm_ring_next(txring, txhead); 1569f8e4e36aSLuigi Rizzo txavail--; 1570f8e4e36aSLuigi Rizzo sent++; 1571f8e4e36aSLuigi Rizzo } 1572f8e4e36aSLuigi Rizzo } 1573406e7723SVincenzo Maffione txring->head = txring->cur = txhead; 157437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 1575f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1576f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 1577f8e4e36aSLuigi Rizzo #endif 1578f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1579f8e4e36aSLuigi Rizzo } 158037e3a6d3SLuigi Rizzo 158180ad548dSVincenzo Maffione targ->completed = 1; 158280ad548dSVincenzo Maffione 158337e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 158437e3a6d3SLuigi Rizzo targ->used = 0; 158537e3a6d3SLuigi Rizzo 1586f8e4e36aSLuigi Rizzo return NULL; 1587f8e4e36aSLuigi Rizzo } 1588f8e4e36aSLuigi Rizzo 1589f8e4e36aSLuigi Rizzo 1590f8e4e36aSLuigi Rizzo static void * 1591f8e4e36aSLuigi Rizzo sender_body(void *data) 1592f8e4e36aSLuigi Rizzo { 1593f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1594f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 15954bf50f18SLuigi Rizzo struct netmap_if *nifp; 159637e3a6d3SLuigi Rizzo struct netmap_ring *txring = NULL; 159737e3a6d3SLuigi Rizzo int i; 159837e3a6d3SLuigi Rizzo uint64_t n = targ->g->npackets / targ->g->nthreads; 159937e3a6d3SLuigi Rizzo uint64_t sent = 0; 160037e3a6d3SLuigi Rizzo uint64_t event = 0; 1601f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 160217885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 16031cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 160417885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 160517885a7bSLuigi Rizzo void *frame; 160617885a7bSLuigi Rizzo int size; 160717885a7bSLuigi Rizzo 1608f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 160980ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 161017885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1611f284c737SGeorge V. Neville-Neil } else { 1612f284c737SGeorge V. Neville-Neil frame = targ->frame; 1613f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1614f284c737SGeorge V. Neville-Neil } 1615b303f675SLuigi Rizzo 16164bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 161768b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 161868b8534bSLuigi Rizzo goto quit; 161968b8534bSLuigi Rizzo 162068b8534bSLuigi Rizzo /* main loop.*/ 16211cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 16221cb4c501SLuigi Rizzo if (rate_limit) { 162317885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 16241cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 162517885a7bSLuigi Rizzo wait_time(targ->tic); 16261cb4c501SLuigi Rizzo nexttime = targ->tic; 16271cb4c501SLuigi Rizzo } 1628f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1629f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1630f8e4e36aSLuigi Rizzo 1631f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 163217885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1633f8e4e36aSLuigi Rizzo sent++; 163480ad548dSVincenzo Maffione update_addresses(pkt, targ); 1635f8e4e36aSLuigi Rizzo if (i > 10000) { 163637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 163737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 163837e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1639f8e4e36aSLuigi Rizzo i = 0; 1640f8e4e36aSLuigi Rizzo } 1641f8e4e36aSLuigi Rizzo } 1642f2637526SLuigi Rizzo #ifndef NO_PCAP 1643f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1644f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1645f2637526SLuigi Rizzo 1646f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1647f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1648f2637526SLuigi Rizzo sent++; 164980ad548dSVincenzo Maffione update_addresses(pkt, targ); 1650f2637526SLuigi Rizzo if (i > 10000) { 165137e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 165237e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 165337e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1654f2637526SLuigi Rizzo i = 0; 1655f2637526SLuigi Rizzo } 1656f2637526SLuigi Rizzo } 1657f2637526SLuigi Rizzo #endif /* NO_PCAP */ 165868b8534bSLuigi Rizzo } else { 16591cb4c501SLuigi Rizzo int tosend = 0; 16609e53f3bdSVincenzo Maffione u_int bufsz, frag_size = targ->g->frag_size; 1661ce3ee1e7SLuigi Rizzo 16624bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 166380ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 166480ad548dSVincenzo Maffione bufsz = txring->nr_buf_size; 16659e53f3bdSVincenzo Maffione if (bufsz < frag_size) 16669e53f3bdSVincenzo Maffione frag_size = bufsz; 166780ad548dSVincenzo Maffione targ->frag_size = targ->g->pkt_size / targ->frags; 16689e53f3bdSVincenzo Maffione if (targ->frag_size > frag_size) { 16699e53f3bdSVincenzo Maffione targ->frags = targ->g->pkt_size / frag_size; 16709e53f3bdSVincenzo Maffione targ->frag_size = frag_size; 16719e53f3bdSVincenzo Maffione if (targ->g->pkt_size % frag_size != 0) 167280ad548dSVincenzo Maffione targ->frags++; 167380ad548dSVincenzo Maffione } 167480ad548dSVincenzo Maffione D("frags %u frag_size %u", targ->frags, targ->frag_size); 1675f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 167680ad548dSVincenzo Maffione int rv; 167768b8534bSLuigi Rizzo 16781cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 16791cb4c501SLuigi Rizzo tosend = targ->g->burst; 168017885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 168117885a7bSLuigi Rizzo wait_time(nexttime); 16821cb4c501SLuigi Rizzo } 16831cb4c501SLuigi Rizzo 168468b8534bSLuigi Rizzo /* 168568b8534bSLuigi Rizzo * wait for available room in the send queue(s) 168668b8534bSLuigi Rizzo */ 168737e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 168880ad548dSVincenzo Maffione (void)rv; 168937e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 169037e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 169137e3a6d3SLuigi Rizzo strerror(errno)); 169237e3a6d3SLuigi Rizzo goto quit; 169337e3a6d3SLuigi Rizzo } 169437e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 169580ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 16963fe77e68SEd Maste if (targ->cancel) 16973fe77e68SEd Maste break; 169880ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 169980ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1700f0ea3689SLuigi Rizzo // goto quit; 170117885a7bSLuigi Rizzo } 1702f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 170337e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 170437e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 170568b8534bSLuigi Rizzo goto quit; 170668b8534bSLuigi Rizzo } 170737e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 170868b8534bSLuigi Rizzo /* 170968b8534bSLuigi Rizzo * scan our queues and send on those with room 171068b8534bSLuigi Rizzo */ 1711f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1712f8e4e36aSLuigi Rizzo D("drop copy"); 171399fb123fSLuigi Rizzo options &= ~OPT_COPY; 1714f8e4e36aSLuigi Rizzo } 1715f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 171637e3a6d3SLuigi Rizzo int m; 171737e3a6d3SLuigi Rizzo uint64_t limit = rate_limit ? tosend : targ->g->burst; 171880ad548dSVincenzo Maffione 171980ad548dSVincenzo Maffione if (n > 0 && n == sent) 172080ad548dSVincenzo Maffione break; 172180ad548dSVincenzo Maffione 1722f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1723f8e4e36aSLuigi Rizzo limit = n - sent; 172468b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 172517885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 172668b8534bSLuigi Rizzo continue; 1727ce3ee1e7SLuigi Rizzo 172880ad548dSVincenzo Maffione if (targ->g->pkt_min_size > 0) { 172980ad548dSVincenzo Maffione size = nrand48(targ->seed) % 173080ad548dSVincenzo Maffione (targ->g->pkt_size - targ->g->pkt_min_size) + 173180ad548dSVincenzo Maffione targ->g->pkt_min_size; 173280ad548dSVincenzo Maffione } 173380ad548dSVincenzo Maffione m = send_packets(txring, pkt, frame, size, targ, 173480ad548dSVincenzo Maffione limit, options); 173580ad548dSVincenzo Maffione ND("limit %lu tail %d m %d", 173680ad548dSVincenzo Maffione limit, txring->tail, m); 173768b8534bSLuigi Rizzo sent += m; 173837e3a6d3SLuigi Rizzo if (m > 0) //XXX-ste: can m be 0? 173937e3a6d3SLuigi Rizzo event++; 174037e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 174180ad548dSVincenzo Maffione targ->ctr.bytes += m*size; 174237e3a6d3SLuigi Rizzo targ->ctr.events = event; 1743ce3ee1e7SLuigi Rizzo if (rate_limit) { 1744ce3ee1e7SLuigi Rizzo tosend -= m; 1745ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1746ce3ee1e7SLuigi Rizzo break; 1747ce3ee1e7SLuigi Rizzo } 174868b8534bSLuigi Rizzo } 174968b8534bSLuigi Rizzo } 175099fb123fSLuigi Rizzo /* flush any remaining packets */ 175180ad548dSVincenzo Maffione if (txring != NULL) { 17524bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 17534bf50f18SLuigi Rizzo txring->tail, txring->head, 175437e3a6d3SLuigi Rizzo (void *)pthread_self()); 1755f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 175680ad548dSVincenzo Maffione } 175768b8534bSLuigi Rizzo 175868b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1759f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 176068b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 176137e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(txring)) { 17624bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 17634bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1764f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 176568b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 176668b8534bSLuigi Rizzo } 176768b8534bSLuigi Rizzo } 1768f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 176968b8534bSLuigi Rizzo 17701cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 177168b8534bSLuigi Rizzo targ->completed = 1; 177237e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 177337e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 177437e3a6d3SLuigi Rizzo targ->ctr.events = event; 177568b8534bSLuigi Rizzo quit: 177668b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 177768b8534bSLuigi Rizzo targ->used = 0; 177868b8534bSLuigi Rizzo 177968b8534bSLuigi Rizzo return (NULL); 178068b8534bSLuigi Rizzo } 178168b8534bSLuigi Rizzo 178268b8534bSLuigi Rizzo 1783f2637526SLuigi Rizzo #ifndef NO_PCAP 178468b8534bSLuigi Rizzo static void 1785f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1786f8e4e36aSLuigi Rizzo const u_char * bytes) 178768b8534bSLuigi Rizzo { 178837e3a6d3SLuigi Rizzo struct my_ctrs *ctr = (struct my_ctrs *)user; 1789f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 179037e3a6d3SLuigi Rizzo ctr->bytes += h->len; 179137e3a6d3SLuigi Rizzo ctr->pkts++; 179268b8534bSLuigi Rizzo } 1793f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 179468b8534bSLuigi Rizzo 179537e3a6d3SLuigi Rizzo 179668b8534bSLuigi Rizzo static int 179737e3a6d3SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) 179868b8534bSLuigi Rizzo { 1799406e7723SVincenzo Maffione u_int head, rx, n; 180037e3a6d3SLuigi Rizzo uint64_t b = 0; 180180ad548dSVincenzo Maffione u_int complete = 0; 180237e3a6d3SLuigi Rizzo 180337e3a6d3SLuigi Rizzo if (bytes == NULL) 180437e3a6d3SLuigi Rizzo bytes = &b; 180568b8534bSLuigi Rizzo 1806406e7723SVincenzo Maffione head = ring->head; 180717885a7bSLuigi Rizzo n = nm_ring_space(ring); 180817885a7bSLuigi Rizzo if (n < limit) 180917885a7bSLuigi Rizzo limit = n; 181068b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 1811406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 181268b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 181368b8534bSLuigi Rizzo 181437e3a6d3SLuigi Rizzo *bytes += slot->len; 1815b303f675SLuigi Rizzo if (dump) 1816406e7723SVincenzo Maffione dump_payload(p, slot->len, ring, head); 181780ad548dSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) 181880ad548dSVincenzo Maffione complete++; 181968b8534bSLuigi Rizzo 1820406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 182168b8534bSLuigi Rizzo } 1822406e7723SVincenzo Maffione ring->head = ring->cur = head; 182368b8534bSLuigi Rizzo 182480ad548dSVincenzo Maffione return (complete); 182568b8534bSLuigi Rizzo } 182668b8534bSLuigi Rizzo 182768b8534bSLuigi Rizzo static void * 182868b8534bSLuigi Rizzo receiver_body(void *data) 182968b8534bSLuigi Rizzo { 183068b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1831f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 18324bf50f18SLuigi Rizzo struct netmap_if *nifp; 183368b8534bSLuigi Rizzo struct netmap_ring *rxring; 1834f8e4e36aSLuigi Rizzo int i; 183537e3a6d3SLuigi Rizzo struct my_ctrs cur; 183620d684ecSAllan Jude uint64_t n = targ->g->npackets / targ->g->nthreads; 183737e3a6d3SLuigi Rizzo 183880ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 183968b8534bSLuigi Rizzo 184068b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 184168b8534bSLuigi Rizzo goto quit; 184268b8534bSLuigi Rizzo 18434bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 18444bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 184568b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 18464bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1847f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1848f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 184968b8534bSLuigi Rizzo break; 185080ad548dSVincenzo Maffione if (i < 0) { 185180ad548dSVincenzo Maffione D("poll() error: %s", strerror(errno)); 185280ad548dSVincenzo Maffione goto quit; 185380ad548dSVincenzo Maffione } 185480ad548dSVincenzo Maffione if (pfd.revents & POLLERR) { 185580ad548dSVincenzo Maffione D("fd error"); 185680ad548dSVincenzo Maffione goto quit; 185780ad548dSVincenzo Maffione } 1858f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1859f0ea3689SLuigi Rizzo i, pfd.revents); 186068b8534bSLuigi Rizzo } 186168b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 18621cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1863f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1864950cf4a2SVincenzo Maffione while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 18654bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1866f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 186737e3a6d3SLuigi Rizzo i = read(targ->g->main_fd, buf, sizeof(buf)); 186837e3a6d3SLuigi Rizzo if (i > 0) { 186937e3a6d3SLuigi Rizzo targ->ctr.pkts++; 187037e3a6d3SLuigi Rizzo targ->ctr.bytes += i; 187137e3a6d3SLuigi Rizzo targ->ctr.events++; 187237e3a6d3SLuigi Rizzo } 1873f8e4e36aSLuigi Rizzo } 1874f2637526SLuigi Rizzo #ifndef NO_PCAP 1875f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 187620d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 1877f2637526SLuigi Rizzo /* XXX should we poll ? */ 18784bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 187937e3a6d3SLuigi Rizzo (u_char *)&targ->ctr); 188037e3a6d3SLuigi Rizzo targ->ctr.events++; 1881f2637526SLuigi Rizzo } 1882f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 188368b8534bSLuigi Rizzo } else { 1884b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 18854bf50f18SLuigi Rizzo 18864bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 188720d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 188868b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 188968b8534bSLuigi Rizzo before quitting. */ 189037e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 189137e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 189237e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 189337e3a6d3SLuigi Rizzo strerror(errno)); 189437e3a6d3SLuigi Rizzo goto quit; 189537e3a6d3SLuigi Rizzo } 189637e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 189737e3a6d3SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 189837e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 189937e3a6d3SLuigi Rizzo targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 190037e3a6d3SLuigi Rizzo goto out; 190137e3a6d3SLuigi Rizzo } 190237e3a6d3SLuigi Rizzo 190337e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 190437e3a6d3SLuigi Rizzo D("poll err"); 190537e3a6d3SLuigi Rizzo goto quit; 190637e3a6d3SLuigi Rizzo } 190737e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 190837e3a6d3SLuigi Rizzo uint64_t cur_space = 0; 190937e3a6d3SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 191037e3a6d3SLuigi Rizzo int m; 191137e3a6d3SLuigi Rizzo 191237e3a6d3SLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 191337e3a6d3SLuigi Rizzo /* compute free space in the ring */ 191437e3a6d3SLuigi Rizzo m = rxring->head + rxring->num_slots - rxring->tail; 191537e3a6d3SLuigi Rizzo if (m >= (int) rxring->num_slots) 191637e3a6d3SLuigi Rizzo m -= rxring->num_slots; 191737e3a6d3SLuigi Rizzo cur_space += m; 191837e3a6d3SLuigi Rizzo if (nm_ring_empty(rxring)) 191937e3a6d3SLuigi Rizzo continue; 192037e3a6d3SLuigi Rizzo 192137e3a6d3SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); 192237e3a6d3SLuigi Rizzo cur.pkts += m; 192380ad548dSVincenzo Maffione if (m > 0) 192437e3a6d3SLuigi Rizzo cur.events++; 192537e3a6d3SLuigi Rizzo } 192637e3a6d3SLuigi Rizzo cur.min_space = targ->ctr.min_space; 192737e3a6d3SLuigi Rizzo if (cur_space < cur.min_space) 192837e3a6d3SLuigi Rizzo cur.min_space = cur_space; 192937e3a6d3SLuigi Rizzo targ->ctr = cur; 193037e3a6d3SLuigi Rizzo } 193137e3a6d3SLuigi Rizzo } 193237e3a6d3SLuigi Rizzo 193337e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 193437e3a6d3SLuigi Rizzo 193537e3a6d3SLuigi Rizzo #if !defined(BUSYWAIT) 193637e3a6d3SLuigi Rizzo out: 193737e3a6d3SLuigi Rizzo #endif 193837e3a6d3SLuigi Rizzo targ->completed = 1; 193937e3a6d3SLuigi Rizzo targ->ctr = cur; 194037e3a6d3SLuigi Rizzo 194137e3a6d3SLuigi Rizzo quit: 194237e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 194337e3a6d3SLuigi Rizzo targ->used = 0; 194437e3a6d3SLuigi Rizzo 194537e3a6d3SLuigi Rizzo return (NULL); 194637e3a6d3SLuigi Rizzo } 194737e3a6d3SLuigi Rizzo 194837e3a6d3SLuigi Rizzo static void * 194937e3a6d3SLuigi Rizzo txseq_body(void *data) 195037e3a6d3SLuigi Rizzo { 195137e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 195237e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 195337e3a6d3SLuigi Rizzo struct netmap_ring *ring; 195437e3a6d3SLuigi Rizzo int64_t sent = 0; 195537e3a6d3SLuigi Rizzo uint64_t event = 0; 195637e3a6d3SLuigi Rizzo int options = targ->g->options | OPT_COPY; 195737e3a6d3SLuigi Rizzo struct timespec nexttime = {0, 0}; 195837e3a6d3SLuigi Rizzo int rate_limit = targ->g->tx_rate; 195937e3a6d3SLuigi Rizzo struct pkt *pkt = &targ->pkt; 196037e3a6d3SLuigi Rizzo int frags = targ->g->frags; 196137e3a6d3SLuigi Rizzo uint32_t sequence = 0; 196237e3a6d3SLuigi Rizzo int budget = 0; 196337e3a6d3SLuigi Rizzo void *frame; 196437e3a6d3SLuigi Rizzo int size; 196537e3a6d3SLuigi Rizzo 196637e3a6d3SLuigi Rizzo if (targ->g->nthreads > 1) { 196737e3a6d3SLuigi Rizzo D("can only txseq ping with 1 thread"); 196837e3a6d3SLuigi Rizzo return NULL; 196937e3a6d3SLuigi Rizzo } 197037e3a6d3SLuigi Rizzo 197137e3a6d3SLuigi Rizzo if (targ->g->npackets > 0) { 197237e3a6d3SLuigi Rizzo D("Ignoring -n argument"); 197337e3a6d3SLuigi Rizzo } 197437e3a6d3SLuigi Rizzo 197580ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 197637e3a6d3SLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 197737e3a6d3SLuigi Rizzo 197837e3a6d3SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 197937e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 198037e3a6d3SLuigi Rizzo goto quit; 198137e3a6d3SLuigi Rizzo 198237e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 198337e3a6d3SLuigi Rizzo if (rate_limit) { 198437e3a6d3SLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 198537e3a6d3SLuigi Rizzo targ->tic.tv_nsec = 0; 198637e3a6d3SLuigi Rizzo wait_time(targ->tic); 198737e3a6d3SLuigi Rizzo nexttime = targ->tic; 198837e3a6d3SLuigi Rizzo } 198937e3a6d3SLuigi Rizzo 199037e3a6d3SLuigi Rizzo /* Only use the first queue. */ 199137e3a6d3SLuigi Rizzo ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); 199237e3a6d3SLuigi Rizzo 199337e3a6d3SLuigi Rizzo while (!targ->cancel) { 199437e3a6d3SLuigi Rizzo int64_t limit; 199537e3a6d3SLuigi Rizzo unsigned int space; 199637e3a6d3SLuigi Rizzo unsigned int head; 199737e3a6d3SLuigi Rizzo int fcnt; 199880ad548dSVincenzo Maffione uint16_t sum = 0; 199980ad548dSVincenzo Maffione int rv; 200037e3a6d3SLuigi Rizzo 200137e3a6d3SLuigi Rizzo if (!rate_limit) { 200237e3a6d3SLuigi Rizzo budget = targ->g->burst; 200337e3a6d3SLuigi Rizzo 200437e3a6d3SLuigi Rizzo } else if (budget <= 0) { 200537e3a6d3SLuigi Rizzo budget = targ->g->burst; 200637e3a6d3SLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 200737e3a6d3SLuigi Rizzo wait_time(nexttime); 200837e3a6d3SLuigi Rizzo } 200937e3a6d3SLuigi Rizzo 201037e3a6d3SLuigi Rizzo /* wait for available room in the send queue */ 201180ad548dSVincenzo Maffione #ifdef BUSYWAIT 201280ad548dSVincenzo Maffione (void)rv; 201380ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 201480ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 201580ad548dSVincenzo Maffione strerror(errno)); 201680ad548dSVincenzo Maffione goto quit; 201780ad548dSVincenzo Maffione } 201880ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 201980ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 202037e3a6d3SLuigi Rizzo if (targ->cancel) 202137e3a6d3SLuigi Rizzo break; 202280ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 202380ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 202480ad548dSVincenzo Maffione // goto quit; 202537e3a6d3SLuigi Rizzo } 202637e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 202737e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 202837e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 202937e3a6d3SLuigi Rizzo goto quit; 203037e3a6d3SLuigi Rizzo } 203180ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 203237e3a6d3SLuigi Rizzo 203337e3a6d3SLuigi Rizzo /* If no room poll() again. */ 203437e3a6d3SLuigi Rizzo space = nm_ring_space(ring); 203537e3a6d3SLuigi Rizzo if (!space) { 203637e3a6d3SLuigi Rizzo continue; 203737e3a6d3SLuigi Rizzo } 203837e3a6d3SLuigi Rizzo 203937e3a6d3SLuigi Rizzo limit = budget; 204037e3a6d3SLuigi Rizzo 204137e3a6d3SLuigi Rizzo if (space < limit) { 204237e3a6d3SLuigi Rizzo limit = space; 204337e3a6d3SLuigi Rizzo } 204437e3a6d3SLuigi Rizzo 204537e3a6d3SLuigi Rizzo /* Cut off ``limit`` to make sure is multiple of ``frags``. */ 204637e3a6d3SLuigi Rizzo if (frags > 1) { 204737e3a6d3SLuigi Rizzo limit = (limit / frags) * frags; 204837e3a6d3SLuigi Rizzo } 204937e3a6d3SLuigi Rizzo 205037e3a6d3SLuigi Rizzo limit = sent + limit; /* Convert to absolute. */ 205137e3a6d3SLuigi Rizzo 205237e3a6d3SLuigi Rizzo for (fcnt = frags, head = ring->head; 205337e3a6d3SLuigi Rizzo sent < limit; sent++, sequence++) { 205437e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 205537e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 205680ad548dSVincenzo Maffione uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; 205780ad548dSVincenzo Maffione 205880ad548dSVincenzo Maffione memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); 205937e3a6d3SLuigi Rizzo 206037e3a6d3SLuigi Rizzo slot->flags = 0; 206180ad548dSVincenzo Maffione t = *w; 206280ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[0] = sequence >> 24; 206380ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; 206480ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 206580ad548dSVincenzo Maffione t = *++w; 206680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; 206780ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; 206880ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 206980ad548dSVincenzo Maffione memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); 207037e3a6d3SLuigi Rizzo nm_pkt_copy(frame, p, size); 207137e3a6d3SLuigi Rizzo if (fcnt == frags) { 207280ad548dSVincenzo Maffione update_addresses(pkt, targ); 207337e3a6d3SLuigi Rizzo } 207437e3a6d3SLuigi Rizzo 207537e3a6d3SLuigi Rizzo if (options & OPT_DUMP) { 207637e3a6d3SLuigi Rizzo dump_payload(p, size, ring, head); 207737e3a6d3SLuigi Rizzo } 207837e3a6d3SLuigi Rizzo 207937e3a6d3SLuigi Rizzo slot->len = size; 208037e3a6d3SLuigi Rizzo 208137e3a6d3SLuigi Rizzo if (--fcnt > 0) { 208237e3a6d3SLuigi Rizzo slot->flags |= NS_MOREFRAG; 208337e3a6d3SLuigi Rizzo } else { 208437e3a6d3SLuigi Rizzo fcnt = frags; 208537e3a6d3SLuigi Rizzo } 208637e3a6d3SLuigi Rizzo 208737e3a6d3SLuigi Rizzo if (sent == limit - 1) { 208837e3a6d3SLuigi Rizzo /* Make sure we don't push an incomplete 208937e3a6d3SLuigi Rizzo * packet. */ 209037e3a6d3SLuigi Rizzo assert(!(slot->flags & NS_MOREFRAG)); 209137e3a6d3SLuigi Rizzo slot->flags |= NS_REPORT; 209237e3a6d3SLuigi Rizzo } 209337e3a6d3SLuigi Rizzo 209437e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 209537e3a6d3SLuigi Rizzo if (rate_limit) { 209637e3a6d3SLuigi Rizzo budget--; 209737e3a6d3SLuigi Rizzo } 209837e3a6d3SLuigi Rizzo } 209937e3a6d3SLuigi Rizzo 210037e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 210137e3a6d3SLuigi Rizzo 210237e3a6d3SLuigi Rizzo event ++; 210337e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 210437e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 210537e3a6d3SLuigi Rizzo targ->ctr.events = event; 210637e3a6d3SLuigi Rizzo } 210737e3a6d3SLuigi Rizzo 210837e3a6d3SLuigi Rizzo /* flush any remaining packets */ 210937e3a6d3SLuigi Rizzo D("flush tail %d head %d on thread %p", 211037e3a6d3SLuigi Rizzo ring->tail, ring->head, 211137e3a6d3SLuigi Rizzo (void *)pthread_self()); 211237e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 211337e3a6d3SLuigi Rizzo 211437e3a6d3SLuigi Rizzo /* final part: wait the TX queues to become empty. */ 211537e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(ring)) { 211637e3a6d3SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 211737e3a6d3SLuigi Rizzo ring->tail, ring->head, targ->nmd->first_tx_ring); 211837e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 211937e3a6d3SLuigi Rizzo usleep(1); /* wait 1 tick */ 212037e3a6d3SLuigi Rizzo } 212137e3a6d3SLuigi Rizzo 212237e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 212337e3a6d3SLuigi Rizzo targ->completed = 1; 212437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 212537e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 212637e3a6d3SLuigi Rizzo targ->ctr.events = event; 212737e3a6d3SLuigi Rizzo quit: 212837e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 212937e3a6d3SLuigi Rizzo targ->used = 0; 213037e3a6d3SLuigi Rizzo 213137e3a6d3SLuigi Rizzo return (NULL); 213237e3a6d3SLuigi Rizzo } 213337e3a6d3SLuigi Rizzo 213437e3a6d3SLuigi Rizzo 213537e3a6d3SLuigi Rizzo static char * 213637e3a6d3SLuigi Rizzo multi_slot_to_string(struct netmap_ring *ring, unsigned int head, 213737e3a6d3SLuigi Rizzo unsigned int nfrags, char *strbuf, size_t strbuflen) 213837e3a6d3SLuigi Rizzo { 213937e3a6d3SLuigi Rizzo unsigned int f; 214037e3a6d3SLuigi Rizzo char *ret = strbuf; 214137e3a6d3SLuigi Rizzo 214237e3a6d3SLuigi Rizzo for (f = 0; f < nfrags; f++) { 214337e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 214437e3a6d3SLuigi Rizzo int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, 214537e3a6d3SLuigi Rizzo slot->flags); 214637e3a6d3SLuigi Rizzo if (m >= (int)strbuflen) { 214737e3a6d3SLuigi Rizzo break; 214837e3a6d3SLuigi Rizzo } 214937e3a6d3SLuigi Rizzo strbuf += m; 215037e3a6d3SLuigi Rizzo strbuflen -= m; 215137e3a6d3SLuigi Rizzo 215237e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 215337e3a6d3SLuigi Rizzo } 215437e3a6d3SLuigi Rizzo 215537e3a6d3SLuigi Rizzo return ret; 215637e3a6d3SLuigi Rizzo } 215737e3a6d3SLuigi Rizzo 215837e3a6d3SLuigi Rizzo static void * 215937e3a6d3SLuigi Rizzo rxseq_body(void *data) 216037e3a6d3SLuigi Rizzo { 216137e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 216237e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 216337e3a6d3SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 216437e3a6d3SLuigi Rizzo struct netmap_ring *ring; 216537e3a6d3SLuigi Rizzo unsigned int frags_exp = 1; 216637e3a6d3SLuigi Rizzo struct my_ctrs cur; 216737e3a6d3SLuigi Rizzo unsigned int frags = 0; 216837e3a6d3SLuigi Rizzo int first_packet = 1; 216937e3a6d3SLuigi Rizzo int first_slot = 1; 217080ad548dSVincenzo Maffione int i, j, af, nrings; 217180ad548dSVincenzo Maffione uint32_t seq, *seq_exp = NULL; 217237e3a6d3SLuigi Rizzo 217380ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 217437e3a6d3SLuigi Rizzo 217537e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 217637e3a6d3SLuigi Rizzo goto quit; 217737e3a6d3SLuigi Rizzo 217880ad548dSVincenzo Maffione nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1; 217980ad548dSVincenzo Maffione seq_exp = calloc(nrings, sizeof(uint32_t)); 218080ad548dSVincenzo Maffione if (seq_exp == NULL) { 218180ad548dSVincenzo Maffione D("failed to allocate seq array"); 218280ad548dSVincenzo Maffione goto quit; 218380ad548dSVincenzo Maffione } 218480ad548dSVincenzo Maffione 218537e3a6d3SLuigi Rizzo D("reading from %s fd %d main_fd %d", 218637e3a6d3SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 218737e3a6d3SLuigi Rizzo /* unbounded wait for the first packet. */ 218837e3a6d3SLuigi Rizzo for (;!targ->cancel;) { 218937e3a6d3SLuigi Rizzo i = poll(&pfd, 1, 1000); 219037e3a6d3SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 219137e3a6d3SLuigi Rizzo break; 219237e3a6d3SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 219337e3a6d3SLuigi Rizzo i, pfd.revents); 219437e3a6d3SLuigi Rizzo } 219537e3a6d3SLuigi Rizzo 219637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 219737e3a6d3SLuigi Rizzo 219837e3a6d3SLuigi Rizzo 219937e3a6d3SLuigi Rizzo while (!targ->cancel) { 220037e3a6d3SLuigi Rizzo unsigned int head; 220137e3a6d3SLuigi Rizzo int limit; 220237e3a6d3SLuigi Rizzo 220380ad548dSVincenzo Maffione #ifdef BUSYWAIT 220480ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 220580ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 220680ad548dSVincenzo Maffione strerror(errno)); 220780ad548dSVincenzo Maffione goto quit; 220880ad548dSVincenzo Maffione } 220980ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 2210f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 22111cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 22128ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 2213f0ea3689SLuigi Rizzo goto out; 221468b8534bSLuigi Rizzo } 221568b8534bSLuigi Rizzo 2216f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 221717885a7bSLuigi Rizzo D("poll err"); 221817885a7bSLuigi Rizzo goto quit; 221917885a7bSLuigi Rizzo } 222080ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 222117885a7bSLuigi Rizzo 222280ad548dSVincenzo Maffione for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) { 222380ad548dSVincenzo Maffione ring = NETMAP_RXRING(targ->nmd->nifp, j); 222437e3a6d3SLuigi Rizzo if (nm_ring_empty(ring)) 222568b8534bSLuigi Rizzo continue; 222668b8534bSLuigi Rizzo 222737e3a6d3SLuigi Rizzo limit = nm_ring_space(ring); 222837e3a6d3SLuigi Rizzo if (limit > targ->g->burst) 222937e3a6d3SLuigi Rizzo limit = targ->g->burst; 223037e3a6d3SLuigi Rizzo 223137e3a6d3SLuigi Rizzo #if 0 223237e3a6d3SLuigi Rizzo /* Enable this if 223337e3a6d3SLuigi Rizzo * 1) we remove the early-return optimization from 223437e3a6d3SLuigi Rizzo * the netmap poll implementation, or 223537e3a6d3SLuigi Rizzo * 2) pipes get NS_MOREFRAG support. 223637e3a6d3SLuigi Rizzo * With the current netmap implementation, an experiment like 223737e3a6d3SLuigi Rizzo * pkt-gen -i vale:1{1 -f txseq -F 9 223837e3a6d3SLuigi Rizzo * pkt-gen -i vale:1}1 -f rxseq 223937e3a6d3SLuigi Rizzo * would get stuck as soon as we find nm_ring_space(ring) < 9, 224037e3a6d3SLuigi Rizzo * since here limit is rounded to 0 and 224137e3a6d3SLuigi Rizzo * pipe rxsync is not called anymore by the poll() of this loop. 224237e3a6d3SLuigi Rizzo */ 224337e3a6d3SLuigi Rizzo if (frags_exp > 1) { 224437e3a6d3SLuigi Rizzo int o = limit; 224537e3a6d3SLuigi Rizzo /* Cut off to the closest smaller multiple. */ 224637e3a6d3SLuigi Rizzo limit = (limit / frags_exp) * frags_exp; 224737e3a6d3SLuigi Rizzo RD(2, "LIMIT %d --> %d", o, limit); 224868b8534bSLuigi Rizzo } 224937e3a6d3SLuigi Rizzo #endif 225037e3a6d3SLuigi Rizzo 225137e3a6d3SLuigi Rizzo for (head = ring->head, i = 0; i < limit; i++) { 225237e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 225337e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 225437e3a6d3SLuigi Rizzo int len = slot->len; 225537e3a6d3SLuigi Rizzo struct pkt *pkt; 225637e3a6d3SLuigi Rizzo 225737e3a6d3SLuigi Rizzo if (dump) { 225837e3a6d3SLuigi Rizzo dump_payload(p, slot->len, ring, head); 225968b8534bSLuigi Rizzo } 226037e3a6d3SLuigi Rizzo 226137e3a6d3SLuigi Rizzo frags++; 226237e3a6d3SLuigi Rizzo if (!(slot->flags & NS_MOREFRAG)) { 226337e3a6d3SLuigi Rizzo if (first_packet) { 226437e3a6d3SLuigi Rizzo first_packet = 0; 226537e3a6d3SLuigi Rizzo } else if (frags != frags_exp) { 226637e3a6d3SLuigi Rizzo char prbuf[512]; 226737e3a6d3SLuigi Rizzo RD(1, "Received packets with %u frags, " 226837e3a6d3SLuigi Rizzo "expected %u, '%s'", frags, frags_exp, 226980ad548dSVincenzo Maffione multi_slot_to_string(ring, head-frags+1, 227080ad548dSVincenzo Maffione frags, 227137e3a6d3SLuigi Rizzo prbuf, sizeof(prbuf))); 227237e3a6d3SLuigi Rizzo } 227337e3a6d3SLuigi Rizzo first_packet = 0; 227437e3a6d3SLuigi Rizzo frags_exp = frags; 227537e3a6d3SLuigi Rizzo frags = 0; 227637e3a6d3SLuigi Rizzo } 227737e3a6d3SLuigi Rizzo 227837e3a6d3SLuigi Rizzo p -= sizeof(pkt->vh) - targ->g->virt_header; 227937e3a6d3SLuigi Rizzo len += sizeof(pkt->vh) - targ->g->virt_header; 228037e3a6d3SLuigi Rizzo pkt = (struct pkt *)p; 228180ad548dSVincenzo Maffione if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP) 228280ad548dSVincenzo Maffione af = AF_INET; 228380ad548dSVincenzo Maffione else 228480ad548dSVincenzo Maffione af = AF_INET6; 228537e3a6d3SLuigi Rizzo 228680ad548dSVincenzo Maffione if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) + 228780ad548dSVincenzo Maffione sizeof(seq)) { 228837e3a6d3SLuigi Rizzo RD(1, "%s: packet too small (len=%u)", __func__, 228937e3a6d3SLuigi Rizzo slot->len); 229037e3a6d3SLuigi Rizzo } else { 229180ad548dSVincenzo Maffione seq = (PKT(pkt, body, af)[0] << 24) | 229280ad548dSVincenzo Maffione (PKT(pkt, body, af)[1] << 16) | 229380ad548dSVincenzo Maffione (PKT(pkt, body, af)[2] << 8) | 229480ad548dSVincenzo Maffione PKT(pkt, body, af)[3]; 229537e3a6d3SLuigi Rizzo if (first_slot) { 229637e3a6d3SLuigi Rizzo /* Grab the first one, whatever it 229737e3a6d3SLuigi Rizzo is. */ 229880ad548dSVincenzo Maffione seq_exp[j] = seq; 229937e3a6d3SLuigi Rizzo first_slot = 0; 230080ad548dSVincenzo Maffione } else if (seq != seq_exp[j]) { 230180ad548dSVincenzo Maffione uint32_t delta = seq - seq_exp[j]; 230237e3a6d3SLuigi Rizzo 230337e3a6d3SLuigi Rizzo if (delta < (0xFFFFFFFF >> 1)) { 230437e3a6d3SLuigi Rizzo RD(2, "Sequence GAP: exp %u found %u", 230580ad548dSVincenzo Maffione seq_exp[j], seq); 230637e3a6d3SLuigi Rizzo } else { 230737e3a6d3SLuigi Rizzo RD(2, "Sequence OUT OF ORDER: " 230880ad548dSVincenzo Maffione "exp %u found %u", seq_exp[j], seq); 230937e3a6d3SLuigi Rizzo } 231080ad548dSVincenzo Maffione seq_exp[j] = seq; 231137e3a6d3SLuigi Rizzo } 231280ad548dSVincenzo Maffione seq_exp[j]++; 231337e3a6d3SLuigi Rizzo } 231437e3a6d3SLuigi Rizzo 231537e3a6d3SLuigi Rizzo cur.bytes += slot->len; 231637e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 231737e3a6d3SLuigi Rizzo cur.pkts++; 231837e3a6d3SLuigi Rizzo } 231937e3a6d3SLuigi Rizzo 232037e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 232137e3a6d3SLuigi Rizzo 232237e3a6d3SLuigi Rizzo cur.events++; 232337e3a6d3SLuigi Rizzo targ->ctr = cur; 232468b8534bSLuigi Rizzo } 232580ad548dSVincenzo Maffione } 2326f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 2327f0ea3689SLuigi Rizzo 232880ad548dSVincenzo Maffione #ifndef BUSYWAIT 2329f0ea3689SLuigi Rizzo out: 233080ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 233168b8534bSLuigi Rizzo targ->completed = 1; 233237e3a6d3SLuigi Rizzo targ->ctr = cur; 233368b8534bSLuigi Rizzo 233468b8534bSLuigi Rizzo quit: 233580ad548dSVincenzo Maffione if (seq_exp != NULL) 233680ad548dSVincenzo Maffione free(seq_exp); 233768b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 233868b8534bSLuigi Rizzo targ->used = 0; 233968b8534bSLuigi Rizzo 234068b8534bSLuigi Rizzo return (NULL); 234168b8534bSLuigi Rizzo } 234268b8534bSLuigi Rizzo 234366a698c9SEd Maste 234468b8534bSLuigi Rizzo static void 234580ad548dSVincenzo Maffione tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg) 234668b8534bSLuigi Rizzo { 234737e3a6d3SLuigi Rizzo double bw, raw_bw, pps, abs; 2348f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 234937e3a6d3SLuigi Rizzo int size; 235068b8534bSLuigi Rizzo 235137e3a6d3SLuigi Rizzo if (cur->pkts == 0) { 235237e3a6d3SLuigi Rizzo printf("%s nothing.\n", msg); 235337e3a6d3SLuigi Rizzo return; 235437e3a6d3SLuigi Rizzo } 235537e3a6d3SLuigi Rizzo 235637e3a6d3SLuigi Rizzo size = (int)(cur->bytes / cur->pkts); 235737e3a6d3SLuigi Rizzo 235837e3a6d3SLuigi Rizzo printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", 235937e3a6d3SLuigi Rizzo msg, 236037e3a6d3SLuigi Rizzo (unsigned long long)cur->pkts, 236137e3a6d3SLuigi Rizzo (unsigned long long)cur->bytes, 236237e3a6d3SLuigi Rizzo (unsigned long long)cur->events, size, delta); 2363f8e4e36aSLuigi Rizzo if (delta == 0) 2364f8e4e36aSLuigi Rizzo delta = 1e-6; 2365f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 2366f8e4e36aSLuigi Rizzo size = 60; 236737e3a6d3SLuigi Rizzo pps = cur->pkts / delta; 236837e3a6d3SLuigi Rizzo bw = (8.0 * cur->bytes) / delta; 236980ad548dSVincenzo Maffione raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta; 237037e3a6d3SLuigi Rizzo abs = cur->pkts / (double)(cur->events); 237166a698c9SEd Maste 237237e3a6d3SLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", 237380ad548dSVincenzo Maffione norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); 237468b8534bSLuigi Rizzo } 237568b8534bSLuigi Rizzo 237668b8534bSLuigi Rizzo static void 237780ad548dSVincenzo Maffione usage(int errcode) 237868b8534bSLuigi Rizzo { 237980ad548dSVincenzo Maffione /* This usage is generated from the pkt-gen man page: 238080ad548dSVincenzo Maffione * $ man pkt-gen > x 238180ad548dSVincenzo Maffione * and pasted here adding the string terminators and endlines with simple 238280ad548dSVincenzo Maffione * regular expressions. */ 238368b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 238468b8534bSLuigi Rizzo fprintf(stderr, 238568b8534bSLuigi Rizzo "Usage:\n" 238668b8534bSLuigi Rizzo "%s arguments\n" 238780ad548dSVincenzo Maffione " -h Show program usage and exit.\n" 238880ad548dSVincenzo Maffione "\n" 238980ad548dSVincenzo Maffione " -i interface\n" 239080ad548dSVincenzo Maffione " Name of the network interface that pkt-gen operates on. It can be a system network interface\n" 239180ad548dSVincenzo Maffione " (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n" 239280ad548dSVincenzo Maffione " monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n" 239380ad548dSVincenzo Maffione " mented in netmap(4) (NIOCREGIF section).\n" 239480ad548dSVincenzo Maffione "\n" 239580ad548dSVincenzo Maffione " -f function\n" 239680ad548dSVincenzo Maffione " The function to be executed by pkt-gen. Specify tx for transmission, rx for reception, ping\n" 239780ad548dSVincenzo Maffione " for client-side ping-pong operation, and pong for server-side ping-pong operation.\n" 239880ad548dSVincenzo Maffione "\n" 239980ad548dSVincenzo Maffione " -n count\n" 2400ed188a7eSVincenzo Maffione " Number of iterations of the pkt-gen function (with 0 meaning infinite). In case of tx or rx,\n" 240180ad548dSVincenzo Maffione " count is the number of packets to receive or transmit. In case of ping or pong, count is the\n" 240280ad548dSVincenzo Maffione " number of ping-pong transactions.\n" 240380ad548dSVincenzo Maffione "\n" 240480ad548dSVincenzo Maffione " -l pkt_size\n" 240580ad548dSVincenzo Maffione " Packet size in bytes excluding CRC. If passed a second time, use random sizes larger or\n" 240680ad548dSVincenzo Maffione " equal than the second one and lower than the first one.\n" 240780ad548dSVincenzo Maffione "\n" 240880ad548dSVincenzo Maffione " -b burst_size\n" 240980ad548dSVincenzo Maffione " Transmit or receive up to burst_size packets at a time.\n" 241080ad548dSVincenzo Maffione "\n" 241180ad548dSVincenzo Maffione " -4 Use IPv4 addresses.\n" 241280ad548dSVincenzo Maffione "\n" 241380ad548dSVincenzo Maffione " -6 Use IPv6 addresses.\n" 241480ad548dSVincenzo Maffione "\n" 241580ad548dSVincenzo Maffione " -d dst_ip[:port[-dst_ip:port]]\n" 241680ad548dSVincenzo Maffione " Destination IPv4/IPv6 address and port, single or range.\n" 241780ad548dSVincenzo Maffione "\n" 241880ad548dSVincenzo Maffione " -s src_ip[:port[-src_ip:port]]\n" 241980ad548dSVincenzo Maffione " Source IPv4/IPv6 address and port, single or range.\n" 242080ad548dSVincenzo Maffione "\n" 242180ad548dSVincenzo Maffione " -D dst_mac\n" 242280ad548dSVincenzo Maffione " Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n" 242380ad548dSVincenzo Maffione "\n" 242480ad548dSVincenzo Maffione " -S src_mac\n" 242580ad548dSVincenzo Maffione " Source MAC address in colon notation.\n" 242680ad548dSVincenzo Maffione "\n" 242780ad548dSVincenzo Maffione " -a cpu_id\n" 242880ad548dSVincenzo Maffione " Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3). If more\n" 242980ad548dSVincenzo Maffione " threads are used, they are pinned to the subsequent CPUs, one per thread.\n" 243080ad548dSVincenzo Maffione "\n" 243180ad548dSVincenzo Maffione " -c cpus\n" 243280ad548dSVincenzo Maffione " Maximum number of CPUs to use (0 means to use all the available ones).\n" 243380ad548dSVincenzo Maffione "\n" 243480ad548dSVincenzo Maffione " -p threads\n" 243580ad548dSVincenzo Maffione " Number of threads to use. By default, only a single thread is used to handle all the netmap\n" 243680ad548dSVincenzo Maffione " rings. If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n" 2437ed188a7eSVincenzo Maffione " single RX ring (in rx mode), or a TX/RX ring pair. The number of threads must be less than or\n" 2438ed188a7eSVincenzo Maffione " equal to the number of TX (or RX) rings available in the device specified by interface.\n" 243980ad548dSVincenzo Maffione "\n" 244080ad548dSVincenzo Maffione " -T report_ms\n" 244180ad548dSVincenzo Maffione " Number of milliseconds between reports.\n" 244280ad548dSVincenzo Maffione "\n" 244380ad548dSVincenzo Maffione " -w wait_for_link_time\n" 2444ed188a7eSVincenzo Maffione " Number of seconds to wait before starting the pkt-gen function, useful to make sure that the\n" 244580ad548dSVincenzo Maffione " network link is up. A network device driver may take some time to enter netmap mode, or to\n" 244680ad548dSVincenzo Maffione " create a new transmit/receive ring pair when netmap(4) requests one.\n" 244780ad548dSVincenzo Maffione "\n" 244880ad548dSVincenzo Maffione " -R rate\n" 244980ad548dSVincenzo Maffione " Packet transmission rate. Not setting the packet transmission rate tells pkt-gen to transmit\n" 2450ed188a7eSVincenzo Maffione " packets as quickly as possible. On servers from 2010 onward netmap(4) is able to com-\n" 245180ad548dSVincenzo Maffione " pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n" 245280ad548dSVincenzo Maffione " your intention is to saturate the link.\n" 245380ad548dSVincenzo Maffione "\n" 245480ad548dSVincenzo Maffione " -X Dump payload of each packet transmitted or received.\n" 245580ad548dSVincenzo Maffione "\n" 245680ad548dSVincenzo Maffione " -H len Add empty virtio-net-header with size 'len'. Valid sizes are 0, 10 and 12. This option is\n" 245780ad548dSVincenzo Maffione " only used with Virtual Machine technologies that use virtio as a network interface.\n" 245880ad548dSVincenzo Maffione "\n" 245980ad548dSVincenzo Maffione " -P file\n" 246080ad548dSVincenzo Maffione " Load the packet to be transmitted from a pcap file rather than constructing it within\n" 246180ad548dSVincenzo Maffione " pkt-gen.\n" 246280ad548dSVincenzo Maffione "\n" 246380ad548dSVincenzo Maffione " -z Use random IPv4/IPv6 src address/port.\n" 246480ad548dSVincenzo Maffione "\n" 246580ad548dSVincenzo Maffione " -Z Use random IPv4/IPv6 dst address/port.\n" 246680ad548dSVincenzo Maffione "\n" 246780ad548dSVincenzo Maffione " -N Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n" 246880ad548dSVincenzo Maffione "\n" 246980ad548dSVincenzo Maffione " -F num_frags\n" 247080ad548dSVincenzo Maffione " Send multi-slot packets, each one with num_frags fragments. A multi-slot packet is repre-\n" 247180ad548dSVincenzo Maffione " sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n" 247280ad548dSVincenzo Maffione " last slot). This is useful to transmit or receive packets larger than the netmap buffer\n" 247380ad548dSVincenzo Maffione " size.\n" 247480ad548dSVincenzo Maffione "\n" 247580ad548dSVincenzo Maffione " -M frag_size\n" 247680ad548dSVincenzo Maffione " In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n" 247780ad548dSVincenzo Maffione " length divided by num_frags.\n" 247880ad548dSVincenzo Maffione "\n" 247980ad548dSVincenzo Maffione " -I Use indirect buffers. It is only valid for transmitting on VALE ports, and it is implemented\n" 248080ad548dSVincenzo Maffione " by setting the NS_INDIRECT flag in the netmap slots.\n" 248180ad548dSVincenzo Maffione "\n" 248280ad548dSVincenzo Maffione " -W Exit immediately if all the RX rings are empty the first time they are examined.\n" 248380ad548dSVincenzo Maffione "\n" 248480ad548dSVincenzo Maffione " -v Increase the verbosity level.\n" 248580ad548dSVincenzo Maffione "\n" 248680ad548dSVincenzo Maffione " -r In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n" 248780ad548dSVincenzo Maffione " netmap buffers is (rubbish mode).\n" 248880ad548dSVincenzo Maffione "\n" 248980ad548dSVincenzo Maffione " -A Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n" 249080ad548dSVincenzo Maffione "\n" 249180ad548dSVincenzo Maffione " -B Take Ethernet framing and CRC into account when computing the average bps. This adds 4 bytes\n" 249280ad548dSVincenzo Maffione " of CRC and 20 bytes of framing to each packet.\n" 249380ad548dSVincenzo Maffione "\n" 249480ad548dSVincenzo Maffione " -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n" 249580ad548dSVincenzo Maffione " Configuration in terms of number of rings and slots to be used when opening the netmap port.\n" 2496ed188a7eSVincenzo Maffione " Such configuration has an effect on software ports created on the fly, such as VALE ports and\n" 249780ad548dSVincenzo Maffione " netmap pipes. The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n" 249880ad548dSVincenzo Maffione " rx_slots, tx_rings, rx_rings. Missing numbers or zeroes stand for default values. As an\n" 249980ad548dSVincenzo Maffione " additional convenience, if exactly one number is specified, then this is assigned to both\n" 250080ad548dSVincenzo Maffione " tx_slots and rx_slots. If there is no fourth number, then the third one is assigned to both\n" 250180ad548dSVincenzo Maffione " tx_rings and rx_rings.\n" 250280ad548dSVincenzo Maffione "\n" 250380ad548dSVincenzo Maffione " -o options data generation options (parsed using atoi)\n" 250480ad548dSVincenzo Maffione " OPT_PREFETCH 1\n" 250580ad548dSVincenzo Maffione " OPT_ACCESS 2\n" 250680ad548dSVincenzo Maffione " OPT_COPY 4\n" 250780ad548dSVincenzo Maffione " OPT_MEMCPY 8\n" 250880ad548dSVincenzo Maffione " OPT_TS 16 (add a timestamp)\n" 250980ad548dSVincenzo Maffione " OPT_INDIRECT 32 (use indirect buffers)\n" 251080ad548dSVincenzo Maffione " OPT_DUMP 64 (dump rx/tx traffic)\n" 251180ad548dSVincenzo Maffione " OPT_RUBBISH 256\n" 2512ed188a7eSVincenzo Maffione " (send whatever the buffers contain)\n" 251380ad548dSVincenzo Maffione " OPT_RANDOM_SRC 512\n" 251480ad548dSVincenzo Maffione " OPT_RANDOM_DST 1024\n" 251580ad548dSVincenzo Maffione " OPT_PPS_STATS 2048\n" 251668b8534bSLuigi Rizzo "", 251768b8534bSLuigi Rizzo cmd); 251880ad548dSVincenzo Maffione exit(errcode); 251968b8534bSLuigi Rizzo } 252068b8534bSLuigi Rizzo 25214bfe1a4fSVincenzo Maffione static int 252280ad548dSVincenzo Maffione start_threads(struct glob_arg *g) { 2523f8e4e36aSLuigi Rizzo int i; 2524f8e4e36aSLuigi Rizzo 2525f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 252680ad548dSVincenzo Maffione struct targ *t; 2527f8e4e36aSLuigi Rizzo /* 2528f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 2529f8e4e36aSLuigi Rizzo * using a single descriptor. 2530f8e4e36aSLuigi Rizzo */ 2531f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 253227bf5dd3SVincenzo Maffione uint64_t seed = (uint64_t)time(0) | ((uint64_t)time(0) << 32); 253380ad548dSVincenzo Maffione t = &targs[i]; 2534f0ea3689SLuigi Rizzo 2535f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 2536f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 2537f0ea3689SLuigi Rizzo t->g = g; 253880ad548dSVincenzo Maffione memcpy(t->seed, &seed, sizeof(t->seed)); 2539f8e4e36aSLuigi Rizzo 2540f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 25414bfe1a4fSVincenzo Maffione int m = -1; 25424bfe1a4fSVincenzo Maffione 25434bfe1a4fSVincenzo Maffione /* 25444bfe1a4fSVincenzo Maffione * if the user wants both HW and SW rings, we need to 25454bfe1a4fSVincenzo Maffione * know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW 25464bfe1a4fSVincenzo Maffione */ 25474bfe1a4fSVincenzo Maffione if (g->orig_mode == NR_REG_NIC_SW) { 25484bfe1a4fSVincenzo Maffione m = (g->td_type == TD_TYPE_RECEIVER ? 25494bfe1a4fSVincenzo Maffione g->nmd->reg.nr_rx_rings : 25504bfe1a4fSVincenzo Maffione g->nmd->reg.nr_tx_rings); 25514bfe1a4fSVincenzo Maffione } 2552f8e4e36aSLuigi Rizzo 255337e3a6d3SLuigi Rizzo if (i > 0) { 25544bfe1a4fSVincenzo Maffione int j; 255537e3a6d3SLuigi Rizzo /* the first thread uses the fd opened by the main 255637e3a6d3SLuigi Rizzo * thread, the other threads re-open /dev/netmap 255737e3a6d3SLuigi Rizzo */ 25584bfe1a4fSVincenzo Maffione t->nmd = nmport_clone(g->nmd); 25594bfe1a4fSVincenzo Maffione if (t->nmd == NULL) 25604bfe1a4fSVincenzo Maffione return -1; 25614bfe1a4fSVincenzo Maffione 25624bfe1a4fSVincenzo Maffione j = i; 25634bfe1a4fSVincenzo Maffione if (m > 0 && j >= m) { 25644bfe1a4fSVincenzo Maffione /* switch to the software rings */ 25654bfe1a4fSVincenzo Maffione t->nmd->reg.nr_mode = NR_REG_ONE_SW; 25664bfe1a4fSVincenzo Maffione j -= m; 256717885a7bSLuigi Rizzo } 25684bfe1a4fSVincenzo Maffione t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK; 2569f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 257037e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_RECEIVER) 25714bfe1a4fSVincenzo Maffione t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL; 2572f8e4e36aSLuigi Rizzo 2573f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 25744bfe1a4fSVincenzo Maffione if (nmport_open_desc(t->nmd) < 0) { 25754bfe1a4fSVincenzo Maffione nmport_undo_prepare(t->nmd); 25764bfe1a4fSVincenzo Maffione t->nmd = NULL; 25774bfe1a4fSVincenzo Maffione return -1; 2578f8e4e36aSLuigi Rizzo } 257937e3a6d3SLuigi Rizzo } else { 258037e3a6d3SLuigi Rizzo t->nmd = g->nmd; 258137e3a6d3SLuigi Rizzo } 2582f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 258380ad548dSVincenzo Maffione t->frags = g->frags; 2584f8e4e36aSLuigi Rizzo } else { 2585f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 2586f8e4e36aSLuigi Rizzo } 2587f0ea3689SLuigi Rizzo t->used = 1; 2588f0ea3689SLuigi Rizzo t->me = i; 2589f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 259080ad548dSVincenzo Maffione t->affinity = (g->affinity + i) % g->cpus; 2591f0ea3689SLuigi Rizzo } else { 2592f0ea3689SLuigi Rizzo t->affinity = -1; 2593f0ea3689SLuigi Rizzo } 2594f8e4e36aSLuigi Rizzo /* default, init packets */ 2595f0ea3689SLuigi Rizzo initialize_packet(t); 259680ad548dSVincenzo Maffione } 259780ad548dSVincenzo Maffione /* Wait for PHY reset. */ 259880ad548dSVincenzo Maffione D("Wait %d secs for phy reset", g->wait_link); 259980ad548dSVincenzo Maffione sleep(g->wait_link); 260080ad548dSVincenzo Maffione D("Ready..."); 2601f8e4e36aSLuigi Rizzo 260280ad548dSVincenzo Maffione for (i = 0; i < g->nthreads; i++) { 260380ad548dSVincenzo Maffione t = &targs[i]; 2604f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 260517885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 2606f0ea3689SLuigi Rizzo t->used = 0; 2607f8e4e36aSLuigi Rizzo } 2608f8e4e36aSLuigi Rizzo } 26094bfe1a4fSVincenzo Maffione return 0; 2610f8e4e36aSLuigi Rizzo } 2611f8e4e36aSLuigi Rizzo 2612f8e4e36aSLuigi Rizzo static void 2613f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 2614f8e4e36aSLuigi Rizzo { 2615f8e4e36aSLuigi Rizzo int i; 2616f8e4e36aSLuigi Rizzo 261737e3a6d3SLuigi Rizzo struct my_ctrs prev, cur; 2618f8e4e36aSLuigi Rizzo double delta_t; 2619f8e4e36aSLuigi Rizzo struct timeval tic, toc; 2620f8e4e36aSLuigi Rizzo 262137e3a6d3SLuigi Rizzo prev.pkts = prev.bytes = prev.events = 0; 262237e3a6d3SLuigi Rizzo gettimeofday(&prev.t, NULL); 2623f8e4e36aSLuigi Rizzo for (;;) { 262480ad548dSVincenzo Maffione char b1[40], b2[40], b3[40], b4[100]; 262537e3a6d3SLuigi Rizzo uint64_t pps, usec; 262637e3a6d3SLuigi Rizzo struct my_ctrs x; 262737e3a6d3SLuigi Rizzo double abs; 2628f8e4e36aSLuigi Rizzo int done = 0; 2629f8e4e36aSLuigi Rizzo 263037e3a6d3SLuigi Rizzo usec = wait_for_next_report(&prev.t, &cur.t, 263137e3a6d3SLuigi Rizzo g->report_interval); 263237e3a6d3SLuigi Rizzo 263337e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 263437e3a6d3SLuigi Rizzo cur.min_space = 0; 263537e3a6d3SLuigi Rizzo if (usec < 10000) /* too short to be meaningful */ 263637e3a6d3SLuigi Rizzo continue; 263737e3a6d3SLuigi Rizzo /* accumulate counts for all threads */ 2638f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 263937e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 264037e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 264137e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 264237e3a6d3SLuigi Rizzo cur.min_space += targs[i].ctr.min_space; 264337e3a6d3SLuigi Rizzo targs[i].ctr.min_space = 99999; 2644f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 2645f8e4e36aSLuigi Rizzo done++; 2646f8e4e36aSLuigi Rizzo } 264737e3a6d3SLuigi Rizzo x.pkts = cur.pkts - prev.pkts; 264837e3a6d3SLuigi Rizzo x.bytes = cur.bytes - prev.bytes; 264937e3a6d3SLuigi Rizzo x.events = cur.events - prev.events; 265037e3a6d3SLuigi Rizzo pps = (x.pkts*1000000 + usec/2) / usec; 265137e3a6d3SLuigi Rizzo abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; 265237e3a6d3SLuigi Rizzo 265337e3a6d3SLuigi Rizzo if (!(g->options & OPT_PPS_STATS)) { 265437e3a6d3SLuigi Rizzo strcpy(b4, ""); 265537e3a6d3SLuigi Rizzo } else { 265637e3a6d3SLuigi Rizzo /* Compute some pps stats using a sliding window. */ 265737e3a6d3SLuigi Rizzo double ppsavg = 0.0, ppsdev = 0.0; 265837e3a6d3SLuigi Rizzo int nsamples = 0; 265937e3a6d3SLuigi Rizzo 266037e3a6d3SLuigi Rizzo g->win[g->win_idx] = pps; 266137e3a6d3SLuigi Rizzo g->win_idx = (g->win_idx + 1) % STATS_WIN; 266237e3a6d3SLuigi Rizzo 266337e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 266437e3a6d3SLuigi Rizzo ppsavg += g->win[i]; 266537e3a6d3SLuigi Rizzo if (g->win[i]) { 266637e3a6d3SLuigi Rizzo nsamples ++; 266737e3a6d3SLuigi Rizzo } 266837e3a6d3SLuigi Rizzo } 266937e3a6d3SLuigi Rizzo ppsavg /= nsamples; 267037e3a6d3SLuigi Rizzo 267137e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 267237e3a6d3SLuigi Rizzo if (g->win[i] == 0) { 2673f8e4e36aSLuigi Rizzo continue; 267437e3a6d3SLuigi Rizzo } 267537e3a6d3SLuigi Rizzo ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); 267637e3a6d3SLuigi Rizzo } 267737e3a6d3SLuigi Rizzo ppsdev /= nsamples; 267837e3a6d3SLuigi Rizzo ppsdev = sqrt(ppsdev); 267937e3a6d3SLuigi Rizzo 268037e3a6d3SLuigi Rizzo snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", 268180ad548dSVincenzo Maffione norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); 268237e3a6d3SLuigi Rizzo } 268337e3a6d3SLuigi Rizzo 268437e3a6d3SLuigi Rizzo D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", 268580ad548dSVincenzo Maffione norm(b1, pps, normalize), b4, 268680ad548dSVincenzo Maffione norm(b2, (double)x.pkts, normalize), 2687760fa2abSVincenzo Maffione norm(b3, 1000000*((double)x.bytes*8+(double)x.pkts*g->framing)/usec, normalize), 268837e3a6d3SLuigi Rizzo (unsigned long long)usec, 268937e3a6d3SLuigi Rizzo abs, (int)cur.min_space); 269037e3a6d3SLuigi Rizzo prev = cur; 269137e3a6d3SLuigi Rizzo 2692f8e4e36aSLuigi Rizzo if (done == g->nthreads) 2693f8e4e36aSLuigi Rizzo break; 2694f8e4e36aSLuigi Rizzo } 2695f8e4e36aSLuigi Rizzo 2696f8e4e36aSLuigi Rizzo timerclear(&tic); 2697f8e4e36aSLuigi Rizzo timerclear(&toc); 269837e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 269937e3a6d3SLuigi Rizzo /* final round */ 2700f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 27011cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 2702f8e4e36aSLuigi Rizzo /* 2703f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 2704f8e4e36aSLuigi Rizzo * file descriptors. 2705f8e4e36aSLuigi Rizzo */ 27061cb4c501SLuigi Rizzo if (targs[i].used) 270737e3a6d3SLuigi Rizzo pthread_join(targs[i].thread, NULL); /* blocking */ 270837e3a6d3SLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 27094bfe1a4fSVincenzo Maffione nmport_close(targs[i].nmd); 271037e3a6d3SLuigi Rizzo targs[i].nmd = NULL; 271137e3a6d3SLuigi Rizzo } else { 2712f8e4e36aSLuigi Rizzo close(targs[i].fd); 271337e3a6d3SLuigi Rizzo } 2714f8e4e36aSLuigi Rizzo 2715f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 2716f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 2717f8e4e36aSLuigi Rizzo 2718f8e4e36aSLuigi Rizzo /* 2719f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 2720f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 2721f8e4e36aSLuigi Rizzo */ 272237e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 272337e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 272437e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 272537e3a6d3SLuigi Rizzo /* collect the largest start (tic) and end (toc) times, 272637e3a6d3SLuigi Rizzo * XXX maybe we should do the earliest tic, or do a weighted 272737e3a6d3SLuigi Rizzo * average ? 272837e3a6d3SLuigi Rizzo */ 27291cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 27301cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 27311cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 27321cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 27331cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 27341cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 2735f8e4e36aSLuigi Rizzo } 2736f8e4e36aSLuigi Rizzo 2737f8e4e36aSLuigi Rizzo /* print output. */ 2738f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 2739f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 274037e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_SENDER) 274180ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Sent"); 274280ad548dSVincenzo Maffione else if (g->td_type == TD_TYPE_RECEIVER) 274380ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Received"); 2744f8e4e36aSLuigi Rizzo } 2745f8e4e36aSLuigi Rizzo 274637e3a6d3SLuigi Rizzo struct td_desc { 274737e3a6d3SLuigi Rizzo int ty; 27487eb32dc8SVincenzo Maffione const char *key; 2749f8e4e36aSLuigi Rizzo void *f; 275080ad548dSVincenzo Maffione int default_burst; 2751f8e4e36aSLuigi Rizzo }; 2752f8e4e36aSLuigi Rizzo 275337e3a6d3SLuigi Rizzo static struct td_desc func[] = { 275480ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ 275580ad548dSVincenzo Maffione { TD_TYPE_SENDER, "tx", sender_body, 512 }, 275680ad548dSVincenzo Maffione { TD_TYPE_OTHER, "ping", ping_body, 1 }, 275780ad548dSVincenzo Maffione { TD_TYPE_OTHER, "pong", pong_body, 1 }, 275880ad548dSVincenzo Maffione { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, 275980ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, 276080ad548dSVincenzo Maffione { 0, NULL, NULL, 0 } 2761f8e4e36aSLuigi Rizzo }; 2762f8e4e36aSLuigi Rizzo 2763f8e4e36aSLuigi Rizzo static int 2764f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 2765f8e4e36aSLuigi Rizzo { 2766f8e4e36aSLuigi Rizzo struct ifreq ifr; 2767f8e4e36aSLuigi Rizzo int fd, err; 27687eb32dc8SVincenzo Maffione const char *clonedev = TAP_CLONEDEV; 2769f8e4e36aSLuigi Rizzo 2770f8e4e36aSLuigi Rizzo (void)err; 2771f8e4e36aSLuigi Rizzo (void)dev; 2772f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 2773f8e4e36aSLuigi Rizzo * 2774f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 2775f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 2776f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 2777f8e4e36aSLuigi Rizzo */ 2778f8e4e36aSLuigi Rizzo 2779f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 2780f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 2781f8e4e36aSLuigi Rizzo static char buf[128]; 2782f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 2783f8e4e36aSLuigi Rizzo clonedev = buf; 2784f8e4e36aSLuigi Rizzo } 2785f8e4e36aSLuigi Rizzo #endif 2786f8e4e36aSLuigi Rizzo /* open the device */ 2787f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 2788f8e4e36aSLuigi Rizzo return fd; 2789f8e4e36aSLuigi Rizzo } 2790f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 2791f8e4e36aSLuigi Rizzo 2792f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 2793f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 2794f8e4e36aSLuigi Rizzo 2795f8e4e36aSLuigi Rizzo #ifdef linux 2796f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 2797f8e4e36aSLuigi Rizzo 2798f8e4e36aSLuigi Rizzo if (*dev) { 2799f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 2800f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 2801f8e4e36aSLuigi Rizzo * specified type */ 280280ad548dSVincenzo Maffione size_t len = strlen(dev); 280380ad548dSVincenzo Maffione if (len > IFNAMSIZ) { 280480ad548dSVincenzo Maffione D("%s too long", dev); 280580ad548dSVincenzo Maffione return -1; 280680ad548dSVincenzo Maffione } 280780ad548dSVincenzo Maffione memcpy(ifr.ifr_name, dev, len); 2808f8e4e36aSLuigi Rizzo } 2809f8e4e36aSLuigi Rizzo 2810f8e4e36aSLuigi Rizzo /* try to create the device */ 2811f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 281208cb3ac7SGordon Bergling D("failed to do a TUNSETIFF: %s", strerror(errno)); 2813f8e4e36aSLuigi Rizzo close(fd); 2814f8e4e36aSLuigi Rizzo return err; 2815f8e4e36aSLuigi Rizzo } 2816f8e4e36aSLuigi Rizzo 2817f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 2818f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 2819f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 2820f8e4e36aSLuigi Rizzo * code below) */ 2821f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 2822f8e4e36aSLuigi Rizzo D("new name is %s", dev); 2823f8e4e36aSLuigi Rizzo #endif /* linux */ 2824f8e4e36aSLuigi Rizzo 2825f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 2826f8e4e36aSLuigi Rizzo * with the virtual interface */ 2827f8e4e36aSLuigi Rizzo return fd; 2828f8e4e36aSLuigi Rizzo } 282968b8534bSLuigi Rizzo 283068b8534bSLuigi Rizzo int 283168b8534bSLuigi Rizzo main(int arc, char **argv) 283268b8534bSLuigi Rizzo { 2833f8e4e36aSLuigi Rizzo int i; 283437e3a6d3SLuigi Rizzo struct sigaction sa; 283537e3a6d3SLuigi Rizzo sigset_t ss; 283668b8534bSLuigi Rizzo 283768b8534bSLuigi Rizzo struct glob_arg g; 283868b8534bSLuigi Rizzo 283968b8534bSLuigi Rizzo int ch; 284068b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 284180ad548dSVincenzo Maffione int wait_link_arg = 0; 284280ad548dSVincenzo Maffione 284380ad548dSVincenzo Maffione int pkt_size_done = 0; 284480ad548dSVincenzo Maffione 284580ad548dSVincenzo Maffione struct td_desc *fn = func; 284668b8534bSLuigi Rizzo 284768b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 284868b8534bSLuigi Rizzo 2849f8e4e36aSLuigi Rizzo g.main_fd = -1; 285080ad548dSVincenzo Maffione g.td_body = fn->f; 285180ad548dSVincenzo Maffione g.td_type = fn->ty; 2852f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 2853f8e4e36aSLuigi Rizzo g.affinity = -1; 2854f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 285580ad548dSVincenzo Maffione g.af = AF_INET; /* default */ 2856f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 2857f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 2858f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 2859f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 286068b8534bSLuigi Rizzo g.pkt_size = 60; 286180ad548dSVincenzo Maffione g.pkt_min_size = 0; 286268b8534bSLuigi Rizzo g.nthreads = 1; 286380ad548dSVincenzo Maffione g.cpus = 1; /* default */ 2864b303f675SLuigi Rizzo g.forever = 1; 28651cb4c501SLuigi Rizzo g.tx_rate = 0; 2866ce3ee1e7SLuigi Rizzo g.frags = 1; 28679e53f3bdSVincenzo Maffione g.frag_size = (u_int)-1; /* use the netmap buffer size by default */ 2868ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 286917885a7bSLuigi Rizzo g.virt_header = 0; 287080ad548dSVincenzo Maffione g.wait_link = 2; /* wait 2 seconds for physical ports */ 287168b8534bSLuigi Rizzo 287280ad548dSVincenzo Maffione while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" 287380ad548dSVincenzo Maffione "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) { 2874f8e4e36aSLuigi Rizzo 287568b8534bSLuigi Rizzo switch(ch) { 287668b8534bSLuigi Rizzo default: 287768b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 287880ad548dSVincenzo Maffione usage(-1); 287980ad548dSVincenzo Maffione break; 288080ad548dSVincenzo Maffione 288180ad548dSVincenzo Maffione case 'h': 288280ad548dSVincenzo Maffione usage(0); 288380ad548dSVincenzo Maffione break; 288480ad548dSVincenzo Maffione 288580ad548dSVincenzo Maffione case '4': 288680ad548dSVincenzo Maffione g.af = AF_INET; 288780ad548dSVincenzo Maffione break; 288880ad548dSVincenzo Maffione 288980ad548dSVincenzo Maffione case '6': 289080ad548dSVincenzo Maffione g.af = AF_INET6; 289180ad548dSVincenzo Maffione break; 289280ad548dSVincenzo Maffione 289380ad548dSVincenzo Maffione case 'N': 289480ad548dSVincenzo Maffione normalize = 0; 289568b8534bSLuigi Rizzo break; 2896f8e4e36aSLuigi Rizzo 2897f8e4e36aSLuigi Rizzo case 'n': 289837e3a6d3SLuigi Rizzo g.npackets = strtoull(optarg, NULL, 10); 2899f8e4e36aSLuigi Rizzo break; 2900f8e4e36aSLuigi Rizzo 2901ce3ee1e7SLuigi Rizzo case 'F': 2902ce3ee1e7SLuigi Rizzo i = atoi(optarg); 2903ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 2904ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 2905ce3ee1e7SLuigi Rizzo break; 2906ce3ee1e7SLuigi Rizzo } 2907ce3ee1e7SLuigi Rizzo g.frags = i; 2908ce3ee1e7SLuigi Rizzo break; 2909ce3ee1e7SLuigi Rizzo 291080ad548dSVincenzo Maffione case 'M': 29119e53f3bdSVincenzo Maffione g.frag_size = atoi(optarg); 291280ad548dSVincenzo Maffione break; 291380ad548dSVincenzo Maffione 2914f8e4e36aSLuigi Rizzo case 'f': 2915f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 2916f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 2917f8e4e36aSLuigi Rizzo break; 2918f8e4e36aSLuigi Rizzo } 291937e3a6d3SLuigi Rizzo if (fn->key) { 2920f8e4e36aSLuigi Rizzo g.td_body = fn->f; 292137e3a6d3SLuigi Rizzo g.td_type = fn->ty; 292237e3a6d3SLuigi Rizzo } else { 2923f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 292437e3a6d3SLuigi Rizzo } 2925f8e4e36aSLuigi Rizzo break; 2926f8e4e36aSLuigi Rizzo 2927f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 292880ad548dSVincenzo Maffione g.options |= atoi(optarg); 292999fb123fSLuigi Rizzo break; 2930f8e4e36aSLuigi Rizzo 2931f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 2932f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 2933f8e4e36aSLuigi Rizzo break; 2934f8e4e36aSLuigi Rizzo 293568b8534bSLuigi Rizzo case 'i': /* interface */ 2936f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 2937f2637526SLuigi Rizzo * otherwise we guess 2938f2637526SLuigi Rizzo */ 2939f2637526SLuigi Rizzo D("interface is %s", optarg); 2940f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 2941f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 2942f0ea3689SLuigi Rizzo break; 2943f0ea3689SLuigi Rizzo } 2944f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 2945f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 2946f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 2947ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 2948f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 2949f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2950f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 2951f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 2952f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 2953f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 2954f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 2955f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 2956f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2957f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 2958f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2959f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 2960f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2961f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 2962f2637526SLuigi Rizzo } 296368b8534bSLuigi Rizzo break; 2964f8e4e36aSLuigi Rizzo 2965b303f675SLuigi Rizzo case 'I': 296680ad548dSVincenzo Maffione g.options |= OPT_INDIRECT; /* use indirect buffers */ 2967b303f675SLuigi Rizzo break; 2968b303f675SLuigi Rizzo 296968b8534bSLuigi Rizzo case 'l': /* pkt_size */ 297080ad548dSVincenzo Maffione if (pkt_size_done) { 297180ad548dSVincenzo Maffione g.pkt_min_size = atoi(optarg); 297280ad548dSVincenzo Maffione } else { 297368b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 297480ad548dSVincenzo Maffione pkt_size_done = 1; 297580ad548dSVincenzo Maffione } 297668b8534bSLuigi Rizzo break; 2977f8e4e36aSLuigi Rizzo 297868b8534bSLuigi Rizzo case 'd': 2979f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 298068b8534bSLuigi Rizzo break; 2981f8e4e36aSLuigi Rizzo 298268b8534bSLuigi Rizzo case 's': 2983f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 298468b8534bSLuigi Rizzo break; 2985f8e4e36aSLuigi Rizzo 298668b8534bSLuigi Rizzo case 'T': /* report interval */ 2987f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 298868b8534bSLuigi Rizzo break; 2989f8e4e36aSLuigi Rizzo 299068b8534bSLuigi Rizzo case 'w': 299180ad548dSVincenzo Maffione g.wait_link = atoi(optarg); 299280ad548dSVincenzo Maffione wait_link_arg = 1; 299368b8534bSLuigi Rizzo break; 2994f8e4e36aSLuigi Rizzo 299580ad548dSVincenzo Maffione case 'W': 299680ad548dSVincenzo Maffione g.forever = 0; /* exit RX with no traffic */ 2997f8e4e36aSLuigi Rizzo break; 2998f8e4e36aSLuigi Rizzo 299968b8534bSLuigi Rizzo case 'b': /* burst */ 300068b8534bSLuigi Rizzo g.burst = atoi(optarg); 300168b8534bSLuigi Rizzo break; 300268b8534bSLuigi Rizzo case 'c': 300368b8534bSLuigi Rizzo g.cpus = atoi(optarg); 300468b8534bSLuigi Rizzo break; 300568b8534bSLuigi Rizzo case 'p': 300668b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 300768b8534bSLuigi Rizzo break; 300868b8534bSLuigi Rizzo 300968b8534bSLuigi Rizzo case 'D': /* destination mac */ 3010f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 301168b8534bSLuigi Rizzo break; 3012f8e4e36aSLuigi Rizzo 301368b8534bSLuigi Rizzo case 'S': /* source mac */ 3014f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 301568b8534bSLuigi Rizzo break; 301668b8534bSLuigi Rizzo case 'v': 301768b8534bSLuigi Rizzo verbose++; 30181cb4c501SLuigi Rizzo break; 30191cb4c501SLuigi Rizzo case 'R': 30201cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 30211cb4c501SLuigi Rizzo break; 3022b303f675SLuigi Rizzo case 'X': 3023b303f675SLuigi Rizzo g.options |= OPT_DUMP; 3024ce3ee1e7SLuigi Rizzo break; 3025ce3ee1e7SLuigi Rizzo case 'C': 3026760fa2abSVincenzo Maffione D("WARNING: the 'C' option is deprecated, use the '+conf:' libnetmap option instead"); 3027ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 302817885a7bSLuigi Rizzo break; 302917885a7bSLuigi Rizzo case 'H': 303017885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 3031f2637526SLuigi Rizzo break; 3032f284c737SGeorge V. Neville-Neil case 'P': 3033f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 3034f284c737SGeorge V. Neville-Neil break; 303537e3a6d3SLuigi Rizzo case 'r': 303637e3a6d3SLuigi Rizzo g.options |= OPT_RUBBISH; 303737e3a6d3SLuigi Rizzo break; 303856717743SAdrian Chadd case 'z': 303956717743SAdrian Chadd g.options |= OPT_RANDOM_SRC; 304056717743SAdrian Chadd break; 304156717743SAdrian Chadd case 'Z': 304256717743SAdrian Chadd g.options |= OPT_RANDOM_DST; 304356717743SAdrian Chadd break; 304437e3a6d3SLuigi Rizzo case 'A': 304537e3a6d3SLuigi Rizzo g.options |= OPT_PPS_STATS; 304637e3a6d3SLuigi Rizzo break; 304780ad548dSVincenzo Maffione case 'B': 304880ad548dSVincenzo Maffione /* raw packets have4 bytes crc + 20 bytes framing */ 304980ad548dSVincenzo Maffione // XXX maybe add an option to pass the IFG 305080ad548dSVincenzo Maffione g.framing = 24 * 8; 305180ad548dSVincenzo Maffione break; 305268b8534bSLuigi Rizzo } 305368b8534bSLuigi Rizzo } 305468b8534bSLuigi Rizzo 3055db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 305668b8534bSLuigi Rizzo D("missing ifname"); 305780ad548dSVincenzo Maffione usage(-1); 305880ad548dSVincenzo Maffione } 305980ad548dSVincenzo Maffione 306080ad548dSVincenzo Maffione if (g.burst == 0) { 306180ad548dSVincenzo Maffione g.burst = fn->default_burst; 306280ad548dSVincenzo Maffione D("using default burst size: %d", g.burst); 306368b8534bSLuigi Rizzo } 3064f8e4e36aSLuigi Rizzo 306537e3a6d3SLuigi Rizzo g.system_cpus = i = system_ncpus(); 3066f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 3067f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 306880ad548dSVincenzo Maffione usage(-1); 306968b8534bSLuigi Rizzo } 307037e3a6d3SLuigi Rizzo D("running on %d cpus (have %d)", g.cpus, i); 307168b8534bSLuigi Rizzo if (g.cpus == 0) 3072f8e4e36aSLuigi Rizzo g.cpus = i; 3073f8e4e36aSLuigi Rizzo 307480ad548dSVincenzo Maffione if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) { 307580ad548dSVincenzo Maffione g.wait_link = 0; 307680ad548dSVincenzo Maffione } 307780ad548dSVincenzo Maffione 30784bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 30794bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 308080ad548dSVincenzo Maffione usage(-1); 308180ad548dSVincenzo Maffione } 308280ad548dSVincenzo Maffione 308380ad548dSVincenzo Maffione if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) { 308480ad548dSVincenzo Maffione D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size); 308580ad548dSVincenzo Maffione usage(-1); 308668b8534bSLuigi Rizzo } 308768b8534bSLuigi Rizzo 3088f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 3089f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 309099fb123fSLuigi Rizzo /* retrieve source mac address. */ 3091f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 309299fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 309399fb123fSLuigi Rizzo // continue, fail later 309499fb123fSLuigi Rizzo } 3095f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 309699fb123fSLuigi Rizzo } 3097f8e4e36aSLuigi Rizzo /* extract address ranges */ 309880ad548dSVincenzo Maffione if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac)) 309980ad548dSVincenzo Maffione usage(-1); 310080ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.src_ip, g.af); 310180ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.dst_ip, g.af); 3102f2637526SLuigi Rizzo 310317885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 310417885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 310517885a7bSLuigi Rizzo D("bad virtio-net-header length"); 310680ad548dSVincenzo Maffione usage(-1); 310717885a7bSLuigi Rizzo } 310817885a7bSLuigi Rizzo 3109f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 3110f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 3111f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 3112f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 3113f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 311480ad548dSVincenzo Maffione usage(-1); 311599fb123fSLuigi Rizzo } 3116f2637526SLuigi Rizzo #ifndef NO_PCAP 3117f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 3118f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 3119f8e4e36aSLuigi Rizzo 3120f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 31214bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 3122f8e4e36aSLuigi Rizzo if (g.p == NULL) { 3123f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 312480ad548dSVincenzo Maffione usage(-1); 3125f8e4e36aSLuigi Rizzo } 31264bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 31274bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 3128f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 3129f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 3130ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 313199fb123fSLuigi Rizzo } else { 31324bfe1a4fSVincenzo Maffione g.nmd = nmport_prepare(g.ifname); 31334bfe1a4fSVincenzo Maffione if (g.nmd == NULL) 313480ad548dSVincenzo Maffione goto out; 31354bfe1a4fSVincenzo Maffione 31364bfe1a4fSVincenzo Maffione parse_nmr_config(g.nmr_config, &g.nmd->reg); 31374bfe1a4fSVincenzo Maffione 31384bfe1a4fSVincenzo Maffione g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR; 3139f0ea3689SLuigi Rizzo 314068b8534bSLuigi Rizzo /* 3141f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 314268b8534bSLuigi Rizzo * 314368b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 314468b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 3145f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 314668b8534bSLuigi Rizzo */ 31474bfe1a4fSVincenzo Maffione g.orig_mode = g.nmd->reg.nr_mode; 314837e3a6d3SLuigi Rizzo if (g.nthreads > 1) { 31494bfe1a4fSVincenzo Maffione switch (g.orig_mode) { 31504bfe1a4fSVincenzo Maffione case NR_REG_ALL_NIC: 31514bfe1a4fSVincenzo Maffione case NR_REG_NIC_SW: 31524bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_NIC; 31534bfe1a4fSVincenzo Maffione break; 31544bfe1a4fSVincenzo Maffione case NR_REG_SW: 31554bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_SW; 31564bfe1a4fSVincenzo Maffione break; 31574bfe1a4fSVincenzo Maffione default: 31584bfe1a4fSVincenzo Maffione break; 315980ad548dSVincenzo Maffione } 31604bfe1a4fSVincenzo Maffione g.nmd->reg.nr_ringid = 0; 31614bfe1a4fSVincenzo Maffione } 31624bfe1a4fSVincenzo Maffione if (nmport_open_desc(g.nmd) < 0) 316337e3a6d3SLuigi Rizzo goto out; 3164f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 31654bfe1a4fSVincenzo Maffione ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10), 316680ad548dSVincenzo Maffione g.nmd->mem); 3167f0ea3689SLuigi Rizzo 316837e3a6d3SLuigi Rizzo if (g.virt_header) { 316937e3a6d3SLuigi Rizzo /* Set the virtio-net header length, since the user asked 317045c67e8fSVincenzo Maffione * for it explicitly. */ 317137e3a6d3SLuigi Rizzo set_vnet_hdr_len(&g); 317237e3a6d3SLuigi Rizzo } else { 317337e3a6d3SLuigi Rizzo /* Check whether the netmap port we opened requires us to send 317437e3a6d3SLuigi Rizzo * and receive frames with virtio-net header. */ 317537e3a6d3SLuigi Rizzo get_vnet_hdr_len(&g); 317637e3a6d3SLuigi Rizzo } 317737e3a6d3SLuigi Rizzo 31784bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 317937e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 31804bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings; 31814bf50f18SLuigi Rizzo else 31824bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings; 318368b8534bSLuigi Rizzo 318468b8534bSLuigi Rizzo /* validate provided nthreads. */ 318568b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 318668b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 318768b8534bSLuigi Rizzo // continue, fail later 318868b8534bSLuigi Rizzo } 318968b8534bSLuigi Rizzo 31909e53f3bdSVincenzo Maffione if (g.td_type == TD_TYPE_SENDER) { 31919e53f3bdSVincenzo Maffione int mtu = get_if_mtu(&g); 31929e53f3bdSVincenzo Maffione 31939e53f3bdSVincenzo Maffione if (mtu > 0 && g.pkt_size > mtu) { 31949e53f3bdSVincenzo Maffione D("pkt_size (%d) must be <= mtu (%d)", 31959e53f3bdSVincenzo Maffione g.pkt_size, mtu); 31969e53f3bdSVincenzo Maffione return -1; 31979e53f3bdSVincenzo Maffione } 31989e53f3bdSVincenzo Maffione } 31999e53f3bdSVincenzo Maffione 3200f2637526SLuigi Rizzo if (verbose) { 3201f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 32024bfe1a4fSVincenzo Maffione struct nmreq_register *req = &g.nmd->reg; 320368b8534bSLuigi Rizzo 3204d7493759SVincenzo Maffione D("nifp at offset %"PRIu64" ntxqs %d nrxqs %d memid %d", 3205f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 32064bfe1a4fSVincenzo Maffione req->nr_mem_id); 32074bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) { 32084bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 3209d7493759SVincenzo Maffione D(" TX%d at offset %p slots %d", i, 321037e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3211f2637526SLuigi Rizzo } 32124bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) { 32134bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 3214d7493759SVincenzo Maffione D(" RX%d at offset %p slots %d", i, 321537e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3216f2637526SLuigi Rizzo } 3217f2637526SLuigi Rizzo } 321868b8534bSLuigi Rizzo 321968b8534bSLuigi Rizzo /* Print some debug information. */ 322068b8534bSLuigi Rizzo fprintf(stdout, 322168b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 322237e3a6d3SLuigi Rizzo (g.td_type == TD_TYPE_SENDER) ? "Sending on" : 322337e3a6d3SLuigi Rizzo ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : 322437e3a6d3SLuigi Rizzo "Working on"), 3225f8e4e36aSLuigi Rizzo g.ifname, 322668b8534bSLuigi Rizzo devqueues, 322768b8534bSLuigi Rizzo g.nthreads, 322868b8534bSLuigi Rizzo g.cpus); 322937e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) { 323068b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 3231f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 3232f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 323368b8534bSLuigi Rizzo } 323468b8534bSLuigi Rizzo 3235f0ea3689SLuigi Rizzo out: 323668b8534bSLuigi Rizzo /* Exit if something went wrong. */ 3237f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 323868b8534bSLuigi Rizzo D("aborting"); 323980ad548dSVincenzo Maffione usage(-1); 324068b8534bSLuigi Rizzo } 324199fb123fSLuigi Rizzo } 324268b8534bSLuigi Rizzo 3243ce3ee1e7SLuigi Rizzo 324499fb123fSLuigi Rizzo if (g.options) { 324537e3a6d3SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", 324699fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 324799fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 324899fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 3249b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 325037e3a6d3SLuigi Rizzo g.options & OPT_COPY ? " copy" : "", 325137e3a6d3SLuigi Rizzo g.options & OPT_RUBBISH ? " rubbish " : ""); 325299fb123fSLuigi Rizzo } 32531cb4c501SLuigi Rizzo 3254ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 3255ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 3256ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 325717885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 3258ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 3259ce3ee1e7SLuigi Rizzo */ 326017885a7bSLuigi Rizzo uint64_t x; 326117885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 326217885a7bSLuigi Rizzo if (g.burst > lim) 326317885a7bSLuigi Rizzo g.burst = lim; 326480ad548dSVincenzo Maffione if (g.burst == 0) 326580ad548dSVincenzo Maffione g.burst = 1; 326617885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 326717885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 32681cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 32691cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 32701cb4c501SLuigi Rizzo } 327137e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 3272ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 3273ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 327468b8534bSLuigi Rizzo /* Install ^C handler. */ 327568b8534bSLuigi Rizzo global_nthreads = g.nthreads; 327637e3a6d3SLuigi Rizzo sigemptyset(&ss); 327737e3a6d3SLuigi Rizzo sigaddset(&ss, SIGINT); 327837e3a6d3SLuigi Rizzo /* block SIGINT now, so that all created threads will inherit the mask */ 327937e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { 328037e3a6d3SLuigi Rizzo D("failed to block SIGINT: %s", strerror(errno)); 328137e3a6d3SLuigi Rizzo } 32824bfe1a4fSVincenzo Maffione if (start_threads(&g) < 0) 32834bfe1a4fSVincenzo Maffione return 1; 328437e3a6d3SLuigi Rizzo /* Install the handler and re-enable SIGINT for the main thread */ 328580ad548dSVincenzo Maffione memset(&sa, 0, sizeof(sa)); 328637e3a6d3SLuigi Rizzo sa.sa_handler = sigint_h; 328737e3a6d3SLuigi Rizzo if (sigaction(SIGINT, &sa, NULL) < 0) { 328837e3a6d3SLuigi Rizzo D("failed to install ^C handler: %s", strerror(errno)); 328937e3a6d3SLuigi Rizzo } 329037e3a6d3SLuigi Rizzo 329137e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { 329237e3a6d3SLuigi Rizzo D("failed to re-enable SIGINT: %s", strerror(errno)); 329337e3a6d3SLuigi Rizzo } 3294f8e4e36aSLuigi Rizzo main_thread(&g); 329537e3a6d3SLuigi Rizzo free(targs); 3296f8e4e36aSLuigi Rizzo return 0; 329768b8534bSLuigi Rizzo } 329868b8534bSLuigi Rizzo 329968b8534bSLuigi Rizzo /* end of file */ 3300