168b8534bSLuigi Rizzo /* 217885a7bSLuigi Rizzo * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. 317885a7bSLuigi Rizzo * Copyright (C) 2013-2014 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 404bf50f18SLuigi Rizzo // #define TRASH_VHOST_HDR 414bf50f18SLuigi Rizzo 42f0ea3689SLuigi Rizzo #define _GNU_SOURCE /* for CPU_SET() */ 43f0ea3689SLuigi Rizzo #include <stdio.h> 44f0ea3689SLuigi Rizzo #define NETMAP_WITH_LIBS 45f0ea3689SLuigi Rizzo #include <net/netmap_user.h> 46f0ea3689SLuigi Rizzo 47f8e4e36aSLuigi Rizzo 48b303f675SLuigi Rizzo #include <ctype.h> // isprint() 49f0ea3689SLuigi Rizzo #include <unistd.h> // sysconf() 50f0ea3689SLuigi Rizzo #include <sys/poll.h> 51f0ea3689SLuigi Rizzo #include <arpa/inet.h> /* ntohs */ 52f0ea3689SLuigi Rizzo #include <sys/sysctl.h> /* sysctl */ 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> 58f0ea3689SLuigi Rizzo 59f0ea3689SLuigi Rizzo #include <pthread.h> 60b303f675SLuigi Rizzo 61f2637526SLuigi Rizzo #ifndef NO_PCAP 62f2637526SLuigi Rizzo #include <pcap/pcap.h> 63f2637526SLuigi Rizzo #endif 64f0ea3689SLuigi Rizzo 65f0ea3689SLuigi Rizzo #ifdef linux 66f0ea3689SLuigi Rizzo 67f0ea3689SLuigi Rizzo #define cpuset_t cpu_set_t 68f0ea3689SLuigi Rizzo 69f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags /* only the low 16 bits here */ 70f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ 71f0ea3689SLuigi Rizzo #include <linux/ethtool.h> 72f0ea3689SLuigi Rizzo #include <linux/sockios.h> 73f0ea3689SLuigi Rizzo 74f0ea3689SLuigi Rizzo #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 75f0ea3689SLuigi Rizzo #include <netinet/ether.h> /* ether_aton */ 76f0ea3689SLuigi Rizzo #include <linux/if_packet.h> /* sockaddr_ll */ 77f0ea3689SLuigi Rizzo #endif /* linux */ 78f0ea3689SLuigi Rizzo 79f0ea3689SLuigi Rizzo #ifdef __FreeBSD__ 80f0ea3689SLuigi Rizzo #include <sys/endian.h> /* le64toh */ 81f0ea3689SLuigi Rizzo #include <machine/param.h> 82f0ea3689SLuigi Rizzo 83f0ea3689SLuigi Rizzo #include <pthread_np.h> /* pthread w/ affinity */ 84f0ea3689SLuigi Rizzo #include <sys/cpuset.h> /* cpu_set */ 85f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 86f0ea3689SLuigi Rizzo #endif /* __FreeBSD__ */ 87f0ea3689SLuigi Rizzo 88f0ea3689SLuigi Rizzo #ifdef __APPLE__ 89f0ea3689SLuigi Rizzo 90f0ea3689SLuigi Rizzo #define cpuset_t uint64_t // XXX 91f0ea3689SLuigi Rizzo static inline void CPU_ZERO(cpuset_t *p) 92f0ea3689SLuigi Rizzo { 93f0ea3689SLuigi Rizzo *p = 0; 94f0ea3689SLuigi Rizzo } 95f0ea3689SLuigi Rizzo 96f0ea3689SLuigi Rizzo static inline void CPU_SET(uint32_t i, cpuset_t *p) 97f0ea3689SLuigi Rizzo { 98f0ea3689SLuigi Rizzo *p |= 1<< (i & 0x3f); 99f0ea3689SLuigi Rizzo } 100f0ea3689SLuigi Rizzo 101f0ea3689SLuigi Rizzo #define pthread_setaffinity_np(a, b, c) ((void)a, 0) 102f0ea3689SLuigi Rizzo 103f0ea3689SLuigi Rizzo #define ifr_flagshigh ifr_flags // XXX 104f0ea3689SLuigi Rizzo #define IFF_PPROMISC IFF_PROMISC 105f0ea3689SLuigi Rizzo #include <net/if_dl.h> /* LLADDR */ 106f0ea3689SLuigi Rizzo #define clock_gettime(a,b) \ 107f0ea3689SLuigi Rizzo do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) 108f0ea3689SLuigi Rizzo #endif /* __APPLE__ */ 109f0ea3689SLuigi Rizzo 110ce3ee1e7SLuigi Rizzo const char *default_payload="netmap pkt-gen DIRECT payload\n" 111ce3ee1e7SLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 112ce3ee1e7SLuigi Rizzo 113ce3ee1e7SLuigi Rizzo const char *indirect_payload="netmap pkt-gen indirect payload\n" 11468b8534bSLuigi Rizzo "http://info.iet.unipi.it/~luigi/netmap/ "; 11568b8534bSLuigi Rizzo 11668b8534bSLuigi Rizzo int verbose = 0; 11768b8534bSLuigi Rizzo 118f0ea3689SLuigi Rizzo #define SKIP_PAYLOAD 1 /* do not check payload. XXX unused */ 11968b8534bSLuigi Rizzo 12017885a7bSLuigi Rizzo 12117885a7bSLuigi Rizzo #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ 12217885a7bSLuigi Rizzo #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ 12317885a7bSLuigi Rizzo #define VIRT_HDR_MAX VIRT_HDR_2 12417885a7bSLuigi Rizzo struct virt_header { 12517885a7bSLuigi Rizzo uint8_t fields[VIRT_HDR_MAX]; 12617885a7bSLuigi Rizzo }; 12717885a7bSLuigi Rizzo 1284bf50f18SLuigi Rizzo #define MAX_BODYSIZE 16384 1294bf50f18SLuigi Rizzo 13068b8534bSLuigi Rizzo struct pkt { 13117885a7bSLuigi Rizzo struct virt_header vh; 13268b8534bSLuigi Rizzo struct ether_header eh; 13368b8534bSLuigi Rizzo struct ip ip; 13468b8534bSLuigi Rizzo struct udphdr udp; 1354bf50f18SLuigi Rizzo uint8_t body[MAX_BODYSIZE]; // XXX hardwired 13668b8534bSLuigi Rizzo } __attribute__((__packed__)); 13768b8534bSLuigi Rizzo 138f8e4e36aSLuigi Rizzo struct ip_range { 139f8e4e36aSLuigi Rizzo char *name; 140ce3ee1e7SLuigi Rizzo uint32_t start, end; /* same as struct in_addr */ 141ce3ee1e7SLuigi Rizzo uint16_t port0, port1; 142f8e4e36aSLuigi Rizzo }; 143f8e4e36aSLuigi Rizzo 144f8e4e36aSLuigi Rizzo struct mac_range { 145f8e4e36aSLuigi Rizzo char *name; 146f8e4e36aSLuigi Rizzo struct ether_addr start, end; 147f8e4e36aSLuigi Rizzo }; 148f8e4e36aSLuigi Rizzo 149f0ea3689SLuigi Rizzo /* ifname can be netmap:foo-xxxx */ 150f0ea3689SLuigi Rizzo #define MAX_IFNAMELEN 64 /* our buffer for ifname */ 1514bf50f18SLuigi Rizzo //#define MAX_PKTSIZE 1536 1524bf50f18SLuigi Rizzo #define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ 1534bf50f18SLuigi Rizzo 1544bf50f18SLuigi Rizzo /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ 1554bf50f18SLuigi Rizzo struct tstamp { 1564bf50f18SLuigi Rizzo uint32_t sec; 1574bf50f18SLuigi Rizzo uint32_t nsec; 1584bf50f18SLuigi Rizzo }; 1594bf50f18SLuigi Rizzo 16068b8534bSLuigi Rizzo /* 16168b8534bSLuigi Rizzo * global arguments for all threads 16268b8534bSLuigi Rizzo */ 163f8e4e36aSLuigi Rizzo 16468b8534bSLuigi Rizzo struct glob_arg { 165f8e4e36aSLuigi Rizzo struct ip_range src_ip; 166f8e4e36aSLuigi Rizzo struct ip_range dst_ip; 167f8e4e36aSLuigi Rizzo struct mac_range dst_mac; 168f8e4e36aSLuigi Rizzo struct mac_range src_mac; 16968b8534bSLuigi Rizzo int pkt_size; 17068b8534bSLuigi Rizzo int burst; 171f8e4e36aSLuigi Rizzo int forever; 17268b8534bSLuigi Rizzo int npackets; /* total packets to send */ 173ce3ee1e7SLuigi Rizzo int frags; /* fragments per packet */ 17468b8534bSLuigi Rizzo int nthreads; 17568b8534bSLuigi Rizzo int cpus; 17699fb123fSLuigi Rizzo int options; /* testing */ 17799fb123fSLuigi Rizzo #define OPT_PREFETCH 1 17899fb123fSLuigi Rizzo #define OPT_ACCESS 2 17999fb123fSLuigi Rizzo #define OPT_COPY 4 18099fb123fSLuigi Rizzo #define OPT_MEMCPY 8 181f8e4e36aSLuigi Rizzo #define OPT_TS 16 /* add a timestamp */ 182b303f675SLuigi Rizzo #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ 183b303f675SLuigi Rizzo #define OPT_DUMP 64 /* dump rx/tx traffic */ 1844bf50f18SLuigi Rizzo #define OPT_MONITOR_TX 128 1854bf50f18SLuigi Rizzo #define OPT_MONITOR_RX 256 186f8e4e36aSLuigi Rizzo int dev_type; 187f2637526SLuigi Rizzo #ifndef NO_PCAP 18868b8534bSLuigi Rizzo pcap_t *p; 189f2637526SLuigi Rizzo #endif 19068b8534bSLuigi Rizzo 1911cb4c501SLuigi Rizzo int tx_rate; 1921cb4c501SLuigi Rizzo struct timespec tx_period; 1931cb4c501SLuigi Rizzo 194f8e4e36aSLuigi Rizzo int affinity; 195f8e4e36aSLuigi Rizzo int main_fd; 196f0ea3689SLuigi Rizzo struct nm_desc *nmd; 197f2637526SLuigi Rizzo int report_interval; /* milliseconds between prints */ 198f8e4e36aSLuigi Rizzo void *(*td_body)(void *); 199f8e4e36aSLuigi Rizzo void *mmap_addr; 200f0ea3689SLuigi Rizzo char ifname[MAX_IFNAMELEN]; 201ce3ee1e7SLuigi Rizzo char *nmr_config; 202ce3ee1e7SLuigi Rizzo int dummy_send; 20317885a7bSLuigi Rizzo int virt_header; /* send also the virt_header */ 204f0ea3689SLuigi Rizzo int extra_bufs; /* goes in nr_arg3 */ 205f284c737SGeorge V. Neville-Neil char *packet_file; /* -P option */ 20668b8534bSLuigi Rizzo }; 207f8e4e36aSLuigi Rizzo enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; 208f8e4e36aSLuigi Rizzo 20968b8534bSLuigi Rizzo 21068b8534bSLuigi Rizzo /* 21168b8534bSLuigi Rizzo * Arguments for a new thread. The same structure is used by 21268b8534bSLuigi Rizzo * the source and the sink 21368b8534bSLuigi Rizzo */ 21468b8534bSLuigi Rizzo struct targ { 21568b8534bSLuigi Rizzo struct glob_arg *g; 21668b8534bSLuigi Rizzo int used; 21768b8534bSLuigi Rizzo int completed; 2183fe77e68SEd Maste int cancel; 21968b8534bSLuigi Rizzo int fd; 220f0ea3689SLuigi Rizzo struct nm_desc *nmd; 221f8e4e36aSLuigi Rizzo volatile uint64_t count; 2221cb4c501SLuigi Rizzo struct timespec tic, toc; 22368b8534bSLuigi Rizzo int me; 22468b8534bSLuigi Rizzo pthread_t thread; 22568b8534bSLuigi Rizzo int affinity; 22668b8534bSLuigi Rizzo 22768b8534bSLuigi Rizzo struct pkt pkt; 228f284c737SGeorge V. Neville-Neil void *frame; 22968b8534bSLuigi Rizzo }; 23068b8534bSLuigi Rizzo 23168b8534bSLuigi Rizzo 232f8e4e36aSLuigi Rizzo /* 233f8e4e36aSLuigi Rizzo * extract the extremes from a range of ipv4 addresses. 234f8e4e36aSLuigi Rizzo * addr_lo[-addr_hi][:port_lo[-port_hi]] 235f8e4e36aSLuigi Rizzo */ 236f8e4e36aSLuigi Rizzo static void 237f8e4e36aSLuigi Rizzo extract_ip_range(struct ip_range *r) 238f8e4e36aSLuigi Rizzo { 239ce3ee1e7SLuigi Rizzo char *ap, *pp; 240ce3ee1e7SLuigi Rizzo struct in_addr a; 241f8e4e36aSLuigi Rizzo 24217885a7bSLuigi Rizzo if (verbose) 243f8e4e36aSLuigi Rizzo D("extract IP range from %s", r->name); 244ce3ee1e7SLuigi Rizzo r->port0 = r->port1 = 0; 245ce3ee1e7SLuigi Rizzo r->start = r->end = 0; 246ce3ee1e7SLuigi Rizzo 247ce3ee1e7SLuigi Rizzo /* the first - splits start/end of range */ 248ce3ee1e7SLuigi Rizzo ap = index(r->name, '-'); /* do we have ports ? */ 249ce3ee1e7SLuigi Rizzo if (ap) { 250ce3ee1e7SLuigi Rizzo *ap++ = '\0'; 251ce3ee1e7SLuigi Rizzo } 252ce3ee1e7SLuigi Rizzo /* grab the initial values (mandatory) */ 253ce3ee1e7SLuigi Rizzo pp = index(r->name, ':'); 254ce3ee1e7SLuigi Rizzo if (pp) { 255ce3ee1e7SLuigi Rizzo *pp++ = '\0'; 256ce3ee1e7SLuigi Rizzo r->port0 = r->port1 = strtol(pp, NULL, 0); 257ce3ee1e7SLuigi Rizzo }; 258ce3ee1e7SLuigi Rizzo inet_aton(r->name, &a); 259ce3ee1e7SLuigi Rizzo r->start = r->end = ntohl(a.s_addr); 260ce3ee1e7SLuigi Rizzo if (ap) { 261ce3ee1e7SLuigi Rizzo pp = index(ap, ':'); 262ce3ee1e7SLuigi Rizzo if (pp) { 263ce3ee1e7SLuigi Rizzo *pp++ = '\0'; 264ce3ee1e7SLuigi Rizzo if (*pp) 265ce3ee1e7SLuigi Rizzo r->port1 = strtol(pp, NULL, 0); 266ce3ee1e7SLuigi Rizzo } 267ce3ee1e7SLuigi Rizzo if (*ap) { 268ce3ee1e7SLuigi Rizzo inet_aton(ap, &a); 269ce3ee1e7SLuigi Rizzo r->end = ntohl(a.s_addr); 270ce3ee1e7SLuigi Rizzo } 271ce3ee1e7SLuigi Rizzo } 272ce3ee1e7SLuigi Rizzo if (r->port0 > r->port1) { 273ce3ee1e7SLuigi Rizzo uint16_t tmp = r->port0; 274f8e4e36aSLuigi Rizzo r->port0 = r->port1; 275ce3ee1e7SLuigi Rizzo r->port1 = tmp; 276f8e4e36aSLuigi Rizzo } 277ce3ee1e7SLuigi Rizzo if (r->start > r->end) { 278ce3ee1e7SLuigi Rizzo uint32_t tmp = r->start; 279f8e4e36aSLuigi Rizzo r->start = r->end; 280ce3ee1e7SLuigi Rizzo r->end = tmp; 281f8e4e36aSLuigi Rizzo } 282ce3ee1e7SLuigi Rizzo { 283ce3ee1e7SLuigi Rizzo struct in_addr a; 284ce3ee1e7SLuigi Rizzo char buf1[16]; // one ip address 285ce3ee1e7SLuigi Rizzo 286ce3ee1e7SLuigi Rizzo a.s_addr = htonl(r->end); 287ce3ee1e7SLuigi Rizzo strncpy(buf1, inet_ntoa(a), sizeof(buf1)); 288ce3ee1e7SLuigi Rizzo a.s_addr = htonl(r->start); 28917885a7bSLuigi Rizzo if (1) 290ce3ee1e7SLuigi Rizzo D("range is %s:%d to %s:%d", 291ce3ee1e7SLuigi Rizzo inet_ntoa(a), r->port0, buf1, r->port1); 292ce3ee1e7SLuigi Rizzo } 293f8e4e36aSLuigi Rizzo } 294f8e4e36aSLuigi Rizzo 295f8e4e36aSLuigi Rizzo static void 296f8e4e36aSLuigi Rizzo extract_mac_range(struct mac_range *r) 297f8e4e36aSLuigi Rizzo { 29817885a7bSLuigi Rizzo if (verbose) 299f8e4e36aSLuigi Rizzo D("extract MAC range from %s", r->name); 300f8e4e36aSLuigi Rizzo bcopy(ether_aton(r->name), &r->start, 6); 301f8e4e36aSLuigi Rizzo bcopy(ether_aton(r->name), &r->end, 6); 302f8e4e36aSLuigi Rizzo #if 0 303f8e4e36aSLuigi Rizzo bcopy(targ->src_mac, eh->ether_shost, 6); 304f8e4e36aSLuigi Rizzo p = index(targ->g->src_mac, '-'); 305f8e4e36aSLuigi Rizzo if (p) 306f8e4e36aSLuigi Rizzo targ->src_mac_range = atoi(p+1); 307f8e4e36aSLuigi Rizzo 308f8e4e36aSLuigi Rizzo bcopy(ether_aton(targ->g->dst_mac), targ->dst_mac, 6); 309f8e4e36aSLuigi Rizzo bcopy(targ->dst_mac, eh->ether_dhost, 6); 310f8e4e36aSLuigi Rizzo p = index(targ->g->dst_mac, '-'); 311f8e4e36aSLuigi Rizzo if (p) 312f8e4e36aSLuigi Rizzo targ->dst_mac_range = atoi(p+1); 313f8e4e36aSLuigi Rizzo #endif 31417885a7bSLuigi Rizzo if (verbose) 315f8e4e36aSLuigi Rizzo D("%s starts at %s", r->name, ether_ntoa(&r->start)); 316f8e4e36aSLuigi Rizzo } 317f8e4e36aSLuigi Rizzo 31868b8534bSLuigi Rizzo static struct targ *targs; 31968b8534bSLuigi Rizzo static int global_nthreads; 32068b8534bSLuigi Rizzo 32168b8534bSLuigi Rizzo /* control-C handler */ 32268b8534bSLuigi Rizzo static void 323f8e4e36aSLuigi Rizzo sigint_h(int sig) 32468b8534bSLuigi Rizzo { 325f8e4e36aSLuigi Rizzo int i; 32668b8534bSLuigi Rizzo 327f8e4e36aSLuigi Rizzo (void)sig; /* UNUSED */ 3284bf50f18SLuigi Rizzo D("received control-C on thread %p", pthread_self()); 329f8e4e36aSLuigi Rizzo for (i = 0; i < global_nthreads; i++) { 330f8e4e36aSLuigi Rizzo targs[i].cancel = 1; 331f8e4e36aSLuigi Rizzo } 33268b8534bSLuigi Rizzo signal(SIGINT, SIG_DFL); 33368b8534bSLuigi Rizzo } 33468b8534bSLuigi Rizzo 33568b8534bSLuigi Rizzo /* sysctl wrapper to return the number of active CPUs */ 33668b8534bSLuigi Rizzo static int 33768b8534bSLuigi Rizzo system_ncpus(void) 33868b8534bSLuigi Rizzo { 339f0ea3689SLuigi Rizzo int ncpus; 340f0ea3689SLuigi Rizzo #if defined (__FreeBSD__) 341f0ea3689SLuigi Rizzo int mib[2] = { CTL_HW, HW_NCPU }; 342f0ea3689SLuigi Rizzo size_t len = sizeof(mib); 34368b8534bSLuigi Rizzo sysctl(mib, 2, &ncpus, &len, NULL, 0); 344f0ea3689SLuigi Rizzo #elif defined(linux) 345f0ea3689SLuigi Rizzo ncpus = sysconf(_SC_NPROCESSORS_ONLN); 346f0ea3689SLuigi Rizzo #else /* others */ 347f0ea3689SLuigi Rizzo ncpus = 1; 348f0ea3689SLuigi Rizzo #endif /* others */ 34968b8534bSLuigi Rizzo return (ncpus); 35068b8534bSLuigi Rizzo } 35168b8534bSLuigi Rizzo 352f8e4e36aSLuigi Rizzo #ifdef __linux__ 353f8e4e36aSLuigi Rizzo #define sockaddr_dl sockaddr_ll 354f8e4e36aSLuigi Rizzo #define sdl_family sll_family 355f8e4e36aSLuigi Rizzo #define AF_LINK AF_PACKET 356f8e4e36aSLuigi Rizzo #define LLADDR(s) s->sll_addr; 357f8e4e36aSLuigi Rizzo #include <linux/if_tun.h> 358f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/net/tun" 359f8e4e36aSLuigi Rizzo #endif /* __linux__ */ 360f8e4e36aSLuigi Rizzo 361f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 362f8e4e36aSLuigi Rizzo #include <net/if_tun.h> 363f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 364f8e4e36aSLuigi Rizzo #endif /* __FreeBSD */ 365f8e4e36aSLuigi Rizzo 366f8e4e36aSLuigi Rizzo #ifdef __APPLE__ 367f8e4e36aSLuigi Rizzo // #warning TAP not supported on apple ? 368f8e4e36aSLuigi Rizzo #include <net/if_utun.h> 369f8e4e36aSLuigi Rizzo #define TAP_CLONEDEV "/dev/tap" 370f8e4e36aSLuigi Rizzo #endif /* __APPLE__ */ 371f8e4e36aSLuigi Rizzo 372f8e4e36aSLuigi Rizzo 37368b8534bSLuigi Rizzo /* 374ce3ee1e7SLuigi Rizzo * parse the vale configuration in conf and put it in nmr. 375f0ea3689SLuigi Rizzo * Return the flag set if necessary. 376ce3ee1e7SLuigi Rizzo * The configuration may consist of 0 to 4 numbers separated 377fc6eb28bSHiren Panchasara * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. 378ce3ee1e7SLuigi Rizzo * Missing numbers or zeroes stand for default values. 379ce3ee1e7SLuigi Rizzo * As an additional convenience, if exactly one number 380fc6eb28bSHiren Panchasara * is specified, then this is assigned to both #tx-slots and #rx-slots. 381fc6eb28bSHiren Panchasara * If there is no 4th number, then the 3rd is assigned to both #tx-rings 382ce3ee1e7SLuigi Rizzo * and #rx-rings. 383ce3ee1e7SLuigi Rizzo */ 384f0ea3689SLuigi Rizzo int 385f0ea3689SLuigi Rizzo parse_nmr_config(const char* conf, struct nmreq *nmr) 386ce3ee1e7SLuigi Rizzo { 387ce3ee1e7SLuigi Rizzo char *w, *tok; 388ce3ee1e7SLuigi Rizzo int i, v; 389ce3ee1e7SLuigi Rizzo 390ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 391ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 392ce3ee1e7SLuigi Rizzo if (conf == NULL || ! *conf) 393f0ea3689SLuigi Rizzo return 0; 394ce3ee1e7SLuigi Rizzo w = strdup(conf); 395ce3ee1e7SLuigi Rizzo for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 396ce3ee1e7SLuigi Rizzo v = atoi(tok); 397ce3ee1e7SLuigi Rizzo switch (i) { 398ce3ee1e7SLuigi Rizzo case 0: 399ce3ee1e7SLuigi Rizzo nmr->nr_tx_slots = nmr->nr_rx_slots = v; 400ce3ee1e7SLuigi Rizzo break; 401ce3ee1e7SLuigi Rizzo case 1: 402ce3ee1e7SLuigi Rizzo nmr->nr_rx_slots = v; 403ce3ee1e7SLuigi Rizzo break; 404ce3ee1e7SLuigi Rizzo case 2: 405ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings = nmr->nr_rx_rings = v; 406ce3ee1e7SLuigi Rizzo break; 407ce3ee1e7SLuigi Rizzo case 3: 408ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings = v; 409ce3ee1e7SLuigi Rizzo break; 410ce3ee1e7SLuigi Rizzo default: 411ce3ee1e7SLuigi Rizzo D("ignored config: %s", tok); 412ce3ee1e7SLuigi Rizzo break; 413ce3ee1e7SLuigi Rizzo } 414ce3ee1e7SLuigi Rizzo } 415ce3ee1e7SLuigi Rizzo D("txr %d txd %d rxr %d rxd %d", 416ce3ee1e7SLuigi Rizzo nmr->nr_tx_rings, nmr->nr_tx_slots, 417ce3ee1e7SLuigi Rizzo nmr->nr_rx_rings, nmr->nr_rx_slots); 418ce3ee1e7SLuigi Rizzo free(w); 419f0ea3689SLuigi Rizzo return (nmr->nr_tx_rings || nmr->nr_tx_slots || 420f0ea3689SLuigi Rizzo nmr->nr_rx_rings || nmr->nr_rx_slots) ? 421f0ea3689SLuigi Rizzo NM_OPEN_RING_CFG : 0; 422ce3ee1e7SLuigi Rizzo } 423ce3ee1e7SLuigi Rizzo 424ce3ee1e7SLuigi Rizzo 425ce3ee1e7SLuigi Rizzo /* 42668b8534bSLuigi Rizzo * locate the src mac address for our interface, put it 42768b8534bSLuigi Rizzo * into the user-supplied buffer. return 0 if ok, -1 on error. 42868b8534bSLuigi Rizzo */ 42968b8534bSLuigi Rizzo static int 43068b8534bSLuigi Rizzo source_hwaddr(const char *ifname, char *buf) 43168b8534bSLuigi Rizzo { 43268b8534bSLuigi Rizzo struct ifaddrs *ifaphead, *ifap; 43368b8534bSLuigi Rizzo int l = sizeof(ifap->ifa_name); 43468b8534bSLuigi Rizzo 43568b8534bSLuigi Rizzo if (getifaddrs(&ifaphead) != 0) { 43668b8534bSLuigi Rizzo D("getifaddrs %s failed", ifname); 43768b8534bSLuigi Rizzo return (-1); 43868b8534bSLuigi Rizzo } 43968b8534bSLuigi Rizzo 44068b8534bSLuigi Rizzo for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { 44168b8534bSLuigi Rizzo struct sockaddr_dl *sdl = 44268b8534bSLuigi Rizzo (struct sockaddr_dl *)ifap->ifa_addr; 44368b8534bSLuigi Rizzo uint8_t *mac; 44468b8534bSLuigi Rizzo 44568b8534bSLuigi Rizzo if (!sdl || sdl->sdl_family != AF_LINK) 44668b8534bSLuigi Rizzo continue; 44768b8534bSLuigi Rizzo if (strncmp(ifap->ifa_name, ifname, l) != 0) 44868b8534bSLuigi Rizzo continue; 44968b8534bSLuigi Rizzo mac = (uint8_t *)LLADDR(sdl); 45068b8534bSLuigi Rizzo sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 45168b8534bSLuigi Rizzo mac[0], mac[1], mac[2], 45268b8534bSLuigi Rizzo mac[3], mac[4], mac[5]); 45368b8534bSLuigi Rizzo if (verbose) 45468b8534bSLuigi Rizzo D("source hwaddr %s", buf); 45568b8534bSLuigi Rizzo break; 45668b8534bSLuigi Rizzo } 45768b8534bSLuigi Rizzo freeifaddrs(ifaphead); 45868b8534bSLuigi Rizzo return ifap ? 0 : 1; 45968b8534bSLuigi Rizzo } 46068b8534bSLuigi Rizzo 46168b8534bSLuigi Rizzo 46268b8534bSLuigi Rizzo /* set the thread affinity. */ 46368b8534bSLuigi Rizzo static int 46468b8534bSLuigi Rizzo setaffinity(pthread_t me, int i) 46568b8534bSLuigi Rizzo { 46668b8534bSLuigi Rizzo cpuset_t cpumask; 46768b8534bSLuigi Rizzo 46868b8534bSLuigi Rizzo if (i == -1) 46968b8534bSLuigi Rizzo return 0; 47068b8534bSLuigi Rizzo 47168b8534bSLuigi Rizzo /* Set thread affinity affinity.*/ 47268b8534bSLuigi Rizzo CPU_ZERO(&cpumask); 47368b8534bSLuigi Rizzo CPU_SET(i, &cpumask); 47468b8534bSLuigi Rizzo 47568b8534bSLuigi Rizzo if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { 47617885a7bSLuigi Rizzo D("Unable to set affinity: %s", strerror(errno)); 47768b8534bSLuigi Rizzo return 1; 47868b8534bSLuigi Rizzo } 47968b8534bSLuigi Rizzo return 0; 48068b8534bSLuigi Rizzo } 48168b8534bSLuigi Rizzo 48268b8534bSLuigi Rizzo /* Compute the checksum of the given ip header. */ 48368b8534bSLuigi Rizzo static uint16_t 484f8e4e36aSLuigi Rizzo checksum(const void *data, uint16_t len, uint32_t sum) 48568b8534bSLuigi Rizzo { 48668b8534bSLuigi Rizzo const uint8_t *addr = data; 487f8e4e36aSLuigi Rizzo uint32_t i; 48868b8534bSLuigi Rizzo 489f8e4e36aSLuigi Rizzo /* Checksum all the pairs of bytes first... */ 490f8e4e36aSLuigi Rizzo for (i = 0; i < (len & ~1U); i += 2) { 491f8e4e36aSLuigi Rizzo sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); 492f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 493f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 494f8e4e36aSLuigi Rizzo } 495f8e4e36aSLuigi Rizzo /* 496f8e4e36aSLuigi Rizzo * If there's a single byte left over, checksum it, too. 497f8e4e36aSLuigi Rizzo * Network byte order is big-endian, so the remaining byte is 498f8e4e36aSLuigi Rizzo * the high byte. 499f8e4e36aSLuigi Rizzo */ 500f8e4e36aSLuigi Rizzo if (i < len) { 501f8e4e36aSLuigi Rizzo sum += addr[i] << 8; 502f8e4e36aSLuigi Rizzo if (sum > 0xFFFF) 503f8e4e36aSLuigi Rizzo sum -= 0xFFFF; 504f8e4e36aSLuigi Rizzo } 505f8e4e36aSLuigi Rizzo return sum; 50668b8534bSLuigi Rizzo } 50768b8534bSLuigi Rizzo 508f8e4e36aSLuigi Rizzo static u_int16_t 509f8e4e36aSLuigi Rizzo wrapsum(u_int32_t sum) 510f8e4e36aSLuigi Rizzo { 511f8e4e36aSLuigi Rizzo sum = ~sum & 0xFFFF; 512f8e4e36aSLuigi Rizzo return (htons(sum)); 51368b8534bSLuigi Rizzo } 51468b8534bSLuigi Rizzo 515b303f675SLuigi Rizzo /* Check the payload of the packet for errors (use it for debug). 516b303f675SLuigi Rizzo * Look for consecutive ascii representations of the size of the packet. 517b303f675SLuigi Rizzo */ 518b303f675SLuigi Rizzo static void 519b303f675SLuigi Rizzo dump_payload(char *p, int len, struct netmap_ring *ring, int cur) 520b303f675SLuigi Rizzo { 521b303f675SLuigi Rizzo char buf[128]; 522b303f675SLuigi Rizzo int i, j, i0; 523b303f675SLuigi Rizzo 524b303f675SLuigi Rizzo /* get the length in ASCII of the length of the packet. */ 525b303f675SLuigi Rizzo 526ce3ee1e7SLuigi Rizzo printf("ring %p cur %5d [buf %6d flags 0x%04x len %5d]\n", 527ce3ee1e7SLuigi Rizzo ring, cur, ring->slot[cur].buf_idx, 528ce3ee1e7SLuigi Rizzo ring->slot[cur].flags, len); 529b303f675SLuigi Rizzo /* hexdump routine */ 530b303f675SLuigi Rizzo for (i = 0; i < len; ) { 531b303f675SLuigi Rizzo memset(buf, sizeof(buf), ' '); 532b303f675SLuigi Rizzo sprintf(buf, "%5d: ", i); 533b303f675SLuigi Rizzo i0 = i; 534b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 535b303f675SLuigi Rizzo sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i])); 536b303f675SLuigi Rizzo i = i0; 537b303f675SLuigi Rizzo for (j=0; j < 16 && i < len; i++, j++) 538b303f675SLuigi Rizzo sprintf(buf+7+j + 48, "%c", 539b303f675SLuigi Rizzo isprint(p[i]) ? p[i] : '.'); 540b303f675SLuigi Rizzo printf("%s\n", buf); 541b303f675SLuigi Rizzo } 542b303f675SLuigi Rizzo } 543b303f675SLuigi Rizzo 54468b8534bSLuigi Rizzo /* 54568b8534bSLuigi Rizzo * Fill a packet with some payload. 546f8e4e36aSLuigi Rizzo * We create a UDP packet so the payload starts at 547f8e4e36aSLuigi Rizzo * 14+20+8 = 42 bytes. 54868b8534bSLuigi Rizzo */ 549f8e4e36aSLuigi Rizzo #ifdef __linux__ 550f8e4e36aSLuigi Rizzo #define uh_sport source 551f8e4e36aSLuigi Rizzo #define uh_dport dest 552f8e4e36aSLuigi Rizzo #define uh_ulen len 553f8e4e36aSLuigi Rizzo #define uh_sum check 554f8e4e36aSLuigi Rizzo #endif /* linux */ 555b303f675SLuigi Rizzo 556ce3ee1e7SLuigi Rizzo /* 557ce3ee1e7SLuigi Rizzo * increment the addressed in the packet, 558ce3ee1e7SLuigi Rizzo * starting from the least significant field. 559ce3ee1e7SLuigi Rizzo * DST_IP DST_PORT SRC_IP SRC_PORT 560ce3ee1e7SLuigi Rizzo */ 561ce3ee1e7SLuigi Rizzo static void 562ce3ee1e7SLuigi Rizzo update_addresses(struct pkt *pkt, struct glob_arg *g) 563ce3ee1e7SLuigi Rizzo { 564ce3ee1e7SLuigi Rizzo uint32_t a; 565ce3ee1e7SLuigi Rizzo uint16_t p; 566ce3ee1e7SLuigi Rizzo struct ip *ip = &pkt->ip; 567ce3ee1e7SLuigi Rizzo struct udphdr *udp = &pkt->udp; 568ce3ee1e7SLuigi Rizzo 569f2637526SLuigi Rizzo do { 570ce3ee1e7SLuigi Rizzo p = ntohs(udp->uh_sport); 571ce3ee1e7SLuigi Rizzo if (p < g->src_ip.port1) { /* just inc, no wrap */ 572ce3ee1e7SLuigi Rizzo udp->uh_sport = htons(p + 1); 573f2637526SLuigi Rizzo break; 574ce3ee1e7SLuigi Rizzo } 575ce3ee1e7SLuigi Rizzo udp->uh_sport = htons(g->src_ip.port0); 576ce3ee1e7SLuigi Rizzo 577ce3ee1e7SLuigi Rizzo a = ntohl(ip->ip_src.s_addr); 578ce3ee1e7SLuigi Rizzo if (a < g->src_ip.end) { /* just inc, no wrap */ 579ce3ee1e7SLuigi Rizzo ip->ip_src.s_addr = htonl(a + 1); 580f2637526SLuigi Rizzo break; 581ce3ee1e7SLuigi Rizzo } 582ce3ee1e7SLuigi Rizzo ip->ip_src.s_addr = htonl(g->src_ip.start); 583ce3ee1e7SLuigi Rizzo 584ce3ee1e7SLuigi Rizzo udp->uh_sport = htons(g->src_ip.port0); 585ce3ee1e7SLuigi Rizzo p = ntohs(udp->uh_dport); 586ce3ee1e7SLuigi Rizzo if (p < g->dst_ip.port1) { /* just inc, no wrap */ 587ce3ee1e7SLuigi Rizzo udp->uh_dport = htons(p + 1); 588f2637526SLuigi Rizzo break; 589ce3ee1e7SLuigi Rizzo } 590ce3ee1e7SLuigi Rizzo udp->uh_dport = htons(g->dst_ip.port0); 591ce3ee1e7SLuigi Rizzo 592ce3ee1e7SLuigi Rizzo a = ntohl(ip->ip_dst.s_addr); 593ce3ee1e7SLuigi Rizzo if (a < g->dst_ip.end) { /* just inc, no wrap */ 594ce3ee1e7SLuigi Rizzo ip->ip_dst.s_addr = htonl(a + 1); 595f2637526SLuigi Rizzo break; 596ce3ee1e7SLuigi Rizzo } 597ce3ee1e7SLuigi Rizzo ip->ip_dst.s_addr = htonl(g->dst_ip.start); 598f2637526SLuigi Rizzo } while (0); 599f2637526SLuigi Rizzo // update checksum 600ce3ee1e7SLuigi Rizzo } 601ce3ee1e7SLuigi Rizzo 602ce3ee1e7SLuigi Rizzo /* 603ce3ee1e7SLuigi Rizzo * initialize one packet and prepare for the next one. 604ce3ee1e7SLuigi Rizzo * The copy could be done better instead of repeating it each time. 605ce3ee1e7SLuigi Rizzo */ 60668b8534bSLuigi Rizzo static void 60768b8534bSLuigi Rizzo initialize_packet(struct targ *targ) 60868b8534bSLuigi Rizzo { 60968b8534bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 61068b8534bSLuigi Rizzo struct ether_header *eh; 61168b8534bSLuigi Rizzo struct ip *ip; 61268b8534bSLuigi Rizzo struct udphdr *udp; 613f8e4e36aSLuigi Rizzo uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip); 614b303f675SLuigi Rizzo const char *payload = targ->g->options & OPT_INDIRECT ? 615ce3ee1e7SLuigi Rizzo indirect_payload : default_payload; 616f2637526SLuigi Rizzo int i, l0 = strlen(payload); 61768b8534bSLuigi Rizzo 618f284c737SGeorge V. Neville-Neil char errbuf[PCAP_ERRBUF_SIZE]; 619f284c737SGeorge V. Neville-Neil pcap_t *file; 620f284c737SGeorge V. Neville-Neil struct pcap_pkthdr *header; 621f284c737SGeorge V. Neville-Neil const unsigned char *packet; 622f284c737SGeorge V. Neville-Neil 623f284c737SGeorge V. Neville-Neil /* Read a packet from a PCAP file if asked. */ 624f284c737SGeorge V. Neville-Neil if (targ->g->packet_file != NULL) { 625f284c737SGeorge V. Neville-Neil if ((file = pcap_open_offline(targ->g->packet_file, 626f284c737SGeorge V. Neville-Neil errbuf)) == NULL) 627f284c737SGeorge V. Neville-Neil D("failed to open pcap file %s", 628f284c737SGeorge V. Neville-Neil targ->g->packet_file); 629f284c737SGeorge V. Neville-Neil if (pcap_next_ex(file, &header, &packet) < 0) 630f284c737SGeorge V. Neville-Neil D("failed to read packet from %s", 631f284c737SGeorge V. Neville-Neil targ->g->packet_file); 632f284c737SGeorge V. Neville-Neil if ((targ->frame = malloc(header->caplen)) == NULL) 633f284c737SGeorge V. Neville-Neil D("out of memory"); 634f284c737SGeorge V. Neville-Neil bcopy(packet, (unsigned char *)targ->frame, header->caplen); 635f284c737SGeorge V. Neville-Neil targ->g->pkt_size = header->caplen; 636f284c737SGeorge V. Neville-Neil pcap_close(file); 637f284c737SGeorge V. Neville-Neil return; 638f284c737SGeorge V. Neville-Neil } 639f284c737SGeorge V. Neville-Neil 640ce3ee1e7SLuigi Rizzo /* create a nice NUL-terminated string */ 641f2637526SLuigi Rizzo for (i = 0; i < paylen; i += l0) { 642f2637526SLuigi Rizzo if (l0 > paylen - i) 643f2637526SLuigi Rizzo l0 = paylen - i; // last round 644f2637526SLuigi Rizzo bcopy(payload, pkt->body + i, l0); 64568b8534bSLuigi Rizzo } 64668b8534bSLuigi Rizzo pkt->body[i-1] = '\0'; 64768b8534bSLuigi Rizzo ip = &pkt->ip; 648f8e4e36aSLuigi Rizzo 649ce3ee1e7SLuigi Rizzo /* prepare the headers */ 65068b8534bSLuigi Rizzo ip->ip_v = IPVERSION; 65168b8534bSLuigi Rizzo ip->ip_hl = 5; 65268b8534bSLuigi Rizzo ip->ip_id = 0; 65368b8534bSLuigi Rizzo ip->ip_tos = IPTOS_LOWDELAY; 65468b8534bSLuigi Rizzo ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh)); 65568b8534bSLuigi Rizzo ip->ip_id = 0; 65668b8534bSLuigi Rizzo ip->ip_off = htons(IP_DF); /* Don't fragment */ 65768b8534bSLuigi Rizzo ip->ip_ttl = IPDEFTTL; 65868b8534bSLuigi Rizzo ip->ip_p = IPPROTO_UDP; 659ce3ee1e7SLuigi Rizzo ip->ip_dst.s_addr = htonl(targ->g->dst_ip.start); 660ce3ee1e7SLuigi Rizzo ip->ip_src.s_addr = htonl(targ->g->src_ip.start); 661f8e4e36aSLuigi Rizzo ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); 662f8e4e36aSLuigi Rizzo 663f8e4e36aSLuigi Rizzo 664f8e4e36aSLuigi Rizzo udp = &pkt->udp; 665ce3ee1e7SLuigi Rizzo udp->uh_sport = htons(targ->g->src_ip.port0); 666ce3ee1e7SLuigi Rizzo udp->uh_dport = htons(targ->g->dst_ip.port0); 667f8e4e36aSLuigi Rizzo udp->uh_ulen = htons(paylen); 668f8e4e36aSLuigi Rizzo /* Magic: taken from sbin/dhclient/packet.c */ 669f8e4e36aSLuigi Rizzo udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp), 670f8e4e36aSLuigi Rizzo checksum(pkt->body, 671f8e4e36aSLuigi Rizzo paylen - sizeof(*udp), 672f8e4e36aSLuigi Rizzo checksum(&ip->ip_src, 2 * sizeof(ip->ip_src), 673f8e4e36aSLuigi Rizzo IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen) 674f8e4e36aSLuigi Rizzo ) 675f8e4e36aSLuigi Rizzo ) 676f8e4e36aSLuigi Rizzo )); 67768b8534bSLuigi Rizzo 67868b8534bSLuigi Rizzo eh = &pkt->eh; 679f8e4e36aSLuigi Rizzo bcopy(&targ->g->src_mac.start, eh->ether_shost, 6); 680f8e4e36aSLuigi Rizzo bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6); 68168b8534bSLuigi Rizzo eh->ether_type = htons(ETHERTYPE_IP); 68217885a7bSLuigi Rizzo 68317885a7bSLuigi Rizzo bzero(&pkt->vh, sizeof(pkt->vh)); 6844bf50f18SLuigi Rizzo #ifdef TRASH_VHOST_HDR 6854bf50f18SLuigi Rizzo /* set bogus content */ 6864bf50f18SLuigi Rizzo pkt->vh.fields[0] = 0xff; 6874bf50f18SLuigi Rizzo pkt->vh.fields[1] = 0xff; 6884bf50f18SLuigi Rizzo pkt->vh.fields[2] = 0xff; 6894bf50f18SLuigi Rizzo pkt->vh.fields[3] = 0xff; 6904bf50f18SLuigi Rizzo pkt->vh.fields[4] = 0xff; 6914bf50f18SLuigi Rizzo pkt->vh.fields[5] = 0xff; 6924bf50f18SLuigi Rizzo #endif /* TRASH_VHOST_HDR */ 693b303f675SLuigi Rizzo // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); 69468b8534bSLuigi Rizzo } 69568b8534bSLuigi Rizzo 6964bf50f18SLuigi Rizzo static void 6974bf50f18SLuigi Rizzo set_vnet_hdr_len(struct targ *t) 6984bf50f18SLuigi Rizzo { 6994bf50f18SLuigi Rizzo int err, l = t->g->virt_header; 7004bf50f18SLuigi Rizzo struct nmreq req; 7014bf50f18SLuigi Rizzo 7024bf50f18SLuigi Rizzo if (l == 0) 7034bf50f18SLuigi Rizzo return; 7044bf50f18SLuigi Rizzo 7054bf50f18SLuigi Rizzo memset(&req, 0, sizeof(req)); 7064bf50f18SLuigi Rizzo bcopy(t->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); 7074bf50f18SLuigi Rizzo req.nr_version = NETMAP_API; 7084bf50f18SLuigi Rizzo req.nr_cmd = NETMAP_BDG_VNET_HDR; 7094bf50f18SLuigi Rizzo req.nr_arg1 = l; 7104bf50f18SLuigi Rizzo err = ioctl(t->fd, NIOCREGIF, &req); 7114bf50f18SLuigi Rizzo if (err) { 7124bf50f18SLuigi Rizzo D("Unable to set vnet header length %d", l); 7134bf50f18SLuigi Rizzo } 7144bf50f18SLuigi Rizzo } 71568b8534bSLuigi Rizzo 71668b8534bSLuigi Rizzo 71768b8534bSLuigi Rizzo /* 71868b8534bSLuigi Rizzo * create and enqueue a batch of packets on a ring. 71968b8534bSLuigi Rizzo * On the last one set NS_REPORT to tell the driver to generate 72068b8534bSLuigi Rizzo * an interrupt when done. 72168b8534bSLuigi Rizzo */ 72268b8534bSLuigi Rizzo static int 72317885a7bSLuigi Rizzo send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, 72417885a7bSLuigi Rizzo int size, struct glob_arg *g, u_int count, int options, 72517885a7bSLuigi Rizzo u_int nfrags) 72668b8534bSLuigi Rizzo { 72717885a7bSLuigi Rizzo u_int n, sent, cur = ring->cur; 728f2637526SLuigi Rizzo u_int fcnt; 72968b8534bSLuigi Rizzo 73017885a7bSLuigi Rizzo n = nm_ring_space(ring); 73117885a7bSLuigi Rizzo if (n < count) 73217885a7bSLuigi Rizzo count = n; 733ce3ee1e7SLuigi Rizzo if (count < nfrags) { 734ce3ee1e7SLuigi Rizzo D("truncating packet, no room for frags %d %d", 735ce3ee1e7SLuigi Rizzo count, nfrags); 736ce3ee1e7SLuigi Rizzo } 73799fb123fSLuigi Rizzo #if 0 73899fb123fSLuigi Rizzo if (options & (OPT_COPY | OPT_PREFETCH) ) { 73968b8534bSLuigi Rizzo for (sent = 0; sent < count; sent++) { 74068b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 74168b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 74268b8534bSLuigi Rizzo 743f2637526SLuigi Rizzo __builtin_prefetch(p); 74417885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 74599fb123fSLuigi Rizzo } 74699fb123fSLuigi Rizzo cur = ring->cur; 74799fb123fSLuigi Rizzo } 74899fb123fSLuigi Rizzo #endif 749ce3ee1e7SLuigi Rizzo for (fcnt = nfrags, sent = 0; sent < count; sent++) { 75099fb123fSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 75199fb123fSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 75299fb123fSLuigi Rizzo 753b303f675SLuigi Rizzo slot->flags = 0; 754b303f675SLuigi Rizzo if (options & OPT_INDIRECT) { 755b303f675SLuigi Rizzo slot->flags |= NS_INDIRECT; 75617885a7bSLuigi Rizzo slot->ptr = (uint64_t)frame; 757ce3ee1e7SLuigi Rizzo } else if (options & OPT_COPY) { 758f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 759f2637526SLuigi Rizzo if (fcnt == nfrags) 760ce3ee1e7SLuigi Rizzo update_addresses(pkt, g); 761ce3ee1e7SLuigi Rizzo } else if (options & OPT_MEMCPY) { 76217885a7bSLuigi Rizzo memcpy(p, frame, size); 763f2637526SLuigi Rizzo if (fcnt == nfrags) 764ce3ee1e7SLuigi Rizzo update_addresses(pkt, g); 765ce3ee1e7SLuigi Rizzo } else if (options & OPT_PREFETCH) { 766f2637526SLuigi Rizzo __builtin_prefetch(p); 767ce3ee1e7SLuigi Rizzo } 768ce3ee1e7SLuigi Rizzo if (options & OPT_DUMP) 769ce3ee1e7SLuigi Rizzo dump_payload(p, size, ring, cur); 77068b8534bSLuigi Rizzo slot->len = size; 771ce3ee1e7SLuigi Rizzo if (--fcnt > 0) 772ce3ee1e7SLuigi Rizzo slot->flags |= NS_MOREFRAG; 773ce3ee1e7SLuigi Rizzo else 774ce3ee1e7SLuigi Rizzo fcnt = nfrags; 775ce3ee1e7SLuigi Rizzo if (sent == count - 1) { 776ce3ee1e7SLuigi Rizzo slot->flags &= ~NS_MOREFRAG; 77768b8534bSLuigi Rizzo slot->flags |= NS_REPORT; 778ce3ee1e7SLuigi Rizzo } 77917885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 78068b8534bSLuigi Rizzo } 78117885a7bSLuigi Rizzo ring->head = ring->cur = cur; 78268b8534bSLuigi Rizzo 78368b8534bSLuigi Rizzo return (sent); 78468b8534bSLuigi Rizzo } 78568b8534bSLuigi Rizzo 786f8e4e36aSLuigi Rizzo /* 787f8e4e36aSLuigi Rizzo * Send a packet, and wait for a response. 788f8e4e36aSLuigi Rizzo * The payload (after UDP header, ofs 42) has a 4-byte sequence 789f8e4e36aSLuigi Rizzo * followed by a struct timeval (or bintime?) 790f8e4e36aSLuigi Rizzo */ 791f8e4e36aSLuigi Rizzo #define PAY_OFS 42 /* where in the pkt... */ 792f8e4e36aSLuigi Rizzo 79368b8534bSLuigi Rizzo static void * 794f8e4e36aSLuigi Rizzo pinger_body(void *data) 79568b8534bSLuigi Rizzo { 79668b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 797f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 798f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 799f8e4e36aSLuigi Rizzo int i, rx = 0, n = targ->g->npackets; 80017885a7bSLuigi Rizzo void *frame; 80117885a7bSLuigi Rizzo int size; 802f0ea3689SLuigi Rizzo uint32_t sent = 0; 803f0ea3689SLuigi Rizzo struct timespec ts, now, last_print; 804f0ea3689SLuigi Rizzo uint32_t count = 0, min = 1000000000, av = 0; 80517885a7bSLuigi Rizzo 80617885a7bSLuigi Rizzo frame = &targ->pkt; 80717885a7bSLuigi Rizzo frame += sizeof(targ->pkt.vh) - targ->g->virt_header; 80817885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 809e5ecae38SEd Maste 810f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 811f8e4e36aSLuigi Rizzo D("can only ping with 1 thread"); 812f8e4e36aSLuigi Rizzo return NULL; 813f95a30bdSEd Maste } 814f8e4e36aSLuigi Rizzo 815f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); 81617885a7bSLuigi Rizzo now = last_print; 817f8e4e36aSLuigi Rizzo while (n == 0 || (int)sent < n) { 818f8e4e36aSLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, 0); 819f8e4e36aSLuigi Rizzo struct netmap_slot *slot; 820f8e4e36aSLuigi Rizzo char *p; 82117885a7bSLuigi Rizzo for (i = 0; i < 1; i++) { /* XXX why the loop for 1 pkt ? */ 822f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 82317885a7bSLuigi Rizzo slot->len = size; 824f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 825f8e4e36aSLuigi Rizzo 82617885a7bSLuigi Rizzo if (nm_ring_empty(ring)) { 827f8e4e36aSLuigi Rizzo D("-- ouch, cannot send"); 828f8e4e36aSLuigi Rizzo } else { 8294bf50f18SLuigi Rizzo struct tstamp *tp; 830f0ea3689SLuigi Rizzo nm_pkt_copy(frame, p, size); 831f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &ts); 832f8e4e36aSLuigi Rizzo bcopy(&sent, p+42, sizeof(sent)); 8334bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 8344bf50f18SLuigi Rizzo tp->sec = (uint32_t)ts.tv_sec; 8354bf50f18SLuigi Rizzo tp->nsec = (uint32_t)ts.tv_nsec; 836f8e4e36aSLuigi Rizzo sent++; 83717885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 838f8e4e36aSLuigi Rizzo } 839f8e4e36aSLuigi Rizzo } 840f8e4e36aSLuigi Rizzo /* should use a parameter to decide how often to send */ 841f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 3000) <= 0) { 84217885a7bSLuigi Rizzo D("poll error/timeout on queue %d: %s", targ->me, 84317885a7bSLuigi Rizzo strerror(errno)); 844f8e4e36aSLuigi Rizzo continue; 845f8e4e36aSLuigi Rizzo } 846f8e4e36aSLuigi Rizzo /* see what we got back */ 847f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; 848f0ea3689SLuigi Rizzo i <= targ->nmd->last_tx_ring; i++) { 849f8e4e36aSLuigi Rizzo ring = NETMAP_RXRING(nifp, i); 85017885a7bSLuigi Rizzo while (!nm_ring_empty(ring)) { 851f8e4e36aSLuigi Rizzo uint32_t seq; 8524bf50f18SLuigi Rizzo struct tstamp *tp; 853f8e4e36aSLuigi Rizzo slot = &ring->slot[ring->cur]; 854f8e4e36aSLuigi Rizzo p = NETMAP_BUF(ring, slot->buf_idx); 855f8e4e36aSLuigi Rizzo 856f8e4e36aSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &now); 857f8e4e36aSLuigi Rizzo bcopy(p+42, &seq, sizeof(seq)); 8584bf50f18SLuigi Rizzo tp = (struct tstamp *)(p+46); 8594bf50f18SLuigi Rizzo ts.tv_sec = (time_t)tp->sec; 8604bf50f18SLuigi Rizzo ts.tv_nsec = (long)tp->nsec; 861f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - ts.tv_sec; 862f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - ts.tv_nsec; 863f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 864f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 865f8e4e36aSLuigi Rizzo ts.tv_sec--; 866f8e4e36aSLuigi Rizzo } 867f8e4e36aSLuigi Rizzo if (1) D("seq %d/%d delta %d.%09d", seq, sent, 868f8e4e36aSLuigi Rizzo (int)ts.tv_sec, (int)ts.tv_nsec); 869f8e4e36aSLuigi Rizzo if (ts.tv_nsec < (int)min) 870f8e4e36aSLuigi Rizzo min = ts.tv_nsec; 871f8e4e36aSLuigi Rizzo count ++; 872f8e4e36aSLuigi Rizzo av += ts.tv_nsec; 87317885a7bSLuigi Rizzo ring->head = ring->cur = nm_ring_next(ring, ring->cur); 874f8e4e36aSLuigi Rizzo rx++; 875f8e4e36aSLuigi Rizzo } 876f8e4e36aSLuigi Rizzo } 877f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 878f8e4e36aSLuigi Rizzo //usleep(100000); 879f8e4e36aSLuigi Rizzo ts.tv_sec = now.tv_sec - last_print.tv_sec; 880f8e4e36aSLuigi Rizzo ts.tv_nsec = now.tv_nsec - last_print.tv_nsec; 881f8e4e36aSLuigi Rizzo if (ts.tv_nsec < 0) { 882f8e4e36aSLuigi Rizzo ts.tv_nsec += 1000000000; 883f8e4e36aSLuigi Rizzo ts.tv_sec--; 884f8e4e36aSLuigi Rizzo } 885f8e4e36aSLuigi Rizzo if (ts.tv_sec >= 1) { 886f8e4e36aSLuigi Rizzo D("count %d min %d av %d", 887f8e4e36aSLuigi Rizzo count, min, av/count); 888f8e4e36aSLuigi Rizzo count = 0; 889f8e4e36aSLuigi Rizzo av = 0; 890f8e4e36aSLuigi Rizzo min = 100000000; 891f8e4e36aSLuigi Rizzo last_print = now; 892f8e4e36aSLuigi Rizzo } 893f8e4e36aSLuigi Rizzo } 894f8e4e36aSLuigi Rizzo return NULL; 895f8e4e36aSLuigi Rizzo } 896f8e4e36aSLuigi Rizzo 897f8e4e36aSLuigi Rizzo 898f8e4e36aSLuigi Rizzo /* 899f8e4e36aSLuigi Rizzo * reply to ping requests 900f8e4e36aSLuigi Rizzo */ 901f8e4e36aSLuigi Rizzo static void * 902f8e4e36aSLuigi Rizzo ponger_body(void *data) 903f8e4e36aSLuigi Rizzo { 904f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 905f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 906f0ea3689SLuigi Rizzo struct netmap_if *nifp = targ->nmd->nifp; 907f8e4e36aSLuigi Rizzo struct netmap_ring *txring, *rxring; 908f8e4e36aSLuigi Rizzo int i, rx = 0, sent = 0, n = targ->g->npackets; 909f8e4e36aSLuigi Rizzo 910f8e4e36aSLuigi Rizzo if (targ->g->nthreads > 1) { 911f8e4e36aSLuigi Rizzo D("can only reply ping with 1 thread"); 912f8e4e36aSLuigi Rizzo return NULL; 913f8e4e36aSLuigi Rizzo } 914f8e4e36aSLuigi Rizzo D("understood ponger %d but don't know how to do it", n); 915f8e4e36aSLuigi Rizzo while (n == 0 || sent < n) { 916f8e4e36aSLuigi Rizzo uint32_t txcur, txavail; 917f8e4e36aSLuigi Rizzo //#define BUSYWAIT 918f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 919f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCRXSYNC, NULL); 920f8e4e36aSLuigi Rizzo #else 921f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1000) <= 0) { 92217885a7bSLuigi Rizzo D("poll error/timeout on queue %d: %s", targ->me, 92317885a7bSLuigi Rizzo strerror(errno)); 924f8e4e36aSLuigi Rizzo continue; 925f8e4e36aSLuigi Rizzo } 926f8e4e36aSLuigi Rizzo #endif 927f8e4e36aSLuigi Rizzo txring = NETMAP_TXRING(nifp, 0); 928f8e4e36aSLuigi Rizzo txcur = txring->cur; 92917885a7bSLuigi Rizzo txavail = nm_ring_space(txring); 930f8e4e36aSLuigi Rizzo /* see what we got back */ 931f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 932f8e4e36aSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 93317885a7bSLuigi Rizzo while (!nm_ring_empty(rxring)) { 934f8e4e36aSLuigi Rizzo uint16_t *spkt, *dpkt; 935f8e4e36aSLuigi Rizzo uint32_t cur = rxring->cur; 936f8e4e36aSLuigi Rizzo struct netmap_slot *slot = &rxring->slot[cur]; 937f8e4e36aSLuigi Rizzo char *src, *dst; 938f8e4e36aSLuigi Rizzo src = NETMAP_BUF(rxring, slot->buf_idx); 939f8e4e36aSLuigi Rizzo //D("got pkt %p of size %d", src, slot->len); 94017885a7bSLuigi Rizzo rxring->head = rxring->cur = nm_ring_next(rxring, cur); 941f8e4e36aSLuigi Rizzo rx++; 942f8e4e36aSLuigi Rizzo if (txavail == 0) 943f8e4e36aSLuigi Rizzo continue; 944f8e4e36aSLuigi Rizzo dst = NETMAP_BUF(txring, 945f8e4e36aSLuigi Rizzo txring->slot[txcur].buf_idx); 946f8e4e36aSLuigi Rizzo /* copy... */ 947f8e4e36aSLuigi Rizzo dpkt = (uint16_t *)dst; 948f8e4e36aSLuigi Rizzo spkt = (uint16_t *)src; 949f0ea3689SLuigi Rizzo nm_pkt_copy(src, dst, slot->len); 950f8e4e36aSLuigi Rizzo dpkt[0] = spkt[3]; 951f8e4e36aSLuigi Rizzo dpkt[1] = spkt[4]; 952f8e4e36aSLuigi Rizzo dpkt[2] = spkt[5]; 953f8e4e36aSLuigi Rizzo dpkt[3] = spkt[0]; 954f8e4e36aSLuigi Rizzo dpkt[4] = spkt[1]; 955f8e4e36aSLuigi Rizzo dpkt[5] = spkt[2]; 956f8e4e36aSLuigi Rizzo txring->slot[txcur].len = slot->len; 957f8e4e36aSLuigi Rizzo /* XXX swap src dst mac */ 95817885a7bSLuigi Rizzo txcur = nm_ring_next(txring, txcur); 959f8e4e36aSLuigi Rizzo txavail--; 960f8e4e36aSLuigi Rizzo sent++; 961f8e4e36aSLuigi Rizzo } 962f8e4e36aSLuigi Rizzo } 96317885a7bSLuigi Rizzo txring->head = txring->cur = txcur; 964f8e4e36aSLuigi Rizzo targ->count = sent; 965f8e4e36aSLuigi Rizzo #ifdef BUSYWAIT 966f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 967f8e4e36aSLuigi Rizzo #endif 968f8e4e36aSLuigi Rizzo //D("tx %d rx %d", sent, rx); 969f8e4e36aSLuigi Rizzo } 970f8e4e36aSLuigi Rizzo return NULL; 971f8e4e36aSLuigi Rizzo } 972f8e4e36aSLuigi Rizzo 9731cb4c501SLuigi Rizzo static __inline int 9741cb4c501SLuigi Rizzo timespec_ge(const struct timespec *a, const struct timespec *b) 9751cb4c501SLuigi Rizzo { 9761cb4c501SLuigi Rizzo 9771cb4c501SLuigi Rizzo if (a->tv_sec > b->tv_sec) 9781cb4c501SLuigi Rizzo return (1); 9791cb4c501SLuigi Rizzo if (a->tv_sec < b->tv_sec) 9801cb4c501SLuigi Rizzo return (0); 9811cb4c501SLuigi Rizzo if (a->tv_nsec >= b->tv_nsec) 9821cb4c501SLuigi Rizzo return (1); 9831cb4c501SLuigi Rizzo return (0); 9841cb4c501SLuigi Rizzo } 9851cb4c501SLuigi Rizzo 9861cb4c501SLuigi Rizzo static __inline struct timespec 9871cb4c501SLuigi Rizzo timeval2spec(const struct timeval *a) 9881cb4c501SLuigi Rizzo { 9891cb4c501SLuigi Rizzo struct timespec ts = { 9901cb4c501SLuigi Rizzo .tv_sec = a->tv_sec, 9911cb4c501SLuigi Rizzo .tv_nsec = a->tv_usec * 1000 9921cb4c501SLuigi Rizzo }; 9931cb4c501SLuigi Rizzo return ts; 9941cb4c501SLuigi Rizzo } 9951cb4c501SLuigi Rizzo 9961cb4c501SLuigi Rizzo static __inline struct timeval 9971cb4c501SLuigi Rizzo timespec2val(const struct timespec *a) 9981cb4c501SLuigi Rizzo { 9991cb4c501SLuigi Rizzo struct timeval tv = { 10001cb4c501SLuigi Rizzo .tv_sec = a->tv_sec, 10011cb4c501SLuigi Rizzo .tv_usec = a->tv_nsec / 1000 10021cb4c501SLuigi Rizzo }; 10031cb4c501SLuigi Rizzo return tv; 10041cb4c501SLuigi Rizzo } 10051cb4c501SLuigi Rizzo 10061cb4c501SLuigi Rizzo 100717885a7bSLuigi Rizzo static __inline struct timespec 100817885a7bSLuigi Rizzo timespec_add(struct timespec a, struct timespec b) 10091cb4c501SLuigi Rizzo { 101017885a7bSLuigi Rizzo struct timespec ret = { a.tv_sec + b.tv_sec, a.tv_nsec + b.tv_nsec }; 101117885a7bSLuigi Rizzo if (ret.tv_nsec >= 1000000000) { 101217885a7bSLuigi Rizzo ret.tv_sec++; 101317885a7bSLuigi Rizzo ret.tv_nsec -= 1000000000; 10141cb4c501SLuigi Rizzo } 101517885a7bSLuigi Rizzo return ret; 10161cb4c501SLuigi Rizzo } 10171cb4c501SLuigi Rizzo 101817885a7bSLuigi Rizzo static __inline struct timespec 101917885a7bSLuigi Rizzo timespec_sub(struct timespec a, struct timespec b) 10201cb4c501SLuigi Rizzo { 102117885a7bSLuigi Rizzo struct timespec ret = { a.tv_sec - b.tv_sec, a.tv_nsec - b.tv_nsec }; 102217885a7bSLuigi Rizzo if (ret.tv_nsec < 0) { 102317885a7bSLuigi Rizzo ret.tv_sec--; 102417885a7bSLuigi Rizzo ret.tv_nsec += 1000000000; 10251cb4c501SLuigi Rizzo } 102617885a7bSLuigi Rizzo return ret; 10271cb4c501SLuigi Rizzo } 10281cb4c501SLuigi Rizzo 1029f8e4e36aSLuigi Rizzo 103017885a7bSLuigi Rizzo /* 103117885a7bSLuigi Rizzo * wait until ts, either busy or sleeping if more than 1ms. 103217885a7bSLuigi Rizzo * Return wakeup time. 103317885a7bSLuigi Rizzo */ 103417885a7bSLuigi Rizzo static struct timespec 103517885a7bSLuigi Rizzo wait_time(struct timespec ts) 103617885a7bSLuigi Rizzo { 103717885a7bSLuigi Rizzo for (;;) { 103817885a7bSLuigi Rizzo struct timespec w, cur; 103917885a7bSLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &cur); 104017885a7bSLuigi Rizzo w = timespec_sub(ts, cur); 104117885a7bSLuigi Rizzo if (w.tv_sec < 0) 104217885a7bSLuigi Rizzo return cur; 104317885a7bSLuigi Rizzo else if (w.tv_sec > 0 || w.tv_nsec > 1000000) 104417885a7bSLuigi Rizzo poll(NULL, 0, 1); 104517885a7bSLuigi Rizzo } 104617885a7bSLuigi Rizzo } 104717885a7bSLuigi Rizzo 1048f8e4e36aSLuigi Rizzo static void * 1049f8e4e36aSLuigi Rizzo sender_body(void *data) 1050f8e4e36aSLuigi Rizzo { 1051f8e4e36aSLuigi Rizzo struct targ *targ = (struct targ *) data; 1052f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; 10534bf50f18SLuigi Rizzo struct netmap_if *nifp; 1054f8e4e36aSLuigi Rizzo struct netmap_ring *txring; 1055f0ea3689SLuigi Rizzo int i, n = targ->g->npackets / targ->g->nthreads; 1056f0ea3689SLuigi Rizzo int64_t sent = 0; 1057f8e4e36aSLuigi Rizzo int options = targ->g->options | OPT_COPY; 105817885a7bSLuigi Rizzo struct timespec nexttime = { 0, 0}; // XXX silence compiler 10591cb4c501SLuigi Rizzo int rate_limit = targ->g->tx_rate; 106017885a7bSLuigi Rizzo struct pkt *pkt = &targ->pkt; 106117885a7bSLuigi Rizzo void *frame; 106217885a7bSLuigi Rizzo int size; 106317885a7bSLuigi Rizzo 1064f284c737SGeorge V. Neville-Neil if (targ->frame == NULL) { 106517885a7bSLuigi Rizzo frame = pkt; 106617885a7bSLuigi Rizzo frame += sizeof(pkt->vh) - targ->g->virt_header; 106717885a7bSLuigi Rizzo size = targ->g->pkt_size + targ->g->virt_header; 1068f284c737SGeorge V. Neville-Neil } else { 1069f284c737SGeorge V. Neville-Neil frame = targ->frame; 1070f284c737SGeorge V. Neville-Neil size = targ->g->pkt_size; 1071f284c737SGeorge V. Neville-Neil } 1072b303f675SLuigi Rizzo 10734bf50f18SLuigi Rizzo D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); 107468b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 107568b8534bSLuigi Rizzo goto quit; 107668b8534bSLuigi Rizzo 107768b8534bSLuigi Rizzo /* main loop.*/ 10781cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 10791cb4c501SLuigi Rizzo if (rate_limit) { 108017885a7bSLuigi Rizzo targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); 10811cb4c501SLuigi Rizzo targ->tic.tv_nsec = 0; 108217885a7bSLuigi Rizzo wait_time(targ->tic); 10831cb4c501SLuigi Rizzo nexttime = targ->tic; 10841cb4c501SLuigi Rizzo } 1085f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1086f8e4e36aSLuigi Rizzo D("writing to file desc %d", targ->g->main_fd); 1087f8e4e36aSLuigi Rizzo 1088f8e4e36aSLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 108917885a7bSLuigi Rizzo if (write(targ->g->main_fd, frame, size) != -1) 1090f8e4e36aSLuigi Rizzo sent++; 1091ce3ee1e7SLuigi Rizzo update_addresses(pkt, targ->g); 1092f8e4e36aSLuigi Rizzo if (i > 10000) { 1093f8e4e36aSLuigi Rizzo targ->count = sent; 1094f8e4e36aSLuigi Rizzo i = 0; 1095f8e4e36aSLuigi Rizzo } 1096f8e4e36aSLuigi Rizzo } 1097f2637526SLuigi Rizzo #ifndef NO_PCAP 1098f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1099f2637526SLuigi Rizzo pcap_t *p = targ->g->p; 1100f2637526SLuigi Rizzo 1101f2637526SLuigi Rizzo for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { 1102f2637526SLuigi Rizzo if (pcap_inject(p, frame, size) != -1) 1103f2637526SLuigi Rizzo sent++; 1104f2637526SLuigi Rizzo update_addresses(pkt, targ->g); 1105f2637526SLuigi Rizzo if (i > 10000) { 1106f2637526SLuigi Rizzo targ->count = sent; 1107f2637526SLuigi Rizzo i = 0; 1108f2637526SLuigi Rizzo } 1109f2637526SLuigi Rizzo } 1110f2637526SLuigi Rizzo #endif /* NO_PCAP */ 111168b8534bSLuigi Rizzo } else { 11121cb4c501SLuigi Rizzo int tosend = 0; 1113ce3ee1e7SLuigi Rizzo int frags = targ->g->frags; 1114ce3ee1e7SLuigi Rizzo 11154bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 1116f8e4e36aSLuigi Rizzo while (!targ->cancel && (n == 0 || sent < n)) { 111768b8534bSLuigi Rizzo 11181cb4c501SLuigi Rizzo if (rate_limit && tosend <= 0) { 11191cb4c501SLuigi Rizzo tosend = targ->g->burst; 112017885a7bSLuigi Rizzo nexttime = timespec_add(nexttime, targ->g->tx_period); 112117885a7bSLuigi Rizzo wait_time(nexttime); 11221cb4c501SLuigi Rizzo } 11231cb4c501SLuigi Rizzo 112468b8534bSLuigi Rizzo /* 112568b8534bSLuigi Rizzo * wait for available room in the send queue(s) 112668b8534bSLuigi Rizzo */ 1127f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 2000) <= 0) { 11283fe77e68SEd Maste if (targ->cancel) 11293fe77e68SEd Maste break; 113017885a7bSLuigi Rizzo D("poll error/timeout on queue %d: %s", targ->me, 113117885a7bSLuigi Rizzo strerror(errno)); 1132f0ea3689SLuigi Rizzo // goto quit; 113317885a7bSLuigi Rizzo } 1134f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 113517885a7bSLuigi Rizzo D("poll error"); 113668b8534bSLuigi Rizzo goto quit; 113768b8534bSLuigi Rizzo } 113868b8534bSLuigi Rizzo /* 113968b8534bSLuigi Rizzo * scan our queues and send on those with room 114068b8534bSLuigi Rizzo */ 1141f8e4e36aSLuigi Rizzo if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) { 1142f8e4e36aSLuigi Rizzo D("drop copy"); 114399fb123fSLuigi Rizzo options &= ~OPT_COPY; 1144f8e4e36aSLuigi Rizzo } 1145f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 11461cb4c501SLuigi Rizzo int m, limit = rate_limit ? tosend : targ->g->burst; 1147f8e4e36aSLuigi Rizzo if (n > 0 && n - sent < limit) 1148f8e4e36aSLuigi Rizzo limit = n - sent; 114968b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 115017885a7bSLuigi Rizzo if (nm_ring_empty(txring)) 115168b8534bSLuigi Rizzo continue; 1152ce3ee1e7SLuigi Rizzo if (frags > 1) 1153ce3ee1e7SLuigi Rizzo limit = ((limit + frags - 1) / frags) * frags; 1154ce3ee1e7SLuigi Rizzo 115517885a7bSLuigi Rizzo m = send_packets(txring, pkt, frame, size, targ->g, 1156ce3ee1e7SLuigi Rizzo limit, options, frags); 1157f2637526SLuigi Rizzo ND("limit %d tail %d frags %d m %d", 1158f2637526SLuigi Rizzo limit, txring->tail, frags, m); 115968b8534bSLuigi Rizzo sent += m; 116068b8534bSLuigi Rizzo targ->count = sent; 1161ce3ee1e7SLuigi Rizzo if (rate_limit) { 1162ce3ee1e7SLuigi Rizzo tosend -= m; 1163ce3ee1e7SLuigi Rizzo if (tosend <= 0) 1164ce3ee1e7SLuigi Rizzo break; 1165ce3ee1e7SLuigi Rizzo } 116668b8534bSLuigi Rizzo } 116768b8534bSLuigi Rizzo } 116899fb123fSLuigi Rizzo /* flush any remaining packets */ 11694bf50f18SLuigi Rizzo D("flush tail %d head %d on thread %p", 11704bf50f18SLuigi Rizzo txring->tail, txring->head, 11714bf50f18SLuigi Rizzo pthread_self()); 1172f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 117368b8534bSLuigi Rizzo 117468b8534bSLuigi Rizzo /* final part: wait all the TX queues to be empty. */ 1175f0ea3689SLuigi Rizzo for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { 117668b8534bSLuigi Rizzo txring = NETMAP_TXRING(nifp, i); 117717885a7bSLuigi Rizzo while (nm_tx_pending(txring)) { 11784bf50f18SLuigi Rizzo RD(5, "pending tx tail %d head %d on ring %d", 11794bf50f18SLuigi Rizzo txring->tail, txring->head, i); 1180f0ea3689SLuigi Rizzo ioctl(pfd.fd, NIOCTXSYNC, NULL); 118168b8534bSLuigi Rizzo usleep(1); /* wait 1 tick */ 118268b8534bSLuigi Rizzo } 118368b8534bSLuigi Rizzo } 1184f2637526SLuigi Rizzo } /* end DEV_NETMAP */ 118568b8534bSLuigi Rizzo 11861cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 118768b8534bSLuigi Rizzo targ->completed = 1; 118868b8534bSLuigi Rizzo targ->count = sent; 118968b8534bSLuigi Rizzo 119068b8534bSLuigi Rizzo quit: 119168b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 119268b8534bSLuigi Rizzo targ->used = 0; 119368b8534bSLuigi Rizzo 119468b8534bSLuigi Rizzo return (NULL); 119568b8534bSLuigi Rizzo } 119668b8534bSLuigi Rizzo 119768b8534bSLuigi Rizzo 1198f2637526SLuigi Rizzo #ifndef NO_PCAP 119968b8534bSLuigi Rizzo static void 1200f8e4e36aSLuigi Rizzo receive_pcap(u_char *user, const struct pcap_pkthdr * h, 1201f8e4e36aSLuigi Rizzo const u_char * bytes) 120268b8534bSLuigi Rizzo { 120368b8534bSLuigi Rizzo int *count = (int *)user; 1204f8e4e36aSLuigi Rizzo (void)h; /* UNUSED */ 1205f8e4e36aSLuigi Rizzo (void)bytes; /* UNUSED */ 120668b8534bSLuigi Rizzo (*count)++; 120768b8534bSLuigi Rizzo } 1208f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 120968b8534bSLuigi Rizzo 121068b8534bSLuigi Rizzo static int 1211b303f675SLuigi Rizzo receive_packets(struct netmap_ring *ring, u_int limit, int dump) 121268b8534bSLuigi Rizzo { 121317885a7bSLuigi Rizzo u_int cur, rx, n; 121468b8534bSLuigi Rizzo 121568b8534bSLuigi Rizzo cur = ring->cur; 121617885a7bSLuigi Rizzo n = nm_ring_space(ring); 121717885a7bSLuigi Rizzo if (n < limit) 121817885a7bSLuigi Rizzo limit = n; 121968b8534bSLuigi Rizzo for (rx = 0; rx < limit; rx++) { 122068b8534bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[cur]; 122168b8534bSLuigi Rizzo char *p = NETMAP_BUF(ring, slot->buf_idx); 122268b8534bSLuigi Rizzo 1223b303f675SLuigi Rizzo if (dump) 1224b303f675SLuigi Rizzo dump_payload(p, slot->len, ring, cur); 122568b8534bSLuigi Rizzo 122617885a7bSLuigi Rizzo cur = nm_ring_next(ring, cur); 122768b8534bSLuigi Rizzo } 122817885a7bSLuigi Rizzo ring->head = ring->cur = cur; 122968b8534bSLuigi Rizzo 123068b8534bSLuigi Rizzo return (rx); 123168b8534bSLuigi Rizzo } 123268b8534bSLuigi Rizzo 123368b8534bSLuigi Rizzo static void * 123468b8534bSLuigi Rizzo receiver_body(void *data) 123568b8534bSLuigi Rizzo { 123668b8534bSLuigi Rizzo struct targ *targ = (struct targ *) data; 1237f0ea3689SLuigi Rizzo struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; 12384bf50f18SLuigi Rizzo struct netmap_if *nifp; 123968b8534bSLuigi Rizzo struct netmap_ring *rxring; 1240f8e4e36aSLuigi Rizzo int i; 1241f8e4e36aSLuigi Rizzo uint64_t received = 0; 124268b8534bSLuigi Rizzo 124368b8534bSLuigi Rizzo if (setaffinity(targ->thread, targ->affinity)) 124468b8534bSLuigi Rizzo goto quit; 124568b8534bSLuigi Rizzo 12464bf50f18SLuigi Rizzo D("reading from %s fd %d main_fd %d", 12474bf50f18SLuigi Rizzo targ->g->ifname, targ->fd, targ->g->main_fd); 124868b8534bSLuigi Rizzo /* unbounded wait for the first packet. */ 12494bf50f18SLuigi Rizzo for (;!targ->cancel;) { 1250f0ea3689SLuigi Rizzo i = poll(&pfd, 1, 1000); 1251f0ea3689SLuigi Rizzo if (i > 0 && !(pfd.revents & POLLERR)) 125268b8534bSLuigi Rizzo break; 1253f0ea3689SLuigi Rizzo RD(1, "waiting for initial packets, poll returns %d %d", 1254f0ea3689SLuigi Rizzo i, pfd.revents); 125568b8534bSLuigi Rizzo } 125668b8534bSLuigi Rizzo /* main loop, exit after 1s silence */ 12571cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); 1258f2637526SLuigi Rizzo if (targ->g->dev_type == DEV_TAP) { 1259f8e4e36aSLuigi Rizzo while (!targ->cancel) { 12604bf50f18SLuigi Rizzo char buf[MAX_BODYSIZE]; 1261f8e4e36aSLuigi Rizzo /* XXX should we poll ? */ 1262f8e4e36aSLuigi Rizzo if (read(targ->g->main_fd, buf, sizeof(buf)) > 0) 1263f8e4e36aSLuigi Rizzo targ->count++; 1264f8e4e36aSLuigi Rizzo } 1265f2637526SLuigi Rizzo #ifndef NO_PCAP 1266f2637526SLuigi Rizzo } else if (targ->g->dev_type == DEV_PCAP) { 1267f2637526SLuigi Rizzo while (!targ->cancel) { 1268f2637526SLuigi Rizzo /* XXX should we poll ? */ 12694bf50f18SLuigi Rizzo pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, 12704bf50f18SLuigi Rizzo (u_char *)&targ->count); 1271f2637526SLuigi Rizzo } 1272f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 127368b8534bSLuigi Rizzo } else { 1274b303f675SLuigi Rizzo int dump = targ->g->options & OPT_DUMP; 12754bf50f18SLuigi Rizzo 12764bf50f18SLuigi Rizzo nifp = targ->nmd->nifp; 12773fe77e68SEd Maste while (!targ->cancel) { 127868b8534bSLuigi Rizzo /* Once we started to receive packets, wait at most 1 seconds 127968b8534bSLuigi Rizzo before quitting. */ 1280f0ea3689SLuigi Rizzo if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { 12811cb4c501SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 12828ce070c1SUlrich Spörlein targ->toc.tv_sec -= 1; /* Subtract timeout time. */ 1283f0ea3689SLuigi Rizzo goto out; 128468b8534bSLuigi Rizzo } 128568b8534bSLuigi Rizzo 1286f0ea3689SLuigi Rizzo if (pfd.revents & POLLERR) { 128717885a7bSLuigi Rizzo D("poll err"); 128817885a7bSLuigi Rizzo goto quit; 128917885a7bSLuigi Rizzo } 129017885a7bSLuigi Rizzo 1291f0ea3689SLuigi Rizzo for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { 129268b8534bSLuigi Rizzo int m; 129368b8534bSLuigi Rizzo 129468b8534bSLuigi Rizzo rxring = NETMAP_RXRING(nifp, i); 129517885a7bSLuigi Rizzo if (nm_ring_empty(rxring)) 129668b8534bSLuigi Rizzo continue; 129768b8534bSLuigi Rizzo 1298b303f675SLuigi Rizzo m = receive_packets(rxring, targ->g->burst, dump); 129968b8534bSLuigi Rizzo received += m; 130068b8534bSLuigi Rizzo } 1301f8e4e36aSLuigi Rizzo targ->count = received; 130268b8534bSLuigi Rizzo } 130368b8534bSLuigi Rizzo } 130468b8534bSLuigi Rizzo 1305f0ea3689SLuigi Rizzo clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); 1306f0ea3689SLuigi Rizzo 1307f0ea3689SLuigi Rizzo out: 130868b8534bSLuigi Rizzo targ->completed = 1; 130968b8534bSLuigi Rizzo targ->count = received; 131068b8534bSLuigi Rizzo 131168b8534bSLuigi Rizzo quit: 131268b8534bSLuigi Rizzo /* reset the ``used`` flag. */ 131368b8534bSLuigi Rizzo targ->used = 0; 131468b8534bSLuigi Rizzo 131568b8534bSLuigi Rizzo return (NULL); 131668b8534bSLuigi Rizzo } 131768b8534bSLuigi Rizzo 1318f8e4e36aSLuigi Rizzo /* very crude code to print a number in normalized form. 1319f8e4e36aSLuigi Rizzo * Caller has to make sure that the buffer is large enough. 1320f8e4e36aSLuigi Rizzo */ 1321f8e4e36aSLuigi Rizzo static const char * 1322f8e4e36aSLuigi Rizzo norm(char *buf, double val) 132366a698c9SEd Maste { 1324f0ea3689SLuigi Rizzo char *units[] = { "", "K", "M", "G", "T" }; 1325f8e4e36aSLuigi Rizzo u_int i; 132666a698c9SEd Maste 1327f0ea3689SLuigi Rizzo for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++) 132866a698c9SEd Maste val /= 1000; 1329f8e4e36aSLuigi Rizzo sprintf(buf, "%.2f %s", val, units[i]); 1330f8e4e36aSLuigi Rizzo return buf; 133166a698c9SEd Maste } 133266a698c9SEd Maste 133368b8534bSLuigi Rizzo static void 133468b8534bSLuigi Rizzo tx_output(uint64_t sent, int size, double delta) 133568b8534bSLuigi Rizzo { 1336f8e4e36aSLuigi Rizzo double bw, raw_bw, pps; 1337f8e4e36aSLuigi Rizzo char b1[40], b2[80], b3[80]; 133868b8534bSLuigi Rizzo 1339f0ea3689SLuigi Rizzo printf("Sent %llu packets, %d bytes each, in %.2f seconds.\n", 1340f0ea3689SLuigi Rizzo (unsigned long long)sent, size, delta); 1341f8e4e36aSLuigi Rizzo if (delta == 0) 1342f8e4e36aSLuigi Rizzo delta = 1e-6; 1343f8e4e36aSLuigi Rizzo if (size < 60) /* correct for min packet size */ 1344f8e4e36aSLuigi Rizzo size = 60; 1345f8e4e36aSLuigi Rizzo pps = sent / delta; 1346f8e4e36aSLuigi Rizzo bw = (8.0 * size * sent) / delta; 1347f8e4e36aSLuigi Rizzo /* raw packets have4 bytes crc + 20 bytes framing */ 1348f8e4e36aSLuigi Rizzo raw_bw = (8.0 * (size + 24) * sent) / delta; 134966a698c9SEd Maste 1350f8e4e36aSLuigi Rizzo printf("Speed: %spps Bandwidth: %sbps (raw %sbps)\n", 1351f8e4e36aSLuigi Rizzo norm(b1, pps), norm(b2, bw), norm(b3, raw_bw) ); 135268b8534bSLuigi Rizzo } 135368b8534bSLuigi Rizzo 135468b8534bSLuigi Rizzo 135568b8534bSLuigi Rizzo static void 135668b8534bSLuigi Rizzo rx_output(uint64_t received, double delta) 135768b8534bSLuigi Rizzo { 1358f8e4e36aSLuigi Rizzo double pps; 1359f8e4e36aSLuigi Rizzo char b1[40]; 136068b8534bSLuigi Rizzo 1361f0ea3689SLuigi Rizzo printf("Received %llu packets, in %.2f seconds.\n", 1362f0ea3689SLuigi Rizzo (unsigned long long) received, delta); 1363f8e4e36aSLuigi Rizzo 1364f8e4e36aSLuigi Rizzo if (delta == 0) 1365f8e4e36aSLuigi Rizzo delta = 1e-6; 1366f8e4e36aSLuigi Rizzo pps = received / delta; 1367f8e4e36aSLuigi Rizzo printf("Speed: %spps\n", norm(b1, pps)); 136868b8534bSLuigi Rizzo } 136968b8534bSLuigi Rizzo 137068b8534bSLuigi Rizzo static void 137168b8534bSLuigi Rizzo usage(void) 137268b8534bSLuigi Rizzo { 137368b8534bSLuigi Rizzo const char *cmd = "pkt-gen"; 137468b8534bSLuigi Rizzo fprintf(stderr, 137568b8534bSLuigi Rizzo "Usage:\n" 137668b8534bSLuigi Rizzo "%s arguments\n" 137768b8534bSLuigi Rizzo "\t-i interface interface name\n" 1378f8e4e36aSLuigi Rizzo "\t-f function tx rx ping pong\n" 1379f8e4e36aSLuigi Rizzo "\t-n count number of iterations (can be 0)\n" 1380f8e4e36aSLuigi Rizzo "\t-t pkts_to_send also forces tx mode\n" 1381f8e4e36aSLuigi Rizzo "\t-r pkts_to_receive also forces rx mode\n" 1382ce3ee1e7SLuigi Rizzo "\t-l pkt_size in bytes excluding CRC\n" 1383ce3ee1e7SLuigi Rizzo "\t-d dst_ip[:port[-dst_ip:port]] single or range\n" 1384ce3ee1e7SLuigi Rizzo "\t-s src_ip[:port[-src_ip:port]] single or range\n" 1385ce3ee1e7SLuigi Rizzo "\t-D dst-mac\n" 1386ce3ee1e7SLuigi Rizzo "\t-S src-mac\n" 1387f8e4e36aSLuigi Rizzo "\t-a cpu_id use setaffinity\n" 138868b8534bSLuigi Rizzo "\t-b burst size testing, mostly\n" 138968b8534bSLuigi Rizzo "\t-c cores cores to use\n" 139068b8534bSLuigi Rizzo "\t-p threads processes/threads to use\n" 139168b8534bSLuigi Rizzo "\t-T report_ms milliseconds between reports\n" 1392f8e4e36aSLuigi Rizzo "\t-P use libpcap instead of netmap\n" 139368b8534bSLuigi Rizzo "\t-w wait_for_link_time in seconds\n" 1394ce3ee1e7SLuigi Rizzo "\t-R rate in packets per second\n" 1395ce3ee1e7SLuigi Rizzo "\t-X dump payload\n" 139617885a7bSLuigi Rizzo "\t-H len add empty virtio-net-header with size 'len'\n" 1397f284c737SGeorge V. Neville-Neil "\t-P file load packet from pcap file" 139868b8534bSLuigi Rizzo "", 139968b8534bSLuigi Rizzo cmd); 140068b8534bSLuigi Rizzo 140168b8534bSLuigi Rizzo exit(0); 140268b8534bSLuigi Rizzo } 140368b8534bSLuigi Rizzo 1404f8e4e36aSLuigi Rizzo static void 1405f8e4e36aSLuigi Rizzo start_threads(struct glob_arg *g) 1406f8e4e36aSLuigi Rizzo { 1407f8e4e36aSLuigi Rizzo int i; 1408f8e4e36aSLuigi Rizzo 1409f8e4e36aSLuigi Rizzo targs = calloc(g->nthreads, sizeof(*targs)); 1410f8e4e36aSLuigi Rizzo /* 1411f8e4e36aSLuigi Rizzo * Now create the desired number of threads, each one 1412f8e4e36aSLuigi Rizzo * using a single descriptor. 1413f8e4e36aSLuigi Rizzo */ 1414f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 1415f0ea3689SLuigi Rizzo struct targ *t = &targs[i]; 1416f0ea3689SLuigi Rizzo 1417f0ea3689SLuigi Rizzo bzero(t, sizeof(*t)); 1418f0ea3689SLuigi Rizzo t->fd = -1; /* default, with pcap */ 1419f0ea3689SLuigi Rizzo t->g = g; 1420f8e4e36aSLuigi Rizzo 1421f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 1422f0ea3689SLuigi Rizzo struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */ 14234bf50f18SLuigi Rizzo uint64_t nmd_flags = 0; 14244bf50f18SLuigi Rizzo nmd.self = &nmd; 1425f8e4e36aSLuigi Rizzo 1426f0ea3689SLuigi Rizzo if (g->nthreads > 1) { 1427f0ea3689SLuigi Rizzo if (nmd.req.nr_flags != NR_REG_ALL_NIC) { 1428f0ea3689SLuigi Rizzo D("invalid nthreads mode %d", nmd.req.nr_flags); 1429f8e4e36aSLuigi Rizzo continue; 1430f8e4e36aSLuigi Rizzo } 1431f0ea3689SLuigi Rizzo nmd.req.nr_flags = NR_REG_ONE_NIC; 1432f0ea3689SLuigi Rizzo nmd.req.nr_ringid = i; 143317885a7bSLuigi Rizzo } 1434f0ea3689SLuigi Rizzo /* Only touch one of the rings (rx is already ok) */ 1435f0ea3689SLuigi Rizzo if (g->td_body == receiver_body) 14364bf50f18SLuigi Rizzo nmd_flags |= NETMAP_NO_TX_POLL; 1437f8e4e36aSLuigi Rizzo 1438f0ea3689SLuigi Rizzo /* register interface. Override ifname and ringid etc. */ 14394bf50f18SLuigi Rizzo if (g->options & OPT_MONITOR_TX) 14404bf50f18SLuigi Rizzo nmd.req.nr_flags |= NR_MONITOR_TX; 14414bf50f18SLuigi Rizzo if (g->options & OPT_MONITOR_RX) 14424bf50f18SLuigi Rizzo nmd.req.nr_flags |= NR_MONITOR_RX; 1443f8e4e36aSLuigi Rizzo 14444bf50f18SLuigi Rizzo t->nmd = nm_open(t->g->ifname, NULL, nmd_flags | 14454bf50f18SLuigi Rizzo NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd); 1446f0ea3689SLuigi Rizzo if (t->nmd == NULL) { 1447f0ea3689SLuigi Rizzo D("Unable to open %s: %s", 1448f0ea3689SLuigi Rizzo t->g->ifname, strerror(errno)); 1449f8e4e36aSLuigi Rizzo continue; 1450f8e4e36aSLuigi Rizzo } 1451f0ea3689SLuigi Rizzo t->fd = t->nmd->fd; 14524bf50f18SLuigi Rizzo set_vnet_hdr_len(t); 1453f0ea3689SLuigi Rizzo 1454f8e4e36aSLuigi Rizzo } else { 1455f8e4e36aSLuigi Rizzo targs[i].fd = g->main_fd; 1456f8e4e36aSLuigi Rizzo } 1457f0ea3689SLuigi Rizzo t->used = 1; 1458f0ea3689SLuigi Rizzo t->me = i; 1459f8e4e36aSLuigi Rizzo if (g->affinity >= 0) { 1460f8e4e36aSLuigi Rizzo if (g->affinity < g->cpus) 1461f0ea3689SLuigi Rizzo t->affinity = g->affinity; 1462f8e4e36aSLuigi Rizzo else 1463f0ea3689SLuigi Rizzo t->affinity = i % g->cpus; 1464f0ea3689SLuigi Rizzo } else { 1465f0ea3689SLuigi Rizzo t->affinity = -1; 1466f0ea3689SLuigi Rizzo } 1467f8e4e36aSLuigi Rizzo /* default, init packets */ 1468f0ea3689SLuigi Rizzo initialize_packet(t); 1469f8e4e36aSLuigi Rizzo 1470f0ea3689SLuigi Rizzo if (pthread_create(&t->thread, NULL, g->td_body, t) == -1) { 147117885a7bSLuigi Rizzo D("Unable to create thread %d: %s", i, strerror(errno)); 1472f0ea3689SLuigi Rizzo t->used = 0; 1473f8e4e36aSLuigi Rizzo } 1474f8e4e36aSLuigi Rizzo } 1475f8e4e36aSLuigi Rizzo } 1476f8e4e36aSLuigi Rizzo 1477f8e4e36aSLuigi Rizzo static void 1478f8e4e36aSLuigi Rizzo main_thread(struct glob_arg *g) 1479f8e4e36aSLuigi Rizzo { 1480f8e4e36aSLuigi Rizzo int i; 1481f8e4e36aSLuigi Rizzo 1482f8e4e36aSLuigi Rizzo uint64_t prev = 0; 1483f8e4e36aSLuigi Rizzo uint64_t count = 0; 1484f8e4e36aSLuigi Rizzo double delta_t; 1485f8e4e36aSLuigi Rizzo struct timeval tic, toc; 1486f8e4e36aSLuigi Rizzo 1487f8e4e36aSLuigi Rizzo gettimeofday(&toc, NULL); 1488f8e4e36aSLuigi Rizzo for (;;) { 1489f8e4e36aSLuigi Rizzo struct timeval now, delta; 1490f8e4e36aSLuigi Rizzo uint64_t pps, usec, my_count, npkts; 1491f8e4e36aSLuigi Rizzo int done = 0; 1492f8e4e36aSLuigi Rizzo 1493f8e4e36aSLuigi Rizzo delta.tv_sec = g->report_interval/1000; 1494f8e4e36aSLuigi Rizzo delta.tv_usec = (g->report_interval%1000)*1000; 1495f8e4e36aSLuigi Rizzo select(0, NULL, NULL, NULL, &delta); 1496f8e4e36aSLuigi Rizzo gettimeofday(&now, NULL); 1497f8e4e36aSLuigi Rizzo timersub(&now, &toc, &toc); 1498f8e4e36aSLuigi Rizzo my_count = 0; 1499f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 1500f8e4e36aSLuigi Rizzo my_count += targs[i].count; 1501f8e4e36aSLuigi Rizzo if (targs[i].used == 0) 1502f8e4e36aSLuigi Rizzo done++; 1503f8e4e36aSLuigi Rizzo } 1504f8e4e36aSLuigi Rizzo usec = toc.tv_sec* 1000000 + toc.tv_usec; 1505f8e4e36aSLuigi Rizzo if (usec < 10000) 1506f8e4e36aSLuigi Rizzo continue; 1507f8e4e36aSLuigi Rizzo npkts = my_count - prev; 1508f8e4e36aSLuigi Rizzo pps = (npkts*1000000 + usec/2) / usec; 1509f0ea3689SLuigi Rizzo D("%llu pps (%llu pkts in %llu usec)", 1510f0ea3689SLuigi Rizzo (unsigned long long)pps, 1511f0ea3689SLuigi Rizzo (unsigned long long)npkts, 1512f0ea3689SLuigi Rizzo (unsigned long long)usec); 1513f8e4e36aSLuigi Rizzo prev = my_count; 1514f8e4e36aSLuigi Rizzo toc = now; 1515f8e4e36aSLuigi Rizzo if (done == g->nthreads) 1516f8e4e36aSLuigi Rizzo break; 1517f8e4e36aSLuigi Rizzo } 1518f8e4e36aSLuigi Rizzo 1519f8e4e36aSLuigi Rizzo timerclear(&tic); 1520f8e4e36aSLuigi Rizzo timerclear(&toc); 1521f8e4e36aSLuigi Rizzo for (i = 0; i < g->nthreads; i++) { 15221cb4c501SLuigi Rizzo struct timespec t_tic, t_toc; 1523f8e4e36aSLuigi Rizzo /* 1524f8e4e36aSLuigi Rizzo * Join active threads, unregister interfaces and close 1525f8e4e36aSLuigi Rizzo * file descriptors. 1526f8e4e36aSLuigi Rizzo */ 15271cb4c501SLuigi Rizzo if (targs[i].used) 1528f8e4e36aSLuigi Rizzo pthread_join(targs[i].thread, NULL); 1529f8e4e36aSLuigi Rizzo close(targs[i].fd); 1530f8e4e36aSLuigi Rizzo 1531f8e4e36aSLuigi Rizzo if (targs[i].completed == 0) 1532f8e4e36aSLuigi Rizzo D("ouch, thread %d exited with error", i); 1533f8e4e36aSLuigi Rizzo 1534f8e4e36aSLuigi Rizzo /* 1535f8e4e36aSLuigi Rizzo * Collect threads output and extract information about 1536f8e4e36aSLuigi Rizzo * how long it took to send all the packets. 1537f8e4e36aSLuigi Rizzo */ 1538f8e4e36aSLuigi Rizzo count += targs[i].count; 15391cb4c501SLuigi Rizzo t_tic = timeval2spec(&tic); 15401cb4c501SLuigi Rizzo t_toc = timeval2spec(&toc); 15411cb4c501SLuigi Rizzo if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) 15421cb4c501SLuigi Rizzo tic = timespec2val(&targs[i].tic); 15431cb4c501SLuigi Rizzo if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc)) 15441cb4c501SLuigi Rizzo toc = timespec2val(&targs[i].toc); 1545f8e4e36aSLuigi Rizzo } 1546f8e4e36aSLuigi Rizzo 1547f8e4e36aSLuigi Rizzo /* print output. */ 1548f8e4e36aSLuigi Rizzo timersub(&toc, &tic, &toc); 1549f8e4e36aSLuigi Rizzo delta_t = toc.tv_sec + 1e-6* toc.tv_usec; 1550f8e4e36aSLuigi Rizzo if (g->td_body == sender_body) 1551f8e4e36aSLuigi Rizzo tx_output(count, g->pkt_size, delta_t); 1552f8e4e36aSLuigi Rizzo else 1553f8e4e36aSLuigi Rizzo rx_output(count, delta_t); 1554f8e4e36aSLuigi Rizzo 1555f8e4e36aSLuigi Rizzo if (g->dev_type == DEV_NETMAP) { 1556f0ea3689SLuigi Rizzo munmap(g->nmd->mem, g->nmd->req.nr_memsize); 1557f8e4e36aSLuigi Rizzo close(g->main_fd); 1558f8e4e36aSLuigi Rizzo } 1559f8e4e36aSLuigi Rizzo } 1560f8e4e36aSLuigi Rizzo 1561f8e4e36aSLuigi Rizzo 1562f8e4e36aSLuigi Rizzo struct sf { 1563f8e4e36aSLuigi Rizzo char *key; 1564f8e4e36aSLuigi Rizzo void *f; 1565f8e4e36aSLuigi Rizzo }; 1566f8e4e36aSLuigi Rizzo 1567f8e4e36aSLuigi Rizzo static struct sf func[] = { 1568f8e4e36aSLuigi Rizzo { "tx", sender_body }, 1569f8e4e36aSLuigi Rizzo { "rx", receiver_body }, 1570f8e4e36aSLuigi Rizzo { "ping", pinger_body }, 1571f8e4e36aSLuigi Rizzo { "pong", ponger_body }, 1572f8e4e36aSLuigi Rizzo { NULL, NULL } 1573f8e4e36aSLuigi Rizzo }; 1574f8e4e36aSLuigi Rizzo 1575f8e4e36aSLuigi Rizzo static int 1576f8e4e36aSLuigi Rizzo tap_alloc(char *dev) 1577f8e4e36aSLuigi Rizzo { 1578f8e4e36aSLuigi Rizzo struct ifreq ifr; 1579f8e4e36aSLuigi Rizzo int fd, err; 1580f8e4e36aSLuigi Rizzo char *clonedev = TAP_CLONEDEV; 1581f8e4e36aSLuigi Rizzo 1582f8e4e36aSLuigi Rizzo (void)err; 1583f8e4e36aSLuigi Rizzo (void)dev; 1584f8e4e36aSLuigi Rizzo /* Arguments taken by the function: 1585f8e4e36aSLuigi Rizzo * 1586f8e4e36aSLuigi Rizzo * char *dev: the name of an interface (or '\0'). MUST have enough 1587f8e4e36aSLuigi Rizzo * space to hold the interface name if '\0' is passed 1588f8e4e36aSLuigi Rizzo * int flags: interface flags (eg, IFF_TUN etc.) 1589f8e4e36aSLuigi Rizzo */ 1590f8e4e36aSLuigi Rizzo 1591f8e4e36aSLuigi Rizzo #ifdef __FreeBSD__ 1592f8e4e36aSLuigi Rizzo if (dev[3]) { /* tapSomething */ 1593f8e4e36aSLuigi Rizzo static char buf[128]; 1594f8e4e36aSLuigi Rizzo snprintf(buf, sizeof(buf), "/dev/%s", dev); 1595f8e4e36aSLuigi Rizzo clonedev = buf; 1596f8e4e36aSLuigi Rizzo } 1597f8e4e36aSLuigi Rizzo #endif 1598f8e4e36aSLuigi Rizzo /* open the device */ 1599f8e4e36aSLuigi Rizzo if( (fd = open(clonedev, O_RDWR)) < 0 ) { 1600f8e4e36aSLuigi Rizzo return fd; 1601f8e4e36aSLuigi Rizzo } 1602f8e4e36aSLuigi Rizzo D("%s open successful", clonedev); 1603f8e4e36aSLuigi Rizzo 1604f8e4e36aSLuigi Rizzo /* preparation of the struct ifr, of type "struct ifreq" */ 1605f8e4e36aSLuigi Rizzo memset(&ifr, 0, sizeof(ifr)); 1606f8e4e36aSLuigi Rizzo 1607f8e4e36aSLuigi Rizzo #ifdef linux 1608f8e4e36aSLuigi Rizzo ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 1609f8e4e36aSLuigi Rizzo 1610f8e4e36aSLuigi Rizzo if (*dev) { 1611f8e4e36aSLuigi Rizzo /* if a device name was specified, put it in the structure; otherwise, 1612f8e4e36aSLuigi Rizzo * the kernel will try to allocate the "next" device of the 1613f8e4e36aSLuigi Rizzo * specified type */ 1614f8e4e36aSLuigi Rizzo strncpy(ifr.ifr_name, dev, IFNAMSIZ); 1615f8e4e36aSLuigi Rizzo } 1616f8e4e36aSLuigi Rizzo 1617f8e4e36aSLuigi Rizzo /* try to create the device */ 1618f8e4e36aSLuigi Rizzo if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { 161917885a7bSLuigi Rizzo D("failed to to a TUNSETIFF: %s", strerror(errno)); 1620f8e4e36aSLuigi Rizzo close(fd); 1621f8e4e36aSLuigi Rizzo return err; 1622f8e4e36aSLuigi Rizzo } 1623f8e4e36aSLuigi Rizzo 1624f8e4e36aSLuigi Rizzo /* if the operation was successful, write back the name of the 1625f8e4e36aSLuigi Rizzo * interface to the variable "dev", so the caller can know 1626f8e4e36aSLuigi Rizzo * it. Note that the caller MUST reserve space in *dev (see calling 1627f8e4e36aSLuigi Rizzo * code below) */ 1628f8e4e36aSLuigi Rizzo strcpy(dev, ifr.ifr_name); 1629f8e4e36aSLuigi Rizzo D("new name is %s", dev); 1630f8e4e36aSLuigi Rizzo #endif /* linux */ 1631f8e4e36aSLuigi Rizzo 1632f8e4e36aSLuigi Rizzo /* this is the special file descriptor that the caller will use to talk 1633f8e4e36aSLuigi Rizzo * with the virtual interface */ 1634f8e4e36aSLuigi Rizzo return fd; 1635f8e4e36aSLuigi Rizzo } 163668b8534bSLuigi Rizzo 163768b8534bSLuigi Rizzo int 163868b8534bSLuigi Rizzo main(int arc, char **argv) 163968b8534bSLuigi Rizzo { 1640f8e4e36aSLuigi Rizzo int i; 164168b8534bSLuigi Rizzo 164268b8534bSLuigi Rizzo struct glob_arg g; 164368b8534bSLuigi Rizzo 164468b8534bSLuigi Rizzo int ch; 164568b8534bSLuigi Rizzo int wait_link = 2; 164668b8534bSLuigi Rizzo int devqueues = 1; /* how many device queues */ 164768b8534bSLuigi Rizzo 164868b8534bSLuigi Rizzo bzero(&g, sizeof(g)); 164968b8534bSLuigi Rizzo 1650f8e4e36aSLuigi Rizzo g.main_fd = -1; 1651f8e4e36aSLuigi Rizzo g.td_body = receiver_body; 1652f8e4e36aSLuigi Rizzo g.report_interval = 1000; /* report interval */ 1653f8e4e36aSLuigi Rizzo g.affinity = -1; 1654f8e4e36aSLuigi Rizzo /* ip addresses can also be a range x.x.x.x-x.x.x.y */ 1655f8e4e36aSLuigi Rizzo g.src_ip.name = "10.0.0.1"; 1656f8e4e36aSLuigi Rizzo g.dst_ip.name = "10.1.0.1"; 1657f8e4e36aSLuigi Rizzo g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; 1658f8e4e36aSLuigi Rizzo g.src_mac.name = NULL; 165968b8534bSLuigi Rizzo g.pkt_size = 60; 166068b8534bSLuigi Rizzo g.burst = 512; // default 166168b8534bSLuigi Rizzo g.nthreads = 1; 166268b8534bSLuigi Rizzo g.cpus = 1; 1663b303f675SLuigi Rizzo g.forever = 1; 16641cb4c501SLuigi Rizzo g.tx_rate = 0; 1665ce3ee1e7SLuigi Rizzo g.frags = 1; 1666ce3ee1e7SLuigi Rizzo g.nmr_config = ""; 166717885a7bSLuigi Rizzo g.virt_header = 0; 166868b8534bSLuigi Rizzo 166968b8534bSLuigi Rizzo while ( (ch = getopt(arc, argv, 1670f284c737SGeorge V. Neville-Neil "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:m:P:")) != -1) { 1671f8e4e36aSLuigi Rizzo struct sf *fn; 1672f8e4e36aSLuigi Rizzo 167368b8534bSLuigi Rizzo switch(ch) { 167468b8534bSLuigi Rizzo default: 167568b8534bSLuigi Rizzo D("bad option %c %s", ch, optarg); 167668b8534bSLuigi Rizzo usage(); 167768b8534bSLuigi Rizzo break; 1678f8e4e36aSLuigi Rizzo 1679f8e4e36aSLuigi Rizzo case 'n': 1680f8e4e36aSLuigi Rizzo g.npackets = atoi(optarg); 1681f8e4e36aSLuigi Rizzo break; 1682f8e4e36aSLuigi Rizzo 1683ce3ee1e7SLuigi Rizzo case 'F': 1684ce3ee1e7SLuigi Rizzo i = atoi(optarg); 1685ce3ee1e7SLuigi Rizzo if (i < 1 || i > 63) { 1686ce3ee1e7SLuigi Rizzo D("invalid frags %d [1..63], ignore", i); 1687ce3ee1e7SLuigi Rizzo break; 1688ce3ee1e7SLuigi Rizzo } 1689ce3ee1e7SLuigi Rizzo g.frags = i; 1690ce3ee1e7SLuigi Rizzo break; 1691ce3ee1e7SLuigi Rizzo 1692f8e4e36aSLuigi Rizzo case 'f': 1693f8e4e36aSLuigi Rizzo for (fn = func; fn->key; fn++) { 1694f8e4e36aSLuigi Rizzo if (!strcmp(fn->key, optarg)) 1695f8e4e36aSLuigi Rizzo break; 1696f8e4e36aSLuigi Rizzo } 1697f8e4e36aSLuigi Rizzo if (fn->key) 1698f8e4e36aSLuigi Rizzo g.td_body = fn->f; 1699f8e4e36aSLuigi Rizzo else 1700f8e4e36aSLuigi Rizzo D("unrecognised function %s", optarg); 1701f8e4e36aSLuigi Rizzo break; 1702f8e4e36aSLuigi Rizzo 1703f8e4e36aSLuigi Rizzo case 'o': /* data generation options */ 170499fb123fSLuigi Rizzo g.options = atoi(optarg); 170599fb123fSLuigi Rizzo break; 1706f8e4e36aSLuigi Rizzo 1707f8e4e36aSLuigi Rizzo case 'a': /* force affinity */ 1708f8e4e36aSLuigi Rizzo g.affinity = atoi(optarg); 1709f8e4e36aSLuigi Rizzo break; 1710f8e4e36aSLuigi Rizzo 171168b8534bSLuigi Rizzo case 'i': /* interface */ 1712f2637526SLuigi Rizzo /* a prefix of tap: netmap: or pcap: forces the mode. 1713f2637526SLuigi Rizzo * otherwise we guess 1714f2637526SLuigi Rizzo */ 1715f2637526SLuigi Rizzo D("interface is %s", optarg); 1716f0ea3689SLuigi Rizzo if (strlen(optarg) > MAX_IFNAMELEN - 8) { 1717f0ea3689SLuigi Rizzo D("ifname too long %s", optarg); 1718f0ea3689SLuigi Rizzo break; 1719f0ea3689SLuigi Rizzo } 1720f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg); 1721f2637526SLuigi Rizzo if (!strcmp(optarg, "null")) { 1722f8e4e36aSLuigi Rizzo g.dev_type = DEV_NETMAP; 1723ce3ee1e7SLuigi Rizzo g.dummy_send = 1; 1724f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap:", 4)) { 1725f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 1726f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 4); 1727f2637526SLuigi Rizzo } else if (!strncmp(optarg, "pcap:", 5)) { 1728f2637526SLuigi Rizzo g.dev_type = DEV_PCAP; 1729f0ea3689SLuigi Rizzo strcpy(g.ifname, optarg + 5); 1730f0ea3689SLuigi Rizzo } else if (!strncmp(optarg, "netmap:", 7) || 1731f0ea3689SLuigi Rizzo !strncmp(optarg, "vale", 4)) { 1732f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 1733f2637526SLuigi Rizzo } else if (!strncmp(optarg, "tap", 3)) { 1734f2637526SLuigi Rizzo g.dev_type = DEV_TAP; 1735f0ea3689SLuigi Rizzo } else { /* prepend netmap: */ 1736f2637526SLuigi Rizzo g.dev_type = DEV_NETMAP; 1737f0ea3689SLuigi Rizzo sprintf(g.ifname, "netmap:%s", optarg); 1738f2637526SLuigi Rizzo } 173968b8534bSLuigi Rizzo break; 1740f8e4e36aSLuigi Rizzo 1741b303f675SLuigi Rizzo case 'I': 1742b303f675SLuigi Rizzo g.options |= OPT_INDIRECT; /* XXX use indirect buffer */ 1743b303f675SLuigi Rizzo break; 1744b303f675SLuigi Rizzo 174568b8534bSLuigi Rizzo case 'l': /* pkt_size */ 174668b8534bSLuigi Rizzo g.pkt_size = atoi(optarg); 174768b8534bSLuigi Rizzo break; 1748f8e4e36aSLuigi Rizzo 174968b8534bSLuigi Rizzo case 'd': 1750f8e4e36aSLuigi Rizzo g.dst_ip.name = optarg; 175168b8534bSLuigi Rizzo break; 1752f8e4e36aSLuigi Rizzo 175368b8534bSLuigi Rizzo case 's': 1754f8e4e36aSLuigi Rizzo g.src_ip.name = optarg; 175568b8534bSLuigi Rizzo break; 1756f8e4e36aSLuigi Rizzo 175768b8534bSLuigi Rizzo case 'T': /* report interval */ 1758f8e4e36aSLuigi Rizzo g.report_interval = atoi(optarg); 175968b8534bSLuigi Rizzo break; 1760f8e4e36aSLuigi Rizzo 176168b8534bSLuigi Rizzo case 'w': 176268b8534bSLuigi Rizzo wait_link = atoi(optarg); 176368b8534bSLuigi Rizzo break; 1764f8e4e36aSLuigi Rizzo 1765b303f675SLuigi Rizzo case 'W': /* XXX changed default */ 1766b303f675SLuigi Rizzo g.forever = 0; /* do not exit rx even with no traffic */ 1767f8e4e36aSLuigi Rizzo break; 1768f8e4e36aSLuigi Rizzo 176968b8534bSLuigi Rizzo case 'b': /* burst */ 177068b8534bSLuigi Rizzo g.burst = atoi(optarg); 177168b8534bSLuigi Rizzo break; 177268b8534bSLuigi Rizzo case 'c': 177368b8534bSLuigi Rizzo g.cpus = atoi(optarg); 177468b8534bSLuigi Rizzo break; 177568b8534bSLuigi Rizzo case 'p': 177668b8534bSLuigi Rizzo g.nthreads = atoi(optarg); 177768b8534bSLuigi Rizzo break; 177868b8534bSLuigi Rizzo 177968b8534bSLuigi Rizzo case 'D': /* destination mac */ 1780f8e4e36aSLuigi Rizzo g.dst_mac.name = optarg; 178168b8534bSLuigi Rizzo break; 1782f8e4e36aSLuigi Rizzo 178368b8534bSLuigi Rizzo case 'S': /* source mac */ 1784f8e4e36aSLuigi Rizzo g.src_mac.name = optarg; 178568b8534bSLuigi Rizzo break; 178668b8534bSLuigi Rizzo case 'v': 178768b8534bSLuigi Rizzo verbose++; 17881cb4c501SLuigi Rizzo break; 17891cb4c501SLuigi Rizzo case 'R': 17901cb4c501SLuigi Rizzo g.tx_rate = atoi(optarg); 17911cb4c501SLuigi Rizzo break; 1792b303f675SLuigi Rizzo case 'X': 1793b303f675SLuigi Rizzo g.options |= OPT_DUMP; 1794ce3ee1e7SLuigi Rizzo break; 1795ce3ee1e7SLuigi Rizzo case 'C': 1796ce3ee1e7SLuigi Rizzo g.nmr_config = strdup(optarg); 179717885a7bSLuigi Rizzo break; 179817885a7bSLuigi Rizzo case 'H': 179917885a7bSLuigi Rizzo g.virt_header = atoi(optarg); 1800f2637526SLuigi Rizzo break; 1801f0ea3689SLuigi Rizzo case 'e': /* extra bufs */ 1802f0ea3689SLuigi Rizzo g.extra_bufs = atoi(optarg); 1803f2637526SLuigi Rizzo break; 18044bf50f18SLuigi Rizzo case 'm': 18054bf50f18SLuigi Rizzo if (strcmp(optarg, "tx") == 0) { 18064bf50f18SLuigi Rizzo g.options |= OPT_MONITOR_TX; 18074bf50f18SLuigi Rizzo } else if (strcmp(optarg, "rx") == 0) { 18084bf50f18SLuigi Rizzo g.options |= OPT_MONITOR_RX; 18094bf50f18SLuigi Rizzo } else { 18104bf50f18SLuigi Rizzo D("unrecognized monitor mode %s", optarg); 18114bf50f18SLuigi Rizzo } 18124bf50f18SLuigi Rizzo break; 1813f284c737SGeorge V. Neville-Neil case 'P': 1814f284c737SGeorge V. Neville-Neil g.packet_file = strdup(optarg); 1815f284c737SGeorge V. Neville-Neil break; 181668b8534bSLuigi Rizzo } 1817f284c737SGeorge V. Neville-Neil 181868b8534bSLuigi Rizzo } 181968b8534bSLuigi Rizzo 1820db6784f2SGeorge V. Neville-Neil if (strlen(g.ifname) <=0 ) { 182168b8534bSLuigi Rizzo D("missing ifname"); 182268b8534bSLuigi Rizzo usage(); 182368b8534bSLuigi Rizzo } 1824f8e4e36aSLuigi Rizzo 1825f8e4e36aSLuigi Rizzo i = system_ncpus(); 1826f8e4e36aSLuigi Rizzo if (g.cpus < 0 || g.cpus > i) { 1827f8e4e36aSLuigi Rizzo D("%d cpus is too high, have only %d cpus", g.cpus, i); 182868b8534bSLuigi Rizzo usage(); 182968b8534bSLuigi Rizzo } 183068b8534bSLuigi Rizzo if (g.cpus == 0) 1831f8e4e36aSLuigi Rizzo g.cpus = i; 1832f8e4e36aSLuigi Rizzo 18334bf50f18SLuigi Rizzo if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) { 18344bf50f18SLuigi Rizzo D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE); 183568b8534bSLuigi Rizzo usage(); 183668b8534bSLuigi Rizzo } 183768b8534bSLuigi Rizzo 1838f8e4e36aSLuigi Rizzo if (g.src_mac.name == NULL) { 1839f8e4e36aSLuigi Rizzo static char mybuf[20] = "00:00:00:00:00:00"; 184099fb123fSLuigi Rizzo /* retrieve source mac address. */ 1841f8e4e36aSLuigi Rizzo if (source_hwaddr(g.ifname, mybuf) == -1) { 184299fb123fSLuigi Rizzo D("Unable to retrieve source mac"); 184399fb123fSLuigi Rizzo // continue, fail later 184499fb123fSLuigi Rizzo } 1845f8e4e36aSLuigi Rizzo g.src_mac.name = mybuf; 184699fb123fSLuigi Rizzo } 1847f8e4e36aSLuigi Rizzo /* extract address ranges */ 1848f8e4e36aSLuigi Rizzo extract_ip_range(&g.src_ip); 1849f8e4e36aSLuigi Rizzo extract_ip_range(&g.dst_ip); 1850f8e4e36aSLuigi Rizzo extract_mac_range(&g.src_mac); 1851f8e4e36aSLuigi Rizzo extract_mac_range(&g.dst_mac); 185299fb123fSLuigi Rizzo 1853f2637526SLuigi Rizzo if (g.src_ip.start != g.src_ip.end || 1854f2637526SLuigi Rizzo g.src_ip.port0 != g.src_ip.port1 || 1855f2637526SLuigi Rizzo g.dst_ip.start != g.dst_ip.end || 1856f2637526SLuigi Rizzo g.dst_ip.port0 != g.dst_ip.port1) 1857f2637526SLuigi Rizzo g.options |= OPT_COPY; 1858f2637526SLuigi Rizzo 185917885a7bSLuigi Rizzo if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 186017885a7bSLuigi Rizzo && g.virt_header != VIRT_HDR_2) { 186117885a7bSLuigi Rizzo D("bad virtio-net-header length"); 186217885a7bSLuigi Rizzo usage(); 186317885a7bSLuigi Rizzo } 186417885a7bSLuigi Rizzo 1865f8e4e36aSLuigi Rizzo if (g.dev_type == DEV_TAP) { 1866f8e4e36aSLuigi Rizzo D("want to use tap %s", g.ifname); 1867f8e4e36aSLuigi Rizzo g.main_fd = tap_alloc(g.ifname); 1868f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 1869f8e4e36aSLuigi Rizzo D("cannot open tap %s", g.ifname); 187099fb123fSLuigi Rizzo usage(); 187199fb123fSLuigi Rizzo } 1872f2637526SLuigi Rizzo #ifndef NO_PCAP 1873f2637526SLuigi Rizzo } else if (g.dev_type == DEV_PCAP) { 1874f8e4e36aSLuigi Rizzo char pcap_errbuf[PCAP_ERRBUF_SIZE]; 1875f8e4e36aSLuigi Rizzo 1876f8e4e36aSLuigi Rizzo pcap_errbuf[0] = '\0'; // init the buffer 18774bf50f18SLuigi Rizzo g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf); 1878f8e4e36aSLuigi Rizzo if (g.p == NULL) { 1879f8e4e36aSLuigi Rizzo D("cannot open pcap on %s", g.ifname); 1880f8e4e36aSLuigi Rizzo usage(); 1881f8e4e36aSLuigi Rizzo } 18824bf50f18SLuigi Rizzo g.main_fd = pcap_fileno(g.p); 18834bf50f18SLuigi Rizzo D("using pcap on %s fileno %d", g.ifname, g.main_fd); 1884f2637526SLuigi Rizzo #endif /* !NO_PCAP */ 1885f2637526SLuigi Rizzo } else if (g.dummy_send) { /* but DEV_NETMAP */ 1886ce3ee1e7SLuigi Rizzo D("using a dummy send routine"); 188799fb123fSLuigi Rizzo } else { 18884bf50f18SLuigi Rizzo struct nmreq base_nmd; 1889f0ea3689SLuigi Rizzo 1890f0ea3689SLuigi Rizzo bzero(&base_nmd, sizeof(base_nmd)); 1891f0ea3689SLuigi Rizzo 18924bf50f18SLuigi Rizzo parse_nmr_config(g.nmr_config, &base_nmd); 1893f0ea3689SLuigi Rizzo if (g.extra_bufs) { 18944bf50f18SLuigi Rizzo base_nmd.nr_arg3 = g.extra_bufs; 1895f0ea3689SLuigi Rizzo } 1896f0ea3689SLuigi Rizzo 189768b8534bSLuigi Rizzo /* 1898f0ea3689SLuigi Rizzo * Open the netmap device using nm_open(). 189968b8534bSLuigi Rizzo * 190068b8534bSLuigi Rizzo * protocol stack and may cause a reset of the card, 190168b8534bSLuigi Rizzo * which in turn may take some time for the PHY to 1902f0ea3689SLuigi Rizzo * reconfigure. We do the open here to have time to reset. 190368b8534bSLuigi Rizzo */ 19044bf50f18SLuigi Rizzo g.nmd = nm_open(g.ifname, &base_nmd, 0, NULL); 1905f0ea3689SLuigi Rizzo if (g.nmd == NULL) { 1906f0ea3689SLuigi Rizzo D("Unable to open %s: %s", g.ifname, strerror(errno)); 1907f0ea3689SLuigi Rizzo goto out; 190868b8534bSLuigi Rizzo } 1909f0ea3689SLuigi Rizzo g.main_fd = g.nmd->fd; 1910f0ea3689SLuigi Rizzo D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem); 1911f0ea3689SLuigi Rizzo 19124bf50f18SLuigi Rizzo /* get num of queues in tx or rx */ 19134bf50f18SLuigi Rizzo if (g.td_body == sender_body) 19144bf50f18SLuigi Rizzo devqueues = g.nmd->req.nr_tx_rings; 19154bf50f18SLuigi Rizzo else 1916f0ea3689SLuigi Rizzo devqueues = g.nmd->req.nr_rx_rings; 191768b8534bSLuigi Rizzo 191868b8534bSLuigi Rizzo /* validate provided nthreads. */ 191968b8534bSLuigi Rizzo if (g.nthreads < 1 || g.nthreads > devqueues) { 192068b8534bSLuigi Rizzo D("bad nthreads %d, have %d queues", g.nthreads, devqueues); 192168b8534bSLuigi Rizzo // continue, fail later 192268b8534bSLuigi Rizzo } 192368b8534bSLuigi Rizzo 1924f2637526SLuigi Rizzo if (verbose) { 1925f0ea3689SLuigi Rizzo struct netmap_if *nifp = g.nmd->nifp; 1926f0ea3689SLuigi Rizzo struct nmreq *req = &g.nmd->req; 192768b8534bSLuigi Rizzo 1928f0ea3689SLuigi Rizzo D("nifp at offset %d, %d tx %d rx region %d", 1929f0ea3689SLuigi Rizzo req->nr_offset, req->nr_tx_rings, req->nr_rx_rings, 1930f0ea3689SLuigi Rizzo req->nr_arg2); 1931f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_tx_rings; i++) { 19324bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_TXRING(nifp, i); 19334bf50f18SLuigi Rizzo D(" TX%d at 0x%lx slots %d", i, 19344bf50f18SLuigi Rizzo (char *)ring - (char *)nifp, ring->num_slots); 1935f2637526SLuigi Rizzo } 1936f0ea3689SLuigi Rizzo for (i = 0; i <= req->nr_rx_rings; i++) { 19374bf50f18SLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(nifp, i); 19384bf50f18SLuigi Rizzo D(" RX%d at 0x%lx slots %d", i, 19394bf50f18SLuigi Rizzo (char *)ring - (char *)nifp, ring->num_slots); 1940f2637526SLuigi Rizzo } 1941f2637526SLuigi Rizzo } 194268b8534bSLuigi Rizzo 194368b8534bSLuigi Rizzo /* Print some debug information. */ 194468b8534bSLuigi Rizzo fprintf(stdout, 194568b8534bSLuigi Rizzo "%s %s: %d queues, %d threads and %d cpus.\n", 1946f8e4e36aSLuigi Rizzo (g.td_body == sender_body) ? "Sending on" : "Receiving from", 1947f8e4e36aSLuigi Rizzo g.ifname, 194868b8534bSLuigi Rizzo devqueues, 194968b8534bSLuigi Rizzo g.nthreads, 195068b8534bSLuigi Rizzo g.cpus); 1951f8e4e36aSLuigi Rizzo if (g.td_body == sender_body) { 195268b8534bSLuigi Rizzo fprintf(stdout, "%s -> %s (%s -> %s)\n", 1953f8e4e36aSLuigi Rizzo g.src_ip.name, g.dst_ip.name, 1954f8e4e36aSLuigi Rizzo g.src_mac.name, g.dst_mac.name); 195568b8534bSLuigi Rizzo } 195668b8534bSLuigi Rizzo 1957f0ea3689SLuigi Rizzo out: 195868b8534bSLuigi Rizzo /* Exit if something went wrong. */ 1959f8e4e36aSLuigi Rizzo if (g.main_fd < 0) { 196068b8534bSLuigi Rizzo D("aborting"); 196168b8534bSLuigi Rizzo usage(); 196268b8534bSLuigi Rizzo } 196399fb123fSLuigi Rizzo } 196468b8534bSLuigi Rizzo 1965ce3ee1e7SLuigi Rizzo 196699fb123fSLuigi Rizzo if (g.options) { 1967b303f675SLuigi Rizzo D("--- SPECIAL OPTIONS:%s%s%s%s%s\n", 196899fb123fSLuigi Rizzo g.options & OPT_PREFETCH ? " prefetch" : "", 196999fb123fSLuigi Rizzo g.options & OPT_ACCESS ? " access" : "", 197099fb123fSLuigi Rizzo g.options & OPT_MEMCPY ? " memcpy" : "", 1971b303f675SLuigi Rizzo g.options & OPT_INDIRECT ? " indirect" : "", 197299fb123fSLuigi Rizzo g.options & OPT_COPY ? " copy" : ""); 197399fb123fSLuigi Rizzo } 19741cb4c501SLuigi Rizzo 1975ce3ee1e7SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; 1976ce3ee1e7SLuigi Rizzo if (g.tx_rate > 0) { 1977ce3ee1e7SLuigi Rizzo /* try to have at least something every second, 197817885a7bSLuigi Rizzo * reducing the burst size to some 0.01s worth of data 1979ce3ee1e7SLuigi Rizzo * (but no less than one full set of fragments) 1980ce3ee1e7SLuigi Rizzo */ 198117885a7bSLuigi Rizzo uint64_t x; 198217885a7bSLuigi Rizzo int lim = (g.tx_rate)/300; 198317885a7bSLuigi Rizzo if (g.burst > lim) 198417885a7bSLuigi Rizzo g.burst = lim; 1985ce3ee1e7SLuigi Rizzo if (g.burst < g.frags) 1986ce3ee1e7SLuigi Rizzo g.burst = g.frags; 198717885a7bSLuigi Rizzo x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate; 198817885a7bSLuigi Rizzo g.tx_period.tv_nsec = x; 19891cb4c501SLuigi Rizzo g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; 19901cb4c501SLuigi Rizzo g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; 19911cb4c501SLuigi Rizzo } 1992ce3ee1e7SLuigi Rizzo if (g.td_body == sender_body) 1993ce3ee1e7SLuigi Rizzo D("Sending %d packets every %ld.%09ld s", 1994ce3ee1e7SLuigi Rizzo g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); 199568b8534bSLuigi Rizzo /* Wait for PHY reset. */ 199668b8534bSLuigi Rizzo D("Wait %d secs for phy reset", wait_link); 199768b8534bSLuigi Rizzo sleep(wait_link); 199868b8534bSLuigi Rizzo D("Ready..."); 199968b8534bSLuigi Rizzo 200068b8534bSLuigi Rizzo /* Install ^C handler. */ 200168b8534bSLuigi Rizzo global_nthreads = g.nthreads; 200268b8534bSLuigi Rizzo signal(SIGINT, sigint_h); 200368b8534bSLuigi Rizzo 2004f8e4e36aSLuigi Rizzo start_threads(&g); 2005f8e4e36aSLuigi Rizzo main_thread(&g); 2006f8e4e36aSLuigi Rizzo return 0; 200768b8534bSLuigi Rizzo } 200868b8534bSLuigi Rizzo 200968b8534bSLuigi Rizzo /* end of file */ 2010