replace ospf with bgp
This commit is contained in:
parent
dfd033af25
commit
e618d0caff
|
@ -19,4 +19,6 @@ in
|
||||||
++ lib.filesystem.listFilesRecursive ./net;
|
++ lib.filesystem.listFilesRecursive ./net;
|
||||||
|
|
||||||
site.net-combined = concatMapAttrsRecursive (name: value: { inherit (value) hosts4 hosts6; }) config.site.net;
|
site.net-combined = concatMapAttrsRecursive (name: value: { inherit (value) hosts4 hosts6; }) config.site.net;
|
||||||
|
|
||||||
|
site.bgp.asn = 4242421127;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{ lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
site.net.c3d2 = {
|
site.net.c3d2 = {
|
||||||
dhcp = {
|
dhcp = {
|
||||||
|
@ -110,28 +111,34 @@
|
||||||
c3d2.hwaddr = "0A:14:48:01:07:05";
|
c3d2.hwaddr = "0A:14:48:01:07:05";
|
||||||
core.hwaddr = "0A:14:48:01:07:04";
|
core.hwaddr = "0A:14:48:01:07:04";
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "anon1" "freifunk" ];
|
bgp.allowedUpstreams = [ "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
c3d2-gw1 = makeGateway {
|
c3d2-gw1 = makeGateway {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
c3d2.hwaddr = "0A:14:48:01:21:01";
|
c3d2.hwaddr = "0A:14:48:01:21:01";
|
||||||
core.hwaddr = "0A:14:48:01:21:00";
|
core.hwaddr = "0A:14:48:01:21:00";
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "flpk-gw" "freifunk" "upstream4" "upstream3" "anon1" ];
|
bgp.allowedUpstreams = [ "flpk-gw" "freifunk" "upstream4" "upstream3" "anon1" ];
|
||||||
};
|
};
|
||||||
c3d2-gw2 = makeGateway {
|
c3d2-gw2 = makeGateway {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
c3d2.hwaddr = "0A:14:48:01:21:03";
|
c3d2.hwaddr = "0A:14:48:01:21:03";
|
||||||
core.hwaddr = "0A:14:48:01:21:02";
|
core.hwaddr = "0A:14:48:01:21:02";
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
|
bgp.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
c3d2-gw3 = makeGateway {
|
c3d2-gw3 = makeGateway {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
c3d2.hwaddr = "0A:14:48:01:21:05";
|
c3d2.hwaddr = "0A:14:48:01:21:05";
|
||||||
core.hwaddr = "0A:14:48:01:21:04";
|
core.hwaddr = "0A:14:48:01:21:04";
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
bgp = {
|
||||||
|
peers.${config.site.net.core.hosts6.dn42.bgp} = {
|
||||||
|
type = "rr_client";
|
||||||
|
name = "rr";
|
||||||
|
};
|
||||||
|
allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
cephMonServers = [ "server5" "server6" "server8" ];
|
cephMonServers = [ "server5" "server6" "server8" ];
|
||||||
in
|
in
|
||||||
|
@ -158,7 +158,13 @@ in
|
||||||
type = "veth";
|
type = "veth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
bgp = {
|
||||||
|
peers.${config.site.net.core.hosts6.dn42.bgp} = {
|
||||||
|
type = "rr_client";
|
||||||
|
name = "rr";
|
||||||
|
};
|
||||||
|
allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
server3 = makeServer;
|
server3 = makeServer;
|
||||||
server5 = makeServer;
|
server5 = makeServer;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
site.net.core = {
|
site.net.core = {
|
||||||
domainName = "core.zentralwerk.org";
|
domainName = "core.zentralwerk.org";
|
||||||
|
@ -132,6 +134,7 @@
|
||||||
upstream4 = "fd23:42:c3d2:581::b:3";
|
upstream4 = "fd23:42:c3d2:581::b:3";
|
||||||
yggdrasil = "fd23:42:c3d2:581:9000::1";
|
yggdrasil = "fd23:42:c3d2:581:9000::1";
|
||||||
vpn-gw = "fd23:42:c3d2:581:9001::1";
|
vpn-gw = "fd23:42:c3d2:581:9001::1";
|
||||||
|
flpk-gw = "fd23:42:c3d2:581:9002::1";
|
||||||
};
|
};
|
||||||
up4 = {
|
up4 = {
|
||||||
anon1 = "2a00:8180:2c00:281::9:1";
|
anon1 = "2a00:8180:2c00:281::9:1";
|
||||||
|
@ -201,15 +204,33 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
site.hosts = {
|
site.hosts = lib.mkMerge ([ {
|
||||||
bgp = {
|
bgp = {
|
||||||
bgp = {
|
bgp = {
|
||||||
asn = 4242421127;
|
|
||||||
peers = {
|
peers = {
|
||||||
"172.22.99.253" = { asn = 64699; };
|
"172.22.99.253" = {
|
||||||
"fe80::a800:42ff:fe7a:3246%c3d2" = { asn = 64699; };
|
asn = 64699;
|
||||||
|
type = "external";
|
||||||
|
name = "dn42_4";
|
||||||
|
};
|
||||||
|
"fe80::a800:42ff:fe7a:3246%c3d2" = {
|
||||||
|
asn = 64699;
|
||||||
|
type = "external";
|
||||||
|
name = "dn42_6";
|
||||||
|
};
|
||||||
|
# ${config.site.net.core.subnet4} = {};
|
||||||
|
${config.site.net.core.subnets6.dn42} = {
|
||||||
|
type = "rr_server";
|
||||||
|
name = "rr";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
# allowedUpstreams =
|
||||||
|
# [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
|
nets4 = [ "172.20.0.0/14" "10.0.0.0/8" ];
|
||||||
|
nets6 =
|
||||||
|
[ "fd00::/8" "2a00:8180:2c00:200::/56" ];
|
||||||
};
|
};
|
||||||
|
role = "container";
|
||||||
interfaces = {
|
interfaces = {
|
||||||
c3d2 = {
|
c3d2 = {
|
||||||
hwaddr = "0A:14:48:01:22:01";
|
hwaddr = "0A:14:48:01:22:01";
|
||||||
|
@ -220,14 +241,21 @@
|
||||||
type = "veth";
|
type = "veth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
|
||||||
allowedUpstreams =
|
|
||||||
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
|
||||||
stubNets4 = [ "172.20.0.0/14" "10.0.0.0/8" ];
|
|
||||||
stubNets6 =
|
|
||||||
[ "fd00::/8" "2a00:8180:2c00:200::/56" ];
|
|
||||||
};
|
|
||||||
role = "container";
|
|
||||||
};
|
};
|
||||||
};
|
} ] ++ builtins.concatMap (hostName:
|
||||||
|
if hostName != "bgp"
|
||||||
|
# everyone in core peers with router "bgp"
|
||||||
|
then [ {
|
||||||
|
${hostName}.bgp = {
|
||||||
|
# peers.${config.site.net.core.hosts4.bgp} = {};
|
||||||
|
peers.${config.site.net.core.hosts6.dn42.bgp} = {
|
||||||
|
type = "rr_client";
|
||||||
|
name = "rr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# TODO: upstreams
|
||||||
|
} ]
|
||||||
|
# except "bgp" itself :)
|
||||||
|
else []
|
||||||
|
) (builtins.attrNames config.site.net.core.hosts6.dn42));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
{ config, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
site.net.flpk = {
|
site.net.flpk = {
|
||||||
domainName = "flpk.zentralwerk.org";
|
domainName = "flpk.zentralwerk.org";
|
||||||
|
@ -48,9 +50,13 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp = {
|
||||||
allowedUpstreams = [ "upstream4" "upstream3" "freifunk" ];
|
allowedUpstreams = [ "upstream4" "upstream3" "freifunk" ];
|
||||||
upstreamInstance = 2;
|
upstreamTable = "vpn_table";
|
||||||
|
peers.${config.site.net.core.subnets6.dn42} = {
|
||||||
|
type = "upstream";
|
||||||
|
name = "up";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
role = "container";
|
role = "container";
|
||||||
};
|
};
|
||||||
|
|
|
@ -192,10 +192,7 @@
|
||||||
type = "veth";
|
type = "veth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
allowedUpstreams =
|
|
||||||
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
|
||||||
};
|
|
||||||
role = "container";
|
role = "container";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ lib.mkMerge (
|
||||||
core.type = "veth";
|
core.type = "veth";
|
||||||
"priv${toString n}".type = "veth";
|
"priv${toString n}".type = "veth";
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
bgp.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) (seq 1 privCount)
|
) (seq 1 privCount)
|
||||||
|
@ -540,7 +540,7 @@ lib.mkMerge (
|
||||||
hwaddr = "0A:14:47:02:2A:19";
|
hwaddr = "0A:14:47:02:2A:19";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
|
bgp.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
priv18-gw = {
|
priv18-gw = {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
type = "veth";
|
type = "veth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp = {
|
||||||
allowedUpstreams = [ "anon1" "freifunk" ];
|
allowedUpstreams = [ "anon1" "freifunk" ];
|
||||||
allowedUpstreams6 = [ "flpk-gw" "anon1" "freifunk" ];
|
allowedUpstreams6 = [ "flpk-gw" "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -206,7 +206,7 @@
|
||||||
gw6 = null;
|
gw6 = null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf.allowedUpstreams =
|
bgp.allowedUpstreams =
|
||||||
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
};
|
};
|
||||||
stats = makeContainer {
|
stats = makeContainer {
|
||||||
|
|
|
@ -24,8 +24,12 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf.upstreamInstance = 7;
|
|
||||||
role = "container";
|
role = "container";
|
||||||
|
bgp.peers.${config.site.net.core.subnets6.dn42} = {
|
||||||
|
asn = config.site.hosts.upstream3.bgp.asn;
|
||||||
|
type = "upstream";
|
||||||
|
name = "up";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
upstream4 = rec {
|
upstream4 = rec {
|
||||||
|
@ -327,17 +331,19 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp = {
|
||||||
upstreamInstance = 8;
|
nets4 = [
|
||||||
stubNets4 = [
|
|
||||||
"${interfaces.up4-pppoe.upstream.staticIpv4Address}/32"
|
"${interfaces.up4-pppoe.upstream.staticIpv4Address}/32"
|
||||||
];
|
];
|
||||||
|
peers.${config.site.net.core.subnets6.dn42} = {
|
||||||
|
asn = config.site.hosts.upstream4.bgp.asn;
|
||||||
|
type = "upstream";
|
||||||
|
name = "up";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
role = "container";
|
role = "container";
|
||||||
};
|
};
|
||||||
|
|
||||||
freifunk.ospf.upstreamInstance = 6;
|
|
||||||
|
|
||||||
anon1 = {
|
anon1 = {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
core = {
|
core = {
|
||||||
|
@ -352,9 +358,14 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp = {
|
||||||
allowedUpstreams = [ "upstream3" "upstream4" "freifunk" ];
|
allowedUpstreams = [ "upstream3" "upstream4" "freifunk" ];
|
||||||
upstreamInstance = 5;
|
upstreamTable = "vpn_table";
|
||||||
|
peers.${config.site.net.core.subnets6.dn42} = {
|
||||||
|
asn = config.site.hosts.upstream3.bgp.asn;
|
||||||
|
type = "upstream";
|
||||||
|
name = "up";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
role = "container";
|
role = "container";
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,8 +33,6 @@
|
||||||
type = "wireguard";
|
type = "wireguard";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp.allowedUpstreams = [ "flpk-gw" "anon1" "freifunk" ];
|
||||||
allowedUpstreams = [ "flpk-gw" "anon1" "freifunk" ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
type = "veth";
|
type = "veth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ospf = {
|
bgp = {
|
||||||
allowedUpstreams =
|
allowedUpstreams =
|
||||||
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
[ "upstream4" "upstream3" "anon1" "freifunk" ];
|
||||||
stubNets6 = [ "200::/7" ];
|
nets6 = [ "200::/7" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.yggdrasil.enable = true;
|
services.yggdrasil.enable = true;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
# Dummy secrets for testing
|
# Dummy secrets for testing
|
||||||
{
|
{
|
||||||
site.net = {
|
|
||||||
core.ospf.secret = "encrypted";
|
|
||||||
};
|
|
||||||
|
|
||||||
site.hosts = {
|
site.hosts = {
|
||||||
ap1.password = "encrypted";
|
ap1.password = "encrypted";
|
||||||
ap2.password = "encrypted";
|
ap2.password = "encrypted";
|
||||||
|
|
|
@ -148,12 +148,6 @@ let
|
||||||
type = with types; attrsOf (attrsOf str);
|
type = with types; attrsOf (attrsOf str);
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
ospf = {
|
|
||||||
secret = mkOption {
|
|
||||||
type = with types; nullOr str;
|
|
||||||
default = null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
dhcp = mkOption {
|
dhcp = mkOption {
|
||||||
type = with types; nullOr (submodule { options = dhcpOpts; });
|
type = with types; nullOr (submodule { options = dhcpOpts; });
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -390,35 +384,10 @@ let
|
||||||
}; });
|
}; });
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
ospf.stubNets4 = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
default = [];
|
|
||||||
description = "Additional IPv4 networks to announce";
|
|
||||||
};
|
|
||||||
ospf.stubNets6 = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
default = [];
|
|
||||||
description = "Additional IPv6 networks to announce";
|
|
||||||
};
|
|
||||||
ospf.allowedUpstreams = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
default = [];
|
|
||||||
description = "Accept default routes from these OSPF routers, in order of preference";
|
|
||||||
};
|
|
||||||
ospf.allowedUpstreams6 = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
default = config.site.hosts.${name}.ospf.allowedUpstreams;
|
|
||||||
description = "Accept IPv6 default routes from these OSPF3 routers, in order of preference";
|
|
||||||
};
|
|
||||||
ospf.upstreamInstance = mkOption {
|
|
||||||
type = with types; nullOr int;
|
|
||||||
default = null;
|
|
||||||
description = "OSPF instance for advertising the default route";
|
|
||||||
};
|
|
||||||
bgp = mkOption {
|
bgp = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type = with types; nullOr (submodule {
|
type = with types; nullOr (submodule {
|
||||||
options = bgpOpts;
|
options = bgpOpts name;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
services.dns = {
|
services.dns = {
|
||||||
|
@ -499,20 +468,52 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bgpOpts = {
|
bgpOpts = hostName: {
|
||||||
asn = mkOption {
|
asn = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
|
default = config.site.bgp.asn;
|
||||||
};
|
};
|
||||||
peers = mkOption {
|
peers = mkOption {
|
||||||
type = with types; attrsOf (submodule ({ ... }: {
|
type = with types; attrsOf (submodule (submoduleArg: {
|
||||||
options = {
|
options = {
|
||||||
asn = mkOption {
|
asn = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
|
default = config.site.bgp.asn;
|
||||||
|
};
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
type = mkOption {
|
||||||
|
type = types.enum [ "external" "rr_server" "rr_client" "upstream" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
|
nets4 = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "Additional IPv4 networks to announce";
|
||||||
|
};
|
||||||
|
nets6 = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "Additional IPv6 networks to announce";
|
||||||
|
};
|
||||||
|
allowedUpstreams = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "Accept default routes from these BGP routers, in order of preference";
|
||||||
|
};
|
||||||
|
allowedUpstreams6 = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = config.site.hosts.${hostName}.bgp.allowedUpstreams;
|
||||||
|
description = "Accept IPv6 default routes from these BGP routers, in order of preference";
|
||||||
|
};
|
||||||
|
upstreamTable = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
linkOpts = hostName: { name, ... }: {
|
linkOpts = hostName: { name, ... }: {
|
||||||
|
@ -623,6 +624,12 @@ in
|
||||||
default = "secret";
|
default = "secret";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bgp = {
|
||||||
|
asn = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config.warnings =
|
config.warnings =
|
||||||
|
@ -643,16 +650,16 @@ in
|
||||||
reportCollisions = name: getter: xs:
|
reportCollisions = name: getter: xs:
|
||||||
map (k: "Duplicate ${name}: ${k}") (findCollisions getter xs);
|
map (k: "Duplicate ${name}: ${k}") (findCollisions getter xs);
|
||||||
|
|
||||||
ospfUpstreamXorGw =
|
bgpUpstreamXorGw =
|
||||||
builtins.concatMap (hostName:
|
builtins.concatMap (hostName:
|
||||||
let
|
let
|
||||||
hostConf = config.site.hosts.${hostName};
|
hostConf = config.site.hosts.${hostName};
|
||||||
gwNets = builtins.filter (netName:
|
gwNets = builtins.filter (netName:
|
||||||
hostConf.interfaces.${netName}.gw4 != null
|
hostConf.interfaces.${netName}.gw4 != null
|
||||||
) (builtins.attrNames hostConf.interfaces);
|
) (builtins.attrNames hostConf.interfaces);
|
||||||
in if gwNets != [] && hostConf.ospf.allowedUpstreams != []
|
in if gwNets != [] && hostConf.bgp.allowedUpstreams or [] != []
|
||||||
then [ ''
|
then [ ''
|
||||||
Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from OSPF
|
Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from BGP
|
||||||
'' ]
|
'' ]
|
||||||
else []
|
else []
|
||||||
) (builtins.attrNames config.site.hosts);
|
) (builtins.attrNames config.site.hosts);
|
||||||
|
@ -660,7 +667,7 @@ in
|
||||||
(reportCollisions "VLAN tag" (x: lib.optional (x.vlan != null) x.vlan) config.site.net) ++
|
(reportCollisions "VLAN tag" (x: lib.optional (x.vlan != null) x.vlan) config.site.net) ++
|
||||||
(reportCollisions "IPv4 subnet" (x: if x.subnet4 == null then [] else [x.subnet4]) config.site.net) ++
|
(reportCollisions "IPv4 subnet" (x: if x.subnet4 == null then [] else [x.subnet4]) config.site.net) ++
|
||||||
(reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++
|
(reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++
|
||||||
ospfUpstreamXorGw;
|
bgpUpstreamXorGw;
|
||||||
|
|
||||||
config.assertions =
|
config.assertions =
|
||||||
# Duplicate host/net name check
|
# Duplicate host/net name check
|
||||||
|
|
|
@ -25,6 +25,42 @@ let
|
||||||
n = n;
|
n = n;
|
||||||
x = builtins.head list;
|
x = builtins.head list;
|
||||||
} ] ++ (enumerate (n + 1) (builtins.tail list));
|
} ] ++ (enumerate (n + 1) (builtins.tail list));
|
||||||
|
|
||||||
|
nets4 =
|
||||||
|
hostConf.bgp.nets4
|
||||||
|
++
|
||||||
|
builtins.concatMap (net:
|
||||||
|
if net != "core"
|
||||||
|
then
|
||||||
|
let
|
||||||
|
subnet4 = config.site.net.${net}.subnet4 or null;
|
||||||
|
in lib.optional (subnet4 != null) subnet4
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
) (builtins.attrNames hostConf.interfaces);
|
||||||
|
|
||||||
|
nets6 =
|
||||||
|
hostConf.bgp.nets6
|
||||||
|
++
|
||||||
|
builtins.concatMap (net:
|
||||||
|
if net != "core"
|
||||||
|
then
|
||||||
|
builtins.attrValues config.site.net.${net}.subnets6 or {}
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
) (builtins.attrNames hostConf.interfaces);
|
||||||
|
|
||||||
|
upstreamsToOrder = upstreams:
|
||||||
|
builtins.foldl' (order: { n, x }:
|
||||||
|
order // {
|
||||||
|
${x} = n;
|
||||||
|
}
|
||||||
|
) {} (enumerate 1 upstreams);
|
||||||
|
upstream4Order = upstreamsToOrder hostConf.bgp.allowedUpstreams;
|
||||||
|
upstream6Order = upstreamsToOrder hostConf.bgp.allowedUpstreams6;
|
||||||
|
allowedUpstreams = lib.unique (
|
||||||
|
hostConf.bgp.allowedUpstreams ++ hostConf.bgp.allowedUpstreams6
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.bird2 = {
|
services.bird2 = {
|
||||||
|
@ -35,31 +71,13 @@ in
|
||||||
protocol kernel K4 {
|
protocol kernel K4 {
|
||||||
learn;
|
learn;
|
||||||
ipv4 {
|
ipv4 {
|
||||||
${if isUpstream
|
export all;
|
||||||
then ''
|
|
||||||
# Install all routes but the default route on upstreams
|
|
||||||
export where net != 0.0.0.0/0;
|
|
||||||
# Learn the upstream default route
|
|
||||||
import where net = 0.0.0.0/0;
|
|
||||||
''
|
|
||||||
else ''
|
|
||||||
export all;
|
|
||||||
''}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
protocol kernel K6 {
|
protocol kernel K6 {
|
||||||
learn;
|
learn;
|
||||||
ipv6 {
|
ipv6 {
|
||||||
${if isUpstream
|
export all;
|
||||||
then ''
|
|
||||||
# Install all routes but the default route on upstreams
|
|
||||||
export where net != ::/0;
|
|
||||||
# Learn the upstream default route
|
|
||||||
import where net = ::/0;
|
|
||||||
''
|
|
||||||
else ''
|
|
||||||
export all;
|
|
||||||
''}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
protocol device {
|
protocol device {
|
||||||
|
@ -84,10 +102,7 @@ in
|
||||||
check link yes;
|
check link yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
${lib.optionalString (
|
${lib.optionalString (hostConf.bgp.upstreamTable != null) ''
|
||||||
builtins.match "anon.*" hostName != null ||
|
|
||||||
hostName == "flpk-gw"
|
|
||||||
) ''
|
|
||||||
# BIRD routing table for Wireguard transport
|
# BIRD routing table for Wireguard transport
|
||||||
ipv4 table vpn_table;
|
ipv4 table vpn_table;
|
||||||
|
|
||||||
|
@ -128,235 +143,6 @@ in
|
||||||
}
|
}
|
||||||
''}
|
''}
|
||||||
|
|
||||||
# OSPFv2 for site-local IPv4
|
|
||||||
protocol ospf v2 ZW4 {
|
|
||||||
ipv4 {
|
|
||||||
import all;
|
|
||||||
# OSPF is self-contained
|
|
||||||
export none;
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on networks with a secret.
|
|
||||||
if config.site.net ? "${net}" && config.site.net.${net}.ospf.secret != null
|
|
||||||
then ''
|
|
||||||
interface "${net}" {
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
else ''
|
|
||||||
interface "${net}" {
|
|
||||||
stub yes;
|
|
||||||
cost 10;
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.interfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
map (stubnet4: ''
|
|
||||||
# Advertise additional route
|
|
||||||
stubnet ${stubnet4} {};
|
|
||||||
'') hostConf.ospf.stubNets4
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
${lib.optionalString isUpstream ''
|
|
||||||
# OSPFv2 to advertise my default route
|
|
||||||
protocol ospf v2 ZW4_${hostNameEscaped} {
|
|
||||||
ipv4 {
|
|
||||||
export where net = 0.0.0.0/0;
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on interfaces with a secret.
|
|
||||||
lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
|
|
||||||
interface "${net}" instance ${toString hostConf.ospf.upstreamInstance} {
|
|
||||||
# Become the designated router
|
|
||||||
priority 10;
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.physicalInterfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
''}
|
|
||||||
|
|
||||||
${(
|
|
||||||
builtins.foldl' ({ text, n }: upstream: {
|
|
||||||
text = ''
|
|
||||||
${text}
|
|
||||||
|
|
||||||
# OSPFv2 to receive a default route from ${upstream}
|
|
||||||
protocol ospf v2 ZW4_${
|
|
||||||
builtins.replaceStrings [ "-" ] [ "_" ] upstream
|
|
||||||
} {
|
|
||||||
ipv4 {
|
|
||||||
import filter {
|
|
||||||
preference = preference + ${toString (100 - n)};
|
|
||||||
accept;
|
|
||||||
};
|
|
||||||
${lib.optionalString (
|
|
||||||
builtins.match "anon.*" hostName != null ||
|
|
||||||
hostName == "flpk-gw"
|
|
||||||
) ''
|
|
||||||
table vpn_table;
|
|
||||||
''}
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on interfaces with a secret.
|
|
||||||
lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
|
|
||||||
interface "${net}" instance ${
|
|
||||||
builtins.replaceStrings [ "-" ] [ "_" ] (
|
|
||||||
toString config.site.hosts.${upstream}.ospf.upstreamInstance
|
|
||||||
)
|
|
||||||
} {
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.physicalInterfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
n = n + 1;
|
|
||||||
}) { text = ""; n = 0; } hostConf.ospf.allowedUpstreams
|
|
||||||
).text}
|
|
||||||
|
|
||||||
# OSPFv3 for site-local IPv6
|
|
||||||
protocol ospf v3 ZW6 {
|
|
||||||
ipv6 {
|
|
||||||
import all;
|
|
||||||
# OSPF is self-contained
|
|
||||||
export none;
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on networks with a secret.
|
|
||||||
if config.site.net.${net}.ospf.secret != null
|
|
||||||
then ''
|
|
||||||
interface "${net}" {
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
else ''
|
|
||||||
interface "${net}" {
|
|
||||||
stub yes;
|
|
||||||
cost 10;
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.physicalInterfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
map (stubnet6: ''
|
|
||||||
# Advertise additional route
|
|
||||||
stubnet ${stubnet6} {};
|
|
||||||
'')
|
|
||||||
hostConf.ospf.stubNets6
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
${lib.optionalString isUpstream ''
|
|
||||||
# OSPFv3 to advertise my default route
|
|
||||||
protocol ospf v3 ZW6_${hostNameEscaped} {
|
|
||||||
ipv6 {
|
|
||||||
export where net = ::/0;
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on interfaces with a secret.
|
|
||||||
lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
|
|
||||||
interface "${net}" instance ${toString hostConf.ospf.upstreamInstance} {
|
|
||||||
# Become the designated router
|
|
||||||
priority 10;
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.physicalInterfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
''}
|
|
||||||
|
|
||||||
${lib.optionalString (builtins.match "anon.*" hostName == null) (
|
|
||||||
builtins.foldl' ({ text, n }: upstream: {
|
|
||||||
text = ''
|
|
||||||
${text}
|
|
||||||
|
|
||||||
# OSPFv3 to receive a default route from ${upstream}
|
|
||||||
protocol ospf v3 ZW6_${
|
|
||||||
builtins.replaceStrings [ "-" ] [ "_" ] upstream
|
|
||||||
} {
|
|
||||||
ipv6 {
|
|
||||||
import filter {
|
|
||||||
preference = preference + ${toString (100 - n)};
|
|
||||||
accept;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
area 0 {
|
|
||||||
${builtins.concatStringsSep "\n" (
|
|
||||||
builtins.attrValues (
|
|
||||||
builtins.mapAttrs (net: _:
|
|
||||||
# Enable OSPF only on interfaces with a secret.
|
|
||||||
lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
|
|
||||||
interface "${net}" instance ${
|
|
||||||
builtins.replaceStrings [ "-" ] [ "_" ] (
|
|
||||||
toString config.site.hosts.${upstream}.ospf.upstreamInstance
|
|
||||||
)
|
|
||||||
} {
|
|
||||||
hello 10;
|
|
||||||
wait 20;
|
|
||||||
authentication cryptographic;
|
|
||||||
password "${config.site.net.${net}.ospf.secret}";
|
|
||||||
};
|
|
||||||
''
|
|
||||||
) hostConf.physicalInterfaces
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
n = n + 1;
|
|
||||||
}) { text = ""; n = 0; } hostConf.ospf.allowedUpstreams6
|
|
||||||
).text}
|
|
||||||
|
|
||||||
# Zentralwerk DN42
|
# Zentralwerk DN42
|
||||||
protocol static {
|
protocol static {
|
||||||
ipv4;
|
ipv4;
|
||||||
|
@ -370,31 +156,146 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
${lib.optionalString (hostConf.bgp != null) ''
|
${lib.optionalString (hostConf.bgp != null) ''
|
||||||
template bgp bgppeer {
|
# zentralwerk-network
|
||||||
|
template bgp bgp_rr_server {
|
||||||
local as ${toString hostConf.bgp.asn};
|
local as ${toString hostConf.bgp.asn};
|
||||||
|
direct;
|
||||||
|
|
||||||
ipv4 {
|
ipv4 {
|
||||||
import all;
|
import filter {
|
||||||
export where source=RTS_STATIC;
|
preference = preference + 200;
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
${lib.optionalString (nets4 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets4} ];
|
||||||
|
''}
|
||||||
};
|
};
|
||||||
ipv6 {
|
ipv6 {
|
||||||
|
import filter {
|
||||||
|
preference = preference + 200;
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
${lib.optionalString (nets6 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets6} ];
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
template bgp bgp_rr_client {
|
||||||
|
local as ${toString hostConf.bgp.asn};
|
||||||
|
direct;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
next hop self on;
|
||||||
|
import filter {
|
||||||
|
preference = preference + 200;
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
${lib.optionalString (nets4 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets4} ];
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
ipv6 {
|
||||||
|
next hop self on;
|
||||||
|
import filter {
|
||||||
|
preference = preference + 200;
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
${lib.optionalString (nets6 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets6} ];
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# dn42
|
||||||
|
template bgp bgp_external {
|
||||||
|
local as ${toString hostConf.bgp.asn};
|
||||||
|
direct;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
next hop self on;
|
||||||
import all;
|
import all;
|
||||||
export where source=RTS_STATIC;
|
export where source = RTS_STATIC;
|
||||||
|
};
|
||||||
|
ipv6 {
|
||||||
|
next hop self on;
|
||||||
|
import all;
|
||||||
|
export where source = RTS_STATIC;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# emitting default routes
|
||||||
|
template bgp bgp_upstream {
|
||||||
|
local as ${toString hostConf.bgp.asn};
|
||||||
|
direct;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
next hop self on;
|
||||||
|
import all;
|
||||||
|
export where net = 0.0.0.0/0;
|
||||||
|
};
|
||||||
|
ipv6 {
|
||||||
|
next hop self on;
|
||||||
|
import all;
|
||||||
|
export where net = ::/0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
${builtins.concatStringsSep "\n" (
|
${lib.concatMapStrings (peer:
|
||||||
map ({ n, x }:
|
let
|
||||||
let
|
peerConf = hostConf.bgp.peers.${peer};
|
||||||
peer = x;
|
isRange = lib.hasInfix "/" peer;
|
||||||
peerConf = hostConf.bgp.peers.${peer};
|
in ''
|
||||||
in ''
|
protocol bgp bgp_${peerConf.name} from bgp_${peerConf.type} {
|
||||||
protocol bgp bgp_${toString n} from bgppeer {
|
neighbor ${lib.optionalString isRange "range"} ${peer} as ${toString peerConf.asn};
|
||||||
neighbor ${peer} as ${toString peerConf.asn};
|
${lib.optionalString isRange ''
|
||||||
}
|
dynamic name "bgp_${peerConf.name}";
|
||||||
''
|
''}
|
||||||
) (enumerate 1 (builtins.attrNames hostConf.bgp.peers))
|
${lib.optionalString (peerConf.type == "rr") ''
|
||||||
)}
|
rr client;
|
||||||
|
''}
|
||||||
|
}
|
||||||
|
'') (builtins.attrNames hostConf.bgp.peers)}
|
||||||
|
|
||||||
|
${lib.concatMapStrings ({ n, x }: let upstream = x; in ''
|
||||||
|
# upstream client instance #${toString n}
|
||||||
|
protocol bgp bgp_up_${upstream} {
|
||||||
|
local as ${toString hostConf.bgp.asn};
|
||||||
|
neighbor ${config.site.net.core.hosts6.dn42.${upstream}} as ${toString hostConf.bgp.asn};
|
||||||
|
direct;
|
||||||
|
|
||||||
|
ipv4 {
|
||||||
|
${if (upstream4Order ? ${upstream})
|
||||||
|
then ''
|
||||||
|
import filter {
|
||||||
|
preference = preference + ${toString (100 - upstream4Order.${upstream})};
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
import none;
|
||||||
|
''}
|
||||||
|
${lib.optionalString (nets4 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets4} ];
|
||||||
|
''}
|
||||||
|
${lib.optionalString (hostConf.bgp.upstreamTable != null) ''
|
||||||
|
table ${hostConf.bgp.upstreamTable};
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
ipv6 {
|
||||||
|
${if (upstream4Order ? ${upstream})
|
||||||
|
then ''
|
||||||
|
import filter {
|
||||||
|
preference = preference + ${toString (100 - upstream4Order.${upstream})};
|
||||||
|
accept;
|
||||||
|
};
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
import none;
|
||||||
|
''}
|
||||||
|
${lib.optionalString (nets6 != []) ''
|
||||||
|
export where net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}") nets6} ];
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'') (enumerate 1 allowedUpstreams)}
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue