Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions ansible/group_vars/ffc_servers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# gre_wanip must be set per host (host_vars), matching WANIP in
# conf/general.local.conf.

# Equivalent to GRE_PEERS in conf/general.conf.
gre_peers:
- { name: brewster, ip: 217.79.184.109 }
- { name: newton, ip: 78.46.48.196 }
- { name: archimedes, ip: 162.252.172.175 }
- { name: descartes, ip: 144.76.4.100 }
- { name: kohn, ip: 91.194.84.98 }
- { name: spooner, ip: 51.158.152.84 }
- { name: hawking, ip: 163.172.25.179 }
- { name: noether, ip: 93.186.197.162 }

# Equivalent to LOG_TO in conf/general.conf.
gre_watchdog_mail_to: "crew@chemnitz.freifunk.net"
24 changes: 24 additions & 0 deletions ansible/roles/gre_tunnels/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
# Public IPv4 address of this server, equivalent to WANIP in conf/general.conf
gre_wanip: ""

# Priority prefix for the systemd-networkd unit files (controls apply order)
gre_networkd_priority: "25"

# GRE backbone peers, equivalent to GRE_PEERS in conf/general.conf.
# The peer whose ip matches gre_wanip is skipped automatically.
# Example:
# gre_peers:
# - { name: brewster, ip: 217.79.184.109 }
# - { name: newton, ip: 78.46.48.196 }
gre_peers: []

# Periodic liveness check, equivalent to gre_cron()/gre_check_tunnel() plus
# the "watchdog" cron entry described in README.md.
gre_watchdog_enabled: true
gre_watchdog_script_path: /usr/local/lib/ffc/gre-watchdog.sh
gre_watchdog_interval: "5min"

# Mail recipient for alerts, equivalent to LOG_TO in conf/general.conf.
# Leave empty to only log to syslog and skip mail alerts.
gre_watchdog_mail_to: ""
14 changes: 14 additions & 0 deletions ansible/roles/gre_tunnels/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
- name: restart systemd-networkd
ansible.builtin.systemd:
name: systemd-networkd
state: restarted

- name: reload systemd daemon
ansible.builtin.systemd:
daemon_reload: true

- name: restart gre-watchdog timer
ansible.builtin.systemd:
name: gre-watchdog.timer
state: restarted
100 changes: 100 additions & 0 deletions ansible/roles/gre_tunnels/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
- name: Verify required GRE variables are set
ansible.builtin.assert:
that:
- gre_wanip is defined and gre_wanip | length > 0
- gre_peers is defined
fail_msg: "gre_wanip and gre_peers must be set (see role defaults)"

- name: Ensure systemd-networkd is enabled and running
ansible.builtin.systemd:
name: systemd-networkd
enabled: true
state: started

- name: Determine active GRE peers (exclude ourselves)
ansible.builtin.set_fact:
gre_active_peers: "{{ gre_peers | rejectattr('ip', 'equalto', gre_wanip) | list }}"

- name: Deploy GRE tunnel netdev units
ansible.builtin.template:
src: gre-tunnel.netdev.j2
dest: "/etc/systemd/network/{{ gre_networkd_priority }}-gre-{{ item.name }}.netdev"
owner: root
group: root
mode: "0644"
loop: "{{ gre_active_peers }}"
loop_control:
label: "{{ item.name }}"
notify: restart systemd-networkd

- name: Deploy GRE tunnel network units
ansible.builtin.template:
src: gre-tunnel.network.j2
dest: "/etc/systemd/network/{{ gre_networkd_priority }}-gre-{{ item.name }}.network"
owner: root
group: root
mode: "0644"
loop: "{{ gre_active_peers }}"
loop_control:
label: "{{ item.name }}"
notify: restart systemd-networkd

- name: Find existing GRE unit files
ansible.builtin.find:
paths: /etc/systemd/network
patterns: "*-gre-*.netdev,*-gre-*.network"
register: gre_existing_units

- name: Remove GRE unit files for peers no longer configured
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ gre_existing_units.files }}"
loop_control:
label: "{{ item.path | basename }}"
when: >
(item.path | basename | regex_replace('^[0-9]+-gre-(.*)\.(netdev|network)$', '\1'))
not in (gre_active_peers | map(attribute='name') | list)
notify: restart systemd-networkd

- name: Deploy GRE tunnel watchdog script
ansible.builtin.template:
src: gre-watchdog.sh.j2
dest: "{{ gre_watchdog_script_path }}"
owner: root
group: root
mode: "0755"
when: gre_watchdog_enabled

- name: Deploy GRE tunnel watchdog systemd service
ansible.builtin.template:
src: gre-watchdog.service.j2
dest: /etc/systemd/system/gre-watchdog.service
owner: root
group: root
mode: "0644"
when: gre_watchdog_enabled
notify:
- reload systemd daemon
- restart gre-watchdog timer

- name: Deploy GRE tunnel watchdog systemd timer
ansible.builtin.template:
src: gre-watchdog.timer.j2
dest: /etc/systemd/system/gre-watchdog.timer
owner: root
group: root
mode: "0644"
when: gre_watchdog_enabled
notify:
- reload systemd daemon
- restart gre-watchdog timer

- name: Enable and start GRE tunnel watchdog timer
ansible.builtin.systemd:
name: gre-watchdog.timer
enabled: true
state: started
daemon_reload: true
when: gre_watchdog_enabled
9 changes: 9 additions & 0 deletions ansible/roles/gre_tunnels/templates/gre-tunnel.netdev.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{ ansible_managed | comment }}
[NetDev]
Name=gre-{{ item.name }}
Kind=gretap

[Tunnel]
Local={{ gre_wanip }}
Remote={{ item.ip }}
TTL=255
17 changes: 17 additions & 0 deletions ansible/roles/gre_tunnels/templates/gre-tunnel.network.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{ ansible_managed | comment }}
[Match]
Name=gre-{{ item.name }}

[Link]
MTUBytes=1426

[Network]
LinkLocalAddressing=no

[Address]
Address=169.254.{{ gre_wanip.split('.')[2] }}.{{ gre_wanip.split('.')[3] }}/32
Peer=169.254.{{ item.ip.split('.')[2] }}.{{ item.ip.split('.')[3] }}/32
Scope=link

[Address]
Address=fe80::ffc:{{ '%x' % (gre_wanip.split('.')[2] | int) }}:{{ '%x' % (gre_wanip.split('.')[3] | int) }}/64
9 changes: 9 additions & 0 deletions ansible/roles/gre_tunnels/templates/gre-watchdog.service.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{ ansible_managed | comment }}
[Unit]
Description=Freifunk Chemnitz GRE tunnel watchdog
After=systemd-networkd.service
Wants=systemd-networkd.service

[Service]
Type=oneshot
ExecStart={{ gre_watchdog_script_path }}
32 changes: 32 additions & 0 deletions ansible/roles/gre_tunnels/templates/gre-watchdog.sh.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
# {{ ansible_managed }}
#
# Checks every gre-* interface for reachability by pinging the all-routers
# multicast address and looking for duplicate replies from the remote end.
# Equivalent to gre_cron()/gre_check_tunnel() in lib/gre.sh.

set -u

mail_to="{{ gre_watchdog_mail_to }}"

log_msg() {
logger "[FFC] $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_alert() {
log_msg "$1"
if [ -n "$mail_to" ]; then
mail -s "[FFC] Server Alert - $(hostname -f)" "$mail_to" <<-EOF
$(date '+%Y-%m-%d %H:%M:%S')

$1
EOF
fi
}

for iface in $(ls /sys/class/net | grep '^gre-'); do
dup_count=$(ping6 -c5 -i1 "ff02::2%${iface}" 2>/dev/null | grep -c DUP)
if [ "$dup_count" -eq 0 ]; then
log_alert "GRE tunnel seems down: $iface"
fi
done
11 changes: 11 additions & 0 deletions ansible/roles/gre_tunnels/templates/gre-watchdog.timer.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{ ansible_managed | comment }}
[Unit]
Description=Run the Freifunk Chemnitz GRE tunnel watchdog periodically

[Timer]
OnBootSec=5min
OnUnitActiveSec={{ gre_watchdog_interval }}
AccuracySec=30s

[Install]
WantedBy=timers.target
6 changes: 6 additions & 0 deletions ansible/site.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Configure Freifunk Chemnitz GRE backbone tunnels
hosts: ffc_servers
become: true
roles:
- gre_tunnels