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.

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.

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.

All routers:

# R1 — set LSR-ID to loopback, enable LDP on core interface
/mpls ldp set lsr-id=1.1.1.1 enabled=yes
/mpls ldp interface add interface=ether1
# R2
/mpls ldp set lsr-id=2.2.2.2 enabled=yes
/mpls ldp interface add interface=ether1
/mpls ldp interface add interface=ether2
# R3
/mpls ldp set lsr-id=3.3.3.3 enabled=yes
/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 state=established and lists the remote LSR-ID, local and remote label spaces, and session uptime. If only state=connecting is shown, the TCP session has not formed — check IGP reachability to the remote LSR-ID.

After sessions form, routers exchange label bindings for all IGP prefixes:

/mpls ldp binding print detail

Each entry shows:

  • prefix — the destination prefix
  • nexthop — the LDP next-hop
  • local-label — the label this router advertises to others for this prefix
  • remote-label — the label received from the upstream LDP neighbor

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 — show binding for R3 loopback
/mpls ldp binding print where prefix=3.3.3.3/32
# Confirm LFIB has forwarding entry
/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
# Binding for 3.3.3.3/32 should show remote-label from R2
/mpls ldp binding print where prefix=3.3.3.3/32
# 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
# Bindings for both 1.1.1.1/32 and 3.3.3.3/32
/mpls ldp binding 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
# Bindings — local-label for 3.3.3.3/32 should be 3 (implicit-null, triggering PHP at R2)
/mpls ldp binding print where prefix=3.3.3.3/32

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 address=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 address=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
# Check binding table — if empty, LDP session may be down
/mpls ldp binding print
# Verify OSPF is advertising all loopbacks and transport subnets
/routing ospf neighbor print
/ip route print where protocol=ospf
# 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 binding table after session upLDP enabled=no globally/mpls ldp set enabled=yes
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]

Global LDP settings.

ParameterDescription
enabledEnable/disable LDP globally (yes/no)
lsr-idRouter LSR-ID, used as LDP transport address — typically loopback /32
transport-addressesOverride transport address per address-family
/mpls ldp set lsr-id=1.1.1.1 enabled=yes
/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 address= for static/targeted neighbors.

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

Label binding table — shows local and remote labels for each prefix.

/mpls ldp binding print detail
/mpls ldp binding print where prefix=10.0.0.0/24

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