Skip to main content

L3VPN service

This page documents the L3VPN service end-to-end: how an operator creates one through the Streamlit catalog, what Infrahub does automatically, and how each vendor's configuration differs.

For field-level schema details see schema-reference.


User flow​

Step-by-step​

  1. Catalog form — The operator fills in the VPN name, selects a tenant, picks a PE and a customer subnet for each site, and chooses a routing protocol (eBGP / static / connected).

  2. Branch + objects — The catalog allocates a vpn_id from vpn_id_pool, opens a feature branch, and writes ServiceL3Vpn + ServiceL3VpnSite objects to Infrahub. All objects start with status = draft / provisioning.

  3. Generator run (event-driven) — Once the sites exist, the catalog adds the ServiceL3Vpn to the l3vpns group. That membership change fires the trigger-l3vpn-generator group trigger (a CoreGroupTriggerRule + CoreGeneratorAction, see objects/events/00_triggers.yml), which runs L3VpnGenerator on the branch. The generator is deliberately not run inside the proposed-change pipeline (execute_in_proposed_change: false in .infrahub.yml): in the pipeline it races artifact rendering, which render before the VRF/IPs exist and produce an empty configuration diff. Running it on the branch-change event guarantees the data lands before artifacts render. L3VpnGenerator does all heavy lifting:

    • Creates an IpamVRF with vrf_rd = <provider-asn>:<vpn_id>.
    • Creates matching import and export route targets.
    • Selects the lowest-numbered free interface on the PE.
    • Allocates a /30 from pe_ce_pool and creates the PE and CE IP addresses.
    • Places the customer subnet prefix into the VRF.
    • Creates a RoutingBGPSession (eBGP, session_type = EXTERNAL) when routing_protocol = ebgp.
    • Promotes ServiceL3Vpn.status to active and ServiceL3VpnSite.status to active.
  4. Proposed Change — Once the generator has finished (service active) and the per-PE artifacts are rendered, the catalog opens a CoreProposedChange from the feature branch into main for review.

  5. Checks — Four checks must pass before merge is allowed (see Checks below).

  6. Transforms — Configuration artifacts are rendered for each PE that has at least one L3VPN site.

  7. Merge — The operator reviews the diff in the Infrahub UI and merges. On the target platform the artifact is pushed via the relevant invoke task (for example, invoke lab.push-arista).


Checks​

CheckFileWhat it enforces
l3vpn_overlapchecks/l3vpn_overlap.pyNo two active ServiceL3Vpn objects share the same vpn_id
l3vpn_site_subnetchecks/l3vpn_site_subnet.pyThe customer subnet is not already claimed by another site in the same VRF
pe_interface_allocchecks/pe_interface_alloc.pyThe nominated PE interface exists and has status = free
backbone_session_countchecks/backbone_session_count.pyEvery PE in the backbone has its full-mesh complement of Nāˆ’1 iBGP sessions (N = PE count — 7 each on the 8-PE financial backbone, 3 each on the 4-PE isp backbone)
batfish_backbonechecks/batfish_backbone.pyStatic validation of the rendered backbone configs via Batfish — see Batfish validation for the full query battery

A failing check blocks merge of the proposed change. The operator can see the check result in the Infrahub UI under the proposed change's Checks tab.


Generator: what it creates​

ObjectCreated byNotes
IpamVRF_ensure_vrfName = VPN name; vrf_rd = <asn>:<vpn_id>
IpamRouteTargetfind_or_create_route_targetSame value used for import and export RT
InterfacePhysical (updated)next_free_physical_interfaceLowest free-status interface on the PE; role set to cust
IpamPrefix (/30)allocate_prefix_from_poolAllocated from pe_ce_pool; placed in VRF
IpamIPAddress Ɨ 2direct create.1 = PE, .2 = CE within the /30
RoutingBGPSession_ensure_ebgp_sessionOnly when routing_protocol = ebgp; session_type = EXTERNAL

The generator is idempotent: re-running it on an L3VPN that already has a VRF and allocated addresses will skip re-creation and only update missing fields.


Per-vendor configuration​

The transform layer renders a full configuration fragment for each PE when that PE has at least one active L3VPN site. Configuration sections differ by vendor. On the default financial backbone every PE is Arista, so trading-floor-vpn renders the Arista EOS form at all four sites; the isp dataset, with one PE per vendor, exercises all four forms below:

Arista EOS​

vrf instance <name>
rd <asn>:<vpn_id>
!
router bgp <asn>
vrf <name>
rd <asn>:<vpn_id>
route-target import <rt>
route-target export <rt>
neighbor <ce-ip> remote-as <ce-asn>
network <customer-subnet>

Cisco IOS-XR​

vrf <name>
address-family ipv4 unicast
import route-target
<rt>
export route-target
<rt>
!
router bgp <asn>
vrf <name>
rd <asn>:<vpn_id>
address-family ipv4 unicast
neighbor <ce-ip>
remote-as <ce-asn>

Juniper Junos​

routing-instances {
<name> {
instance-type vrf;
interface <pe-iface>;
vrf-target target:<rt>;
protocols {
bgp {
group PE-CE {
neighbor <ce-ip> {
peer-as <ce-asn>;
}
}
}
}
}
}

Nokia SR OS​

service {
vprn "<name>" customer "1" create
route-distinguisher <rd>
vrf-target target:<rt>
interface "<pe-iface>" create
address <pe-ip>/<mask>
sap <port>:0 create
exit
exit
bgp-vpn-backup
no shutdown
exit
}