Table of Contents
PXELINUX TFTP to HTTP Migration
The Problem
Migrate from PXELINUX/TFTP deployment environment to gPXE/HTTP based environment with easy roll out and back out, and zero changes to PXELINUX menu/configuration files and production application code that drives deployment operations. Eventually replace 01-xx-xx-xx-xx-xx–xx mac based configuration files on the file system with rewrite rules to an application server for configuration generation.
TFTP
- Slow
- Prone to failure
- Limited entry points for extensibility
Environment
- 24/7/365 production
- RHEL4/5 deployment servers
- ISC DHCP
- tftp-hpa (serving from /tftpboot/)
- MAC based configuration files automatically written to /tftpboot/PXELINUX.cfg/.
- Apache web server
- Serving up installation and other content to the deployment network.
Original TFTP Setup
- xinetd based
- Starting a new process for each connection seemed more stable than running the service as a daemon.
- /etc/xinetd.d/tftp
# default: off # description: The tftp server serves files using the trivial file transfer \ # protocol. The tftp protocol is often used to boot diskless \ # workstations, download configuration files to network-aware printers, \ # and to start the installation process for some operating systems. service tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -vvvvs /tftpboot -m /tftpboot/tftpd.map disable = no per_source = 11 cps = 100 2 flags = IPv4 }
- tftpd.map is only used to changing Windows paths (\) to Linux paths (/)
rg \\ /
Original DHCPD Setup
- dhcpd.conf
ddns-update-style none; ignore client-updates; allow bootp; allow booting; DHCPD_INTERFACE = "eth0"; default-lease-time 600; max-lease-time 7200; option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list, 3a, 3b); subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.50 192.168.0.150; default-lease-time 7200; max-lease-time 14400; option subnet-mask 255.255.255.0; option routers 192.168.0.1; option domain-name-servers 192.168.0.1; next-server 192.168.0.1; filename "pxelinux.0"; }
gPXE to the rescue
The undionly image should do the trick as we are already booting PXELINUX via the BIOS PXE ROM on all of our machines and we do not want to attempt to burn gPXE into the bios for the large number of current and future motherboards we might have. We did attempt to use the gPXELINUX image with and without keeppxe but undionly chaining in PXELINUX produced more reliable and expected behavior with our boot images in respect to the previous PXELINUX/tftp implementation.
As stated earlier we wanted easy roll out/back while testing and for initial production deployment in the event things went wrong. The following requirements had to be met:
- The current tftp service must not be altered.
- The current tftp folder must not change location.
- The new implementation should be fast and easy to roll out/back.
Configure Apache for gPXE
This was done with a simple Alias and Directory entry in our vhost configuration:
Alias "/gpxe" "/tftpboot" <Directory "/tftpboot"> Order allow,deny Allow from all </Directory>
Create boot script for gPXE
We simply want to chain in PXELINUX. We could have embedded this in the undionly image or used a simple text file, but this script might eventually contain more logic/features.
- /tftpboot/boot.php
<?php echo "#!gpxe\n"; echo 'chain pxelinux.0' ."\n"; ?>
Note that we are not passing any HTTP, IP, etc etc information in this script, gPXE will simply Do the Right Thing.
Changes to DHCP
- dhcpd.conf
#filename "pxelinux.0"; if ((exists user-class) and (option user-class = "gPXE")) { filename "http://192.168.0.1/gpxe/boot.php"; } else { filename "undionly.kpxe"; }
The above changes now load undionly.kpxe if the client is not gPXE. This prevents an infinite loop.
Now we simply restart dhcpd and clients will start loading PXELINUX configurations and images from http://192.168.0.1/gpxe/ without any changes needed to menus, kernel/append paths, etc as long as your setup was already using relative paths for /tftpboot/.
Roll back is as simple as commenting out the new filename block, uncommenting the original filename, and restarting dhcpd:
- dhcpd.conf
filename "pxelinux.0"; #if ((exists user-class) and (option user-class = "gPXE")) { # filename "http://192.168.0.1/gpxe/boot.php"; #} else { # filename "undionly.kpxe"; #}
Gotchas and Issues Encountered
- Use recent versions of gPXE and PXELINUX.
- If you are using comboot modules for PXELINUX make sure they are all from the same Syslinux version.
- COM32 modules from Syslinux 4.00+ can not be used with gPXE directly. gpxe/gpxelinux.0 (In Syslinux official distribution) is undionly.kkpxe, PXELINUX and a special script that does work.
- If you are running selinux you may need to relabel the /tftpboot directory as public content:
- chcon -R -t public_content_t /tftpboot/
- semanage fcontext -a -t public_content_t '/tftpboot(/.*)?'
We also experienced DHCP timeouts on some of our older switches. It seems that although the link was “up” it was not yet passing traffic (spanning-tree portfast did not seem to be the issue in this case). The easiest way around the issue was to increase the gPXE banner timeout in src/config/general.h to 10 seconds and rebuild the undionly image:
/* * Timer configuration * */ #define BANNER_TIMEOUT 100 /* Tenths of a second for which the shell banner should appear */