⬢ DragonFlyBSD Kernel Audit
DF-5847 / cycler-original-from-DF3389.c
← back to finding ↓ download raw
/* 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;
}