DF-3389 / cycler.c
/* DF-3389 race harness — address cycler (runs as ROOT). * * Adds and deletes fd99:3389::1/64 on lo0 as fast as the kernel allows, * using the same SIOCAIFADDR_IN6 / SIOCDIFADDR_IN6 ioctls as ifconfig(8), * but without fork/exec overhead so the purge rate is kernel-bound. * Each delete walks in6_purgeaddr -> in6_unlink_ifa -> ifa_ifunlink + * ifa_destroy, i.e. the synchronous all-netisr refcount teardown rounds. * * build: cc -O2 -o cycler cycler.c * run: ./cycler <seconds> [sleep_us] */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/time.h> #include <net/if.h> #include <netinet/in.h> #include <netinet6/in6_var.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> int main(int argc, char **argv) { double dur = argc > 1 ? atof(argv[1]) : 60.0; int susp = argc > 2 ? atoi(argv[2]) : 0; struct in6_aliasreq ifra; struct timeval t0, t1; unsigned long addok = 0, adderr = 0, delok = 0, delerr = 0, last = 0; double el, lastel = 0; int s; s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return 1; } memset(&ifra, 0, sizeof(ifra)); strncpy(ifra.ifra_name, "lo0", sizeof(ifra.ifra_name) - 1); ifra.ifra_addr.sin6_family = AF_INET6; ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); if (inet_pton(AF_INET6, "fd99:3389::1", &ifra.ifra_addr.sin6_addr) != 1) { fprintf(stderr, "inet_pton\n"); return 1; } /* /64 prefix mask */ ifra.ifra_prefixmask.sin6_family = AF_INET6; ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); memset(&ifra.ifra_prefixmask.sin6_addr, 0xff, 8); /* permanent address: infinite lifetimes (also silences the * per-add "valid lifetime is 0" kernel log) */ ifra.ifra_lifetime.ia6t_vltime = 0xffffffffu; ifra.ifra_lifetime.ia6t_pltime = 0xffffffffu; gettimeofday(&t0, NULL); for (;;) { if (ioctl(s, SIOCAIFADDR_IN6, &ifra) == 0) addok++; else adderr++; if (susp) usleep(susp); if (ioctl(s, SIOCDIFADDR_IN6, &ifra) == 0) delok++; else delerr++; if (susp) usleep(susp); gettimeofday(&t1, NULL); el = (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1e6; if (el - lastel >= 5.0) { printf("cycler cycles=%.0f/s addok=%lu adderr=%lu " "delok=%lu delerr=%lu (lasterr=%d)\n", (addok - last) / (el - lastel), addok, adderr, delok, delerr, errno); fflush(stdout); last = addok; lastel = el; } if (el >= dur) break; } /* leave the address deleted */ printf("cycler DONE addok=%lu adderr=%lu delok=%lu delerr=%lu\n", addok, adderr, delok, delerr); return 0; } |