Skip to content

iPXE 自定义编译

PxeLab 使用自定义编译的 iPXE 二进制实现两阶段网络引导。本文介绍内嵌引导脚本、编译环境与全部编译目标。

相关文档: 引导架构与无盘启动 | 架构映射与 Secure Boot


概述

每个 iPXE 二进制内嵌同一份引导脚本,执行 DHCP 后通过 HTTP 加载引导菜单,避免了 PXE BIOS/UEFI 缓存 DHCP 数据导致的链式加载循环。

内嵌脚本

bash
#!ipxe
# PxeLab embedded iPXE script
# This script is compiled into iPXE binaries via EMBED= parameter
# It chains to the PxeLab HTTP server for dynamic boot menu generation

:netboot
dhcp net0 || goto dhcp_failed

# Determine server address from DHCP
isset ${next-server} && set pxelab-server ${next-server}
isset ${proxydhcp/next-server} && set pxelab-server ${proxydhcp/next-server}
isset ${pxelab-server} || set pxelab-server ${dhcp-server}

# Build chain URL
set pxelab-url http://${pxelab-server}:8080/boot/ipxe/script?mac=${net0/mac}

# Chain to PxeLab server
chain ${pxelab-url} || goto failsafe

:dhcp_failed
echo DHCP failed - no network configuration available
goto failsafe

:failsafe
echo
echo Connection to PxeLab server failed.
echo
menu Failsafe Menu
item --gap System Operations
item retry        Retry network boot
item netconfig    Manual network configuration
item localboot    Boot from local disk
item debug        iPXE Debug Shell
choose failsafe_choice || goto localboot
goto ${failsafe_choice}

:retry
goto netboot

:netconfig
echo
echo Manual Network Configuration:
echo
ifstat
echo
echo -n Interface number [0 for net0]: && read net-dev
isset ${net-dev} || set net-dev 0
echo -n IP address: && read net${net-dev}/ip
echo -n Subnet mask: && read net${net-dev}/netmask
echo -n Gateway: && read net${net-dev}/gateway
echo -n DNS server: && read dns
ifopen net${net-dev}
echo
echo Attempting chainload...
goto netboot

:localboot
exit

:debug
echo Type "exit" to return to menu
shell
goto failsafe

脚本逻辑:

  1. DHCP 优先 — 执行 dhcp net0 获取 IP,同时接收 ProxyDHCP OFFER(如存在);失败时进入 failsafe 菜单
  2. server 地址三级判断 — 依次取 ${next-server}(普通 DHCP 的 siaddr)、${proxydhcp/next-server}(ProxyDHCP 的 siaddr)、${dhcp-server}(兜底),存入独立变量 pxelab-server
  3. Proxy 模式proxydhcp/next-server 存在 → 使用它作为 PxeLab 地址(即 ProxyDHCP 的 siaddr 字段)
  4. Server 模式 — 无 proxy 数据 → 使用 ${dhcp-server}(PxeLab 本身就是 DHCP 服务器)
  5. HTTP 链加载 — 通过 HTTP 链到 PxeLab 动态引导菜单;失败进入 failsafe 菜单
  6. failsafe 菜单 — 提供重试、手动网络配置、本地启动、调试 shell 四个选项,便于现场排查

优势:无需硬编码 IP、不依赖 ${next-server} 的 scope 优先级、不依赖 PXE_STACK 编译选项。Proxy 和 Server 两种模式共用同一份脚本。

PXE_STACK 说明

已不再需要。 实测发现 PXE_STACK 在 Legacy BIOS(undionly.kpxe)下无法正确导入 ProxyDHCP 数据——PXE ROM 将 proxy 数据存为 Option 43 子选项,PXE_STACK 读不到。当前方案通过 iPXE 的 dhcp 命令原生接收 yiaddr=0 的 ProxyDHCP OFFER 并存入 proxydhcp scope。

ProxyDHCP 识别条件

iPXE 的 dhcp_offer() 将 OFFER 识别为 ProxyDHCP 的两个必要条件:

  1. yiaddr == 0.0.0.0 — 关键判据,表示「不分配 IP」
  2. Option 60 = "PXEClient" — UEFI PXE Base Code 要求 OFFER 中必须回写此选项

PxeLab 的 appendProxyPXEOptions() 确保两者同时满足,并一并设置 siaddr、Option 54、Option 66、Option 43。


编译环境

  • Linux 主机,需安装:
    • gitmakegccxz
    • 各目标架构的交叉编译器:
      • gcc-aarch64-linux-gnu(ARM64 UEFI)
      • gcc-x86-64-linux-gnu(x86 UEFI,通常已内置)
      • gcc-i686-linux-gnu(IA32 UEFI,可选)
    • 网络访问(克隆 iPXE 源码)

编译命令

1) 克隆 iPXE 源码

bash
git clone --depth 1 https://github.com/ipxe/ipxe.git
cd ipxe/src

2) 创建内嵌脚本

仓库内置了 boot/embedd.ipxe(PxeLab 官方使用的内嵌脚本),直接复制或参考它:

bash
cat > embedd.ipxe << "IPXE_EOF"
#!ipxe
# PxeLab embedded iPXE script
# This script is compiled into iPXE binaries via EMBED= parameter
# It chains to the PxeLab HTTP server for dynamic boot menu generation

:netboot
dhcp net0 || goto dhcp_failed

# Determine server address from DHCP
isset ${next-server} && set pxelab-server ${next-server}
isset ${proxydhcp/next-server} && set pxelab-server ${proxydhcp/next-server}
isset ${pxelab-server} || set pxelab-server ${dhcp-server}

# Build chain URL
set pxelab-url http://${pxelab-server}:8080/boot/ipxe/script?mac=${net0/mac}

# Chain to PxeLab server
chain ${pxelab-url} || goto failsafe

:dhcp_failed
echo DHCP failed - no network configuration available
goto failsafe

:failsafe
echo
echo Connection to PxeLab server failed.
echo
menu Failsafe Menu
item --gap System Operations
item retry        Retry network boot
item netconfig    Manual network configuration
item localboot    Boot from local disk
item debug        iPXE Debug Shell
choose failsafe_choice || goto localboot
goto ${failsafe_choice}

:retry
goto netboot

:netconfig
echo
echo Manual Network Configuration:
echo
ifstat
echo
echo -n Interface number [0 for net0]: && read net-dev
isset ${net-dev} || set net-dev 0
echo -n IP address: && read net${net-dev}/ip
echo -n Subnet mask: && read net${net-dev}/netmask
echo -n Gateway: && read net${net-dev}/gateway
echo -n DNS server: && read dns
ifopen net${net-dev}
echo
echo Attempting chainload...
goto netboot

:localboot
exit

:debug
echo Type "exit" to return to menu
shell
goto failsafe
IPXE_EOF

3) 启用 HTTPS

编辑 src/config/general.h,取消注释或添加:

c
#define DOWNLOAD_PROTOCOL_HTTPS

DOWNLOAD_PROTOCOL_HTTPS 使 iPXE 能从 netboot 目录引用的 https://github.com/... 等 HTTPS 地址下载内核和 initrd。

其他配置项(PXE_MENUPXEXTPXE_STACK 等)无需修改,默认值即可。PXE_STACK 不再是必要条件(见上文说明)。

4) 编译全部目标

bash
# BIOS x86 — UNDI(使用 PXE ROM 网络栈,不含原生网卡驱动)
make bin/undionly.kpxe EMBED=embedd.ipxe

# BIOS x86 — 全驱动(体积较大,个别网卡可能有兼容问题)
make bin/ipxe.pxe EMBED=embedd.ipxe

# UEFI x86-64 — SNP(使用 UEFI 网络栈)
make bin-x86_64-efi/ipxe.efi EMBED=embedd.ipxe

# UEFI IA32
make bin-i386-efi/ipxe.efi EMBED=embedd.ipxe

# UEFI ARM64(需要 aarch64 交叉编译器)
make bin-arm64-efi/ipxe.efi EMBED=embedd.ipxe CROSS=aarch64-linux-gnu-

使用 PxeLab Makefile 快捷编译

PxeLab 仓库自带 Makefile 目标:

bash
make ipxe-build        # 编译 x86_64 EFI(非嵌入式,默认)
make ipxe-build-embed  # 编译 x86_64 EFI(嵌入式 failsafe)
make ipxe-build-all    # Docker 交叉编译全部架构(推荐)

编译产物

编译产物架构PxeLab 文件名大小
bin/undionly.kpxeBIOS x86(UNDI)undionly.kpxe~71KB
bin/ipxe.pxeBIOS x86(全驱动)ipxe.pxe~392KB
bin-x86_64-efi/ipxe.efiUEFI x86-64ipxe.efi~1.1MB
bin-i386-efi/ipxe.efiUEFI IA32ipxe32.efi~1.0MB
bin-arm64-efi/ipxe.efiUEFI ARM64ipxe-arm64.efi~1.2MB
bin-x86_64-efi/snponly.efiEFI BC(SNP 驱动)snponly.efi-
ipxe-riscv64.efiRISC-V 64ipxe-riscv64.efi-
ipxe-loong64.efiLoongArch64ipxe-loong64.efi-
ipxe-x86_64-sb.efiEFI x86-64-Secure Boot iPXE
ipxe-arm64-sb.efiEFI ARM64-Secure Boot iPXE
shim-x86_64.efi / shim-arm64.efi--Secure Boot Shim

集成到 PxeLab

编译产物需复制到两个位置:

bash
# 运行时引导目录
cp bin/undionly.kpxe /path/to/PxeLab/boot/
cp bin-x86_64-efi/ipxe.efi /path/to/PxeLab/boot/
# ... 以此类推

# 内嵌 bootdist(首次运行时释放)
cp bin/undionly.kpxe /path/to/PxeLab/cmd/pxelab/bootdist/
cp bin-x86_64-efi/ipxe.efi /path/to/PxeLab/cmd/pxelab/bootdist/
# ... 以此类推

然后重新编译 PxeLab:

bash
cd /path/to/PxeLab
go build ./cmd/pxelab/

架构映射

客户端架构到引导文件名的映射逻辑见 internal/boot/archmap.go;架构映射表与 Secure Boot 详见架构映射与 Secure Boot

PxeLab - 一体化 PXE 网络引导服务器