402 lines
13 KiB
Django/Jinja
402 lines
13 KiB
Django/Jinja
{% set lo_address = interfaces | selectattr('name', '==', 'lo')
|
|
| map(attribute='ip_addresses') | first
|
|
| selectattr('role') | selectattr('role.value', '==', 'loopback')
|
|
| map(attribute='address') %}
|
|
{% set my_index = inventory_hostname.split('-')[1]|int %}
|
|
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
|
{% set my_vlans = bridge.tagged_vlans | sort(attribute='vid') -%}
|
|
|
|
frr defaults datacenter
|
|
log syslog informational
|
|
service integrated-vtysh-config
|
|
|
|
# Route to the outside world.
|
|
vrf outside
|
|
ip route 0.0.0.0/0 {{ (interfaces | selectattr('name', '==', iface_uplink) | first).custom_fields.gateway.address | ipaddr('address') }} {{ iface_uplink }}
|
|
ipv6 route ::/0 fe80::2 {{ iface_uplink }}
|
|
|
|
# Don’t announce anything at start until we get routes from all our peers.
|
|
# Without this packets might get dropped until all routes are synced.
|
|
bgp update-delay 10
|
|
|
|
# Route installation into kernel fails (rarely) without this option.
|
|
# It is not documented anywhere and appears to be a Cumulus extension.
|
|
zebra nexthop proto only
|
|
|
|
router-id {{ lo_address | ipv4 | first | ipaddr('address') }}
|
|
|
|
# Default VRF.
|
|
router bgp {{ asn.asn }}
|
|
bgp bestpath as-path multipath-relax
|
|
|
|
neighbor fabric peer-group
|
|
neighbor fabric remote-as external
|
|
neighbor fabric capability extended-nexthop
|
|
|
|
neighbor peerlink.4094 interface remote-as external
|
|
neighbor peerlink.4094 capability extended-nexthop
|
|
neighbor peerlink.4094 bfd 3 150 150
|
|
|
|
{% for iface in ifaces_fabric %}
|
|
neighbor {{ iface }} interface peer-group fabric
|
|
neighbor {{ iface }} bfd 3 150 150
|
|
{% endfor %}
|
|
|
|
address-family ipv4 unicast
|
|
redistribute connected route-map loopback
|
|
|
|
neighbor fabric soft-reconfiguration inbound
|
|
neighbor fabric route-map fabric->default in
|
|
neighbor fabric route-map default->fabric out
|
|
|
|
import vrf outside
|
|
import vrf route-map default-import
|
|
exit-address-family
|
|
|
|
address-family ipv6 unicast
|
|
redistribute connected route-map loopback
|
|
|
|
neighbor fabric activate
|
|
neighbor fabric soft-reconfiguration inbound
|
|
neighbor fabric route-map fabric->default in
|
|
neighbor fabric route-map default->fabric out
|
|
|
|
import vrf outside
|
|
import vrf route-map default-import
|
|
exit-address-family
|
|
|
|
address-family l2vpn evpn
|
|
advertise-all-vni
|
|
advertise-default-gw
|
|
neighbor fabric activate
|
|
neighbor peerlink.4094 activate
|
|
exit-address-family
|
|
|
|
|
|
# Outside VRF. Direct route to the world, everything else goes to the firewall.
|
|
router bgp {{ asn.asn }} vrf outside
|
|
bgp bestpath as-path multipath-relax
|
|
|
|
neighbor peerlink.4 interface remote-as external
|
|
neighbor peerlink.4 capability extended-nexthop
|
|
neighbor peerlink.4 bfd 3 150 150
|
|
|
|
neighbor firewall peer-group
|
|
neighbor firewall remote-as external
|
|
neighbor firewall capability extended-nexthop
|
|
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.4 interface peer-group firewall
|
|
neighbor {{ iface }}.4 bfd 3 150 150
|
|
{% endfor %}
|
|
|
|
address-family ipv4 unicast
|
|
neighbor peerlink.4 soft-reconfiguration inbound
|
|
neighbor peerlink.4 route-map peer.4->me in
|
|
neighbor peerlink.4 route-map me->peer.4 out
|
|
|
|
neighbor firewall allowas-in 1
|
|
neighbor firewall default-originate
|
|
neighbor firewall soft-reconfiguration inbound
|
|
neighbor firewall route-map outside->firewall out
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.4 route-map firewall-{{ loop.index }}->outside in
|
|
{% endfor %}
|
|
|
|
redistribute static
|
|
redistribute connected route-map loopback-outside
|
|
import vrf default
|
|
import vrf route-map outside-import
|
|
exit-address-family
|
|
|
|
address-family ipv6 unicast
|
|
neighbor peerlink.4 activate
|
|
neighbor peerlink.4 allowas-in origin
|
|
neighbor peerlink.4 soft-reconfiguration inbound
|
|
neighbor peerlink.4 route-map peer.4->me in
|
|
neighbor peerlink.4 route-map me->peer.4 out
|
|
|
|
neighbor firewall activate
|
|
neighbor firewall allowas-in 1
|
|
neighbor firewall default-originate
|
|
neighbor firewall soft-reconfiguration inbound
|
|
neighbor firewall route-map outside->firewall out
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.4 route-map firewall-{{ loop.index }}->outside in
|
|
{% endfor %}
|
|
|
|
redistribute static
|
|
redistribute connected route-map loopback-outside
|
|
import vrf default
|
|
import vrf route-map outside-import
|
|
exit-address-family
|
|
|
|
|
|
# Inside VRF. Default route via firewall. Direct routes to servers and offices.
|
|
router bgp {{ asn.asn }} vrf inside
|
|
bgp bestpath as-path multipath-relax
|
|
|
|
neighbor peerlink.2 interface remote-as external
|
|
neighbor peerlink.2 capability extended-nexthop
|
|
neighbor peerlink.2 bfd 3 150 150
|
|
|
|
neighbor firewall peer-group
|
|
neighbor firewall remote-as external
|
|
neighbor firewall capability extended-nexthop
|
|
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.2 interface peer-group firewall
|
|
neighbor {{ iface }}.2 bfd 3 150 150
|
|
{% endfor %}
|
|
|
|
address-family ipv4 unicast
|
|
neighbor peerlink.2 soft-reconfiguration inbound
|
|
neighbor peerlink.2 route-map peer.2->me in
|
|
neighbor peerlink.2 route-map me->peer.2 out
|
|
|
|
neighbor firewall allowas-in 1
|
|
neighbor firewall soft-reconfiguration inbound
|
|
neighbor firewall route-map inside->firewall out
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.2 route-map firewall-{{ loop.index }}->inside in
|
|
{% endfor %}
|
|
|
|
redistribute connected route-map loopback-inside
|
|
{% for vlan in my_vlans %}
|
|
import vrf {{ vlan.name }}
|
|
{% endfor %}
|
|
import vrf default
|
|
import vrf route-map inside-import
|
|
exit-address-family
|
|
|
|
address-family ipv6 unicast
|
|
neighbor peerlink.2 activate
|
|
neighbor peerlink.2 soft-reconfiguration inbound
|
|
neighbor peerlink.2 route-map peer.2->me in
|
|
neighbor peerlink.2 route-map me->peer.2 out
|
|
|
|
neighbor firewall activate
|
|
neighbor firewall allowas-in 1
|
|
neighbor firewall soft-reconfiguration inbound
|
|
neighbor firewall route-map inside->firewall out
|
|
{% for iface in ifaces_firewall %}
|
|
neighbor {{ iface }}.2 route-map firewall-{{ loop.index }}->inside in
|
|
{% endfor %}
|
|
|
|
redistribute connected route-map loopback-inside
|
|
{% for vlan in my_vlans %}
|
|
import vrf {{ vlan.name }}
|
|
{% endfor %}
|
|
import vrf default
|
|
import vrf route-map inside-import
|
|
exit-address-family
|
|
|
|
|
|
{% for vlan in my_vlans %}
|
|
# VRF for L2 network {{ vlan.name }}. Imports gateway from inside VRF.
|
|
router bgp {{ asn.asn }} vrf {{ vlan.name }}
|
|
bgp bestpath as-path multipath-relax
|
|
|
|
address-family ipv4 unicast
|
|
redistribute connected
|
|
import vrf inside
|
|
import vrf route-map office-import
|
|
exit-address-family
|
|
|
|
address-family ipv6 unicast
|
|
redistribute connected
|
|
import vrf inside
|
|
import vrf route-map office-import
|
|
exit-address-family
|
|
|
|
{% endfor %}
|
|
|
|
# Prefix lists.
|
|
ip prefix-list default permit 0.0.0.0/0
|
|
ipv6 prefix-list default permit ::/0
|
|
|
|
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
|
ipv6 prefix-list fabric permit 2001:1470:fffd:3400::/64 ge 128
|
|
|
|
{% for vlan in my_vlans %}
|
|
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true) %}
|
|
{% for prefix in prefixes %}
|
|
{% if prefix.family.value == 4 %}
|
|
ip prefix-list office permit {{ prefix.prefix }} ge 24
|
|
{% else %}
|
|
ipv6 prefix-list office permit {{ prefix.prefix }} ge 64
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
|
|
ip prefix-list vpn permit {{ wg_net | ipaddr('subnet') }}
|
|
|
|
ip prefix-list nat permit {{ wg_ip | ipaddr('host') }}
|
|
{% for network in nat %}
|
|
ip prefix-list nat permit {{ network }}
|
|
{% endfor %}
|
|
|
|
{% for prefix in query('netbox.netbox.nb_lookup', 'prefixes', raw_data=true, api_filter='role=bgp') | selectattr('tenant') %}
|
|
{% if prefix.family.value == 4 %}
|
|
ip prefix-list dc permit {{ prefix.prefix }} ge 32
|
|
{% else %}
|
|
ipv6 prefix-list dc permit {{ prefix.prefix }} ge 64
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
# Route maps for redistributing own IPs from various VRFs.
|
|
route-map loopback permit 1
|
|
match interface lo
|
|
route-map loopback-inside permit 1
|
|
match interface inside
|
|
route-map loopback-outside permit 1
|
|
match interface outside
|
|
|
|
# Route maps for importing between VRFs.
|
|
route-map default-import permit 10
|
|
match ip address prefix-list default
|
|
route-map default-import permit 11
|
|
match ipv6 address prefix-list default
|
|
route-map default-import permit 21
|
|
match ipv6 address prefix-list office
|
|
route-map default-import permit 30
|
|
match ip address prefix-list nat
|
|
|
|
route-map outside-import permit 10
|
|
match ip address prefix-list dc
|
|
route-map outside-import permit 11
|
|
match ipv6 address prefix-list dc
|
|
|
|
route-map office-import permit 10
|
|
match ip address prefix-list default
|
|
route-map office-import permit 11
|
|
match ipv6 address prefix-list default
|
|
|
|
route-map inside-import permit 20
|
|
match ip address prefix-list office
|
|
route-map inside-import permit 21
|
|
match ipv6 address prefix-list office
|
|
|
|
# Route maps for advertised and received routes.
|
|
# Inside ↔ fabric.
|
|
route-map default->fabric permit 10
|
|
match ip address prefix-list default
|
|
route-map default->fabric permit 11
|
|
match ipv6 address prefix-list default
|
|
route-map default->fabric permit 20
|
|
match ip address prefix-list fabric
|
|
|
|
route-map fabric->default permit 10
|
|
match ip address prefix-list fabric
|
|
route-map fabric->default permit 20
|
|
match ip address prefix-list dc
|
|
route-map fabric->default permit 21
|
|
match ipv6 address prefix-list dc
|
|
|
|
# Inside ↔ firewall.
|
|
route-map inside->firewall permit 1
|
|
match interface lo
|
|
route-map inside->firewall permit 20
|
|
match ip address prefix-list office
|
|
route-map inside->firewall permit 21
|
|
match ipv6 address prefix-list office
|
|
|
|
route-map firewall->inside permit 1
|
|
match ip address prefix-list fabric
|
|
route-map firewall->inside permit 2
|
|
match ipv6 address prefix-list fabric
|
|
route-map firewall->inside permit 10
|
|
match ip address prefix-list default
|
|
route-map firewall->inside permit 11
|
|
match ipv6 address prefix-list default
|
|
|
|
# Outside ↔ firewall.
|
|
route-map outside->firewall permit 10
|
|
match ip address prefix-list default
|
|
route-map outside->firewall permit 11
|
|
match ipv6 address prefix-list default
|
|
|
|
route-map firewall->outside permit 1
|
|
match ip address prefix-list fabric
|
|
route-map firewall->outside permit 2
|
|
match ipv6 address prefix-list fabric
|
|
route-map firewall->outside permit 21
|
|
match ipv6 address prefix-list office
|
|
route-map firewall->outside permit 30
|
|
match ip address prefix-list nat
|
|
|
|
# Tag routes from each firewall. Set weight for primary to 200 and secondary to 100.
|
|
{% for firewall in ifaces_firewall %}
|
|
route-map firewall-{{ loop.index }}->inside permit 1
|
|
set tag {{ loop.index }}
|
|
set weight {{ 100 * loop.index }}
|
|
call firewall->inside
|
|
route-map firewall-{{ loop.index }}->outside permit 1
|
|
set tag {{ loop.index }}
|
|
set weight {{ 100 * loop.index }}
|
|
call firewall->outside
|
|
{% endfor %}
|
|
|
|
# Backup routes over peer link are announced to the peer with BGP
|
|
# metrics 190 and 90. These values are copied to weights by receiving
|
|
# peer, to be used alongside local routes with weights 200 and 100.
|
|
# These are the route maps for peerlink in the inside VRF.
|
|
{% for firewall in ifaces_firewall %}
|
|
{% set metric = 100 * loop.index - 10 %}
|
|
route-map me->peer.2 permit {{ loop.index }}
|
|
match tag {{ loop.index }}
|
|
on-match goto 100
|
|
set metric {{ metric }}
|
|
route-map peer.2->me permit {{ loop.index }}
|
|
match metric {{ metric }}
|
|
on-match goto 100
|
|
set weight {{ metric }}
|
|
{% endfor %}
|
|
|
|
# Advertised backup routes for paths that go through the firewall
|
|
# (default route).
|
|
route-map me->peer.2 permit 110
|
|
match ip address prefix-list default
|
|
route-map me->peer.2 permit 111
|
|
match ipv6 address prefix-list default
|
|
|
|
# Received backup routes (same as above).
|
|
route-map peer.2->me permit 110
|
|
match ip address prefix-list default
|
|
route-map peer.2->me permit 111
|
|
match ipv6 address prefix-list default
|
|
|
|
# These are the route maps for peerlink in the outside VRF.
|
|
{% for firewall in ifaces_firewall %}
|
|
{% set metric = 100 * loop.index - 10 %}
|
|
route-map me->peer.4 permit {{ loop.index }}
|
|
match tag {{ loop.index }}
|
|
on-match goto 100
|
|
set metric {{ metric }}
|
|
route-map peer.4->me permit {{ loop.index }}
|
|
match metric {{ metric }}
|
|
on-match goto 100
|
|
set weight {{ metric }}
|
|
{% endfor %}
|
|
|
|
# Backup routes for uplink and paths that go through the firewall
|
|
# (default route and NAT/IPv6 addresses for office networks).
|
|
route-map me->peer.4 permit 110
|
|
match ip address prefix-list default
|
|
route-map me->peer.4 permit 111
|
|
match ipv6 address prefix-list default
|
|
route-map me->peer.4 permit 120
|
|
match ip address prefix-list nat
|
|
route-map me->peer.4 permit 131
|
|
match ipv6 address prefix-list office
|
|
|
|
# Received backup routes (same as above).
|
|
route-map peer.4->me permit 110
|
|
match ip address prefix-list default
|
|
route-map peer.4->me permit 111
|
|
match ipv6 address prefix-list default
|
|
route-map peer.4->me permit 120
|
|
match ip address prefix-list nat
|
|
route-map peer.4->me permit 131
|
|
match ipv6 address prefix-list office
|