IPv6 on JunOS – Static Routing

In my previous post I configured IPv6 with Prefix Delegation. IPv6-PD is alright for a simple topology but it is very, very limiting and seems quite complicated to implement when you have many subnets in a complex topology.

This post will cover static IPv6 routing. Ideally I would have implemented OSPFv3 to handle dynamic routing but sadly, my switches do not support that feature, even with the EFL license.

Lab Topology

Here is a small part of my network which I’ll be using to test it.

IPv6 Topology

Notice that the client VLAN is the only segment with a globally routed IPv6 address. With IPv6, it is perfectly fine to use only link-local (non-routed) addressing on your transit networks, and in fact it has several benefits! If you’re curious what those benefits are, you can read all about it in RFC7407 by Eric Vyncke and Michael Behringer.

Addressing configuration

My provider has assigned me two static prefixes to me. These are not the real ones btw 🙂

IPv6 LAN prefix 	2a02:1234:420a::/48
IPv6 WAN prefix 	2a02:1234:8401:9a00::/64

First, let’s configure our WAN interface with a static IP address in the WAN range.

[edit]
admin@NPFW01# set interfaces pp0 unit 0 family inet6 address 2a02:1234:8401:9a00::1/64

As I’m using PPPoE, I will need to add a static default route (::/0) with the pp0.0 interface as next-hop. Also, I’m using VRFs so I need to add it under the right routing instance.

[edit routing-instances VRF-Edge]
admin@NPFW01# set routing-options rib VRF-Edge.inet6.0 static route ::/0 next-hop pp0.0

A quick ping to Google to verify that we have IPv6 connectivity on the external interface.

admin@NPFW01> ping inet6 2001:4860:4860::8888 routing-instance VRF-Edge source 2a02:1234:8401:9a00::1 rapid count 10
PING6(56=40+8+8 bytes) 2a02:1234:8401:9a00::1 --> 2001:4860:4860::8888
!!!!!!!!!!
--- 2001:4860:4860::8888 ping6 statistics ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 30.980/31.647/32.716/0.444 ms

So far, so good. Let’s configure the internal interfaces now.

Configuration for the link-local addresses on the Firewall:

[edit interfaces ae0 unit 90 family inet6]
admin@NPFW01# show
address fe80:90::2/64;
[edit interfaces ae1 unit 10 family inet6]
admin@NPFW01# show
address fe80:10::2/64;
[edit interfaces ae1 unit 100 family inet6]
admin@NPFW01# show
address fe80:100::2/64;

And for the switch:

{master:0}[edit interfaces vlan unit 10 family inet6]
admin@NPSWC01# show
address fe80:10::1/64;
{master:0}[edit interfaces vlan unit 90 family inet6]
admin@NPSWC01# show
address fe80:90::1/64;
{master:0}[edit interfaces vlan unit 100 family inet6]
admin@NPSWC01# show
address fe80:100::1/64;
{master:0}[edit interfaces vlan unit 101 family inet6]
admin@NPSWC01# show
address fe80:101::1/64;

In my case, the interfaces are already in the right routing instances so I don’t need to add them anymore. Don’t forget this step though, if you are recreating this in your own lab.

After a commit, we can confirm reachability between the devices inside their routing instances.

admin@NPSWC01> ping fe80:90::2 routing-instance VRF-Transit source fe80:90::1 rapid count 5
PING6(56=40+8+8 bytes) fe80:90::1 --> fe80:90::2
!!!!!
--- fe80:90::2 ping6 statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 3.981/4.689/6.566/0.947 ms
admin@NPSWC01> ping fe80:10::2 routing-instance VRF-Transit source fe80:10::1 rapid count 5
PING6(56=40+8+8 bytes) fe80:10::1 --> fe80:10::2
!!!!!
--- fe80:10::2 ping6 statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 4.181/5.018/6.296/0.731 ms
admin@NPSWC01> ping fe80:100::2 routing-instance VRF-NP source fe80:100::1 rapid count 5
PING6(56=40+8+8 bytes) fe80:100::1 --> fe80:100::2
!!!!!
--- fe80:100::2 ping6 statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 3.924/4.819/5.715/0.575 ms

Both devices should now have an entry for eachother in the IPv6 neighbour tables, which is the equivalent of the v4 ARP table.

admin@NPSWC01> show ipv6 neighbors
IPv6 Address                 Linklayer Address  State       Exp Rtr Secure Interface
fe80:10::2                   a8:d0:e5:d3:2a:81  stale       927 yes no      vlan.10
fe80:90::2                   a8:d0:e5:d3:2a:80  stale       896 yes no      vlan.90
fe80:100::2                  a8:d0:e5:d3:2a:81  stale       887 yes no      vlan.100

Client network addressing

Last step is to assign the VLAN201 interface with a publically routed interface. I will be configuring this address: 2a02:1234:420a:10c9::1/64

There are probably more elegant addressing designs but this is what I came up with:

  • The first 48 bits are our globally routed prefix.
  • For the next 16 bits, I’ve used the leading 4 bits to represent the site number. This is my first site, so number 1.
  • The last 12 bits represent the VLAN number in hexadecimal notation, as there are 4096 vlans available in the dot1q standard – VLAN201 is C9 in hex!

Granted, it’s not the most scalable solution, as it only gives me 15 more sites and it wastes a lot of addresses but hey, this is not a multinational yet! 🙂

Here’s the configuration for the VLAN201 SVI:

{master:0}[edit interfaces vlan unit 201 family inet6]
admin@NPSWC01# show
address 2a02:1234:420a:10c9::1/64;

Enabling Router Advertisements

To enable dynamic address assignments (SLAAC) for the clients behind it, we also need to enable router advertisements on this interface. The other-stateful-configuration command will add the O-Flag to the advertisements, so we can later add the additional DNS information via DHCPv6.

{master:0}[edit protocols router-advertisement interface vlan.201]
admin@NPSWC01# show
other-stateful-configuration;
prefix 2a02:1234:420a:10c9::/64;
}

After committing, the client has assigned itself an IPv6 based on the received router advertisements.

Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . : ***-networks.local
   IPv6 Address. . . . . . . . . . . : 2a02:1234:420a:10c9:b1d1:660c:ac69:c5f8
   Temporary IPv6 Address. . . . . . : 2a02:1234:420a:10c9:3c71:b6f2:e93f:67ab
   Link-local IPv6 Address . . . . . : fe80::b1d1:660c:ac69:c5f8%6
   IPv4 Address. . . . . . . . . . . : 10.255.1.13
   Subnet Mask . . . . . . . . . . . : 255.255.255.128
   Default Gateway . . . . . . . . . : fe80::5e45:27ff:fee7:af81%6
                                       10.255.1.1

The basics are now in place. Now we will add some routing to make this prefix reachable.

Configuring static routes

As mentioned, my EX2200 switches do not support OSPFv3 so static routing is the only option for now…

Note – If you are using link-local addresses as the next-hop, you must use the qualified-next-hop statement with the interface in question.

Static routes, using link-local addresses, added on the switch’s routing-instances:

{master:0}[edit routing-instances VRF-Transit routing-options]
admin@NPSWC01# show
rib VRF-Transit.inet6.0 {
    static {
        route ::/0 {
            qualified-next-hop fe80:90::2 {
                interface vlan.90;
            }
        }
        route 2a02:1234:420a:10c9::/64 {
            qualified-next-hop fe80:10::2 {
                interface vlan.10;
            }
        }
    }
}
{master:0}[edit routing-instances VRF-NP routing-options]
admin@NPSWC01# show
rib VRF-NP.inet6.0 {
    static {
        route ::/0 {
            qualified-next-hop fe80:100::2 {
                interface vlan.100;
            }
        }
    }
}

And the routes on the firewall:

[edit routing-instances VRF-Internal routing-options]
admin@NPFW01# show
rib VRF-Internal.inet6.0 {
    static {
        route ::/0 {
            qualified-next-hop fe80:10::1 {
                interface ae1.10;
            }
        }
        route 2a02:1234:420a:10c9::/64 {
            qualified-next-hop fe80:100::1 {
                interface ae1.100;
            }
        }
    }
}
admin@NPFW01# show
rib VRF-Edge.inet6.0 {
    static {
        route ::/0 next-hop pp0.0;
        route 2a02:1234:420a:10c9::/64 {
            qualified-next-hop fe80:90::1 {
                interface ae0.90;
            }
        }
    }
}

After adding this configuration, and assuming that the necessary firewall policies are in place, the client can now ping outbound to the internet.

C:\Users\user>ping 2001:4860:4860::8888

Pinging 2001:4860:4860::8888 with 32 bytes of data:
Reply from 2001:4860:4860::8888: time=30ms
Reply from 2001:4860:4860::8888: time=30ms
Reply from 2001:4860:4860::8888: time=31ms
Reply from 2001:4860:4860::8888: time=30ms

Ping statistics for 2001:4860:4860::8888:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 30ms, Maximum = 31ms, Average = 30ms

That’s all it takes to implement static routing for IPv6, easy-peasy!

IPv6 on Juniper SRX – Prefix Delegation & DHCPv6

I’m currently setting up IPv6 in my own office so I thought it would be worth documenting the configuration I’m adding on my Juniper equipment to make it all work.

I have an internet subscription with a static IPv4 address and also included with it is a /48 static IPv6 prefix. There are two ways I can set it up: static configuration or “semi-automatic” by using Prefix Delegation. This article discusses the latter and in my next post I will document the static configuration, as that’s what I will ultimately be using.

First Things First – Enabling IPv6 Forwarding

Before you can start using IPv6 on the SRX, the device needs to be explicitly configured to forward V6 traffic. This because, by default, the forwarding mode for IPv6 is set to drop. You can verify this on the command line – as shown below, the default forwarding mode for Inet6 traffic is drop:

np@NP-FW01> show security flow status
  Flow forwarding mode:
    Inet forwarding mode: flow based
    Inet6 forwarding mode: drop
    MPLS forwarding mode: drop
    ISO forwarding mode: drop
  Flow trace status
    Flow tracing status: off
  Flow session distribution
    Distribution mode: RR-based
  Flow ipsec performance acceleration: off
  Flow packet ordering
    Ordering mode: Hardware

To activate it, you must change the forwarding mode. There are three modes to choose from: drop (default), flow-based and packet-based.

[edit]
np@NP-FW01# set security forwarding-options family inet6 mode ?
Possible completions:
  drop                 Disable forwarding
  flow-based           Enable flow-based forwarding
  packet-based         Enable packet-based forwarding

I’m using the SRX as a stateful firewall, so I’ll configure flow-based and commit. JunOS will warn you that the change is active only after a device reboot, so I’ll reboot the SRX and continue below.

[edit]
np@NP-FW01# set security forwarding-options family inet6 mode flow-based
[edit]
np@NP-FW01# show | compare
[edit security]
+   forwarding-options {
+       family {
+           inet6 {
+               mode flow-based;
+           }
+       }
+   }
[edit]
np@NP-FW01# commit
warning: You have enabled/disabled inet6 flow.
You must reboot the system for your change to take effect.
If you have deployed a cluster, be sure to reboot all nodes.
commit complete

After the reboot, the forwarding mode is set to flow based and we can start implementing IPv6.

np@NP-FW01> show security flow status
  Flow forwarding mode:
    Inet forwarding mode: flow based
    Inet6 forwarding mode: flow based
    MPLS forwarding mode: drop
    ISO forwarding mode: drop
  Flow trace status
    Flow tracing status: off
  Flow session distribution
    Distribution mode: RR-based
  Flow ipsec performance acceleration: off
  Flow packet ordering
    Ordering mode: Hardware

Configuring IPv6 with Prefix Delegation

Prefix delegation is a simple method to automate the assignment of IPv6 prefixes on subscriber equipment. The CPE (in my case the SRX) informs the upstream router, called the Broadband Network Gateway (BNG) that it wants to use Prefix Delegation. The BNG retrieves the prefix for the subscriber and announces the /48 back to the CPE, after which both sides confirm the prefix allocation. The CPE will then automatically divide the /48 into smaller /64 subnets on the LAN interfaces it has configured for PD Router Advertisements.

If you want to find out exactly how it works, you can find more information in RFC3633

First, we configure the outside interface, pp0.0 in my case. Notice that we are configuring this under family inet6.

The DHCPv6 client is activated on the outside, ISP-facing interface. Some PD-specific configuration is added and we will request the DNS server addresses from the provider.

[edit interfaces pp0 unit 0 family inet6]
np@NP-FW01# show
dhcpv6-client {
    client-type statefull;
    client-ia-type ia-pd;
    rapid-commit;
    client-identifier duid-type duid-ll;
    req-option dns-server;
    retransmission-attempt 0;
}

The LAN interface, in my case ae0.311, on which I will further delegate the prefix, is specified. Showing this separately as it’s important not to miss this one! 🙂

[edit interfaces pp0 unit 0 family inet6]
np@NP-FW01# set dhcpv6-client update-router-advertisement interface ae0.311

The last step is to allow DHCPv6 packets on the security zone inbound traffic. Could be that you need to add it under the interface, if you specified it further down on that level.

[edit security zones security-zone edge-untrust]
np@NP-FW01# set host-inbound-traffic system-services dhcpv6

If you want to use this on the LAN segment, you will also need to enable DHCPv6 on that security zone and interface. I’m using a guest VLAN for testing so I’ll enable it there.

[edit]
np@NP-FW01# set security zones security-zone edge-guest host-inbound-traffic system-services dhcpv6

After a commit, we see that interface ae0.311 now has a public IPv6 address with a /64 mask.

np@NP-FW01> show interfaces terse
Interface               Admin Link Proto    Local                 Remote

 ae0.311                 up    up   inet     192.168.200.1/24
                                   inet6    2a02:1234:420a:1::1/64
                                            fe80::aad0:e501:37d3:2a80/64
...

Notice that the SRX has taken the original /48 prefix and automatically derived a /64 subnet from it for interface ae0.311: 2a02:1234:420a:1::1/64 .

Note – real prefix modified for obvious reasons 🙂

Before we can test reachability, we will need to configure the default route via pp0.0. I’m using routing-instances (VRFs) so I will add it on my external edge instance.

[edit routing-instances VRF-Edge routing-options]
np@NP-FW01# show
rib VRF-Edge.inet6.0 {
    static {
        route ::/0 next-hop pp0.0;
    }
}

With the default route in place, we should be able to ping a public v6 address from this VRF. Below, we are pinging Google DNS, from the interface with Prefix Delegation.

np@NP-FW01> ping 2001:4860:4860::8888 routing-instance VRF-Edge rapid count 10 source 2a02:1234:420a:1::1
PING6(56=40+8+8 bytes) 2a02:1234:420a:1::1 --> 2001:4860:4860::8888
!!!!!!!!!!
--- 2001:4860:4860::8888 ping6 statistics ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max/std-dev = 31.811/32.841/35.861/1.163 ms

Success! This shows that IPv6-PD is working as expected and that the delegated prefix is globally reachable.

After connecting a test machine inside the VLAN, we can confirm that the router advertisements are working as expected. The client has taken the /64 prefix and assigned itself an EUI-64 address.

Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . : netprobe.guest
   Description . . . . . . . . . . . : Intel(R) Ethernet Connection (4) I219-V
   Physical Address. . . . . . . . . : C8-5B-76-BC-04-6E
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   IPv6 Address. . . . . . . . . . . : 2a02:1234:420a:1:103f:efd8:f2f7:d0cf(Preferred)
   Temporary IPv6 Address. . . . . . : 2a02:1234:420a:1:293c:fd60:c216:8123(Preferred)
   Link-local IPv6 Address . . . . . : fe80::103f:efd8:f2f7:d0cf%14(Preferred)
   IPv4 Address. . . . . . . . . . . : 192.168.200.13(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Lease Obtained. . . . . . . . . . : zondag 12 november 2017 15:23:41
   Lease Expires . . . . . . . . . . : maandag 13 november 2017 15:26:16
   Default Gateway . . . . . . . . . : fe80::aad0:e501:37d3:2a80%14
                                       192.168.200.1
   DHCP Server . . . . . . . . . . . : 192.168.200.1
   DHCPv6 IAID . . . . . . . . . . . : 63462262
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-20-35-58-1B-C8-5B-76-BC-04-6E
   DNS Servers . . . . . . . . . . . : 208.67.220.123
                                       208.67.222.123
   NetBIOS over Tcpip. . . . . . . . : Enabled

Now, this part seems to be working fine, but you may notice that the client has not received any IPv6 name servers.
This is because the client uses SLAAC to configure its v6 address based on the Router Advertisements, but it still relies on DHCPv6 to receive any special information such as DNS servers.

To make this work, we need to add a few more bits of configuration to use the SRX as a a DHCPv6 server.

Handing out DNS servers via DHCPv6

First, configure the DHCPv6 pool with the prefix and the DNS server you want to hand out. I’m using Google DNS here.

np@NP-FW01# show routing-instances VRF-Edge access address-assignment
pool vlan311-dhcpv6 {
    family inet6 {
        prefix 2a02:1234:420a:1::/64;
        dhcp-attributes {
            dns-server {
                2001:4860:4860::8888;
                2001:4860:4860::8844;
            }
        }
    }
}

Next, configure the internal DHCPv6 server under system services, referring to the pool you just created – add it under routing-instances if required!

np@NP-FW01# show routing-instances VRF-Edge system services dhcp-local-server
dhcpv6 {
    overrides {
        interface-client-limit 100;
        process-inform {
            pool vlan311-dhcpv6;
        }
    }
    group ipv6 {
        interface ae0.311;
    }
}
group group-vlan311 {
    interface ae0.311;
}

Activate Router Advertisements for your outside interface. It doesn’t seem to work for me without this.

[edit]
np@NP-FW01# show protocols router-advertisement
interface pp0.0;

The following bit controls the Router Advertisements on the delegated interface and activates the O-Flag (Other Information) on the RAs.

[edit interfaces pp0 unit 0 family inet6 dhcpv6-client update-router-advertisement interface ae0.311]
+         other-stateful-configuration;
+         max-advertisement-interval 6;
+         min-advertisement-interval 3;

After adding this configuration, we see the client has now successfully picked up the new DNS settings.

Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . : netprobe.guest
   Description . . . . . . . . . . . : Intel(R) Ethernet Connection (4) I219-V
   Physical Address. . . . . . . . . : C8-5B-76-BC-04-6E
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   IPv6 Address. . . . . . . . . . . : 2a02:1234:420a:1:103f:efd8:f2f7:d0cf(Preferred)
   Temporary IPv6 Address. . . . . . : 2a02:1234:420a:1:488c:f549:1e67:254c(Preferred)
   Link-local IPv6 Address . . . . . : fe80::103f:efd8:f2f7:d0cf%14(Preferred)
   IPv4 Address. . . . . . . . . . . : 192.168.200.13(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Lease Obtained. . . . . . . . . . : zondag 12 november 2017 15:23:41
   Lease Expires . . . . . . . . . . : maandag 13 november 2017 17:08:57
   Default Gateway . . . . . . . . . : fe80::aad0:e501:37d3:2a80%14
                                       192.168.200.1
   DHCP Server . . . . . . . . . . . : 192.168.200.1
   DHCPv6 IAID . . . . . . . . . . . : 63462262
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-20-35-58-1B-C8-5B-76-BC-04-6E
   DNS Servers . . . . . . . . . . . : 2001:4860:4860::8888
                                       2001:4860:4860::8844
                                       208.67.220.123
                                       208.67.222.123
   NetBIOS over Tcpip. . . . . . . . : Enabled

After adding a security policy that allows IPv6 traffic, the client can succesfully communicate over IPv6.

C:\Users\Simon>nslookup - 2001:4860:4860::8888
Default Server:  google-public-dns-a.google.com
Address:  2001:4860:4860::8888

> google.com
Server:  google-public-dns-a.google.com
Address:  2001:4860:4860::8888

Non-authoritative answer:
Name:    google.com
Addresses:  2a00:1450:400e:80b::200e
          172.217.20.110

C:\Users\Simon>ping -6 www.google.com

Pinging www.google.com [2a00:1450:400e:806::2004] with 32 bytes of data:
Reply from 2a00:1450:400e:806::2004: time=30ms
Reply from 2a00:1450:400e:806::2004: time=31ms
Reply from 2a00:1450:400e:806::2004: time=31ms
Reply from 2a00:1450:400e:806::2004: time=30ms

Ping statistics for 2a00:1450:400e:806::2004:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 30ms, Maximum = 31ms, Average = 30ms

Verification Commands

Checking which prefix was allocated to you by the ISP – don’t forget to specify the routing-instance if you are using them.

np@NP-FW01> show dhcpv6 client binding routing-instance VRF-Edge

IP/prefix                       Expires     State      ClientType    Interface       Client DUID
2a02:1234:420a::/48              2590728     BOUND      STATEFUL      pp0.0           LL0x29-a8:d0:e5:d3:2a:47

You can renew the prefix lease this way:

np@NP-FW01> request dhcpv6 client renew routing-instance VRF-Edge interface pp0.0

Displaying the IPv6 neighbours – this is similar to your ARP table in IPv4.

np@NP-FW01> show ipv6 neighbors
IPv6 Address                 Linklayer Address  State       Exp Rtr Secure Interface
2a02:1234:420a:1:488c:f549:1e67:254c
                             c8:5b:76:bc:04:6e  stale       1017 no no      ae0.311
fe80::103f:efd8:f2f7:d0cf    c8:5b:76:bc:04:6e  stale       363 no  no      ae0.311

Statistics for the DHCPv6 server:

np@NP-FW01> show dhcpv6 server statistics routing-instance VRF-Edge
Dhcpv6 Packets dropped:
    Total               0

Messages received:
    DHCPV6_DECLINE             1
    DHCPV6_SOLICIT             6
    DHCPV6_INFORMATION_REQUEST 60
    DHCPV6_RELEASE             0
    DHCPV6_REQUEST             3
    DHCPV6_CONFIRM             0
    DHCPV6_RENEW               0
    DHCPV6_REBIND              0
    DHCPV6_RELAY_FORW          0
    DHCPV6_RELAY_REPL          0

Messages sent:
    DHCPV6_ADVERTISE           4
    DHCPV6_REPLY               8
    DHCPV6_RECONFIGURE         0
    DHCPV6_RELAY_REPL          0

Now, if I was running a fairly simple network with just a few subnets, I would be using Prefix Delegation but I also have a couple of L3 devices behind this firewall. Extending PD all the way down would make it overly complex, so I’ll go for static configuration with OSPFv3 in the next article.

Please let me know in the comments if this configuration did not work for you!