cofractal-ams01: bgp-over-ipv4

This commit is contained in:
Luke Granger-Brown 2023-01-18 23:41:42 +00:00
parent 756c1a3dd2
commit 9213875d8b
2 changed files with 65 additions and 19 deletions

View file

@ -6,6 +6,7 @@
{ {
imports = [ imports = [
../lib/zfs.nix ../lib/zfs.nix
../lib/bgp.nix
]; ];
# Otherwise _this_ machine won't enumerate things properly. # Otherwise _this_ machine won't enumerate things properly.
@ -136,5 +137,31 @@
(bindMountSvc "/var/lib/tailscale" "tailscaled.service") (bindMountSvc "/var/lib/tailscale" "tailscaled.service")
]; ];
services.lukegbgp = let
local.asn = 205479;
in {
enable = true;
config = {
local = {
routerID = "199.19.152.160";
};
export.v4 = [ ];
peering.cofractal = {
local = local // {
v6 = "2a09:a446:1337:ffff::10";
};
remote = {
asn = 26073;
export_community = 6000;
routers = [{
v6 = "2a09:a446:1337:ffff::2";
} {
v6 = "2a09:a446:1337:ffff::3";
}];
};
};
};
};
system.stateVersion = "23.05"; system.stateVersion = "23.05";
} }

View file

@ -6,8 +6,8 @@
let let
generateSnippet = base: args: lib.concatStringsSep "\n" (lib.mapAttrsToList ( ixName: ix: generateSnippetForIX (args // { ixName = ixName; ix = ix; }) ) base ); generateSnippet = base: args: lib.concatStringsSep "\n" (lib.mapAttrsToList ( ixName: ix: generateSnippetForIX (args // { ixName = ixName; ix = ix; }) ) base );
generateSnippetForIX = { ixName, ix, ... }@args: '' generateSnippetForIX = { ixName, ix, ... }@args: ''
${lib.optionalString (doesIPv4 ix) ''
ipv4 table ${ixName}4; ipv4 table ${ixName}4;
ipv6 table ${ixName}6;
filter bgp_in_${ixName}4 filter bgp_in_${ixName}4
prefix set allnet; prefix set allnet;
int set allas; int set allas;
@ -19,35 +19,38 @@ let
bgp_local_pref = ${toString ix.remote.bgp_local_pref}; bgp_local_pref = ${toString ix.remote.bgp_local_pref};
accept; accept;
} }
filter bgp_in_${ixName}6
prefix set allnet;
int set allas;
{
if ! (avoid_martians6()) then reject;
${if ix.remote.must_be_next_hop then "if (bgp_path.first != ${toString ix.remote.asn}) then reject;" else "# no next-hop requirement"}
${lib.concatMapStringsSep "\n" (asn: "if (bgp_path ~ [= * ${toString asn} * =]) then reject;") ix.remote.drop_asns}
if (bgp_path ~ [= * 16276 * =] && gw = 2001:7f8:4::3f94:2) then gw = 2001:7f8:4::3f94:1; # OVH must go via router 1; router 2 is bork.
bgp_local_pref = ${toString ix.remote.bgp_local_pref};
accept;
}
filter bgp_export_${ixName}4 filter bgp_export_${ixName}4
{ {
if ! ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community) then reject; if ! ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community) then reject;
bgp_ext_community.delete([(ro, ${toString ix.local.asn}, *)]); bgp_ext_community.delete([(ro, ${toString ix.local.asn}, *)]);
accept; accept;
} }
filter bgp_export_${ixName}6
{
if ! ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community) then reject;
bgp_ext_community.delete([(ro, ${toString ix.local.asn}, *)]);
accept;
}
protocol pipe ${ixName}pipe_4 { protocol pipe ${ixName}pipe_4 {
table ${ixName}4; table ${ixName}4;
peer table master4; peer table master4;
import ${if ix.remote.is_route_collector then "all" else "where ((ro, ${toString ix.local.asn}, ${toString ix.remote.export_community}) ~ bgp_ext_community)"}; import ${if ix.remote.is_route_collector then "all" else "where ((ro, ${toString ix.local.asn}, ${toString ix.remote.export_community}) ~ bgp_ext_community)"};
export filter bgp_in_${ixName}4; export filter bgp_in_${ixName}4;
}; };
''}
ipv6 table ${ixName}6;
filter bgp_in_${ixName}6
prefix set allnet;
int set allas;
{
if ! (avoid_martians6()) then reject;
${if ix.remote.must_be_next_hop then "if (bgp_path.first != ${toString ix.remote.asn}) then reject;" else "# no next-hop requirement"}
${lib.concatMapStringsSep "\n" (asn: "if (bgp_path ~ [= * ${toString asn} * =]) then reject;") ix.remote.drop_asns}
if (bgp_path ~ [= * 16276 * =] && gw = 2001:7f8:4::3f94:2) then gw = 2001:7f8:4::3f94:1; # OVH must go via router 1; router 2 is bork.
bgp_local_pref = ${toString ix.remote.bgp_local_pref};
accept;
}
filter bgp_export_${ixName}6
{
if ! ((ro, ${toString ix.local.asn}, 1000) ~ bgp_ext_community) then reject;
bgp_ext_community.delete([(ro, ${toString ix.local.asn}, *)]);
accept;
}
protocol pipe ${ixName}pipe_6 { protocol pipe ${ixName}pipe_6 {
table ${ixName}6; table ${ixName}6;
peer table master6; peer table master6;
@ -55,12 +58,14 @@ let
export filter bgp_in_${ixName}6; export filter bgp_in_${ixName}6;
}; };
'' + lib.concatImapStringsSep "\n" ( i: v: generateSnippetForRouter (args // { routerNum = i; router = v; }) ) ix.remote.routers; '' + lib.concatImapStringsSep "\n" ( i: v: generateSnippetForRouter (args // { routerNum = i; router = v; }) ) ix.remote.routers;
doesIPv4 = ix: (ix.local.v4 != null) || ix.v4onv6;
enabledSnippet = { enabled ? true, ... }: "disabled ${if enabled then "off" else "on"};"; enabledSnippet = { enabled ? true, ... }: "disabled ${if enabled then "off" else "on"};";
passwordSnippet = { password ? null, ... }: if password == null then "# no password" else "password \"${password}\";"; passwordSnippet = { password ? null, ... }: if password == null then "# no password" else "password \"${password}\";";
multihopSnippet = { multihop ? null, ... }: if multihop == null then "# not multihop" else "multihop ${toString multihop};"; multihopSnippet = { multihop ? null, ... }: if multihop == null then "# not multihop" else "multihop ${toString multihop};";
passiveSnippet = { passive, ... }: "passive ${if passive then "on" else "off"};"; passiveSnippet = { passive, ... }: "passive ${if passive then "on" else "off"};";
prefixLimitSnippet = limit: if limit == null then "# no import limit" else "import limit ${toString limit} action restart;"; prefixLimitSnippet = limit: if limit == null then "# no import limit" else "import limit ${toString limit} action restart;";
generateSnippetForRouter = { ixName, ix, routerNum, router, ... }: '' generateSnippetForRouter = { ixName, ix, routerNum, router, ... }: ''
${lib.optionalString (ix.local.v4 != null) ''
protocol bgp ${ixName}${toString routerNum}_4 { protocol bgp ${ixName}${toString routerNum}_4 {
${enabledSnippet router} ${enabledSnippet router}
${passwordSnippet router} ${passwordSnippet router}
@ -77,6 +82,7 @@ let
${prefixLimitSnippet ix.remote.prefix_limit.v4} ${prefixLimitSnippet ix.remote.prefix_limit.v4}
}; };
}; };
''}
protocol bgp ${ixName}${toString routerNum}_6 { protocol bgp ${ixName}${toString routerNum}_6 {
${enabledSnippet router} ${enabledSnippet router}
${passwordSnippet router} ${passwordSnippet router}
@ -86,6 +92,14 @@ let
neighbor ${router.v6} as ${toString ix.remote.asn}; neighbor ${router.v6} as ${toString ix.remote.asn};
graceful restart on; graceful restart on;
long lived graceful restart on; long lived graceful restart on;
${lib.optionalString (ix.v4onv6) ''
ipv4 {
table ${ixName}4;
import all;
export ${if ix.remote.is_route_collector then "all" else "filter bgp_export_${ixName}4"};
${prefixLimitSnippet ix.remote.prefix_limit.v4}
};
''}
ipv6 { ipv6 {
table ${ixName}6; table ${ixName}6;
import all; import all;
@ -124,7 +138,8 @@ in {
type = int; type = int;
}; };
v4 = mkOption { # lukegbgp.config.peering.<foo>.local.v4 v4 = mkOption { # lukegbgp.config.peering.<foo>.local.v4
type = str; type = nullOr str;
default = null;
}; };
v6 = mkOption { # lukegbgp.config.peering.<foo>.local.v6 v6 = mkOption { # lukegbgp.config.peering.<foo>.local.v6
type = str; type = str;
@ -132,6 +147,10 @@ in {
}; };
}; };
}; };
v4onv6 = mkOption {
type = bool;
default = false;
};
remote = mkOption { # lukegbgp.config.peering.<foo>.remote remote = mkOption { # lukegbgp.config.peering.<foo>.remote
type = submodule { type = submodule {
options = { options = {