Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Nov 2018 08:55:26 +0000 (UTC)
From:      Vincenzo Maffione <vmaffione@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r340619 - stable/12/tools/tools/netmap
Message-ID:  <201811190855.wAJ8tQMG097816@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: vmaffione
Date: Mon Nov 19 08:55:26 2018
New Revision: 340619
URL: https://svnweb.freebsd.org/changeset/base/340619

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
  
  Differential Revision:  https://reviews.freebsd.org/D17698

Modified:
  stable/12/tools/tools/netmap/pkt-gen.8
  stable/12/tools/tools/netmap/pkt-gen.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/tools/tools/netmap/pkt-gen.8
==============================================================================
--- stable/12/tools/tools/netmap/pkt-gen.8	Mon Nov 19 08:53:52 2018	(r340618)
+++ stable/12/tools/tools/netmap/pkt-gen.8	Mon Nov 19 08:55:26 2018	(r340619)
@@ -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/12/tools/tools/netmap/pkt-gen.c
==============================================================================
--- stable/12/tools/tools/netmap/pkt-gen.c	Mon Nov 19 08:53:52 2018	(r340618)
+++ stable/12/tools/tools/netmap/pkt-gen.c	Mon Nov 19 08:55:26 2018	(r340619)
@@ -55,6 +55,11 @@
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/udp.h>
+#include <netinet/ip6.h>
+#ifdef linux
+#define IPV6_VERSION	0x60
+#define IPV6_DEFHLIM	64
+#endif
 #include <assert.h>
 #include <math.h>
 
@@ -66,16 +71,18 @@
 
 #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;
+	*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) !SetThreadAffinityMask(a, *c)    //((void)a, 0)
@@ -155,12 +162,12 @@ ether_ntoa(const struct ether_addr *n)
 #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)
@@ -169,7 +176,7 @@ static inline void CPU_SET(uint32_t i, cpuset_t *p)
 #define IFF_PPROMISC   IFF_PROMISC
 #include <net/if_dl.h>  /* 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"
@@ -179,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
@@ -195,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;
 };
 
@@ -227,15 +252,18 @@ 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;
 	uint64_t npackets;	/* total packets to send */
-	int frags;	/* fragments per packet */
+	int frags;		/* fragments per packet */
+	u_int mtu;		/* size of each fragment */
 	int nthreads;
 	int cpus;	/* cpus used for running */
 	int system_cpus;	/* cpus on the system */
@@ -271,12 +299,12 @@ struct glob_arg {
 	char *nmr_config;
 	int dummy_send;
 	int virt_header;	/* send also the virt_header */
-	int extra_bufs;		/* goes in nr_arg3 */
-	int extra_pipes;	/* goes in nr_arg1 */
 	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 };
 
@@ -304,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, '-');
@@ -391,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;
@@ -456,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
@@ -500,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;
 }
 
@@ -513,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);
@@ -527,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",
@@ -562,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
@@ -588,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));
@@ -637,64 +753,198 @@ dump_payload(const char *_p, int len, struct netmap_ri
 #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);
+		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
+		ip_sum = cksum_add(ip_sum, naddr >> 16);
+		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
 	}
-
-	if (g->options & OPT_RANDOM_DST) {
-		udp->uh_dport = random();
-		ip->ip_dst.s_addr = random();
-	} else {
-		p = ntohs(udp->uh_dport);
-		if (p < g->dst_ip.port1) { /* just inc, no wrap */
-			udp->uh_dport = htons(p + 1);
+	if (oport != nport) {
+		udp_sum = cksum_add(udp_sum, ~oport);
+		udp_sum = cksum_add(udp_sum, nport);
+	}
+	do {
+		naddr = oaddr = ntohl(ip.ip_dst.s_addr);
+		nport = oport = ntohs(udp.uh_dport);
+		if (g->options & OPT_RANDOM_DST) {
+			ip.ip_dst.s_addr = nrand48(t->seed);
+			udp.uh_dport = nrand48(t->seed);
+			naddr = ntohl(ip.ip_dst.s_addr);
+			nport = ntohs(udp.uh_dport);
 			break;
 		}
-		udp->uh_dport = htons(g->dst_ip.port0);
-
-		a = ntohl(ip->ip_dst.s_addr);
-		if (a < g->dst_ip.end) { /* just inc, no wrap */
-			ip->ip_dst.s_addr = htonl(a + 1);
+		if (oport < g->dst_ip.port1) {
+			nport = oport + 1;
+			udp.uh_dport = htons(nport);
 			break;
 		}
+		nport = g->dst_ip.port0;
+		udp.uh_dport = htons(nport);
+		if (oaddr < g->dst_ip.ipv4.end) {
+			naddr = oaddr + 1;
+			ip.ip_dst.s_addr = htonl(naddr);
+			break;
+		}
+		naddr = g->dst_ip.ipv4.start;
+		ip.ip_dst.s_addr = htonl(naddr);
+	} while (0);
+	/* update checksums */
+	if (oaddr != naddr) {
+		ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
+		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
+		ip_sum = cksum_add(ip_sum, naddr >> 16);
+		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
 	}
-	ip->ip_dst.s_addr = htonl(g->dst_ip.start);
-    } while (0);
-    // update checksum
+	if (oport != nport) {
+		udp_sum = cksum_add(udp_sum, ~oport);
+		udp_sum = cksum_add(udp_sum, nport);
+	}
+	if (udp_sum != 0)
+		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum));
+	if (ip_sum != 0) {
+		ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum));
+		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum));
+	}
+	memcpy(&pkt->ipv4.ip, &ip, sizeof(ip));
+	memcpy(&pkt->ipv4.udp, &udp, sizeof(udp));
 }
 
+#ifndef s6_addr16
+#define	s6_addr16	__u6_addr.__u6_addr16
+#endif
+static void
+update_ip6(struct pkt *pkt, struct targ *t)
+{
+	struct glob_arg *g = t->g;
+	struct ip6_hdr ip6;
+	struct udphdr udp;
+	uint16_t udp_sum;
+	uint16_t oaddr, naddr;
+	uint16_t oport, nport;
+	uint8_t group;
+
+	memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6));
+	memcpy(&udp, &pkt->ipv6.udp, sizeof(udp));
+	do {
+		udp_sum = 0;
+		group = g->src_ip.ipv6.sgroup;
+		naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]);
+		nport = oport = ntohs(udp.uh_sport);
+		if (g->options & OPT_RANDOM_SRC) {
+			ip6.ip6_src.s6_addr16[group] = nrand48(t->seed);
+			udp.uh_sport = nrand48(t->seed);
+			naddr = ntohs(ip6.ip6_src.s6_addr16[group]);
+			nport = ntohs(udp.uh_sport);
+			break;
+		}
+		if (oport < g->src_ip.port1) {
+			nport = oport + 1;
+			udp.uh_sport = htons(nport);
+			break;
+		}
+		nport = g->src_ip.port0;
+		udp.uh_sport = htons(nport);
+		if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) {
+			naddr = oaddr + 1;
+			ip6.ip6_src.s6_addr16[group] = htons(naddr);
+			break;
+		}
+		naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]);
+		ip6.ip6_src.s6_addr16[group] = htons(naddr);
+	} while (0);
+	/* update checksums if needed */
+	if (oaddr != naddr)
+		udp_sum = cksum_add(~oaddr, naddr);
+	if (oport != nport)
+		udp_sum = cksum_add(udp_sum,
+		    cksum_add(~oport, nport));
+	do {
+		group = g->dst_ip.ipv6.egroup;
+		naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
+		nport = oport = ntohs(udp.uh_dport);
+		if (g->options & OPT_RANDOM_DST) {
+			ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed);
+			udp.uh_dport = nrand48(t->seed);
+			naddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
+			nport = ntohs(udp.uh_dport);
+			break;
+		}
+		if (oport < g->dst_ip.port1) {
+			nport = oport + 1;
+			udp.uh_dport = htons(nport);
+			break;
+		}
+		nport = g->dst_ip.port0;
+		udp.uh_dport = htons(nport);
+		if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) {
+			naddr = oaddr + 1;
+			ip6.ip6_dst.s6_addr16[group] = htons(naddr);
+			break;
+		}
+		naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]);
+		ip6.ip6_dst.s6_addr16[group] = htons(naddr);
+	} while (0);
+	/* update checksums */
+	if (oaddr != naddr)
+		udp_sum = cksum_add(udp_sum,
+		    cksum_add(~oaddr, naddr));
+	if (oport != nport)
+		udp_sum = cksum_add(udp_sum,
+		    cksum_add(~oport, nport));
+	if (udp_sum != 0)
+		udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum);
+	memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6));
+	memcpy(&pkt->ipv6.udp, &udp, sizeof(udp));
+}
+
+static void
+update_addresses(struct pkt *pkt, struct targ *t)
+{
+
+	if (t->g->af == AF_INET)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811190855.wAJ8tQMG097816>