Skip to content

Templates and Inheritance

Thomas Mangin edited this page Nov 13, 2025 · 4 revisions

Templates and Inheritance

Configuration reuse patterns for large-scale ExaBGP deployments


Table of Contents


Overview

Templates and inheritance allow you to define configuration once and reuse it across multiple neighbors, reducing duplication and maintenance burden.

Key concepts:

  • Template: A named configuration block that can be inherited
  • Inheritance: A neighbor inherits settings from a template using inherit
  • Group: A collection of neighbors with shared configuration
  • Override: Child configurations can override template settings

Benefits:

  • DRY: Don't Repeat Yourself - define once, reuse everywhere
  • Consistency: Ensure all neighbors use same settings
  • Maintainability: Update one template, affect all inheritors
  • Scalability: Manage hundreds of neighbors efficiently

Why Use Templates

Without Templates (Repetitive)

neighbor 192.168.1.1 {
    router-id 10.0.0.1;
    local-address 192.168.1.2;
    local-as 65001;
    peer-as 65000;

    family {
        ipv4 unicast;
        ipv6 unicast;
    }

    capability {
        route-refresh;
        graceful-restart;
    }
}

neighbor 192.168.2.1 {
    router-id 10.0.0.1;
    local-address 192.168.2.2;
    local-as 65001;
    peer-as 65000;

    family {
        ipv4 unicast;
        ipv6 unicast;
    }

    capability {
        route-refresh;
        graceful-restart;
    }
}

neighbor 192.168.3.1 {
    router-id 10.0.0.1;
    local-address 192.168.3.2;
    local-as 65001;
    peer-as 65000;

    family {
        ipv4 unicast;
        ipv6 unicast;
    }

    capability {
        route-refresh;
        graceful-restart;
    }
}

Problems:

  • 30+ lines for 3 neighbors
  • Changing capabilities requires editing 3 places
  • Error-prone (typos, inconsistencies)
  • Doesn't scale to 100+ neighbors

With Templates (DRY)

# Define template once
template {
    neighbor ebgp-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
            ipv6 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }
    }
}

# Use template (just 5 lines per neighbor)
neighbor 192.168.1.1 {
    inherit ebgp-peer;
    local-address 192.168.1.2;
    peer-as 65000;
}

neighbor 192.168.2.1 {
    inherit ebgp-peer;
    local-address 192.168.2.2;
    peer-as 65000;
}

neighbor 192.168.3.1 {
    inherit ebgp-peer;
    local-address 192.168.3.2;
    peer-as 65000;
}

Benefits:

  • 18 lines total (vs 30+)
  • Change capabilities once, affects all neighbors
  • Consistent configuration guaranteed
  • Easy to add 100 more neighbors

Template Syntax

Basic Template Definition

template {
    neighbor <template-name> {
        <directives>
    }
}

Example:

template {
    neighbor basic-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
        }

        capability {
            route-refresh;
        }
    }
}

Multiple Templates

You can define multiple templates:

template {
    # Template for eBGP peers
    neighbor ebgp-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
            ipv6 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }
    }

    # Template for iBGP peers
    neighbor ibgp-peer {
        router-id 10.0.0.1;
        local-as 65001;
        peer-as 65001;  # iBGP

        family {
            ipv4 unicast;
            ipv6 unicast;
            ipv4 mpls-vpn;
        }

        capability {
            route-refresh;
            graceful-restart 120;
        }
    }

    # Template for FlowSpec
    neighbor flowspec-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 flowspec;
        }
    }
}

Using Templates with inherit

Basic Inheritance

template {
    neighbor common-settings {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
        }
    }
}

neighbor 192.168.1.1 {
    inherit common-settings;
    local-address 192.168.1.2;
    peer-as 65000;
}

What happens:

  1. Neighbor inherits all directives from template
  2. Neighbor adds/overrides with its own directives
  3. Final configuration combines both

Overriding Template Values

Child configurations can override template settings:

template {
    neighbor default-peer {
        router-id 10.0.0.1;
        local-as 65001;
        hold-time 180;  # Default hold-time

        family {
            ipv4 unicast;
        }
    }
}

neighbor 192.168.1.1 {
    inherit default-peer;
    local-address 192.168.1.2;
    peer-as 65000;
}

neighbor 192.168.2.1 {
    inherit default-peer;
    local-address 192.168.2.2;
    peer-as 65000;
    hold-time 90;  # Override: use shorter hold-time
}

Result:

  • 192.168.1.1 uses hold-time 180 (from template)
  • 192.168.2.1 uses hold-time 90 (overridden)

Adding to Template Configuration

You can add to template configuration:

template {
    neighbor basic-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
        }

        capability {
            route-refresh;
        }
    }
}

neighbor 192.168.1.1 {
    inherit basic-peer;
    local-address 192.168.1.2;
    peer-as 65000;

    # Add additional family
    family {
        ipv4 unicast;
        ipv6 unicast;  # Added
    }

    # Add MD5 authentication
    md5-password "secret123";
}

Important: Family blocks are merged, not replaced. Other directives are replaced when overridden.


Group Configuration

Groups combine template functionality with neighbor definitions in a single block.

Basic Group

group internal-peers {
    # Shared configuration
    router-id 10.0.0.1;
    local-address 10.0.0.1;
    local-as 65001;
    peer-as 65001;  # iBGP

    family {
        ipv4 unicast;
    }

    capability {
        route-refresh;
    }

    # Neighbor 1
    neighbor 10.0.0.2 {
        description "iBGP Peer 1";
    }

    # Neighbor 2
    neighbor 10.0.0.3 {
        description "iBGP Peer 2";
    }

    # Neighbor 3
    neighbor 10.0.0.4 {
        description "iBGP Peer 3";
    }
}

Benefits:

  • Group configuration inherited by all neighbors
  • Each neighbor only specifies unique settings
  • Clear logical grouping

Group with Per-Neighbor Overrides

group edge-routers {
    router-id 10.0.0.1;
    local-as 65001;
    peer-as 65000;  # eBGP

    family {
        ipv4 unicast;
    }

    capability {
        route-refresh;
        graceful-restart;
    }

    # Neighbor with defaults
    neighbor 192.168.1.1 {
        local-address 192.168.1.2;
        description "Edge Router 1";
    }

    # Neighbor with override
    neighbor 192.168.2.1 {
        local-address 192.168.2.2;
        description "Edge Router 2 (short hold-time)";
        hold-time 90;  # Override group default
    }

    # Neighbor with MD5
    neighbor 192.168.3.1 {
        local-address 192.168.3.2;
        description "Edge Router 3 (MD5 auth)";
        md5-password "secret123";  # Add MD5
    }
}

Multiple Groups

# iBGP group
group ibgp-peers {
    router-id 10.0.0.1;
    local-address 10.0.0.1;
    local-as 65001;
    peer-as 65001;

    multihop 5;

    family {
        ipv4 unicast;
        ipv6 unicast;
    }

    neighbor 10.0.0.2 { }
    neighbor 10.0.0.3 { }
}

# eBGP group
group ebgp-peers {
    router-id 10.0.0.1;
    local-as 65001;

    family {
        ipv4 unicast;
    }

    capability {
        route-refresh;
    }

    neighbor 192.168.1.1 {
        local-address 192.168.1.2;
        peer-as 65000;
    }

    neighbor 192.168.2.1 {
        local-address 192.168.2.2;
        peer-as 65002;
    }
}

# FlowSpec group
group flowspec-peers {
    router-id 10.0.0.1;
    local-as 65001;

    family {
        ipv4 flowspec;
    }

    api {
        processes [ ddos-blocker ];
    }

    neighbor 192.168.10.1 {
        local-address 192.168.10.2;
        peer-as 65000;
    }
}

Inheritance Rules

Rule 1: Template Must Be Defined First

Wrong:

neighbor 192.168.1.1 {
    inherit my-template;  # ERROR: template not defined yet
    # ...
}

template {
    neighbor my-template {
        # ...
    }
}

Correct:

template {
    neighbor my-template {
        # ...
    }
}

neighbor 192.168.1.1 {
    inherit my-template;  # OK: template defined above
    # ...
}

Rule 2: Only One Template Per Neighbor

Wrong:

neighbor 192.168.1.1 {
    inherit template1;
    inherit template2;  # ERROR: can't inherit multiple templates
    # ...
}

Workaround: Use nested inheritance or merge templates manually.


Rule 3: Child Overrides Take Precedence

template {
    neighbor my-template {
        hold-time 180;
        md5-password "default";
    }
}

neighbor 192.168.1.1 {
    inherit my-template;
    hold-time 90;           # Overrides template
    md5-password "custom";  # Overrides template
    # Final: hold-time=90, md5-password="custom"
}

Rule 4: Family Blocks Are Merged

template {
    neighbor my-template {
        family {
            ipv4 unicast;
        }
    }
}

neighbor 192.168.1.1 {
    inherit my-template;
    family {
        ipv6 unicast;  # Merged with template
    }
    # Final: ipv4 unicast + ipv6 unicast
}

Note: This is an exception to Rule 3. Most blocks are replaced, but family is merged.


Rule 5: API Processes Are Merged

template {
    neighbor my-template {
        api {
            processes [ process1 ];
        }
    }
}

neighbor 192.168.1.1 {
    inherit my-template;
    api {
        processes [ process2 ];
    }
    # Final: processes [ process1, process2 ]
}

Variables and Substitution

ExaBGP does not have native variable substitution. However, you can achieve this using:

  1. Configuration generation scripts
  2. Environment variables in processes
  3. External templating tools (Jinja2, ERB, etc.)

Method 1: Shell Script Generation

#!/bin/bash

# Variables
ROUTER_ID="10.0.0.1"
LOCAL_AS="65001"
PEER_AS="65000"

# Generate configuration
cat > /etc/exabgp/exabgp.conf <<EOF
template {
    neighbor ebgp-peer {
        router-id ${ROUTER_ID};
        local-as ${LOCAL_AS};
        peer-as ${PEER_AS};

        family {
            ipv4 unicast;
        }
    }
}

neighbor 192.168.1.1 {
    inherit ebgp-peer;
    local-address 192.168.1.2;
}

neighbor 192.168.2.1 {
    inherit ebgp-peer;
    local-address 192.168.2.2;
}
EOF

Method 2: Jinja2 Templates

Template file (exabgp.conf.j2):

template {
    neighbor ebgp-peer {
        router-id {{ router_id }};
        local-as {{ local_as }};
        peer-as {{ peer_as }};

        family {
            ipv4 unicast;
        }
    }
}

{% for neighbor in neighbors %}
neighbor {{ neighbor.ip }} {
    inherit ebgp-peer;
    local-address {{ neighbor.local_address }};
    description "{{ neighbor.description }}";
}
{% endfor %}

Render script (generate_config.py):

from jinja2 import Template

config = {
    'router_id': '10.0.0.1',
    'local_as': 65001,
    'peer_as': 65000,
    'neighbors': [
        {'ip': '192.168.1.1', 'local_address': '192.168.1.2', 'description': 'Router 1'},
        {'ip': '192.168.2.1', 'local_address': '192.168.2.2', 'description': 'Router 2'},
        {'ip': '192.168.3.1', 'local_address': '192.168.3.2', 'description': 'Router 3'},
    ]
}

with open('exabgp.conf.j2') as f:
    template = Template(f.read())

with open('/etc/exabgp/exabgp.conf', 'w') as f:
    f.write(template.render(config))

Method 3: Process Environment Variables

Environment variables can be used inside processes, not in configuration file:

process healthcheck {
    run /etc/exabgp/api/healthcheck.py;
    encoder text;
    env {
        SERVICE_IP = "100.10.0.100";
        SERVICE_PORT = "80";
        ANNOUNCE_PREFIX = "100.10.0.0/24";
    }
}

Process script (healthcheck.py):

import os

service_ip = os.environ['SERVICE_IP']
service_port = os.environ['SERVICE_PORT']
announce_prefix = os.environ['ANNOUNCE_PREFIX']

# Use variables in logic
if check_health(service_ip, service_port):
    print(f"announce route {announce_prefix} next-hop self")
else:
    print(f"withdraw route {announce_prefix}")

DRY Principles

DRY: Don't Repeat Yourself

Principle 1: Extract Common Configuration

Before:

neighbor 192.168.1.1 { router-id 10.0.0.1; local-as 65001; family { ipv4 unicast; } }
neighbor 192.168.2.1 { router-id 10.0.0.1; local-as 65001; family { ipv4 unicast; } }
neighbor 192.168.3.1 { router-id 10.0.0.1; local-as 65001; family { ipv4 unicast; } }

After:

template {
    neighbor common { router-id 10.0.0.1; local-as 65001; family { ipv4 unicast; } }
}
neighbor 192.168.1.1 { inherit common; local-address 192.168.1.2; peer-as 65000; }
neighbor 192.168.2.1 { inherit common; local-address 192.168.2.2; peer-as 65000; }
neighbor 192.168.3.1 { inherit common; local-address 192.168.3.2; peer-as 65000; }

Principle 2: Template Hierarchy

Create specialized templates from base templates (via config generation):

Base template:

template {
    neighbor base-peer {
        router-id 10.0.0.1;
        local-as 65001;

        capability {
            route-refresh;
        }
    }
}

Specialized templates (add features):

template {
    neighbor base-peer { /* ... */ }

    neighbor ebgp-peer {
        router-id 10.0.0.1;
        local-as 65001;

        capability {
            route-refresh;
            graceful-restart;  # Added for eBGP
        }

        family {
            ipv4 unicast;
            ipv6 unicast;
        }
    }

    neighbor ibgp-peer {
        router-id 10.0.0.1;
        local-as 65001;
        peer-as 65001;  # iBGP

        capability {
            route-refresh;
        }

        family {
            ipv4 unicast;
            ipv6 unicast;
            ipv4 mpls-vpn;  # Added for iBGP
        }
    }
}

Principle 3: Single Source of Truth

Bad: Duplicate values across config

neighbor 192.168.1.1 { local-as 65001; /* ... */ }
neighbor 192.168.2.1 { local-as 65001; /* ... */ }
neighbor 192.168.3.1 { local-as 65001; /* ... */ }
# If AS number changes, must update 3 places

Good: Define once in template

template {
    neighbor common { local-as 65001; /* ... */ }
}
neighbor 192.168.1.1 { inherit common; /* ... */ }
neighbor 192.168.2.1 { inherit common; /* ... */ }
neighbor 192.168.3.1 { inherit common; /* ... */ }
# AS number change: update 1 place

Large-Scale Deployment Patterns

Pattern 1: Regional Peering (100+ Neighbors)

# Template for all peers
template {
    neighbor global-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
            ipv6 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }
    }
}

# US region
group us-peers {
    inherit global-peer;

    neighbor 192.168.1.1 { local-address 192.168.1.2; peer-as 65100; description "US-East-1"; }
    neighbor 192.168.1.3 { local-address 192.168.1.2; peer-as 65101; description "US-East-2"; }
    neighbor 192.168.2.1 { local-address 192.168.2.2; peer-as 65102; description "US-West-1"; }
    # ... 50 more US peers
}

# EU region
group eu-peers {
    inherit global-peer;

    neighbor 192.168.10.1 { local-address 192.168.10.2; peer-as 65200; description "EU-West-1"; }
    neighbor 192.168.10.3 { local-address 192.168.10.2; peer-as 65201; description "EU-West-2"; }
    # ... 50 more EU peers
}

Note: ExaBGP doesn't support inherit in group blocks natively. Use config generation for this pattern.


Pattern 2: Multi-Service BGP (Different Families)

# Base template
template {
    neighbor base-config {
        router-id 10.0.0.1;
        local-as 65001;
        capability { route-refresh; }
    }
}

# Unicast template
template {
    neighbor unicast-peer {
        router-id 10.0.0.1;
        local-as 65001;
        family { ipv4 unicast; ipv6 unicast; }
        capability { route-refresh; graceful-restart; }
    }
}

# FlowSpec template
template {
    neighbor flowspec-peer {
        router-id 10.0.0.1;
        local-as 65001;
        family { ipv4 flowspec; }
    }
}

# VPN template
template {
    neighbor vpn-peer {
        router-id 10.0.0.1;
        local-as 65001;
        family { ipv4 mpls-vpn; l2vpn evpn; }
        capability { extended-message; }
    }
}

# Use appropriate template per service
neighbor 192.168.1.1 { inherit unicast-peer; local-address 192.168.1.2; peer-as 65000; }
neighbor 192.168.2.1 { inherit flowspec-peer; local-address 192.168.2.2; peer-as 65000; }
neighbor 192.168.3.1 { inherit vpn-peer; local-address 192.168.3.2; peer-as 65000; }

Pattern 3: Automated Config Generation

Python script to generate config for 1000 peers:

#!/usr/bin/env python3

# Configuration data
config = {
    'router_id': '10.0.0.1',
    'local_as': 65001,
    'peers': []
}

# Generate 1000 peers
for i in range(1, 1001):
    config['peers'].append({
        'ip': f'192.168.{i//256}.{i%256}',
        'local_address': '10.0.0.1',
        'peer_as': 65000 + (i % 10),
        'description': f'Peer-{i}'
    })

# Write configuration
with open('/etc/exabgp/exabgp.conf', 'w') as f:
    # Template
    f.write("""
template {
    neighbor base-peer {
        router-id %s;
        local-as %s;

        family {
            ipv4 unicast;
        }

        capability {
            route-refresh;
        }
    }
}
""" % (config['router_id'], config['local_as']))

    # Neighbors
    for peer in config['peers']:
        f.write("""
neighbor %s {
    inherit base-peer;
    local-address %s;
    peer-as %s;
    description "%s";
}
""" % (peer['ip'], peer['local_address'], peer['peer_as'], peer['description']))

print(f"Generated config with {len(config['peers'])} neighbors")

Advanced Template Patterns

Pattern 1: API Process Templates

# Define processes
process healthcheck {
    run /etc/exabgp/api/healthcheck.py;
    encoder text;
}

process receive-routes {
    run /etc/exabgp/api/receive.py;
    encoder json;
    receive { parsed; updates; }
}

# Template with API
template {
    neighbor api-enabled {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
        }

        api {
            processes [ healthcheck, receive-routes ];
        }
    }
}

# Use template
neighbor 192.168.1.1 {
    inherit api-enabled;
    local-address 192.168.1.2;
    peer-as 65000;
}

Pattern 2: Security Templates

# High-security template
template {
    neighbor secure-peer {
        router-id 10.0.0.1;
        local-as 65001;

        md5-password "ChangeThisPassword!";
        ttl-security 255;
        hold-time 90;

        family {
            ipv4 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }
    }
}

# Use for sensitive peers
neighbor 203.0.113.1 {
    inherit secure-peer;
    local-address 192.0.2.1;
    peer-as 13335;  # Cloudflare
    description "Critical Transit Provider";
    md5-password "ActualSecurePassword123!";  # Override default
}

Pattern 3: Multi-Hop iBGP Template

template {
    neighbor ibgp-rr-client {
        router-id 10.0.0.1;
        local-address 10.0.0.1;  # Loopback
        local-as 65001;
        peer-as 65001;  # iBGP

        multihop 5;

        family {
            ipv4 unicast;
            ipv6 unicast;
            ipv4 mpls-vpn;
        }

        capability {
            route-refresh;
            graceful-restart 120;
        }
    }
}

# Route reflector clients
neighbor 10.0.0.2 { inherit ibgp-rr-client; description "RR Client 1"; }
neighbor 10.0.0.3 { inherit ibgp-rr-client; description "RR Client 2"; }
neighbor 10.0.0.4 { inherit ibgp-rr-client; description "RR Client 3"; }

Real-World Examples

Example 1: ISP Edge Router (10 Upstreams)

process announce-anycast {
    run /etc/exabgp/api/announce_anycast.py;
    encoder text;
}

template {
    neighbor upstream-provider {
        router-id 192.0.2.1;
        local-as 65001;

        family {
            ipv4 unicast;
            ipv6 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }

        api {
            processes [ announce-anycast ];
        }
    }
}

# 10 upstream providers
neighbor 203.0.113.1 { inherit upstream-provider; local-address 203.0.113.2; peer-as 174; description "Cogent"; }
neighbor 203.0.113.5 { inherit upstream-provider; local-address 203.0.113.6; peer-as 1299; description "Telia"; }
neighbor 203.0.113.9 { inherit upstream-provider; local-address 203.0.113.10; peer-as 3356; description "Level3"; }
# ... 7 more providers

Example 2: Data Center Fabric (100 Leaf Switches)

Config generation for 100 leafs:

#!/usr/bin/env python3

# Template
template = """
template {{
    neighbor leaf-switch {{
        router-id 10.0.0.1;
        local-address 10.0.0.1;
        local-as 65000;

        family {{
            l2vpn evpn;
        }}

        capability {{
            extended-message;
        }}
    }}
}}
"""

# Generate 100 leaf neighbors
with open('/etc/exabgp/exabgp.conf', 'w') as f:
    f.write(template)

    for rack in range(1, 11):  # 10 racks
        for leaf in range(1, 11):  # 10 leafs per rack
            leaf_id = (rack - 1) * 10 + leaf
            leaf_ip = f"10.{rack}.{leaf}.1"

            f.write(f"""
neighbor {leaf_ip} {{
    inherit leaf-switch;
    peer-as 65{leaf_id:03d};
    description "Rack{rack:02d}-Leaf{leaf:02d}";
}}
""")

Example 3: DDoS Mitigation Network (50 Scrubbing Centers)

process ddos-blocker {
    run /etc/exabgp/api/ddos_blocker.py;
    encoder text;
}

template {
    neighbor scrubbing-center {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 flowspec;
        }

        api {
            processes [ ddos-blocker ];
        }
    }
}

# Regional scrubbing centers
group us-scrubbers {
    neighbor 192.168.1.1 { inherit scrubbing-center; local-address 192.168.1.2; peer-as 65000; description "US-East-1 Scrubber"; }
    neighbor 192.168.2.1 { inherit scrubbing-center; local-address 192.168.2.2; peer-as 65000; description "US-West-1 Scrubber"; }
    # ... more US
}

group eu-scrubbers {
    neighbor 192.168.10.1 { inherit scrubbing-center; local-address 192.168.10.2; peer-as 65000; description "EU-West-1 Scrubber"; }
    neighbor 192.168.11.1 { inherit scrubbing-center; local-address 192.168.11.2; peer-as 65000; description "EU-Central-1 Scrubber"; }
    # ... more EU
}

Best Practices

1. Name Templates Descriptively

Bad:

template { neighbor t1 { /* ... */ } }
template { neighbor t2 { /* ... */ } }

Good:

template { neighbor ebgp-unicast-peer { /* ... */ } }
template { neighbor ibgp-vpn-peer { /* ... */ } }
template { neighbor flowspec-ddos-peer { /* ... */ } }

2. Document Template Purpose

# Template: eBGP peers for internet transit
# Used by: All upstream providers
# Families: IPv4/IPv6 unicast
# Features: Graceful restart, route refresh
template {
    neighbor ebgp-transit {
        router-id 10.0.0.1;
        local-as 65001;

        family {
            ipv4 unicast;
            ipv6 unicast;
        }

        capability {
            route-refresh;
            graceful-restart;
        }
    }
}

3. Keep Templates Simple

Bad: Overly complex template

template {
    neighbor complex-template {
        # 50+ lines of configuration
        # ...
    }
}

Good: Break into focused templates

template {
    neighbor base-peer { /* Core settings */ }
    neighbor ebgp-peer { /* eBGP specifics */ }
    neighbor ibgp-peer { /* iBGP specifics */ }
}

4. Use Configuration Generation for Complex Hierarchies

ExaBGP doesn't support template inheritance directly. For complex scenarios, generate config:

# config_generator.py
class TemplateRegistry:
    def __init__(self):
        self.templates = {}

    def register(self, name, config):
        self.templates[name] = config

    def generate(self, template_name, overrides):
        base = self.templates[template_name].copy()
        base.update(overrides)
        return base

# Use it
registry = TemplateRegistry()
registry.register('base', {'router_id': '10.0.0.1', 'local_as': 65001})
registry.register('ebgp', {**registry.templates['base'], 'peer_as': 65000})

# Generate neighbor
neighbor = registry.generate('ebgp', {'local_address': '192.168.1.2'})

5. Version Control Your Templates

# Store templates in version control
/etc/exabgp/
β”œβ”€β”€ exabgp.conf              # Main config (generated)
β”œβ”€β”€ templates/
β”‚   β”œβ”€β”€ base.conf            # Base template
β”‚   β”œβ”€β”€ ebgp.conf            # eBGP template
β”‚   β”œβ”€β”€ ibgp.conf            # iBGP template
β”‚   └── flowspec.conf        # FlowSpec template
β”œβ”€β”€ peers/
β”‚   β”œβ”€β”€ transit.yaml         # Transit peer data
β”‚   └── customers.yaml       # Customer peer data
└── generate_config.py       # Config generator

Common Patterns

Pattern: eBGP + iBGP Separation

# eBGP template
template {
    neighbor ebgp-peer {
        router-id 10.0.0.1;
        local-as 65001;

        family { ipv4 unicast; ipv6 unicast; }
        capability { route-refresh; graceful-restart; }
    }
}

# iBGP template
template {
    neighbor ibgp-peer {
        router-id 10.0.0.1;
        local-address 10.0.0.1;
        local-as 65001;
        peer-as 65001;

        multihop 5;

        family { ipv4 unicast; ipv6 unicast; ipv4 mpls-vpn; }
        capability { route-refresh; graceful-restart 120; }
    }
}

# eBGP neighbors
neighbor 203.0.113.1 { inherit ebgp-peer; local-address 203.0.113.2; peer-as 174; }

# iBGP neighbors
neighbor 10.0.0.2 { inherit ibgp-peer; }
neighbor 10.0.0.3 { inherit ibgp-peer; }

Pattern: Staged Rollout

# Old template (existing neighbors)
template {
    neighbor legacy-peer {
        hold-time 180;
        capability { route-refresh; }
    }
}

# New template (improved settings)
template {
    neighbor modern-peer {
        hold-time 90;  # Faster failure detection
        capability { route-refresh; graceful-restart; }  # Added GR
    }
}

# Migrate neighbors gradually
neighbor 192.168.1.1 { inherit legacy-peer; /* ... */ }
neighbor 192.168.2.1 { inherit modern-peer; /* ... */ }  # Migrated
neighbor 192.168.3.1 { inherit legacy-peer; /* ... */ }

Troubleshooting

Problem: Template Not Found

Error:

Configuration error: template 'my-template' not found

Cause: Template not defined before use.

Fix:

# Define template BEFORE use
template {
    neighbor my-template { /* ... */ }
}

# Then use it
neighbor 192.168.1.1 {
    inherit my-template;
    # ...
}

Problem: Unexpected Override Behavior

Scenario:

template {
    neighbor my-template {
        hold-time 180;
    }
}

neighbor 192.168.1.1 {
    inherit my-template;
    hold-time 90;
}

Question: Why is hold-time 90, not 180?

Answer: Child configurations override template values. This is expected behavior.


Problem: Family Not Merged as Expected

Scenario:

template {
    neighbor my-template {
        family { ipv4 unicast; }
    }
}

neighbor 192.168.1.1 {
    inherit my-template;
    # Expecting both ipv4 and ipv6, but only have ipv4
}

Fix: Explicitly declare both families:

neighbor 192.168.1.1 {
    inherit my-template;
    family {
        ipv4 unicast;  # From template (merged)
        ipv6 unicast;  # Added
    }
}

Problem: Group Doesn't Work as Expected

ExaBGP group syntax is limited. For complex grouping, use config generation.

Instead of:

# Not supported: inherit in group
group my-group {
    inherit my-template;  # ERROR
    # ...
}

Use:

# Python config generator
for peer in group_members:
    print(f"""
neighbor {peer.ip} {{
    inherit my-template;
    local-address {peer.local_address};
    peer-as {peer.peer_as};
}}
""")

See Also


Ready to scale? Start with Quick Start Guide β†’


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

Clone this wiki locally