diff --git a/profiles/default.nix b/profiles/default.nix index 841ac25..087804c 100644 --- a/profiles/default.nix +++ b/profiles/default.nix @@ -7,6 +7,7 @@ ./common-dns ./common-networking ./cybercluster-vm + ./dn42-router ./fem-net ./hetzner-cloud ./mercury-vm diff --git a/profiles/dn42-router/default.nix b/profiles/dn42-router/default.nix new file mode 100644 index 0000000..ddbb64f --- /dev/null +++ b/profiles/dn42-router/default.nix @@ -0,0 +1,272 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.profiles.clerie.dn42-router; + + myAsn = 4242422574; + ospf6Table = 1337; + bgp6Table = 2342; + +in { + + options.profiles.clerie.dn42-router = { + enable = mkEnableOption "DN42 router base config"; + loopbackIp = mkOption { + type = types.str; + description = "IPv6 lookback IP"; + }; + routerId = mkOption { + type = types.str; + description = "IPv6 lookback IP"; + }; + ospfInterfaces = mkOption { + type = with types; listOf str; + default = []; + }; + ibgpPeers = mkOption { + type = with types; listOf (submodule ({ ... }: { + options = { + remoteAddress = mkOption { + type = types.str; + }; + peerName = mkOption { + type = types.str; + }; + }; + })); + default = {}; + description = "External bgp peers"; + }; + bgpPeers = mkOption { + type = with types; listOf (submodule ({ ... }: { + options = { + localAddress = mkOption { + type = types.str; + }; + remoteAddress = mkOption { + type = types.str; + }; + peerName = mkOption { + type = types.str; + }; + remoteAsn = mkOption { + type = types.str; + }; + }; + })); + default = {}; + description = "External bgp peers"; + }; + wireguardPeers = mkOption { + type = with types; listOf (submodule ({ ... }: { + options = { + interfaceName = mkOption { + type = types.str; + }; + localAddress = mkOption { + type = types.str; + }; + #localAddressPrefixlen = ; + remoteAddress = mkOption { + type = types.str; + }; + #remoteAddressPrefixlen = ; + #localPrivateKey = ; + #remotePublicKey = ; + #localListenPort = ; + #remoteEnpoint = ; + peerName = mkOption { + type = types.str; + }; + remoteAsn = mkOption { + type = types.str; + }; + }; + })); + default = []; + description = "External bgp peers"; + }; + birdExtraConfig = mkOption { + type = types.str; + default = ""; + }; + }; + + config = mkIf config.profiles.clerie.dn42-router.enable { + + systemd.network.config.routeTables = { + bgp6 = bgp6Table; + ospf6 = ospf6Table; + }; + systemd.network.config.addRouteTablesToIPRoute2 = true; + + systemd.network.netdevs."10-lo-dn42" = { + netdevConfig = { + Kind = "dummy"; + Name = "lo-dn42"; + }; + }; + + systemd.network.networks."10-lo-dn42" = { + matchConfig.Name = "lo-dn42"; + address = [ "${ cfg.loopbackIp }/128" ]; + linkConfig.RequiredForOnline = "no"; + routingPolicyRules = [ + { + Priority = 10000; + Family = "ipv6"; + To = "fd56:4902:eca0::/48"; + Table = "ospf6"; + } + { + Priority = 11000; + Family = "ipv6"; + Table = "bgp6"; + } + { + Priority = 15000; + Family = "ipv6"; + From = "fd56:4902:eca0::/48"; + Type = "unreachable"; + } + { + Priority = 16000; + Family = "ipv6"; + To = "fd56:4902:eca0::/48"; + Type = "unreachable"; + } + { + Priority = 20000; + Family = "both"; + Table = "main"; + } + ]; + }; + + services.bird.enable = true; + services.bird.package = pkgs.bird2; + services.bird.config = '' + router id ${ cfg.routerId }; + + ipv6 table ospf6; + ipv6 table bgp6; + + protocol direct { + interface "lo-dn42"; + ipv6 { + table ospf6; + }; + } + + protocol static { + ipv6 { + table bgp6; + }; + route fd56:4902:eca0::/48 via "lo-dn42"; + } + + protocol kernel { + ipv6 { + table ospf6; + export filter { + krt_prefsrc=${ cfg.loopbackIp }; + accept; + }; + import none; + }; + kernel table ${ toString ospf6Table }; + } + + protocol kernel { + ipv6 { + table bgp6; + export filter { + krt_prefsrc=${ cfg.loopbackIp }; + accept; + }; + import none; + }; + kernel table ${ toString bgp6Table }; + } + + protocol device { + scan time 10; + } + + protocol ospf v3 { + ipv6 { + table ospf6; + import all; + export all; + }; + area 0 { + ${ concatMapStringsSep "\n" (interfaceName: '' + interface "${interfaceName}" { + cost 80; + type broadcast; + }; + '') cfg.ospfInterfaces} + }; + } + + template bgp ibgp_peer { + local as ${ toString myAsn }; + graceful restart on; + source address ${ cfg.loopbackIp}; + ipv6 { + table bgp6; + igp table ospf6; + next hop self; + import keep filtered; + import all; + export all; + }; + } + + ${concatMapStringsSep "\n" ( peerConfig: '' + protocol bgp ${peerConfig.peerName} from ibgp_peer { + neighbor ${peerConfig.remoteAddress} as ${ toString myAsn }; + } + '') cfg.ibgpPeers} + + template bgp bgp_peer { + local as ${ toString myAsn }; + graceful restart on; + ipv6 { + table bgp6; + next hop self; + import keep filtered; + import filter { + if net ~ [fd00::/8{48,64}] then accept; + reject; + }; + export filter { + if net ~ [fd00::/8{48,64}] then accept; + reject; + }; + }; + } + + ${concatMapStringsSep "\n" ( peerConfig: '' + protocol bgp ${peerConfig.peerName} from bgp_peer { + neighbor ${peerConfig.remoteAddress} as ${peerConfig.remoteAsn}; + source address ${peerConfig.localAddress}; + } + '') cfg.bgpPeers} + + ${concatMapStringsSep "\n" ( peerConfig: '' + protocol bgp ${peerConfig.peerName} from bgp_peer { + neighbor ${peerConfig.remoteAddress}%${peerConfig.interfaceName} as ${peerConfig.remoteAsn}; + source address ${peerConfig.localAddress}; + } + '') cfg.wireguardPeers} + + ${ cfg.birdExtraConfig } + + ''; + + }; +}