[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