nixos-module/container/bird: revert bgp experiments for now

This commit is contained in:
Astro 2023-01-22 01:43:33 +01:00
parent f2bb5a2735
commit ae6de7754c
14 changed files with 360 additions and 346 deletions

View File

@ -19,6 +19,4 @@ in
++ lib.filesystem.listFilesRecursive ./net;
site.net-combined = concatMapAttrsRecursive (name: value: { inherit (value) hosts4 hosts6; }) config.site.net;
site.bgp.asn = 4242421127;
}

View File

@ -1,5 +1,4 @@
{ config, lib, ... }:
{ lib, ... }:
{
site.net.c3d2 = {
dhcp = {
@ -109,34 +108,28 @@
c3d2.hwaddr = "0A:14:48:01:07:05";
core.hwaddr = "0A:14:48:01:07:04";
};
bgp.allowedUpstreams = [ "anon1" "freifunk" ];
ospf.allowedUpstreams = [ "anon1" "freifunk" ];
};
c3d2-gw1 = makeGateway {
interfaces = {
c3d2.hwaddr = "0A:14:48:01:21:01";
core.hwaddr = "0A:14:48:01:21:00";
};
bgp.allowedUpstreams = [ "flpk-gw" "freifunk" "upstream4" "upstream3" "anon1" ];
ospf.allowedUpstreams = [ "flpk-gw" "freifunk" "upstream4" "upstream3" "anon1" ];
};
c3d2-gw2 = makeGateway {
interfaces = {
c3d2.hwaddr = "0A:14:48:01:21:03";
core.hwaddr = "0A:14:48:01:21:02";
};
bgp.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
};
c3d2-gw3 = makeGateway {
interfaces = {
c3d2.hwaddr = "0A:14:48:01:21:05";
core.hwaddr = "0A:14:48:01:21:04";
};
bgp = {
peers.${config.site.net.core.hosts6.dn42.bgp} = {
type = "rr_client";
name = "rr";
};
allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
};
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
};
};
}

View File

@ -1,4 +1,4 @@
{ config, lib, ... }:
{ lib, ... }:
let
cephMonServers = [ "server5" "server6" "server8" ];
in
@ -158,13 +158,7 @@ in
type = "veth";
};
};
bgp = {
peers.${config.site.net.core.hosts6.dn42.bgp} = {
type = "rr_client";
name = "rr";
};
allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
};
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
};
server3 = makeServer;
server5 = makeServer;

View File

@ -1,5 +1,3 @@
{ config, lib, ... }:
{
site.net.core = {
domainName = "core.zentralwerk.org";
@ -133,7 +131,6 @@
upstream3 = "fd23:42:c3d2:581::b:2";
upstream4 = "fd23:42:c3d2:581::b:3";
vpn-gw = "fd23:42:c3d2:581:9001::1";
flpk-gw = "fd23:42:c3d2:581:9002::1";
};
up4 = {
anon1 = "2a00:8180:2c00:281::9:1";
@ -202,33 +199,15 @@
};
};
site.hosts = lib.mkMerge ([ {
site.hosts = {
bgp = {
bgp = {
asn = 4242421127;
peers = {
"172.22.99.253" = {
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";
};
"172.22.99.253" = { asn = 64699; };
"fe80::a800:42ff:fe7a:3246%c3d2" = { asn = 64699; };
};
# 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 = {
c3d2 = {
hwaddr = "0A:14:48:01:22:01";
@ -239,21 +218,14 @@
type = "veth";
};
};
};
} ] ++ 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";
};
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" ];
};
# TODO: upstreams
} ]
# except "bgp" itself :)
else []
) (builtins.attrNames config.site.net.core.hosts6.dn42));
role = "container";
};
};
}

View File

@ -1,5 +1,3 @@
{ config, ... }:
{
site.net.flpk = {
domainName = "flpk.zentralwerk.org";
@ -50,15 +48,9 @@
};
};
};
bgp = {
upstreamTable = "vpn_table";
ospf = {
allowedUpstreams = [ "upstream4" "upstream3" "freifunk" ];
# IPv6 ::/0 via wireguard tunnel
allowedUpstreams6 = [];
peers.${config.site.net.core.subnets6.dn42} = {
type = "upstream";
name = "up";
};
upstreamInstance = 2;
};
role = "container";
};

View File

@ -192,7 +192,10 @@
type = "veth";
};
};
bgp.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
ospf = {
allowedUpstreams =
[ "upstream4" "upstream3" "anon1" "freifunk" ];
};
role = "container";
};
}

View File

@ -38,7 +38,7 @@ lib.mkMerge (
core.type = "veth";
"priv${toString n}".type = "veth";
};
bgp.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ];
};
}
) (seq 1 privCount)
@ -540,7 +540,7 @@ lib.mkMerge (
hwaddr = "0A:14:47:02:2A:19";
};
};
bgp.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ];
};
priv18-gw = {
interfaces = {

View File

@ -39,7 +39,7 @@
type = "veth";
};
};
bgp = {
ospf = {
allowedUpstreams = [ "anon1" "freifunk" ];
allowedUpstreams6 = [ "flpk-gw" "anon1" "freifunk" ];
};

View File

@ -206,7 +206,7 @@
gw6 = null;
};
};
bgp.allowedUpstreams =
ospf.allowedUpstreams =
[ "upstream4" "upstream3" "anon1" "freifunk" ];
};
stats = makeContainer {

View File

@ -24,12 +24,8 @@ in
};
};
};
ospf.upstreamInstance = 7;
role = "container";
bgp.peers.${config.site.net.core.subnets6.dn42} = {
asn = config.site.hosts.upstream3.bgp.asn;
type = "upstream";
name = "up";
};
};
upstream4 = rec {
@ -325,19 +321,17 @@ in
};
};
};
bgp = {
nets4 = [
ospf = {
upstreamInstance = 8;
stubNets4 = [
"${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";
};
freifunk.ospf.upstreamInstance = 6;
anon1 = {
interfaces = {
core = {
@ -352,16 +346,9 @@ in
};
};
};
bgp = {
upstreamTable = "vpn_table";
ospf = {
allowedUpstreams = [ "upstream3" "upstream4" "freifunk" ];
# IPv6 ::/0 via wireguard tunnel
allowedUpstreams6 = [];
peers.${config.site.net.core.subnets6.dn42} = {
asn = config.site.hosts.upstream3.bgp.asn;
type = "upstream";
name = "up";
};
upstreamInstance = 5;
};
role = "container";
};

View File

@ -33,6 +33,8 @@
type = "wireguard";
};
};
bgp.allowedUpstreams = [ "flpk-gw" "anon1" "freifunk" ];
ospf = {
allowedUpstreams = [ "flpk-gw" "anon1" "freifunk" ];
};
};
}

View File

@ -1,5 +1,9 @@
# Dummy secrets for testing
{
site.net = {
core.ospf.secret = "encrypted";
};
site.hosts = {
ap1.password = "encrypted";
ap2.password = "encrypted";

View File

@ -148,6 +148,12 @@ let
type = with types; attrsOf (attrsOf str);
default = {};
};
ospf = {
secret = mkOption {
type = with types; nullOr str;
default = null;
};
};
dhcp = mkOption {
type = with types; nullOr (submodule { options = dhcpOpts; });
default = null;
@ -384,10 +390,35 @@ let
}; });
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 {
default = null;
type = with types; nullOr (submodule {
options = bgpOpts name;
options = bgpOpts;
});
};
services.dns = {
@ -458,52 +489,20 @@ let
};
};
bgpOpts = hostName: {
bgpOpts = {
asn = mkOption {
type = types.int;
default = config.site.bgp.asn;
};
peers = mkOption {
type = with types; attrsOf (submodule (submoduleArg: {
type = with types; attrsOf (submodule ({ ... }: {
options = {
asn = mkOption {
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 = {};
};
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, ... }: {
@ -614,12 +613,6 @@ in
default = "secret";
};
};
bgp = {
asn = mkOption {
type = types.int;
};
};
};
config.warnings =
@ -640,16 +633,16 @@ in
reportCollisions = name: getter: xs:
map (k: "Duplicate ${name}: ${k}") (findCollisions getter xs);
bgpUpstreamXorGw =
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.bgp.allowedUpstreams or [] != []
in if gwNets != [] && hostConf.ospf.allowedUpstreams != []
then [ ''
Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from BGP
Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from OSPF
'' ]
else []
) (builtins.attrNames config.site.hosts);
@ -657,7 +650,7 @@ in
(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 "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++
bgpUpstreamXorGw;
ospfUpstreamXorGw;
config.assertions =
# Duplicate host/net name check

View File

@ -25,42 +25,6 @@ let
n = n;
x = builtins.head 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
{
services.bird2 = {
@ -71,13 +35,31 @@ in
protocol kernel K4 {
learn;
ipv4 {
export all;
${if isUpstream
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 {
learn;
ipv6 {
export all;
${if isUpstream
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 {
@ -102,7 +84,10 @@ in
check link yes;
}
${lib.optionalString (hostConf.bgp.upstreamTable != null) ''
${lib.optionalString (
builtins.match "anon.*" hostName != null ||
hostName == "flpk-gw"
) ''
# BIRD routing table for Wireguard transport
ipv4 table vpn_table;
@ -143,6 +128,235 @@ 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
protocol static {
ipv4;
@ -156,170 +370,31 @@ in
}
${lib.optionalString (hostConf.bgp != null) ''
# zentralwerk-network
template bgp bgp_rr_server {
template bgp bgppeer {
local as ${toString hostConf.bgp.asn};
direct;
ipv4 {
import filter {
preference = preference + 200;
accept;
};
export filter {
if net ~ [ ${config.site.net.core.subnet4} ] then {
reject;
import all;
export where source=RTS_STATIC;
};
ipv6 {
import all;
export where source=RTS_STATIC;
};
}
${builtins.concatStringsSep "\n" (
map ({ n, x }:
let
peer = x;
peerConf = hostConf.bgp.peers.${peer};
in ''
protocol bgp bgp_${toString n} from bgppeer {
neighbor ${peer} as ${toString peerConf.asn};
}
${lib.optionalString (nets4 != []) ''
if net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}+") nets4} ] then {
accept;
}
''}
reject;
};
};
ipv6 {
import filter {
preference = preference + 200;
accept;
};
export filter {
if net ~ [ ${lib.concatStringsSep ", " (builtins.attrValues config.site.net.core.subnets6)} ] then {
reject;
}
${lib.optionalString (nets6 != []) ''
if net ~ [ ${lib.concatMapStringsSep ", " (n: "${n}+") nets6} ] then {
accept;
}
''}
reject;
};
};
}
template bgp bgp_rr_client {
local as ${toString hostConf.bgp.asn};
direct;
connect delay time 1;
connect retry time 3;
error wait time 1 5;
error forget time 5;
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;
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;
};
}
${lib.concatMapStrings (peer:
let
peerConf = hostConf.bgp.peers.${peer};
isRange = lib.hasInfix "/" peer;
in ''
protocol bgp bgp_${peerConf.name} from bgp_${peerConf.type} {
neighbor ${lib.optionalString isRange "range"} ${peer} as ${toString peerConf.asn};
${lib.optionalString isRange ''
dynamic name "bgp_${peerConf.name}";
''}
${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_${builtins.replaceStrings ["-"] ["_"] upstream} {
local as ${toString hostConf.bgp.asn};
neighbor ${config.site.net.core.hosts6.dn42.${upstream}} as ${toString hostConf.bgp.asn};
direct;
connect delay time 1;
connect retry time 3;
error wait time 1 5;
error forget time 5;
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)}
''
) (enumerate 1 (builtins.attrNames hostConf.bgp.peers))
)}
''}
'';
};
@ -353,7 +428,8 @@ in
];
};
instance = {
ipv4 = "bgp_up";
ipv4 = "ZW4_${hostNameEscaped}";
ipv6 = "ZW6_${hostNameEscaped}";
};
checkService = addressFamily: {
description = "Check connectivity for ${addressFamily}";
@ -392,6 +468,6 @@ in
};
in lib.mkIf isUpstream {
check-upstream-ipv4 = checkService "ipv4";
#check-upstream-ipv6 = checkService "ipv6";
check-upstream-ipv6 = checkService "ipv6";
};
}