Tag Archives: kilo

Using OpenStack Heat to Deploy an IPv6-enabled Instance

In this post I will talk about how to use a basic OpenStack Heat template to build a dual-stack (IPv4 and IPv6) Neutron network, router and launch an instance that will use StateLess Address AutoConfiguration (SLAAC) for IPv6 address assignment.

In the May, 2015 post I discussed, in detail, how to build a dual-stack tenant and use a variety of IPv6 address assignment methods (SLAAC, Stateless DHCPv6, Stateful DHCPv6) for OpenStack instances.

To build on the previous post, I wanted to show a basic Heat template for building an IPv4 and IPv6 network with the basic parameters such as CIDR, gateway and pools.  I want Heat to also launch an OpenStack instance (what Heat calls a Server) that attaches to those networks.  Finally, the template will create a new security group that will create security group rules for both IPv4 and IPv6.

The Heat template that I am referring to in this post can be found here: https://github.com/shmcfarl/my-heat-templates/blob/master/single-v6-test.yaml. That specific template is using SLAAC.  You can also take a look at this template which uses Stateless DHCPv6: https://github.com/shmcfarl/my-heat-templates/blob/master/stateless-demo-slb-trusty.yaml. You can modify the template from there to play around with DHCPv6 Stateful. Hint, it’s all in the resource properties of:

ipv6_address_mode: <slaac/dhcpv6-stateless/dhcpv6-stateful>
ipv6_ra_mode: <slaac/dhcpv6-stateless/dhcpv6-stateful>)

Heat Template

I am not going to teach you Heat. There are countless resources out there that do a much better job than I ever could on teaching Heat.  A couple of places to start are:

The Heat Orchestration Template (HOT) Guide is a great resource for finding the various parameters, resources and properties that can be used in Heat.

The primary place to dig into IPv6 capabilities within Heat is in the Heat template guide under OS::Neutron::Subnet.  You can jump to it here: http://docs.openstack.org/hot-reference/content/OS__Neutron__Subnet.html.  I am not going to walk through all of what is in the guide but I will point out specific properties that I have used in the example Heat template I referenced before.

Let’s take a look at the IPv6-specific parts of the example template.  In the example template file I have created a parameter section that includes various items such as key, image, flavor and so on.  The IPv6 section includes:

  • The private IPv6 network (2001:db8:cafe:1e::/64)
  • The private IPv6 gateway (2001:db8:cafe:1e::1)
  • The beginning and ending range of the IPv6 address allocation pool (2001:db8:cafe:1e::2 – 2001:db8:cafe:1e:ffff:ffff:ffff:fffe)
private_net_v6:
    type: string
    description: Private IPv6 subnet address
    default: 2001:db8:cafe:1e::/64
private_net_v6_gateway:
    type: string
    description: Private IPv6 network gateway address
    default: 2001:db8:cafe:1e::1
private_net_v6_pool_start:
    type: string
    description: Start of private network IPv6 address allocation pool
    default: 2001:db8:cafe:1e::2
private_net_v6_pool_end:
    type: string
    description: End of private network IPv6 address allocation pool
    default: 2001:db8:cafe:1e:ffff:ffff:ffff:fffe

The next section to look at is in the “resources” section and this is where things go into action. The “private_v6_subnet” has various resource types and properties to include:

  • Version is IPv6
  • IPv6 address and RA modes are SLAAC
  • The network property (set in the parameter section)
  • The CIDR property which is the “private_net_v6” from the parameter section
  • The gateway IPv6 address is defined in the “private_net_v6_gateway” parameter
  • The allocation pool is defined in the “private_net_v6_pool_start/end” parameters
  private_v6_subnet:
    type: OS::Neutron::Subnet
    properties:
      ip_version: 6
      ipv6_address_mode: slaac
      ipv6_ra_mode: slaac
      network: { get_resource: private_net }
      cidr: { get_param: private_net_v6 }
      gateway_ip: { get_param: private_net_v6_gateway }
      allocation_pools:
        - start: { get_param: private_net_v6_pool_start }
          end: { get_param: private_net_v6_pool_end }

The next IPv6-relevant area of the resource section is “router_interface_v6”. In the “router_interface_v6” resource, there is a reference to the previously created “router” resource (see template file for full resource list) and the “private_v6_subnet”. This entry is simply attaching a new router interface to the Private IPv6 subnet.

  router_interface_v6:
    type: OS::Neutron::RouterInterface
    properties:
      router: { get_resource: router }
      subnet: { get_resource: private_v6_subnet }

Next, there is the Server (AKA “instance” or “VM”) creation section. There is nothing IPv6 specific here. On the network property line, Heat is pointing to “get_resource: private_net” which is the private network that both IPv4 and IPv6 subnets are associated with. That line, basically, attaches the server to a dual-stack network.

server1:
    type: OS::Nova::Server
    properties:
      name: Server1
      image: { get_param: image }
      flavor: { get_param: flavor }
      key_name: { get_param: key_name }
      networks:
        - network: { get_resource: private_net }
      config_drive: "true"
      user_data_format: RAW
      user_data: |
        #!/bin/bash
      security_groups: [{ get_resource: server_security_group }]

Finally, there is the security group section which enables rules for both IPv4 and IPv6. In this example ports 22, 80 and ICMP are open for IPv4 and IPv6.

server_security_group:
    type: OS::Neutron::SecurityGroup
    properties:
      description: Heat-deployed security group.
      name: heat-security-group
      rules: [
        {remote_ip_prefix: 0.0.0.0/0,
        protocol: tcp,
        port_range_min: 22,
        port_range_max: 22},
        {remote_ip_prefix: 0.0.0.0/0,
        protocol: icmp},
        {remote_ip_prefix: 0.0.0.0/0,
        protocol: tcp,
        port_range_min: 80,
        port_range_max: 80},
        {remote_ip_prefix: "::/0",
        ethertype: IPv6,
        protocol: tcp,
        port_range_min: 22,
        port_range_max: 22},
        {remote_ip_prefix: "::/0",
        ethertype: IPv6,
        protocol: icmp},
        {remote_ip_prefix: "::/0",
        ethertype: IPv6,
        protocol: tcp,
        port_range_min: 80,
        port_range_max: 80}]

Now, let’s deploy this template and see how it all looks. I am deploying the Heat “stack” using the Heat “stack-create” command (alternatively you can deploy it using the ‘Orchestration > Stacks > Launch Stack’ interface in the OpenStack Dashboard). In this example I am running “stack-create” using the “-r” argument to indicate ‘rollback’ (in the event something goes wrong, I don’t want the whole stack to build out). Then I am using the “-f” argument to indicate that I am using a file to build the Heat stack. The stack is named “demo-v6”:

root@c71-kilo-aio:~$ heat stack-create -r -f Heat-Templates/single-v6-test.yaml demo-v6
+--------------------------------------+------------+--------------------+----------------------+
| id                                   | stack_name | stack_status       | creation_time        |
+--------------------------------------+------------+--------------------+----------------------+
| 688388f5-4ae1-4d39-bf85-6f9a591a4420 | demo-v6    | CREATE_IN_PROGRESS | 2015-06-29T15:44:18Z |
+--------------------------------------+------------+--------------------+----------------------+

After a few minutes, the Heat stack is built:

root@c71-kilo-aio:~$ heat stack-list
+--------------------------------------+------------+-----------------+----------------------+
| id                                   | stack_name | stack_status    | creation_time        |
+--------------------------------------+------------+-----------------+----------------------+
| 688388f5-4ae1-4d39-bf85-6f9a591a4420 | demo-v6    | CREATE_COMPLETE | 2015-06-29T15:44:18Z |
+--------------------------------------+------------+-----------------+----------------------+

Here is a messy view of the obligatory OpenStack Dashboard Network Topology view (Note: Some Horizon guru needs to line break the IPv4 and IPv6 addresses for the instances so they are readable ;-)):

net-topo

 

Here’s a cleaner view of things:

  • Network list – You can see the new Heat-built “test_net” with the two subnets (IPv4/IPv6) as well as the previously built (by the admin) “Public-Network”:
root@c71-kilo-aio:~$ neutron net-list
+--------------------------------------+----------------+------------------------------------------------------------+
| id                                   | name           | subnets                                                    |
+--------------------------------------+----------------+------------------------------------------------------------+
| 2e03a628-e85e-4519-b1bb-a579880be0ae | test_net       | 93764f36-c56b-4c65-b7d7-cb78a694353b 10.10.30.0/24         |
|                                      |                | cafb610a-2aaa-4640-b0f0-8bb4b60cbaf2 2001:db8:cafe:1e::/64 |
| f6a55029-d875-48a8-aab9-1a5a5399592b | Public-Network | dda7d8f1-89a6-40bb-b11b-64a62c103828 192.168.81.0/24       |
|                                      |                | f2107125-c98e-4375-a81f-d0f4d34bdae3 2001:db8:cafe:51::/64 |
+--------------------------------------+----------------+------------------------------------------------------------+
  • Subnet list:
root@c71-kilo-aio:~$ neutron subnet-list
+--------------------------------------+----------------------------------------+-----------------------+---------------------------------------------------------------------------------+
| id                                   | name                                   | cidr                  | allocation_pools                                                                |
+--------------------------------------+----------------------------------------+-----------------------+---------------------------------------------------------------------------------+
| 93764f36-c56b-4c65-b7d7-cb78a694353b | demo-v6-private_subnet-6evpyylqyux7    | 10.10.30.0/24         | {"start": "10.10.30.2", "end": "10.10.30.254"}                                  |
| dda7d8f1-89a6-40bb-b11b-64a62c103828 | Public-Subnet-v4                       | 192.168.81.0/24       | {"start": "192.168.81.5", "end": "192.168.81.254"}                              |
| f2107125-c98e-4375-a81f-d0f4d34bdae3 | Public-Subnet-v6                       | 2001:db8:cafe:51::/64 | {"start": "2001:db8:cafe:51::3", "end": "2001:db8:cafe:51:ffff:ffff:ffff:fffe"} |
| cafb610a-2aaa-4640-b0f0-8bb4b60cbaf2 | demo-v6-private_v6_subnet-vvsmlbkc6sds | 2001:db8:cafe:1e::/64 | {"start": "2001:db8:cafe:1e::2", "end": "2001:db8:cafe:1e:ffff:ffff:ffff:fffe"} |
+--------------------------------------+----------------------------------------+-----------------------+---------------------------------------------------------------------------------+
  • Here is the “subnet-show” of the Heat-built subnet for the Private IPv6 subnet. The allocation pool range, gateway, IPv6 version, IPv6 address mode and IPv6 RA modes are all defined as we wanted (based on the Heat template):
root@c71-kilo-aio:~$ neutron subnet-show demo-v6-private_v6_subnet-vvsmlbkc6sds
+-------------------+---------------------------------------------------------------------------------+
| Field             | Value                                                                           |
+-------------------+---------------------------------------------------------------------------------+
| allocation_pools  | {"start": "2001:db8:cafe:1e::2", "end": "2001:db8:cafe:1e:ffff:ffff:ffff:fffe"} |
| cidr              | 2001:db8:cafe:1e::/64                                                           |
| dns_nameservers   |                                                                                 |
| enable_dhcp       | True                                                                            |
| gateway_ip        | 2001:db8:cafe:1e::1                                                             |
| host_routes       |                                                                                 |
| id                | cafb610a-2aaa-4640-b0f0-8bb4b60cbaf2                                            |
| ip_version        | 6                                                                               |
| ipv6_address_mode | slaac                                                                           |
| ipv6_ra_mode      | slaac                                                                           |
| name              | demo-v6-private_v6_subnet-vvsmlbkc6sds                                          |
| network_id        | 2e03a628-e85e-4519-b1bb-a579880be0ae                                            |
| subnetpool_id     |                                                                                 |
| tenant_id         | dc52b50429f74aeabb3935eb3e2bcb04                                                |
+-------------------+---------------------------------------------------------------------------------+
  • Router port list – You can see that the router has IPv4/IPv6 addresses on the tenant and public network interfaces:
root@c71-kilo-aio:~$ neutron router-port-list demo-v6-router-txy5s5bcixqd | grep ip_address | sed -e 's#.*ip_address": "\([^"]\+\).*#\1#'
10.10.30.1
2001:db8:cafe:1e::1
192.168.81.75
2001:db8:cafe:51::3f
  • Security Group list:
root@c71-kilo-aio:~$ neutron security-group-list
+-----------------------------+---------------------+---------------------------------------------------+
| id                          | name                | security_group_rules                              |
+-----------------------------+---------------------+---------------------------------------------------+
| 69f81e8e-5059-4a...         | heat-security-group | egress, IPv4                                      |                                                       |                             |                     | egress, IPv6                                      |
|                             |                     | ingress, IPv4, 22/tcp, remote_ip_prefix: 0.0.0.0/0|                                                       |                             |                     | ingress, IPv4, 80/tcp, remote_ip_prefix: 0.0.0.0/0|
|                             |                     | ingress, IPv4, icmp, remote_ip_prefix: 0.0.0.0/0  |
|                             |                     | ingress, IPv6, 22/tcp, remote_ip_prefix: ::/0     |
|                             |                     | ingress, IPv6, 80/tcp, remote_ip_prefix: ::/0     |
|                             |                     | ingress, IPv6, icmp, remote_ip_prefix: ::/0       |
+--------------------------------------+---------------------+------------------------------------------+
  • Server/Instance list:
root@c71-kilo-aio:~$ nova list
+--------------------------------------+---------+--------+------------+-------------+-----------------------------------------------------------+
| ID                                   | Name    | Status | Task State | Power State | Networks                                                  |
+--------------------------------------+---------+--------+------------+-------------+-----------------------------------------------------------+
| d7bfc606-f9da-4be5-b3e8-2219882c3da6 | Server1 | ACTIVE | -          | Running     | test_net=10.10.30.3, 2001:db8:cafe:1e:f816:3eff:fea8:7d2c |
+--------------------------------------+---------+--------+------------+-------------+-----------------------------------------------------------+

Finally, inside the instance, you can see that both IPv4 and IPv6 addresses are assigned:

root@c71-kilo-aio:~$ ip netns exec qrouter-d2ff159a-b603-4a3b-b5f7-481bff40613e ssh fedora@2001:db8:cafe:1e:f816:3eff:fea8:7d2c
The authenticity of host '2001:db8:cafe:1e:f816:3eff:fea8:7d2c (2001:db8:cafe:1e:f816:3eff:fea8:7d2c)' can't be established.
ECDSA key fingerprint is 41:e2:ea:28:e5:6d:ae:50:24:81:ad:5e:db:d7:a0:21.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '2001:db8:cafe:1e:f816:3eff:fea8:7d2c' (ECDSA) to the list of known hosts.
[fedora@server1 ~]$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc pfifo_fast state UP group default qlen 1000
    link/ether fa:16:3e:a8:7d:2c brd ff:ff:ff:ff:ff:ff
    inet 10.10.30.3/24 brd 10.10.30.255 scope global dynamic eth0
       valid_lft 79179sec preferred_lft 79179sec
    inet6 2001:db8:cafe:1e:f816:3eff:fea8:7d2c/64 scope global mngtmpaddr dynamic
       valid_lft 86400sec preferred_lft 14400sec
    inet6 fe80::f816:3eff:fea8:7d2c/64 scope link
       valid_lft forever preferred_lft forever

I hope this gives you a starting point for adding IPv6 to your Heat template collection.

Thanks,
Shannon

Tenant IPv6 Deployment in OpenStack Kilo Release

You folks know that I have been dancing to the IPv6 music for the last 12 years or so. IPv6 is so popular that I still earn about 75 cents a month on my book royalties. 🙂

I have been fairly disappointed in the deployment of IPv6 in an OpenStack environment.  Many individuals and companies have beat on IPv6 over the past couple of years to get it to where it is today in OpenStack and we should all be super greatful.  In this post I will go over some design and deployment considerations for IPv6 in the OpenStack Kilo release.

Note: I refer to the term “tenant” vs. what OpenStack calls a “project”.

Cloud and IPv6

IPv6 has had a rough go of it over the many years it has been around. It is usually a rough go when you try to inject it into any cloud deployment. And I do mean ANY cloud deployment.  The hard stuff with cloud and IPv6 includes (not an exhaustive list):

  • API Endpoints – Enabling IPv6 on the non-Tenant-facing portion of the cloud stack
  • Provisioning, Orchestration and Management – This includes CI/CD, bare-metal provisioning (i.e. Cobbler, Ironic), automation tools such as Ansible, Puppet, etc.. and the overall Data Center management tools
  • Management/communication protocol interoperability and support of IPv6
  • Support for IPv6 in both virtual and physical networking
  • Oh, let’s not forget – expertise

In this post I am not going to address all of the above as none of us have that kind of time.  What I will talk about is making a choice to enable ALL of OpenStack for IPv6 or settling for the really important part, which is the tenant-facing part and how that looks when configured.

There are two common ways of embracing IPv6 within OpenStack (I am not discussing IPv6-only options here):

  • Dual Stack everything
  • Conditional Dual Stack

Figure 1 shows an example of a “dual stack everything” approach. It is what is sounds like. Everything in the entire stack is both IPv4 and IPv6 enabled.  This includes the API endpoints, the DBs, the tools and systems that surround OpenStack (i.e. provisioning and automation).  This, kids, can be a real pain in the butt, especially if this is a brownfield deployment where you have to go in an muck around with database entries for IPv6 and so on.

Figure 1. Dual Stack Everything

ds-everything

This is where “conditional dual stack” comes in.  It allows you to control when and where IPv6 is enabled.  In many cases, it is just in the tenant space, at least initially.

Figure 2 shows an example of where we have an IPv4-only OpenStack control plane (API/DB/etc) but dual stack for anything that faces something a tenant would see/control/interact with.  Optionally, this is where you can begin experimenting (I stress that word) with IPv6-only tenant networks.

Figure 2. Conditional Dual Stack

conditional

 

No matter which path you go down (and there are variances to the two I have pointed out here), you will end up dealing with IPv6 in the tenant space.  So, let’s talk about that part.

Tenant IPv6 Address Options

There are many combinations to IPv6 address assignment and even the types of addresses you can use.  For tenant address types you can use:

You can use those independently or together.  As far as planning out the use of GUA, ULA or combination of the two you have to think about the requirements of the tenant.  Most of the time the tenant has no clue what ‘routable’ means or NAT and they shouldn’t.  In the context of IPv6, we don’t want to do NAT, ever. Well, with one exception – we may need, for a very temporary use case, NAT64 where we translating incoming IPv6 connections into back-end IPv4-only nodes.  This is an entirely different use case than wanting to translate between two IPv6 address spaces.  Don’t do that. 🙂

With all of that said, I tend to see two of MANY address options in production deployments:

  • Cloud provider assigned addressing – Provider owns and assigns IPv6 addressing
  • Tenant-provided addressing – Tenant brings their own IPv6 addressing and the cloud provider has to route it

What I mean by “cloud provider assigned addressing” is that the owner of the system (the cloud provider – which could be a public provider or just an Enterprise IT shop) will obtain a Provider Independent (PI) or Provider Assigned (PA) IPv6 address block, design an address plan and then assign blocks out of that plan to each tenant. This works well, is easy to do and is the way you should do it.

Tenant-provided addressing is possible, but messy.  In the Enterprise space, this is not something that usually happens unless you are dealing with a merger & acquisition (M&A) situation where an acquired company wants their existing IPv6 addressing to be used in the acquiring company’s cloud service.  This is something that is requested when an Enterprise or another SP is using another public cloud provider.  Again, it is totally doable but it requires a lot of planning with BGP, address space design, etc..

From an address assignment perspective, you can use:

  • Static/manual configuration
  • StateLess Address AutoConfiguration (SLAAC) – IPv6 prefix (i.e /64) is assigned to the end node via a router advertisement (RA) and the node self-constructs the interface ID (IID) portion of the address (i.e. the last /64 bits)
  • Stateful DHCPv6 – Just like IPv4 DHCP, a DHCPv6 server hands out full IPv6 addressing and any configured options
  • Stateless DHCPv6 – A combination of SLAAC (for address assignment) and DHCPv6 (for option assignment – DNS name, domain name)

In the OpenStack Kilo release we have functional support for SLAAC, Stateful DHCPv6 and Stateless DHCPv6.  I will cover the configuration of all three in this post.

Example Topology

The lab setup I am using for this post includes:

  • Kilo
  • Devstack – only because I did this testing before packages were available for RDO/Packstack, Ubuntu/Juju/MaaS or any other intaller
  • All-in-one node (although in another lab I have I did this same setup on 7 nodes and it worked as expected)
  • The lab I did this test in did not have external IPv6 connectivity to the Internet, but I do have IPv6 throughout that lab so I could verify proper routing beyond OpenStack

Figure 3 shows a basic topology of the example setup.  The all-in-one (AIO) has a management network interface (eth0) and an OpenStack public network interface (eth1).  Both interfaces are connected to a Top-of-Rack (ToR) switch which has an uplink to the Data Center Aggregation Layer switches (via trunked VLANs).  The Aggregation Layer switches have VLAN interfaces for each network and are providing IPv4 and IPv6 routing for the rest of the lab. There are IPv6 routes configured on the Aggregation Layer switches for each IPv6 prefix within the OpenStack tenant space.  Off of the ToR is a DNS server that is IPv4 and IPv6 enabled.

Figure 3. Example Topology

topo

Before I walk through each address assignment type, I will create the public network and subnets as the cloud admin. This can be done in the dashboard or via the Neutron client CLI. In this example a “public” network is created and the upstream Data Center L3 switches (–router:external) will be used as the gateway. An IPv4 subnet is created with an allocation range so that the addresses assigned do not collide with IPv4 addresses assigned on the Data Center L3 switches. An IPv6 subnet is created which also has an allocation range defined. If you have an upstream gateway address that is not .1 (v4) or ::1 (v6) then you need to identify the real gateway address using the “–gateway” option:

neutron net-create public --router:external

neutron subnet-create --name public-subnet --allocation-pool start=172.16.12.5,end=172.16.12.254 public 172.16.12.0/24

neutron subnet-create --ip-version=6 --name=public-v6-subnet --allocation-pool start=2001:db8:cafe:d::5,end=2001:db8:cafe:d:ffff:ffff:ffff:fffe --disable-dhcp public 2001:db8:cafe:d::/64

Let’s walk through SLAAC, Stateful DHCPv6 and Stateless DHCPv6.

SLAAC

Figure 4 gives a topology view of the SLAAC example I am referencing.  The Neutron router has a private network with IPv4 and IPv6 subnets and a public network with gateway connections (Also, dual stack) to the Data Center. The instance will have a dual stack connection and receive DHCPv4 address assigned from DNSMASQ and IPv6 address assignment via radvd in SLAAC mode:

Figure 4. SLAAC Topology Example

slaac-topo

When you use SLAAC mode in the tenant space, the Router Advertisement Daemon (radvd) is used to send router advertisements (RAs) in response to Router Solicitations (RS) as well as at a regular interval.  When you create a Neutron network and subnet for IPv6 you have to select the “IPv6 Address Configuration Mode” from the “Subnet Details” screen in the dashboard. In this case you would select “SLAAC: Address discovered from OpenStack Router”.  If you were doing this via CLI, you would use the option arguments of “–ipv6-address-mode=slaac –ipv6-ra-mode=slaac” when you create the subnet.  In the example below, a new Neutron network (“private”) is created along with the IPv6 subnet creation (IPv4 subnet creation is not shown). The option arguments are added to identify SLAAC mode. Also, no DNS servers are added here as that information for IPv6 would not get injected into the instance and the instance (since it is set for SLAAC-only) would not ask for DNS and other options:

neutron net-create private
 
neutron subnet-create --ip-version=6 --name=private_v6_subnet --ipv6-address-mode=slaac --ipv6-ra-mode=slaac private 2001:db8:cafe::/64

Created a new subnet:
+-------------------+----------------------------------------------------------------+
| Field             | Value                                                          |
+-------------------+----------------------------------------------------------------+
| allocation_pools  | {"start": "2001:db8:cafe::2", "end": "2001:db8:cafe:0:ffff:ffff:ffff:fffe"}|
| cidr              | 2001:db8:cafe::/64                                             |
| dns_nameservers   |                                                                |
| enable_dhcp       | True                                                           |
| gateway_ip        | 2001:db8:cafe::1                                               |
| host_routes       |                                                                |
| id                | 42cc3dbc-938b-4ad6-b12e-59aef7618477                           |
| ip_version        | 6                                                              |
| ipv6_address_mode | slaac                                                          |
| ipv6_ra_mode      | slaac                                                          |
| name              | private_v6_subnet                                              |
| network_id        | 7166ce15-c581-4195-9479-ad2283193d06                           |
| subnetpool_id     |                                                                |
| tenant_id         | f057804eb39b4618b40e06196e16265b                               |
+-------------------+----------------------------------------------------------------+

Inside the tenant (as a tenant member or admin) a Neutron router needs to be created along with attaching the router to the public network and the two subnets:

neutron router-create router

neutron router-gateway-set router public

neutron router-interface-add router private_v4_subnet

neutron router-interface-add router private_v6_subnet

When an instance boots inside the tenant and attaches to the “private” network it will have access to both the IPv4 and the IPv6 subnets that were defined previously. Note: Both Windows (since Windows 7/Server 2008) and Linux (from a long time ago) support SLAAC out of the box just so basic IPv6 protocol support is enabled.  The instance will receive and IPv4 address via DNSMASQ and an IPv6 address via radvd. Note: The host will NOT receive any kind of IPv6 DNS entry from OpenStack. There are a couple of considerations to understand with this. An instance can get both IPv4 and IPv6 DNS information for a host over IPv4 transport. You don’t need to access a DNS server natively over IPv6 in order to receive IPv6 host information in a lookup. But, if you do want to have an IPv6 entry in the /etc/resolv.conf file then, in SLAAC mode, you will need to configure it manually, setup cloud-init to inject it or just bake that entry into the image that is booted.

A highly summarized view of a tcpdump capture reveals the basic flow of a SLAAC exchange.  The ICMPv6 Flags field states “none” and the Prefix Information Flag field has “auto” enabled. The combination of “none” (Managed and Other bits = 0) and “auto” (Auto bit = 1) indicates SLAAC is used and DHCPv6 is not used. You can read more on this in RFC 4861:

IP6 (hlim 255, next-header ICMPv6 (58) payload length: 16) fe80::f816:3eff:fe79:5acc > ff02::2: [icmp6 sum ok] ICMP6, router solicitation, length 16
	  source link-address option (1), length 8 (1): fa:16:3e:79:5a:cc
	    0x0000:  fa16 3e79 5acc

IP6 (hlim 255, next-header ICMPv6 (58) payload length: 56) fe80::f816:3eff:fec3:17b4 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 56
	hop limit 64, Flags [none], pref medium, router lifetime 30s, reachable time 0s, retrans time 0s
	  prefix info option (3), length 32 (4): 2001:db8:cafe::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s
	    0x0000:  40c0 0001 5180 0000 3840 0000 0000 2001
	    0x0010:  0db8 cafe 0000 0000 0000 0000 0000
	  source link-address option (1), length 8 (1): fa:16:3e:c3:17:b4
	    0x0000:  fa16 3ec3 17b4

The instance will send out a router solicitation and the router will reply with a router advertisement. In that RA, the router will send various bits of information (various lifetimes and other stuff) and, in the case of SLAAC, it will send out a “Flags [none]”, indicating that it is not giving out anything other than a prefix. In that RA is the prefix from the subnet that was configured earlier (2001:db8:cafe::/64). The instance will use that prefix, along with its own IID (discussed earlier) to come up with a valid 128-bit IPv6 address. The instance will use the router’s link-local address as its gateway.  After the host has the IPv6 address it will go through a series of events such as Duplicate Address Detection (DAD) and so on. I won’t be explaining all of that stuff here. 😉

Stateful DHCPv6

Figure 5 is a topology view of the Stateful DHCPv6 layout. It is pretty much the same as with SLAAC only using a different IPv4 and IPv6 prefix.

Figure 5. Stateful DHCPv6 Topology Example

stateful-topo

Just like with SLAAC mode, radvd is used with Stateful DHCPv6 mode.  Instead of using the prefix announcement (Auto bit set to 1) in the RA to assist with IPv6 address assignment (SLAAC mode), Stateful DHCPv6 uses the Managed bit (set to 1) and the Auto bit (set to 0) to instruct the instance to perform a  DHCPv6 solicit for both address assignment and other options.

Configuring OpenStack to use Stateful DHCPv6 is done using the same process as was shown in the SLAAC example only with different options. In the dashboard, “DHCPv6 stateful: Address discovered from OpenStack DHCP” is selected in the “subnet details” screen.  Unlike with SLAAC, a DNS name server entry can be added and it will be sent to the instance.  If the Neutron client CLI is used then the option arguments would be: “–ipv6-address-mode=dhcpv6-stateful –ipv6-ra-mode=dhcpv6-stateful”.  Here’s an example:

neutron net-create private-dhcpv6
 
neutron subnet-create --ip-version=6 --name=private_dhcpv6_subnet --ipv6-address-mode=dhcpv6-stateful --ipv6-ra-mode=dhcpv6-stateful private-dhcpv6 2001:db8:cafe:1::/64 --dns-nameserver 2001:db8:cafe:a::e
Created a new subnet:
+-------------------+----------------------------------------------------------------+
| Field             | Value                                                          |
+-------------------+----------------------------------------------------------------+
| allocation_pools  | {"start": "2001:db8:cafe:1::2", "end": "2001:db8:cafe:1:ffff:ffff:ffff:fffe"} |
| cidr              | 2001:db8:cafe:1::/64                                           |
| dns_nameservers   | 2001:db8:cafe:a::e                                             |
| enable_dhcp       | True                                                           |
| gateway_ip        | 2001:db8:cafe:1::1                                             |
| host_routes       |                                                                |
| id                | 545ea206-9d14-4dca-8bae-7940719bdab5                           |
| ip_version        | 6                                                              |
| ipv6_address_mode | dhcpv6-stateful                                                |
| ipv6_ra_mode      | dhcpv6-stateful                                                |
| name              | private_dhcpv6_subnet                                          |
| network_id        | 55ed8333-2876-400a-92c1-ef49bc10aa2b                           |
| subnetpool_id     |                                                                |
| tenant_id         | f057804eb39b4618b40e06196e16265b                               |
+-------------------+----------------------------------------------------------------+

After performing “neutron router-interface-add” for each subnet (see SLAAC example), it’s time to setup the instance operating system for DHCPv6 operation. To learn about how Microsoft Windows supports IPv6 address assignment check out this blog.  No Linux version that I have ever worked with is configured, by default, to use DHCPv6.  For Ubuntu you have to add the “inet6 dhcp” line in the /etc/network/interfaces file:

auto eth0
iface eth0 inet dhcp
iface eth0 inet6 dhcp

I have tested CentOS 7 and Fedora 21 in this test bed and the following configuration works on those (add to the appropriate interface in /etc/sysconfig/network-scripts/):

IPV6INIT="yes"
DHCPV6C="yes"

Included below is a highly summarized output from a tcpdump capture of a Stateful DHCPv6 exchange.  There is a lot more going on here than in the SLAAC example.  Just like the SLAAC example, there is a RS/RA exchange but that is where the similarity ends.  In the RA below, the ICMPv6 Flags field is set to “managed” (M bit = 1). Note: that when the M bit is set to 1, the O bit, per RFC 4861 is redundant and can be ignored.  The instance will receive the RA and see that the “managed” flag is set and will then begin the DHCPv6 client process.  The instance will send a DHCPv6 Solicit to the ‘all DHCP servers’ well-known IPv6 multicast address (ff02::1:2).  Radvd will do a DHCPv6 advertise with all of the good stuff (address and options). The instance will do a DHCPv6 request for options (it processed the address info from the advertise) and the server will finish the sequence with a DHCPv6 reply.  You can read a summary view of this process here:

IP6 (hlim 255, next-header ICMPv6 (58) payload length: 24) fe80::f816:3eff:fe77:e5a0 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 24
	hop limit 64, Flags [managed], pref medium, router lifetime 30s, reachable time 0s, retrans time 0s
	  source link-address option (1), length 8 (1): fa:16:3e:77:e5:a0
	    0x0000:  fa16 3e77 e5a0

IP6 (hlim 1, next-header UDP (17) payload length: 64) fe80::f816:3eff:fe22:386b.546 > ff02::1:2.547: [udp sum ok] dhcp6 solicit (xid=85680b (client-ID hwaddr/time type 1 time 482446373 fa163e22386b) (option-request DNS-server DNS-search-list Client-FQDN SNTP-servers) (elapsed-time 101) (IA_NA IAID:1042430059 T1:3600 T2:5400))

IP6 (class 0xc0, hlim 64, next-header UDP (17) payload length: 175) fe80::f816:3eff:fe06:176f.547 > fe80::f816:3eff:fe22:386b.546: [udp sum ok] dhcp6 advertise (xid=85680b (client-ID hwaddr/time type 1 time 482446373 fa163e22386b) (server-ID hwaddr type 1 fa163e06176f) (IA_NA IAID:1042430059 T1:43200 T2:75600 (IA_ADDR 2001:db8:cafe:1::4 pltime:86400 vltime:86400)) (status-code success) (preference 255) (DNS-search-list openstacklocal.) (DNS-server 2001:db8:cafe:a::e) (Client-FQDN))

IP6 (hlim 1, next-header UDP (17) payload length: 106) fe80::f816:3eff:fe22:386b.546 > ff02::1:2.547: [udp sum ok] dhcp6 request (xid=9cb172 (client-ID hwaddr/time type 1 time 482446373 fa163e22386b) (server-ID hwaddr type 1 fa163e06176f) (option-request DNS-server DNS-search-list Client-FQDN SNTP-servers) (elapsed-time 0) (IA_NA IAID:1042430059 T1:3600 T2:5400 (IA_ADDR 2001:db8:cafe:1::4 pltime:7200 vltime:7500)))

IP6 (class 0xc0, hlim 64, next-header UDP (17) payload length: 186) fe80::f816:3eff:fe06:176f.547 > fe80::f816:3eff:fe22:386b.546: [udp sum ok] dhcp6 reply (xid=9cb172 (client-ID hwaddr/time type 1 time 482446373 fa163e22386b) (server-ID hwaddr type 1 fa163e06176f) (IA_NA IAID:1042430059 T1:3600 T2:6300 (IA_ADDR 2001:db8:cafe:1::4 pltime:7200 vltime:7500)) (status-code success) (DNS-search-list openstacklocal.) (DNS-server 2001:db8:cafe:a::e) (Client-FQDN))

Stateless DHCPv6

Stateless DHCPv6 is a combo of SLAAC (for address assignment) and DHCPv6 (for options).  For the sake of consistency with the last two sections, here is a topology sample for Stateless DHCPv6:

Figure 6. Stateless DHCPv6 Sample Topology

stateless-topo

The configuration of Stateless DHCPv6 is similar to that of Stateful DHCPv6.  In the dashboard, select “DHCPv6 stateless: Address discovered from OpenStack Router and additional information from OpenStack DHCP” from the “subnet details” screen.  The options argument changes if using the Neutron client CLI: “–ipv6-address-mode=dhcpv6-stateless –ipv6-ra-mode=dhcpv6-stateless private-dhcpv6-stateless”.  Here is an example:

neutron net-create private-dhcpv6-stateless

neutron subnet-create --ip-version=6 --name=private_dhcpv6_stateless_subnet --ipv6-address-mode=dhcpv6-stateless --ipv6-ra-mode=dhcpv6-stateless private-dhcpv6-stateless 2001:db8:cafe:2::/64 --dns-nameserver 2001:db8:cafe:a::e
Created a new subnet:
+-------------------+--------------------------------------------------------------+
| Field             | Value                                                        |
+-------------------+--------------------------------------------------------------+
| allocation_pools  | {"start": "2001:db8:cafe:2::2", "end": "2001:db8:cafe:2:ffff:ffff:ffff:fffe"} |
| cidr              | 2001:db8:cafe:2::/64                                         |
| dns_nameservers   | 2001:db8:cafe:a::e                                           |
| enable_dhcp       | True                                                         |
| gateway_ip        | 2001:db8:cafe:2::1                                           |
| host_routes       |                                                              |
| id                | edd1d404-e949-4cdf-9812-334bbf0e5cec                         |
| ip_version        | 6                                                            |
| ipv6_address_mode | dhcpv6-stateless                                             |
| ipv6_ra_mode      | dhcpv6-stateless                                             |
| name              | private_dhcpv6_stateless_subnet                              |
| network_id        | f65c6e60-d31e-4a1c-8136-599c3855b86a                         |
| subnetpool_id     |                                                              |
| tenant_id         | f057804eb39b4618b40e06196e16265b                             |
+-------------------+--------------------------------------------------------------+

After performing “neutron router-interface-add” for each subnet (again, see the SLAAC example), edits need to be made to the instance operating system for Stateless DHCPv6 operation. In the Ubuntu /etc/network/interfaces file, ensure the “inet6” line is set to “auto” and enable the stateless flag:

iface eth0 inet6 auto
dhcp 1

Again, I only tested CentOS7 and Fedora 21 with this setup so your mileage may vary but for those OSes, set the following for the appropriate interface in /etc/sysconfig/network-scripts/:

IPV6INIT="yes"
DHCPV6C="yes"
DHCPV6C_OPTIONS="-S"

Below is the output from tcpdump for the Stateless DHCPv6 exchange.  Radvd sends out the RS with the ICMPv6 Flags field set with the O bit set to 1 and the Prefix Information Flag field has “auto” enabled. This combination basically says “I, the router, will provide you, the instance,  a prefix via SLAAC and you come back asking for options”.  The instance will issue a “dhcp6 inf-req” to get the options and radvd will reply:

IP6 (hlim 255, next-header ICMPv6 (58) payload length: 56) fe80::f816:3eff:fec1:bc52 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 56
	hop limit 64, Flags [other stateful], pref medium, router lifetime 30s, reachable time 0s, retrans time 0s
	  prefix info option (3), length 32 (4): 2001:db8:cafe:2::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s
	    0x0000:  40c0 0001 5180 0000 3840 0000 0000 2001
	    0x0010:  0db8 cafe 0002 0000 0000 0000 0000
	  source link-address option (1), length 8 (1): fa:16:3e:c1:bc:52
	    0x0000:  fa16 3ec1 bc52

IP6 (hlim 1, next-header UDP (17) payload length: 44) fe80::f816:3eff:fefe:d157.546 > ff02::1:2.547: [udp sum ok] dhcp6 inf-req (xid=d2dbc8 (client-ID hwaddr type 1 fa163efed157) (option-request DNS-server DNS-search-list Client-FQDN SNTP-servers) (elapsed-time 94))

IP6 (class 0xc0, hlim 64, next-header UDP (17) payload length: 88) fe80::f816:3eff:fe2d:a6de.547 > fe80::f816:3eff:fefe:d157.546: [udp sum ok] dhcp6 reply (xid=d2dbc8 (client-ID hwaddr type 1 fa163efed157) (server-ID hwaddr type 1 fa163e2da6de) (DNS-search-list openstacklocal.) (DNS-server 2001:db8:cafe:a::e) (lifetime 86400))

I am sorry for the legnth of the blog post. In retrospect I should have broken this post into multiple posts but oh well.

I hope this was helpful.

Cheers,
Shannon