Have Fun with OpenStack and IPv6 Prefix Delegation

In this post I will talk about IPv6 Prefix Delegation (PD) in OpenStack.  IPv6 is a super important feature, especially in OpenStack. Unlike traditional IPv4 deployments with OpenStack where the cloud admin does not have to worry much about overlapping IPs and colliding address scopes, this is a real issue with IPv6 in OpenStack.  Other than Provider Network scenarios where there is a real exposure of the addressing to each tenant,  in most other scenarios (like using the Neutron L3 agent and having external/private networks per-tenant) overlapping IP support and NAT are used. In these scenarios, tenant A can use 10.0.0.0/24 and tenant B can use 10.0.0.0/24 and you have no fear of address collisions.  With IPv6, there is no NAT and there is no overlapping IP function so IPv6 prefixes can collide and you need a way to prevent the tenant from just willy nilly picking prefixes out of thin are.

There are three common ways to provide IPv6 prefixes to tenant subnets:

Take a look at RFC3633 and 3769 that are referenced above to get a very good look at how IPv6 PD works.  A quick summary of IPv6 PD:

  • IPv6 PD was originally designed to allow a downstream router (Requesting router) to request a prefix from an upstream router (Delegating router) and use the assigned IPv6 prefix for the subscriber-side networks
  • Basically, it is for routers asking other routers/relays/servers for a whole prefix that can be used to ‘seed’ downstream networks with an IPv6 prefix of their own

The following figure is a very basic example of how an IPv6 PD exchange may happen.

  1. A requesting router sends a solicitation upstream asking for an IPv6 prefix
  2. The delegating router/server provides one out of its pool of prefixes
  3. A host comes online and needs an IPv6 address (by sending a solicitation [SLAAC])
  4. The requesting router advertises the IPv6 PD prefix for the host to use

ipv6-pd-flow

The figure below is an example topology that is used for this post.  There is an OpenStack All-in-One (AIO) node that is connected to an L2 switch.  A Dibbler server is deployed and also attached to the L2 switch.  In OpenStack, a public network with an IPv6 prefix is already configured. The goal is to assign an IPv6 prefix to the tenant interface of the Neutron router.

ipv6-pd-topo

Dibbler Server Configuration

The Dibbler server configuration is straightforward. After you have installed Dibber on your test Linux machine, edit the /etc/dibbler/server.conf file and update the pd-class. In the following example, the pd-pool that prefixes will come out of is 2001:db8:face::/48 and the default prefix-length (pd-length) that is assigned is a /64:

pd-class {
     pd-pool 2001:db8:face::/48
     pd-length 64
 }

On the OpenStack side, you need to follow the steps outlined in the OpenStack Neutron IPv6 documentation for installation/setup. Once that is done, the /etc/neutron/neutron.conf file needs to be updated to enable IPv6 PD:

ipv6_pd_enabled = True

Create the Neutron public/external network (In this example I am using a basic flat network type):

neutron net-create public --provider:network_type flat --provider:physical_network public --router:external

Create the Neutron subnet for the public network. Note: This network is a transient network that is used to reach the upstream Dibbler server. Don’t assign a prefix to this network from the pd-pool you defined in the Dibbler configuration:

neutron subnet-create public --ip-version 6 --name public-v6-subnet  2001:db8:bad:cafe::/64

Create a Neutron router:

neutron router-create pd-rtr

Connect the public Neutron network to the Neutron router:

neutron router-gateway-set pd-rtr public

Now, the more interesting part comes in. Within the tenant, create the Neutron network (no dependency on the actual name):

neutron net-create ipv6-pd

Create the Neutron subnet using the special flag –-use-default-subnetpool (this is super critical to do or it won’t work):

neutron subnet-create ipv6-pd --name ipv6-pd-1 --ip_version 6 --ipv6_ra_mode slaac --ipv6_address_mode slaac --use-default-subnetpool

In the output from the subnet-create step, look for”

subnetpool_id | prefix_delegation

Magic happens and unicorns and rainbows appear right after this next step. This is where the Dibbler client running within OpenStack triggers the whole process.

Attach the Neutron router to the new Neutron subnet that was just created:

neutron router-interface-add pd-rtr ipv6-pd-1

Have the Neutron L3 Log running so you can see a thing of beauty:

2016-10-17 15:03:46.822 DEBUG neutron.agent.linux.dibbler [-] Enable IPv6 PD for router 561ed48c-182c-4073-b157-77130280d5b9 subnet 3bc82226-816f-4d71-983e-7429d3d5475a ri_ifname qr-98120bdd-d1 from (pid=56056) enable /opt/stack/neutron/neutron/agent/linux/dibbler.py:123

2016-10-17 15:03:46.824 DEBUG neutron.agent.linux.utils [-] Running command (rootwrap daemon): ['ip', 'netns', 'exec', 'qrouter-561ed48c-182c-4073-b157-77130280d5b9', 'dibbler-client', 'start', '-w', '/opt/stack/data/neutron/pd/561ed48c-182c-4073-b157-77130280d5b9:3bc82226-816f-4d71-983e-7429d3d5475a:qr-98120bdd-d1'] from (pid=56056) execute_rootwrap_daemon /opt/stack/neutron/neutron/agent/linux/utils.py:100

2016-10-17 15:03:46.847 DEBUG neutron.agent.linux.dibbler [-] dibbler client enabled for router 561ed48c-182c-4073-b157-77130280d5b9 subnet 3bc82226-816f-4d71-983e-7429d3d5475a ri_ifname qr-98120bdd-d1 from (pid=56056) enable /opt/stack/neutron/neutron/agent/linux/dibbler.py:129

Have a tcpdump running on the bridge interface that is associated with the public network/physical NIC. The actual messages may change based on this being a brand new assignment vs a renew but the basics are:

  • Client: “Bro (server), gimme a prefix (solicit)”
  • Server: “Sure, bonehead take this one” (advertises out of its pool (2001:db8:face:2ff2::/64 – Remember our pd-pool prefix from the Dibbler config?)
  • Client: “Sweet! I got this prefix advertised and it seems fine so I will officially request it”
  • Server replies and it is a success
15:03:46.852214 IP6 (flowlabel 0x7bf3b, hlim 1, next-header UDP (17) payload length: 60) fe80::f816:3eff:feff:ccb0.dhcpv6-client > ff02::1:2.dhcpv6-server: [udp sum ok] dhcp6 solicit (xid=800a54 (client-ID vid 000022b83bc82226) (IA_PD IAID:1 T1:4294967295 T2:4294967295) (elapsed-time 0))

15:03:46.853654 IP6 (flowlabel 0x80c10, hlim 64, next-header UDP (17) payload length: 134) fe80::20c:29ff:fe87:2f6b.dhcpv6-server > fe80::f816:3eff:feff:ccb0.dhcpv6-client: [udp sum ok] dhcp6 advertise (xid=800a54 (IA_PD IAID:1 T1:2000 T2:3000 (IA_PD-prefix 2001:db8:face:2ff2::/64 pltime:3600 vltime:7200) (status-code success)) (server-ID hwaddr/time type 1 time 529454623 000c29872f6b) (client-ID vid 000022b83bc82226) (preference 0))

15:03:47.955793 IP6 (flowlabel 0x7bf3b, hlim 1, next-header UDP (17) payload length: 107) fe80::f816:3eff:feff:ccb0.dhcpv6-client > ff02::1:2.dhcpv6-server: [udp sum ok] dhcp6 request (xid=561e28 (client-ID vid 000022b83bc82226) (IA_PD IAID:1 T1:4294967295 T2:4294967295 (IA_PD-prefix 2001:db8:face:2ff2::/64 pltime:3600 vltime:7200)) (server-ID hwaddr/time type 1 time 529454623 000c29872f6b) (elapsed-time 0))

15:03:47.956239 IP6 (flowlabel 0x80c10, hlim 64, next-header UDP (17) payload length: 134) fe80::20c:29ff:fe87:2f6b.dhcpv6-server > fe80::f816:3eff:feff:ccb0.dhcpv6-client: [udp sum ok] dhcp6 reply (xid=561e28 (IA_PD IAID:1 T1:2000 T2:3000 (IA_PD-prefix 2001:db8:face:2ff2::/64 pltime:3600 vltime:7200) (status-code success)) (server-ID hwaddr/time type 1 time 529454623 000c29872f6b) (client-ID vid 000022b83bc82226) (preference 0))

On the Dibbler server log (output truncated for clarity):

03:46 Server Notice    Received SOLICIT on br-ex/8, trans-id=0x800a54, 3 opts: 1 25 8 (non-relayed)
. . .
03:46 Server Debug     Adding client (DUID=00:02:00:00:22:b8:3b:c8:22:26:81:6f:4d:71:98:3e:74:29:d3:d5:47:5a) to addrDB.
03:46 Server Debug     PD: Adding PD (iaid=1) to addrDB.
03:46 Server Debug     PD: Adding 2001:db8:face:2ff2:: prefix to PD (iaid=1) to addrDB.
. . .
03:46 Server Notice    Sending ADVERTISE on br-ex/8,transID=0x800a54, opts: 25 2 1 7, 0 relay(s).
. . .
03:47 Server Notice    Received REQUEST on br-ex/8, trans-id=0x561e28, 4 opts: 1 25 2 8 (non-relayed)
. . .
03:47 Server Debug     Checking prefix 2001:db8:face:2ff2:: against reservations ...
03:47 Server Debug     PD: Requested prefix (2001:db8:face:2ff2::) is free, great!
03:47 Server Debug     Adding client (DUID=00:02:00:00:22:b8:3b:c8:22:26:81:6f:4d:71:98:3e:74:29:d3:d5:47:5a) to addrDB.
03:47 Server Debug     PD: Adding PD (iaid=1) to addrDB.
03:47 Server Debug     PD: Adding 2001:db8:face:2ff2:: prefix to PD (iaid=1) to addrDB.
03:47 Server Debug     PD: Prefix usage for class 0 increased to 2.
03:47 Server Info      PD: assigned prefix(es):2001:db8:face:2ff2::/64

That is IPv6 Prefix Delegation for OpenStack. There is a LOT that I did not cover in this post so please read about IPv6 PD in reference links I provided in the beginning.

Leave a Reply

Your email address will not be published. Required fields are marked *