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 1989e53f3bdSVincenzo Maffione #define MAX_BODYSIZE 65536 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 MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ 2424bf50f18SLuigi Rizzo 2434bf50f18SLuigi Rizzo /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ 2444bf50f18SLuigi Rizzo struct tstamp { 2454bf50f18SLuigi Rizzo uint32_t sec; 2464bf50f18SLuigi Rizzo uint32_t nsec; 2474bf50f18SLuigi Rizzo }; 2484bf50f18SLuigi Rizzo 24968b8534bSLuigi Rizzo /* 25068b8534bSLuigi Rizzo * global arguments for all threads 25168b8534bSLuigi Rizzo */ 252f8e4e36aSLuigi Rizzo 25368b8534bSLuigi Rizzo struct glob_arg { 25480ad548dSVincenzo Maffione int af; /* address family AF_INET/AF_INET6 */ 255f8e4e36aSLuigi Rizzo struct ip_range src_ip; 256f8e4e36aSLuigi Rizzo struct ip_range dst_ip; 257f8e4e36aSLuigi Rizzo struct mac_range dst_mac; 258f8e4e36aSLuigi Rizzo struct mac_range src_mac; 25968b8534bSLuigi Rizzo int pkt_size; 26080ad548dSVincenzo Maffione int pkt_min_size; 26168b8534bSLuigi Rizzo int burst; 262f8e4e36aSLuigi Rizzo int forever; 26337e3a6d3SLuigi Rizzo uint64_t npackets; /* total packets to send */ 264ce3ee1e7SLuigi Rizzo int frags; /* fragments per packet */ 2659e53f3bdSVincenzo Maffione u_int frag_size; /* size of each fragment */ 26668b8534bSLuigi Rizzo int nthreads; 26737e3a6d3SLuigi Rizzo int cpus; /* cpus used for running */ 26837e3a6d3SLuigi Rizzo int system_cpus; /* cpus on the system */ 26937e3a6d3SLuigi Rizzo 27099fb123fSLuigi Rizzo int options; /* testing */ 27199fb123fSLuigi Rizzo #define OPT_PREFETCH 1 27299fb123fSLuigi Rizzo #define OPT_ACCESS 2 27399fb123fSLuigi Rizzo #define OPT_COPY 4 27499fb123fSLuigi Rizzo #define OPT_MEMCPY 8 275f8e4e36aSLuigi Rizzo #define OPT_TS 16 /* add a timestamp */ 276b303f675SLuigi Rizzo #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ 277b303f675SLuigi Rizzo #define OPT_DUMP 64 /* dump rx/tx traffic */ 27837e3a6d3SLuigi Rizzo #define OPT_RUBBISH 256 /* send wathever the buffers contain */ 27956717743SAdrian Chadd #define OPT_RANDOM_SRC 512 28056717743SAdrian Chadd #define OPT_RANDOM_DST 1024 28137e3a6d3SLuigi Rizzo #define OPT_PPS_STATS 2048 282f8e4e36aSLuigi Rizzo int dev_type; 283f2637526SLuigi Rizzo #ifndef NO_PCAP 28468b8534bSLuigi Rizzo pcap_t *p; 285f2637526SLuigi Rizzo #endif 28668b8534bSLuigi Rizzo 2871cb4c501SLuigi Rizzo int tx_rate; 2881cb4c501SLuigi Rizzo struct timespec tx_period; 2891cb4c501SLuigi Rizzo 290f8e4e36aSLuigi Rizzo int affinity; 291f8e4e36aSLuigi Rizzo int main_fd; 292f0ea3689SLuigi Rizzo struct nm_desc *nmd; 293f2637526SLuigi Rizzo int report_interval; /* milliseconds between prints */ 294f8e4e36aSLuigi Rizzo void *(*td_body)(void *); 29537e3a6d3SLuigi Rizzo int td_type; 296f8e4e36aSLuigi Rizzo void *mmap_addr; 297f0ea3689SLuigi Rizzo char ifname[MAX_IFNAMELEN]; 298ce3ee1e7SLuigi Rizzo char *nmr_config; 299ce3ee1e7SLuigi Rizzo int dummy_send; 30017885a7bSLuigi Rizzo int virt_header; /* send also the virt_header */ 301f284c737SGeorge V. Neville-Neil char *packet_file; /* -P option */ 30237e3a6d3SLuigi Rizzo #define STATS_WIN 15 30337e3a6d3SLuigi Rizzo int win_idx; 30437e3a6d3SLuigi Rizzo int64_t win[STATS_WIN]; 30580ad548dSVincenzo Maffione int wait_link; 30680ad548dSVincenzo Maffione int framing; /* #bits of framing (for bw output) */ 30768b8534bSLuigi Rizzo }; 308f8e4e36aSLuigi Rizzo enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; 309f8e4e36aSLuigi Rizzo 3109e53f3bdSVincenzo Maffione enum { 3119e53f3bdSVincenzo Maffione TD_TYPE_SENDER = 1, 3129e53f3bdSVincenzo Maffione TD_TYPE_RECEIVER, 3139e53f3bdSVincenzo Maffione TD_TYPE_OTHER, 3149e53f3bdSVincenzo Maffione }; 31568b8534bSLuigi Rizzo 31668b8534bSLuigi Rizzo /* 31768b8534bSLuigi Rizzo * Arguments for a new thread. The same structure is used by 31868b8534bSLuigi Rizzo * the source and the sink 31968b8534bSLuigi Rizzo */ 32068b8534bSLuigi Rizzo struct targ { 32168b8534bSLuigi Rizzo struct glob_arg *g; 32268b8534bSLuigi Rizzo int used; 32368b8534bSLuigi Rizzo int completed; 3243fe77e68SEd Maste int cancel; 32568b8534bSLuigi Rizzo int fd; 326f0ea3689SLuigi Rizzo struct nm_desc *nmd; 32737e3a6d3SLuigi Rizzo /* these ought to be volatile, but they are 32837e3a6d3SLuigi Rizzo * only sampled and errors should not accumulate 32937e3a6d3SLuigi Rizzo */ 33037e3a6d3SLuigi Rizzo struct my_ctrs ctr; 33137e3a6d3SLuigi Rizzo 3321cb4c501SLuigi Rizzo struct timespec tic, toc; 33368b8534bSLuigi Rizzo int me; 33468b8534bSLuigi Rizzo pthread_t thread; 33568b8534bSLuigi Rizzo int affinity; 33668b8534bSLuigi Rizzo 33768b8534bSLuigi Rizzo struct pkt pkt; 338f284c737SGeorge V. Neville-Neil void *frame; 33980ad548dSVincenzo Maffione uint16_t seed[3]; 34080ad548dSVincenzo Maffione u_int frags; 34180ad548dSVincenzo Maffione u_int frag_size; 34268b8534bSLuigi Rizzo }; 34368b8534bSLuigi Rizzo 34480ad548dSVincenzo Maffione static __inline uint16_t 34580ad548dSVincenzo Maffione cksum_add(uint16_t sum, uint16_t a) 34680ad548dSVincenzo Maffione { 34780ad548dSVincenzo Maffione uint16_t res; 34868b8534bSLuigi Rizzo 34980ad548dSVincenzo Maffione res = sum + a; 35080ad548dSVincenzo Maffione return (res + (res < a)); 35180ad548dSVincenzo Maffione } 35280ad548dSVincenzo Maffione 35380ad548dSVincenzo Maffione static void 35480ad548dSVincenzo Maffione extract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port) 35580ad548dSVincenzo Maffione { 35680ad548dSVincenzo Maffione struct in_addr a; 35780ad548dSVincenzo Maffione char *pp; 35880ad548dSVincenzo Maffione 35980ad548dSVincenzo Maffione pp = strchr(name, ':'); 36080ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 36180ad548dSVincenzo Maffione *pp++ = '\0'; 36280ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 36380ad548dSVincenzo Maffione } 36480ad548dSVincenzo Maffione 36580ad548dSVincenzo Maffione inet_pton(AF_INET, name, &a); 36680ad548dSVincenzo Maffione *addr = ntohl(a.s_addr); 36780ad548dSVincenzo Maffione } 36880ad548dSVincenzo Maffione 36980ad548dSVincenzo Maffione static void 37080ad548dSVincenzo Maffione extract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port, 37180ad548dSVincenzo Maffione uint8_t *group) 37280ad548dSVincenzo Maffione { 37380ad548dSVincenzo Maffione char *pp; 37480ad548dSVincenzo Maffione 37580ad548dSVincenzo Maffione /* 37680ad548dSVincenzo Maffione * We accept IPv6 address in the following form: 37780ad548dSVincenzo Maffione * group@[2001:DB8::1001]:port (w/ brackets and port) 37880ad548dSVincenzo Maffione * group@[2001:DB8::1] (w/ brackets and w/o port) 37980ad548dSVincenzo Maffione * group@2001:DB8::1234 (w/o brackets and w/o port) 38080ad548dSVincenzo Maffione */ 38180ad548dSVincenzo Maffione pp = strchr(name, '@'); 38280ad548dSVincenzo Maffione if (pp != NULL) { 38380ad548dSVincenzo Maffione *pp++ = '\0'; 38480ad548dSVincenzo Maffione *group = (uint8_t)strtol(name, NULL, 0); 38580ad548dSVincenzo Maffione if (*group > 7) 38680ad548dSVincenzo Maffione *group = 7; 38780ad548dSVincenzo Maffione name = pp; 38880ad548dSVincenzo Maffione } 38980ad548dSVincenzo Maffione if (name[0] == '[') 39080ad548dSVincenzo Maffione name++; 39180ad548dSVincenzo Maffione pp = strchr(name, ']'); 39280ad548dSVincenzo Maffione if (pp != NULL) 39380ad548dSVincenzo Maffione *pp++ = '\0'; 39480ad548dSVincenzo Maffione if (pp != NULL && *pp != ':') 39580ad548dSVincenzo Maffione pp = NULL; 39680ad548dSVincenzo Maffione if (pp != NULL) { /* do we have ports ? */ 39780ad548dSVincenzo Maffione *pp++ = '\0'; 39880ad548dSVincenzo Maffione *port = (uint16_t)strtol(pp, NULL, 0); 39980ad548dSVincenzo Maffione } 40080ad548dSVincenzo Maffione inet_pton(AF_INET6, name, addr); 40180ad548dSVincenzo Maffione } 402f8e4e36aSLuigi Rizzo /* 403f8e4e36aSLuigi Rizzo * extract the extremes from a range of ipv4 addresses. 404f8e4e36aSLuigi Rizzo * addr_lo[-addr_hi][:port_lo[-port_hi]] 405f8e4e36aSLuigi Rizzo */ 40680ad548dSVincenzo Maffione static int 40780ad548dSVincenzo Maffione extract_ip_range(struct ip_range *r, int af) 408f8e4e36aSLuigi Rizzo { 40980ad548dSVincenzo Maffione char *name, *ap, start[INET6_ADDRSTRLEN]; 41080ad548dSVincenzo Maffione char end[INET6_ADDRSTRLEN]; 411ce3ee1e7SLuigi Rizzo struct in_addr a; 41280ad548dSVincenzo Maffione uint32_t tmp; 413f8e4e36aSLuigi Rizzo 41417885a7bSLuigi Rizzo if (verbose) 415f8e4e36aSLuigi Rizzo D("extract IP range from %s", r->name); 416ce3ee1e7SLuigi Rizzo 41780ad548dSVincenzo Maffione name = strdup(r->name); 41880ad548dSVincenzo Maffione if (name == NULL) { 41980ad548dSVincenzo Maffione D("strdup failed"); 42080ad548dSVincenzo Maffione usage(-1); 42180ad548dSVincenzo Maffione } 422ce3ee1e7SLuigi Rizzo /* the first - splits start/end of range */ 42380ad548dSVincenzo Maffione ap = strchr(name, '-'); 42480ad548dSVincenzo Maffione if (ap != NULL) 425ce3ee1e7SLuigi Rizzo *ap++ = '\0'; 42680ad548dSVincenzo Maffione r->port0 = 1234; /* default port */ 42780ad548dSVincenzo Maffione if (af == AF_INET6) { 42880ad548dSVincenzo Maffione r->ipv6.sgroup = 7; /* default group */ 42980ad548dSVincenzo Maffione extract_ipv6_addr(name, &r->ipv6.start, &r->port0, 43080ad548dSVincenzo Maffione &r->ipv6.sgroup); 43180ad548dSVincenzo Maffione } else 43280ad548dSVincenzo Maffione extract_ipv4_addr(name, &r->ipv4.start, &r->port0); 43380ad548dSVincenzo Maffione 43480ad548dSVincenzo Maffione r->port1 = r->port0; 43580ad548dSVincenzo Maffione if (af == AF_INET6) { 43680ad548dSVincenzo Maffione if (ap != NULL) { 43780ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 43880ad548dSVincenzo Maffione extract_ipv6_addr(ap, &r->ipv6.end, &r->port1, 43980ad548dSVincenzo Maffione &r->ipv6.egroup); 44080ad548dSVincenzo Maffione } else { 44180ad548dSVincenzo Maffione r->ipv6.end = r->ipv6.start; 44280ad548dSVincenzo Maffione r->ipv6.egroup = r->ipv6.sgroup; 443ce3ee1e7SLuigi Rizzo } 44480ad548dSVincenzo Maffione } else { 44580ad548dSVincenzo Maffione if (ap != NULL) { 44680ad548dSVincenzo Maffione extract_ipv4_addr(ap, &r->ipv4.end, &r->port1); 44780ad548dSVincenzo Maffione if (r->ipv4.start > r->ipv4.end) { 44880ad548dSVincenzo Maffione tmp = r->ipv4.end; 44980ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 45080ad548dSVincenzo Maffione r->ipv4.start = tmp; 451ce3ee1e7SLuigi Rizzo } 45280ad548dSVincenzo Maffione } else 45380ad548dSVincenzo Maffione r->ipv4.end = r->ipv4.start; 454ce3ee1e7SLuigi Rizzo } 45580ad548dSVincenzo Maffione 456ce3ee1e7SLuigi Rizzo if (r->port0 > r->port1) { 45780ad548dSVincenzo Maffione tmp = r->port0; 458f8e4e36aSLuigi Rizzo r->port0 = r->port1; 459ce3ee1e7SLuigi Rizzo r->port1 = tmp; 460f8e4e36aSLuigi Rizzo } 46180ad548dSVincenzo Maffione if (af == AF_INET) { 46280ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.start); 46380ad548dSVincenzo Maffione inet_ntop(af, &a, start, sizeof(start)); 46480ad548dSVincenzo Maffione a.s_addr = htonl(r->ipv4.end); 46580ad548dSVincenzo Maffione inet_ntop(af, &a, end, sizeof(end)); 46680ad548dSVincenzo Maffione } else { 46780ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.start, start, sizeof(start)); 46880ad548dSVincenzo Maffione inet_ntop(af, &r->ipv6.end, end, sizeof(end)); 469f8e4e36aSLuigi Rizzo } 47080ad548dSVincenzo Maffione if (af == AF_INET) 47180ad548dSVincenzo Maffione D("range is %s:%d to %s:%d", start, r->port0, end, r->port1); 47280ad548dSVincenzo Maffione else 47380ad548dSVincenzo Maffione D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup, 47480ad548dSVincenzo Maffione start, r->port0, r->ipv6.egroup, end, r->port1); 475ce3ee1e7SLuigi Rizzo 47680ad548dSVincenzo Maffione free(name); 47780ad548dSVincenzo Maffione if (r->port0 != r->port1 || 47880ad548dSVincenzo Maffione (af == AF_INET && r->ipv4.start != r->ipv4.end) || 47980ad548dSVincenzo Maffione (af == AF_INET6 && 48080ad548dSVincenzo Maffione !IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end))) 48180ad548dSVincenzo Maffione return (OPT_COPY); 48280ad548dSVincenzo Maffione return (0); 483f8e4e36aSLuigi Rizzo } 484f8e4e36aSLuigi Rizzo 48580ad548dSVincenzo Maffione static int 486f8e4e36aSLuigi Rizzo extract_mac_range(struct mac_range *r) 487f8e4e36aSLuigi Rizzo { 48880ad548dSVincenzo Maffione struct ether_addr *e; 48917885a7bSLuigi Rizzo if (verbose) 490f8e4e36aSLuigi Rizzo D("extract MAC range from %s", r->name); 49180ad548dSVincenzo Maffione 49280ad548dSVincenzo Maffione e = ether_aton(r->name); 49380ad548dSVincenzo Maffione if (e == NULL) { 49480ad548dSVincenzo Maffione D("invalid MAC address '%s'", r->name); 49580ad548dSVincenzo Maffione return 1; 49680ad548dSVincenzo Maffione } 49780ad548dSVincenzo Maffione bcopy(e, &r->start, 6); 49880ad548dSVincenzo Maffione bcopy(e, &r->end, 6); 499f8e4e36aSLuigi Rizzo #if 0 500f8e4e36aSLuigi Rizzo bcopy(targ->src_mac, eh->ether_shost, 6); 501f8e4e36aSLuigi Rizzo p = index(targ->g->src_mac, '-'); 502f8e4e36aSLuigi Rizzo if (p) 503f8e4e36aSLuigi Rizzo targ->src_mac_range = atoi(p+1); 504f8e4e36aSLuigi Rizzo 505f8e4e36aSLuigi Rizzo bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6); 506f8e4e36aSLuigi Rizzo bcopy(targ->dst_mac, eh->ether_dhost, 6); 507f8e4e36aSLuigi Rizzo p = index(targ->g->dst_mac, '-'); 508f8e4e36aSLuigi Rizzo if (p) 509f8e4e36aSLuigi Rizzo targ->dst_mac_range = atoi(p+1); 510f8e4e36aSLuigi Rizzo #endif 51117885a7bSLuigi Rizzo if (verbose) 512f8e4e36aSLuigi Rizzo D("%s starts at %s", r->name, ether_ntoa(&r->start)); 51380ad548dSVincenzo Maffione return 0; 514f8e4e36aSLuigi Rizzo } 515f8e4e36aSLuigi Rizzo 5169e53f3bdSVincenzo Maffione static int 5179e53f3bdSVincenzo Maffione get_if_mtu(const struct glob_arg *g) 5189e53f3bdSVincenzo Maffione { 5199e53f3bdSVincenzo Maffione char ifname[IFNAMSIZ]; 5209e53f3bdSVincenzo Maffione struct ifreq ifreq; 5219e53f3bdSVincenzo Maffione int s, ret; 5229e53f3bdSVincenzo Maffione 5239e53f3bdSVincenzo Maffione if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{') 5249e53f3bdSVincenzo Maffione && !strchr(g->ifname, '}')) { 5259e53f3bdSVincenzo Maffione /* Parse the interface name and ask the kernel for the 5269e53f3bdSVincenzo Maffione * MTU value. */ 5279e53f3bdSVincenzo Maffione strncpy(ifname, g->ifname+7, IFNAMSIZ-1); 5289e53f3bdSVincenzo Maffione ifname[strcspn(ifname, "-*^{}/@")] = '\0'; 5299e53f3bdSVincenzo Maffione 5309e53f3bdSVincenzo Maffione s = socket(AF_INET, SOCK_DGRAM, 0); 5319e53f3bdSVincenzo Maffione if (s < 0) { 5329e53f3bdSVincenzo Maffione D("socket() failed: %s", strerror(errno)); 5339e53f3bdSVincenzo Maffione return s; 5349e53f3bdSVincenzo Maffione } 5359e53f3bdSVincenzo Maffione 5369e53f3bdSVincenzo Maffione memset(&ifreq, 0, sizeof(ifreq)); 5379e53f3bdSVincenzo Maffione strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); 5389e53f3bdSVincenzo Maffione 5399e53f3bdSVincenzo Maffione ret = ioctl(s, SIOCGIFMTU, &ifreq); 5409e53f3bdSVincenzo Maffione if (ret) { 5419e53f3bdSVincenzo Maffione D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno)); 5429e53f3bdSVincenzo Maffione } 5439e53f3bdSVincenzo Maffione 5449e53f3bdSVincenzo Maffione return ifreq.ifr_mtu; 5459e53f3bdSVincenzo Maffione } 5469e53f3bdSVincenzo Maffione 5479e53f3bdSVincenzo Maffione /* This is a pipe or a VALE port, where the MTU is very large, 5489e53f3bdSVincenzo Maffione * so we use some practical limit. */ 5499e53f3bdSVincenzo Maffione return 65536; 5509e53f3bdSVincenzo Maffione } 5519e53f3bdSVincenzo Maffione 55268b8534bSLuigi Rizzo static struct targ *targs; 55368b8534bSLuigi Rizzo static int global_nthreads; 55468b8534bSLuigi Rizzo 55568b8534bSLuigi Rizzo /* control-C handler */ 55668b8534bSLuigi Rizzo static void 557f8e4e36aSLuigi Rizzo sigint_h(int sig) 55868b8534bSLuigi Rizzo { 559f8e4e36aSLuigi Rizzo int i; 56068b8534bSLuigi Rizzo 561f8e4e36aSLuigi Rizzo (void)sig; /* UNUSED */ 56237e3a6d3SLuigi Rizzo D("received control-C on thread %p", (void *)pthread_self()); 563f8e4e36aSLuigi Rizzo for (i = 0; i < global_nthreads; i++) { 564f8e4e36aSLuigi Rizzo targs[i].cancel = 1; 565f8e4e36aSLuigi Rizzo } 56668b8534bSLuigi Rizzo } 56768b8534bSLuigi Rizzo 56868b8534bSLuigi Rizzo /* sysctl wrapper to return the number of active CPUs */ 56968b8534bSLuigi Rizzo static int 57068b8534bSLuigi Rizzo system_ncpus(void) 57168b8534bSLuigi Rizzo { 572f0ea3689SLuigi Rizzo int ncpus; 573f0ea3689SLuigi Rizzo #if defined (__FreeBSD__) 574f0ea3689SLuigi Rizzo int mib[2] = { CTL_HW, HW_NCPU }; 575f0ea3689SLuigi Rizzo size_t len = sizeof(mib); 57668b8534bSLuigi Rizzo sysctl(mib, 2, &ncpus, &len, NULL, 0); 577f0ea3689SLuigi Rizzo #elif defined(linux) 578f0ea3689SLuigi Rizzo ncpus = sysconf(_SC_NPROCESSORS_ONLN); 57937e3a6d3SLuigi Rizzo #elif defined(_WIN32) 58037e3a6d3SLuigi Rizzo { 58137e3a6d3SLuigi Rizzo SYSTEM_INFO sysinfo; 58237e3a6d3SLuigi Rizzo GetSystemInfo(&sysinfo); 58337e3a6d3SLuigi Rizzo ncpus = sysinfo.dwNumberOfProcessors; 58437e3a6d3SLuigi Rizzo } 585f0ea3689SLuigi Rizzo #else /* others */ 586f0ea3689SLuigi Rizzo ncpus = 1; 587f0ea3689SLuigi Rizzo #endif /* others */ 58868b8534bSLuigi Rizzo return (ncpus); 58968b8534bSLuigi Rizzo } 59068b8534bSLuigi Rizzo 591f8e4e36aSLuigi Rizzo #ifdef __linux__ 592f8e4e36aSLuigi Rizzo #define sockaddr_dl sockaddr_ll 593f8e4e36aSLuigi Rizzo #define sdl_family sll_family 594f8e4e36aSLuigi Rizzo #define AF_LINK AF_PACKET 595f8e4e36aSLuigi Rizzo #define LLADDR(s) s->sll_addr; 596f8e4e36aSLuigi Rizzo #include <linux/if_tun.h> 597f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/net/tun" 598f8e4e36aSLuigi Rizzo #endif /* __linux__ */ 599f8e4e36aSLuigi Rizzo 600f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 601f8e4e36aSLuigi Rizzo #include <net/if_tun.h> 602f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 603f8e4e36aSLuigi Rizzo #endif /* __FreeBSD */ 604f8e4e36aSLuigi Rizzo 605f8e4e36aSLuigi Rizzo #ifdef __APPLE__ 606f8e4e36aSLuigi Rizzo // #warning TAP not supported on apple ? 607f8e4e36aSLuigi Rizzo #include <net/if_utun.h> 608f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 609f8e4e36aSLuigi Rizzo #endif /* __APPLE__ */ 610f8e4e36aSLuigi Rizzo 611f8e4e36aSLuigi Rizzo 61268b8534bSLuigi Rizzo /* 613ce3ee1e7SLuigi Rizzo * parse the vale configuration in conf and put it in nmr. 614f0ea3689SLuigi Rizzo * Return the flag set if necessary. 61580ad548dSVincenzo Maffione * The configuration may consist of 1 to 4 numbers separated 616fc6eb28bSHiren Panchasara * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. 617ce3ee1e7SLuigi Rizzo * Missing numbers or zeroes stand for default values. 618ce3ee1e7SLuigi Rizzo * As an additional convenience, if exactly one number 619fc6eb28bSHiren Panchasara * is specified, then this is assigned to both #tx-slots and #rx-slots. 620fc6eb28bSHiren Panchasara * If there is no 4th number, then the 3rd is assigned to both #tx-rings 621ce3ee1e7SLuigi Rizzo * and #rx-rings. 622ce3ee1e7SLuigi Rizzo */ 623f0ea3689SLuigi Rizzo int 624f0ea3689SLuigi Rizzo parse_nmr_config(const char* conf, struct nmreq *nmr) 625ce3ee1e7SLuigi Rizzo { 626ce3ee1e7SLuigi Rizzo char *w, *tok; 627ce3ee1e7SLuigi Rizzo int i, v; 628ce3ee1e7SLuigi Rizzo 629ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 630ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 631ce3ee1e7SLuigi Rizzo if (conf == NULL || ! *conf) 632f0ea3689SLuigi Rizzo return 0; 633ce3ee1e7SLuigi Rizzo w = strdup(conf); 634ce3ee1e7SLuigi Rizzo for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 635ce3ee1e7SLuigi Rizzo v = atoi(tok); 636ce3ee1e7SLuigi Rizzo switch (i) { 637ce3ee1e7SLuigi Rizzo case 0: 638ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = v; 639ce3ee1e7SLuigi Rizzo break; 640ce3ee1e7SLuigi Rizzo case 1: 641ce3ee1e7SLuigi Rizzo nmr->nr_rx_slots = v; 642ce3ee1e7SLuigi Rizzo break; 643ce3ee1e7SLuigi Rizzo case 2: 644ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = v; 645ce3ee1e7SLuigi Rizzo break; 646ce3ee1e7SLuigi Rizzo case 3: 647ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings = v; 648ce3ee1e7SLuigi Rizzo break; 649ce3ee1e7SLuigi Rizzo default: 650ce3ee1e7SLuigi Rizzo D("ignored config: %s", tok); 651ce3ee1e7SLuigi Rizzo break; 652ce3ee1e7SLuigi Rizzo } 653ce3ee1e7SLuigi Rizzo } 654ce3ee1e7SLuigi Rizzo D("txr %d txd %d rxr %d rxd %d", 655ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings, nmr->nr_tx_slots, 656ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings, nmr->nr_rx_slots); 657ce3ee1e7SLuigi Rizzo free(w); 658f0ea3689SLuigi Rizzo return (nmr->nr_tx_rings || nmr->nr_tx_slots || 659f0ea3689SLuigi Rizzo nmr->nr_rx_rings || nmr->nr_rx_slots) ? 660f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG : 0; 661ce3ee1e7SLuigi Rizzo } 662ce3ee1e7SLuigi Rizzo 663ce3ee1e7SLuigi Rizzo 664ce3ee1e7SLuigi Rizzo /* 66568b8534bSLuigi Rizzo * locate the src mac address for our interface, put it 66668b8534bSLuigi Rizzo * into the user-supplied buffer. return 0 if ok, -1 on error. 66768b8534bSLuigi Rizzo */ 66868b8534bSLuigi Rizzo static int 66968b8534bSLuigi Rizzo source_hwaddr(const char *ifname, char *buf) 67068b8534bSLuigi Rizzo { 67168b8534bSLuigi Rizzo struct ifaddrs *ifaphead, *ifap; 67268b8534bSLuigi Rizzo 67368b8534bSLuigi Rizzo if (getifaddrs(&ifaphead) != 0) { 67468b8534bSLuigi Rizzo D("getifaddrs %s failed", ifname); 67568b8534bSLuigi Rizzo return (-1); 67668b8534bSLuigi Rizzo } 67768b8534bSLuigi Rizzo 67868b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 67968b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 68068b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 68168b8534bSLuigi Rizzo uint8_t *mac; 68268b8534bSLuigi Rizzo 68368b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 68468b8534bSLuigi Rizzo continue; 68580ad548dSVincenzo Maffione if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) 68668b8534bSLuigi Rizzo continue; 68768b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 68868b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 68968b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 69068b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 69168b8534bSLuigi Rizzo if (verbose) 69268b8534bSLuigi Rizzo D("source hwaddr %s", buf); 69368b8534bSLuigi Rizzo break; 69468b8534bSLuigi Rizzo } 69568b8534bSLuigi Rizzo freeifaddrs(ifaphead); 69668b8534bSLuigi Rizzo return ifap ? 0 : 1; 69768b8534bSLuigi Rizzo } 69868b8534bSLuigi Rizzo 69968b8534bSLuigi Rizzo 70068b8534bSLuigi Rizzo /* set the thread affinity. */ 70168b8534bSLuigi Rizzo static int 70268b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 70368b8534bSLuigi Rizzo { 70468b8534bSLuigi Rizzo cpuset_t cpumask; 70568b8534bSLuigi Rizzo 70668b8534bSLuigi Rizzo if (i == -1) 70768b8534bSLuigi Rizzo return 0; 70868b8534bSLuigi Rizzo 70968b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 71068b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 71168b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 71268b8534bSLuigi Rizzo 71368b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 71417885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 71568b8534bSLuigi Rizzo return 1; 71668b8534bSLuigi Rizzo } 71768b8534bSLuigi Rizzo return 0; 71868b8534bSLuigi Rizzo } 71968b8534bSLuigi Rizzo 72080ad548dSVincenzo Maffione 72168b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 72280ad548dSVincenzo Maffione static uint32_t 723f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 72468b8534bSLuigi Rizzo { 72568b8534bSLuigi Rizzo const uint8_t *addr = data; 726f8e4e36aSLuigi Rizzo uint32_t i; 72768b8534bSLuigi Rizzo 728f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 729f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 730f8e4e36aSLuigi Rizzo sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); 731f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 732f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 733f8e4e36aSLuigi Rizzo } 734f8e4e36aSLuigi Rizzo /* 735f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 736f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 737f8e4e36aSLuigi Rizzo * the high byte. 738f8e4e36aSLuigi Rizzo */ 739f8e4e36aSLuigi Rizzo if (i < len) { 740f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 741f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 742f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 743f8e4e36aSLuigi Rizzo } 744f8e4e36aSLuigi Rizzo return sum; 74568b8534bSLuigi Rizzo } 74668b8534bSLuigi Rizzo 74780ad548dSVincenzo Maffione static uint16_t 74880ad548dSVincenzo Maffione wrapsum(uint32_t sum) 749f8e4e36aSLuigi Rizzo { 750f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 751f8e4e36aSLuigi Rizzo return (htons(sum)); 75268b8534bSLuigi Rizzo } 75368b8534bSLuigi Rizzo 754b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 755b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 756b303f675SLuigi Rizzo */ 757b303f675SLuigi Rizzo static void 75837e3a6d3SLuigi Rizzo dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) 759b303f675SLuigi Rizzo { 760b303f675SLuigi Rizzo char buf[128]; 761b303f675SLuigi Rizzo int i, j, i0; 76237e3a6d3SLuigi Rizzo const unsigned char *p = (const unsigned char *)_p; 763b303f675SLuigi Rizzo 764b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 765b303f675SLuigi Rizzo 766ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 767ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 768ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 769b303f675SLuigi Rizzo /* hexdump routine */ 770b303f675SLuigi Rizzo for (i = 0; i < len; ) { 771b797f66cSConrad Meyer memset(buf, ' ', sizeof(buf)); 772b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 773b303f675SLuigi Rizzo i0 = i; 774b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 775b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 776b303f675SLuigi Rizzo i = i0; 777b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 778b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 779b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 780b303f675SLuigi Rizzo printf("%s\n", buf); 781b303f675SLuigi Rizzo } 782b303f675SLuigi Rizzo } 783b303f675SLuigi Rizzo 78468b8534bSLuigi Rizzo /* 78568b8534bSLuigi Rizzo * Fill a packet with some payload. 786f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 787f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 78868b8534bSLuigi Rizzo */ 789f8e4e36aSLuigi Rizzo #ifdef __linux__ 790f8e4e36aSLuigi Rizzo #define uh_sport source 791f8e4e36aSLuigi Rizzo #define uh_dport dest 792f8e4e36aSLuigi Rizzo #define uh_ulen len 793f8e4e36aSLuigi Rizzo #define uh_sum check 794f8e4e36aSLuigi Rizzo #endif /* linux */ 795b303f675SLuigi Rizzo 796ce3ee1e7SLuigi Rizzo static void 79780ad548dSVincenzo Maffione update_ip(struct pkt *pkt, struct targ *t) 798ce3ee1e7SLuigi Rizzo { 79980ad548dSVincenzo Maffione struct glob_arg *g = t->g; 80080ad548dSVincenzo Maffione struct ip ip; 80180ad548dSVincenzo Maffione struct udphdr udp; 80280ad548dSVincenzo Maffione uint32_t oaddr, naddr; 80380ad548dSVincenzo Maffione uint16_t oport, nport; 80480ad548dSVincenzo Maffione uint16_t ip_sum, udp_sum; 805ce3ee1e7SLuigi Rizzo 80680ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 80780ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); 808f2637526SLuigi Rizzo do { 80980ad548dSVincenzo Maffione ip_sum = udp_sum = 0; 81080ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_src.s_addr); 81180ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 81256717743SAdrian Chadd if (g->options & OPT_RANDOM_SRC) { 81380ad548dSVincenzo Maffione ip.ip_src.s_addr = nrand48(t->seed); 81480ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 81580ad548dSVincenzo Maffione naddr = ntohl(ip.ip_src.s_addr); 81680ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 817f2637526SLuigi Rizzo break; 818ce3ee1e7SLuigi Rizzo } 81980ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 82080ad548dSVincenzo Maffione nport = oport + 1; 82180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 822f2637526SLuigi Rizzo break; 823ce3ee1e7SLuigi Rizzo } 82480ad548dSVincenzo Maffione nport = g->src_ip.port0; 82580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 82680ad548dSVincenzo Maffione if (oaddr < g->src_ip.ipv4.end) { 82780ad548dSVincenzo Maffione naddr = oaddr + 1; 82880ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 829f2637526SLuigi Rizzo break; 830ce3ee1e7SLuigi Rizzo } 83180ad548dSVincenzo Maffione naddr = g->src_ip.ipv4.start; 83280ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(naddr); 833f2637526SLuigi Rizzo } while (0); 83480ad548dSVincenzo Maffione /* update checksums if needed */ 83580ad548dSVincenzo Maffione if (oaddr != naddr) { 83680ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 83780ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 83880ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 83980ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 84080ad548dSVincenzo Maffione } 84180ad548dSVincenzo Maffione if (oport != nport) { 84280ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 84380ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 84480ad548dSVincenzo Maffione } 84580ad548dSVincenzo Maffione do { 84680ad548dSVincenzo Maffione naddr = oaddr = ntohl(ip.ip_dst.s_addr); 84780ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 84880ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 84980ad548dSVincenzo Maffione ip.ip_dst.s_addr = nrand48(t->seed); 85080ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 85180ad548dSVincenzo Maffione naddr = ntohl(ip.ip_dst.s_addr); 85280ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 85380ad548dSVincenzo Maffione break; 85480ad548dSVincenzo Maffione } 85580ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 85680ad548dSVincenzo Maffione nport = oport + 1; 85780ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 85880ad548dSVincenzo Maffione break; 85980ad548dSVincenzo Maffione } 86080ad548dSVincenzo Maffione nport = g->dst_ip.port0; 86180ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 86280ad548dSVincenzo Maffione if (oaddr < g->dst_ip.ipv4.end) { 86380ad548dSVincenzo Maffione naddr = oaddr + 1; 86480ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 86580ad548dSVincenzo Maffione break; 86680ad548dSVincenzo Maffione } 86780ad548dSVincenzo Maffione naddr = g->dst_ip.ipv4.start; 86880ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(naddr); 86980ad548dSVincenzo Maffione } while (0); 87080ad548dSVincenzo Maffione /* update checksums */ 87180ad548dSVincenzo Maffione if (oaddr != naddr) { 87280ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr >> 16); 87380ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); 87480ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr >> 16); 87580ad548dSVincenzo Maffione ip_sum = cksum_add(ip_sum, naddr & 0xffff); 87680ad548dSVincenzo Maffione } 87780ad548dSVincenzo Maffione if (oport != nport) { 87880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, ~oport); 87980ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, nport); 88080ad548dSVincenzo Maffione } 88180ad548dSVincenzo Maffione if (udp_sum != 0) 88280ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); 88380ad548dSVincenzo Maffione if (ip_sum != 0) { 88480ad548dSVincenzo Maffione ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); 88580ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); 88680ad548dSVincenzo Maffione } 88780ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 88880ad548dSVincenzo Maffione memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); 889ce3ee1e7SLuigi Rizzo } 890ce3ee1e7SLuigi Rizzo 89180ad548dSVincenzo Maffione #ifndef s6_addr16 89280ad548dSVincenzo Maffione #define s6_addr16 __u6_addr.__u6_addr16 89380ad548dSVincenzo Maffione #endif 89480ad548dSVincenzo Maffione static void 89580ad548dSVincenzo Maffione update_ip6(struct pkt *pkt, struct targ *t) 89680ad548dSVincenzo Maffione { 89780ad548dSVincenzo Maffione struct glob_arg *g = t->g; 89880ad548dSVincenzo Maffione struct ip6_hdr ip6; 89980ad548dSVincenzo Maffione struct udphdr udp; 90080ad548dSVincenzo Maffione uint16_t udp_sum; 90180ad548dSVincenzo Maffione uint16_t oaddr, naddr; 90280ad548dSVincenzo Maffione uint16_t oport, nport; 90380ad548dSVincenzo Maffione uint8_t group; 90480ad548dSVincenzo Maffione 90580ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); 90680ad548dSVincenzo Maffione memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); 90780ad548dSVincenzo Maffione do { 90880ad548dSVincenzo Maffione udp_sum = 0; 90980ad548dSVincenzo Maffione group = g->src_ip.ipv6.sgroup; 91080ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); 91180ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_sport); 91280ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_SRC) { 91380ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = nrand48(t->seed); 91480ad548dSVincenzo Maffione udp.uh_sport = nrand48(t->seed); 91580ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_src.s6_addr16[group]); 91680ad548dSVincenzo Maffione nport = ntohs(udp.uh_sport); 91780ad548dSVincenzo Maffione break; 91880ad548dSVincenzo Maffione } 91980ad548dSVincenzo Maffione if (oport < g->src_ip.port1) { 92080ad548dSVincenzo Maffione nport = oport + 1; 92180ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 92280ad548dSVincenzo Maffione break; 92380ad548dSVincenzo Maffione } 92480ad548dSVincenzo Maffione nport = g->src_ip.port0; 92580ad548dSVincenzo Maffione udp.uh_sport = htons(nport); 92680ad548dSVincenzo Maffione if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { 92780ad548dSVincenzo Maffione naddr = oaddr + 1; 92880ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 92980ad548dSVincenzo Maffione break; 93080ad548dSVincenzo Maffione } 93180ad548dSVincenzo Maffione naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); 93280ad548dSVincenzo Maffione ip6.ip6_src.s6_addr16[group] = htons(naddr); 93380ad548dSVincenzo Maffione } while (0); 93480ad548dSVincenzo Maffione /* update checksums if needed */ 93580ad548dSVincenzo Maffione if (oaddr != naddr) 93680ad548dSVincenzo Maffione udp_sum = cksum_add(~oaddr, naddr); 93780ad548dSVincenzo Maffione if (oport != nport) 93880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 93980ad548dSVincenzo Maffione cksum_add(~oport, nport)); 94080ad548dSVincenzo Maffione do { 94180ad548dSVincenzo Maffione group = g->dst_ip.ipv6.egroup; 94280ad548dSVincenzo Maffione naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 94380ad548dSVincenzo Maffione nport = oport = ntohs(udp.uh_dport); 94480ad548dSVincenzo Maffione if (g->options & OPT_RANDOM_DST) { 94580ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed); 94680ad548dSVincenzo Maffione udp.uh_dport = nrand48(t->seed); 94780ad548dSVincenzo Maffione naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); 94880ad548dSVincenzo Maffione nport = ntohs(udp.uh_dport); 94980ad548dSVincenzo Maffione break; 95080ad548dSVincenzo Maffione } 95180ad548dSVincenzo Maffione if (oport < g->dst_ip.port1) { 95280ad548dSVincenzo Maffione nport = oport + 1; 95380ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 95480ad548dSVincenzo Maffione break; 95580ad548dSVincenzo Maffione } 95680ad548dSVincenzo Maffione nport = g->dst_ip.port0; 95780ad548dSVincenzo Maffione udp.uh_dport = htons(nport); 95880ad548dSVincenzo Maffione if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { 95980ad548dSVincenzo Maffione naddr = oaddr + 1; 96080ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 96180ad548dSVincenzo Maffione break; 96280ad548dSVincenzo Maffione } 96380ad548dSVincenzo Maffione naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); 96480ad548dSVincenzo Maffione ip6.ip6_dst.s6_addr16[group] = htons(naddr); 96580ad548dSVincenzo Maffione } while (0); 96680ad548dSVincenzo Maffione /* update checksums */ 96780ad548dSVincenzo Maffione if (oaddr != naddr) 96880ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 96980ad548dSVincenzo Maffione cksum_add(~oaddr, naddr)); 97080ad548dSVincenzo Maffione if (oport != nport) 97180ad548dSVincenzo Maffione udp_sum = cksum_add(udp_sum, 97280ad548dSVincenzo Maffione cksum_add(~oport, nport)); 97380ad548dSVincenzo Maffione if (udp_sum != 0) 97480ad548dSVincenzo Maffione udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); 97580ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 97680ad548dSVincenzo Maffione memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); 97780ad548dSVincenzo Maffione } 97880ad548dSVincenzo Maffione 97980ad548dSVincenzo Maffione static void 98080ad548dSVincenzo Maffione update_addresses(struct pkt *pkt, struct targ *t) 98180ad548dSVincenzo Maffione { 98280ad548dSVincenzo Maffione 98380ad548dSVincenzo Maffione if (t->g->af == AF_INET) 98480ad548dSVincenzo Maffione update_ip(pkt, t); 98580ad548dSVincenzo Maffione else 98680ad548dSVincenzo Maffione update_ip6(pkt, t); 98780ad548dSVincenzo Maffione } 988ce3ee1e7SLuigi Rizzo /* 989ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 990ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 991ce3ee1e7SLuigi Rizzo */ 99268b8534bSLuigi Rizzo static void 99368b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 99468b8534bSLuigi Rizzo { 99568b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 99668b8534bSLuigi Rizzo struct ether_header *eh; 99780ad548dSVincenzo Maffione struct ip6_hdr ip6; 99880ad548dSVincenzo Maffione struct ip ip; 99980ad548dSVincenzo Maffione struct udphdr udp; 100080ad548dSVincenzo Maffione void *udp_ptr; 100180ad548dSVincenzo Maffione uint16_t paylen; 100280ad548dSVincenzo Maffione uint32_t csum = 0; 1003b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 1004ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 1005f2637526SLuigi Rizzo int i, l0 = strlen(payload); 100668b8534bSLuigi Rizzo 100737e3a6d3SLuigi Rizzo #ifndef NO_PCAP 1008f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 1009f284c737SGeorge V. Neville-Neil pcap_t *file; 1010f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 1011f284c737SGeorge V. Neville-Neil const unsigned char *packet; 1012f284c737SGeorge V. Neville-Neil 1013f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 1014f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 1015f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 1016f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 1017f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 1018f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1019f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 1020f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 1021f284c737SGeorge V. Neville-Neil targ->g->packet_file); 1022f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 1023f284c737SGeorge V. Neville-Neil D("out of memory"); 1024f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 1025f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 1026f284c737SGeorge V. Neville-Neil pcap_close(file); 1027f284c737SGeorge V. Neville-Neil return; 1028f284c737SGeorge V. Neville-Neil } 102937e3a6d3SLuigi Rizzo #endif 1030f284c737SGeorge V. Neville-Neil 103180ad548dSVincenzo Maffione paylen = targ->g->pkt_size - sizeof(*eh) - 103280ad548dSVincenzo Maffione (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); 103380ad548dSVincenzo Maffione 1034ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 1035f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 1036f2637526SLuigi Rizzo if (l0 > paylen - i) 1037f2637526SLuigi Rizzo l0 = paylen - i; // last round 103880ad548dSVincenzo Maffione bcopy(payload, PKT(pkt, body, targ->g->af) + i, l0); 103968b8534bSLuigi Rizzo } 104080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[i - 1] = '\0'; 1041f8e4e36aSLuigi Rizzo 1042ce3ee1e7SLuigi Rizzo /* prepare the headers */ 104368b8534bSLuigi Rizzo eh = &pkt->eh; 1044f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 1045f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 104680ad548dSVincenzo Maffione 104780ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 104868b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 104980ad548dSVincenzo Maffione memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); 105080ad548dSVincenzo Maffione udp_ptr = &pkt->ipv4.udp; 105180ad548dSVincenzo Maffione ip.ip_v = IPVERSION; 105280ad548dSVincenzo Maffione ip.ip_hl = sizeof(ip) >> 2; 105380ad548dSVincenzo Maffione ip.ip_id = 0; 105480ad548dSVincenzo Maffione ip.ip_tos = IPTOS_LOWDELAY; 105580ad548dSVincenzo Maffione ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); 105680ad548dSVincenzo Maffione ip.ip_id = 0; 105780ad548dSVincenzo Maffione ip.ip_off = htons(IP_DF); /* Don't fragment */ 105880ad548dSVincenzo Maffione ip.ip_ttl = IPDEFTTL; 105980ad548dSVincenzo Maffione ip.ip_p = IPPROTO_UDP; 106080ad548dSVincenzo Maffione ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); 106180ad548dSVincenzo Maffione ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); 106280ad548dSVincenzo Maffione ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); 106380ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 106480ad548dSVincenzo Maffione } else { 106580ad548dSVincenzo Maffione eh->ether_type = htons(ETHERTYPE_IPV6); 106680ad548dSVincenzo Maffione memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); 106780ad548dSVincenzo Maffione udp_ptr = &pkt->ipv6.udp; 106880ad548dSVincenzo Maffione ip6.ip6_flow = 0; 106980ad548dSVincenzo Maffione ip6.ip6_plen = htons(paylen); 107080ad548dSVincenzo Maffione ip6.ip6_vfc = IPV6_VERSION; 107180ad548dSVincenzo Maffione ip6.ip6_nxt = IPPROTO_UDP; 107280ad548dSVincenzo Maffione ip6.ip6_hlim = IPV6_DEFHLIM; 107380ad548dSVincenzo Maffione ip6.ip6_src = targ->g->src_ip.ipv6.start; 107480ad548dSVincenzo Maffione ip6.ip6_dst = targ->g->dst_ip.ipv6.start; 107580ad548dSVincenzo Maffione } 107680ad548dSVincenzo Maffione memcpy(&udp, udp_ptr, sizeof(udp)); 107780ad548dSVincenzo Maffione 107880ad548dSVincenzo Maffione udp.uh_sport = htons(targ->g->src_ip.port0); 107980ad548dSVincenzo Maffione udp.uh_dport = htons(targ->g->dst_ip.port0); 108080ad548dSVincenzo Maffione udp.uh_ulen = htons(paylen); 108180ad548dSVincenzo Maffione if (targ->g->af == AF_INET) { 108280ad548dSVincenzo Maffione /* Magic: taken from sbin/dhclient/packet.c */ 108380ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 108480ad548dSVincenzo Maffione checksum(&udp, sizeof(udp), /* udp header */ 108580ad548dSVincenzo Maffione checksum(pkt->ipv4.body, /* udp payload */ 108680ad548dSVincenzo Maffione paylen - sizeof(udp), 108780ad548dSVincenzo Maffione checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 108880ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv4.ip.ip_src), 108980ad548dSVincenzo Maffione IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); 109080ad548dSVincenzo Maffione memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); 109180ad548dSVincenzo Maffione } else { 109280ad548dSVincenzo Maffione /* Save part of pseudo header checksum into csum */ 109380ad548dSVincenzo Maffione csum = IPPROTO_UDP << 24; 109480ad548dSVincenzo Maffione csum = checksum(&csum, sizeof(csum), paylen); 109580ad548dSVincenzo Maffione udp.uh_sum = wrapsum( 109680ad548dSVincenzo Maffione checksum(udp_ptr, sizeof(udp), /* udp header */ 109780ad548dSVincenzo Maffione checksum(pkt->ipv6.body, /* udp payload */ 109880ad548dSVincenzo Maffione paylen - sizeof(udp), 109980ad548dSVincenzo Maffione checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 110080ad548dSVincenzo Maffione 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); 110180ad548dSVincenzo Maffione memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); 110280ad548dSVincenzo Maffione } 110380ad548dSVincenzo Maffione memcpy(udp_ptr, &udp, sizeof(udp)); 110417885a7bSLuigi Rizzo 110517885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 1106b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 110768b8534bSLuigi Rizzo } 110868b8534bSLuigi Rizzo 11094bf50f18SLuigi Rizzo static void 111037e3a6d3SLuigi Rizzo get_vnet_hdr_len(struct glob_arg *g) 11114bf50f18SLuigi Rizzo { 111237e3a6d3SLuigi Rizzo struct nmreq req; 111337e3a6d3SLuigi Rizzo int err; 111437e3a6d3SLuigi Rizzo 111537e3a6d3SLuigi Rizzo memset(&req, 0, sizeof(req)); 111637e3a6d3SLuigi Rizzo bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); 111737e3a6d3SLuigi Rizzo req.nr_version = NETMAP_API; 111837e3a6d3SLuigi Rizzo req.nr_cmd = NETMAP_VNET_HDR_GET; 111937e3a6d3SLuigi Rizzo err = ioctl(g->main_fd, NIOCREGIF, &req); 112037e3a6d3SLuigi Rizzo if (err) { 112137e3a6d3SLuigi Rizzo D("Unable to get virtio-net header length"); 112237e3a6d3SLuigi Rizzo return; 112337e3a6d3SLuigi Rizzo } 112437e3a6d3SLuigi Rizzo 112537e3a6d3SLuigi Rizzo g->virt_header = req.nr_arg1; 112637e3a6d3SLuigi Rizzo if (g->virt_header) { 112737e3a6d3SLuigi Rizzo D("Port requires virtio-net header, length = %d", 112837e3a6d3SLuigi Rizzo g->virt_header); 112937e3a6d3SLuigi Rizzo } 113037e3a6d3SLuigi Rizzo } 113137e3a6d3SLuigi Rizzo 113237e3a6d3SLuigi Rizzo static void 113337e3a6d3SLuigi Rizzo set_vnet_hdr_len(struct glob_arg *g) 113437e3a6d3SLuigi Rizzo { 113537e3a6d3SLuigi Rizzo int err, l = g->virt_header; 11364bf50f18SLuigi Rizzo struct nmreq req; 11374bf50f18SLuigi Rizzo 11384bf50f18SLuigi Rizzo if (l == 0) 11394bf50f18SLuigi Rizzo return; 11404bf50f18SLuigi Rizzo 11414bf50f18SLuigi Rizzo memset(&req, 0, sizeof(req)); 114237e3a6d3SLuigi Rizzo bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); 11434bf50f18SLuigi Rizzo req.nr_version = NETMAP_API; 11444bf50f18SLuigi Rizzo req.nr_cmd = NETMAP_BDG_VNET_HDR; 11454bf50f18SLuigi Rizzo req.nr_arg1 = l; 114637e3a6d3SLuigi Rizzo err = ioctl(g->main_fd, NIOCREGIF, &req); 11474bf50f18SLuigi Rizzo if (err) { 114837e3a6d3SLuigi Rizzo D("Unable to set virtio-net header length %d", l); 11494bf50f18SLuigi Rizzo } 11504bf50f18SLuigi Rizzo } 115168b8534bSLuigi Rizzo 115268b8534bSLuigi Rizzo /* 115368b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 115468b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 115568b8534bSLuigi Rizzo * an interrupt when done. 115668b8534bSLuigi Rizzo */ 115768b8534bSLuigi Rizzo static int 115817885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 115980ad548dSVincenzo Maffione int size, struct targ *t, u_int count, int options) 116068b8534bSLuigi Rizzo { 116117885a7bSLuigi Rizzo u_int n, sent, cur = ring->cur; 116280ad548dSVincenzo Maffione u_int frags = t->frags; 116380ad548dSVincenzo Maffione u_int frag_size = t->frag_size; 116480ad548dSVincenzo Maffione struct netmap_slot *slot = &ring->slot[cur]; 116568b8534bSLuigi Rizzo 116617885a7bSLuigi Rizzo n = nm_ring_space(ring); 116799fb123fSLuigi Rizzo #if 0 116899fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 116968b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 117068b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 117168b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 117268b8534bSLuigi Rizzo 1173f2637526SLuigi Rizzo __builtin_prefetch(p); 117417885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 117599fb123fSLuigi Rizzo } 117699fb123fSLuigi Rizzo cur = ring->cur; 117799fb123fSLuigi Rizzo } 117899fb123fSLuigi Rizzo #endif 117980ad548dSVincenzo Maffione for (sent = 0; sent < count && n >= frags; sent++, n--) { 118080ad548dSVincenzo Maffione char *p; 118180ad548dSVincenzo Maffione int buf_changed; 118280ad548dSVincenzo Maffione u_int tosend = size; 118380ad548dSVincenzo Maffione 118480ad548dSVincenzo Maffione slot = &ring->slot[cur]; 118580ad548dSVincenzo Maffione p = NETMAP_BUF(ring, slot->buf_idx); 118680ad548dSVincenzo Maffione buf_changed = slot->flags & NS_BUF_CHANGED; 118799fb123fSLuigi Rizzo 1188b303f675SLuigi Rizzo slot->flags = 0; 118937e3a6d3SLuigi Rizzo if (options & OPT_RUBBISH) { 119037e3a6d3SLuigi Rizzo /* do nothing */ 119137e3a6d3SLuigi Rizzo } else if (options & OPT_INDIRECT) { 1192b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 119337e3a6d3SLuigi Rizzo slot->ptr = (uint64_t)((uintptr_t)frame); 119480ad548dSVincenzo Maffione } else if (frags > 1) { 119580ad548dSVincenzo Maffione u_int i; 119680ad548dSVincenzo Maffione const char *f = frame; 119780ad548dSVincenzo Maffione char *fp = p; 119880ad548dSVincenzo Maffione for (i = 0; i < frags - 1; i++) { 119980ad548dSVincenzo Maffione memcpy(fp, f, frag_size); 120080ad548dSVincenzo Maffione slot->len = frag_size; 120180ad548dSVincenzo Maffione slot->flags = NS_MOREFRAG; 120280ad548dSVincenzo Maffione if (options & OPT_DUMP) 120380ad548dSVincenzo Maffione dump_payload(fp, frag_size, ring, cur); 120480ad548dSVincenzo Maffione tosend -= frag_size; 120580ad548dSVincenzo Maffione f += frag_size; 120680ad548dSVincenzo Maffione cur = nm_ring_next(ring, cur); 120780ad548dSVincenzo Maffione slot = &ring->slot[cur]; 120880ad548dSVincenzo Maffione fp = NETMAP_BUF(ring, slot->buf_idx); 120980ad548dSVincenzo Maffione } 121080ad548dSVincenzo Maffione n -= (frags - 1); 121180ad548dSVincenzo Maffione p = fp; 121280ad548dSVincenzo Maffione slot->flags = 0; 121380ad548dSVincenzo Maffione memcpy(p, f, tosend); 121480ad548dSVincenzo Maffione update_addresses(pkt, t); 121580ad548dSVincenzo Maffione } else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) { 121680ad548dSVincenzo Maffione if (options & OPT_COPY) 1217f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 121880ad548dSVincenzo Maffione else 121917885a7bSLuigi Rizzo memcpy(p, frame, size); 122080ad548dSVincenzo Maffione update_addresses(pkt, t); 1221ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 1222f2637526SLuigi Rizzo __builtin_prefetch(p); 1223ce3ee1e7SLuigi Rizzo } 122480ad548dSVincenzo Maffione slot->len = tosend; 1225ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 122680ad548dSVincenzo Maffione dump_payload(p, tosend, ring, cur); 122717885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 122868b8534bSLuigi Rizzo } 122980ad548dSVincenzo Maffione if (sent) { 123080ad548dSVincenzo Maffione slot->flags |= NS_REPORT; 123117885a7bSLuigi Rizzo ring->head = ring->cur = cur; 123280ad548dSVincenzo Maffione } 123380ad548dSVincenzo Maffione if (sent < count) { 123480ad548dSVincenzo Maffione /* tell netmap that we need more slots */ 123580ad548dSVincenzo Maffione ring->cur = ring->tail; 123680ad548dSVincenzo Maffione } 123768b8534bSLuigi Rizzo 123868b8534bSLuigi Rizzo return (sent); 123968b8534bSLuigi Rizzo } 124068b8534bSLuigi Rizzo 1241f8e4e36aSLuigi Rizzo /* 124237e3a6d3SLuigi Rizzo * Index of the highest bit set 124337e3a6d3SLuigi Rizzo */ 124437e3a6d3SLuigi Rizzo uint32_t 124537e3a6d3SLuigi Rizzo msb64(uint64_t x) 124637e3a6d3SLuigi Rizzo { 124737e3a6d3SLuigi Rizzo uint64_t m = 1ULL << 63; 124837e3a6d3SLuigi Rizzo int i; 124937e3a6d3SLuigi Rizzo 125037e3a6d3SLuigi Rizzo for (i = 63; i >= 0; i--, m >>=1) 125137e3a6d3SLuigi Rizzo if (m & x) 125237e3a6d3SLuigi Rizzo return i; 125337e3a6d3SLuigi Rizzo return 0; 125437e3a6d3SLuigi Rizzo } 125537e3a6d3SLuigi Rizzo 125637e3a6d3SLuigi Rizzo /* 125780ad548dSVincenzo Maffione * wait until ts, either busy or sleeping if more than 1ms. 125880ad548dSVincenzo Maffione * Return wakeup time. 125980ad548dSVincenzo Maffione */ 126080ad548dSVincenzo Maffione static struct timespec 126180ad548dSVincenzo Maffione wait_time(struct timespec ts) 126280ad548dSVincenzo Maffione { 126380ad548dSVincenzo Maffione for (;;) { 126480ad548dSVincenzo Maffione struct timespec w, cur; 126580ad548dSVincenzo Maffione clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 126680ad548dSVincenzo Maffione w = timespec_sub(ts, cur); 126780ad548dSVincenzo Maffione if (w.tv_sec < 0) 126880ad548dSVincenzo Maffione return cur; 126980ad548dSVincenzo Maffione else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 127080ad548dSVincenzo Maffione poll(NULL, 0, 1); 127180ad548dSVincenzo Maffione } 127280ad548dSVincenzo Maffione } 127380ad548dSVincenzo Maffione 127480ad548dSVincenzo Maffione /* 1275f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 1276f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 1277f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 1278f8e4e36aSLuigi Rizzo */ 1279f8e4e36aSLuigi Rizzo 128068b8534bSLuigi Rizzo static void * 128180ad548dSVincenzo Maffione ping_body(void *data) 128268b8534bSLuigi Rizzo { 128368b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1284f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1285f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 128680ad548dSVincenzo Maffione int i, m, rx = 0; 128717885a7bSLuigi Rizzo void *frame; 128817885a7bSLuigi Rizzo int size; 1289f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 129080ad548dSVincenzo Maffione struct timespec nexttime = {0, 0}; /* silence compiler */ 129137e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 129237e3a6d3SLuigi Rizzo uint64_t count = 0, t_cur, t_min = ~0, av = 0; 129380ad548dSVincenzo Maffione uint64_t g_min = ~0, g_av = 0; 129437e3a6d3SLuigi Rizzo uint64_t buckets[64]; /* bins for delays, ns */ 129580ad548dSVincenzo Maffione int rate_limit = targ->g->tx_rate, tosend = 0; 129617885a7bSLuigi Rizzo 129780ad548dSVincenzo Maffione frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header; 129817885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1299e5ecae38SEd Maste 130037e3a6d3SLuigi Rizzo 1301f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1302f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 1303f8e4e36aSLuigi Rizzo return NULL; 1304f95a30bdSEd Maste } 1305f8e4e36aSLuigi Rizzo 130637e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1307f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 130817885a7bSLuigi Rizzo now = last_print; 130980ad548dSVincenzo Maffione if (rate_limit) { 131080ad548dSVincenzo Maffione targ->tic = timespec_add(now, (struct timespec){2,0}); 131180ad548dSVincenzo Maffione targ->tic.tv_nsec = 0; 131280ad548dSVincenzo Maffione wait_time(targ->tic); 131380ad548dSVincenzo Maffione nexttime = targ->tic; 131480ad548dSVincenzo Maffione } 131537e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 131680ad548dSVincenzo Maffione struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1317f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 1318f8e4e36aSLuigi Rizzo char *p; 131980ad548dSVincenzo Maffione int rv; 132080ad548dSVincenzo Maffione uint64_t limit, event = 0; 132180ad548dSVincenzo Maffione 132280ad548dSVincenzo Maffione if (rate_limit && tosend <= 0) { 132380ad548dSVincenzo Maffione tosend = targ->g->burst; 132480ad548dSVincenzo Maffione nexttime = timespec_add(nexttime, targ->g->tx_period); 132580ad548dSVincenzo Maffione wait_time(nexttime); 132680ad548dSVincenzo Maffione } 132780ad548dSVincenzo Maffione 132880ad548dSVincenzo Maffione limit = rate_limit ? tosend : targ->g->burst; 132980ad548dSVincenzo Maffione if (n > 0 && n - sent < limit) 133080ad548dSVincenzo Maffione limit = n - sent; 133180ad548dSVincenzo Maffione for (m = 0; (unsigned)m < limit; m++) { 1332f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 133317885a7bSLuigi Rizzo slot->len = size; 1334f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1335f8e4e36aSLuigi Rizzo 133617885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 1337f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 133880ad548dSVincenzo Maffione break; 1339f8e4e36aSLuigi Rizzo } else { 13404bf50f18SLuigi Rizzo struct tstamp *tp; 1341f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 1342f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 1343f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 13444bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13454bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 13464bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 1347f8e4e36aSLuigi Rizzo sent++; 134817885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 1349f8e4e36aSLuigi Rizzo } 1350f8e4e36aSLuigi Rizzo } 135180ad548dSVincenzo Maffione if (m > 0) 135280ad548dSVincenzo Maffione event++; 135380ad548dSVincenzo Maffione targ->ctr.pkts = sent; 135480ad548dSVincenzo Maffione targ->ctr.bytes = sent*size; 135580ad548dSVincenzo Maffione targ->ctr.events = event; 135680ad548dSVincenzo Maffione if (rate_limit) 135780ad548dSVincenzo Maffione tosend -= m; 135880ad548dSVincenzo Maffione #ifdef BUSYWAIT 135980ad548dSVincenzo Maffione rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); 136080ad548dSVincenzo Maffione if (rv < 0) { 136180ad548dSVincenzo Maffione D("TXSYNC error on queue %d: %s", targ->me, 136217885a7bSLuigi Rizzo strerror(errno)); 136380ad548dSVincenzo Maffione } 136480ad548dSVincenzo Maffione again: 136580ad548dSVincenzo Maffione ioctl(pfd.fd, NIOCRXSYNC, NULL); 136680ad548dSVincenzo Maffione #else 136780ad548dSVincenzo Maffione /* should use a parameter to decide how often to send */ 136880ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 3000)) <= 0) { 136980ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 137080ad548dSVincenzo Maffione (rv ? strerror(errno) : "timeout")); 1371f8e4e36aSLuigi Rizzo continue; 1372f8e4e36aSLuigi Rizzo } 137380ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1374f8e4e36aSLuigi Rizzo /* see what we got back */ 137580ad548dSVincenzo Maffione rx = 0; 137680ad548dSVincenzo Maffione for (i = targ->nmd->first_rx_ring; 137780ad548dSVincenzo Maffione i <= targ->nmd->last_rx_ring; i++) { 1378f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 137917885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 1380f8e4e36aSLuigi Rizzo uint32_t seq; 13814bf50f18SLuigi Rizzo struct tstamp *tp; 138237e3a6d3SLuigi Rizzo int pos; 138337e3a6d3SLuigi Rizzo 1384f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 1385f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 1386f8e4e36aSLuigi Rizzo 1387f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 1388f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 13894bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 13904bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 13914bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 1392f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 1393f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 1394f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1395f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1396f8e4e36aSLuigi Rizzo ts.tv_sec--; 1397f8e4e36aSLuigi Rizzo } 139880ad548dSVincenzo Maffione if (0) D("seq %d/%llu delta %d.%09d", seq, 139980ad548dSVincenzo Maffione (unsigned long long)sent, 1400f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 140137e3a6d3SLuigi Rizzo t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; 140237e3a6d3SLuigi Rizzo if (t_cur < t_min) 140337e3a6d3SLuigi Rizzo t_min = t_cur; 1404f8e4e36aSLuigi Rizzo count ++; 140537e3a6d3SLuigi Rizzo av += t_cur; 140637e3a6d3SLuigi Rizzo pos = msb64(t_cur); 140737e3a6d3SLuigi Rizzo buckets[pos]++; 140837e3a6d3SLuigi Rizzo /* now store it in a bucket */ 140917885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 1410f8e4e36aSLuigi Rizzo rx++; 1411f8e4e36aSLuigi Rizzo } 1412f8e4e36aSLuigi Rizzo } 1413f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1414f8e4e36aSLuigi Rizzo //usleep(100000); 1415f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 1416f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 1417f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 1418f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 1419f8e4e36aSLuigi Rizzo ts.tv_sec--; 1420f8e4e36aSLuigi Rizzo } 1421f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 142237e3a6d3SLuigi Rizzo D("count %d RTT: min %d av %d ns", 142337e3a6d3SLuigi Rizzo (int)count, (int)t_min, (int)(av/count)); 142480ad548dSVincenzo Maffione int k, j, kmin, off; 142537e3a6d3SLuigi Rizzo char buf[512]; 142637e3a6d3SLuigi Rizzo 142737e3a6d3SLuigi Rizzo for (kmin = 0; kmin < 64; kmin ++) 142837e3a6d3SLuigi Rizzo if (buckets[kmin]) 142937e3a6d3SLuigi Rizzo break; 143037e3a6d3SLuigi Rizzo for (k = 63; k >= kmin; k--) 143137e3a6d3SLuigi Rizzo if (buckets[k]) 143237e3a6d3SLuigi Rizzo break; 143337e3a6d3SLuigi Rizzo buf[0] = '\0'; 143480ad548dSVincenzo Maffione off = 0; 143580ad548dSVincenzo Maffione for (j = kmin; j <= k; j++) { 143680ad548dSVincenzo Maffione off += sprintf(buf + off, " %5d", (int)buckets[j]); 143780ad548dSVincenzo Maffione } 143837e3a6d3SLuigi Rizzo D("k: %d .. %d\n\t%s", 1<<kmin, 1<<k, buf); 143937e3a6d3SLuigi Rizzo bzero(&buckets, sizeof(buckets)); 1440f8e4e36aSLuigi Rizzo count = 0; 144180ad548dSVincenzo Maffione g_av += av; 1442f8e4e36aSLuigi Rizzo av = 0; 144380ad548dSVincenzo Maffione if (t_min < g_min) 144480ad548dSVincenzo Maffione g_min = t_min; 144537e3a6d3SLuigi Rizzo t_min = ~0; 1446f8e4e36aSLuigi Rizzo last_print = now; 1447f8e4e36aSLuigi Rizzo } 144880ad548dSVincenzo Maffione #ifdef BUSYWAIT 144980ad548dSVincenzo Maffione if (rx < m && ts.tv_sec <= 3 && !targ->cancel) 145080ad548dSVincenzo Maffione goto again; 145180ad548dSVincenzo Maffione #endif /* BUSYWAIT */ 1452f8e4e36aSLuigi Rizzo } 145337e3a6d3SLuigi Rizzo 145480ad548dSVincenzo Maffione if (sent > 0) { 145580ad548dSVincenzo Maffione D("RTT over %llu packets: min %d av %d ns", 145680ad548dSVincenzo Maffione (long long unsigned)sent, (int)g_min, 145780ad548dSVincenzo Maffione (int)((double)g_av/sent)); 145880ad548dSVincenzo Maffione } 145980ad548dSVincenzo Maffione targ->completed = 1; 146080ad548dSVincenzo Maffione 146137e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 146237e3a6d3SLuigi Rizzo targ->used = 0; 146337e3a6d3SLuigi Rizzo 1464f8e4e36aSLuigi Rizzo return NULL; 1465f8e4e36aSLuigi Rizzo } 1466f8e4e36aSLuigi Rizzo 1467f8e4e36aSLuigi Rizzo 1468f8e4e36aSLuigi Rizzo /* 1469f8e4e36aSLuigi Rizzo * reply to ping requests 1470f8e4e36aSLuigi Rizzo */ 1471f8e4e36aSLuigi Rizzo static void * 147280ad548dSVincenzo Maffione pong_body(void *data) 1473f8e4e36aSLuigi Rizzo { 1474f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1475f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 1476f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 1477f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 147837e3a6d3SLuigi Rizzo int i, rx = 0; 147937e3a6d3SLuigi Rizzo uint64_t sent = 0, n = targ->g->npackets; 1480f8e4e36aSLuigi Rizzo 1481f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 1482f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 1483f8e4e36aSLuigi Rizzo return NULL; 1484f8e4e36aSLuigi Rizzo } 148580ad548dSVincenzo Maffione if (n > 0) 148680ad548dSVincenzo Maffione D("understood ponger %llu but don't know how to do it", 148780ad548dSVincenzo Maffione (unsigned long long)n); 148837e3a6d3SLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 1489f8e4e36aSLuigi Rizzo uint32_t txcur, txavail; 1490f8e4e36aSLuigi Rizzo //#define BUSYWAIT 1491f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1492f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 1493f8e4e36aSLuigi Rizzo #else 149480ad548dSVincenzo Maffione int rv; 149580ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 1000)) <= 0) { 149680ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 149780ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1498f8e4e36aSLuigi Rizzo continue; 1499f8e4e36aSLuigi Rizzo } 1500f8e4e36aSLuigi Rizzo #endif 150180ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 1502f8e4e36aSLuigi Rizzo txcur = txring->cur; 150317885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 1504f8e4e36aSLuigi Rizzo /* see what we got back */ 1505f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 1506f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 150717885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 1508f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 1509f8e4e36aSLuigi Rizzo uint32_t cur = rxring->cur; 1510f8e4e36aSLuigi Rizzo struct netmap_slot *slot = &rxring->slot[cur]; 1511f8e4e36aSLuigi Rizzo char *src, *dst; 1512f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 1513f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 151417885a7bSLuigi Rizzo rxring->head = rxring->cur = nm_ring_next(rxring, cur); 1515f8e4e36aSLuigi Rizzo rx++; 1516f8e4e36aSLuigi Rizzo if (txavail == 0) 1517f8e4e36aSLuigi Rizzo continue; 1518f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 1519f8e4e36aSLuigi Rizzo txring->slot[txcur].buf_idx); 1520f8e4e36aSLuigi Rizzo /* copy... */ 1521f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 1522f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 1523f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 152480ad548dSVincenzo Maffione /* swap source and destination MAC */ 1525f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 1526f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 1527f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 1528f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 1529f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 1530f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 1531f8e4e36aSLuigi Rizzo txring->slot[txcur].len = slot->len; 153217885a7bSLuigi Rizzo txcur = nm_ring_next(txring, txcur); 1533f8e4e36aSLuigi Rizzo txavail--; 1534f8e4e36aSLuigi Rizzo sent++; 1535f8e4e36aSLuigi Rizzo } 1536f8e4e36aSLuigi Rizzo } 153717885a7bSLuigi Rizzo txring->head = txring->cur = txcur; 153837e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 1539f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 1540f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 1541f8e4e36aSLuigi Rizzo #endif 1542f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 1543f8e4e36aSLuigi Rizzo } 154437e3a6d3SLuigi Rizzo 154580ad548dSVincenzo Maffione targ->completed = 1; 154680ad548dSVincenzo Maffione 154737e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 154837e3a6d3SLuigi Rizzo targ->used = 0; 154937e3a6d3SLuigi Rizzo 1550f8e4e36aSLuigi Rizzo return NULL; 1551f8e4e36aSLuigi Rizzo } 1552f8e4e36aSLuigi Rizzo 1553f8e4e36aSLuigi Rizzo 1554f8e4e36aSLuigi Rizzo static void * 1555f8e4e36aSLuigi Rizzo sender_body(void *data) 1556f8e4e36aSLuigi Rizzo { 1557f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1558f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 15594bf50f18SLuigi Rizzo struct netmap_if *nifp; 156037e3a6d3SLuigi Rizzo struct netmap_ring *txring = NULL; 156137e3a6d3SLuigi Rizzo int i; 156237e3a6d3SLuigi Rizzo uint64_t n = targ->g->npackets / targ->g->nthreads; 156337e3a6d3SLuigi Rizzo uint64_t sent = 0; 156437e3a6d3SLuigi Rizzo uint64_t event = 0; 1565f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 156617885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 15671cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 156817885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 156917885a7bSLuigi Rizzo void *frame; 157017885a7bSLuigi Rizzo int size; 157117885a7bSLuigi Rizzo 1572f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 157380ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 157417885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1575f284c737SGeorge V. Neville-Neil } else { 1576f284c737SGeorge V. Neville-Neil frame = targ->frame; 1577f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1578f284c737SGeorge V. Neville-Neil } 1579b303f675SLuigi Rizzo 15804bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 158168b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 158268b8534bSLuigi Rizzo goto quit; 158368b8534bSLuigi Rizzo 158468b8534bSLuigi Rizzo /* main loop.*/ 15851cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 15861cb4c501SLuigi Rizzo if (rate_limit) { 158717885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 15881cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 158917885a7bSLuigi Rizzo wait_time(targ->tic); 15901cb4c501SLuigi Rizzo nexttime = targ->tic; 15911cb4c501SLuigi Rizzo } 1592f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1593f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1594f8e4e36aSLuigi Rizzo 1595f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 159617885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1597f8e4e36aSLuigi Rizzo sent++; 159880ad548dSVincenzo Maffione update_addresses(pkt, targ); 1599f8e4e36aSLuigi Rizzo if (i > 10000) { 160037e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 160137e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 160237e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1603f8e4e36aSLuigi Rizzo i = 0; 1604f8e4e36aSLuigi Rizzo } 1605f8e4e36aSLuigi Rizzo } 1606f2637526SLuigi Rizzo #ifndef NO_PCAP 1607f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1608f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1609f2637526SLuigi Rizzo 1610f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1611f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1612f2637526SLuigi Rizzo sent++; 161380ad548dSVincenzo Maffione update_addresses(pkt, targ); 1614f2637526SLuigi Rizzo if (i > 10000) { 161537e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 161637e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 161737e3a6d3SLuigi Rizzo targ->ctr.events = sent; 1618f2637526SLuigi Rizzo i = 0; 1619f2637526SLuigi Rizzo } 1620f2637526SLuigi Rizzo } 1621f2637526SLuigi Rizzo #endif /* NO_PCAP */ 162268b8534bSLuigi Rizzo } else { 16231cb4c501SLuigi Rizzo int tosend = 0; 16249e53f3bdSVincenzo Maffione u_int bufsz, frag_size = targ->g->frag_size; 1625ce3ee1e7SLuigi Rizzo 16264bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 162780ad548dSVincenzo Maffione txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); 162880ad548dSVincenzo Maffione bufsz = txring->nr_buf_size; 16299e53f3bdSVincenzo Maffione if (bufsz < frag_size) 16309e53f3bdSVincenzo Maffione frag_size = bufsz; 163180ad548dSVincenzo Maffione targ->frag_size = targ->g->pkt_size / targ->frags; 16329e53f3bdSVincenzo Maffione if (targ->frag_size > frag_size) { 16339e53f3bdSVincenzo Maffione targ->frags = targ->g->pkt_size / frag_size; 16349e53f3bdSVincenzo Maffione targ->frag_size = frag_size; 16359e53f3bdSVincenzo Maffione if (targ->g->pkt_size % frag_size != 0) 163680ad548dSVincenzo Maffione targ->frags++; 163780ad548dSVincenzo Maffione } 163880ad548dSVincenzo Maffione D("frags %u frag_size %u", targ->frags, targ->frag_size); 1639f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 164080ad548dSVincenzo Maffione int rv; 164168b8534bSLuigi Rizzo 16421cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 16431cb4c501SLuigi Rizzo tosend = targ->g->burst; 164417885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 164517885a7bSLuigi Rizzo wait_time(nexttime); 16461cb4c501SLuigi Rizzo } 16471cb4c501SLuigi Rizzo 164868b8534bSLuigi Rizzo /* 164968b8534bSLuigi Rizzo * wait for available room in the send queue(s) 165068b8534bSLuigi Rizzo */ 165137e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 165280ad548dSVincenzo Maffione (void)rv; 165337e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 165437e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 165537e3a6d3SLuigi Rizzo strerror(errno)); 165637e3a6d3SLuigi Rizzo goto quit; 165737e3a6d3SLuigi Rizzo } 165837e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 165980ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 16603fe77e68SEd Maste if (targ->cancel) 16613fe77e68SEd Maste break; 166280ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 166380ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 1664f0ea3689SLuigi Rizzo // goto quit; 166517885a7bSLuigi Rizzo } 1666f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 166737e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 166837e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 166968b8534bSLuigi Rizzo goto quit; 167068b8534bSLuigi Rizzo } 167137e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 167268b8534bSLuigi Rizzo /* 167368b8534bSLuigi Rizzo * scan our queues and send on those with room 167468b8534bSLuigi Rizzo */ 1675f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1676f8e4e36aSLuigi Rizzo D("drop copy"); 167799fb123fSLuigi Rizzo options &= ~OPT_COPY; 1678f8e4e36aSLuigi Rizzo } 1679f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 168037e3a6d3SLuigi Rizzo int m; 168137e3a6d3SLuigi Rizzo uint64_t limit = rate_limit ? tosend : targ->g->burst; 168280ad548dSVincenzo Maffione 168380ad548dSVincenzo Maffione if (n > 0 && n == sent) 168480ad548dSVincenzo Maffione break; 168580ad548dSVincenzo Maffione 1686f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1687f8e4e36aSLuigi Rizzo limit = n - sent; 168868b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 168917885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 169068b8534bSLuigi Rizzo continue; 1691ce3ee1e7SLuigi Rizzo 169280ad548dSVincenzo Maffione if (targ->g->pkt_min_size > 0) { 169380ad548dSVincenzo Maffione size = nrand48(targ->seed) % 169480ad548dSVincenzo Maffione (targ->g->pkt_size - targ->g->pkt_min_size) + 169580ad548dSVincenzo Maffione targ->g->pkt_min_size; 169680ad548dSVincenzo Maffione } 169780ad548dSVincenzo Maffione m = send_packets(txring, pkt, frame, size, targ, 169880ad548dSVincenzo Maffione limit, options); 169980ad548dSVincenzo Maffione ND("limit %lu tail %d m %d", 170080ad548dSVincenzo Maffione limit, txring->tail, m); 170168b8534bSLuigi Rizzo sent += m; 170237e3a6d3SLuigi Rizzo if (m > 0) //XXX-ste: can m be 0? 170337e3a6d3SLuigi Rizzo event++; 170437e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 170580ad548dSVincenzo Maffione targ->ctr.bytes += m*size; 170637e3a6d3SLuigi Rizzo targ->ctr.events = event; 1707ce3ee1e7SLuigi Rizzo if (rate_limit) { 1708ce3ee1e7SLuigi Rizzo tosend -= m; 1709ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1710ce3ee1e7SLuigi Rizzo break; 1711ce3ee1e7SLuigi Rizzo } 171268b8534bSLuigi Rizzo } 171368b8534bSLuigi Rizzo } 171499fb123fSLuigi Rizzo /* flush any remaining packets */ 171580ad548dSVincenzo Maffione if (txring != NULL) { 17164bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 17174bf50f18SLuigi Rizzo txring->tail, txring->head, 171837e3a6d3SLuigi Rizzo (void *)pthread_self()); 1719f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 172080ad548dSVincenzo Maffione } 172168b8534bSLuigi Rizzo 172268b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1723f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 172468b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 172537e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(txring)) { 17264bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 17274bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1728f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 172968b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 173068b8534bSLuigi Rizzo } 173168b8534bSLuigi Rizzo } 1732f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 173368b8534bSLuigi Rizzo 17341cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 173568b8534bSLuigi Rizzo targ->completed = 1; 173637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 173737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent*size; 173837e3a6d3SLuigi Rizzo targ->ctr.events = event; 173968b8534bSLuigi Rizzo quit: 174068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 174168b8534bSLuigi Rizzo targ->used = 0; 174268b8534bSLuigi Rizzo 174368b8534bSLuigi Rizzo return (NULL); 174468b8534bSLuigi Rizzo } 174568b8534bSLuigi Rizzo 174668b8534bSLuigi Rizzo 1747f2637526SLuigi Rizzo #ifndef NO_PCAP 174868b8534bSLuigi Rizzo static void 1749f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1750f8e4e36aSLuigi Rizzo const u_char * bytes) 175168b8534bSLuigi Rizzo { 175237e3a6d3SLuigi Rizzo struct my_ctrs *ctr = (struct my_ctrs *)user; 1753f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 175437e3a6d3SLuigi Rizzo ctr->bytes += h->len; 175537e3a6d3SLuigi Rizzo ctr->pkts++; 175668b8534bSLuigi Rizzo } 1757f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 175868b8534bSLuigi Rizzo 175937e3a6d3SLuigi Rizzo 176068b8534bSLuigi Rizzo static int 176137e3a6d3SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) 176268b8534bSLuigi Rizzo { 176317885a7bSLuigi Rizzo u_int cur, rx, n; 176437e3a6d3SLuigi Rizzo uint64_t b = 0; 176580ad548dSVincenzo Maffione u_int complete = 0; 176637e3a6d3SLuigi Rizzo 176737e3a6d3SLuigi Rizzo if (bytes == NULL) 176837e3a6d3SLuigi Rizzo bytes = &b; 176968b8534bSLuigi Rizzo 177068b8534bSLuigi Rizzo cur = ring->cur; 177117885a7bSLuigi Rizzo n = nm_ring_space(ring); 177217885a7bSLuigi Rizzo if (n < limit) 177317885a7bSLuigi Rizzo limit = n; 177468b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 177568b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 177668b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 177768b8534bSLuigi Rizzo 177837e3a6d3SLuigi Rizzo *bytes += slot->len; 1779b303f675SLuigi Rizzo if (dump) 1780b303f675SLuigi Rizzo dump_payload(p, slot->len, ring, cur); 178180ad548dSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) 178280ad548dSVincenzo Maffione complete++; 178368b8534bSLuigi Rizzo 178417885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 178568b8534bSLuigi Rizzo } 178617885a7bSLuigi Rizzo ring->head = ring->cur = cur; 178768b8534bSLuigi Rizzo 178880ad548dSVincenzo Maffione return (complete); 178968b8534bSLuigi Rizzo } 179068b8534bSLuigi Rizzo 179168b8534bSLuigi Rizzo static void * 179268b8534bSLuigi Rizzo receiver_body(void *data) 179368b8534bSLuigi Rizzo { 179468b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1795f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 17964bf50f18SLuigi Rizzo struct netmap_if *nifp; 179768b8534bSLuigi Rizzo struct netmap_ring *rxring; 1798f8e4e36aSLuigi Rizzo int i; 179937e3a6d3SLuigi Rizzo struct my_ctrs cur; 180037e3a6d3SLuigi Rizzo 180180ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 180268b8534bSLuigi Rizzo 180368b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 180468b8534bSLuigi Rizzo goto quit; 180568b8534bSLuigi Rizzo 18064bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 18074bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 180868b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 18094bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1810f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1811f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 181268b8534bSLuigi Rizzo break; 181380ad548dSVincenzo Maffione if (i < 0) { 181480ad548dSVincenzo Maffione D("poll() error: %s", strerror(errno)); 181580ad548dSVincenzo Maffione goto quit; 181680ad548dSVincenzo Maffione } 181780ad548dSVincenzo Maffione if (pfd.revents & POLLERR) { 181880ad548dSVincenzo Maffione D("fd error"); 181980ad548dSVincenzo Maffione goto quit; 182080ad548dSVincenzo Maffione } 1821f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1822f0ea3689SLuigi Rizzo i, pfd.revents); 182368b8534bSLuigi Rizzo } 182468b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 18251cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1826f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1827f8e4e36aSLuigi Rizzo while (!targ->cancel) { 18284bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1829f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 183037e3a6d3SLuigi Rizzo i = read(targ->g->main_fd, buf, sizeof(buf)); 183137e3a6d3SLuigi Rizzo if (i > 0) { 183237e3a6d3SLuigi Rizzo targ->ctr.pkts++; 183337e3a6d3SLuigi Rizzo targ->ctr.bytes += i; 183437e3a6d3SLuigi Rizzo targ->ctr.events++; 183537e3a6d3SLuigi Rizzo } 1836f8e4e36aSLuigi Rizzo } 1837f2637526SLuigi Rizzo #ifndef NO_PCAP 1838f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1839f2637526SLuigi Rizzo while (!targ->cancel) { 1840f2637526SLuigi Rizzo /* XXX should we poll ? */ 18414bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 184237e3a6d3SLuigi Rizzo (u_char *)&targ->ctr); 184337e3a6d3SLuigi Rizzo targ->ctr.events++; 1844f2637526SLuigi Rizzo } 1845f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 184668b8534bSLuigi Rizzo } else { 1847b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 18484bf50f18SLuigi Rizzo 18494bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 18503fe77e68SEd Maste while (!targ->cancel) { 185168b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 185268b8534bSLuigi Rizzo before quitting. */ 185337e3a6d3SLuigi Rizzo #ifdef BUSYWAIT 185437e3a6d3SLuigi Rizzo if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 185537e3a6d3SLuigi Rizzo D("ioctl error on queue %d: %s", targ->me, 185637e3a6d3SLuigi Rizzo strerror(errno)); 185737e3a6d3SLuigi Rizzo goto quit; 185837e3a6d3SLuigi Rizzo } 185937e3a6d3SLuigi Rizzo #else /* !BUSYWAIT */ 186037e3a6d3SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 186137e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 186237e3a6d3SLuigi Rizzo targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 186337e3a6d3SLuigi Rizzo goto out; 186437e3a6d3SLuigi Rizzo } 186537e3a6d3SLuigi Rizzo 186637e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 186737e3a6d3SLuigi Rizzo D("poll err"); 186837e3a6d3SLuigi Rizzo goto quit; 186937e3a6d3SLuigi Rizzo } 187037e3a6d3SLuigi Rizzo #endif /* !BUSYWAIT */ 187137e3a6d3SLuigi Rizzo uint64_t cur_space = 0; 187237e3a6d3SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 187337e3a6d3SLuigi Rizzo int m; 187437e3a6d3SLuigi Rizzo 187537e3a6d3SLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 187637e3a6d3SLuigi Rizzo /* compute free space in the ring */ 187737e3a6d3SLuigi Rizzo m = rxring->head + rxring->num_slots - rxring->tail; 187837e3a6d3SLuigi Rizzo if (m >= (int) rxring->num_slots) 187937e3a6d3SLuigi Rizzo m -= rxring->num_slots; 188037e3a6d3SLuigi Rizzo cur_space += m; 188137e3a6d3SLuigi Rizzo if (nm_ring_empty(rxring)) 188237e3a6d3SLuigi Rizzo continue; 188337e3a6d3SLuigi Rizzo 188437e3a6d3SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); 188537e3a6d3SLuigi Rizzo cur.pkts += m; 188680ad548dSVincenzo Maffione if (m > 0) 188737e3a6d3SLuigi Rizzo cur.events++; 188837e3a6d3SLuigi Rizzo } 188937e3a6d3SLuigi Rizzo cur.min_space = targ->ctr.min_space; 189037e3a6d3SLuigi Rizzo if (cur_space < cur.min_space) 189137e3a6d3SLuigi Rizzo cur.min_space = cur_space; 189237e3a6d3SLuigi Rizzo targ->ctr = cur; 189337e3a6d3SLuigi Rizzo } 189437e3a6d3SLuigi Rizzo } 189537e3a6d3SLuigi Rizzo 189637e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 189737e3a6d3SLuigi Rizzo 189837e3a6d3SLuigi Rizzo #if !defined(BUSYWAIT) 189937e3a6d3SLuigi Rizzo out: 190037e3a6d3SLuigi Rizzo #endif 190137e3a6d3SLuigi Rizzo targ->completed = 1; 190237e3a6d3SLuigi Rizzo targ->ctr = cur; 190337e3a6d3SLuigi Rizzo 190437e3a6d3SLuigi Rizzo quit: 190537e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 190637e3a6d3SLuigi Rizzo targ->used = 0; 190737e3a6d3SLuigi Rizzo 190837e3a6d3SLuigi Rizzo return (NULL); 190937e3a6d3SLuigi Rizzo } 191037e3a6d3SLuigi Rizzo 191137e3a6d3SLuigi Rizzo static void * 191237e3a6d3SLuigi Rizzo txseq_body(void *data) 191337e3a6d3SLuigi Rizzo { 191437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 191537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 191637e3a6d3SLuigi Rizzo struct netmap_ring *ring; 191737e3a6d3SLuigi Rizzo int64_t sent = 0; 191837e3a6d3SLuigi Rizzo uint64_t event = 0; 191937e3a6d3SLuigi Rizzo int options = targ->g->options | OPT_COPY; 192037e3a6d3SLuigi Rizzo struct timespec nexttime = {0, 0}; 192137e3a6d3SLuigi Rizzo int rate_limit = targ->g->tx_rate; 192237e3a6d3SLuigi Rizzo struct pkt *pkt = &targ->pkt; 192337e3a6d3SLuigi Rizzo int frags = targ->g->frags; 192437e3a6d3SLuigi Rizzo uint32_t sequence = 0; 192537e3a6d3SLuigi Rizzo int budget = 0; 192637e3a6d3SLuigi Rizzo void *frame; 192737e3a6d3SLuigi Rizzo int size; 192837e3a6d3SLuigi Rizzo 192937e3a6d3SLuigi Rizzo if (targ->g->nthreads > 1) { 193037e3a6d3SLuigi Rizzo D("can only txseq ping with 1 thread"); 193137e3a6d3SLuigi Rizzo return NULL; 193237e3a6d3SLuigi Rizzo } 193337e3a6d3SLuigi Rizzo 193437e3a6d3SLuigi Rizzo if (targ->g->npackets > 0) { 193537e3a6d3SLuigi Rizzo D("Ignoring -n argument"); 193637e3a6d3SLuigi Rizzo } 193737e3a6d3SLuigi Rizzo 193880ad548dSVincenzo Maffione frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header; 193937e3a6d3SLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 194037e3a6d3SLuigi Rizzo 194137e3a6d3SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 194237e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 194337e3a6d3SLuigi Rizzo goto quit; 194437e3a6d3SLuigi Rizzo 194537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 194637e3a6d3SLuigi Rizzo if (rate_limit) { 194737e3a6d3SLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 194837e3a6d3SLuigi Rizzo targ->tic.tv_nsec = 0; 194937e3a6d3SLuigi Rizzo wait_time(targ->tic); 195037e3a6d3SLuigi Rizzo nexttime = targ->tic; 195137e3a6d3SLuigi Rizzo } 195237e3a6d3SLuigi Rizzo 195337e3a6d3SLuigi Rizzo /* Only use the first queue. */ 195437e3a6d3SLuigi Rizzo ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); 195537e3a6d3SLuigi Rizzo 195637e3a6d3SLuigi Rizzo while (!targ->cancel) { 195737e3a6d3SLuigi Rizzo int64_t limit; 195837e3a6d3SLuigi Rizzo unsigned int space; 195937e3a6d3SLuigi Rizzo unsigned int head; 196037e3a6d3SLuigi Rizzo int fcnt; 196180ad548dSVincenzo Maffione uint16_t sum = 0; 196280ad548dSVincenzo Maffione int rv; 196337e3a6d3SLuigi Rizzo 196437e3a6d3SLuigi Rizzo if (!rate_limit) { 196537e3a6d3SLuigi Rizzo budget = targ->g->burst; 196637e3a6d3SLuigi Rizzo 196737e3a6d3SLuigi Rizzo } else if (budget <= 0) { 196837e3a6d3SLuigi Rizzo budget = targ->g->burst; 196937e3a6d3SLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 197037e3a6d3SLuigi Rizzo wait_time(nexttime); 197137e3a6d3SLuigi Rizzo } 197237e3a6d3SLuigi Rizzo 197337e3a6d3SLuigi Rizzo /* wait for available room in the send queue */ 197480ad548dSVincenzo Maffione #ifdef BUSYWAIT 197580ad548dSVincenzo Maffione (void)rv; 197680ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { 197780ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 197880ad548dSVincenzo Maffione strerror(errno)); 197980ad548dSVincenzo Maffione goto quit; 198080ad548dSVincenzo Maffione } 198180ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 198280ad548dSVincenzo Maffione if ( (rv = poll(&pfd, 1, 2000)) <= 0) { 198337e3a6d3SLuigi Rizzo if (targ->cancel) 198437e3a6d3SLuigi Rizzo break; 198580ad548dSVincenzo Maffione D("poll error on queue %d: %s", targ->me, 198680ad548dSVincenzo Maffione rv ? strerror(errno) : "timeout"); 198780ad548dSVincenzo Maffione // goto quit; 198837e3a6d3SLuigi Rizzo } 198937e3a6d3SLuigi Rizzo if (pfd.revents & POLLERR) { 199037e3a6d3SLuigi Rizzo D("poll error on %d ring %d-%d", pfd.fd, 199137e3a6d3SLuigi Rizzo targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); 199237e3a6d3SLuigi Rizzo goto quit; 199337e3a6d3SLuigi Rizzo } 199480ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 199537e3a6d3SLuigi Rizzo 199637e3a6d3SLuigi Rizzo /* If no room poll() again. */ 199737e3a6d3SLuigi Rizzo space = nm_ring_space(ring); 199837e3a6d3SLuigi Rizzo if (!space) { 199937e3a6d3SLuigi Rizzo continue; 200037e3a6d3SLuigi Rizzo } 200137e3a6d3SLuigi Rizzo 200237e3a6d3SLuigi Rizzo limit = budget; 200337e3a6d3SLuigi Rizzo 200437e3a6d3SLuigi Rizzo if (space < limit) { 200537e3a6d3SLuigi Rizzo limit = space; 200637e3a6d3SLuigi Rizzo } 200737e3a6d3SLuigi Rizzo 200837e3a6d3SLuigi Rizzo /* Cut off ``limit`` to make sure is multiple of ``frags``. */ 200937e3a6d3SLuigi Rizzo if (frags > 1) { 201037e3a6d3SLuigi Rizzo limit = (limit / frags) * frags; 201137e3a6d3SLuigi Rizzo } 201237e3a6d3SLuigi Rizzo 201337e3a6d3SLuigi Rizzo limit = sent + limit; /* Convert to absolute. */ 201437e3a6d3SLuigi Rizzo 201537e3a6d3SLuigi Rizzo for (fcnt = frags, head = ring->head; 201637e3a6d3SLuigi Rizzo sent < limit; sent++, sequence++) { 201737e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 201837e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 201980ad548dSVincenzo Maffione uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; 202080ad548dSVincenzo Maffione 202180ad548dSVincenzo Maffione memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); 202237e3a6d3SLuigi Rizzo 202337e3a6d3SLuigi Rizzo slot->flags = 0; 202480ad548dSVincenzo Maffione t = *w; 202580ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[0] = sequence >> 24; 202680ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; 202780ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 202880ad548dSVincenzo Maffione t = *++w; 202980ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; 203080ad548dSVincenzo Maffione PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; 203180ad548dSVincenzo Maffione sum = ~cksum_add(~sum, cksum_add(~t, *w)); 203280ad548dSVincenzo Maffione memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); 203337e3a6d3SLuigi Rizzo nm_pkt_copy(frame, p, size); 203437e3a6d3SLuigi Rizzo if (fcnt == frags) { 203580ad548dSVincenzo Maffione update_addresses(pkt, targ); 203637e3a6d3SLuigi Rizzo } 203737e3a6d3SLuigi Rizzo 203837e3a6d3SLuigi Rizzo if (options & OPT_DUMP) { 203937e3a6d3SLuigi Rizzo dump_payload(p, size, ring, head); 204037e3a6d3SLuigi Rizzo } 204137e3a6d3SLuigi Rizzo 204237e3a6d3SLuigi Rizzo slot->len = size; 204337e3a6d3SLuigi Rizzo 204437e3a6d3SLuigi Rizzo if (--fcnt > 0) { 204537e3a6d3SLuigi Rizzo slot->flags |= NS_MOREFRAG; 204637e3a6d3SLuigi Rizzo } else { 204737e3a6d3SLuigi Rizzo fcnt = frags; 204837e3a6d3SLuigi Rizzo } 204937e3a6d3SLuigi Rizzo 205037e3a6d3SLuigi Rizzo if (sent == limit - 1) { 205137e3a6d3SLuigi Rizzo /* Make sure we don't push an incomplete 205237e3a6d3SLuigi Rizzo * packet. */ 205337e3a6d3SLuigi Rizzo assert(!(slot->flags & NS_MOREFRAG)); 205437e3a6d3SLuigi Rizzo slot->flags |= NS_REPORT; 205537e3a6d3SLuigi Rizzo } 205637e3a6d3SLuigi Rizzo 205737e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 205837e3a6d3SLuigi Rizzo if (rate_limit) { 205937e3a6d3SLuigi Rizzo budget--; 206037e3a6d3SLuigi Rizzo } 206137e3a6d3SLuigi Rizzo } 206237e3a6d3SLuigi Rizzo 206337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 206437e3a6d3SLuigi Rizzo 206537e3a6d3SLuigi Rizzo event ++; 206637e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 206737e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 206837e3a6d3SLuigi Rizzo targ->ctr.events = event; 206937e3a6d3SLuigi Rizzo } 207037e3a6d3SLuigi Rizzo 207137e3a6d3SLuigi Rizzo /* flush any remaining packets */ 207237e3a6d3SLuigi Rizzo D("flush tail %d head %d on thread %p", 207337e3a6d3SLuigi Rizzo ring->tail, ring->head, 207437e3a6d3SLuigi Rizzo (void *)pthread_self()); 207537e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 207637e3a6d3SLuigi Rizzo 207737e3a6d3SLuigi Rizzo /* final part: wait the TX queues to become empty. */ 207837e3a6d3SLuigi Rizzo while (!targ->cancel && nm_tx_pending(ring)) { 207937e3a6d3SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 208037e3a6d3SLuigi Rizzo ring->tail, ring->head, targ->nmd->first_tx_ring); 208137e3a6d3SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 208237e3a6d3SLuigi Rizzo usleep(1); /* wait 1 tick */ 208337e3a6d3SLuigi Rizzo } 208437e3a6d3SLuigi Rizzo 208537e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 208637e3a6d3SLuigi Rizzo targ->completed = 1; 208737e3a6d3SLuigi Rizzo targ->ctr.pkts = sent; 208837e3a6d3SLuigi Rizzo targ->ctr.bytes = sent * size; 208937e3a6d3SLuigi Rizzo targ->ctr.events = event; 209037e3a6d3SLuigi Rizzo quit: 209137e3a6d3SLuigi Rizzo /* reset the ``used`` flag. */ 209237e3a6d3SLuigi Rizzo targ->used = 0; 209337e3a6d3SLuigi Rizzo 209437e3a6d3SLuigi Rizzo return (NULL); 209537e3a6d3SLuigi Rizzo } 209637e3a6d3SLuigi Rizzo 209737e3a6d3SLuigi Rizzo 209837e3a6d3SLuigi Rizzo static char * 209937e3a6d3SLuigi Rizzo multi_slot_to_string(struct netmap_ring *ring, unsigned int head, 210037e3a6d3SLuigi Rizzo unsigned int nfrags, char *strbuf, size_t strbuflen) 210137e3a6d3SLuigi Rizzo { 210237e3a6d3SLuigi Rizzo unsigned int f; 210337e3a6d3SLuigi Rizzo char *ret = strbuf; 210437e3a6d3SLuigi Rizzo 210537e3a6d3SLuigi Rizzo for (f = 0; f < nfrags; f++) { 210637e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 210737e3a6d3SLuigi Rizzo int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, 210837e3a6d3SLuigi Rizzo slot->flags); 210937e3a6d3SLuigi Rizzo if (m >= (int)strbuflen) { 211037e3a6d3SLuigi Rizzo break; 211137e3a6d3SLuigi Rizzo } 211237e3a6d3SLuigi Rizzo strbuf += m; 211337e3a6d3SLuigi Rizzo strbuflen -= m; 211437e3a6d3SLuigi Rizzo 211537e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 211637e3a6d3SLuigi Rizzo } 211737e3a6d3SLuigi Rizzo 211837e3a6d3SLuigi Rizzo return ret; 211937e3a6d3SLuigi Rizzo } 212037e3a6d3SLuigi Rizzo 212137e3a6d3SLuigi Rizzo static void * 212237e3a6d3SLuigi Rizzo rxseq_body(void *data) 212337e3a6d3SLuigi Rizzo { 212437e3a6d3SLuigi Rizzo struct targ *targ = (struct targ *) data; 212537e3a6d3SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 212637e3a6d3SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 212737e3a6d3SLuigi Rizzo struct netmap_ring *ring; 212837e3a6d3SLuigi Rizzo unsigned int frags_exp = 1; 212937e3a6d3SLuigi Rizzo struct my_ctrs cur; 213037e3a6d3SLuigi Rizzo unsigned int frags = 0; 213137e3a6d3SLuigi Rizzo int first_packet = 1; 213237e3a6d3SLuigi Rizzo int first_slot = 1; 213380ad548dSVincenzo Maffione int i, j, af, nrings; 213480ad548dSVincenzo Maffione uint32_t seq, *seq_exp = NULL; 213537e3a6d3SLuigi Rizzo 213680ad548dSVincenzo Maffione memset(&cur, 0, sizeof(cur)); 213737e3a6d3SLuigi Rizzo 213837e3a6d3SLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 213937e3a6d3SLuigi Rizzo goto quit; 214037e3a6d3SLuigi Rizzo 214180ad548dSVincenzo Maffione nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1; 214280ad548dSVincenzo Maffione seq_exp = calloc(nrings, sizeof(uint32_t)); 214380ad548dSVincenzo Maffione if (seq_exp == NULL) { 214480ad548dSVincenzo Maffione D("failed to allocate seq array"); 214580ad548dSVincenzo Maffione goto quit; 214680ad548dSVincenzo Maffione } 214780ad548dSVincenzo Maffione 214837e3a6d3SLuigi Rizzo D("reading from %s fd %d main_fd %d", 214937e3a6d3SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 215037e3a6d3SLuigi Rizzo /* unbounded wait for the first packet. */ 215137e3a6d3SLuigi Rizzo for (;!targ->cancel;) { 215237e3a6d3SLuigi Rizzo i = poll(&pfd, 1, 1000); 215337e3a6d3SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 215437e3a6d3SLuigi Rizzo break; 215537e3a6d3SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 215637e3a6d3SLuigi Rizzo i, pfd.revents); 215737e3a6d3SLuigi Rizzo } 215837e3a6d3SLuigi Rizzo 215937e3a6d3SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 216037e3a6d3SLuigi Rizzo 216137e3a6d3SLuigi Rizzo 216237e3a6d3SLuigi Rizzo while (!targ->cancel) { 216337e3a6d3SLuigi Rizzo unsigned int head; 216437e3a6d3SLuigi Rizzo int limit; 216537e3a6d3SLuigi Rizzo 216680ad548dSVincenzo Maffione #ifdef BUSYWAIT 216780ad548dSVincenzo Maffione if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { 216880ad548dSVincenzo Maffione D("ioctl error on queue %d: %s", targ->me, 216980ad548dSVincenzo Maffione strerror(errno)); 217080ad548dSVincenzo Maffione goto quit; 217180ad548dSVincenzo Maffione } 217280ad548dSVincenzo Maffione #else /* !BUSYWAIT */ 2173f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 21741cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 21758ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 2176f0ea3689SLuigi Rizzo goto out; 217768b8534bSLuigi Rizzo } 217868b8534bSLuigi Rizzo 2179f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 218017885a7bSLuigi Rizzo D("poll err"); 218117885a7bSLuigi Rizzo goto quit; 218217885a7bSLuigi Rizzo } 218380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 218417885a7bSLuigi Rizzo 218580ad548dSVincenzo Maffione for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) { 218680ad548dSVincenzo Maffione ring = NETMAP_RXRING(targ->nmd->nifp, j); 218737e3a6d3SLuigi Rizzo if (nm_ring_empty(ring)) 218868b8534bSLuigi Rizzo continue; 218968b8534bSLuigi Rizzo 219037e3a6d3SLuigi Rizzo limit = nm_ring_space(ring); 219137e3a6d3SLuigi Rizzo if (limit > targ->g->burst) 219237e3a6d3SLuigi Rizzo limit = targ->g->burst; 219337e3a6d3SLuigi Rizzo 219437e3a6d3SLuigi Rizzo #if 0 219537e3a6d3SLuigi Rizzo /* Enable this if 219637e3a6d3SLuigi Rizzo * 1) we remove the early-return optimization from 219737e3a6d3SLuigi Rizzo * the netmap poll implementation, or 219837e3a6d3SLuigi Rizzo * 2) pipes get NS_MOREFRAG support. 219937e3a6d3SLuigi Rizzo * With the current netmap implementation, an experiment like 220037e3a6d3SLuigi Rizzo * pkt-gen -i vale:1{1 -f txseq -F 9 220137e3a6d3SLuigi Rizzo * pkt-gen -i vale:1}1 -f rxseq 220237e3a6d3SLuigi Rizzo * would get stuck as soon as we find nm_ring_space(ring) < 9, 220337e3a6d3SLuigi Rizzo * since here limit is rounded to 0 and 220437e3a6d3SLuigi Rizzo * pipe rxsync is not called anymore by the poll() of this loop. 220537e3a6d3SLuigi Rizzo */ 220637e3a6d3SLuigi Rizzo if (frags_exp > 1) { 220737e3a6d3SLuigi Rizzo int o = limit; 220837e3a6d3SLuigi Rizzo /* Cut off to the closest smaller multiple. */ 220937e3a6d3SLuigi Rizzo limit = (limit / frags_exp) * frags_exp; 221037e3a6d3SLuigi Rizzo RD(2, "LIMIT %d --> %d", o, limit); 221168b8534bSLuigi Rizzo } 221237e3a6d3SLuigi Rizzo #endif 221337e3a6d3SLuigi Rizzo 221437e3a6d3SLuigi Rizzo for (head = ring->head, i = 0; i < limit; i++) { 221537e3a6d3SLuigi Rizzo struct netmap_slot *slot = &ring->slot[head]; 221637e3a6d3SLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 221737e3a6d3SLuigi Rizzo int len = slot->len; 221837e3a6d3SLuigi Rizzo struct pkt *pkt; 221937e3a6d3SLuigi Rizzo 222037e3a6d3SLuigi Rizzo if (dump) { 222137e3a6d3SLuigi Rizzo dump_payload(p, slot->len, ring, head); 222268b8534bSLuigi Rizzo } 222337e3a6d3SLuigi Rizzo 222437e3a6d3SLuigi Rizzo frags++; 222537e3a6d3SLuigi Rizzo if (!(slot->flags & NS_MOREFRAG)) { 222637e3a6d3SLuigi Rizzo if (first_packet) { 222737e3a6d3SLuigi Rizzo first_packet = 0; 222837e3a6d3SLuigi Rizzo } else if (frags != frags_exp) { 222937e3a6d3SLuigi Rizzo char prbuf[512]; 223037e3a6d3SLuigi Rizzo RD(1, "Received packets with %u frags, " 223137e3a6d3SLuigi Rizzo "expected %u, '%s'", frags, frags_exp, 223280ad548dSVincenzo Maffione multi_slot_to_string(ring, head-frags+1, 223380ad548dSVincenzo Maffione frags, 223437e3a6d3SLuigi Rizzo prbuf, sizeof(prbuf))); 223537e3a6d3SLuigi Rizzo } 223637e3a6d3SLuigi Rizzo first_packet = 0; 223737e3a6d3SLuigi Rizzo frags_exp = frags; 223837e3a6d3SLuigi Rizzo frags = 0; 223937e3a6d3SLuigi Rizzo } 224037e3a6d3SLuigi Rizzo 224137e3a6d3SLuigi Rizzo p -= sizeof(pkt->vh) - targ->g->virt_header; 224237e3a6d3SLuigi Rizzo len += sizeof(pkt->vh) - targ->g->virt_header; 224337e3a6d3SLuigi Rizzo pkt = (struct pkt *)p; 224480ad548dSVincenzo Maffione if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP) 224580ad548dSVincenzo Maffione af = AF_INET; 224680ad548dSVincenzo Maffione else 224780ad548dSVincenzo Maffione af = AF_INET6; 224837e3a6d3SLuigi Rizzo 224980ad548dSVincenzo Maffione if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) + 225080ad548dSVincenzo Maffione sizeof(seq)) { 225137e3a6d3SLuigi Rizzo RD(1, "%s: packet too small (len=%u)", __func__, 225237e3a6d3SLuigi Rizzo slot->len); 225337e3a6d3SLuigi Rizzo } else { 225480ad548dSVincenzo Maffione seq = (PKT(pkt, body, af)[0] << 24) | 225580ad548dSVincenzo Maffione (PKT(pkt, body, af)[1] << 16) | 225680ad548dSVincenzo Maffione (PKT(pkt, body, af)[2] << 8) | 225780ad548dSVincenzo Maffione PKT(pkt, body, af)[3]; 225837e3a6d3SLuigi Rizzo if (first_slot) { 225937e3a6d3SLuigi Rizzo /* Grab the first one, whatever it 226037e3a6d3SLuigi Rizzo is. */ 226180ad548dSVincenzo Maffione seq_exp[j] = seq; 226237e3a6d3SLuigi Rizzo first_slot = 0; 226380ad548dSVincenzo Maffione } else if (seq != seq_exp[j]) { 226480ad548dSVincenzo Maffione uint32_t delta = seq - seq_exp[j]; 226537e3a6d3SLuigi Rizzo 226637e3a6d3SLuigi Rizzo if (delta < (0xFFFFFFFF >> 1)) { 226737e3a6d3SLuigi Rizzo RD(2, "Sequence GAP: exp %u found %u", 226880ad548dSVincenzo Maffione seq_exp[j], seq); 226937e3a6d3SLuigi Rizzo } else { 227037e3a6d3SLuigi Rizzo RD(2, "Sequence OUT OF ORDER: " 227180ad548dSVincenzo Maffione "exp %u found %u", seq_exp[j], seq); 227237e3a6d3SLuigi Rizzo } 227380ad548dSVincenzo Maffione seq_exp[j] = seq; 227437e3a6d3SLuigi Rizzo } 227580ad548dSVincenzo Maffione seq_exp[j]++; 227637e3a6d3SLuigi Rizzo } 227737e3a6d3SLuigi Rizzo 227837e3a6d3SLuigi Rizzo cur.bytes += slot->len; 227937e3a6d3SLuigi Rizzo head = nm_ring_next(ring, head); 228037e3a6d3SLuigi Rizzo cur.pkts++; 228137e3a6d3SLuigi Rizzo } 228237e3a6d3SLuigi Rizzo 228337e3a6d3SLuigi Rizzo ring->cur = ring->head = head; 228437e3a6d3SLuigi Rizzo 228537e3a6d3SLuigi Rizzo cur.events++; 228637e3a6d3SLuigi Rizzo targ->ctr = cur; 228768b8534bSLuigi Rizzo } 228880ad548dSVincenzo Maffione } 2289f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 2290f0ea3689SLuigi Rizzo 229180ad548dSVincenzo Maffione #ifndef BUSYWAIT 2292f0ea3689SLuigi Rizzo out: 229380ad548dSVincenzo Maffione #endif /* !BUSYWAIT */ 229468b8534bSLuigi Rizzo targ->completed = 1; 229537e3a6d3SLuigi Rizzo targ->ctr = cur; 229668b8534bSLuigi Rizzo 229768b8534bSLuigi Rizzo quit: 229880ad548dSVincenzo Maffione if (seq_exp != NULL) 229980ad548dSVincenzo Maffione free(seq_exp); 230068b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 230168b8534bSLuigi Rizzo targ->used = 0; 230268b8534bSLuigi Rizzo 230368b8534bSLuigi Rizzo return (NULL); 230468b8534bSLuigi Rizzo } 230568b8534bSLuigi Rizzo 230666a698c9SEd Maste 230768b8534bSLuigi Rizzo static void 230880ad548dSVincenzo Maffione tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg) 230968b8534bSLuigi Rizzo { 231037e3a6d3SLuigi Rizzo double bw, raw_bw, pps, abs; 2311f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 231237e3a6d3SLuigi Rizzo int size; 231368b8534bSLuigi Rizzo 231437e3a6d3SLuigi Rizzo if (cur->pkts == 0) { 231537e3a6d3SLuigi Rizzo printf("%s nothing.\n", msg); 231637e3a6d3SLuigi Rizzo return; 231737e3a6d3SLuigi Rizzo } 231837e3a6d3SLuigi Rizzo 231937e3a6d3SLuigi Rizzo size = (int)(cur->bytes / cur->pkts); 232037e3a6d3SLuigi Rizzo 232137e3a6d3SLuigi Rizzo printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", 232237e3a6d3SLuigi Rizzo msg, 232337e3a6d3SLuigi Rizzo (unsigned long long)cur->pkts, 232437e3a6d3SLuigi Rizzo (unsigned long long)cur->bytes, 232537e3a6d3SLuigi Rizzo (unsigned long long)cur->events, size, delta); 2326f8e4e36aSLuigi Rizzo if (delta == 0) 2327f8e4e36aSLuigi Rizzo delta = 1e-6; 2328f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 2329f8e4e36aSLuigi Rizzo size = 60; 233037e3a6d3SLuigi Rizzo pps = cur->pkts / delta; 233137e3a6d3SLuigi Rizzo bw = (8.0 * cur->bytes) / delta; 233280ad548dSVincenzo Maffione raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta; 233337e3a6d3SLuigi Rizzo abs = cur->pkts / (double)(cur->events); 233466a698c9SEd Maste 233537e3a6d3SLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", 233680ad548dSVincenzo Maffione norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); 233768b8534bSLuigi Rizzo } 233868b8534bSLuigi Rizzo 233968b8534bSLuigi Rizzo static void 234080ad548dSVincenzo Maffione usage(int errcode) 234168b8534bSLuigi Rizzo { 234280ad548dSVincenzo Maffione /* This usage is generated from the pkt-gen man page: 234380ad548dSVincenzo Maffione * $ man pkt-gen > x 234480ad548dSVincenzo Maffione * and pasted here adding the string terminators and endlines with simple 234580ad548dSVincenzo Maffione * regular expressions. */ 234668b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 234768b8534bSLuigi Rizzo fprintf(stderr, 234868b8534bSLuigi Rizzo "Usage:\n" 234968b8534bSLuigi Rizzo "%s arguments\n" 235080ad548dSVincenzo Maffione " -h Show program usage and exit.\n" 235180ad548dSVincenzo Maffione "\n" 235280ad548dSVincenzo Maffione " -i interface\n" 235380ad548dSVincenzo Maffione " Name of the network interface that pkt-gen operates on. It can be a system network interface\n" 235480ad548dSVincenzo Maffione " (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n" 235580ad548dSVincenzo Maffione " monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n" 235680ad548dSVincenzo Maffione " mented in netmap(4) (NIOCREGIF section).\n" 235780ad548dSVincenzo Maffione "\n" 235880ad548dSVincenzo Maffione " -f function\n" 235980ad548dSVincenzo Maffione " The function to be executed by pkt-gen. Specify tx for transmission, rx for reception, ping\n" 236080ad548dSVincenzo Maffione " for client-side ping-pong operation, and pong for server-side ping-pong operation.\n" 236180ad548dSVincenzo Maffione "\n" 236280ad548dSVincenzo Maffione " -n count\n" 236380ad548dSVincenzo Maffione " Number of iterations of the pkt-gen function, with 0 meaning infinite). In case of tx or rx,\n" 236480ad548dSVincenzo Maffione " count is the number of packets to receive or transmit. In case of ping or pong, count is the\n" 236580ad548dSVincenzo Maffione " number of ping-pong transactions.\n" 236680ad548dSVincenzo Maffione "\n" 236780ad548dSVincenzo Maffione " -l pkt_size\n" 236880ad548dSVincenzo Maffione " Packet size in bytes excluding CRC. If passed a second time, use random sizes larger or\n" 236980ad548dSVincenzo Maffione " equal than the second one and lower than the first one.\n" 237080ad548dSVincenzo Maffione "\n" 237180ad548dSVincenzo Maffione " -b burst_size\n" 237280ad548dSVincenzo Maffione " Transmit or receive up to burst_size packets at a time.\n" 237380ad548dSVincenzo Maffione "\n" 237480ad548dSVincenzo Maffione " -4 Use IPv4 addresses.\n" 237580ad548dSVincenzo Maffione "\n" 237680ad548dSVincenzo Maffione " -6 Use IPv6 addresses.\n" 237780ad548dSVincenzo Maffione "\n" 237880ad548dSVincenzo Maffione " -d dst_ip[:port[-dst_ip:port]]\n" 237980ad548dSVincenzo Maffione " Destination IPv4/IPv6 address and port, single or range.\n" 238080ad548dSVincenzo Maffione "\n" 238180ad548dSVincenzo Maffione " -s src_ip[:port[-src_ip:port]]\n" 238280ad548dSVincenzo Maffione " Source IPv4/IPv6 address and port, single or range.\n" 238380ad548dSVincenzo Maffione "\n" 238480ad548dSVincenzo Maffione " -D dst_mac\n" 238580ad548dSVincenzo Maffione " Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n" 238680ad548dSVincenzo Maffione "\n" 238780ad548dSVincenzo Maffione " -S src_mac\n" 238880ad548dSVincenzo Maffione " Source MAC address in colon notation.\n" 238980ad548dSVincenzo Maffione "\n" 239080ad548dSVincenzo Maffione " -a cpu_id\n" 239180ad548dSVincenzo Maffione " Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3). If more\n" 239280ad548dSVincenzo Maffione " threads are used, they are pinned to the subsequent CPUs, one per thread.\n" 239380ad548dSVincenzo Maffione "\n" 239480ad548dSVincenzo Maffione " -c cpus\n" 239580ad548dSVincenzo Maffione " Maximum number of CPUs to use (0 means to use all the available ones).\n" 239680ad548dSVincenzo Maffione "\n" 239780ad548dSVincenzo Maffione " -p threads\n" 239880ad548dSVincenzo Maffione " Number of threads to use. By default, only a single thread is used to handle all the netmap\n" 239980ad548dSVincenzo Maffione " rings. If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n" 240080ad548dSVincenzo Maffione " single RX ring (in rx mode), or a TX/RX ring couple. The number of threads must be less or\n" 240180ad548dSVincenzo Maffione " equal than the number of TX (or RX) ring available in the device specified by interface.\n" 240280ad548dSVincenzo Maffione "\n" 240380ad548dSVincenzo Maffione " -T report_ms\n" 240480ad548dSVincenzo Maffione " Number of milliseconds between reports.\n" 240580ad548dSVincenzo Maffione "\n" 240680ad548dSVincenzo Maffione " -w wait_for_link_time\n" 240780ad548dSVincenzo Maffione " Number of seconds to wait before starting the pkt-gen function, useuful to make sure that the\n" 240880ad548dSVincenzo Maffione " network link is up. A network device driver may take some time to enter netmap mode, or to\n" 240980ad548dSVincenzo Maffione " create a new transmit/receive ring pair when netmap(4) requests one.\n" 241080ad548dSVincenzo Maffione "\n" 241180ad548dSVincenzo Maffione " -R rate\n" 241280ad548dSVincenzo Maffione " Packet transmission rate. Not setting the packet transmission rate tells pkt-gen to transmit\n" 241380ad548dSVincenzo Maffione " packets as quickly as possible. On servers from 2010 on-wards netmap(4) is able to com-\n" 241480ad548dSVincenzo Maffione " pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n" 241580ad548dSVincenzo Maffione " your intention is to saturate the link.\n" 241680ad548dSVincenzo Maffione "\n" 241780ad548dSVincenzo Maffione " -X Dump payload of each packet transmitted or received.\n" 241880ad548dSVincenzo Maffione "\n" 241980ad548dSVincenzo Maffione " -H len Add empty virtio-net-header with size 'len'. Valid sizes are 0, 10 and 12. This option is\n" 242080ad548dSVincenzo Maffione " only used with Virtual Machine technologies that use virtio as a network interface.\n" 242180ad548dSVincenzo Maffione "\n" 242280ad548dSVincenzo Maffione " -P file\n" 242380ad548dSVincenzo Maffione " Load the packet to be transmitted from a pcap file rather than constructing it within\n" 242480ad548dSVincenzo Maffione " pkt-gen.\n" 242580ad548dSVincenzo Maffione "\n" 242680ad548dSVincenzo Maffione " -z Use random IPv4/IPv6 src address/port.\n" 242780ad548dSVincenzo Maffione "\n" 242880ad548dSVincenzo Maffione " -Z Use random IPv4/IPv6 dst address/port.\n" 242980ad548dSVincenzo Maffione "\n" 243080ad548dSVincenzo Maffione " -N Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n" 243180ad548dSVincenzo Maffione "\n" 243280ad548dSVincenzo Maffione " -F num_frags\n" 243380ad548dSVincenzo Maffione " Send multi-slot packets, each one with num_frags fragments. A multi-slot packet is repre-\n" 243480ad548dSVincenzo Maffione " sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n" 243580ad548dSVincenzo Maffione " last slot). This is useful to transmit or receive packets larger than the netmap buffer\n" 243680ad548dSVincenzo Maffione " size.\n" 243780ad548dSVincenzo Maffione "\n" 243880ad548dSVincenzo Maffione " -M frag_size\n" 243980ad548dSVincenzo Maffione " In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n" 244080ad548dSVincenzo Maffione " length divided by num_frags.\n" 244180ad548dSVincenzo Maffione "\n" 244280ad548dSVincenzo Maffione " -I Use indirect buffers. It is only valid for transmitting on VALE ports, and it is implemented\n" 244380ad548dSVincenzo Maffione " by setting the NS_INDIRECT flag in the netmap slots.\n" 244480ad548dSVincenzo Maffione "\n" 244580ad548dSVincenzo Maffione " -W Exit immediately if all the RX rings are empty the first time they are examined.\n" 244680ad548dSVincenzo Maffione "\n" 244780ad548dSVincenzo Maffione " -v Increase the verbosity level.\n" 244880ad548dSVincenzo Maffione "\n" 244980ad548dSVincenzo Maffione " -r In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n" 245080ad548dSVincenzo Maffione " netmap buffers is (rubbish mode).\n" 245180ad548dSVincenzo Maffione "\n" 245280ad548dSVincenzo Maffione " -A Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n" 245380ad548dSVincenzo Maffione "\n" 245480ad548dSVincenzo Maffione " -B Take Ethernet framing and CRC into account when computing the average bps. This adds 4 bytes\n" 245580ad548dSVincenzo Maffione " of CRC and 20 bytes of framing to each packet.\n" 245680ad548dSVincenzo Maffione "\n" 245780ad548dSVincenzo Maffione " -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n" 245880ad548dSVincenzo Maffione " Configuration in terms of number of rings and slots to be used when opening the netmap port.\n" 245980ad548dSVincenzo Maffione " Such configuration has effect on software ports created on the fly, such as VALE ports and\n" 246080ad548dSVincenzo Maffione " netmap pipes. The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n" 246180ad548dSVincenzo Maffione " rx_slots, tx_rings, rx_rings. Missing numbers or zeroes stand for default values. As an\n" 246280ad548dSVincenzo Maffione " additional convenience, if exactly one number is specified, then this is assigned to both\n" 246380ad548dSVincenzo Maffione " tx_slots and rx_slots. If there is no fourth number, then the third one is assigned to both\n" 246480ad548dSVincenzo Maffione " tx_rings and rx_rings.\n" 246580ad548dSVincenzo Maffione "\n" 246680ad548dSVincenzo Maffione " -o options data generation options (parsed using atoi)\n" 246780ad548dSVincenzo Maffione " OPT_PREFETCH 1\n" 246880ad548dSVincenzo Maffione " OPT_ACCESS 2\n" 246980ad548dSVincenzo Maffione " OPT_COPY 4\n" 247080ad548dSVincenzo Maffione " OPT_MEMCPY 8\n" 247180ad548dSVincenzo Maffione " OPT_TS 16 (add a timestamp)\n" 247280ad548dSVincenzo Maffione " OPT_INDIRECT 32 (use indirect buffers)\n" 247380ad548dSVincenzo Maffione " OPT_DUMP 64 (dump rx/tx traffic)\n" 247480ad548dSVincenzo Maffione " OPT_RUBBISH 256\n" 247580ad548dSVincenzo Maffione " (send wathever the buffers contain)\n" 247680ad548dSVincenzo Maffione " OPT_RANDOM_SRC 512\n" 247780ad548dSVincenzo Maffione " OPT_RANDOM_DST 1024\n" 247880ad548dSVincenzo Maffione " OPT_PPS_STATS 2048\n" 247968b8534bSLuigi Rizzo "", 248068b8534bSLuigi Rizzo cmd); 248180ad548dSVincenzo Maffione exit(errcode); 248268b8534bSLuigi Rizzo } 248368b8534bSLuigi Rizzo 2484f8e4e36aSLuigi Rizzo static void 248580ad548dSVincenzo Maffione start_threads(struct glob_arg *g) { 2486f8e4e36aSLuigi Rizzo int i; 2487f8e4e36aSLuigi Rizzo 2488f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 248980ad548dSVincenzo Maffione struct targ *t; 2490f8e4e36aSLuigi Rizzo /* 2491f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 2492f8e4e36aSLuigi Rizzo * using a single descriptor. 2493f8e4e36aSLuigi Rizzo */ 2494f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 249580ad548dSVincenzo Maffione uint64_t seed = time(0) | (time(0) << 32); 249680ad548dSVincenzo Maffione t = &targs[i]; 2497f0ea3689SLuigi Rizzo 2498f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 2499f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 2500f0ea3689SLuigi Rizzo t->g = g; 250180ad548dSVincenzo Maffione memcpy(t->seed, &seed, sizeof(t->seed)); 2502f8e4e36aSLuigi Rizzo 2503f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 2504f0ea3689SLuigi Rizzo struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */ 25054bf50f18SLuigi Rizzo uint64_t nmd_flags = 0; 25064bf50f18SLuigi Rizzo nmd.self = &nmd; 2507f8e4e36aSLuigi Rizzo 250837e3a6d3SLuigi Rizzo if (i > 0) { 250937e3a6d3SLuigi Rizzo /* the first thread uses the fd opened by the main 251037e3a6d3SLuigi Rizzo * thread, the other threads re-open /dev/netmap 251137e3a6d3SLuigi Rizzo */ 2512f0ea3689SLuigi Rizzo if (g->nthreads > 1) { 251337e3a6d3SLuigi Rizzo nmd.req.nr_flags = 251437e3a6d3SLuigi Rizzo g->nmd->req.nr_flags & ~NR_REG_MASK; 251537e3a6d3SLuigi Rizzo nmd.req.nr_flags |= NR_REG_ONE_NIC; 2516f0ea3689SLuigi Rizzo nmd.req.nr_ringid = i; 251717885a7bSLuigi Rizzo } 2518f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 251937e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_RECEIVER) 25204bf50f18SLuigi Rizzo nmd_flags |= NETMAP_NO_TX_POLL; 2521f8e4e36aSLuigi Rizzo 2522f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 25234bf50f18SLuigi Rizzo t->nmd = nm_open(t->g->ifname, NULL, nmd_flags | 25244bf50f18SLuigi Rizzo NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd); 2525f0ea3689SLuigi Rizzo if (t->nmd == NULL) { 2526f0ea3689SLuigi Rizzo D("Unable to open %s: %s", 2527f0ea3689SLuigi Rizzo t->g->ifname, strerror(errno)); 2528f8e4e36aSLuigi Rizzo continue; 2529f8e4e36aSLuigi Rizzo } 253037e3a6d3SLuigi Rizzo } else { 253137e3a6d3SLuigi Rizzo t->nmd = g->nmd; 253237e3a6d3SLuigi Rizzo } 2533f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 253480ad548dSVincenzo Maffione t->frags = g->frags; 2535f8e4e36aSLuigi Rizzo } else { 2536f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 2537f8e4e36aSLuigi Rizzo } 2538f0ea3689SLuigi Rizzo t->used = 1; 2539f0ea3689SLuigi Rizzo t->me = i; 2540f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 254180ad548dSVincenzo Maffione t->affinity = (g->affinity + i) % g->cpus; 2542f0ea3689SLuigi Rizzo } else { 2543f0ea3689SLuigi Rizzo t->affinity = -1; 2544f0ea3689SLuigi Rizzo } 2545f8e4e36aSLuigi Rizzo /* default, init packets */ 2546f0ea3689SLuigi Rizzo initialize_packet(t); 254780ad548dSVincenzo Maffione } 254880ad548dSVincenzo Maffione /* Wait for PHY reset. */ 254980ad548dSVincenzo Maffione D("Wait %d secs for phy reset", g->wait_link); 255080ad548dSVincenzo Maffione sleep(g->wait_link); 255180ad548dSVincenzo Maffione D("Ready..."); 2552f8e4e36aSLuigi Rizzo 255380ad548dSVincenzo Maffione for (i = 0; i < g->nthreads; i++) { 255480ad548dSVincenzo Maffione t = &targs[i]; 2555f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 255617885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 2557f0ea3689SLuigi Rizzo t->used = 0; 2558f8e4e36aSLuigi Rizzo } 2559f8e4e36aSLuigi Rizzo } 2560f8e4e36aSLuigi Rizzo } 2561f8e4e36aSLuigi Rizzo 2562f8e4e36aSLuigi Rizzo static void 2563f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 2564f8e4e36aSLuigi Rizzo { 2565f8e4e36aSLuigi Rizzo int i; 2566f8e4e36aSLuigi Rizzo 256737e3a6d3SLuigi Rizzo struct my_ctrs prev, cur; 2568f8e4e36aSLuigi Rizzo double delta_t; 2569f8e4e36aSLuigi Rizzo struct timeval tic, toc; 2570f8e4e36aSLuigi Rizzo 257137e3a6d3SLuigi Rizzo prev.pkts = prev.bytes = prev.events = 0; 257237e3a6d3SLuigi Rizzo gettimeofday(&prev.t, NULL); 2573f8e4e36aSLuigi Rizzo for (;;) { 257480ad548dSVincenzo Maffione char b1[40], b2[40], b3[40], b4[100]; 257537e3a6d3SLuigi Rizzo uint64_t pps, usec; 257637e3a6d3SLuigi Rizzo struct my_ctrs x; 257737e3a6d3SLuigi Rizzo double abs; 2578f8e4e36aSLuigi Rizzo int done = 0; 2579f8e4e36aSLuigi Rizzo 258037e3a6d3SLuigi Rizzo usec = wait_for_next_report(&prev.t, &cur.t, 258137e3a6d3SLuigi Rizzo g->report_interval); 258237e3a6d3SLuigi Rizzo 258337e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 258437e3a6d3SLuigi Rizzo cur.min_space = 0; 258537e3a6d3SLuigi Rizzo if (usec < 10000) /* too short to be meaningful */ 258637e3a6d3SLuigi Rizzo continue; 258737e3a6d3SLuigi Rizzo /* accumulate counts for all threads */ 2588f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 258937e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 259037e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 259137e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 259237e3a6d3SLuigi Rizzo cur.min_space += targs[i].ctr.min_space; 259337e3a6d3SLuigi Rizzo targs[i].ctr.min_space = 99999; 2594f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 2595f8e4e36aSLuigi Rizzo done++; 2596f8e4e36aSLuigi Rizzo } 259737e3a6d3SLuigi Rizzo x.pkts = cur.pkts - prev.pkts; 259837e3a6d3SLuigi Rizzo x.bytes = cur.bytes - prev.bytes; 259937e3a6d3SLuigi Rizzo x.events = cur.events - prev.events; 260037e3a6d3SLuigi Rizzo pps = (x.pkts*1000000 + usec/2) / usec; 260137e3a6d3SLuigi Rizzo abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; 260237e3a6d3SLuigi Rizzo 260337e3a6d3SLuigi Rizzo if (!(g->options & OPT_PPS_STATS)) { 260437e3a6d3SLuigi Rizzo strcpy(b4, ""); 260537e3a6d3SLuigi Rizzo } else { 260637e3a6d3SLuigi Rizzo /* Compute some pps stats using a sliding window. */ 260737e3a6d3SLuigi Rizzo double ppsavg = 0.0, ppsdev = 0.0; 260837e3a6d3SLuigi Rizzo int nsamples = 0; 260937e3a6d3SLuigi Rizzo 261037e3a6d3SLuigi Rizzo g->win[g->win_idx] = pps; 261137e3a6d3SLuigi Rizzo g->win_idx = (g->win_idx + 1) % STATS_WIN; 261237e3a6d3SLuigi Rizzo 261337e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 261437e3a6d3SLuigi Rizzo ppsavg += g->win[i]; 261537e3a6d3SLuigi Rizzo if (g->win[i]) { 261637e3a6d3SLuigi Rizzo nsamples ++; 261737e3a6d3SLuigi Rizzo } 261837e3a6d3SLuigi Rizzo } 261937e3a6d3SLuigi Rizzo ppsavg /= nsamples; 262037e3a6d3SLuigi Rizzo 262137e3a6d3SLuigi Rizzo for (i = 0; i < STATS_WIN; i++) { 262237e3a6d3SLuigi Rizzo if (g->win[i] == 0) { 2623f8e4e36aSLuigi Rizzo continue; 262437e3a6d3SLuigi Rizzo } 262537e3a6d3SLuigi Rizzo ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); 262637e3a6d3SLuigi Rizzo } 262737e3a6d3SLuigi Rizzo ppsdev /= nsamples; 262837e3a6d3SLuigi Rizzo ppsdev = sqrt(ppsdev); 262937e3a6d3SLuigi Rizzo 263037e3a6d3SLuigi Rizzo snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", 263180ad548dSVincenzo Maffione norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); 263237e3a6d3SLuigi Rizzo } 263337e3a6d3SLuigi Rizzo 263437e3a6d3SLuigi Rizzo D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", 263580ad548dSVincenzo Maffione norm(b1, pps, normalize), b4, 263680ad548dSVincenzo Maffione norm(b2, (double)x.pkts, normalize), 263780ad548dSVincenzo Maffione norm(b3, (double)x.bytes*8+(double)x.pkts*g->framing, normalize), 263837e3a6d3SLuigi Rizzo (unsigned long long)usec, 263937e3a6d3SLuigi Rizzo abs, (int)cur.min_space); 264037e3a6d3SLuigi Rizzo prev = cur; 264137e3a6d3SLuigi Rizzo 2642f8e4e36aSLuigi Rizzo if (done == g->nthreads) 2643f8e4e36aSLuigi Rizzo break; 2644f8e4e36aSLuigi Rizzo } 2645f8e4e36aSLuigi Rizzo 2646f8e4e36aSLuigi Rizzo timerclear(&tic); 2647f8e4e36aSLuigi Rizzo timerclear(&toc); 264837e3a6d3SLuigi Rizzo cur.pkts = cur.bytes = cur.events = 0; 264937e3a6d3SLuigi Rizzo /* final round */ 2650f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 26511cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 2652f8e4e36aSLuigi Rizzo /* 2653f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 2654f8e4e36aSLuigi Rizzo * file descriptors. 2655f8e4e36aSLuigi Rizzo */ 26561cb4c501SLuigi Rizzo if (targs[i].used) 265737e3a6d3SLuigi Rizzo pthread_join(targs[i].thread, NULL); /* blocking */ 265837e3a6d3SLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 265937e3a6d3SLuigi Rizzo nm_close(targs[i].nmd); 266037e3a6d3SLuigi Rizzo targs[i].nmd = NULL; 266137e3a6d3SLuigi Rizzo } else { 2662f8e4e36aSLuigi Rizzo close(targs[i].fd); 266337e3a6d3SLuigi Rizzo } 2664f8e4e36aSLuigi Rizzo 2665f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 2666f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 2667f8e4e36aSLuigi Rizzo 2668f8e4e36aSLuigi Rizzo /* 2669f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 2670f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 2671f8e4e36aSLuigi Rizzo */ 267237e3a6d3SLuigi Rizzo cur.pkts += targs[i].ctr.pkts; 267337e3a6d3SLuigi Rizzo cur.bytes += targs[i].ctr.bytes; 267437e3a6d3SLuigi Rizzo cur.events += targs[i].ctr.events; 267537e3a6d3SLuigi Rizzo /* collect the largest start (tic) and end (toc) times, 267637e3a6d3SLuigi Rizzo * XXX maybe we should do the earliest tic, or do a weighted 267737e3a6d3SLuigi Rizzo * average ? 267837e3a6d3SLuigi Rizzo */ 26791cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 26801cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 26811cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 26821cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 26831cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 26841cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 2685f8e4e36aSLuigi Rizzo } 2686f8e4e36aSLuigi Rizzo 2687f8e4e36aSLuigi Rizzo /* print output. */ 2688f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 2689f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 269037e3a6d3SLuigi Rizzo if (g->td_type == TD_TYPE_SENDER) 269180ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Sent"); 269280ad548dSVincenzo Maffione else if (g->td_type == TD_TYPE_RECEIVER) 269380ad548dSVincenzo Maffione tx_output(g, &cur, delta_t, "Received"); 2694f8e4e36aSLuigi Rizzo } 2695f8e4e36aSLuigi Rizzo 269637e3a6d3SLuigi Rizzo struct td_desc { 269737e3a6d3SLuigi Rizzo int ty; 2698f8e4e36aSLuigi Rizzo char *key; 2699f8e4e36aSLuigi Rizzo void *f; 270080ad548dSVincenzo Maffione int default_burst; 2701f8e4e36aSLuigi Rizzo }; 2702f8e4e36aSLuigi Rizzo 270337e3a6d3SLuigi Rizzo static struct td_desc func[] = { 270480ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ 270580ad548dSVincenzo Maffione { TD_TYPE_SENDER, "tx", sender_body, 512 }, 270680ad548dSVincenzo Maffione { TD_TYPE_OTHER, "ping", ping_body, 1 }, 270780ad548dSVincenzo Maffione { TD_TYPE_OTHER, "pong", pong_body, 1 }, 270880ad548dSVincenzo Maffione { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, 270980ad548dSVincenzo Maffione { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, 271080ad548dSVincenzo Maffione { 0, NULL, NULL, 0 } 2711f8e4e36aSLuigi Rizzo }; 2712f8e4e36aSLuigi Rizzo 2713f8e4e36aSLuigi Rizzo static int 2714f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 2715f8e4e36aSLuigi Rizzo { 2716f8e4e36aSLuigi Rizzo struct ifreq ifr; 2717f8e4e36aSLuigi Rizzo int fd, err; 2718f8e4e36aSLuigi Rizzo char *clonedev = TAP_CLONEDEV; 2719f8e4e36aSLuigi Rizzo 2720f8e4e36aSLuigi Rizzo (void)err; 2721f8e4e36aSLuigi Rizzo (void)dev; 2722f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 2723f8e4e36aSLuigi Rizzo * 2724f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 2725f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 2726f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 2727f8e4e36aSLuigi Rizzo */ 2728f8e4e36aSLuigi Rizzo 2729f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 2730f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 2731f8e4e36aSLuigi Rizzo static char buf[128]; 2732f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 2733f8e4e36aSLuigi Rizzo clonedev = buf; 2734f8e4e36aSLuigi Rizzo } 2735f8e4e36aSLuigi Rizzo #endif 2736f8e4e36aSLuigi Rizzo /* open the device */ 2737f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 2738f8e4e36aSLuigi Rizzo return fd; 2739f8e4e36aSLuigi Rizzo } 2740f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 2741f8e4e36aSLuigi Rizzo 2742f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 2743f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 2744f8e4e36aSLuigi Rizzo 2745f8e4e36aSLuigi Rizzo #ifdef linux 2746f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 2747f8e4e36aSLuigi Rizzo 2748f8e4e36aSLuigi Rizzo if (*dev) { 2749f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 2750f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 2751f8e4e36aSLuigi Rizzo * specified type */ 275280ad548dSVincenzo Maffione size_t len = strlen(dev); 275380ad548dSVincenzo Maffione if (len > IFNAMSIZ) { 275480ad548dSVincenzo Maffione D("%s too long", dev); 275580ad548dSVincenzo Maffione return -1; 275680ad548dSVincenzo Maffione } 275780ad548dSVincenzo Maffione memcpy(ifr.ifr_name, dev, len); 2758f8e4e36aSLuigi Rizzo } 2759f8e4e36aSLuigi Rizzo 2760f8e4e36aSLuigi Rizzo /* try to create the device */ 2761f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 276217885a7bSLuigi Rizzo D("failed to to a TUNSETIFF: %s", strerror(errno)); 2763f8e4e36aSLuigi Rizzo close(fd); 2764f8e4e36aSLuigi Rizzo return err; 2765f8e4e36aSLuigi Rizzo } 2766f8e4e36aSLuigi Rizzo 2767f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 2768f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 2769f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 2770f8e4e36aSLuigi Rizzo * code below) */ 2771f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 2772f8e4e36aSLuigi Rizzo D("new name is %s", dev); 2773f8e4e36aSLuigi Rizzo #endif /* linux */ 2774f8e4e36aSLuigi Rizzo 2775f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 2776f8e4e36aSLuigi Rizzo * with the virtual interface */ 2777f8e4e36aSLuigi Rizzo return fd; 2778f8e4e36aSLuigi Rizzo } 277968b8534bSLuigi Rizzo 278068b8534bSLuigi Rizzo int 278168b8534bSLuigi Rizzo main(int arc, char **argv) 278268b8534bSLuigi Rizzo { 2783f8e4e36aSLuigi Rizzo int i; 278437e3a6d3SLuigi Rizzo struct sigaction sa; 278537e3a6d3SLuigi Rizzo sigset_t ss; 278668b8534bSLuigi Rizzo 278768b8534bSLuigi Rizzo struct glob_arg g; 278868b8534bSLuigi Rizzo 278968b8534bSLuigi Rizzo int ch; 279068b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 279180ad548dSVincenzo Maffione int wait_link_arg = 0; 279280ad548dSVincenzo Maffione 279380ad548dSVincenzo Maffione int pkt_size_done = 0; 279480ad548dSVincenzo Maffione 279580ad548dSVincenzo Maffione struct td_desc *fn = func; 279668b8534bSLuigi Rizzo 279768b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 279868b8534bSLuigi Rizzo 2799f8e4e36aSLuigi Rizzo g.main_fd = -1; 280080ad548dSVincenzo Maffione g.td_body = fn->f; 280180ad548dSVincenzo Maffione g.td_type = fn->ty; 2802f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 2803f8e4e36aSLuigi Rizzo g.affinity = -1; 2804f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 280580ad548dSVincenzo Maffione g.af = AF_INET; /* default */ 2806f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 2807f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 2808f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 2809f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 281068b8534bSLuigi Rizzo g.pkt_size = 60; 281180ad548dSVincenzo Maffione g.pkt_min_size = 0; 281268b8534bSLuigi Rizzo g.nthreads = 1; 281380ad548dSVincenzo Maffione g.cpus = 1; /* default */ 2814b303f675SLuigi Rizzo g.forever = 1; 28151cb4c501SLuigi Rizzo g.tx_rate = 0; 2816ce3ee1e7SLuigi Rizzo g.frags = 1; 28179e53f3bdSVincenzo Maffione g.frag_size = (u_int)-1; /* use the netmap buffer size by default */ 2818ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 281917885a7bSLuigi Rizzo g.virt_header = 0; 282080ad548dSVincenzo Maffione g.wait_link = 2; /* wait 2 seconds for physical ports */ 282168b8534bSLuigi Rizzo 282280ad548dSVincenzo Maffione while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" 282380ad548dSVincenzo Maffione "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) { 2824f8e4e36aSLuigi Rizzo 282568b8534bSLuigi Rizzo switch(ch) { 282668b8534bSLuigi Rizzo default: 282768b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 282880ad548dSVincenzo Maffione usage(-1); 282980ad548dSVincenzo Maffione break; 283080ad548dSVincenzo Maffione 283180ad548dSVincenzo Maffione case 'h': 283280ad548dSVincenzo Maffione usage(0); 283380ad548dSVincenzo Maffione break; 283480ad548dSVincenzo Maffione 283580ad548dSVincenzo Maffione case '4': 283680ad548dSVincenzo Maffione g.af = AF_INET; 283780ad548dSVincenzo Maffione break; 283880ad548dSVincenzo Maffione 283980ad548dSVincenzo Maffione case '6': 284080ad548dSVincenzo Maffione g.af = AF_INET6; 284180ad548dSVincenzo Maffione break; 284280ad548dSVincenzo Maffione 284380ad548dSVincenzo Maffione case 'N': 284480ad548dSVincenzo Maffione normalize = 0; 284568b8534bSLuigi Rizzo break; 2846f8e4e36aSLuigi Rizzo 2847f8e4e36aSLuigi Rizzo case 'n': 284837e3a6d3SLuigi Rizzo g.npackets = strtoull(optarg, NULL, 10); 2849f8e4e36aSLuigi Rizzo break; 2850f8e4e36aSLuigi Rizzo 2851ce3ee1e7SLuigi Rizzo case 'F': 2852ce3ee1e7SLuigi Rizzo i = atoi(optarg); 2853ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 2854ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 2855ce3ee1e7SLuigi Rizzo break; 2856ce3ee1e7SLuigi Rizzo } 2857ce3ee1e7SLuigi Rizzo g.frags = i; 2858ce3ee1e7SLuigi Rizzo break; 2859ce3ee1e7SLuigi Rizzo 286080ad548dSVincenzo Maffione case 'M': 28619e53f3bdSVincenzo Maffione g.frag_size = atoi(optarg); 286280ad548dSVincenzo Maffione break; 286380ad548dSVincenzo Maffione 2864f8e4e36aSLuigi Rizzo case 'f': 2865f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 2866f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 2867f8e4e36aSLuigi Rizzo break; 2868f8e4e36aSLuigi Rizzo } 286937e3a6d3SLuigi Rizzo if (fn->key) { 2870f8e4e36aSLuigi Rizzo g.td_body = fn->f; 287137e3a6d3SLuigi Rizzo g.td_type = fn->ty; 287237e3a6d3SLuigi Rizzo } else { 2873f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 287437e3a6d3SLuigi Rizzo } 2875f8e4e36aSLuigi Rizzo break; 2876f8e4e36aSLuigi Rizzo 2877f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 287880ad548dSVincenzo Maffione g.options |= atoi(optarg); 287999fb123fSLuigi Rizzo break; 2880f8e4e36aSLuigi Rizzo 2881f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 2882f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 2883f8e4e36aSLuigi Rizzo break; 2884f8e4e36aSLuigi Rizzo 288568b8534bSLuigi Rizzo case 'i': /* interface */ 2886f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 2887f2637526SLuigi Rizzo * otherwise we guess 2888f2637526SLuigi Rizzo */ 2889f2637526SLuigi Rizzo D("interface is %s", optarg); 2890f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 2891f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 2892f0ea3689SLuigi Rizzo break; 2893f0ea3689SLuigi Rizzo } 2894f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 2895f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 2896f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 2897ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 2898f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 2899f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2900f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 2901f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 2902f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 2903f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 2904f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 2905f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 2906f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2907f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 2908f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 2909f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 2910f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 2911f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 2912f2637526SLuigi Rizzo } 291368b8534bSLuigi Rizzo break; 2914f8e4e36aSLuigi Rizzo 2915b303f675SLuigi Rizzo case 'I': 291680ad548dSVincenzo Maffione g.options |= OPT_INDIRECT; /* use indirect buffers */ 2917b303f675SLuigi Rizzo break; 2918b303f675SLuigi Rizzo 291968b8534bSLuigi Rizzo case 'l': /* pkt_size */ 292080ad548dSVincenzo Maffione if (pkt_size_done) { 292180ad548dSVincenzo Maffione g.pkt_min_size = atoi(optarg); 292280ad548dSVincenzo Maffione } else { 292368b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 292480ad548dSVincenzo Maffione pkt_size_done = 1; 292580ad548dSVincenzo Maffione } 292668b8534bSLuigi Rizzo break; 2927f8e4e36aSLuigi Rizzo 292868b8534bSLuigi Rizzo case 'd': 2929f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 293068b8534bSLuigi Rizzo break; 2931f8e4e36aSLuigi Rizzo 293268b8534bSLuigi Rizzo case 's': 2933f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 293468b8534bSLuigi Rizzo break; 2935f8e4e36aSLuigi Rizzo 293668b8534bSLuigi Rizzo case 'T': /* report interval */ 2937f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 293868b8534bSLuigi Rizzo break; 2939f8e4e36aSLuigi Rizzo 294068b8534bSLuigi Rizzo case 'w': 294180ad548dSVincenzo Maffione g.wait_link = atoi(optarg); 294280ad548dSVincenzo Maffione wait_link_arg = 1; 294368b8534bSLuigi Rizzo break; 2944f8e4e36aSLuigi Rizzo 294580ad548dSVincenzo Maffione case 'W': 294680ad548dSVincenzo Maffione g.forever = 0; /* exit RX with no traffic */ 2947f8e4e36aSLuigi Rizzo break; 2948f8e4e36aSLuigi Rizzo 294968b8534bSLuigi Rizzo case 'b': /* burst */ 295068b8534bSLuigi Rizzo g.burst = atoi(optarg); 295168b8534bSLuigi Rizzo break; 295268b8534bSLuigi Rizzo case 'c': 295368b8534bSLuigi Rizzo g.cpus = atoi(optarg); 295468b8534bSLuigi Rizzo break; 295568b8534bSLuigi Rizzo case 'p': 295668b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 295768b8534bSLuigi Rizzo break; 295868b8534bSLuigi Rizzo 295968b8534bSLuigi Rizzo case 'D': /* destination mac */ 2960f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 296168b8534bSLuigi Rizzo break; 2962f8e4e36aSLuigi Rizzo 296368b8534bSLuigi Rizzo case 'S': /* source mac */ 2964f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 296568b8534bSLuigi Rizzo break; 296668b8534bSLuigi Rizzo case 'v': 296768b8534bSLuigi Rizzo verbose++; 29681cb4c501SLuigi Rizzo break; 29691cb4c501SLuigi Rizzo case 'R': 29701cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 29711cb4c501SLuigi Rizzo break; 2972b303f675SLuigi Rizzo case 'X': 2973b303f675SLuigi Rizzo g.options |= OPT_DUMP; 2974ce3ee1e7SLuigi Rizzo break; 2975ce3ee1e7SLuigi Rizzo case 'C': 2976ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 297717885a7bSLuigi Rizzo break; 297817885a7bSLuigi Rizzo case 'H': 297917885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 2980f2637526SLuigi Rizzo break; 2981f284c737SGeorge V. Neville-Neil case 'P': 2982f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 2983f284c737SGeorge V. Neville-Neil break; 298437e3a6d3SLuigi Rizzo case 'r': 298537e3a6d3SLuigi Rizzo g.options |= OPT_RUBBISH; 298637e3a6d3SLuigi Rizzo break; 298756717743SAdrian Chadd case 'z': 298856717743SAdrian Chadd g.options |= OPT_RANDOM_SRC; 298956717743SAdrian Chadd break; 299056717743SAdrian Chadd case 'Z': 299156717743SAdrian Chadd g.options |= OPT_RANDOM_DST; 299256717743SAdrian Chadd break; 299337e3a6d3SLuigi Rizzo case 'A': 299437e3a6d3SLuigi Rizzo g.options |= OPT_PPS_STATS; 299537e3a6d3SLuigi Rizzo break; 299680ad548dSVincenzo Maffione case 'B': 299780ad548dSVincenzo Maffione /* raw packets have4 bytes crc + 20 bytes framing */ 299880ad548dSVincenzo Maffione // XXX maybe add an option to pass the IFG 299980ad548dSVincenzo Maffione g.framing = 24 * 8; 300080ad548dSVincenzo Maffione break; 300168b8534bSLuigi Rizzo } 300268b8534bSLuigi Rizzo } 300368b8534bSLuigi Rizzo 3004db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 300568b8534bSLuigi Rizzo D("missing ifname"); 300680ad548dSVincenzo Maffione usage(-1); 300780ad548dSVincenzo Maffione } 300880ad548dSVincenzo Maffione 300980ad548dSVincenzo Maffione if (g.burst == 0) { 301080ad548dSVincenzo Maffione g.burst = fn->default_burst; 301180ad548dSVincenzo Maffione D("using default burst size: %d", g.burst); 301268b8534bSLuigi Rizzo } 3013f8e4e36aSLuigi Rizzo 301437e3a6d3SLuigi Rizzo g.system_cpus = i = system_ncpus(); 3015f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 3016f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 301780ad548dSVincenzo Maffione usage(-1); 301868b8534bSLuigi Rizzo } 301937e3a6d3SLuigi Rizzo D("running on %d cpus (have %d)", g.cpus, i); 302068b8534bSLuigi Rizzo if (g.cpus == 0) 3021f8e4e36aSLuigi Rizzo g.cpus = i; 3022f8e4e36aSLuigi Rizzo 302380ad548dSVincenzo Maffione if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) { 302480ad548dSVincenzo Maffione g.wait_link = 0; 302580ad548dSVincenzo Maffione } 302680ad548dSVincenzo Maffione 30274bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 30284bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 302980ad548dSVincenzo Maffione usage(-1); 303080ad548dSVincenzo Maffione } 303180ad548dSVincenzo Maffione 303280ad548dSVincenzo Maffione if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) { 303380ad548dSVincenzo Maffione D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size); 303480ad548dSVincenzo Maffione usage(-1); 303568b8534bSLuigi Rizzo } 303668b8534bSLuigi Rizzo 3037f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 3038f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 303999fb123fSLuigi Rizzo /* retrieve source mac address. */ 3040f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 304199fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 304299fb123fSLuigi Rizzo // continue, fail later 304399fb123fSLuigi Rizzo } 3044f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 304599fb123fSLuigi Rizzo } 3046f8e4e36aSLuigi Rizzo /* extract address ranges */ 304780ad548dSVincenzo Maffione if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac)) 304880ad548dSVincenzo Maffione usage(-1); 304980ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.src_ip, g.af); 305080ad548dSVincenzo Maffione g.options |= extract_ip_range(&g.dst_ip, g.af); 3051f2637526SLuigi Rizzo 305217885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 305317885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 305417885a7bSLuigi Rizzo D("bad virtio-net-header length"); 305580ad548dSVincenzo Maffione usage(-1); 305617885a7bSLuigi Rizzo } 305717885a7bSLuigi Rizzo 3058f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 3059f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 3060f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 3061f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 3062f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 306380ad548dSVincenzo Maffione usage(-1); 306499fb123fSLuigi Rizzo } 3065f2637526SLuigi Rizzo #ifndef NO_PCAP 3066f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 3067f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 3068f8e4e36aSLuigi Rizzo 3069f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 30704bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 3071f8e4e36aSLuigi Rizzo if (g.p == NULL) { 3072f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 307380ad548dSVincenzo Maffione usage(-1); 3074f8e4e36aSLuigi Rizzo } 30754bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 30764bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 3077f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 3078f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 3079ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 308099fb123fSLuigi Rizzo } else { 308180ad548dSVincenzo Maffione struct nm_desc base_nmd; 308280ad548dSVincenzo Maffione char errmsg[MAXERRMSG]; 308380ad548dSVincenzo Maffione u_int flags; 3084f0ea3689SLuigi Rizzo 3085f0ea3689SLuigi Rizzo bzero(&base_nmd, sizeof(base_nmd)); 3086f0ea3689SLuigi Rizzo 308780ad548dSVincenzo Maffione parse_nmr_config(g.nmr_config, &base_nmd.req); 308837e3a6d3SLuigi Rizzo 308980ad548dSVincenzo Maffione base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR; 309080ad548dSVincenzo Maffione 309180ad548dSVincenzo Maffione if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) { 309280ad548dSVincenzo Maffione D("Invalid name '%s': %s", g.ifname, errmsg); 309380ad548dSVincenzo Maffione goto out; 309480ad548dSVincenzo Maffione } 3095f0ea3689SLuigi Rizzo 309668b8534bSLuigi Rizzo /* 3097f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 309868b8534bSLuigi Rizzo * 309968b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 310068b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 3101f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 310268b8534bSLuigi Rizzo */ 310380ad548dSVincenzo Maffione flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 | 310480ad548dSVincenzo Maffione NM_OPEN_ARG3 | NM_OPEN_RING_CFG; 310537e3a6d3SLuigi Rizzo if (g.nthreads > 1) { 310680ad548dSVincenzo Maffione base_nmd.req.nr_flags &= ~NR_REG_MASK; 310780ad548dSVincenzo Maffione base_nmd.req.nr_flags |= NR_REG_ONE_NIC; 310880ad548dSVincenzo Maffione base_nmd.req.nr_ringid = 0; 310980ad548dSVincenzo Maffione } 311080ad548dSVincenzo Maffione g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd); 311137e3a6d3SLuigi Rizzo if (g.nmd == NULL) { 311237e3a6d3SLuigi Rizzo D("Unable to open %s: %s", g.ifname, strerror(errno)); 311337e3a6d3SLuigi Rizzo goto out; 311437e3a6d3SLuigi Rizzo } 3115f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 311680ad548dSVincenzo Maffione D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10), 311780ad548dSVincenzo Maffione g.nmd->mem); 3118f0ea3689SLuigi Rizzo 311937e3a6d3SLuigi Rizzo if (g.virt_header) { 312037e3a6d3SLuigi Rizzo /* Set the virtio-net header length, since the user asked 312137e3a6d3SLuigi Rizzo * for it explicitely. */ 312237e3a6d3SLuigi Rizzo set_vnet_hdr_len(&g); 312337e3a6d3SLuigi Rizzo } else { 312437e3a6d3SLuigi Rizzo /* Check whether the netmap port we opened requires us to send 312537e3a6d3SLuigi Rizzo * and receive frames with virtio-net header. */ 312637e3a6d3SLuigi Rizzo get_vnet_hdr_len(&g); 312737e3a6d3SLuigi Rizzo } 312837e3a6d3SLuigi Rizzo 31294bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 313037e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 31314bf50f18SLuigi Rizzo devqueues = g.nmd->req.nr_tx_rings; 31324bf50f18SLuigi Rizzo else 3133f0ea3689SLuigi Rizzo devqueues = g.nmd->req.nr_rx_rings; 313468b8534bSLuigi Rizzo 313568b8534bSLuigi Rizzo /* validate provided nthreads. */ 313668b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 313768b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 313868b8534bSLuigi Rizzo // continue, fail later 313968b8534bSLuigi Rizzo } 314068b8534bSLuigi Rizzo 31419e53f3bdSVincenzo Maffione if (g.td_type == TD_TYPE_SENDER) { 31429e53f3bdSVincenzo Maffione int mtu = get_if_mtu(&g); 31439e53f3bdSVincenzo Maffione 31449e53f3bdSVincenzo Maffione if (mtu > 0 && g.pkt_size > mtu) { 31459e53f3bdSVincenzo Maffione D("pkt_size (%d) must be <= mtu (%d)", 31469e53f3bdSVincenzo Maffione g.pkt_size, mtu); 31479e53f3bdSVincenzo Maffione return -1; 31489e53f3bdSVincenzo Maffione } 31499e53f3bdSVincenzo Maffione } 31509e53f3bdSVincenzo Maffione 3151f2637526SLuigi Rizzo if (verbose) { 3152f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 3153f0ea3689SLuigi Rizzo struct nmreq *req = &g.nmd->req; 315468b8534bSLuigi Rizzo 3155f0ea3689SLuigi Rizzo D("nifp at offset %d, %d tx %d rx region %d", 3156f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 3157f0ea3689SLuigi Rizzo req->nr_arg2); 3158f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_tx_rings; i++) { 31594bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 316037e3a6d3SLuigi Rizzo D(" TX%d at 0x%p slots %d", i, 316137e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3162f2637526SLuigi Rizzo } 3163f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_rx_rings; i++) { 31644bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 316537e3a6d3SLuigi Rizzo D(" RX%d at 0x%p slots %d", i, 316637e3a6d3SLuigi Rizzo (void *)((char *)ring - (char *)nifp), ring->num_slots); 3167f2637526SLuigi Rizzo } 3168f2637526SLuigi Rizzo } 316968b8534bSLuigi Rizzo 317068b8534bSLuigi Rizzo /* Print some debug information. */ 317168b8534bSLuigi Rizzo fprintf(stdout, 317268b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 317337e3a6d3SLuigi Rizzo (g.td_type == TD_TYPE_SENDER) ? "Sending on" : 317437e3a6d3SLuigi Rizzo ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : 317537e3a6d3SLuigi Rizzo "Working on"), 3176f8e4e36aSLuigi Rizzo g.ifname, 317768b8534bSLuigi Rizzo devqueues, 317868b8534bSLuigi Rizzo g.nthreads, 317968b8534bSLuigi Rizzo g.cpus); 318037e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) { 318168b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 3182f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 3183f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 318468b8534bSLuigi Rizzo } 318568b8534bSLuigi Rizzo 3186f0ea3689SLuigi Rizzo out: 318768b8534bSLuigi Rizzo /* Exit if something went wrong. */ 3188f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 318968b8534bSLuigi Rizzo D("aborting"); 319080ad548dSVincenzo Maffione usage(-1); 319168b8534bSLuigi Rizzo } 319299fb123fSLuigi Rizzo } 319368b8534bSLuigi Rizzo 3194ce3ee1e7SLuigi Rizzo 319599fb123fSLuigi Rizzo if (g.options) { 319637e3a6d3SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", 319799fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 319899fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 319999fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 3200b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 320137e3a6d3SLuigi Rizzo g.options & OPT_COPY ? " copy" : "", 320237e3a6d3SLuigi Rizzo g.options & OPT_RUBBISH ? " rubbish " : ""); 320399fb123fSLuigi Rizzo } 32041cb4c501SLuigi Rizzo 3205ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 3206ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 3207ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 320817885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 3209ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 3210ce3ee1e7SLuigi Rizzo */ 321117885a7bSLuigi Rizzo uint64_t x; 321217885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 321317885a7bSLuigi Rizzo if (g.burst > lim) 321417885a7bSLuigi Rizzo g.burst = lim; 321580ad548dSVincenzo Maffione if (g.burst == 0) 321680ad548dSVincenzo Maffione g.burst = 1; 321717885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 321817885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 32191cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 32201cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 32211cb4c501SLuigi Rizzo } 322237e3a6d3SLuigi Rizzo if (g.td_type == TD_TYPE_SENDER) 3223ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 3224ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 322568b8534bSLuigi Rizzo /* Install ^C handler. */ 322668b8534bSLuigi Rizzo global_nthreads = g.nthreads; 322737e3a6d3SLuigi Rizzo sigemptyset(&ss); 322837e3a6d3SLuigi Rizzo sigaddset(&ss, SIGINT); 322937e3a6d3SLuigi Rizzo /* block SIGINT now, so that all created threads will inherit the mask */ 323037e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { 323137e3a6d3SLuigi Rizzo D("failed to block SIGINT: %s", strerror(errno)); 323237e3a6d3SLuigi Rizzo } 3233f8e4e36aSLuigi Rizzo start_threads(&g); 323437e3a6d3SLuigi Rizzo /* Install the handler and re-enable SIGINT for the main thread */ 323580ad548dSVincenzo Maffione memset(&sa, 0, sizeof(sa)); 323637e3a6d3SLuigi Rizzo sa.sa_handler = sigint_h; 323737e3a6d3SLuigi Rizzo if (sigaction(SIGINT, &sa, NULL) < 0) { 323837e3a6d3SLuigi Rizzo D("failed to install ^C handler: %s", strerror(errno)); 323937e3a6d3SLuigi Rizzo } 324037e3a6d3SLuigi Rizzo 324137e3a6d3SLuigi Rizzo if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { 324237e3a6d3SLuigi Rizzo D("failed to re-enable SIGINT: %s", strerror(errno)); 324337e3a6d3SLuigi Rizzo } 3244f8e4e36aSLuigi Rizzo main_thread(&g); 324537e3a6d3SLuigi Rizzo free(targs); 3246f8e4e36aSLuigi Rizzo return 0; 324768b8534bSLuigi Rizzo } 324868b8534bSLuigi Rizzo 324968b8534bSLuigi Rizzo /* end of file */ 3250