Tidy up pxe flow
This commit is contained in:
@@ -23,8 +23,12 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
mkdir -p /srv/tftp
|
mkdir -p /srv/tftp
|
||||||
# User-supplied iPXE binary (ipxe.efi) from the read-only source mount.
|
# User-supplied iPXE binary (snponly.efi) from the read-only source mount.
|
||||||
cp -f /tftp-src/*.efi /srv/tftp/ 2>/dev/null || true
|
cp -f /tftp-src/*.efi /srv/tftp/ 2>/dev/null || true
|
||||||
|
# autoexec.ipxe was an STP-era workaround (ifopen+retry before autoboot); it's no
|
||||||
|
# longer rendered — PortFast on the switch port is the real fix. Remove any stale
|
||||||
|
# copy left in a long-lived container's writable layer.
|
||||||
|
rm -f /srv/tftp/autoexec.ipxe
|
||||||
|
|
||||||
extract_cmdline() { # $1 = UKI path; echoes the cleaned cmdline (empty on failure)
|
extract_cmdline() { # $1 = UKI path; echoes the cleaned cmdline (empty on failure)
|
||||||
uki="$1"
|
uki="$1"
|
||||||
@@ -47,49 +51,28 @@ render_boot_ipxe() {
|
|||||||
echo " hit a dracut shell under Secure Boot OFF (no embedded cmdline)." >&2
|
echo " hit a dracut shell under Secure Boot OFF (no embedded cmdline)." >&2
|
||||||
echo " Check the /artifacts mount + binutils, or enable Secure Boot." >&2
|
echo " Check the /artifacts mount + binutils, or enable Secure Boot." >&2
|
||||||
fi
|
fi
|
||||||
# Render the SAME boot logic to two files:
|
# boot.ipxe is fetched as the DHCP bootfile (dnsmasq tag:ipxe) AFTER iPXE's
|
||||||
# autoexec.ipxe — iPXE fetches + runs this at STARTUP (before autoboot). The
|
# normal autoboot DHCP has already configured the link, so it just fetches and
|
||||||
# leading `ifopen net0` brings the link UP on NICs whose NII/UNDI link iPXE
|
# boots the UKI. `imgargs` feeds the UKI's REAL cmdline (Secure Boot OFF — see
|
||||||
# can't establish during autoboot — e.g. EliteBook 820 G4 / Intel I219-LM,
|
# top); without it iPXE would pass the image name as the cmdline and dracut
|
||||||
# which sits at link:down ("No configurable methods") until ifopen. Without
|
# would drop to an emergency shell. (every fallible step is '||'-guarded — a
|
||||||
# this, autoboot fails before it can even DHCP for boot.ipxe.
|
# bare failure aborts the iPXE script.)
|
||||||
# boot.ipxe — the DHCP-bootfile fallback (tag:ipxe) for firmware that DOES
|
#
|
||||||
# autoboot-DHCP fine; harmless to carry the same ifopen.
|
# REQUIRES PortFast/edge on the switch port: iPXE's autoboot opens the NIC,
|
||||||
# Both feed iPXE the UKI's REAL cmdline via imgargs (Secure Boot OFF; see top).
|
# which bounces the PHY; without PortFast the switch's STP forwarding delay
|
||||||
for f in /srv/tftp/autoexec.ipxe /srv/tftp/boot.ipxe; do
|
# (~30s) drops the DHCP and the boot fails. (We removed the old ifopen+retry
|
||||||
cat > "$f" <<EOF
|
# workaround now that PortFast is the documented requirement — serving/tftp/README.)
|
||||||
|
cat > /srv/tftp/boot.ipxe <<EOF
|
||||||
#!ipxe
|
#!ipxe
|
||||||
# NOTE: in iPXE a bare failing command aborts the script (-> iPXE exits -> the
|
dhcp net0 || goto err
|
||||||
# firmware restarts PXE), so EVERY step that can fail is guarded with '||'.
|
|
||||||
#
|
|
||||||
# The link is already up + forwarding here (the TFTP fetch of this script just
|
|
||||||
# succeeded), so try DHCP FIRST without touching the PHY — on a PortFast/edge
|
|
||||||
# port this succeeds immediately with no delay.
|
|
||||||
dhcp net0 && goto have_ip || echo initial DHCP failed; will reset link and retry
|
|
||||||
# Fallback: reset the link, then retry DHCP long enough to outlast the switch's
|
|
||||||
# STP forwarding delay (~30s) that the ifopen bounce triggers. A single ifopen
|
|
||||||
# (held open across the loop) means the PHY bounces ONCE; STP then converges and
|
|
||||||
# a later DHCP gets through. PROPER fix is PortFast/edge on the switch port so
|
|
||||||
# there's no delay at all — see serving/tftp/README.md.
|
|
||||||
ifopen net0 || goto err
|
|
||||||
set tries 0
|
|
||||||
:dhcp_retry
|
|
||||||
dhcp net0 && goto have_ip || echo DHCP retry \${tries}
|
|
||||||
inc tries || goto err
|
|
||||||
iseq \${tries} 30 && goto no_ip || sleep 3
|
|
||||||
goto dhcp_retry
|
|
||||||
:have_ip
|
|
||||||
imgfetch http://${SERVER_IP}/${uki} || goto err
|
imgfetch http://${SERVER_IP}/${uki} || goto err
|
||||||
imgargs ${uki} ${cmdline}
|
imgargs ${uki} ${cmdline}
|
||||||
boot ${uki} || goto err
|
boot ${uki} || goto err
|
||||||
:no_ip
|
|
||||||
echo No DHCP after ~90s on net0 - enable PortFast/edge on the switch port (STP delay).
|
|
||||||
:err
|
:err
|
||||||
echo Fleet iPXE chain failed (\${errno}) - dropping to iPXE shell
|
echo Fleet iPXE chain failed (\${errno}) - dropping to iPXE shell
|
||||||
shell
|
shell
|
||||||
EOF
|
EOF
|
||||||
done
|
echo "rendered /srv/tftp/boot.ipxe -> ${uki} (cmdline: ${cmdline:-<MISSING>})"
|
||||||
echo "rendered autoexec.ipxe + boot.ipxe -> ${uki} (cmdline: ${cmdline:-<MISSING>})"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -n "${SERVER_IP:-}" ] && [ -n "${IMAGE_VERSION:-}" ]; then
|
if [ -n "${SERVER_IP:-}" ] && [ -n "${IMAGE_VERSION:-}" ]; then
|
||||||
|
|||||||
+17
-5
@@ -11,10 +11,16 @@ Flow for a PXE-only host:
|
|||||||
|
|
||||||
```
|
```
|
||||||
firmware PXE (PXEClient) --TFTP--> snponly.efi (iPXE)
|
firmware PXE (PXEClient) --TFTP--> snponly.efi (iPXE)
|
||||||
iPXE re-DHCPs (user-class "iPXE") --> handed boot.ipxe (TFTP)
|
iPXE autoboot DHCP (user-class "iPXE") --> handed boot.ipxe (TFTP)
|
||||||
boot.ipxe: imgfetch UKI over HTTP -> imgargs <real cmdline> -> boot
|
boot.ipxe: imgfetch UKI over HTTP -> imgargs <real cmdline> -> boot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Requires PortFast/edge on the switch port** (see the gotchas below). iPXE's
|
||||||
|
> autoboot opens the NIC, which bounces the PHY; without PortFast the switch's STP
|
||||||
|
> forwarding delay (~30 s) drops iPXE's DHCP and the boot fails. PortFast removes
|
||||||
|
> the delay. (The earlier `autoexec.ipxe` + `ifopen` + DHCP-retry workaround was
|
||||||
|
> removed once PortFast was identified as the real fix.)
|
||||||
|
|
||||||
`boot.ipxe` is **rendered at container start** by the dnsmasq entrypoint; only the
|
`boot.ipxe` is **rendered at container start** by the dnsmasq entrypoint; only the
|
||||||
iPXE binary (`snponly.efi`) is supplied here. The script exists because of a sharp
|
iPXE binary (`snponly.efi`) is supplied here. The script exists because of a sharp
|
||||||
edge:
|
edge:
|
||||||
@@ -107,10 +113,16 @@ Hard-won findings from bringing up the first PXE-only physical host:
|
|||||||
~30 s to every boot — PortFast removes the delay entirely.
|
~30 s to every boot — PortFast removes the delay entirely.
|
||||||
- **iPXE aborts the script on any unguarded command failure** (→ iPXE exits → the
|
- **iPXE aborts the script on any unguarded command failure** (→ iPXE exits → the
|
||||||
firmware restarts the whole PXE process, looking like "it doesn't retry"). Every
|
firmware restarts the whole PXE process, looking like "it doesn't retry"). Every
|
||||||
fallible step in `boot.ipxe`/`autoexec.ipxe` is therefore `||`-guarded.
|
fallible step in `boot.ipxe` is therefore `||`-guarded.
|
||||||
- **`autoexec.ipxe`** (rendered by the dnsmasq entrypoint) is fetched + run at
|
- **`boot.ipxe`** (rendered by the dnsmasq entrypoint, served as the `tag:ipxe`
|
||||||
iPXE startup, *replacing* the default autoboot; that's where the `ifopen` +
|
DHCP bootfile) does `dhcp` + `imgfetch` UKI + `imgargs <real cmdline>` + `boot`.
|
||||||
DHCP-retry + `imgargs <real cmdline>` chain lives.
|
The cmdline injection is needed only because **Secure Boot is OFF** (the stub
|
||||||
|
takes the loader's cmdline); under Secure Boot it's a no-op and `boot.ipxe`
|
||||||
|
could collapse to a plain `chain` of the UKI.
|
||||||
|
- **Removed STP-era workaround:** an `autoexec.ipxe` that ran `ifopen net0` + a
|
||||||
|
DHCP-retry loop before autoboot was used to wait out STP. It's gone now that
|
||||||
|
**PortFast is the fix** — if you ever run on a switch you can't set PortFast on,
|
||||||
|
that ifopen+retry approach (in git history) is the fallback.
|
||||||
|
|
||||||
## Note
|
## Note
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user