v0.6.1: latest iPXE + automatic NIC driver fallback (more devices, zero toggle)

Mirrors the worthwhile device-support wins from iVentoy 1.0.24→1.0.35 onto our
(very different) proxy-DHCP + iPXE-chainload architecture. iVentoy's other
changes are inapplicable (arm64-server / distro-display fixes live in its
injected Linux, which we don't have), niche (iSCSI), or closed-source
(Matrix Boot).

iPXE refreshed (mirrors 1.0.35 "Update iPXE")
- Pin the from-source build to ipxe/ipxe master @ 2026-06-09
  (95ffbf4745553e8a207922389929e1943c0237c0) — newer NIC drivers + EFI fixes.
  The pin also busts the cached ipxe-build Docker layer so the release
  actually recompiles iPXE; build-ipxe.sh now shallow-fetches an exact SHA.

Automatic NIC driver fallback (mirrors 1.0.34 "driver/boot-file mode" — but
no operator toggle, per request)
- New DriverMode {Firmware, Builtin} in core; ClientArch::ipxe_bootfile_mode
  maps each arch to either the firmware-net build (snponly/undionly, default)
  or the all-drivers build (ipxe.efi/ipxe.pxe/ipxe-i386.efi/ipxe-arm64.efi).
- The DHCP proxy serves Firmware by default — byte-for-byte unchanged, so
  hardware that boots today never regresses. A new DriverEscalation state
  machine watches for the tell-tale failure: a MAC re-PXE-boots (fresh
  firmware DISCOVER) without ever completing the iPXE-user-class handoff that
  proves the firmware NIC stack worked. That MAC is automatically escalated to
  iPXE's own NIC drivers, and the choice is sticky after a confirmed handoff
  (debounced for the :67/:4011 same-boot pair, TTL-pruned, capped). It just
  works — no settings, no UI.
- All-drivers binaries fetched per arch (ipxe.pxe + i386/arm64 native EFI;
  x86_64 ipxe.efi already built from source with PNG); ipxe-assets embeds
  *.pxe and logs availability per (arch, mode).

Core principles intact: DHCP-proxy-only, container-first, Rust-focused (the
logic is all Rust; only the iPXE fetch/build stays shell), Windows hard-rules
untouched (this never goes near Windows boot).

Validation: clippy clean; full workspace test suite green (core 99 incl. new
DriverMode tests, dhcp-proxy +4 escalation tests, http-api 31+68, iso-store
61, tftp 6, bin 2); fmt-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Miles Ward
2026-06-09 11:18:07 -04:00
co-authored by Claude Opus 4.8
parent 24879fcc90
commit 4f193cac05
12 changed files with 444 additions and 55 deletions
+202
View File
@@ -0,0 +1,202 @@
//! Automatic per-MAC NIC driver-mode escalation (v0.6.1).
//!
//! OpenPXE serves the firmware-net iPXE build (`snponly`/`undionly`) by
//! default — it's the most reliable choice for chainloading because the
//! firmware just proved its network works by downloading the NBP. A minority
//! of NICs have a missing or buggy firmware UNDI/SNP stack; those clients
//! TFTP the binary fine, but then iPXE can't bring the link up, so the
//! tell-tale second DHCP DISCOVER carrying the `iPXE` user-class never arrives
//! and the machine eventually re-PXE-boots.
//!
//! We detect exactly that: a *fresh* firmware DISCOVER from a MAC whose
//! previous firmware attempt was never confirmed by an iPXE handoff means the
//! firmware-net build failed → escalate that MAC to [`DriverMode::Builtin`]
//! (iPXE's own NIC drivers). The decision is sticky — once a MAC settles on a
//! mode that completes the handoff, later boots go straight to it. There is no
//! operator toggle; it just works, and the default (firmware) path is
//! unchanged so hardware that already boots never regresses.
use openpxe_core::DriverMode;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::time::{Duration, Instant};
/// Multiple DISCOVERs within this window belong to the *same* boot (DHCP
/// retransmits, plus the :4011 PXE Boot Server query that follows the :67
/// DISCOVER). They must not be mistaken for a failed-and-retried boot.
const SAME_BOOT_DEBOUNCE: Duration = Duration::from_secs(8);
/// Forget a MAC's state after this long with no activity, so a transient
/// escalation doesn't pin a client to Builtin forever and the map stays
/// bounded over a long-running deployment.
const ENTRY_TTL: Duration = Duration::from_mins(30);
/// Hard cap on tracked MACs. Past this we evict the least-recently-seen
/// entry — escalation is best-effort, never a memory-growth vector.
const MAX_ENTRIES: usize = 4096;
#[derive(Debug, Clone, Copy)]
struct Entry {
mode: DriverMode,
/// True once we've served `mode` and are waiting for the iPXE handoff to
/// confirm it worked. A *new* boot arriving while this is still true means
/// the previous attempt failed and we should escalate.
awaiting_confirm: bool,
last_seen: Instant,
}
/// Tracks per-MAC driver-mode escalation. Cheap to share via `Arc`.
#[derive(Debug, Default)]
pub struct DriverEscalation {
inner: Mutex<HashMap<String, Entry>>,
}
impl DriverEscalation {
#[must_use]
pub fn new() -> Self {
Self::default()
}
/// Decide the driver mode for a firmware (PXEClient/HTTPClient) boot from
/// `mac`. `primary` is true for the main DHCP DISCOVER (:67) and false for
/// the PXE Boot Server query (:4011); only the primary path drives
/// escalation, and only when it's clearly a *new* boot (outside the
/// same-boot debounce). The :4011 path just echoes the current mode.
pub fn mode_for_firmware_attempt(&self, mac: &str, primary: bool) -> DriverMode {
self.decide_at(mac, primary, Instant::now())
}
/// Record that `mac` completed the iPXE handoff (a DISCOVER carrying the
/// `iPXE` user-class). The mode we last served worked, so stop awaiting
/// confirmation and keep it sticky for next time.
pub fn mark_ipxe_success(&self, mac: &str) {
self.confirm_at(mac, Instant::now());
}
fn decide_at(&self, mac: &str, primary: bool, now: Instant) -> DriverMode {
let mut g = self.inner.lock();
g.retain(|_, e| now.duration_since(e.last_seen) < ENTRY_TTL);
match g.get_mut(mac) {
None => {
g.insert(
mac.to_owned(),
Entry {
mode: DriverMode::Firmware,
// Only the primary DISCOVER opens a confirmation window.
awaiting_confirm: primary,
last_seen: now,
},
);
if g.len() > MAX_ENTRIES {
evict_oldest(&mut g);
}
DriverMode::Firmware
}
Some(entry) => {
let recent = now.duration_since(entry.last_seen) < SAME_BOOT_DEBOUNCE;
if primary && !recent {
// A genuinely new boot. If the previous attempt was never
// confirmed, the firmware-net build failed → escalate to
// the all-drivers build. Builtin is the most capable build
// we have, so it's the single escalation target (and a MAC
// already on Builtin simply stays there).
if entry.awaiting_confirm {
entry.mode = DriverMode::Builtin;
}
entry.awaiting_confirm = true;
}
entry.last_seen = now;
entry.mode
}
}
}
fn confirm_at(&self, mac: &str, now: Instant) {
let mut g = self.inner.lock();
if let Some(e) = g.get_mut(mac) {
e.awaiting_confirm = false;
e.last_seen = now;
}
}
}
fn evict_oldest(map: &mut HashMap<String, Entry>) {
if let Some(oldest) = map
.iter()
.min_by_key(|(_, e)| e.last_seen)
.map(|(k, _)| k.clone())
{
map.remove(&oldest);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn firmware_first_then_escalates_on_unconfirmed_retry() {
let e = DriverEscalation::new();
let t0 = Instant::now();
// Boot 1, primary DISCOVER: firmware.
assert_eq!(e.decide_at("aa", true, t0), DriverMode::Firmware);
// Same boot's :4011 query (+1s, within debounce): still firmware, no escalation.
assert_eq!(
e.decide_at("aa", false, t0 + Duration::from_secs(1)),
DriverMode::Firmware
);
// Firmware net failed → no iPXE handoff → machine re-PXE-boots much
// later: escalate to builtin drivers.
assert_eq!(
e.decide_at("aa", true, t0 + Duration::from_mins(1)),
DriverMode::Builtin
);
}
#[test]
fn builtin_is_sticky_after_success() {
let e = DriverEscalation::new();
let t0 = Instant::now();
assert_eq!(e.decide_at("bb", true, t0), DriverMode::Firmware);
assert_eq!(
e.decide_at("bb", true, t0 + Duration::from_mins(1)),
DriverMode::Builtin
);
// Builtin worked this time — confirm the handoff.
e.confirm_at("bb", t0 + Duration::from_secs(61));
// Next cold boot goes straight to builtin (no wasted firmware attempt).
assert_eq!(
e.decide_at("bb", true, t0 + Duration::from_mins(2)),
DriverMode::Builtin
);
}
#[test]
fn confirmed_firmware_never_escalates() {
let e = DriverEscalation::new();
let t0 = Instant::now();
assert_eq!(e.decide_at("cc", true, t0), DriverMode::Firmware);
// snponly worked: handoff confirmed.
e.confirm_at("cc", t0 + Duration::from_secs(2));
// A later boot stays on firmware — no spurious escalation.
assert_eq!(
e.decide_at("cc", true, t0 + Duration::from_mins(5)),
DriverMode::Firmware
);
}
#[test]
fn stale_entry_is_forgotten_and_resets_to_firmware() {
let e = DriverEscalation::new();
let t0 = Instant::now();
assert_eq!(e.decide_at("dd", true, t0), DriverMode::Firmware);
assert_eq!(
e.decide_at("dd", true, t0 + Duration::from_mins(1)),
DriverMode::Builtin
);
// After the TTL with no activity the entry is pruned → fresh firmware.
let later = t0 + Duration::from_mins(1) + ENTRY_TTL + Duration::from_secs(1);
assert_eq!(e.decide_at("dd", true, later), DriverMode::Firmware);
}
}