[Midnightbsd-cvs] src [11935] trunk/tools/tools/netrate/netsend: update

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Jul 21 13:04:22 EDT 2018


Revision: 11935
          http://svnweb.midnightbsd.org/src/?rev=11935
Author:   laffer1
Date:     2018-07-21 13:04:20 -0400 (Sat, 21 Jul 2018)
Log Message:
-----------
update

Modified Paths:
--------------
    trunk/tools/tools/netrate/netsend/Makefile
    trunk/tools/tools/netrate/netsend/netsend.c

Modified: trunk/tools/tools/netrate/netsend/Makefile
===================================================================
--- trunk/tools/tools/netrate/netsend/Makefile	2018-07-21 16:54:16 UTC (rev 11934)
+++ trunk/tools/tools/netrate/netsend/Makefile	2018-07-21 17:04:20 UTC (rev 11935)
@@ -1,9 +1,10 @@
+# $MidnightBSD$
 #
-# $FreeBSD: src/tools/tools/netrate/netsend/Makefile,v 1.4 2004/12/21 08:47:28 ru Exp $
+# $FreeBSD: stable/10/tools/tools/netrate/netsend/Makefile 276486 2014-12-31 23:25:37Z ngie $
 #
 
 CFLAGS+=	-Wall
 PROG=	netsend
-NO_MAN=
+MAN=
 
 .include <bsd.prog.mk>

Modified: trunk/tools/tools/netrate/netsend/netsend.c
===================================================================
--- trunk/tools/tools/netrate/netsend/netsend.c	2018-07-21 16:54:16 UTC (rev 11934)
+++ trunk/tools/tools/netrate/netsend/netsend.c	2018-07-21 17:04:20 UTC (rev 11935)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2004 Robert N. M. Watson
  * All rights reserved.
@@ -23,11 +24,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/tools/tools/netrate/netsend/netsend.c,v 1.8 2005/04/21 19:28:22 mux Exp $
+ * $FreeBSD: stable/10/tools/tools/netrate/netsend/netsend.c 244731 2012-12-27 09:15:21Z luigi $
  */
 
+#include <sys/endian.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <net/if.h>		/* if_nametoindex() */
 #include <sys/time.h>
 
 #include <netinet/in.h>
@@ -39,12 +42,27 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <netdb.h>
+
+/* program arguments */
+struct _a {
+	int s;
+	int ipv6;
+	struct timespec interval;
+	int port, port_max;
+	long duration;
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+	int packet_len;
+	void *packet;
+};
+
 static void
 usage(void)
 {
 
 	fprintf(stderr,
-	    "netsend [ip] [port] [payloadsize] [rate] [duration]\n");
+	    "netsend [ip] [port[-port_max]] [payloadsize] [packet_rate] [duration]\n");
 	exit(-1);
 }
 
@@ -114,10 +132,12 @@
  * Calculate a second-aligned starting time for the packet stream.  Busy
  * wait between our calculated interval and dropping the provided packet
  * into the socket.  If we hit our duration limit, bail.
+ * We sweep the ports from a->port to a->port_max included.
+ * If the two ports are the same we connect() the socket upfront, which
+ * almost halves the cost of the sendto() call.
  */
 static int
-timing_loop(int s, struct timespec interval, long duration, u_char *packet,
-    u_int packet_len)
+timing_loop(struct _a *a)
 {
 	struct timespec nexttime, starttime, tmptime;
 	long long waited;
@@ -124,6 +144,11 @@
 	u_int32_t counter;
 	long finishtime;
 	long send_errors, send_calls;
+	/* do not call gettimeofday more than every 20us */
+	long minres_ns = 200000;
+	int ic, gettimeofday_cycles;
+	int cur_port;
+	uint64_t n, ns;
 
 	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
 		perror("clock_getres");
@@ -130,10 +155,22 @@
 		return (-1);
 	}
 
-	if (timespec_ge(&tmptime, &interval))
+	ns = a->interval.tv_nsec;
+	if (timespec_ge(&tmptime, &a->interval))
 		fprintf(stderr,
-		    "warning: interval less than resolution (%jd.%09ld)\n",
+		    "warning: interval (%jd.%09ld) less than resolution (%jd.%09ld)\n",
+		    (intmax_t)a->interval.tv_sec, a->interval.tv_nsec,
 		    (intmax_t)tmptime.tv_sec, tmptime.tv_nsec);
+		/* interval too short, limit the number of gettimeofday()
+		 * calls, but also make sure there is at least one every
+		 * some 100 packets.
+		 */
+	if ((long)ns < minres_ns/100)
+		gettimeofday_cycles = 100;
+	else
+		gettimeofday_cycles = minres_ns/ns;
+	fprintf(stderr,
+	    "calling time every %d cycles\n", gettimeofday_cycles);
 
 	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
 		perror("clock_gettime");
@@ -146,15 +183,35 @@
 	if (wait_time(starttime, NULL, NULL) == -1)
 		return (-1);
 	nexttime = starttime;
-	finishtime = starttime.tv_sec + duration;
+	finishtime = starttime.tv_sec + a->duration;
 
 	send_errors = send_calls = 0;
 	counter = 0;
 	waited = 0;
+	ic = gettimeofday_cycles;
+	cur_port = a->port;
+	if (a->port == a->port_max) {
+		if (a->ipv6) {
+			if (connect(a->s, (struct sockaddr *)&a->sin6, sizeof(a->sin6))) {
+				perror("connect (ipv6)");
+				return (-1);
+			}
+		} else {
+			if (connect(a->s, (struct sockaddr *)&a->sin, sizeof(a->sin))) {
+				perror("connect (ipv4)");
+				return (-1);
+			}
+		}
+	}
 	while (1) {
-		timespec_add(&nexttime, &interval);
-		if (wait_time(nexttime, &tmptime, &waited) == -1)
-			return (-1);
+		int ret;
+
+		timespec_add(&nexttime, &a->interval);
+		if (--ic <= 0) {
+			ic = gettimeofday_cycles;
+			if (wait_time(nexttime, &tmptime, &waited) == -1)
+				return (-1);
+		}
 		/*
 		 * We maintain and, if there's room, send a counter.  Note
 		 * that even if the error is purely local, we still increment
@@ -164,17 +221,31 @@
 		 * previous send, the error will turn up the current send
 		 * operation, causing the current sequence number also to be
 		 * skipped.
-		 *
-		 * XXXRW: Note alignment assumption.
+		 * The counter is incremented only on the initial port number,
+		 * so all destinations will see the same set of packets.
 		 */
-		if (packet_len >= 4) {
-			*((u_int32_t *)packet) = htonl(counter);
+		if (cur_port == a->port && a->packet_len >= 4) {
+			be32enc(a->packet, counter);
 			counter++;
 		}
-		if (send(s, packet, packet_len, 0) < 0)
+		if (a->port == a->port_max) { /* socket already bound */
+			ret = send(a->s, a->packet, a->packet_len, 0);
+		} else {
+			a->sin.sin_port = htons(cur_port++);
+			if (cur_port > a->port_max)
+				cur_port = a->port;
+			if (a->ipv6) {
+			ret = sendto(a->s, a->packet, a->packet_len, 0,
+			    (struct sockaddr *)&a->sin6, sizeof(a->sin6));
+			} else {
+			ret = sendto(a->s, a->packet, a->packet_len, 0,
+				(struct sockaddr *)&a->sin, sizeof(a->sin));
+			}
+		}
+		if (ret < 0)
 			send_errors++;
 		send_calls++;
-		if (duration != 0 && tmptime.tv_sec >= finishtime)
+		if (a->duration != 0 && tmptime.tv_sec >= finishtime)
 			goto done;
 	}
 
@@ -191,11 +262,18 @@
 	    tmptime.tv_nsec);
 	printf("send calls:        %ld\n", send_calls);
 	printf("send errors:       %ld\n", send_errors);
-	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
-	    duration);
+	printf("approx send rate:  %ld pps\n", (send_calls - send_errors) /
+	    a->duration);
+	n = send_calls - send_errors;
+	if (n > 0) {
+		ns = (tmptime.tv_sec - starttime.tv_sec) * 1000000000UL +
+			(tmptime.tv_nsec - starttime.tv_nsec);
+		n = ns / n;
+	}
+	printf("time/packet:       %u ns\n", (u_int)n);
 	printf("approx error rate: %ld\n", (send_errors / send_calls));
 	printf("waited:            %lld\n", waited);
-	printf("approx waits/sec:  %lld\n", (long long)(waited / duration));
+	printf("approx waits/sec:  %lld\n", (long long)(waited / a->duration));
 	printf("approx wait rate:  %lld\n", (long long)(waited / send_calls));
 
 	return (0);
@@ -204,27 +282,58 @@
 int
 main(int argc, char *argv[])
 {
-	long rate, payloadsize, port, duration;
-	struct timespec interval;
-	struct sockaddr_in sin;
-	char *dummy, *packet;
-	int s;
+	long rate, payloadsize, port;
+	char *dummy;
+	struct _a a;	/* arguments */
+	struct addrinfo hints, *res, *ressave;
 
+	bzero(&a, sizeof(a));
+
 	if (argc != 6)
 		usage();
 
-	bzero(&sin, sizeof(sin));
-	sin.sin_len = sizeof(sin);
-	sin.sin_family = AF_INET;
-	if (inet_aton(argv[1], &sin.sin_addr) == 0) {
-		perror(argv[1]);
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+
+	if (getaddrinfo(argv[1], NULL, &hints, &res) != 0) {
+		fprintf(stderr, "Couldn't resolv %s\n", argv[1]);
 		return (-1);
 	}
+	ressave = res;
+	while (res) {
+		if (res->ai_family == AF_INET) {
+			memcpy(&a.sin, res->ai_addr, res->ai_addrlen);
+			a.ipv6 = 0;
+			break;
+		} else if (res->ai_family == AF_INET6) {
+			memcpy(&a.sin6, res->ai_addr, res->ai_addrlen);
+			a.ipv6 = 1;
+			break;
+		} 
+		res = res->ai_next;
+	}
+	if (!res) {
+		fprintf(stderr, "Couldn't resolv %s\n", argv[1]);
+		exit(1);
+	}
+	freeaddrinfo(ressave);
 
 	port = strtoul(argv[2], &dummy, 10);
-	if (port < 1 || port > 65535 || *dummy != '\0')
+	if (port < 1 || port > 65535)
 		usage();
-	sin.sin_port = htons(port);
+	if (*dummy != '\0' && *dummy != '-')
+		usage();
+	if (a.ipv6)
+		a.sin6.sin6_port = htons(port);
+	else
+		a.sin.sin_port = htons(port);
+	a.port = a.port_max = port;
+	if (*dummy == '-') {	/* set high port */
+		port = strtoul(dummy + 1, &dummy, 10);
+		if (port < a.port || port > 65535)
+			usage();
+		a.port_max = port;
+	}
 
 	payloadsize = strtoul(argv[3], &dummy, 10);
 	if (payloadsize < 0 || *dummy != '\0')
@@ -233,55 +342,54 @@
 		fprintf(stderr, "payloadsize > 32768\n");
 		return (-1);
 	}
+	a.packet_len = payloadsize;
 
 	/*
 	 * Specify an arbitrary limit.  It's exactly that, not selected by
-	 .* any particular strategy.  '0' is a special value meaning "blast",
+	 * any particular strategy.  '0' is a special value meaning "blast",
 	 * and avoids the cost of a timing loop.
 	 */
 	rate = strtoul(argv[4], &dummy, 10);
-	if (rate < 1 || *dummy != '\0')
+	if (rate < 0 || *dummy != '\0')
 		usage();
 	if (rate > MAX_RATE) {
-		fprintf(stderr, "rate > %d\n", MAX_RATE);
+		fprintf(stderr, "packet rate at most %d\n", MAX_RATE);
 		return (-1);
 	}
 
-	duration = strtoul(argv[5], &dummy, 10);
-	if (duration < 0 || *dummy != '\0')
+	a.duration = strtoul(argv[5], &dummy, 10);
+	if (a.duration < 0 || *dummy != '\0')
 		usage();
 
-	packet = malloc(payloadsize);
-	if (packet == NULL) {
+	a.packet = malloc(payloadsize);
+	if (a.packet == NULL) {
 		perror("malloc");
 		return (-1);
 	}
-	bzero(packet, payloadsize);
-
+	bzero(a.packet, payloadsize);
 	if (rate == 0) {
-		interval.tv_sec = 0;
-		interval.tv_nsec = 0;
+		a.interval.tv_sec = 0;
+		a.interval.tv_nsec = 0;
 	} else if (rate == 1) {
-		interval.tv_sec = 1;
-		interval.tv_nsec = 0;
+		a.interval.tv_sec = 1;
+		a.interval.tv_nsec = 0;
 	} else {
-		interval.tv_sec = 0;
-		interval.tv_nsec = ((1 * 1000000000) / rate);
+		a.interval.tv_sec = 0;
+		a.interval.tv_nsec = ((1 * 1000000000) / rate);
 	}
-	printf("Sending packet of payload size %ld every %jd.%09ld for %ld "
-	    "seconds\n", payloadsize, (intmax_t)interval.tv_sec,
-	    interval.tv_nsec, duration);
 
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s == -1) {
+	printf("Sending packet of payload size %ld every %jd.%09lds for %ld "
+	    "seconds\n", payloadsize, (intmax_t)a.interval.tv_sec,
+	    a.interval.tv_nsec, a.duration);
+
+	if (a.ipv6)
+		a.s = socket(PF_INET6, SOCK_DGRAM, 0);
+	else
+		a.s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (a.s == -1) {
 		perror("socket");
 		return (-1);
 	}
 
-	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
-		perror("connect");
-		return (-1);
-	}
-
-	return (timing_loop(s, interval, duration, packet, payloadsize));
+	return (timing_loop(&a));
 }



More information about the Midnightbsd-cvs mailing list