← All posts
How-To

Verifying MPLS L3VPNs with Python: RD, RT, and the Routes That Should Be There

A repeatable check that catches the silent VPN leak before the customer calls.

NAPT Team10 min read
MPLS L3VPN topologyCE-APE-1VRF: CUST-APE-2VRF: CUST-ACE-BMP-BGP VPNv4 carries RD-tagged routes across the core
An L3VPN is only correct when both PEs agree on the VRF's route-targets.

MPLS VPNs fail in the quietest way possible: a single mistyped route-target and a customer's two sites simply cannot see each other, while every link is green. Verification means checking the control plane, not the cables.

The three identities that must line up

  • VRF — the isolated routing table for the customer on each PE.
  • Route Distinguisher — makes overlapping customer prefixes globally unique inside MP-BGP.
  • Route Target — controls which VRFs import and export the routes. A VPN works only when PE-1's export RT matches PE-2's import RT.

Collect the VRF detail

python
from netmiko import ConnectHandler

def vrf_detail(host):
    conn = ConnectHandler(device_type="cisco_ios_xr", host=host,
                          username="ro", password="••••")
    # use_textfsm parses raw output into list[dict]
    return conn.send_command("show vrf CUST-A detail", use_textfsm=True)

The use_textfsm=True flag runs the output through a TextFSM template so you get structured records instead of text to regex.

Check RT consistency across PEs

python
pe1 = vrf_detail("10.0.0.1")[0]
pe2 = vrf_detail("10.0.0.2")[0]

# PE-1 must export what PE-2 imports, and vice versa
ok = (set(pe1["export_rt"]) == set(pe2["import_rt"]) and
      set(pe2["export_rt"]) == set(pe1["import_rt"]))

if not ok:
    print("RT MISMATCH")
    print(f"  PE-1 export {pe1['export_rt']}  vs  PE-2 import {pe2['import_rt']}")
    print(f"  PE-2 export {pe2['export_rt']}  vs  PE-1 import {pe1['import_rt']}")

Prove the routes actually arrived

RT config being correct is necessary, not sufficient. Confirm the remote prefix is installed in the VRF.

python
routes = conn.send_command("show ip route vrf CUST-A", use_textfsm=True)
remote = [r for r in routes if r["network"].startswith("192.168.20.")]
print("Remote site reachable:" , bool(remote))
Warning: A matching RT with no installed routes points upstream: the remote CE is not advertising, or MP-BGP between PEs is not up. Check show bgp vpnv4 unicast summary next.

Make it a standing check

Schedule this across every PE pair and emit a finding keyed vpn/rt-mismatch/CUST-A on failure. The Intent engine can express the same invariant declaratively — "every PE serving CUST-A shares a symmetric RT set" — and verify it on a cadence.

#mpls#vpn#how-to

Was this helpful?

Generate scripts for the task covered in this post

Describe what you need and NAPT writes production-ready automation in Netmiko, NAPALM, or Nornir.

Open Script Generator →
New to NAPT? Start with the Setup Guide

Related posts