2016년 2월 6일 토요일

UEFI and Legacy BIOS PXE netboot through dnsmasq

Nowadays new computers for both consumers and the server room support UEFI (Unified Extensible Firmware Interface) and I have even seen some recent machines that don't support Legacy BIOS at all.

Legacy BIOS PXE netboot uses a UNDI (Unified Network Device Interface) driver but UEFI PXE does not. I therefore had to make some changes in my /etc/dnsmasq.conf file to enable UEFI PXE. Luckily, dnsmasq can autodetect the type of pxe client it is dealing with if you set a few options in the .conf file:

# Test for the architecture of a netboot client. PXE clients are
# supposed to send their architecture as option 93. (See RFC 4578)

dhcp-match=x86PC, option:client-arch, 0 #BIOS x86
dhcp-match=BC_EFI, option:client-arch, 7 #EFI x86-64


# Load different PXE boot image depending on client architecture
pxe-service=tag:x86PC,X86PC, "Install Linux on x86 legacy BIOS", pxelinux
pxe-service=tag:BC_EFI,BC_EFI, "Install Linux on x86-64 UEFI", uefi/bootx64.efi



# Set boot file name only when tag is "bios" or "uefi"
dhcp-boot=tag:x86PC,pxelinux.0  # for Legacy BIOS detected by dhcp-match above
dhcp-boot=tag:BC_EFI,uefi/bootx64.efi # for UEFI arch detected by dhcp-match above


# Enable dnsmasq's built-in TFTP server
enable-tftp

# Set the root directory for files available via FTP.
tftp-root=/usr/local/tftpboot/pxelinux


My entire dnsmasq.conf file can be found here:
https://github.com/gojun077/jun-dotfiles/blob/master/dnsmasq

The directory hierarchy of my tftp-root directory is as follows:

[archjun@pinkS310 pxelinux]$ tree -d /usr/local/tftpboot/pxelinux/
/usr/local/tftpboot/pxelinux/

├── EFI
│   └── BOOT
├── images
│   ├── arch_x64
│   ├── fedora23_x64
│   └── xubuntu15-10_x64
├── kickstart-pxe
├── pxelinux.cfg
└── uefi

9 directories

Note that this hierarchy will be different depending on which Linux distribution's bootx64.efi file you decide to use. Although the EFI boot files are named almost identically across various linux distros, bootx64.efi looks for boot-related files in slightly different paths. You can find this file (and other EFI boot-related files) from the installation .iso file for your distribution. Normally the files will be located in the path ../EFI/BOOT/ on the installation DVD/iso image and will contain the files bootx64.efi (BOOTX64.EFI), grubx64.efi, a sample grub.cfg and possibly other files (like MokManager.efi and shim.efi for UEFI secure boot).

Since I am using the bootx64.efi file from CentOS 7,  I have to place files in the directories that CentOS 7 expects. Recall that my tftp-root= path defined in dnsmasq.conf is /usr/local/tftpboot/pxelinux/, hereafter simply referred to as tftp-root. The required paths are as follows.

EFI network boot program (NBP): tftp-root/uefi/bootx64.efi
EFI grub loader: tftp-root/grubx64.efi,
EFI grub menu: tftp-root/grub.cfg or tftp-root/EFI/BOOT/grub.cfg

The paths will be different if you use a bootx64.efi from another distro, however. For example, Fedora 23 looks for grubx64.efi within tftp-root/uefi/ while Ubuntu looks for grubx64.efi under tftp-root/.

The nice thing about the bootx64.efi from CentOS 7 is that it emits verbose debugging info in the systemd journal (which can be viewed in real-time with journalctl -f) if it cannot find boot files in the expected paths. Here is an example from journalctl:

...
Feb 01 17:38:06 pinkS310 dnsmasq-tftp[31773]: sent /usr/local/tftpboot/pxelinux/uefi/bootx64.efi to 192.168.95.150
Feb 01 17:38:06 pinkS310 dnsmasq-tftp[31773]: file /usr/local/tftpboot/pxelinux/grubx64.efi not found

...

By looking carefully at the system logs in real-time, you can find out where you need to place files in your tftp-root directory hierarchy, but I found that verbose debugging is not emitted when using the bootx64.efi files from Fedora 23 and Ubuntu.

Although I am using the CentOS 7 EFI boot files, I can install non-CentOS distros over PXE through grub menu once grub.cfg is loaded.

Here is my grub.cfg which installs Fedora 23 Server over http and allows me to control the install from a remote machine using vncviewer:



You will notice that the kernel vmlinuz and the initial ramdisk initrd.img  are in the images directory which is a subdirectory of tftp-root (refer to the directory tree above). This subdirectory contains more directories storing the kernels and ramdisk images for multiple distros (in my case, fedora, archlinux, and ubuntu). These images can be used over both UEFI and legacy BIOS PXE.

If dnsmasq detects that a client only supports legacy BIOS PXE when it receives a DHCP request, it will send pxelinux.0 instead of bootx64.efi as the NBP. Then instead of grub.cfg, the default legacy BIOS PXE config file will be loaded from tftp-root/pxelinux.cfg/default

Here is a legacy BIOS pxe config file that installs Archlinux:


Note that the config syntax differs by linux distribution. In the case of Archlinux, before loading the initial ramdisk, you must first load Intel microcode (if you are using an Intel CPU). Also the syntax for sending installation files over http differs from that of, say, Fedora or RHEL/CentOS.