Skip to content

Instantly share code, notes, and snippets.

@mgerdts
Created February 12, 2020 21:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgerdts/5f9514cd07a168d8bff3803c6830ff8e to your computer and use it in GitHub Desktop.
Save mgerdts/5f9514cd07a168d8bff3803c6830ff8e to your computer and use it in GitHub Desktop.
ipxe chainload from qemu built-in to Joyent

I have a box running Fedora, which runs a bunch of VMs. I want to iPXE boot using a larger ipxe script than is allowed by the ipxe that is embedded in qemu's virtual nic. That is, a VM is booting with iPXE but not the right ipxe.

Let's consider two VMs, debian10 and debian-live-ipxe. The DHCP server is running debian10, the other is pxe booting.

The procedure followed is roughly:

Grab the .tar.gz from the manta directory mentioned by /Joyent_Dev/public/builds/ipxe/master-latest.

Copy boot/undionly.kpxe from that archive to /tftpboot/.

Modify /etc/dhcp/dhcpd.conf to have the following.

default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
authoritative;
option space ipxe;
option ipxe-encap-opts code 175 = encapsulate ipxe;
option ipxe.https code 20 = unsigned integer 8;

subnet 192.168.42.0 netmask 255.255.255.0 {
	range 192.168.42.100 192.168.42.200
	next-server 192.168.42.1;
	filename "undionly.kpxe";
}

Run systemctl restart isc-dhcp-server.

Run tcpdump to capture packets the appropriate interface.

tcpdump -i enp8s0 -w /tmp/pkts ether port bootps

Boot the other VM. Once it loops through ipxe a couple times, you can kill it. You should notice that the first ipxe banner doesn't say Joyent and the subsequent ones do.

Stop the packet capture. Use tcpdump -r /tmp/pkts -vv to display the packet captures. Compare the first two packets that have DHCP-Message Option 53, length 1: Discover. In this example, I've pasted them into files named 1 and 2.

# diff 1 2
1c1
<     0.0.0.0.bootpc > 255.255.255.255.bootps: [udp sum ok] BOOTP/DHCP, Request from 52:54:00:9d:7d:60 (oui Unknown), length 397, xid 0x556ed510, secs 4, Flags [none] (0x0000)
---
>     0.0.0.0.bootpc > 255.255.255.255.bootps: [udp sum ok] BOOTP/DHCP, Request from 52:54:00:9d:7d:60 (oui Unknown), length 397, xid 0xc4a6cf39, secs 4, Flags [Broadcast] (0x8000)
19c19
< 	    T175 Option 175, length 45: 177.5.1.26.244.16.65.235.3.1.0.0.23.1.1.34.1.1.19.1.1.17.1.1.39.1.1.25.1.1.16.1.2.33.1.1.21.1.1.24.1.1.18.1.1
---
> 	    T175 Option 175, length 45: 177.5.1.26.244.16.65.235.3.1.0.0.23.1.1.34.1.1.19.1.1.20.1.1.39.1.1.25.1.1.16.1.2.33.1.1.21.1.1.24.1.1.38.1.1
20a21
> 	    GUID Option 97, length 17: 0.106.152.94.124.99.214.254.64.167.134.211.7.24.58.130.83

There a couple things to latch onto there. One is that Option 175 has different set of options. A little more than half way through we see the built-in ipxe has embedded option 17 and the Joyent one has embedded option 20. The other is that the second one has GUID Option 97 and the other doesn't. Let's use the ipxe embedded option to differentiate.

Modify /etc/dhcp/dhcpd.conf again to be:

default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
authoritative;
option space ipxe;
option ipxe-encap-opts code 175 = encapsulate ipxe;
option ipxe.https code 20 = unsigned integer 8;

subnet 192.168.42.0 netmask 255.255.255.0 {
	option ipxe.no-pxedhcp 1;
	range 192.168.42.100 192.168.42.200;
	# Joyent iPXE supports https, but the one with qemu doesn't.  We don't
	# really care about https but it is a reasonable indication that we can
	# support 16 modules and a 4 KiB ipxe script.
	if exists ipxe.https {
		filename "http://192.168.42.1/boot.ipxe";
	} else {
		next-server 192.168.42.1;
		filename "undionly.kpxe";
	}
}

Restart dhcpd: systemctl restart isc-dhcp-server

Reboot the other box. The first time it will download and execute the Joyent ipxe boot program via tftp. The Joyent ipxe program will then download the boot.ipxe script vi http.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment