From owner-svn-src-stable@FreeBSD.ORG Mon Sep 5 12:39:16 2011 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 519261065670; Mon, 5 Sep 2011 12:39:16 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 3E7D28FC18; Mon, 5 Sep 2011 12:39:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p85CdGZK038234; Mon, 5 Sep 2011 12:39:16 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p85CdGs4038232; Mon, 5 Sep 2011 12:39:16 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <201109051239.p85CdGs4038232@svn.freebsd.org> From: Marius Strobl Date: Mon, 5 Sep 2011 12:39:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r225399 - stable/7/tools/tools/netrate/netsend X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 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: Mon, 05 Sep 2011 12:39:16 -0000 Author: marius Date: Mon Sep 5 12:39:15 2011 New Revision: 225399 URL: http://svn.freebsd.org/changeset/base/225399 Log: MFC: r198136 Support the specification of a range of destination ports e.g. netsend 127.0.0.1 6666-7777 [payloadsize] [packet_rate] [duration] Modified: stable/7/tools/tools/netrate/netsend/netsend.c Directory Properties: stable/7/tools/tools/netrate/netsend/ (props changed) Modified: stable/7/tools/tools/netrate/netsend/netsend.c ============================================================================== --- stable/7/tools/tools/netrate/netsend/netsend.c Mon Sep 5 12:39:14 2011 (r225398) +++ stable/7/tools/tools/netrate/netsend/netsend.c Mon Sep 5 12:39:15 2011 (r225399) @@ -39,12 +39,23 @@ #include #include +/* program arguments */ +struct _a { + int s; + struct timespec interval; + int port, port_max; + long duration; + struct sockaddr_in sin; + 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 +125,12 @@ wait_time(struct timespec ts, struct tim * 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; @@ -127,18 +140,19 @@ timing_loop(int s, struct timespec inter /* do not call gettimeofday more than every 20us */ long minres_ns = 20000; int ic, gettimeofday_cycles; + int cur_port; if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { perror("clock_getres"); return (-1); } - if (timespec_ge(&tmptime, &interval)) + if (timespec_ge(&tmptime, &a->interval)) fprintf(stderr, "warning: interval (%jd.%09ld) less than resolution (%jd.%09ld)\n", - (intmax_t)interval.tv_sec, interval.tv_nsec, + (intmax_t)a->interval.tv_sec, a->interval.tv_nsec, (intmax_t)tmptime.tv_sec, tmptime.tv_nsec); - if (tmptime.tv_nsec < minres_ns) { + if (a->interval.tv_nsec < minres_ns) { gettimeofday_cycles = minres_ns/(tmptime.tv_nsec + 1); fprintf(stderr, "calling time every %d cycles\n", gettimeofday_cycles); @@ -156,14 +170,23 @@ timing_loop(int s, struct timespec inter 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 (connect(a->s, (struct sockaddr *)&a->sin, sizeof(a->sin))) { + perror("connect"); + return (-1); + } + } while (1) { - timespec_add(&nexttime, &interval); + int ret; + + timespec_add(&nexttime, &a->interval); if (--ic <= 0) { ic = gettimeofday_cycles; if (wait_time(nexttime, &tmptime, &waited) == -1) @@ -178,17 +201,28 @@ timing_loop(int s, struct timespec inter * previous send, the error will turn up the current send * operation, causing the current sequence number also to be * skipped. + * The counter is incremented only on the initial port number, + * so all destinations will see the same set of packets. * * XXXRW: Note alignment assumption. */ - if (packet_len >= 4) { - *((u_int32_t *)packet) = htonl(counter); + if (cur_port == a->port && a->packet_len >= 4) { + *((u_int32_t *)a->packet) = htonl(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; + 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; } @@ -205,11 +239,11 @@ done: 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); 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); @@ -218,27 +252,35 @@ done: 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 */ + + 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) { + a.sin.sin_len = sizeof(a.sin); + a.sin.sin_family = AF_INET; + if (inet_aton(argv[1], &a.sin.sin_addr) == 0) { perror(argv[1]); return (-1); } 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(); + 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') @@ -247,56 +289,51 @@ main(int argc, char *argv[]) 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", * and avoids the cost of a timing loop. - * XXX 0 is not actually implemented. */ 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.%09lds for %ld " - "seconds\n", payloadsize, (intmax_t)interval.tv_sec, - interval.tv_nsec, duration); + "seconds\n", payloadsize, (intmax_t)a.interval.tv_sec, + a.interval.tv_nsec, a.duration); - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s == -1) { + 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)); }