From f8cb06b8d5b6e91ef8e80857f74eca997dc4ac09 Mon Sep 17 00:00:00 2001
From: Nico Boehr <nico@nicoboehr.de>
Date: Sat, 31 May 2025 12:50:28 +0200
Subject: [PATCH] backbone_babel: add optional support for bird

---
 roles/backbone_babel/defaults/main.yml        |  1 +
 roles/backbone_babel/tasks/main.yml           |  6 +++
 roles/backbone_babel/tasks/routing_bird.yml   | 34 +++++++++++++
 .../templates/bird-backbone-babel.conf.j2     | 50 +++++++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 roles/backbone_babel/tasks/routing_bird.yml
 create mode 100644 roles/backbone_babel/templates/bird-backbone-babel.conf.j2

diff --git a/roles/backbone_babel/defaults/main.yml b/roles/backbone_babel/defaults/main.yml
index c7e00da..26b5cc7 100644
--- a/roles/backbone_babel/defaults/main.yml
+++ b/roles/backbone_babel/defaults/main.yml
@@ -3,3 +3,4 @@ bb_babel_wg_private_key_path: /etc/wireguard/wg-private.key
 bb_babel_wg_public_key_path: /etc/wireguard/wg-public.key
 bb_babel_loopback_ipv6: []
 bb_babel_loopback_ipv4: []
+bb_babel_routing_daemon: babeld
diff --git a/roles/backbone_babel/tasks/main.yml b/roles/backbone_babel/tasks/main.yml
index ae4258a..6c126f9 100644
--- a/roles/backbone_babel/tasks/main.yml
+++ b/roles/backbone_babel/tasks/main.yml
@@ -59,3 +59,9 @@
 - name: Set up babel routing daemon
   ansible.builtin.include_tasks:
     file: routing_babeld.yml
+  when: "bb_babel_routing_daemon == 'babeld'"
+
+- name: Set up bird routing daemon
+  ansible.builtin.include_tasks:
+    file: routing_bird.yml
+  when: "bb_babel_routing_daemon == 'bird'"
diff --git a/roles/backbone_babel/tasks/routing_bird.yml b/roles/backbone_babel/tasks/routing_bird.yml
new file mode 100644
index 0000000..d72bd33
--- /dev/null
+++ b/roles/backbone_babel/tasks/routing_bird.yml
@@ -0,0 +1,34 @@
+---
+- name: Install bird2
+  ansible.builtin.apt:
+    name: bird2
+    state: present
+
+- name: Mask babeld to avoid conflicts with bird
+  ansible.builtin.systemd_service:
+    name: babeld
+    enabled: false
+    masked: yes
+    state: stopped
+
+- name: Enable bird
+  ansible.builtin.systemd_service:
+    name: bird
+    enabled: true
+    masked: no
+    state: started
+
+- name: Ensure bird config is included
+  ansible.builtin.lineinfile:
+    line: 'include "/etc/bird/bird-backbone-babel.conf";'
+    regexp: '^include "/etc/bird/bird-backbone-babel.conf"'
+    path: /etc/bird/bird.conf
+    create: true
+
+- name: "Deploy bird config"
+  ansible.builtin.template:
+    src: bird-backbone-babel.conf.j2
+    dest: "/etc/bird/bird-backbone-babel.conf"
+  vars:
+    # list remote line names for connections we are on either side (line_a or line_b) of
+    interfaces: "{{ bb_babel_wg_connections|selectattr('line_a', 'in', local_lines)|map(attribute='line_b') + bb_babel_wg_connections|selectattr('line_b', 'in', local_lines)|map(attribute='line_a') + bb_babel_peer_interfaces|default([]) }}"
diff --git a/roles/backbone_babel/templates/bird-backbone-babel.conf.j2 b/roles/backbone_babel/templates/bird-backbone-babel.conf.j2
new file mode 100644
index 0000000..bca852e
--- /dev/null
+++ b/roles/backbone_babel/templates/bird-backbone-babel.conf.j2
@@ -0,0 +1,50 @@
+# ANSIBLE managed
+filter import_backbone_babel {
+{% for network in bb_babel_networks|ansible.utils.ipv6 %}
+	if net.type = NET_IP6 && net ~ [{{ network }}+] then {
+		accept;
+	}
+{% endfor %}
+{% for network in bb_babel_networks|ansible.utils.ipv4 %}
+	if net.type = NET_IP4 && net ~ [{{ network }}+] then {
+		accept;
+	}
+{% endfor %}
+	reject;
+};
+filter export_backbone_babel {
+	if ! (source ~ [RTS_STATIC, RTS_BABEL]) then {
+		reject;
+	}
+{% for network in bb_babel_networks|ansible.utils.ipv6 %}
+	if net.type = NET_IP6 && net ~ [{{ network }}+] then {
+		accept;
+	}
+{% endfor %}
+{% for network in bb_babel_networks|ansible.utils.ipv4 %}
+	if net.type = NET_IP4 && net ~ [{{ network }}+] then {
+		accept;
+	}
+{% endfor %}
+	reject;
+};
+
+protocol babel backbone_babel {
+{% for interface in interfaces %}
+        interface "{{ interface }}" {
+                type wired;
+        };
+{% endfor %}
+        ipv6 {
+                import filter import_backbone_babel;
+		import keep filtered on;
+                export filter export_backbone_babel;
+        };
+
+        ipv4 {
+                import filter import_backbone_babel;
+		import keep filtered on;
+                export filter export_backbone_babel;
+        };
+}
+
-- 
GitLab