From owner-svn-src-stable@freebsd.org Tue Dec 4 07:30:03 2018 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 16BAF1326F60; Tue, 4 Dec 2018 07:30:03 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id BAFE36A7A3; Tue, 4 Dec 2018 07:30:02 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9C8522204D; Tue, 4 Dec 2018 07:30:02 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wB47U2v6038073; Tue, 4 Dec 2018 07:30:02 GMT (envelope-from vmaffione@FreeBSD.org) Received: (from vmaffione@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wB47U25s038071; Tue, 4 Dec 2018 07:30:02 GMT (envelope-from vmaffione@FreeBSD.org) Message-Id: <201812040730.wB47U25s038071@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: vmaffione set sender to vmaffione@FreeBSD.org using -f From: Vincenzo Maffione Date: Tue, 4 Dec 2018 07:30:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r341457 - stable/11/tools/tools/netmap X-SVN-Group: stable-11 X-SVN-Commit-Author: vmaffione X-SVN-Commit-Paths: stable/11/tools/tools/netmap X-SVN-Commit-Revision: 341457 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: BAFE36A7A3 X-Spamd-Result: default: False [0.25 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-0.42)[-0.423,0]; NEURAL_SPAM_LONG(0.19)[0.192,0]; NEURAL_SPAM_SHORT(0.48)[0.485,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-Rspamd-Server: mx1.freebsd.org X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Dec 2018 07:30:03 -0000 Author: vmaffione Date: Tue Dec 4 07:30:02 2018 New Revision: 341457 URL: https://svnweb.freebsd.org/changeset/base/341457 Log: MFC r340325 netmap: pkt-gen: several updates from upstream Various improvements to the netmap pkt-gen program: - indentation fixes - support for IPV6 - fixes to checksum computation - support for NS_MOREFRAG - rate limiting in ping mode Reviewed by: bcr, 0mp Approved by: gnn (mentor) Differential Revision: https://reviews.freebsd.org/D17698 Modified: stable/11/tools/tools/netmap/pkt-gen.8 stable/11/tools/tools/netmap/pkt-gen.c Directory Properties: stable/11/ (props changed) Modified: stable/11/tools/tools/netmap/pkt-gen.8 ============================================================================== --- stable/11/tools/tools/netmap/pkt-gen.8 Tue Dec 4 06:11:04 2018 (r341456) +++ stable/11/tools/tools/netmap/pkt-gen.8 Tue Dec 4 07:30:02 2018 (r341457) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 23, 2018 +.Dd October 31, 2018 .Dt PKT-GEN 8 .Os .Sh NAME @@ -36,96 +36,215 @@ .Bl -item -compact .It .Nm +.Op Fl h46XzZNIWvrAB .Op Fl i Ar interface .Op Fl f Ar function .Op Fl n Ar count -.Op Fl t Ar pkts_to_send -.Op Fl r Ar pkts_to_receive .Op Fl l Ar pkt_size +.Op Fl b Ar burst_size .Op Fl d Ar dst_ip[:port[-dst_ip:port]] .Op Fl s Ar src_ip[:port[-src_ip:port]] -.Op Fl D Ar dst-mac -.Op Fl S Ar src-mac +.Op Fl D Ar dst_mac +.Op Fl S Ar src_mac .Op Fl a Ar cpu_id -.Op Fl b Ar burst size -.Op Fl c Ar cores +.Op Fl c Ar cpus .Op Fl p Ar threads .Op Fl T Ar report_ms -.Op Fl P +.Op Fl P Ar file .Op Fl w Ar wait_for_link_time .Op Fl R Ar rate -.Op Fl X .Op Fl H Ar len -.Op Fl P Ar xfile -.Op Fl z -.Op Fl Z +.Op Fl F Ar num_frags +.Op Fl M Ar frag_size +.Op Fl C Ar port_config +.El .Sh DESCRIPTION .Nm -generates and receives raw network packets using -.Xr netmap 4 . +leverages +.Xr netmap 4 +to generate and receive raw network packets in batches. The arguments are as follows: -.Pp .Bl -tag -width Ds +.It Fl h +Show program usage and exit. .It Fl i Ar interface -Network interface name. -.It Fl f Ar function tx rx ping pong -Set the function to transmit, receive of ping/pong. -.It Fl n count -Number of iterations (can be 0). -.It Fl t pkts_to_send -Number of packets to send. Also forces transmit mode. -.It Fl r Ar pkts_to_receive -Number of packets to receive. Also forces rx mode. +Name of the network interface that +.Nm +operates on. +It can be a system network interface (e.g., em0), +the name of a +.Xr vale 4 +port (e.g., valeSSS:PPP), the name of a netmap pipe or monitor, +or any valid netmap port name accepted by the +.Ar nm_open +library function, as documented in +.Xr netmap 4 +(NIOCREGIF section). +.It Fl f Ar function +The function to be executed by +.Nm . +Specify +.Cm tx +for transmission, +.Cm rx +for reception, +.Cm ping +for client-side ping-pong operation, and +.Cm pong +for server-side ping-pong operation. +.It Fl n Ar count +Number of iterations of the +.Nm +function, with 0 meaning infinite). +In case of +.Cm tx +or +.Cm rx , +.Ar count +is the number of packets to receive or transmit. +In case of +.Cm ping +or +.Cm pong , +.Ar count +is the number of ping-pong transactions. .It Fl l Ar pkt_size Packet size in bytes excluding CRC. +If passed a second time, use random sizes larger or equal than the +second one and lower than the first one. +.It Fl b Ar burst_size +Transmit or receive up to +.Ar burst_size +packets at a time. +.It Fl 4 +Use IPv4 addresses. +.It Fl 6 +Use IPv6 addresses. .It Fl d Ar dst_ip[:port[-dst_ip:port]] -Destination IPv4 address and port, single or range. +Destination IPv4/IPv6 address and port, single or range. .It Fl s Ar src_ip[:port[-src_ip:port]] -Source IPv4 address and port, single or range. -.It Fl D Ar dst-mac -Destination MAC address in colon notation. -.It Fl S Ar src-mac +Source IPv4/IPv6 address and port, single or range. +.It Fl D Ar dst_mac +Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00). +.It Fl S Ar src_mac Source MAC address in colon notation. .It Fl a Ar cpu_id -Tie +Pin the first thread of .Nm -to a particular CPU core using -.Xr setaffinity 2. -.It Fl b Ar burst size -Set the size of a burst of packets. -.It Fl c Ar cores -Number of cores to use. +to a particular CPU using +.Xr pthread_setaffinity_np 3 . +If more threads are used, they are pinned to the subsequent CPUs, +one per thread. +.It Fl c Ar cpus +Maximum number of CPUs to use (0 means to use all the available ones). .It Fl p Ar threads Number of threads to use. +By default, only a single thread is used +to handle all the netmap rings. +If +.Ar threads +is larger than one, each thread handles a single TX ring (in +.Cm tx +mode), a single RX ring (in +.Cm rx +mode), or a TX/RX ring couple. +The number of +.Ar threads +must be less or equal than the number of TX (or RX) ring available +in the device specified by +.Ar interface . .It Fl T Ar report_ms Number of milliseconds between reports. -.It Fl P -Use libpcap instead of netmap for reading or writing. .It Fl w Ar wait_for_link_time -Number of seconds to wait to make sure that the network link is up. A -network device driver may take some time to create a new -transmit/receive ring pair when +Number of seconds to wait before starting the +.Nm +function, useuful to make sure that the network link is up. +A network device driver may take some time to enter netmap mode, or +to create a new transmit/receive ring pair when .Xr netmap 4 requests one. .It Fl R Ar rate -Packet transmission rate. Not setting the packet transmission rate tells +Packet transmission rate. +Not setting the packet transmission rate tells .Nm -to transmit packets as quickly as possible. On servers from 2010 on-wards +to transmit packets as quickly as possible. +On servers from 2010 on-wards .Xr netmap 4 is able to completely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless your intention is to saturate the link. .It Fl X -Dump payload transmitted or received. +Dump payload of each packet transmitted or received. .It Fl H Ar len -Add empty virtio-net-header with size 'len'. This option is only use -with Virtual Machine technologies that use virtio as a network interface. +Add empty virtio-net-header with size +.Ar len . +Valid sizes are 0, 10 and 12. +This option is only used with Virtual Machine technologies that use virtio +as a network interface. .It Fl P Ar file -Load the packet from a pcap file rather than constructing it inside of -.Nm +Load the packet to be transmitted from a pcap file rather than constructing +it within +.Nm . .It Fl z -Use random IPv4 src address/port +Use random IPv4/IPv6 src address/port. .It Fl Z -Use random IPv4 dst address/port +Use random IPv4/IPv6 dst address/port. +.It Fl N +Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.). +.It Fl F Ar num_frags +Send multi-slot packets, each one with +.Ar num_frags +fragments. +A multi-slot packet is represented by two or more consecutive netmap slots +with the +.Ar NS_MOREFRAG +flag set (except for the last slot). +This is useful to transmit or receive packets larger than the netmap +buffer size. +.It Fl M Ar frag_size +In multi-slot mode, +.Ar frag_size +specifies the size of each fragment, if smaller than the packet length +divided by +.Ar num_frags . +.It Fl I +Use indirect buffers. +It is only valid for transmitting on VALE ports, +and it is implemented by setting the +.Ar NS_INDIRECT +flag in the netmap slots. +.It Fl W +Exit immediately if all the RX rings are empty the first time they are +examined. +.It Fl v +Increase the verbosity level. +.It Fl r +In +.Cm tx +mode, do not initialize packets, but send whatever the content of +the uninitialized netmap buffers is (rubbish mode). +.It Fl A +Compute mean and standard deviation (over a sliding window) for the +transmit or receive rate. +.It Fl B +Take Ethernet framing and CRC into account when computing the average bps. +This adds 4 bytes of CRC and 20 bytes of framing to each packet. +.It Fl C Ar tx_slots Ns Oo Cm \&, Ns Ar rx_slots Ns Oo Cm \&, Ns Ar tx_rings Ns Oo Cm \&, Ns Ar rx_rings Oc Oc Oc +Configuration in terms of number of rings and slots to be used when +opening the netmap port. +Such configuration has effect on software ports +created on the fly, such as VALE ports and netmap pipes. +The configuration may consist of 1 to 4 numbers separated by commas: +.Dq tx_slots,rx_slots,tx_rings,rx_rings . +Missing numbers or zeroes stand for default values. +As an additional convenience, if exactly one number is specified, +then this is assigned to both +.Ar tx_slots +and +.Ar rx_slots . +If there is no fourth number, then the third one is assigned to both +.Ar tx_rings +and +.Ar rx_rings . .El .Pp .Nm @@ -133,7 +252,7 @@ is a raw packet generator that can utilize either .Xr netmap 4 or .Xr bpf 4 -but which is most often uses with +but which is most often used with .Xr netmap 4 . The .Ar interface name @@ -146,7 +265,8 @@ system to balance traffic across the interface. .Nm can peel off one or more of the transmit or receive rings for its own use without interfering with packets that might otherwise be destined -for the host. For example on a system with a Chelsio Network +for the host. +For example on a system with a Chelsio Network Interface Card (NIC) the interface specification of .Ar -i netmap:ncxl0 gives @@ -156,20 +276,20 @@ the more commonly known cxl0 interface, which is used system's TCP/IP stack. .Sh EXAMPLES Capture and count all packets arriving on the operating system's cxl0 -interface. Using this will block packets from reaching the operating +interface. +Using this will block packets from reaching the operating system's network stack. -.Dl +.Bd -literal -offset indent +pkt-gen -i cxl0 -f rx +.Ed .Pp -.Nm --i cxl0 -f rx -.Pp Send a stream of fake DNS packets between two hosts with a packet -length of 128 bytes. You must set the destination MAC address for +length of 128 bytes. +You must set the destination MAC address for packets to be received by the target host. -.Pp -.Dl -.Nm --i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0 +.Bd -literal -offset intent +pkt-gen -i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0 +.Ed .Sh SEE ALSO .Xr netmap 4 , .Xr bridge 8 Modified: stable/11/tools/tools/netmap/pkt-gen.c ============================================================================== --- stable/11/tools/tools/netmap/pkt-gen.c Tue Dec 4 06:11:04 2018 (r341456) +++ stable/11/tools/tools/netmap/pkt-gen.c Tue Dec 4 07:30:02 2018 (r341457) @@ -1,6 +1,6 @@ /* * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. - * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2013-2015 Universita` di Pisa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,8 +37,6 @@ * */ -// #define TRASH_VHOST_HDR - #define _GNU_SOURCE /* for CPU_SET() */ #include #define NETMAP_WITH_LIBS @@ -49,12 +47,21 @@ #include // sysconf() #include #include /* ntohs */ +#ifndef _WIN32 #include /* sysctl */ +#endif #include /* getifaddrs */ #include #include #include #include +#include +#ifdef linux +#define IPV6_VERSION 0x60 +#define IPV6_DEFHLIM 64 +#endif +#include +#include #include @@ -62,6 +69,71 @@ #include #endif +#include "ctrs.h" + +static void usage(int); + +#ifdef _WIN32 +#define cpuset_t DWORD_PTR //uint64_t +static inline void CPU_ZERO(cpuset_t *p) +{ + *p = 0; +} + +static inline void CPU_SET(uint32_t i, cpuset_t *p) +{ + *p |= 1<< (i & 0x3f); +} + +#define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c) //((void)a, 0) +#define TAP_CLONEDEV "/dev/tap" +#define AF_LINK 18 //defined in winsocks.h +#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME +#include + +/* + * Convert an ASCII representation of an ethernet address to + * binary form. + */ +struct ether_addr * +ether_aton(const char *a) +{ + int i; + static struct ether_addr o; + unsigned int o0, o1, o2, o3, o4, o5; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); + + if (i != 6) + return (NULL); + + o.octet[0]=o0; + o.octet[1]=o1; + o.octet[2]=o2; + o.octet[3]=o3; + o.octet[4]=o4; + o.octet[5]=o5; + + return ((struct ether_addr *)&o); +} + +/* + * Convert a binary representation of an ethernet address to + * an ASCII string. + */ +char * +ether_ntoa(const struct ether_addr *n) +{ + int i; + static char a[18]; + + i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", + n->octet[0], n->octet[1], n->octet[2], + n->octet[3], n->octet[4], n->octet[5]); + return (i < 17 ? NULL : (char *)&a); +} +#endif /* _WIN32 */ + #ifdef linux #define cpuset_t cpu_set_t @@ -90,12 +162,12 @@ #define cpuset_t uint64_t // XXX static inline void CPU_ZERO(cpuset_t *p) { - *p = 0; + *p = 0; } static inline void CPU_SET(uint32_t i, cpuset_t *p) { - *p |= 1<< (i & 0x3f); + *p |= 1<< (i & 0x3f); } #define pthread_setaffinity_np(a, b, c) ((void)a, 0) @@ -104,7 +176,7 @@ static inline void CPU_SET(uint32_t i, cpuset_t *p) #define IFF_PPROMISC IFF_PROMISC #include /* LLADDR */ #define clock_gettime(a,b) \ - do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) + do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) #endif /* __APPLE__ */ const char *default_payload="netmap pkt-gen DIRECT payload\n" @@ -114,10 +186,8 @@ const char *indirect_payload="netmap pkt-gen indirect "http://info.iet.unipi.it/~luigi/netmap/ "; int verbose = 0; +int normalize = 1; -#define SKIP_PAYLOAD 1 /* do not check payload. XXX unused */ - - #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ #define VIRT_HDR_MAX VIRT_HDR_2 @@ -130,14 +200,34 @@ struct virt_header { struct pkt { struct virt_header vh; struct ether_header eh; - struct ip ip; - struct udphdr udp; - uint8_t body[MAX_BODYSIZE]; // XXX hardwired + union { + struct { + struct ip ip; + struct udphdr udp; + uint8_t body[MAX_BODYSIZE]; /* hardwired */ + } ipv4; + struct { + struct ip6_hdr ip; + struct udphdr udp; + uint8_t body[MAX_BODYSIZE]; /* hardwired */ + } ipv6; + }; } __attribute__((__packed__)); +#define PKT(p, f, af) \ + ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f) + struct ip_range { char *name; - uint32_t start, end; /* same as struct in_addr */ + union { + struct { + uint32_t start, end; /* same as struct in_addr */ + } ipv4; + struct { + struct in6_addr start, end; + uint8_t sgroup, egroup; + } ipv6; + }; uint16_t port0, port1; }; @@ -162,17 +252,22 @@ struct tstamp { */ struct glob_arg { + int af; /* address family AF_INET/AF_INET6 */ struct ip_range src_ip; struct ip_range dst_ip; struct mac_range dst_mac; struct mac_range src_mac; int pkt_size; + int pkt_min_size; int burst; int forever; - int npackets; /* total packets to send */ - int frags; /* fragments per packet */ + uint64_t npackets; /* total packets to send */ + int frags; /* fragments per packet */ + u_int mtu; /* size of each fragment */ int nthreads; - int cpus; + int cpus; /* cpus used for running */ + int system_cpus; /* cpus on the system */ + int options; /* testing */ #define OPT_PREFETCH 1 #define OPT_ACCESS 2 @@ -181,10 +276,10 @@ struct glob_arg { #define OPT_TS 16 /* add a timestamp */ #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ #define OPT_DUMP 64 /* dump rx/tx traffic */ -#define OPT_MONITOR_TX 128 -#define OPT_MONITOR_RX 256 +#define OPT_RUBBISH 256 /* send wathever the buffers contain */ #define OPT_RANDOM_SRC 512 #define OPT_RANDOM_DST 1024 +#define OPT_PPS_STATS 2048 int dev_type; #ifndef NO_PCAP pcap_t *p; @@ -198,13 +293,18 @@ struct glob_arg { struct nm_desc *nmd; int report_interval; /* milliseconds between prints */ void *(*td_body)(void *); + int td_type; void *mmap_addr; char ifname[MAX_IFNAMELEN]; char *nmr_config; int dummy_send; int virt_header; /* send also the virt_header */ - int extra_bufs; /* goes in nr_arg3 */ char *packet_file; /* -P option */ +#define STATS_WIN 15 + int win_idx; + int64_t win[STATS_WIN]; + int wait_link; + int framing; /* #bits of framing (for bw output) */ }; enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; @@ -220,7 +320,11 @@ struct targ { int cancel; int fd; struct nm_desc *nmd; - volatile uint64_t count; + /* these ought to be volatile, but they are + * only sampled and errors should not accumulate + */ + struct my_ctrs ctr; + struct timespec tic, toc; int me; pthread_t thread; @@ -228,79 +332,166 @@ struct targ { struct pkt pkt; void *frame; + uint16_t seed[3]; + u_int frags; + u_int frag_size; }; +static __inline uint16_t +cksum_add(uint16_t sum, uint16_t a) +{ + uint16_t res; + res = sum + a; + return (res + (res < a)); +} + +static void +extract_ipv4_addr(char *name, uint32_t *addr, uint16_t *port) +{ + struct in_addr a; + char *pp; + + pp = strchr(name, ':'); + if (pp != NULL) { /* do we have ports ? */ + *pp++ = '\0'; + *port = (uint16_t)strtol(pp, NULL, 0); + } + + inet_pton(AF_INET, name, &a); + *addr = ntohl(a.s_addr); +} + +static void +extract_ipv6_addr(char *name, struct in6_addr *addr, uint16_t *port, + uint8_t *group) +{ + char *pp; + + /* + * We accept IPv6 address in the following form: + * group@[2001:DB8::1001]:port (w/ brackets and port) + * group@[2001:DB8::1] (w/ brackets and w/o port) + * group@2001:DB8::1234 (w/o brackets and w/o port) + */ + pp = strchr(name, '@'); + if (pp != NULL) { + *pp++ = '\0'; + *group = (uint8_t)strtol(name, NULL, 0); + if (*group > 7) + *group = 7; + name = pp; + } + if (name[0] == '[') + name++; + pp = strchr(name, ']'); + if (pp != NULL) + *pp++ = '\0'; + if (pp != NULL && *pp != ':') + pp = NULL; + if (pp != NULL) { /* do we have ports ? */ + *pp++ = '\0'; + *port = (uint16_t)strtol(pp, NULL, 0); + } + inet_pton(AF_INET6, name, addr); +} /* * extract the extremes from a range of ipv4 addresses. * addr_lo[-addr_hi][:port_lo[-port_hi]] */ -static void -extract_ip_range(struct ip_range *r) +static int +extract_ip_range(struct ip_range *r, int af) { - char *ap, *pp; + char *name, *ap, start[INET6_ADDRSTRLEN]; + char end[INET6_ADDRSTRLEN]; struct in_addr a; + uint32_t tmp; if (verbose) D("extract IP range from %s", r->name); - r->port0 = r->port1 = 0; - r->start = r->end = 0; + name = strdup(r->name); + if (name == NULL) { + D("strdup failed"); + usage(-1); + } /* the first - splits start/end of range */ - ap = index(r->name, '-'); /* do we have ports ? */ - if (ap) { + ap = strchr(name, '-'); + if (ap != NULL) *ap++ = '\0'; - } - /* grab the initial values (mandatory) */ - pp = index(r->name, ':'); - if (pp) { - *pp++ = '\0'; - r->port0 = r->port1 = strtol(pp, NULL, 0); - }; - inet_aton(r->name, &a); - r->start = r->end = ntohl(a.s_addr); - if (ap) { - pp = index(ap, ':'); - if (pp) { - *pp++ = '\0'; - if (*pp) - r->port1 = strtol(pp, NULL, 0); + r->port0 = 1234; /* default port */ + if (af == AF_INET6) { + r->ipv6.sgroup = 7; /* default group */ + extract_ipv6_addr(name, &r->ipv6.start, &r->port0, + &r->ipv6.sgroup); + } else + extract_ipv4_addr(name, &r->ipv4.start, &r->port0); + + r->port1 = r->port0; + if (af == AF_INET6) { + if (ap != NULL) { + r->ipv6.egroup = r->ipv6.sgroup; + extract_ipv6_addr(ap, &r->ipv6.end, &r->port1, + &r->ipv6.egroup); + } else { + r->ipv6.end = r->ipv6.start; + r->ipv6.egroup = r->ipv6.sgroup; } - if (*ap) { - inet_aton(ap, &a); - r->end = ntohl(a.s_addr); - } + } else { + if (ap != NULL) { + extract_ipv4_addr(ap, &r->ipv4.end, &r->port1); + if (r->ipv4.start > r->ipv4.end) { + tmp = r->ipv4.end; + r->ipv4.end = r->ipv4.start; + r->ipv4.start = tmp; + } + } else + r->ipv4.end = r->ipv4.start; } + if (r->port0 > r->port1) { - uint16_t tmp = r->port0; + tmp = r->port0; r->port0 = r->port1; r->port1 = tmp; } - if (r->start > r->end) { - uint32_t tmp = r->start; - r->start = r->end; - r->end = tmp; + if (af == AF_INET) { + a.s_addr = htonl(r->ipv4.start); + inet_ntop(af, &a, start, sizeof(start)); + a.s_addr = htonl(r->ipv4.end); + inet_ntop(af, &a, end, sizeof(end)); + } else { + inet_ntop(af, &r->ipv6.start, start, sizeof(start)); + inet_ntop(af, &r->ipv6.end, end, sizeof(end)); } - { - struct in_addr a; - char buf1[16]; // one ip address + if (af == AF_INET) + D("range is %s:%d to %s:%d", start, r->port0, end, r->port1); + else + D("range is %d@[%s]:%d to %d@[%s]:%d", r->ipv6.sgroup, + start, r->port0, r->ipv6.egroup, end, r->port1); - a.s_addr = htonl(r->end); - strncpy(buf1, inet_ntoa(a), sizeof(buf1)); - a.s_addr = htonl(r->start); - if (1) - D("range is %s:%d to %s:%d", - inet_ntoa(a), r->port0, buf1, r->port1); - } + free(name); + if (r->port0 != r->port1 || + (af == AF_INET && r->ipv4.start != r->ipv4.end) || + (af == AF_INET6 && + !IN6_ARE_ADDR_EQUAL(&r->ipv6.start, &r->ipv6.end))) + return (OPT_COPY); + return (0); } -static void +static int extract_mac_range(struct mac_range *r) { + struct ether_addr *e; if (verbose) D("extract MAC range from %s", r->name); - bcopy(ether_aton(r->name), &r->start, 6); - bcopy(ether_aton(r->name), &r->end, 6); + + e = ether_aton(r->name); + if (e == NULL) { + D("invalid MAC address '%s'", r->name); + return 1; + } + bcopy(e, &r->start, 6); + bcopy(e, &r->end, 6); #if 0 bcopy(targ->src_mac, eh->ether_shost, 6); p = index(targ->g->src_mac, '-'); @@ -315,6 +506,7 @@ extract_mac_range(struct mac_range *r) #endif if (verbose) D("%s starts at %s", r->name, ether_ntoa(&r->start)); + return 0; } static struct targ *targs; @@ -327,11 +519,10 @@ sigint_h(int sig) int i; (void)sig; /* UNUSED */ - D("received control-C on thread %p", pthread_self()); + D("received control-C on thread %p", (void *)pthread_self()); for (i = 0; i < global_nthreads; i++) { targs[i].cancel = 1; } - signal(SIGINT, SIG_DFL); } /* sysctl wrapper to return the number of active CPUs */ @@ -345,6 +536,12 @@ system_ncpus(void) sysctl(mib, 2, &ncpus, &len, NULL, 0); #elif defined(linux) ncpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_WIN32) + { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + ncpus = sysinfo.dwNumberOfProcessors; + } #else /* others */ ncpus = 1; #endif /* others */ @@ -375,7 +572,7 @@ system_ncpus(void) /* * parse the vale configuration in conf and put it in nmr. * Return the flag set if necessary. - * The configuration may consist of 0 to 4 numbers separated + * The configuration may consist of 1 to 4 numbers separated * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings. * Missing numbers or zeroes stand for default values. * As an additional convenience, if exactly one number @@ -419,7 +616,7 @@ parse_nmr_config(const char* conf, struct nmreq *nmr) nmr->nr_rx_rings, nmr->nr_rx_slots); free(w); return (nmr->nr_tx_rings || nmr->nr_tx_slots || - nmr->nr_rx_rings || nmr->nr_rx_slots) ? + nmr->nr_rx_rings || nmr->nr_rx_slots) ? NM_OPEN_RING_CFG : 0; } @@ -432,7 +629,6 @@ static int source_hwaddr(const char *ifname, char *buf) { struct ifaddrs *ifaphead, *ifap; - int l = sizeof(ifap->ifa_name); if (getifaddrs(&ifaphead) != 0) { D("getifaddrs %s failed", ifname); @@ -446,7 +642,7 @@ source_hwaddr(const char *ifname, char *buf) if (!sdl || sdl->sdl_family != AF_LINK) continue; - if (strncmp(ifap->ifa_name, ifname, l) != 0) + if (strncmp(ifap->ifa_name, ifname, IFNAMSIZ) != 0) continue; mac = (uint8_t *)LLADDR(sdl); sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", @@ -481,19 +677,20 @@ setaffinity(pthread_t me, int i) return 0; } + /* Compute the checksum of the given ip header. */ -static uint16_t +static uint32_t checksum(const void *data, uint16_t len, uint32_t sum) { - const uint8_t *addr = data; + const uint8_t *addr = data; uint32_t i; - /* Checksum all the pairs of bytes first... */ - for (i = 0; i < (len & ~1U); i += 2) { - sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); - if (sum > 0xFFFF) - sum -= 0xFFFF; - } + /* Checksum all the pairs of bytes first... */ + for (i = 0; i < (len & ~1U); i += 2) { + sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } /* * If there's a single byte left over, checksum it, too. * Network byte order is big-endian, so the remaining byte is @@ -507,8 +704,8 @@ checksum(const void *data, uint16_t len, uint32_t sum) return sum; } -static u_int16_t -wrapsum(u_int32_t sum) +static uint16_t +wrapsum(uint32_t sum) { sum = ~sum & 0xFFFF; return (htons(sum)); @@ -518,10 +715,11 @@ wrapsum(u_int32_t sum) * Look for consecutive ascii representations of the size of the packet. */ static void -dump_payload(char *p, int len, struct netmap_ring *ring, int cur) +dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) { char buf[128]; int i, j, i0; + const unsigned char *p = (const unsigned char *)_p; /* get the length in ASCII of the length of the packet. */ @@ -530,7 +728,7 @@ dump_payload(char *p, int len, struct netmap_ring *rin ring->slot[cur].flags, len); /* hexdump routine */ for (i = 0; i < len; ) { - memset(buf, sizeof(buf), ' '); + memset(buf, ' ', sizeof(buf)); sprintf(buf, "%5d: ", i); i0 = i; for (j=0; j < 16 && i < len; i++, j++) @@ -555,64 +753,198 @@ dump_payload(char *p, int len, struct netmap_ring *rin #define uh_sum check #endif /* linux */ -/* - * increment the addressed in the packet, - * starting from the least significant field. - * DST_IP DST_PORT SRC_IP SRC_PORT - */ static void -update_addresses(struct pkt *pkt, struct glob_arg *g) +update_ip(struct pkt *pkt, struct targ *t) { - uint32_t a; - uint16_t p; - struct ip *ip = &pkt->ip; - struct udphdr *udp = &pkt->udp; + struct glob_arg *g = t->g; + struct ip ip; + struct udphdr udp; + uint32_t oaddr, naddr; + uint16_t oport, nport; + uint16_t ip_sum, udp_sum; - do { - /* XXX for now it doesn't handle non-random src, random dst */ - if (g->options & OPT_RANDOM_SRC) { - udp->uh_sport = random(); - ip->ip_src.s_addr = random(); - } else { - p = ntohs(udp->uh_sport); - if (p < g->src_ip.port1) { /* just inc, no wrap */ - udp->uh_sport = htons(p + 1); + memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); + memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); + do { + ip_sum = udp_sum = 0; + naddr = oaddr = ntohl(ip.ip_src.s_addr); + nport = oport = ntohs(udp.uh_sport); + if (g->options & OPT_RANDOM_SRC) { + ip.ip_src.s_addr = nrand48(t->seed); + udp.uh_sport = nrand48(t->seed); + naddr = ntohl(ip.ip_src.s_addr); + nport = ntohs(udp.uh_sport); break; } - udp->uh_sport = htons(g->src_ip.port0); - - a = ntohl(ip->ip_src.s_addr); - if (a < g->src_ip.end) { /* just inc, no wrap */ - ip->ip_src.s_addr = htonl(a + 1); + if (oport < g->src_ip.port1) { + nport = oport + 1; + udp.uh_sport = htons(nport); break; } - ip->ip_src.s_addr = htonl(g->src_ip.start); - - udp->uh_sport = htons(g->src_ip.port0); + nport = g->src_ip.port0; + udp.uh_sport = htons(nport); + if (oaddr < g->src_ip.ipv4.end) { + naddr = oaddr + 1; + ip.ip_src.s_addr = htonl(naddr); + break; + } + naddr = g->src_ip.ipv4.start; + ip.ip_src.s_addr = htonl(naddr); + } while (0); + /* update checksums if needed */ + if (oaddr != naddr) { + ip_sum = cksum_add(ip_sum, ~oaddr >> 16); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***