На домашних роутерах в качестве сервера DNS и DHCP обычно используется dnsmasq. В прошивках типа TomatoUSB есть возможность задать для него дополнительные опции, в том числе и для загрузки по сети с помощью PXE. Вот с этим у меня и возникли заморочки, потому что для машин с UEFI надо отдавать не обычный pxe-загрузчик, а efi-приложение.
Для начала немного теории.
При загрузке по сети часть прошивки материнской платы поднимает сетевой интерфейс и пытается его настроить с помощью DHCP, отправляя соответствующий широковещательный запрос в сеть. В этом запросе содержится куча служебной информации о хосте, чтобы правильно настроенный DHCP-сервер мог отдать правильные настройки.
Все передаваемые и принимаемые параметры называются опциями, и их очень много, да ещё и производители железа могут свои добавлять для удобства. Протокол это вроде бы как позволяет.
Когда-то давно я даже нашёл документ с их списком. Вот он.
Теперь практика.
Из всех опций для идентификации архитектуры клиента нужна опция №93. Значения её полей можно найти в RFC4578.
Type Architecture Name ---- ----------------- 0 Intel x86PC 1 NEC/PC98 2 EFI Itanium 3 DEC Alpha 4 Arc x86 5 Intel Lean Client 6 EFI IA32 7 EFI BC 8 EFI Xscale 9 EFI x86-64
dnsmasq надо настроить так, чтобы для клиентов с 64-битным UEFI отдавался загрузчик в виде EFI-приложения, а для клиентов с BIOS отдавался обычный PXE-загрузчик. Если для isc-dhcp-server подобное делается с помощью расписывания условий, то для dnsmasq это делается с помощью установки значений тегов. Вот такой кусок конфига я задал в настройках роутера:
dhcp-match=set:efi-x86_64,option:client-arch,7 dhcp-match=set:efi-x86_64,option:client-arch,9 dhcp-match=set:bios,option:client-arch,0 dhcp-boot=tag:efi-x86_64,syslinux.efi,itxserver,192.168.1.30 dhcp-boot=tag:bios,pxelinux.0,itxserver,192.168.1.30
В строках 1-3 проверяется значение полученной от клиента опции "client-arch" (№93). Если оно равно 7 или 9, то устанавливается тег "efi-x86_64", если значение равно 0, то устанавливается тег "bios".
В 4 и 5 строке по соответствующим тегам отдаётся нужное имя файла и адрес tftp-сервера. В данном случае сервер один, но для UEFI-клиентов отдаётся имя файла "syslinux.efi", а для BIOS-клиентов - "pxelinux.0".
Второй проблемой стало тестирование настроек DHCP-сервера без привлечения реальных и виртуальных машин. Т.е. нужна была программа, которая может сформировать нужный запрос для DHCP-сервера и расшифровать полученный ответ. И такую программу я нашёл. Она так и называется dhcptest. Она написана на языке D, установка компилятора которого - тот ещё квест, но есть готовые бинарники для Windows. Для правильной работы в Linux программе нужны права root.
Если программу запустить с параметром "--query" или набрать команду "d" в интерактивном режиме, то она сформирует запрос к DHCP-серверу и расшифрует полученный ответ, но в нём не будет ничего про файл-загрузчик и tftp-сервер:
op=BOOTREPLY chaddr=7F:DC:9E:3F:52:87 hops=0 xid=A6A4422B secs=0 flags=8000 ciaddr=0.0.0.0 yiaddr=192.168.1.26 siaddr=192.168.1.1 giaddr=0.0.0.0 sname= file=
Чтобы сделать правильный запрос, надо к списку добавить опцию №93 (client-arch) типа u16 со значением 0, 7 или 9. Делается это добавлением ключа "--option "93[u16]=7"". В данном случае опция имеет значение 7 (EFI BC). Теперь в ответе есть нужные поля:
op=BOOTREPLY chaddr=46:67:94:75:D6:FC hops=0 xid=43CA0C4E secs=0 flags=8000 ciaddr=0.0.0.0 yiaddr=192.168.1.6 siaddr=192.168.1.30 giaddr=0.0.0.0 sname=itxserver file=syslinux.efi
Ещё одной полезной программой при настройке является dhcpdump. Она тоже требует права root для работы. Для запуска требуется указать сетевой интерфейс для прослушивания. Из-за того, что по протоколу DHCP запросы и ответы посылаются широковещательными пакетами, то их можно подслушать на других узлах той же подсети.
С помощью этой программы я подсматривал за процессом получения настроек при загрузке по сети виртуальной машины.