mirror of
https://github.com/danderson/netboot.git
synced 2025-10-16 18:11:21 +02:00
Force machines to chainload through Pixiecore's embedded iPXE.
This guarantees that we load the real OS from an iPXE with a known featureset, rather than rely on the firmware iPXEs to be correct. Also switch to ipxe.pxe for BIOS boots instead of undionly.kpxe. ipxe.pxe works when you chainload from one iPXE to another, whereas undionly.kpxe encounters some kind of poorly explained bug where it loses the ability to configure networking. Tested against the following configurations: - VirtualBox + BIOS w/ iPXE - VirtualBox + BIOS w/ Intel UNDI - VirtualBox + EFI - KVM + SeaBIOS w/ iPXE - KVM + OVMF (EFI) - Dell R610 + Dell BIOS/PXE Fixes #51, fixes #52.
This commit is contained in:
parent
5f8e425f57
commit
029be8d339
@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli.Ipxe[pixiecore.FirmwareX86PC] = ipxe.MustAsset("undionly.kpxe")
|
||||
cli.Ipxe[pixiecore.FirmwareX86PC] = ipxe.MustAsset("ipxe.pxe")
|
||||
cli.Ipxe[pixiecore.FirmwareEFI32] = ipxe.MustAsset("ipxe-i386.efi")
|
||||
cli.Ipxe[pixiecore.FirmwareEFI64] = ipxe.MustAsset("ipxe-x86_64.efi")
|
||||
cli.Ipxe[pixiecore.FirmwareEFIBC] = ipxe.MustAsset("ipxe-x86_64.efi")
|
||||
|
13
pixiecore/README.testing
Normal file
13
pixiecore/README.testing
Normal file
@ -0,0 +1,13 @@
|
||||
# Testing pixiecore
|
||||
|
||||
This is a braindump of the different hardware configurations that
|
||||
exhibit different behaviors.
|
||||
|
||||
| Machine | Firmware | PXE firmware | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| Proxmox VM | SeaBIOS | iPXE | |
|
||||
| Proxmox VM | OVMF | OVMF | Good UEFI baseline, many UEFI firmwares are derived from OVMF/TianoCore/EDK2e |
|
||||
| VirtualBox (OSS) | VirtualBox BIOS | customized iPXE | Cannot boot with `next-server` and `filename`, must be booted with iPXE-specific commands |
|
||||
| VirtualBox (w/ extension pack) | VirtualBox BIOS | Intel UNDI | Good BIOS baseline, Intel UNDI is the basis for many BIOS PXE firmwares |
|
||||
| VirtualBox (OSS) | VirtualBox EFI | ?? | Unclear what the EFI firmware is, but provides more diversity |
|
||||
| Dell R610 | Dell BIOS | Dell | The only bare metal machine I have right now with remote management. Strange custom firmwares, also a decent variety test. |
|
@ -17,6 +17,8 @@
|
||||
set attempts:int32 10
|
||||
set x:int32 0
|
||||
|
||||
set user-class pixiecore
|
||||
|
||||
# Try to get a filename from ProxyDHCP, retrying a couple of times if
|
||||
# we fail.
|
||||
:loop
|
||||
|
@ -36,7 +36,7 @@ func (s *Server) serveDHCP(conn *dhcp4.Conn) error {
|
||||
s.debug("DHCP", "Ignoring packet from %s: %s", pkt.HardwareAddr, err)
|
||||
continue
|
||||
}
|
||||
mach, isIpxe, fwtype, err := s.validateDHCP(pkt)
|
||||
mach, client, fwtype, err := s.validateDHCP(pkt)
|
||||
if err != nil {
|
||||
s.log("DHCP", "Unusable packet from %s: %s", pkt.HardwareAddr, err)
|
||||
continue
|
||||
@ -56,7 +56,7 @@ func (s *Server) serveDHCP(conn *dhcp4.Conn) error {
|
||||
}
|
||||
|
||||
s.log("DHCP", "Offering to boot %s", pkt.HardwareAddr)
|
||||
if isIpxe {
|
||||
if client == clientSoftwarePixiecoreIPXE {
|
||||
s.machineEvent(pkt.HardwareAddr, machineStateProxyDHCPIpxe, "Offering to boot iPXE")
|
||||
} else {
|
||||
s.machineEvent(pkt.HardwareAddr, machineStateProxyDHCP, "Offering to boot")
|
||||
@ -69,7 +69,7 @@ func (s *Server) serveDHCP(conn *dhcp4.Conn) error {
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := s.offerDHCP(pkt, mach, serverIP, isIpxe, fwtype)
|
||||
resp, err := s.offerDHCP(pkt, mach, serverIP, client, fwtype)
|
||||
if err != nil {
|
||||
s.log("DHCP", "Failed to construct ProxyDHCP offer for %s: %s", pkt.HardwareAddr, err)
|
||||
continue
|
||||
@ -94,14 +94,22 @@ func (s *Server) isBootDHCP(pkt *dhcp4.Packet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) validateDHCP(pkt *dhcp4.Packet) (mach Machine, isIpxe bool, fwtype Firmware, err error) {
|
||||
type clientSoftware int
|
||||
|
||||
const (
|
||||
clientSoftwareGeneric clientSoftware = iota
|
||||
clientSoftwareIPXE
|
||||
clientSoftwarePixiecoreIPXE
|
||||
)
|
||||
|
||||
func (s *Server) validateDHCP(pkt *dhcp4.Packet) (mach Machine, client clientSoftware, fwtype Firmware, err error) {
|
||||
fwt, err := pkt.Options.Uint16(93)
|
||||
if err != nil {
|
||||
return mach, false, 0, fmt.Errorf("malformed DHCP option 93 (required for PXE): %s", err)
|
||||
return mach, 0, 0, fmt.Errorf("malformed DHCP option 93 (required for PXE): %s", err)
|
||||
}
|
||||
fwtype = Firmware(fwt)
|
||||
if s.Ipxe[fwtype] == nil {
|
||||
return mach, false, 0, fmt.Errorf("unsupported client firmware type '%d' (please file a bug!)", fwtype)
|
||||
return mach, 0, 0, fmt.Errorf("unsupported client firmware type '%d' (please file a bug!)", fwtype)
|
||||
}
|
||||
|
||||
guid := pkt.Options[97]
|
||||
@ -114,41 +122,30 @@ func (s *Server) validateDHCP(pkt *dhcp4.Packet) (mach Machine, isIpxe bool, fwt
|
||||
// well accept these buggy ROMs.
|
||||
case 17:
|
||||
if guid[0] != 0 {
|
||||
return mach, false, 0, errors.New("malformed client GUID (option 97), leading byte must be zero")
|
||||
return mach, 0, 0, errors.New("malformed client GUID (option 97), leading byte must be zero")
|
||||
}
|
||||
default:
|
||||
return mach, false, 0, errors.New("malformed client GUID (option 97), wrong size")
|
||||
return mach, 0, 0, errors.New("malformed client GUID (option 97), wrong size")
|
||||
}
|
||||
|
||||
// iPXE options
|
||||
supportsHTTP, supportsBzImage := false, false
|
||||
if len(pkt.Options[175]) > 0 {
|
||||
bs := pkt.Options[175]
|
||||
for len(bs) > 0 {
|
||||
if len(bs) < 2 || len(bs)-2 < int(bs[1]) {
|
||||
return mach, false, 0, errors.New("malformed iPXE option")
|
||||
}
|
||||
switch bs[0] {
|
||||
case 19:
|
||||
// This iPXE build supports HTTP.
|
||||
supportsHTTP = true
|
||||
case 24:
|
||||
// This iPXE build supports bzImage.
|
||||
supportsBzImage = true
|
||||
}
|
||||
bs = bs[2+int(bs[1]):]
|
||||
// We need to identify two special kinds of PXE clients: generic
|
||||
// iPXE, and the iPXE embedded in Pixiecore.
|
||||
client = clientSoftwareGeneric
|
||||
if userClass, err := pkt.Options.String(77); err == nil {
|
||||
switch userClass {
|
||||
case "iPXE":
|
||||
client = clientSoftwareIPXE
|
||||
case "pixiecore":
|
||||
client = clientSoftwarePixiecoreIPXE
|
||||
}
|
||||
}
|
||||
// This firmware is an appropriate iPXE if it can speak HTTP and
|
||||
// bzImage. If not, we'll chainload our own internal iPXE.
|
||||
isIpxe = supportsHTTP && supportsBzImage
|
||||
|
||||
mach.MAC = pkt.HardwareAddr
|
||||
mach.Arch = fwToArch[fwtype]
|
||||
return mach, isIpxe, fwtype, nil
|
||||
return mach, client, fwtype, nil
|
||||
}
|
||||
|
||||
func (s *Server) offerDHCP(pkt *dhcp4.Packet, mach Machine, serverIP net.IP, isIpxe bool, fwtype Firmware) (*dhcp4.Packet, error) {
|
||||
func (s *Server) offerDHCP(pkt *dhcp4.Packet, mach Machine, serverIP net.IP, client clientSoftware, fwtype Firmware) (*dhcp4.Packet, error) {
|
||||
resp := &dhcp4.Packet{
|
||||
Type: dhcp4.MsgOffer,
|
||||
TransactionID: pkt.TransactionID,
|
||||
@ -166,11 +163,14 @@ func (s *Server) offerDHCP(pkt *dhcp4.Packet, mach Machine, serverIP net.IP, isI
|
||||
resp.Options[97] = pkt.Options[97]
|
||||
}
|
||||
|
||||
if isIpxe {
|
||||
resp.BootFilename = fmt.Sprintf("http://%s:%d/_/ipxe?arch=%d&mac=%s", serverIP, s.HTTPPort, mach.Arch, mach.MAC)
|
||||
} else {
|
||||
switch client {
|
||||
case clientSoftwareGeneric:
|
||||
resp.BootServerName = serverIP.String()
|
||||
resp.BootFilename = fmt.Sprintf("%s/%d", mach.MAC, fwtype)
|
||||
case clientSoftwareIPXE:
|
||||
resp.BootFilename = fmt.Sprintf("tftp://%s/%s/%d", serverIP, mach.MAC, fwtype)
|
||||
case clientSoftwarePixiecoreIPXE:
|
||||
resp.BootFilename = fmt.Sprintf("http://%s:%d/_/ipxe?arch=%d&mac=%s", serverIP, s.HTTPPort, mach.Arch, mach.MAC)
|
||||
}
|
||||
|
||||
if fwtype == FirmwareX86PC {
|
||||
|
4
third_party/Makefile
vendored
4
third_party/Makefile
vendored
@ -5,11 +5,11 @@ ipxe:
|
||||
git clone git://git.ipxe.org/ipxe.git
|
||||
(cd ipxe && git rev-parse HEAD >COMMIT-ID)
|
||||
rm -rf ipxe/.git
|
||||
(cd ipxe/src && make bin/undionly.kpxe EMBED=../../../pixiecore/boot.ipxe)
|
||||
(cd ipxe/src && make bin/ipxe.pxe EMBED=../../../pixiecore/boot.ipxe)
|
||||
(cd ipxe/src && make bin-x86_64-efi/ipxe.efi EMBED=../../../pixiecore/boot.ipxe)
|
||||
(cd ipxe/src && make bin-i386-efi/ipxe.efi EMBED=../../../pixiecore/boot.ipxe)
|
||||
(cd ipxe && rm -rf bin && mkdir bin)
|
||||
mv -f ipxe/src/bin/undionly.kpxe ipxe/bin/undionly.kpxe
|
||||
mv -f ipxe/src/bin/ipxe.pxe ipxe/bin/ipxe.pxe
|
||||
mv -f ipxe/src/bin-x86_64-efi/ipxe.efi ipxe/bin/ipxe-x86_64.efi
|
||||
mv -f ipxe/src/bin-i386-efi/ipxe.efi ipxe/bin/ipxe-i386.efi
|
||||
go-bindata -o ipxe/ipxe-bin.go -pkg ipxe -nometadata -nomemcopy -prefix ipxe/bin/ ipxe/bin
|
||||
|
29
third_party/ipxe/ipxe-bin.go
vendored
29
third_party/ipxe/ipxe-bin.go
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user