diff --git a/flake.lock b/flake.lock index 753c7e3..407818d 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ "search": "search" }, "locked": { - "lastModified": 1765413700, - "narHash": "sha256-INy4w+BPh8qmZqjuPl6I99v5Pmbjj2rGgw1ZAF3CCE4=", + "lastModified": 1765502499, + "narHash": "sha256-1keygd7+VHlak3rpja3Xq3Sxc+oXFH72ynUzRQz6ps8=", "owner": "wavelens", "repo": "gobgp.nix", - "rev": "a7f5b6a76a6b7a181f94886be32fafd781352bbd", + "rev": "f4edf4c4e86c0dcb9ba3a6c5ae487fd7ce11a3f1", "type": "github" }, "original": { diff --git a/tests/bgp-extended-nexthop/default.nix b/tests/bgp-extended-nexthop/default.nix index 65ddf09..047c76a 100644 --- a/tests/bgp-extended-nexthop/default.nix +++ b/tests/bgp-extended-nexthop/default.nix @@ -1,7 +1,10 @@ -{ ... }: +{ inputs, ... }: { name = "bgp-extended-nexthop"; + # required in node c - gobgp module + node.pkgsReadOnly = false; + defaults = { networking.firewall.allowedTCPPorts = [ 179 ]; }; @@ -29,14 +32,20 @@ neighbor fe80::2 capability extended-nexthop neighbor fe80::2 interface eth1 + neighbor fe80::3 remote-as 64498 + neighbor fe80::3 capability extended-nexthop + neighbor fe80::3 interface eth1 + address-family ipv4 unicast network 198.51.100.0/25 neighbor fe80::2 activate + neighbor fe80::3 activate exit-address-family address-family ipv6 unicast network 2001:db8:beef::/48 neighbor fe80::2 activate + neighbor fe80::3 activate exit-address-family ''; }; @@ -73,14 +82,12 @@ } protocol static static4 { - vrf "vrf0"; ipv4; route 198.51.100.128/25 unreachable; } protocol static static6 { - vrf "vrf0"; ipv6; route 2001:db8:c0de::/48 unreachable; @@ -102,9 +109,117 @@ export all; }; } + + protocol bgp c { + local as 64497; + neighbor fe80::3 as 64498; + interface "eth1"; + + ipv4 { + extended next hop on; + import all; + export all; + }; + + ipv6 { + import all; + export all; + }; + } ''; }; }; + c = { + imports = [ inputs.gobgp.nixosModules.gobgp ]; + networking.interfaces.eth1.ipv6.addresses = [ + { + address = "fe80::3"; + prefixLength = 64; + } + ]; + services.gobgpd = { + enable = true; + zebra = true; + validateConfig = false; + config = { + global = { + as = 64498; + router-id = "192.0.2.3"; + apply-policy = { + default-import-policy = "accept-route"; + export-policy-list = [ "c-out" ]; + default-export-policy = "reject-route"; + }; + }; + zebra = { + enabled = true; + redistribute-route-type-list = [ + "kernel" + "directly-connected" + "static" + ]; + }; + static-paths = { + "unreachable-ipv4".prefix = "203.0.113.0/24"; + "unreachable-ipv6".prefix = "2001:db8:dead::/48"; + }; + neighbors = { + "a" = { + neighbor-address = "fe80::1%eth1"; + peer-as = 64496; + afi-safis = { + "ipv4-unicast" = { }; + "ipv6-unicast" = { }; + }; + }; + "b" = { + neighbor-address = "fe80::2%eth1"; + peer-as = 64497; + afi-safis = { + "ipv4-unicast" = { }; + "ipv6-unicast" = { }; + }; + }; + }; + defined-sets.prefix-sets = { + "c-out-ipv4".prefix-list = [ + { + ip-prefix = "203.0.113.0/24"; + masklength-range = "24..32"; + } + ]; + "c-out-ipv6".prefix-list = [ + { + ip-prefix = "2001:db8:dead::/48"; + masklength-range = "48..128"; + } + ]; + }; + policy-definitions."c-out" = { + statements = { + "c-out-ipv4" = { + actions.route-disposition = "accept-route"; + conditions = { + match-prefix-set = { + prefix-set = "c-out-ipv4"; + match-set-options = "any"; + }; + }; + }; + "c-out-ipv6" = { + actions.route-disposition = "accept-route"; + conditions = { + match-prefix-set = { + prefix-set = "c-out-ipv6"; + match-set-options = "any"; + }; + }; + }; + }; + }; + }; + }; + }; }; testScript = '' @@ -117,14 +232,31 @@ b.wait_for_unit("bird.service") with subtest("ensure bgp sessions are established"): - a.wait_until_succeeds("vtysh -c 'show bgp ipv4 summary' | grep 'fe80::2.*1\\s*2\\s*N/A'") - a.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep 'fe80::2.*1\\s*2\\s*N/A'") + a.wait_until_succeeds("vtysh -c 'show bgp ipv4 summary' | grep 'fe80::2.*2\\s*3\\s*N/A'") + a.wait_until_succeeds("vtysh -c 'show bgp ipv4 summary' | grep 'fe80::3.*1\\s*3\\s*N/A'") b.wait_until_succeeds("birdc show protocols | grep 'a.*Established'") + b.wait_until_succeeds("birdc show protocols | grep 'c.*Established'") + c.wait_until_succeeds("gobgp neighbor -a 'ipv4' | grep 'fe80::1%eth1.*Establ.*|.*3.*2'") + c.wait_until_succeeds("gobgp neighbor -a 'ipv4' | grep 'fe80::2%eth1.*Establ.*|.*2.*2'") + + # IPv6 DAD might need some time to complete for the local link address, which is required by frr + a.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep 'fe80::2.*2\\s*3\\s*N/A'") + a.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep 'fe80::3.*1\\s*3\\s*N/A'") + c.wait_until_succeeds("gobgp neighbor -a 'ipv6' | grep 'fe80::1%eth1.*Establ.*|.*3.*2'") + c.wait_until_succeeds("gobgp neighbor -a 'ipv6' | grep 'fe80::2%eth1.*Establ.*|.*2.*2'") with subtest("ensure routes have been installed"): - a.succeed("ip route show | grep 198.51.100.128/25") b.succeed("ip route show | grep 198.51.100.0/25") - a.succeed("ip -6 route show | grep 2001:db8:c0de::/48") + c.succeed("ip route show | grep 198.51.100.0/25") + a.succeed("ip route show | grep 198.51.100.128/25") + c.succeed("ip route show | grep 198.51.100.128/25") + a.succeed("ip route show | grep 203.0.113.0/24") + b.succeed("ip route show | grep 203.0.113.0/24") b.succeed("ip -6 route show | grep 2001:db8:beef::/48") + c.succeed("ip -6 route show | grep 2001:db8:beef::/48") + a.succeed("ip -6 route show | grep 2001:db8:c0de::/48") + c.succeed("ip -6 route show | grep 2001:db8:c0de::/48") + a.succeed("ip -6 route show | grep 2001:db8:dead::/48") + b.succeed("ip -6 route show | grep 2001:db8:dead::/48") ''; }