dn42-peering/provision-config.py

80 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
import json
from pathlib import Path
import subprocess
import sys
upstream_config_file = Path(sys.argv[1]).resolve()
bird_config_file = Path(sys.argv[2]).resolve()
print("Loading upstream config from {}".format(upstream_config_file))
print("Deploying bird peering config file to {}".format(bird_config_file))
print("\n")
upstream_config = json.loads(upstream_config_file.read_text())
# collect tunnel interface names
tunnel_interface_names = []
# collect bird 2 peering directives
bird_config = ""
for peering in upstream_config:
tunnel_interface_name = "peer{id}as{asn}".format(
id=peering["peering-id"],
asn=str(peering["remote-as"])[-4:],
)
print("Configuring {}".format(tunnel_interface_name))
tunnel_interface_names.append(tunnel_interface_name)
tunnel_config = """[Interface]
PrivateKey = {local_privatekey}
ListenPort = {local_endpoint_port}
[Peer]
PublicKey = {remote_publickey}
Endpoint = {remote_endpoint_addr}:{remote_endpoint_port}
AllowedIPs = fd00::/8, fe80::/10""".format(
local_privatekey=peering["local-privatekey"],
local_endpoint_port=peering["local-endpoint-port"],
remote_publickey=peering["remote-publickey"],
remote_endpoint_addr=peering["remote-endpoint-addr"],
remote_endpoint_port=peering["remote-endpoint-port"],
)
tunnel_config_file = Path() / "{}.conf".format(tunnel_interface_name)
tunnel_config_file.write_text(tunnel_config)
r = subprocess.run(["ip", "address", "show", "dev", tunnel_interface_name], capture_output=True)
if r.returncode != 0:
subprocess.run(["ip", "link", "add", "dev", tunnel_interface_name, "type", "wireguard"], check=True)
subprocess.run(["ip", "link", "set", "up", "dev", tunnel_interface_name], check=True)
subprocess.run(["wg", "syncconf", tunnel_interface_name, tunnel_config_file], check=True)
subprocess.run(["ip", "address", "change", "{}/128".format(peering["local-ip"]), "peer", "{}/128".format(peering["remote-ip"]), "dev", tunnel_interface_name], check=True)
tunnel_config_file.unlink(missing_ok=True)
bird_config += """
protocol bgp {tunnel_interface_name} from bgp_dn42 {{
neighbor {remote_ip}%{tunnel_interface_name} as {remote_as};
}}
""".format(
tunnel_interface_name=tunnel_interface_name,
remote_ip=peering["remote-ip"],
remote_as=peering["remote-as"],
)
# Writing generated bird config
bird_config_file.write_text(bird_config)
# remove all peer interfaces that are not supported
r = subprocess.run(["ip", "--json", "link", "show"], check=True, capture_output=True,text=True)
interfaces = json.loads(r.stdout)
for interface in interfaces:
if interface["ifname"].startswith("peer") and interface["ifname"] not in tunnel_interface_names:
print("Removing {}".format(interface["ifname"]))
subprocess.run(["ip", "link", "delete", interface["ifname"]], check=True)