2007年9月18日火曜日

LSRR with nuttcp

iperf どうしようか...と考えていたところ nuttcp なるものを発見。例のごとく読み切れていないのだけど、クライアント側からの trans のみで有効なパッチを適当に作成して測定してみたところ...遅いっ。遅すぎる。なーぜー? 他の環境でも試してみよう。

あっ /proc/sys/net/ipv4/conf/eth#/accept_source_route だけではダメで all/accept_source_route も 1 に。また conntrack してるなら INVALID も受付けるように。

--- nuttcp-5.3.1.c.orig 2007-09-18 21:19:37.000000000 +0900
+++ nuttcp-5.3.1.c 2007-09-18 23:32:05.000000000 +0900
@@ -357,6 +357,16 @@
#include "addrinfo.h" /* from missing */
#endif

+/* Source record routing */
+#include <netinet/ip.h>
+#include <sys/queue.h>
+struct entry {
+ char *hname;
+ char strict;
+ TAILQ_ENTRY(entry) entries;
+};
+TAILQ_HEAD(qhead, entry);
+
static struct timeval time0; /* Time at which timing started */
static struct timeval timepk; /* Time at which last packet sent */
static struct timeval timep; /* Previous time - for interval reporting */
@@ -465,6 +475,8 @@
int delay( int us );
int mread( int fd, char *bufp, unsigned n);
char *getoptvalp( char **argv, int index, int reqval, int *skiparg );
+char *alloc_inet_srr(int is_ssrr);
+int add_inet_gate(char *optr, char *hname);

int vers_major = 5;
int vers_minor = 3;
@@ -508,6 +520,12 @@
int srvrwin=0;
/* end nick code */

+/* source record routing */
+int ngates = 0;
+struct qhead gates;
+struct qhead *gatesp;
+/* end source record routing */
+
int udp = 0; /* 0 = tcp, !0 = udp */
int udplossinfo = 0; /* set to 1 to give UDP loss info for
* interval reporting */
@@ -641,7 +659,8 @@
-T## transmit timeout in seconds (or (m|M)inutes or (h|H)ours)\n\
-i## receiver interval reporting in seconds (or (m|M)inutes)\n\
-Ixxx identifier for nuttcp output (max of 40 characters)\n\
- -F flip option to reverse direction of data connection open\n"
+ -F flip option to reverse direction of data connection open\n\
+ -gxxx specifies lsrr point\n"
#ifdef HAVE_SETPRIO
" -xP## set nuttcp process priority (must be root)\n"
#endif
@@ -972,6 +991,7 @@
short save_events;
int skiparg;
int reqval;
+ struct entry *gate;

sendwin = 0;
rcvwin = 0;
@@ -1435,6 +1455,24 @@
goto usage;
}
break;
+ case 'g':
+ reqval = 1;
+ gate = (struct entry *)calloc(1, sizeof(struct entry));
+ cp1 = getoptvalp(argv, 2, reqval, &skiparg);
+ gate->hname = calloc(1, strlen(cp1) + 1);
+ strncpy(gate->hname, cp1, strlen(cp1));
+ if (!ngates) {
+ TAILQ_INIT(&gates);
+ } else {
+ if (ngates > 9) {
+ fprintf(stderr, "too many gate was specified\n");
+ fflush(stderr);
+ exit(1);
+ }
+ }
+ TAILQ_INSERT_TAIL(&gates, gate, entries);
+ ngates++;
+ break;
case 'h':
default:
goto usage;
@@ -1608,6 +1646,11 @@
fprintf(stderr, "server mode only allowed for receiver\n");
goto usage;
}
+ if (ngates) {
+ fprintf(stderr, "source route only allowed for client\n");
+ goto usage;
+ }
+
udp = 0;
sinkmode = 1;
start_idx = 0;
@@ -2576,6 +2619,29 @@
err("setsockopt");
}
}
+ if (ngates) {
+ if (af == AF_INET6) {
+ fprintf(stderr, "source route allowed for AF_INET only, sorry");
+ fflush(stderr);
+ exit(1);
+ }
+
+ cp1 = alloc_inet_srr(0);
+ if (!cp1)
+ err("alloc");
+ for (gate = gates.tqh_first; gate != NULL; gate = gate->entries.tqe_next) {
+ i = add_inet_gate(cp1, gate->hname);
+ if (!i)
+ err("add gate");
+ if (i < 0) {
+ fprintf(stderr, "%s: %s\n", gai_strerror(i), gate->hname);
+ exit(1);
+ }
+ }
+ if (setsockopt(fd[stream_idx], IPPROTO_IP, IP_OPTIONS, cp1, i)) {
+ err("setsockopt");
+ }
+ }
}
if (!udp || (stream_idx == 0)) {
if (((trans && !reverse) && (stream_idx > 0)) ||
@@ -4572,3 +4638,59 @@

return(*nextarg);
}
+
+/* from Richard W. Stevens, unpv12 */
+
+char *
+alloc_inet_srr(int is_ssrr) {
+ char *opt, *p;
+
+ p = calloc(1, 44); /* NOP, code, len, ptr, up to 10 addresses */
+ if (!p) {
+ return NULL;
+ }
+ opt = p;
+ *opt++ = IPOPT_NOP; /* NOP for alignment */
+ *opt++ = is_ssrr ? IPOPT_SSRR : IPOPT_LSRR;
+ *opt++ = 3; /* fill in the length */
+ *opt++ = 4; /* offset to first address */
+
+ return p;
+}
+
+int
+add_inet_gate(char *optr, char *hname)
+{
+ int n;
+ struct addrinfo *ai, hints;
+ struct sockaddr_in *sin;
+
+ char *lenptr = optr + 2; /* pointer to length byte in SRR option */
+
+ if (*optr != IPOPT_NOP) {
+ errno = EINVAL; /* slight sanity check */
+ return 0;
+ }
+ if (*lenptr > 9) {
+ errno = ENOBUFS;
+ return 0; /* too many source routes */
+ }
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_flags = AI_CANONNAME; /* always return canonical name */
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = 0;
+
+ if ((n = getaddrinfo(hname, NULL, &hints, &ai)) != 0) {
+ return n;
+ }
+
+ sin = (struct sockaddr_in *) ai->ai_addr;
+ memcpy(optr + 1 + *lenptr, &sin->sin_addr, sizeof(struct in_addr));
+ freeaddrinfo(ai);
+
+ *lenptr += sizeof(struct in_addr);
+
+ return *lenptr + 1; /* size for setsockopt() */
+}
すっかり LSRR ハマってる自分。

0 件のコメント: