#!/bin/bash
# Usage: ./reproducer.sh --nids N [--verbosity V]

set -euo pipefail

NIDS=""
VERBOSITY=4

# Parse args
while [[ $# -gt 0 ]]; do
    case "$1" in
        --nids) NIDS="$2"; shift 2 ;;
        --verbosity|-v) VERBOSITY="$2"; shift 2 ;;
        *) echo "Unknown arg: $1"; exit 1 ;;
    esac
done

if [[ -z "$NIDS" ]]; then
    echo "Usage: $0 --nids N [--verbosity V]"
    exit 1
fi

echo "================================================="
echo " Reproducer                                      "
echo " Max NIDs:  $NIDS                                "
echo " Verbosity: $VERBOSITY                           "
echo "================================================="

cleanup() {
    echo ""
    echo "[Cleanup] Tearing down synthetic NIDs..."
    for (( i=1; i<=NIDS; i++ )); do
        lnetctl net del --net tcp${i} 2>/dev/null || true
        ip link del dummy${i} 2>/dev/null || true
    done
}
trap cleanup EXIT

# Pre-flight
echo "[Pre-flight] Checking modules and limits..."
modprobe dummy 2>/dev/null || true
modprobe lnet 2>/dev/null || true
lnetctl lnet configure 2>/dev/null || true

if ! command -v strace &> /dev/null; then
    echo "[Pre-flight] ERROR: strace is required for binary payload measurement. Please install it first."
    exit 1
fi

MAX_IF=$(cat /sys/module/lnet/parameters/lnet_interfaces_max 2>/dev/null || echo 0)
if [ "$MAX_IF" -lt 1024 ]; then
    echo "[Pre-flight] Raising lnet_interfaces_max to 1024"
    lnetctl set max_interfaces 1024 || true
fi

echo "[Test] Beginning incremental interface addition..."

for (( i=1; i<=NIDS; i++ )); do
    # 1. Add single NID
    ip3=$((i / 256))
    ip4=$((i % 256))
    
    ip link add dummy${i} type dummy 2>/dev/null || true
    ip addr add 10.254.${ip3}.${ip4}/24 dev dummy${i} 2>/dev/null || true
    ip link set dummy${i} up
    
    lnetctl net add --net tcp${i} --if dummy${i} >/dev/null 2>&1
    
    # 2. Test dump size and stability
    res=0
    binary_size=$(timeout 60 strace -e trace=recvmsg lnetctl net show -v $VERBOSITY 2>&1 | grep 'MSG_PEEK|MSG_TRUNC' | tail -n 1 | awk -F'=' '{print $NF}' | tr -d ' ' || true)
    if [[ -z "$binary_size" ]]; then binary_size=0; fi
    
    timeout 60 lnetctl net show -v $VERBOSITY > /tmp/lnet_dump.yaml 2>&1 || res=$?
    
    # Check results
    if [[ $res -eq 124 ]]; then
        echo "--> [FAIL] Infinite Loop Timeout triggered at exactly $i NIDs."
        exit 1
    elif [[ $res -eq 134 || $res -eq 137 ]]; then
        echo "--> [FAIL] Userspace Crash (Heap Corruption) triggered at exactly $i NIDs."
        exit 1
    elif [[ $res -ne 0 ]]; then
        echo "--> [FAIL] Unknown exit code $res at $i NIDs."
        exit 1
    else
        dump_size=$(wc -c < /tmp/lnet_dump.yaml 2>/dev/null || echo 0)
        echo "  - $i NIDs : PASS (Binary: $binary_size bytes | YAML: $dump_size bytes)"
    fi
done

echo "================================================="
echo " SUCCESS: All $NIDS NIDs configured and dumped cleanly."
echo "================================================="
