Configuring BGP
This document describes the device data model parameters one should consider when creating a BGP device configuration template. For a wider picture, please see the contributing new devices document.
Most of the document assumes you already created an Ansible task list that is able to deploy device configuration from a template. If you plan to use Ansible modules to build initial device configuration, see Using Ansible Configuration Modules for more details.
Notes:
The device configuration template (in Jinja2 format) should be stored in
netsim/templates/bgp/<nos>.j2with nos being the value of netlab_device_type or ansible_network_os variable (see Using Your Devices with Ansible Playbooks for more details.Most of the data model attributes are optional. Use
if sth is defined,sth|default(value)orif 'sth' in ifdatain your Jinja2 templates to check for the presence of optional attributes. Try to be consistent ;)
Supporting Multiple Address Families
The BGP data model assumes all devices handle dual-stack deployments and providers bgp.ipv4 and bgp.ipv6 attributes to indicate which address families you should configure.
BGP neighbors data can contain ipv4 and ipv6 addresses. If a neighbor has both addresses you have to configure two BGP neighbor sessions, one for IPv4, the other one for IPv6.
netlab assumes the IPv4 BGP session carries the IPv4 address family (plus other address families like MPLS/VPN or EVPN) and the IPv6 BGP session carries the IPv6 address family. It’s possible to disable the default address family with the activate BGP neighbor attribute.
Global BGP Parameters
netlab data model assumes a single BGP process running in the global routing table and VRFs (VRFs are not covered in this document). Device-wide parameters are set in bgp dictionary:
bgp.advertise_loopback (boolean) – When set to True, the BGP process should advertise the IPv4/IPv6 prefix assigned to loopback interface
bgp.as – The BGP AS number (always present)
bgp.community – The BGP communities propagation rules
bgp.ipv4 – You should configure IPv4 BGP address family
bgp.ipv6 – You should configure IPv6 BGP address family
bgp.neighbors – A list of IBGP and EBGP neighbors
bgp.next_hop_self – When set to True, the BGP process should set itself as the next hop on EBGP routes propagated as IBGP routes.
bgp.originate – A list of additional IPv4 prefixes that should be advertised by the BGP process. You’ll probably have to create static routes to support these prefixes.
bgp.router_id – The BGP router ID
bgp.rr – When set to True, the device is a BGP route reflector.
Interface BGP Parameters
There’s a single BGP-related interface parameter:
bgp.advertise – advertise the prefix assigned to the interface in the BGP process. Used to advertise stub networks instead of doing redistribution of connected prefixes.
BGP Neighbors
Each entry in the bgp.neighbors list describes an adjacent device that could be an endpoint of IBGP or EBGP sessions. A single adjacent device might have an IPv4 and an IPv6 BGP session, which would usually have to be configured as two distinct BGP neighbors.
A description of a BGP neighbor might have these parameters:
activate.ipv4 – Activate the IPv4 AF on the IPv4 BGP session.
activate.ipv6 – Activate the IPv6 AF on the IPv6 BGP session.
as – Remote autonomous system
local_as – Local autonomous system (when using local-as functionality)
ipv4 – IPv4 address of an IPv4 BGP neighbor
ipv6 – IPv6 address of an IPv6 BGP neighbor
name – Neighbor name (used in descriptions)
type – Neighbor type: ibgp, ebgp or localas_ibgp. The localas_ibgp type is used when the local_as turns an EBGP session into a fake IBGP session.
BGP Configuration Framework
The global BGP configuration should configure the BGP process and the address families. The configuration template should then use the bgp.neighbors list to configure individual BGP sessions, and activate those sessions within the address families. Finally, the template should originate the local prefixes.
Cisco IOS OSPFv2 example:
{% set pid = ospf.process|default(1) %}
router ospf {{ pid }}
{% if ospf.router_id|ipv4 %}
router-id {{ ospf.router_id }}
{% endif %}
{% if ospf.reference_bandwidth is defined %}
auto-cost reference-bandwidth {{ ospf.reference_bandwidth }}
{% endif %}
Arista EOS OSPFv3 example:
{% set pid = ospf.process|default(1) %}
ipv6 router ospf {{ pid }}
router-id {{ ospf.router_id }}
{% if ospf.reference_bandwidth is defined %}
auto-cost reference-bandwidth {{ ospf.reference_bandwidth }}
{% endif %}
Configuring OSPF Interfaces
OSPF interface parameters are specified within the ospf dictionary on individual interfaces. That dictionary may contain these parameters:
area – interface OSPF area (always present)
network_type – OSPF network type (optional, use platform default when the value is missing). Allowed values (when specified) are
point-to-point,point-to-multipoint,broadcast,non-broadcast.passive – interface is a passive OSPF interface (optional)
cost – interface cost
bfd – BFD is active on the interface (see IGP/BFD Interaction and IGP BFD Configuration Template Boilerplate for more details).
Interface part of OSPF configuration template starts with a for loop over all configured interfaces that have OSPF parameters. You MUST check for presence of ospf interface dictionary to exclude external (inter-AS) interfaces from the OSPF routing process.
You might want to use interface description as a comment to help you troubleshoot the final configuration snippets:
{% for l in interfaces if 'ospf' in l %}
interface {{ l.ifname }}
! {{ l.name|default("") }}
...
{% endfor %}
If you want to support OSPFv2 and OSPFv3 you should also check whether IPv4/IPv6 is configured on the interfaces. OSPFv3 example:
{% for l in interfaces if 'ospf' in l and 'ipv6' in l %}
interface {{ l.ifname }}
! {{ l.name|default("") }}
...
{% endfor %}
The rest of the interface configuration should check the presence of various attributes you decided to support. Nexus OS OSPFv2-only example:
{% for l in interfaces if 'ospf' in l %}
interface {{ l.ifname }}
! {{ l.name|default("") }}
ip router ospf {{ pid }} area {{ l.ospf.area }}
{% if l.ospf.network_type|default("") in ["broadcast","point-to-point"] %}
ip ospf network {{ l.ospf.network_type }}
{% endif %}
{% if l.ospf.cost is defined %}
ip ospf cost {{ l.ospf.cost }}
{% endif %}
{% if l.ospf.passive|default(False) %}
ip ospf passive-interface
{% endif %}
{% if l.ospf.bfd|default(False) %}
ip ospf bfd
{% endif %}
!
{% endfor %}
Configuring Passive Interfaces
Some network devices configure passive interfaces within the routing protocol configuration (example: Cisco IOS, Arista EOS), others configure them within interface configuration (see Nexus OS example above).
Cisco IOS passive interface configuration is done within router ospf block. OSPFv2 example:
{% set pid = ospf.process|default(1) %}
router ospf {{ pid }}
{% if ospf.router_id|ipv4 %}
router-id {{ ospf.router_id }}
{% endif %}
{% if ospf.reference_bandwidth is defined %}
auto-cost reference-bandwidth {{ ospf.reference_bandwidth }}
{% endif %}
{% for l in interfaces if l.ospf.passive|default(False) %}
passive-interface {{ l.ifname }}
{% endfor %}
Limited Network Type Support
Some devices (example: Nexus OS) don’t support all OSPF network types. OSPF module checks the validity of network_type value, but not the device support – check ospf.network_type value in configuration templates to prevent deployment errors.
Please note that the ospf.network_type is an optional attribute and might not be present. Use l.ospf.network_type is defined or l.ospf.network_type|default("") in your template.
Nexus OS OSPFv2-only example:
{% for l in interfaces if 'ospf' in l %}
interface {{ l.ifname }}
! {{ l.name|default("") }}
{% if l.ospf.network_type|default("") in ["broadcast","point-to-point"] %}
ip ospf network {{ l.ospf.network_type }}
{% endif %}
!
{% endfor %}
Mapping Network Type into Device-Specific Keywords
Junos configures OSPF network types with different keywords than most other devices, and uses lack of interface-type parameter to indicate broadcast OSPF network.
If you’re facing a similar challenge, use a mapping dictionary in your template:
{% set KW_NETWORK_TYPE = {'point-to-point': 'p2p','point-to-multipoint': 'p2mp', 'non-broadcast': 'nbma' } %}
protocols {
ospf {
{% for l in interfaces if 'ospf' in l %}
area {{ l.ospf.area }} {
interface {{ l.ifname }} {
{% if l.ospf.network_type is defined and l.ospf.network_type != 'broadcast' %}
interface-type {{ KW_NETWORK_TYPE[l.ospf.network_type] }};
{% endif %}
Unnumbered IPv4 Interfaces
Arista EOS needs additional OSPF settings to support OSPF over unnumbered IPv4 interfaces. Use ospf.unnumbered parameter to detect OSPF running over IPv4 unnumbered interface. Arista EOS OSPFv2 example:
router ospf {{ pid }}
{% if ospf.router_id|ipv4 %}
router-id {{ ospf.router_id }}
{% endif %}
{% if ospf.unnumbered is defined %}
interface unnumbered hello mask tx 0.0.0.0
{% endif %}