LDP Transport Address

Today in an instructor-led SPCOR class, a student raised their hand, claiming that their lab wasn’t working. The objective of the first part of the lab was to configure LDP between two connected routers, PE1 and P1. OSPF was already pre-configured in everyone’s lab. P1 was already configured for LDP, so we just had to configure PE1.

Step 1 was to configure the following on PE1:

#PE1

mpls ldp
 router-id 10.1.1.1
 int gi0/0/0/0          ! Gi0/0/0/0 connects to P1
!
commit

Step 2 was to verify the LDP neighborship, but the student’s neighborship would not come up. Upon commit, you were supposed to see the LDP neighborship between PE1 and P1 go up.

The student and instructor began troubleshooting the lab itself, speculating that there was some bug in the pre-configured lab. After spending several minutes verifying that yes, LDP was running on P1, and yes, OSPF was configured correctly on PE1 and P1, they finally discovered the issue. The student misconfigured the router-id as 10.0.1.1, which was not an IP on PE1. Lo0 on PE1 was 10.1.1.1. This completely prevented the neighborship from coming up, and in this article we’ll explore why.

The importance of the LDP RID

In routing protocols such as OSPF and BGP, the router ID is a 32 bit integer. Although the RID takes the form of an IP address, it does not necessarily need to be a reachable IP on the device. For convenience it usually is, but it does not have to be.

It’s useful to think of the RID as a string. The RID is just a “name” or string that describes each router in the topology. Neither OSPF or BGP actually use the RID for anything to do with IP forwarding. The RID isn’t used as a next-hop for example. The protocols just use the RID to identify other routers in the network. For OSPF, nodes in the graph are represented by their RID, but it has nothing to do with IP forwarding. IP addresses are “hung” off the RID in the OSPF graph to enable IP routing.

If you weren’t familiar with LDP, you might think that LDP operates in exactly the same way. But LDP, by default, actually needs the RID to be a reachable IP on the router! So not only does the LDP RID need to be an up/up IP, but the neighbor router needs to be able to reach that IP. (Usually by learning a path to the IP via the IGP). This is because LDP uses the RID as the transport addresses by default. This is the address that the neighbor router will use when trying to establish an LDP session. Let’s see how this works in the lab.

Lab

First let’s examine the LDP neighborship process using two XRv routers connected back-to-back on Gi0/0/0/0.

#XR1
int lo0
 ip add 1.1.1.1/32
!
int lo1
 ip add 1.1.1.2/32
!
int gi0/0/0/0
 ip add 10.1.2.1/24
 no shut
!
router ospf 1
 area 0
  int gi0/0/0/0
   network point-to-point
  int lo0
  int lo1

#XR2
int lo0
 ip add 2.2.2.2/32
!
int lo1
 ip add 2.2.2.3/32
!
int gi0/0/0/0
 ip add 10.1.2.2/24
 no shut
!
router ospf 1
 area 0
  int gi0/0/0/0
   network point-to-point
  int lo0
  int lo1

Let’s form a basic LDP neighborship:

#XR1, XR2
mpls ldp
 int gi0/0/0/0

First, the routers multicast LDP Hellos to UDP/224.0.0.2 in order to discover each other. Notice that the RID for XR1 is 1.1.1.1 and there is a Transport Address listed in the Hello message, which is also 1.1.1.1.

If you’re not used to IOS XR, you might be surprised that 1.1.1.1 is the RID and not 1.1.1.2. Isn’t it usually the highest loopback IP address that is used for the RID? Lo1 (1.1.1.2) is higher than Lo0 (1.1.1.1). On IOS XR the automatic RID selection process is a bit different than IOS XE. The RID is decided as such:

  1. The IP address of the lowest numerical loopback. (Lo0 is lower than Lo1).

  2. If no loopback is present, a value of 0.0.0.0 is used. (Which makes neighborship impossible).

LDP only uses UDP to dynamically discover neighbors and maintain neighborships via Hellos. Once a neighbor is discovered, a TCP/646 connection is made using the neighbor’s transport address. By default, the transport address is the RID, which explains why the student’s lab wasn’t working when they misconfigured the RID! The other neighbor needed to open a TCP connection to 10.0.1.1, but it did not have a route to this IP.

Notice that in our lab, the TCP connection uses 1.1.1.1 and 2.2.2.2, which is each router’s Lo0 address. The TCP connection is used to actually exchange the label advertisements. (Just to note, LDP’s use of TCP enables the ability to form targeted LDP sessions which are multihop, similar to BGP. Targeted LDP sessions are used for LDP session protection and L2VPN using Martini circuits, also called xconnects or psuedowires).

We have the ability to manually configure the transport address. What if we want to use Lo0 as the RID, but Lo1 as the transport address? Let’s try it out:

#XR1
mpls ldp 
 address-family ipv4
  discovery transport-address 1.1.1.2

#XR2
mpls ldp 
 address-family ipv4
  discovery transport-address 2.2.2.3

Remember, by default our RID will be the lowest loopback IP, which in our case is Lo0, so we can leave the RID unspecified in the configuration. The TCP session is closed, and then restarted automatically, using the new transport addresses:

What happens if we leave the transport-address statically configured, but make the RID a non-reachable IP on XR1? Just for fun let’s use 10.0.1.1, which was the mistake made in the lab today. 10.0.1.1 is also unreachable in this lab.

#XR1
mpls ldp
 router-id 10.0.1.1

The hellos from XR1 list the new (unreachable) RID but still the same transport-address that we manually set earlier:

XR1 sends a Notification LDP message and then restarts the TCP connection. This is disruptive, so you wouldn’t want to change the RID or transport address in production.

Even though the RID (10.0.1.1) is not a reachable IP, XR2 is able to form a neighborship with 10.0.1.1 because we manually specified the transport address as 1.1.1.2, which XR2 can reach and form a TCP connection with.

RP/0/0/CPU0:XR2#show mpls ldp nei br
Wed Jul 20 22:46:42.434 UTC

Peer               GR  NSR  Up Time     Discovery   Addresses     Labels    
                                        ipv4  ipv6  ipv4  ipv6  ipv4   ipv6 
-----------------  --  ---  ----------  ----------  ----------  ------------
10.0.1.1:0         N   N    00:02:44    1     0     3     0     5      0

If we did not have the transport address manually specified, the neighborship would fail, just as it did for the student today.

By the way, what happens to the TCP connection if no label messages are exchanged for an extended period of time? TCP keepalives are used to keep the connection up. The UDP Hellos continue to detect the neighbor reachability, the same way Hellos are used by OSPF. Note that the UDP Hellos use the IPs of the physical interfaces themselves (10.1.2.0/24) so we didn’t have to worry about that in our lab.

Conclusion

We’ve learned that the RID for LDP needs to be a reachable IP on the router by default. The reason for this is that if the transport address is not manually specified, the RID is also used as the transport address.

We also saw that it is possible to manually specify a transport address, and then use an unreachable RID. The LDP RID is truly just a string, the same way a RID is used in OSPF and BGP. However, because the RID is by default the transport address, we can run into the issue that the student had in the lab today.

Additional Information

While coming across this issue again, I noticed something which is useful when troubleshooting this issue. When two routers have discovered each other using LDP discovery messages, but cannot route to each other’s loopback, you will see the following output in show mpls ldp discovery:

R1#show mpls ldp discovery 
 Local LDP Identifier:
    1.1.1.1:0
    Discovery Sources:
    Interfaces:
        GigabitEthernet1 (ldp): xmit/recv
            

Above, R1 discovered R2 (2.2.2.2:0) but has no route to R2’s loopback. The LDP session is not up.

If R1 could not discover R2 at all (for example an inbound UDP/646 ACL was configured), we would not see R2’s LDP RID in that output.

ip access-list extended BLOCK_LDP_DISCOVERY
 10 deny udp any any eq 646
 20 permit ip any any
!
int Gi1
 ip access-gorup BLOCK_LDP_DISCOVERY in


R1#show mpls ldp discovery 
 Local LDP Identifier:
    1.1.1.1:0
    Discovery Sources:
    Interfaces:
        GigabitEthernet1 (ldp): xmit

If R2’s RID is reachable, then you see the following output with this show command:

R1#show mpls ldp discovery 
 Local LDP Identifier:
    1.1.1.1:0
    Discovery Sources:
    Interfaces:
        GigabitEthernet1 (ldp): xmit/recv
            LDP Id: 2.2.2.2:0
  • The only difference compared to when the transport address is not reachable, is the phrase no route next to the LDP ID

Last updated