-
Notifications
You must be signed in to change notification settings - Fork 459
Use Cases Service Provider VPN
ExaBGP enables service provider L3VPN services using MPLS L3VPN for enterprise customers, Internet and VPN separation, and BGP/MPLS VPN architecture.
- Overview
- MPLS L3VPN Architecture
- Internet and VPN Separation
- Multi-VRF Customer Services
- Configuration Examples
- See Also
Service providers offer L3VPN services for:
- Enterprise connectivity: Connect branch offices, headquarters, data centers
- Internet access: Separate internet and VPN traffic
- Managed services: Hosting, cloud connectivity, managed WAN
- Multi-tenancy: Isolate customer networks
- Any-to-any connectivity: Full mesh within VPN
- Hub-and-spoke: Centralized internet/DC access
ExaBGP enables L3VPN services by:
- VPN route advertisement: Advertise customer prefixes with RD/RT
- Route target control: Import/export routes per customer
- Service provisioning: Dynamic VPN setup via API
- Internet gateway: Provide internet access per VPN
Important: ExaBGP exchanges VPN routes but does NOT create MPLS labels or VRFs. Your PE router must configure the MPLS data plane and VRF forwarding.
Provide L3VPN for enterprise customer:
#!/usr/bin/env python3
import sys
# Enterprise L3VPN configuration
CUSTOMER_VPN = {
'customer': 'Enterprise-A',
'vrf': 'CUSTOMER-A',
'rd': '10.1.1.1:100',
'rt_export': '65000:100',
'rt_import': '65000:100',
'sites': {
'hq': '192.168.1.0/24',
'branch-1': '192.168.2.0/24',
'branch-2': '192.168.3.0/24',
'datacenter': '192.168.100.0/24'
}
}
PE_ADDRESS = "10.1.1.1"
SITE = 'hq' # This PE serves HQ site
# Announce site prefix
if SITE in CUSTOMER_VPN['sites']:
prefix = CUSTOMER_VPN['sites'][SITE]
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {CUSTOMER_VPN['rd']} "
f"route-target {CUSTOMER_VPN['rt_export']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakConnect multiple customer sites via L3VPN:
#!/usr/bin/env python3
import sys
# Multi-site enterprise VPN
ENTERPRISE_VPN = {
'customer-id': 'ACME-Corp',
'rd': '10.1.1.1:200',
'rt': '65000:200',
'sites': [
{'pe': '10.1.1.1', 'location': 'New York HQ', 'prefix': '10.100.1.0/24'},
{'pe': '10.2.2.2', 'location': 'London', 'prefix': '10.100.2.0/24'},
{'pe': '10.3.3.3', 'location': 'Singapore', 'prefix': '10.100.3.0/24'},
{'pe': '10.4.4.4', 'location': 'Data Center', 'prefix': '10.100.100.0/24'}
]
}
PE_ADDRESS = "10.1.1.1"
# Find sites at this PE
local_sites = [s for s in ENTERPRISE_VPN['sites'] if s['pe'] == PE_ADDRESS]
# Announce local site prefixes
for site in local_sites:
print(f"announce route {site['prefix']} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {ENTERPRISE_VPN['rd']} "
f"route-target {ENTERPRISE_VPN['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakCentral hub site with spoke branches:
#!/usr/bin/env python3
import sys
# Hub-and-spoke VPN
HUB_SPOKE_VPN = {
'hub': {
'rd': '10.1.1.1:300',
'rt_export': '65000:300',
'rt_import': '65000:301', # Import from spokes
'prefix': '10.200.0.0/16' # Hub prefix
},
'spokes': {
'rd': '10.1.1.1:301',
'rt_export': '65000:301', # Export to hub
'rt_import': '65000:300', # Import from hub only
'prefixes': [
'10.201.1.0/24', # Branch 1
'10.201.2.0/24', # Branch 2
'10.201.3.0/24' # Branch 3
]
}
}
PE_ADDRESS = "10.1.1.1"
ROLE = 'hub' # or 'spoke'
if ROLE == 'hub':
# Announce hub prefix
print(f"announce route {HUB_SPOKE_VPN['hub']['prefix']} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {HUB_SPOKE_VPN['hub']['rd']} "
f"route-target {HUB_SPOKE_VPN['hub']['rt_export']}", flush=True)
else:
# Announce spoke prefixes
for prefix in HUB_SPOKE_VPN['spokes']['prefixes']:
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {HUB_SPOKE_VPN['spokes']['rd']} "
f"route-target {HUB_SPOKE_VPN['spokes']['rt_export']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakProvide both internet and VPN access per customer:
#!/usr/bin/env python3
import sys
# Customer with both VPN and internet
CUSTOMER = {
'vpn': {
'rd': '10.1.1.1:100',
'rt_export': '65000:100',
'rt_import': '65000:100',
'prefixes': ['192.168.1.0/24', '192.168.2.0/24']
},
'internet': {
'rd': '10.1.1.1:999',
'rt_export': '65000:999', # Internet VRF
'rt_import': '65000:999',
'default_route': '0.0.0.0/0',
'gateway': '10.1.1.254'
}
}
PE_ADDRESS = "10.1.1.1"
# Announce VPN routes
for prefix in CUSTOMER['vpn']['prefixes']:
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {CUSTOMER['vpn']['rd']} "
f"route-target {CUSTOMER['vpn']['rt_export']}", flush=True)
# Announce default route for internet VRF
print(f"announce route {CUSTOMER['internet']['default_route']} "
f"next-hop {CUSTOMER['internet']['gateway']} "
f"route-distinguisher {CUSTOMER['internet']['rd']} "
f"route-target {CUSTOMER['internet']['rt_export']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakDifferent internet breakout per customer:
#!/usr/bin/env python3
import sys
# Multiple customers with dedicated internet gateways
CUSTOMERS = {
'customer-a': {
'vpn-rd': '10.1.1.1:100',
'vpn-rt': '65000:100',
'internet-gateway': '10.1.10.1',
'internet-rd': '10.1.1.1:1000',
'internet-rt': '65000:1000'
},
'customer-b': {
'vpn-rd': '10.1.1.1:200',
'vpn-rt': '65000:200',
'internet-gateway': '10.1.20.1',
'internet-rd': '10.1.1.1:2000',
'internet-rt': '65000:2000'
}
}
# Announce default routes with customer-specific gateways
for customer_id, config in CUSTOMERS.items():
print(f"announce route 0.0.0.0/0 "
f"next-hop {config['internet-gateway']} "
f"route-distinguisher {config['internet-rd']} "
f"route-target {config['internet-rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakProvide network segmentation within customer network:
#!/usr/bin/env python3
import sys
# Customer with multiple VRFs
CUSTOMER_VRFS = {
'ACME-Corp': {
'corporate': {
'rd': '10.1.1.1:100',
'rt': '65000:100',
'prefixes': ['10.100.0.0/16']
},
'guest': {
'rd': '10.1.1.1:101',
'rt': '65000:101',
'prefixes': ['10.200.0.0/16']
},
'iot': {
'rd': '10.1.1.1:102',
'rt': '65000:102',
'prefixes': ['10.300.0.0/16']
},
'dmz': {
'rd': '10.1.1.1:103',
'rt': '65000:103',
'prefixes': ['10.400.0.0/16']
}
}
}
PE_ADDRESS = "10.1.1.1"
# Announce all VRFs
for customer, vrfs in CUSTOMER_VRFS.items():
for vrf_name, config in vrfs.items():
for prefix in config['prefixes']:
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {config['rd']} "
f"route-target {config['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakAllow controlled communication between VRFs:
#!/usr/bin/env python3
import sys
# VRFs with selective route import/export
VRFS_WITH_LEAKING = {
'corporate': {
'rd': '10.1.1.1:100',
'rt_export': ['65000:100'],
'rt_import': ['65000:100', '65000:999'], # Import shared services
'prefixes': ['10.100.0.0/16']
},
'guest': {
'rd': '10.1.1.1:101',
'rt_export': ['65000:101'],
'rt_import': ['65000:101', '65000:999'], # Import shared services
'prefixes': ['10.200.0.0/16']
},
'shared-services': {
'rd': '10.1.1.1:999',
'rt_export': ['65000:999'], # All VRFs import this
'rt_import': ['65000:100', '65000:101'], # Can reach all VRFs
'prefixes': ['10.255.0.0/16'] # DNS, NTP, etc.
}
}
PE_ADDRESS = "10.1.1.1"
# Announce routes with appropriate RTs
for vrf_name, config in VRFS_WITH_LEAKING.items():
for prefix in config['prefixes']:
# Export with all configured RTs
rt_list = ' '.join(config['rt_export'])
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {config['rd']} "
f"route-target {rt_list}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakConfiguration (/etc/exabgp/l3vpn-pe.conf):
process vpn-controller {
run python3 /etc/exabgp/l3vpn-announce.py;
encoder json;
}
# Connection to route reflector
neighbor 10.0.0.1 {
router-id 10.1.1.1;
local-address 10.1.1.1;
local-as 65001;
peer-as 65001;
family {
ipv4 mpls-vpn;
ipv6 mpls-vpn;
}
api {
processes [ vpn-controller ];
}
}API Program (/etc/exabgp/l3vpn-announce.py):
#!/usr/bin/env python3
import sys
import json
# Active VPNs
ACTIVE_VPNS = {}
next_vpn_id = 1000
PE_ADDRESS = "10.1.1.1"
RD_BASE = "10.1.1.1"
RT_BASE = 65000
def create_vpn(customer_id, prefixes):
"""Create new L3VPN for customer"""
global next_vpn_id
vpn_id = next_vpn_id
next_vpn_id += 1
vpn_config = {
'customer': customer_id,
'vpn_id': vpn_id,
'rd': f"{RD_BASE}:{vpn_id}",
'rt': f"{RT_BASE}:{vpn_id}",
'prefixes': prefixes
}
# Announce prefixes
for prefix in prefixes:
print(f"announce route {prefix} "
f"next-hop {PE_ADDRESS} "
f"route-distinguisher {vpn_config['rd']} "
f"route-target {vpn_config['rt']}", flush=True)
ACTIVE_VPNS[customer_id] = vpn_config
return vpn_config
def delete_vpn(customer_id):
"""Delete L3VPN"""
if customer_id not in ACTIVE_VPNS:
return False
vpn = ACTIVE_VPNS[customer_id]
# Withdraw all prefixes
for prefix in vpn['prefixes']:
print(f"withdraw route {prefix} "
f"route-distinguisher {vpn['rd']}", flush=True)
del ACTIVE_VPNS[customer_id]
return True
# Listen for provisioning commands
while True:
line = sys.stdin.readline().strip()
if not line:
continue
try:
command = json.loads(line)
if command.get('action') == 'create_vpn':
vpn = create_vpn(
command['customer_id'],
command.get('prefixes', [])
)
print(json.dumps({'status': 'success', 'vpn': vpn}),
file=sys.stderr, flush=True)
elif command.get('action') == 'delete_vpn':
success = delete_vpn(command['customer_id'])
print(json.dumps({'status': 'success' if success else 'failed'}),
file=sys.stderr, flush=True)
except Exception as e:
print(json.dumps({'status': 'error', 'message': str(e)}),
file=sys.stderr, flush=True)π» Ghost written by Claude (Anthropic AI)
π Home
π Getting Started
π§ API
π‘οΈ Use Cases
π Address Families
βοΈ Configuration
π Operations
π Reference
- Architecture
- BGP State Machine
- Communities (RFC)
- Extended Communities
- BGP Ecosystem
- Capabilities (AFI/SAFI)
- RFC Support
π Migration
π Community
π External
- GitHub Repo β
- Slack β
- Issues β
π» Ghost written by Claude (Anthropic AI)