This post will guide you through installing isc-dhcpd on OmniOS inside a zone (software virtualized container).

Configuring the system

To get started, first install zadm on OmniOS inside the global zone. This tool makes creating and managing zones simple and is reminiscent of the vmadm command on SmartOS.

Install zadm:

pkg install zadm

I personally use this config for zadm (shoutouts to @papertigers for this), but feel free to customize this as you like.

/etc/opt/ooce/zadm/zadm.conf

{
    "CONFIG"  : {
        "format"          : "toml"
    },
    "CONSOLE"  : {
        "auto_connect"    : "off",
        "auto_disconnect" : "on",
        "escape_char"     : "_"
    },
    "SNAPSHOT" : {
        "prefix"          : "zadm__"
    }
}

Test that zadm was installed and works as expected by running:

dave - GZ:amon sunos ~ $ zadm list
NAME              STATUS     BRAND       RAM    CPUS  SHARES
global            running    ipkg        16G       4       1

Note that for this blog post I ran all of these commands on a fresh system so only 1 zone is running (the global zone).

Create the datasets needed, and you can customize these if you’d like but for the sake of this post I’ll be using these datasets:

zfs create -o mountpoint=/zones rpool/zones
zfs create rpool/zones/config
zfs create rpool/zones/root

Where:

  • /zones/config toml files for each zone used during zone creation.
  • /zones/root zone root FS data.

For example, a zone named foo would have files like:

  • /zones/config/foo.toml
  • /zones/zones/foo

Creating the NICs

To get started we must create the NICs in the global zone before creating the zone that will house the DHCP server. It is possible to have zadm create NICs for us for simple zone deployments but we need more control here to ensure the NICs are persistent and can process DHCP traffic on multiple VLANs.

My physical server has 2 physical NICs - I plan on using this as my home router eventually. Until then, only 1 NIC is in use so we must find it by name to use for our zone NICs:

$ dladm show-phys
LINK         MEDIA                STATE      SPEED    DUPLEX   DEVICE
rge0         Ethernet             up         1000     full     rge0
rge1         Ethernet             unknown    0        unknown  rge1

We can see that rge0 is the interface that is currently in use, so we will use that to create the NICs for the zone.

My home network has multiple VLANs - this DHCP server will sit on all of them and properly tag them. A quick synopsis of my network looks like:

  • 10.0.1.0/24 - untagged
  • 10.0.2.0/24 - vlan 3
  • 10.0.3.0/24 - vlan 4
  • 10.0.4.0/24 - vlan 5
  • 10.0.5.0/24 - vlan 6

“But Dave, your VLAN IDs are off-by-one… isn’t that confusing?” YES. Yes it is, lol, I’ll get around to it a swear.

Now that we now the physical NIC we are going to create these NICs on and the VLAN IDs we can create them with dladm:

sudo dladm create-vnic -l rge0 dhcp_0
sudo dladm create-vnic -l rge0 -v 3 dhcp_3
sudo dladm create-vnic -l rge0 -v 4 dhcp_4
sudo dladm create-vnic -l rge0 -v 5 dhcp_5
sudo dladm create-vnic -l rge0 -v 6 dhcp_6

We can verify their creation with:

$ sudo dladm show-vnic | grep dhcp
dhcp_0       rge0       1000     2:8:20:fb:a1:19   random      0    --
dhcp_3       rge0       1000     2:8:20:cf:fd:7e   random      3    --
dhcp_4       rge0       1000     2:8:20:81:1d:d3   random      4    --
dhcp_5       rge0       1000     2:8:20:30:d3:f6   random      5    --
dhcp_6       rge0       1000     2:8:20:46:c0:ca   random      6    --

Creating the zone

Now we are ready to create the zone! Start by creating a toml file to represent the zone:

/zones/config/dhcp.toml

autoboot="true"
brand="lipkg"
dns-domain="rapture.com"
ip-type="exclusive"
limitpriv="default"
zonename="dhcp"
zonepath="/zones/root/dhcp"
resolvers=[
  "10.0.1.3",
  "10.0.1.2",
]

[[net]]
global-nic="rge0"
physical="dhcp_0"

[[net]]
global-nic="rge0"
physical="dhcp_3"
vlan-id="3"

[[net]]
global-nic="rge0"
physical="dhcp_4"
vlan-id="4"

[[net]]
global-nic="rge0"
physical="dhcp_5"
vlan-id="5"

[[net]]
global-nic="rge0"
physical="dhcp_6"
vlan-id="6"

[capped-memory]
physical="512M"
swap="2G"

Then, run zadm create to create the zone!

$ sudo zadm create -b lipkg -t dhcp.toml dhcp
A ZFS file system has been created for this zone.
Sanity Check: Looking for 'entire' incorporation.
       Image: Preparing at /zones/root/dhcp/root.

       Cache: Using /var/pkg/publisher.
  Installing: Packages (output follows)
   Publisher: Using omnios (https://pkg.omnios.org/r151052/core/).
   Publisher: Using omnios (https://us-west.mirror.omnios.org/r151052/core/).
   Publisher: Using extra.omnios (https://pkg.omnios.org/r151052/extra/).
   Publisher: Using extra.omnios (https://us-west.mirror.omnios.org/r151052/extra/).
Packages to install: 392
Mediators to change:   8
 Services to change:   7

DOWNLOAD                                PKGS         FILES    XFER (MB)   SPEED
Completed                            392/392   32972/32972  307.2/307.2      --

PHASE                                          ITEMS
Installing new actions                   66485/66485
Updating package state database                 Done
Updating package cache                           0/0
Updating image state                            Done
Creating fast lookup database                   Done
 Postinstall: Copying SMF seed repository ... done.
        Done: Installation completed in 142.004 seconds.

We can now boot the zone and login to it. You may have to wait a second or two after booting the zone to login to it:

sudo zadm boot dhcp
sudo zlogin dhcp

Once we are inside the zone we can verify we see the interfaces with:

root@dhcp:~# dladm
LINK        CLASS     MTU    STATE    BRIDGE     OVER
dhcp_0      vnic      1500   up       --         ?
dhcp_3      vnic      1500   up       --         ?
dhcp_4      vnic      1500   up       --         ?
dhcp_5      vnic      1500   up       --         ?
dhcp_6      vnic      1500   up       --         ?

Configuring networking in the zone

We can go through and manually set the IP addresses to each interface in the zone - these will be persistent so you only need to run these commands once. For my setup I’m using .4 as the last octet for this server on each network it lives on.

Inside the zone run these commands:

ipadm create-addr -T static -a 10.0.1.4/24 dhcp_0/v4
ipadm create-addr -T static -a 10.0.2.4/24 dhcp_3/v4
ipadm create-addr -T static -a 10.0.3.4/24 dhcp_4/v4
ipadm create-addr -T static -a 10.0.4.4/24 dhcp_5/v4
ipadm create-addr -T static -a 10.0.5.4/24 dhcp_6/v4

The last step is to add the default gateway so we can hit the internet from the zone:

route -p add default 10.0.1.1

Installing the software

Now we can install the isc-dhcp package to get the DHCP server:

root@dhcp:~# pkg install isc-dhcp
           Packages to install:  1
            Services to change:  7
       Create boot environment: No
Create backup boot environment: No

DOWNLOAD                                PKGS         FILES    XFER (MB)   SPEED
Completed                                1/1         20/20      4.7/4.7  2.0M/s

PHASE                                          ITEMS
Installing new actions                         34/34
Updating package state database                 Done
Updating package cache                           0/0
Updating image state                            Done
Creating fast lookup database                   Done
Updating package cache                           2/2

This will install the package and create an SMF manifest for the service without actually starting it for us. We can get the service ready by copying the example config into place, editing it, and starting the service!

cp /usr/share/isc-dhcp/examples/dhcpd.conf.example /etc/dhcpd.conf
vim /etc/dhcpd.conf
# edit, edit, edit, :wq

Start the service with:

svcadm enable dhcp:ipv4

And that’s it! You now have a working DHCP server on OmniOS. You can verify it is running with:

root@dhcp:~# svcs dhcp:ipv4
STATE          STIME    FMRI
online          0:45:51 svc:/network/service/dhcp:ipv4

Helpful hints

It took me a bit to find the example config until I remember I could ask the package manager what files it installed:

dave@dhcp:~$ pkg contents isc-dhcp
PATH
etc/security/auth_attr.d/network%2Fservice%2Fdhcp
lib/svc/manifest/network/isc-dhcp.xml
lib/svc/method/isc-dhcp
usr/bin/omshell
usr/sbin/dhcpd
usr/sbin/dhcrelay
usr/share/isc-dhcp
usr/share/isc-dhcp/examples
usr/share/isc-dhcp/examples/dhcpd.conf.example
usr/share/man/man1/omshell.1
usr/share/man/man5/dhcp-eval.5
usr/share/man/man5/dhcp-options.5
usr/share/man/man5/dhcpd.conf.5
usr/share/man/man5/dhcpd.leases.5
usr/share/man/man8/dhcpd.8
usr/share/man/man8/dhcrelay.8
var/db
var/db/dhcpd.leases
var/db/dhcpd.leases~
var/db/dhcpd6.leases
var/db/dhcpd6.leases~

This clarified where pkg placed the package files during installation.