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 687eda82511SVincenzo Maffione /* remove 'netmap:' prefix before comparing interfaces */ 688eda82511SVincenzo Maffione if (!strncmp(ifname, "netmap:", 7)) 689eda82511SVincenzo Maffione ifname = &ifname[7]; 690eda82511SVincenzo Maffione 69168b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 69268b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 69368b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 69468b8534bSLuigi Rizzo uint8_t *mac; 69568b8534bSLuigi Rizzo 69668b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 69768b8534bSLuigi Rizzo continue; 69880ad548dSVincenzo Maffione if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) 69968b8534bSLuigi Rizzo continue; 70068b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 70168b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 70268b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 70368b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 70468b8534bSLuigi Rizzo if (verbose) 70568b8534bSLuigi Rizzo D("source hwaddr %s", buf); 70668b8534bSLuigi Rizzo break; 70768b8534bSLuigi Rizzo } 70868b8534bSLuigi Rizzo freeifaddrs(ifaphead); 70968b8534bSLuigi Rizzo return ifap ? 0 : 1; 71068b8534bSLuigi Rizzo } 71168b8534bSLuigi Rizzo 71268b8534bSLuigi Rizzo 71368b8534bSLuigi Rizzo /* set the thread affinity. */ 71468b8534bSLuigi Rizzo static int 71568b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 71668b8534bSLuigi Rizzo { 71768b8534bSLuigi Rizzo cpuset_t cpumask; 71868b8534bSLuigi Rizzo 71968b8534bSLuigi Rizzo if (i == -1) 72068b8534bSLuigi Rizzo return 0; 72168b8534bSLuigi Rizzo 72268b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 72368b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 72468b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 72568b8534bSLuigi Rizzo 72668b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 72717885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 72868b8534bSLuigi Rizzo return 1; 72968b8534bSLuigi Rizzo } 73068b8534bSLuigi Rizzo return 0; 73168b8534bSLuigi Rizzo } 73268b8534bSLuigi Rizzo 73380ad548dSVincenzo Maffione 73468b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 73580ad548dSVincenzo Maffione static uint32_t 736f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 73768b8534bSLuigi Rizzo { 73868b8534bSLuigi Rizzo const uint8_t *addr = data; 739f8e4e36aSLuigi Rizzo uint32_t i; 74068b8534bSLuigi Rizzo 741f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 742f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 7437eb32dc8SVincenzo Maffione sum += (uint16_t)ntohs(*((const uint16_t *)(addr + i))); 744f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 745f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 746f8e4e36aSLuigi Rizzo } 747f8e4e36aSLuigi Rizzo /* 748f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 749f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 750f8e4e36aSLuigi Rizzo * the high byte. 751f8e4e36aSLuigi Rizzo */ 752f8e4e36aSLuigi Rizzo if (i < len) { 753f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 754f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 755f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 756f8e4e36aSLuigi Rizzo } 757f8e4e36aSLuigi Rizzo return sum; 75868b8534bSLuigi Rizzo } 75968b8534bSLuigi Rizzo 76080ad548dSVincenzo Maffione static uint16_t 76180ad548dSVincenzo Maffione wrapsum(uint32_t sum) 762f8e4e36aSLuigi Rizzo { 763f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 764f8e4e36aSLuigi Rizzo return (htons(sum)); 76568b8534bSLuigi Rizzo } 76668b8534bSLuigi Rizzo 767b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 768b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 769b303f675SLuigi Rizzo */ 770b303f675SLuigi Rizzo static void 77137e3a6d3SLuigi Rizzo dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) 772b303f675SLuigi Rizzo { 773b303f675SLuigi Rizzo char buf[128]; 774b303f675SLuigi Rizzo int i, j, i0; 77537e3a6d3SLuigi Rizzo const unsigned char *p = (const unsigned char *)_p; 776b303f675SLuigi Rizzo 777b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 778b303f675SLuigi Rizzo 779ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 780ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 781ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 782b303f675SLuigi Rizzo /* hexdump routine */ 783b303f675SLuigi Rizzo for (i = 0; i < len; ) { 784b797f66cSConrad Meyer memset(buf, ' ', sizeof(buf)); 785b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 786b303f675SLuigi Rizzo i0 = i; 787b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 788b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 789b303f675SLuigi Rizzo i = i0; 790b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 791b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 792b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 793b303f675SLuigi Rizzo printf("%s\n", buf); 794b303f675SLuigi Rizzo } 795b303f675SLuigi Rizzo } 796b303f675SLuigi Rizzo 79768b8534bSLuigi Rizzo /* 79868b8534bSLuigi Rizzo * Fill a packet with some payload. 799f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 800f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 80168b8534bSLuigi Rizzo */ 802f8e4e36aSLuigi Rizzo #ifdef __linux__ 803f8e4e36aSLuigi Rizzo #define uh_sport source 804f8e4e36aSLuigi Rizzo #define uh_dport dest 805f8e4e36aSLuigi Rizzo #define uh_ulen len 806f8e4e36aSLuigi Rizzo #define uh_sum check 807f8e4e36aSLuigi Rizzo #endif /* linux */ 808b303f675SLuigi Rizzo 80927bf5dd3SVincenzo Maffione static uint16_t 81027bf5dd3SVincenzo Maffione new_ip_sum(uint16_t ip_sum, uint32_t oaddr, uint32_t naddr) 81127bf5dd3SVincenzo Maffione { 81227bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 81327bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 81427bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 81527bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 81627bf5dd3SVincenzo Maffione return ip_sum; 81727bf5dd3SVincenzo Maffione } 81827bf5dd3SVincenzo Maffione 81927bf5dd3SVincenzo Maffione static uint16_t 82027bf5dd3SVincenzo Maffione new_udp_sum(uint16_t udp_sum, uint16_t oport, uint16_t nport) 82127bf5dd3SVincenzo Maffione { 82227bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 82327bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 82427bf5dd3SVincenzo Maffione return udp_sum; 82527bf5dd3SVincenzo Maffione } 82627bf5dd3SVincenzo Maffione 82727bf5dd3SVincenzo Maffione 828ce3ee1e7SLuigi Rizzo static void 82980ad548dSVincenzo Maffione update_ip(struct pkt *pkt, struct targ *t) 830ce3ee1e7SLuigi Rizzo { 83180ad548dSVincenzo Maffione struct glob_arg *g = t->g; 83280ad548dSVincenzo Maffione struct ip ip; 83380ad548dSVincenzo Maffione struct udphdr udp; 83480ad548dSVincenzo Maffione uint32_t oaddr, naddr; 83580ad548dSVincenzo Maffione uint16_t oport, nport; 83627bf5dd3SVincenzo Maffione uint16_t ip_sum = 0, udp_sum = 0; 837ce3ee1e7SLuigi Rizzo 83880ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 83980ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); 840f2637526SLuigi Rizzo do { 84180ad548dSVincenzo Maffione ip_sum = udp_sum = 0; 84280ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_src.s_addr); 84380ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 84456717743SAdrian Chadd if (g->options & OPT_RANDOM_SRC) { 84580ad548dSVincenzo Maffione ip.ip_src.s_addr = nrand48(t->seed); 84680ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 84780ad548dSVincenzo Maffione naddr = ntohl(ip.ip_src.s_addr); 84880ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 84927bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 85027bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 85127bf5dd3SVincenzo Maffione } else { 85280ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 85380ad548dSVincenzo Maffione nport = oport + 1; 85480ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 85527bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 856f2637526SLuigi Rizzo break; 857ce3ee1e7SLuigi Rizzo } 85880ad548dSVincenzo Maffione nport = g->src_ip.port0; 85980ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 86080ad548dSVincenzo Maffione if (oaddr < g->src_ip.ipv4.end) { 86180ad548dSVincenzo Maffione naddr = oaddr + 1; 86280ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 86327bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 864f2637526SLuigi Rizzo break; 865ce3ee1e7SLuigi Rizzo } 86680ad548dSVincenzo Maffione naddr = g->src_ip.ipv4.start; 86780ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 86827bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 86980ad548dSVincenzo Maffione } 87027bf5dd3SVincenzo Maffione 87180ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_dst.s_addr); 87280ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 87380ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 87480ad548dSVincenzo Maffione ip.ip_dst.s_addr = nrand48(t->seed); 87580ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 87680ad548dSVincenzo Maffione naddr = ntohl(ip.ip_dst.s_addr); 87780ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 87827bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 87927bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 88027bf5dd3SVincenzo Maffione } else { 88180ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 88280ad548dSVincenzo Maffione nport = oport + 1; 88380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88427bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 88580ad548dSVincenzo Maffione break; 88680ad548dSVincenzo Maffione } 88780ad548dSVincenzo Maffione nport = g->dst_ip.port0; 88880ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88980ad548dSVincenzo Maffione if (oaddr < g->dst_ip.ipv4.end) { 89080ad548dSVincenzo Maffione naddr = oaddr + 1; 89180ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 89227bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 89380ad548dSVincenzo Maffione break; 89480ad548dSVincenzo Maffione } 89580ad548dSVincenzo Maffione naddr = g->dst_ip.ipv4.start; 89680ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 89727bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 89827bf5dd3SVincenzo Maffione } 89980ad548dSVincenzo Maffione } while (0); 90080ad548dSVincenzo Maffione /* update checksums */ 90180ad548dSVincenzo Maffione if (udp_sum != 0) 90280ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); 90380ad548dSVincenzo Maffione if (ip_sum != 0) { 90480ad548dSVincenzo Maffione ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); 90580ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); 90680ad548dSVincenzo Maffione } 90780ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 90880ad548dSVincenzo Maffione memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); 909ce3ee1e7SLuigi Rizzo } 910ce3ee1e7SLuigi Rizzo 91180ad548dSVincenzo Maffione #ifndef s6_addr16 91280ad548dSVincenzo Maffione #define s6_addr16 __u6_addr.__u6_addr16 91380ad548dSVincenzo Maffione #endif 91480ad548dSVincenzo Maffione static void 91580ad548dSVincenzo Maffione update_ip6(struct pkt *pkt, struct targ *t) 91680ad548dSVincenzo Maffione { 91780ad548dSVincenzo Maffione struct glob_arg *g = t->g; 91880ad548dSVincenzo Maffione struct ip6_hdr ip6; 91980ad548dSVincenzo Maffione struct udphdr udp; 92080ad548dSVincenzo Maffione uint16_t udp_sum; 92180ad548dSVincenzo Maffione uint16_t oaddr, naddr; 92280ad548dSVincenzo Maffione uint16_t oport, nport; 92380ad548dSVincenzo Maffione uint8_t group; 92480ad548dSVincenzo Maffione 92580ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); 92680ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); 92780ad548dSVincenzo Maffione do { 92880ad548dSVincenzo Maffione udp_sum = 0; 92980ad548dSVincenzo Maffione group = g->src_ip.ipv6.sgroup; 93080ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); 93180ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 93280ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_SRC) { 93380ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = nrand48(t->seed); 93480ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 93580ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_src.s6_addr16[group]); 93680ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 93780ad548dSVincenzo Maffione break; 93880ad548dSVincenzo Maffione } 93980ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 94080ad548dSVincenzo Maffione nport = oport + 1; 94180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 94280ad548dSVincenzo Maffione break; 94380ad548dSVincenzo Maffione } 94480ad548dSVincenzo Maffione nport = g->src_ip.port0; 94580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 94680ad548dSVincenzo Maffione if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { 94780ad548dSVincenzo Maffione naddr = oaddr + 1; 94880ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 94980ad548dSVincenzo Maffione break; 95080ad548dSVincenzo Maffione } 95180ad548dSVincenzo Maffione naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); 95280ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 95327bf5dd3SVincenzo Maffione 95480ad548dSVincenzo Maffione /* update checksums if needed */ 95580ad548dSVincenzo Maffione if (oaddr != naddr) 95680ad548dSVincenzo Maffione udp_sum = cksum_add(~oaddr, naddr); 95780ad548dSVincenzo Maffione if (oport != nport) 95880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 95980ad548dSVincenzo Maffione cksum_add(~oport, nport)); 96027bf5dd3SVincenzo Maffione 96180ad548dSVincenzo Maffione group = g->dst_ip.ipv6.egroup; 96280ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 96380ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 96480ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 96580ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed); 96680ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 96780ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 96880ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 96980ad548dSVincenzo Maffione break; 97080ad548dSVincenzo Maffione } 97180ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 97280ad548dSVincenzo Maffione nport = oport + 1; 97380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97480ad548dSVincenzo Maffione break; 97580ad548dSVincenzo Maffione } 97680ad548dSVincenzo Maffione nport = g->dst_ip.port0; 97780ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97880ad548dSVincenzo Maffione if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { 97980ad548dSVincenzo Maffione naddr = oaddr + 1; 98080ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 98180ad548dSVincenzo Maffione break; 98280ad548dSVincenzo Maffione } 98380ad548dSVincenzo Maffione naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); 98480ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 98580ad548dSVincenzo Maffione } while (0); 98680ad548dSVincenzo Maffione /* update checksums */ 98780ad548dSVincenzo Maffione if (oaddr != naddr) 98880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 98980ad548dSVincenzo Maffione cksum_add(~oaddr, naddr)); 99080ad548dSVincenzo Maffione if (oport != nport) 99180ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 99280ad548dSVincenzo Maffione cksum_add(~oport, nport)); 99380ad548dSVincenzo Maffione if (udp_sum != 0) 99480ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); 99580ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 99680ad548dSVincenzo Maffione memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); 99780ad548dSVincenzo Maffione } 99880ad548dSVincenzo Maffione 99980ad548dSVincenzo Maffione static void 100080ad548dSVincenzo Maffione update_addresses(struct pkt *pkt, struct targ *t) 100180ad548dSVincenzo Maffione { 100280ad548dSVincenzo Maffione 100380ad548dSVincenzo Maffione if (t->g->af == AF_INET) 100480ad548dSVincenzo Maffione update_ip(pkt, t); 100580ad548dSVincenzo Maffione else 100680ad548dSVincenzo Maffione update_ip6(pkt, t); 100780ad548dSVincenzo Maffione } 1008ce3ee1e7SLuigi Rizzo /* 1009ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 1010ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 1011ce3ee1e7SLuigi Rizzo */ 101268b8534bSLuigi Rizzo static void 101368b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 101468b8534bSLuigi Rizzo { 101568b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 101668b8534bSLuigi Rizzo struct ether_header *eh; 101780ad548dSVincenzo Maffione struct ip6_hdr ip6; 101880ad548dSVincenzo Maffione struct ip ip; 101980ad548dSVincenzo Maffione struct udphdr udp; 102080ad548dSVincenzo Maffione void *udp_ptr; 102180ad548dSVincenzo Maffione uint16_t paylen; 102280ad548dSVincenzo Maffione uint32_t csum = 0; 1023b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 1024ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 1025f2637526SLuigi Rizzo int i, l0 = strlen(payload); 102668b8534bSLuigi Rizzo 102737e3a6d3SLuigi Rizzo #ifndef NO_PCAP 1028f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 1029f284c737SGeorge V. Neville-Neil pcap_t *file; 1030f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 1031f284c737SGeorge V. Neville-Neil const unsigned char *packet; 1032f284c737SGeorge V. Neville-Neil 1033f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 1034f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 1035f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 1036f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 1037f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 1038f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1039f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 1040f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 1041f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1042f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 1043f284c737SGeorge V. Neville-Neil D("out of memory"); 1044f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 1045f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 1046f284c737SGeorge V. Neville-Neil pcap_close(file); 1047f284c737SGeorge V. Neville-Neil return; 1048f284c737SGeorge V. Neville-Neil } 104937e3a6d3SLuigi Rizzo #endif 1050f284c737SGeorge V. Neville-Neil 105180ad548dSVincenzo Maffione paylen = targ->g->pkt_size - sizeof(*eh) - 105280ad548dSVincenzo Maffione (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); 105380ad548dSVincenzo Maffione 1054ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 1055f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 1056f2637526SLuigi Rizzo if (l0 > paylen - i) 1057f2637526SLuigi Rizzo l0 = paylen - i; // last round 105880ad548dSVincenzo Maffione bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0); 105968b8534bSLuigi Rizzo } 106080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[i - 1] = '\0'; 1061f8e4e36aSLuigi Rizzo 1062ce3ee1e7SLuigi Rizzo /* prepare the headers */ 106368b8534bSLuigi Rizzo eh = &pkt->eh; 1064f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 1065f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 106680ad548dSVincenzo Maffione 106780ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 106868b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 106980ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 107080ad548dSVincenzo Maffione udp_ptr = &pkt->ipv4.udp; 107180ad548dSVincenzo Maffione ip.ip_v = IPVERSION; 107280ad548dSVincenzo Maffione ip.ip_hl = sizeof(ip) >> 2; 107380ad548dSVincenzo Maffione ip.ip_id = 0; 107480ad548dSVincenzo Maffione ip.ip_tos = IPTOS_LOWDELAY; 107580ad548dSVincenzo Maffione ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); 107680ad548dSVincenzo Maffione ip.ip_id = 0; 107780ad548dSVincenzo Maffione ip.ip_off = htons(IP_DF); /* Don't fragment */ 107880ad548dSVincenzo Maffione ip.ip_ttl = IPDEFTTL; 107980ad548dSVincenzo Maffione ip.ip_p = IPPROTO_UDP; 108080ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); 108180ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); 108280ad548dSVincenzo Maffione ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); 108380ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 108480ad548dSVincenzo Maffione } else { 108580ad548dSVincenzo Maffione eh->ether_type = htons(ETHERTYPE_IPV6); 108680ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); 108780ad548dSVincenzo Maffione udp_ptr = &pkt->ipv6.udp; 108880ad548dSVincenzo Maffione ip6.ip6_flow = 0; 108980ad548dSVincenzo Maffione ip6.ip6_plen = htons(paylen); 109080ad548dSVincenzo Maffione ip6.ip6_vfc = IPV6_VERSION; 109180ad548dSVincenzo Maffione ip6.ip6_nxt = IPPROTO_UDP; 109280ad548dSVincenzo Maffione ip6.ip6_hlim = IPV6_DEFHLIM; 109380ad548dSVincenzo Maffione ip6.ip6_src = targ->g->src_ip.ipv6.start; 109480ad548dSVincenzo Maffione ip6.ip6_dst = targ->g->dst_ip.ipv6.start; 109580ad548dSVincenzo Maffione } 109680ad548dSVincenzo Maffione memcpy(&udp, udp_ptr, sizeof(udp)); 109780ad548dSVincenzo Maffione 109880ad548dSVincenzo Maffione udp.uh_sport = htons(targ->g->src_ip.port0); 109980ad548dSVincenzo Maffione udp.uh_dport = htons(targ->g->dst_ip.port0); 110080ad548dSVincenzo Maffione udp.uh_ulen = htons(paylen); 110180ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 110280ad548dSVincenzo Maffione /* Magic: taken from sbin/dhclient/packet.c */ 110380ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 110480ad548dSVincenzo Maffione checksum(&udp, sizeof(udp), /* udp header */ 110580ad548dSVincenzo Maffione checksum(pkt->ipv4.body, /* udp payload */ 110680ad548dSVincenzo Maffione paylen - sizeof(udp), 110780ad548dSVincenzo Maffione checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 110880ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv4.ip.ip_src), 110980ad548dSVincenzo Maffione IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); 111080ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 111180ad548dSVincenzo Maffione } else { 111280ad548dSVincenzo Maffione /* Save part of pseudo header checksum into csum */ 111380ad548dSVincenzo Maffione csum = IPPROTO_UDP << 24; 111480ad548dSVincenzo Maffione csum = checksum(&csum, sizeof(csum), paylen); 111580ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 111680ad548dSVincenzo Maffione checksum(udp_ptr, sizeof(udp), /* udp header */ 111780ad548dSVincenzo Maffione checksum(pkt->ipv6.body, /* udp payload */ 111880ad548dSVincenzo Maffione paylen - sizeof(udp), 111980ad548dSVincenzo Maffione checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 112080ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); 112180ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 112280ad548dSVincenzo Maffione } 112380ad548dSVincenzo Maffione memcpy(udp_ptr, &udp, sizeof(udp)); 112417885a7bSLuigi Rizzo 112517885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 1126b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 112768b8534bSLuigi Rizzo } 112868b8534bSLuigi Rizzo 11294bf50f18SLuigi Rizzo static void 113037e3a6d3SLuigi Rizzo get_vnet_hdr_len(struct glob_arg *g) 11314bf50f18SLuigi Rizzo { 11324bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11334bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 113437e3a6d3SLuigi Rizzo int err; 113537e3a6d3SLuigi Rizzo 11364bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11374bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET; 11384bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11394bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11404bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11414bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 114237e3a6d3SLuigi Rizzo if (err) { 114337e3a6d3SLuigi Rizzo D("Unable to get virtio-net header length"); 114437e3a6d3SLuigi Rizzo return; 114537e3a6d3SLuigi Rizzo } 114637e3a6d3SLuigi Rizzo 11474bfe1a4fSVincenzo Maffione g->virt_header = ph.nr_hdr_len; 114837e3a6d3SLuigi Rizzo if (g->virt_header) { 114937e3a6d3SLuigi Rizzo D("Port requires virtio-net header, length = %d", 115037e3a6d3SLuigi Rizzo g->virt_header); 115137e3a6d3SLuigi Rizzo } 115237e3a6d3SLuigi Rizzo } 115337e3a6d3SLuigi Rizzo 115437e3a6d3SLuigi Rizzo static void 115537e3a6d3SLuigi Rizzo set_vnet_hdr_len(struct glob_arg *g) 115637e3a6d3SLuigi Rizzo { 115737e3a6d3SLuigi Rizzo int err, l = g->virt_header; 11584bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11594bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 11604bf50f18SLuigi Rizzo 11614bf50f18SLuigi Rizzo if (l == 0) 11624bf50f18SLuigi Rizzo return; 11634bf50f18SLuigi Rizzo 11644bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11654bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET; 11664bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11674bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11684bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11694bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 11704bf50f18SLuigi Rizzo if (err) { 117137e3a6d3SLuigi Rizzo D("Unable to set virtio-net header length %d", l); 11724bf50f18SLuigi Rizzo } 11734bf50f18SLuigi Rizzo } 117468b8534bSLuigi Rizzo 117568b8534bSLuigi Rizzo /* 117668b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 117768b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 117868b8534bSLuigi Rizzo * an interrupt when done. 117968b8534bSLuigi Rizzo */ 118068b8534bSLuigi Rizzo static int 118117885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 118280ad548dSVincenzo Maffione int size, struct targ *t, u_int count, int options) 118368b8534bSLuigi Rizzo { 1184406e7723SVincenzo Maffione u_int n, sent, head = ring->head; 118580ad548dSVincenzo Maffione u_int frags = t->frags; 118680ad548dSVincenzo Maffione u_int frag_size = t->frag_size; 1187406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 118868b8534bSLuigi Rizzo 118917885a7bSLuigi Rizzo n = nm_ring_space(ring); 119099fb123fSLuigi Rizzo #if 0 119199fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 119268b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 1193406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 119468b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 119568b8534bSLuigi Rizzo 1196f2637526SLuigi Rizzo __builtin_prefetch(p); 1197406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 119899fb123fSLuigi Rizzo } 1199406e7723SVincenzo Maffione head = ring->head; 120099fb123fSLuigi Rizzo } 120199fb123fSLuigi Rizzo #endif 120280ad548dSVincenzo Maffione for (sent = 0; sent < count && n >= frags; sent++, n--) { 120380ad548dSVincenzo Maffione char *p; 120480ad548dSVincenzo Maffione int buf_changed; 120580ad548dSVincenzo Maffione u_int tosend = size; 120680ad548dSVincenzo Maffione 1207406e7723SVincenzo Maffione slot = &ring->slot[head]; 120880ad548dSVincenzo Maffione p = NETMAP_BUF(ring, slot->buf_idx); 120980ad548dSVincenzo Maffione buf_changed = slot->flags & NS_BUF_CHANGED; 121099fb123fSLuigi Rizzo 1211b303f675SLuigi Rizzo slot->flags = 0; 121237e3a6d3SLuigi Rizzo if (options & OPT_RUBBISH) { 121337e3a6d3SLuigi Rizzo /* do nothing */ 121437e3a6d3SLuigi Rizzo } else if (options & OPT_INDIRECT) { 1215b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 121637e3a6d3SLuigi Rizzo slot->ptr = (uint64_t)((uintptr_t)frame); 121780ad548dSVincenzo Maffione } else if (frags > 1) { 121880ad548dSVincenzo Maffione u_int i; 121980ad548dSVincenzo Maffione const char *f = frame; 122080ad548dSVincenzo Maffione char *fp = p; 122180ad548dSVincenzo Maffione for (i = 0; i < frags - 1; i++) { 122280ad548dSVincenzo Maffione memcpy(fp, f, frag_size); 122380ad548dSVincenzo Maffione slot->len = frag_size; 122480ad548dSVincenzo Maffione slot->flags = NS_MOREFRAG; 122580ad548dSVincenzo Maffione if (options & OPT_DUMP) 1226406e7723SVincenzo Maffione dump_payload(fp, frag_size, ring, head); 122780ad548dSVincenzo Maffione tosend -= frag_size; 122880ad548dSVincenzo Maffione f += frag_size; 1229406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 1230406e7723SVincenzo Maffione slot = &ring->slot[head]; 123180ad548dSVincenzo Maffione fp = NETMAP_BUF(ring, slot->buf_idx); 123280ad548dSVincenzo Maffione } 123380ad548dSVincenzo Maffione n -= (frags - 1); 123480ad548dSVincenzo Maffione p = fp; 123580ad548dSVincenzo Maffione slot->flags = 0; 123680ad548dSVincenzo Maffione memcpy(p, f, tosend); 123780ad548dSVincenzo Maffione update_addresses(pkt, t); 123880ad548dSVincenzo Maffione } else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) { 123980ad548dSVincenzo Maffione if (options & OPT_COPY) 1240f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 124180ad548dSVincenzo Maffione else 124217885a7bSLuigi Rizzo memcpy(p, frame, size); 124380ad548dSVincenzo Maffione update_addresses(pkt, t); 1244ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 1245f2637526SLuigi Rizzo __builtin_prefetch(p); 1246ce3ee1e7SLuigi Rizzo } 124780ad548dSVincenzo Maffione slot->len = tosend; 1248ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 1249406e7723SVincenzo Maffione dump_payload(p, tosend, ring, head); 1250406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 125168b8534bSLuigi Rizzo } 125280ad548dSVincenzo Maffione if (sent) { 125380ad548dSVincenzo Maffione slot->flags |= NS_REPORT; 1254406e7723SVincenzo Maffione ring->head = ring->cur = head; 125580ad548dSVincenzo Maffione } 125680ad548dSVincenzo Maffione if (sent < count) { 125780ad548dSVincenzo Maffione /* tell netmap that we need more slots */ 125880ad548dSVincenzo Maffione ring->cur = ring->tail; 125980ad548dSVincenzo Maffione } 126068b8534bSLuigi Rizzo 126168b8534bSLuigi Rizzo return (sent); 126268b8534bSLuigi Rizzo } 126368b8534bSLuigi Rizzo 1264f8e4e36aSLuigi Rizzo /* 126537e3a6d3SLuigi Rizzo * Index of the highest bit set 126637e3a6d3SLuigi Rizzo */ 12677eb32dc8SVincenzo Maffione static uint32_t 126837e3a6d3SLuigi Rizzo msb64(uint64_t x) 126937e3a6d3SLuigi Rizzo { 127037e3a6d3SLuigi Rizzo uint64_t m = 1ULL << 63; 127137e3a6d3SLuigi Rizzo int i; 127237e3a6d3SLuigi Rizzo 127337e3a6d3SLuigi Rizzo for (i = 63; i >= 0; i--, m >>=1) 127437e3a6d3SLuigi Rizzo if (m & x) 127537e3a6d3SLuigi Rizzo return i; 127637e3a6d3SLuigi Rizzo return 0; 127737e3a6d3SLuigi Rizzo } 127837e3a6d3SLuigi Rizzo 127937e3a6d3SLuigi Rizzo /* 128080ad548dSVincenzo Maffione * wait until ts, either busy or sleeping if more than 1ms. 128180ad548dSVincenzo Maffione * Return wakeup time. 128280ad548dSVincenzo Maffione */ 128380ad548dSVincenzo Maffione static struct timespec 128480ad548dSVincenzo Maffione wait_time(struct timespec ts) 128580ad548dSVincenzo Maffione { 128680ad548dSVincenzo Maffione for (;;) { 128780ad548dSVincenzo Maffione struct timespec w, cur; 128880ad548dSVincenzo Maffione clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 128980ad548dSVincenzo Maffione w = timespec_sub(ts, cur); 129080ad548dSVincenzo Maffione if (w.tv_sec < 0) 129180ad548dSVincenzo Maffione return cur; 129280ad548dSVincenzo Maffione else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 129380ad548dSVincenzo Maffione poll(NULL, 0, 1); 129480ad548dSVincenzo Maffione } 129580ad548dSVincenzo Maffione } 129680ad548dSVincenzo Maffione 129780ad548dSVincenzo Maffione /* 1298f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 1299f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 1300f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 1301f8e4e36aSLuigi Rizzo */ 1302f8e4e36aSLuigi Rizzo 130368b8534bSLuigi Rizzo static void * 130480ad548dSVincenzo Maffione ping_body(void *data) 130568b8534bSLuigi Rizzo { 130668b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1307f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1308f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 130980ad548dSVincenzo Maffione int i, m, rx = 0; 131017885a7bSLuigi Rizzo void *frame; 131117885a7bSLuigi Rizzo int size; 1312f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 131380ad548dSVincenzo Maffione struct timespec nexttime = {0, 0}; /* silence compiler */ 131437e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 131537e3a6d3SLuigi Rizzo uint64_t count = 0, t_cur, t_min = ~0, av = 0; 131680ad548dSVincenzo Maffione uint64_t g_min = ~0, g_av = 0; 131737e3a6d3SLuigi Rizzo uint64_t buckets[64]; /* bins for delays, ns */ 131880ad548dSVincenzo Maffione int rate_limit = targ->g->tx_rate, tosend = 0; 131917885a7bSLuigi Rizzo 132080ad548dSVincenzo Maffione frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header; 132117885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1322e5ecae38SEd Maste 132337e3a6d3SLuigi Rizzo 1324f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1325f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 1326f8e4e36aSLuigi Rizzo return NULL; 1327f95a30bdSEd Maste } 1328f8e4e36aSLuigi Rizzo 13299a7abd93SVincenzo Maffione if (targ->g->af == AF_INET6) { 13309a7abd93SVincenzo Maffione D("Warning: ping-pong with IPv6 not supported"); 13319a7abd93SVincenzo Maffione } 13329a7abd93SVincenzo Maffione 133337e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1334f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 133517885a7bSLuigi Rizzo now = last_print; 133680ad548dSVincenzo Maffione if (rate_limit) { 133780ad548dSVincenzo Maffione targ->tic = timespec_add(now, (struct timespec){2,0}); 133880ad548dSVincenzo Maffione targ->tic.tv_nsec = 0; 133980ad548dSVincenzo Maffione wait_time(targ->tic); 134080ad548dSVincenzo Maffione nexttime = targ->tic; 134180ad548dSVincenzo Maffione } 134237e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 134380ad548dSVincenzo Maffione struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1344f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 1345f8e4e36aSLuigi Rizzo char *p; 134680ad548dSVincenzo Maffione int rv; 134780ad548dSVincenzo Maffione uint64_t limit, event = 0; 134880ad548dSVincenzo Maffione 134980ad548dSVincenzo Maffione if (rate_limit && tosend <= 0) { 135080ad548dSVincenzo Maffione tosend = targ->g->burst; 135180ad548dSVincenzo Maffione nexttime = timespec_add(nexttime, targ->g->tx_period); 135280ad548dSVincenzo Maffione wait_time(nexttime); 135380ad548dSVincenzo Maffione } 135480ad548dSVincenzo Maffione 135580ad548dSVincenzo Maffione limit = rate_limit ? tosend : targ->g->burst; 135680ad548dSVincenzo Maffione if (n > 0 && n - sent < limit) 135780ad548dSVincenzo Maffione limit = n - sent; 135880ad548dSVincenzo Maffione for (m = 0; (unsigned)m < limit; m++) { 1359406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 136017885a7bSLuigi Rizzo slot->len = size; 1361f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1362f8e4e36aSLuigi Rizzo 136317885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 1364f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 136580ad548dSVincenzo Maffione break; 1366f8e4e36aSLuigi Rizzo } else { 13674bf50f18SLuigi Rizzo struct tstamp *tp; 1368f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 1369f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 1370f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 13714bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13724bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 13734bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 1374f8e4e36aSLuigi Rizzo sent++; 1375406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1376f8e4e36aSLuigi Rizzo } 1377f8e4e36aSLuigi Rizzo } 137880ad548dSVincenzo Maffione if (m > 0) 137980ad548dSVincenzo Maffione event++; 138080ad548dSVincenzo Maffione targ->ctr.pkts = sent; 138180ad548dSVincenzo Maffione targ->ctr.bytes = sent*size; 138280ad548dSVincenzo Maffione targ->ctr.events = event; 138380ad548dSVincenzo Maffione if (rate_limit) 138480ad548dSVincenzo Maffione tosend -= m; 138580ad548dSVincenzo Maffione #ifdef BUSYWAIT 138680ad548dSVincenzo Maffione rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); 138780ad548dSVincenzo Maffione if (rv < 0) { 138880ad548dSVincenzo Maffione D("TXSYNC error on queue %d: %s", targ->me, 138917885a7bSLuigi Rizzo strerror(errno)); 139080ad548dSVincenzo Maffione } 139180ad548dSVincenzo Maffione again: 139280ad548dSVincenzo Maffione ioctl(pfd.fd, NIOCRXSYNC, NULL); 139380ad548dSVincenzo Maffione #else 139480ad548dSVincenzo Maffione /* should use a parameter to decide how often to send */ 139580ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 3000)) <= 0) { 139680ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 139780ad548dSVincenzo Maffione (rv ? strerror(errno) : "timeout")); 1398f8e4e36aSLuigi Rizzo continue; 1399f8e4e36aSLuigi Rizzo } 140080ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1401f8e4e36aSLuigi Rizzo /* see what we got back */ 140280ad548dSVincenzo Maffione rx = 0; 140380ad548dSVincenzo Maffione for (i = targ->nmd->first_rx_ring; 140480ad548dSVincenzo Maffione i <= targ->nmd->last_rx_ring; i++) { 1405f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 140617885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 1407f8e4e36aSLuigi Rizzo uint32_t seq; 14084bf50f18SLuigi Rizzo struct tstamp *tp; 140937e3a6d3SLuigi Rizzo int pos; 141037e3a6d3SLuigi Rizzo 1411406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 1412f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1413f8e4e36aSLuigi Rizzo 1414f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 1415f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 14164bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 14174bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 14184bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 1419f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 1420f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 1421f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1422f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1423f8e4e36aSLuigi Rizzo ts.tv_sec--; 1424f8e4e36aSLuigi Rizzo } 142580ad548dSVincenzo Maffione if (0) D("seq %d/%llu delta %d.%09d", seq, 142680ad548dSVincenzo Maffione (unsigned long long)sent, 1427f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 142837e3a6d3SLuigi Rizzo t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; 142937e3a6d3SLuigi Rizzo if (t_cur < t_min) 143037e3a6d3SLuigi Rizzo t_min = t_cur; 1431f8e4e36aSLuigi Rizzo count ++; 143237e3a6d3SLuigi Rizzo av += t_cur; 143337e3a6d3SLuigi Rizzo pos = msb64(t_cur); 143437e3a6d3SLuigi Rizzo buckets[pos]++; 143537e3a6d3SLuigi Rizzo /* now store it in a bucket */ 1436406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1437f8e4e36aSLuigi Rizzo rx++; 1438f8e4e36aSLuigi Rizzo } 1439f8e4e36aSLuigi Rizzo } 1440f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1441f8e4e36aSLuigi Rizzo //usleep(100000); 1442f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 1443f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 1444f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1445f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1446f8e4e36aSLuigi Rizzo ts.tv_sec--; 1447f8e4e36aSLuigi Rizzo } 1448f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 144937e3a6d3SLuigi Rizzo D("count %d RTT: min %d av %d ns", 145037e3a6d3SLuigi Rizzo (int)count, (int)t_min, (int)(av/count)); 145180ad548dSVincenzo Maffione int k, j, kmin, off; 145237e3a6d3SLuigi Rizzo char buf[512]; 145337e3a6d3SLuigi Rizzo 145437e3a6d3SLuigi Rizzo for (kmin = 0; kmin < 64; kmin ++) 145537e3a6d3SLuigi Rizzo if (buckets[kmin]) 145637e3a6d3SLuigi Rizzo break; 145737e3a6d3SLuigi Rizzo for (k = 63; k >= kmin; k--) 145837e3a6d3SLuigi Rizzo if (buckets[k]) 145937e3a6d3SLuigi Rizzo break; 146037e3a6d3SLuigi Rizzo buf[0] = '\0'; 146180ad548dSVincenzo Maffione off = 0; 146280ad548dSVincenzo Maffione for (j = kmin; j <= k; j++) { 146380ad548dSVincenzo Maffione off += sprintf(buf + off, " %5d", (int)buckets[j]); 146480ad548dSVincenzo Maffione } 146537e3a6d3SLuigi Rizzo D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf); 146637e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1467f8e4e36aSLuigi Rizzo count = 0; 146880ad548dSVincenzo Maffione g_av += av; 1469f8e4e36aSLuigi Rizzo av = 0; 147080ad548dSVincenzo Maffione if (t_min < g_min) 147180ad548dSVincenzo Maffione g_min = t_min; 147237e3a6d3SLuigi Rizzo t_min = ~0; 1473f8e4e36aSLuigi Rizzo last_print = now; 1474f8e4e36aSLuigi Rizzo } 147580ad548dSVincenzo Maffione #ifdef BUSYWAIT 147680ad548dSVincenzo Maffione if (rx < m && ts.tv_sec <= 3 && !targ->cancel) 147780ad548dSVincenzo Maffione goto again; 147880ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1479f8e4e36aSLuigi Rizzo } 148037e3a6d3SLuigi Rizzo 148180ad548dSVincenzo Maffione if (sent > 0) { 148280ad548dSVincenzo Maffione D("RTT over %llu packets: min %d av %d ns", 148380ad548dSVincenzo Maffione (long long unsigned)sent, (int)g_min, 148480ad548dSVincenzo Maffione (int)((double)g_av/sent)); 148580ad548dSVincenzo Maffione } 148680ad548dSVincenzo Maffione targ->completed = 1; 148780ad548dSVincenzo Maffione 148837e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 148937e3a6d3SLuigi Rizzo targ->used = 0; 149037e3a6d3SLuigi Rizzo 1491f8e4e36aSLuigi Rizzo return NULL; 1492f8e4e36aSLuigi Rizzo } 1493f8e4e36aSLuigi Rizzo 1494f8e4e36aSLuigi Rizzo 1495f8e4e36aSLuigi Rizzo /* 1496f8e4e36aSLuigi Rizzo * reply to ping requests 1497f8e4e36aSLuigi Rizzo */ 1498f8e4e36aSLuigi Rizzo static void * 149980ad548dSVincenzo Maffione pong_body(void *data) 1500f8e4e36aSLuigi Rizzo { 1501f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1502f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1503f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 1504f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 150537e3a6d3SLuigi Rizzo int i, rx = 0; 150637e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 1507f8e4e36aSLuigi Rizzo 1508f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1509f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 1510f8e4e36aSLuigi Rizzo return NULL; 1511f8e4e36aSLuigi Rizzo } 151280ad548dSVincenzo Maffione if (n > 0) 151380ad548dSVincenzo Maffione D("understood ponger %llu but don't know how to do it", 151480ad548dSVincenzo Maffione (unsigned long long)n); 15159a7abd93SVincenzo Maffione 15169a7abd93SVincenzo Maffione if (targ->g->af == AF_INET6) { 15179a7abd93SVincenzo Maffione D("Warning: ping-pong with IPv6 not supported"); 15189a7abd93SVincenzo Maffione } 15199a7abd93SVincenzo Maffione 152037e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 1521406e7723SVincenzo Maffione uint32_t txhead, txavail; 1522f8e4e36aSLuigi Rizzo //#define BUSYWAIT 1523f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1524f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 1525f8e4e36aSLuigi Rizzo #else 152680ad548dSVincenzo Maffione int rv; 152780ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 1000)) <= 0) { 152880ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 152980ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1530f8e4e36aSLuigi Rizzo continue; 1531f8e4e36aSLuigi Rizzo } 1532f8e4e36aSLuigi Rizzo #endif 153380ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1534406e7723SVincenzo Maffione txhead = txring->head; 153517885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 1536f8e4e36aSLuigi Rizzo /* see what we got back */ 1537f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 1538f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 153917885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 1540f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 1541406e7723SVincenzo Maffione uint32_t head = rxring->head; 1542406e7723SVincenzo Maffione struct netmap_slot *slot = &rxring->slot[head]; 1543f8e4e36aSLuigi Rizzo char *src, *dst; 1544f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 1545f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 1546406e7723SVincenzo Maffione rxring->head = rxring->cur = nm_ring_next(rxring, head); 1547f8e4e36aSLuigi Rizzo rx++; 1548f8e4e36aSLuigi Rizzo if (txavail == 0) 1549f8e4e36aSLuigi Rizzo continue; 1550f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 1551406e7723SVincenzo Maffione txring->slot[txhead].buf_idx); 1552f8e4e36aSLuigi Rizzo /* copy... */ 1553f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 1554f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 1555f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 155680ad548dSVincenzo Maffione /* swap source and destination MAC */ 1557f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 1558f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 1559f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 1560f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 1561f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 1562f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 15639a7abd93SVincenzo Maffione /* swap source and destination IPv4 */ 15649a7abd93SVincenzo Maffione if (spkt[6] == htons(ETHERTYPE_IP)) { 15659a7abd93SVincenzo Maffione dpkt[13] = spkt[15]; 15669a7abd93SVincenzo Maffione dpkt[14] = spkt[16]; 15679a7abd93SVincenzo Maffione dpkt[15] = spkt[13]; 15689a7abd93SVincenzo Maffione dpkt[16] = spkt[14]; 15699a7abd93SVincenzo Maffione } 1570406e7723SVincenzo Maffione txring->slot[txhead].len = slot->len; 15719a7abd93SVincenzo Maffione //dump_payload(dst, slot->len, txring, txhead); 1572406e7723SVincenzo Maffione txhead = nm_ring_next(txring, txhead); 1573f8e4e36aSLuigi Rizzo txavail--; 1574f8e4e36aSLuigi Rizzo sent++; 1575f8e4e36aSLuigi Rizzo } 1576f8e4e36aSLuigi Rizzo } 1577406e7723SVincenzo Maffione txring->head = txring->cur = txhead; 157837e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 1579f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1580f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 1581f8e4e36aSLuigi Rizzo #endif 1582f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1583f8e4e36aSLuigi Rizzo } 158437e3a6d3SLuigi Rizzo 158580ad548dSVincenzo Maffione targ->completed = 1; 158680ad548dSVincenzo Maffione 158737e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 158837e3a6d3SLuigi Rizzo targ->used = 0; 158937e3a6d3SLuigi Rizzo 1590f8e4e36aSLuigi Rizzo return NULL; 1591f8e4e36aSLuigi Rizzo } 1592f8e4e36aSLuigi Rizzo 1593f8e4e36aSLuigi Rizzo 1594f8e4e36aSLuigi Rizzo static void * 1595f8e4e36aSLuigi Rizzo sender_body(void *data) 1596f8e4e36aSLuigi Rizzo { 1597f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1598f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 15994bf50f18SLuigi Rizzo struct netmap_if *nifp; 160037e3a6d3SLuigi Rizzo struct netmap_ring *txring = NULL; 160137e3a6d3SLuigi Rizzo int i; 160237e3a6d3SLuigi Rizzo uint64_t n = targ->g->npackets / targ->g->nthreads; 160337e3a6d3SLuigi Rizzo uint64_t sent = 0; 160437e3a6d3SLuigi Rizzo uint64_t event = 0; 1605f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 160617885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 16071cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 160817885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 160917885a7bSLuigi Rizzo void *frame; 161017885a7bSLuigi Rizzo int size; 161117885a7bSLuigi Rizzo 1612f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 161380ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 161417885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1615f284c737SGeorge V. Neville-Neil } else { 1616f284c737SGeorge V. Neville-Neil frame = targ->frame; 1617f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1618f284c737SGeorge V. Neville-Neil } 1619b303f675SLuigi Rizzo 16204bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 162168b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 162268b8534bSLuigi Rizzo goto quit; 162368b8534bSLuigi Rizzo 162468b8534bSLuigi Rizzo /* main loop.*/ 16251cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 16261cb4c501SLuigi Rizzo if (rate_limit) { 162717885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 16281cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 162917885a7bSLuigi Rizzo wait_time(targ->tic); 16301cb4c501SLuigi Rizzo nexttime = targ->tic; 16311cb4c501SLuigi Rizzo } 1632f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1633f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1634f8e4e36aSLuigi Rizzo 1635f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 163617885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1637f8e4e36aSLuigi Rizzo sent++; 163880ad548dSVincenzo Maffione update_addresses(pkt, targ); 1639f8e4e36aSLuigi Rizzo if (i > 10000) { 164037e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 164137e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 164237e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1643f8e4e36aSLuigi Rizzo i = 0; 1644f8e4e36aSLuigi Rizzo } 1645f8e4e36aSLuigi Rizzo } 1646f2637526SLuigi Rizzo #ifndef NO_PCAP 1647f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1648f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1649f2637526SLuigi Rizzo 1650f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1651f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1652f2637526SLuigi Rizzo sent++; 165380ad548dSVincenzo Maffione update_addresses(pkt, targ); 1654f2637526SLuigi Rizzo if (i > 10000) { 165537e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 165637e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 165737e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1658f2637526SLuigi Rizzo i = 0; 1659f2637526SLuigi Rizzo } 1660f2637526SLuigi Rizzo } 1661f2637526SLuigi Rizzo #endif /* NO_PCAP */ 166268b8534bSLuigi Rizzo } else { 16631cb4c501SLuigi Rizzo int tosend = 0; 16649e53f3bdSVincenzo Maffione u_int bufsz, frag_size = targ->g->frag_size; 1665ce3ee1e7SLuigi Rizzo 16664bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 166780ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 166880ad548dSVincenzo Maffione bufsz = txring->nr_buf_size; 16699e53f3bdSVincenzo Maffione if (bufsz < frag_size) 16709e53f3bdSVincenzo Maffione frag_size = bufsz; 167180ad548dSVincenzo Maffione targ->frag_size = targ->g->pkt_size / targ->frags; 16729e53f3bdSVincenzo Maffione if (targ->frag_size > frag_size) { 16739e53f3bdSVincenzo Maffione targ->frags = targ->g->pkt_size / frag_size; 16749e53f3bdSVincenzo Maffione targ->frag_size = frag_size; 16759e53f3bdSVincenzo Maffione if (targ->g->pkt_size % frag_size != 0) 167680ad548dSVincenzo Maffione targ->frags++; 167780ad548dSVincenzo Maffione } 167880ad548dSVincenzo Maffione D("frags %u frag_size %u", targ->frags, targ->frag_size); 1679f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 168080ad548dSVincenzo Maffione int rv; 168168b8534bSLuigi Rizzo 16821cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 16831cb4c501SLuigi Rizzo tosend = targ->g->burst; 168417885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 168517885a7bSLuigi Rizzo wait_time(nexttime); 16861cb4c501SLuigi Rizzo } 16871cb4c501SLuigi Rizzo 168868b8534bSLuigi Rizzo /* 168968b8534bSLuigi Rizzo * wait for available room in the send queue(s) 169068b8534bSLuigi Rizzo */ 169137e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 169280ad548dSVincenzo Maffione (void)rv; 169337e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 169437e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 169537e3a6d3SLuigi Rizzo strerror(errno)); 169637e3a6d3SLuigi Rizzo goto quit; 169737e3a6d3SLuigi Rizzo } 169837e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 169980ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 17003fe77e68SEd Maste if (targ->cancel) 17013fe77e68SEd Maste break; 170280ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 170380ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1704f0ea3689SLuigi Rizzo // goto quit; 170517885a7bSLuigi Rizzo } 1706f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 170737e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 170837e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 170968b8534bSLuigi Rizzo goto quit; 171068b8534bSLuigi Rizzo } 171137e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 171268b8534bSLuigi Rizzo /* 171368b8534bSLuigi Rizzo * scan our queues and send on those with room 171468b8534bSLuigi Rizzo */ 1715f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1716f8e4e36aSLuigi Rizzo D("drop copy"); 171799fb123fSLuigi Rizzo options &= ~OPT_COPY; 1718f8e4e36aSLuigi Rizzo } 1719f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 172037e3a6d3SLuigi Rizzo int m; 172137e3a6d3SLuigi Rizzo uint64_t limit = rate_limit ? tosend : targ->g->burst; 172280ad548dSVincenzo Maffione 172380ad548dSVincenzo Maffione if (n > 0 && n == sent) 172480ad548dSVincenzo Maffione break; 172580ad548dSVincenzo Maffione 1726f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1727f8e4e36aSLuigi Rizzo limit = n - sent; 172868b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 172917885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 173068b8534bSLuigi Rizzo continue; 1731ce3ee1e7SLuigi Rizzo 173280ad548dSVincenzo Maffione if (targ->g->pkt_min_size > 0) { 173380ad548dSVincenzo Maffione size = nrand48(targ->seed) % 173480ad548dSVincenzo Maffione (targ->g->pkt_size - targ->g->pkt_min_size) + 173580ad548dSVincenzo Maffione targ->g->pkt_min_size; 173680ad548dSVincenzo Maffione } 173780ad548dSVincenzo Maffione m = send_packets(txring, pkt, frame, size, targ, 173880ad548dSVincenzo Maffione limit, options); 173980ad548dSVincenzo Maffione ND("limit %lu tail %d m %d", 174080ad548dSVincenzo Maffione limit, txring->tail, m); 174168b8534bSLuigi Rizzo sent += m; 174237e3a6d3SLuigi Rizzo if (m > 0) //XXX-ste: can m be 0? 174337e3a6d3SLuigi Rizzo event++; 174437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 174580ad548dSVincenzo Maffione targ->ctr.bytes += m*size; 174637e3a6d3SLuigi Rizzo targ->ctr.events = event; 1747ce3ee1e7SLuigi Rizzo if (rate_limit) { 1748ce3ee1e7SLuigi Rizzo tosend -= m; 1749ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1750ce3ee1e7SLuigi Rizzo break; 1751ce3ee1e7SLuigi Rizzo } 175268b8534bSLuigi Rizzo } 175368b8534bSLuigi Rizzo } 175499fb123fSLuigi Rizzo /* flush any remaining packets */ 175580ad548dSVincenzo Maffione if (txring != NULL) { 17564bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 17574bf50f18SLuigi Rizzo txring->tail, txring->head, 175837e3a6d3SLuigi Rizzo (void *)pthread_self()); 1759f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 176080ad548dSVincenzo Maffione } 176168b8534bSLuigi Rizzo 176268b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1763f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 176468b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 176537e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(txring)) { 17664bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 17674bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1768f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 176968b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 177068b8534bSLuigi Rizzo } 177168b8534bSLuigi Rizzo } 1772f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 177368b8534bSLuigi Rizzo 17741cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 177568b8534bSLuigi Rizzo targ->completed = 1; 177637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 177737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 177837e3a6d3SLuigi Rizzo targ->ctr.events = event; 177968b8534bSLuigi Rizzo quit: 178068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 178168b8534bSLuigi Rizzo targ->used = 0; 178268b8534bSLuigi Rizzo 178368b8534bSLuigi Rizzo return (NULL); 178468b8534bSLuigi Rizzo } 178568b8534bSLuigi Rizzo 178668b8534bSLuigi Rizzo 1787f2637526SLuigi Rizzo #ifndef NO_PCAP 178868b8534bSLuigi Rizzo static void 1789f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1790f8e4e36aSLuigi Rizzo const u_char * bytes) 179168b8534bSLuigi Rizzo { 179237e3a6d3SLuigi Rizzo struct my_ctrs *ctr = (struct my_ctrs *)user; 1793f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 179437e3a6d3SLuigi Rizzo ctr->bytes += h->len; 179537e3a6d3SLuigi Rizzo ctr->pkts++; 179668b8534bSLuigi Rizzo } 1797f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 179868b8534bSLuigi Rizzo 179937e3a6d3SLuigi Rizzo 180068b8534bSLuigi Rizzo static int 180137e3a6d3SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) 180268b8534bSLuigi Rizzo { 1803406e7723SVincenzo Maffione u_int head, rx, n; 180437e3a6d3SLuigi Rizzo uint64_t b = 0; 180580ad548dSVincenzo Maffione u_int complete = 0; 180637e3a6d3SLuigi Rizzo 180737e3a6d3SLuigi Rizzo if (bytes == NULL) 180837e3a6d3SLuigi Rizzo bytes = &b; 180968b8534bSLuigi Rizzo 1810406e7723SVincenzo Maffione head = ring->head; 181117885a7bSLuigi Rizzo n = nm_ring_space(ring); 181217885a7bSLuigi Rizzo if (n < limit) 181317885a7bSLuigi Rizzo limit = n; 181468b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 1815406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 181668b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 181768b8534bSLuigi Rizzo 181837e3a6d3SLuigi Rizzo *bytes += slot->len; 1819b303f675SLuigi Rizzo if (dump) 1820406e7723SVincenzo Maffione dump_payload(p, slot->len, ring, head); 182180ad548dSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) 182280ad548dSVincenzo Maffione complete++; 182368b8534bSLuigi Rizzo 1824406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 182568b8534bSLuigi Rizzo } 1826406e7723SVincenzo Maffione ring->head = ring->cur = head; 182768b8534bSLuigi Rizzo 182880ad548dSVincenzo Maffione return (complete); 182968b8534bSLuigi Rizzo } 183068b8534bSLuigi Rizzo 183168b8534bSLuigi Rizzo static void * 183268b8534bSLuigi Rizzo receiver_body(void *data) 183368b8534bSLuigi Rizzo { 183468b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1835f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 18364bf50f18SLuigi Rizzo struct netmap_if *nifp; 183768b8534bSLuigi Rizzo struct netmap_ring *rxring; 1838f8e4e36aSLuigi Rizzo int i; 183937e3a6d3SLuigi Rizzo struct my_ctrs cur; 184020d684ecSAllan Jude uint64_t n = targ->g->npackets / targ->g->nthreads; 184137e3a6d3SLuigi Rizzo 184280ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 184368b8534bSLuigi Rizzo 184468b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 184568b8534bSLuigi Rizzo goto quit; 184668b8534bSLuigi Rizzo 18474bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 18484bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 184968b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 18504bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1851f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1852f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 185368b8534bSLuigi Rizzo break; 185480ad548dSVincenzo Maffione if (i < 0) { 185580ad548dSVincenzo Maffione D("poll() error: %s", strerror(errno)); 185680ad548dSVincenzo Maffione goto quit; 185780ad548dSVincenzo Maffione } 185880ad548dSVincenzo Maffione if (pfd.revents & POLLERR) { 185980ad548dSVincenzo Maffione D("fd error"); 186080ad548dSVincenzo Maffione goto quit; 186180ad548dSVincenzo Maffione } 1862f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1863f0ea3689SLuigi Rizzo i, pfd.revents); 186468b8534bSLuigi Rizzo } 186568b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 18661cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1867f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1868950cf4a2SVincenzo Maffione while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 18694bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1870f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 187137e3a6d3SLuigi Rizzo i = read(targ->g->main_fd, buf, sizeof(buf)); 187237e3a6d3SLuigi Rizzo if (i > 0) { 187337e3a6d3SLuigi Rizzo targ->ctr.pkts++; 187437e3a6d3SLuigi Rizzo targ->ctr.bytes += i; 187537e3a6d3SLuigi Rizzo targ->ctr.events++; 187637e3a6d3SLuigi Rizzo } 1877f8e4e36aSLuigi Rizzo } 1878f2637526SLuigi Rizzo #ifndef NO_PCAP 1879f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 188020d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 1881f2637526SLuigi Rizzo /* XXX should we poll ? */ 18824bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 188337e3a6d3SLuigi Rizzo (u_char *)&targ->ctr); 188437e3a6d3SLuigi Rizzo targ->ctr.events++; 1885f2637526SLuigi Rizzo } 1886f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 188768b8534bSLuigi Rizzo } else { 1888b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 18894bf50f18SLuigi Rizzo 18904bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 189120d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 189268b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 189368b8534bSLuigi Rizzo before quitting. */ 189437e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 189537e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 189637e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 189737e3a6d3SLuigi Rizzo strerror(errno)); 189837e3a6d3SLuigi Rizzo goto quit; 189937e3a6d3SLuigi Rizzo } 190037e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 190137e3a6d3SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 190237e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 190337e3a6d3SLuigi Rizzo targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 190437e3a6d3SLuigi Rizzo goto out; 190537e3a6d3SLuigi Rizzo } 190637e3a6d3SLuigi Rizzo 190737e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 190837e3a6d3SLuigi Rizzo D("poll err"); 190937e3a6d3SLuigi Rizzo goto quit; 191037e3a6d3SLuigi Rizzo } 191137e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 191237e3a6d3SLuigi Rizzo uint64_t cur_space = 0; 191337e3a6d3SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 191437e3a6d3SLuigi Rizzo int m; 191537e3a6d3SLuigi Rizzo 191637e3a6d3SLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 191737e3a6d3SLuigi Rizzo /* compute free space in the ring */ 191837e3a6d3SLuigi Rizzo m = rxring->head + rxring->num_slots - rxring->tail; 191937e3a6d3SLuigi Rizzo if (m >= (int) rxring->num_slots) 192037e3a6d3SLuigi Rizzo m -= rxring->num_slots; 192137e3a6d3SLuigi Rizzo cur_space += m; 192237e3a6d3SLuigi Rizzo if (nm_ring_empty(rxring)) 192337e3a6d3SLuigi Rizzo continue; 192437e3a6d3SLuigi Rizzo 192537e3a6d3SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); 192637e3a6d3SLuigi Rizzo cur.pkts += m; 192780ad548dSVincenzo Maffione if (m > 0) 192837e3a6d3SLuigi Rizzo cur.events++; 192937e3a6d3SLuigi Rizzo } 193037e3a6d3SLuigi Rizzo cur.min_space = targ->ctr.min_space; 193137e3a6d3SLuigi Rizzo if (cur_space < cur.min_space) 193237e3a6d3SLuigi Rizzo cur.min_space = cur_space; 193337e3a6d3SLuigi Rizzo targ->ctr = cur; 193437e3a6d3SLuigi Rizzo } 193537e3a6d3SLuigi Rizzo } 193637e3a6d3SLuigi Rizzo 193737e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 193837e3a6d3SLuigi Rizzo 193937e3a6d3SLuigi Rizzo #if !defined(BUSYWAIT) 194037e3a6d3SLuigi Rizzo out: 194137e3a6d3SLuigi Rizzo #endif 194237e3a6d3SLuigi Rizzo targ->completed = 1; 194337e3a6d3SLuigi Rizzo targ->ctr = cur; 194437e3a6d3SLuigi Rizzo 194537e3a6d3SLuigi Rizzo quit: 194637e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 194737e3a6d3SLuigi Rizzo targ->used = 0; 194837e3a6d3SLuigi Rizzo 194937e3a6d3SLuigi Rizzo return (NULL); 195037e3a6d3SLuigi Rizzo } 195137e3a6d3SLuigi Rizzo 195237e3a6d3SLuigi Rizzo static void * 195337e3a6d3SLuigi Rizzo txseq_body(void *data) 195437e3a6d3SLuigi Rizzo { 195537e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 195637e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 195737e3a6d3SLuigi Rizzo struct netmap_ring *ring; 195837e3a6d3SLuigi Rizzo int64_t sent = 0; 195937e3a6d3SLuigi Rizzo uint64_t event = 0; 196037e3a6d3SLuigi Rizzo int options = targ->g->options | OPT_COPY; 196137e3a6d3SLuigi Rizzo struct timespec nexttime = {0, 0}; 196237e3a6d3SLuigi Rizzo int rate_limit = targ->g->tx_rate; 196337e3a6d3SLuigi Rizzo struct pkt *pkt = &targ->pkt; 196437e3a6d3SLuigi Rizzo int frags = targ->g->frags; 196537e3a6d3SLuigi Rizzo uint32_t sequence = 0; 196637e3a6d3SLuigi Rizzo int budget = 0; 196737e3a6d3SLuigi Rizzo void *frame; 196837e3a6d3SLuigi Rizzo int size; 196937e3a6d3SLuigi Rizzo 197037e3a6d3SLuigi Rizzo if (targ->g->nthreads > 1) { 197137e3a6d3SLuigi Rizzo D("can only txseq ping with 1 thread"); 197237e3a6d3SLuigi Rizzo return NULL; 197337e3a6d3SLuigi Rizzo } 197437e3a6d3SLuigi Rizzo 197537e3a6d3SLuigi Rizzo if (targ->g->npackets > 0) { 197637e3a6d3SLuigi Rizzo D("Ignoring -n argument"); 197737e3a6d3SLuigi Rizzo } 197837e3a6d3SLuigi Rizzo 197980ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 198037e3a6d3SLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 198137e3a6d3SLuigi Rizzo 198237e3a6d3SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 198337e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 198437e3a6d3SLuigi Rizzo goto quit; 198537e3a6d3SLuigi Rizzo 198637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 198737e3a6d3SLuigi Rizzo if (rate_limit) { 198837e3a6d3SLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 198937e3a6d3SLuigi Rizzo targ->tic.tv_nsec = 0; 199037e3a6d3SLuigi Rizzo wait_time(targ->tic); 199137e3a6d3SLuigi Rizzo nexttime = targ->tic; 199237e3a6d3SLuigi Rizzo } 199337e3a6d3SLuigi Rizzo 199437e3a6d3SLuigi Rizzo /* Only use the first queue. */ 199537e3a6d3SLuigi Rizzo ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); 199637e3a6d3SLuigi Rizzo 199737e3a6d3SLuigi Rizzo while (!targ->cancel) { 199837e3a6d3SLuigi Rizzo int64_t limit; 199937e3a6d3SLuigi Rizzo unsigned int space; 200037e3a6d3SLuigi Rizzo unsigned int head; 200137e3a6d3SLuigi Rizzo int fcnt; 200280ad548dSVincenzo Maffione uint16_t sum = 0; 200380ad548dSVincenzo Maffione int rv; 200437e3a6d3SLuigi Rizzo 200537e3a6d3SLuigi Rizzo if (!rate_limit) { 200637e3a6d3SLuigi Rizzo budget = targ->g->burst; 200737e3a6d3SLuigi Rizzo 200837e3a6d3SLuigi Rizzo } else if (budget <= 0) { 200937e3a6d3SLuigi Rizzo budget = targ->g->burst; 201037e3a6d3SLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 201137e3a6d3SLuigi Rizzo wait_time(nexttime); 201237e3a6d3SLuigi Rizzo } 201337e3a6d3SLuigi Rizzo 201437e3a6d3SLuigi Rizzo /* wait for available room in the send queue */ 201580ad548dSVincenzo Maffione #ifdef BUSYWAIT 201680ad548dSVincenzo Maffione (void)rv; 201780ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 201880ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 201980ad548dSVincenzo Maffione strerror(errno)); 202080ad548dSVincenzo Maffione goto quit; 202180ad548dSVincenzo Maffione } 202280ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 202380ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 202437e3a6d3SLuigi Rizzo if (targ->cancel) 202537e3a6d3SLuigi Rizzo break; 202680ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 202780ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 202880ad548dSVincenzo Maffione // goto quit; 202937e3a6d3SLuigi Rizzo } 203037e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 203137e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 203237e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 203337e3a6d3SLuigi Rizzo goto quit; 203437e3a6d3SLuigi Rizzo } 203580ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 203637e3a6d3SLuigi Rizzo 203737e3a6d3SLuigi Rizzo /* If no room poll() again. */ 203837e3a6d3SLuigi Rizzo space = nm_ring_space(ring); 203937e3a6d3SLuigi Rizzo if (!space) { 204037e3a6d3SLuigi Rizzo continue; 204137e3a6d3SLuigi Rizzo } 204237e3a6d3SLuigi Rizzo 204337e3a6d3SLuigi Rizzo limit = budget; 204437e3a6d3SLuigi Rizzo 204537e3a6d3SLuigi Rizzo if (space < limit) { 204637e3a6d3SLuigi Rizzo limit = space; 204737e3a6d3SLuigi Rizzo } 204837e3a6d3SLuigi Rizzo 204937e3a6d3SLuigi Rizzo /* Cut off ``limit`` to make sure is multiple of ``frags``. */ 205037e3a6d3SLuigi Rizzo if (frags > 1) { 205137e3a6d3SLuigi Rizzo limit = (limit / frags) * frags; 205237e3a6d3SLuigi Rizzo } 205337e3a6d3SLuigi Rizzo 205437e3a6d3SLuigi Rizzo limit = sent + limit; /* Convert to absolute. */ 205537e3a6d3SLuigi Rizzo 205637e3a6d3SLuigi Rizzo for (fcnt = frags, head = ring->head; 205737e3a6d3SLuigi Rizzo sent < limit; sent++, sequence++) { 205837e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 205937e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 206080ad548dSVincenzo Maffione uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; 206180ad548dSVincenzo Maffione 206280ad548dSVincenzo Maffione memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); 206337e3a6d3SLuigi Rizzo 206437e3a6d3SLuigi Rizzo slot->flags = 0; 206580ad548dSVincenzo Maffione t = *w; 206680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[0] = sequence >> 24; 206780ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; 206880ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 206980ad548dSVincenzo Maffione t = *++w; 207080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; 207180ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; 207280ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 207380ad548dSVincenzo Maffione memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); 207437e3a6d3SLuigi Rizzo nm_pkt_copy(frame, p, size); 207537e3a6d3SLuigi Rizzo if (fcnt == frags) { 207680ad548dSVincenzo Maffione update_addresses(pkt, targ); 207737e3a6d3SLuigi Rizzo } 207837e3a6d3SLuigi Rizzo 207937e3a6d3SLuigi Rizzo if (options & OPT_DUMP) { 208037e3a6d3SLuigi Rizzo dump_payload(p, size, ring, head); 208137e3a6d3SLuigi Rizzo } 208237e3a6d3SLuigi Rizzo 208337e3a6d3SLuigi Rizzo slot->len = size; 208437e3a6d3SLuigi Rizzo 208537e3a6d3SLuigi Rizzo if (--fcnt > 0) { 208637e3a6d3SLuigi Rizzo slot->flags |= NS_MOREFRAG; 208737e3a6d3SLuigi Rizzo } else { 208837e3a6d3SLuigi Rizzo fcnt = frags; 208937e3a6d3SLuigi Rizzo } 209037e3a6d3SLuigi Rizzo 209137e3a6d3SLuigi Rizzo if (sent == limit - 1) { 209237e3a6d3SLuigi Rizzo /* Make sure we don't push an incomplete 209337e3a6d3SLuigi Rizzo * packet. */ 209437e3a6d3SLuigi Rizzo assert(!(slot->flags & NS_MOREFRAG)); 209537e3a6d3SLuigi Rizzo slot->flags |= NS_REPORT; 209637e3a6d3SLuigi Rizzo } 209737e3a6d3SLuigi Rizzo 209837e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 209937e3a6d3SLuigi Rizzo if (rate_limit) { 210037e3a6d3SLuigi Rizzo budget--; 210137e3a6d3SLuigi Rizzo } 210237e3a6d3SLuigi Rizzo } 210337e3a6d3SLuigi Rizzo 210437e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 210537e3a6d3SLuigi Rizzo 210637e3a6d3SLuigi Rizzo event ++; 210737e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 210837e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 210937e3a6d3SLuigi Rizzo targ->ctr.events = event; 211037e3a6d3SLuigi Rizzo } 211137e3a6d3SLuigi Rizzo 211237e3a6d3SLuigi Rizzo /* flush any remaining packets */ 211337e3a6d3SLuigi Rizzo D("flush tail %d head %d on thread %p", 211437e3a6d3SLuigi Rizzo ring->tail, ring->head, 211537e3a6d3SLuigi Rizzo (void *)pthread_self()); 211637e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 211737e3a6d3SLuigi Rizzo 211837e3a6d3SLuigi Rizzo /* final part: wait the TX queues to become empty. */ 211937e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(ring)) { 212037e3a6d3SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 212137e3a6d3SLuigi Rizzo ring->tail, ring->head, targ->nmd->first_tx_ring); 212237e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 212337e3a6d3SLuigi Rizzo usleep(1); /* wait 1 tick */ 212437e3a6d3SLuigi Rizzo } 212537e3a6d3SLuigi Rizzo 212637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 212737e3a6d3SLuigi Rizzo targ->completed = 1; 212837e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 212937e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 213037e3a6d3SLuigi Rizzo targ->ctr.events = event; 213137e3a6d3SLuigi Rizzo quit: 213237e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 213337e3a6d3SLuigi Rizzo targ->used = 0; 213437e3a6d3SLuigi Rizzo 213537e3a6d3SLuigi Rizzo return (NULL); 213637e3a6d3SLuigi Rizzo } 213737e3a6d3SLuigi Rizzo 213837e3a6d3SLuigi Rizzo 213937e3a6d3SLuigi Rizzo static char * 214037e3a6d3SLuigi Rizzo multi_slot_to_string(struct netmap_ring *ring, unsigned int head, 214137e3a6d3SLuigi Rizzo unsigned int nfrags, char *strbuf, size_t strbuflen) 214237e3a6d3SLuigi Rizzo { 214337e3a6d3SLuigi Rizzo unsigned int f; 214437e3a6d3SLuigi Rizzo char *ret = strbuf; 214537e3a6d3SLuigi Rizzo 214637e3a6d3SLuigi Rizzo for (f = 0; f < nfrags; f++) { 214737e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 214837e3a6d3SLuigi Rizzo int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, 214937e3a6d3SLuigi Rizzo slot->flags); 215037e3a6d3SLuigi Rizzo if (m >= (int)strbuflen) { 215137e3a6d3SLuigi Rizzo break; 215237e3a6d3SLuigi Rizzo } 215337e3a6d3SLuigi Rizzo strbuf += m; 215437e3a6d3SLuigi Rizzo strbuflen -= m; 215537e3a6d3SLuigi Rizzo 215637e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 215737e3a6d3SLuigi Rizzo } 215837e3a6d3SLuigi Rizzo 215937e3a6d3SLuigi Rizzo return ret; 216037e3a6d3SLuigi Rizzo } 216137e3a6d3SLuigi Rizzo 216237e3a6d3SLuigi Rizzo static void * 216337e3a6d3SLuigi Rizzo rxseq_body(void *data) 216437e3a6d3SLuigi Rizzo { 216537e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 216637e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 216737e3a6d3SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 216837e3a6d3SLuigi Rizzo struct netmap_ring *ring; 216937e3a6d3SLuigi Rizzo unsigned int frags_exp = 1; 217037e3a6d3SLuigi Rizzo struct my_ctrs cur; 217137e3a6d3SLuigi Rizzo unsigned int frags = 0; 217237e3a6d3SLuigi Rizzo int first_packet = 1; 217337e3a6d3SLuigi Rizzo int first_slot = 1; 217480ad548dSVincenzo Maffione int i, j, af, nrings; 217580ad548dSVincenzo Maffione uint32_t seq, *seq_exp = NULL; 217637e3a6d3SLuigi Rizzo 217780ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 217837e3a6d3SLuigi Rizzo 217937e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 218037e3a6d3SLuigi Rizzo goto quit; 218137e3a6d3SLuigi Rizzo 218280ad548dSVincenzo Maffione nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1; 218380ad548dSVincenzo Maffione seq_exp = calloc(nrings, sizeof(uint32_t)); 218480ad548dSVincenzo Maffione if (seq_exp == NULL) { 218580ad548dSVincenzo Maffione D("failed to allocate seq array"); 218680ad548dSVincenzo Maffione goto quit; 218780ad548dSVincenzo Maffione } 218880ad548dSVincenzo Maffione 218937e3a6d3SLuigi Rizzo D("reading from %s fd %d main_fd %d", 219037e3a6d3SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 219137e3a6d3SLuigi Rizzo /* unbounded wait for the first packet. */ 219237e3a6d3SLuigi Rizzo for (;!targ->cancel;) { 219337e3a6d3SLuigi Rizzo i = poll(&pfd, 1, 1000); 219437e3a6d3SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 219537e3a6d3SLuigi Rizzo break; 219637e3a6d3SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 219737e3a6d3SLuigi Rizzo i, pfd.revents); 219837e3a6d3SLuigi Rizzo } 219937e3a6d3SLuigi Rizzo 220037e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 220137e3a6d3SLuigi Rizzo 220237e3a6d3SLuigi Rizzo 220337e3a6d3SLuigi Rizzo while (!targ->cancel) { 220437e3a6d3SLuigi Rizzo unsigned int head; 220537e3a6d3SLuigi Rizzo int limit; 220637e3a6d3SLuigi Rizzo 220780ad548dSVincenzo Maffione #ifdef BUSYWAIT 220880ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 220980ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 221080ad548dSVincenzo Maffione strerror(errno)); 221180ad548dSVincenzo Maffione goto quit; 221280ad548dSVincenzo Maffione } 221380ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 2214f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 22151cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 22168ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 2217f0ea3689SLuigi Rizzo goto out; 221868b8534bSLuigi Rizzo } 221968b8534bSLuigi Rizzo 2220f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 222117885a7bSLuigi Rizzo D("poll err"); 222217885a7bSLuigi Rizzo goto quit; 222317885a7bSLuigi Rizzo } 222480ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 222517885a7bSLuigi Rizzo 222680ad548dSVincenzo Maffione for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) { 222780ad548dSVincenzo Maffione ring = NETMAP_RXRING(targ->nmd->nifp, j); 222837e3a6d3SLuigi Rizzo if (nm_ring_empty(ring)) 222968b8534bSLuigi Rizzo continue; 223068b8534bSLuigi Rizzo 223137e3a6d3SLuigi Rizzo limit = nm_ring_space(ring); 223237e3a6d3SLuigi Rizzo if (limit > targ->g->burst) 223337e3a6d3SLuigi Rizzo limit = targ->g->burst; 223437e3a6d3SLuigi Rizzo 223537e3a6d3SLuigi Rizzo #if 0 223637e3a6d3SLuigi Rizzo /* Enable this if 223737e3a6d3SLuigi Rizzo * 1) we remove the early-return optimization from 223837e3a6d3SLuigi Rizzo * the netmap poll implementation, or 223937e3a6d3SLuigi Rizzo * 2) pipes get NS_MOREFRAG support. 224037e3a6d3SLuigi Rizzo * With the current netmap implementation, an experiment like 224137e3a6d3SLuigi Rizzo * pkt-gen -i vale:1{1 -f txseq -F 9 224237e3a6d3SLuigi Rizzo * pkt-gen -i vale:1}1 -f rxseq 224337e3a6d3SLuigi Rizzo * would get stuck as soon as we find nm_ring_space(ring) < 9, 224437e3a6d3SLuigi Rizzo * since here limit is rounded to 0 and 224537e3a6d3SLuigi Rizzo * pipe rxsync is not called anymore by the poll() of this loop. 224637e3a6d3SLuigi Rizzo */ 224737e3a6d3SLuigi Rizzo if (frags_exp > 1) { 224837e3a6d3SLuigi Rizzo int o = limit; 224937e3a6d3SLuigi Rizzo /* Cut off to the closest smaller multiple. */ 225037e3a6d3SLuigi Rizzo limit = (limit / frags_exp) * frags_exp; 225137e3a6d3SLuigi Rizzo RD(2, "LIMIT %d --> %d", o, limit); 225268b8534bSLuigi Rizzo } 225337e3a6d3SLuigi Rizzo #endif 225437e3a6d3SLuigi Rizzo 225537e3a6d3SLuigi Rizzo for (head = ring->head, i = 0; i < limit; i++) { 225637e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 225737e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 225837e3a6d3SLuigi Rizzo int len = slot->len; 225937e3a6d3SLuigi Rizzo struct pkt *pkt; 226037e3a6d3SLuigi Rizzo 226137e3a6d3SLuigi Rizzo if (dump) { 226237e3a6d3SLuigi Rizzo dump_payload(p, slot->len, ring, head); 226368b8534bSLuigi Rizzo } 226437e3a6d3SLuigi Rizzo 226537e3a6d3SLuigi Rizzo frags++; 226637e3a6d3SLuigi Rizzo if (!(slot->flags & NS_MOREFRAG)) { 226737e3a6d3SLuigi Rizzo if (first_packet) { 226837e3a6d3SLuigi Rizzo first_packet = 0; 226937e3a6d3SLuigi Rizzo } else if (frags != frags_exp) { 227037e3a6d3SLuigi Rizzo char prbuf[512]; 227137e3a6d3SLuigi Rizzo RD(1, "Received packets with %u frags, " 227237e3a6d3SLuigi Rizzo "expected %u, '%s'", frags, frags_exp, 227380ad548dSVincenzo Maffione multi_slot_to_string(ring, head-frags+1, 227480ad548dSVincenzo Maffione frags, 227537e3a6d3SLuigi Rizzo prbuf, sizeof(prbuf))); 227637e3a6d3SLuigi Rizzo } 227737e3a6d3SLuigi Rizzo first_packet = 0; 227837e3a6d3SLuigi Rizzo frags_exp = frags; 227937e3a6d3SLuigi Rizzo frags = 0; 228037e3a6d3SLuigi Rizzo } 228137e3a6d3SLuigi Rizzo 228237e3a6d3SLuigi Rizzo p -= sizeof(pkt->vh) - targ->g->virt_header; 228337e3a6d3SLuigi Rizzo len += sizeof(pkt->vh) - targ->g->virt_header; 228437e3a6d3SLuigi Rizzo pkt = (struct pkt *)p; 228580ad548dSVincenzo Maffione if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP) 228680ad548dSVincenzo Maffione af = AF_INET; 228780ad548dSVincenzo Maffione else 228880ad548dSVincenzo Maffione af = AF_INET6; 228937e3a6d3SLuigi Rizzo 229080ad548dSVincenzo Maffione if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) + 229180ad548dSVincenzo Maffione sizeof(seq)) { 229237e3a6d3SLuigi Rizzo RD(1, "%s: packet too small (len=%u)", __func__, 229337e3a6d3SLuigi Rizzo slot->len); 229437e3a6d3SLuigi Rizzo } else { 229580ad548dSVincenzo Maffione seq = (PKT(pkt, body, af)[0] << 24) | 229680ad548dSVincenzo Maffione (PKT(pkt, body, af)[1] << 16) | 229780ad548dSVincenzo Maffione (PKT(pkt, body, af)[2] << 8) | 229880ad548dSVincenzo Maffione PKT(pkt, body, af)[3]; 229937e3a6d3SLuigi Rizzo if (first_slot) { 230037e3a6d3SLuigi Rizzo /* Grab the first one, whatever it 230137e3a6d3SLuigi Rizzo is. */ 230280ad548dSVincenzo Maffione seq_exp[j] = seq; 230337e3a6d3SLuigi Rizzo first_slot = 0; 230480ad548dSVincenzo Maffione } else if (seq != seq_exp[j]) { 230580ad548dSVincenzo Maffione uint32_t delta = seq - seq_exp[j]; 230637e3a6d3SLuigi Rizzo 230737e3a6d3SLuigi Rizzo if (delta < (0xFFFFFFFF >> 1)) { 230837e3a6d3SLuigi Rizzo RD(2, "Sequence GAP: exp %u found %u", 230980ad548dSVincenzo Maffione seq_exp[j], seq); 231037e3a6d3SLuigi Rizzo } else { 231137e3a6d3SLuigi Rizzo RD(2, "Sequence OUT OF ORDER: " 231280ad548dSVincenzo Maffione "exp %u found %u", seq_exp[j], seq); 231337e3a6d3SLuigi Rizzo } 231480ad548dSVincenzo Maffione seq_exp[j] = seq; 231537e3a6d3SLuigi Rizzo } 231680ad548dSVincenzo Maffione seq_exp[j]++; 231737e3a6d3SLuigi Rizzo } 231837e3a6d3SLuigi Rizzo 231937e3a6d3SLuigi Rizzo cur.bytes += slot->len; 232037e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 232137e3a6d3SLuigi Rizzo cur.pkts++; 232237e3a6d3SLuigi Rizzo } 232337e3a6d3SLuigi Rizzo 232437e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 232537e3a6d3SLuigi Rizzo 232637e3a6d3SLuigi Rizzo cur.events++; 232737e3a6d3SLuigi Rizzo targ->ctr = cur; 232868b8534bSLuigi Rizzo } 232980ad548dSVincenzo Maffione } 2330f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 2331f0ea3689SLuigi Rizzo 233280ad548dSVincenzo Maffione #ifndef BUSYWAIT 2333f0ea3689SLuigi Rizzo out: 233480ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 233568b8534bSLuigi Rizzo targ->completed = 1; 233637e3a6d3SLuigi Rizzo targ->ctr = cur; 233768b8534bSLuigi Rizzo 233868b8534bSLuigi Rizzo quit: 233980ad548dSVincenzo Maffione if (seq_exp != NULL) 234080ad548dSVincenzo Maffione free(seq_exp); 234168b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 234268b8534bSLuigi Rizzo targ->used = 0; 234368b8534bSLuigi Rizzo 234468b8534bSLuigi Rizzo return (NULL); 234568b8534bSLuigi Rizzo } 234668b8534bSLuigi Rizzo 234766a698c9SEd Maste 234868b8534bSLuigi Rizzo static void 234980ad548dSVincenzo Maffione tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg) 235068b8534bSLuigi Rizzo { 235137e3a6d3SLuigi Rizzo double bw, raw_bw, pps, abs; 2352f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 235337e3a6d3SLuigi Rizzo int size; 235468b8534bSLuigi Rizzo 235537e3a6d3SLuigi Rizzo if (cur->pkts == 0) { 235637e3a6d3SLuigi Rizzo printf("%s nothing.\n", msg); 235737e3a6d3SLuigi Rizzo return; 235837e3a6d3SLuigi Rizzo } 235937e3a6d3SLuigi Rizzo 236037e3a6d3SLuigi Rizzo size = (int)(cur->bytes / cur->pkts); 236137e3a6d3SLuigi Rizzo 236237e3a6d3SLuigi Rizzo printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", 236337e3a6d3SLuigi Rizzo msg, 236437e3a6d3SLuigi Rizzo (unsigned long long)cur->pkts, 236537e3a6d3SLuigi Rizzo (unsigned long long)cur->bytes, 236637e3a6d3SLuigi Rizzo (unsigned long long)cur->events, size, delta); 2367f8e4e36aSLuigi Rizzo if (delta == 0) 2368f8e4e36aSLuigi Rizzo delta = 1e-6; 2369f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 2370f8e4e36aSLuigi Rizzo size = 60; 237137e3a6d3SLuigi Rizzo pps = cur->pkts / delta; 237237e3a6d3SLuigi Rizzo bw = (8.0 * cur->bytes) / delta; 237380ad548dSVincenzo Maffione raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta; 237437e3a6d3SLuigi Rizzo abs = cur->pkts / (double)(cur->events); 237566a698c9SEd Maste 237637e3a6d3SLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", 237780ad548dSVincenzo Maffione norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); 237868b8534bSLuigi Rizzo } 237968b8534bSLuigi Rizzo 238068b8534bSLuigi Rizzo static void 238180ad548dSVincenzo Maffione usage(int errcode) 238268b8534bSLuigi Rizzo { 238380ad548dSVincenzo Maffione /* This usage is generated from the pkt-gen man page: 238480ad548dSVincenzo Maffione * $ man pkt-gen > x 238580ad548dSVincenzo Maffione * and pasted here adding the string terminators and endlines with simple 238680ad548dSVincenzo Maffione * regular expressions. */ 238768b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 238868b8534bSLuigi Rizzo fprintf(stderr, 238968b8534bSLuigi Rizzo "Usage:\n" 239068b8534bSLuigi Rizzo "%s arguments\n" 239180ad548dSVincenzo Maffione " -h Show program usage and exit.\n" 239280ad548dSVincenzo Maffione "\n" 239380ad548dSVincenzo Maffione " -i interface\n" 239480ad548dSVincenzo Maffione " Name of the network interface that pkt-gen operates on. It can be a system network interface\n" 239580ad548dSVincenzo Maffione " (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n" 239680ad548dSVincenzo Maffione " monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n" 239780ad548dSVincenzo Maffione " mented in netmap(4) (NIOCREGIF section).\n" 239880ad548dSVincenzo Maffione "\n" 239980ad548dSVincenzo Maffione " -f function\n" 240080ad548dSVincenzo Maffione " The function to be executed by pkt-gen. Specify tx for transmission, rx for reception, ping\n" 240180ad548dSVincenzo Maffione " for client-side ping-pong operation, and pong for server-side ping-pong operation.\n" 240280ad548dSVincenzo Maffione "\n" 240380ad548dSVincenzo Maffione " -n count\n" 2404ed188a7eSVincenzo Maffione " Number of iterations of the pkt-gen function (with 0 meaning infinite). In case of tx or rx,\n" 240580ad548dSVincenzo Maffione " count is the number of packets to receive or transmit. In case of ping or pong, count is the\n" 240680ad548dSVincenzo Maffione " number of ping-pong transactions.\n" 240780ad548dSVincenzo Maffione "\n" 240880ad548dSVincenzo Maffione " -l pkt_size\n" 240980ad548dSVincenzo Maffione " Packet size in bytes excluding CRC. If passed a second time, use random sizes larger or\n" 241080ad548dSVincenzo Maffione " equal than the second one and lower than the first one.\n" 241180ad548dSVincenzo Maffione "\n" 241280ad548dSVincenzo Maffione " -b burst_size\n" 241380ad548dSVincenzo Maffione " Transmit or receive up to burst_size packets at a time.\n" 241480ad548dSVincenzo Maffione "\n" 241580ad548dSVincenzo Maffione " -4 Use IPv4 addresses.\n" 241680ad548dSVincenzo Maffione "\n" 241780ad548dSVincenzo Maffione " -6 Use IPv6 addresses.\n" 241880ad548dSVincenzo Maffione "\n" 241980ad548dSVincenzo Maffione " -d dst_ip[:port[-dst_ip:port]]\n" 242080ad548dSVincenzo Maffione " Destination IPv4/IPv6 address and port, single or range.\n" 242180ad548dSVincenzo Maffione "\n" 242280ad548dSVincenzo Maffione " -s src_ip[:port[-src_ip:port]]\n" 242380ad548dSVincenzo Maffione " Source IPv4/IPv6 address and port, single or range.\n" 242480ad548dSVincenzo Maffione "\n" 242580ad548dSVincenzo Maffione " -D dst_mac\n" 242680ad548dSVincenzo Maffione " Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n" 242780ad548dSVincenzo Maffione "\n" 242880ad548dSVincenzo Maffione " -S src_mac\n" 242980ad548dSVincenzo Maffione " Source MAC address in colon notation.\n" 243080ad548dSVincenzo Maffione "\n" 243180ad548dSVincenzo Maffione " -a cpu_id\n" 243280ad548dSVincenzo Maffione " Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3). If more\n" 243380ad548dSVincenzo Maffione " threads are used, they are pinned to the subsequent CPUs, one per thread.\n" 243480ad548dSVincenzo Maffione "\n" 243580ad548dSVincenzo Maffione " -c cpus\n" 243680ad548dSVincenzo Maffione " Maximum number of CPUs to use (0 means to use all the available ones).\n" 243780ad548dSVincenzo Maffione "\n" 243880ad548dSVincenzo Maffione " -p threads\n" 243980ad548dSVincenzo Maffione " Number of threads to use. By default, only a single thread is used to handle all the netmap\n" 244080ad548dSVincenzo Maffione " rings. If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n" 2441ed188a7eSVincenzo Maffione " single RX ring (in rx mode), or a TX/RX ring pair. The number of threads must be less than or\n" 2442ed188a7eSVincenzo Maffione " equal to the number of TX (or RX) rings available in the device specified by interface.\n" 244380ad548dSVincenzo Maffione "\n" 244480ad548dSVincenzo Maffione " -T report_ms\n" 244580ad548dSVincenzo Maffione " Number of milliseconds between reports.\n" 244680ad548dSVincenzo Maffione "\n" 244780ad548dSVincenzo Maffione " -w wait_for_link_time\n" 2448ed188a7eSVincenzo Maffione " Number of seconds to wait before starting the pkt-gen function, useful to make sure that the\n" 244980ad548dSVincenzo Maffione " network link is up. A network device driver may take some time to enter netmap mode, or to\n" 245080ad548dSVincenzo Maffione " create a new transmit/receive ring pair when netmap(4) requests one.\n" 245180ad548dSVincenzo Maffione "\n" 245280ad548dSVincenzo Maffione " -R rate\n" 245380ad548dSVincenzo Maffione " Packet transmission rate. Not setting the packet transmission rate tells pkt-gen to transmit\n" 2454ed188a7eSVincenzo Maffione " packets as quickly as possible. On servers from 2010 onward netmap(4) is able to com-\n" 245580ad548dSVincenzo Maffione " pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n" 245680ad548dSVincenzo Maffione " your intention is to saturate the link.\n" 245780ad548dSVincenzo Maffione "\n" 245880ad548dSVincenzo Maffione " -X Dump payload of each packet transmitted or received.\n" 245980ad548dSVincenzo Maffione "\n" 246080ad548dSVincenzo Maffione " -H len Add empty virtio-net-header with size 'len'. Valid sizes are 0, 10 and 12. This option is\n" 246180ad548dSVincenzo Maffione " only used with Virtual Machine technologies that use virtio as a network interface.\n" 246280ad548dSVincenzo Maffione "\n" 246380ad548dSVincenzo Maffione " -P file\n" 246480ad548dSVincenzo Maffione " Load the packet to be transmitted from a pcap file rather than constructing it within\n" 246580ad548dSVincenzo Maffione " pkt-gen.\n" 246680ad548dSVincenzo Maffione "\n" 246780ad548dSVincenzo Maffione " -z Use random IPv4/IPv6 src address/port.\n" 246880ad548dSVincenzo Maffione "\n" 246980ad548dSVincenzo Maffione " -Z Use random IPv4/IPv6 dst address/port.\n" 247080ad548dSVincenzo Maffione "\n" 247180ad548dSVincenzo Maffione " -N Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n" 247280ad548dSVincenzo Maffione "\n" 247380ad548dSVincenzo Maffione " -F num_frags\n" 247480ad548dSVincenzo Maffione " Send multi-slot packets, each one with num_frags fragments. A multi-slot packet is repre-\n" 247580ad548dSVincenzo Maffione " sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n" 247680ad548dSVincenzo Maffione " last slot). This is useful to transmit or receive packets larger than the netmap buffer\n" 247780ad548dSVincenzo Maffione " size.\n" 247880ad548dSVincenzo Maffione "\n" 247980ad548dSVincenzo Maffione " -M frag_size\n" 248080ad548dSVincenzo Maffione " In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n" 248180ad548dSVincenzo Maffione " length divided by num_frags.\n" 248280ad548dSVincenzo Maffione "\n" 248380ad548dSVincenzo Maffione " -I Use indirect buffers. It is only valid for transmitting on VALE ports, and it is implemented\n" 248480ad548dSVincenzo Maffione " by setting the NS_INDIRECT flag in the netmap slots.\n" 248580ad548dSVincenzo Maffione "\n" 248680ad548dSVincenzo Maffione " -W Exit immediately if all the RX rings are empty the first time they are examined.\n" 248780ad548dSVincenzo Maffione "\n" 248880ad548dSVincenzo Maffione " -v Increase the verbosity level.\n" 248980ad548dSVincenzo Maffione "\n" 249080ad548dSVincenzo Maffione " -r In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n" 249180ad548dSVincenzo Maffione " netmap buffers is (rubbish mode).\n" 249280ad548dSVincenzo Maffione "\n" 249380ad548dSVincenzo Maffione " -A Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n" 249480ad548dSVincenzo Maffione "\n" 249580ad548dSVincenzo Maffione " -B Take Ethernet framing and CRC into account when computing the average bps. This adds 4 bytes\n" 249680ad548dSVincenzo Maffione " of CRC and 20 bytes of framing to each packet.\n" 249780ad548dSVincenzo Maffione "\n" 249880ad548dSVincenzo Maffione " -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n" 249980ad548dSVincenzo Maffione " Configuration in terms of number of rings and slots to be used when opening the netmap port.\n" 2500ed188a7eSVincenzo Maffione " Such configuration has an effect on software ports created on the fly, such as VALE ports and\n" 250180ad548dSVincenzo Maffione " netmap pipes. The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n" 250280ad548dSVincenzo Maffione " rx_slots, tx_rings, rx_rings. Missing numbers or zeroes stand for default values. As an\n" 250380ad548dSVincenzo Maffione " additional convenience, if exactly one number is specified, then this is assigned to both\n" 250480ad548dSVincenzo Maffione " tx_slots and rx_slots. If there is no fourth number, then the third one is assigned to both\n" 250580ad548dSVincenzo Maffione " tx_rings and rx_rings.\n" 250680ad548dSVincenzo Maffione "\n" 250780ad548dSVincenzo Maffione " -o options data generation options (parsed using atoi)\n" 250880ad548dSVincenzo Maffione " OPT_PREFETCH 1\n" 250980ad548dSVincenzo Maffione " OPT_ACCESS 2\n" 251080ad548dSVincenzo Maffione " OPT_COPY 4\n" 251180ad548dSVincenzo Maffione " OPT_MEMCPY 8\n" 251280ad548dSVincenzo Maffione " OPT_TS 16 (add a timestamp)\n" 251380ad548dSVincenzo Maffione " OPT_INDIRECT 32 (use indirect buffers)\n" 251480ad548dSVincenzo Maffione " OPT_DUMP 64 (dump rx/tx traffic)\n" 251580ad548dSVincenzo Maffione " OPT_RUBBISH 256\n" 2516ed188a7eSVincenzo Maffione " (send whatever the buffers contain)\n" 251780ad548dSVincenzo Maffione " OPT_RANDOM_SRC 512\n" 251880ad548dSVincenzo Maffione " OPT_RANDOM_DST 1024\n" 251980ad548dSVincenzo Maffione " OPT_PPS_STATS 2048\n" 252068b8534bSLuigi Rizzo "", 252168b8534bSLuigi Rizzo cmd); 252280ad548dSVincenzo Maffione exit(errcode); 252368b8534bSLuigi Rizzo } 252468b8534bSLuigi Rizzo 25254bfe1a4fSVincenzo Maffione static int 252680ad548dSVincenzo Maffione start_threads(struct glob_arg *g) { 2527f8e4e36aSLuigi Rizzo int i; 2528f8e4e36aSLuigi Rizzo 2529f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 253080ad548dSVincenzo Maffione struct targ *t; 2531f8e4e36aSLuigi Rizzo /* 2532f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 2533f8e4e36aSLuigi Rizzo * using a single descriptor. 2534f8e4e36aSLuigi Rizzo */ 2535f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 253627bf5dd3SVincenzo Maffione uint64_t seed = (uint64_t)time(0) | ((uint64_t)time(0) << 32); 253780ad548dSVincenzo Maffione t = &targs[i]; 2538f0ea3689SLuigi Rizzo 2539f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 2540f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 2541f0ea3689SLuigi Rizzo t->g = g; 254280ad548dSVincenzo Maffione memcpy(t->seed, &seed, sizeof(t->seed)); 2543f8e4e36aSLuigi Rizzo 2544f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 25454bfe1a4fSVincenzo Maffione int m = -1; 25464bfe1a4fSVincenzo Maffione 25474bfe1a4fSVincenzo Maffione /* 25484bfe1a4fSVincenzo Maffione * if the user wants both HW and SW rings, we need to 25494bfe1a4fSVincenzo Maffione * know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW 25504bfe1a4fSVincenzo Maffione */ 25514bfe1a4fSVincenzo Maffione if (g->orig_mode == NR_REG_NIC_SW) { 25524bfe1a4fSVincenzo Maffione m = (g->td_type == TD_TYPE_RECEIVER ? 25534bfe1a4fSVincenzo Maffione g->nmd->reg.nr_rx_rings : 25544bfe1a4fSVincenzo Maffione g->nmd->reg.nr_tx_rings); 25554bfe1a4fSVincenzo Maffione } 2556f8e4e36aSLuigi Rizzo 255737e3a6d3SLuigi Rizzo if (i > 0) { 25584bfe1a4fSVincenzo Maffione int j; 255937e3a6d3SLuigi Rizzo /* the first thread uses the fd opened by the main 256037e3a6d3SLuigi Rizzo * thread, the other threads re-open /dev/netmap 256137e3a6d3SLuigi Rizzo */ 25624bfe1a4fSVincenzo Maffione t->nmd = nmport_clone(g->nmd); 25634bfe1a4fSVincenzo Maffione if (t->nmd == NULL) 25644bfe1a4fSVincenzo Maffione return -1; 25654bfe1a4fSVincenzo Maffione 25664bfe1a4fSVincenzo Maffione j = i; 25674bfe1a4fSVincenzo Maffione if (m > 0 && j >= m) { 25684bfe1a4fSVincenzo Maffione /* switch to the software rings */ 25694bfe1a4fSVincenzo Maffione t->nmd->reg.nr_mode = NR_REG_ONE_SW; 25704bfe1a4fSVincenzo Maffione j -= m; 257117885a7bSLuigi Rizzo } 25724bfe1a4fSVincenzo Maffione t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK; 2573f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 257437e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_RECEIVER) 25754bfe1a4fSVincenzo Maffione t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL; 2576f8e4e36aSLuigi Rizzo 2577f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 25784bfe1a4fSVincenzo Maffione if (nmport_open_desc(t->nmd) < 0) { 25794bfe1a4fSVincenzo Maffione nmport_undo_prepare(t->nmd); 25804bfe1a4fSVincenzo Maffione t->nmd = NULL; 25814bfe1a4fSVincenzo Maffione return -1; 2582f8e4e36aSLuigi Rizzo } 258337e3a6d3SLuigi Rizzo } else { 258437e3a6d3SLuigi Rizzo t->nmd = g->nmd; 258537e3a6d3SLuigi Rizzo } 2586f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 258780ad548dSVincenzo Maffione t->frags = g->frags; 2588f8e4e36aSLuigi Rizzo } else { 2589f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 2590f8e4e36aSLuigi Rizzo } 2591f0ea3689SLuigi Rizzo t->used = 1; 2592f0ea3689SLuigi Rizzo t->me = i; 2593f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 259480ad548dSVincenzo Maffione t->affinity = (g->affinity + i) % g->cpus; 2595f0ea3689SLuigi Rizzo } else { 2596f0ea3689SLuigi Rizzo t->affinity = -1; 2597f0ea3689SLuigi Rizzo } 2598f8e4e36aSLuigi Rizzo /* default, init packets */ 2599f0ea3689SLuigi Rizzo initialize_packet(t); 260080ad548dSVincenzo Maffione } 260180ad548dSVincenzo Maffione /* Wait for PHY reset. */ 260280ad548dSVincenzo Maffione D("Wait %d secs for phy reset", g->wait_link); 260380ad548dSVincenzo Maffione sleep(g->wait_link); 260480ad548dSVincenzo Maffione D("Ready..."); 2605f8e4e36aSLuigi Rizzo 260680ad548dSVincenzo Maffione for (i = 0; i < g->nthreads; i++) { 260780ad548dSVincenzo Maffione t = &targs[i]; 2608f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 260917885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 2610f0ea3689SLuigi Rizzo t->used = 0; 2611f8e4e36aSLuigi Rizzo } 2612f8e4e36aSLuigi Rizzo } 26134bfe1a4fSVincenzo Maffione return 0; 2614f8e4e36aSLuigi Rizzo } 2615f8e4e36aSLuigi Rizzo 2616f8e4e36aSLuigi Rizzo static void 2617f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 2618f8e4e36aSLuigi Rizzo { 2619f8e4e36aSLuigi Rizzo int i; 2620f8e4e36aSLuigi Rizzo 262137e3a6d3SLuigi Rizzo struct my_ctrs prev, cur; 2622f8e4e36aSLuigi Rizzo double delta_t; 2623f8e4e36aSLuigi Rizzo struct timeval tic, toc; 2624f8e4e36aSLuigi Rizzo 262537e3a6d3SLuigi Rizzo prev.pkts = prev.bytes = prev.events = 0; 262637e3a6d3SLuigi Rizzo gettimeofday(&prev.t, NULL); 2627f8e4e36aSLuigi Rizzo for (;;) { 262880ad548dSVincenzo Maffione char b1[40], b2[40], b3[40], b4[100]; 262937e3a6d3SLuigi Rizzo uint64_t pps, usec; 263037e3a6d3SLuigi Rizzo struct my_ctrs x; 263137e3a6d3SLuigi Rizzo double abs; 2632f8e4e36aSLuigi Rizzo int done = 0; 2633f8e4e36aSLuigi Rizzo 263437e3a6d3SLuigi Rizzo usec = wait_for_next_report(&prev.t, &cur.t, 263537e3a6d3SLuigi Rizzo g->report_interval); 263637e3a6d3SLuigi Rizzo 263737e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 263837e3a6d3SLuigi Rizzo cur.min_space = 0; 263937e3a6d3SLuigi Rizzo if (usec < 10000) /* too short to be meaningful */ 264037e3a6d3SLuigi Rizzo continue; 264137e3a6d3SLuigi Rizzo /* accumulate counts for all threads */ 2642f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 264337e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 264437e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 264537e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 264637e3a6d3SLuigi Rizzo cur.min_space += targs[i].ctr.min_space; 264737e3a6d3SLuigi Rizzo targs[i].ctr.min_space = 99999; 2648f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 2649f8e4e36aSLuigi Rizzo done++; 2650f8e4e36aSLuigi Rizzo } 265137e3a6d3SLuigi Rizzo x.pkts = cur.pkts - prev.pkts; 265237e3a6d3SLuigi Rizzo x.bytes = cur.bytes - prev.bytes; 265337e3a6d3SLuigi Rizzo x.events = cur.events - prev.events; 265437e3a6d3SLuigi Rizzo pps = (x.pkts*1000000 + usec/2) / usec; 265537e3a6d3SLuigi Rizzo abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; 265637e3a6d3SLuigi Rizzo 265737e3a6d3SLuigi Rizzo if (!(g->options & OPT_PPS_STATS)) { 265837e3a6d3SLuigi Rizzo strcpy(b4, ""); 265937e3a6d3SLuigi Rizzo } else { 266037e3a6d3SLuigi Rizzo /* Compute some pps stats using a sliding window. */ 266137e3a6d3SLuigi Rizzo double ppsavg = 0.0, ppsdev = 0.0; 266237e3a6d3SLuigi Rizzo int nsamples = 0; 266337e3a6d3SLuigi Rizzo 266437e3a6d3SLuigi Rizzo g->win[g->win_idx] = pps; 266537e3a6d3SLuigi Rizzo g->win_idx = (g->win_idx + 1) % STATS_WIN; 266637e3a6d3SLuigi Rizzo 266737e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 266837e3a6d3SLuigi Rizzo ppsavg += g->win[i]; 266937e3a6d3SLuigi Rizzo if (g->win[i]) { 267037e3a6d3SLuigi Rizzo nsamples ++; 267137e3a6d3SLuigi Rizzo } 267237e3a6d3SLuigi Rizzo } 267337e3a6d3SLuigi Rizzo ppsavg /= nsamples; 267437e3a6d3SLuigi Rizzo 267537e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 267637e3a6d3SLuigi Rizzo if (g->win[i] == 0) { 2677f8e4e36aSLuigi Rizzo continue; 267837e3a6d3SLuigi Rizzo } 267937e3a6d3SLuigi Rizzo ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); 268037e3a6d3SLuigi Rizzo } 268137e3a6d3SLuigi Rizzo ppsdev /= nsamples; 268237e3a6d3SLuigi Rizzo ppsdev = sqrt(ppsdev); 268337e3a6d3SLuigi Rizzo 268437e3a6d3SLuigi Rizzo snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", 268580ad548dSVincenzo Maffione norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); 268637e3a6d3SLuigi Rizzo } 268737e3a6d3SLuigi Rizzo 268837e3a6d3SLuigi Rizzo D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", 268980ad548dSVincenzo Maffione norm(b1, pps, normalize), b4, 269080ad548dSVincenzo Maffione norm(b2, (double)x.pkts, normalize), 2691760fa2abSVincenzo Maffione norm(b3, 1000000*((double)x.bytes*8+(double)x.pkts*g->framing)/usec, normalize), 269237e3a6d3SLuigi Rizzo (unsigned long long)usec, 269337e3a6d3SLuigi Rizzo abs, (int)cur.min_space); 269437e3a6d3SLuigi Rizzo prev = cur; 269537e3a6d3SLuigi Rizzo 2696f8e4e36aSLuigi Rizzo if (done == g->nthreads) 2697f8e4e36aSLuigi Rizzo break; 2698f8e4e36aSLuigi Rizzo } 2699f8e4e36aSLuigi Rizzo 2700f8e4e36aSLuigi Rizzo timerclear(&tic); 2701f8e4e36aSLuigi Rizzo timerclear(&toc); 270237e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 270337e3a6d3SLuigi Rizzo /* final round */ 2704f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 27051cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 2706f8e4e36aSLuigi Rizzo /* 2707f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 2708f8e4e36aSLuigi Rizzo * file descriptors. 2709f8e4e36aSLuigi Rizzo */ 27101cb4c501SLuigi Rizzo if (targs[i].used) 271137e3a6d3SLuigi Rizzo pthread_join(targs[i].thread, NULL); /* blocking */ 271237e3a6d3SLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 27134bfe1a4fSVincenzo Maffione nmport_close(targs[i].nmd); 271437e3a6d3SLuigi Rizzo targs[i].nmd = NULL; 271537e3a6d3SLuigi Rizzo } else { 2716f8e4e36aSLuigi Rizzo close(targs[i].fd); 271737e3a6d3SLuigi Rizzo } 2718f8e4e36aSLuigi Rizzo 2719f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 2720f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 2721f8e4e36aSLuigi Rizzo 2722f8e4e36aSLuigi Rizzo /* 2723f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 2724f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 2725f8e4e36aSLuigi Rizzo */ 272637e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 272737e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 272837e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 272937e3a6d3SLuigi Rizzo /* collect the largest start (tic) and end (toc) times, 273037e3a6d3SLuigi Rizzo * XXX maybe we should do the earliest tic, or do a weighted 273137e3a6d3SLuigi Rizzo * average ? 273237e3a6d3SLuigi Rizzo */ 27331cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 27341cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 27351cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 27361cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 27371cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 27381cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 2739f8e4e36aSLuigi Rizzo } 2740f8e4e36aSLuigi Rizzo 2741f8e4e36aSLuigi Rizzo /* print output. */ 2742f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 2743f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 274437e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_SENDER) 274580ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Sent"); 274680ad548dSVincenzo Maffione else if (g->td_type == TD_TYPE_RECEIVER) 274780ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Received"); 2748f8e4e36aSLuigi Rizzo } 2749f8e4e36aSLuigi Rizzo 275037e3a6d3SLuigi Rizzo struct td_desc { 275137e3a6d3SLuigi Rizzo int ty; 27527eb32dc8SVincenzo Maffione const char *key; 2753f8e4e36aSLuigi Rizzo void *f; 275480ad548dSVincenzo Maffione int default_burst; 2755f8e4e36aSLuigi Rizzo }; 2756f8e4e36aSLuigi Rizzo 275737e3a6d3SLuigi Rizzo static struct td_desc func[] = { 275880ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ 275980ad548dSVincenzo Maffione { TD_TYPE_SENDER, "tx", sender_body, 512 }, 276080ad548dSVincenzo Maffione { TD_TYPE_OTHER, "ping", ping_body, 1 }, 276180ad548dSVincenzo Maffione { TD_TYPE_OTHER, "pong", pong_body, 1 }, 276280ad548dSVincenzo Maffione { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, 276380ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, 276480ad548dSVincenzo Maffione { 0, NULL, NULL, 0 } 2765f8e4e36aSLuigi Rizzo }; 2766f8e4e36aSLuigi Rizzo 2767f8e4e36aSLuigi Rizzo static int 2768f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 2769f8e4e36aSLuigi Rizzo { 2770f8e4e36aSLuigi Rizzo struct ifreq ifr; 2771f8e4e36aSLuigi Rizzo int fd, err; 27727eb32dc8SVincenzo Maffione const char *clonedev = TAP_CLONEDEV; 2773f8e4e36aSLuigi Rizzo 2774f8e4e36aSLuigi Rizzo (void)err; 2775f8e4e36aSLuigi Rizzo (void)dev; 2776f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 2777f8e4e36aSLuigi Rizzo * 2778f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 2779f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 2780f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 2781f8e4e36aSLuigi Rizzo */ 2782f8e4e36aSLuigi Rizzo 2783f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 2784f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 2785f8e4e36aSLuigi Rizzo static char buf[128]; 2786f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 2787f8e4e36aSLuigi Rizzo clonedev = buf; 2788f8e4e36aSLuigi Rizzo } 2789f8e4e36aSLuigi Rizzo #endif 2790f8e4e36aSLuigi Rizzo /* open the device */ 2791f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 2792f8e4e36aSLuigi Rizzo return fd; 2793f8e4e36aSLuigi Rizzo } 2794f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 2795f8e4e36aSLuigi Rizzo 2796f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 2797f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 2798f8e4e36aSLuigi Rizzo 2799f8e4e36aSLuigi Rizzo #ifdef linux 2800f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 2801f8e4e36aSLuigi Rizzo 2802f8e4e36aSLuigi Rizzo if (*dev) { 2803f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 2804f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 2805f8e4e36aSLuigi Rizzo * specified type */ 280680ad548dSVincenzo Maffione size_t len = strlen(dev); 280780ad548dSVincenzo Maffione if (len > IFNAMSIZ) { 280880ad548dSVincenzo Maffione D("%s too long", dev); 280980ad548dSVincenzo Maffione return -1; 281080ad548dSVincenzo Maffione } 281180ad548dSVincenzo Maffione memcpy(ifr.ifr_name, dev, len); 2812f8e4e36aSLuigi Rizzo } 2813f8e4e36aSLuigi Rizzo 2814f8e4e36aSLuigi Rizzo /* try to create the device */ 2815f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 281608cb3ac7SGordon Bergling D("failed to do a TUNSETIFF: %s", strerror(errno)); 2817f8e4e36aSLuigi Rizzo close(fd); 2818f8e4e36aSLuigi Rizzo return err; 2819f8e4e36aSLuigi Rizzo } 2820f8e4e36aSLuigi Rizzo 2821f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 2822f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 2823f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 2824f8e4e36aSLuigi Rizzo * code below) */ 2825f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 2826f8e4e36aSLuigi Rizzo D("new name is %s", dev); 2827f8e4e36aSLuigi Rizzo #endif /* linux */ 2828f8e4e36aSLuigi Rizzo 2829f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 2830f8e4e36aSLuigi Rizzo * with the virtual interface */ 2831f8e4e36aSLuigi Rizzo return fd; 2832f8e4e36aSLuigi Rizzo } 283368b8534bSLuigi Rizzo 283468b8534bSLuigi Rizzo int 283568b8534bSLuigi Rizzo main(int arc, char **argv) 283668b8534bSLuigi Rizzo { 2837f8e4e36aSLuigi Rizzo int i; 283837e3a6d3SLuigi Rizzo struct sigaction sa; 283937e3a6d3SLuigi Rizzo sigset_t ss; 284068b8534bSLuigi Rizzo 284168b8534bSLuigi Rizzo struct glob_arg g; 284268b8534bSLuigi Rizzo 284368b8534bSLuigi Rizzo int ch; 284468b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 284580ad548dSVincenzo Maffione int wait_link_arg = 0; 284680ad548dSVincenzo Maffione 284780ad548dSVincenzo Maffione int pkt_size_done = 0; 284880ad548dSVincenzo Maffione 284980ad548dSVincenzo Maffione struct td_desc *fn = func; 285068b8534bSLuigi Rizzo 285168b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 285268b8534bSLuigi Rizzo 2853f8e4e36aSLuigi Rizzo g.main_fd = -1; 285480ad548dSVincenzo Maffione g.td_body = fn->f; 285580ad548dSVincenzo Maffione g.td_type = fn->ty; 2856f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 2857f8e4e36aSLuigi Rizzo g.affinity = -1; 2858f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 285980ad548dSVincenzo Maffione g.af = AF_INET; /* default */ 2860f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 2861f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 2862f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 2863f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 286468b8534bSLuigi Rizzo g.pkt_size = 60; 286580ad548dSVincenzo Maffione g.pkt_min_size = 0; 286668b8534bSLuigi Rizzo g.nthreads = 1; 286780ad548dSVincenzo Maffione g.cpus = 1; /* default */ 2868b303f675SLuigi Rizzo g.forever = 1; 28691cb4c501SLuigi Rizzo g.tx_rate = 0; 2870ce3ee1e7SLuigi Rizzo g.frags = 1; 28719e53f3bdSVincenzo Maffione g.frag_size = (u_int)-1; /* use the netmap buffer size by default */ 2872ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 287317885a7bSLuigi Rizzo g.virt_header = 0; 287480ad548dSVincenzo Maffione g.wait_link = 2; /* wait 2 seconds for physical ports */ 287568b8534bSLuigi Rizzo 287680ad548dSVincenzo Maffione while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" 287780ad548dSVincenzo Maffione "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) { 2878f8e4e36aSLuigi Rizzo 287968b8534bSLuigi Rizzo switch(ch) { 288068b8534bSLuigi Rizzo default: 288168b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 288280ad548dSVincenzo Maffione usage(-1); 288380ad548dSVincenzo Maffione break; 288480ad548dSVincenzo Maffione 288580ad548dSVincenzo Maffione case 'h': 288680ad548dSVincenzo Maffione usage(0); 288780ad548dSVincenzo Maffione break; 288880ad548dSVincenzo Maffione 288980ad548dSVincenzo Maffione case '4': 289080ad548dSVincenzo Maffione g.af = AF_INET; 289180ad548dSVincenzo Maffione break; 289280ad548dSVincenzo Maffione 289380ad548dSVincenzo Maffione case '6': 289480ad548dSVincenzo Maffione g.af = AF_INET6; 289580ad548dSVincenzo Maffione break; 289680ad548dSVincenzo Maffione 289780ad548dSVincenzo Maffione case 'N': 289880ad548dSVincenzo Maffione normalize = 0; 289968b8534bSLuigi Rizzo break; 2900f8e4e36aSLuigi Rizzo 2901f8e4e36aSLuigi Rizzo case 'n': 290237e3a6d3SLuigi Rizzo g.npackets = strtoull(optarg, NULL, 10); 2903f8e4e36aSLuigi Rizzo break; 2904f8e4e36aSLuigi Rizzo 2905ce3ee1e7SLuigi Rizzo case 'F': 2906ce3ee1e7SLuigi Rizzo i = atoi(optarg); 2907ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 2908ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 2909ce3ee1e7SLuigi Rizzo break; 2910ce3ee1e7SLuigi Rizzo } 2911ce3ee1e7SLuigi Rizzo g.frags = i; 2912ce3ee1e7SLuigi Rizzo break; 2913ce3ee1e7SLuigi Rizzo 291480ad548dSVincenzo Maffione case 'M': 29159e53f3bdSVincenzo Maffione g.frag_size = atoi(optarg); 291680ad548dSVincenzo Maffione break; 291780ad548dSVincenzo Maffione 2918f8e4e36aSLuigi Rizzo case 'f': 2919f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 2920f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 2921f8e4e36aSLuigi Rizzo break; 2922f8e4e36aSLuigi Rizzo } 292337e3a6d3SLuigi Rizzo if (fn->key) { 2924f8e4e36aSLuigi Rizzo g.td_body = fn->f; 292537e3a6d3SLuigi Rizzo g.td_type = fn->ty; 292637e3a6d3SLuigi Rizzo } else { 2927f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 292837e3a6d3SLuigi Rizzo } 2929f8e4e36aSLuigi Rizzo break; 2930f8e4e36aSLuigi Rizzo 2931f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 293280ad548dSVincenzo Maffione g.options |= atoi(optarg); 293399fb123fSLuigi Rizzo break; 2934f8e4e36aSLuigi Rizzo 2935f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 2936f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 2937f8e4e36aSLuigi Rizzo break; 2938f8e4e36aSLuigi Rizzo 293968b8534bSLuigi Rizzo case 'i': /* interface */ 2940f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 2941f2637526SLuigi Rizzo * otherwise we guess 2942f2637526SLuigi Rizzo */ 2943f2637526SLuigi Rizzo D("interface is %s", optarg); 2944f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 2945f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 2946f0ea3689SLuigi Rizzo break; 2947f0ea3689SLuigi Rizzo } 2948f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 2949f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 2950f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 2951ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 2952f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 2953f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2954f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 2955f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 2956f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 2957f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 2958f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 2959f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 2960f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2961f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 2962f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2963f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 2964f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2965f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 2966f2637526SLuigi Rizzo } 296768b8534bSLuigi Rizzo break; 2968f8e4e36aSLuigi Rizzo 2969b303f675SLuigi Rizzo case 'I': 297080ad548dSVincenzo Maffione g.options |= OPT_INDIRECT; /* use indirect buffers */ 2971b303f675SLuigi Rizzo break; 2972b303f675SLuigi Rizzo 297368b8534bSLuigi Rizzo case 'l': /* pkt_size */ 297480ad548dSVincenzo Maffione if (pkt_size_done) { 297580ad548dSVincenzo Maffione g.pkt_min_size = atoi(optarg); 297680ad548dSVincenzo Maffione } else { 297768b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 297880ad548dSVincenzo Maffione pkt_size_done = 1; 297980ad548dSVincenzo Maffione } 298068b8534bSLuigi Rizzo break; 2981f8e4e36aSLuigi Rizzo 298268b8534bSLuigi Rizzo case 'd': 2983f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 298468b8534bSLuigi Rizzo break; 2985f8e4e36aSLuigi Rizzo 298668b8534bSLuigi Rizzo case 's': 2987f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 298868b8534bSLuigi Rizzo break; 2989f8e4e36aSLuigi Rizzo 299068b8534bSLuigi Rizzo case 'T': /* report interval */ 2991f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 299268b8534bSLuigi Rizzo break; 2993f8e4e36aSLuigi Rizzo 299468b8534bSLuigi Rizzo case 'w': 299580ad548dSVincenzo Maffione g.wait_link = atoi(optarg); 299680ad548dSVincenzo Maffione wait_link_arg = 1; 299768b8534bSLuigi Rizzo break; 2998f8e4e36aSLuigi Rizzo 299980ad548dSVincenzo Maffione case 'W': 300080ad548dSVincenzo Maffione g.forever = 0; /* exit RX with no traffic */ 3001f8e4e36aSLuigi Rizzo break; 3002f8e4e36aSLuigi Rizzo 300368b8534bSLuigi Rizzo case 'b': /* burst */ 300468b8534bSLuigi Rizzo g.burst = atoi(optarg); 300568b8534bSLuigi Rizzo break; 300668b8534bSLuigi Rizzo case 'c': 300768b8534bSLuigi Rizzo g.cpus = atoi(optarg); 300868b8534bSLuigi Rizzo break; 300968b8534bSLuigi Rizzo case 'p': 301068b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 301168b8534bSLuigi Rizzo break; 301268b8534bSLuigi Rizzo 301368b8534bSLuigi Rizzo case 'D': /* destination mac */ 3014f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 301568b8534bSLuigi Rizzo break; 3016f8e4e36aSLuigi Rizzo 301768b8534bSLuigi Rizzo case 'S': /* source mac */ 3018f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 301968b8534bSLuigi Rizzo break; 302068b8534bSLuigi Rizzo case 'v': 302168b8534bSLuigi Rizzo verbose++; 30221cb4c501SLuigi Rizzo break; 30231cb4c501SLuigi Rizzo case 'R': 30241cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 30251cb4c501SLuigi Rizzo break; 3026b303f675SLuigi Rizzo case 'X': 3027b303f675SLuigi Rizzo g.options |= OPT_DUMP; 3028ce3ee1e7SLuigi Rizzo break; 3029ce3ee1e7SLuigi Rizzo case 'C': 3030760fa2abSVincenzo Maffione D("WARNING: the 'C' option is deprecated, use the '+conf:' libnetmap option instead"); 3031ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 303217885a7bSLuigi Rizzo break; 303317885a7bSLuigi Rizzo case 'H': 303417885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 3035f2637526SLuigi Rizzo break; 3036f284c737SGeorge V. Neville-Neil case 'P': 3037f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 3038f284c737SGeorge V. Neville-Neil break; 303937e3a6d3SLuigi Rizzo case 'r': 304037e3a6d3SLuigi Rizzo g.options |= OPT_RUBBISH; 304137e3a6d3SLuigi Rizzo break; 304256717743SAdrian Chadd case 'z': 304356717743SAdrian Chadd g.options |= OPT_RANDOM_SRC; 304456717743SAdrian Chadd break; 304556717743SAdrian Chadd case 'Z': 304656717743SAdrian Chadd g.options |= OPT_RANDOM_DST; 304756717743SAdrian Chadd break; 304837e3a6d3SLuigi Rizzo case 'A': 304937e3a6d3SLuigi Rizzo g.options |= OPT_PPS_STATS; 305037e3a6d3SLuigi Rizzo break; 305180ad548dSVincenzo Maffione case 'B': 305280ad548dSVincenzo Maffione /* raw packets have4 bytes crc + 20 bytes framing */ 305380ad548dSVincenzo Maffione // XXX maybe add an option to pass the IFG 305480ad548dSVincenzo Maffione g.framing = 24 * 8; 305580ad548dSVincenzo Maffione break; 305668b8534bSLuigi Rizzo } 305768b8534bSLuigi Rizzo } 305868b8534bSLuigi Rizzo 3059db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 306068b8534bSLuigi Rizzo D("missing ifname"); 306180ad548dSVincenzo Maffione usage(-1); 306280ad548dSVincenzo Maffione } 306380ad548dSVincenzo Maffione 306480ad548dSVincenzo Maffione if (g.burst == 0) { 306580ad548dSVincenzo Maffione g.burst = fn->default_burst; 306680ad548dSVincenzo Maffione D("using default burst size: %d", g.burst); 306768b8534bSLuigi Rizzo } 3068f8e4e36aSLuigi Rizzo 306937e3a6d3SLuigi Rizzo g.system_cpus = i = system_ncpus(); 3070f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 3071f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 307280ad548dSVincenzo Maffione usage(-1); 307368b8534bSLuigi Rizzo } 307437e3a6d3SLuigi Rizzo D("running on %d cpus (have %d)", g.cpus, i); 307568b8534bSLuigi Rizzo if (g.cpus == 0) 3076f8e4e36aSLuigi Rizzo g.cpus = i; 3077f8e4e36aSLuigi Rizzo 307880ad548dSVincenzo Maffione if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) { 307980ad548dSVincenzo Maffione g.wait_link = 0; 308080ad548dSVincenzo Maffione } 308180ad548dSVincenzo Maffione 30824bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 30834bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 308480ad548dSVincenzo Maffione usage(-1); 308580ad548dSVincenzo Maffione } 308680ad548dSVincenzo Maffione 308780ad548dSVincenzo Maffione if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) { 308880ad548dSVincenzo Maffione D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size); 308980ad548dSVincenzo Maffione usage(-1); 309068b8534bSLuigi Rizzo } 309168b8534bSLuigi Rizzo 3092f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 3093f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 309499fb123fSLuigi Rizzo /* retrieve source mac address. */ 3095f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 309699fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 309799fb123fSLuigi Rizzo // continue, fail later 309899fb123fSLuigi Rizzo } 3099f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 310099fb123fSLuigi Rizzo } 3101f8e4e36aSLuigi Rizzo /* extract address ranges */ 310280ad548dSVincenzo Maffione if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac)) 310380ad548dSVincenzo Maffione usage(-1); 310480ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.src_ip, g.af); 310580ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.dst_ip, g.af); 3106f2637526SLuigi Rizzo 310717885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 310817885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 310917885a7bSLuigi Rizzo D("bad virtio-net-header length"); 311080ad548dSVincenzo Maffione usage(-1); 311117885a7bSLuigi Rizzo } 311217885a7bSLuigi Rizzo 3113f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 3114f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 3115f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 3116f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 3117f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 311880ad548dSVincenzo Maffione usage(-1); 311999fb123fSLuigi Rizzo } 3120f2637526SLuigi Rizzo #ifndef NO_PCAP 3121f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 3122f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 3123f8e4e36aSLuigi Rizzo 3124f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 31254bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 3126f8e4e36aSLuigi Rizzo if (g.p == NULL) { 3127f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 312880ad548dSVincenzo Maffione usage(-1); 3129f8e4e36aSLuigi Rizzo } 31304bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 31314bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 3132f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 3133f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 3134ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 313599fb123fSLuigi Rizzo } else { 31364bfe1a4fSVincenzo Maffione g.nmd = nmport_prepare(g.ifname); 31374bfe1a4fSVincenzo Maffione if (g.nmd == NULL) 313880ad548dSVincenzo Maffione goto out; 31394bfe1a4fSVincenzo Maffione 31404bfe1a4fSVincenzo Maffione parse_nmr_config(g.nmr_config, &g.nmd->reg); 31414bfe1a4fSVincenzo Maffione 31424bfe1a4fSVincenzo Maffione g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR; 3143f0ea3689SLuigi Rizzo 314468b8534bSLuigi Rizzo /* 3145f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 314668b8534bSLuigi Rizzo * 314768b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 314868b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 3149f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 315068b8534bSLuigi Rizzo */ 31514bfe1a4fSVincenzo Maffione g.orig_mode = g.nmd->reg.nr_mode; 315237e3a6d3SLuigi Rizzo if (g.nthreads > 1) { 31534bfe1a4fSVincenzo Maffione switch (g.orig_mode) { 31544bfe1a4fSVincenzo Maffione case NR_REG_ALL_NIC: 31554bfe1a4fSVincenzo Maffione case NR_REG_NIC_SW: 31564bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_NIC; 31574bfe1a4fSVincenzo Maffione break; 31584bfe1a4fSVincenzo Maffione case NR_REG_SW: 31594bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_SW; 31604bfe1a4fSVincenzo Maffione break; 31614bfe1a4fSVincenzo Maffione default: 31624bfe1a4fSVincenzo Maffione break; 316380ad548dSVincenzo Maffione } 31644bfe1a4fSVincenzo Maffione g.nmd->reg.nr_ringid = 0; 31654bfe1a4fSVincenzo Maffione } 31664bfe1a4fSVincenzo Maffione if (nmport_open_desc(g.nmd) < 0) 316737e3a6d3SLuigi Rizzo goto out; 3168f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 31694bfe1a4fSVincenzo Maffione ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10), 317080ad548dSVincenzo Maffione g.nmd->mem); 3171f0ea3689SLuigi Rizzo 317237e3a6d3SLuigi Rizzo if (g.virt_header) { 317337e3a6d3SLuigi Rizzo /* Set the virtio-net header length, since the user asked 317445c67e8fSVincenzo Maffione * for it explicitly. */ 317537e3a6d3SLuigi Rizzo set_vnet_hdr_len(&g); 317637e3a6d3SLuigi Rizzo } else { 317737e3a6d3SLuigi Rizzo /* Check whether the netmap port we opened requires us to send 317837e3a6d3SLuigi Rizzo * and receive frames with virtio-net header. */ 317937e3a6d3SLuigi Rizzo get_vnet_hdr_len(&g); 318037e3a6d3SLuigi Rizzo } 318137e3a6d3SLuigi Rizzo 31824bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 318337e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 31844bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings; 31854bf50f18SLuigi Rizzo else 31864bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings; 318768b8534bSLuigi Rizzo 318868b8534bSLuigi Rizzo /* validate provided nthreads. */ 318968b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 319068b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 319168b8534bSLuigi Rizzo // continue, fail later 319268b8534bSLuigi Rizzo } 319368b8534bSLuigi Rizzo 31949e53f3bdSVincenzo Maffione if (g.td_type == TD_TYPE_SENDER) { 31959e53f3bdSVincenzo Maffione int mtu = get_if_mtu(&g); 31969e53f3bdSVincenzo Maffione 31979e53f3bdSVincenzo Maffione if (mtu > 0 && g.pkt_size > mtu) { 31989e53f3bdSVincenzo Maffione D("pkt_size (%d) must be <= mtu (%d)", 31999e53f3bdSVincenzo Maffione g.pkt_size, mtu); 32009e53f3bdSVincenzo Maffione return -1; 32019e53f3bdSVincenzo Maffione } 32029e53f3bdSVincenzo Maffione } 32039e53f3bdSVincenzo Maffione 3204f2637526SLuigi Rizzo if (verbose) { 3205f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 32064bfe1a4fSVincenzo Maffione struct nmreq_register *req = &g.nmd->reg; 320768b8534bSLuigi Rizzo 3208d7493759SVincenzo Maffione D("nifp at offset %"PRIu64" ntxqs %d nrxqs %d memid %d", 3209f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 32104bfe1a4fSVincenzo Maffione req->nr_mem_id); 32114bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) { 32124bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 3213d7493759SVincenzo Maffione D(" TX%d at offset %p slots %d", i, 321437e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3215f2637526SLuigi Rizzo } 32164bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) { 32174bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 3218d7493759SVincenzo Maffione D(" RX%d at offset %p slots %d", i, 321937e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3220f2637526SLuigi Rizzo } 3221f2637526SLuigi Rizzo } 322268b8534bSLuigi Rizzo 322368b8534bSLuigi Rizzo /* Print some debug information. */ 322468b8534bSLuigi Rizzo fprintf(stdout, 322568b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 322637e3a6d3SLuigi Rizzo (g.td_type == TD_TYPE_SENDER) ? "Sending on" : 322737e3a6d3SLuigi Rizzo ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : 322837e3a6d3SLuigi Rizzo "Working on"), 3229f8e4e36aSLuigi Rizzo g.ifname, 323068b8534bSLuigi Rizzo devqueues, 323168b8534bSLuigi Rizzo g.nthreads, 323268b8534bSLuigi Rizzo g.cpus); 323337e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) { 323468b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 3235f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 3236f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 323768b8534bSLuigi Rizzo } 323868b8534bSLuigi Rizzo 3239f0ea3689SLuigi Rizzo out: 324068b8534bSLuigi Rizzo /* Exit if something went wrong. */ 3241f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 324268b8534bSLuigi Rizzo D("aborting"); 324380ad548dSVincenzo Maffione usage(-1); 324468b8534bSLuigi Rizzo } 324599fb123fSLuigi Rizzo } 324668b8534bSLuigi Rizzo 3247ce3ee1e7SLuigi Rizzo 324899fb123fSLuigi Rizzo if (g.options) { 324937e3a6d3SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", 325099fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 325199fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 325299fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 3253b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 325437e3a6d3SLuigi Rizzo g.options & OPT_COPY ? " copy" : "", 325537e3a6d3SLuigi Rizzo g.options & OPT_RUBBISH ? " rubbish " : ""); 325699fb123fSLuigi Rizzo } 32571cb4c501SLuigi Rizzo 3258ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 3259ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 3260ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 326117885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 3262ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 3263ce3ee1e7SLuigi Rizzo */ 326417885a7bSLuigi Rizzo uint64_t x; 326517885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 326617885a7bSLuigi Rizzo if (g.burst > lim) 326717885a7bSLuigi Rizzo g.burst = lim; 326880ad548dSVincenzo Maffione if (g.burst == 0) 326980ad548dSVincenzo Maffione g.burst = 1; 327017885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 327117885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 32721cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 32731cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 32741cb4c501SLuigi Rizzo } 327537e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 3276ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 3277ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 327868b8534bSLuigi Rizzo /* Install ^C handler. */ 327968b8534bSLuigi Rizzo global_nthreads = g.nthreads; 328037e3a6d3SLuigi Rizzo sigemptyset(&ss); 328137e3a6d3SLuigi Rizzo sigaddset(&ss, SIGINT); 328237e3a6d3SLuigi Rizzo /* block SIGINT now, so that all created threads will inherit the mask */ 328337e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { 328437e3a6d3SLuigi Rizzo D("failed to block SIGINT: %s", strerror(errno)); 328537e3a6d3SLuigi Rizzo } 32864bfe1a4fSVincenzo Maffione if (start_threads(&g) < 0) 32874bfe1a4fSVincenzo Maffione return 1; 328837e3a6d3SLuigi Rizzo /* Install the handler and re-enable SIGINT for the main thread */ 328980ad548dSVincenzo Maffione memset(&sa, 0, sizeof(sa)); 329037e3a6d3SLuigi Rizzo sa.sa_handler = sigint_h; 329137e3a6d3SLuigi Rizzo if (sigaction(SIGINT, &sa, NULL) < 0) { 329237e3a6d3SLuigi Rizzo D("failed to install ^C handler: %s", strerror(errno)); 329337e3a6d3SLuigi Rizzo } 329437e3a6d3SLuigi Rizzo 329537e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { 329637e3a6d3SLuigi Rizzo D("failed to re-enable SIGINT: %s", strerror(errno)); 329737e3a6d3SLuigi Rizzo } 3298f8e4e36aSLuigi Rizzo main_thread(&g); 329937e3a6d3SLuigi Rizzo free(targs); 3300f8e4e36aSLuigi Rizzo return 0; 330168b8534bSLuigi Rizzo } 330268b8534bSLuigi Rizzo 330368b8534bSLuigi Rizzo /* end of file */ 3304