### This file is generated using Ansible and will be overwritten.
### Do not change this file directly!

log syslog all;
log "/var/log/bird.log" all;
debug protocols all;
timeformat base     iso long;
timeformat log      iso long;
timeformat protocol iso long;
timeformat route    iso long;

router id {{ router_id }};

define my_asn = {{ hessnet_asn }};

define my_prefixes_ipv6 = [
{% for prefix in v6_prefixes %}
	{{ prefix }}+{{"," if not loop.last }}
{% endfor %}
];

define my_prefixes_ipv4 = [
{% for prefix in v4_prefixes %}
	{{ prefix }}+{{"," if not loop.last }}
{% endfor %}
];

define my_net_aggregated_ipv6 = [
{% for prefix in v6_prefixes %}
	{{ prefix }}{{"," if not loop.last }}
{% endfor %}
];

define my_net_aggregated_ipv4 = [
{% for prefix in v4_prefixes %}
	{{ prefix }}{{"," if not loop.last }}
{% endfor %}
];

# functions and filters

function is_default_route() {
	case net.type {
		NET_IP4: if net = 0.0.0.0/0 then return true;
		NET_IP6: if net = ::/0 then return true;
	}
	return false;
}

function is_own_route() {
	case net.type {
		NET_IP4: if net ~ my_prefixes_ipv4 then return true;
		NET_IP6: if net ~ my_prefixes_ipv6 then return true;
	}
	return false;
}

function is_own_aggregated_net() {
	case net.type {
		NET_IP4: if net ~ my_net_aggregated_ipv4 then return true;
		NET_IP6: if net ~ my_net_aggregated_ipv6 then return true;
	}
	return false;
}

function honor_graceful_shutdown()
{
	# RFC 8326 Graceful BGP Session Shutdown
	if (65535, 0) ~ bgp_community then {
		bgp_local_pref = 0;
	}
}

function peer_export_default_only() {
	if !is_default_route() then reject;
	accept;
}

function peer_export_dfz() {
	if source !~ [ RTS_BGP, RTS_STATIC ] then reject;
	if is_default_route() then reject;
	accept;
}

function peer_export_dfz_and_default() {
	if is_default_route() then {
		peer_export_default_only();
	}
	else {
		peer_export_dfz();
	}
}

filter kernel_export {
	if source !~ [ RTS_BGP, RTS_OSPF, RTS_OSPF_EXT1, RTS_OSPF_EXT2, RTS_STATIC ] then reject;
	if is_default_route() then accept;
	if is_own_route() then accept;
	reject;
}

filter ospf_export {
	if source !~ [ RTS_DEVICE ] then reject;
	if is_own_route() then accept;
	reject;
}

filter transit_import {
	honor_graceful_shutdown();
#	bgp_large_community.add(({{hessnet_asn}},1,1));
	accept;
}

filter transit_export {
	if proto = "noAnnounce_v6" then reject;
	if proto = "noAnnounce_v4" then reject;
  	if is_own_aggregated_net() then accept;
    reject;
}

filter myroutes_import_export {
	if source !~ [ RTS_BGP, RTS_STATIC ] then reject;
	if is_own_route() then accept;
	reject;
}

{% if announce_from_here is sameas true %}
protocol static announce_v6 {
  	ipv6;
{% for prefix in v6_prefixes %}
  	route {{ prefix }} unreachable;
{% endfor %}
}

protocol static announce_v4 {
	ipv4;
{% for prefix in v4_prefixes %}
	route {{ prefix }} unreachable;
{% endfor %}
}
{% endif %}

protocol static noAnnounce_v6 {
	ipv6;
{% if configure_static_multihop_routes is sameas true %}
{% for peer in bgp_peers %}
{% if peer.neighbor_ip | ipv6 %}
	route {{ peer.neighbor_ip }}/128 via {{ router_v6_ip }};
{% endif %}
{% endfor %}
{% endif %}
{% if extra_static_routes is defined %}
    # other static routes
{% for route in extra_static_routes %}
	route {{ route.route }} via "{{ route.destination }}";
{% endfor %}
{% endif %}
}

protocol static noAnnounce_v4 {
	ipv4;
{% if configure_static_multihop_routes is sameas true %}
{% for peer in bgp_peers %}
{% if peer.neighbor_ip | ipv4 %}
	route {{ peer.neighbor_ip }}/32 via {{ router_v4_ip }};
{% endif %}
{% endfor %}
{% endif %}
}

protocol device { 
	scan time 5;
}

protocol direct {
	ipv6;
	interface "dummy*";
}

protocol kernel {
  	ipv4 {
    		import filter myroutes_import_export;
    		export filter kernel_export;
  	};
}

protocol kernel kernel6 {
  	ipv6 {
		import filter myroutes_import_export;
    	export filter kernel_export;
  	};
}

template bgp transit_v6 {
  	local as my_asn;
  	hold time 600;
  	ipv6 {
    		import filter transit_import; 
    		export filter transit_export;
  	};
}

template bgp transit_v4 {
  	local as my_asn;
  	hold time 600;
  	ipv4 {
    		import filter transit_import; 
    		export filter transit_export;
  	};
}

template bgp peer_vultr_v6 {
	local as my_asn;
	source address {{ router_v6_ip }};
	graceful restart on;
	multihop 2;
	ipv6 {
		import filter transit_import;
		export filter transit_export;
	};
}

template bgp peer_vultr_v4 {
	local as my_asn;
	source address {{router_v4_ip}};
	graceful restart on;
	multihop 2;
	ipv4 {
		import filter transit_import;
		export filter transit_export;
	};
}

template bgp peer_hessnet {
 	local as my_asn;
	ipv6 {
		#next hop self;
 		import none;
		export none;  
	};
}

template bgp ibgp_hessnet {
 	local as my_asn;
	ipv6 {
		next hop self;
 		import all;
		export filter { if is_own_route() then reject; accept; };  
	};
}

{% for peer in bgp_peers %}
protocol bgp {{ peer.name }} from {{ peer.template }} {
	neighbor {{peer.neighbor_ip}} as {{peer.peer_asn}};
{% if peer.password is defined %}
	password "{{ peer.password }}";
{% endif %}
{% if peer.filters is defined %}
	ipv6 {
		export filter {{ peer.filters.export }};
		import filter {{ peer.filters.import }};
	};
{% endif %}
}

{% endfor %}

# OSPF
protocol ospf v3 {
	area 0 {
		interface "dummy0" {
			stub;
		};
		
		interface "wg*" { };
		interface "tun*" { };
		interface "v6tunnel*" { };
	};
	
	ipv6 {
		import all;
		export filter ospf_export; 
	};
}
