-
Notifications
You must be signed in to change notification settings - Fork 459
Use Cases Service Provider L2VPN
ExaBGP enables service provider L2VPN services using VPLS for enterprise customers, E-LINE/E-LAN services, and circuit provisioning.
- Overview
- VPLS for Enterprise Services
- E-LINE and E-LAN Services
- Circuit Provisioning
- Configuration Examples
- See Also
Service providers offer various L2VPN services:
- VPLS: Virtual Private LAN Service (multipoint-to-multipoint)
- E-LINE: Point-to-point Ethernet service
- E-LAN: Multipoint Ethernet LAN service
- E-TREE: Rooted multipoint service
ExaBGP enables L2VPN service provisioning by:
- VPLS endpoint advertisement: Announce PE router participation in VPLS
- Circuit provisioning: Dynamic circuit setup via API
- Multi-customer support: Isolate services using Route Targets
- Service automation: Integrate with OSS/BSS systems
Important: ExaBGP announces VPLS routes but does NOT create pseudowires or MPLS tunnels. Your network OS must configure the data plane.
Provide multipoint L2 connectivity for enterprise customer:
#!/usr/bin/env python3
import sys
# Enterprise customer VPLS
CUSTOMER_VPLS = {
'customer-id': 'ACME-Corp',
'vpls-id': 1000,
'rd': '10.1.1.1:1000',
'rt_export': '65000:1000',
'rt_import': '65000:1000',
'pe-endpoints': [
{'pe': '10.1.1.1', 'site': 'New York HQ'},
{'pe': '10.2.2.2', 'site': 'London Office'},
{'pe': '10.3.3.3', 'site': 'Tokyo Office'}
]
}
# Announce VPLS endpoint
PE_ADDRESS = "10.1.1.1" # This PE
print(f"announce route-distinguisher {CUSTOMER_VPLS['rd']} "
f"vpls {CUSTOMER_VPLS['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {CUSTOMER_VPLS['rt_export']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakConnect multiple customer sites via VPLS:
#!/usr/bin/env python3
import sys
# Multi-site customer VPLS
CUSTOMERS = {
'enterprise-a': {
'vpls-id': 1001,
'rd': '10.1.1.1:1001',
'rt': '65000:1001',
'sites': ['site-1', 'site-2', 'site-3', 'site-4']
},
'enterprise-b': {
'vpls-id': 1002,
'rd': '10.1.1.1:1002',
'rt': '65000:1002',
'sites': ['site-a', 'site-b']
}
}
PE_ADDRESS = "10.1.1.1"
# Announce VPLS for all customers at this PE
for customer, config in CUSTOMERS.items():
print(f"announce route-distinguisher {config['rd']} "
f"vpls {config['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {config['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakHub-and-spoke VPLS topology:
#!/usr/bin/env python3
import sys
# Hierarchical VPLS (hub-and-spoke)
HVPLS = {
'core': {
'vpls-id': 2000,
'rd': '10.1.1.1:2000',
'rt': '65000:2000',
'role': 'hub'
},
'edge-sites': [
{
'vpls-id': 2001,
'rd': '10.1.1.1:2001',
'rt': '65000:2001',
'role': 'spoke',
'parent-vpls': 2000
},
{
'vpls-id': 2002,
'rd': '10.1.1.1:2002',
'rt': '65000:2002',
'role': 'spoke',
'parent-vpls': 2000
}
]
}
PE_ADDRESS = "10.1.1.1"
ROLE = 'hub' # or 'spoke'
if ROLE == 'hub':
# Announce core VPLS
config = HVPLS['core']
print(f"announce route-distinguisher {config['rd']} "
f"vpls {config['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {config['rt']}", flush=True)
else:
# Announce spoke VPLS
for spoke in HVPLS['edge-sites']:
print(f"announce route-distinguisher {spoke['rd']} "
f"vpls {spoke['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {spoke['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakPoint-to-point Ethernet private line:
#!/usr/bin/env python3
import sys
# E-LINE service (point-to-point)
ELINE_SERVICES = {
'eline-001': {
'customer': 'ACME-Corp',
'circuit-id': 'NYC-LON-001',
'vpls-id': 3001,
'rd': '10.1.1.1:3001',
'rt': '65000:3001',
'endpoints': ['10.1.1.1', '10.2.2.2'], # NYC, London PEs
'bandwidth': '1G'
},
'eline-002': {
'customer': 'TechCo',
'circuit-id': 'LAX-SFO-002',
'vpls-id': 3002,
'rd': '10.1.1.1:3002',
'rt': '65000:3002',
'endpoints': ['10.3.3.3', '10.4.4.4'],
'bandwidth': '10G'
}
}
PE_ADDRESS = "10.1.1.1"
# Announce E-LINE services at this PE
for service_id, config in ELINE_SERVICES.items():
if PE_ADDRESS in config['endpoints']:
print(f"announce route-distinguisher {config['rd']} "
f"vpls {config['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {config['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakMultipoint Ethernet LAN service:
#!/usr/bin/env python3
import sys
# E-LAN service (multipoint)
ELAN_SERVICES = {
'elan-retail-001': {
'customer': 'RetailChain',
'vpls-id': 4001,
'rd': '10.1.1.1:4001',
'rt': '65000:4001',
'sites': [
{'pe': '10.1.1.1', 'location': 'Store-1'},
{'pe': '10.2.2.2', 'location': 'Store-2'},
{'pe': '10.3.3.3', 'location': 'Store-3'},
{'pe': '10.4.4.4', 'location': 'DC-Primary'}
]
}
}
PE_ADDRESS = "10.1.1.1"
# Announce E-LAN services
for service_id, config in ELAN_SERVICES.items():
# Check if this PE participates
participating = any(site['pe'] == PE_ADDRESS for site in config['sites'])
if participating:
print(f"announce route-distinguisher {config['rd']} "
f"vpls {config['vpls-id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {config['rt']}", flush=True)
while True:
line = sys.stdin.readline().strip()
if not line:
breakProvision services on-demand via API:
#!/usr/bin/env python3
import sys
import json
# Active services database
ACTIVE_SERVICES = {}
# Next available VPLS ID
next_vpls_id = 5000
PE_ADDRESS = "10.1.1.1"
RD_BASE = "10.1.1.1"
RT_BASE = 65000
def provision_vpls_service(customer_id, service_type, endpoints):
"""Dynamically provision new VPLS service"""
global next_vpls_id
vpls_id = next_vpls_id
next_vpls_id += 1
service_config = {
'customer': customer_id,
'type': service_type,
'vpls-id': vpls_id,
'rd': f"{RD_BASE}:{vpls_id}",
'rt': f"{RT_BASE}:{vpls_id}",
'endpoints': endpoints,
'status': 'active'
}
# Announce VPLS if this PE is an endpoint
if PE_ADDRESS in endpoints:
print(f"announce route-distinguisher {service_config['rd']} "
f"vpls {vpls_id} "
f"endpoint {PE_ADDRESS} "
f"route-target {service_config['rt']}", flush=True)
ACTIVE_SERVICES[vpls_id] = service_config
return service_config
def decommission_service(vpls_id):
"""Decommission VPLS service"""
if vpls_id not in ACTIVE_SERVICES:
return False
service = ACTIVE_SERVICES[vpls_id]
# Withdraw VPLS announcement
print(f"withdraw route-distinguisher {service['rd']} "
f"vpls {vpls_id}", flush=True)
service['status'] = 'inactive'
del ACTIVE_SERVICES[vpls_id]
return True
# Listen for provisioning requests
while True:
line = sys.stdin.readline().strip()
if not line:
continue
try:
command = json.loads(line)
if command.get('action') == 'provision':
service = provision_vpls_service(
customer_id=command['customer_id'],
service_type=command.get('type', 'vpls'),
endpoints=command.get('endpoints', [])
)
print(json.dumps({'status': 'success', 'service': service}),
file=sys.stderr, flush=True)
elif command.get('action') == 'decommission':
success = decommission_service(command['vpls_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)Integrate with service provider OSS/BSS systems:
#!/usr/bin/env python3
import sys
import json
import requests
# OSS/BSS API configuration
OSS_API_URL = "https://oss.example.com/api/v1"
API_KEY = "secret-key"
PE_ADDRESS = "10.1.1.1"
def fetch_service_orders():
"""Fetch pending service orders from OSS"""
try:
response = requests.get(
f"{OSS_API_URL}/service-orders",
headers={'Authorization': f"Bearer {API_KEY}"},
params={'pe': PE_ADDRESS, 'status': 'pending'}
)
return response.json().get('orders', [])
except:
return []
def update_service_status(order_id, status):
"""Update service status in OSS"""
try:
requests.put(
f"{OSS_API_URL}/service-orders/{order_id}",
headers={'Authorization': f"Bearer {API_KEY}"},
json={'status': status}
)
except:
pass
def provision_from_oss():
"""Provision services from OSS orders"""
orders = fetch_service_orders()
for order in orders:
try:
# Provision service
rd = f"{PE_ADDRESS}:{order['vpls_id']}"
rt = f"65000:{order['vpls_id']}"
print(f"announce route-distinguisher {rd} "
f"vpls {order['vpls_id']} "
f"endpoint {PE_ADDRESS} "
f"route-target {rt}", flush=True)
# Update OSS
update_service_status(order['id'], 'active')
except Exception as e:
update_service_status(order['id'], 'failed')
# Initial provisioning
provision_from_oss()
# Periodic sync
import time
while True:
time.sleep(300) # Check every 5 minutes
provision_from_oss()Configuration (/etc/exabgp/vpls-pe.conf):
process vpls-controller {
run python3 /etc/exabgp/vpls-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 {
l2vpn vpls;
}
api {
processes [ vpls-controller ];
}
}Configuration (/etc/exabgp/eline-service.conf):
process eline-provisioning {
run python3 /etc/exabgp/eline-provision.py;
encoder json;
}
neighbor 10.0.0.1 {
router-id 10.1.1.1;
local-address 10.1.1.1;
local-as 65001;
peer-as 65001;
family {
l2vpn vpls;
}
api {
processes [ eline-provisioning ];
receive {
parsed;
}
}
}π» 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)