Created
February 15, 2026 05:30
-
-
Save albb0920/09a773369282f6ee5b83f1d2c9dcdedd to your computer and use it in GitHub Desktop.
aqtion-freebsd-aq2 issue #5 reproduction script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # Run as root on the test host. | |
| # | |
| # Both-sides-in-jail RA VLAN test: | |
| # - Router in VNET jail on REF_IF (and REF_IF.<vlan> for tagged RA) | |
| # - Client in VNET jail on PARENT_IF (and PARENT_IF.<vlan> as TEST_IF) | |
| # - Compare parent promisc OFF vs ON | |
| # | |
| # Exit: | |
| # 0 => FIXED (baseline works) | |
| # 2 => BUG_PRESENT (baseline fails, promisc passes) | |
| # 1 => INCONCLUSIVE | |
| set -e | |
| TEST_IF="${TEST_IF:-aq0.4}" | |
| REF_IF="${REF_IF:-igc1}" | |
| PARENT_IF="${PARENT_IF:-}" | |
| RA_VLAN_MODE="${RA_VLAN_MODE:-tagged}" # tagged|untagged | |
| RUN_BASELINE="${RUN_BASELINE:-1}" | |
| RUN_PROMISC="${RUN_PROMISC:-1}" | |
| STRESS_ITERS="${STRESS_ITERS:-1}" | |
| VLAN_FLAP_COUNT="${VLAN_FLAP_COUNT:-0}" | |
| ADDR_CHURN_COUNT="${ADDR_CHURN_COUNT:-0}" | |
| ROUTER_JAIL="${ROUTER_JAIL:-ra6router}" | |
| CLIENT_JAIL="${CLIENT_JAIL:-ra6client}" | |
| PREFIX_BASE="${PREFIX_BASE:-fd00:77::}" | |
| ROUTER_ADDR="${ROUTER_ADDR:-fd00:77::1/64}" | |
| EXPECT_PREFIX="${EXPECT_PREFIX:-fd00:77:}" | |
| PREFIX_BASE2="${PREFIX_BASE2:-}" | |
| ROUTER_ADDR2="${ROUTER_ADDR2:-}" | |
| EXPECT_PREFIX2="${EXPECT_PREFIX2:-}" | |
| REQUIRE_BOTH_PREFIXES="${REQUIRE_BOTH_PREFIXES:-0}" | |
| TEST_VLAN_ID="" | |
| CLIENT_TEST_IF="" | |
| ROUTER_RA_IF="$REF_IF" | |
| RCONF="/tmp/rtadvd-${ROUTER_JAIL}.conf" | |
| RLOG="/tmp/${ROUTER_JAIL}.rtadvd.log" | |
| RPKT="/tmp/${ROUTER_JAIL}.ra.pcap.log" | |
| CPKT="/tmp/${CLIENT_JAIL}.ra.pcap.log" | |
| RSLOG="/tmp/${CLIENT_JAIL}.rtsol.log" | |
| IFPLOG="/tmp/${CLIENT_JAIL}.parent.ifconfig.log" | |
| IFVLOG="/tmp/${CLIENT_JAIL}.test.ifconfig.log" | |
| IFPLOG_POST="/tmp/${CLIENT_JAIL}.parent.ifconfig.post.log" | |
| IFVLOG_POST="/tmp/${CLIENT_JAIL}.test.ifconfig.post.log" | |
| RTPID="" | |
| RTPDUMP="" | |
| CTPDUMP="" | |
| if [ -z "$PARENT_IF" ]; then | |
| case "$TEST_IF" in | |
| *.*) PARENT_IF="${TEST_IF%%.*}" ;; | |
| *) PARENT_IF="$TEST_IF" ;; | |
| esac | |
| fi | |
| case "$TEST_IF" in | |
| *.*) | |
| TEST_VLAN_ID="${TEST_IF#*.}" | |
| CLIENT_TEST_IF="${PARENT_IF}.${TEST_VLAN_ID}" | |
| if [ "$RA_VLAN_MODE" = "untagged" ]; then | |
| ROUTER_RA_IF="$REF_IF" | |
| else | |
| ROUTER_RA_IF="${REF_IF}.${TEST_VLAN_ID}" | |
| fi | |
| ;; | |
| *) | |
| CLIENT_TEST_IF="$TEST_IF" | |
| ROUTER_RA_IF="$REF_IF" | |
| ;; | |
| esac | |
| cleanup() { | |
| set +e | |
| [ -n "$CTPDUMP" ] && jexec "$CLIENT_JAIL" kill -2 "$CTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$RTPDUMP" ] && jexec "$ROUTER_JAIL" kill -2 "$RTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$RTPID" ] && jexec "$ROUTER_JAIL" kill -2 "$RTPID" >/dev/null 2>&1 || true | |
| sleep 1 | |
| [ -n "$CTPDUMP" ] && jexec "$CLIENT_JAIL" kill -9 "$CTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$RTPDUMP" ] && jexec "$ROUTER_JAIL" kill -9 "$RTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$RTPID" ] && jexec "$ROUTER_JAIL" kill -9 "$RTPID" >/dev/null 2>&1 || true | |
| CTPDUMP="" | |
| RTPDUMP="" | |
| RTPID="" | |
| if jls -j "$CLIENT_JAIL" >/dev/null 2>&1; then | |
| jexec "$CLIENT_JAIL" pkill tcpdump >/dev/null 2>&1 || true | |
| jail -r "$CLIENT_JAIL" >/dev/null 2>&1 || true | |
| fi | |
| if jls -j "$ROUTER_JAIL" >/dev/null 2>&1; then | |
| jexec "$ROUTER_JAIL" pkill rtadvd >/dev/null 2>&1 || true | |
| jexec "$ROUTER_JAIL" pkill tcpdump >/dev/null 2>&1 || true | |
| jail -r "$ROUTER_JAIL" >/dev/null 2>&1 || true | |
| fi | |
| } | |
| trap cleanup EXIT INT TERM | |
| wait_jail_iface_active() { | |
| jailn="$1" | |
| ifn="$2" | |
| timeout_s="$3" | |
| i=0 | |
| while [ "$i" -lt "$timeout_s" ]; do | |
| if jexec "$jailn" ifconfig "$ifn" >/dev/null 2>&1; then | |
| if jexec "$jailn" ifconfig "$ifn" | grep -q "status: active"; then | |
| return 0 | |
| fi | |
| fi | |
| i=$((i + 1)) | |
| sleep 1 | |
| done | |
| echo "WARN: link not active in jail for $ifn" | |
| jexec "$jailn" ifconfig "$ifn" || true | |
| return 1 | |
| } | |
| clear_client_addrs() { | |
| for a in $(jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 | awk '/inet6 / {print $2}' | grep -v '^fe80:' || true); do | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 "$a" delete >/dev/null 2>&1 || true | |
| done | |
| } | |
| flap_client_vlan() { | |
| n=0 | |
| while [ "$n" -lt "$VLAN_FLAP_COUNT" ]; do | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" destroy >/dev/null 2>&1 || true | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" create | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" vlan "$TEST_VLAN_ID" vlandev "$PARENT_IF" up | |
| n=$((n + 1)) | |
| done | |
| } | |
| churn_client_ipv6_mcast() { | |
| n=0 | |
| while [ "$n" -lt "$ADDR_CHURN_COUNT" ]; do | |
| h=$(printf '%x' $((4096 + n))) | |
| addr="fdce:${h}::1" | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 "${addr}/64" add >/dev/null 2>&1 || true | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 "${addr}" delete >/dev/null 2>&1 || true | |
| n=$((n + 1)) | |
| done | |
| } | |
| setup_router_jail() { | |
| jail -c name="$ROUTER_JAIL" host.hostname="$ROUTER_JAIL" persist path=/ allow.raw_sockets vnet vnet.interface="$REF_IF" | |
| jexec "$ROUTER_JAIL" ifconfig "$REF_IF" up | |
| jexec "$ROUTER_JAIL" ifconfig "$REF_IF" inet6 -ifdisabled up | |
| wait_jail_iface_active "$ROUTER_JAIL" "$REF_IF" 20 || true | |
| if [ -n "$TEST_VLAN_ID" ] && [ "$RA_VLAN_MODE" != "untagged" ]; then | |
| jexec "$ROUTER_JAIL" ifconfig "$ROUTER_RA_IF" create | |
| jexec "$ROUTER_JAIL" ifconfig "$ROUTER_RA_IF" vlan "$TEST_VLAN_ID" vlandev "$REF_IF" up | |
| fi | |
| jexec "$ROUTER_JAIL" ifconfig "$ROUTER_RA_IF" inet6 -ifdisabled up | |
| jexec "$ROUTER_JAIL" ifconfig "$ROUTER_RA_IF" inet6 "$ROUTER_ADDR" | |
| if [ -n "$ROUTER_ADDR2" ]; then | |
| jexec "$ROUTER_JAIL" ifconfig "$ROUTER_RA_IF" inet6 "$ROUTER_ADDR2" | |
| fi | |
| jexec "$ROUTER_JAIL" sysctl net.inet6.ip6.forwarding=1 >/dev/null | |
| if [ -n "$PREFIX_BASE2" ]; then | |
| cat > "$RCONF" <<EOF | |
| ${ROUTER_RA_IF}:\ | |
| :maxinterval#10:mininterval#3:\ | |
| :addr="${PREFIX_BASE}":prefixlen#64:\ | |
| :addr0="${PREFIX_BASE2}":prefixlen0#64:pinfoflags="la": | |
| EOF | |
| else | |
| cat > "$RCONF" <<EOF | |
| ${ROUTER_RA_IF}:\ | |
| :maxinterval#10:mininterval#3:\ | |
| :addr="${PREFIX_BASE}":prefixlen#64:pinfoflags="la": | |
| EOF | |
| fi | |
| jexec "$ROUTER_JAIL" sh -c "rtadvd -f -c '$RCONF' '$ROUTER_RA_IF' > '$RLOG' 2>&1 & echo \$!" > "/tmp/${ROUTER_JAIL}.rt.pid" | |
| RTPID=$(cat "/tmp/${ROUTER_JAIL}.rt.pid") | |
| sleep 1 | |
| if ! jexec "$ROUTER_JAIL" kill -0 "$RTPID" >/dev/null 2>&1; then | |
| echo "ERROR: rtadvd exited early for $ROUTER_RA_IF" | |
| cat "$RLOG" || true | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| setup_client_jail() { | |
| promisc_mode="$1" # on|off | |
| jail -c name="$CLIENT_JAIL" host.hostname="$CLIENT_JAIL" persist path=/ allow.raw_sockets vnet vnet.interface="$PARENT_IF" | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" up | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" inet6 -ifdisabled up | |
| wait_jail_iface_active "$CLIENT_JAIL" "$PARENT_IF" 20 || true | |
| if [ -n "$TEST_VLAN_ID" ]; then | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" create | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" vlan "$TEST_VLAN_ID" vlandev "$PARENT_IF" up | |
| if [ "$VLAN_FLAP_COUNT" -gt 0 ]; then | |
| flap_client_vlan | |
| fi | |
| fi | |
| if [ "$promisc_mode" = "on" ]; then | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" promisc | |
| else | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" -promisc >/dev/null 2>&1 || true | |
| fi | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 -ifdisabled accept_rtadv up | |
| clear_client_addrs | |
| if [ "$ADDR_CHURN_COUNT" -gt 0 ]; then | |
| churn_client_ipv6_mcast | |
| fi | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" > "$IFPLOG" | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" > "$IFVLOG" | |
| jexec "$CLIENT_JAIL" netstat -g -f link >/tmp/${CLIENT_JAIL}.mcast.log 2>&1 || true | |
| } | |
| start_captures() { | |
| rm -f "$RPKT" "$CPKT" "$RSLOG" | |
| jexec "$ROUTER_JAIL" sh -c "tcpdump -p -l -U -ni '$ROUTER_RA_IF' -e -vv -c 1 'icmp6 and ip6[40]==134' > '$RPKT' 2>&1 & echo \$!" > "/tmp/${ROUTER_JAIL}.td.pid" | |
| RTPDUMP=$(cat "/tmp/${ROUTER_JAIL}.td.pid") | |
| jexec "$CLIENT_JAIL" sh -c "tcpdump -p -l -U -ni '$CLIENT_TEST_IF' -e -vv -c 1 'icmp6 and ip6[40]==134' > '$CPKT' 2>&1 & echo \$!" > "/tmp/${CLIENT_JAIL}.td.pid" | |
| CTPDUMP=$(cat "/tmp/${CLIENT_JAIL}.td.pid") | |
| } | |
| stop_captures() { | |
| [ -n "$RTPDUMP" ] && jexec "$ROUTER_JAIL" kill -2 "$RTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$CTPDUMP" ] && jexec "$CLIENT_JAIL" kill -2 "$CTPDUMP" >/dev/null 2>&1 || true | |
| sleep 1 | |
| [ -n "$RTPDUMP" ] && jexec "$ROUTER_JAIL" kill -9 "$RTPDUMP" >/dev/null 2>&1 || true | |
| [ -n "$CTPDUMP" ] && jexec "$CLIENT_JAIL" kill -9 "$CTPDUMP" >/dev/null 2>&1 || true | |
| RTPDUMP="" | |
| CTPDUMP="" | |
| } | |
| slaac_present() { | |
| if ! jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 | grep -q 'autoconf'; then | |
| return 1 | |
| fi | |
| if ! jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 | grep -q "$EXPECT_PREFIX"; then | |
| return 1 | |
| fi | |
| if [ "$REQUIRE_BOTH_PREFIXES" = "1" ]; then | |
| if [ -z "$EXPECT_PREFIX2" ]; then | |
| return 1 | |
| fi | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" inet6 | grep -q "$EXPECT_PREFIX2" | |
| fi | |
| } | |
| run_ra_case() { | |
| desc="$1" | |
| promisc_mode="$2" | |
| tag="$promisc_mode" | |
| echo "== Test Case: $desc ==" | |
| cleanup 2>/dev/null || true | |
| setup_router_jail || return 1 | |
| setup_client_jail "$promisc_mode" || return 1 | |
| cp "$IFPLOG" "/tmp/${CLIENT_JAIL}.${tag}.parent.ifconfig.log" | |
| cp "$IFVLOG" "/tmp/${CLIENT_JAIL}.${tag}.test.ifconfig.log" | |
| echo "DEBUG: Client parent ifconfig ($promisc_mode):" | |
| cat "$IFPLOG" || true | |
| echo "DEBUG: Client test ifconfig ($promisc_mode):" | |
| cat "$IFVLOG" || true | |
| start_captures | |
| sleep 1 | |
| jexec "$CLIENT_JAIL" rtsol "$CLIENT_TEST_IF" >"$RSLOG" 2>&1 || true | |
| if [ "$REQUIRE_BOTH_PREFIXES" = "1" ]; then | |
| sleep 14 | |
| else | |
| sleep 6 | |
| fi | |
| stop_captures | |
| jexec "$CLIENT_JAIL" ifconfig "$PARENT_IF" > "$IFPLOG_POST" | |
| jexec "$CLIENT_JAIL" ifconfig "$CLIENT_TEST_IF" > "$IFVLOG_POST" | |
| echo "DEBUG: Client parent ifconfig POST-capture ($promisc_mode):" | |
| cat "$IFPLOG_POST" || true | |
| echo "DEBUG: Client test ifconfig POST-capture ($promisc_mode):" | |
| cat "$IFVLOG_POST" || true | |
| echo " -> Verifying SLAAC on $CLIENT_TEST_IF ($CLIENT_JAIL)" | |
| if slaac_present; then | |
| echo "PASS: $desc" | |
| return 0 | |
| fi | |
| echo "FAIL: $desc" | |
| echo "DEBUG: Router capture:" | |
| cat "$RPKT" || true | |
| echo "DEBUG: rtadvd log:" | |
| cat "$RLOG" || true | |
| echo "DEBUG: Client capture:" | |
| cat "$CPKT" || true | |
| echo "DEBUG: rtsol output:" | |
| cat "$RSLOG" || true | |
| echo "DEBUG: Client parent ifconfig:" | |
| cat "$IFPLOG" || true | |
| echo "DEBUG: Client test ifconfig:" | |
| cat "$IFVLOG" || true | |
| return 1 | |
| } | |
| if [ "$(id -u)" -ne 0 ]; then | |
| echo "Must run as root." | |
| exit 1 | |
| fi | |
| if ! ifconfig "$REF_IF" >/dev/null 2>&1; then | |
| echo "REF_IF not found: $REF_IF" | |
| exit 1 | |
| fi | |
| if ! ifconfig "$PARENT_IF" >/dev/null 2>&1; then | |
| echo "PARENT_IF not found: $PARENT_IF" | |
| exit 1 | |
| fi | |
| if jls -j "$ROUTER_JAIL" >/dev/null 2>&1 || jls -j "$CLIENT_JAIL" >/dev/null 2>&1; then | |
| echo "Router/client jail already exists; set ROUTER_JAIL/CLIENT_JAIL." | |
| exit 1 | |
| fi | |
| echo "=== RA VLAN Repro Test (Both In Jails) ===" | |
| echo "TEST_IF=$TEST_IF CLIENT_TEST_IF=$CLIENT_TEST_IF PARENT_IF=$PARENT_IF REF_IF=$REF_IF RA_VLAN_MODE=$RA_VLAN_MODE ROUTER_RA_IF=$ROUTER_RA_IF STRESS_ITERS=$STRESS_ITERS VLAN_FLAP_COUNT=$VLAN_FLAP_COUNT ADDR_CHURN_COUNT=$ADDR_CHURN_COUNT REQUIRE_BOTH_PREFIXES=$REQUIRE_BOTH_PREFIXES EXPECT_PREFIX=$EXPECT_PREFIX EXPECT_PREFIX2=$EXPECT_PREFIX2" | |
| FINAL_RC=1 | |
| ITER=1 | |
| while [ "$ITER" -le "$STRESS_ITERS" ]; do | |
| echo "" | |
| echo "---- Iteration $ITER/$STRESS_ITERS ----" | |
| BASE_OK=1 | |
| PROMISC_OK=1 | |
| if [ "$RUN_BASELINE" = "1" ]; then | |
| if run_ra_case "Baseline (parent promisc OFF) [iter $ITER]" "off"; then | |
| BASE_OK=0 | |
| fi | |
| fi | |
| if [ "$RUN_PROMISC" = "1" ]; then | |
| echo "" | |
| if run_ra_case "Parent promisc ON [iter $ITER]" "on"; then | |
| PROMISC_OK=0 | |
| fi | |
| fi | |
| if [ "$BASE_OK" -ne 0 ] && [ "$PROMISC_OK" -eq 0 ]; then | |
| FINAL_RC=2 | |
| break | |
| fi | |
| if [ "$BASE_OK" -eq 0 ]; then | |
| FINAL_RC=0 | |
| fi | |
| ITER=$((ITER + 1)) | |
| done | |
| echo "" | |
| echo "=== Summary ===" | |
| if [ "$FINAL_RC" -eq 2 ]; then | |
| echo "Result: BUG_PRESENT (fails baseline, passes with parent promisc)." | |
| exit 2 | |
| fi | |
| if [ "$FINAL_RC" -eq 0 ]; then | |
| echo "Result: FIXED (baseline already works without parent promisc)." | |
| exit 0 | |
| fi | |
| echo "Result: INCONCLUSIVE (both modes failed or environment mismatch)." | |
| exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment