Skip to content

MPLS and LDP: Label Distribution and Label Switching Paths

MPLS and LDP: Label Distribution and Label Switching Paths

Section titled “MPLS and LDP: Label Distribution and Label Switching Paths”

This guide covers RouterOS 7 MPLS fundamentals and the Label Distribution Protocol (LDP): enabling MPLS forwarding on interfaces, configuring LDP for automatic label exchange, verifying label-switched paths (LSPs), and reading the Label Forwarding Information Base (LFIB).

MPLS separates the IP routing decision from the per-hop forwarding action. Once a packet enters an MPLS domain, routers forward it by swapping short fixed-length labels rather than performing a full IP lookup at every hop. LDP automates the process of distributing those labels between routers so that end-to-end LSPs form automatically from the IGP routing table.

MPLS LDP Topology — LER Ingress, LSR Transit, LER Egress with label distribution paths MPLS LDP Topology — LER Ingress, LSR Transit, LER Egress with label distribution paths

Every router in an MPLS domain performs one of three label operations on each packet:

OperationRouter RoleAction
PushIngress LERAttach an MPLS label to an incoming IP packet, creating an MPLS packet.
SwapTransit LSRReplace the top label with a new label and forward to the next hop.
PopEgress LERRemove the MPLS label and deliver the original IP packet.
  • LER (Label Edge Router) — sits at the boundary between the IP and MPLS domains. The ingress LER pushes the first label; the egress LER pops the final label.
  • LSR (Label Switch Router) — a core router that only swaps labels. It never examines the inner IP header.

By default, RouterOS uses PHP: the router before the egress LER pops the label, forwarding a plain IP packet to the egress. This removes one lookup at the egress router. The label value 3 (implicit null) signals PHP to the penultimate hop.

LDP automates LSP creation from the IGP topology:

  1. Hello discovery — LDP sends UDP hellos to the multicast address 224.0.0.202 on port 646 to discover directly connected LDP neighbors.
  2. Session establishment — neighbors negotiate a TCP session on port 646 using their LSR-IDs (typically loopback addresses) as transport endpoints.
  3. Label advertisement — each router assigns a local label to every IGP prefix it knows and advertises the binding to all LDP neighbors. Neighbors chain these bindings into end-to-end LSPs.

MPLS Label Switching Packet Flow — push at ingress LER, swap at transit LSR, pop at egress LER MPLS Label Switching Packet Flow — push at ingress LER, swap at transit LSR, pop at egress LER

  • RouterOS 7.x (MPLS features are available by default; verify with /system/package/print)
  • An IGP (OSPF or IS-IS) advertising loopback /32 addresses and transport subnets between all MPLS routers
  • A stable loopback interface on each router to serve as the LDP LSR-ID and OSPF router-id
  • IP connectivity between all LDP transport addresses before enabling LDP

The examples below use a three-router linear topology matching the diagram above:

RouterRoleLoopbackLink to next-hop
R1Ingress LER1.1.1.1/32ether1 — 10.0.0.0/30 → R2
R2Transit LSR2.2.2.2/32ether1 — 10.0.0.0/30 → R1, ether2 — 10.0.0.4/30 → R3
R3Egress LER3.3.3.3/32ether1 — 10.0.0.4/30 → R2

Step 1: Configure Loopback and IGP Underlay

Section titled “Step 1: Configure Loopback and IGP Underlay”

Each router needs a loopback with a /32 address and an IGP advertising it. OSPF is used here; IS-IS works equally well. If your lab uses different physical port numbers, substitute your actual core-facing interfaces in the commands below.

R1:

# Create loopback bridge
/interface bridge add name=loopback
# Assign LSR-ID address
/ip address add address=1.1.1.1/32 interface=loopback
# Configure OSPF with router-id matching the loopback
/routing ospf instance add name=default router-id=1.1.1.1
/routing ospf area add name=backbone area-id=0.0.0.0 instance=default
/routing ospf interface-template add area=backbone interfaces=loopback passive
/routing ospf interface-template add area=backbone interfaces=ether1

R2:

/interface bridge add name=loopback
/ip address add address=2.2.2.2/32 interface=loopback
/routing ospf instance add name=default router-id=2.2.2.2
/routing ospf area add name=backbone area-id=0.0.0.0 instance=default
/routing ospf interface-template add area=backbone interfaces=loopback passive
/routing ospf interface-template add area=backbone interfaces=ether1,ether2

R3:

/interface bridge add name=loopback
/ip address add address=3.3.3.3/32 interface=loopback
/routing ospf instance add name=default router-id=3.3.3.3
/routing ospf area add name=backbone area-id=0.0.0.0 instance=default
/routing ospf interface-template add area=backbone interfaces=loopback passive
/routing ospf interface-template add area=backbone interfaces=ether1

Verify IGP reachability before proceeding:

# On R1 — should resolve to R3 loopback via OSPF
/ip route print where dst-address=3.3.3.3/32
/ping 3.3.3.3 count=3

MPLS must be enabled on the physical interfaces that carry labeled traffic. Do not enable MPLS on the loopback itself. On staging CHR, that means using the non-management lab interfaces rather than ether1.

All routers — enable MPLS on core-facing interfaces:

# R1
/mpls interface add interface=ether1
# R2
/mpls interface add interface=ether1
/mpls interface add interface=ether2
# R3
/mpls interface add interface=ether1

Verify:

/mpls interface print

Expected output shows each interface with MPLS flag set.

LDP requires a global LSR-ID (the loopback address) and per-interface enabling. LDP uses the LSR-ID as the transport address for TCP sessions, so it must match an address reachable via IGP. As with MPLS, replace the example interface names with your actual core-facing ports when ether1 is reserved for management.

All routers:

# R1 — create LDP instance with LSR-ID and transport address
/mpls ldp add afi=ip lsr-id=1.1.1.1 transport-addresses=1.1.1.1
/mpls ldp interface add interface=ether1
# R2
/mpls ldp add afi=ip lsr-id=2.2.2.2 transport-addresses=2.2.2.2
/mpls ldp interface add interface=ether1
/mpls ldp interface add interface=ether2
# R3
/mpls ldp add afi=ip lsr-id=3.3.3.3 transport-addresses=3.3.3.3
/mpls ldp interface add interface=ether1

LDP discovery starts within seconds of enabling LDP interfaces. Check for established sessions:

/mpls ldp neighbor print detail

A healthy neighbor entry shows the O (OPERATIONAL) flag and lists the remote transport address, local transport, peer, and addresses. If the O flag is absent (only C = active-connect or W = passive-wait), the TCP session has not formed — check IGP reachability to the remote LSR-ID.

Read the Label Forwarding Information Base (LFIB)

Section titled “Read the Label Forwarding Information Base (LFIB)”

The LFIB is the active forwarding table used for labeled packet switching:

/mpls forwarding-table print detail

Key fields:

FieldMeaning
in-labelLabel value matched on incoming packets
out-labelLabel pushed on outgoing packets (3 = PHP/implicit-null, 0 = explicit-null)
interfaceOutgoing interface
nexthopNext-hop IP address
operationswap, pop, or push

From the ingress LER, confirm a full LSP exists to the egress loopback:

# On R1 — confirm LFIB has a forwarding entry for R3 loopback
/mpls forwarding-table print where nexthop~"10.0.0"

If R2 is performing PHP, traffic from R1 will carry a label all the way to R2, where R2 pops it and sends a plain IP packet to R3. This is correct and expected behaviour.

/mpls settings print

Review propagate-ttl (whether IP TTL is decremented through the MPLS domain) and allow-fast-path (hardware/fast-path label switching).

Example 1: Full LSP Verification on a Three-Router Chain

Section titled “Example 1: Full LSP Verification on a Three-Router Chain”

After completing the configuration above, run these checks on each router:

R1 (Ingress LER):

# LDP neighbor to R2 should be established
/mpls ldp neighbor print
# LFIB should push R2's advertised label for traffic to 3.3.3.3/32
/mpls forwarding-table print detail

R2 (Transit LSR):

# Two neighbors: R1 and R3
/mpls ldp neighbor print
# LFIB shows swap or pop operations for each prefix
/mpls forwarding-table print detail

R3 (Egress LER):

# LDP neighbor to R2
/mpls ldp neighbor print
# LFIB — 3.3.3.3/32 should show PHP (label 3/implicit-null) triggering pop at R2
/mpls forwarding-table print detail

For applications like VPLS that require LDP sessions between non-adjacent routers, use targeted (unicast) hellos:

# On R1 — establish targeted LDP session to R3 loopback
/mpls ldp neighbor add transport=3.3.3.3

Targeted sessions use the same TCP port 646 but send unicast hellos instead of multicast. Verify with:

/mpls ldp neighbor print detail where transport=3.3.3.3
# 1. Verify MPLS is enabled on the interface
/mpls interface print detail
# 2. Verify LDP is enabled on the interface
/mpls ldp interface print detail
# 3. Check LDP global settings — lsr-id must be set
/mpls ldp print
# 4. Confirm IGP reachability to the remote LSR-ID
/ip route print where dst-address=<remote-lsr-id>/32
/ping <remote-lsr-id>

If /ping to the remote LSR-ID fails, fix the IGP underlay first. LDP TCP sessions cannot establish without routable transport addresses.

# Confirm session is established (not just discovered)
/mpls ldp neighbor print detail
# Verify OSPF is advertising all loopbacks and transport subnets
/routing ospf neighbor print
/ip route print where protocol=ospf
# Check LFIB — if empty, LDP session may be down or no IGP routes are present
/mpls forwarding-table print detail
# Confirm LFIB has entries for destination prefixes
/mpls forwarding-table print detail
# Check if fast-path is enabled (hardware switching)
/mpls settings print
# Trace label path
/tool traceroute <destination> use-dns=no
SymptomLikely CauseResolution
state=connecting in neighbor tableNo IP route to remote LSR-IDFix IGP; ensure loopbacks are advertised
Empty LFIB after session upNo LDP instance configured/mpls ldp add afi=ip lsr-id=<id> transport-addresses=<id>
LFIB missing entriesMPLS not enabled on interface/mpls interface add interface=<iface>
PHP not occurring at penultimate hopRemote router not advertising implicit-nullCheck egress router LDP binding for label=3 on its own prefix
Labels assigned but traffic dropsMTU too small for MPLS overheadAdd 4 bytes per label to interface MTU; check /mpls settings

Enables MPLS forwarding on a physical interface.

ParameterDescription
interfaceInterface name
/mpls interface add interface=ether1
/mpls interface print detail
/mpls interface remove [find interface=ether1]

LDP instance configuration. LDP is enabled by creating an instance (one per address-family/VRF). There is no global on/off toggle — the instance existing is what enables LDP.

ParameterDescription
afiAddress family (ip for IPv4)
lsr-idRouter LSR-ID, used as LDP router identifier — typically loopback /32
transport-addressesTCP session endpoint address — typically the same loopback /32
/mpls ldp add afi=ip lsr-id=1.1.1.1 transport-addresses=1.1.1.1
/mpls ldp print

Enables LDP on a specific interface for neighbor discovery.

/mpls ldp interface add interface=ether1
/mpls ldp interface print detail

View discovered and established LDP neighbors. Use add transport= to configure a static targeted neighbor.

/mpls ldp neighbor print detail
/mpls ldp neighbor add transport=3.3.3.3

Active LFIB — the table used for label-based packet forwarding decisions.

/mpls forwarding-table print detail
/mpls forwarding-table print where in-label=100

Global MPLS behaviour flags.

/mpls settings print
/mpls settings set propagate-ttl=yes
  • RFC 5036 — LDP Specification (core protocol)
  • RFC 3031 — MPLS Architecture
  • RFC 3032 — MPLS Label Stack Encoding
  • RFC 3443 — TTL Processing in Multi-Protocol Label Switching (MPLS) Networks