FreeBSD PXE boot Part 2


Some posts ago I wrote that I was busy to find out how a FreeBSD machine can be PXE-ed from a Linux server. Well, I found that some time ago, but I didn’t have the time to type it here, yet. Well, as always, once you know how it’s done, it’s quite simple. But because a lot of the FreeBSD documentation is very old (talking about FreeBSD 4, 5 and 6) it takes some time to find it all.

Oke, here we go!

Prereqs

First of all you need a working NFS, DHCP, Web and TFTP server on your Linux machine. How to do that is beyond this document and also fairly easy. In my case the Puppet/Repository/NFS/Name/DHCP/TFTP/Web server is the system with IP 192.168.0.1 and in the nameserver the host frinst (short for FreeBSD installation test machine) is defined with IP 192.168.0.2.

This machine also has a 1TB disk mounted as /repo, the place where all software and repositories are placed.

And you need to have root access to a FreeBSD machine to play around with memory file systems.

Software

To start things of we need the FreeBSD software. I downloaded it from the Dutch Unix Users Group (NLUUG). We need two things, the complete install CD and a simple boot CD. Maybe it can be done with one, I haven’t tested that, so this is what I did.

First get the FreeBSD bootonly iso and copy the contents to the PXE directory

wget http://ftp.nluug.nl/FreeBSD/ISO-IMAGES-i386/8.2/FreeBSD-8.2-RELEASE-i386-bootonly.iso
mount -o loop FreeBSD-8.2-RELEASE-i386-bootonly.iso /mnt
mkdir -p /tftpboot/images/freebsd/i386/8.2
cd /tftpboot/images/freebsd/i386/8.2
cp -R /mnt/* .
umount /mnt

Now get the complete FreeBSD installation disk and copy that to the repository

wget http://ftp.nluug.nl/FreeBSD/ISO-IMAGES-i386/8.2/FreeBSD-8.2-RELEASE-i386-disc1.iso
mount -o loop FreeBSD-8.2-RELEASE-i386-disc1.iso /mnt
mkdir -p /repo/freebsd/FreeBSD-8.2-i386
cd /repo/freebsd/FreeBSD-8.2-i386
cp -R /mnt/* .
umount /mnt

and get all updates for this FreeBSD version

mkdir -p /repo/freebsd/pub/FreeBSD/ports/i386/packages-8.2-release
cd /repo/freebsd/pub/FreeBSD/ports/i386/packages-8.2-release
rsync -va --delete ftp.nluug.nl::FreeBSD/ports/i386/packages-8.2-release/All .
rsync -va --delete ftp.nluug.nl::FreeBSD/ports/i386/packages-8.2-release/Latest .

PXE/TFTP

Now the PXE/TFTP server needs to know how to handle a boot request coming from the FreeBSD machine. This needs a chain loader to make things work. This is how I did it:

DEFAULT vesamenu.c32
PROMPT 0
TIMEOUT 300
MENU TITLE FreeBSD 8.2 Installation

LABEL FreeBSD 8.2 i386 - Normal
	MENU LABEL FreeBSD 8.2 i386 - Normal
	PXE images/freebsd/i386/8.2/boot/pxeboot
	TEXT HELP
	Install FreeBSD 8.2 for i386 (32 bits) with normal filesystems
	ENDTEXT

MENU SEPARATOR

DHCP

In your DHCP server there should be an entry for the new machine and it should look something like this

group {
	# Test
	host frinst {
		hardware ethernet xx:xx:xx:xx:xx:xx;
		fixed-address frinst;
		option host-name "frinst";
		next-server 192.168.0.1;
		filename "pxelinux.0";
		option root-path "192.168.0.1:/tftpboot/images/freebsd/i386/8.2";
	}
}

Take a long and good look at the root-path option. This should point to the FreeBSD image directory on the TFTP server.

NFS

The NFS server needs to export the repository and the TFTP directories for FreeBSD installation. The export file needs to have:

/tftpboot/images/freebsd  192.168.0.0/24(fsid=10,ro,no_root_squash,no_subtree_check)
/repo/freebsd             192.168.0.0/24(fsid=11,ro,no_root_squash,no_subtree_check)

Notice that the fsid is not 0 and that they are all different.

Sysinstall

Finally we have all the prelim stuff sorted out. But we we try to install the FreeBSD machine, you get the standard sysinstall screens and no automation. And that was just what we wanted.

To make that work we need some extra’s.

First we need to switch off the default menu actions of sysinstall

Edit the file /tftp/images/freebsd/i386/8.2/boot/loader.conf to look like

mfsroot_load="YES"
mfsroot_type="mfs_root"
mfsroot_name="/boot/mfsroot"
autoboot_delay=0
vfs.root.mountfrom="ufs:/dev/md0"

and the file /tftp/images/freebsd/i386/8.2/boot/loader.rc

include /boot/loader.4th
start
check-password

and create a script that gets executed at the end of the installation process. This script must be in the directory /repo/freebsd/FreeBSD-8.2-i386 and is executed as /dist/inst_post at the end of the installation.

#!/bin/sh

#------------------------------------------------------------------------------#
# Set the package root for the post installation                               #
#------------------------------------------------------------------------------#
PACKAGEROOT='http://muppet.tonkersten.com/freebsd'
export PACKAGEROOT

#------------------------------------------------------------------------------#
# Install and enable Puppet                                                    #
#------------------------------------------------------------------------------#
pkg_add -r puppet
echo 'puppet_enable="YES"' >> /etc/rc.conf

#------------------------------------------------------------------------------#
# Set the PACKAGEROOT to the muppet server                                     #
#------------------------------------------------------------------------------#
echo '# Set the PACKAGEROOT to the muppet server' >> /etc/csh.cshrc
echo 'setenv PACKAGEROOT "http://muppet.tonkersten.com/freebsd"' >> /etc/csh.cshrc
#
echo '# Set the PACKAGEROOT to the muppet server' >> /etc/profile
echo 'PACKAGEROOT="http://muppet.tonkersten.com/freebsd"' >> /etc/profile
echo 'export PACKAGEROOT' >> /etc/profile

#------------------------------------------------------------------------------#
# Set the default root password                                                #
#------------------------------------------------------------------------------#
echo '$1$nUXX0vpK$RPLtXUmvxcdB4UaqMhzYd.' | pw user mod root -H 0

#------------------------------------------------------------------------------#
# That's all, folks!!                                                          #
#------------------------------------------------------------------------------#
exit

OK, almost there

Now all things are in place to tell FreeBSD to use them. But that is not as easy as it sounds. We need to modify the memory file system, so that it contains the file install.cfg, used by sysinstall to perform a unattended installation.

First create a file called install.cfg containing

#------------------------------------------------------------------------------#
# Turn on extra debugging.                                                     #
#------------------------------------------------------------------------------#
debug=YES

#------------------------------------------------------------------------------#
# Ok, this ought to turn off ALL prompting, don't complain to me that you      #
# lost a machine because you netbooted it on the same subnet as this           #
# box                                                                          #
#------------------------------------------------------------------------------#
nonInteractive=YES
noWarn=YES
tryDHCP=YES

#------------------------------------------------------------------------------#
# My host specific data (Should be changed later)                              #
#------------------------------------------------------------------------------#
hostname=frinst
domainname=tonkersten.com

#------------------------------------------------------------------------------#
# Which installation device to use                                             #
#     le0 -< VMware machines                                                   #
#------------------------------------------------------------------------------#
nfs=192.168.0.1:/repo/freebsd/FreeBSD-8.2-i386
netDev=le0
tryDHCP=YES
mediaSetNFS

#------------------------------------------------------------------------------#
# Select which distributions we want.                                          #
# Like this:                                                                   #
#     dists=base bin doc manpages dict info des compat1x compat3x crypto       #
#     distSetCustom                                                            #
#                                                                              #
# Or like this:                                                                #
#    distSetMinimum, distSetUser, distSetXUser, distSetKernDeveloper           #
#    distSetDeveloper, distSetXDeveloper and distSetEverything                 #
#                                                                              #
# Watch out: When just installing 'base' you also need GENERIC, otherwise you  #
#            don't have a kernel                                               #
#------------------------------------------------------------------------------#
distSetMinimum

#------------------------------------------------------------------------------#
# Now set the parameters for the partition editor on da0.                      #
#------------------------------------------------------------------------------#
disk=da0
partition=all
bootManager=standard
diskPartitionEditor
#diskPartitionWrite

#------------------------------------------------------------------------------#
# All sizes are expressed in 512 byte blocks!                                  #
#                                                                              #
# A 500MB root partition, followed by a 2G swap partition, followed by         #
# a 1G /var, a 1G /tmp, a 1G /sidn with softupdates and a /usr using all the   #
# remaining space on the disk /usr has softupdates enables (non zero option    #
# after the mountpoint)                                                        #
#------------------------------------------------------------------------------#
da0s1-1=ufs 1024000 /
da0s1-2=swap 4096000 none
da0s1-3=ufs 2048000 /var
da0s1-4=ufs 2048000 /tmp
da0s1-5=ufs 2048000 /sidn 1
da0s1-6=ufs 0 /usr 1
#
# Let's do it!
diskLabelEditor

#------------------------------------------------------------------------------#
# OK, everything is set. Start the install                                     #
#------------------------------------------------------------------------------#
installCommit

#------------------------------------------------------------------------------#
# Run post commands                                                            #
#------------------------------------------------------------------------------#
command="/dist/inst_post"
system

#------------------------------------------------------------------------------#
# That's all, folks!!                                                          #
#------------------------------------------------------------------------------#
shutdown

This file now needs to be inserted into the memory file system. On a FreeBSD
box do

~~~ {.bash}
cd /tmp
cp -p ~/mfsroot.gz .
gunzip mfsroot.gz
mdconfig -f mfsroot -u 0
mount /dev/md0 /mnt
cp -p ~/install.cfg /mnt
umount /mnt
mdconfig -d -u 0
gzip mfsroot
cp -p mfsroot.gz ~

and that should be it.

Now boot the new machine with PXE and select the FreeBSD installation option and the machine will be auto installed and from now on it will be manged with the Puppet configuration system. Just as easy as that.

See also