On Fri, Aug 19, 2011 at 11:25:23PM +1000, Damien Miller wrote:
>
> Thanks, I like this. Could you add IPV6_TCLASS for IF_INET6 too?
>
So here is the version with IPV6_TCLASS and -T instead of -t, since
only traceroute uses -t, while ping and nc uses -T.
I did some basic tests but my knowledge of IPv6 is hideous, so please
test. From what I could read, IPV6_TCLASS should behave like IP_TOS.
Obs: this also includes the fix for the segfault mentioned in the
other thread.
Index: tcpbench.1
===================================================================
RCS file: /cvs/src/usr.bin/tcpbench/tcpbench.1,v
retrieving revision 1.12
diff -d -u -p -w -r1.12 tcpbench.1
--- tcpbench.1 16 Mar 2011 08:06:10 -0000 1.12
+++ tcpbench.1 20 Aug 2011 06:41:07 -0000
@@ -31,6 +31,7 @@
.Op Fl p Ar port
.Op Fl r Ar interval
.Op Fl S Ar space
+.Op Fl T Ar toskeyword
.Op Fl V Ar rtable
.Ar hostname
.Nm
@@ -41,6 +42,7 @@
.Op Fl k Ar kvars
.Op Fl p Ar port
.Op Fl r Ar interval
+.Op Fl T Ar toskeyword
.Op Fl S Ar space
.Op Fl V Ar rtable
.Ek
@@ -105,6 +107,21 @@ connections.
It defaults to using TCP if
.Fl u
is not specified.
+.It Fl T Ar toskeyword
+Change IPv4 TOS or IPv6 TCLASS value.
+.Ar toskeyword
+may be one of
+.Ar critical ,
+.Ar inetcontrol ,
+.Ar lowdelay ,
+.Ar netcontrol ,
+.Ar throughput ,
+.Ar reliability ,
+or one of the DiffServ Code Points:
+.Ar ef ,
+.Ar af11 ... af43 ,
+.Ar cs0 ... cs7 ;
+or one number in either hex or decimal.
.It Fl u
Use UDP instead of TCP; this must be specified on both the client
and the server.
Index: tcpbench.c
===================================================================
RCS file: /cvs/src/usr.bin/tcpbench/tcpbench.c,v
retrieving revision 1.22
diff -d -u -p -w -r1.22 tcpbench.c
--- tcpbench.c 21 Jun 2011 17:31:07 -0000 1.22
+++ tcpbench.c 20 Aug 2011 06:39:02 -0000
@@ -65,6 +65,7 @@ struct {
int Sflag; /* Socket buffer size (tcp mode) */
u_int rflag; /* Report rate (ms) */
int sflag; /* True if server */
+ int Tflag; /* ToS if != -1 */
int vflag; /* Verbose */
int uflag; /* UDP mode */
kvm_t *kvmh; /* Kvm handler */
@@ -113,7 +114,7 @@ static void client_init(struct addrinfo
static int clock_gettime_tv(clockid_t, struct timeval *);
static void udp_server_handle_sc(int, short, void *);
static void udp_process_slice(int, short, void *);
-
+static int map_tos(char *, int *);
/*
* We account the mainstats here, that is the stats
* for all connections, all variables starting with slice
@@ -173,9 +174,10 @@ usage(void)
fprintf(stderr,
"usage: tcpbench -l\n"
" tcpbench [-uv] [-B buf] [-k kvars] [-n connections] [-p
port]\n"
- " [-r interval] [-S space] [-V rtable] hostname\n"
+ " [-r interval] [-S space] [-T toskeyword] [-V
rtable]\n"
+ " hostname\n"
" tcpbench -s [-uv] [-B buf] [-k kvars] [-p port]\n"
- " [-r interval] [-S space] [-V rtable]\n");
+ " [-r interval] [-S space] [-T toskeyword] [-V
rtable]\n");
exit(1);
}
@@ -642,6 +644,7 @@ again:
} else if (n == 0) {
if (ptb->vflag)
fprintf(stderr, "%8d closed by remote end\n", sc->fd);
+ event_del(&sc->ev);
close(sc->fd);
TAILQ_REMOVE(&sc_queue, sc, entry);
free(sc);
@@ -679,6 +682,16 @@ again:
r |= O_NONBLOCK;
if (fcntl(sock, F_SETFL, r) == -1)
err(1, "fcntl(F_SETFL, O_NONBLOCK)");
+ if (ptb->Tflag != -1 && ss.ss_family == AF_INET) {
+ if (setsockopt(sock, IPPROTO_IP, IP_TOS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IP_TOS");
+ }
+ if (ptb->Tflag != -1 && ss.ss_family == AF_INET6) {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IPV_TCLASS");
+ }
/* Alloc client structure and register reading callback */
if ((sc = calloc(1, sizeof(*sc))) == NULL)
err(1, "calloc");
@@ -728,6 +741,16 @@ server_init(struct addrinfo *aitop, stru
err(1, "setsockopt SO_RTABLE");
}
}
+ if (ptb->Tflag != -1 && ai->ai_family == AF_INET) {
+ if (setsockopt(sock, IPPROTO_IP, IP_TOS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IP_TOS");
+ }
+ if (ptb->Tflag != -1 && ai->ai_family == AF_INET6) {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IPV_TCLASS");
+ }
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on)) == -1)
warn("reuse port");
@@ -820,6 +843,16 @@ client_init(struct addrinfo *aitop, int
warn("socket");
continue;
}
+ if (ptb->Tflag != -1 && ai->ai_family == AF_INET) {
+ if (setsockopt(sock, IPPROTO_IP, IP_TOS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IP_TOS");
+ }
+ if (ptb->Tflag != -1 && ai->ai_family == AF_INET6) {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
+ &ptb->Tflag, sizeof(ptb->Tflag)))
+ err(1, "setsockopt IPV_TCLASS");
+ }
if (ptb->Vflag) {
if (setsockopt(sock, SOL_SOCKET, SO_RTABLE,
&ptb->Vflag, sizeof(ptb->Vflag)) == -1) {
@@ -874,6 +907,54 @@ client_init(struct addrinfo *aitop, int
fprintf(stderr, "%u connections established\n", nconn);
}
+static int
+map_tos(char *s, int *val)
+{
+ /* DiffServ Codepoints and other TOS mappings */
+ const struct toskeywords {
+ const char *keyword;
+ int val;
+ } *t, toskeywords[] = {
+ { "af11", IPTOS_DSCP_AF11 },
+ { "af12", IPTOS_DSCP_AF12 },
+ { "af13", IPTOS_DSCP_AF13 },
+ { "af21", IPTOS_DSCP_AF21 },
+ { "af22", IPTOS_DSCP_AF22 },
+ { "af23", IPTOS_DSCP_AF23 },
+ { "af31", IPTOS_DSCP_AF31 },
+ { "af32", IPTOS_DSCP_AF32 },
+ { "af33", IPTOS_DSCP_AF33 },
+ { "af41", IPTOS_DSCP_AF41 },
+ { "af42", IPTOS_DSCP_AF42 },
+ { "af43", IPTOS_DSCP_AF43 },
+ { "critical", IPTOS_PREC_CRITIC_ECP },
+ { "cs0", IPTOS_DSCP_CS0 },
+ { "cs1", IPTOS_DSCP_CS1 },
+ { "cs2", IPTOS_DSCP_CS2 },
+ { "cs3", IPTOS_DSCP_CS3 },
+ { "cs4", IPTOS_DSCP_CS4 },
+ { "cs5", IPTOS_DSCP_CS5 },
+ { "cs6", IPTOS_DSCP_CS6 },
+ { "cs7", IPTOS_DSCP_CS7 },
+ { "ef", IPTOS_DSCP_EF },
+ { "inetcontrol", IPTOS_PREC_INTERNETCONTROL },
+ { "lowdelay", IPTOS_LOWDELAY },
+ { "netcontrol", IPTOS_PREC_NETCONTROL },
+ { "reliability", IPTOS_RELIABILITY },
+ { "throughput", IPTOS_THROUGHPUT },
+ { NULL, -1 },
+ };
+
+ for (t = toskeywords; t->keyword != NULL; t++) {
+ if (strcmp(s, t->keyword) == 0) {
+ *val = t->val;
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
int
main(int argc, char **argv)
{
@@ -897,9 +978,10 @@ main(int argc, char **argv)
ptb->kvmh = NULL;
ptb->kvars = NULL;
ptb->rflag = DEFAULT_STATS_INTERVAL;
+ ptb->Tflag = -1;
nconn = 1;
- while ((ch = getopt(argc, argv, "B:hlk:n:p:r:sS:uvV:")) != -1) {
+ while ((ch = getopt(argc, argv, "B:hlk:n:p:r:sS:T:uvV:")) != -1) {
switch (ch) {
case 'l':
list_kvars();
@@ -955,6 +1037,19 @@ main(int argc, char **argv)
break;
case 'u':
ptb->uflag = 1;
+ break;
+ case 'T':
+ if (map_tos(optarg, &ptb->Tflag))
+ break;
+ errstr = NULL;
+ if (strlen(optarg) > 1 && optarg[0] == '0' &&
+ optarg[1] == 'x')
+ ptb->Tflag = (int)strtol(optarg, NULL, 16);
+ else
+ ptb->Tflag = (int)strtonum(optarg, 0, 255,
+ &errstr);
+ if (ptb->Tflag == -1 || ptb->Tflag > 255 || errstr)
+ errx(1, "illegal tos value %s", optarg);
break;
case 'h':
default: