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 <stdio.h> 42f0ea3689SLuigi Rizzo #define NETMAP_WITH_LIBS 43f0ea3689SLuigi Rizzo #include <net/netmap_user.h> 44f0ea3689SLuigi Rizzo 45f8e4e36aSLuigi Rizzo 46b303f675SLuigi Rizzo #include <ctype.h> // isprint() 47f0ea3689SLuigi Rizzo #include <unistd.h> // sysconf() 48f0ea3689SLuigi Rizzo #include <sys/poll.h> 49f0ea3689SLuigi Rizzo #include <arpa/inet.h> /* ntohs */ 5037e3a6d3SLuigi Rizzo #ifndef _WIN32 51f0ea3689SLuigi Rizzo #include <sys/sysctl.h> /* sysctl */ 5237e3a6d3SLuigi Rizzo #endif 53f0ea3689SLuigi Rizzo #include <ifaddrs.h> /* getifaddrs */ 54f0ea3689SLuigi Rizzo #include <net/ethernet.h> 55f0ea3689SLuigi Rizzo #include <netinet/in.h> 56f0ea3689SLuigi Rizzo #include <netinet/ip.h> 57f0ea3689SLuigi Rizzo #include <netinet/udp.h> 5880ad548dSVincenzo Maffione #include <netinet/ip6.h> 5980ad548dSVincenzo Maffione #ifdef linux 6080ad548dSVincenzo Maffione #define IPV6_VERSION 0x60 6180ad548dSVincenzo Maffione #define IPV6_DEFHLIM 64 6280ad548dSVincenzo Maffione #endif 6337e3a6d3SLuigi Rizzo #include <assert.h> 6437e3a6d3SLuigi Rizzo #include <math.h> 65f0ea3689SLuigi Rizzo 66f0ea3689SLuigi Rizzo #include <pthread.h> 67b303f675SLuigi Rizzo 68f2637526SLuigi Rizzo #ifndef NO_PCAP 69f2637526SLuigi Rizzo #include <pcap/pcap.h> 70f2637526SLuigi Rizzo #endif 71f0ea3689SLuigi Rizzo 7237e3a6d3SLuigi Rizzo #include "ctrs.h" 7337e3a6d3SLuigi Rizzo 7480ad548dSVincenzo Maffione static void usage(int); 7580ad548dSVincenzo Maffione 7637e3a6d3SLuigi Rizzo #ifdef _WIN32 7737e3a6d3SLuigi Rizzo #define cpuset_t DWORD_PTR //uint64_t 7837e3a6d3SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 7937e3a6d3SLuigi Rizzo { 8037e3a6d3SLuigi Rizzo *p = 0; 8137e3a6d3SLuigi Rizzo } 8237e3a6d3SLuigi Rizzo 8337e3a6d3SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 8437e3a6d3SLuigi Rizzo { 8537e3a6d3SLuigi Rizzo *p |= 1<< (i & 0x3f); 8637e3a6d3SLuigi Rizzo } 8737e3a6d3SLuigi Rizzo 8837e3a6d3SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c) //((void)a, 0) 8937e3a6d3SLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 9037e3a6d3SLuigi Rizzo #define AF_LINK 18 //defined in winsocks.h 9137e3a6d3SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 9237e3a6d3SLuigi Rizzo #include <net/if_dl.h> 9337e3a6d3SLuigi Rizzo 9437e3a6d3SLuigi Rizzo /* 9537e3a6d3SLuigi Rizzo * Convert an ASCII representation of an ethernet address to 9637e3a6d3SLuigi Rizzo * binary form. 9737e3a6d3SLuigi Rizzo */ 9837e3a6d3SLuigi Rizzo struct ether_addr * 9937e3a6d3SLuigi Rizzo ether_aton(const char *a) 10037e3a6d3SLuigi Rizzo { 10137e3a6d3SLuigi Rizzo int i; 10237e3a6d3SLuigi Rizzo static struct ether_addr o; 10337e3a6d3SLuigi Rizzo unsigned int o0, o1, o2, o3, o4, o5; 10437e3a6d3SLuigi Rizzo 10537e3a6d3SLuigi Rizzo i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); 10637e3a6d3SLuigi Rizzo 10737e3a6d3SLuigi Rizzo if (i != 6) 10837e3a6d3SLuigi Rizzo return (NULL); 10937e3a6d3SLuigi Rizzo 11037e3a6d3SLuigi Rizzo o.octet[0]=o0; 11137e3a6d3SLuigi Rizzo o.octet[1]=o1; 11237e3a6d3SLuigi Rizzo o.octet[2]=o2; 11337e3a6d3SLuigi Rizzo o.octet[3]=o3; 11437e3a6d3SLuigi Rizzo o.octet[4]=o4; 11537e3a6d3SLuigi Rizzo o.octet[5]=o5; 11637e3a6d3SLuigi Rizzo 11737e3a6d3SLuigi Rizzo return ((struct ether_addr *)&o); 11837e3a6d3SLuigi Rizzo } 11937e3a6d3SLuigi Rizzo 12037e3a6d3SLuigi Rizzo /* 12137e3a6d3SLuigi Rizzo * Convert a binary representation of an ethernet address to 12237e3a6d3SLuigi Rizzo * an ASCII string. 12337e3a6d3SLuigi Rizzo */ 12437e3a6d3SLuigi Rizzo char * 12537e3a6d3SLuigi Rizzo ether_ntoa(const struct ether_addr *n) 12637e3a6d3SLuigi Rizzo { 12737e3a6d3SLuigi Rizzo int i; 12837e3a6d3SLuigi Rizzo static char a[18]; 12937e3a6d3SLuigi Rizzo 13037e3a6d3SLuigi Rizzo i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", 13137e3a6d3SLuigi Rizzo n->octet[0], n->octet[1], n->octet[2], 13237e3a6d3SLuigi Rizzo n->octet[3], n->octet[4], n->octet[5]); 13337e3a6d3SLuigi Rizzo return (i < 17 ? NULL : (char *)&a); 13437e3a6d3SLuigi Rizzo } 13537e3a6d3SLuigi Rizzo #endif /* _WIN32 */ 13637e3a6d3SLuigi Rizzo 137f0ea3689SLuigi Rizzo #ifdef linux 138f0ea3689SLuigi Rizzo 139f0ea3689SLuigi Rizzo #define cpuset_t cpu_set_t 140f0ea3689SLuigi Rizzo 141f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags /* only the low 16 bits here */ 142f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ 143f0ea3689SLuigi Rizzo #include <linux/ethtool.h> 144f0ea3689SLuigi Rizzo #include <linux/sockios.h> 145f0ea3689SLuigi Rizzo 146f0ea3689SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 147f0ea3689SLuigi Rizzo #include <netinet/ether.h> /* ether_aton */ 148f0ea3689SLuigi Rizzo #include <linux/if_packet.h> /* sockaddr_ll */ 149f0ea3689SLuigi Rizzo #endif /* linux */ 150f0ea3689SLuigi Rizzo 151f0ea3689SLuigi Rizzo #ifdef __FreeBSD__ 152f0ea3689SLuigi Rizzo #include <sys/endian.h> /* le64toh */ 153f0ea3689SLuigi Rizzo #include <machine/param.h> 154f0ea3689SLuigi Rizzo 155f0ea3689SLuigi Rizzo #include <pthread_np.h> /* pthread w/ affinity */ 156f0ea3689SLuigi Rizzo #include <sys/cpuset.h> /* cpu_set */ 157f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 158f0ea3689SLuigi Rizzo #endif /* __FreeBSD__ */ 159f0ea3689SLuigi Rizzo 160f0ea3689SLuigi Rizzo #ifdef __APPLE__ 161f0ea3689SLuigi Rizzo 162f0ea3689SLuigi Rizzo #define cpuset_t uint64_t // XXX 163f0ea3689SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 164f0ea3689SLuigi Rizzo { 165f0ea3689SLuigi Rizzo *p = 0; 166f0ea3689SLuigi Rizzo } 167f0ea3689SLuigi Rizzo 168f0ea3689SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 169f0ea3689SLuigi Rizzo { 170f0ea3689SLuigi Rizzo *p |= 1<< (i & 0x3f); 171f0ea3689SLuigi Rizzo } 172f0ea3689SLuigi Rizzo 173f0ea3689SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) ((void)a, 0) 174f0ea3689SLuigi Rizzo 175f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags // XXX 176f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC 177f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 178f0ea3689SLuigi Rizzo #define clock_gettime(a,b) \ 179f0ea3689SLuigi Rizzo do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) 180f0ea3689SLuigi Rizzo #endif /* __APPLE__ */ 181f0ea3689SLuigi Rizzo 182ce3ee1e7SLuigi Rizzo const char *default_payload="netmap pkt-gen DIRECT payload\n" 183ce3ee1e7SLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 184ce3ee1e7SLuigi Rizzo 185ce3ee1e7SLuigi Rizzo const char *indirect_payload="netmap pkt-gen indirect payload\n" 18668b8534bSLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 18768b8534bSLuigi Rizzo 18868b8534bSLuigi Rizzo int verbose = 0; 18980ad548dSVincenzo Maffione int normalize = 1; 19017885a7bSLuigi Rizzo 19117885a7bSLuigi Rizzo #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ 19217885a7bSLuigi Rizzo #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ 19317885a7bSLuigi Rizzo #define VIRT_HDR_MAX VIRT_HDR_2 19417885a7bSLuigi Rizzo struct virt_header { 19517885a7bSLuigi Rizzo uint8_t fields[VIRT_HDR_MAX]; 19617885a7bSLuigi Rizzo }; 19717885a7bSLuigi Rizzo 1984bf50f18SLuigi Rizzo #define MAX_BODYSIZE 16384 1994bf50f18SLuigi Rizzo 20068b8534bSLuigi Rizzo struct pkt { 20117885a7bSLuigi Rizzo struct virt_header vh; 20268b8534bSLuigi Rizzo struct ether_header eh; 20380ad548dSVincenzo Maffione union { 20480ad548dSVincenzo Maffione struct { 20568b8534bSLuigi Rizzo struct ip ip; 20668b8534bSLuigi Rizzo struct udphdr udp; 20780ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 20880ad548dSVincenzo Maffione } ipv4; 20980ad548dSVincenzo Maffione struct { 21080ad548dSVincenzo Maffione struct ip6_hdr ip; 21180ad548dSVincenzo Maffione struct udphdr udp; 21280ad548dSVincenzo Maffione uint8_t body[MAX_BODYSIZE]; /* hardwired */ 21380ad548dSVincenzo Maffione } ipv6; 21480ad548dSVincenzo Maffione }; 21568b8534bSLuigi Rizzo } __attribute__((__packed__)); 21668b8534bSLuigi Rizzo 21780ad548dSVincenzo Maffione #define PKT(p, f, af) \ 21880ad548dSVincenzo Maffione ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f) 21980ad548dSVincenzo Maffione 220f8e4e36aSLuigi Rizzo struct ip_range { 221f8e4e36aSLuigi Rizzo char *name; 22280ad548dSVincenzo Maffione union { 22380ad548dSVincenzo Maffione struct { 224ce3ee1e7SLuigi Rizzo uint32_t start, end; /* same as struct in_addr */ 22580ad548dSVincenzo Maffione } ipv4; 22680ad548dSVincenzo Maffione struct { 22780ad548dSVincenzo Maffione struct in6_addr start, end; 22880ad548dSVincenzo Maffione uint8_t sgroup, egroup; 22980ad548dSVincenzo Maffione } ipv6; 23080ad548dSVincenzo Maffione }; 231ce3ee1e7SLuigi Rizzo uint16_t port0, port1; 232f8e4e36aSLuigi Rizzo }; 233f8e4e36aSLuigi Rizzo 234f8e4e36aSLuigi Rizzo struct mac_range { 235f8e4e36aSLuigi Rizzo char *name; 236f8e4e36aSLuigi Rizzo struct ether_addr start, end; 237f8e4e36aSLuigi Rizzo }; 238f8e4e36aSLuigi Rizzo 239f0ea3689SLuigi Rizzo /* ifname can be netmap:foo-xxxx */ 240f0ea3689SLuigi Rizzo #define MAX_IFNAMELEN 64 /* our buffer for ifname */ 2414bf50f18SLuigi Rizzo //#define MAX_PKTSIZE 1536 2424bf50f18SLuigi Rizzo #define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ 2434bf50f18SLuigi Rizzo 2444bf50f18SLuigi Rizzo /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ 2454bf50f18SLuigi Rizzo struct tstamp { 2464bf50f18SLuigi Rizzo uint32_t sec; 2474bf50f18SLuigi Rizzo uint32_t nsec; 2484bf50f18SLuigi Rizzo }; 2494bf50f18SLuigi Rizzo 25068b8534bSLuigi Rizzo /* 25168b8534bSLuigi Rizzo * global arguments for all threads 25268b8534bSLuigi Rizzo */ 253f8e4e36aSLuigi Rizzo 25468b8534bSLuigi Rizzo struct glob_arg { 25580ad548dSVincenzo Maffione int af; /* address family AF_INET/AF_INET6 */ 256f8e4e36aSLuigi Rizzo struct ip_range src_ip; 257f8e4e36aSLuigi Rizzo struct ip_range dst_ip; 258f8e4e36aSLuigi Rizzo struct mac_range dst_mac; 259f8e4e36aSLuigi Rizzo struct mac_range src_mac; 26068b8534bSLuigi Rizzo int pkt_size; 26180ad548dSVincenzo Maffione int pkt_min_size; 26268b8534bSLuigi Rizzo int burst; 263f8e4e36aSLuigi Rizzo int forever; 26437e3a6d3SLuigi Rizzo uint64_t npackets; /* total packets to send */ 265ce3ee1e7SLuigi Rizzo int frags; /* fragments per packet */ 26680ad548dSVincenzo Maffione u_int mtu; /* size of each fragment */ 26768b8534bSLuigi Rizzo int nthreads; 26837e3a6d3SLuigi Rizzo int cpus; /* cpus used for running */ 26937e3a6d3SLuigi Rizzo int system_cpus; /* cpus on the system */ 27037e3a6d3SLuigi Rizzo 27199fb123fSLuigi Rizzo int options; /* testing */ 27299fb123fSLuigi Rizzo #define OPT_PREFETCH 1 27399fb123fSLuigi Rizzo #define OPT_ACCESS 2 27499fb123fSLuigi Rizzo #define OPT_COPY 4 27599fb123fSLuigi Rizzo #define OPT_MEMCPY 8 276f8e4e36aSLuigi Rizzo #define OPT_TS 16 /* add a timestamp */ 277b303f675SLuigi Rizzo #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ 278b303f675SLuigi Rizzo #define OPT_DUMP 64 /* dump rx/tx traffic */ 27937e3a6d3SLuigi Rizzo #define OPT_RUBBISH 256 /* send wathever the buffers contain */ 28056717743SAdrian Chadd #define OPT_RANDOM_SRC 512 28156717743SAdrian Chadd #define OPT_RANDOM_DST 1024 28237e3a6d3SLuigi Rizzo #define OPT_PPS_STATS 2048 283f8e4e36aSLuigi Rizzo int dev_type; 284f2637526SLuigi Rizzo #ifndef NO_PCAP 28568b8534bSLuigi Rizzo pcap_t *p; 286f2637526SLuigi Rizzo #endif 28768b8534bSLuigi Rizzo 2881cb4c501SLuigi Rizzo int tx_rate; 2891cb4c501SLuigi Rizzo struct timespec tx_period; 2901cb4c501SLuigi Rizzo 291f8e4e36aSLuigi Rizzo int affinity; 292f8e4e36aSLuigi Rizzo int main_fd; 293f0ea3689SLuigi Rizzo struct nm_desc *nmd; 294f2637526SLuigi Rizzo int report_interval; /* milliseconds between prints */ 295f8e4e36aSLuigi Rizzo void *(*td_body)(void *); 29637e3a6d3SLuigi Rizzo int td_type; 297f8e4e36aSLuigi Rizzo void *mmap_addr; 298f0ea3689SLuigi Rizzo char ifname[MAX_IFNAMELEN]; 299ce3ee1e7SLuigi Rizzo char *nmr_config; 300ce3ee1e7SLuigi Rizzo int dummy_send; 30117885a7bSLuigi Rizzo int virt_header; /* send also the virt_header */ 302f284c737SGeorge V. Neville-Neil char *packet_file; /* -P option */ 30337e3a6d3SLuigi Rizzo #define STATS_WIN 15 30437e3a6d3SLuigi Rizzo int win_idx; 30537e3a6d3SLuigi Rizzo int64_t win[STATS_WIN]; 30680ad548dSVincenzo Maffione int wait_link; 30780ad548dSVincenzo Maffione int framing; /* #bits of framing (for bw output) */ 30868b8534bSLuigi Rizzo }; 309f8e4e36aSLuigi Rizzo enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; 310f8e4e36aSLuigi Rizzo 31168b8534bSLuigi Rizzo 31268b8534bSLuigi Rizzo /* 31368b8534bSLuigi Rizzo * Arguments for a new thread. The same structure is used by 31468b8534bSLuigi Rizzo * the source and the sink 31568b8534bSLuigi Rizzo */ 31668b8534bSLuigi Rizzo struct targ { 31768b8534bSLuigi Rizzo struct glob_arg *g; 31868b8534bSLuigi Rizzo int used; 31968b8534bSLuigi Rizzo int completed; 3203fe77e68SEd Maste int cancel; 32168b8534bSLuigi Rizzo int fd; 322f0ea3689SLuigi Rizzo struct nm_desc *nmd; 32337e3a6d3SLuigi Rizzo /* these ought to be volatile, but they are 32437e3a6d3SLuigi Rizzo * only sampled and errors should not accumulate 32537e3a6d3SLuigi Rizzo */ 32637e3a6d3SLuigi Rizzo struct my_ctrs ctr; 32737e3a6d3SLuigi Rizzo 3281cb4c501SLuigi Rizzo struct timespec tic, toc; 32968b8534bSLuigi Rizzo int me; 33068b8534bSLuigi Rizzo pthread_t thread; 33168b8534bSLuigi Rizzo int affinity; 33268b8534bSLuigi Rizzo 33368b8534bSLuigi Rizzo struct pkt pkt; 334f284c737SGeorge V. Neville-Neil void *frame; 33580ad548dSVincenzo Maffione uint16_t seed[3]; 33680ad548dSVincenzo Maffione u_int frags; 33780ad548dSVincenzo Maffione u_int frag_size; 33868b8534bSLuigi Rizzo }; 33968b8534bSLuigi Rizzo 34080ad548dSVincenzo Maffione static __inline uint16_t 34180ad548dSVincenzo Maffione cksum_add(uint16_t sum, uint16_t a) 34280ad548dSVincenzo Maffione { 34380ad548dSVincenzo Maffione uint16_t res; 34468b8534bSLuigi Rizzo 34580ad548dSVincenzo Maffione res = sum + a; 34680ad548dSVincenzo Maffione return (res + (res < a)); 34780ad548dSVincenzo Maffione } 34880ad548dSVincenzo Maffione 34980ad548dSVincenzo Maffione static void 35080ad548dSVincenzo Maffione extract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port) 35180ad548dSVincenzo Maffione { 35280ad548dSVincenzo Maffione struct in_addr a; 35380ad548dSVincenzo Maffione char *pp; 35480ad548dSVincenzo Maffione 35580ad548dSVincenzo Maffione pp = strchr(name, ':'); 35680ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 35780ad548dSVincenzo Maffione *pp++ = '\0'; 35880ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 35980ad548dSVincenzo Maffione } 36080ad548dSVincenzo Maffione 36180ad548dSVincenzo Maffione inet_pton(AF_INET, name, &a); 36280ad548dSVincenzo Maffione *addr = ntohl(a.s_addr); 36380ad548dSVincenzo Maffione } 36480ad548dSVincenzo Maffione 36580ad548dSVincenzo Maffione static void 36680ad548dSVincenzo Maffione extract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port, 36780ad548dSVincenzo Maffione uint8_t *group) 36880ad548dSVincenzo Maffione { 36980ad548dSVincenzo Maffione char *pp; 37080ad548dSVincenzo Maffione 37180ad548dSVincenzo Maffione /* 37280ad548dSVincenzo Maffione * We accept IPv6 address in the following form: 37380ad548dSVincenzo Maffione * group@[2001:DB8::1001]:port (w/ brackets and port) 37480ad548dSVincenzo Maffione * group@[2001:DB8::1] (w/ brackets and w/o port) 37580ad548dSVincenzo Maffione * group@2001:DB8::1234 (w/o brackets and w/o port) 37680ad548dSVincenzo Maffione */ 37780ad548dSVincenzo Maffione pp = strchr(name, '@'); 37880ad548dSVincenzo Maffione if (pp != NULL) { 37980ad548dSVincenzo Maffione *pp++ = '\0'; 38080ad548dSVincenzo Maffione *group = (uint8_t)strtol(name, NULL, 0); 38180ad548dSVincenzo Maffione if (*group > 7) 38280ad548dSVincenzo Maffione *group = 7; 38380ad548dSVincenzo Maffione name = pp; 38480ad548dSVincenzo Maffione } 38580ad548dSVincenzo Maffione if (name[0] == '[') 38680ad548dSVincenzo Maffione name++; 38780ad548dSVincenzo Maffione pp = strchr(name, ']'); 38880ad548dSVincenzo Maffione if (pp != NULL) 38980ad548dSVincenzo Maffione *pp++ = '\0'; 39080ad548dSVincenzo Maffione if (pp != NULL && *pp != ':') 39180ad548dSVincenzo Maffione pp = NULL; 39280ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 39380ad548dSVincenzo Maffione *pp++ = '\0'; 39480ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 39580ad548dSVincenzo Maffione } 39680ad548dSVincenzo Maffione inet_pton(AF_INET6, name, addr); 39780ad548dSVincenzo Maffione } 398f8e4e36aSLuigi Rizzo /* 399f8e4e36aSLuigi Rizzo * extract the extremes from a range of ipv4 addresses. 400f8e4e36aSLuigi Rizzo * addr_lo[-addr_hi][:port_lo[-port_hi]] 401f8e4e36aSLuigi Rizzo */ 40280ad548dSVincenzo Maffione static int 40380ad548dSVincenzo Maffione extract_ip_range(struct ip_range *r, int af) 404f8e4e36aSLuigi Rizzo { 40580ad548dSVincenzo Maffione char *name, *ap, start[INET6_ADDRSTRLEN]; 40680ad548dSVincenzo Maffione char end[INET6_ADDRSTRLEN]; 407ce3ee1e7SLuigi Rizzo struct in_addr a; 40880ad548dSVincenzo Maffione uint32_t tmp; 409f8e4e36aSLuigi Rizzo 41017885a7bSLuigi Rizzo if (verbose) 411f8e4e36aSLuigi Rizzo D("extract IP range from %s", r->name); 412ce3ee1e7SLuigi Rizzo 41380ad548dSVincenzo Maffione name = strdup(r->name); 41480ad548dSVincenzo Maffione if (name == NULL) { 41580ad548dSVincenzo Maffione D("strdup failed"); 41680ad548dSVincenzo Maffione usage(-1); 41780ad548dSVincenzo Maffione } 418ce3ee1e7SLuigi Rizzo /* the first - splits start/end of range */ 41980ad548dSVincenzo Maffione ap = strchr(name, '-'); 42080ad548dSVincenzo Maffione if (ap != NULL) 421ce3ee1e7SLuigi Rizzo *ap++ = '\0'; 42280ad548dSVincenzo Maffione r->port0 = 1234; /* default port */ 42380ad548dSVincenzo Maffione if (af == AF_INET6) { 42480ad548dSVincenzo Maffione r->ipv6.sgroup = 7; /* default group */ 42580ad548dSVincenzo Maffione extract_ipv6_addr(name, &r->ipv6.start, &r->port0, 42680ad548dSVincenzo Maffione &r->ipv6.sgroup); 42780ad548dSVincenzo Maffione } else 42880ad548dSVincenzo Maffione extract_ipv4_addr(name, &r->ipv4.start, &r->port0); 42980ad548dSVincenzo Maffione 43080ad548dSVincenzo Maffione r->port1 = r->port0; 43180ad548dSVincenzo Maffione if (af == AF_INET6) { 43280ad548dSVincenzo Maffione if (ap != NULL) { 43380ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 43480ad548dSVincenzo Maffione extract_ipv6_addr(ap, &r->ipv6.end, &r->port1, 43580ad548dSVincenzo Maffione &r->ipv6.egroup); 43680ad548dSVincenzo Maffione } else { 43780ad548dSVincenzo Maffione r->ipv6.end = r->ipv6.start; 43880ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 439ce3ee1e7SLuigi Rizzo } 44080ad548dSVincenzo Maffione } else { 44180ad548dSVincenzo Maffione if (ap != NULL) { 44280ad548dSVincenzo Maffione extract_ipv4_addr(ap, &r->ipv4.end, &r->port1); 44380ad548dSVincenzo Maffione if (r->ipv4.start > r->ipv4.end) { 44480ad548dSVincenzo Maffione tmp = r->ipv4.end; 44580ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 44680ad548dSVincenzo Maffione r->ipv4.start = tmp; 447ce3ee1e7SLuigi Rizzo } 44880ad548dSVincenzo Maffione } else 44980ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 450ce3ee1e7SLuigi Rizzo } 45180ad548dSVincenzo Maffione 452ce3ee1e7SLuigi Rizzo if (r->port0 > r->port1) { 45380ad548dSVincenzo Maffione tmp = r->port0; 454f8e4e36aSLuigi Rizzo r->port0 = r->port1; 455ce3ee1e7SLuigi Rizzo r->port1 = tmp; 456f8e4e36aSLuigi Rizzo } 45780ad548dSVincenzo Maffione if (af == AF_INET) { 45880ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.start); 45980ad548dSVincenzo Maffione inet_ntop(af, &a, start, sizeof(start)); 46080ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.end); 46180ad548dSVincenzo Maffione inet_ntop(af, &a, end, sizeof(end)); 46280ad548dSVincenzo Maffione } else { 46380ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.start, start, sizeof(start)); 46480ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.end, end, sizeof(end)); 465f8e4e36aSLuigi Rizzo } 46680ad548dSVincenzo Maffione if (af == AF_INET) 46780ad548dSVincenzo Maffione D("range is %s:%d to %s:%d", start, r->port0, end, r->port1); 46880ad548dSVincenzo Maffione else 46980ad548dSVincenzo Maffione D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup, 47080ad548dSVincenzo Maffione start, r->port0, r->ipv6.egroup, end, r->port1); 471ce3ee1e7SLuigi Rizzo 47280ad548dSVincenzo Maffione free(name); 47380ad548dSVincenzo Maffione if (r->port0 != r->port1 || 47480ad548dSVincenzo Maffione (af == AF_INET && r->ipv4.start != r->ipv4.end) || 47580ad548dSVincenzo Maffione (af == AF_INET6 && 47680ad548dSVincenzo Maffione !IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end))) 47780ad548dSVincenzo Maffione return (OPT_COPY); 47880ad548dSVincenzo Maffione return (0); 479f8e4e36aSLuigi Rizzo } 480f8e4e36aSLuigi Rizzo 48180ad548dSVincenzo Maffione static int 482f8e4e36aSLuigi Rizzo extract_mac_range(struct mac_range *r) 483f8e4e36aSLuigi Rizzo { 48480ad548dSVincenzo Maffione struct ether_addr *e; 48517885a7bSLuigi Rizzo if (verbose) 486f8e4e36aSLuigi Rizzo D("extract MAC range from %s", r->name); 48780ad548dSVincenzo Maffione 48880ad548dSVincenzo Maffione e = ether_aton(r->name); 48980ad548dSVincenzo Maffione if (e == NULL) { 49080ad548dSVincenzo Maffione D("invalid MAC address '%s'", r->name); 49180ad548dSVincenzo Maffione return 1; 49280ad548dSVincenzo Maffione } 49380ad548dSVincenzo Maffione bcopy(e, &r->start, 6); 49480ad548dSVincenzo Maffione bcopy(e, &r->end, 6); 495f8e4e36aSLuigi Rizzo #if 0 496f8e4e36aSLuigi Rizzo bcopy(targ->src_mac, eh->ether_shost, 6); 497f8e4e36aSLuigi Rizzo p = index(targ->g->src_mac, '-'); 498f8e4e36aSLuigi Rizzo if (p) 499f8e4e36aSLuigi Rizzo targ->src_mac_range = atoi(p+1); 500f8e4e36aSLuigi Rizzo 501f8e4e36aSLuigi Rizzo bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6); 502f8e4e36aSLuigi Rizzo bcopy(targ->dst_mac, eh->ether_dhost, 6); 503f8e4e36aSLuigi Rizzo p = index(targ->g->dst_mac, '-'); 504f8e4e36aSLuigi Rizzo if (p) 505f8e4e36aSLuigi Rizzo targ->dst_mac_range = atoi(p+1); 506f8e4e36aSLuigi Rizzo #endif 50717885a7bSLuigi Rizzo if (verbose) 508f8e4e36aSLuigi Rizzo D("%s starts at %s", r->name, ether_ntoa(&r->start)); 50980ad548dSVincenzo Maffione return 0; 510f8e4e36aSLuigi Rizzo } 511f8e4e36aSLuigi Rizzo 51268b8534bSLuigi Rizzo static struct targ *targs; 51368b8534bSLuigi Rizzo static int global_nthreads; 51468b8534bSLuigi Rizzo 51568b8534bSLuigi Rizzo /* control-C handler */ 51668b8534bSLuigi Rizzo static void 517f8e4e36aSLuigi Rizzo sigint_h(int sig) 51868b8534bSLuigi Rizzo { 519f8e4e36aSLuigi Rizzo int i; 52068b8534bSLuigi Rizzo 521f8e4e36aSLuigi Rizzo (void)sig; /* UNUSED */ 52237e3a6d3SLuigi Rizzo D("received control-C on thread %p", (void *)pthread_self()); 523f8e4e36aSLuigi Rizzo for (i = 0; i < global_nthreads; i++) { 524f8e4e36aSLuigi Rizzo targs[i].cancel = 1; 525f8e4e36aSLuigi Rizzo } 52668b8534bSLuigi Rizzo } 52768b8534bSLuigi Rizzo 52868b8534bSLuigi Rizzo /* sysctl wrapper to return the number of active CPUs */ 52968b8534bSLuigi Rizzo static int 53068b8534bSLuigi Rizzo system_ncpus(void) 53168b8534bSLuigi Rizzo { 532f0ea3689SLuigi Rizzo int ncpus; 533f0ea3689SLuigi Rizzo #if defined (__FreeBSD__) 534f0ea3689SLuigi Rizzo int mib[2] = { CTL_HW, HW_NCPU }; 535f0ea3689SLuigi Rizzo size_t len = sizeof(mib); 53668b8534bSLuigi Rizzo sysctl(mib, 2, &ncpus, &len, NULL, 0); 537f0ea3689SLuigi Rizzo #elif defined(linux) 538f0ea3689SLuigi Rizzo ncpus = sysconf(_SC_NPROCESSORS_ONLN); 53937e3a6d3SLuigi Rizzo #elif defined(_WIN32) 54037e3a6d3SLuigi Rizzo { 54137e3a6d3SLuigi Rizzo SYSTEM_INFO sysinfo; 54237e3a6d3SLuigi Rizzo GetSystemInfo(&sysinfo); 54337e3a6d3SLuigi Rizzo ncpus = sysinfo.dwNumberOfProcessors; 54437e3a6d3SLuigi Rizzo } 545f0ea3689SLuigi Rizzo #else /* others */ 546f0ea3689SLuigi Rizzo ncpus = 1; 547f0ea3689SLuigi Rizzo #endif /* others */ 54868b8534bSLuigi Rizzo return (ncpus); 54968b8534bSLuigi Rizzo } 55068b8534bSLuigi Rizzo 551f8e4e36aSLuigi Rizzo #ifdef __linux__ 552f8e4e36aSLuigi Rizzo #define sockaddr_dl sockaddr_ll 553f8e4e36aSLuigi Rizzo #define sdl_family sll_family 554f8e4e36aSLuigi Rizzo #define AF_LINK AF_PACKET 555f8e4e36aSLuigi Rizzo #define LLADDR(s) s->sll_addr; 556f8e4e36aSLuigi Rizzo #include <linux/if_tun.h> 557f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/net/tun" 558f8e4e36aSLuigi Rizzo #endif /* __linux__ */ 559f8e4e36aSLuigi Rizzo 560f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 561f8e4e36aSLuigi Rizzo #include <net/if_tun.h> 562f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 563f8e4e36aSLuigi Rizzo #endif /* __FreeBSD */ 564f8e4e36aSLuigi Rizzo 565f8e4e36aSLuigi Rizzo #ifdef __APPLE__ 566f8e4e36aSLuigi Rizzo // #warning TAP not supported on apple ? 567f8e4e36aSLuigi Rizzo #include <net/if_utun.h> 568f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 569f8e4e36aSLuigi Rizzo #endif /* __APPLE__ */ 570f8e4e36aSLuigi Rizzo 571f8e4e36aSLuigi Rizzo 57268b8534bSLuigi Rizzo /* 573ce3ee1e7SLuigi Rizzo * parse the vale configuration in conf and put it in nmr. 574f0ea3689SLuigi Rizzo * Return the flag set if necessary. 57580ad548dSVincenzo Maffione * The configuration may consist of 1 to 4 numbers separated 576fc6eb28bSHiren Panchasara * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. 577ce3ee1e7SLuigi Rizzo * Missing numbers or zeroes stand for default values. 578ce3ee1e7SLuigi Rizzo * As an additional convenience, if exactly one number 579fc6eb28bSHiren Panchasara * is specified, then this is assigned to both #tx-slots and #rx-slots. 580fc6eb28bSHiren Panchasara * If there is no 4th number, then the 3rd is assigned to both #tx-rings 581ce3ee1e7SLuigi Rizzo * and #rx-rings. 582ce3ee1e7SLuigi Rizzo */ 583f0ea3689SLuigi Rizzo int 584f0ea3689SLuigi Rizzo parse_nmr_config(const char* conf, struct nmreq *nmr) 585ce3ee1e7SLuigi Rizzo { 586ce3ee1e7SLuigi Rizzo char *w, *tok; 587ce3ee1e7SLuigi Rizzo int i, v; 588ce3ee1e7SLuigi Rizzo 589ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 590ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 591ce3ee1e7SLuigi Rizzo if (conf == NULL || ! *conf) 592f0ea3689SLuigi Rizzo return 0; 593ce3ee1e7SLuigi Rizzo w = strdup(conf); 594ce3ee1e7SLuigi Rizzo for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 595ce3ee1e7SLuigi Rizzo v = atoi(tok); 596ce3ee1e7SLuigi Rizzo switch (i) { 597ce3ee1e7SLuigi Rizzo case 0: 598ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = v; 599ce3ee1e7SLuigi Rizzo break; 600ce3ee1e7SLuigi Rizzo case 1: 601ce3ee1e7SLuigi Rizzo nmr->nr_rx_slots = v; 602ce3ee1e7SLuigi Rizzo break; 603ce3ee1e7SLuigi Rizzo case 2: 604ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = v; 605ce3ee1e7SLuigi Rizzo break; 606ce3ee1e7SLuigi Rizzo case 3: 607ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings = v; 608ce3ee1e7SLuigi Rizzo break; 609ce3ee1e7SLuigi Rizzo default: 610ce3ee1e7SLuigi Rizzo D("ignored config: %s", tok); 611ce3ee1e7SLuigi Rizzo break; 612ce3ee1e7SLuigi Rizzo } 613ce3ee1e7SLuigi Rizzo } 614ce3ee1e7SLuigi Rizzo D("txr %d txd %d rxr %d rxd %d", 615ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings, nmr->nr_tx_slots, 616ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings, nmr->nr_rx_slots); 617ce3ee1e7SLuigi Rizzo free(w); 618f0ea3689SLuigi Rizzo return (nmr->nr_tx_rings || nmr->nr_tx_slots || 619f0ea3689SLuigi Rizzo nmr->nr_rx_rings || nmr->nr_rx_slots) ? 620f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG : 0; 621ce3ee1e7SLuigi Rizzo } 622ce3ee1e7SLuigi Rizzo 623ce3ee1e7SLuigi Rizzo 624ce3ee1e7SLuigi Rizzo /* 62568b8534bSLuigi Rizzo * locate the src mac address for our interface, put it 62668b8534bSLuigi Rizzo * into the user-supplied buffer. return 0 if ok, -1 on error. 62768b8534bSLuigi Rizzo */ 62868b8534bSLuigi Rizzo static int 62968b8534bSLuigi Rizzo source_hwaddr(const char *ifname, char *buf) 63068b8534bSLuigi Rizzo { 63168b8534bSLuigi Rizzo struct ifaddrs *ifaphead, *ifap; 63268b8534bSLuigi Rizzo 63368b8534bSLuigi Rizzo if (getifaddrs(&ifaphead) != 0) { 63468b8534bSLuigi Rizzo D("getifaddrs %s failed", ifname); 63568b8534bSLuigi Rizzo return (-1); 63668b8534bSLuigi Rizzo } 63768b8534bSLuigi Rizzo 63868b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 63968b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 64068b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 64168b8534bSLuigi Rizzo uint8_t *mac; 64268b8534bSLuigi Rizzo 64368b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 64468b8534bSLuigi Rizzo continue; 64580ad548dSVincenzo Maffione if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) 64668b8534bSLuigi Rizzo continue; 64768b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 64868b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 64968b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 65068b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 65168b8534bSLuigi Rizzo if (verbose) 65268b8534bSLuigi Rizzo D("source hwaddr %s", buf); 65368b8534bSLuigi Rizzo break; 65468b8534bSLuigi Rizzo } 65568b8534bSLuigi Rizzo freeifaddrs(ifaphead); 65668b8534bSLuigi Rizzo return ifap ? 0 : 1; 65768b8534bSLuigi Rizzo } 65868b8534bSLuigi Rizzo 65968b8534bSLuigi Rizzo 66068b8534bSLuigi Rizzo /* set the thread affinity. */ 66168b8534bSLuigi Rizzo static int 66268b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 66368b8534bSLuigi Rizzo { 66468b8534bSLuigi Rizzo cpuset_t cpumask; 66568b8534bSLuigi Rizzo 66668b8534bSLuigi Rizzo if (i == -1) 66768b8534bSLuigi Rizzo return 0; 66868b8534bSLuigi Rizzo 66968b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 67068b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 67168b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 67268b8534bSLuigi Rizzo 67368b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 67417885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 67568b8534bSLuigi Rizzo return 1; 67668b8534bSLuigi Rizzo } 67768b8534bSLuigi Rizzo return 0; 67868b8534bSLuigi Rizzo } 67968b8534bSLuigi Rizzo 68080ad548dSVincenzo Maffione 68168b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 68280ad548dSVincenzo Maffione static uint32_t 683f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 68468b8534bSLuigi Rizzo { 68568b8534bSLuigi Rizzo const uint8_t *addr = data; 686f8e4e36aSLuigi Rizzo uint32_t i; 68768b8534bSLuigi Rizzo 688f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 689f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 690f8e4e36aSLuigi Rizzo sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); 691f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 692f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 693f8e4e36aSLuigi Rizzo } 694f8e4e36aSLuigi Rizzo /* 695f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 696f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 697f8e4e36aSLuigi Rizzo * the high byte. 698f8e4e36aSLuigi Rizzo */ 699f8e4e36aSLuigi Rizzo if (i < len) { 700f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 701f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 702f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 703f8e4e36aSLuigi Rizzo } 704f8e4e36aSLuigi Rizzo return sum; 70568b8534bSLuigi Rizzo } 70668b8534bSLuigi Rizzo 70780ad548dSVincenzo Maffione static uint16_t 70880ad548dSVincenzo Maffione wrapsum(uint32_t sum) 709f8e4e36aSLuigi Rizzo { 710f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 711f8e4e36aSLuigi Rizzo return (htons(sum)); 71268b8534bSLuigi Rizzo } 71368b8534bSLuigi Rizzo 714b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 715b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 716b303f675SLuigi Rizzo */ 717b303f675SLuigi Rizzo static void 71837e3a6d3SLuigi Rizzo dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) 719b303f675SLuigi Rizzo { 720b303f675SLuigi Rizzo char buf[128]; 721b303f675SLuigi Rizzo int i, j, i0; 72237e3a6d3SLuigi Rizzo const unsigned char *p = (const unsigned char *)_p; 723b303f675SLuigi Rizzo 724b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 725b303f675SLuigi Rizzo 726ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 727ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 728ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 729b303f675SLuigi Rizzo /* hexdump routine */ 730b303f675SLuigi Rizzo for (i = 0; i < len; ) { 731b797f66cSConrad Meyer memset(buf, ' ', sizeof(buf)); 732b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 733b303f675SLuigi Rizzo i0 = i; 734b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 735b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 736b303f675SLuigi Rizzo i = i0; 737b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 738b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 739b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 740b303f675SLuigi Rizzo printf("%s\n", buf); 741b303f675SLuigi Rizzo } 742b303f675SLuigi Rizzo } 743b303f675SLuigi Rizzo 74468b8534bSLuigi Rizzo /* 74568b8534bSLuigi Rizzo * Fill a packet with some payload. 746f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 747f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 74868b8534bSLuigi Rizzo */ 749f8e4e36aSLuigi Rizzo #ifdef __linux__ 750f8e4e36aSLuigi Rizzo #define uh_sport source 751f8e4e36aSLuigi Rizzo #define uh_dport dest 752f8e4e36aSLuigi Rizzo #define uh_ulen len 753f8e4e36aSLuigi Rizzo #define uh_sum check 754f8e4e36aSLuigi Rizzo #endif /* linux */ 755b303f675SLuigi Rizzo 756ce3ee1e7SLuigi Rizzo static void 75780ad548dSVincenzo Maffione update_ip(struct pkt *pkt, struct targ *t) 758ce3ee1e7SLuigi Rizzo { 75980ad548dSVincenzo Maffione struct glob_arg *g = t->g; 76080ad548dSVincenzo Maffione struct ip ip; 76180ad548dSVincenzo Maffione struct udphdr udp; 76280ad548dSVincenzo Maffione uint32_t oaddr, naddr; 76380ad548dSVincenzo Maffione uint16_t oport, nport; 76480ad548dSVincenzo Maffione uint16_t ip_sum, udp_sum; 765ce3ee1e7SLuigi Rizzo 76680ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 76780ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); 768f2637526SLuigi Rizzo do { 76980ad548dSVincenzo Maffione ip_sum = udp_sum = 0; 77080ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_src.s_addr); 77180ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 77256717743SAdrian Chadd if (g->options & OPT_RANDOM_SRC) { 77380ad548dSVincenzo Maffione ip.ip_src.s_addr = nrand48(t->seed); 77480ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 77580ad548dSVincenzo Maffione naddr = ntohl(ip.ip_src.s_addr); 77680ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 777f2637526SLuigi Rizzo break; 778ce3ee1e7SLuigi Rizzo } 77980ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 78080ad548dSVincenzo Maffione nport = oport + 1; 78180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 782f2637526SLuigi Rizzo break; 783ce3ee1e7SLuigi Rizzo } 78480ad548dSVincenzo Maffione nport = g->src_ip.port0; 78580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 78680ad548dSVincenzo Maffione if (oaddr < g->src_ip.ipv4.end) { 78780ad548dSVincenzo Maffione naddr = oaddr + 1; 78880ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 789f2637526SLuigi Rizzo break; 790ce3ee1e7SLuigi Rizzo } 79180ad548dSVincenzo Maffione naddr = g->src_ip.ipv4.start; 79280ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 793f2637526SLuigi Rizzo } while (0); 79480ad548dSVincenzo Maffione /* update checksums if needed */ 79580ad548dSVincenzo Maffione if (oaddr != naddr) { 79680ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 79780ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 79880ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 79980ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 80080ad548dSVincenzo Maffione } 80180ad548dSVincenzo Maffione if (oport != nport) { 80280ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 80380ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 80480ad548dSVincenzo Maffione } 80580ad548dSVincenzo Maffione do { 80680ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_dst.s_addr); 80780ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 80880ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 80980ad548dSVincenzo Maffione ip.ip_dst.s_addr = nrand48(t->seed); 81080ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 81180ad548dSVincenzo Maffione naddr = ntohl(ip.ip_dst.s_addr); 81280ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 81380ad548dSVincenzo Maffione break; 81480ad548dSVincenzo Maffione } 81580ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 81680ad548dSVincenzo Maffione nport = oport + 1; 81780ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 81880ad548dSVincenzo Maffione break; 81980ad548dSVincenzo Maffione } 82080ad548dSVincenzo Maffione nport = g->dst_ip.port0; 82180ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 82280ad548dSVincenzo Maffione if (oaddr < g->dst_ip.ipv4.end) { 82380ad548dSVincenzo Maffione naddr = oaddr + 1; 82480ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 82580ad548dSVincenzo Maffione break; 82680ad548dSVincenzo Maffione } 82780ad548dSVincenzo Maffione naddr = g->dst_ip.ipv4.start; 82880ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 82980ad548dSVincenzo Maffione } while (0); 83080ad548dSVincenzo Maffione /* update checksums */ 83180ad548dSVincenzo Maffione if (oaddr != naddr) { 83280ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 83380ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 83480ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 83580ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 83680ad548dSVincenzo Maffione } 83780ad548dSVincenzo Maffione if (oport != nport) { 83880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 83980ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 84080ad548dSVincenzo Maffione } 84180ad548dSVincenzo Maffione if (udp_sum != 0) 84280ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); 84380ad548dSVincenzo Maffione if (ip_sum != 0) { 84480ad548dSVincenzo Maffione ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); 84580ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); 84680ad548dSVincenzo Maffione } 84780ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 84880ad548dSVincenzo Maffione memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); 849ce3ee1e7SLuigi Rizzo } 850ce3ee1e7SLuigi Rizzo 85180ad548dSVincenzo Maffione #ifndef s6_addr16 85280ad548dSVincenzo Maffione #define s6_addr16 __u6_addr.__u6_addr16 85380ad548dSVincenzo Maffione #endif 85480ad548dSVincenzo Maffione static void 85580ad548dSVincenzo Maffione update_ip6(struct pkt *pkt, struct targ *t) 85680ad548dSVincenzo Maffione { 85780ad548dSVincenzo Maffione struct glob_arg *g = t->g; 85880ad548dSVincenzo Maffione struct ip6_hdr ip6; 85980ad548dSVincenzo Maffione struct udphdr udp; 86080ad548dSVincenzo Maffione uint16_t udp_sum; 86180ad548dSVincenzo Maffione uint16_t oaddr, naddr; 86280ad548dSVincenzo Maffione uint16_t oport, nport; 86380ad548dSVincenzo Maffione uint8_t group; 86480ad548dSVincenzo Maffione 86580ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); 86680ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); 86780ad548dSVincenzo Maffione do { 86880ad548dSVincenzo Maffione udp_sum = 0; 86980ad548dSVincenzo Maffione group = g->src_ip.ipv6.sgroup; 87080ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); 87180ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 87280ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_SRC) { 87380ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = nrand48(t->seed); 87480ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 87580ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_src.s6_addr16[group]); 87680ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 87780ad548dSVincenzo Maffione break; 87880ad548dSVincenzo Maffione } 87980ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 88080ad548dSVincenzo Maffione nport = oport + 1; 88180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 88280ad548dSVincenzo Maffione break; 88380ad548dSVincenzo Maffione } 88480ad548dSVincenzo Maffione nport = g->src_ip.port0; 88580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 88680ad548dSVincenzo Maffione if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { 88780ad548dSVincenzo Maffione naddr = oaddr + 1; 88880ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 88980ad548dSVincenzo Maffione break; 89080ad548dSVincenzo Maffione } 89180ad548dSVincenzo Maffione naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); 89280ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 89380ad548dSVincenzo Maffione } while (0); 89480ad548dSVincenzo Maffione /* update checksums if needed */ 89580ad548dSVincenzo Maffione if (oaddr != naddr) 89680ad548dSVincenzo Maffione udp_sum = cksum_add(~oaddr, naddr); 89780ad548dSVincenzo Maffione if (oport != nport) 89880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 89980ad548dSVincenzo Maffione cksum_add(~oport, nport)); 90080ad548dSVincenzo Maffione do { 90180ad548dSVincenzo Maffione group = g->dst_ip.ipv6.egroup; 90280ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 90380ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 90480ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 90580ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed); 90680ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 90780ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 90880ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 90980ad548dSVincenzo Maffione break; 91080ad548dSVincenzo Maffione } 91180ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 91280ad548dSVincenzo Maffione nport = oport + 1; 91380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 91480ad548dSVincenzo Maffione break; 91580ad548dSVincenzo Maffione } 91680ad548dSVincenzo Maffione nport = g->dst_ip.port0; 91780ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 91880ad548dSVincenzo Maffione if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { 91980ad548dSVincenzo Maffione naddr = oaddr + 1; 92080ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 92180ad548dSVincenzo Maffione break; 92280ad548dSVincenzo Maffione } 92380ad548dSVincenzo Maffione naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); 92480ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 92580ad548dSVincenzo Maffione } while (0); 92680ad548dSVincenzo Maffione /* update checksums */ 92780ad548dSVincenzo Maffione if (oaddr != naddr) 92880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 92980ad548dSVincenzo Maffione cksum_add(~oaddr, naddr)); 93080ad548dSVincenzo Maffione if (oport != nport) 93180ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 93280ad548dSVincenzo Maffione cksum_add(~oport, nport)); 93380ad548dSVincenzo Maffione if (udp_sum != 0) 93480ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); 93580ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 93680ad548dSVincenzo Maffione memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); 93780ad548dSVincenzo Maffione } 93880ad548dSVincenzo Maffione 93980ad548dSVincenzo Maffione static void 94080ad548dSVincenzo Maffione update_addresses(struct pkt *pkt, struct targ *t) 94180ad548dSVincenzo Maffione { 94280ad548dSVincenzo Maffione 94380ad548dSVincenzo Maffione if (t->g->af == AF_INET) 94480ad548dSVincenzo Maffione update_ip(pkt, t); 94580ad548dSVincenzo Maffione else 94680ad548dSVincenzo Maffione update_ip6(pkt, t); 94780ad548dSVincenzo Maffione } 948ce3ee1e7SLuigi Rizzo /* 949ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 950ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 951ce3ee1e7SLuigi Rizzo */ 95268b8534bSLuigi Rizzo static void 95368b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 95468b8534bSLuigi Rizzo { 95568b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 95668b8534bSLuigi Rizzo struct ether_header *eh; 95780ad548dSVincenzo Maffione struct ip6_hdr ip6; 95880ad548dSVincenzo Maffione struct ip ip; 95980ad548dSVincenzo Maffione struct udphdr udp; 96080ad548dSVincenzo Maffione void *udp_ptr; 96180ad548dSVincenzo Maffione uint16_t paylen; 96280ad548dSVincenzo Maffione uint32_t csum = 0; 963b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 964ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 965f2637526SLuigi Rizzo int i, l0 = strlen(payload); 96668b8534bSLuigi Rizzo 96737e3a6d3SLuigi Rizzo #ifndef NO_PCAP 968f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 969f284c737SGeorge V. Neville-Neil pcap_t *file; 970f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 971f284c737SGeorge V. Neville-Neil const unsigned char *packet; 972f284c737SGeorge V. Neville-Neil 973f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 974f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 975f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 976f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 977f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 978f284c737SGeorge V. Neville-Neil targ->g->packet_file); 979f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 980f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 981f284c737SGeorge V. Neville-Neil targ->g->packet_file); 982f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 983f284c737SGeorge V. Neville-Neil D("out of memory"); 984f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 985f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 986f284c737SGeorge V. Neville-Neil pcap_close(file); 987f284c737SGeorge V. Neville-Neil return; 988f284c737SGeorge V. Neville-Neil } 98937e3a6d3SLuigi Rizzo #endif 990f284c737SGeorge V. Neville-Neil 99180ad548dSVincenzo Maffione paylen = targ->g->pkt_size - sizeof(*eh) - 99280ad548dSVincenzo Maffione (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); 99380ad548dSVincenzo Maffione 994ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 995f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 996f2637526SLuigi Rizzo if (l0 > paylen - i) 997f2637526SLuigi Rizzo l0 = paylen - i; // last round 99880ad548dSVincenzo Maffione bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0); 99968b8534bSLuigi Rizzo } 100080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[i - 1] = '\0'; 1001f8e4e36aSLuigi Rizzo 1002ce3ee1e7SLuigi Rizzo /* prepare the headers */ 100368b8534bSLuigi Rizzo eh = &pkt->eh; 1004f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 1005f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 100680ad548dSVincenzo Maffione 100780ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 100868b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 100980ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 101080ad548dSVincenzo Maffione udp_ptr = &pkt->ipv4.udp; 101180ad548dSVincenzo Maffione ip.ip_v = IPVERSION; 101280ad548dSVincenzo Maffione ip.ip_hl = sizeof(ip) >> 2; 101380ad548dSVincenzo Maffione ip.ip_id = 0; 101480ad548dSVincenzo Maffione ip.ip_tos = IPTOS_LOWDELAY; 101580ad548dSVincenzo Maffione ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); 101680ad548dSVincenzo Maffione ip.ip_id = 0; 101780ad548dSVincenzo Maffione ip.ip_off = htons(IP_DF); /* Don't fragment */ 101880ad548dSVincenzo Maffione ip.ip_ttl = IPDEFTTL; 101980ad548dSVincenzo Maffione ip.ip_p = IPPROTO_UDP; 102080ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); 102180ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); 102280ad548dSVincenzo Maffione ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); 102380ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 102480ad548dSVincenzo Maffione } else { 102580ad548dSVincenzo Maffione eh->ether_type = htons(ETHERTYPE_IPV6); 102680ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); 102780ad548dSVincenzo Maffione udp_ptr = &pkt->ipv6.udp; 102880ad548dSVincenzo Maffione ip6.ip6_flow = 0; 102980ad548dSVincenzo Maffione ip6.ip6_plen = htons(paylen); 103080ad548dSVincenzo Maffione ip6.ip6_vfc = IPV6_VERSION; 103180ad548dSVincenzo Maffione ip6.ip6_nxt = IPPROTO_UDP; 103280ad548dSVincenzo Maffione ip6.ip6_hlim = IPV6_DEFHLIM; 103380ad548dSVincenzo Maffione ip6.ip6_src = targ->g->src_ip.ipv6.start; 103480ad548dSVincenzo Maffione ip6.ip6_dst = targ->g->dst_ip.ipv6.start; 103580ad548dSVincenzo Maffione } 103680ad548dSVincenzo Maffione memcpy(&udp, udp_ptr, sizeof(udp)); 103780ad548dSVincenzo Maffione 103880ad548dSVincenzo Maffione udp.uh_sport = htons(targ->g->src_ip.port0); 103980ad548dSVincenzo Maffione udp.uh_dport = htons(targ->g->dst_ip.port0); 104080ad548dSVincenzo Maffione udp.uh_ulen = htons(paylen); 104180ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 104280ad548dSVincenzo Maffione /* Magic: taken from sbin/dhclient/packet.c */ 104380ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 104480ad548dSVincenzo Maffione checksum(&udp, sizeof(udp), /* udp header */ 104580ad548dSVincenzo Maffione checksum(pkt->ipv4.body, /* udp payload */ 104680ad548dSVincenzo Maffione paylen - sizeof(udp), 104780ad548dSVincenzo Maffione checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 104880ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv4.ip.ip_src), 104980ad548dSVincenzo Maffione IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); 105080ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 105180ad548dSVincenzo Maffione } else { 105280ad548dSVincenzo Maffione /* Save part of pseudo header checksum into csum */ 105380ad548dSVincenzo Maffione csum = IPPROTO_UDP << 24; 105480ad548dSVincenzo Maffione csum = checksum(&csum, sizeof(csum), paylen); 105580ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 105680ad548dSVincenzo Maffione checksum(udp_ptr, sizeof(udp), /* udp header */ 105780ad548dSVincenzo Maffione checksum(pkt->ipv6.body, /* udp payload */ 105880ad548dSVincenzo Maffione paylen - sizeof(udp), 105980ad548dSVincenzo Maffione checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 106080ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); 106180ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 106280ad548dSVincenzo Maffione } 106380ad548dSVincenzo Maffione memcpy(udp_ptr, &udp, sizeof(udp)); 106417885a7bSLuigi Rizzo 106517885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 1066b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 106768b8534bSLuigi Rizzo } 106868b8534bSLuigi Rizzo 10694bf50f18SLuigi Rizzo static void 107037e3a6d3SLuigi Rizzo get_vnet_hdr_len(struct glob_arg *g) 10714bf50f18SLuigi Rizzo { 107237e3a6d3SLuigi Rizzo struct nmreq req; 107337e3a6d3SLuigi Rizzo int err; 107437e3a6d3SLuigi Rizzo 107537e3a6d3SLuigi Rizzo memset(&req, 0, sizeof(req)); 107637e3a6d3SLuigi Rizzo bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); 107737e3a6d3SLuigi Rizzo req.nr_version = NETMAP_API; 107837e3a6d3SLuigi Rizzo req.nr_cmd = NETMAP_VNET_HDR_GET; 107937e3a6d3SLuigi Rizzo err = ioctl(g->main_fd, NIOCREGIF, &req); 108037e3a6d3SLuigi Rizzo if (err) { 108137e3a6d3SLuigi Rizzo D("Unable to get virtio-net header length"); 108237e3a6d3SLuigi Rizzo return; 108337e3a6d3SLuigi Rizzo } 108437e3a6d3SLuigi Rizzo 108537e3a6d3SLuigi Rizzo g->virt_header = req.nr_arg1; 108637e3a6d3SLuigi Rizzo if (g->virt_header) { 108737e3a6d3SLuigi Rizzo D("Port requires virtio-net header, length = %d", 108837e3a6d3SLuigi Rizzo g->virt_header); 108937e3a6d3SLuigi Rizzo } 109037e3a6d3SLuigi Rizzo } 109137e3a6d3SLuigi Rizzo 109237e3a6d3SLuigi Rizzo static void 109337e3a6d3SLuigi Rizzo set_vnet_hdr_len(struct glob_arg *g) 109437e3a6d3SLuigi Rizzo { 109537e3a6d3SLuigi Rizzo int err, l = g->virt_header; 10964bf50f18SLuigi Rizzo struct nmreq req; 10974bf50f18SLuigi Rizzo 10984bf50f18SLuigi Rizzo if (l == 0) 10994bf50f18SLuigi Rizzo return; 11004bf50f18SLuigi Rizzo 11014bf50f18SLuigi Rizzo memset(&req, 0, sizeof(req)); 110237e3a6d3SLuigi Rizzo bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); 11034bf50f18SLuigi Rizzo req.nr_version = NETMAP_API; 11044bf50f18SLuigi Rizzo req.nr_cmd = NETMAP_BDG_VNET_HDR; 11054bf50f18SLuigi Rizzo req.nr_arg1 = l; 110637e3a6d3SLuigi Rizzo err = ioctl(g->main_fd, NIOCREGIF, &req); 11074bf50f18SLuigi Rizzo if (err) { 110837e3a6d3SLuigi Rizzo D("Unable to set virtio-net header length %d", l); 11094bf50f18SLuigi Rizzo } 11104bf50f18SLuigi Rizzo } 111168b8534bSLuigi Rizzo 111268b8534bSLuigi Rizzo /* 111368b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 111468b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 111568b8534bSLuigi Rizzo * an interrupt when done. 111668b8534bSLuigi Rizzo */ 111768b8534bSLuigi Rizzo static int 111817885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 111980ad548dSVincenzo Maffione int size, struct targ *t, u_int count, int options) 112068b8534bSLuigi Rizzo { 112117885a7bSLuigi Rizzo u_int n, sent, cur = ring->cur; 112280ad548dSVincenzo Maffione u_int frags = t->frags; 112380ad548dSVincenzo Maffione u_int frag_size = t->frag_size; 112480ad548dSVincenzo Maffione struct netmap_slot *slot = &ring->slot[cur]; 112568b8534bSLuigi Rizzo 112617885a7bSLuigi Rizzo n = nm_ring_space(ring); 112799fb123fSLuigi Rizzo #if 0 112899fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 112968b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 113068b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 113168b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 113268b8534bSLuigi Rizzo 1133f2637526SLuigi Rizzo __builtin_prefetch(p); 113417885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 113599fb123fSLuigi Rizzo } 113699fb123fSLuigi Rizzo cur = ring->cur; 113799fb123fSLuigi Rizzo } 113899fb123fSLuigi Rizzo #endif 113980ad548dSVincenzo Maffione for (sent = 0; sent < count && n >= frags; sent++, n--) { 114080ad548dSVincenzo Maffione char *p; 114180ad548dSVincenzo Maffione int buf_changed; 114280ad548dSVincenzo Maffione u_int tosend = size; 114380ad548dSVincenzo Maffione 114480ad548dSVincenzo Maffione slot = &ring->slot[cur]; 114580ad548dSVincenzo Maffione p = NETMAP_BUF(ring, slot->buf_idx); 114680ad548dSVincenzo Maffione buf_changed = slot->flags & NS_BUF_CHANGED; 114799fb123fSLuigi Rizzo 1148b303f675SLuigi Rizzo slot->flags = 0; 114937e3a6d3SLuigi Rizzo if (options & OPT_RUBBISH) { 115037e3a6d3SLuigi Rizzo /* do nothing */ 115137e3a6d3SLuigi Rizzo } else if (options & OPT_INDIRECT) { 1152b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 115337e3a6d3SLuigi Rizzo slot->ptr = (uint64_t)((uintptr_t)frame); 115480ad548dSVincenzo Maffione } else if (frags > 1) { 115580ad548dSVincenzo Maffione u_int i; 115680ad548dSVincenzo Maffione const char *f = frame; 115780ad548dSVincenzo Maffione char *fp = p; 115880ad548dSVincenzo Maffione for (i = 0; i < frags - 1; i++) { 115980ad548dSVincenzo Maffione memcpy(fp, f, frag_size); 116080ad548dSVincenzo Maffione slot->len = frag_size; 116180ad548dSVincenzo Maffione slot->flags = NS_MOREFRAG; 116280ad548dSVincenzo Maffione if (options & OPT_DUMP) 116380ad548dSVincenzo Maffione dump_payload(fp, frag_size, ring, cur); 116480ad548dSVincenzo Maffione tosend -= frag_size; 116580ad548dSVincenzo Maffione f += frag_size; 116680ad548dSVincenzo Maffione cur = nm_ring_next(ring, cur); 116780ad548dSVincenzo Maffione slot = &ring->slot[cur]; 116880ad548dSVincenzo Maffione fp = NETMAP_BUF(ring, slot->buf_idx); 116980ad548dSVincenzo Maffione } 117080ad548dSVincenzo Maffione n -= (frags - 1); 117180ad548dSVincenzo Maffione p = fp; 117280ad548dSVincenzo Maffione slot->flags = 0; 117380ad548dSVincenzo Maffione memcpy(p, f, tosend); 117480ad548dSVincenzo Maffione update_addresses(pkt, t); 117580ad548dSVincenzo Maffione } else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) { 117680ad548dSVincenzo Maffione if (options & OPT_COPY) 1177f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 117880ad548dSVincenzo Maffione else 117917885a7bSLuigi Rizzo memcpy(p, frame, size); 118080ad548dSVincenzo Maffione update_addresses(pkt, t); 1181ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 1182f2637526SLuigi Rizzo __builtin_prefetch(p); 1183ce3ee1e7SLuigi Rizzo } 118480ad548dSVincenzo Maffione slot->len = tosend; 1185ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 118680ad548dSVincenzo Maffione dump_payload(p, tosend, ring, cur); 118717885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 118868b8534bSLuigi Rizzo } 118980ad548dSVincenzo Maffione if (sent) { 119080ad548dSVincenzo Maffione slot->flags |= NS_REPORT; 119117885a7bSLuigi Rizzo ring->head = ring->cur = cur; 119280ad548dSVincenzo Maffione } 119380ad548dSVincenzo Maffione if (sent < count) { 119480ad548dSVincenzo Maffione /* tell netmap that we need more slots */ 119580ad548dSVincenzo Maffione ring->cur = ring->tail; 119680ad548dSVincenzo Maffione } 119768b8534bSLuigi Rizzo 119868b8534bSLuigi Rizzo return (sent); 119968b8534bSLuigi Rizzo } 120068b8534bSLuigi Rizzo 1201f8e4e36aSLuigi Rizzo /* 120237e3a6d3SLuigi Rizzo * Index of the highest bit set 120337e3a6d3SLuigi Rizzo */ 120437e3a6d3SLuigi Rizzo uint32_t 120537e3a6d3SLuigi Rizzo msb64(uint64_t x) 120637e3a6d3SLuigi Rizzo { 120737e3a6d3SLuigi Rizzo uint64_t m = 1ULL << 63; 120837e3a6d3SLuigi Rizzo int i; 120937e3a6d3SLuigi Rizzo 121037e3a6d3SLuigi Rizzo for (i = 63; i >= 0; i--, m >>=1) 121137e3a6d3SLuigi Rizzo if (m & x) 121237e3a6d3SLuigi Rizzo return i; 121337e3a6d3SLuigi Rizzo return 0; 121437e3a6d3SLuigi Rizzo } 121537e3a6d3SLuigi Rizzo 121637e3a6d3SLuigi Rizzo /* 121780ad548dSVincenzo Maffione * wait until ts, either busy or sleeping if more than 1ms. 121880ad548dSVincenzo Maffione * Return wakeup time. 121980ad548dSVincenzo Maffione */ 122080ad548dSVincenzo Maffione static struct timespec 122180ad548dSVincenzo Maffione wait_time(struct timespec ts) 122280ad548dSVincenzo Maffione { 122380ad548dSVincenzo Maffione for (;;) { 122480ad548dSVincenzo Maffione struct timespec w, cur; 122580ad548dSVincenzo Maffione clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 122680ad548dSVincenzo Maffione w = timespec_sub(ts, cur); 122780ad548dSVincenzo Maffione if (w.tv_sec < 0) 122880ad548dSVincenzo Maffione return cur; 122980ad548dSVincenzo Maffione else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 123080ad548dSVincenzo Maffione poll(NULL, 0, 1); 123180ad548dSVincenzo Maffione } 123280ad548dSVincenzo Maffione } 123380ad548dSVincenzo Maffione 123480ad548dSVincenzo Maffione /* 1235f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 1236f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 1237f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 1238f8e4e36aSLuigi Rizzo */ 1239f8e4e36aSLuigi Rizzo 124068b8534bSLuigi Rizzo static void * 124180ad548dSVincenzo Maffione ping_body(void *data) 124268b8534bSLuigi Rizzo { 124368b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1244f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1245f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 124680ad548dSVincenzo Maffione int i, m, rx = 0; 124717885a7bSLuigi Rizzo void *frame; 124817885a7bSLuigi Rizzo int size; 1249f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 125080ad548dSVincenzo Maffione struct timespec nexttime = {0, 0}; /* silence compiler */ 125137e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 125237e3a6d3SLuigi Rizzo uint64_t count = 0, t_cur, t_min = ~0, av = 0; 125380ad548dSVincenzo Maffione uint64_t g_min = ~0, g_av = 0; 125437e3a6d3SLuigi Rizzo uint64_t buckets[64]; /* bins for delays, ns */ 125580ad548dSVincenzo Maffione int rate_limit = targ->g->tx_rate, tosend = 0; 125617885a7bSLuigi Rizzo 125780ad548dSVincenzo Maffione frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header; 125817885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1259e5ecae38SEd Maste 126037e3a6d3SLuigi Rizzo 1261f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1262f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 1263f8e4e36aSLuigi Rizzo return NULL; 1264f95a30bdSEd Maste } 1265f8e4e36aSLuigi Rizzo 126637e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1267f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 126817885a7bSLuigi Rizzo now = last_print; 126980ad548dSVincenzo Maffione if (rate_limit) { 127080ad548dSVincenzo Maffione targ->tic = timespec_add(now, (struct timespec){2,0}); 127180ad548dSVincenzo Maffione targ->tic.tv_nsec = 0; 127280ad548dSVincenzo Maffione wait_time(targ->tic); 127380ad548dSVincenzo Maffione nexttime = targ->tic; 127480ad548dSVincenzo Maffione } 127537e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 127680ad548dSVincenzo Maffione struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1277f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 1278f8e4e36aSLuigi Rizzo char *p; 127980ad548dSVincenzo Maffione int rv; 128080ad548dSVincenzo Maffione uint64_t limit, event = 0; 128180ad548dSVincenzo Maffione 128280ad548dSVincenzo Maffione if (rate_limit && tosend <= 0) { 128380ad548dSVincenzo Maffione tosend = targ->g->burst; 128480ad548dSVincenzo Maffione nexttime = timespec_add(nexttime, targ->g->tx_period); 128580ad548dSVincenzo Maffione wait_time(nexttime); 128680ad548dSVincenzo Maffione } 128780ad548dSVincenzo Maffione 128880ad548dSVincenzo Maffione limit = rate_limit ? tosend : targ->g->burst; 128980ad548dSVincenzo Maffione if (n > 0 && n - sent < limit) 129080ad548dSVincenzo Maffione limit = n - sent; 129180ad548dSVincenzo Maffione for (m = 0; (unsigned)m < limit; m++) { 1292f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 129317885a7bSLuigi Rizzo slot->len = size; 1294f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1295f8e4e36aSLuigi Rizzo 129617885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 1297f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 129880ad548dSVincenzo Maffione break; 1299f8e4e36aSLuigi Rizzo } else { 13004bf50f18SLuigi Rizzo struct tstamp *tp; 1301f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 1302f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 1303f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 13044bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13054bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 13064bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 1307f8e4e36aSLuigi Rizzo sent++; 130817885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 1309f8e4e36aSLuigi Rizzo } 1310f8e4e36aSLuigi Rizzo } 131180ad548dSVincenzo Maffione if (m > 0) 131280ad548dSVincenzo Maffione event++; 131380ad548dSVincenzo Maffione targ->ctr.pkts = sent; 131480ad548dSVincenzo Maffione targ->ctr.bytes = sent*size; 131580ad548dSVincenzo Maffione targ->ctr.events = event; 131680ad548dSVincenzo Maffione if (rate_limit) 131780ad548dSVincenzo Maffione tosend -= m; 131880ad548dSVincenzo Maffione #ifdef BUSYWAIT 131980ad548dSVincenzo Maffione rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); 132080ad548dSVincenzo Maffione if (rv < 0) { 132180ad548dSVincenzo Maffione D("TXSYNC error on queue %d: %s", targ->me, 132217885a7bSLuigi Rizzo strerror(errno)); 132380ad548dSVincenzo Maffione } 132480ad548dSVincenzo Maffione again: 132580ad548dSVincenzo Maffione ioctl(pfd.fd, NIOCRXSYNC, NULL); 132680ad548dSVincenzo Maffione #else 132780ad548dSVincenzo Maffione /* should use a parameter to decide how often to send */ 132880ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 3000)) <= 0) { 132980ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 133080ad548dSVincenzo Maffione (rv ? strerror(errno) : "timeout")); 1331f8e4e36aSLuigi Rizzo continue; 1332f8e4e36aSLuigi Rizzo } 133380ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1334f8e4e36aSLuigi Rizzo /* see what we got back */ 133580ad548dSVincenzo Maffione rx = 0; 133680ad548dSVincenzo Maffione for (i = targ->nmd->first_rx_ring; 133780ad548dSVincenzo Maffione i <= targ->nmd->last_rx_ring; i++) { 1338f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 133917885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 1340f8e4e36aSLuigi Rizzo uint32_t seq; 13414bf50f18SLuigi Rizzo struct tstamp *tp; 134237e3a6d3SLuigi Rizzo int pos; 134337e3a6d3SLuigi Rizzo 1344f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 1345f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1346f8e4e36aSLuigi Rizzo 1347f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 1348f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 13494bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13504bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 13514bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 1352f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 1353f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 1354f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1355f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1356f8e4e36aSLuigi Rizzo ts.tv_sec--; 1357f8e4e36aSLuigi Rizzo } 135880ad548dSVincenzo Maffione if (0) D("seq %d/%llu delta %d.%09d", seq, 135980ad548dSVincenzo Maffione (unsigned long long)sent, 1360f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 136137e3a6d3SLuigi Rizzo t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; 136237e3a6d3SLuigi Rizzo if (t_cur < t_min) 136337e3a6d3SLuigi Rizzo t_min = t_cur; 1364f8e4e36aSLuigi Rizzo count ++; 136537e3a6d3SLuigi Rizzo av += t_cur; 136637e3a6d3SLuigi Rizzo pos = msb64(t_cur); 136737e3a6d3SLuigi Rizzo buckets[pos]++; 136837e3a6d3SLuigi Rizzo /* now store it in a bucket */ 136917885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 1370f8e4e36aSLuigi Rizzo rx++; 1371f8e4e36aSLuigi Rizzo } 1372f8e4e36aSLuigi Rizzo } 1373f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1374f8e4e36aSLuigi Rizzo //usleep(100000); 1375f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 1376f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 1377f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1378f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1379f8e4e36aSLuigi Rizzo ts.tv_sec--; 1380f8e4e36aSLuigi Rizzo } 1381f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 138237e3a6d3SLuigi Rizzo D("count %d RTT: min %d av %d ns", 138337e3a6d3SLuigi Rizzo (int)count, (int)t_min, (int)(av/count)); 138480ad548dSVincenzo Maffione int k, j, kmin, off; 138537e3a6d3SLuigi Rizzo char buf[512]; 138637e3a6d3SLuigi Rizzo 138737e3a6d3SLuigi Rizzo for (kmin = 0; kmin < 64; kmin ++) 138837e3a6d3SLuigi Rizzo if (buckets[kmin]) 138937e3a6d3SLuigi Rizzo break; 139037e3a6d3SLuigi Rizzo for (k = 63; k >= kmin; k--) 139137e3a6d3SLuigi Rizzo if (buckets[k]) 139237e3a6d3SLuigi Rizzo break; 139337e3a6d3SLuigi Rizzo buf[0] = '\0'; 139480ad548dSVincenzo Maffione off = 0; 139580ad548dSVincenzo Maffione for (j = kmin; j <= k; j++) { 139680ad548dSVincenzo Maffione off += sprintf(buf + off, " %5d", (int)buckets[j]); 139780ad548dSVincenzo Maffione } 139837e3a6d3SLuigi Rizzo D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf); 139937e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1400f8e4e36aSLuigi Rizzo count = 0; 140180ad548dSVincenzo Maffione g_av += av; 1402f8e4e36aSLuigi Rizzo av = 0; 140380ad548dSVincenzo Maffione if (t_min < g_min) 140480ad548dSVincenzo Maffione g_min = t_min; 140537e3a6d3SLuigi Rizzo t_min = ~0; 1406f8e4e36aSLuigi Rizzo last_print = now; 1407f8e4e36aSLuigi Rizzo } 140880ad548dSVincenzo Maffione #ifdef BUSYWAIT 140980ad548dSVincenzo Maffione if (rx < m && ts.tv_sec <= 3 && !targ->cancel) 141080ad548dSVincenzo Maffione goto again; 141180ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1412f8e4e36aSLuigi Rizzo } 141337e3a6d3SLuigi Rizzo 141480ad548dSVincenzo Maffione if (sent > 0) { 141580ad548dSVincenzo Maffione D("RTT over %llu packets: min %d av %d ns", 141680ad548dSVincenzo Maffione (long long unsigned)sent, (int)g_min, 141780ad548dSVincenzo Maffione (int)((double)g_av/sent)); 141880ad548dSVincenzo Maffione } 141980ad548dSVincenzo Maffione targ->completed = 1; 142080ad548dSVincenzo Maffione 142137e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 142237e3a6d3SLuigi Rizzo targ->used = 0; 142337e3a6d3SLuigi Rizzo 1424f8e4e36aSLuigi Rizzo return NULL; 1425f8e4e36aSLuigi Rizzo } 1426f8e4e36aSLuigi Rizzo 1427f8e4e36aSLuigi Rizzo 1428f8e4e36aSLuigi Rizzo /* 1429f8e4e36aSLuigi Rizzo * reply to ping requests 1430f8e4e36aSLuigi Rizzo */ 1431f8e4e36aSLuigi Rizzo static void * 143280ad548dSVincenzo Maffione pong_body(void *data) 1433f8e4e36aSLuigi Rizzo { 1434f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1435f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1436f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 1437f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 143837e3a6d3SLuigi Rizzo int i, rx = 0; 143937e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 1440f8e4e36aSLuigi Rizzo 1441f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1442f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 1443f8e4e36aSLuigi Rizzo return NULL; 1444f8e4e36aSLuigi Rizzo } 144580ad548dSVincenzo Maffione if (n > 0) 144680ad548dSVincenzo Maffione D("understood ponger %llu but don't know how to do it", 144780ad548dSVincenzo Maffione (unsigned long long)n); 144837e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 1449f8e4e36aSLuigi Rizzo uint32_t txcur, txavail; 1450f8e4e36aSLuigi Rizzo //#define BUSYWAIT 1451f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1452f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 1453f8e4e36aSLuigi Rizzo #else 145480ad548dSVincenzo Maffione int rv; 145580ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 1000)) <= 0) { 145680ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 145780ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1458f8e4e36aSLuigi Rizzo continue; 1459f8e4e36aSLuigi Rizzo } 1460f8e4e36aSLuigi Rizzo #endif 146180ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1462f8e4e36aSLuigi Rizzo txcur = txring->cur; 146317885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 1464f8e4e36aSLuigi Rizzo /* see what we got back */ 1465f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 1466f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 146717885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 1468f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 1469f8e4e36aSLuigi Rizzo uint32_t cur = rxring->cur; 1470f8e4e36aSLuigi Rizzo struct netmap_slot *slot = &rxring->slot[cur]; 1471f8e4e36aSLuigi Rizzo char *src, *dst; 1472f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 1473f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 147417885a7bSLuigi Rizzo rxring->head = rxring->cur = nm_ring_next(rxring, cur); 1475f8e4e36aSLuigi Rizzo rx++; 1476f8e4e36aSLuigi Rizzo if (txavail == 0) 1477f8e4e36aSLuigi Rizzo continue; 1478f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 1479f8e4e36aSLuigi Rizzo txring->slot[txcur].buf_idx); 1480f8e4e36aSLuigi Rizzo /* copy... */ 1481f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 1482f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 1483f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 148480ad548dSVincenzo Maffione /* swap source and destination MAC */ 1485f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 1486f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 1487f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 1488f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 1489f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 1490f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 1491f8e4e36aSLuigi Rizzo txring->slot[txcur].len = slot->len; 149217885a7bSLuigi Rizzo txcur = nm_ring_next(txring, txcur); 1493f8e4e36aSLuigi Rizzo txavail--; 1494f8e4e36aSLuigi Rizzo sent++; 1495f8e4e36aSLuigi Rizzo } 1496f8e4e36aSLuigi Rizzo } 149717885a7bSLuigi Rizzo txring->head = txring->cur = txcur; 149837e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 1499f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1500f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 1501f8e4e36aSLuigi Rizzo #endif 1502f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1503f8e4e36aSLuigi Rizzo } 150437e3a6d3SLuigi Rizzo 150580ad548dSVincenzo Maffione targ->completed = 1; 150680ad548dSVincenzo Maffione 150737e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 150837e3a6d3SLuigi Rizzo targ->used = 0; 150937e3a6d3SLuigi Rizzo 1510f8e4e36aSLuigi Rizzo return NULL; 1511f8e4e36aSLuigi Rizzo } 1512f8e4e36aSLuigi Rizzo 1513f8e4e36aSLuigi Rizzo 1514f8e4e36aSLuigi Rizzo static void * 1515f8e4e36aSLuigi Rizzo sender_body(void *data) 1516f8e4e36aSLuigi Rizzo { 1517f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1518f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 15194bf50f18SLuigi Rizzo struct netmap_if *nifp; 152037e3a6d3SLuigi Rizzo struct netmap_ring *txring = NULL; 152137e3a6d3SLuigi Rizzo int i; 152237e3a6d3SLuigi Rizzo uint64_t n = targ->g->npackets / targ->g->nthreads; 152337e3a6d3SLuigi Rizzo uint64_t sent = 0; 152437e3a6d3SLuigi Rizzo uint64_t event = 0; 1525f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 152617885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 15271cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 152817885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 152917885a7bSLuigi Rizzo void *frame; 153017885a7bSLuigi Rizzo int size; 153117885a7bSLuigi Rizzo 1532f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 153380ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 153417885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1535f284c737SGeorge V. Neville-Neil } else { 1536f284c737SGeorge V. Neville-Neil frame = targ->frame; 1537f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1538f284c737SGeorge V. Neville-Neil } 1539b303f675SLuigi Rizzo 15404bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 154168b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 154268b8534bSLuigi Rizzo goto quit; 154368b8534bSLuigi Rizzo 154468b8534bSLuigi Rizzo /* main loop.*/ 15451cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 15461cb4c501SLuigi Rizzo if (rate_limit) { 154717885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 15481cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 154917885a7bSLuigi Rizzo wait_time(targ->tic); 15501cb4c501SLuigi Rizzo nexttime = targ->tic; 15511cb4c501SLuigi Rizzo } 1552f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1553f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1554f8e4e36aSLuigi Rizzo 1555f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 155617885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1557f8e4e36aSLuigi Rizzo sent++; 155880ad548dSVincenzo Maffione update_addresses(pkt, targ); 1559f8e4e36aSLuigi Rizzo if (i > 10000) { 156037e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 156137e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 156237e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1563f8e4e36aSLuigi Rizzo i = 0; 1564f8e4e36aSLuigi Rizzo } 1565f8e4e36aSLuigi Rizzo } 1566f2637526SLuigi Rizzo #ifndef NO_PCAP 1567f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1568f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1569f2637526SLuigi Rizzo 1570f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1571f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1572f2637526SLuigi Rizzo sent++; 157380ad548dSVincenzo Maffione update_addresses(pkt, targ); 1574f2637526SLuigi Rizzo if (i > 10000) { 157537e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 157637e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 157737e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1578f2637526SLuigi Rizzo i = 0; 1579f2637526SLuigi Rizzo } 1580f2637526SLuigi Rizzo } 1581f2637526SLuigi Rizzo #endif /* NO_PCAP */ 158268b8534bSLuigi Rizzo } else { 15831cb4c501SLuigi Rizzo int tosend = 0; 158480ad548dSVincenzo Maffione u_int bufsz, mtu = targ->g->mtu; 1585ce3ee1e7SLuigi Rizzo 15864bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 158780ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 158880ad548dSVincenzo Maffione bufsz = txring->nr_buf_size; 158980ad548dSVincenzo Maffione if (bufsz < mtu) 159080ad548dSVincenzo Maffione mtu = bufsz; 159180ad548dSVincenzo Maffione targ->frag_size = targ->g->pkt_size / targ->frags; 159280ad548dSVincenzo Maffione if (targ->frag_size > mtu) { 159380ad548dSVincenzo Maffione targ->frags = targ->g->pkt_size / mtu; 159480ad548dSVincenzo Maffione targ->frag_size = mtu; 159580ad548dSVincenzo Maffione if (targ->g->pkt_size % mtu != 0) 159680ad548dSVincenzo Maffione targ->frags++; 159780ad548dSVincenzo Maffione } 159880ad548dSVincenzo Maffione D("frags %u frag_size %u", targ->frags, targ->frag_size); 1599f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 160080ad548dSVincenzo Maffione int rv; 160168b8534bSLuigi Rizzo 16021cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 16031cb4c501SLuigi Rizzo tosend = targ->g->burst; 160417885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 160517885a7bSLuigi Rizzo wait_time(nexttime); 16061cb4c501SLuigi Rizzo } 16071cb4c501SLuigi Rizzo 160868b8534bSLuigi Rizzo /* 160968b8534bSLuigi Rizzo * wait for available room in the send queue(s) 161068b8534bSLuigi Rizzo */ 161137e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 161280ad548dSVincenzo Maffione (void)rv; 161337e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 161437e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 161537e3a6d3SLuigi Rizzo strerror(errno)); 161637e3a6d3SLuigi Rizzo goto quit; 161737e3a6d3SLuigi Rizzo } 161837e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 161980ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 16203fe77e68SEd Maste if (targ->cancel) 16213fe77e68SEd Maste break; 162280ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 162380ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1624f0ea3689SLuigi Rizzo // goto quit; 162517885a7bSLuigi Rizzo } 1626f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 162737e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 162837e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 162968b8534bSLuigi Rizzo goto quit; 163068b8534bSLuigi Rizzo } 163137e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 163268b8534bSLuigi Rizzo /* 163368b8534bSLuigi Rizzo * scan our queues and send on those with room 163468b8534bSLuigi Rizzo */ 1635f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1636f8e4e36aSLuigi Rizzo D("drop copy"); 163799fb123fSLuigi Rizzo options &= ~OPT_COPY; 1638f8e4e36aSLuigi Rizzo } 1639f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 164037e3a6d3SLuigi Rizzo int m; 164137e3a6d3SLuigi Rizzo uint64_t limit = rate_limit ? tosend : targ->g->burst; 164280ad548dSVincenzo Maffione 164380ad548dSVincenzo Maffione if (n > 0 && n == sent) 164480ad548dSVincenzo Maffione break; 164580ad548dSVincenzo Maffione 1646f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1647f8e4e36aSLuigi Rizzo limit = n - sent; 164868b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 164917885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 165068b8534bSLuigi Rizzo continue; 1651ce3ee1e7SLuigi Rizzo 165280ad548dSVincenzo Maffione if (targ->g->pkt_min_size > 0) { 165380ad548dSVincenzo Maffione size = nrand48(targ->seed) % 165480ad548dSVincenzo Maffione (targ->g->pkt_size - targ->g->pkt_min_size) + 165580ad548dSVincenzo Maffione targ->g->pkt_min_size; 165680ad548dSVincenzo Maffione } 165780ad548dSVincenzo Maffione m = send_packets(txring, pkt, frame, size, targ, 165880ad548dSVincenzo Maffione limit, options); 165980ad548dSVincenzo Maffione ND("limit %lu tail %d m %d", 166080ad548dSVincenzo Maffione limit, txring->tail, m); 166168b8534bSLuigi Rizzo sent += m; 166237e3a6d3SLuigi Rizzo if (m > 0) //XXX-ste: can m be 0? 166337e3a6d3SLuigi Rizzo event++; 166437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 166580ad548dSVincenzo Maffione targ->ctr.bytes += m*size; 166637e3a6d3SLuigi Rizzo targ->ctr.events = event; 1667ce3ee1e7SLuigi Rizzo if (rate_limit) { 1668ce3ee1e7SLuigi Rizzo tosend -= m; 1669ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1670ce3ee1e7SLuigi Rizzo break; 1671ce3ee1e7SLuigi Rizzo } 167268b8534bSLuigi Rizzo } 167368b8534bSLuigi Rizzo } 167499fb123fSLuigi Rizzo /* flush any remaining packets */ 167580ad548dSVincenzo Maffione if (txring != NULL) { 16764bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 16774bf50f18SLuigi Rizzo txring->tail, txring->head, 167837e3a6d3SLuigi Rizzo (void *)pthread_self()); 1679f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 168080ad548dSVincenzo Maffione } 168168b8534bSLuigi Rizzo 168268b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1683f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 168468b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 168537e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(txring)) { 16864bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 16874bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1688f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 168968b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 169068b8534bSLuigi Rizzo } 169168b8534bSLuigi Rizzo } 1692f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 169368b8534bSLuigi Rizzo 16941cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 169568b8534bSLuigi Rizzo targ->completed = 1; 169637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 169737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 169837e3a6d3SLuigi Rizzo targ->ctr.events = event; 169968b8534bSLuigi Rizzo quit: 170068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 170168b8534bSLuigi Rizzo targ->used = 0; 170268b8534bSLuigi Rizzo 170368b8534bSLuigi Rizzo return (NULL); 170468b8534bSLuigi Rizzo } 170568b8534bSLuigi Rizzo 170668b8534bSLuigi Rizzo 1707f2637526SLuigi Rizzo #ifndef NO_PCAP 170868b8534bSLuigi Rizzo static void 1709f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1710f8e4e36aSLuigi Rizzo const u_char * bytes) 171168b8534bSLuigi Rizzo { 171237e3a6d3SLuigi Rizzo struct my_ctrs *ctr = (struct my_ctrs *)user; 1713f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 171437e3a6d3SLuigi Rizzo ctr->bytes += h->len; 171537e3a6d3SLuigi Rizzo ctr->pkts++; 171668b8534bSLuigi Rizzo } 1717f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 171868b8534bSLuigi Rizzo 171937e3a6d3SLuigi Rizzo 172068b8534bSLuigi Rizzo static int 172137e3a6d3SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) 172268b8534bSLuigi Rizzo { 172317885a7bSLuigi Rizzo u_int cur, rx, n; 172437e3a6d3SLuigi Rizzo uint64_t b = 0; 172580ad548dSVincenzo Maffione u_int complete = 0; 172637e3a6d3SLuigi Rizzo 172737e3a6d3SLuigi Rizzo if (bytes == NULL) 172837e3a6d3SLuigi Rizzo bytes = &b; 172968b8534bSLuigi Rizzo 173068b8534bSLuigi Rizzo cur = ring->cur; 173117885a7bSLuigi Rizzo n = nm_ring_space(ring); 173217885a7bSLuigi Rizzo if (n < limit) 173317885a7bSLuigi Rizzo limit = n; 173468b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 173568b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 173668b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 173768b8534bSLuigi Rizzo 173837e3a6d3SLuigi Rizzo *bytes += slot->len; 1739b303f675SLuigi Rizzo if (dump) 1740b303f675SLuigi Rizzo dump_payload(p, slot->len, ring, cur); 174180ad548dSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) 174280ad548dSVincenzo Maffione complete++; 174368b8534bSLuigi Rizzo 174417885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 174568b8534bSLuigi Rizzo } 174617885a7bSLuigi Rizzo ring->head = ring->cur = cur; 174768b8534bSLuigi Rizzo 174880ad548dSVincenzo Maffione return (complete); 174968b8534bSLuigi Rizzo } 175068b8534bSLuigi Rizzo 175168b8534bSLuigi Rizzo static void * 175268b8534bSLuigi Rizzo receiver_body(void *data) 175368b8534bSLuigi Rizzo { 175468b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1755f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 17564bf50f18SLuigi Rizzo struct netmap_if *nifp; 175768b8534bSLuigi Rizzo struct netmap_ring *rxring; 1758f8e4e36aSLuigi Rizzo int i; 175937e3a6d3SLuigi Rizzo struct my_ctrs cur; 176037e3a6d3SLuigi Rizzo 176180ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 176268b8534bSLuigi Rizzo 176368b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 176468b8534bSLuigi Rizzo goto quit; 176568b8534bSLuigi Rizzo 17664bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 17674bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 176868b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 17694bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1770f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1771f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 177268b8534bSLuigi Rizzo break; 177380ad548dSVincenzo Maffione if (i < 0) { 177480ad548dSVincenzo Maffione D("poll() error: %s", strerror(errno)); 177580ad548dSVincenzo Maffione goto quit; 177680ad548dSVincenzo Maffione } 177780ad548dSVincenzo Maffione if (pfd.revents & POLLERR) { 177880ad548dSVincenzo Maffione D("fd error"); 177980ad548dSVincenzo Maffione goto quit; 178080ad548dSVincenzo Maffione } 1781f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1782f0ea3689SLuigi Rizzo i, pfd.revents); 178368b8534bSLuigi Rizzo } 178468b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 17851cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1786f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1787f8e4e36aSLuigi Rizzo while (!targ->cancel) { 17884bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1789f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 179037e3a6d3SLuigi Rizzo i = read(targ->g->main_fd, buf, sizeof(buf)); 179137e3a6d3SLuigi Rizzo if (i > 0) { 179237e3a6d3SLuigi Rizzo targ->ctr.pkts++; 179337e3a6d3SLuigi Rizzo targ->ctr.bytes += i; 179437e3a6d3SLuigi Rizzo targ->ctr.events++; 179537e3a6d3SLuigi Rizzo } 1796f8e4e36aSLuigi Rizzo } 1797f2637526SLuigi Rizzo #ifndef NO_PCAP 1798f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1799f2637526SLuigi Rizzo while (!targ->cancel) { 1800f2637526SLuigi Rizzo /* XXX should we poll ? */ 18014bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 180237e3a6d3SLuigi Rizzo (u_char *)&targ->ctr); 180337e3a6d3SLuigi Rizzo targ->ctr.events++; 1804f2637526SLuigi Rizzo } 1805f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 180668b8534bSLuigi Rizzo } else { 1807b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 18084bf50f18SLuigi Rizzo 18094bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 18103fe77e68SEd Maste while (!targ->cancel) { 181168b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 181268b8534bSLuigi Rizzo before quitting. */ 181337e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 181437e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 181537e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 181637e3a6d3SLuigi Rizzo strerror(errno)); 181737e3a6d3SLuigi Rizzo goto quit; 181837e3a6d3SLuigi Rizzo } 181937e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 182037e3a6d3SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 182137e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 182237e3a6d3SLuigi Rizzo targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 182337e3a6d3SLuigi Rizzo goto out; 182437e3a6d3SLuigi Rizzo } 182537e3a6d3SLuigi Rizzo 182637e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 182737e3a6d3SLuigi Rizzo D("poll err"); 182837e3a6d3SLuigi Rizzo goto quit; 182937e3a6d3SLuigi Rizzo } 183037e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 183137e3a6d3SLuigi Rizzo uint64_t cur_space = 0; 183237e3a6d3SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 183337e3a6d3SLuigi Rizzo int m; 183437e3a6d3SLuigi Rizzo 183537e3a6d3SLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 183637e3a6d3SLuigi Rizzo /* compute free space in the ring */ 183737e3a6d3SLuigi Rizzo m = rxring->head + rxring->num_slots - rxring->tail; 183837e3a6d3SLuigi Rizzo if (m >= (int) rxring->num_slots) 183937e3a6d3SLuigi Rizzo m -= rxring->num_slots; 184037e3a6d3SLuigi Rizzo cur_space += m; 184137e3a6d3SLuigi Rizzo if (nm_ring_empty(rxring)) 184237e3a6d3SLuigi Rizzo continue; 184337e3a6d3SLuigi Rizzo 184437e3a6d3SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); 184537e3a6d3SLuigi Rizzo cur.pkts += m; 184680ad548dSVincenzo Maffione if (m > 0) 184737e3a6d3SLuigi Rizzo cur.events++; 184837e3a6d3SLuigi Rizzo } 184937e3a6d3SLuigi Rizzo cur.min_space = targ->ctr.min_space; 185037e3a6d3SLuigi Rizzo if (cur_space < cur.min_space) 185137e3a6d3SLuigi Rizzo cur.min_space = cur_space; 185237e3a6d3SLuigi Rizzo targ->ctr = cur; 185337e3a6d3SLuigi Rizzo } 185437e3a6d3SLuigi Rizzo } 185537e3a6d3SLuigi Rizzo 185637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 185737e3a6d3SLuigi Rizzo 185837e3a6d3SLuigi Rizzo #if !defined(BUSYWAIT) 185937e3a6d3SLuigi Rizzo out: 186037e3a6d3SLuigi Rizzo #endif 186137e3a6d3SLuigi Rizzo targ->completed = 1; 186237e3a6d3SLuigi Rizzo targ->ctr = cur; 186337e3a6d3SLuigi Rizzo 186437e3a6d3SLuigi Rizzo quit: 186537e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 186637e3a6d3SLuigi Rizzo targ->used = 0; 186737e3a6d3SLuigi Rizzo 186837e3a6d3SLuigi Rizzo return (NULL); 186937e3a6d3SLuigi Rizzo } 187037e3a6d3SLuigi Rizzo 187137e3a6d3SLuigi Rizzo static void * 187237e3a6d3SLuigi Rizzo txseq_body(void *data) 187337e3a6d3SLuigi Rizzo { 187437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 187537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 187637e3a6d3SLuigi Rizzo struct netmap_ring *ring; 187737e3a6d3SLuigi Rizzo int64_t sent = 0; 187837e3a6d3SLuigi Rizzo uint64_t event = 0; 187937e3a6d3SLuigi Rizzo int options = targ->g->options | OPT_COPY; 188037e3a6d3SLuigi Rizzo struct timespec nexttime = {0, 0}; 188137e3a6d3SLuigi Rizzo int rate_limit = targ->g->tx_rate; 188237e3a6d3SLuigi Rizzo struct pkt *pkt = &targ->pkt; 188337e3a6d3SLuigi Rizzo int frags = targ->g->frags; 188437e3a6d3SLuigi Rizzo uint32_t sequence = 0; 188537e3a6d3SLuigi Rizzo int budget = 0; 188637e3a6d3SLuigi Rizzo void *frame; 188737e3a6d3SLuigi Rizzo int size; 188837e3a6d3SLuigi Rizzo 188937e3a6d3SLuigi Rizzo if (targ->g->nthreads > 1) { 189037e3a6d3SLuigi Rizzo D("can only txseq ping with 1 thread"); 189137e3a6d3SLuigi Rizzo return NULL; 189237e3a6d3SLuigi Rizzo } 189337e3a6d3SLuigi Rizzo 189437e3a6d3SLuigi Rizzo if (targ->g->npackets > 0) { 189537e3a6d3SLuigi Rizzo D("Ignoring -n argument"); 189637e3a6d3SLuigi Rizzo } 189737e3a6d3SLuigi Rizzo 189880ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 189937e3a6d3SLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 190037e3a6d3SLuigi Rizzo 190137e3a6d3SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 190237e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 190337e3a6d3SLuigi Rizzo goto quit; 190437e3a6d3SLuigi Rizzo 190537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 190637e3a6d3SLuigi Rizzo if (rate_limit) { 190737e3a6d3SLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 190837e3a6d3SLuigi Rizzo targ->tic.tv_nsec = 0; 190937e3a6d3SLuigi Rizzo wait_time(targ->tic); 191037e3a6d3SLuigi Rizzo nexttime = targ->tic; 191137e3a6d3SLuigi Rizzo } 191237e3a6d3SLuigi Rizzo 191337e3a6d3SLuigi Rizzo /* Only use the first queue. */ 191437e3a6d3SLuigi Rizzo ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); 191537e3a6d3SLuigi Rizzo 191637e3a6d3SLuigi Rizzo while (!targ->cancel) { 191737e3a6d3SLuigi Rizzo int64_t limit; 191837e3a6d3SLuigi Rizzo unsigned int space; 191937e3a6d3SLuigi Rizzo unsigned int head; 192037e3a6d3SLuigi Rizzo int fcnt; 192180ad548dSVincenzo Maffione uint16_t sum = 0; 192280ad548dSVincenzo Maffione int rv; 192337e3a6d3SLuigi Rizzo 192437e3a6d3SLuigi Rizzo if (!rate_limit) { 192537e3a6d3SLuigi Rizzo budget = targ->g->burst; 192637e3a6d3SLuigi Rizzo 192737e3a6d3SLuigi Rizzo } else if (budget <= 0) { 192837e3a6d3SLuigi Rizzo budget = targ->g->burst; 192937e3a6d3SLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 193037e3a6d3SLuigi Rizzo wait_time(nexttime); 193137e3a6d3SLuigi Rizzo } 193237e3a6d3SLuigi Rizzo 193337e3a6d3SLuigi Rizzo /* wait for available room in the send queue */ 193480ad548dSVincenzo Maffione #ifdef BUSYWAIT 193580ad548dSVincenzo Maffione (void)rv; 193680ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 193780ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 193880ad548dSVincenzo Maffione strerror(errno)); 193980ad548dSVincenzo Maffione goto quit; 194080ad548dSVincenzo Maffione } 194180ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 194280ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 194337e3a6d3SLuigi Rizzo if (targ->cancel) 194437e3a6d3SLuigi Rizzo break; 194580ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 194680ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 194780ad548dSVincenzo Maffione // goto quit; 194837e3a6d3SLuigi Rizzo } 194937e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 195037e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 195137e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 195237e3a6d3SLuigi Rizzo goto quit; 195337e3a6d3SLuigi Rizzo } 195480ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 195537e3a6d3SLuigi Rizzo 195637e3a6d3SLuigi Rizzo /* If no room poll() again. */ 195737e3a6d3SLuigi Rizzo space = nm_ring_space(ring); 195837e3a6d3SLuigi Rizzo if (!space) { 195937e3a6d3SLuigi Rizzo continue; 196037e3a6d3SLuigi Rizzo } 196137e3a6d3SLuigi Rizzo 196237e3a6d3SLuigi Rizzo limit = budget; 196337e3a6d3SLuigi Rizzo 196437e3a6d3SLuigi Rizzo if (space < limit) { 196537e3a6d3SLuigi Rizzo limit = space; 196637e3a6d3SLuigi Rizzo } 196737e3a6d3SLuigi Rizzo 196837e3a6d3SLuigi Rizzo /* Cut off ``limit`` to make sure is multiple of ``frags``. */ 196937e3a6d3SLuigi Rizzo if (frags > 1) { 197037e3a6d3SLuigi Rizzo limit = (limit / frags) * frags; 197137e3a6d3SLuigi Rizzo } 197237e3a6d3SLuigi Rizzo 197337e3a6d3SLuigi Rizzo limit = sent + limit; /* Convert to absolute. */ 197437e3a6d3SLuigi Rizzo 197537e3a6d3SLuigi Rizzo for (fcnt = frags, head = ring->head; 197637e3a6d3SLuigi Rizzo sent < limit; sent++, sequence++) { 197737e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 197837e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 197980ad548dSVincenzo Maffione uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; 198080ad548dSVincenzo Maffione 198180ad548dSVincenzo Maffione memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); 198237e3a6d3SLuigi Rizzo 198337e3a6d3SLuigi Rizzo slot->flags = 0; 198480ad548dSVincenzo Maffione t = *w; 198580ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[0] = sequence >> 24; 198680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; 198780ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 198880ad548dSVincenzo Maffione t = *++w; 198980ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; 199080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; 199180ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 199280ad548dSVincenzo Maffione memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); 199337e3a6d3SLuigi Rizzo nm_pkt_copy(frame, p, size); 199437e3a6d3SLuigi Rizzo if (fcnt == frags) { 199580ad548dSVincenzo Maffione update_addresses(pkt, targ); 199637e3a6d3SLuigi Rizzo } 199737e3a6d3SLuigi Rizzo 199837e3a6d3SLuigi Rizzo if (options & OPT_DUMP) { 199937e3a6d3SLuigi Rizzo dump_payload(p, size, ring, head); 200037e3a6d3SLuigi Rizzo } 200137e3a6d3SLuigi Rizzo 200237e3a6d3SLuigi Rizzo slot->len = size; 200337e3a6d3SLuigi Rizzo 200437e3a6d3SLuigi Rizzo if (--fcnt > 0) { 200537e3a6d3SLuigi Rizzo slot->flags |= NS_MOREFRAG; 200637e3a6d3SLuigi Rizzo } else { 200737e3a6d3SLuigi Rizzo fcnt = frags; 200837e3a6d3SLuigi Rizzo } 200937e3a6d3SLuigi Rizzo 201037e3a6d3SLuigi Rizzo if (sent == limit - 1) { 201137e3a6d3SLuigi Rizzo /* Make sure we don't push an incomplete 201237e3a6d3SLuigi Rizzo * packet. */ 201337e3a6d3SLuigi Rizzo assert(!(slot->flags & NS_MOREFRAG)); 201437e3a6d3SLuigi Rizzo slot->flags |= NS_REPORT; 201537e3a6d3SLuigi Rizzo } 201637e3a6d3SLuigi Rizzo 201737e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 201837e3a6d3SLuigi Rizzo if (rate_limit) { 201937e3a6d3SLuigi Rizzo budget--; 202037e3a6d3SLuigi Rizzo } 202137e3a6d3SLuigi Rizzo } 202237e3a6d3SLuigi Rizzo 202337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 202437e3a6d3SLuigi Rizzo 202537e3a6d3SLuigi Rizzo event ++; 202637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 202737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 202837e3a6d3SLuigi Rizzo targ->ctr.events = event; 202937e3a6d3SLuigi Rizzo } 203037e3a6d3SLuigi Rizzo 203137e3a6d3SLuigi Rizzo /* flush any remaining packets */ 203237e3a6d3SLuigi Rizzo D("flush tail %d head %d on thread %p", 203337e3a6d3SLuigi Rizzo ring->tail, ring->head, 203437e3a6d3SLuigi Rizzo (void *)pthread_self()); 203537e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 203637e3a6d3SLuigi Rizzo 203737e3a6d3SLuigi Rizzo /* final part: wait the TX queues to become empty. */ 203837e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(ring)) { 203937e3a6d3SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 204037e3a6d3SLuigi Rizzo ring->tail, ring->head, targ->nmd->first_tx_ring); 204137e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 204237e3a6d3SLuigi Rizzo usleep(1); /* wait 1 tick */ 204337e3a6d3SLuigi Rizzo } 204437e3a6d3SLuigi Rizzo 204537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 204637e3a6d3SLuigi Rizzo targ->completed = 1; 204737e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 204837e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 204937e3a6d3SLuigi Rizzo targ->ctr.events = event; 205037e3a6d3SLuigi Rizzo quit: 205137e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 205237e3a6d3SLuigi Rizzo targ->used = 0; 205337e3a6d3SLuigi Rizzo 205437e3a6d3SLuigi Rizzo return (NULL); 205537e3a6d3SLuigi Rizzo } 205637e3a6d3SLuigi Rizzo 205737e3a6d3SLuigi Rizzo 205837e3a6d3SLuigi Rizzo static char * 205937e3a6d3SLuigi Rizzo multi_slot_to_string(struct netmap_ring *ring, unsigned int head, 206037e3a6d3SLuigi Rizzo unsigned int nfrags, char *strbuf, size_t strbuflen) 206137e3a6d3SLuigi Rizzo { 206237e3a6d3SLuigi Rizzo unsigned int f; 206337e3a6d3SLuigi Rizzo char *ret = strbuf; 206437e3a6d3SLuigi Rizzo 206537e3a6d3SLuigi Rizzo for (f = 0; f < nfrags; f++) { 206637e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 206737e3a6d3SLuigi Rizzo int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, 206837e3a6d3SLuigi Rizzo slot->flags); 206937e3a6d3SLuigi Rizzo if (m >= (int)strbuflen) { 207037e3a6d3SLuigi Rizzo break; 207137e3a6d3SLuigi Rizzo } 207237e3a6d3SLuigi Rizzo strbuf += m; 207337e3a6d3SLuigi Rizzo strbuflen -= m; 207437e3a6d3SLuigi Rizzo 207537e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 207637e3a6d3SLuigi Rizzo } 207737e3a6d3SLuigi Rizzo 207837e3a6d3SLuigi Rizzo return ret; 207937e3a6d3SLuigi Rizzo } 208037e3a6d3SLuigi Rizzo 208137e3a6d3SLuigi Rizzo static void * 208237e3a6d3SLuigi Rizzo rxseq_body(void *data) 208337e3a6d3SLuigi Rizzo { 208437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 208537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 208637e3a6d3SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 208737e3a6d3SLuigi Rizzo struct netmap_ring *ring; 208837e3a6d3SLuigi Rizzo unsigned int frags_exp = 1; 208937e3a6d3SLuigi Rizzo struct my_ctrs cur; 209037e3a6d3SLuigi Rizzo unsigned int frags = 0; 209137e3a6d3SLuigi Rizzo int first_packet = 1; 209237e3a6d3SLuigi Rizzo int first_slot = 1; 209380ad548dSVincenzo Maffione int i, j, af, nrings; 209480ad548dSVincenzo Maffione uint32_t seq, *seq_exp = NULL; 209537e3a6d3SLuigi Rizzo 209680ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 209737e3a6d3SLuigi Rizzo 209837e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 209937e3a6d3SLuigi Rizzo goto quit; 210037e3a6d3SLuigi Rizzo 210180ad548dSVincenzo Maffione nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1; 210280ad548dSVincenzo Maffione seq_exp = calloc(nrings, sizeof(uint32_t)); 210380ad548dSVincenzo Maffione if (seq_exp == NULL) { 210480ad548dSVincenzo Maffione D("failed to allocate seq array"); 210580ad548dSVincenzo Maffione goto quit; 210680ad548dSVincenzo Maffione } 210780ad548dSVincenzo Maffione 210837e3a6d3SLuigi Rizzo D("reading from %s fd %d main_fd %d", 210937e3a6d3SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 211037e3a6d3SLuigi Rizzo /* unbounded wait for the first packet. */ 211137e3a6d3SLuigi Rizzo for (;!targ->cancel;) { 211237e3a6d3SLuigi Rizzo i = poll(&pfd, 1, 1000); 211337e3a6d3SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 211437e3a6d3SLuigi Rizzo break; 211537e3a6d3SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 211637e3a6d3SLuigi Rizzo i, pfd.revents); 211737e3a6d3SLuigi Rizzo } 211837e3a6d3SLuigi Rizzo 211937e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 212037e3a6d3SLuigi Rizzo 212137e3a6d3SLuigi Rizzo 212237e3a6d3SLuigi Rizzo while (!targ->cancel) { 212337e3a6d3SLuigi Rizzo unsigned int head; 212437e3a6d3SLuigi Rizzo int limit; 212537e3a6d3SLuigi Rizzo 212680ad548dSVincenzo Maffione #ifdef BUSYWAIT 212780ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 212880ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 212980ad548dSVincenzo Maffione strerror(errno)); 213080ad548dSVincenzo Maffione goto quit; 213180ad548dSVincenzo Maffione } 213280ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 2133f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 21341cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 21358ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 2136f0ea3689SLuigi Rizzo goto out; 213768b8534bSLuigi Rizzo } 213868b8534bSLuigi Rizzo 2139f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 214017885a7bSLuigi Rizzo D("poll err"); 214117885a7bSLuigi Rizzo goto quit; 214217885a7bSLuigi Rizzo } 214380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 214417885a7bSLuigi Rizzo 214580ad548dSVincenzo Maffione for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) { 214680ad548dSVincenzo Maffione ring = NETMAP_RXRING(targ->nmd->nifp, j); 214737e3a6d3SLuigi Rizzo if (nm_ring_empty(ring)) 214868b8534bSLuigi Rizzo continue; 214968b8534bSLuigi Rizzo 215037e3a6d3SLuigi Rizzo limit = nm_ring_space(ring); 215137e3a6d3SLuigi Rizzo if (limit > targ->g->burst) 215237e3a6d3SLuigi Rizzo limit = targ->g->burst; 215337e3a6d3SLuigi Rizzo 215437e3a6d3SLuigi Rizzo #if 0 215537e3a6d3SLuigi Rizzo /* Enable this if 215637e3a6d3SLuigi Rizzo * 1) we remove the early-return optimization from 215737e3a6d3SLuigi Rizzo * the netmap poll implementation, or 215837e3a6d3SLuigi Rizzo * 2) pipes get NS_MOREFRAG support. 215937e3a6d3SLuigi Rizzo * With the current netmap implementation, an experiment like 216037e3a6d3SLuigi Rizzo * pkt-gen -i vale:1{1 -f txseq -F 9 216137e3a6d3SLuigi Rizzo * pkt-gen -i vale:1}1 -f rxseq 216237e3a6d3SLuigi Rizzo * would get stuck as soon as we find nm_ring_space(ring) < 9, 216337e3a6d3SLuigi Rizzo * since here limit is rounded to 0 and 216437e3a6d3SLuigi Rizzo * pipe rxsync is not called anymore by the poll() of this loop. 216537e3a6d3SLuigi Rizzo */ 216637e3a6d3SLuigi Rizzo if (frags_exp > 1) { 216737e3a6d3SLuigi Rizzo int o = limit; 216837e3a6d3SLuigi Rizzo /* Cut off to the closest smaller multiple. */ 216937e3a6d3SLuigi Rizzo limit = (limit / frags_exp) * frags_exp; 217037e3a6d3SLuigi Rizzo RD(2, "LIMIT %d --> %d", o, limit); 217168b8534bSLuigi Rizzo } 217237e3a6d3SLuigi Rizzo #endif 217337e3a6d3SLuigi Rizzo 217437e3a6d3SLuigi Rizzo for (head = ring->head, i = 0; i < limit; i++) { 217537e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 217637e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 217737e3a6d3SLuigi Rizzo int len = slot->len; 217837e3a6d3SLuigi Rizzo struct pkt *pkt; 217937e3a6d3SLuigi Rizzo 218037e3a6d3SLuigi Rizzo if (dump) { 218137e3a6d3SLuigi Rizzo dump_payload(p, slot->len, ring, head); 218268b8534bSLuigi Rizzo } 218337e3a6d3SLuigi Rizzo 218437e3a6d3SLuigi Rizzo frags++; 218537e3a6d3SLuigi Rizzo if (!(slot->flags & NS_MOREFRAG)) { 218637e3a6d3SLuigi Rizzo if (first_packet) { 218737e3a6d3SLuigi Rizzo first_packet = 0; 218837e3a6d3SLuigi Rizzo } else if (frags != frags_exp) { 218937e3a6d3SLuigi Rizzo char prbuf[512]; 219037e3a6d3SLuigi Rizzo RD(1, "Received packets with %u frags, " 219137e3a6d3SLuigi Rizzo "expected %u, '%s'", frags, frags_exp, 219280ad548dSVincenzo Maffione multi_slot_to_string(ring, head-frags+1, 219380ad548dSVincenzo Maffione frags, 219437e3a6d3SLuigi Rizzo prbuf, sizeof(prbuf))); 219537e3a6d3SLuigi Rizzo } 219637e3a6d3SLuigi Rizzo first_packet = 0; 219737e3a6d3SLuigi Rizzo frags_exp = frags; 219837e3a6d3SLuigi Rizzo frags = 0; 219937e3a6d3SLuigi Rizzo } 220037e3a6d3SLuigi Rizzo 220137e3a6d3SLuigi Rizzo p -= sizeof(pkt->vh) - targ->g->virt_header; 220237e3a6d3SLuigi Rizzo len += sizeof(pkt->vh) - targ->g->virt_header; 220337e3a6d3SLuigi Rizzo pkt = (struct pkt *)p; 220480ad548dSVincenzo Maffione if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP) 220580ad548dSVincenzo Maffione af = AF_INET; 220680ad548dSVincenzo Maffione else 220780ad548dSVincenzo Maffione af = AF_INET6; 220837e3a6d3SLuigi Rizzo 220980ad548dSVincenzo Maffione if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) + 221080ad548dSVincenzo Maffione sizeof(seq)) { 221137e3a6d3SLuigi Rizzo RD(1, "%s: packet too small (len=%u)", __func__, 221237e3a6d3SLuigi Rizzo slot->len); 221337e3a6d3SLuigi Rizzo } else { 221480ad548dSVincenzo Maffione seq = (PKT(pkt, body, af)[0] << 24) | 221580ad548dSVincenzo Maffione (PKT(pkt, body, af)[1] << 16) | 221680ad548dSVincenzo Maffione (PKT(pkt, body, af)[2] << 8) | 221780ad548dSVincenzo Maffione PKT(pkt, body, af)[3]; 221837e3a6d3SLuigi Rizzo if (first_slot) { 221937e3a6d3SLuigi Rizzo /* Grab the first one, whatever it 222037e3a6d3SLuigi Rizzo is. */ 222180ad548dSVincenzo Maffione seq_exp[j] = seq; 222237e3a6d3SLuigi Rizzo first_slot = 0; 222380ad548dSVincenzo Maffione } else if (seq != seq_exp[j]) { 222480ad548dSVincenzo Maffione uint32_t delta = seq - seq_exp[j]; 222537e3a6d3SLuigi Rizzo 222637e3a6d3SLuigi Rizzo if (delta < (0xFFFFFFFF >> 1)) { 222737e3a6d3SLuigi Rizzo RD(2, "Sequence GAP: exp %u found %u", 222880ad548dSVincenzo Maffione seq_exp[j], seq); 222937e3a6d3SLuigi Rizzo } else { 223037e3a6d3SLuigi Rizzo RD(2, "Sequence OUT OF ORDER: " 223180ad548dSVincenzo Maffione "exp %u found %u", seq_exp[j], seq); 223237e3a6d3SLuigi Rizzo } 223380ad548dSVincenzo Maffione seq_exp[j] = seq; 223437e3a6d3SLuigi Rizzo } 223580ad548dSVincenzo Maffione seq_exp[j]++; 223637e3a6d3SLuigi Rizzo } 223737e3a6d3SLuigi Rizzo 223837e3a6d3SLuigi Rizzo cur.bytes += slot->len; 223937e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 224037e3a6d3SLuigi Rizzo cur.pkts++; 224137e3a6d3SLuigi Rizzo } 224237e3a6d3SLuigi Rizzo 224337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 224437e3a6d3SLuigi Rizzo 224537e3a6d3SLuigi Rizzo cur.events++; 224637e3a6d3SLuigi Rizzo targ->ctr = cur; 224768b8534bSLuigi Rizzo } 224880ad548dSVincenzo Maffione } 2249f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 2250f0ea3689SLuigi Rizzo 225180ad548dSVincenzo Maffione #ifndef BUSYWAIT 2252f0ea3689SLuigi Rizzo out: 225380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 225468b8534bSLuigi Rizzo targ->completed = 1; 225537e3a6d3SLuigi Rizzo targ->ctr = cur; 225668b8534bSLuigi Rizzo 225768b8534bSLuigi Rizzo quit: 225880ad548dSVincenzo Maffione if (seq_exp != NULL) 225980ad548dSVincenzo Maffione free(seq_exp); 226068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 226168b8534bSLuigi Rizzo targ->used = 0; 226268b8534bSLuigi Rizzo 226368b8534bSLuigi Rizzo return (NULL); 226468b8534bSLuigi Rizzo } 226568b8534bSLuigi Rizzo 226666a698c9SEd Maste 226768b8534bSLuigi Rizzo static void 226880ad548dSVincenzo Maffione tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg) 226968b8534bSLuigi Rizzo { 227037e3a6d3SLuigi Rizzo double bw, raw_bw, pps, abs; 2271f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 227237e3a6d3SLuigi Rizzo int size; 227368b8534bSLuigi Rizzo 227437e3a6d3SLuigi Rizzo if (cur->pkts == 0) { 227537e3a6d3SLuigi Rizzo printf("%s nothing.\n", msg); 227637e3a6d3SLuigi Rizzo return; 227737e3a6d3SLuigi Rizzo } 227837e3a6d3SLuigi Rizzo 227937e3a6d3SLuigi Rizzo size = (int)(cur->bytes / cur->pkts); 228037e3a6d3SLuigi Rizzo 228137e3a6d3SLuigi Rizzo printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", 228237e3a6d3SLuigi Rizzo msg, 228337e3a6d3SLuigi Rizzo (unsigned long long)cur->pkts, 228437e3a6d3SLuigi Rizzo (unsigned long long)cur->bytes, 228537e3a6d3SLuigi Rizzo (unsigned long long)cur->events, size, delta); 2286f8e4e36aSLuigi Rizzo if (delta == 0) 2287f8e4e36aSLuigi Rizzo delta = 1e-6; 2288f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 2289f8e4e36aSLuigi Rizzo size = 60; 229037e3a6d3SLuigi Rizzo pps = cur->pkts / delta; 229137e3a6d3SLuigi Rizzo bw = (8.0 * cur->bytes) / delta; 229280ad548dSVincenzo Maffione raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta; 229337e3a6d3SLuigi Rizzo abs = cur->pkts / (double)(cur->events); 229466a698c9SEd Maste 229537e3a6d3SLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", 229680ad548dSVincenzo Maffione norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); 229768b8534bSLuigi Rizzo } 229868b8534bSLuigi Rizzo 229968b8534bSLuigi Rizzo static void 230080ad548dSVincenzo Maffione usage(int errcode) 230168b8534bSLuigi Rizzo { 230280ad548dSVincenzo Maffione /* This usage is generated from the pkt-gen man page: 230380ad548dSVincenzo Maffione * $ man pkt-gen > x 230480ad548dSVincenzo Maffione * and pasted here adding the string terminators and endlines with simple 230580ad548dSVincenzo Maffione * regular expressions. */ 230668b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 230768b8534bSLuigi Rizzo fprintf(stderr, 230868b8534bSLuigi Rizzo "Usage:\n" 230968b8534bSLuigi Rizzo "%s arguments\n" 231080ad548dSVincenzo Maffione " -h Show program usage and exit.\n" 231180ad548dSVincenzo Maffione "\n" 231280ad548dSVincenzo Maffione " -i interface\n" 231380ad548dSVincenzo Maffione " Name of the network interface that pkt-gen operates on. It can be a system network interface\n" 231480ad548dSVincenzo Maffione " (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n" 231580ad548dSVincenzo Maffione " monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n" 231680ad548dSVincenzo Maffione " mented in netmap(4) (NIOCREGIF section).\n" 231780ad548dSVincenzo Maffione "\n" 231880ad548dSVincenzo Maffione " -f function\n" 231980ad548dSVincenzo Maffione " The function to be executed by pkt-gen. Specify tx for transmission, rx for reception, ping\n" 232080ad548dSVincenzo Maffione " for client-side ping-pong operation, and pong for server-side ping-pong operation.\n" 232180ad548dSVincenzo Maffione "\n" 232280ad548dSVincenzo Maffione " -n count\n" 232380ad548dSVincenzo Maffione " Number of iterations of the pkt-gen function, with 0 meaning infinite). In case of tx or rx,\n" 232480ad548dSVincenzo Maffione " count is the number of packets to receive or transmit. In case of ping or pong, count is the\n" 232580ad548dSVincenzo Maffione " number of ping-pong transactions.\n" 232680ad548dSVincenzo Maffione "\n" 232780ad548dSVincenzo Maffione " -l pkt_size\n" 232880ad548dSVincenzo Maffione " Packet size in bytes excluding CRC. If passed a second time, use random sizes larger or\n" 232980ad548dSVincenzo Maffione " equal than the second one and lower than the first one.\n" 233080ad548dSVincenzo Maffione "\n" 233180ad548dSVincenzo Maffione " -b burst_size\n" 233280ad548dSVincenzo Maffione " Transmit or receive up to burst_size packets at a time.\n" 233380ad548dSVincenzo Maffione "\n" 233480ad548dSVincenzo Maffione " -4 Use IPv4 addresses.\n" 233580ad548dSVincenzo Maffione "\n" 233680ad548dSVincenzo Maffione " -6 Use IPv6 addresses.\n" 233780ad548dSVincenzo Maffione "\n" 233880ad548dSVincenzo Maffione " -d dst_ip[:port[-dst_ip:port]]\n" 233980ad548dSVincenzo Maffione " Destination IPv4/IPv6 address and port, single or range.\n" 234080ad548dSVincenzo Maffione "\n" 234180ad548dSVincenzo Maffione " -s src_ip[:port[-src_ip:port]]\n" 234280ad548dSVincenzo Maffione " Source IPv4/IPv6 address and port, single or range.\n" 234380ad548dSVincenzo Maffione "\n" 234480ad548dSVincenzo Maffione " -D dst_mac\n" 234580ad548dSVincenzo Maffione " Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n" 234680ad548dSVincenzo Maffione "\n" 234780ad548dSVincenzo Maffione " -S src_mac\n" 234880ad548dSVincenzo Maffione " Source MAC address in colon notation.\n" 234980ad548dSVincenzo Maffione "\n" 235080ad548dSVincenzo Maffione " -a cpu_id\n" 235180ad548dSVincenzo Maffione " Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3). If more\n" 235280ad548dSVincenzo Maffione " threads are used, they are pinned to the subsequent CPUs, one per thread.\n" 235380ad548dSVincenzo Maffione "\n" 235480ad548dSVincenzo Maffione " -c cpus\n" 235580ad548dSVincenzo Maffione " Maximum number of CPUs to use (0 means to use all the available ones).\n" 235680ad548dSVincenzo Maffione "\n" 235780ad548dSVincenzo Maffione " -p threads\n" 235880ad548dSVincenzo Maffione " Number of threads to use. By default, only a single thread is used to handle all the netmap\n" 235980ad548dSVincenzo Maffione " rings. If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n" 236080ad548dSVincenzo Maffione " single RX ring (in rx mode), or a TX/RX ring couple. The number of threads must be less or\n" 236180ad548dSVincenzo Maffione " equal than the number of TX (or RX) ring available in the device specified by interface.\n" 236280ad548dSVincenzo Maffione "\n" 236380ad548dSVincenzo Maffione " -T report_ms\n" 236480ad548dSVincenzo Maffione " Number of milliseconds between reports.\n" 236580ad548dSVincenzo Maffione "\n" 236680ad548dSVincenzo Maffione " -w wait_for_link_time\n" 236780ad548dSVincenzo Maffione " Number of seconds to wait before starting the pkt-gen function, useuful to make sure that the\n" 236880ad548dSVincenzo Maffione " network link is up. A network device driver may take some time to enter netmap mode, or to\n" 236980ad548dSVincenzo Maffione " create a new transmit/receive ring pair when netmap(4) requests one.\n" 237080ad548dSVincenzo Maffione "\n" 237180ad548dSVincenzo Maffione " -R rate\n" 237280ad548dSVincenzo Maffione " Packet transmission rate. Not setting the packet transmission rate tells pkt-gen to transmit\n" 237380ad548dSVincenzo Maffione " packets as quickly as possible. On servers from 2010 on-wards netmap(4) is able to com-\n" 237480ad548dSVincenzo Maffione " pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n" 237580ad548dSVincenzo Maffione " your intention is to saturate the link.\n" 237680ad548dSVincenzo Maffione "\n" 237780ad548dSVincenzo Maffione " -X Dump payload of each packet transmitted or received.\n" 237880ad548dSVincenzo Maffione "\n" 237980ad548dSVincenzo Maffione " -H len Add empty virtio-net-header with size 'len'. Valid sizes are 0, 10 and 12. This option is\n" 238080ad548dSVincenzo Maffione " only used with Virtual Machine technologies that use virtio as a network interface.\n" 238180ad548dSVincenzo Maffione "\n" 238280ad548dSVincenzo Maffione " -P file\n" 238380ad548dSVincenzo Maffione " Load the packet to be transmitted from a pcap file rather than constructing it within\n" 238480ad548dSVincenzo Maffione " pkt-gen.\n" 238580ad548dSVincenzo Maffione "\n" 238680ad548dSVincenzo Maffione " -z Use random IPv4/IPv6 src address/port.\n" 238780ad548dSVincenzo Maffione "\n" 238880ad548dSVincenzo Maffione " -Z Use random IPv4/IPv6 dst address/port.\n" 238980ad548dSVincenzo Maffione "\n" 239080ad548dSVincenzo Maffione " -N Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n" 239180ad548dSVincenzo Maffione "\n" 239280ad548dSVincenzo Maffione " -F num_frags\n" 239380ad548dSVincenzo Maffione " Send multi-slot packets, each one with num_frags fragments. A multi-slot packet is repre-\n" 239480ad548dSVincenzo Maffione " sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n" 239580ad548dSVincenzo Maffione " last slot). This is useful to transmit or receive packets larger than the netmap buffer\n" 239680ad548dSVincenzo Maffione " size.\n" 239780ad548dSVincenzo Maffione "\n" 239880ad548dSVincenzo Maffione " -M frag_size\n" 239980ad548dSVincenzo Maffione " In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n" 240080ad548dSVincenzo Maffione " length divided by num_frags.\n" 240180ad548dSVincenzo Maffione "\n" 240280ad548dSVincenzo Maffione " -I Use indirect buffers. It is only valid for transmitting on VALE ports, and it is implemented\n" 240380ad548dSVincenzo Maffione " by setting the NS_INDIRECT flag in the netmap slots.\n" 240480ad548dSVincenzo Maffione "\n" 240580ad548dSVincenzo Maffione " -W Exit immediately if all the RX rings are empty the first time they are examined.\n" 240680ad548dSVincenzo Maffione "\n" 240780ad548dSVincenzo Maffione " -v Increase the verbosity level.\n" 240880ad548dSVincenzo Maffione "\n" 240980ad548dSVincenzo Maffione " -r In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n" 241080ad548dSVincenzo Maffione " netmap buffers is (rubbish mode).\n" 241180ad548dSVincenzo Maffione "\n" 241280ad548dSVincenzo Maffione " -A Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n" 241380ad548dSVincenzo Maffione "\n" 241480ad548dSVincenzo Maffione " -B Take Ethernet framing and CRC into account when computing the average bps. This adds 4 bytes\n" 241580ad548dSVincenzo Maffione " of CRC and 20 bytes of framing to each packet.\n" 241680ad548dSVincenzo Maffione "\n" 241780ad548dSVincenzo Maffione " -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n" 241880ad548dSVincenzo Maffione " Configuration in terms of number of rings and slots to be used when opening the netmap port.\n" 241980ad548dSVincenzo Maffione " Such configuration has effect on software ports created on the fly, such as VALE ports and\n" 242080ad548dSVincenzo Maffione " netmap pipes. The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n" 242180ad548dSVincenzo Maffione " rx_slots, tx_rings, rx_rings. Missing numbers or zeroes stand for default values. As an\n" 242280ad548dSVincenzo Maffione " additional convenience, if exactly one number is specified, then this is assigned to both\n" 242380ad548dSVincenzo Maffione " tx_slots and rx_slots. If there is no fourth number, then the third one is assigned to both\n" 242480ad548dSVincenzo Maffione " tx_rings and rx_rings.\n" 242580ad548dSVincenzo Maffione "\n" 242680ad548dSVincenzo Maffione " -o options data generation options (parsed using atoi)\n" 242780ad548dSVincenzo Maffione " OPT_PREFETCH 1\n" 242880ad548dSVincenzo Maffione " OPT_ACCESS 2\n" 242980ad548dSVincenzo Maffione " OPT_COPY 4\n" 243080ad548dSVincenzo Maffione " OPT_MEMCPY 8\n" 243180ad548dSVincenzo Maffione " OPT_TS 16 (add a timestamp)\n" 243280ad548dSVincenzo Maffione " OPT_INDIRECT 32 (use indirect buffers)\n" 243380ad548dSVincenzo Maffione " OPT_DUMP 64 (dump rx/tx traffic)\n" 243480ad548dSVincenzo Maffione " OPT_RUBBISH 256\n" 243580ad548dSVincenzo Maffione " (send wathever the buffers contain)\n" 243680ad548dSVincenzo Maffione " OPT_RANDOM_SRC 512\n" 243780ad548dSVincenzo Maffione " OPT_RANDOM_DST 1024\n" 243880ad548dSVincenzo Maffione " OPT_PPS_STATS 2048\n" 243968b8534bSLuigi Rizzo "", 244068b8534bSLuigi Rizzo cmd); 244180ad548dSVincenzo Maffione exit(errcode); 244268b8534bSLuigi Rizzo } 244368b8534bSLuigi Rizzo 244437e3a6d3SLuigi Rizzo enum { 244537e3a6d3SLuigi Rizzo TD_TYPE_SENDER = 1, 244637e3a6d3SLuigi Rizzo TD_TYPE_RECEIVER, 244737e3a6d3SLuigi Rizzo TD_TYPE_OTHER, 244837e3a6d3SLuigi Rizzo }; 244937e3a6d3SLuigi Rizzo 2450f8e4e36aSLuigi Rizzo static void 245180ad548dSVincenzo Maffione start_threads(struct glob_arg *g) { 2452f8e4e36aSLuigi Rizzo int i; 2453f8e4e36aSLuigi Rizzo 2454f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 245580ad548dSVincenzo Maffione struct targ *t; 2456f8e4e36aSLuigi Rizzo /* 2457f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 2458f8e4e36aSLuigi Rizzo * using a single descriptor. 2459f8e4e36aSLuigi Rizzo */ 2460f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 246180ad548dSVincenzo Maffione uint64_t seed = time(0) | (time(0) << 32); 246280ad548dSVincenzo Maffione t = &targs[i]; 2463f0ea3689SLuigi Rizzo 2464f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 2465f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 2466f0ea3689SLuigi Rizzo t->g = g; 246780ad548dSVincenzo Maffione memcpy(t->seed, &seed, sizeof(t->seed)); 2468f8e4e36aSLuigi Rizzo 2469f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 2470f0ea3689SLuigi Rizzo struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */ 24714bf50f18SLuigi Rizzo uint64_t nmd_flags = 0; 24724bf50f18SLuigi Rizzo nmd.self = &nmd; 2473f8e4e36aSLuigi Rizzo 247437e3a6d3SLuigi Rizzo if (i > 0) { 247537e3a6d3SLuigi Rizzo /* the first thread uses the fd opened by the main 247637e3a6d3SLuigi Rizzo * thread, the other threads re-open /dev/netmap 247737e3a6d3SLuigi Rizzo */ 2478f0ea3689SLuigi Rizzo if (g->nthreads > 1) { 247937e3a6d3SLuigi Rizzo nmd.req.nr_flags = 248037e3a6d3SLuigi Rizzo g->nmd->req.nr_flags & ~NR_REG_MASK; 248137e3a6d3SLuigi Rizzo nmd.req.nr_flags |= NR_REG_ONE_NIC; 2482f0ea3689SLuigi Rizzo nmd.req.nr_ringid = i; 248317885a7bSLuigi Rizzo } 2484f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 248537e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_RECEIVER) 24864bf50f18SLuigi Rizzo nmd_flags |= NETMAP_NO_TX_POLL; 2487f8e4e36aSLuigi Rizzo 2488f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 24894bf50f18SLuigi Rizzo t->nmd = nm_open(t->g->ifname, NULL, nmd_flags | 24904bf50f18SLuigi Rizzo NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd); 2491f0ea3689SLuigi Rizzo if (t->nmd == NULL) { 2492f0ea3689SLuigi Rizzo D("Unable to open %s: %s", 2493f0ea3689SLuigi Rizzo t->g->ifname, strerror(errno)); 2494f8e4e36aSLuigi Rizzo continue; 2495f8e4e36aSLuigi Rizzo } 249637e3a6d3SLuigi Rizzo } else { 249737e3a6d3SLuigi Rizzo t->nmd = g->nmd; 249837e3a6d3SLuigi Rizzo } 2499f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 250080ad548dSVincenzo Maffione t->frags = g->frags; 2501f8e4e36aSLuigi Rizzo } else { 2502f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 2503f8e4e36aSLuigi Rizzo } 2504f0ea3689SLuigi Rizzo t->used = 1; 2505f0ea3689SLuigi Rizzo t->me = i; 2506f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 250780ad548dSVincenzo Maffione t->affinity = (g->affinity + i) % g->cpus; 2508f0ea3689SLuigi Rizzo } else { 2509f0ea3689SLuigi Rizzo t->affinity = -1; 2510f0ea3689SLuigi Rizzo } 2511f8e4e36aSLuigi Rizzo /* default, init packets */ 2512f0ea3689SLuigi Rizzo initialize_packet(t); 251380ad548dSVincenzo Maffione } 251480ad548dSVincenzo Maffione /* Wait for PHY reset. */ 251580ad548dSVincenzo Maffione D("Wait %d secs for phy reset", g->wait_link); 251680ad548dSVincenzo Maffione sleep(g->wait_link); 251780ad548dSVincenzo Maffione D("Ready..."); 2518f8e4e36aSLuigi Rizzo 251980ad548dSVincenzo Maffione for (i = 0; i < g->nthreads; i++) { 252080ad548dSVincenzo Maffione t = &targs[i]; 2521f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 252217885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 2523f0ea3689SLuigi Rizzo t->used = 0; 2524f8e4e36aSLuigi Rizzo } 2525f8e4e36aSLuigi Rizzo } 2526f8e4e36aSLuigi Rizzo } 2527f8e4e36aSLuigi Rizzo 2528f8e4e36aSLuigi Rizzo static void 2529f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 2530f8e4e36aSLuigi Rizzo { 2531f8e4e36aSLuigi Rizzo int i; 2532f8e4e36aSLuigi Rizzo 253337e3a6d3SLuigi Rizzo struct my_ctrs prev, cur; 2534f8e4e36aSLuigi Rizzo double delta_t; 2535f8e4e36aSLuigi Rizzo struct timeval tic, toc; 2536f8e4e36aSLuigi Rizzo 253737e3a6d3SLuigi Rizzo prev.pkts = prev.bytes = prev.events = 0; 253837e3a6d3SLuigi Rizzo gettimeofday(&prev.t, NULL); 2539f8e4e36aSLuigi Rizzo for (;;) { 254080ad548dSVincenzo Maffione char b1[40], b2[40], b3[40], b4[100]; 254137e3a6d3SLuigi Rizzo uint64_t pps, usec; 254237e3a6d3SLuigi Rizzo struct my_ctrs x; 254337e3a6d3SLuigi Rizzo double abs; 2544f8e4e36aSLuigi Rizzo int done = 0; 2545f8e4e36aSLuigi Rizzo 254637e3a6d3SLuigi Rizzo usec = wait_for_next_report(&prev.t, &cur.t, 254737e3a6d3SLuigi Rizzo g->report_interval); 254837e3a6d3SLuigi Rizzo 254937e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 255037e3a6d3SLuigi Rizzo cur.min_space = 0; 255137e3a6d3SLuigi Rizzo if (usec < 10000) /* too short to be meaningful */ 255237e3a6d3SLuigi Rizzo continue; 255337e3a6d3SLuigi Rizzo /* accumulate counts for all threads */ 2554f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 255537e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 255637e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 255737e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 255837e3a6d3SLuigi Rizzo cur.min_space += targs[i].ctr.min_space; 255937e3a6d3SLuigi Rizzo targs[i].ctr.min_space = 99999; 2560f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 2561f8e4e36aSLuigi Rizzo done++; 2562f8e4e36aSLuigi Rizzo } 256337e3a6d3SLuigi Rizzo x.pkts = cur.pkts - prev.pkts; 256437e3a6d3SLuigi Rizzo x.bytes = cur.bytes - prev.bytes; 256537e3a6d3SLuigi Rizzo x.events = cur.events - prev.events; 256637e3a6d3SLuigi Rizzo pps = (x.pkts*1000000 + usec/2) / usec; 256737e3a6d3SLuigi Rizzo abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; 256837e3a6d3SLuigi Rizzo 256937e3a6d3SLuigi Rizzo if (!(g->options & OPT_PPS_STATS)) { 257037e3a6d3SLuigi Rizzo strcpy(b4, ""); 257137e3a6d3SLuigi Rizzo } else { 257237e3a6d3SLuigi Rizzo /* Compute some pps stats using a sliding window. */ 257337e3a6d3SLuigi Rizzo double ppsavg = 0.0, ppsdev = 0.0; 257437e3a6d3SLuigi Rizzo int nsamples = 0; 257537e3a6d3SLuigi Rizzo 257637e3a6d3SLuigi Rizzo g->win[g->win_idx] = pps; 257737e3a6d3SLuigi Rizzo g->win_idx = (g->win_idx + 1) % STATS_WIN; 257837e3a6d3SLuigi Rizzo 257937e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 258037e3a6d3SLuigi Rizzo ppsavg += g->win[i]; 258137e3a6d3SLuigi Rizzo if (g->win[i]) { 258237e3a6d3SLuigi Rizzo nsamples ++; 258337e3a6d3SLuigi Rizzo } 258437e3a6d3SLuigi Rizzo } 258537e3a6d3SLuigi Rizzo ppsavg /= nsamples; 258637e3a6d3SLuigi Rizzo 258737e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 258837e3a6d3SLuigi Rizzo if (g->win[i] == 0) { 2589f8e4e36aSLuigi Rizzo continue; 259037e3a6d3SLuigi Rizzo } 259137e3a6d3SLuigi Rizzo ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); 259237e3a6d3SLuigi Rizzo } 259337e3a6d3SLuigi Rizzo ppsdev /= nsamples; 259437e3a6d3SLuigi Rizzo ppsdev = sqrt(ppsdev); 259537e3a6d3SLuigi Rizzo 259637e3a6d3SLuigi Rizzo snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", 259780ad548dSVincenzo Maffione norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); 259837e3a6d3SLuigi Rizzo } 259937e3a6d3SLuigi Rizzo 260037e3a6d3SLuigi Rizzo D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", 260180ad548dSVincenzo Maffione norm(b1, pps, normalize), b4, 260280ad548dSVincenzo Maffione norm(b2, (double)x.pkts, normalize), 260380ad548dSVincenzo Maffione norm(b3, (double)x.bytes*8+(double)x.pkts*g->framing, normalize), 260437e3a6d3SLuigi Rizzo (unsigned long long)usec, 260537e3a6d3SLuigi Rizzo abs, (int)cur.min_space); 260637e3a6d3SLuigi Rizzo prev = cur; 260737e3a6d3SLuigi Rizzo 2608f8e4e36aSLuigi Rizzo if (done == g->nthreads) 2609f8e4e36aSLuigi Rizzo break; 2610f8e4e36aSLuigi Rizzo } 2611f8e4e36aSLuigi Rizzo 2612f8e4e36aSLuigi Rizzo timerclear(&tic); 2613f8e4e36aSLuigi Rizzo timerclear(&toc); 261437e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 261537e3a6d3SLuigi Rizzo /* final round */ 2616f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 26171cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 2618f8e4e36aSLuigi Rizzo /* 2619f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 2620f8e4e36aSLuigi Rizzo * file descriptors. 2621f8e4e36aSLuigi Rizzo */ 26221cb4c501SLuigi Rizzo if (targs[i].used) 262337e3a6d3SLuigi Rizzo pthread_join(targs[i].thread, NULL); /* blocking */ 262437e3a6d3SLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 262537e3a6d3SLuigi Rizzo nm_close(targs[i].nmd); 262637e3a6d3SLuigi Rizzo targs[i].nmd = NULL; 262737e3a6d3SLuigi Rizzo } else { 2628f8e4e36aSLuigi Rizzo close(targs[i].fd); 262937e3a6d3SLuigi Rizzo } 2630f8e4e36aSLuigi Rizzo 2631f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 2632f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 2633f8e4e36aSLuigi Rizzo 2634f8e4e36aSLuigi Rizzo /* 2635f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 2636f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 2637f8e4e36aSLuigi Rizzo */ 263837e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 263937e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 264037e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 264137e3a6d3SLuigi Rizzo /* collect the largest start (tic) and end (toc) times, 264237e3a6d3SLuigi Rizzo * XXX maybe we should do the earliest tic, or do a weighted 264337e3a6d3SLuigi Rizzo * average ? 264437e3a6d3SLuigi Rizzo */ 26451cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 26461cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 26471cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 26481cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 26491cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 26501cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 2651f8e4e36aSLuigi Rizzo } 2652f8e4e36aSLuigi Rizzo 2653f8e4e36aSLuigi Rizzo /* print output. */ 2654f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 2655f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 265637e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_SENDER) 265780ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Sent"); 265880ad548dSVincenzo Maffione else if (g->td_type == TD_TYPE_RECEIVER) 265980ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Received"); 2660f8e4e36aSLuigi Rizzo } 2661f8e4e36aSLuigi Rizzo 266237e3a6d3SLuigi Rizzo struct td_desc { 266337e3a6d3SLuigi Rizzo int ty; 2664f8e4e36aSLuigi Rizzo char *key; 2665f8e4e36aSLuigi Rizzo void *f; 266680ad548dSVincenzo Maffione int default_burst; 2667f8e4e36aSLuigi Rizzo }; 2668f8e4e36aSLuigi Rizzo 266937e3a6d3SLuigi Rizzo static struct td_desc func[] = { 267080ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ 267180ad548dSVincenzo Maffione { TD_TYPE_SENDER, "tx", sender_body, 512 }, 267280ad548dSVincenzo Maffione { TD_TYPE_OTHER, "ping", ping_body, 1 }, 267380ad548dSVincenzo Maffione { TD_TYPE_OTHER, "pong", pong_body, 1 }, 267480ad548dSVincenzo Maffione { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, 267580ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, 267680ad548dSVincenzo Maffione { 0, NULL, NULL, 0 } 2677f8e4e36aSLuigi Rizzo }; 2678f8e4e36aSLuigi Rizzo 2679f8e4e36aSLuigi Rizzo static int 2680f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 2681f8e4e36aSLuigi Rizzo { 2682f8e4e36aSLuigi Rizzo struct ifreq ifr; 2683f8e4e36aSLuigi Rizzo int fd, err; 2684f8e4e36aSLuigi Rizzo char *clonedev = TAP_CLONEDEV; 2685f8e4e36aSLuigi Rizzo 2686f8e4e36aSLuigi Rizzo (void)err; 2687f8e4e36aSLuigi Rizzo (void)dev; 2688f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 2689f8e4e36aSLuigi Rizzo * 2690f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 2691f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 2692f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 2693f8e4e36aSLuigi Rizzo */ 2694f8e4e36aSLuigi Rizzo 2695f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 2696f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 2697f8e4e36aSLuigi Rizzo static char buf[128]; 2698f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 2699f8e4e36aSLuigi Rizzo clonedev = buf; 2700f8e4e36aSLuigi Rizzo } 2701f8e4e36aSLuigi Rizzo #endif 2702f8e4e36aSLuigi Rizzo /* open the device */ 2703f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 2704f8e4e36aSLuigi Rizzo return fd; 2705f8e4e36aSLuigi Rizzo } 2706f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 2707f8e4e36aSLuigi Rizzo 2708f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 2709f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 2710f8e4e36aSLuigi Rizzo 2711f8e4e36aSLuigi Rizzo #ifdef linux 2712f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 2713f8e4e36aSLuigi Rizzo 2714f8e4e36aSLuigi Rizzo if (*dev) { 2715f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 2716f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 2717f8e4e36aSLuigi Rizzo * specified type */ 271880ad548dSVincenzo Maffione size_t len = strlen(dev); 271980ad548dSVincenzo Maffione if (len > IFNAMSIZ) { 272080ad548dSVincenzo Maffione D("%s too long", dev); 272180ad548dSVincenzo Maffione return -1; 272280ad548dSVincenzo Maffione } 272380ad548dSVincenzo Maffione memcpy(ifr.ifr_name, dev, len); 2724f8e4e36aSLuigi Rizzo } 2725f8e4e36aSLuigi Rizzo 2726f8e4e36aSLuigi Rizzo /* try to create the device */ 2727f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 272817885a7bSLuigi Rizzo D("failed to to a TUNSETIFF: %s", strerror(errno)); 2729f8e4e36aSLuigi Rizzo close(fd); 2730f8e4e36aSLuigi Rizzo return err; 2731f8e4e36aSLuigi Rizzo } 2732f8e4e36aSLuigi Rizzo 2733f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 2734f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 2735f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 2736f8e4e36aSLuigi Rizzo * code below) */ 2737f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 2738f8e4e36aSLuigi Rizzo D("new name is %s", dev); 2739f8e4e36aSLuigi Rizzo #endif /* linux */ 2740f8e4e36aSLuigi Rizzo 2741f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 2742f8e4e36aSLuigi Rizzo * with the virtual interface */ 2743f8e4e36aSLuigi Rizzo return fd; 2744f8e4e36aSLuigi Rizzo } 274568b8534bSLuigi Rizzo 274668b8534bSLuigi Rizzo int 274768b8534bSLuigi Rizzo main(int arc, char **argv) 274868b8534bSLuigi Rizzo { 2749f8e4e36aSLuigi Rizzo int i; 275037e3a6d3SLuigi Rizzo struct sigaction sa; 275137e3a6d3SLuigi Rizzo sigset_t ss; 275268b8534bSLuigi Rizzo 275368b8534bSLuigi Rizzo struct glob_arg g; 275468b8534bSLuigi Rizzo 275568b8534bSLuigi Rizzo int ch; 275668b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 275780ad548dSVincenzo Maffione int wait_link_arg = 0; 275880ad548dSVincenzo Maffione 275980ad548dSVincenzo Maffione int pkt_size_done = 0; 276080ad548dSVincenzo Maffione 276180ad548dSVincenzo Maffione struct td_desc *fn = func; 276268b8534bSLuigi Rizzo 276368b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 276468b8534bSLuigi Rizzo 2765f8e4e36aSLuigi Rizzo g.main_fd = -1; 276680ad548dSVincenzo Maffione g.td_body = fn->f; 276780ad548dSVincenzo Maffione g.td_type = fn->ty; 2768f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 2769f8e4e36aSLuigi Rizzo g.affinity = -1; 2770f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 277180ad548dSVincenzo Maffione g.af = AF_INET; /* default */ 2772f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 2773f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 2774f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 2775f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 277668b8534bSLuigi Rizzo g.pkt_size = 60; 277780ad548dSVincenzo Maffione g.pkt_min_size = 0; 277868b8534bSLuigi Rizzo g.nthreads = 1; 277980ad548dSVincenzo Maffione g.cpus = 1; /* default */ 2780b303f675SLuigi Rizzo g.forever = 1; 27811cb4c501SLuigi Rizzo g.tx_rate = 0; 2782ce3ee1e7SLuigi Rizzo g.frags =1; 278380ad548dSVincenzo Maffione g.mtu = 1500; 2784ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 278517885a7bSLuigi Rizzo g.virt_header = 0; 278680ad548dSVincenzo Maffione g.wait_link = 2; /* wait 2 seconds for physical ports */ 278768b8534bSLuigi Rizzo 278880ad548dSVincenzo Maffione while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" 278980ad548dSVincenzo Maffione "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) { 2790f8e4e36aSLuigi Rizzo 279168b8534bSLuigi Rizzo switch(ch) { 279268b8534bSLuigi Rizzo default: 279368b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 279480ad548dSVincenzo Maffione usage(-1); 279580ad548dSVincenzo Maffione break; 279680ad548dSVincenzo Maffione 279780ad548dSVincenzo Maffione case 'h': 279880ad548dSVincenzo Maffione usage(0); 279980ad548dSVincenzo Maffione break; 280080ad548dSVincenzo Maffione 280180ad548dSVincenzo Maffione case '4': 280280ad548dSVincenzo Maffione g.af = AF_INET; 280380ad548dSVincenzo Maffione break; 280480ad548dSVincenzo Maffione 280580ad548dSVincenzo Maffione case '6': 280680ad548dSVincenzo Maffione g.af = AF_INET6; 280780ad548dSVincenzo Maffione break; 280880ad548dSVincenzo Maffione 280980ad548dSVincenzo Maffione case 'N': 281080ad548dSVincenzo Maffione normalize = 0; 281168b8534bSLuigi Rizzo break; 2812f8e4e36aSLuigi Rizzo 2813f8e4e36aSLuigi Rizzo case 'n': 281437e3a6d3SLuigi Rizzo g.npackets = strtoull(optarg, NULL, 10); 2815f8e4e36aSLuigi Rizzo break; 2816f8e4e36aSLuigi Rizzo 2817ce3ee1e7SLuigi Rizzo case 'F': 2818ce3ee1e7SLuigi Rizzo i = atoi(optarg); 2819ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 2820ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 2821ce3ee1e7SLuigi Rizzo break; 2822ce3ee1e7SLuigi Rizzo } 2823ce3ee1e7SLuigi Rizzo g.frags = i; 2824ce3ee1e7SLuigi Rizzo break; 2825ce3ee1e7SLuigi Rizzo 282680ad548dSVincenzo Maffione case 'M': 282780ad548dSVincenzo Maffione g.mtu = atoi(optarg); 282880ad548dSVincenzo Maffione break; 282980ad548dSVincenzo Maffione 2830f8e4e36aSLuigi Rizzo case 'f': 2831f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 2832f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 2833f8e4e36aSLuigi Rizzo break; 2834f8e4e36aSLuigi Rizzo } 283537e3a6d3SLuigi Rizzo if (fn->key) { 2836f8e4e36aSLuigi Rizzo g.td_body = fn->f; 283737e3a6d3SLuigi Rizzo g.td_type = fn->ty; 283837e3a6d3SLuigi Rizzo } else { 2839f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 284037e3a6d3SLuigi Rizzo } 2841f8e4e36aSLuigi Rizzo break; 2842f8e4e36aSLuigi Rizzo 2843f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 284480ad548dSVincenzo Maffione g.options |= atoi(optarg); 284599fb123fSLuigi Rizzo break; 2846f8e4e36aSLuigi Rizzo 2847f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 2848f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 2849f8e4e36aSLuigi Rizzo break; 2850f8e4e36aSLuigi Rizzo 285168b8534bSLuigi Rizzo case 'i': /* interface */ 2852f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 2853f2637526SLuigi Rizzo * otherwise we guess 2854f2637526SLuigi Rizzo */ 2855f2637526SLuigi Rizzo D("interface is %s", optarg); 2856f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 2857f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 2858f0ea3689SLuigi Rizzo break; 2859f0ea3689SLuigi Rizzo } 2860f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 2861f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 2862f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 2863ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 2864f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 2865f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2866f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 2867f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 2868f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 2869f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 2870f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 2871f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 2872f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2873f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 2874f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2875f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 2876f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2877f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 2878f2637526SLuigi Rizzo } 287968b8534bSLuigi Rizzo break; 2880f8e4e36aSLuigi Rizzo 2881b303f675SLuigi Rizzo case 'I': 288280ad548dSVincenzo Maffione g.options |= OPT_INDIRECT; /* use indirect buffers */ 2883b303f675SLuigi Rizzo break; 2884b303f675SLuigi Rizzo 288568b8534bSLuigi Rizzo case 'l': /* pkt_size */ 288680ad548dSVincenzo Maffione if (pkt_size_done) { 288780ad548dSVincenzo Maffione g.pkt_min_size = atoi(optarg); 288880ad548dSVincenzo Maffione } else { 288968b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 289080ad548dSVincenzo Maffione pkt_size_done = 1; 289180ad548dSVincenzo Maffione } 289268b8534bSLuigi Rizzo break; 2893f8e4e36aSLuigi Rizzo 289468b8534bSLuigi Rizzo case 'd': 2895f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 289668b8534bSLuigi Rizzo break; 2897f8e4e36aSLuigi Rizzo 289868b8534bSLuigi Rizzo case 's': 2899f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 290068b8534bSLuigi Rizzo break; 2901f8e4e36aSLuigi Rizzo 290268b8534bSLuigi Rizzo case 'T': /* report interval */ 2903f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 290468b8534bSLuigi Rizzo break; 2905f8e4e36aSLuigi Rizzo 290668b8534bSLuigi Rizzo case 'w': 290780ad548dSVincenzo Maffione g.wait_link = atoi(optarg); 290880ad548dSVincenzo Maffione wait_link_arg = 1; 290968b8534bSLuigi Rizzo break; 2910f8e4e36aSLuigi Rizzo 291180ad548dSVincenzo Maffione case 'W': 291280ad548dSVincenzo Maffione g.forever = 0; /* exit RX with no traffic */ 2913f8e4e36aSLuigi Rizzo break; 2914f8e4e36aSLuigi Rizzo 291568b8534bSLuigi Rizzo case 'b': /* burst */ 291668b8534bSLuigi Rizzo g.burst = atoi(optarg); 291768b8534bSLuigi Rizzo break; 291868b8534bSLuigi Rizzo case 'c': 291968b8534bSLuigi Rizzo g.cpus = atoi(optarg); 292068b8534bSLuigi Rizzo break; 292168b8534bSLuigi Rizzo case 'p': 292268b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 292368b8534bSLuigi Rizzo break; 292468b8534bSLuigi Rizzo 292568b8534bSLuigi Rizzo case 'D': /* destination mac */ 2926f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 292768b8534bSLuigi Rizzo break; 2928f8e4e36aSLuigi Rizzo 292968b8534bSLuigi Rizzo case 'S': /* source mac */ 2930f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 293168b8534bSLuigi Rizzo break; 293268b8534bSLuigi Rizzo case 'v': 293368b8534bSLuigi Rizzo verbose++; 29341cb4c501SLuigi Rizzo break; 29351cb4c501SLuigi Rizzo case 'R': 29361cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 29371cb4c501SLuigi Rizzo break; 2938b303f675SLuigi Rizzo case 'X': 2939b303f675SLuigi Rizzo g.options |= OPT_DUMP; 2940ce3ee1e7SLuigi Rizzo break; 2941ce3ee1e7SLuigi Rizzo case 'C': 2942ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 294317885a7bSLuigi Rizzo break; 294417885a7bSLuigi Rizzo case 'H': 294517885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 2946f2637526SLuigi Rizzo break; 2947f284c737SGeorge V. Neville-Neil case 'P': 2948f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 2949f284c737SGeorge V. Neville-Neil break; 295037e3a6d3SLuigi Rizzo case 'r': 295137e3a6d3SLuigi Rizzo g.options |= OPT_RUBBISH; 295237e3a6d3SLuigi Rizzo break; 295356717743SAdrian Chadd case 'z': 295456717743SAdrian Chadd g.options |= OPT_RANDOM_SRC; 295556717743SAdrian Chadd break; 295656717743SAdrian Chadd case 'Z': 295756717743SAdrian Chadd g.options |= OPT_RANDOM_DST; 295856717743SAdrian Chadd break; 295937e3a6d3SLuigi Rizzo case 'A': 296037e3a6d3SLuigi Rizzo g.options |= OPT_PPS_STATS; 296137e3a6d3SLuigi Rizzo break; 296280ad548dSVincenzo Maffione case 'B': 296380ad548dSVincenzo Maffione /* raw packets have4 bytes crc + 20 bytes framing */ 296480ad548dSVincenzo Maffione // XXX maybe add an option to pass the IFG 296580ad548dSVincenzo Maffione g.framing = 24 * 8; 296680ad548dSVincenzo Maffione break; 296768b8534bSLuigi Rizzo } 296868b8534bSLuigi Rizzo } 296968b8534bSLuigi Rizzo 2970db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 297168b8534bSLuigi Rizzo D("missing ifname"); 297280ad548dSVincenzo Maffione usage(-1); 297380ad548dSVincenzo Maffione } 297480ad548dSVincenzo Maffione 297580ad548dSVincenzo Maffione if (g.burst == 0) { 297680ad548dSVincenzo Maffione g.burst = fn->default_burst; 297780ad548dSVincenzo Maffione D("using default burst size: %d", g.burst); 297868b8534bSLuigi Rizzo } 2979f8e4e36aSLuigi Rizzo 298037e3a6d3SLuigi Rizzo g.system_cpus = i = system_ncpus(); 2981f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 2982f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 298380ad548dSVincenzo Maffione usage(-1); 298468b8534bSLuigi Rizzo } 298537e3a6d3SLuigi Rizzo D("running on %d cpus (have %d)", g.cpus, i); 298668b8534bSLuigi Rizzo if (g.cpus == 0) 2987f8e4e36aSLuigi Rizzo g.cpus = i; 2988f8e4e36aSLuigi Rizzo 298980ad548dSVincenzo Maffione if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) { 299080ad548dSVincenzo Maffione g.wait_link = 0; 299180ad548dSVincenzo Maffione } 299280ad548dSVincenzo Maffione 29934bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 29944bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 299580ad548dSVincenzo Maffione usage(-1); 299680ad548dSVincenzo Maffione } 299780ad548dSVincenzo Maffione 299880ad548dSVincenzo Maffione if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) { 299980ad548dSVincenzo Maffione D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size); 300080ad548dSVincenzo Maffione usage(-1); 300168b8534bSLuigi Rizzo } 300268b8534bSLuigi Rizzo 3003f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 3004f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 300599fb123fSLuigi Rizzo /* retrieve source mac address. */ 3006f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 300799fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 300899fb123fSLuigi Rizzo // continue, fail later 300999fb123fSLuigi Rizzo } 3010f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 301199fb123fSLuigi Rizzo } 3012f8e4e36aSLuigi Rizzo /* extract address ranges */ 301380ad548dSVincenzo Maffione if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac)) 301480ad548dSVincenzo Maffione usage(-1); 301580ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.src_ip, g.af); 301680ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.dst_ip, g.af); 3017f2637526SLuigi Rizzo 301817885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 301917885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 302017885a7bSLuigi Rizzo D("bad virtio-net-header length"); 302180ad548dSVincenzo Maffione usage(-1); 302217885a7bSLuigi Rizzo } 302317885a7bSLuigi Rizzo 3024f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 3025f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 3026f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 3027f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 3028f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 302980ad548dSVincenzo Maffione usage(-1); 303099fb123fSLuigi Rizzo } 3031f2637526SLuigi Rizzo #ifndef NO_PCAP 3032f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 3033f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 3034f8e4e36aSLuigi Rizzo 3035f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 30364bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 3037f8e4e36aSLuigi Rizzo if (g.p == NULL) { 3038f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 303980ad548dSVincenzo Maffione usage(-1); 3040f8e4e36aSLuigi Rizzo } 30414bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 30424bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 3043f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 3044f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 3045ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 304699fb123fSLuigi Rizzo } else { 304780ad548dSVincenzo Maffione struct nm_desc base_nmd; 304880ad548dSVincenzo Maffione char errmsg[MAXERRMSG]; 304980ad548dSVincenzo Maffione u_int flags; 3050f0ea3689SLuigi Rizzo 3051f0ea3689SLuigi Rizzo bzero(&base_nmd, sizeof(base_nmd)); 3052f0ea3689SLuigi Rizzo 305380ad548dSVincenzo Maffione parse_nmr_config(g.nmr_config, &base_nmd.req); 305437e3a6d3SLuigi Rizzo 305580ad548dSVincenzo Maffione base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR; 305680ad548dSVincenzo Maffione 305780ad548dSVincenzo Maffione if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) { 305880ad548dSVincenzo Maffione D("Invalid name '%s': %s", g.ifname, errmsg); 305980ad548dSVincenzo Maffione goto out; 306080ad548dSVincenzo Maffione } 3061f0ea3689SLuigi Rizzo 306268b8534bSLuigi Rizzo /* 3063f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 306468b8534bSLuigi Rizzo * 306568b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 306668b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 3067f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 306868b8534bSLuigi Rizzo */ 306980ad548dSVincenzo Maffione flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 | 307080ad548dSVincenzo Maffione NM_OPEN_ARG3 | NM_OPEN_RING_CFG; 307137e3a6d3SLuigi Rizzo if (g.nthreads > 1) { 307280ad548dSVincenzo Maffione base_nmd.req.nr_flags &= ~NR_REG_MASK; 307380ad548dSVincenzo Maffione base_nmd.req.nr_flags |= NR_REG_ONE_NIC; 307480ad548dSVincenzo Maffione base_nmd.req.nr_ringid = 0; 307580ad548dSVincenzo Maffione } 307680ad548dSVincenzo Maffione g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd); 307737e3a6d3SLuigi Rizzo if (g.nmd == NULL) { 307837e3a6d3SLuigi Rizzo D("Unable to open %s: %s", g.ifname, strerror(errno)); 307937e3a6d3SLuigi Rizzo goto out; 308037e3a6d3SLuigi Rizzo } 3081f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 308280ad548dSVincenzo Maffione D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10), 308380ad548dSVincenzo Maffione g.nmd->mem); 3084f0ea3689SLuigi Rizzo 308537e3a6d3SLuigi Rizzo if (g.virt_header) { 308637e3a6d3SLuigi Rizzo /* Set the virtio-net header length, since the user asked 308737e3a6d3SLuigi Rizzo * for it explicitely. */ 308837e3a6d3SLuigi Rizzo set_vnet_hdr_len(&g); 308937e3a6d3SLuigi Rizzo } else { 309037e3a6d3SLuigi Rizzo /* Check whether the netmap port we opened requires us to send 309137e3a6d3SLuigi Rizzo * and receive frames with virtio-net header. */ 309237e3a6d3SLuigi Rizzo get_vnet_hdr_len(&g); 309337e3a6d3SLuigi Rizzo } 309437e3a6d3SLuigi Rizzo 30954bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 309637e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 30974bf50f18SLuigi Rizzo devqueues = g.nmd->req.nr_tx_rings; 30984bf50f18SLuigi Rizzo else 3099f0ea3689SLuigi Rizzo devqueues = g.nmd->req.nr_rx_rings; 310068b8534bSLuigi Rizzo 310168b8534bSLuigi Rizzo /* validate provided nthreads. */ 310268b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 310368b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 310468b8534bSLuigi Rizzo // continue, fail later 310568b8534bSLuigi Rizzo } 310668b8534bSLuigi Rizzo 3107f2637526SLuigi Rizzo if (verbose) { 3108f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 3109f0ea3689SLuigi Rizzo struct nmreq *req = &g.nmd->req; 311068b8534bSLuigi Rizzo 3111f0ea3689SLuigi Rizzo D("nifp at offset %d, %d tx %d rx region %d", 3112f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 3113f0ea3689SLuigi Rizzo req->nr_arg2); 3114f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_tx_rings; i++) { 31154bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 311637e3a6d3SLuigi Rizzo D(" TX%d at 0x%p slots %d", i, 311737e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3118f2637526SLuigi Rizzo } 3119f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_rx_rings; i++) { 31204bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 312137e3a6d3SLuigi Rizzo D(" RX%d at 0x%p slots %d", i, 312237e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3123f2637526SLuigi Rizzo } 3124f2637526SLuigi Rizzo } 312568b8534bSLuigi Rizzo 312668b8534bSLuigi Rizzo /* Print some debug information. */ 312768b8534bSLuigi Rizzo fprintf(stdout, 312868b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 312937e3a6d3SLuigi Rizzo (g.td_type == TD_TYPE_SENDER) ? "Sending on" : 313037e3a6d3SLuigi Rizzo ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : 313137e3a6d3SLuigi Rizzo "Working on"), 3132f8e4e36aSLuigi Rizzo g.ifname, 313368b8534bSLuigi Rizzo devqueues, 313468b8534bSLuigi Rizzo g.nthreads, 313568b8534bSLuigi Rizzo g.cpus); 313637e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) { 313768b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 3138f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 3139f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 314068b8534bSLuigi Rizzo } 314168b8534bSLuigi Rizzo 3142f0ea3689SLuigi Rizzo out: 314368b8534bSLuigi Rizzo /* Exit if something went wrong. */ 3144f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 314568b8534bSLuigi Rizzo D("aborting"); 314680ad548dSVincenzo Maffione usage(-1); 314768b8534bSLuigi Rizzo } 314899fb123fSLuigi Rizzo } 314968b8534bSLuigi Rizzo 3150ce3ee1e7SLuigi Rizzo 315199fb123fSLuigi Rizzo if (g.options) { 315237e3a6d3SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", 315399fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 315499fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 315599fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 3156b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 315737e3a6d3SLuigi Rizzo g.options & OPT_COPY ? " copy" : "", 315837e3a6d3SLuigi Rizzo g.options & OPT_RUBBISH ? " rubbish " : ""); 315999fb123fSLuigi Rizzo } 31601cb4c501SLuigi Rizzo 3161ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 3162ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 3163ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 316417885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 3165ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 3166ce3ee1e7SLuigi Rizzo */ 316717885a7bSLuigi Rizzo uint64_t x; 316817885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 316917885a7bSLuigi Rizzo if (g.burst > lim) 317017885a7bSLuigi Rizzo g.burst = lim; 317180ad548dSVincenzo Maffione if (g.burst == 0) 317280ad548dSVincenzo Maffione g.burst = 1; 317317885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 317417885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 31751cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 31761cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 31771cb4c501SLuigi Rizzo } 317837e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 3179ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 3180ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 318168b8534bSLuigi Rizzo /* Install ^C handler. */ 318268b8534bSLuigi Rizzo global_nthreads = g.nthreads; 318337e3a6d3SLuigi Rizzo sigemptyset(&ss); 318437e3a6d3SLuigi Rizzo sigaddset(&ss, SIGINT); 318537e3a6d3SLuigi Rizzo /* block SIGINT now, so that all created threads will inherit the mask */ 318637e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { 318737e3a6d3SLuigi Rizzo D("failed to block SIGINT: %s", strerror(errno)); 318837e3a6d3SLuigi Rizzo } 3189f8e4e36aSLuigi Rizzo start_threads(&g); 319037e3a6d3SLuigi Rizzo /* Install the handler and re-enable SIGINT for the main thread */ 319180ad548dSVincenzo Maffione memset(&sa, 0, sizeof(sa)); 319237e3a6d3SLuigi Rizzo sa.sa_handler = sigint_h; 319337e3a6d3SLuigi Rizzo if (sigaction(SIGINT, &sa, NULL) < 0) { 319437e3a6d3SLuigi Rizzo D("failed to install ^C handler: %s", strerror(errno)); 319537e3a6d3SLuigi Rizzo } 319637e3a6d3SLuigi Rizzo 319737e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { 319837e3a6d3SLuigi Rizzo D("failed to re-enable SIGINT: %s", strerror(errno)); 319937e3a6d3SLuigi Rizzo } 3200f8e4e36aSLuigi Rizzo main_thread(&g); 320137e3a6d3SLuigi Rizzo free(targs); 3202f8e4e36aSLuigi Rizzo return 0; 320368b8534bSLuigi Rizzo } 320468b8534bSLuigi Rizzo 320568b8534bSLuigi Rizzo /* end of file */ 3206