Files
pxe-server/playbook/blancco-init.sh
cproudlock d7ec6a2b5f Blancco: sweep full NIC driver tree into kexec-initrd + verbose init
Previous approach listed ~6 specific drivers (e1000e, igb, tg3, bnx2,
bnxt_en, b44) and silenced insmod errors (2>/dev/null). On modern Dell
fleet (Latitude 5330/5440, Pro-series, newer OptiPlex) this missed
igc (Intel I225/I226) entirely, and for the drivers we did include,
dependency modules they need at insmod time (libeth, libie, dca,
i2c-algo-bit, macsec, mii, libphy, ptp, ...) were never bundled.
insmod does not resolve dependencies, so NIC drivers that need
helpers failed to load silently.

playbook/pxe_server_setup.yml (kexec-initrd build):
  - Sweep the whole drivers/net/ethernet tree (~170 drivers, all
    vendors, ~15 MB total). Drivers for hardware not present skip
    without binding.
  - Add common helper dirs: drivers/net/{phy,mdio}, drivers/i2c/algos,
    drivers/dca, drivers/ptp, net/macsec, drivers/ssb.
  - overlay.ko kept.

playbook/blancco-init.sh:
  - Load helpers BEFORE main NIC drivers (libeth/libie, dca,
    i2c-algo-bit, macsec, mii, ssb, libphy, mdio*, phy*, ptp*),
    then iterate remaining modules.
  - Remove 2>/dev/null on insmod so actual failures surface on the
    boot console.
  - Print kernel version + /sys/class/net before/after driver load,
    plus dmesg grep for NIC driver activity.
  - On "no interface found" failure, dump dmesg tail and drop to a
    busybox shell for manual debug rather than just hanging.

Separate from this commit but related: kexec-initrd.img on both PXE
servers (.1 and .2) was rebuilt inline with these changes. Pre-rebuild
binary kept as kexec-initrd.img.bak-<timestamp>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 13:29:35 -04:00

197 lines
6.3 KiB
Bash

#!/bin/sh
# Blancco PXE Loader - init script for custom initramfs
# Boot chain: iPXE -> GRUB EFI -> Ubuntu kernel + this initramfs -> switch_root to Blancco
#
# Blancco's own kernel freezes on Dell Precision towers during PXE boot.
# Workaround: boot Ubuntu kernel, download Blancco rootfs (squashfs), mount
# overlay filesystem, and switch_root into Blancco's userspace.
export PATH=/bin:/sbin
echo ""
echo "============================================"
echo " Blancco PXE loader"
echo "============================================"
echo ""
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev 2>/dev/null
mkdir -p /tmp /run
echo "[1/4] Loading NIC drivers..."
echo " Kernel: $(uname -r)"
echo " Interfaces before driver load: $(ls /sys/class/net/ 2>/dev/null)"
# Dependency modules first. insmod does not resolve deps; main NIC
# drivers like igb need dca + i2c-algo-bit, atlantic needs macsec,
# some Intel drivers need libeth/libie. Load helpers first so the
# main driver module has its required symbols available.
for mod in /lib/modules/libeth.ko /lib/modules/libie*.ko /lib/modules/dca.ko \
/lib/modules/i2c-algo-bit.ko /lib/modules/macsec.ko \
/lib/modules/mii.ko /lib/modules/ssb.ko /lib/modules/libphy.ko \
/lib/modules/mdio*.ko /lib/modules/phy*.ko /lib/modules/ptp*.ko; do
[ -f "$mod" ] || continue
insmod "$mod" 2>&1 | grep -v '^$' | head -1 || true
done
# Main NIC drivers (everything else in /lib/modules/ that is not a helper
# or the overlay/squashfs modules). Errors are now VISIBLE so if a
# driver fails to load we can see why.
for mod in /lib/modules/*.ko; do
base=$(basename "$mod")
case "$base" in
libeth.ko|libie*.ko|dca.ko|i2c-algo-bit.ko|macsec.ko|mii.ko|ssb.ko|libphy.ko|overlay.ko|squashfs.ko|mdio*.ko|phy*.ko|ptp*.ko)
continue ;;
esac
echo " insmod $base"
insmod "$mod" 2>&1 | head -1 || true
done
sleep 5
echo " Interfaces after driver load: $(ls /sys/class/net/ 2>/dev/null)"
echo " Kernel messages mentioning NIC driver activity:"
dmesg 2>/dev/null | grep -iE "eth|igc|igb|bnxt|tg3|r8169|atlantic|e1000|ixgbe|i40e|eno|ens|enp" | tail -20
echo " Waiting for network interface..."
IFACE=""
COUNT=0
while [ $COUNT -lt 60 ]; do
for i in /sys/class/net/*; do
ifname="${i##*/}"
if [ "$ifname" != "lo" ] && [ -d "$i" ]; then
IFACE=$ifname
break 2
fi
done
COUNT=$((COUNT + 1))
sleep 1
echo -n "."
done
echo ""
if [ -z "$IFACE" ]; then
echo ""
echo "ERROR: No network interface found after 60s."
echo " /sys/class/net/: $(ls /sys/class/net/ 2>/dev/null)"
echo " Last 40 lines of dmesg (look for probe failures):"
dmesg 2>/dev/null | tail -40
echo ""
echo " Dropping to busybox shell for manual debug. reboot with 'reboot -f'."
exec sh
fi
echo " Interface: $IFACE"
ip link set $IFACE up
sleep 2
SERVER=10.9.100.1
ifconfig $IFACE 10.9.100.250 netmask 255.255.255.0 up
sleep 1
echo " IP: 10.9.100.250"
echo "[2/4] Downloading Blancco rootfs (666MB)..."
wget -O /tmp/airootfs.sfs http://$SERVER/blancco/arch/x86_64/airootfs.sfs 2>&1
if [ ! -s /tmp/airootfs.sfs ]; then
echo "ERROR: Failed to download rootfs!"
exec sh
fi
echo " OK ($(wc -c < /tmp/airootfs.sfs) bytes)"
echo "[3/4] Mounting rootfs..."
mkdir -p /run/lower /run/upper /run/work /run/newroot
losetup /dev/loop0 /tmp/airootfs.sfs
mount -t squashfs -o ro /dev/loop0 /run/lower
if [ $? -ne 0 ]; then
echo "ERROR: squashfs mount failed!"
exec sh
fi
insmod /lib/modules/overlay.ko 2>/dev/null
mount -t tmpfs -o size=50% tmpfs /run/upper
mkdir -p /run/upper/upper /run/upper/work
mount -t overlay overlay -o lowerdir=/run/lower,upperdir=/run/upper/upper,workdir=/run/upper/work /run/newroot
if [ $? -ne 0 ]; then
echo "ERROR: overlay mount failed!"
exec sh
fi
echo "[4/5] Installing kernel modules (132MB)..."
wget -O /tmp/kmod.tar.gz http://$SERVER/blancco/kmod.tar.gz 2>&1
if [ -s /tmp/kmod.tar.gz ]; then
cd /run/newroot
gunzip -c /tmp/kmod.tar.gz | tar xf -
rm -f /tmp/kmod.tar.gz
cd /
echo " OK"
else
echo " WARNING: Failed to download kernel modules"
fi
echo "[5/6] Switching root to Blancco..."
mkdir -p /run/newroot/run /run/newroot/proc /run/newroot/sys /run/newroot/dev /run/newroot/tmp
echo "[6/6] Downloading Blancco config..."
wget -O /run/newroot/albus/config.xml http://$SERVER/blancco/config-clean.xml 2>&1
wget -O /run/newroot/albus/preferences.xml http://$SERVER/blancco/preferences.xml 2>&1
if [ -s /run/newroot/albus/config.xml ]; then
echo " config.xml: $(wc -c < /run/newroot/albus/config.xml) bytes"
else
echo " WARNING: Failed to download config.xml"
fi
if [ -s /run/newroot/albus/preferences.xml ]; then
cp -f /run/newroot/albus/preferences.xml /run/newroot/albus/preferences.save
echo " preferences.xml: $(wc -c < /run/newroot/albus/preferences.xml) bytes"
else
echo " WARNING: Failed to download preferences.xml"
fi
# Pre-configure X.org to use modesetting driver (generic KMS, works with all GPUs)
mkdir -p /run/newroot/etc/X11/xorg.conf.d
echo " X.org: forcing modesetting driver"
cat > /run/newroot/etc/X11/xorg.conf.d/20-failsafeDriver.conf << 'XEOF'
Section "Device"
Identifier "Failsafe Video Device"
Driver "modesetting"
EndSection
XEOF
# Enable SSH for remote debugging
echo " Enabling SSH (root:blancco)..."
if [ -f /run/newroot/etc/ssh/sshd_config ]; then
sed 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /run/newroot/etc/ssh/sshd_config > /run/newroot/etc/ssh/sshd_config.new || true
mv /run/newroot/etc/ssh/sshd_config.new /run/newroot/etc/ssh/sshd_config || true
fi
cat > /run/newroot/etc/rc.local << 'RCEOF'
#!/bin/bash
echo 'root:blancco' | chpasswd
ssh-keygen -A 2>/dev/null
/usr/bin/sshd 2>/dev/null
RCEOF
chmod +x /run/newroot/etc/rc.local
cat > /run/newroot/etc/systemd/system/pxe-debug.service << 'SVCEOF'
[Unit]
Description=PXE Debug SSH
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/rc.local
[Install]
WantedBy=multi-user.target
SVCEOF
ln -sf /etc/systemd/system/pxe-debug.service /run/newroot/etc/systemd/system/multi-user.target.wants/pxe-debug.service 2>/dev/null
mount --move /proc /run/newroot/proc
mount --move /sys /run/newroot/sys
mount --move /dev /run/newroot/dev
echo " Starting Blancco..."
exec switch_root /run/newroot /sbin/init