168b8534bSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. 337e3a6d3SLuigi Rizzo * Copyright (C) 2013-2015 Universita` di Pisa. All rights reserved. 468b8534bSLuigi Rizzo * 568b8534bSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 668b8534bSLuigi Rizzo * modification, are permitted provided that the following conditions 768b8534bSLuigi Rizzo * are met: 868b8534bSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 968b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 1068b8534bSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 1168b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 1268b8534bSLuigi Rizzo * documentation and/or other materials provided with the distribution. 1368b8534bSLuigi Rizzo * 1468b8534bSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1568b8534bSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1668b8534bSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1768b8534bSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1868b8534bSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1968b8534bSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2068b8534bSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2168b8534bSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2268b8534bSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2368b8534bSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2468b8534bSLuigi Rizzo * SUCH DAMAGE. 2568b8534bSLuigi Rizzo */ 2668b8534bSLuigi Rizzo 2768b8534bSLuigi Rizzo /* 2868b8534bSLuigi Rizzo * $FreeBSD$ 29ce3ee1e7SLuigi Rizzo * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $ 3068b8534bSLuigi Rizzo * 3168b8534bSLuigi Rizzo * Example program to show how to build a multithreaded packet 3268b8534bSLuigi Rizzo * source/sink using the netmap device. 3368b8534bSLuigi Rizzo * 3468b8534bSLuigi Rizzo * In this example we create a programmable number of threads 3568b8534bSLuigi Rizzo * to take care of all the queues of the interface used to 3668b8534bSLuigi Rizzo * send or receive traffic. 3768b8534bSLuigi Rizzo * 3868b8534bSLuigi Rizzo */ 3968b8534bSLuigi Rizzo 40f0ea3689SLuigi Rizzo #define _GNU_SOURCE /* for CPU_SET() */ 41f0ea3689SLuigi Rizzo #include <arpa/inet.h> /* ntohs */ 424bfe1a4fSVincenzo Maffione #include <assert.h> 434bfe1a4fSVincenzo Maffione #include <ctype.h> // isprint() 444bfe1a4fSVincenzo Maffione #include <errno.h> 454bfe1a4fSVincenzo Maffione #include <fcntl.h> 46f0ea3689SLuigi Rizzo #include <ifaddrs.h> /* getifaddrs */ 474bfe1a4fSVincenzo Maffione #include <libnetmap.h> 484bfe1a4fSVincenzo Maffione #include <math.h> 49f0ea3689SLuigi Rizzo #include <net/ethernet.h> 50f0ea3689SLuigi Rizzo #include <netinet/in.h> 51f0ea3689SLuigi Rizzo #include <netinet/ip.h> 5280ad548dSVincenzo Maffione #include <netinet/ip6.h> 534bfe1a4fSVincenzo Maffione #include <netinet/udp.h> 544bfe1a4fSVincenzo Maffione #ifndef NO_PCAP 554bfe1a4fSVincenzo Maffione #include <pcap/pcap.h> 564bfe1a4fSVincenzo Maffione #endif 574bfe1a4fSVincenzo Maffione #include <pthread.h> 584bfe1a4fSVincenzo Maffione #include <signal.h> 594bfe1a4fSVincenzo Maffione #include <stdio.h> 604bfe1a4fSVincenzo Maffione #include <stdlib.h> 614bfe1a4fSVincenzo Maffione #include <string.h> 624bfe1a4fSVincenzo Maffione #include <sys/ioctl.h> 634bfe1a4fSVincenzo Maffione #include <sys/poll.h> 644bfe1a4fSVincenzo Maffione #include <sys/stat.h> 654bfe1a4fSVincenzo Maffione #if !defined(_WIN32) && !defined(linux) 664bfe1a4fSVincenzo Maffione #include <sys/sysctl.h> /* sysctl */ 674bfe1a4fSVincenzo Maffione #endif 684bfe1a4fSVincenzo Maffione #include <sys/types.h> 694bfe1a4fSVincenzo Maffione #include <unistd.h> // sysconf() 7080ad548dSVincenzo Maffione #ifdef linux 7180ad548dSVincenzo Maffione #define IPV6_VERSION 0x60 7280ad548dSVincenzo Maffione #define IPV6_DEFHLIM 64 7380ad548dSVincenzo Maffione #endif 74f0ea3689SLuigi Rizzo 7537e3a6d3SLuigi Rizzo #include "ctrs.h" 7637e3a6d3SLuigi Rizzo 7780ad548dSVincenzo Maffione static void usage(int); 7880ad548dSVincenzo Maffione 7937e3a6d3SLuigi Rizzo #ifdef _WIN32 8037e3a6d3SLuigi Rizzo #define cpuset_t DWORD_PTR //uint64_t 8137e3a6d3SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 8237e3a6d3SLuigi Rizzo { 8337e3a6d3SLuigi Rizzo *p = 0; 8437e3a6d3SLuigi Rizzo } 8537e3a6d3SLuigi Rizzo 8637e3a6d3SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 8737e3a6d3SLuigi Rizzo { 8837e3a6d3SLuigi Rizzo *p |= 1<< (i & 0x3f); 8937e3a6d3SLuigi Rizzo } 9037e3a6d3SLuigi Rizzo 9137e3a6d3SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c) //((void)a, 0) 9237e3a6d3SLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 9337e3a6d3SLuigi Rizzo #define AF_LINK 18 //defined in winsocks.h 9437e3a6d3SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 9537e3a6d3SLuigi Rizzo #include <net/if_dl.h> 9637e3a6d3SLuigi Rizzo 9737e3a6d3SLuigi Rizzo /* 9837e3a6d3SLuigi Rizzo * Convert an ASCII representation of an ethernet address to 9937e3a6d3SLuigi Rizzo * binary form. 10037e3a6d3SLuigi Rizzo */ 10137e3a6d3SLuigi Rizzo struct ether_addr * 10237e3a6d3SLuigi Rizzo ether_aton(const char *a) 10337e3a6d3SLuigi Rizzo { 10437e3a6d3SLuigi Rizzo int i; 10537e3a6d3SLuigi Rizzo static struct ether_addr o; 10637e3a6d3SLuigi Rizzo unsigned int o0, o1, o2, o3, o4, o5; 10737e3a6d3SLuigi Rizzo 10837e3a6d3SLuigi Rizzo i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); 10937e3a6d3SLuigi Rizzo 11037e3a6d3SLuigi Rizzo if (i != 6) 11137e3a6d3SLuigi Rizzo return (NULL); 11237e3a6d3SLuigi Rizzo 11337e3a6d3SLuigi Rizzo o.octet[0]=o0; 11437e3a6d3SLuigi Rizzo o.octet[1]=o1; 11537e3a6d3SLuigi Rizzo o.octet[2]=o2; 11637e3a6d3SLuigi Rizzo o.octet[3]=o3; 11737e3a6d3SLuigi Rizzo o.octet[4]=o4; 11837e3a6d3SLuigi Rizzo o.octet[5]=o5; 11937e3a6d3SLuigi Rizzo 12037e3a6d3SLuigi Rizzo return ((struct ether_addr *)&o); 12137e3a6d3SLuigi Rizzo } 12237e3a6d3SLuigi Rizzo 12337e3a6d3SLuigi Rizzo /* 12437e3a6d3SLuigi Rizzo * Convert a binary representation of an ethernet address to 12537e3a6d3SLuigi Rizzo * an ASCII string. 12637e3a6d3SLuigi Rizzo */ 12737e3a6d3SLuigi Rizzo char * 12837e3a6d3SLuigi Rizzo ether_ntoa(const struct ether_addr *n) 12937e3a6d3SLuigi Rizzo { 13037e3a6d3SLuigi Rizzo int i; 13137e3a6d3SLuigi Rizzo static char a[18]; 13237e3a6d3SLuigi Rizzo 13337e3a6d3SLuigi Rizzo i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", 13437e3a6d3SLuigi Rizzo n->octet[0], n->octet[1], n->octet[2], 13537e3a6d3SLuigi Rizzo n->octet[3], n->octet[4], n->octet[5]); 13637e3a6d3SLuigi Rizzo return (i < 17 ? NULL : (char *)&a); 13737e3a6d3SLuigi Rizzo } 13837e3a6d3SLuigi Rizzo #endif /* _WIN32 */ 13937e3a6d3SLuigi Rizzo 140f0ea3689SLuigi Rizzo #ifdef linux 141f0ea3689SLuigi Rizzo 142f0ea3689SLuigi Rizzo #define cpuset_t cpu_set_t 143f0ea3689SLuigi Rizzo 144f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags /* only the low 16 bits here */ 145f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ 146f0ea3689SLuigi Rizzo #include <linux/ethtool.h> 147f0ea3689SLuigi Rizzo #include <linux/sockios.h> 148f0ea3689SLuigi Rizzo 149f0ea3689SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 150f0ea3689SLuigi Rizzo #include <netinet/ether.h> /* ether_aton */ 151f0ea3689SLuigi Rizzo #include <linux/if_packet.h> /* sockaddr_ll */ 152f0ea3689SLuigi Rizzo #endif /* linux */ 153f0ea3689SLuigi Rizzo 154f0ea3689SLuigi Rizzo #ifdef __FreeBSD__ 155f0ea3689SLuigi Rizzo #include <sys/endian.h> /* le64toh */ 156f0ea3689SLuigi Rizzo #include <machine/param.h> 157f0ea3689SLuigi Rizzo 158f0ea3689SLuigi Rizzo #include <pthread_np.h> /* pthread w/ affinity */ 159f0ea3689SLuigi Rizzo #include <sys/cpuset.h> /* cpu_set */ 160f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 161f0ea3689SLuigi Rizzo #endif /* __FreeBSD__ */ 162f0ea3689SLuigi Rizzo 163f0ea3689SLuigi Rizzo #ifdef __APPLE__ 164f0ea3689SLuigi Rizzo 165f0ea3689SLuigi Rizzo #define cpuset_t uint64_t // XXX 166f0ea3689SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 167f0ea3689SLuigi Rizzo { 168f0ea3689SLuigi Rizzo *p = 0; 169f0ea3689SLuigi Rizzo } 170f0ea3689SLuigi Rizzo 171f0ea3689SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 172f0ea3689SLuigi Rizzo { 173f0ea3689SLuigi Rizzo *p |= 1<< (i & 0x3f); 174f0ea3689SLuigi Rizzo } 175f0ea3689SLuigi Rizzo 176f0ea3689SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) ((void)a, 0) 177f0ea3689SLuigi Rizzo 178f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags // XXX 179f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC 180f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 181f0ea3689SLuigi Rizzo #define clock_gettime(a,b) \ 182f0ea3689SLuigi Rizzo do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) 183f0ea3689SLuigi Rizzo #endif /* __APPLE__ */ 184f0ea3689SLuigi Rizzo 1857eb32dc8SVincenzo Maffione static const char *default_payload = "netmap pkt-gen DIRECT payload\n" 186ce3ee1e7SLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 187ce3ee1e7SLuigi Rizzo 1887eb32dc8SVincenzo Maffione static const char *indirect_payload = "netmap pkt-gen indirect payload\n" 18968b8534bSLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 19068b8534bSLuigi Rizzo 1917eb32dc8SVincenzo Maffione static int verbose = 0; 1927eb32dc8SVincenzo Maffione static int normalize = 1; 19317885a7bSLuigi Rizzo 19417885a7bSLuigi Rizzo #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ 19517885a7bSLuigi Rizzo #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ 19617885a7bSLuigi Rizzo #define VIRT_HDR_MAX VIRT_HDR_2 19717885a7bSLuigi Rizzo struct virt_header { 19817885a7bSLuigi Rizzo uint8_t fields[VIRT_HDR_MAX]; 19917885a7bSLuigi Rizzo }; 20017885a7bSLuigi Rizzo 2019e53f3bdSVincenzo Maffione #define MAX_BODYSIZE 65536 2024bf50f18SLuigi Rizzo 20368b8534bSLuigi Rizzo struct pkt { 20417885a7bSLuigi Rizzo struct virt_header vh; 20568b8534bSLuigi Rizzo struct ether_header eh; 20680ad548dSVincenzo Maffione union { 20780ad548dSVincenzo Maffione struct { 20868b8534bSLuigi Rizzo struct ip ip; 20968b8534bSLuigi Rizzo struct udphdr udp; 21080ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 21180ad548dSVincenzo Maffione } ipv4; 21280ad548dSVincenzo Maffione struct { 21380ad548dSVincenzo Maffione struct ip6_hdr ip; 21480ad548dSVincenzo Maffione struct udphdr udp; 21580ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 21680ad548dSVincenzo Maffione } ipv6; 21780ad548dSVincenzo Maffione }; 21868b8534bSLuigi Rizzo } __attribute__((__packed__)); 21968b8534bSLuigi Rizzo 22080ad548dSVincenzo Maffione #define PKT(p, f, af) \ 22180ad548dSVincenzo Maffione ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f) 22280ad548dSVincenzo Maffione 223f8e4e36aSLuigi Rizzo struct ip_range { 2247eb32dc8SVincenzo Maffione const char *name; 22580ad548dSVincenzo Maffione union { 22680ad548dSVincenzo Maffione struct { 227ce3ee1e7SLuigi Rizzo uint32_t start, end; /* same as struct in_addr */ 22880ad548dSVincenzo Maffione } ipv4; 22980ad548dSVincenzo Maffione struct { 23080ad548dSVincenzo Maffione struct in6_addr start, end; 23180ad548dSVincenzo Maffione uint8_t sgroup, egroup; 23280ad548dSVincenzo Maffione } ipv6; 23380ad548dSVincenzo Maffione }; 234ce3ee1e7SLuigi Rizzo uint16_t port0, port1; 235f8e4e36aSLuigi Rizzo }; 236f8e4e36aSLuigi Rizzo 237f8e4e36aSLuigi Rizzo struct mac_range { 2387eb32dc8SVincenzo Maffione const char *name; 239f8e4e36aSLuigi Rizzo struct ether_addr start, end; 240f8e4e36aSLuigi Rizzo }; 241f8e4e36aSLuigi Rizzo 242f0ea3689SLuigi Rizzo /* ifname can be netmap:foo-xxxx */ 2434bfe1a4fSVincenzo Maffione #define MAX_IFNAMELEN 512 /* our buffer for ifname */ 2444bfe1a4fSVincenzo Maffione //#define MAX_PKTSIZE 1536 2454bf50f18SLuigi Rizzo #define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ 2464bf50f18SLuigi Rizzo 2474bf50f18SLuigi Rizzo /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ 2484bf50f18SLuigi Rizzo struct tstamp { 2494bf50f18SLuigi Rizzo uint32_t sec; 2504bf50f18SLuigi Rizzo uint32_t nsec; 2514bf50f18SLuigi Rizzo }; 2524bf50f18SLuigi Rizzo 25368b8534bSLuigi Rizzo /* 25468b8534bSLuigi Rizzo * global arguments for all threads 25568b8534bSLuigi Rizzo */ 256f8e4e36aSLuigi Rizzo 25768b8534bSLuigi Rizzo struct glob_arg { 25880ad548dSVincenzo Maffione int af; /* address family AF_INET/AF_INET6 */ 259f8e4e36aSLuigi Rizzo struct ip_range src_ip; 260f8e4e36aSLuigi Rizzo struct ip_range dst_ip; 261f8e4e36aSLuigi Rizzo struct mac_range dst_mac; 262f8e4e36aSLuigi Rizzo struct mac_range src_mac; 26368b8534bSLuigi Rizzo int pkt_size; 26480ad548dSVincenzo Maffione int pkt_min_size; 26568b8534bSLuigi Rizzo int burst; 266f8e4e36aSLuigi Rizzo int forever; 26737e3a6d3SLuigi Rizzo uint64_t npackets; /* total packets to send */ 268ce3ee1e7SLuigi Rizzo int frags; /* fragments per packet */ 2699e53f3bdSVincenzo Maffione u_int frag_size; /* size of each fragment */ 27068b8534bSLuigi Rizzo int nthreads; 27137e3a6d3SLuigi Rizzo int cpus; /* cpus used for running */ 27237e3a6d3SLuigi Rizzo int system_cpus; /* cpus on the system */ 27337e3a6d3SLuigi Rizzo 27499fb123fSLuigi Rizzo int options; /* testing */ 27599fb123fSLuigi Rizzo #define OPT_PREFETCH 1 27699fb123fSLuigi Rizzo #define OPT_ACCESS 2 27799fb123fSLuigi Rizzo #define OPT_COPY 4 27899fb123fSLuigi Rizzo #define OPT_MEMCPY 8 279f8e4e36aSLuigi Rizzo #define OPT_TS 16 /* add a timestamp */ 280b303f675SLuigi Rizzo #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ 281b303f675SLuigi Rizzo #define OPT_DUMP 64 /* dump rx/tx traffic */ 282ed188a7eSVincenzo Maffione #define OPT_RUBBISH 256 /* send whatever the buffers contain */ 28356717743SAdrian Chadd #define OPT_RANDOM_SRC 512 28456717743SAdrian Chadd #define OPT_RANDOM_DST 1024 28537e3a6d3SLuigi Rizzo #define OPT_PPS_STATS 2048 286f8e4e36aSLuigi Rizzo int dev_type; 287f2637526SLuigi Rizzo #ifndef NO_PCAP 28868b8534bSLuigi Rizzo pcap_t *p; 289f2637526SLuigi Rizzo #endif 29068b8534bSLuigi Rizzo 2911cb4c501SLuigi Rizzo int tx_rate; 2921cb4c501SLuigi Rizzo struct timespec tx_period; 2931cb4c501SLuigi Rizzo 294f8e4e36aSLuigi Rizzo int affinity; 295f8e4e36aSLuigi Rizzo int main_fd; 2964bfe1a4fSVincenzo Maffione struct nmport_d *nmd; 2974bfe1a4fSVincenzo Maffione uint32_t orig_mode; 298f2637526SLuigi Rizzo int report_interval; /* milliseconds between prints */ 299f8e4e36aSLuigi Rizzo void *(*td_body)(void *); 30037e3a6d3SLuigi Rizzo int td_type; 301f8e4e36aSLuigi Rizzo void *mmap_addr; 302f0ea3689SLuigi Rizzo char ifname[MAX_IFNAMELEN]; 3037eb32dc8SVincenzo Maffione const char *nmr_config; 304ce3ee1e7SLuigi Rizzo int dummy_send; 30517885a7bSLuigi Rizzo int virt_header; /* send also the virt_header */ 306f284c737SGeorge V. Neville-Neil char *packet_file; /* -P option */ 30737e3a6d3SLuigi Rizzo #define STATS_WIN 15 30837e3a6d3SLuigi Rizzo int win_idx; 30937e3a6d3SLuigi Rizzo int64_t win[STATS_WIN]; 31080ad548dSVincenzo Maffione int wait_link; 31180ad548dSVincenzo Maffione int framing; /* #bits of framing (for bw output) */ 31268b8534bSLuigi Rizzo }; 313f8e4e36aSLuigi Rizzo enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; 314f8e4e36aSLuigi Rizzo 3159e53f3bdSVincenzo Maffione enum { 3169e53f3bdSVincenzo Maffione TD_TYPE_SENDER = 1, 3179e53f3bdSVincenzo Maffione TD_TYPE_RECEIVER, 3189e53f3bdSVincenzo Maffione TD_TYPE_OTHER, 3199e53f3bdSVincenzo Maffione }; 32068b8534bSLuigi Rizzo 32168b8534bSLuigi Rizzo /* 32268b8534bSLuigi Rizzo * Arguments for a new thread. The same structure is used by 32368b8534bSLuigi Rizzo * the source and the sink 32468b8534bSLuigi Rizzo */ 32568b8534bSLuigi Rizzo struct targ { 32668b8534bSLuigi Rizzo struct glob_arg *g; 32768b8534bSLuigi Rizzo int used; 32868b8534bSLuigi Rizzo int completed; 3293fe77e68SEd Maste int cancel; 33068b8534bSLuigi Rizzo int fd; 3314bfe1a4fSVincenzo Maffione struct nmport_d *nmd; 33237e3a6d3SLuigi Rizzo /* these ought to be volatile, but they are 33337e3a6d3SLuigi Rizzo * only sampled and errors should not accumulate 33437e3a6d3SLuigi Rizzo */ 33537e3a6d3SLuigi Rizzo struct my_ctrs ctr; 33637e3a6d3SLuigi Rizzo 3371cb4c501SLuigi Rizzo struct timespec tic, toc; 33868b8534bSLuigi Rizzo int me; 33968b8534bSLuigi Rizzo pthread_t thread; 34068b8534bSLuigi Rizzo int affinity; 34168b8534bSLuigi Rizzo 34268b8534bSLuigi Rizzo struct pkt pkt; 343f284c737SGeorge V. Neville-Neil void *frame; 34480ad548dSVincenzo Maffione uint16_t seed[3]; 34580ad548dSVincenzo Maffione u_int frags; 34680ad548dSVincenzo Maffione u_int frag_size; 34768b8534bSLuigi Rizzo }; 34868b8534bSLuigi Rizzo 34980ad548dSVincenzo Maffione static __inline uint16_t 35080ad548dSVincenzo Maffione cksum_add(uint16_t sum, uint16_t a) 35180ad548dSVincenzo Maffione { 35280ad548dSVincenzo Maffione uint16_t res; 35368b8534bSLuigi Rizzo 35480ad548dSVincenzo Maffione res = sum + a; 35580ad548dSVincenzo Maffione return (res + (res < a)); 35680ad548dSVincenzo Maffione } 35780ad548dSVincenzo Maffione 35880ad548dSVincenzo Maffione static void 35980ad548dSVincenzo Maffione extract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port) 36080ad548dSVincenzo Maffione { 36180ad548dSVincenzo Maffione struct in_addr a; 36280ad548dSVincenzo Maffione char *pp; 36380ad548dSVincenzo Maffione 36480ad548dSVincenzo Maffione pp = strchr(name, ':'); 36580ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 36680ad548dSVincenzo Maffione *pp++ = '\0'; 36780ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 36880ad548dSVincenzo Maffione } 36980ad548dSVincenzo Maffione 37080ad548dSVincenzo Maffione inet_pton(AF_INET, name, &a); 37180ad548dSVincenzo Maffione *addr = ntohl(a.s_addr); 37280ad548dSVincenzo Maffione } 37380ad548dSVincenzo Maffione 37480ad548dSVincenzo Maffione static void 37580ad548dSVincenzo Maffione extract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port, 37680ad548dSVincenzo Maffione uint8_t *group) 37780ad548dSVincenzo Maffione { 37880ad548dSVincenzo Maffione char *pp; 37980ad548dSVincenzo Maffione 38080ad548dSVincenzo Maffione /* 38180ad548dSVincenzo Maffione * We accept IPv6 address in the following form: 38280ad548dSVincenzo Maffione * group@[2001:DB8::1001]:port (w/ brackets and port) 38380ad548dSVincenzo Maffione * group@[2001:DB8::1] (w/ brackets and w/o port) 38480ad548dSVincenzo Maffione * group@2001:DB8::1234 (w/o brackets and w/o port) 38580ad548dSVincenzo Maffione */ 38680ad548dSVincenzo Maffione pp = strchr(name, '@'); 38780ad548dSVincenzo Maffione if (pp != NULL) { 38880ad548dSVincenzo Maffione *pp++ = '\0'; 38980ad548dSVincenzo Maffione *group = (uint8_t)strtol(name, NULL, 0); 39080ad548dSVincenzo Maffione if (*group > 7) 39180ad548dSVincenzo Maffione *group = 7; 39280ad548dSVincenzo Maffione name = pp; 39380ad548dSVincenzo Maffione } 39480ad548dSVincenzo Maffione if (name[0] == '[') 39580ad548dSVincenzo Maffione name++; 39680ad548dSVincenzo Maffione pp = strchr(name, ']'); 39780ad548dSVincenzo Maffione if (pp != NULL) 39880ad548dSVincenzo Maffione *pp++ = '\0'; 39980ad548dSVincenzo Maffione if (pp != NULL && *pp != ':') 40080ad548dSVincenzo Maffione pp = NULL; 40180ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 40280ad548dSVincenzo Maffione *pp++ = '\0'; 40380ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 40480ad548dSVincenzo Maffione } 40580ad548dSVincenzo Maffione inet_pton(AF_INET6, name, addr); 40680ad548dSVincenzo Maffione } 407f8e4e36aSLuigi Rizzo /* 408f8e4e36aSLuigi Rizzo * extract the extremes from a range of ipv4 addresses. 409f8e4e36aSLuigi Rizzo * addr_lo[-addr_hi][:port_lo[-port_hi]] 410f8e4e36aSLuigi Rizzo */ 41180ad548dSVincenzo Maffione static int 41280ad548dSVincenzo Maffione extract_ip_range(struct ip_range *r, int af) 413f8e4e36aSLuigi Rizzo { 41480ad548dSVincenzo Maffione char *name, *ap, start[INET6_ADDRSTRLEN]; 41580ad548dSVincenzo Maffione char end[INET6_ADDRSTRLEN]; 416ce3ee1e7SLuigi Rizzo struct in_addr a; 41780ad548dSVincenzo Maffione uint32_t tmp; 418f8e4e36aSLuigi Rizzo 41917885a7bSLuigi Rizzo if (verbose) 420f8e4e36aSLuigi Rizzo D("extract IP range from %s", r->name); 421ce3ee1e7SLuigi Rizzo 42280ad548dSVincenzo Maffione name = strdup(r->name); 42380ad548dSVincenzo Maffione if (name == NULL) { 42480ad548dSVincenzo Maffione D("strdup failed"); 42580ad548dSVincenzo Maffione usage(-1); 42680ad548dSVincenzo Maffione } 427ce3ee1e7SLuigi Rizzo /* the first - splits start/end of range */ 42880ad548dSVincenzo Maffione ap = strchr(name, '-'); 42980ad548dSVincenzo Maffione if (ap != NULL) 430ce3ee1e7SLuigi Rizzo *ap++ = '\0'; 43180ad548dSVincenzo Maffione r->port0 = 1234; /* default port */ 43280ad548dSVincenzo Maffione if (af == AF_INET6) { 43380ad548dSVincenzo Maffione r->ipv6.sgroup = 7; /* default group */ 43480ad548dSVincenzo Maffione extract_ipv6_addr(name, &r->ipv6.start, &r->port0, 43580ad548dSVincenzo Maffione &r->ipv6.sgroup); 43680ad548dSVincenzo Maffione } else 43780ad548dSVincenzo Maffione extract_ipv4_addr(name, &r->ipv4.start, &r->port0); 43880ad548dSVincenzo Maffione 43980ad548dSVincenzo Maffione r->port1 = r->port0; 44080ad548dSVincenzo Maffione if (af == AF_INET6) { 44180ad548dSVincenzo Maffione if (ap != NULL) { 44280ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 44380ad548dSVincenzo Maffione extract_ipv6_addr(ap, &r->ipv6.end, &r->port1, 44480ad548dSVincenzo Maffione &r->ipv6.egroup); 44580ad548dSVincenzo Maffione } else { 44680ad548dSVincenzo Maffione r->ipv6.end = r->ipv6.start; 44780ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 448ce3ee1e7SLuigi Rizzo } 44980ad548dSVincenzo Maffione } else { 45080ad548dSVincenzo Maffione if (ap != NULL) { 45180ad548dSVincenzo Maffione extract_ipv4_addr(ap, &r->ipv4.end, &r->port1); 45280ad548dSVincenzo Maffione if (r->ipv4.start > r->ipv4.end) { 45380ad548dSVincenzo Maffione tmp = r->ipv4.end; 45480ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 45580ad548dSVincenzo Maffione r->ipv4.start = tmp; 456ce3ee1e7SLuigi Rizzo } 45780ad548dSVincenzo Maffione } else 45880ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 459ce3ee1e7SLuigi Rizzo } 46080ad548dSVincenzo Maffione 461ce3ee1e7SLuigi Rizzo if (r->port0 > r->port1) { 46280ad548dSVincenzo Maffione tmp = r->port0; 463f8e4e36aSLuigi Rizzo r->port0 = r->port1; 464ce3ee1e7SLuigi Rizzo r->port1 = tmp; 465f8e4e36aSLuigi Rizzo } 46680ad548dSVincenzo Maffione if (af == AF_INET) { 46780ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.start); 46880ad548dSVincenzo Maffione inet_ntop(af, &a, start, sizeof(start)); 46980ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.end); 47080ad548dSVincenzo Maffione inet_ntop(af, &a, end, sizeof(end)); 47180ad548dSVincenzo Maffione } else { 47280ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.start, start, sizeof(start)); 47380ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.end, end, sizeof(end)); 474f8e4e36aSLuigi Rizzo } 47580ad548dSVincenzo Maffione if (af == AF_INET) 47680ad548dSVincenzo Maffione D("range is %s:%d to %s:%d", start, r->port0, end, r->port1); 47780ad548dSVincenzo Maffione else 47880ad548dSVincenzo Maffione D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup, 47980ad548dSVincenzo Maffione start, r->port0, r->ipv6.egroup, end, r->port1); 480ce3ee1e7SLuigi Rizzo 48180ad548dSVincenzo Maffione free(name); 48280ad548dSVincenzo Maffione if (r->port0 != r->port1 || 48380ad548dSVincenzo Maffione (af == AF_INET && r->ipv4.start != r->ipv4.end) || 48480ad548dSVincenzo Maffione (af == AF_INET6 && 48580ad548dSVincenzo Maffione !IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end))) 48680ad548dSVincenzo Maffione return (OPT_COPY); 48780ad548dSVincenzo Maffione return (0); 488f8e4e36aSLuigi Rizzo } 489f8e4e36aSLuigi Rizzo 49080ad548dSVincenzo Maffione static int 491f8e4e36aSLuigi Rizzo extract_mac_range(struct mac_range *r) 492f8e4e36aSLuigi Rizzo { 49380ad548dSVincenzo Maffione struct ether_addr *e; 49417885a7bSLuigi Rizzo if (verbose) 495f8e4e36aSLuigi Rizzo D("extract MAC range from %s", r->name); 49680ad548dSVincenzo Maffione 49780ad548dSVincenzo Maffione e = ether_aton(r->name); 49880ad548dSVincenzo Maffione if (e == NULL) { 49980ad548dSVincenzo Maffione D("invalid MAC address '%s'", r->name); 50080ad548dSVincenzo Maffione return 1; 50180ad548dSVincenzo Maffione } 50280ad548dSVincenzo Maffione bcopy(e, &r->start, 6); 50380ad548dSVincenzo Maffione bcopy(e, &r->end, 6); 504f8e4e36aSLuigi Rizzo #if 0 505f8e4e36aSLuigi Rizzo bcopy(targ->src_mac, eh->ether_shost, 6); 506f8e4e36aSLuigi Rizzo p = index(targ->g->src_mac, '-'); 507f8e4e36aSLuigi Rizzo if (p) 508f8e4e36aSLuigi Rizzo targ->src_mac_range = atoi(p+1); 509f8e4e36aSLuigi Rizzo 510f8e4e36aSLuigi Rizzo bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6); 511f8e4e36aSLuigi Rizzo bcopy(targ->dst_mac, eh->ether_dhost, 6); 512f8e4e36aSLuigi Rizzo p = index(targ->g->dst_mac, '-'); 513f8e4e36aSLuigi Rizzo if (p) 514f8e4e36aSLuigi Rizzo targ->dst_mac_range = atoi(p+1); 515f8e4e36aSLuigi Rizzo #endif 51617885a7bSLuigi Rizzo if (verbose) 517f8e4e36aSLuigi Rizzo D("%s starts at %s", r->name, ether_ntoa(&r->start)); 51880ad548dSVincenzo Maffione return 0; 519f8e4e36aSLuigi Rizzo } 520f8e4e36aSLuigi Rizzo 5219e53f3bdSVincenzo Maffione static int 5229e53f3bdSVincenzo Maffione get_if_mtu(const struct glob_arg *g) 5239e53f3bdSVincenzo Maffione { 5249e53f3bdSVincenzo Maffione struct ifreq ifreq; 5259e53f3bdSVincenzo Maffione int s, ret; 5264bfe1a4fSVincenzo Maffione const char *ifname = g->nmd->hdr.nr_name; 5274bfe1a4fSVincenzo Maffione size_t len; 5289e53f3bdSVincenzo Maffione 5294bfe1a4fSVincenzo Maffione if (!strncmp(g->ifname, "netmap:", 7) && !strchr(ifname, '{') 5304bfe1a4fSVincenzo Maffione && !strchr(ifname, '}')) { 5314bfe1a4fSVincenzo Maffione 5324bfe1a4fSVincenzo Maffione len = strlen(ifname); 5334bfe1a4fSVincenzo Maffione 5344bfe1a4fSVincenzo Maffione if (len > IFNAMSIZ) { 5354bfe1a4fSVincenzo Maffione D("'%s' too long, cannot ask for MTU", ifname); 5364bfe1a4fSVincenzo Maffione return -1; 5374bfe1a4fSVincenzo Maffione } 5389e53f3bdSVincenzo Maffione 5399e53f3bdSVincenzo Maffione s = socket(AF_INET, SOCK_DGRAM, 0); 5409e53f3bdSVincenzo Maffione if (s < 0) { 5419e53f3bdSVincenzo Maffione D("socket() failed: %s", strerror(errno)); 5429e53f3bdSVincenzo Maffione return s; 5439e53f3bdSVincenzo Maffione } 5449e53f3bdSVincenzo Maffione 5459e53f3bdSVincenzo Maffione memset(&ifreq, 0, sizeof(ifreq)); 5464bfe1a4fSVincenzo Maffione memcpy(ifreq.ifr_name, ifname, len); 5479e53f3bdSVincenzo Maffione 5489e53f3bdSVincenzo Maffione ret = ioctl(s, SIOCGIFMTU, &ifreq); 5499e53f3bdSVincenzo Maffione if (ret) { 5509e53f3bdSVincenzo Maffione D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno)); 5519e53f3bdSVincenzo Maffione } 5529e53f3bdSVincenzo Maffione 5534bfe1a4fSVincenzo Maffione close(s); 5544bfe1a4fSVincenzo Maffione 5559e53f3bdSVincenzo Maffione return ifreq.ifr_mtu; 5569e53f3bdSVincenzo Maffione } 5579e53f3bdSVincenzo Maffione 5589e53f3bdSVincenzo Maffione /* This is a pipe or a VALE port, where the MTU is very large, 5599e53f3bdSVincenzo Maffione * so we use some practical limit. */ 5609e53f3bdSVincenzo Maffione return 65536; 5619e53f3bdSVincenzo Maffione } 5629e53f3bdSVincenzo Maffione 56368b8534bSLuigi Rizzo static struct targ *targs; 56468b8534bSLuigi Rizzo static int global_nthreads; 56568b8534bSLuigi Rizzo 56668b8534bSLuigi Rizzo /* control-C handler */ 56768b8534bSLuigi Rizzo static void 568f8e4e36aSLuigi Rizzo sigint_h(int sig) 56968b8534bSLuigi Rizzo { 570f8e4e36aSLuigi Rizzo int i; 57168b8534bSLuigi Rizzo 572f8e4e36aSLuigi Rizzo (void)sig; /* UNUSED */ 57337e3a6d3SLuigi Rizzo D("received control-C on thread %p", (void *)pthread_self()); 574f8e4e36aSLuigi Rizzo for (i = 0; i < global_nthreads; i++) { 575f8e4e36aSLuigi Rizzo targs[i].cancel = 1; 576f8e4e36aSLuigi Rizzo } 57768b8534bSLuigi Rizzo } 57868b8534bSLuigi Rizzo 57968b8534bSLuigi Rizzo /* sysctl wrapper to return the number of active CPUs */ 58068b8534bSLuigi Rizzo static int 58168b8534bSLuigi Rizzo system_ncpus(void) 58268b8534bSLuigi Rizzo { 583f0ea3689SLuigi Rizzo int ncpus; 584f0ea3689SLuigi Rizzo #if defined (__FreeBSD__) 585f0ea3689SLuigi Rizzo int mib[2] = { CTL_HW, HW_NCPU }; 586f0ea3689SLuigi Rizzo size_t len = sizeof(mib); 58768b8534bSLuigi Rizzo sysctl(mib, 2, &ncpus, &len, NULL, 0); 588f0ea3689SLuigi Rizzo #elif defined(linux) 589f0ea3689SLuigi Rizzo ncpus = sysconf(_SC_NPROCESSORS_ONLN); 59037e3a6d3SLuigi Rizzo #elif defined(_WIN32) 59137e3a6d3SLuigi Rizzo { 59237e3a6d3SLuigi Rizzo SYSTEM_INFO sysinfo; 59337e3a6d3SLuigi Rizzo GetSystemInfo(&sysinfo); 59437e3a6d3SLuigi Rizzo ncpus = sysinfo.dwNumberOfProcessors; 59537e3a6d3SLuigi Rizzo } 596f0ea3689SLuigi Rizzo #else /* others */ 597f0ea3689SLuigi Rizzo ncpus = 1; 598f0ea3689SLuigi Rizzo #endif /* others */ 59968b8534bSLuigi Rizzo return (ncpus); 60068b8534bSLuigi Rizzo } 60168b8534bSLuigi Rizzo 602f8e4e36aSLuigi Rizzo #ifdef __linux__ 603f8e4e36aSLuigi Rizzo #define sockaddr_dl sockaddr_ll 604f8e4e36aSLuigi Rizzo #define sdl_family sll_family 605f8e4e36aSLuigi Rizzo #define AF_LINK AF_PACKET 606f8e4e36aSLuigi Rizzo #define LLADDR(s) s->sll_addr; 607f8e4e36aSLuigi Rizzo #include <linux/if_tun.h> 608f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/net/tun" 609f8e4e36aSLuigi Rizzo #endif /* __linux__ */ 610f8e4e36aSLuigi Rizzo 611f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 612f8e4e36aSLuigi Rizzo #include <net/if_tun.h> 613f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 614f8e4e36aSLuigi Rizzo #endif /* __FreeBSD */ 615f8e4e36aSLuigi Rizzo 616f8e4e36aSLuigi Rizzo #ifdef __APPLE__ 617f8e4e36aSLuigi Rizzo // #warning TAP not supported on apple ? 618f8e4e36aSLuigi Rizzo #include <net/if_utun.h> 619f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 620f8e4e36aSLuigi Rizzo #endif /* __APPLE__ */ 621f8e4e36aSLuigi Rizzo 622f8e4e36aSLuigi Rizzo 62368b8534bSLuigi Rizzo /* 624ce3ee1e7SLuigi Rizzo * parse the vale configuration in conf and put it in nmr. 625f0ea3689SLuigi Rizzo * Return the flag set if necessary. 62680ad548dSVincenzo Maffione * The configuration may consist of 1 to 4 numbers separated 627fc6eb28bSHiren Panchasara * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. 628ce3ee1e7SLuigi Rizzo * Missing numbers or zeroes stand for default values. 629ce3ee1e7SLuigi Rizzo * As an additional convenience, if exactly one number 630fc6eb28bSHiren Panchasara * is specified, then this is assigned to both #tx-slots and #rx-slots. 631fc6eb28bSHiren Panchasara * If there is no 4th number, then the 3rd is assigned to both #tx-rings 632ce3ee1e7SLuigi Rizzo * and #rx-rings. 633ce3ee1e7SLuigi Rizzo */ 6347eb32dc8SVincenzo Maffione static int 6354bfe1a4fSVincenzo Maffione parse_nmr_config(const char* conf, struct nmreq_register *nmr) 636ce3ee1e7SLuigi Rizzo { 637ce3ee1e7SLuigi Rizzo char *w, *tok; 638ce3ee1e7SLuigi Rizzo int i, v; 639ce3ee1e7SLuigi Rizzo 640ce3ee1e7SLuigi Rizzo if (conf == NULL || ! *conf) 641f0ea3689SLuigi Rizzo return 0; 642406e7723SVincenzo Maffione nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 643406e7723SVincenzo Maffione nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 644ce3ee1e7SLuigi Rizzo w = strdup(conf); 645ce3ee1e7SLuigi Rizzo for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 646ce3ee1e7SLuigi Rizzo v = atoi(tok); 647ce3ee1e7SLuigi Rizzo switch (i) { 648ce3ee1e7SLuigi Rizzo case 0: 649ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = v; 650ce3ee1e7SLuigi Rizzo break; 651ce3ee1e7SLuigi Rizzo case 1: 652ce3ee1e7SLuigi Rizzo nmr->nr_rx_slots = v; 653ce3ee1e7SLuigi Rizzo break; 654ce3ee1e7SLuigi Rizzo case 2: 655ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = v; 656ce3ee1e7SLuigi Rizzo break; 657ce3ee1e7SLuigi Rizzo case 3: 658ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings = v; 659ce3ee1e7SLuigi Rizzo break; 660ce3ee1e7SLuigi Rizzo default: 661ce3ee1e7SLuigi Rizzo D("ignored config: %s", tok); 662ce3ee1e7SLuigi Rizzo break; 663ce3ee1e7SLuigi Rizzo } 664ce3ee1e7SLuigi Rizzo } 665ce3ee1e7SLuigi Rizzo D("txr %d txd %d rxr %d rxd %d", 666ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings, nmr->nr_tx_slots, 667ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings, nmr->nr_rx_slots); 668ce3ee1e7SLuigi Rizzo free(w); 6694bfe1a4fSVincenzo Maffione return 0; 670ce3ee1e7SLuigi Rizzo } 671ce3ee1e7SLuigi Rizzo 672ce3ee1e7SLuigi Rizzo 673ce3ee1e7SLuigi Rizzo /* 67468b8534bSLuigi Rizzo * locate the src mac address for our interface, put it 67568b8534bSLuigi Rizzo * into the user-supplied buffer. return 0 if ok, -1 on error. 67668b8534bSLuigi Rizzo */ 67768b8534bSLuigi Rizzo static int 67868b8534bSLuigi Rizzo source_hwaddr(const char *ifname, char *buf) 67968b8534bSLuigi Rizzo { 68068b8534bSLuigi Rizzo struct ifaddrs *ifaphead, *ifap; 68168b8534bSLuigi Rizzo 68268b8534bSLuigi Rizzo if (getifaddrs(&ifaphead) != 0) { 68368b8534bSLuigi Rizzo D("getifaddrs %s failed", ifname); 68468b8534bSLuigi Rizzo return (-1); 68568b8534bSLuigi Rizzo } 68668b8534bSLuigi Rizzo 68768b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 68868b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 68968b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 69068b8534bSLuigi Rizzo uint8_t *mac; 69168b8534bSLuigi Rizzo 69268b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 69368b8534bSLuigi Rizzo continue; 69480ad548dSVincenzo Maffione if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) 69568b8534bSLuigi Rizzo continue; 69668b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 69768b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 69868b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 69968b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 70068b8534bSLuigi Rizzo if (verbose) 70168b8534bSLuigi Rizzo D("source hwaddr %s", buf); 70268b8534bSLuigi Rizzo break; 70368b8534bSLuigi Rizzo } 70468b8534bSLuigi Rizzo freeifaddrs(ifaphead); 70568b8534bSLuigi Rizzo return ifap ? 0 : 1; 70668b8534bSLuigi Rizzo } 70768b8534bSLuigi Rizzo 70868b8534bSLuigi Rizzo 70968b8534bSLuigi Rizzo /* set the thread affinity. */ 71068b8534bSLuigi Rizzo static int 71168b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 71268b8534bSLuigi Rizzo { 71368b8534bSLuigi Rizzo cpuset_t cpumask; 71468b8534bSLuigi Rizzo 71568b8534bSLuigi Rizzo if (i == -1) 71668b8534bSLuigi Rizzo return 0; 71768b8534bSLuigi Rizzo 71868b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 71968b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 72068b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 72168b8534bSLuigi Rizzo 72268b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 72317885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 72468b8534bSLuigi Rizzo return 1; 72568b8534bSLuigi Rizzo } 72668b8534bSLuigi Rizzo return 0; 72768b8534bSLuigi Rizzo } 72868b8534bSLuigi Rizzo 72980ad548dSVincenzo Maffione 73068b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 73180ad548dSVincenzo Maffione static uint32_t 732f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 73368b8534bSLuigi Rizzo { 73468b8534bSLuigi Rizzo const uint8_t *addr = data; 735f8e4e36aSLuigi Rizzo uint32_t i; 73668b8534bSLuigi Rizzo 737f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 738f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 7397eb32dc8SVincenzo Maffione sum += (uint16_t)ntohs(*((const uint16_t *)(addr + i))); 740f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 741f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 742f8e4e36aSLuigi Rizzo } 743f8e4e36aSLuigi Rizzo /* 744f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 745f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 746f8e4e36aSLuigi Rizzo * the high byte. 747f8e4e36aSLuigi Rizzo */ 748f8e4e36aSLuigi Rizzo if (i < len) { 749f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 750f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 751f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 752f8e4e36aSLuigi Rizzo } 753f8e4e36aSLuigi Rizzo return sum; 75468b8534bSLuigi Rizzo } 75568b8534bSLuigi Rizzo 75680ad548dSVincenzo Maffione static uint16_t 75780ad548dSVincenzo Maffione wrapsum(uint32_t sum) 758f8e4e36aSLuigi Rizzo { 759f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 760f8e4e36aSLuigi Rizzo return (htons(sum)); 76168b8534bSLuigi Rizzo } 76268b8534bSLuigi Rizzo 763b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 764b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 765b303f675SLuigi Rizzo */ 766b303f675SLuigi Rizzo static void 76737e3a6d3SLuigi Rizzo dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) 768b303f675SLuigi Rizzo { 769b303f675SLuigi Rizzo char buf[128]; 770b303f675SLuigi Rizzo int i, j, i0; 77137e3a6d3SLuigi Rizzo const unsigned char *p = (const unsigned char *)_p; 772b303f675SLuigi Rizzo 773b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 774b303f675SLuigi Rizzo 775ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 776ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 777ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 778b303f675SLuigi Rizzo /* hexdump routine */ 779b303f675SLuigi Rizzo for (i = 0; i < len; ) { 780b797f66cSConrad Meyer memset(buf, ' ', sizeof(buf)); 781b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 782b303f675SLuigi Rizzo i0 = i; 783b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 784b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 785b303f675SLuigi Rizzo i = i0; 786b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 787b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 788b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 789b303f675SLuigi Rizzo printf("%s\n", buf); 790b303f675SLuigi Rizzo } 791b303f675SLuigi Rizzo } 792b303f675SLuigi Rizzo 79368b8534bSLuigi Rizzo /* 79468b8534bSLuigi Rizzo * Fill a packet with some payload. 795f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 796f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 79768b8534bSLuigi Rizzo */ 798f8e4e36aSLuigi Rizzo #ifdef __linux__ 799f8e4e36aSLuigi Rizzo #define uh_sport source 800f8e4e36aSLuigi Rizzo #define uh_dport dest 801f8e4e36aSLuigi Rizzo #define uh_ulen len 802f8e4e36aSLuigi Rizzo #define uh_sum check 803f8e4e36aSLuigi Rizzo #endif /* linux */ 804b303f675SLuigi Rizzo 80527bf5dd3SVincenzo Maffione static uint16_t 80627bf5dd3SVincenzo Maffione new_ip_sum(uint16_t ip_sum, uint32_t oaddr, uint32_t naddr) 80727bf5dd3SVincenzo Maffione { 80827bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 80927bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 81027bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 81127bf5dd3SVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 81227bf5dd3SVincenzo Maffione return ip_sum; 81327bf5dd3SVincenzo Maffione } 81427bf5dd3SVincenzo Maffione 81527bf5dd3SVincenzo Maffione static uint16_t 81627bf5dd3SVincenzo Maffione new_udp_sum(uint16_t udp_sum, uint16_t oport, uint16_t nport) 81727bf5dd3SVincenzo Maffione { 81827bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 81927bf5dd3SVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 82027bf5dd3SVincenzo Maffione return udp_sum; 82127bf5dd3SVincenzo Maffione } 82227bf5dd3SVincenzo Maffione 82327bf5dd3SVincenzo Maffione 824ce3ee1e7SLuigi Rizzo static void 82580ad548dSVincenzo Maffione update_ip(struct pkt *pkt, struct targ *t) 826ce3ee1e7SLuigi Rizzo { 82780ad548dSVincenzo Maffione struct glob_arg *g = t->g; 82880ad548dSVincenzo Maffione struct ip ip; 82980ad548dSVincenzo Maffione struct udphdr udp; 83080ad548dSVincenzo Maffione uint32_t oaddr, naddr; 83180ad548dSVincenzo Maffione uint16_t oport, nport; 83227bf5dd3SVincenzo Maffione uint16_t ip_sum = 0, udp_sum = 0; 833ce3ee1e7SLuigi Rizzo 83480ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 83580ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); 836f2637526SLuigi Rizzo do { 83780ad548dSVincenzo Maffione ip_sum = udp_sum = 0; 83880ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_src.s_addr); 83980ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 84056717743SAdrian Chadd if (g->options & OPT_RANDOM_SRC) { 84180ad548dSVincenzo Maffione ip.ip_src.s_addr = nrand48(t->seed); 84280ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 84380ad548dSVincenzo Maffione naddr = ntohl(ip.ip_src.s_addr); 84480ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 84527bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 84627bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 84727bf5dd3SVincenzo Maffione } else { 84880ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 84980ad548dSVincenzo Maffione nport = oport + 1; 85080ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 85127bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 852f2637526SLuigi Rizzo break; 853ce3ee1e7SLuigi Rizzo } 85480ad548dSVincenzo Maffione nport = g->src_ip.port0; 85580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 85680ad548dSVincenzo Maffione if (oaddr < g->src_ip.ipv4.end) { 85780ad548dSVincenzo Maffione naddr = oaddr + 1; 85880ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 85927bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 860f2637526SLuigi Rizzo break; 861ce3ee1e7SLuigi Rizzo } 86280ad548dSVincenzo Maffione naddr = g->src_ip.ipv4.start; 86380ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 86427bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 86580ad548dSVincenzo Maffione } 86627bf5dd3SVincenzo Maffione 86780ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_dst.s_addr); 86880ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 86980ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 87080ad548dSVincenzo Maffione ip.ip_dst.s_addr = nrand48(t->seed); 87180ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 87280ad548dSVincenzo Maffione naddr = ntohl(ip.ip_dst.s_addr); 87380ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 87427bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 87527bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 87627bf5dd3SVincenzo Maffione } else { 87780ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 87880ad548dSVincenzo Maffione nport = oport + 1; 87980ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88027bf5dd3SVincenzo Maffione udp_sum = new_udp_sum(udp_sum, oport, nport); 88180ad548dSVincenzo Maffione break; 88280ad548dSVincenzo Maffione } 88380ad548dSVincenzo Maffione nport = g->dst_ip.port0; 88480ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 88580ad548dSVincenzo Maffione if (oaddr < g->dst_ip.ipv4.end) { 88680ad548dSVincenzo Maffione naddr = oaddr + 1; 88780ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 88827bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 88980ad548dSVincenzo Maffione break; 89080ad548dSVincenzo Maffione } 89180ad548dSVincenzo Maffione naddr = g->dst_ip.ipv4.start; 89280ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 89327bf5dd3SVincenzo Maffione ip_sum = new_ip_sum(ip_sum, oaddr, naddr); 89427bf5dd3SVincenzo Maffione } 89580ad548dSVincenzo Maffione } while (0); 89680ad548dSVincenzo Maffione /* update checksums */ 89780ad548dSVincenzo Maffione if (udp_sum != 0) 89880ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); 89980ad548dSVincenzo Maffione if (ip_sum != 0) { 90080ad548dSVincenzo Maffione ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); 90180ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); 90280ad548dSVincenzo Maffione } 90380ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 90480ad548dSVincenzo Maffione memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); 905ce3ee1e7SLuigi Rizzo } 906ce3ee1e7SLuigi Rizzo 90780ad548dSVincenzo Maffione #ifndef s6_addr16 90880ad548dSVincenzo Maffione #define s6_addr16 __u6_addr.__u6_addr16 90980ad548dSVincenzo Maffione #endif 91080ad548dSVincenzo Maffione static void 91180ad548dSVincenzo Maffione update_ip6(struct pkt *pkt, struct targ *t) 91280ad548dSVincenzo Maffione { 91380ad548dSVincenzo Maffione struct glob_arg *g = t->g; 91480ad548dSVincenzo Maffione struct ip6_hdr ip6; 91580ad548dSVincenzo Maffione struct udphdr udp; 91680ad548dSVincenzo Maffione uint16_t udp_sum; 91780ad548dSVincenzo Maffione uint16_t oaddr, naddr; 91880ad548dSVincenzo Maffione uint16_t oport, nport; 91980ad548dSVincenzo Maffione uint8_t group; 92080ad548dSVincenzo Maffione 92180ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); 92280ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); 92380ad548dSVincenzo Maffione do { 92480ad548dSVincenzo Maffione udp_sum = 0; 92580ad548dSVincenzo Maffione group = g->src_ip.ipv6.sgroup; 92680ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); 92780ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 92880ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_SRC) { 92980ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = nrand48(t->seed); 93080ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 93180ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_src.s6_addr16[group]); 93280ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 93380ad548dSVincenzo Maffione break; 93480ad548dSVincenzo Maffione } 93580ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 93680ad548dSVincenzo Maffione nport = oport + 1; 93780ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 93880ad548dSVincenzo Maffione break; 93980ad548dSVincenzo Maffione } 94080ad548dSVincenzo Maffione nport = g->src_ip.port0; 94180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 94280ad548dSVincenzo Maffione if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { 94380ad548dSVincenzo Maffione naddr = oaddr + 1; 94480ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 94580ad548dSVincenzo Maffione break; 94680ad548dSVincenzo Maffione } 94780ad548dSVincenzo Maffione naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); 94880ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 94927bf5dd3SVincenzo Maffione 95080ad548dSVincenzo Maffione /* update checksums if needed */ 95180ad548dSVincenzo Maffione if (oaddr != naddr) 95280ad548dSVincenzo Maffione udp_sum = cksum_add(~oaddr, naddr); 95380ad548dSVincenzo Maffione if (oport != nport) 95480ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 95580ad548dSVincenzo Maffione cksum_add(~oport, nport)); 95627bf5dd3SVincenzo Maffione 95780ad548dSVincenzo Maffione group = g->dst_ip.ipv6.egroup; 95880ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 95980ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 96080ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 96180ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed); 96280ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 96380ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 96480ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 96580ad548dSVincenzo Maffione break; 96680ad548dSVincenzo Maffione } 96780ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 96880ad548dSVincenzo Maffione nport = oport + 1; 96980ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97080ad548dSVincenzo Maffione break; 97180ad548dSVincenzo Maffione } 97280ad548dSVincenzo Maffione nport = g->dst_ip.port0; 97380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 97480ad548dSVincenzo Maffione if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { 97580ad548dSVincenzo Maffione naddr = oaddr + 1; 97680ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 97780ad548dSVincenzo Maffione break; 97880ad548dSVincenzo Maffione } 97980ad548dSVincenzo Maffione naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); 98080ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 98180ad548dSVincenzo Maffione } while (0); 98280ad548dSVincenzo Maffione /* update checksums */ 98380ad548dSVincenzo Maffione if (oaddr != naddr) 98480ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 98580ad548dSVincenzo Maffione cksum_add(~oaddr, naddr)); 98680ad548dSVincenzo Maffione if (oport != nport) 98780ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 98880ad548dSVincenzo Maffione cksum_add(~oport, nport)); 98980ad548dSVincenzo Maffione if (udp_sum != 0) 99080ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); 99180ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 99280ad548dSVincenzo Maffione memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); 99380ad548dSVincenzo Maffione } 99480ad548dSVincenzo Maffione 99580ad548dSVincenzo Maffione static void 99680ad548dSVincenzo Maffione update_addresses(struct pkt *pkt, struct targ *t) 99780ad548dSVincenzo Maffione { 99880ad548dSVincenzo Maffione 99980ad548dSVincenzo Maffione if (t->g->af == AF_INET) 100080ad548dSVincenzo Maffione update_ip(pkt, t); 100180ad548dSVincenzo Maffione else 100280ad548dSVincenzo Maffione update_ip6(pkt, t); 100380ad548dSVincenzo Maffione } 1004ce3ee1e7SLuigi Rizzo /* 1005ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 1006ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 1007ce3ee1e7SLuigi Rizzo */ 100868b8534bSLuigi Rizzo static void 100968b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 101068b8534bSLuigi Rizzo { 101168b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 101268b8534bSLuigi Rizzo struct ether_header *eh; 101380ad548dSVincenzo Maffione struct ip6_hdr ip6; 101480ad548dSVincenzo Maffione struct ip ip; 101580ad548dSVincenzo Maffione struct udphdr udp; 101680ad548dSVincenzo Maffione void *udp_ptr; 101780ad548dSVincenzo Maffione uint16_t paylen; 101880ad548dSVincenzo Maffione uint32_t csum = 0; 1019b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 1020ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 1021f2637526SLuigi Rizzo int i, l0 = strlen(payload); 102268b8534bSLuigi Rizzo 102337e3a6d3SLuigi Rizzo #ifndef NO_PCAP 1024f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 1025f284c737SGeorge V. Neville-Neil pcap_t *file; 1026f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 1027f284c737SGeorge V. Neville-Neil const unsigned char *packet; 1028f284c737SGeorge V. Neville-Neil 1029f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 1030f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 1031f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 1032f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 1033f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 1034f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1035f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 1036f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 1037f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1038f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 1039f284c737SGeorge V. Neville-Neil D("out of memory"); 1040f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 1041f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 1042f284c737SGeorge V. Neville-Neil pcap_close(file); 1043f284c737SGeorge V. Neville-Neil return; 1044f284c737SGeorge V. Neville-Neil } 104537e3a6d3SLuigi Rizzo #endif 1046f284c737SGeorge V. Neville-Neil 104780ad548dSVincenzo Maffione paylen = targ->g->pkt_size - sizeof(*eh) - 104880ad548dSVincenzo Maffione (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); 104980ad548dSVincenzo Maffione 1050ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 1051f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 1052f2637526SLuigi Rizzo if (l0 > paylen - i) 1053f2637526SLuigi Rizzo l0 = paylen - i; // last round 105480ad548dSVincenzo Maffione bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0); 105568b8534bSLuigi Rizzo } 105680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[i - 1] = '\0'; 1057f8e4e36aSLuigi Rizzo 1058ce3ee1e7SLuigi Rizzo /* prepare the headers */ 105968b8534bSLuigi Rizzo eh = &pkt->eh; 1060f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 1061f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 106280ad548dSVincenzo Maffione 106380ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 106468b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 106580ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 106680ad548dSVincenzo Maffione udp_ptr = &pkt->ipv4.udp; 106780ad548dSVincenzo Maffione ip.ip_v = IPVERSION; 106880ad548dSVincenzo Maffione ip.ip_hl = sizeof(ip) >> 2; 106980ad548dSVincenzo Maffione ip.ip_id = 0; 107080ad548dSVincenzo Maffione ip.ip_tos = IPTOS_LOWDELAY; 107180ad548dSVincenzo Maffione ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); 107280ad548dSVincenzo Maffione ip.ip_id = 0; 107380ad548dSVincenzo Maffione ip.ip_off = htons(IP_DF); /* Don't fragment */ 107480ad548dSVincenzo Maffione ip.ip_ttl = IPDEFTTL; 107580ad548dSVincenzo Maffione ip.ip_p = IPPROTO_UDP; 107680ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); 107780ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); 107880ad548dSVincenzo Maffione ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); 107980ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 108080ad548dSVincenzo Maffione } else { 108180ad548dSVincenzo Maffione eh->ether_type = htons(ETHERTYPE_IPV6); 108280ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); 108380ad548dSVincenzo Maffione udp_ptr = &pkt->ipv6.udp; 108480ad548dSVincenzo Maffione ip6.ip6_flow = 0; 108580ad548dSVincenzo Maffione ip6.ip6_plen = htons(paylen); 108680ad548dSVincenzo Maffione ip6.ip6_vfc = IPV6_VERSION; 108780ad548dSVincenzo Maffione ip6.ip6_nxt = IPPROTO_UDP; 108880ad548dSVincenzo Maffione ip6.ip6_hlim = IPV6_DEFHLIM; 108980ad548dSVincenzo Maffione ip6.ip6_src = targ->g->src_ip.ipv6.start; 109080ad548dSVincenzo Maffione ip6.ip6_dst = targ->g->dst_ip.ipv6.start; 109180ad548dSVincenzo Maffione } 109280ad548dSVincenzo Maffione memcpy(&udp, udp_ptr, sizeof(udp)); 109380ad548dSVincenzo Maffione 109480ad548dSVincenzo Maffione udp.uh_sport = htons(targ->g->src_ip.port0); 109580ad548dSVincenzo Maffione udp.uh_dport = htons(targ->g->dst_ip.port0); 109680ad548dSVincenzo Maffione udp.uh_ulen = htons(paylen); 109780ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 109880ad548dSVincenzo Maffione /* Magic: taken from sbin/dhclient/packet.c */ 109980ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 110080ad548dSVincenzo Maffione checksum(&udp, sizeof(udp), /* udp header */ 110180ad548dSVincenzo Maffione checksum(pkt->ipv4.body, /* udp payload */ 110280ad548dSVincenzo Maffione paylen - sizeof(udp), 110380ad548dSVincenzo Maffione checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 110480ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv4.ip.ip_src), 110580ad548dSVincenzo Maffione IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); 110680ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 110780ad548dSVincenzo Maffione } else { 110880ad548dSVincenzo Maffione /* Save part of pseudo header checksum into csum */ 110980ad548dSVincenzo Maffione csum = IPPROTO_UDP << 24; 111080ad548dSVincenzo Maffione csum = checksum(&csum, sizeof(csum), paylen); 111180ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 111280ad548dSVincenzo Maffione checksum(udp_ptr, sizeof(udp), /* udp header */ 111380ad548dSVincenzo Maffione checksum(pkt->ipv6.body, /* udp payload */ 111480ad548dSVincenzo Maffione paylen - sizeof(udp), 111580ad548dSVincenzo Maffione checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 111680ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); 111780ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 111880ad548dSVincenzo Maffione } 111980ad548dSVincenzo Maffione memcpy(udp_ptr, &udp, sizeof(udp)); 112017885a7bSLuigi Rizzo 112117885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 1122b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 112368b8534bSLuigi Rizzo } 112468b8534bSLuigi Rizzo 11254bf50f18SLuigi Rizzo static void 112637e3a6d3SLuigi Rizzo get_vnet_hdr_len(struct glob_arg *g) 11274bf50f18SLuigi Rizzo { 11284bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11294bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 113037e3a6d3SLuigi Rizzo int err; 113137e3a6d3SLuigi Rizzo 11324bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11334bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET; 11344bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11354bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11364bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11374bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 113837e3a6d3SLuigi Rizzo if (err) { 113937e3a6d3SLuigi Rizzo D("Unable to get virtio-net header length"); 114037e3a6d3SLuigi Rizzo return; 114137e3a6d3SLuigi Rizzo } 114237e3a6d3SLuigi Rizzo 11434bfe1a4fSVincenzo Maffione g->virt_header = ph.nr_hdr_len; 114437e3a6d3SLuigi Rizzo if (g->virt_header) { 114537e3a6d3SLuigi Rizzo D("Port requires virtio-net header, length = %d", 114637e3a6d3SLuigi Rizzo g->virt_header); 114737e3a6d3SLuigi Rizzo } 114837e3a6d3SLuigi Rizzo } 114937e3a6d3SLuigi Rizzo 115037e3a6d3SLuigi Rizzo static void 115137e3a6d3SLuigi Rizzo set_vnet_hdr_len(struct glob_arg *g) 115237e3a6d3SLuigi Rizzo { 115337e3a6d3SLuigi Rizzo int err, l = g->virt_header; 11544bfe1a4fSVincenzo Maffione struct nmreq_header hdr; 11554bfe1a4fSVincenzo Maffione struct nmreq_port_hdr ph; 11564bf50f18SLuigi Rizzo 11574bf50f18SLuigi Rizzo if (l == 0) 11584bf50f18SLuigi Rizzo return; 11594bf50f18SLuigi Rizzo 11604bfe1a4fSVincenzo Maffione hdr = g->nmd->hdr; /* copy name and version */ 11614bfe1a4fSVincenzo Maffione hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET; 11624bfe1a4fSVincenzo Maffione hdr.nr_options = 0; 11634bfe1a4fSVincenzo Maffione memset(&ph, 0, sizeof(ph)); 11644bfe1a4fSVincenzo Maffione hdr.nr_body = (uintptr_t)&ph; 11654bfe1a4fSVincenzo Maffione err = ioctl(g->main_fd, NIOCCTRL, &hdr); 11664bf50f18SLuigi Rizzo if (err) { 116737e3a6d3SLuigi Rizzo D("Unable to set virtio-net header length %d", l); 11684bf50f18SLuigi Rizzo } 11694bf50f18SLuigi Rizzo } 117068b8534bSLuigi Rizzo 117168b8534bSLuigi Rizzo /* 117268b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 117368b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 117468b8534bSLuigi Rizzo * an interrupt when done. 117568b8534bSLuigi Rizzo */ 117668b8534bSLuigi Rizzo static int 117717885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 117880ad548dSVincenzo Maffione int size, struct targ *t, u_int count, int options) 117968b8534bSLuigi Rizzo { 1180406e7723SVincenzo Maffione u_int n, sent, head = ring->head; 118180ad548dSVincenzo Maffione u_int frags = t->frags; 118280ad548dSVincenzo Maffione u_int frag_size = t->frag_size; 1183406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 118468b8534bSLuigi Rizzo 118517885a7bSLuigi Rizzo n = nm_ring_space(ring); 118699fb123fSLuigi Rizzo #if 0 118799fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 118868b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 1189406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 119068b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 119168b8534bSLuigi Rizzo 1192f2637526SLuigi Rizzo __builtin_prefetch(p); 1193406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 119499fb123fSLuigi Rizzo } 1195406e7723SVincenzo Maffione head = ring->head; 119699fb123fSLuigi Rizzo } 119799fb123fSLuigi Rizzo #endif 119880ad548dSVincenzo Maffione for (sent = 0; sent < count && n >= frags; sent++, n--) { 119980ad548dSVincenzo Maffione char *p; 120080ad548dSVincenzo Maffione int buf_changed; 120180ad548dSVincenzo Maffione u_int tosend = size; 120280ad548dSVincenzo Maffione 1203406e7723SVincenzo Maffione slot = &ring->slot[head]; 120480ad548dSVincenzo Maffione p = NETMAP_BUF(ring, slot->buf_idx); 120580ad548dSVincenzo Maffione buf_changed = slot->flags & NS_BUF_CHANGED; 120699fb123fSLuigi Rizzo 1207b303f675SLuigi Rizzo slot->flags = 0; 120837e3a6d3SLuigi Rizzo if (options & OPT_RUBBISH) { 120937e3a6d3SLuigi Rizzo /* do nothing */ 121037e3a6d3SLuigi Rizzo } else if (options & OPT_INDIRECT) { 1211b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 121237e3a6d3SLuigi Rizzo slot->ptr = (uint64_t)((uintptr_t)frame); 121380ad548dSVincenzo Maffione } else if (frags > 1) { 121480ad548dSVincenzo Maffione u_int i; 121580ad548dSVincenzo Maffione const char *f = frame; 121680ad548dSVincenzo Maffione char *fp = p; 121780ad548dSVincenzo Maffione for (i = 0; i < frags - 1; i++) { 121880ad548dSVincenzo Maffione memcpy(fp, f, frag_size); 121980ad548dSVincenzo Maffione slot->len = frag_size; 122080ad548dSVincenzo Maffione slot->flags = NS_MOREFRAG; 122180ad548dSVincenzo Maffione if (options & OPT_DUMP) 1222406e7723SVincenzo Maffione dump_payload(fp, frag_size, ring, head); 122380ad548dSVincenzo Maffione tosend -= frag_size; 122480ad548dSVincenzo Maffione f += frag_size; 1225406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 1226406e7723SVincenzo Maffione slot = &ring->slot[head]; 122780ad548dSVincenzo Maffione fp = NETMAP_BUF(ring, slot->buf_idx); 122880ad548dSVincenzo Maffione } 122980ad548dSVincenzo Maffione n -= (frags - 1); 123080ad548dSVincenzo Maffione p = fp; 123180ad548dSVincenzo Maffione slot->flags = 0; 123280ad548dSVincenzo Maffione memcpy(p, f, tosend); 123380ad548dSVincenzo Maffione update_addresses(pkt, t); 123480ad548dSVincenzo Maffione } else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) { 123580ad548dSVincenzo Maffione if (options & OPT_COPY) 1236f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 123780ad548dSVincenzo Maffione else 123817885a7bSLuigi Rizzo memcpy(p, frame, size); 123980ad548dSVincenzo Maffione update_addresses(pkt, t); 1240ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 1241f2637526SLuigi Rizzo __builtin_prefetch(p); 1242ce3ee1e7SLuigi Rizzo } 124380ad548dSVincenzo Maffione slot->len = tosend; 1244ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 1245406e7723SVincenzo Maffione dump_payload(p, tosend, ring, head); 1246406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 124768b8534bSLuigi Rizzo } 124880ad548dSVincenzo Maffione if (sent) { 124980ad548dSVincenzo Maffione slot->flags |= NS_REPORT; 1250406e7723SVincenzo Maffione ring->head = ring->cur = head; 125180ad548dSVincenzo Maffione } 125280ad548dSVincenzo Maffione if (sent < count) { 125380ad548dSVincenzo Maffione /* tell netmap that we need more slots */ 125480ad548dSVincenzo Maffione ring->cur = ring->tail; 125580ad548dSVincenzo Maffione } 125668b8534bSLuigi Rizzo 125768b8534bSLuigi Rizzo return (sent); 125868b8534bSLuigi Rizzo } 125968b8534bSLuigi Rizzo 1260f8e4e36aSLuigi Rizzo /* 126137e3a6d3SLuigi Rizzo * Index of the highest bit set 126237e3a6d3SLuigi Rizzo */ 12637eb32dc8SVincenzo Maffione static uint32_t 126437e3a6d3SLuigi Rizzo msb64(uint64_t x) 126537e3a6d3SLuigi Rizzo { 126637e3a6d3SLuigi Rizzo uint64_t m = 1ULL << 63; 126737e3a6d3SLuigi Rizzo int i; 126837e3a6d3SLuigi Rizzo 126937e3a6d3SLuigi Rizzo for (i = 63; i >= 0; i--, m >>=1) 127037e3a6d3SLuigi Rizzo if (m & x) 127137e3a6d3SLuigi Rizzo return i; 127237e3a6d3SLuigi Rizzo return 0; 127337e3a6d3SLuigi Rizzo } 127437e3a6d3SLuigi Rizzo 127537e3a6d3SLuigi Rizzo /* 127680ad548dSVincenzo Maffione * wait until ts, either busy or sleeping if more than 1ms. 127780ad548dSVincenzo Maffione * Return wakeup time. 127880ad548dSVincenzo Maffione */ 127980ad548dSVincenzo Maffione static struct timespec 128080ad548dSVincenzo Maffione wait_time(struct timespec ts) 128180ad548dSVincenzo Maffione { 128280ad548dSVincenzo Maffione for (;;) { 128380ad548dSVincenzo Maffione struct timespec w, cur; 128480ad548dSVincenzo Maffione clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 128580ad548dSVincenzo Maffione w = timespec_sub(ts, cur); 128680ad548dSVincenzo Maffione if (w.tv_sec < 0) 128780ad548dSVincenzo Maffione return cur; 128880ad548dSVincenzo Maffione else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 128980ad548dSVincenzo Maffione poll(NULL, 0, 1); 129080ad548dSVincenzo Maffione } 129180ad548dSVincenzo Maffione } 129280ad548dSVincenzo Maffione 129380ad548dSVincenzo Maffione /* 1294f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 1295f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 1296f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 1297f8e4e36aSLuigi Rizzo */ 1298f8e4e36aSLuigi Rizzo 129968b8534bSLuigi Rizzo static void * 130080ad548dSVincenzo Maffione ping_body(void *data) 130168b8534bSLuigi Rizzo { 130268b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1303f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1304f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 130580ad548dSVincenzo Maffione int i, m, rx = 0; 130617885a7bSLuigi Rizzo void *frame; 130717885a7bSLuigi Rizzo int size; 1308f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 130980ad548dSVincenzo Maffione struct timespec nexttime = {0, 0}; /* silence compiler */ 131037e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 131137e3a6d3SLuigi Rizzo uint64_t count = 0, t_cur, t_min = ~0, av = 0; 131280ad548dSVincenzo Maffione uint64_t g_min = ~0, g_av = 0; 131337e3a6d3SLuigi Rizzo uint64_t buckets[64]; /* bins for delays, ns */ 131480ad548dSVincenzo Maffione int rate_limit = targ->g->tx_rate, tosend = 0; 131517885a7bSLuigi Rizzo 131680ad548dSVincenzo Maffione frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header; 131717885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1318e5ecae38SEd Maste 131937e3a6d3SLuigi Rizzo 1320f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1321f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 1322f8e4e36aSLuigi Rizzo return NULL; 1323f95a30bdSEd Maste } 1324f8e4e36aSLuigi Rizzo 132537e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1326f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 132717885a7bSLuigi Rizzo now = last_print; 132880ad548dSVincenzo Maffione if (rate_limit) { 132980ad548dSVincenzo Maffione targ->tic = timespec_add(now, (struct timespec){2,0}); 133080ad548dSVincenzo Maffione targ->tic.tv_nsec = 0; 133180ad548dSVincenzo Maffione wait_time(targ->tic); 133280ad548dSVincenzo Maffione nexttime = targ->tic; 133380ad548dSVincenzo Maffione } 133437e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 133580ad548dSVincenzo Maffione struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1336f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 1337f8e4e36aSLuigi Rizzo char *p; 133880ad548dSVincenzo Maffione int rv; 133980ad548dSVincenzo Maffione uint64_t limit, event = 0; 134080ad548dSVincenzo Maffione 134180ad548dSVincenzo Maffione if (rate_limit && tosend <= 0) { 134280ad548dSVincenzo Maffione tosend = targ->g->burst; 134380ad548dSVincenzo Maffione nexttime = timespec_add(nexttime, targ->g->tx_period); 134480ad548dSVincenzo Maffione wait_time(nexttime); 134580ad548dSVincenzo Maffione } 134680ad548dSVincenzo Maffione 134780ad548dSVincenzo Maffione limit = rate_limit ? tosend : targ->g->burst; 134880ad548dSVincenzo Maffione if (n > 0 && n - sent < limit) 134980ad548dSVincenzo Maffione limit = n - sent; 135080ad548dSVincenzo Maffione for (m = 0; (unsigned)m < limit; m++) { 1351406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 135217885a7bSLuigi Rizzo slot->len = size; 1353f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1354f8e4e36aSLuigi Rizzo 135517885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 1356f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 135780ad548dSVincenzo Maffione break; 1358f8e4e36aSLuigi Rizzo } else { 13594bf50f18SLuigi Rizzo struct tstamp *tp; 1360f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 1361f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 1362f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 13634bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13644bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 13654bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 1366f8e4e36aSLuigi Rizzo sent++; 1367406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1368f8e4e36aSLuigi Rizzo } 1369f8e4e36aSLuigi Rizzo } 137080ad548dSVincenzo Maffione if (m > 0) 137180ad548dSVincenzo Maffione event++; 137280ad548dSVincenzo Maffione targ->ctr.pkts = sent; 137380ad548dSVincenzo Maffione targ->ctr.bytes = sent*size; 137480ad548dSVincenzo Maffione targ->ctr.events = event; 137580ad548dSVincenzo Maffione if (rate_limit) 137680ad548dSVincenzo Maffione tosend -= m; 137780ad548dSVincenzo Maffione #ifdef BUSYWAIT 137880ad548dSVincenzo Maffione rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); 137980ad548dSVincenzo Maffione if (rv < 0) { 138080ad548dSVincenzo Maffione D("TXSYNC error on queue %d: %s", targ->me, 138117885a7bSLuigi Rizzo strerror(errno)); 138280ad548dSVincenzo Maffione } 138380ad548dSVincenzo Maffione again: 138480ad548dSVincenzo Maffione ioctl(pfd.fd, NIOCRXSYNC, NULL); 138580ad548dSVincenzo Maffione #else 138680ad548dSVincenzo Maffione /* should use a parameter to decide how often to send */ 138780ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 3000)) <= 0) { 138880ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 138980ad548dSVincenzo Maffione (rv ? strerror(errno) : "timeout")); 1390f8e4e36aSLuigi Rizzo continue; 1391f8e4e36aSLuigi Rizzo } 139280ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1393f8e4e36aSLuigi Rizzo /* see what we got back */ 139480ad548dSVincenzo Maffione rx = 0; 139580ad548dSVincenzo Maffione for (i = targ->nmd->first_rx_ring; 139680ad548dSVincenzo Maffione i <= targ->nmd->last_rx_ring; i++) { 1397f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 139817885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 1399f8e4e36aSLuigi Rizzo uint32_t seq; 14004bf50f18SLuigi Rizzo struct tstamp *tp; 140137e3a6d3SLuigi Rizzo int pos; 140237e3a6d3SLuigi Rizzo 1403406e7723SVincenzo Maffione slot = &ring->slot[ring->head]; 1404f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1405f8e4e36aSLuigi Rizzo 1406f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 1407f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 14084bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 14094bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 14104bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 1411f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 1412f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 1413f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1414f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1415f8e4e36aSLuigi Rizzo ts.tv_sec--; 1416f8e4e36aSLuigi Rizzo } 141780ad548dSVincenzo Maffione if (0) D("seq %d/%llu delta %d.%09d", seq, 141880ad548dSVincenzo Maffione (unsigned long long)sent, 1419f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 142037e3a6d3SLuigi Rizzo t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; 142137e3a6d3SLuigi Rizzo if (t_cur < t_min) 142237e3a6d3SLuigi Rizzo t_min = t_cur; 1423f8e4e36aSLuigi Rizzo count ++; 142437e3a6d3SLuigi Rizzo av += t_cur; 142537e3a6d3SLuigi Rizzo pos = msb64(t_cur); 142637e3a6d3SLuigi Rizzo buckets[pos]++; 142737e3a6d3SLuigi Rizzo /* now store it in a bucket */ 1428406e7723SVincenzo Maffione ring->head = ring->cur = nm_ring_next(ring, ring->head); 1429f8e4e36aSLuigi Rizzo rx++; 1430f8e4e36aSLuigi Rizzo } 1431f8e4e36aSLuigi Rizzo } 1432f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1433f8e4e36aSLuigi Rizzo //usleep(100000); 1434f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 1435f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 1436f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1437f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1438f8e4e36aSLuigi Rizzo ts.tv_sec--; 1439f8e4e36aSLuigi Rizzo } 1440f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 144137e3a6d3SLuigi Rizzo D("count %d RTT: min %d av %d ns", 144237e3a6d3SLuigi Rizzo (int)count, (int)t_min, (int)(av/count)); 144380ad548dSVincenzo Maffione int k, j, kmin, off; 144437e3a6d3SLuigi Rizzo char buf[512]; 144537e3a6d3SLuigi Rizzo 144637e3a6d3SLuigi Rizzo for (kmin = 0; kmin < 64; kmin ++) 144737e3a6d3SLuigi Rizzo if (buckets[kmin]) 144837e3a6d3SLuigi Rizzo break; 144937e3a6d3SLuigi Rizzo for (k = 63; k >= kmin; k--) 145037e3a6d3SLuigi Rizzo if (buckets[k]) 145137e3a6d3SLuigi Rizzo break; 145237e3a6d3SLuigi Rizzo buf[0] = '\0'; 145380ad548dSVincenzo Maffione off = 0; 145480ad548dSVincenzo Maffione for (j = kmin; j <= k; j++) { 145580ad548dSVincenzo Maffione off += sprintf(buf + off, " %5d", (int)buckets[j]); 145680ad548dSVincenzo Maffione } 145737e3a6d3SLuigi Rizzo D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf); 145837e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1459f8e4e36aSLuigi Rizzo count = 0; 146080ad548dSVincenzo Maffione g_av += av; 1461f8e4e36aSLuigi Rizzo av = 0; 146280ad548dSVincenzo Maffione if (t_min < g_min) 146380ad548dSVincenzo Maffione g_min = t_min; 146437e3a6d3SLuigi Rizzo t_min = ~0; 1465f8e4e36aSLuigi Rizzo last_print = now; 1466f8e4e36aSLuigi Rizzo } 146780ad548dSVincenzo Maffione #ifdef BUSYWAIT 146880ad548dSVincenzo Maffione if (rx < m && ts.tv_sec <= 3 && !targ->cancel) 146980ad548dSVincenzo Maffione goto again; 147080ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1471f8e4e36aSLuigi Rizzo } 147237e3a6d3SLuigi Rizzo 147380ad548dSVincenzo Maffione if (sent > 0) { 147480ad548dSVincenzo Maffione D("RTT over %llu packets: min %d av %d ns", 147580ad548dSVincenzo Maffione (long long unsigned)sent, (int)g_min, 147680ad548dSVincenzo Maffione (int)((double)g_av/sent)); 147780ad548dSVincenzo Maffione } 147880ad548dSVincenzo Maffione targ->completed = 1; 147980ad548dSVincenzo Maffione 148037e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 148137e3a6d3SLuigi Rizzo targ->used = 0; 148237e3a6d3SLuigi Rizzo 1483f8e4e36aSLuigi Rizzo return NULL; 1484f8e4e36aSLuigi Rizzo } 1485f8e4e36aSLuigi Rizzo 1486f8e4e36aSLuigi Rizzo 1487f8e4e36aSLuigi Rizzo /* 1488f8e4e36aSLuigi Rizzo * reply to ping requests 1489f8e4e36aSLuigi Rizzo */ 1490f8e4e36aSLuigi Rizzo static void * 149180ad548dSVincenzo Maffione pong_body(void *data) 1492f8e4e36aSLuigi Rizzo { 1493f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1494f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1495f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 1496f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 149737e3a6d3SLuigi Rizzo int i, rx = 0; 149837e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 1499f8e4e36aSLuigi Rizzo 1500f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1501f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 1502f8e4e36aSLuigi Rizzo return NULL; 1503f8e4e36aSLuigi Rizzo } 150480ad548dSVincenzo Maffione if (n > 0) 150580ad548dSVincenzo Maffione D("understood ponger %llu but don't know how to do it", 150680ad548dSVincenzo Maffione (unsigned long long)n); 150737e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 1508406e7723SVincenzo Maffione uint32_t txhead, txavail; 1509f8e4e36aSLuigi Rizzo //#define BUSYWAIT 1510f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1511f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 1512f8e4e36aSLuigi Rizzo #else 151380ad548dSVincenzo Maffione int rv; 151480ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 1000)) <= 0) { 151580ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 151680ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1517f8e4e36aSLuigi Rizzo continue; 1518f8e4e36aSLuigi Rizzo } 1519f8e4e36aSLuigi Rizzo #endif 152080ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1521406e7723SVincenzo Maffione txhead = txring->head; 152217885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 1523f8e4e36aSLuigi Rizzo /* see what we got back */ 1524f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 1525f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 152617885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 1527f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 1528406e7723SVincenzo Maffione uint32_t head = rxring->head; 1529406e7723SVincenzo Maffione struct netmap_slot *slot = &rxring->slot[head]; 1530f8e4e36aSLuigi Rizzo char *src, *dst; 1531f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 1532f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 1533406e7723SVincenzo Maffione rxring->head = rxring->cur = nm_ring_next(rxring, head); 1534f8e4e36aSLuigi Rizzo rx++; 1535f8e4e36aSLuigi Rizzo if (txavail == 0) 1536f8e4e36aSLuigi Rizzo continue; 1537f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 1538406e7723SVincenzo Maffione txring->slot[txhead].buf_idx); 1539f8e4e36aSLuigi Rizzo /* copy... */ 1540f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 1541f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 1542f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 154380ad548dSVincenzo Maffione /* swap source and destination MAC */ 1544f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 1545f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 1546f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 1547f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 1548f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 1549f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 1550406e7723SVincenzo Maffione txring->slot[txhead].len = slot->len; 1551406e7723SVincenzo Maffione txhead = nm_ring_next(txring, txhead); 1552f8e4e36aSLuigi Rizzo txavail--; 1553f8e4e36aSLuigi Rizzo sent++; 1554f8e4e36aSLuigi Rizzo } 1555f8e4e36aSLuigi Rizzo } 1556406e7723SVincenzo Maffione txring->head = txring->cur = txhead; 155737e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 1558f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1559f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 1560f8e4e36aSLuigi Rizzo #endif 1561f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1562f8e4e36aSLuigi Rizzo } 156337e3a6d3SLuigi Rizzo 156480ad548dSVincenzo Maffione targ->completed = 1; 156580ad548dSVincenzo Maffione 156637e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 156737e3a6d3SLuigi Rizzo targ->used = 0; 156837e3a6d3SLuigi Rizzo 1569f8e4e36aSLuigi Rizzo return NULL; 1570f8e4e36aSLuigi Rizzo } 1571f8e4e36aSLuigi Rizzo 1572f8e4e36aSLuigi Rizzo 1573f8e4e36aSLuigi Rizzo static void * 1574f8e4e36aSLuigi Rizzo sender_body(void *data) 1575f8e4e36aSLuigi Rizzo { 1576f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1577f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 15784bf50f18SLuigi Rizzo struct netmap_if *nifp; 157937e3a6d3SLuigi Rizzo struct netmap_ring *txring = NULL; 158037e3a6d3SLuigi Rizzo int i; 158137e3a6d3SLuigi Rizzo uint64_t n = targ->g->npackets / targ->g->nthreads; 158237e3a6d3SLuigi Rizzo uint64_t sent = 0; 158337e3a6d3SLuigi Rizzo uint64_t event = 0; 1584f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 158517885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 15861cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 158717885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 158817885a7bSLuigi Rizzo void *frame; 158917885a7bSLuigi Rizzo int size; 159017885a7bSLuigi Rizzo 1591f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 159280ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 159317885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1594f284c737SGeorge V. Neville-Neil } else { 1595f284c737SGeorge V. Neville-Neil frame = targ->frame; 1596f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1597f284c737SGeorge V. Neville-Neil } 1598b303f675SLuigi Rizzo 15994bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 160068b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 160168b8534bSLuigi Rizzo goto quit; 160268b8534bSLuigi Rizzo 160368b8534bSLuigi Rizzo /* main loop.*/ 16041cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 16051cb4c501SLuigi Rizzo if (rate_limit) { 160617885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 16071cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 160817885a7bSLuigi Rizzo wait_time(targ->tic); 16091cb4c501SLuigi Rizzo nexttime = targ->tic; 16101cb4c501SLuigi Rizzo } 1611f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1612f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1613f8e4e36aSLuigi Rizzo 1614f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 161517885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1616f8e4e36aSLuigi Rizzo sent++; 161780ad548dSVincenzo Maffione update_addresses(pkt, targ); 1618f8e4e36aSLuigi Rizzo if (i > 10000) { 161937e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 162037e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 162137e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1622f8e4e36aSLuigi Rizzo i = 0; 1623f8e4e36aSLuigi Rizzo } 1624f8e4e36aSLuigi Rizzo } 1625f2637526SLuigi Rizzo #ifndef NO_PCAP 1626f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1627f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1628f2637526SLuigi Rizzo 1629f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1630f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1631f2637526SLuigi Rizzo sent++; 163280ad548dSVincenzo Maffione update_addresses(pkt, targ); 1633f2637526SLuigi Rizzo if (i > 10000) { 163437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 163537e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 163637e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1637f2637526SLuigi Rizzo i = 0; 1638f2637526SLuigi Rizzo } 1639f2637526SLuigi Rizzo } 1640f2637526SLuigi Rizzo #endif /* NO_PCAP */ 164168b8534bSLuigi Rizzo } else { 16421cb4c501SLuigi Rizzo int tosend = 0; 16439e53f3bdSVincenzo Maffione u_int bufsz, frag_size = targ->g->frag_size; 1644ce3ee1e7SLuigi Rizzo 16454bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 164680ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 164780ad548dSVincenzo Maffione bufsz = txring->nr_buf_size; 16489e53f3bdSVincenzo Maffione if (bufsz < frag_size) 16499e53f3bdSVincenzo Maffione frag_size = bufsz; 165080ad548dSVincenzo Maffione targ->frag_size = targ->g->pkt_size / targ->frags; 16519e53f3bdSVincenzo Maffione if (targ->frag_size > frag_size) { 16529e53f3bdSVincenzo Maffione targ->frags = targ->g->pkt_size / frag_size; 16539e53f3bdSVincenzo Maffione targ->frag_size = frag_size; 16549e53f3bdSVincenzo Maffione if (targ->g->pkt_size % frag_size != 0) 165580ad548dSVincenzo Maffione targ->frags++; 165680ad548dSVincenzo Maffione } 165780ad548dSVincenzo Maffione D("frags %u frag_size %u", targ->frags, targ->frag_size); 1658f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 165980ad548dSVincenzo Maffione int rv; 166068b8534bSLuigi Rizzo 16611cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 16621cb4c501SLuigi Rizzo tosend = targ->g->burst; 166317885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 166417885a7bSLuigi Rizzo wait_time(nexttime); 16651cb4c501SLuigi Rizzo } 16661cb4c501SLuigi Rizzo 166768b8534bSLuigi Rizzo /* 166868b8534bSLuigi Rizzo * wait for available room in the send queue(s) 166968b8534bSLuigi Rizzo */ 167037e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 167180ad548dSVincenzo Maffione (void)rv; 167237e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 167337e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 167437e3a6d3SLuigi Rizzo strerror(errno)); 167537e3a6d3SLuigi Rizzo goto quit; 167637e3a6d3SLuigi Rizzo } 167737e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 167880ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 16793fe77e68SEd Maste if (targ->cancel) 16803fe77e68SEd Maste break; 168180ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 168280ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1683f0ea3689SLuigi Rizzo // goto quit; 168417885a7bSLuigi Rizzo } 1685f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 168637e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 168737e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 168868b8534bSLuigi Rizzo goto quit; 168968b8534bSLuigi Rizzo } 169037e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 169168b8534bSLuigi Rizzo /* 169268b8534bSLuigi Rizzo * scan our queues and send on those with room 169368b8534bSLuigi Rizzo */ 1694f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1695f8e4e36aSLuigi Rizzo D("drop copy"); 169699fb123fSLuigi Rizzo options &= ~OPT_COPY; 1697f8e4e36aSLuigi Rizzo } 1698f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 169937e3a6d3SLuigi Rizzo int m; 170037e3a6d3SLuigi Rizzo uint64_t limit = rate_limit ? tosend : targ->g->burst; 170180ad548dSVincenzo Maffione 170280ad548dSVincenzo Maffione if (n > 0 && n == sent) 170380ad548dSVincenzo Maffione break; 170480ad548dSVincenzo Maffione 1705f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1706f8e4e36aSLuigi Rizzo limit = n - sent; 170768b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 170817885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 170968b8534bSLuigi Rizzo continue; 1710ce3ee1e7SLuigi Rizzo 171180ad548dSVincenzo Maffione if (targ->g->pkt_min_size > 0) { 171280ad548dSVincenzo Maffione size = nrand48(targ->seed) % 171380ad548dSVincenzo Maffione (targ->g->pkt_size - targ->g->pkt_min_size) + 171480ad548dSVincenzo Maffione targ->g->pkt_min_size; 171580ad548dSVincenzo Maffione } 171680ad548dSVincenzo Maffione m = send_packets(txring, pkt, frame, size, targ, 171780ad548dSVincenzo Maffione limit, options); 171880ad548dSVincenzo Maffione ND("limit %lu tail %d m %d", 171980ad548dSVincenzo Maffione limit, txring->tail, m); 172068b8534bSLuigi Rizzo sent += m; 172137e3a6d3SLuigi Rizzo if (m > 0) //XXX-ste: can m be 0? 172237e3a6d3SLuigi Rizzo event++; 172337e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 172480ad548dSVincenzo Maffione targ->ctr.bytes += m*size; 172537e3a6d3SLuigi Rizzo targ->ctr.events = event; 1726ce3ee1e7SLuigi Rizzo if (rate_limit) { 1727ce3ee1e7SLuigi Rizzo tosend -= m; 1728ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1729ce3ee1e7SLuigi Rizzo break; 1730ce3ee1e7SLuigi Rizzo } 173168b8534bSLuigi Rizzo } 173268b8534bSLuigi Rizzo } 173399fb123fSLuigi Rizzo /* flush any remaining packets */ 173480ad548dSVincenzo Maffione if (txring != NULL) { 17354bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 17364bf50f18SLuigi Rizzo txring->tail, txring->head, 173737e3a6d3SLuigi Rizzo (void *)pthread_self()); 1738f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 173980ad548dSVincenzo Maffione } 174068b8534bSLuigi Rizzo 174168b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1742f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 174368b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 174437e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(txring)) { 17454bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 17464bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1747f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 174868b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 174968b8534bSLuigi Rizzo } 175068b8534bSLuigi Rizzo } 1751f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 175268b8534bSLuigi Rizzo 17531cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 175468b8534bSLuigi Rizzo targ->completed = 1; 175537e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 175637e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 175737e3a6d3SLuigi Rizzo targ->ctr.events = event; 175868b8534bSLuigi Rizzo quit: 175968b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 176068b8534bSLuigi Rizzo targ->used = 0; 176168b8534bSLuigi Rizzo 176268b8534bSLuigi Rizzo return (NULL); 176368b8534bSLuigi Rizzo } 176468b8534bSLuigi Rizzo 176568b8534bSLuigi Rizzo 1766f2637526SLuigi Rizzo #ifndef NO_PCAP 176768b8534bSLuigi Rizzo static void 1768f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1769f8e4e36aSLuigi Rizzo const u_char * bytes) 177068b8534bSLuigi Rizzo { 177137e3a6d3SLuigi Rizzo struct my_ctrs *ctr = (struct my_ctrs *)user; 1772f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 177337e3a6d3SLuigi Rizzo ctr->bytes += h->len; 177437e3a6d3SLuigi Rizzo ctr->pkts++; 177568b8534bSLuigi Rizzo } 1776f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 177768b8534bSLuigi Rizzo 177837e3a6d3SLuigi Rizzo 177968b8534bSLuigi Rizzo static int 178037e3a6d3SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) 178168b8534bSLuigi Rizzo { 1782406e7723SVincenzo Maffione u_int head, rx, n; 178337e3a6d3SLuigi Rizzo uint64_t b = 0; 178480ad548dSVincenzo Maffione u_int complete = 0; 178537e3a6d3SLuigi Rizzo 178637e3a6d3SLuigi Rizzo if (bytes == NULL) 178737e3a6d3SLuigi Rizzo bytes = &b; 178868b8534bSLuigi Rizzo 1789406e7723SVincenzo Maffione head = ring->head; 179017885a7bSLuigi Rizzo n = nm_ring_space(ring); 179117885a7bSLuigi Rizzo if (n < limit) 179217885a7bSLuigi Rizzo limit = n; 179368b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 1794406e7723SVincenzo Maffione struct netmap_slot *slot = &ring->slot[head]; 179568b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 179668b8534bSLuigi Rizzo 179737e3a6d3SLuigi Rizzo *bytes += slot->len; 1798b303f675SLuigi Rizzo if (dump) 1799406e7723SVincenzo Maffione dump_payload(p, slot->len, ring, head); 180080ad548dSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) 180180ad548dSVincenzo Maffione complete++; 180268b8534bSLuigi Rizzo 1803406e7723SVincenzo Maffione head = nm_ring_next(ring, head); 180468b8534bSLuigi Rizzo } 1805406e7723SVincenzo Maffione ring->head = ring->cur = head; 180668b8534bSLuigi Rizzo 180780ad548dSVincenzo Maffione return (complete); 180868b8534bSLuigi Rizzo } 180968b8534bSLuigi Rizzo 181068b8534bSLuigi Rizzo static void * 181168b8534bSLuigi Rizzo receiver_body(void *data) 181268b8534bSLuigi Rizzo { 181368b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1814f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 18154bf50f18SLuigi Rizzo struct netmap_if *nifp; 181668b8534bSLuigi Rizzo struct netmap_ring *rxring; 1817f8e4e36aSLuigi Rizzo int i; 181837e3a6d3SLuigi Rizzo struct my_ctrs cur; 181920d684ecSAllan Jude uint64_t n = targ->g->npackets / targ->g->nthreads; 182037e3a6d3SLuigi Rizzo 182180ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 182268b8534bSLuigi Rizzo 182368b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 182468b8534bSLuigi Rizzo goto quit; 182568b8534bSLuigi Rizzo 18264bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 18274bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 182868b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 18294bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1830f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1831f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 183268b8534bSLuigi Rizzo break; 183380ad548dSVincenzo Maffione if (i < 0) { 183480ad548dSVincenzo Maffione D("poll() error: %s", strerror(errno)); 183580ad548dSVincenzo Maffione goto quit; 183680ad548dSVincenzo Maffione } 183780ad548dSVincenzo Maffione if (pfd.revents & POLLERR) { 183880ad548dSVincenzo Maffione D("fd error"); 183980ad548dSVincenzo Maffione goto quit; 184080ad548dSVincenzo Maffione } 1841f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1842f0ea3689SLuigi Rizzo i, pfd.revents); 184368b8534bSLuigi Rizzo } 184468b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 18451cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1846f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1847950cf4a2SVincenzo Maffione while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 18484bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1849f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 185037e3a6d3SLuigi Rizzo i = read(targ->g->main_fd, buf, sizeof(buf)); 185137e3a6d3SLuigi Rizzo if (i > 0) { 185237e3a6d3SLuigi Rizzo targ->ctr.pkts++; 185337e3a6d3SLuigi Rizzo targ->ctr.bytes += i; 185437e3a6d3SLuigi Rizzo targ->ctr.events++; 185537e3a6d3SLuigi Rizzo } 1856f8e4e36aSLuigi Rizzo } 1857f2637526SLuigi Rizzo #ifndef NO_PCAP 1858f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 185920d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 1860f2637526SLuigi Rizzo /* XXX should we poll ? */ 18614bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 186237e3a6d3SLuigi Rizzo (u_char *)&targ->ctr); 186337e3a6d3SLuigi Rizzo targ->ctr.events++; 1864f2637526SLuigi Rizzo } 1865f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 186668b8534bSLuigi Rizzo } else { 1867b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 18684bf50f18SLuigi Rizzo 18694bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 187020d684ecSAllan Jude while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) { 187168b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 187268b8534bSLuigi Rizzo before quitting. */ 187337e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 187437e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 187537e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 187637e3a6d3SLuigi Rizzo strerror(errno)); 187737e3a6d3SLuigi Rizzo goto quit; 187837e3a6d3SLuigi Rizzo } 187937e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 188037e3a6d3SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 188137e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 188237e3a6d3SLuigi Rizzo targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 188337e3a6d3SLuigi Rizzo goto out; 188437e3a6d3SLuigi Rizzo } 188537e3a6d3SLuigi Rizzo 188637e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 188737e3a6d3SLuigi Rizzo D("poll err"); 188837e3a6d3SLuigi Rizzo goto quit; 188937e3a6d3SLuigi Rizzo } 189037e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 189137e3a6d3SLuigi Rizzo uint64_t cur_space = 0; 189237e3a6d3SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 189337e3a6d3SLuigi Rizzo int m; 189437e3a6d3SLuigi Rizzo 189537e3a6d3SLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 189637e3a6d3SLuigi Rizzo /* compute free space in the ring */ 189737e3a6d3SLuigi Rizzo m = rxring->head + rxring->num_slots - rxring->tail; 189837e3a6d3SLuigi Rizzo if (m >= (int) rxring->num_slots) 189937e3a6d3SLuigi Rizzo m -= rxring->num_slots; 190037e3a6d3SLuigi Rizzo cur_space += m; 190137e3a6d3SLuigi Rizzo if (nm_ring_empty(rxring)) 190237e3a6d3SLuigi Rizzo continue; 190337e3a6d3SLuigi Rizzo 190437e3a6d3SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); 190537e3a6d3SLuigi Rizzo cur.pkts += m; 190680ad548dSVincenzo Maffione if (m > 0) 190737e3a6d3SLuigi Rizzo cur.events++; 190837e3a6d3SLuigi Rizzo } 190937e3a6d3SLuigi Rizzo cur.min_space = targ->ctr.min_space; 191037e3a6d3SLuigi Rizzo if (cur_space < cur.min_space) 191137e3a6d3SLuigi Rizzo cur.min_space = cur_space; 191237e3a6d3SLuigi Rizzo targ->ctr = cur; 191337e3a6d3SLuigi Rizzo } 191437e3a6d3SLuigi Rizzo } 191537e3a6d3SLuigi Rizzo 191637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 191737e3a6d3SLuigi Rizzo 191837e3a6d3SLuigi Rizzo #if !defined(BUSYWAIT) 191937e3a6d3SLuigi Rizzo out: 192037e3a6d3SLuigi Rizzo #endif 192137e3a6d3SLuigi Rizzo targ->completed = 1; 192237e3a6d3SLuigi Rizzo targ->ctr = cur; 192337e3a6d3SLuigi Rizzo 192437e3a6d3SLuigi Rizzo quit: 192537e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 192637e3a6d3SLuigi Rizzo targ->used = 0; 192737e3a6d3SLuigi Rizzo 192837e3a6d3SLuigi Rizzo return (NULL); 192937e3a6d3SLuigi Rizzo } 193037e3a6d3SLuigi Rizzo 193137e3a6d3SLuigi Rizzo static void * 193237e3a6d3SLuigi Rizzo txseq_body(void *data) 193337e3a6d3SLuigi Rizzo { 193437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 193537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 193637e3a6d3SLuigi Rizzo struct netmap_ring *ring; 193737e3a6d3SLuigi Rizzo int64_t sent = 0; 193837e3a6d3SLuigi Rizzo uint64_t event = 0; 193937e3a6d3SLuigi Rizzo int options = targ->g->options | OPT_COPY; 194037e3a6d3SLuigi Rizzo struct timespec nexttime = {0, 0}; 194137e3a6d3SLuigi Rizzo int rate_limit = targ->g->tx_rate; 194237e3a6d3SLuigi Rizzo struct pkt *pkt = &targ->pkt; 194337e3a6d3SLuigi Rizzo int frags = targ->g->frags; 194437e3a6d3SLuigi Rizzo uint32_t sequence = 0; 194537e3a6d3SLuigi Rizzo int budget = 0; 194637e3a6d3SLuigi Rizzo void *frame; 194737e3a6d3SLuigi Rizzo int size; 194837e3a6d3SLuigi Rizzo 194937e3a6d3SLuigi Rizzo if (targ->g->nthreads > 1) { 195037e3a6d3SLuigi Rizzo D("can only txseq ping with 1 thread"); 195137e3a6d3SLuigi Rizzo return NULL; 195237e3a6d3SLuigi Rizzo } 195337e3a6d3SLuigi Rizzo 195437e3a6d3SLuigi Rizzo if (targ->g->npackets > 0) { 195537e3a6d3SLuigi Rizzo D("Ignoring -n argument"); 195637e3a6d3SLuigi Rizzo } 195737e3a6d3SLuigi Rizzo 195880ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 195937e3a6d3SLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 196037e3a6d3SLuigi Rizzo 196137e3a6d3SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 196237e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 196337e3a6d3SLuigi Rizzo goto quit; 196437e3a6d3SLuigi Rizzo 196537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 196637e3a6d3SLuigi Rizzo if (rate_limit) { 196737e3a6d3SLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 196837e3a6d3SLuigi Rizzo targ->tic.tv_nsec = 0; 196937e3a6d3SLuigi Rizzo wait_time(targ->tic); 197037e3a6d3SLuigi Rizzo nexttime = targ->tic; 197137e3a6d3SLuigi Rizzo } 197237e3a6d3SLuigi Rizzo 197337e3a6d3SLuigi Rizzo /* Only use the first queue. */ 197437e3a6d3SLuigi Rizzo ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); 197537e3a6d3SLuigi Rizzo 197637e3a6d3SLuigi Rizzo while (!targ->cancel) { 197737e3a6d3SLuigi Rizzo int64_t limit; 197837e3a6d3SLuigi Rizzo unsigned int space; 197937e3a6d3SLuigi Rizzo unsigned int head; 198037e3a6d3SLuigi Rizzo int fcnt; 198180ad548dSVincenzo Maffione uint16_t sum = 0; 198280ad548dSVincenzo Maffione int rv; 198337e3a6d3SLuigi Rizzo 198437e3a6d3SLuigi Rizzo if (!rate_limit) { 198537e3a6d3SLuigi Rizzo budget = targ->g->burst; 198637e3a6d3SLuigi Rizzo 198737e3a6d3SLuigi Rizzo } else if (budget <= 0) { 198837e3a6d3SLuigi Rizzo budget = targ->g->burst; 198937e3a6d3SLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 199037e3a6d3SLuigi Rizzo wait_time(nexttime); 199137e3a6d3SLuigi Rizzo } 199237e3a6d3SLuigi Rizzo 199337e3a6d3SLuigi Rizzo /* wait for available room in the send queue */ 199480ad548dSVincenzo Maffione #ifdef BUSYWAIT 199580ad548dSVincenzo Maffione (void)rv; 199680ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 199780ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 199880ad548dSVincenzo Maffione strerror(errno)); 199980ad548dSVincenzo Maffione goto quit; 200080ad548dSVincenzo Maffione } 200180ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 200280ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 200337e3a6d3SLuigi Rizzo if (targ->cancel) 200437e3a6d3SLuigi Rizzo break; 200580ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 200680ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 200780ad548dSVincenzo Maffione // goto quit; 200837e3a6d3SLuigi Rizzo } 200937e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 201037e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 201137e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 201237e3a6d3SLuigi Rizzo goto quit; 201337e3a6d3SLuigi Rizzo } 201480ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 201537e3a6d3SLuigi Rizzo 201637e3a6d3SLuigi Rizzo /* If no room poll() again. */ 201737e3a6d3SLuigi Rizzo space = nm_ring_space(ring); 201837e3a6d3SLuigi Rizzo if (!space) { 201937e3a6d3SLuigi Rizzo continue; 202037e3a6d3SLuigi Rizzo } 202137e3a6d3SLuigi Rizzo 202237e3a6d3SLuigi Rizzo limit = budget; 202337e3a6d3SLuigi Rizzo 202437e3a6d3SLuigi Rizzo if (space < limit) { 202537e3a6d3SLuigi Rizzo limit = space; 202637e3a6d3SLuigi Rizzo } 202737e3a6d3SLuigi Rizzo 202837e3a6d3SLuigi Rizzo /* Cut off ``limit`` to make sure is multiple of ``frags``. */ 202937e3a6d3SLuigi Rizzo if (frags > 1) { 203037e3a6d3SLuigi Rizzo limit = (limit / frags) * frags; 203137e3a6d3SLuigi Rizzo } 203237e3a6d3SLuigi Rizzo 203337e3a6d3SLuigi Rizzo limit = sent + limit; /* Convert to absolute. */ 203437e3a6d3SLuigi Rizzo 203537e3a6d3SLuigi Rizzo for (fcnt = frags, head = ring->head; 203637e3a6d3SLuigi Rizzo sent < limit; sent++, sequence++) { 203737e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 203837e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 203980ad548dSVincenzo Maffione uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; 204080ad548dSVincenzo Maffione 204180ad548dSVincenzo Maffione memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); 204237e3a6d3SLuigi Rizzo 204337e3a6d3SLuigi Rizzo slot->flags = 0; 204480ad548dSVincenzo Maffione t = *w; 204580ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[0] = sequence >> 24; 204680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; 204780ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 204880ad548dSVincenzo Maffione t = *++w; 204980ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; 205080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; 205180ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 205280ad548dSVincenzo Maffione memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); 205337e3a6d3SLuigi Rizzo nm_pkt_copy(frame, p, size); 205437e3a6d3SLuigi Rizzo if (fcnt == frags) { 205580ad548dSVincenzo Maffione update_addresses(pkt, targ); 205637e3a6d3SLuigi Rizzo } 205737e3a6d3SLuigi Rizzo 205837e3a6d3SLuigi Rizzo if (options & OPT_DUMP) { 205937e3a6d3SLuigi Rizzo dump_payload(p, size, ring, head); 206037e3a6d3SLuigi Rizzo } 206137e3a6d3SLuigi Rizzo 206237e3a6d3SLuigi Rizzo slot->len = size; 206337e3a6d3SLuigi Rizzo 206437e3a6d3SLuigi Rizzo if (--fcnt > 0) { 206537e3a6d3SLuigi Rizzo slot->flags |= NS_MOREFRAG; 206637e3a6d3SLuigi Rizzo } else { 206737e3a6d3SLuigi Rizzo fcnt = frags; 206837e3a6d3SLuigi Rizzo } 206937e3a6d3SLuigi Rizzo 207037e3a6d3SLuigi Rizzo if (sent == limit - 1) { 207137e3a6d3SLuigi Rizzo /* Make sure we don't push an incomplete 207237e3a6d3SLuigi Rizzo * packet. */ 207337e3a6d3SLuigi Rizzo assert(!(slot->flags & NS_MOREFRAG)); 207437e3a6d3SLuigi Rizzo slot->flags |= NS_REPORT; 207537e3a6d3SLuigi Rizzo } 207637e3a6d3SLuigi Rizzo 207737e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 207837e3a6d3SLuigi Rizzo if (rate_limit) { 207937e3a6d3SLuigi Rizzo budget--; 208037e3a6d3SLuigi Rizzo } 208137e3a6d3SLuigi Rizzo } 208237e3a6d3SLuigi Rizzo 208337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 208437e3a6d3SLuigi Rizzo 208537e3a6d3SLuigi Rizzo event ++; 208637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 208737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 208837e3a6d3SLuigi Rizzo targ->ctr.events = event; 208937e3a6d3SLuigi Rizzo } 209037e3a6d3SLuigi Rizzo 209137e3a6d3SLuigi Rizzo /* flush any remaining packets */ 209237e3a6d3SLuigi Rizzo D("flush tail %d head %d on thread %p", 209337e3a6d3SLuigi Rizzo ring->tail, ring->head, 209437e3a6d3SLuigi Rizzo (void *)pthread_self()); 209537e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 209637e3a6d3SLuigi Rizzo 209737e3a6d3SLuigi Rizzo /* final part: wait the TX queues to become empty. */ 209837e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(ring)) { 209937e3a6d3SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 210037e3a6d3SLuigi Rizzo ring->tail, ring->head, targ->nmd->first_tx_ring); 210137e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 210237e3a6d3SLuigi Rizzo usleep(1); /* wait 1 tick */ 210337e3a6d3SLuigi Rizzo } 210437e3a6d3SLuigi Rizzo 210537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 210637e3a6d3SLuigi Rizzo targ->completed = 1; 210737e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 210837e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 210937e3a6d3SLuigi Rizzo targ->ctr.events = event; 211037e3a6d3SLuigi Rizzo quit: 211137e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 211237e3a6d3SLuigi Rizzo targ->used = 0; 211337e3a6d3SLuigi Rizzo 211437e3a6d3SLuigi Rizzo return (NULL); 211537e3a6d3SLuigi Rizzo } 211637e3a6d3SLuigi Rizzo 211737e3a6d3SLuigi Rizzo 211837e3a6d3SLuigi Rizzo static char * 211937e3a6d3SLuigi Rizzo multi_slot_to_string(struct netmap_ring *ring, unsigned int head, 212037e3a6d3SLuigi Rizzo unsigned int nfrags, char *strbuf, size_t strbuflen) 212137e3a6d3SLuigi Rizzo { 212237e3a6d3SLuigi Rizzo unsigned int f; 212337e3a6d3SLuigi Rizzo char *ret = strbuf; 212437e3a6d3SLuigi Rizzo 212537e3a6d3SLuigi Rizzo for (f = 0; f < nfrags; f++) { 212637e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 212737e3a6d3SLuigi Rizzo int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, 212837e3a6d3SLuigi Rizzo slot->flags); 212937e3a6d3SLuigi Rizzo if (m >= (int)strbuflen) { 213037e3a6d3SLuigi Rizzo break; 213137e3a6d3SLuigi Rizzo } 213237e3a6d3SLuigi Rizzo strbuf += m; 213337e3a6d3SLuigi Rizzo strbuflen -= m; 213437e3a6d3SLuigi Rizzo 213537e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 213637e3a6d3SLuigi Rizzo } 213737e3a6d3SLuigi Rizzo 213837e3a6d3SLuigi Rizzo return ret; 213937e3a6d3SLuigi Rizzo } 214037e3a6d3SLuigi Rizzo 214137e3a6d3SLuigi Rizzo static void * 214237e3a6d3SLuigi Rizzo rxseq_body(void *data) 214337e3a6d3SLuigi Rizzo { 214437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 214537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 214637e3a6d3SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 214737e3a6d3SLuigi Rizzo struct netmap_ring *ring; 214837e3a6d3SLuigi Rizzo unsigned int frags_exp = 1; 214937e3a6d3SLuigi Rizzo struct my_ctrs cur; 215037e3a6d3SLuigi Rizzo unsigned int frags = 0; 215137e3a6d3SLuigi Rizzo int first_packet = 1; 215237e3a6d3SLuigi Rizzo int first_slot = 1; 215380ad548dSVincenzo Maffione int i, j, af, nrings; 215480ad548dSVincenzo Maffione uint32_t seq, *seq_exp = NULL; 215537e3a6d3SLuigi Rizzo 215680ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 215737e3a6d3SLuigi Rizzo 215837e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 215937e3a6d3SLuigi Rizzo goto quit; 216037e3a6d3SLuigi Rizzo 216180ad548dSVincenzo Maffione nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1; 216280ad548dSVincenzo Maffione seq_exp = calloc(nrings, sizeof(uint32_t)); 216380ad548dSVincenzo Maffione if (seq_exp == NULL) { 216480ad548dSVincenzo Maffione D("failed to allocate seq array"); 216580ad548dSVincenzo Maffione goto quit; 216680ad548dSVincenzo Maffione } 216780ad548dSVincenzo Maffione 216837e3a6d3SLuigi Rizzo D("reading from %s fd %d main_fd %d", 216937e3a6d3SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 217037e3a6d3SLuigi Rizzo /* unbounded wait for the first packet. */ 217137e3a6d3SLuigi Rizzo for (;!targ->cancel;) { 217237e3a6d3SLuigi Rizzo i = poll(&pfd, 1, 1000); 217337e3a6d3SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 217437e3a6d3SLuigi Rizzo break; 217537e3a6d3SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 217637e3a6d3SLuigi Rizzo i, pfd.revents); 217737e3a6d3SLuigi Rizzo } 217837e3a6d3SLuigi Rizzo 217937e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 218037e3a6d3SLuigi Rizzo 218137e3a6d3SLuigi Rizzo 218237e3a6d3SLuigi Rizzo while (!targ->cancel) { 218337e3a6d3SLuigi Rizzo unsigned int head; 218437e3a6d3SLuigi Rizzo int limit; 218537e3a6d3SLuigi Rizzo 218680ad548dSVincenzo Maffione #ifdef BUSYWAIT 218780ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 218880ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 218980ad548dSVincenzo Maffione strerror(errno)); 219080ad548dSVincenzo Maffione goto quit; 219180ad548dSVincenzo Maffione } 219280ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 2193f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 21941cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 21958ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 2196f0ea3689SLuigi Rizzo goto out; 219768b8534bSLuigi Rizzo } 219868b8534bSLuigi Rizzo 2199f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 220017885a7bSLuigi Rizzo D("poll err"); 220117885a7bSLuigi Rizzo goto quit; 220217885a7bSLuigi Rizzo } 220380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 220417885a7bSLuigi Rizzo 220580ad548dSVincenzo Maffione for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) { 220680ad548dSVincenzo Maffione ring = NETMAP_RXRING(targ->nmd->nifp, j); 220737e3a6d3SLuigi Rizzo if (nm_ring_empty(ring)) 220868b8534bSLuigi Rizzo continue; 220968b8534bSLuigi Rizzo 221037e3a6d3SLuigi Rizzo limit = nm_ring_space(ring); 221137e3a6d3SLuigi Rizzo if (limit > targ->g->burst) 221237e3a6d3SLuigi Rizzo limit = targ->g->burst; 221337e3a6d3SLuigi Rizzo 221437e3a6d3SLuigi Rizzo #if 0 221537e3a6d3SLuigi Rizzo /* Enable this if 221637e3a6d3SLuigi Rizzo * 1) we remove the early-return optimization from 221737e3a6d3SLuigi Rizzo * the netmap poll implementation, or 221837e3a6d3SLuigi Rizzo * 2) pipes get NS_MOREFRAG support. 221937e3a6d3SLuigi Rizzo * With the current netmap implementation, an experiment like 222037e3a6d3SLuigi Rizzo * pkt-gen -i vale:1{1 -f txseq -F 9 222137e3a6d3SLuigi Rizzo * pkt-gen -i vale:1}1 -f rxseq 222237e3a6d3SLuigi Rizzo * would get stuck as soon as we find nm_ring_space(ring) < 9, 222337e3a6d3SLuigi Rizzo * since here limit is rounded to 0 and 222437e3a6d3SLuigi Rizzo * pipe rxsync is not called anymore by the poll() of this loop. 222537e3a6d3SLuigi Rizzo */ 222637e3a6d3SLuigi Rizzo if (frags_exp > 1) { 222737e3a6d3SLuigi Rizzo int o = limit; 222837e3a6d3SLuigi Rizzo /* Cut off to the closest smaller multiple. */ 222937e3a6d3SLuigi Rizzo limit = (limit / frags_exp) * frags_exp; 223037e3a6d3SLuigi Rizzo RD(2, "LIMIT %d --> %d", o, limit); 223168b8534bSLuigi Rizzo } 223237e3a6d3SLuigi Rizzo #endif 223337e3a6d3SLuigi Rizzo 223437e3a6d3SLuigi Rizzo for (head = ring->head, i = 0; i < limit; i++) { 223537e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 223637e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 223737e3a6d3SLuigi Rizzo int len = slot->len; 223837e3a6d3SLuigi Rizzo struct pkt *pkt; 223937e3a6d3SLuigi Rizzo 224037e3a6d3SLuigi Rizzo if (dump) { 224137e3a6d3SLuigi Rizzo dump_payload(p, slot->len, ring, head); 224268b8534bSLuigi Rizzo } 224337e3a6d3SLuigi Rizzo 224437e3a6d3SLuigi Rizzo frags++; 224537e3a6d3SLuigi Rizzo if (!(slot->flags & NS_MOREFRAG)) { 224637e3a6d3SLuigi Rizzo if (first_packet) { 224737e3a6d3SLuigi Rizzo first_packet = 0; 224837e3a6d3SLuigi Rizzo } else if (frags != frags_exp) { 224937e3a6d3SLuigi Rizzo char prbuf[512]; 225037e3a6d3SLuigi Rizzo RD(1, "Received packets with %u frags, " 225137e3a6d3SLuigi Rizzo "expected %u, '%s'", frags, frags_exp, 225280ad548dSVincenzo Maffione multi_slot_to_string(ring, head-frags+1, 225380ad548dSVincenzo Maffione frags, 225437e3a6d3SLuigi Rizzo prbuf, sizeof(prbuf))); 225537e3a6d3SLuigi Rizzo } 225637e3a6d3SLuigi Rizzo first_packet = 0; 225737e3a6d3SLuigi Rizzo frags_exp = frags; 225837e3a6d3SLuigi Rizzo frags = 0; 225937e3a6d3SLuigi Rizzo } 226037e3a6d3SLuigi Rizzo 226137e3a6d3SLuigi Rizzo p -= sizeof(pkt->vh) - targ->g->virt_header; 226237e3a6d3SLuigi Rizzo len += sizeof(pkt->vh) - targ->g->virt_header; 226337e3a6d3SLuigi Rizzo pkt = (struct pkt *)p; 226480ad548dSVincenzo Maffione if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP) 226580ad548dSVincenzo Maffione af = AF_INET; 226680ad548dSVincenzo Maffione else 226780ad548dSVincenzo Maffione af = AF_INET6; 226837e3a6d3SLuigi Rizzo 226980ad548dSVincenzo Maffione if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) + 227080ad548dSVincenzo Maffione sizeof(seq)) { 227137e3a6d3SLuigi Rizzo RD(1, "%s: packet too small (len=%u)", __func__, 227237e3a6d3SLuigi Rizzo slot->len); 227337e3a6d3SLuigi Rizzo } else { 227480ad548dSVincenzo Maffione seq = (PKT(pkt, body, af)[0] << 24) | 227580ad548dSVincenzo Maffione (PKT(pkt, body, af)[1] << 16) | 227680ad548dSVincenzo Maffione (PKT(pkt, body, af)[2] << 8) | 227780ad548dSVincenzo Maffione PKT(pkt, body, af)[3]; 227837e3a6d3SLuigi Rizzo if (first_slot) { 227937e3a6d3SLuigi Rizzo /* Grab the first one, whatever it 228037e3a6d3SLuigi Rizzo is. */ 228180ad548dSVincenzo Maffione seq_exp[j] = seq; 228237e3a6d3SLuigi Rizzo first_slot = 0; 228380ad548dSVincenzo Maffione } else if (seq != seq_exp[j]) { 228480ad548dSVincenzo Maffione uint32_t delta = seq - seq_exp[j]; 228537e3a6d3SLuigi Rizzo 228637e3a6d3SLuigi Rizzo if (delta < (0xFFFFFFFF >> 1)) { 228737e3a6d3SLuigi Rizzo RD(2, "Sequence GAP: exp %u found %u", 228880ad548dSVincenzo Maffione seq_exp[j], seq); 228937e3a6d3SLuigi Rizzo } else { 229037e3a6d3SLuigi Rizzo RD(2, "Sequence OUT OF ORDER: " 229180ad548dSVincenzo Maffione "exp %u found %u", seq_exp[j], seq); 229237e3a6d3SLuigi Rizzo } 229380ad548dSVincenzo Maffione seq_exp[j] = seq; 229437e3a6d3SLuigi Rizzo } 229580ad548dSVincenzo Maffione seq_exp[j]++; 229637e3a6d3SLuigi Rizzo } 229737e3a6d3SLuigi Rizzo 229837e3a6d3SLuigi Rizzo cur.bytes += slot->len; 229937e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 230037e3a6d3SLuigi Rizzo cur.pkts++; 230137e3a6d3SLuigi Rizzo } 230237e3a6d3SLuigi Rizzo 230337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 230437e3a6d3SLuigi Rizzo 230537e3a6d3SLuigi Rizzo cur.events++; 230637e3a6d3SLuigi Rizzo targ->ctr = cur; 230768b8534bSLuigi Rizzo } 230880ad548dSVincenzo Maffione } 2309f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 2310f0ea3689SLuigi Rizzo 231180ad548dSVincenzo Maffione #ifndef BUSYWAIT 2312f0ea3689SLuigi Rizzo out: 231380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 231468b8534bSLuigi Rizzo targ->completed = 1; 231537e3a6d3SLuigi Rizzo targ->ctr = cur; 231668b8534bSLuigi Rizzo 231768b8534bSLuigi Rizzo quit: 231880ad548dSVincenzo Maffione if (seq_exp != NULL) 231980ad548dSVincenzo Maffione free(seq_exp); 232068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 232168b8534bSLuigi Rizzo targ->used = 0; 232268b8534bSLuigi Rizzo 232368b8534bSLuigi Rizzo return (NULL); 232468b8534bSLuigi Rizzo } 232568b8534bSLuigi Rizzo 232666a698c9SEd Maste 232768b8534bSLuigi Rizzo static void 232880ad548dSVincenzo Maffione tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg) 232968b8534bSLuigi Rizzo { 233037e3a6d3SLuigi Rizzo double bw, raw_bw, pps, abs; 2331f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 233237e3a6d3SLuigi Rizzo int size; 233368b8534bSLuigi Rizzo 233437e3a6d3SLuigi Rizzo if (cur->pkts == 0) { 233537e3a6d3SLuigi Rizzo printf("%s nothing.\n", msg); 233637e3a6d3SLuigi Rizzo return; 233737e3a6d3SLuigi Rizzo } 233837e3a6d3SLuigi Rizzo 233937e3a6d3SLuigi Rizzo size = (int)(cur->bytes / cur->pkts); 234037e3a6d3SLuigi Rizzo 234137e3a6d3SLuigi Rizzo printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", 234237e3a6d3SLuigi Rizzo msg, 234337e3a6d3SLuigi Rizzo (unsigned long long)cur->pkts, 234437e3a6d3SLuigi Rizzo (unsigned long long)cur->bytes, 234537e3a6d3SLuigi Rizzo (unsigned long long)cur->events, size, delta); 2346f8e4e36aSLuigi Rizzo if (delta == 0) 2347f8e4e36aSLuigi Rizzo delta = 1e-6; 2348f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 2349f8e4e36aSLuigi Rizzo size = 60; 235037e3a6d3SLuigi Rizzo pps = cur->pkts / delta; 235137e3a6d3SLuigi Rizzo bw = (8.0 * cur->bytes) / delta; 235280ad548dSVincenzo Maffione raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta; 235337e3a6d3SLuigi Rizzo abs = cur->pkts / (double)(cur->events); 235466a698c9SEd Maste 235537e3a6d3SLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", 235680ad548dSVincenzo Maffione norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); 235768b8534bSLuigi Rizzo } 235868b8534bSLuigi Rizzo 235968b8534bSLuigi Rizzo static void 236080ad548dSVincenzo Maffione usage(int errcode) 236168b8534bSLuigi Rizzo { 236280ad548dSVincenzo Maffione /* This usage is generated from the pkt-gen man page: 236380ad548dSVincenzo Maffione * $ man pkt-gen > x 236480ad548dSVincenzo Maffione * and pasted here adding the string terminators and endlines with simple 236580ad548dSVincenzo Maffione * regular expressions. */ 236668b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 236768b8534bSLuigi Rizzo fprintf(stderr, 236868b8534bSLuigi Rizzo "Usage:\n" 236968b8534bSLuigi Rizzo "%s arguments\n" 237080ad548dSVincenzo Maffione " -h Show program usage and exit.\n" 237180ad548dSVincenzo Maffione "\n" 237280ad548dSVincenzo Maffione " -i interface\n" 237380ad548dSVincenzo Maffione " Name of the network interface that pkt-gen operates on. It can be a system network interface\n" 237480ad548dSVincenzo Maffione " (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n" 237580ad548dSVincenzo Maffione " monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n" 237680ad548dSVincenzo Maffione " mented in netmap(4) (NIOCREGIF section).\n" 237780ad548dSVincenzo Maffione "\n" 237880ad548dSVincenzo Maffione " -f function\n" 237980ad548dSVincenzo Maffione " The function to be executed by pkt-gen. Specify tx for transmission, rx for reception, ping\n" 238080ad548dSVincenzo Maffione " for client-side ping-pong operation, and pong for server-side ping-pong operation.\n" 238180ad548dSVincenzo Maffione "\n" 238280ad548dSVincenzo Maffione " -n count\n" 2383ed188a7eSVincenzo Maffione " Number of iterations of the pkt-gen function (with 0 meaning infinite). In case of tx or rx,\n" 238480ad548dSVincenzo Maffione " count is the number of packets to receive or transmit. In case of ping or pong, count is the\n" 238580ad548dSVincenzo Maffione " number of ping-pong transactions.\n" 238680ad548dSVincenzo Maffione "\n" 238780ad548dSVincenzo Maffione " -l pkt_size\n" 238880ad548dSVincenzo Maffione " Packet size in bytes excluding CRC. If passed a second time, use random sizes larger or\n" 238980ad548dSVincenzo Maffione " equal than the second one and lower than the first one.\n" 239080ad548dSVincenzo Maffione "\n" 239180ad548dSVincenzo Maffione " -b burst_size\n" 239280ad548dSVincenzo Maffione " Transmit or receive up to burst_size packets at a time.\n" 239380ad548dSVincenzo Maffione "\n" 239480ad548dSVincenzo Maffione " -4 Use IPv4 addresses.\n" 239580ad548dSVincenzo Maffione "\n" 239680ad548dSVincenzo Maffione " -6 Use IPv6 addresses.\n" 239780ad548dSVincenzo Maffione "\n" 239880ad548dSVincenzo Maffione " -d dst_ip[:port[-dst_ip:port]]\n" 239980ad548dSVincenzo Maffione " Destination IPv4/IPv6 address and port, single or range.\n" 240080ad548dSVincenzo Maffione "\n" 240180ad548dSVincenzo Maffione " -s src_ip[:port[-src_ip:port]]\n" 240280ad548dSVincenzo Maffione " Source IPv4/IPv6 address and port, single or range.\n" 240380ad548dSVincenzo Maffione "\n" 240480ad548dSVincenzo Maffione " -D dst_mac\n" 240580ad548dSVincenzo Maffione " Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n" 240680ad548dSVincenzo Maffione "\n" 240780ad548dSVincenzo Maffione " -S src_mac\n" 240880ad548dSVincenzo Maffione " Source MAC address in colon notation.\n" 240980ad548dSVincenzo Maffione "\n" 241080ad548dSVincenzo Maffione " -a cpu_id\n" 241180ad548dSVincenzo Maffione " Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3). If more\n" 241280ad548dSVincenzo Maffione " threads are used, they are pinned to the subsequent CPUs, one per thread.\n" 241380ad548dSVincenzo Maffione "\n" 241480ad548dSVincenzo Maffione " -c cpus\n" 241580ad548dSVincenzo Maffione " Maximum number of CPUs to use (0 means to use all the available ones).\n" 241680ad548dSVincenzo Maffione "\n" 241780ad548dSVincenzo Maffione " -p threads\n" 241880ad548dSVincenzo Maffione " Number of threads to use. By default, only a single thread is used to handle all the netmap\n" 241980ad548dSVincenzo Maffione " rings. If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n" 2420ed188a7eSVincenzo Maffione " single RX ring (in rx mode), or a TX/RX ring pair. The number of threads must be less than or\n" 2421ed188a7eSVincenzo Maffione " equal to the number of TX (or RX) rings available in the device specified by interface.\n" 242280ad548dSVincenzo Maffione "\n" 242380ad548dSVincenzo Maffione " -T report_ms\n" 242480ad548dSVincenzo Maffione " Number of milliseconds between reports.\n" 242580ad548dSVincenzo Maffione "\n" 242680ad548dSVincenzo Maffione " -w wait_for_link_time\n" 2427ed188a7eSVincenzo Maffione " Number of seconds to wait before starting the pkt-gen function, useful to make sure that the\n" 242880ad548dSVincenzo Maffione " network link is up. A network device driver may take some time to enter netmap mode, or to\n" 242980ad548dSVincenzo Maffione " create a new transmit/receive ring pair when netmap(4) requests one.\n" 243080ad548dSVincenzo Maffione "\n" 243180ad548dSVincenzo Maffione " -R rate\n" 243280ad548dSVincenzo Maffione " Packet transmission rate. Not setting the packet transmission rate tells pkt-gen to transmit\n" 2433ed188a7eSVincenzo Maffione " packets as quickly as possible. On servers from 2010 onward netmap(4) is able to com-\n" 243480ad548dSVincenzo Maffione " pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n" 243580ad548dSVincenzo Maffione " your intention is to saturate the link.\n" 243680ad548dSVincenzo Maffione "\n" 243780ad548dSVincenzo Maffione " -X Dump payload of each packet transmitted or received.\n" 243880ad548dSVincenzo Maffione "\n" 243980ad548dSVincenzo Maffione " -H len Add empty virtio-net-header with size 'len'. Valid sizes are 0, 10 and 12. This option is\n" 244080ad548dSVincenzo Maffione " only used with Virtual Machine technologies that use virtio as a network interface.\n" 244180ad548dSVincenzo Maffione "\n" 244280ad548dSVincenzo Maffione " -P file\n" 244380ad548dSVincenzo Maffione " Load the packet to be transmitted from a pcap file rather than constructing it within\n" 244480ad548dSVincenzo Maffione " pkt-gen.\n" 244580ad548dSVincenzo Maffione "\n" 244680ad548dSVincenzo Maffione " -z Use random IPv4/IPv6 src address/port.\n" 244780ad548dSVincenzo Maffione "\n" 244880ad548dSVincenzo Maffione " -Z Use random IPv4/IPv6 dst address/port.\n" 244980ad548dSVincenzo Maffione "\n" 245080ad548dSVincenzo Maffione " -N Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n" 245180ad548dSVincenzo Maffione "\n" 245280ad548dSVincenzo Maffione " -F num_frags\n" 245380ad548dSVincenzo Maffione " Send multi-slot packets, each one with num_frags fragments. A multi-slot packet is repre-\n" 245480ad548dSVincenzo Maffione " sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n" 245580ad548dSVincenzo Maffione " last slot). This is useful to transmit or receive packets larger than the netmap buffer\n" 245680ad548dSVincenzo Maffione " size.\n" 245780ad548dSVincenzo Maffione "\n" 245880ad548dSVincenzo Maffione " -M frag_size\n" 245980ad548dSVincenzo Maffione " In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n" 246080ad548dSVincenzo Maffione " length divided by num_frags.\n" 246180ad548dSVincenzo Maffione "\n" 246280ad548dSVincenzo Maffione " -I Use indirect buffers. It is only valid for transmitting on VALE ports, and it is implemented\n" 246380ad548dSVincenzo Maffione " by setting the NS_INDIRECT flag in the netmap slots.\n" 246480ad548dSVincenzo Maffione "\n" 246580ad548dSVincenzo Maffione " -W Exit immediately if all the RX rings are empty the first time they are examined.\n" 246680ad548dSVincenzo Maffione "\n" 246780ad548dSVincenzo Maffione " -v Increase the verbosity level.\n" 246880ad548dSVincenzo Maffione "\n" 246980ad548dSVincenzo Maffione " -r In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n" 247080ad548dSVincenzo Maffione " netmap buffers is (rubbish mode).\n" 247180ad548dSVincenzo Maffione "\n" 247280ad548dSVincenzo Maffione " -A Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n" 247380ad548dSVincenzo Maffione "\n" 247480ad548dSVincenzo Maffione " -B Take Ethernet framing and CRC into account when computing the average bps. This adds 4 bytes\n" 247580ad548dSVincenzo Maffione " of CRC and 20 bytes of framing to each packet.\n" 247680ad548dSVincenzo Maffione "\n" 247780ad548dSVincenzo Maffione " -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n" 247880ad548dSVincenzo Maffione " Configuration in terms of number of rings and slots to be used when opening the netmap port.\n" 2479ed188a7eSVincenzo Maffione " Such configuration has an effect on software ports created on the fly, such as VALE ports and\n" 248080ad548dSVincenzo Maffione " netmap pipes. The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n" 248180ad548dSVincenzo Maffione " rx_slots, tx_rings, rx_rings. Missing numbers or zeroes stand for default values. As an\n" 248280ad548dSVincenzo Maffione " additional convenience, if exactly one number is specified, then this is assigned to both\n" 248380ad548dSVincenzo Maffione " tx_slots and rx_slots. If there is no fourth number, then the third one is assigned to both\n" 248480ad548dSVincenzo Maffione " tx_rings and rx_rings.\n" 248580ad548dSVincenzo Maffione "\n" 248680ad548dSVincenzo Maffione " -o options data generation options (parsed using atoi)\n" 248780ad548dSVincenzo Maffione " OPT_PREFETCH 1\n" 248880ad548dSVincenzo Maffione " OPT_ACCESS 2\n" 248980ad548dSVincenzo Maffione " OPT_COPY 4\n" 249080ad548dSVincenzo Maffione " OPT_MEMCPY 8\n" 249180ad548dSVincenzo Maffione " OPT_TS 16 (add a timestamp)\n" 249280ad548dSVincenzo Maffione " OPT_INDIRECT 32 (use indirect buffers)\n" 249380ad548dSVincenzo Maffione " OPT_DUMP 64 (dump rx/tx traffic)\n" 249480ad548dSVincenzo Maffione " OPT_RUBBISH 256\n" 2495ed188a7eSVincenzo Maffione " (send whatever the buffers contain)\n" 249680ad548dSVincenzo Maffione " OPT_RANDOM_SRC 512\n" 249780ad548dSVincenzo Maffione " OPT_RANDOM_DST 1024\n" 249880ad548dSVincenzo Maffione " OPT_PPS_STATS 2048\n" 249968b8534bSLuigi Rizzo "", 250068b8534bSLuigi Rizzo cmd); 250180ad548dSVincenzo Maffione exit(errcode); 250268b8534bSLuigi Rizzo } 250368b8534bSLuigi Rizzo 25044bfe1a4fSVincenzo Maffione static int 250580ad548dSVincenzo Maffione start_threads(struct glob_arg *g) { 2506f8e4e36aSLuigi Rizzo int i; 2507f8e4e36aSLuigi Rizzo 2508f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 250980ad548dSVincenzo Maffione struct targ *t; 2510f8e4e36aSLuigi Rizzo /* 2511f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 2512f8e4e36aSLuigi Rizzo * using a single descriptor. 2513f8e4e36aSLuigi Rizzo */ 2514f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 251527bf5dd3SVincenzo Maffione uint64_t seed = (uint64_t)time(0) | ((uint64_t)time(0) << 32); 251680ad548dSVincenzo Maffione t = &targs[i]; 2517f0ea3689SLuigi Rizzo 2518f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 2519f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 2520f0ea3689SLuigi Rizzo t->g = g; 252180ad548dSVincenzo Maffione memcpy(t->seed, &seed, sizeof(t->seed)); 2522f8e4e36aSLuigi Rizzo 2523f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 25244bfe1a4fSVincenzo Maffione int m = -1; 25254bfe1a4fSVincenzo Maffione 25264bfe1a4fSVincenzo Maffione /* 25274bfe1a4fSVincenzo Maffione * if the user wants both HW and SW rings, we need to 25284bfe1a4fSVincenzo Maffione * know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW 25294bfe1a4fSVincenzo Maffione */ 25304bfe1a4fSVincenzo Maffione if (g->orig_mode == NR_REG_NIC_SW) { 25314bfe1a4fSVincenzo Maffione m = (g->td_type == TD_TYPE_RECEIVER ? 25324bfe1a4fSVincenzo Maffione g->nmd->reg.nr_rx_rings : 25334bfe1a4fSVincenzo Maffione g->nmd->reg.nr_tx_rings); 25344bfe1a4fSVincenzo Maffione } 2535f8e4e36aSLuigi Rizzo 253637e3a6d3SLuigi Rizzo if (i > 0) { 25374bfe1a4fSVincenzo Maffione int j; 253837e3a6d3SLuigi Rizzo /* the first thread uses the fd opened by the main 253937e3a6d3SLuigi Rizzo * thread, the other threads re-open /dev/netmap 254037e3a6d3SLuigi Rizzo */ 25414bfe1a4fSVincenzo Maffione t->nmd = nmport_clone(g->nmd); 25424bfe1a4fSVincenzo Maffione if (t->nmd == NULL) 25434bfe1a4fSVincenzo Maffione return -1; 25444bfe1a4fSVincenzo Maffione 25454bfe1a4fSVincenzo Maffione j = i; 25464bfe1a4fSVincenzo Maffione if (m > 0 && j >= m) { 25474bfe1a4fSVincenzo Maffione /* switch to the software rings */ 25484bfe1a4fSVincenzo Maffione t->nmd->reg.nr_mode = NR_REG_ONE_SW; 25494bfe1a4fSVincenzo Maffione j -= m; 255017885a7bSLuigi Rizzo } 25514bfe1a4fSVincenzo Maffione t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK; 2552f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 255337e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_RECEIVER) 25544bfe1a4fSVincenzo Maffione t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL; 2555f8e4e36aSLuigi Rizzo 2556f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 25574bfe1a4fSVincenzo Maffione if (nmport_open_desc(t->nmd) < 0) { 25584bfe1a4fSVincenzo Maffione nmport_undo_prepare(t->nmd); 25594bfe1a4fSVincenzo Maffione t->nmd = NULL; 25604bfe1a4fSVincenzo Maffione return -1; 2561f8e4e36aSLuigi Rizzo } 256237e3a6d3SLuigi Rizzo } else { 256337e3a6d3SLuigi Rizzo t->nmd = g->nmd; 256437e3a6d3SLuigi Rizzo } 2565f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 256680ad548dSVincenzo Maffione t->frags = g->frags; 2567f8e4e36aSLuigi Rizzo } else { 2568f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 2569f8e4e36aSLuigi Rizzo } 2570f0ea3689SLuigi Rizzo t->used = 1; 2571f0ea3689SLuigi Rizzo t->me = i; 2572f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 257380ad548dSVincenzo Maffione t->affinity = (g->affinity + i) % g->cpus; 2574f0ea3689SLuigi Rizzo } else { 2575f0ea3689SLuigi Rizzo t->affinity = -1; 2576f0ea3689SLuigi Rizzo } 2577f8e4e36aSLuigi Rizzo /* default, init packets */ 2578f0ea3689SLuigi Rizzo initialize_packet(t); 257980ad548dSVincenzo Maffione } 258080ad548dSVincenzo Maffione /* Wait for PHY reset. */ 258180ad548dSVincenzo Maffione D("Wait %d secs for phy reset", g->wait_link); 258280ad548dSVincenzo Maffione sleep(g->wait_link); 258380ad548dSVincenzo Maffione D("Ready..."); 2584f8e4e36aSLuigi Rizzo 258580ad548dSVincenzo Maffione for (i = 0; i < g->nthreads; i++) { 258680ad548dSVincenzo Maffione t = &targs[i]; 2587f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 258817885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 2589f0ea3689SLuigi Rizzo t->used = 0; 2590f8e4e36aSLuigi Rizzo } 2591f8e4e36aSLuigi Rizzo } 25924bfe1a4fSVincenzo Maffione return 0; 2593f8e4e36aSLuigi Rizzo } 2594f8e4e36aSLuigi Rizzo 2595f8e4e36aSLuigi Rizzo static void 2596f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 2597f8e4e36aSLuigi Rizzo { 2598f8e4e36aSLuigi Rizzo int i; 2599f8e4e36aSLuigi Rizzo 260037e3a6d3SLuigi Rizzo struct my_ctrs prev, cur; 2601f8e4e36aSLuigi Rizzo double delta_t; 2602f8e4e36aSLuigi Rizzo struct timeval tic, toc; 2603f8e4e36aSLuigi Rizzo 260437e3a6d3SLuigi Rizzo prev.pkts = prev.bytes = prev.events = 0; 260537e3a6d3SLuigi Rizzo gettimeofday(&prev.t, NULL); 2606f8e4e36aSLuigi Rizzo for (;;) { 260780ad548dSVincenzo Maffione char b1[40], b2[40], b3[40], b4[100]; 260837e3a6d3SLuigi Rizzo uint64_t pps, usec; 260937e3a6d3SLuigi Rizzo struct my_ctrs x; 261037e3a6d3SLuigi Rizzo double abs; 2611f8e4e36aSLuigi Rizzo int done = 0; 2612f8e4e36aSLuigi Rizzo 261337e3a6d3SLuigi Rizzo usec = wait_for_next_report(&prev.t, &cur.t, 261437e3a6d3SLuigi Rizzo g->report_interval); 261537e3a6d3SLuigi Rizzo 261637e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 261737e3a6d3SLuigi Rizzo cur.min_space = 0; 261837e3a6d3SLuigi Rizzo if (usec < 10000) /* too short to be meaningful */ 261937e3a6d3SLuigi Rizzo continue; 262037e3a6d3SLuigi Rizzo /* accumulate counts for all threads */ 2621f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 262237e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 262337e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 262437e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 262537e3a6d3SLuigi Rizzo cur.min_space += targs[i].ctr.min_space; 262637e3a6d3SLuigi Rizzo targs[i].ctr.min_space = 99999; 2627f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 2628f8e4e36aSLuigi Rizzo done++; 2629f8e4e36aSLuigi Rizzo } 263037e3a6d3SLuigi Rizzo x.pkts = cur.pkts - prev.pkts; 263137e3a6d3SLuigi Rizzo x.bytes = cur.bytes - prev.bytes; 263237e3a6d3SLuigi Rizzo x.events = cur.events - prev.events; 263337e3a6d3SLuigi Rizzo pps = (x.pkts*1000000 + usec/2) / usec; 263437e3a6d3SLuigi Rizzo abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; 263537e3a6d3SLuigi Rizzo 263637e3a6d3SLuigi Rizzo if (!(g->options & OPT_PPS_STATS)) { 263737e3a6d3SLuigi Rizzo strcpy(b4, ""); 263837e3a6d3SLuigi Rizzo } else { 263937e3a6d3SLuigi Rizzo /* Compute some pps stats using a sliding window. */ 264037e3a6d3SLuigi Rizzo double ppsavg = 0.0, ppsdev = 0.0; 264137e3a6d3SLuigi Rizzo int nsamples = 0; 264237e3a6d3SLuigi Rizzo 264337e3a6d3SLuigi Rizzo g->win[g->win_idx] = pps; 264437e3a6d3SLuigi Rizzo g->win_idx = (g->win_idx + 1) % STATS_WIN; 264537e3a6d3SLuigi Rizzo 264637e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 264737e3a6d3SLuigi Rizzo ppsavg += g->win[i]; 264837e3a6d3SLuigi Rizzo if (g->win[i]) { 264937e3a6d3SLuigi Rizzo nsamples ++; 265037e3a6d3SLuigi Rizzo } 265137e3a6d3SLuigi Rizzo } 265237e3a6d3SLuigi Rizzo ppsavg /= nsamples; 265337e3a6d3SLuigi Rizzo 265437e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 265537e3a6d3SLuigi Rizzo if (g->win[i] == 0) { 2656f8e4e36aSLuigi Rizzo continue; 265737e3a6d3SLuigi Rizzo } 265837e3a6d3SLuigi Rizzo ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); 265937e3a6d3SLuigi Rizzo } 266037e3a6d3SLuigi Rizzo ppsdev /= nsamples; 266137e3a6d3SLuigi Rizzo ppsdev = sqrt(ppsdev); 266237e3a6d3SLuigi Rizzo 266337e3a6d3SLuigi Rizzo snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", 266480ad548dSVincenzo Maffione norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); 266537e3a6d3SLuigi Rizzo } 266637e3a6d3SLuigi Rizzo 266737e3a6d3SLuigi Rizzo D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", 266880ad548dSVincenzo Maffione norm(b1, pps, normalize), b4, 266980ad548dSVincenzo Maffione norm(b2, (double)x.pkts, normalize), 2670760fa2abSVincenzo Maffione norm(b3, 1000000*((double)x.bytes*8+(double)x.pkts*g->framing)/usec, normalize), 267137e3a6d3SLuigi Rizzo (unsigned long long)usec, 267237e3a6d3SLuigi Rizzo abs, (int)cur.min_space); 267337e3a6d3SLuigi Rizzo prev = cur; 267437e3a6d3SLuigi Rizzo 2675f8e4e36aSLuigi Rizzo if (done == g->nthreads) 2676f8e4e36aSLuigi Rizzo break; 2677f8e4e36aSLuigi Rizzo } 2678f8e4e36aSLuigi Rizzo 2679f8e4e36aSLuigi Rizzo timerclear(&tic); 2680f8e4e36aSLuigi Rizzo timerclear(&toc); 268137e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 268237e3a6d3SLuigi Rizzo /* final round */ 2683f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 26841cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 2685f8e4e36aSLuigi Rizzo /* 2686f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 2687f8e4e36aSLuigi Rizzo * file descriptors. 2688f8e4e36aSLuigi Rizzo */ 26891cb4c501SLuigi Rizzo if (targs[i].used) 269037e3a6d3SLuigi Rizzo pthread_join(targs[i].thread, NULL); /* blocking */ 269137e3a6d3SLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 26924bfe1a4fSVincenzo Maffione nmport_close(targs[i].nmd); 269337e3a6d3SLuigi Rizzo targs[i].nmd = NULL; 269437e3a6d3SLuigi Rizzo } else { 2695f8e4e36aSLuigi Rizzo close(targs[i].fd); 269637e3a6d3SLuigi Rizzo } 2697f8e4e36aSLuigi Rizzo 2698f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 2699f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 2700f8e4e36aSLuigi Rizzo 2701f8e4e36aSLuigi Rizzo /* 2702f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 2703f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 2704f8e4e36aSLuigi Rizzo */ 270537e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 270637e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 270737e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 270837e3a6d3SLuigi Rizzo /* collect the largest start (tic) and end (toc) times, 270937e3a6d3SLuigi Rizzo * XXX maybe we should do the earliest tic, or do a weighted 271037e3a6d3SLuigi Rizzo * average ? 271137e3a6d3SLuigi Rizzo */ 27121cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 27131cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 27141cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 27151cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 27161cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 27171cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 2718f8e4e36aSLuigi Rizzo } 2719f8e4e36aSLuigi Rizzo 2720f8e4e36aSLuigi Rizzo /* print output. */ 2721f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 2722f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 272337e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_SENDER) 272480ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Sent"); 272580ad548dSVincenzo Maffione else if (g->td_type == TD_TYPE_RECEIVER) 272680ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Received"); 2727f8e4e36aSLuigi Rizzo } 2728f8e4e36aSLuigi Rizzo 272937e3a6d3SLuigi Rizzo struct td_desc { 273037e3a6d3SLuigi Rizzo int ty; 27317eb32dc8SVincenzo Maffione const char *key; 2732f8e4e36aSLuigi Rizzo void *f; 273380ad548dSVincenzo Maffione int default_burst; 2734f8e4e36aSLuigi Rizzo }; 2735f8e4e36aSLuigi Rizzo 273637e3a6d3SLuigi Rizzo static struct td_desc func[] = { 273780ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ 273880ad548dSVincenzo Maffione { TD_TYPE_SENDER, "tx", sender_body, 512 }, 273980ad548dSVincenzo Maffione { TD_TYPE_OTHER, "ping", ping_body, 1 }, 274080ad548dSVincenzo Maffione { TD_TYPE_OTHER, "pong", pong_body, 1 }, 274180ad548dSVincenzo Maffione { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, 274280ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, 274380ad548dSVincenzo Maffione { 0, NULL, NULL, 0 } 2744f8e4e36aSLuigi Rizzo }; 2745f8e4e36aSLuigi Rizzo 2746f8e4e36aSLuigi Rizzo static int 2747f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 2748f8e4e36aSLuigi Rizzo { 2749f8e4e36aSLuigi Rizzo struct ifreq ifr; 2750f8e4e36aSLuigi Rizzo int fd, err; 27517eb32dc8SVincenzo Maffione const char *clonedev = TAP_CLONEDEV; 2752f8e4e36aSLuigi Rizzo 2753f8e4e36aSLuigi Rizzo (void)err; 2754f8e4e36aSLuigi Rizzo (void)dev; 2755f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 2756f8e4e36aSLuigi Rizzo * 2757f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 2758f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 2759f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 2760f8e4e36aSLuigi Rizzo */ 2761f8e4e36aSLuigi Rizzo 2762f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 2763f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 2764f8e4e36aSLuigi Rizzo static char buf[128]; 2765f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 2766f8e4e36aSLuigi Rizzo clonedev = buf; 2767f8e4e36aSLuigi Rizzo } 2768f8e4e36aSLuigi Rizzo #endif 2769f8e4e36aSLuigi Rizzo /* open the device */ 2770f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 2771f8e4e36aSLuigi Rizzo return fd; 2772f8e4e36aSLuigi Rizzo } 2773f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 2774f8e4e36aSLuigi Rizzo 2775f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 2776f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 2777f8e4e36aSLuigi Rizzo 2778f8e4e36aSLuigi Rizzo #ifdef linux 2779f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 2780f8e4e36aSLuigi Rizzo 2781f8e4e36aSLuigi Rizzo if (*dev) { 2782f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 2783f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 2784f8e4e36aSLuigi Rizzo * specified type */ 278580ad548dSVincenzo Maffione size_t len = strlen(dev); 278680ad548dSVincenzo Maffione if (len > IFNAMSIZ) { 278780ad548dSVincenzo Maffione D("%s too long", dev); 278880ad548dSVincenzo Maffione return -1; 278980ad548dSVincenzo Maffione } 279080ad548dSVincenzo Maffione memcpy(ifr.ifr_name, dev, len); 2791f8e4e36aSLuigi Rizzo } 2792f8e4e36aSLuigi Rizzo 2793f8e4e36aSLuigi Rizzo /* try to create the device */ 2794f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 279517885a7bSLuigi Rizzo D("failed to to a TUNSETIFF: %s", strerror(errno)); 2796f8e4e36aSLuigi Rizzo close(fd); 2797f8e4e36aSLuigi Rizzo return err; 2798f8e4e36aSLuigi Rizzo } 2799f8e4e36aSLuigi Rizzo 2800f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 2801f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 2802f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 2803f8e4e36aSLuigi Rizzo * code below) */ 2804f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 2805f8e4e36aSLuigi Rizzo D("new name is %s", dev); 2806f8e4e36aSLuigi Rizzo #endif /* linux */ 2807f8e4e36aSLuigi Rizzo 2808f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 2809f8e4e36aSLuigi Rizzo * with the virtual interface */ 2810f8e4e36aSLuigi Rizzo return fd; 2811f8e4e36aSLuigi Rizzo } 281268b8534bSLuigi Rizzo 281368b8534bSLuigi Rizzo int 281468b8534bSLuigi Rizzo main(int arc, char **argv) 281568b8534bSLuigi Rizzo { 2816f8e4e36aSLuigi Rizzo int i; 281737e3a6d3SLuigi Rizzo struct sigaction sa; 281837e3a6d3SLuigi Rizzo sigset_t ss; 281968b8534bSLuigi Rizzo 282068b8534bSLuigi Rizzo struct glob_arg g; 282168b8534bSLuigi Rizzo 282268b8534bSLuigi Rizzo int ch; 282368b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 282480ad548dSVincenzo Maffione int wait_link_arg = 0; 282580ad548dSVincenzo Maffione 282680ad548dSVincenzo Maffione int pkt_size_done = 0; 282780ad548dSVincenzo Maffione 282880ad548dSVincenzo Maffione struct td_desc *fn = func; 282968b8534bSLuigi Rizzo 283068b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 283168b8534bSLuigi Rizzo 2832f8e4e36aSLuigi Rizzo g.main_fd = -1; 283380ad548dSVincenzo Maffione g.td_body = fn->f; 283480ad548dSVincenzo Maffione g.td_type = fn->ty; 2835f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 2836f8e4e36aSLuigi Rizzo g.affinity = -1; 2837f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 283880ad548dSVincenzo Maffione g.af = AF_INET; /* default */ 2839f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 2840f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 2841f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 2842f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 284368b8534bSLuigi Rizzo g.pkt_size = 60; 284480ad548dSVincenzo Maffione g.pkt_min_size = 0; 284568b8534bSLuigi Rizzo g.nthreads = 1; 284680ad548dSVincenzo Maffione g.cpus = 1; /* default */ 2847b303f675SLuigi Rizzo g.forever = 1; 28481cb4c501SLuigi Rizzo g.tx_rate = 0; 2849ce3ee1e7SLuigi Rizzo g.frags = 1; 28509e53f3bdSVincenzo Maffione g.frag_size = (u_int)-1; /* use the netmap buffer size by default */ 2851ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 285217885a7bSLuigi Rizzo g.virt_header = 0; 285380ad548dSVincenzo Maffione g.wait_link = 2; /* wait 2 seconds for physical ports */ 285468b8534bSLuigi Rizzo 285580ad548dSVincenzo Maffione while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" 285680ad548dSVincenzo Maffione "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) { 2857f8e4e36aSLuigi Rizzo 285868b8534bSLuigi Rizzo switch(ch) { 285968b8534bSLuigi Rizzo default: 286068b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 286180ad548dSVincenzo Maffione usage(-1); 286280ad548dSVincenzo Maffione break; 286380ad548dSVincenzo Maffione 286480ad548dSVincenzo Maffione case 'h': 286580ad548dSVincenzo Maffione usage(0); 286680ad548dSVincenzo Maffione break; 286780ad548dSVincenzo Maffione 286880ad548dSVincenzo Maffione case '4': 286980ad548dSVincenzo Maffione g.af = AF_INET; 287080ad548dSVincenzo Maffione break; 287180ad548dSVincenzo Maffione 287280ad548dSVincenzo Maffione case '6': 287380ad548dSVincenzo Maffione g.af = AF_INET6; 287480ad548dSVincenzo Maffione break; 287580ad548dSVincenzo Maffione 287680ad548dSVincenzo Maffione case 'N': 287780ad548dSVincenzo Maffione normalize = 0; 287868b8534bSLuigi Rizzo break; 2879f8e4e36aSLuigi Rizzo 2880f8e4e36aSLuigi Rizzo case 'n': 288137e3a6d3SLuigi Rizzo g.npackets = strtoull(optarg, NULL, 10); 2882f8e4e36aSLuigi Rizzo break; 2883f8e4e36aSLuigi Rizzo 2884ce3ee1e7SLuigi Rizzo case 'F': 2885ce3ee1e7SLuigi Rizzo i = atoi(optarg); 2886ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 2887ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 2888ce3ee1e7SLuigi Rizzo break; 2889ce3ee1e7SLuigi Rizzo } 2890ce3ee1e7SLuigi Rizzo g.frags = i; 2891ce3ee1e7SLuigi Rizzo break; 2892ce3ee1e7SLuigi Rizzo 289380ad548dSVincenzo Maffione case 'M': 28949e53f3bdSVincenzo Maffione g.frag_size = atoi(optarg); 289580ad548dSVincenzo Maffione break; 289680ad548dSVincenzo Maffione 2897f8e4e36aSLuigi Rizzo case 'f': 2898f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 2899f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 2900f8e4e36aSLuigi Rizzo break; 2901f8e4e36aSLuigi Rizzo } 290237e3a6d3SLuigi Rizzo if (fn->key) { 2903f8e4e36aSLuigi Rizzo g.td_body = fn->f; 290437e3a6d3SLuigi Rizzo g.td_type = fn->ty; 290537e3a6d3SLuigi Rizzo } else { 2906f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 290737e3a6d3SLuigi Rizzo } 2908f8e4e36aSLuigi Rizzo break; 2909f8e4e36aSLuigi Rizzo 2910f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 291180ad548dSVincenzo Maffione g.options |= atoi(optarg); 291299fb123fSLuigi Rizzo break; 2913f8e4e36aSLuigi Rizzo 2914f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 2915f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 2916f8e4e36aSLuigi Rizzo break; 2917f8e4e36aSLuigi Rizzo 291868b8534bSLuigi Rizzo case 'i': /* interface */ 2919f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 2920f2637526SLuigi Rizzo * otherwise we guess 2921f2637526SLuigi Rizzo */ 2922f2637526SLuigi Rizzo D("interface is %s", optarg); 2923f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 2924f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 2925f0ea3689SLuigi Rizzo break; 2926f0ea3689SLuigi Rizzo } 2927f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 2928f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 2929f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 2930ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 2931f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 2932f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2933f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 2934f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 2935f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 2936f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 2937f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 2938f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 2939f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2940f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 2941f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2942f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 2943f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2944f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 2945f2637526SLuigi Rizzo } 294668b8534bSLuigi Rizzo break; 2947f8e4e36aSLuigi Rizzo 2948b303f675SLuigi Rizzo case 'I': 294980ad548dSVincenzo Maffione g.options |= OPT_INDIRECT; /* use indirect buffers */ 2950b303f675SLuigi Rizzo break; 2951b303f675SLuigi Rizzo 295268b8534bSLuigi Rizzo case 'l': /* pkt_size */ 295380ad548dSVincenzo Maffione if (pkt_size_done) { 295480ad548dSVincenzo Maffione g.pkt_min_size = atoi(optarg); 295580ad548dSVincenzo Maffione } else { 295668b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 295780ad548dSVincenzo Maffione pkt_size_done = 1; 295880ad548dSVincenzo Maffione } 295968b8534bSLuigi Rizzo break; 2960f8e4e36aSLuigi Rizzo 296168b8534bSLuigi Rizzo case 'd': 2962f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 296368b8534bSLuigi Rizzo break; 2964f8e4e36aSLuigi Rizzo 296568b8534bSLuigi Rizzo case 's': 2966f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 296768b8534bSLuigi Rizzo break; 2968f8e4e36aSLuigi Rizzo 296968b8534bSLuigi Rizzo case 'T': /* report interval */ 2970f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 297168b8534bSLuigi Rizzo break; 2972f8e4e36aSLuigi Rizzo 297368b8534bSLuigi Rizzo case 'w': 297480ad548dSVincenzo Maffione g.wait_link = atoi(optarg); 297580ad548dSVincenzo Maffione wait_link_arg = 1; 297668b8534bSLuigi Rizzo break; 2977f8e4e36aSLuigi Rizzo 297880ad548dSVincenzo Maffione case 'W': 297980ad548dSVincenzo Maffione g.forever = 0; /* exit RX with no traffic */ 2980f8e4e36aSLuigi Rizzo break; 2981f8e4e36aSLuigi Rizzo 298268b8534bSLuigi Rizzo case 'b': /* burst */ 298368b8534bSLuigi Rizzo g.burst = atoi(optarg); 298468b8534bSLuigi Rizzo break; 298568b8534bSLuigi Rizzo case 'c': 298668b8534bSLuigi Rizzo g.cpus = atoi(optarg); 298768b8534bSLuigi Rizzo break; 298868b8534bSLuigi Rizzo case 'p': 298968b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 299068b8534bSLuigi Rizzo break; 299168b8534bSLuigi Rizzo 299268b8534bSLuigi Rizzo case 'D': /* destination mac */ 2993f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 299468b8534bSLuigi Rizzo break; 2995f8e4e36aSLuigi Rizzo 299668b8534bSLuigi Rizzo case 'S': /* source mac */ 2997f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 299868b8534bSLuigi Rizzo break; 299968b8534bSLuigi Rizzo case 'v': 300068b8534bSLuigi Rizzo verbose++; 30011cb4c501SLuigi Rizzo break; 30021cb4c501SLuigi Rizzo case 'R': 30031cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 30041cb4c501SLuigi Rizzo break; 3005b303f675SLuigi Rizzo case 'X': 3006b303f675SLuigi Rizzo g.options |= OPT_DUMP; 3007ce3ee1e7SLuigi Rizzo break; 3008ce3ee1e7SLuigi Rizzo case 'C': 3009760fa2abSVincenzo Maffione D("WARNING: the 'C' option is deprecated, use the '+conf:' libnetmap option instead"); 3010ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 301117885a7bSLuigi Rizzo break; 301217885a7bSLuigi Rizzo case 'H': 301317885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 3014f2637526SLuigi Rizzo break; 3015f284c737SGeorge V. Neville-Neil case 'P': 3016f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 3017f284c737SGeorge V. Neville-Neil break; 301837e3a6d3SLuigi Rizzo case 'r': 301937e3a6d3SLuigi Rizzo g.options |= OPT_RUBBISH; 302037e3a6d3SLuigi Rizzo break; 302156717743SAdrian Chadd case 'z': 302256717743SAdrian Chadd g.options |= OPT_RANDOM_SRC; 302356717743SAdrian Chadd break; 302456717743SAdrian Chadd case 'Z': 302556717743SAdrian Chadd g.options |= OPT_RANDOM_DST; 302656717743SAdrian Chadd break; 302737e3a6d3SLuigi Rizzo case 'A': 302837e3a6d3SLuigi Rizzo g.options |= OPT_PPS_STATS; 302937e3a6d3SLuigi Rizzo break; 303080ad548dSVincenzo Maffione case 'B': 303180ad548dSVincenzo Maffione /* raw packets have4 bytes crc + 20 bytes framing */ 303280ad548dSVincenzo Maffione // XXX maybe add an option to pass the IFG 303380ad548dSVincenzo Maffione g.framing = 24 * 8; 303480ad548dSVincenzo Maffione break; 303568b8534bSLuigi Rizzo } 303668b8534bSLuigi Rizzo } 303768b8534bSLuigi Rizzo 3038db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 303968b8534bSLuigi Rizzo D("missing ifname"); 304080ad548dSVincenzo Maffione usage(-1); 304180ad548dSVincenzo Maffione } 304280ad548dSVincenzo Maffione 304380ad548dSVincenzo Maffione if (g.burst == 0) { 304480ad548dSVincenzo Maffione g.burst = fn->default_burst; 304580ad548dSVincenzo Maffione D("using default burst size: %d", g.burst); 304668b8534bSLuigi Rizzo } 3047f8e4e36aSLuigi Rizzo 304837e3a6d3SLuigi Rizzo g.system_cpus = i = system_ncpus(); 3049f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 3050f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 305180ad548dSVincenzo Maffione usage(-1); 305268b8534bSLuigi Rizzo } 305337e3a6d3SLuigi Rizzo D("running on %d cpus (have %d)", g.cpus, i); 305468b8534bSLuigi Rizzo if (g.cpus == 0) 3055f8e4e36aSLuigi Rizzo g.cpus = i; 3056f8e4e36aSLuigi Rizzo 305780ad548dSVincenzo Maffione if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) { 305880ad548dSVincenzo Maffione g.wait_link = 0; 305980ad548dSVincenzo Maffione } 306080ad548dSVincenzo Maffione 30614bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 30624bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 306380ad548dSVincenzo Maffione usage(-1); 306480ad548dSVincenzo Maffione } 306580ad548dSVincenzo Maffione 306680ad548dSVincenzo Maffione if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) { 306780ad548dSVincenzo Maffione D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size); 306880ad548dSVincenzo Maffione usage(-1); 306968b8534bSLuigi Rizzo } 307068b8534bSLuigi Rizzo 3071f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 3072f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 307399fb123fSLuigi Rizzo /* retrieve source mac address. */ 3074f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 307599fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 307699fb123fSLuigi Rizzo // continue, fail later 307799fb123fSLuigi Rizzo } 3078f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 307999fb123fSLuigi Rizzo } 3080f8e4e36aSLuigi Rizzo /* extract address ranges */ 308180ad548dSVincenzo Maffione if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac)) 308280ad548dSVincenzo Maffione usage(-1); 308380ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.src_ip, g.af); 308480ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.dst_ip, g.af); 3085f2637526SLuigi Rizzo 308617885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 308717885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 308817885a7bSLuigi Rizzo D("bad virtio-net-header length"); 308980ad548dSVincenzo Maffione usage(-1); 309017885a7bSLuigi Rizzo } 309117885a7bSLuigi Rizzo 3092f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 3093f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 3094f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 3095f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 3096f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 309780ad548dSVincenzo Maffione usage(-1); 309899fb123fSLuigi Rizzo } 3099f2637526SLuigi Rizzo #ifndef NO_PCAP 3100f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 3101f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 3102f8e4e36aSLuigi Rizzo 3103f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 31044bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 3105f8e4e36aSLuigi Rizzo if (g.p == NULL) { 3106f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 310780ad548dSVincenzo Maffione usage(-1); 3108f8e4e36aSLuigi Rizzo } 31094bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 31104bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 3111f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 3112f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 3113ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 311499fb123fSLuigi Rizzo } else { 31154bfe1a4fSVincenzo Maffione g.nmd = nmport_prepare(g.ifname); 31164bfe1a4fSVincenzo Maffione if (g.nmd == NULL) 311780ad548dSVincenzo Maffione goto out; 31184bfe1a4fSVincenzo Maffione 31194bfe1a4fSVincenzo Maffione parse_nmr_config(g.nmr_config, &g.nmd->reg); 31204bfe1a4fSVincenzo Maffione 31214bfe1a4fSVincenzo Maffione g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR; 3122f0ea3689SLuigi Rizzo 312368b8534bSLuigi Rizzo /* 3124f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 312568b8534bSLuigi Rizzo * 312668b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 312768b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 3128f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 312968b8534bSLuigi Rizzo */ 31304bfe1a4fSVincenzo Maffione g.orig_mode = g.nmd->reg.nr_mode; 313137e3a6d3SLuigi Rizzo if (g.nthreads > 1) { 31324bfe1a4fSVincenzo Maffione switch (g.orig_mode) { 31334bfe1a4fSVincenzo Maffione case NR_REG_ALL_NIC: 31344bfe1a4fSVincenzo Maffione case NR_REG_NIC_SW: 31354bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_NIC; 31364bfe1a4fSVincenzo Maffione break; 31374bfe1a4fSVincenzo Maffione case NR_REG_SW: 31384bfe1a4fSVincenzo Maffione g.nmd->reg.nr_mode = NR_REG_ONE_SW; 31394bfe1a4fSVincenzo Maffione break; 31404bfe1a4fSVincenzo Maffione default: 31414bfe1a4fSVincenzo Maffione break; 314280ad548dSVincenzo Maffione } 31434bfe1a4fSVincenzo Maffione g.nmd->reg.nr_ringid = 0; 31444bfe1a4fSVincenzo Maffione } 31454bfe1a4fSVincenzo Maffione if (nmport_open_desc(g.nmd) < 0) 314637e3a6d3SLuigi Rizzo goto out; 3147f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 31484bfe1a4fSVincenzo Maffione ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10), 314980ad548dSVincenzo Maffione g.nmd->mem); 3150f0ea3689SLuigi Rizzo 315137e3a6d3SLuigi Rizzo if (g.virt_header) { 315237e3a6d3SLuigi Rizzo /* Set the virtio-net header length, since the user asked 315345c67e8fSVincenzo Maffione * for it explicitly. */ 315437e3a6d3SLuigi Rizzo set_vnet_hdr_len(&g); 315537e3a6d3SLuigi Rizzo } else { 315637e3a6d3SLuigi Rizzo /* Check whether the netmap port we opened requires us to send 315737e3a6d3SLuigi Rizzo * and receive frames with virtio-net header. */ 315837e3a6d3SLuigi Rizzo get_vnet_hdr_len(&g); 315937e3a6d3SLuigi Rizzo } 316037e3a6d3SLuigi Rizzo 31614bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 316237e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 31634bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings; 31644bf50f18SLuigi Rizzo else 31654bfe1a4fSVincenzo Maffione devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings; 316668b8534bSLuigi Rizzo 316768b8534bSLuigi Rizzo /* validate provided nthreads. */ 316868b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 316968b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 317068b8534bSLuigi Rizzo // continue, fail later 317168b8534bSLuigi Rizzo } 317268b8534bSLuigi Rizzo 31739e53f3bdSVincenzo Maffione if (g.td_type == TD_TYPE_SENDER) { 31749e53f3bdSVincenzo Maffione int mtu = get_if_mtu(&g); 31759e53f3bdSVincenzo Maffione 31769e53f3bdSVincenzo Maffione if (mtu > 0 && g.pkt_size > mtu) { 31779e53f3bdSVincenzo Maffione D("pkt_size (%d) must be <= mtu (%d)", 31789e53f3bdSVincenzo Maffione g.pkt_size, mtu); 31799e53f3bdSVincenzo Maffione return -1; 31809e53f3bdSVincenzo Maffione } 31819e53f3bdSVincenzo Maffione } 31829e53f3bdSVincenzo Maffione 3183f2637526SLuigi Rizzo if (verbose) { 3184f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 31854bfe1a4fSVincenzo Maffione struct nmreq_register *req = &g.nmd->reg; 318668b8534bSLuigi Rizzo 3187d7493759SVincenzo Maffione D("nifp at offset %"PRIu64" ntxqs %d nrxqs %d memid %d", 3188f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 31894bfe1a4fSVincenzo Maffione req->nr_mem_id); 31904bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) { 31914bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 3192d7493759SVincenzo Maffione D(" TX%d at offset %p slots %d", i, 319337e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3194f2637526SLuigi Rizzo } 31954bfe1a4fSVincenzo Maffione for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) { 31964bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 3197d7493759SVincenzo Maffione D(" RX%d at offset %p slots %d", i, 319837e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3199f2637526SLuigi Rizzo } 3200f2637526SLuigi Rizzo } 320168b8534bSLuigi Rizzo 320268b8534bSLuigi Rizzo /* Print some debug information. */ 320368b8534bSLuigi Rizzo fprintf(stdout, 320468b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 320537e3a6d3SLuigi Rizzo (g.td_type == TD_TYPE_SENDER) ? "Sending on" : 320637e3a6d3SLuigi Rizzo ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : 320737e3a6d3SLuigi Rizzo "Working on"), 3208f8e4e36aSLuigi Rizzo g.ifname, 320968b8534bSLuigi Rizzo devqueues, 321068b8534bSLuigi Rizzo g.nthreads, 321168b8534bSLuigi Rizzo g.cpus); 321237e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) { 321368b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 3214f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 3215f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 321668b8534bSLuigi Rizzo } 321768b8534bSLuigi Rizzo 3218f0ea3689SLuigi Rizzo out: 321968b8534bSLuigi Rizzo /* Exit if something went wrong. */ 3220f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 322168b8534bSLuigi Rizzo D("aborting"); 322280ad548dSVincenzo Maffione usage(-1); 322368b8534bSLuigi Rizzo } 322499fb123fSLuigi Rizzo } 322568b8534bSLuigi Rizzo 3226ce3ee1e7SLuigi Rizzo 322799fb123fSLuigi Rizzo if (g.options) { 322837e3a6d3SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", 322999fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 323099fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 323199fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 3232b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 323337e3a6d3SLuigi Rizzo g.options & OPT_COPY ? " copy" : "", 323437e3a6d3SLuigi Rizzo g.options & OPT_RUBBISH ? " rubbish " : ""); 323599fb123fSLuigi Rizzo } 32361cb4c501SLuigi Rizzo 3237ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 3238ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 3239ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 324017885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 3241ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 3242ce3ee1e7SLuigi Rizzo */ 324317885a7bSLuigi Rizzo uint64_t x; 324417885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 324517885a7bSLuigi Rizzo if (g.burst > lim) 324617885a7bSLuigi Rizzo g.burst = lim; 324780ad548dSVincenzo Maffione if (g.burst == 0) 324880ad548dSVincenzo Maffione g.burst = 1; 324917885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 325017885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 32511cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 32521cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 32531cb4c501SLuigi Rizzo } 325437e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 3255ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 3256ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 325768b8534bSLuigi Rizzo /* Install ^C handler. */ 325868b8534bSLuigi Rizzo global_nthreads = g.nthreads; 325937e3a6d3SLuigi Rizzo sigemptyset(&ss); 326037e3a6d3SLuigi Rizzo sigaddset(&ss, SIGINT); 326137e3a6d3SLuigi Rizzo /* block SIGINT now, so that all created threads will inherit the mask */ 326237e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { 326337e3a6d3SLuigi Rizzo D("failed to block SIGINT: %s", strerror(errno)); 326437e3a6d3SLuigi Rizzo } 32654bfe1a4fSVincenzo Maffione if (start_threads(&g) < 0) 32664bfe1a4fSVincenzo Maffione return 1; 326737e3a6d3SLuigi Rizzo /* Install the handler and re-enable SIGINT for the main thread */ 326880ad548dSVincenzo Maffione memset(&sa, 0, sizeof(sa)); 326937e3a6d3SLuigi Rizzo sa.sa_handler = sigint_h; 327037e3a6d3SLuigi Rizzo if (sigaction(SIGINT, &sa, NULL) < 0) { 327137e3a6d3SLuigi Rizzo D("failed to install ^C handler: %s", strerror(errno)); 327237e3a6d3SLuigi Rizzo } 327337e3a6d3SLuigi Rizzo 327437e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { 327537e3a6d3SLuigi Rizzo D("failed to re-enable SIGINT: %s", strerror(errno)); 327637e3a6d3SLuigi Rizzo } 3277f8e4e36aSLuigi Rizzo main_thread(&g); 327837e3a6d3SLuigi Rizzo free(targs); 3279f8e4e36aSLuigi Rizzo return 0; 328068b8534bSLuigi Rizzo } 328168b8534bSLuigi Rizzo 328268b8534bSLuigi Rizzo /* end of file */ 3283