PXE 网络启动原理:协议栈、交互流程与文件加载顺序

各位好,我是老张。今天咱们开始《网络启动场景参数调优》的第一章。说实话,PXE 这东西我入行头三年都没真正搞明白——直到有一次在数据中心部署 200 台裸机服务器,DHCP 死活给不出正确地址,我才被迫把整个协议栈啃了一遍。嗯,从那以后,我再也不敢轻视这个“看起来简单”的启动流程了。

1.1 PXE 协议栈:谁在跟谁说话?

PXE 全称是 Preboot eXecution Environment,说白了就是让一台还没装系统的机器,通过网络把操作系统内核拉下来。你想想看,一台裸机连硬盘都没有,它怎么上网?靠的就是网卡固件里内置的 PXE 客户端。

整个协议栈分三层:

  • 底层:网卡驱动 + UDP/IP 协议栈(固化在网卡 ROM 或 UEFI 中)
  • 中间层:DHCP 协议(获取 IP 和启动服务器地址)
  • 上层:TFTP 协议(下载启动文件)

我习惯把 PXE 客户端比作一个“网络启动小管家”。它不依赖操作系统,只靠网卡自带的几 KB 代码就能跑起来。这个管家会依次做三件事:要地址、找服务器、拿文件。

关键点:PXE 客户端只支持 UDP 传输。TCP 协议栈太大,塞不进网卡固件。所以 TFTP 成了唯一选择——虽然它慢,但够轻量。

1.2 DHCP 与 TFTP 的交互流程

整个交互过程分四个阶段。我画了一张流程图,你一看就明白:

PXE 网络启动交互流程 PXE 网络启动交互流程 PXE 客户端(裸机) DHCP 服务器 TFTP 服务器 ① DHCP Discover(广播) ② DHCP Offer(含 next-server) ③ DHCP Request ④ DHCP Ack(确认) ⑤ TFTP RRQ(读请求:bootfile) ⑥ TFTP DATA(分块传输) ⑦ 加载并执行 bootfile ⚠️ 避坑提醒: • DHCP 的 next-server 字段必须指向 TFTP 服务器 IP,写错就加载不到文件。 • TFTP 默认端口 69,防火墙必须放行 UDP 69 和临时数据端口。 • 我曾经遇到一个坑:DHCP 返回的 bootfile 名带路径,但 TFTP 根目录没配好, PXE 客户端一直报 "File not found"——折腾了俩小时才发现是路径问题。

流程拆开来看,其实就四步:

  1. DHCP Discover(广播):PXE 客户端发广播,问“谁给我个 IP 和启动服务器地址?”
  2. DHCP Offer(含扩展字段):DHCP 服务器回应,除了 IP,还带上 next-server(TFTP 服务器 IP)和 filename(启动文件名)。
  3. DHCP Request / Ack:客户端确认租约,服务器确认。
  4. TFTP 传输:客户端向 TFTP 服务器发起读请求,分块下载启动文件。

我的经验:DHCP 的 Offer 包里有几个关键选项——Option 66(next-server)和 Option 67(bootfile)。有些老旧 DHCP 服务器不支持这些扩展选项,你得手动配。我建议用 dnsmasq 做测试,它原生支持 PXE,省心很多。

1.3 启动文件加载顺序

文件下载下来之后,PXE 客户端怎么知道该执行哪个?这里有个优先级顺序。我整理了一张表:

优先级 文件来源 说明
1(最高) DHCP Option 67(filename) 服务器明确指定的启动文件,最优先
2 UEFI 默认路径 如 efi/boot/bootx64.efi(仅 UEFI 模式)
3 BIOS 默认路径 如 pxelinux.0(传统 BIOS 模式)
4(最低) 网卡固件内置路径 极少用,部分网卡有硬编码路径

实际项目中,我几乎只用 Option 67 指定文件名。为什么?因为默认路径太容易出问题。举个例子:

  • UEFI 模式下,如果 DHCP 没给 filename,客户端会尝试 efi/boot/bootx64.efi。但你的 TFTP 根目录下可能根本没有这个路径结构。
  • BIOS 模式下,默认找 pxelinux.0。但如果你用的是 GRUB2 做启动器,文件名是 grubx64.efi,那就对不上。

⚠️ 注意:我曾经在混合环境(部分 UEFI、部分 BIOS)里踩过坑。同一台 DHCP 服务器,给 UEFI 客户端返回 bootx64.efi,给 BIOS 客户端返回 pxelinux.0。怎么区分?靠 DHCP 的 Option 60(Vendor Class Identifier)。UEFI 客户端会发 "PXEClient:Arch:00007",BIOS 发 "PXEClient:Arch:00000"。DHCP 服务器可以根据这个做条件分发。

1.4 一个完整的 PXE 启动文件链

启动文件本身不是孤立的。它还会去加载配置文件、内核、initrd。典型的链式加载过程是这样的:

  1. 第一阶段加载器(如 pxelinux.0 或 bootx64.efi)
  2. 配置文件(如 pxelinux.cfg/default 或 grub.cfg)
  3. 内核(如 vmlinuz)
  4. 初始内存盘(如 initrd.img)

每个环节都依赖 TFTP 传输。你想想看,如果 TFTP 的块大小(blksize)默认是 512 字节,一个 5MB 的内核要传 10000 多次——能不慢吗?这就是后面章节要讲的调优点了。

一句话总结:PXE 启动就是“广播要地址 → 拿配置 → TFTP 拉文件 → 加载执行”四步走。每一步都可能成为瓶颈,咱们后面会逐个拆解。