There are at least three ways that x86 machines can try to boot from the network; BIOS PXE boot, UEFI PXE boot, and UEFI HTTP boot . All of them start by the machine asking a DHCP server for what it should boot, and all of them require different answers from the DHCP server. If you want to support more than one network booting option, your DHCP server needs to give each sort of client the right answer for it, which generally means you have to tell the DHCP server how to tell the types of clients apart.
(If you have all modern machines you can probably get away with only supporting UEFI PXE booting, which will simplify your life slightly.)
The DHCP server we use is the standard and now old-fashioned ISC DHCP server. There are a variety of guides for how to configure your ISC DHCP server for multiple types of network booting, but for various reasons I'm writing my own. This one is actually tested in real use (I've booted machines all three ways from this configuration).
When DHCP clients send out network booting requests, they include two important pieces of information, their "vendor class identifier" and their 'architecture'; these are DHCP option code 60 and DHCP option code 93 respectively. The vendor class identifier is a string and the architecture is a 16-bit integer. ISC DHCP has names for both options,
vendor-class-identifier
and
pxe-system-type
respectively ( cf ), although the latter appears to be recent enough that a lot of Internet writeups think you have to define it yourself in your dhcpd.conf, eg:
option pxe-arch code 93 = unsigned integer 16;
Since I didn't read up on all of this before this entry, my dhcpd.conf contains this superstition and I haven't (yet) tested a version without it.
If all you care about is UEFI x86 systems, you can use the vendor class identifier to tell apart UEFI PXE booting and UEFI HTTP booting. In PXE booting, it starts with 'PXEClient', and in HTTP booting, it starts with 'HTTPClient'. This results in a configuration snippet that looks like this:
class "pxeclients" {
# TFTP
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server X.Y.Z.Q;
filename "/grub/shimx64.efi";
}
class "httpclients" {
match if substring (option vendor-class-identifier, 0, 10) = "HTTPClient";
# the v-c-i in the reply is required
option vendor-class-identifier "HTTPClient";
filename "https://X.Y.Z.Q/grub/shimx64.efi";
}
If you also want to handle BIOS PXE systems, you need something more complicated, because both BIOS PXE and UEFI PXE have a vendor class identifier that starts with 'PXEClient'. You can be more precise by matching more of the vendor class identifier because it also includes an 'Arch:XXXXX' string ( cf ), but I think it's simpler to switch to using the 'architecture' number (which is what the 'Arch:' part is telling you anyway). The official list of architecture types is IANA's Processor Architecture Types , and one thing to know when reading it is that 'x64' is 64-bit x86, not Itanium. In practice with x86, what you'll see is 0x00 (BIOS PXE), 0x07 (UEFI PXE), and 0x10 (UEFI HTTP). In your dhcpd.conf, this looks like:
if (option pxe-arch = 00:10) {
# The v-c-i is required
option vendor-class-identifier "HTTPClient";
filename "https://X.Y.Z.Q/grub/shimx64.efi";
} else if (option pxe-arch = 00:07) {
next-server X.Y.Z.Q;
filename "/grub/shimx64.efi";
} else {
next-server X.Y.Z.Q;
filename "/pxe/lpxelinux.0";
}
(Technically I should check pxe-arch for the last clause.)
I believe you can use the official '
pxe-system-type
' here instead of my self-defined version, but I'm copying this example straight from my known-working dhcpd.conf. Also, as covered in dhcp-eval , possibly this would be more clearly written as a switch statement. I may experiment with both changes later, but this is what's working for me today.
(See also my entry on the various steps of a network install from an Ubuntu server ISO , which discusses the shimx64.efi and lpxelinux.0 bits a bit more.)