Base BIRD setup
This commit is contained in:
parent
5c114b7602
commit
46b10f53af
15 changed files with 335 additions and 9 deletions
inventory/production
playbooks
roles
bird_base
bird_edge
tasks
templates/bird
bgp-peers.d
conf.d
filter.d
|
@ -1,10 +1,3 @@
|
|||
---
|
||||
nullmailer_relay: srv-mail-infra.echirolles.fr
|
||||
nullmailer_dest_addr: admininfrastructure@echirolles.fr
|
||||
nullmailer_defaultdomain: echirolles.fr
|
||||
|
||||
borgmatic_server: 'ssh://borgbackup@pbs1.echirolles.fr/.'
|
||||
|
||||
firewall_allow_checkmk: true
|
||||
checkmk_servers:
|
||||
- 10.35.40.25
|
||||
my_asn: 4242422112
|
||||
my_net: 'fd73:ea37:6131::/48'
|
||||
|
|
2
inventory/production/group_vars/fr-gnb1.yml
Normal file
2
inventory/production/group_vars/fr-gnb1.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
location_id: 16
|
|
@ -1 +1,4 @@
|
|||
---
|
||||
router_ip6: 'fd73:ea37:6131:1600::1'
|
||||
bird_region: 41
|
||||
bird_country: 1250
|
||||
|
|
|
@ -4,6 +4,14 @@ soldanelle.tobast.dn42 ansible_host=2001:912:1ac0:2fb0:be24:11ff:fef3:1906
|
|||
[fully_managed]
|
||||
soldanelle.tobast.dn42
|
||||
|
||||
## Geo groups
|
||||
[fr-gnb1]
|
||||
soldanelle.tobast.dn42
|
||||
|
||||
## Functionnal groups
|
||||
[edge_router]
|
||||
soldanelle.tobast.dn42
|
||||
|
||||
[nginx]
|
||||
|
||||
## Groups configuration
|
||||
|
|
5
playbooks/deploy_bird.yml
Normal file
5
playbooks/deploy_bird.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- hosts: edge_router
|
||||
roles:
|
||||
- bird_base
|
||||
- bird_edge
|
14
roles/bird_base/README.md
Normal file
14
roles/bird_base/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Bird base
|
||||
|
||||
Base installation or BIRD routing daemon. Does not configure further routing.
|
||||
|
||||
## Variables
|
||||
|
||||
* `bird_region`: region, as of DN42 BGP communities
|
||||
* `bird_country`: country, as ISO-3166 country code + 1000
|
||||
|
||||
### Shared between roles
|
||||
|
||||
* `router_ip6`: main ipv6 address of the router
|
||||
* `location_id`: typically defined in the geographical group. ID of this
|
||||
location, typically in 16-ff.
|
35
roles/bird_base/tasks/main.yml
Normal file
35
roles/bird_base/tasks/main.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
- name: Install BIRD
|
||||
apt:
|
||||
name: bird2
|
||||
|
||||
- name: Create configuration directiries
|
||||
file:
|
||||
path: "/etc/bird/{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: bird
|
||||
mode: 0750
|
||||
loop:
|
||||
- conf.d
|
||||
- filter.d
|
||||
|
||||
- name: Install configuration templates
|
||||
template:
|
||||
src: '{{ item }}.conf.j2'
|
||||
dest: '/etc/bird/{{ item }}.conf'
|
||||
loop:
|
||||
- header
|
||||
- bird
|
||||
- filter.d/10-base_filters
|
||||
|
||||
- name: Fetch ROA6 file (FIXME)
|
||||
get_url:
|
||||
url: 'https://dn42.burble.com/roa/dn42_roa_bird2_6.conf'
|
||||
dest: '/etc/bird/dn42_roa_6.conf'
|
||||
|
||||
- name: Etckeeper - commit
|
||||
import_role:
|
||||
name: etckeeper_commit
|
||||
vars:
|
||||
etckeeper_reason: Configure base BIRD
|
64
roles/bird_base/templates/bird.conf.j2
Normal file
64
roles/bird_base/templates/bird.conf.j2
Normal file
|
@ -0,0 +1,64 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
include "/etc/bird/header.conf";
|
||||
|
||||
# Configure logging
|
||||
log syslog all;
|
||||
# log "/var/log/bird.log" { debug, trace, info, remote, warning, error, auth, fatal, bug };
|
||||
|
||||
# Set router ID. It is a unique identification of your router, usually one of
|
||||
# IPv4 addresses of the router. It is recommended to configure it explicitly.
|
||||
# router id 198.51.100.1;
|
||||
router id MY_RID;
|
||||
hostname HOSTNAME;
|
||||
|
||||
#####
|
||||
## END HEADER
|
||||
#####
|
||||
|
||||
function is_self_net() {
|
||||
return net ~ MY_NET;
|
||||
}
|
||||
function is_within_self_net() {
|
||||
return net ~ MY_NETSET;
|
||||
}
|
||||
function is_valid_network() {
|
||||
return net ~ [fd00::/8{44,64}];
|
||||
}
|
||||
|
||||
include "/etc/bird/filter.d/*.conf";
|
||||
|
||||
include "/etc/bird/conf.d/*.conf";
|
||||
|
||||
# The Device protocol is not a real routing protocol. It does not generate any
|
||||
# routes and it only serves as a module for getting information about network
|
||||
# interfaces from the kernel. It is necessary in almost any configuration.
|
||||
protocol device {}
|
||||
|
||||
# The direct protocol is not a real routing protocol. It automatically generates
|
||||
# direct routes to all network interfaces. Can exist in as many instances as you
|
||||
# wish if you want to populate multiple routing tables with direct routes.
|
||||
protocol direct {
|
||||
disabled; # Disable by default
|
||||
#ipv4; # Connect to default IPv4 table
|
||||
#ipv6; # ... and to default IPv6 table
|
||||
}
|
||||
|
||||
# The Kernel protocol is not a real routing protocol. Instead of communicating
|
||||
# with other routers in the network, it performs synchronization of BIRD
|
||||
# routing tables with the OS kernel. One instance per table.
|
||||
protocol kernel kernel4 {
|
||||
description "Kernel IPv4";
|
||||
ipv4 { export all; };
|
||||
}
|
||||
|
||||
protocol kernel kernel6 {
|
||||
description "Kernel IPv6";
|
||||
ipv6 { export all; };
|
||||
}
|
||||
|
||||
protocol static static_exported_my_AS {
|
||||
description "AS{{ my_asn }}";
|
||||
route MY_NET unreachable;
|
||||
ipv6 {};
|
||||
}
|
17
roles/bird_base/templates/filter.d/10-base_filters.conf.j2
Normal file
17
roles/bird_base/templates/filter.d/10-base_filters.conf.j2
Normal file
|
@ -0,0 +1,17 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
function is_martians() {
|
||||
return net ~ [ 169.254.0.0/16+, 224.0.0.0/4+, 240.0.0.0/4+, 0.0.0.0/32{1,32}];
|
||||
}
|
||||
|
||||
function is_rfc1918() {
|
||||
return net ~ [ 172.16.0.0/12+, 192.168.0.0/16+, 10.0.0.0/8+ ];
|
||||
}
|
||||
|
||||
function is_default () {
|
||||
return net ~ [ ::/0 ];
|
||||
}
|
||||
|
||||
function is_exportable() {
|
||||
return net ~ MY_NETSET;
|
||||
}
|
11
roles/bird_base/templates/header.conf.j2
Normal file
11
roles/bird_base/templates/header.conf.j2
Normal file
|
@ -0,0 +1,11 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
define MY_ASN = {{ my_asn }};
|
||||
define MY_IP = {{ router_ip6 }};
|
||||
define MY_NET = {{ my_net }};
|
||||
define MY_NETSET = [{{my_net}}+];
|
||||
define MY_RID = 42.21.12.{{ location_id }};
|
||||
define HOSTNAME = "{{ ansible_fqdn }}";
|
||||
|
||||
define REGION = {{ bird_region }};
|
||||
define COUNTRY = {{ bird_country }};
|
26
roles/bird_edge/tasks/main.yml
Normal file
26
roles/bird_edge/tasks/main.yml
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
- name: Create configuration directiries
|
||||
file:
|
||||
path: "/etc/bird/{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: bird
|
||||
mode: 0750
|
||||
loop:
|
||||
- bgp-peers.d
|
||||
|
||||
- name: Install configuration templates
|
||||
template:
|
||||
src: 'bird/{{ item }}.conf.j2'
|
||||
dest: '/etc/bird/{{ item }}.conf'
|
||||
loop:
|
||||
- conf.d/30-bgp
|
||||
- filter.d/25-community_filters
|
||||
- filter.d/30-bgp_filters
|
||||
- bgp-peers.d/00-dummy
|
||||
|
||||
- name: Etckeeper - commit
|
||||
import_role:
|
||||
name: etckeeper_commit
|
||||
vars:
|
||||
etckeeper_reason: Configure BIRD for edge routing
|
|
@ -0,0 +1,4 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
# This page intentionnaly left blank
|
||||
# (BIRD complains about empty glob otherwise)
|
22
roles/bird_edge/templates/bird/conf.d/30-bgp.conf.j2
Normal file
22
roles/bird_edge/templates/bird/conf.d/30-bgp.conf.j2
Normal file
|
@ -0,0 +1,22 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
template bgp dn42_peer {
|
||||
description "DN42 peering";
|
||||
local as MY_ASN;
|
||||
advertise hostname on;
|
||||
|
||||
enforce first as on;
|
||||
prefer older on;
|
||||
|
||||
graceful restart on;
|
||||
long lived graceful restart on;
|
||||
enable extended messages on;
|
||||
|
||||
bfd graceful;
|
||||
|
||||
ipv6 {
|
||||
next hop self;
|
||||
};
|
||||
}
|
||||
|
||||
include "/etc/bird/bgp-peers.d/*.conf";
|
|
@ -0,0 +1,47 @@
|
|||
#/etc/bird/community_filters.conf
|
||||
function update_latency(int link_latency) {
|
||||
bgp_community.add((64511, link_latency));
|
||||
if (64511, 9) ~ bgp_community then { bgp_community.delete([(64511, 1..8)]); return 9; }
|
||||
else if (64511, 8) ~ bgp_community then { bgp_community.delete([(64511, 1..7)]); return 8; }
|
||||
else if (64511, 7) ~ bgp_community then { bgp_community.delete([(64511, 1..6)]); return 7; }
|
||||
else if (64511, 6) ~ bgp_community then { bgp_community.delete([(64511, 1..5)]); return 6; }
|
||||
else if (64511, 5) ~ bgp_community then { bgp_community.delete([(64511, 1..4)]); return 5; }
|
||||
else if (64511, 4) ~ bgp_community then { bgp_community.delete([(64511, 1..3)]); return 4; }
|
||||
else if (64511, 3) ~ bgp_community then { bgp_community.delete([(64511, 1..2)]); return 3; }
|
||||
else if (64511, 2) ~ bgp_community then { bgp_community.delete([(64511, 1..1)]); return 2; }
|
||||
else return 1;
|
||||
}
|
||||
|
||||
function update_bandwidth(int link_bandwidth) {
|
||||
bgp_community.add((64511, link_bandwidth));
|
||||
if (64511, 21) ~ bgp_community then { bgp_community.delete([(64511, 22..29)]); return 21; }
|
||||
else if (64511, 22) ~ bgp_community then { bgp_community.delete([(64511, 23..29)]); return 22; }
|
||||
else if (64511, 23) ~ bgp_community then { bgp_community.delete([(64511, 24..29)]); return 23; }
|
||||
else if (64511, 24) ~ bgp_community then { bgp_community.delete([(64511, 25..29)]); return 24; }
|
||||
else if (64511, 25) ~ bgp_community then { bgp_community.delete([(64511, 26..29)]); return 25; }
|
||||
else if (64511, 26) ~ bgp_community then { bgp_community.delete([(64511, 27..29)]); return 26; }
|
||||
else if (64511, 27) ~ bgp_community then { bgp_community.delete([(64511, 28..29)]); return 27; }
|
||||
else if (64511, 28) ~ bgp_community then { bgp_community.delete([(64511, 29..29)]); return 28; }
|
||||
else return 29;
|
||||
}
|
||||
|
||||
function update_crypto(int link_crypto) {
|
||||
bgp_community.add((64511, link_crypto));
|
||||
if (64511, 31) ~ bgp_community then { bgp_community.delete([(64511, 32..34)]); return 31; }
|
||||
else if (64511, 32) ~ bgp_community then { bgp_community.delete([(64511, 33..34)]); return 32; }
|
||||
else if (64511, 33) ~ bgp_community then { bgp_community.delete([(64511, 34..34)]); return 33; }
|
||||
else return 34;
|
||||
}
|
||||
|
||||
function update_flags(int link_latency; int link_bandwidth; int link_crypto)
|
||||
int dn42_latency;
|
||||
int dn42_bandwidth;
|
||||
int dn42_crypto;
|
||||
{
|
||||
dn42_latency = update_latency(link_latency);
|
||||
dn42_bandwidth = update_bandwidth(link_bandwidth) - 20;
|
||||
dn42_crypto = update_crypto(link_crypto) - 30;
|
||||
# replace 4 with your calculated bandwidth value
|
||||
if dn42_bandwidth > 4 then dn42_bandwidth = 4;
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
{{ ansible_managed | comment }}
|
||||
|
||||
roa6 table dn42_roa6;
|
||||
|
||||
protocol static {
|
||||
roa6 { table dn42_roa6; };
|
||||
include "/etc/bird/dn42_roa_6.conf";
|
||||
}
|
||||
|
||||
function dn42_update_geo() {
|
||||
if is_self_net() then {
|
||||
bgp_community.add((64511, REGION));
|
||||
bgp_community.add((64511, COUNTRY));
|
||||
}
|
||||
}
|
||||
|
||||
function dn42_reject_roa() {
|
||||
if (roa_check(dn42_roa6, net, bgp_path.last) != ROA_VALID) then {
|
||||
print "Reject: bad ROA";
|
||||
reject;
|
||||
}
|
||||
}
|
||||
|
||||
function bgp_dn42_import(
|
||||
string import_type; int link_latency; int link_bw; int link_crypto
|
||||
) {
|
||||
if ! (import_type = "transit-backup" || import_type = "transit" || import_type="core") then {
|
||||
print "bgp_import: parametre import_type invalide";
|
||||
reject;
|
||||
}
|
||||
|
||||
# weird routes are not accepted
|
||||
if is_default() || is_martians() || is_rfc1918() then reject;
|
||||
|
||||
# Restrict networks to DN42
|
||||
if (!is_valid_network()) then reject;
|
||||
|
||||
# own routes are not accepted
|
||||
if is_self_net() then reject;
|
||||
|
||||
# in case of peering or transit, the routes within own network are not accepted.
|
||||
if import_type = "transit" || import_type = "transit-backup" then {
|
||||
if is_within_self_net() then reject;
|
||||
}
|
||||
|
||||
dn42_reject_roa();
|
||||
|
||||
update_flags(link_latency, link_bw, link_crypto);
|
||||
dn42_update_geo();
|
||||
|
||||
# bgp local preference by default
|
||||
if import_type = "transit-backup" then bgp_local_pref=50;
|
||||
if import_type = "transit" then bgp_local_pref=100;
|
||||
|
||||
krt_prefsrc = MY_IP;
|
||||
|
||||
accept;
|
||||
}
|
||||
|
||||
function bgp_dn42_export(
|
||||
int link_latency; int link_bw; int link_crypto
|
||||
) {
|
||||
if (source !~ [RTS_STATIC, RTS_BGP]) then reject;
|
||||
|
||||
# weird routes are not accepted
|
||||
if is_default() || is_martians() || is_rfc1918() then reject;
|
||||
|
||||
# Restrict networks to DN42
|
||||
if (!is_valid_network()) then reject;
|
||||
|
||||
update_flags(link_latency, link_bw, link_crypto);
|
||||
dn42_update_geo();
|
||||
|
||||
accept;
|
||||
}
|
Loading…
Add table
Reference in a new issue