Skip to content

Use Cases Service Provider L2VPN

Thomas Mangin edited this page Nov 15, 2025 · 1 revision

Service Provider Layer 2 VPN Services

ExaBGP enables service provider L2VPN services using VPLS for enterprise customers, E-LINE/E-LAN services, and circuit provisioning.

Table of Contents

Overview

L2VPN Service Types

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 Role

ExaBGP enables L2VPN service provisioning by:

  1. VPLS endpoint advertisement: Announce PE router participation in VPLS
  2. Circuit provisioning: Dynamic circuit setup via API
  3. Multi-customer support: Isolate services using Route Targets
  4. 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.

VPLS for Enterprise Services

Basic VPLS Service

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:
        break

Multi-Site VPLS

Connect 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:
        break

Hierarchical VPLS

Hub-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:
        break

E-LINE and E-LAN Services

E-LINE Service

Point-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:
        break

E-LAN Service

Multipoint 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:
        break

Circuit Provisioning

Dynamic Service Provisioning

Provision 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)

Integration with OSS/BSS

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 Examples

VPLS PE Router

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 ];
    }
}

E-LINE Service Configuration

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;
        }
    }
}

See Also

Address Families

Related Use Cases

Configuration

Features


πŸ‘» Ghost written by Claude (Anthropic AI)

Clone this wiki locally