Skip to content

Commit 8c1a09a

Browse files
committed
Refactor anycast setup
- Link interface presence with lifetime of service - Remove autoservice and NAT scripting; import device routes instead
1 parent 3973517 commit 8c1a09a

File tree

22 files changed

+44
-162
lines changed

22 files changed

+44
-162
lines changed

anycast-dns.yml

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
- role: config-loopback
2323
dummy_iface: "{{ dummy_interfaces.anycast_recursors }}"
2424
- role: config-iptables
25-
- config-bird2-autoservice
2625

2726
# Install & configure PowerDNS authoritative server
2827
- role: config-powerdns

dn42-registry

Submodule dn42-registry updated from 773af0b to 3371506

global-config/dns-entries.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ dns_records:
1414
# DNS & web anycast
1515
"ns":
1616
type: host_record
17-
ip4: "{{ dummy_interfaces.anycast_auth_dns.ip4_natmap[0] }}"
17+
ip4: "{{ dummy_interfaces.anycast_auth_dns.ip4[0] }}"
1818
ip6: "{{ dummy_interfaces.anycast_auth_dns.ip6[0] }}"
1919
"dns":
2020
type: host_record
21-
ip4: "{{ dummy_interfaces.anycast_recursors.ip4_natmap[0] }}"
21+
ip4: "{{ dummy_interfaces.anycast_recursors.ip4[0] }}"
2222
ip6: "{{ dummy_interfaces.anycast_recursors.ip6[0] }}"
2323
"@":
2424
type: multi
2525
records:
2626
- type: A
27-
target: "{{ dummy_interfaces.anycast_recursors.ip4_natmap[0] }}"
27+
target: "{{ dummy_interfaces.anycast_recursors.ip4[0] }}"
2828
- type: AAAA
2929
target: "{{ dummy_interfaces.anycast_recursors.ip6[0] }}"
3030
"www":

global-config/general.yml

+5-14
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,17 @@ dummy_interfaces:
1717
ifname: "igp-dummy0"
1818
ip4: ["{{ ownip }}"]
1919
ip6: ["{{ ownip6 }}"]
20-
igp_announce: yes
20+
track_service: no
2121
anycast_auth_dns:
2222
ifname: "igp-dummy1"
23-
ip4: ["169.254.208.21"]
24-
ip4_natmap: ["172.22.108.21"]
23+
ip4: ["172.22.108.21"]
2524
ip6: ["fd86:bad:11b7:53::1"]
26-
igp_announce: no
27-
track_service: pdns
25+
track_service: yes
2826
anycast_recursors:
2927
ifname: "igp-dummy2"
30-
# HACK: 169.254.208.53 et al. are internal IPs with 1-to-1 NAT to anycast service IPs. This works around
31-
# Linux unconditionally dropping IPv4 "Martian packets": i.e. those with a source IP matching
32-
# a locally bound address, but not sent from that interface
33-
# These NAT rules are coded in roles/config-iptables/templates and triggered by a
34-
# pdns-recursor service override
35-
ip4: ["169.254.208.22", "169.254.208.53", "169.254.208.81"]
36-
ip4_natmap: ["172.22.108.22", "172.23.0.53", "172.20.0.81"]
28+
ip4: ["172.22.108.22", "172.23.0.53", "172.20.0.81"]
3729
ip6: ["fd86:bad:11b7:53::2", "fd42:d42:d42:53::1/64", "fd42:d42:d42:81::1/64"]
38-
igp_announce: no
39-
track_service: pdns-recursor
30+
track_service: yes
4031

4132
# Interfaces to clean up (e.g. for decommissioned nodes)
4233
cleanup_remove_ifaces: []

reconfigure-bird.yml

-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@
66
become: yes
77
roles:
88
- config-bird2
9-
- config-bird2-autoservice

reconfigure.yml

-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,3 @@
1616
- config-gre-plain
1717
- config-igpping
1818
- config-bird2
19-
- config-bird2-autoservice

roles/config-bird2-autoservice/handlers

-1
This file was deleted.

roles/config-bird2-autoservice/tasks/main.yml

-22
This file was deleted.

roles/config-bird2-autoservice/templates/autoservice-route.conf.j2

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% if 'anycast_pool' in group_names %}
2+
protocol direct anycast_import {
3+
ipv4;
4+
ipv6;
5+
interface {{ dummy_interfaces.values() | list | selectattr("track_service") | map(attribute='ifname') | map("to_json") | sort | join(", ") }};
6+
}
7+
{% else %}
8+
# Anycast not enabled on this node
9+
{% endif %}

roles/config-bird2/config/bird.conf.j2

+1-3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,4 @@ template bgp dnpeers {
143143
include "/etc/bird/ospf.conf";
144144
include "/etc/bird/ibgp.conf";
145145
include "/etc/bird/local*.conf";
146-
{% if 'anycast_pool' in group_names %}
147-
include "/etc/bird/autoservice-enabled/*.conf";
148-
{% endif %}
146+
include "/etc/bird/anycast_services.conf";

roles/config-bird2/config/community_filters.conf

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ function dn42_import_filter(int link_latency; int link_bandwidth; int link_crypt
7171
}
7272

7373
function dn42_export_filter(int link_latency; int link_bandwidth; int link_crypto) {
74-
if ((is_valid_network() || is_valid_network_v6()) && source ~ [RTS_STATIC, RTS_BGP]) then {
75-
if source = RTS_STATIC then {
74+
if ((is_valid_network() || is_valid_network_v6()) && source ~ [RTS_STATIC, RTS_BGP, RTS_DEVICE]) then {
75+
if source ~ [RTS_STATIC, RTS_DEVICE] then {
7676
bgp_community.add((64511, DN42_REGION));
7777
}
7878
update_flags(link_latency, link_bandwidth, link_crypto);
@@ -121,7 +121,7 @@ function dn42_export_noexport(int link_latency; int link_bandwidth; int link_cry
121121

122122
# Only export static routes (aggregates, mostly)
123123
function dn42_export_peer_only(int link_latency; int link_bandwidth; int link_crypto) {
124-
if (source = RTS_STATIC) then {
124+
if (source ~ [RTS_STATIC, RTS_DEVICE]) then {
125125
dn42_export_filter(link_latency, link_bandwidth, link_crypto);
126126
} else {
127127
reject;

roles/config-bird2/config/custom_filters.conf.j2

+1-6
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function ebgp_export_filter() {
188188
if (bgp_path.len = 0) then {
189189
bgp_large_community.add((OWNAS, LC_ORIGIN_NODEID, NODEID));
190190
}
191-
if source = RTS_STATIC then {
191+
if source ~ [RTS_STATIC, RTS_DEVICE] then {
192192
{% for region_tag in dn42_regions[1:] %}
193193
bgp_community.add((64511, {{ region_tag }}));
194194
{% endfor %}
@@ -222,10 +222,5 @@ function ibgp_export_filter() {
222222
if (source != RTS_BGP && !is_ibgp_network()) then {
223223
reject;
224224
}
225-
# Don't export device routes for dn42 anycast networks. These will be filled in via a static route config
226-
# triggered by service start/stop
227-
if (is_ibgp_network() && source = RTS_DEVICE) then {
228-
reject;
229-
}
230225
accept;
231226
}

roles/config-bird2/config/ospf_interfaces.conf.j2

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ area 0 {
1313
type ptp;
1414
};
1515
{% endfor %}
16-
{# In order: global stub ifname globs, local stub ifnames (appended), dummy interfaces with igp_announce=yes #}
17-
{% for entry in stub_ifnames + stub_ifnames_append|default([]) + (dummy_interfaces.values() | list | selectattr("igp_announce") | map(attribute='ifname') | list | sort) %}
16+
{# In order: global stub ifname globs, local stub ifnames (appended), dummy interfaces with track_service=no #}
17+
{% for entry in stub_ifnames + stub_ifnames_append|default([]) + (dummy_interfaces.values() | list | rejectattr("track_service") | map(attribute='ifname') | list | sort) %}
1818
interface "{{ entry }}" {
1919
stub on;
2020
};

roles/config-bird2/config/peers/grc_export.conf

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ protocol bgp burble_grc_2602 {
88
ipv4 {
99
add paths tx;
1010
import none;
11-
export where is_valid_network() && source ~ [RTS_STATIC, RTS_BGP];
11+
export where is_valid_network() && source ~ [RTS_STATIC, RTS_BGP, RTS_DEVICE];
1212
};
1313

1414
ipv6 {
1515
add paths tx;
1616
import none;
17-
export where is_valid_network_v6() && source ~ [RTS_STATIC, RTS_BGP];
17+
export where is_valid_network_v6() && source ~ [RTS_STATIC, RTS_BGP, RTS_DEVICE];
1818
};
1919
}

roles/config-iptables/tasks/main.yml

-9
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,6 @@
4646
notify:
4747
- "Reload iptables rules"
4848

49-
- name: "Template iptables NAT support script"
50-
template:
51-
src: apply-anycast.j2
52-
dest: "{{ iptables_dir }}/apply-anycast"
53-
mode: '755'
54-
notify:
55-
- "Reload iptables rules"
56-
when: "'anycast_pool' in group_names"
57-
5849
- name: "Write iptables rules for IPv4"
5950
blockinfile:
6051
dest: "{{ iptables_rules_path }}"

roles/config-iptables/templates/apply-anycast.j2

-46
This file was deleted.

roles/config-iptables/templates/apply.j2

-12
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,3 @@ fi
77

88
iptables-restore < {{ iptables_rules_path | quote }} && echo 'applied IPv4 rules'
99
ip6tables-restore < {{ ip6tables_rules_path | quote }} && echo 'applied IPv6 rules'
10-
11-
{% if 'anycast_pool' in group_names %}
12-
{% for service_name, anycast_iface in dummy_interfaces.items() %}
13-
{% if 'track_service' in anycast_iface %}
14-
if systemctl is-active --quiet "{{ anycast_iface.track_service }}"; then
15-
/etc/iptables/apply-anycast start "{{ service_name }}"
16-
else
17-
/etc/iptables/apply-anycast stop "{{ service_name }}"
18-
fi
19-
{% endif %}
20-
{% endfor %}
21-
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1+
{% if not dummy_iface.track_service %}
12
auto {{ dummy_iface.ifname | mandatory }}
3+
{% endif %}
24
{#
35
Use a namespace variable to track state across scopes: https://stackoverflow.com/a/61342337
46
In particular we only want to attach the interface creation pre-up command to the first IP associated with
57
an interface, or that command will run multiple times and cause errors.
68
Note: this requires Jinja2 2.10+
79
#}
810
{% set ns = namespace(has_init_line=false) %}
11+
{% macro init_lines(dummy_iface) %}
12+
{% if not ns.has_init_line %}
13+
{# Cap MTU at IPv6 minimum as PMTUD setup is tricky... #}
14+
mtu 1280
15+
pre-up ip link add {{ dummy_iface.ifname }} type dummy
16+
{% set ns.has_init_line = true %}
17+
{% endif %}
18+
{% endmacro %}
919

1020
{% for ip in dummy_iface.ip4 %}
1121
iface {{ dummy_iface.ifname | mandatory }} inet static
@@ -14,11 +24,7 @@ iface {{ dummy_iface.ifname | mandatory }} inet static
1424
{% set ip = ip | ipaddr('host') %}
1525
{% endif %}
1626
address {{ ip }}
17-
{% if not ns.has_init_line %}
18-
mtu 1280
19-
pre-up ip link add {{ dummy_iface.ifname }} type dummy
20-
{% set ns.has_init_line = true %}
21-
{% endif %}
27+
{{ init_lines(dummy_iface) }}
2228
{% endfor %}
2329

2430
{% for ip in dummy_iface.ip6 %}
@@ -27,10 +33,6 @@ iface {{ dummy_iface.ifname }} inet6 static
2733
{% if ip | ipaddr('address') %}
2834
{% set ip = ip | ipaddr('host') %}
2935
{% endif %}
30-
mtu 1280
3136
address {{ ip }}
32-
{% if not ns.has_init_line %}
33-
pre-up ip link add {{ dummy_iface.ifname }} type dummy
34-
{% set ns.has_init_line = true %}
35-
{% endif %}
37+
{{ init_lines(dummy_iface) }}
3638
{% endfor %}

roles/config-powerdns-recursor/tasks/main.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,5 @@
4747
User: "{{ pdns_rec_user }}"
4848
Group: "{{ pdns_rec_group }}"
4949
# Start/stop
50-
# XXX: 2nd arg (autoservice name) is hardcoded here
51-
ExecStartPost: "+-{{ iptables_dir }}/apply-anycast start anycast_recursors"
52-
ExecStopPost: "+-{{ iptables_dir }}/apply-anycast stop anycast_recursors"
50+
ExecStartPre: "+ifup {{ dummy_interfaces.anycast_recursors.ifname }} --force"
51+
ExecStopPost: "+ip link del {{ dummy_interfaces.anycast_recursors.ifname }}"

roles/config-powerdns/tasks/main.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@
6767
User: "{{ pdns_user }}"
6868
Group: "{{ pdns_group }}"
6969
# Start/stop
70-
# XXX: 2nd arg (autoservice name) is hardcoded here
71-
ExecStartPost: "+-{{ iptables_dir }}/apply-anycast start anycast_auth_dns"
72-
ExecStopPost: "+-{{ iptables_dir }}/apply-anycast stop anycast_auth_dns"
70+
ExecStartPre: "+ifup {{ dummy_interfaces.anycast_auth_dns.ifname }} --force"
71+
ExecStopPost: "+ip link del {{ dummy_interfaces.anycast_auth_dns.ifname }}"
7372

7473
- name: "Synchronize DNS zones"
7574
synchronize:

scripts/make-forward-zones.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ptr_zones["31.172.in-addr.arpa"]="$REGISTRY_ROOT/inetnum/172.31.0.0_16"
2525
ptr_zones["10.in-addr.arpa"]="$REGISTRY_ROOT/inetnum/10.0.0.0_8"
2626
ptr_zones["d.f.ip6.arpa"]="$REGISTRY_ROOT/inet6num/fd00::_8"
2727

28-
local_authserver_ip4="$(yq -r .dummy_interfaces.anycast_auth_dns.ip4_natmap[0] "$DNS_CONFIG")"
28+
local_authserver_ip4="$(yq -r .dummy_interfaces.anycast_auth_dns.ip4[0] "$DNS_CONFIG")"
2929
local_authserver_ip6="$(yq -r .dummy_interfaces.anycast_auth_dns.ip6[0] "$DNS_CONFIG")"
3030

3131
addrtype() {

0 commit comments

Comments
 (0)