summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2004-09-10 19:09:50 +0000
committerrwatson <rwatson@FreeBSD.org>2004-09-10 19:09:50 +0000
commit29bafe61204c5cfce53de42adecae08becc2cb17 (patch)
treea2615fc1f1bac31f7e85b53a2b52912189717387 /tools
parenteb98a123e433c17741de3019ff3a79b10f989384 (diff)
downloadFreeBSD-src-29bafe61204c5cfce53de42adecae08becc2cb17.zip
FreeBSD-src-29bafe61204c5cfce53de42adecae08becc2cb17.tar.gz
Add netrate (netreceive, netsend), a tool for generating (and sinking)
UDP packets of specified size at a fixed rate. I've been using this for netperf-related testing.
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/netrate/Makefile11
-rw-r--r--tools/tools/netrate/README57
-rw-r--r--tools/tools/netrate/netreceive/Makefile8
-rw-r--r--tools/tools/netrate/netreceive/netreceive.c94
-rw-r--r--tools/tools/netrate/netsend/Makefile8
-rw-r--r--tools/tools/netrate/netsend/netsend.c220
6 files changed, 398 insertions, 0 deletions
diff --git a/tools/tools/netrate/Makefile b/tools/tools/netrate/Makefile
new file mode 100644
index 0000000..6f10939
--- /dev/null
+++ b/tools/tools/netrate/Makefile
@@ -0,0 +1,11 @@
+#
+# $FreeBSD$
+#
+
+all:
+ (cd netreceive ; make)
+ (cd netsend ; make)
+
+clean:
+ (cd netreceive ; make clean)
+ (cd netsend ; make clean)
diff --git a/tools/tools/netrate/README b/tools/tools/netrate/README
new file mode 100644
index 0000000..ff24962
--- /dev/null
+++ b/tools/tools/netrate/README
@@ -0,0 +1,57 @@
+Netsend and Netreceive
+----------------------
+
+This pair of binaries is used to fixed rate UDP performance testing.
+
+The netreceive tool consists solely of a UDP packet sink bound to a
+specified UDP port. Packets received on its port are copied to user space
+and discarded.
+
+The netsend tool acts as a packet source, generating packets of the
+specified size at the specified rate to a target IP address and port
+number:
+
+ netsend [ip] [port] [payloadsize] [rate] [duration]
+
+The payloadsize field specifies the size of the UDP payload, not the total
+packet size, which will also include a variety of headers (typically,
+ethernet, IP, and UDP).
+
+The rate indicates the number of packets/second to attempt to deliver.
+
+The duration is the duration of the run in seconds.
+
+The netsend tool will wait for around two seconds to synchronize with the
+wall clock for timing purposes. It will then busy-wait between packet
+transmits.
+
+The netsend/netreceive tools are under the following copyright and
+license:
+
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+$FreeBSD$
diff --git a/tools/tools/netrate/netreceive/Makefile b/tools/tools/netrate/netreceive/Makefile
new file mode 100644
index 0000000..998ad0b
--- /dev/null
+++ b/tools/tools/netrate/netreceive/Makefile
@@ -0,0 +1,8 @@
+#
+# $FreeBSD$
+#
+
+PROG= netreceive
+NOMAN= yes
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/netreceive/netreceive.c b/tools/tools/netrate/netreceive/netreceive.c
new file mode 100644
index 0000000..e3fecc5
--- /dev/null
+++ b/tools/tools/netrate/netreceive/netreceive.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "netreceive [port]\n");
+ exit(-1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_in sin;
+ char *dummy, *packet;
+ long port;
+ int s;
+
+ if (argc != 2)
+ usage();
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ port = strtoul(argv[1], &dummy, 10);
+ if (port < 1 || port > 65535 || *dummy != '\0')
+ usage();
+ sin.sin_port = htons(port);
+
+ packet = malloc(65536);
+ if (packet == NULL) {
+ perror("malloc");
+ return (-1);
+ }
+ bzero(packet, 65536);
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s == -1) {
+ perror("socket");
+ return (-1);
+ }
+
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ perror("bind");
+ return (-1);
+ }
+
+ printf("netreceive listening on UDP port %d\n", (u_short)port);
+
+ while (1) {
+ if (recv(s, packet, 65536, 0) < 0)
+ perror("recv");
+ }
+}
diff --git a/tools/tools/netrate/netsend/Makefile b/tools/tools/netrate/netsend/Makefile
new file mode 100644
index 0000000..230cef7
--- /dev/null
+++ b/tools/tools/netrate/netsend/Makefile
@@ -0,0 +1,8 @@
+#
+# $FreeBSD$
+#
+
+PROG= netsend
+NOMAN= yes
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/netsend/netsend.c b/tools/tools/netrate/netsend/netsend.c
new file mode 100644
index 0000000..29e26ce
--- /dev/null
+++ b/tools/tools/netrate/netsend/netsend.c
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+ "netsend [ip] [port] [payloadsize] [rate] [duration]\n");
+ exit(-1);
+}
+
+static __inline void
+timespec_add(struct timespec *tsa, struct timespec *tsb)
+{
+
+ tsa->tv_sec += tsb->tv_sec;
+ tsa->tv_nsec += tsb->tv_nsec;
+ if (tsa->tv_nsec >= 1000000000) {
+ tsa->tv_sec++;
+ tsa->tv_nsec -= 1000000000;
+ }
+}
+
+/*
+ * Busy wait spinning until we reach (or slightly pass) the desired time.
+ * Optionally return the current time as retrieved on the last time check
+ * to the caller.
+ */
+int
+wait_time(struct timespec ts, struct timespec *wakeup_ts)
+{
+ struct timespec curtime;
+
+ curtime.tv_sec = 0;
+ curtime.tv_nsec = 0;
+
+ while (curtime.tv_sec < ts.tv_sec || curtime.tv_nsec < ts.tv_nsec) {
+ if (clock_gettime(CLOCK_REALTIME, &curtime) < -1) {
+ perror("clock_gettime");
+ return (-1);
+ }
+ }
+ if (wakeup_ts != NULL)
+ *wakeup_ts = curtime;
+ return (0);
+}
+
+/*
+ * 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.
+ */
+int
+timing_loop(int s, struct timespec interval, long duration, u_char *packet,
+ u_int packet_len)
+{
+ struct timespec starttime, tmptime;
+ u_int32_t counter;
+ long finishtime;
+
+ if (clock_gettime(CLOCK_REALTIME, &starttime) < -1) {
+ perror("clock_gettime");
+ return (-1);
+ }
+ tmptime.tv_sec = 2;
+ tmptime.tv_nsec = 0;
+ timespec_add(&starttime, &tmptime);
+ starttime.tv_nsec = 0;
+ if (wait_time(starttime, NULL) == -1)
+ return (-1);
+ finishtime = starttime.tv_sec + duration;
+
+ counter = 0;
+ while (1) {
+ timespec_add(&starttime, &interval);
+ if (wait_time(starttime, &tmptime) == -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
+ * the counter, so missing sequence numbers on the receive
+ * side should not be assumed to be packets lost in transit.
+ * For example, if the UDP socket gets back an ICMP from a
+ * previous send, the error will turn up the current send
+ * operation, causing the current sequence number also to be
+ * skipped.
+ *
+ * XXXRW: Note alignment assumption.
+ */
+ if (packet_len >= 4) {
+ *((u_int32_t *)packet) = htonl(counter);
+ counter++;
+ }
+ if (send(s, packet, packet_len, 0) < 0)
+ perror("send");
+ if (duration != 0 && tmptime.tv_sec >= finishtime)
+ return (0);
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ long rate, payloadsize, port, duration;
+ struct timespec interval;
+ struct sockaddr_in sin;
+ char *dummy, *packet;
+ int s;
+
+ 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]);
+ return (-1);
+ }
+
+ port = strtoul(argv[2], &dummy, 10);
+ if (port < 1 || port > 65535 || *dummy != '\0')
+ usage();
+ sin.sin_port = htons(port);
+
+ payloadsize = strtoul(argv[3], &dummy, 10);
+ if (payloadsize < 0 || *dummy != '\0')
+ usage();
+ if (payloadsize > 32768) {
+ fprintf(stderr, "payloadsize > 32768\n");
+ return (-1);
+ }
+
+ /*
+ * Specify an arbitrary limit. It's exactly that, not selected by
+ * any particular strategy.
+ */
+ rate = strtoul(argv[4], &dummy, 10);
+ if (rate < 1 || *dummy != '\0')
+ usage();
+ if (rate > 1000000) {
+ fprintf(stderr, "rate > 100000\n");
+ return (-1);
+ }
+
+ duration = strtoul(argv[5], &dummy, 10);
+ if (duration < 0 || *dummy != '\0')
+ usage();
+
+ packet = malloc(payloadsize);
+ if (packet == NULL) {
+ perror("malloc");
+ return (-1);
+ }
+ bzero(packet, payloadsize);
+
+ if (rate == 1) {
+ interval.tv_sec = 1;
+ interval.tv_nsec = 0;
+ } else {
+ interval.tv_sec = 0;
+ interval.tv_nsec = ((1 * 1000000000) / rate);
+ }
+ printf("Sending packet of payload size %ld every %d.%09lu for %ld "
+ "seconds\n", payloadsize, interval.tv_sec, interval.tv_nsec,
+ duration);
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (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));
+}
OpenPOWER on IntegriCloud