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

Environment

Original TFTP Setup

  # 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
  }
  rg \\ /

Original DHCPD Setup

  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:

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.

  <?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

          #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:

          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

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 */