nixos-module/container/bird: implement upstream failover
parent
ce49c22d2e
commit
257e6686b9
|
@ -58,7 +58,8 @@ in
|
|||
|
||||
config.site.hosts = lib.mkMerge (
|
||||
[
|
||||
{
|
||||
{ # Static definitions
|
||||
|
||||
mgmt-gw.firewall.enable = true;
|
||||
priv13-gw.firewall.enable = true;
|
||||
|
||||
|
@ -74,8 +75,24 @@ in
|
|||
|
||||
services.dnscache.enable = true;
|
||||
};
|
||||
|
||||
c3d2-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ];
|
||||
serv-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ];
|
||||
cls-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ];
|
||||
mgmt-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ];
|
||||
bgp.ospf.allowedUpstreams = [ "upstream1" "upstream2" ];
|
||||
}
|
||||
|
||||
(
|
||||
builtins.mapAttrs (hostName: _: {
|
||||
ospf.allowedUpstreams = [ "upstream2" "upstream1" ];
|
||||
}) (
|
||||
lib.filterAttrs (hostName: _:
|
||||
builtins.match "priv[[:digit:]]+-gw" hostName != null
|
||||
) pillar.containers
|
||||
)
|
||||
)
|
||||
|
||||
(builtins.foldl' (result: hostName: result // {
|
||||
"${hostName}" = {
|
||||
role = "server";
|
||||
|
|
|
@ -202,6 +202,11 @@ let
|
|||
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";
|
||||
};
|
||||
wireguard = mkOption {
|
||||
default = {};
|
||||
type = with types; attrsOf (submodule (
|
||||
|
@ -291,8 +296,23 @@ in
|
|||
)).dup;
|
||||
reportCollisions = name: getter: xs:
|
||||
map (k: "Duplicate ${name}: ${k}") (findCollisions getter xs);
|
||||
|
||||
ospfUpstreamXorGw =
|
||||
builtins.concatMap (hostName:
|
||||
let
|
||||
hostConf = config.site.hosts.${hostName};
|
||||
gwNets = builtins.filter (netName:
|
||||
hostConf.interfaces.${netName}.gw4 != null
|
||||
) (builtins.attrNames hostConf.interfaces);
|
||||
in if gwNets != [] && hostConf.ospf.allowedUpstreams != []
|
||||
then [ ''
|
||||
Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from OSPF
|
||||
'' ]
|
||||
else []
|
||||
) (builtins.attrNames config.site.hosts);
|
||||
in
|
||||
(reportCollisions "VLAN tag" (x: [x.vlan]) 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;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
let
|
||||
hostConf = config.site.hosts.${hostName};
|
||||
|
||||
isUpstream = builtins.any (net:
|
||||
hostConf.interfaces.${net}.upstream != null
|
||||
) (builtins.attrNames hostConf.interfaces);
|
||||
|
||||
# Configuring a gateway? If so, this is the associated net.
|
||||
gatewayNet =
|
||||
let
|
||||
|
@ -29,13 +33,33 @@ in
|
|||
router id ${config.site.net.core.hosts4.${hostName}};
|
||||
|
||||
protocol kernel K4 {
|
||||
learn;
|
||||
ipv4 {
|
||||
export all;
|
||||
${lib.optionalString isUpstream ''
|
||||
# Learn the default route
|
||||
import filter {
|
||||
if net ~ [ 0.0.0.0/0 ] then {
|
||||
accept;
|
||||
}
|
||||
reject;
|
||||
};
|
||||
''}
|
||||
};
|
||||
}
|
||||
protocol kernel K6 {
|
||||
learn;
|
||||
ipv6 {
|
||||
export all;
|
||||
${lib.optionalString isUpstream ''
|
||||
# Learn the default route
|
||||
import filter {
|
||||
if net ~ [ ::/0 ] then {
|
||||
accept;
|
||||
}
|
||||
reject;
|
||||
};
|
||||
''}
|
||||
};
|
||||
}
|
||||
protocol device {
|
||||
|
@ -67,6 +91,26 @@ in
|
|||
|
||||
# OSPFv2 for site-local IPv4
|
||||
protocol ospf v2 ZW4 {
|
||||
ipv4 {
|
||||
export all;
|
||||
import filter {
|
||||
if net ~ [ 0.0.0.0/0 ] then {
|
||||
${(builtins.foldl' (result: gateway: {
|
||||
text = ''
|
||||
${result.text}
|
||||
if ospf_router_id = ${config.site.net.core.hosts4.${gateway}} then {
|
||||
preference = preference + ${toString result.n};
|
||||
accept;
|
||||
}
|
||||
'';
|
||||
n = result.n - 10;
|
||||
}) { text = ""; n = 900; } config.site.hosts.${hostName}.ospf.allowedUpstreams
|
||||
).text}
|
||||
reject;
|
||||
}
|
||||
accept;
|
||||
};
|
||||
};
|
||||
area 0 {
|
||||
# Enabled on these networks
|
||||
networks {
|
||||
|
@ -107,6 +151,26 @@ in
|
|||
|
||||
# OSPFv3 for site-local IPv6
|
||||
protocol ospf v3 ZW6 {
|
||||
ipv6 {
|
||||
export all;
|
||||
import filter {
|
||||
if net ~ [ ::/0 ] then {
|
||||
${(builtins.foldl' (result: gateway: {
|
||||
text = ''
|
||||
${result.text}
|
||||
if ospf_router_id = ${config.site.net.core.hosts4.${gateway}} then {
|
||||
preference = preference + ${toString result.n};
|
||||
accept;
|
||||
}
|
||||
'';
|
||||
n = result.n - 10;
|
||||
}) { text = ""; n = 900; } config.site.hosts.${hostName}.ospf.allowedUpstreams
|
||||
).text}
|
||||
reject;
|
||||
}
|
||||
accept;
|
||||
};
|
||||
};
|
||||
area 0 {
|
||||
# Enabled on these networks
|
||||
networks {
|
||||
|
|
|
@ -14,8 +14,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream1
|
||||
gw6: upstream1
|
||||
# gw: upstream1
|
||||
# gw6: upstream1
|
||||
hwaddr: 0A:14:48:01:06:01
|
||||
serv:
|
||||
type: veth
|
||||
|
@ -25,8 +25,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream1
|
||||
gw6: upstream1
|
||||
# gw: upstream1
|
||||
# gw6: upstream1
|
||||
hwaddr: 0A:14:48:01:06:03
|
||||
cluster:
|
||||
type: phys
|
||||
|
@ -36,8 +36,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:19:00
|
||||
priv1:
|
||||
type: phys
|
||||
|
@ -47,8 +47,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:18:00
|
||||
priv2:
|
||||
type: phys
|
||||
|
@ -58,8 +58,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:08:00
|
||||
priv3:
|
||||
type: phys
|
||||
|
@ -69,8 +69,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:17:01
|
||||
priv4:
|
||||
type: phys
|
||||
|
@ -80,8 +80,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:12:00
|
||||
priv5:
|
||||
type: phys
|
||||
|
@ -91,8 +91,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: anon1
|
||||
gw6: upstream2
|
||||
# gw: anon1
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:11:00
|
||||
priv6:
|
||||
type: phys
|
||||
|
@ -102,8 +102,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:10:00
|
||||
priv7:
|
||||
type: phys
|
||||
|
@ -113,8 +113,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:09:00
|
||||
priv8:
|
||||
type: phys
|
||||
|
@ -124,8 +124,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:20:00
|
||||
priv9:
|
||||
type: phys
|
||||
|
@ -135,8 +135,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:13:02
|
||||
priv10:
|
||||
type: phys
|
||||
|
@ -146,8 +146,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:29:00
|
||||
priv11:
|
||||
type: phys
|
||||
|
@ -157,8 +157,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:00
|
||||
priv12:
|
||||
type: phys
|
||||
|
@ -168,8 +168,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:10
|
||||
priv13:
|
||||
type: phys
|
||||
|
@ -179,8 +179,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:12
|
||||
priv14:
|
||||
type: phys
|
||||
|
@ -190,8 +190,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: anon1
|
||||
gw6: upstream2
|
||||
# gw: anon1
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:14
|
||||
priv15:
|
||||
type: phys
|
||||
|
@ -201,8 +201,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:16
|
||||
priv16:
|
||||
type: phys
|
||||
|
@ -212,8 +212,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:18
|
||||
priv17:
|
||||
type: phys
|
||||
|
@ -223,8 +223,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:1A
|
||||
priv18:
|
||||
type: phys
|
||||
|
@ -234,8 +234,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:1C
|
||||
priv19:
|
||||
type: phys
|
||||
|
@ -245,8 +245,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:1E
|
||||
priv20:
|
||||
type: phys
|
||||
|
@ -256,8 +256,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:20
|
||||
priv21:
|
||||
type: phys
|
||||
|
@ -267,8 +267,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:24
|
||||
priv22:
|
||||
type: phys
|
||||
|
@ -278,8 +278,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:22
|
||||
priv23:
|
||||
type: phys
|
||||
|
@ -289,8 +289,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:26
|
||||
priv24:
|
||||
type: phys
|
||||
|
@ -300,8 +300,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:28
|
||||
priv25:
|
||||
type: phys
|
||||
|
@ -311,8 +311,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:2A
|
||||
priv26:
|
||||
type: phys
|
||||
|
@ -322,8 +322,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:2C
|
||||
priv27:
|
||||
type: phys
|
||||
|
@ -333,8 +333,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:2E
|
||||
priv28:
|
||||
type: phys
|
||||
|
@ -344,8 +344,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:30
|
||||
priv29:
|
||||
type: phys
|
||||
|
@ -355,8 +355,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:32
|
||||
priv30:
|
||||
type: phys
|
||||
|
@ -366,8 +366,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:34
|
||||
priv31:
|
||||
type: phys
|
||||
|
@ -377,8 +377,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:36
|
||||
priv32:
|
||||
type: phys
|
||||
|
@ -388,8 +388,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:38
|
||||
priv33:
|
||||
type: phys
|
||||
|
@ -399,8 +399,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:40
|
||||
priv34:
|
||||
type: phys
|
||||
|
@ -410,8 +410,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:42
|
||||
priv35:
|
||||
type: phys
|
||||
|
@ -421,8 +421,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:44
|
||||
priv36:
|
||||
type: phys
|
||||
|
@ -432,8 +432,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:46
|
||||
priv37:
|
||||
type: phys
|
||||
|
@ -443,8 +443,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:48
|
||||
priv38:
|
||||
type: phys
|
||||
|
@ -454,8 +454,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:4A
|
||||
priv39:
|
||||
type: phys
|
||||
|
@ -465,8 +465,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream2
|
||||
gw6: upstream2
|
||||
# gw: upstream2
|
||||
# gw6: upstream2
|
||||
hwaddr: 0A:14:48:01:2A:4C
|
||||
priv40:
|
||||
type: phys
|
||||
|
@ -504,8 +504,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream1
|
||||
gw6: upstream1
|
||||
# gw: upstream1
|
||||
# gw6: upstream1
|
||||
hwaddr: 0A:14:48:01:21:00
|
||||
c3d2:
|
||||
type: veth
|
||||
|
@ -526,8 +526,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream1
|
||||
gw6: upstream1
|
||||
# gw: upstream1
|
||||
# gw6: upstream1
|
||||
hwaddr: 0A:14:48:01:22:00
|
||||
c3d2:
|
||||
type: veth
|
||||
|
@ -561,8 +561,8 @@ containers:
|
|||
interfaces:
|
||||
core:
|
||||
type: veth
|
||||
gw: upstream1
|
||||
gw6: upstream1
|
||||
# gw: upstream1
|
||||
# gw6: upstream1
|
||||
hwaddr: 0A:14:48:01:24:01
|
||||
mgmt:
|
||||
type: veth
|
||||
|
|
Loading…
Reference in New Issue