DHCP iPXE Workaround

german

#1

Hallo,

ich bin gerade dabei, meine PXE Bootumgebung auf den UCS zu migrieren und stelle hiermit meine Idee zur Verfügung und hoffe auf eine einfache “Lösung” für den letzten Feinschliff. Hintergrund ist, dass ich mit den normalen PXE Möglichkeiten nicht zufrieden war / bin. Ich habe dann auf Anraten eines Kollegen mir das Projekt iPXE näher angesehen und war von den vielfältigen Möglichkeiten fasziniert. Der wohl größte Vorteil ist, dass man statt eines langsamen TFTP Protokolls auf HTTP, NFS etc. zurückgreifen kann, was das Booten über das Netz extrem beschleunigt. Da ich maximal flexibel sein möchte, habe ich folgendes umgesetzt.

Die Standard dhcpd.conf, welche sich bei UCS dynamisch generiert, wird um einige Informationen erweitert. Dazu habe ich in die /etc/dhcp/local.conf die iPXE Options eingefügt.

# Declare the iPXE/gPXE/Etherboot option space
option space ipxe;
option ipxe-encap-opts code 175 = encapsulate ipxe;

# iPXE options, can be set in DHCP response packet
option ipxe.priority         code   1 = signed integer 8;
option ipxe.keep-san         code   8 = unsigned integer 8;
option ipxe.skip-san-boot    code   9 = unsigned integer 8;
option ipxe.syslogs          code  85 = string;
option ipxe.cert             code  91 = string;
option ipxe.privkey          code  92 = string;
option ipxe.crosscert        code  93 = string;
option ipxe.no-pxedhcp       code 176 = unsigned integer 8;
option ipxe.bus-id           code 177 = string;
option ipxe.bios-drive       code 189 = unsigned integer 8;
option ipxe.username         code 190 = string;
option ipxe.password         code 191 = string;
option ipxe.reverse-username code 192 = string;
option ipxe.reverse-password code 193 = string;
option ipxe.version          code 235 = string;
option iscsi-initiator-iqn   code 203 = string;

# iPXE feature flags, set in DHCP request packet
option ipxe.pxeext    code 16 = unsigned integer 8;
option ipxe.iscsi     code 17 = unsigned integer 8;
option ipxe.aoe       code 18 = unsigned integer 8;
option ipxe.http      code 19 = unsigned integer 8;
option ipxe.https     code 20 = unsigned integer 8;
option ipxe.tftp      code 21 = unsigned integer 8;
option ipxe.ftp       code 22 = unsigned integer 8;
option ipxe.dns       code 23 = unsigned integer 8;
option ipxe.bzimage   code 24 = unsigned integer 8;
option ipxe.multiboot code 25 = unsigned integer 8;
option ipxe.slam      code 26 = unsigned integer 8;
option ipxe.srp       code 27 = unsigned integer 8;
option ipxe.nbi       code 32 = unsigned integer 8;
option ipxe.pxe       code 33 = unsigned integer 8;
option ipxe.elf       code 34 = unsigned integer 8;
option ipxe.comboot   code 35 = unsigned integer 8;
option ipxe.efi       code 36 = unsigned integer 8;
option ipxe.fcoe      code 37 = unsigned integer 8;
option ipxe.vlan      code 38 = unsigned integer 8;
option ipxe.menu      code 39 = unsigned integer 8;
option ipxe.sdi       code 40 = unsigned integer 8;
option ipxe.nfs       code 41 = unsigned integer 8;

# Other useful general options
# http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.txt
option arch code 93 = unsigned integer 16;

Als nächsten Schritt habe ich mir unter https://rom-o-matic.eu/ für x86, x64, UEFI usw. jeweils einen angepassten iPXE Kernel erstellt.

Normalerweise kann man an dieser Stelle im UCS nur ein einziges Boot File angeben. Hier fängt meine Frage an die Community an. Im Webinterface von UCS, habe ich die Möglichkeit unter Domäne / DHCP für meine Netze jeweils individuelle Einstellungen vorzunehmen. Direkt Punkt 1 unter den Richtlinien, DHCP Boot, lässt mir “nur” eine Möglichkeit offen, den Kernel zu booten. Da wir im vorangegangenen Schritt jedoch mehrere Kernel erstellt haben, möchte ich diese auch nutzen können, um für UEFI, BIOS oder x86 sowie x64 Systemen die jeweils passende Boot Umgebung zur Verfügung stellen zu können. Dazu fügt man im Normalfalle dem DHCP Pool die folgenden Informationen hinzu.

allow bootp;
allow booting;
next-server 192.168.0.1; # bootsrv.testlab.lan

# Disable ProxyDHCP, we're in control of the primary DHCP server
option ipxe.no-pxedhcp 1;

# Make sure the iPXE we're loading supports what we need,
# if not load a full-featured version
if    exists ipxe.http
  and exists ipxe.menu
  and exists ipxe.nfs
  and ( ( exists ipxe.pxe
      and exists ipxe.bzimage
      and exists ipxe.elf
      and exists ipxe.comboot
  ) or (
      exists ipxe.efi
  ) ) {
    filename "http://192.168.0.1/boot.ipxe";
}
elsif exists user-class and option user-class = "iPXE" {
    # We're already using iPXE, but not a feature-full version,
    # and possibly an out-of-date version from ROM, so load a more
    # complete version with native drivers
    # Allow both legacy BIOS and EFI architectures
    if option arch = 00:06 {
        filename "ipxe-x86.efi";
    } elsif option arch = 00:07 {
        filename "ipxe-x64.efi";
	} elsif option arch = 00:09 {
        filename "ipxe-x64.efi";
    } elsif option arch = 00:00 {
        filename "ipxe.pxe";
    }
}
elsif exists user-class and option user-class = "gPXE" {
    # Boot old version of gPXE burned into their ROM to iPXE
    filename "ipxe.pxe";
}
elsif option arch = 00:06 {
    # EFI 32-bit
    filename "ipxe-x86.efi";
}
elsif option arch = 00:07 {
    # EFI 64-bit
    filename "ipxe-x64.efi";
}
elsif option arch = 00:09 {
    # EFI 64-bit
    filename "ipxe-x64.efi";
}
elsif option arch = 00:00 {
    # Legacy BIOS x86 mode
    filename "ipxe.pxe";
}
else {
    #filename "undionly.kpxe";
}

Die Abfragen führen zu dem jeweils für das System optimierten Kernel und starten im Anschluss das iPXE Boot Menü, welches auch dynamisch als PHP Webseite generiert werden kann. So lässt sich jeder Wunsch und jede Anforderung die ich habe lösen. Ganz gleich ob ich ein Windows per PXE Booten möchte, oder einfach nur eine Live CD / DVD einbinden will. Selbst Systeme per iSCSI lassen sich ansteuern. Ich tausche mit dem Code quasi den Kernel der Netzwerkkarte aus und ersetze Ihn durch den iPXE fähigen Kernel und boote damit erneut per PXE.

Wo kann ich den Code im UCS hinterlegen, so dass er bei der Generierung der dhcpd.conf Datei diesen im DHCP Pool des Subnetz berücksichtigt?

Grüße
Markus


#2

Hallo,

wenn ich die Lösung richtig verstehe, muß die Konfiguration innerhalb des “pool {}”-Blocks eingefügt werden.
Diese Information kommt aber aus dem LDAP. Das wird vermutlich ohne Produkterweiterung nicht gehen.

Viele Grüße,
Dirk Ahrnke


#3

[quote=“ms-kassel”]
ich bin gerade dabei, meine PXE Bootumgebung auf den UCS zu migrieren und stelle hiermit meine Idee zur Verfügung und hoffe auf eine einfache “Lösung” für den letzten Feinschliff. Hintergrund ist, dass ich mit den normalen PXE Möglichkeiten nicht zufrieden war / bin. Ich habe dann auf Anraten eines Kollegen mir das Projekt iPXE näher angesehen und war von den vielfältigen Möglichkeiten fasziniert. Der wohl größte Vorteil ist, dass man statt eines langsamen TFTP Protokolls auf HTTP, NFS etc. zurückgreifen kann, was das Booten über das Netz extrem beschleunigt. Da ich maximal flexibel sein möchte, habe ich folgendes umgesetzt.[/quote]

Das LDAP-Schema /usr/share/univention-ldap/schema/dhcp.schema für DHCP ist flexibel genug, dass man im LDAP auch noch andere Konfigurationseinstellungen speichern kann. Fast alle LDAP-Objektklassen bringen standardmäßig die beiden Attribute “dhcpOptions” und “dhcpStatement” mit, über die man beliebige Optionen aus “man 5 dhcp-options” oder sogar beliebige Textblöcke für die “dhcpd.conf” einfügen kann. Für die LDAP-Objekte, für die das Attribute dhcpOptions nicht standardmäßig vorgesehen ist gibt es zudem die AUXILIARY objectClass “dhcpOptions”, über die mann dann doch weitere DHCP-Optionen nachrüsten kann.

Beide LDAP-Attribute sind aber standardmäßig nicht über die UMC zugreifbar, können aber über den Mechanismus der sog. Erweiterten Attribute http://docs.software-univention.de/manual-4.1.html#central:extendedattrs nachgerüstet werden: In [bug]32557[/bug] ist das für die benötigten DHCP-Attribute beschrieben, wir das geht. Man findet diese beiden EAs dann jeweils auf dem Reiter “Advanced Setting” unter “Low-level DHCP configuration”.

Achtung: Gerade die “Statements” sind sehr fehleranfällig, da deren Inhalt 1:1 in die Konfiguration für den dhcpd integriert wird; macht man dort einen Syntaxfehler, startet der dhcpd i.d.R. nicht mehr. Man sollte deswegen unbedingt die /var/log/daemon.log beobachten, in der standardmäßig die Fehlermeldungen laden. Zur besseren Fehlersuche kann man aber auch dhcpd -f -t direkt ausführen und bekommt dann die Fehlermeldungen auf der Konsole angezeigt. Eine weitere nützliche Möglichkeit zur Fehlersuche ist es, in der Datei /etc/dhcp/dhcpd.conf das Kommentarzeichen # vor ldap-debug-file zu entfernen; dann schreibt der dhcpd beim Starten den statischen Teil der Konfiguration aus dem LDAP in die angegebene Datei, was das Auffinden von Fehlern anhand der angezeigten Zeilennummern vereinfacht.

Anstatt diese Einstellungen in die Datei auf jedem DHCP-Server einzeln zu schreiben kann man dann den gesamten Block einfach als dhcpStatement am DHCP-Service-Eintrag speichern. Das hat dann die gleiche Wirkung wir die lokale-Datei aber den Vorteil, das alles im LDAP protokolliert ist.

iPXE (zugegeben in einer älteren Version) ist übrigens bereits Bestandteil von UCS und wird u.a. für die profilbasierte Installation benutzt: http://docs.software-univention.de/installation-4.1.html#profile:netinstaller

Die ersten beiden Einstellungen sind in UCS über die “Policy: DHCP Allow/Deny” abgedeckt, der next-Server über die “Policy: DHCP Boot”

Der große-if-Block würde dann wieder in ein dhcpStatement am Subnet- oder Pool-Objekt im LDAP gehören.

Philipp Hahn