Header Image

Internet VRF goes IPv6

Intention

Howdy folks, today, after a long period of waiting, we want to tackle an interesting topic for most service providers. And this of course is how to enable you IPv4 based Internet VRF to be able to route IPv6 addresses as well, without having to re-think the entire network design! Before we get started, we have to lay some ground work.

Base Configurations

As usual, we start of with the MXimal performance Lab in its initial configuration. To shorten some things, I pre-deployed the neccessary configuration for an IPv4 based Internet VRF. For this to work, I simply activated MPLS and LDP on all the core interfaces interconnecting the P and PE devices as well as creating one large OSPF domain (IS-IS would also be useful and enable the possibility to extend to SPRING, however OSPF and LDP are the protocols still most used in networks).

MPLS, LDP and OSPF configuration:

All devices of the MPL receive a default OSPF, MPLS and LDP configuration. Check down below on what the configuration is for each device.

P1 and P2
[edit]
+  protocols {
+      ldp {
+          interface xe-0/0/0.0;
+          interface xe-0/0/1.0;
+          interface xe-0/0/2.0;
+          interface xe-0/0/3.0;
+          interface lo0.0;
+      }
+      mpls {
+          interface xe-0/0/0.0;
+          interface xe-0/0/1.0;
+          interface xe-0/0/2.0;
+          interface xe-0/0/3.0;
+      }
+      ospf {
+          area 0.0.0.0 {
+              interface xe-0/0/0.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/1.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/2.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/3.0 {
+                  interface-type p2p;
+              }
+              interface lo0.0;
+          }
+      }
+  }

P3 and P4
[edit]
+  protocols {
+      ldp {
+          interface xe-0/0/0.0;
+          interface xe-0/0/1.0;
+          interface xe-0/0/2.0;
+          interface xe-0/0/4.0;
+          interface lo0.0;
+      }
+      mpls {
+          interface xe-0/0/0.0;
+          interface xe-0/0/1.0;
+          interface xe-0/0/2.0;
+          interface xe-0/0/4.0;
+      }
+      ospf {
+          area 0.0.0.0 {
+              interface xe-0/0/0.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/1.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/2.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/4.0 {
+                  interface-type p2p;
+              }
+              interface lo0.0;
+          }
+      }
+  }

PE1 and PE2
[edit]
+  protocols {
+      ldp {
+          interface xe-0/0/3.0;
+          interface xe-0/0/4.0;
+          interface lo0.0;
+      }
+      mpls {
+          interface xe-0/0/3.0;
+          interface xe-0/0/4.0;
+      }
+      ospf {
+          area 0.0.0.0 {
+              interface xe-0/0/3.0 {
+                  interface-type p2p;
+              }
+              interface xe-0/0/4.0 {
+                  interface-type p2p;
+              }
+              interface lo0.0;
+          }
+      }
+  }

Internet VRF with IPv4

We also need an IPv4 Internet VRF. For this, PE1 simulates a Peering Router, which peers with different Autonomous Systems. For the sake of simplicity, I will use a logical system as well as lt interface so you do not need any more virtual routers.

Although we will run AS213928, we have to get creative with the IPv4 prefix. For learning purposes, I will lend the prefix 1.0.1.0/24 and 1.0.2.0/30 as a transfer network. Of coure, we peer with AS42 ;).

PE1

PE1 Configuration
[edit]
+ logical-systems {
+     AS42 {
+         interfaces {
+             lt-0/0/0 {
+                 unit 1 {
+                     description "Peering Link AS213928";
+                     encapsulation ethernet;
+                     peer-unit 0;
+                     family inet {
+                         address 1.0.2.2/30;
+                     }
+                 }
+             }
+             lo0 {
+                 unit 1 {
+                     family inet {
+                         address 42.42.42.42/32;
+                     }
+                 }
+             }
+         }
+         protocols {
+             bgp {
+                 group PEERING {
+                     type external;
+                     family inet {
+                         unicast;
+                     }
+                     export EXPORT_PING;
+                     neighbor 1.0.2.1 {
+                         local-address 1.0.2.2;
+                         peer-as 213928;
+                     }
+                 }
+             }
+         }
+         policy-options {
+             policy-statement EXPORT_PING {
+                 term 1 {
+                     from {
+                         route-filter 42.42.42.42/32 exact;
+                     }
+                     then accept;
+                 }
+             }
+         }
+         routing-options {
+             autonomous-system 42;
+         }
+     }
+ }
[edit interfaces]
+   lt-0/0/0 {
+       unit 0 {
+           description "Peering Link AS42";
+           encapsulation ethernet;
+           peer-unit 1;
+           family inet {
+               address 1.0.2.1/30;
+           }
+       }
+   }
[edit]
+  policy-options {
+      policy-statement EXPORT_AGGREGATE_ROUTE {
+          term 1 {
+              from {
+                  route-filter 1.0.1.0/24 exact;
+              }
+              then accept;
+          }
+          term 2 {
+              then reject;
+          }
+      }
+  }
+  routing-instances {
+      INTERNET {
+          instance-type vrf;
+          routing-options {
+              aggregate {
+                  route 1.0.1.0/24;
+              }
+          }
+          protocols {
+              bgp {
+                  group PEERING {
+                      type external;
+                      family inet {
+                          unicast;
+                      }
+                      neighbor 1.0.2.2 {
+                          local-address 1.0.2.1;
+                          export EXPORT_AGGREGATE_ROUTE;
+                          peer-as 42;
+                      }
+                  }
+              }
+          }
+          interface lt-0/0/0.0;
+          route-distinguisher 172.16.2.1:1000;
+          vrf-target target:213928L:1000;
+          vrf-table-label;
+      }
+  }
[edit routing-options]
+   autonomous-system 213928;
[edit protocols]
+   bgp {
+       group MESH {
+           type internal;
+           local-address 172.16.1.1;
+           family inet-vpn {
+               unicast;
+           }
+           neighbor 172.16.1.2;
+       }
+   }

This configuration might look complicated but actually it isn’t. We create a logical system called AS42, which has the interface lt-0/0/0.1 (which is linked to lt-0/0/0.0). Inside the LS, we have a BGP peering with AS213928 over the lt interface and announce the address of the lo0.1 interface.

Inside the main instance, we have the counterpart for the lt interface, a BGP session to PE2 as well as the VRF configuration, in which we peer with the AS42 inside the logical system. There are simple polices and an aggregate route.

PE2

PE2 Configuration
[edit interfaces]
+   xe-0/0/5 {
+       unit 0 {
+           description "Sample Customer";
+           family inet {
+               address 1.0.1.1/30;
+           }
+       }
+   }
[edit]
+  routing-instances {
+      INTERNET {
+          instance-type vrf;
+          interface xe-0/0/5.0;
+          route-distinguisher 172.16.2.2:1000;
+          vrf-target target:213928L:1000;
+          vrf-table-label;
+      }
+  }
[edit routing-options]
+   autonomous-system 213928;
[edit protocols]
+   bgp {
+       group MESH {
+           type internal;
+           local-address 172.16.1.2;
+           family inet-vpn {
+               unicast;
+           }
+           neighbor 172.16.1.1;
+       }
+   }

This configuration is simpler, as we only have the BGP session to PE1 and the VRF itself. For testing purposes, the xe-0/0/5 interface is connected to a VPC, which has the address 1.0.1.2.

Veryfiying the INTERNET VRF

Firstly, lets check some routing tables on the devices. On PE1, we have this

user@PE1.mpl> show route table INTERNET.inet.0

INTERNET.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.0.1.0/24         *[Aggregate/130] 00:06:00
                       Reject
1.0.1.0/30         *[BGP/170] 00:06:00, localpref 100, from 172.16.1.2
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.26 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.30 via xe-0/0/4.0, Push 16, Push 299792(top)
1.0.2.0/30         *[Direct/0] 00:08:32
                    >  via lt-0/0/0.0
1.0.2.1/32         *[Local/0] 00:08:32
                       Local via lt-0/0/0.0
42.42.42.42/32     *[BGP/170] 00:08:30, localpref 100
                      AS path: 42 I, validation-state: unverified
                    >  to 1.0.2.2 via lt-0/0/0.0

As you can see, there is the 1.0.1.0/24 aggregate route which we advertise to AS42 as well as the 1.0.1.0/30 network which is used on PE2 for the simulated customer. Other than that, there is really not that much going on other than the transfer network (1.0.2.0/30) and the prefix from AS42 (42.42.42.42).

On PE2, it looks quite similar:

user@PE2.mpl> show route table INTERNET.inet.0

INTERNET.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

1.0.1.0/24         *[BGP/170] 00:07:38, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
1.0.1.0/30         *[Direct/0] 00:07:38
                    >  via xe-0/0/5.0
1.0.1.1/32         *[Local/0] 00:07:38
                       Local via xe-0/0/5.0
1.0.2.0/30         *[BGP/170] 00:10:09, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
42.42.42.42/32     *[BGP/170] 00:10:07, localpref 100, from 172.16.1.1
                      AS path: 42 I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)

Only that the point of view is switched now. If we want to test the connectivity, we can ping the 42.42.42.42 from the customer VPC:

customer> ping 42.42.42.42 -c 5

84 bytes from 42.42.42.42 icmp_seq=1 ttl=60 time=4.461 ms
84 bytes from 42.42.42.42 icmp_seq=2 ttl=60 time=4.210 ms
84 bytes from 42.42.42.42 icmp_seq=3 ttl=60 time=5.842 ms
84 bytes from 42.42.42.42 icmp_seq=4 ttl=60 time=4.251 ms
84 bytes from 42.42.42.42 icmp_seq=5 ttl=60 time=4.086 ms

customer>

And as you can see, we can successfully ping the address.

Taking a look at the traffic path

In order to understand how we are going to extend the functionality with IPv6, we firstly need to really understand whats happening here. And what best as to play a wonderful round of “Be the Packet”. YAYYYY

To get things started, we look at the customer VPC. Here, everything is pretty simple. If we check the ip interface and routing configuration, we can see the following:

customer> show

NAME   IP/MASK              GATEWAY           MAC                LPORT  RHOST:PORT
custome1.0.1.2/30           1.0.1.1           00:50:79:66:68:00  20797  127.0.0.1:20798
       fe80::250:79ff:fe66:6800/64

We have the 1.0.1.2/30 address configured locally and use 1.0.1.1 as our default gateway, which is the interface address of PE2’s xe-0/0/5 interface:

user@PE2.mpl> show configuration interfaces xe-0/0/5
unit 0 {
    description "Sample Customer";
    family inet {
        address 1.0.1.1/30;
    }
}

This interface is configured inside the INTERNET VRF on PE2:

user@PE2.mpl> show configuration routing-instances INTERNET
instance-type vrf;
interface xe-0/0/5.0;
route-distinguisher 172.16.2.2:1000;
vrf-target target:213928L:1000;
vrf-table-label;

(Which is why we saw an entry for 1.0.1.0/30 in the routing table of the VRF INTERNET on PE2 locally connected)

But how do we travel to PE1 from now one? The routing table tells us everything we need to know:

user@PE2.mpl> show route table INTERNET.inet.0 42.42.42.42/32

INTERNET.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

42.42.42.42/32     *[BGP/170] 00:15:36, localpref 100, from 172.16.1.1
                      AS path: 42 I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)

As you can see, there is one route with two candidates, one of which is selected as the best path. If we look at the route, we will exit through interface xe-0/0/3, which really is P2. Additionally, we will push two MPLS labels, 16 and 299808 on top. How do we get those? Well first off, we need to know which label does what.

The 299808 label is our transport label. It is used to signal the next router in the chain how to proceed with this packet. This is one of the fundamental use cases for MPLS, defining LSPs by the use of labels. We can actually see, what P2 does with this label:

user@P2.mpl> show route label 299808

mpls.0: 15 destinations, 15 routes (15 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

299808             *[LDP/9] 00:39:54, metric 1
                       to 10.255.255.1 via xe-0/0/0.0, Swap 299776
                    >  to 10.255.255.17 via xe-0/0/2.0, Swap 299824

If the packet reaches P2, it looks up the label value and determines, that it needs to swap the label with 299824 and relay the packet out to xe-0/0/2 towards P3. On P3, we can do the same:

user@P3.mpl> show route label 299824

mpls.0: 15 destinations, 15 routes (15 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

299824             *[LDP/9] 00:41:06, metric 1
                    >  to 10.255.255.29 via xe-0/0/4.0, Pop
299824(S=0)        *[LDP/9] 00:41:06, metric 1
                    >  to 10.255.255.29 via xe-0/0/4.0, Pop

Here, the action is also quite clear: pop the label and relay out the xe-0/0/4 interface, which directly connects to PE1. Now PE1 receives this packet and does what exactly?

Do you remember the other label from earlier, label 16? This now comes into play. As we just popped the transport label at the penultimate pop (which is why we call this penultimate hop popping), only this label is left for PE1 to investigate. Let’s check, what it has to offer for it:

user@PE1.mpl> show route label 16

mpls.0: 14 destinations, 14 routes (14 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

16                 *[VPN/0] 00:33:07
                    >  via lsi.0 (INTERNET), Pop

So here, we also pop the label and relay it to lsi.0? What is this? This is a helper interface which is used to send the packet to the routing-instance, where a normal route lookup will be performed. This label only has meaning to PE1 and determines which service the packet belongs to, thus we call it the service label.

From now one, the packet will be forwarded by PE1 as the routing table tells it to, which is through the lt interface over to our logical system.

user@PE1.mpl> show route table INTERNET.inet.0 42.42.42.42/32

INTERNET.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

42.42.42.42/32     *[BGP/170] 00:25:09, localpref 100
                      AS path: 42 I, validation-state: unverified
                    >  to 1.0.2.2 via lt-0/0/0.0

So now we know what the labels do but we do not know, how we get a hold of all those labels. Let’s start with the transport labels. For this, we use our trusty old LDP, which automatically creates a full mesh of LSPs for our network. On PE2, our inet.3 (which is our MPLS LSP table) is packed with LSPs to all devices in our network:

user@PE2.mpl> show route table inet.3

inet.3: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

172.16.0.1/32      *[LDP/9] 00:48:28, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299792
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299792
172.16.0.2/32      *[LDP/9] 00:48:56, metric 1
                    >  to 10.255.255.37 via xe-0/0/3.0
172.16.0.3/32      *[LDP/9] 00:48:28, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299824
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299824
172.16.0.4/32      *[LDP/9] 00:48:28, metric 1
                    >  to 10.255.255.33 via xe-0/0/4.0
172.16.1.1/32      *[LDP/9] 00:48:28, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299808
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299808                 

And where does PE2 know which transport label to use? For this, our BGP session to PE1 comes in handy. Inside the BGP session, we use the inet-vpn unicast family, which lets both PE devices exchange inet-vpn routes. You can see those routes being received on either PE router:

user@PE2.mpl> show route table bgp.l3vpn

bgp.l3vpn.0: 3 destinations, 3 routes (3 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

172.16.2.1:1000:1.0.1.0/24
                   *[BGP/170] 00:26:38, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
172.16.2.1:1000:1.0.2.0/30
                   *[BGP/170] 00:29:09, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
172.16.2.1:1000:42.42.42.42/32
                   *[BGP/170] 00:29:07, localpref 100, from 172.16.1.1
                      AS path: 42 I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)

Behind these weird looking prefixes hide the routes which will later get installed in the INTERNET VRF routing table. If we take a closer look at the 172.16.2.1:1000:42.42.42.42/32 route, which we initially used to get to 42.42.42.42, we can see something (I shortened the output a little):

user@PE2.mpl> show route table bgp.l3vpn 42.42.42.42/32 extensive

bgp.l3vpn.0: 3 destinations, 3 routes (3 active, 0 holddown, 0 hidden)
172.16.2.1:1000:42.42.42.42/32 (1 entry, 0 announced)
        *BGP    Preference: 170/-101
                Route Distinguisher: 172.16.2.1:1000
...
                Thread: junos-main
                Indirect next hops: 1
                        Protocol next hop: 172.16.1.1 Metric: 1
                        Label operation: Push 16
                        Label TTL action: prop-ttl
...

Inside this overly long output, there hides an important field which is called the protocol next hop, 172.16.1.1 in this case. This tells PE2 that if you want to forward traffic for this prefix, it need to get to 172.16.1.1. And as we all learned, Junos always tries to resolve BGP routes in the inet.3 before looking into the inet.0. And as we saw earlier, we have an LSP in the inet.3 for 172.16.1.1. And there we have the transport label we need to use.

And how about the service label? This is a lot simpler. Each PE creates a list of service labels for all its services and through the magic of BGP, we also get to know which service label to use. If you look at the last output, right underneath the protocol next hop, there is a label operation. This instructs PE2 to also push label 16, but on the bottom of the label stack (so that we have the transport label first and the service label second).

Adapting to IPv6

Now you know, how a simple IPv4 INTERNET VRF looks like. But how do we extend this to be IPv6 capable? This should be simple, just add family inet6-vpn to the BGP session and expand the peering with AS42 to use IPv6 as well, right? Well, let’s check what happens.

Configuration

Adding IPv6 functionality to PE1
[edit logical-systems AS42 interfaces lt-0/0/0 unit 1]
+       family inet6 {
+           address 2000::1:0:2:2/126;
+       }
[edit logical-systems AS42 interfaces lo0 unit 1]
+       family inet6 {
+           address 2000::42/128;
+       }
[edit logical-systems AS42 protocols bgp]
      group PEERING { ... }
+     group PEERING_v6 {
+         type external;
+         family inet6 {
+             unicast;
+         }
+         export EXPORT_PING_v6;
+         neighbor 2000::1:0:2:1 {
+             local-address 2000::1:0:2:2;
+             peer-as 213928;
+         }
+     }
[edit logical-systems AS42 policy-options]
+    policy-statement EXPORT_PING_v6 {
+        term 1 {
+            from {
+                route-filter 2000::42/128 exact;
+            }
+            then accept;
+        }
+    }
[edit interfaces lt-0/0/0 unit 0]
+      family inet6 {
+          address 2000::1:0:2:1/126;
+      }
[edit policy-options]
+   policy-statement EXPORT_AGGREGATE_ROUTE_v6 {
+       term 1 {
+           from {
+               route-filter 2000::1:0:1:0/112 exact;
+           }
+           then accept;
+       }
+   }
[edit routing-instances INTERNET routing-options]
+     rib INTERNET.inet6.0 {
+         aggregate {
+             route 2000::1:0:1:0/112;
+         }
+     }
[edit routing-instances INTERNET protocols bgp]
       group PEERING { ... }
+      group PEERING_v6 {
+          type external;
+          family inet6 {
+              unicast;
+          }
+          neighbor 2000::1:0:2:2 {
+              local-address 2000::1:0:2:1;
+              export EXPORT_AGGREGATE_ROUTE_v6;
+              peer-as 42;
+          }
+      }
[edit protocols bgp group MESH]
+      family inet6-vpn {
+          unicast;
+      }

So what have we changed? We added some IPv6 addresses to the lt and lo0.1 interface as well as configuring some export policies and adding an additional IPv6 based peering between AS42 and AS213928. But most importantly, our MESH BGP group now features the inet6-vpn address family.

Adding IPv6 functionality to PE2
[edit interfaces xe-0/0/5 unit 0]
+      family inet6 {
+          address 2000::1:0:1:1/126;
+      }
[edit protocols bgp group MESH]
+      family inet6-vpn {
+          unicast;
+      }

Here, we just added the inet6-vpn capability to the BGP session as well as adding an IPv6 network to our customer interface.

Testing the IPv6 configuration

Alright, we should be able to ping 2000::42 from the customer, right?

customer> ping 2000::42

host (2000::42) not reachable

Huh, this looks odd. Let’s check whats going wrong here. We may start on PE2, which is the first hop after the customer VPC. Let’s check our routing table for the VRF:

user@PE2.mpl> show route table INTERNET.inet6.0

INTERNET.inet6.0: 6 destinations, 6 routes (4 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both

2000::1:0:1:0/126  *[Direct/0] 00:04:46
                    >  via xe-0/0/5.0
2000::1:0:1:1/128  *[Local/0] 00:04:46
                       Local via xe-0/0/5.0
fe80::e9d:dff:fe72:7/128
                   *[Local/0] 00:04:46
                       Local via xe-0/0/5.0
ff02::2/128        *[INET6/0] 01:01:30
                       MultiRecv

It looks like there is no route for 2000::42. Let’s check on PE1, maybe our peering does not work:

user@PE1.mpl> show route table INTERNET.inet6.0

INTERNET.inet6.0: 7 destinations, 7 routes (5 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both

2000::42/128       *[BGP/170] 00:06:36, localpref 100
                      AS path: 42 I, validation-state: unverified
                    >  to 2000::1:0:2:2 via lt-0/0/0.0
2000::1:0:2:0/126  *[Direct/0] 00:06:39
                    >  via lt-0/0/0.0
2000::1:0:2:1/128  *[Local/0] 00:06:39
                       Local via lt-0/0/0.0
fe80::e8e:9a00:4f:2/128
                   *[Local/0] 00:06:39
                       Local via lt-0/0/0.0
ff02::2/128        *[INET6/0] 01:02:37
                       MultiRecv

This is odd, we have a route for 2000::42 here. But wait, there seems to be some hidden routes. Why are they hidden?

user@PE2.mpl> show route table INTERNET.inet6.0 hidden

INTERNET.inet6.0: 6 destinations, 6 routes (4 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both

2000::42/128        [BGP/170] 00:06:14, localpref 100, from 172.16.1.1
                      AS path: 42 I, validation-state: unverified
                       Unusable
2000::1:0:2:0/126   [BGP/170] 00:06:14, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                       Unusable

These routes seem unusable. But what is the reason for this?

user@PE2.mpl> show route table INTERNET.inet6.0 hidden extensive

INTERNET.inet6.0: 6 destinations, 6 routes (4 active, 0 holddown, 2 hidden)
2000::42/128 (1 entry, 0 announced)
         BGP    Preference: 170/-101
                Route Distinguisher: 172.16.2.1:1000
                Next hop type: Unusable, Next hop index: 0
                Address: 0x76a5324
                Next-hop reference count: 4, key opaque handle: 0x0, non-key opaque handle: 0x0
                Source: 172.16.1.1
                State: <Secondary Hidden Int Ext Changed ProtectionCand>
                Local AS: 213928 Peer AS: 213928
                Age: 7:16
                Validation State: unverified
                Task: BGP_213928.172.16.1.1
                AS path: 42 I
                Communities: target:213928L:1000
                Import Accepted
                VPN Label: 16
                Localpref: 100
                Router ID: 172.16.1.1
                Primary Routing Table: bgp.l3vpn-inet6.0
                Thread: junos-main
                Indirect next hops: 1
                        Protocol next hop: ::ffff:172.16.1.1
                        Label operation: Push 16
                        Label TTL action: prop-ttl
                        Load balance label: Label 16: None;
                        Indirect next hop: 0x0 - INH Session ID: 0

2000::1:0:2:0/126 (1 entry, 0 announced)
         BGP    Preference: 170/-101
                Route Distinguisher: 172.16.2.1:1000
                Next hop type: Unusable, Next hop index: 0
                Address: 0x76a5324
                Next-hop reference count: 4, key opaque handle: 0x0, non-key opaque handle: 0x0
                Source: 172.16.1.1
                State: <Secondary Hidden Int Ext Changed ProtectionCand>
                Local AS: 213928 Peer AS: 213928
                Age: 7:16
                Validation State: unverified
                Task: BGP_213928.172.16.1.1
                AS path: I
                Communities: target:213928L:1000
                Import Accepted
                VPN Label: 16
                Localpref: 100
                Router ID: 172.16.1.1
                Primary Routing Table: bgp.l3vpn-inet6.0
                Thread: junos-main
                Indirect next hops: 1
                        Protocol next hop: ::ffff:172.16.1.1
                        Label operation: Push 16
                        Label TTL action: prop-ttl
                        Load balance label: Label 16: None;
                        Indirect next hop: 0x0 - INH Session ID: 0

Oh, a classic, the next hop is unusable. What next hop address does it expect? ::ffff:172.16.1.1? This does not look like it is correct. Or is it?

Let’s clear some things up. First off, this prefix looks so weird because our BGP mesh session between PE1 and PE2 is only IPv4 based, but the addresses are IPv6. For this reason, Junos creates these weire IPv4 to IPv6 mappings. But why doesn’t it install these prefixes? As you already know, BGP tries using the inet.3 table to resolve an LSP. If unavailable, it uses the inet.0. For inet6-vpn routes, this is the same, with a small difference. It checks the inet6.3 table for the LSP and then inet6.0. How do these tables look like?

user@PE2.mpl> show route table inet6.3

user@PE2.mpl>

Currently, it looks like it does not exist. And the inet6.0?

user@PE2.mpl> show route table inet6.0

inet6.0: 9 destinations, 9 routes (9 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

2a01:beef::34/127  *[Direct/0] 12:02:14
                    >  via xe-0/0/4.0
2a01:beef::34/128  *[Local/0] 12:02:14
                       Local via xe-0/0/4.0
2a01:beef::38/127  *[Direct/0] 12:02:14
                    >  via xe-0/0/3.0
2a01:beef::38/128  *[Local/0] 12:02:14
                       Local via xe-0/0/3.0
2a01:beef:b::2/128 *[Direct/0] 12:02:25
                    >  via lo0.0
fe80::e9a:6a0f:fcfa:0/128
                   *[Direct/0] 12:02:25
                    >  via lo0.0
fe80::e9d:dff:fe72:5/128
                   *[Local/0] 12:02:14
                       Local via xe-0/0/3.0
fe80::e9d:dff:fe72:6/128
                   *[Local/0] 12:02:14
                       Local via xe-0/0/4.0
ff02::2/128        *[INET6/0] 12:15:52
                       MultiRecv

Well, there are some routes but none looks like the protocol next hop of the BGP prefix.

And this is perfectly normal, as we did not tell our router to create LSPs in this format (we only configured LDP as quite a lot of LSPs are using). In order to have an LSP table for inet6, we need to use a v6 capable label distribution protocol. There is something like LDPv6 in existence, however this is quite new and only a handful of manufacturers implemented it (Juniper is one of them). But there must be a simpler way. And there is, it is called ipv6-tunneling.

This feature solves our problem. We can simply activate it like this:

[edit]
user@PE2.mpl# set protocols mpls ipv6-tunneling

And after committing, we now have an inet6.3 table:

user@PE2.mpl> show route table inet6.3

inet6.3: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

::ffff:172.16.0.1/128
                   *[LDP/9] 00:00:06, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299792
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299792
::ffff:172.16.0.2/128
                   *[LDP/9] 00:00:06, metric 1
                    >  to 10.255.255.37 via xe-0/0/3.0
::ffff:172.16.0.3/128
                   *[LDP/9] 00:00:06, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299824
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299824
::ffff:172.16.0.4/128
                   *[LDP/9] 00:00:06, metric 1
                    >  to 10.255.255.33 via xe-0/0/4.0
::ffff:172.16.1.1/128
                   *[LDP/9] 00:00:06, metric 1
                       to 10.255.255.37 via xe-0/0/3.0, Push 299808
                    >  to 10.255.255.33 via xe-0/0/4.0, Push 299808

How does this feature work? It takes the inet.3 table and maps all LSPs to a IPv6 format, which you can see with the ::ffff: prefix. Now, the BGP prefixes from earlier have an LSP in the inet6.3 table and can be installed into the INTERNET.inet6.0 table:

user@PE2.mpl> show route table INTERNET.inet6.0

INTERNET.inet6.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

2000::42/128       *[BGP/170] 00:01:42, localpref 100, from 172.16.1.1
                      AS path: 42 I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
2000::1:0:1:0/126  *[Direct/0] 00:12:53
                    >  via xe-0/0/5.0
2000::1:0:1:1/128  *[Local/0] 00:12:53
                       Local via xe-0/0/5.0
2000::1:0:2:0/126  *[BGP/170] 00:01:42, localpref 100, from 172.16.1.1
                      AS path: I, validation-state: unverified
                    >  to 10.255.255.37 via xe-0/0/3.0, Push 16, Push 299808(top)
                       to 10.255.255.33 via xe-0/0/4.0, Push 16, Push 299808(top)
fe80::e9d:dff:fe72:7/128
                   *[Local/0] 00:12:53
                       Local via xe-0/0/5.0
ff02::2/128        *[INET6/0] 01:09:37
                       MultiRecv

This feature only works locally, so we have to activate it on all Ingress LSRs. As we use the same LSP as for IPv4, none of the transit devices need to have this feature activated, as they are not interested in the payload but only on the MPLS labels. For this reason, the actual traffic path will be the exact same as for IPv4 traffic. So after we’ve activated the feature on PE1 as well, our ping should now work perfectly fine:

customer> ping 2000::42 -c 5

2000::42 icmp6_seq=1 ttl=64 time=0.953 ms
2000::42 icmp6_seq=2 ttl=64 time=0.789 ms
2000::42 icmp6_seq=3 ttl=64 time=0.686 ms
2000::42 icmp6_seq=4 ttl=64 time=0.692 ms
2000::42 icmp6_seq=5 ttl=64 time=0.654 ms

customer>

So what did we learn today? We’ve learned how to setup a simple INTERNET VRF using MPLS, BGP, LDP and OSPF as well as extending its capabilites to IPv6 using ipv6-tunneling. I hope you enjoyed this post and learned something new!

Leave a Reply

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