141 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Django/Jinja
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Django/Jinja
		
	
	
	
	
	
| {% set addrs = interfaces | selectattr('name', '==', 'lo') |
 | |
|         map(attribute='ip_addresses') | first | selectattr('role') %}
 | |
| {% set loopback = addrs | selectattr('role.value', '==', 'loopback') | map(attribute='address') -%}
 | |
| 
 | |
| frr defaults datacenter
 | |
| service integrated-vtysh-config
 | |
| log syslog
 | |
| 
 | |
| # Without this frr and kernel ECMP routes sometimes get desynced when a link is
 | |
| # lost and found. Maybe related to https://github.com/FRRouting/frr/issues/12239.
 | |
| zebra nexthop-group keep 1
 | |
| 
 | |
| router-id {{ loopback | ipv4 | first | ipaddr('address') }}
 | |
| 
 | |
| bfd
 | |
|   profile fast
 | |
|     receive-interval 150
 | |
|     transmit-interval 150
 | |
| 
 | |
| # Default VRF has two connections to each exit, one for inside and one
 | |
| # for outside networks. The efault route is received from the outside
 | |
| # peers and distributed back to inside peers. Routes to office
 | |
| # networks and NAT IPs are distributed to outside peers.
 | |
| router bgp {{ asn.asn }}
 | |
|   # Allow multipathing through different ASs with equal path length.
 | |
|   bgp bestpath as-path multipath-relax
 | |
|   # NAT IPs are not on any interface so disable checking for it.
 | |
|   no bgp network import-check
 | |
| 
 | |
| {% for group in ['inside', 'outside'] %}
 | |
|   neighbor {{ group }} peer-group
 | |
|   neighbor {{ group }} remote-as external
 | |
|   neighbor {{ group }} capability extended-nexthop
 | |
| {% endfor %}
 | |
| 
 | |
| {% for iface in interfaces | selectattr('name', 'match', '^lan') %}
 | |
|   neighbor {{ iface.name }}.2 interface peer-group inside
 | |
|   neighbor {{ iface.name }}.2 bfd profile fast
 | |
|   neighbor {{ iface.name }}.4 interface peer-group outside
 | |
|   neighbor {{ iface.name }}.4 bfd profile fast
 | |
| {% endfor %}
 | |
| 
 | |
| {% for family in ['ipv4', 'ipv6'] %}
 | |
|   address-family {{ family }} unicast
 | |
| {% if family == 'ipv4' %}
 | |
| {% for network in nat %}
 | |
|     network {{ network }}
 | |
| {% endfor %}
 | |
| 
 | |
| {% endif %}
 | |
|     redistribute connected route-map loopback
 | |
|     maximum-paths 16
 | |
| 
 | |
|     neighbor outside activate
 | |
|     neighbor outside soft-reconfiguration inbound
 | |
|     neighbor outside route-map outside->default in
 | |
|     neighbor outside route-map default->outside out
 | |
| 
 | |
|     neighbor inside activate
 | |
|     neighbor inside allowas-in origin
 | |
|     neighbor inside default-originate
 | |
|     neighbor inside soft-reconfiguration inbound
 | |
|     neighbor inside route-map inside->default in
 | |
|     neighbor inside route-map default->inside out
 | |
|   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
 | |
| 
 | |
| {% for prefix in vrf_prefixes | rejectattr('vrf.name', '==', 'outside')
 | |
|     | sort(attribute='family.value') %}
 | |
| {% if prefix.family.value == 4 %}
 | |
| ip prefix-list office permit {{ prefix.prefix }}
 | |
| {% elif prefix.family.value == 6 %}
 | |
| ipv6 prefix-list office permit {{ prefix.prefix }}
 | |
| {% endif %}
 | |
| {% endfor %}
 | |
| 
 | |
| {% if wg_net is defined %}
 | |
| ip prefix-list vpn permit {{ wg_net | ipaddr('subnet') }}
 | |
| {% endif %}
 | |
| {% if wg_net6 is defined %}
 | |
| ipv6 prefix-list vpn permit {{ wg_net6 | ipaddr('subnet') }}
 | |
| {% endif %}
 | |
| 
 | |
| {% for network in nat %}
 | |
| ip prefix-list nat permit {{ network }}
 | |
| {% endfor %}
 | |
| {# TODO WG endpoint should probably be in a separate prefix-list. #}
 | |
| ip prefix-list nat permit {{ wg_ip }}
 | |
| 
 | |
| route-map loopback permit 1
 | |
|   match interface lo
 | |
| route-map loopback permit 2
 | |
|   match interface wg
 | |
| 
 | |
| # Get routes to offices from inside peers.
 | |
| route-map inside->default permit 10
 | |
|   match ip address prefix-list fabric
 | |
| route-map inside->default permit 20
 | |
|   match ip address prefix-list office
 | |
| route-map inside->default permit 21
 | |
|   match ipv6 address prefix-list office
 | |
| 
 | |
| # Send default route and VPN network to inside peers.
 | |
| route-map default->inside permit 1
 | |
|   match interface lo
 | |
| route-map default->inside permit 20
 | |
|   match ip address prefix-list default
 | |
| route-map default->inside permit 21
 | |
|   match ipv6 address prefix-list default
 | |
| # I don’t think these /need/ to be announced separately since we are sending the default route anyway.
 | |
| #route-map default->inside permit 30
 | |
| #  match ip address prefix-list vpn
 | |
| #route-map default->inside permit 31
 | |
| #  match ipv6 address prefix-list vpn
 | |
| 
 | |
| # Get default route from outside peers.
 | |
| route-map outside->default permit 10
 | |
|   match ip address prefix-list default
 | |
| route-map outside->default permit 11
 | |
|   match ipv6 address prefix-list default
 | |
| 
 | |
| # Send inside and NAT addresses to outside peers so inbound packets go through the firewall.
 | |
| route-map default->outside permit 1
 | |
|   match interface lo
 | |
| route-map default->outside permit 20
 | |
|   match ip address prefix-list office
 | |
| route-map default->outside permit 21
 | |
|   match ipv6 address prefix-list office
 | |
| route-map default->outside permit 30
 | |
|   match ip address prefix-list nat
 | |
| route-map default->outside permit 40
 | |
|   match ip address prefix-list vpn
 | |
| route-map default->outside permit 41
 | |
|   match ipv6 address prefix-list vpn
 |