Update: As of 20150917T235937Z full support for IPv6 has been added to vmadm with the added ips and gateways parameters. If you're using SmartDataCenter, these parameters won't (yet) be added automatically, so the following may be useful to you. But if you're using SmartOS, see the updated SmartOS IPv6 configuration wiki page.


There have been a lot of requests for IPv6 support in SmartOS. I'm happy to say that there is now partial support for IPv6 in SmartOS, though it's not enabled by default and there may be some things you don't expect. This essay is specific to running stand-alone SmartOS systems on bare metal. This doesn't apply to running instances in the Joyent Cloud or for private cloud SDC.

Update: I now have a project up on Github that fully automates enabling SLAAC IPv6 on SmartOS. It works for global and non-global zones and automatically identifies all interfaces available, regardless of the driver name.

First, some definitions so we're all speaking the same language.

  • Compute Node (CN): A non-virtualized physical host.
  • Global Zone (GZ): The Operating System instance in control of all real hardware resources.
  • OS Zone: A SmartMachine zone using OS virtualization. This is the same thing as a Solaris zone.
  • KVM Zone A zone running a KVM virtual machine using hardware emulation.
  • Compute Instance (CI): A SmartMachine zone or KVM virtual machine.
  • Smart Data Center (SDC): Joyent's Smart Data Center private cloud product. SDC backends the Joyent Cloud.

There are two modes of networking with SmartOS. The default is for the global zone to control the address and routes. A static IP is assigned in the zone definition when it's created, along with a netmask and default gateway and network access is restricted to the assigned IP to prevent tennants from causing shenanigans on your network. The other is to set the IP to DHCP, enable allow_ip_spoofing and be done with it. The former mode is preferred for public cloud providers (such as Joyent) and the latter may be preferred for private cloud providers (i.e., enterprises) or small deployments where all tennants are trusted. For example, at home where I have only a single CN and I'm the only operator, I just use DHCP and allow_ip_spoofing.

By far the easiest way to permit IPv6 in a SmartOS zone is to have router-advertisements on your network and enable allow_ip_spoofing. As long as the CI has IPv6 enabled (see below for enabling IPv6 within the zone) you're done. But some don't want to abandon the protection that anti-spoofing provides.

Whether you use static assignment or DHCP in SmartOS, the CI (and probably you too) doesn't care what the IP is. In fact, KVM zones with static IP configuration are configured for DHCP with the Global Zone acting as the DHCP server. If you have another DHCP server on your network it will never see the requests and they will not conflict. In SDC, entire networks are allocated to SDC. By default SDC itself will assign IPs to CIs. In the vast majority of cases it doesn't matter which IP a host has, just as long as it has one.

Which brings us to IPv6. It's true that in SmartOS when a NIC is defined for a CI you can't define an IPv6 address in the ip field (in my testing this is because netmask is a required parameter for static address assignment, but there's no valid way to express an IPv6 netmask that is acceptable to vmadm). But like it or not, IPv4 is still a required part of our world. A host without some type of IPv4 network access will be extremely limited. There's also no ip6 field.

But there doesn't need to be. Remembering that in almost all cases we don't care which IP so long as there is one, IPv6 can be enabled without allowing IP spoofing by adding IPv6 addresses to the allowed_ips property of the NIC. The most common method of IPv6 assignment is SLAAC. If you're using SLAAC then you neither want, nor need SmartOS handing out IPv6 addresses. The global and link-local addresses can be derived from the mac property of NIC of the CI. Add these to allowed_ips property of the NIC definition and the zone definition is fully configured for IPv6 (you don't need an IPv6 gateway definition because it will be picked up automatically by router-advertisements).

Permitting IPv6 in a Zone

Here's an example nic from a zone I have with IPv6 addresses allowed. Note that both the derived link-local and global addresses are permitted.

[root@wasp ~]# vmadm get 94ff50ad-ac74-46ac-8b9d-c05ddf55f434 | json -a nics
[
  {
    "interface": "net0",
    "mac": "72:9c:d5:34:47:59",
    "nic_tag": "external",
    "gateway": "198.51.100.1",
    "allowed_ips": [
      "fe80::709c:d5ff:fe34:4759",
      "2001:db8::709c:d5ff:fe34:4759"
    ],
    "ip": "198.51.100.37",
    "netmask": "255.255.0.0",
    "model": "virtio",
    "primary": true
  }
]

In my workflow, I create zones with autoboot set to false, then add IPv6 addresses based on the mac assigned by vmadm then I enable autoboot and boot the zone. This is scripted of course, so it's a single atomic action.

Enabling IPv6 in a SmartMachine Instance

Once the zone definition has the IPv6 address(es) allowed it needs to be enabled in the zone. For KVM images, most vended by Joyent will already have IPv6 enabled (even Ubuntu Certified images in Joyent Cloud will boot with link-local IPv6 addresses, though they will be mostly useless). For SmartOS instances you will need to enable it.

In order to enable IPv6 in a SmartOS zone you need to enable ndp and use ipadm create-addr.

svcadm enable ndp
ipadm create-addr -t -T addrconf net0/v6

Instead of doing this manually I've taken the extra step and created an SMF manifest for IPv6.

I have a user-script that downloads this from github, saves it to /opt/custom/smf/ipv6.xml and restarts manifest-import. After the import is finished, IPv6 can be enabled with svcadm. Using the -r flag enables all dependencies (i.e., ndp) as well.

svcadm enable -r site/ipv6

Enabling the service is also done as part of the user-script.

If you do actually want specific static IPv6 assignment, do everthing I've described above. Then, in addition to that use mdata-get sdc:nics to pull the NIC definition and extract the IPv6 addresses from allowed_ips and explicitly assign them. I admit that for those who want explicit static addresses this is less than ideal, but with a little effort it can be scripted and made completely automatic.