Hi,
I'm tinkering with ToS->CoS (802.1p) translation in vlan(4) so I
needed something to test, tcpbench seems to deserve a tos option.
It uses the same map_option() from pfctl with some minor tweeks.
So it accepts decimal, hexadecimal, critical, lowdelay, af11...
Option chosen was -t, couldn't find anything related in other programs.
Index: usr.bin/tcpbench/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
--- usr.bin/tcpbench/tcpbench.c 21 Jun 2011 17:31:07 -0000 1.22
+++ usr.bin/tcpbench/tcpbench.c 18 Aug 2011 13:45:11 -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);
}
@@ -679,6 +681,11 @@ 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");
+ }
/* Alloc client structure and register reading callback */
if ((sc = calloc(1, sizeof(*sc))) == NULL)
err(1, "calloc");
@@ -728,6 +735,11 @@ 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 (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on)) == -1)
warn("reuse port");
@@ -820,6 +832,11 @@ 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->Vflag) {
if (setsockopt(sock, SOL_SOCKET, SO_RTABLE,
&ptb->Vflag, sizeof(ptb->Vflag)) == -1) {
@@ -874,6 +891,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 +962,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 +1021,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:
Index: usr.bin/tcpbench/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
--- usr.bin/tcpbench/tcpbench.1 16 Mar 2011 08:06:10 -0000 1.12
+++ usr.bin/tcpbench/tcpbench.1 18 Aug 2011 06:42:35 -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,22 @@ connections.
It defaults to using TCP if
.Fl u
is not specified.
+.It Fl t Ar toskeyword
+Change IPv4 TOS 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.
+This option only applies to AF_INET sockets.
.It Fl u
Use UDP instead of TCP; this must be specified on both the client
and the server.