network/mikrotik-tool/mpls.md
2026-05-08 17:47:42 -05:00

7.4 KiB
Raw Blame History

MPLS / LDP enablement: verona ↔ climax ↔ core

Goal: bring up MPLS forwarding with LDP across the veronaclimaxcore spine on RouterOS 7, leaving the rest of the network untouched. Once these three are running labeled forwarding, expanding to other PoPs is incremental (add the LDP instance + interface on each new router).

Topology being labeled

verona (10.254.254.101)
  └── ether3-climax-11ghz  10.250.1.25/29 ──┐
                                            │  10.250.1.24/29 (AF11 backhaul)
  ┌── ether6-verona-11ghz  10.250.1.30/29 ──┘
climax (10.254.254.102)
  └── ether4-380-airfiber24 10.250.1.94/29 ──┐
                                             │  10.250.1.88/29 (AF24 backhaul)
  ┌── ether5-climax          10.250.1.89/29 ─┘
core (10.254.254.253)

OSPFv2 (backbone-v2, area 0) already redistributes connected, so all three loopbacks are reachable. That is the IGP we attach LDP to. Nothing else changes.

RouterOS versions in play: verona 7.20.8, climax 7.22, core 7.20.6 — all include MPLS in the system package, no extra .npk to install.

Pre-flight (run on each of the three before configuring)

# OSPF must be up and loopbacks reachable end-to-end.
/routing ospf neighbor print
/ip route print where dst-address~"10.254.254.10[12]/32" or dst-address~"10.254.254.253/32"

# Confirm the underlay MTU on the AF11 / AF24 ports — MPLS adds 4 bytes per
# label, so we want headroom. Check both physical (l2mtu) and IP MTU:
/interface print detail where name~"ether3-climax-11ghz|ether6-verona-11ghz|ether4-380-airfiber|ether5-climax"

Expected: l2mtu ≥ 1600 on the AF radios (default on CCR ports). If anything is at 1500 we'll bump mpls-mtu to 1500 explicitly so we never generate a 1504-byte frame the radio drops.

Step 1 — verona (10.254.254.101)

# LDP instance, lsr-id and transport address pinned to the loopback.
/mpls ldp
add disabled=no lsr-id=10.254.254.101 transport-addresses=10.254.254.101 vrf=main

# Enable LDP discovery on the climax-facing link only.
/mpls ldp interface
add interface=ether3-climax-11ghz

# Pin the MPLS MTU explicitly. mpls-mtu is the cap on the *labeled* frame,
# so a 1500-byte IP payload + 4-byte label = 1504 needs at least 1508 to
# pass; 1508 also leaves room for one extra stacked label (VPN/FRR/etc.).
/mpls interface
add interface=ether3-climax-11ghz mpls-mtu=1508

Step 2 — climax (10.254.254.102)

/mpls ldp
add disabled=no lsr-id=10.254.254.102 transport-addresses=10.254.254.102 vrf=main

/mpls ldp interface
add interface=ether6-verona-11ghz
add interface=ether4-380-airfiber24

/mpls interface
add interface=ether6-verona-11ghz   mpls-mtu=1508
add interface=ether4-380-airfiber24 mpls-mtu=1508

Step 3 — core (10.254.254.253)

/mpls ldp
add disabled=no lsr-id=10.254.254.253 transport-addresses=10.254.254.253 vrf=main

/mpls ldp interface
add interface=ether5-climax

/mpls interface
add interface=ether5-climax mpls-mtu=1508

Order doesn't matter — LDP discovery is symmetric. As soon as both ends of a link have /mpls ldp interface populated, hellos start flowing on 224.0.0.2:646 and a TCP session forms between the two transport addresses.

Verification (the actually-works part)

A. Control plane: LDP adjacencies

Run on each router:

/mpls ldp neighbor print detail

Required state:

  • peer= lists the neighbor's lsr-id (a loopback IP),
  • transport= is the neighbor's loopback IP,
  • flag column shows O (operational); D (dynamic) is fine — nD (not discovered) or missing entries means hellos aren't reaching the far side (firewall, wrong interface, MTU).

Expected counts:

Router LDP neighbors
verona 1 (climax)
climax 2 (verona, core)
core 1 (climax)

B. Control plane: label bindings exist for the remote loopbacks

/mpls ldp local-binding  print where dst-address~"10.254.254.(101|102|253)/32"
/mpls ldp remote-binding print where dst-address~"10.254.254.(101|102|253)/32"

Each router should advertise an implicit-null (or label 3) for its own loopback in local-binding, and learn labels for the two other loopbacks in remote-binding.

C. Forwarding plane: FIB has the labels

/mpls forwarding-table print

You should see entries with out-label, out-interface, and nexthop matching the OSPF next-hop toward each remote loopback. On climax you'll see two entries — one swapping toward verona, one toward core. On verona and core you'll see one entry for each remote loopback (the second loopback is reached via climax with stacked labels collapsing to a single label because we have only three nodes).

D. Data plane: traceroute prints labels

From verona, source-routed off the loopback:

/tool traceroute 10.254.254.253 src-address=10.254.254.101 count=3

A working MPLS path prints MPLS Label=NNNN E=0 ... on the first hop (climax) — that is the smoking gun. Without MPLS the same traceroute succeeds but no MPLS Label= field appears.

Repeat from core in the other direction:

/tool traceroute 10.254.254.101 src-address=10.254.254.253 count=3

E. Data plane: MTU check

We pinned mpls-mtu=1508 — verify a full-size packet still passes once labeled (1500 IP + 4 label = 1504 on the wire, well below both the 1508 cap and the radio l2mtu of 2024):

# from verona, send 1500-byte ICMP DF=yes to core's loopback
/ping 10.254.254.253 src-address=10.254.254.101 size=1500 do-not-fragment count=5

100% return = path is large enough for label + 1500 payload. Any loss means the labeled frame (1504 bytes) doesn't fit somewhere — most likely an l2mtu issue on a backhaul radio. Either bump l2mtu on the radio side, or raise mpls-mtu if you increased the IP MTU. Do not lower mpls-mtu below 1508 — that caps the labeled frame and will cause ICMP-frag-needed for ordinary 1500-byte DF customer traffic.

Rollback (per router)

If anything misbehaves, MPLS is purely additive — removing the two tables returns the box to plain IP forwarding. OSPF is untouched.

/mpls ldp interface remove [find]
/mpls ldp           remove [find]
# leave /mpls interface mpls-mtu settings as-is; harmless without LDP.

Notes & caveats

  • Don't enable LDP on customer-facing or CGNAT interfaces. Only the three backbone ports listed above. LDP advertised onto a customer port would expose label bindings to anyone who joined the broadcast domain.
  • No BGP-LU, no L3VPN, no TE yet. This is plain IPv4 LDP only — the point is to get labeled IGP forwarding working between these three before layering services on top.
  • iBGP next-hop-self is not required for this phase because we have no BGP-painted services riding the LSPs yet. When that changes (e.g., bringing public /24s in over iBGP), confirm next-hop-self on the ingress LSR so labeled paths terminate at a router with an LSP.
  • OSPFv3 / IPv6 LDP is intentionally out of scope. RouterOS 7 LDP is IPv4-only; v6 transport would need MPLSv6 / 6PE which we are not setting up here.
  • BFD on the AF radios (already enabled on the veronaclimax and climaxcore OSPF templates with use-bfd=yes) is what fast-fails the underlay; LDP itself follows OSPF and tears down accordingly.
  • Expanding to other PoPs: repeat steps 13 on the new router with its loopback as lsr-id/transport-addresses, then add /mpls ldp interface on the link to whichever existing MPLS router it peers with. No flag day.