From 3ac383794beaeeaeab3812b4e41ab762cff2f973 Mon Sep 17 00:00:00 2001 From: Nico Felbinger Date: Sun, 12 Jul 2026 02:50:37 +0200 Subject: [PATCH] tests/bgp-frr-srv6: init --- tests/README.md | 1 + tests/bgp-frr-srv6/README.md | 59 +++++++++ tests/bgp-frr-srv6/ce1.nix | 66 ++++++++++ tests/bgp-frr-srv6/ce2.nix | 97 +++++++++++++++ tests/bgp-frr-srv6/ce3.nix | 54 ++++++++ tests/bgp-frr-srv6/ce4.nix | 65 ++++++++++ tests/bgp-frr-srv6/default.nix | 196 +++++++++++++++++++++++++++++ tests/bgp-frr-srv6/p1.nix | 44 +++++++ tests/bgp-frr-srv6/pe1.nix | 219 +++++++++++++++++++++++++++++++++ tests/bgp-frr-srv6/pe2.nix | 203 ++++++++++++++++++++++++++++++ tests/bgp-frr-srv6/pe3.nix | 193 +++++++++++++++++++++++++++++ 11 files changed, 1197 insertions(+) create mode 100644 tests/bgp-frr-srv6/README.md create mode 100644 tests/bgp-frr-srv6/ce1.nix create mode 100644 tests/bgp-frr-srv6/ce2.nix create mode 100644 tests/bgp-frr-srv6/ce3.nix create mode 100644 tests/bgp-frr-srv6/ce4.nix create mode 100644 tests/bgp-frr-srv6/default.nix create mode 100644 tests/bgp-frr-srv6/p1.nix create mode 100644 tests/bgp-frr-srv6/pe1.nix create mode 100644 tests/bgp-frr-srv6/pe2.nix create mode 100644 tests/bgp-frr-srv6/pe3.nix diff --git a/tests/README.md b/tests/README.md index 93b0b8a..c71ccb2 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,6 +6,7 @@ | bgp-extended-nexthop | FRR, BIRD3 | | bgp-frr-unnumbered | FRR | | bgp-frr-vpn-route-leak | FRR | +| bgp-frr-srv6 | FRR, (GoBGP) | | bgp-md5 | FRR, BIRD3 | | bgp-prefsource | FRR, BIRD3 | | bgp-simple | FRR, BIRD3, GoBGP | diff --git a/tests/bgp-frr-srv6/README.md b/tests/bgp-frr-srv6/README.md new file mode 100644 index 0000000..1c0c3eb --- /dev/null +++ b/tests/bgp-frr-srv6/README.md @@ -0,0 +1,59 @@ +# bgp-frr-srv6 + +This integration test implements a basic service-provider topology to test IPv6 Segment Routing (SRv6) behavior end-to-end. + +The provider network consists of four routers (P1, PE1, PE2, and PE3) and uses only ipv6. Customers A and B are connected to the provider through customer-edge routers: CE1 and CE2 for customer A, and CE3 and CE4 for customer B. In this setup, CE1 and CE3 connect into PE1, while CE2 connects into PE2, and CE4 connects into PE3. + +```mermaid +flowchart LR + CE1["CE1 + (A)"] + CE2["CE2 + (A)"] + CE3["CE3 + (B)"] + CE4["CE4 + (B)"] + + CE3 --20--- PE1 + CE1 --10--- PE1 + PE1 --3--- P1 + P1 --4--- PE2 --11--- CE2 + P1 --5--- PE3 --21--- CE4 + PE2 --6--- PE1 +``` + +## Addresses + +| System | IPv4 | IPv6 | +|--------|-------------------------|-------------------------------| +| P1 | | | +| PE1 | | 2001:db8:1::/48 (lo: :ffff::1)| +| PE2 | | 2001:db8:2::/48 (lo: :ffff::1)| +| PE3 | | 2001:db8:3::/48 (lo: :ffff::1)| +| CE1 | 10.10.1.0/24 (lo: .100) | 3fff:aaaa:1::/48 (lo: ::100) | +| CE2 | 10.10.2.0/24 (lo: .100) | 3fff:aaaa:2::/48 (lo: ::100) | +| CE3 | 10.20.1.0/24 (lo: .100) | 3fff:bbbb:1::/48 (lo: ::100) | +| CE4 | 10.20.2.0/24 (lo: .100) | 3fff:bbbb:2::/48 (lo: ::100) | + + +## Software Selection +| System | Network Implementation | Routing Daemon | +|--------|---------------------------|------------------| +| P1 | legacy networking options | FRR (isisd) | +| PE1 | legacy networking options | FRR (isisd,bgpd) | +| PE2 | systemd-network | FRR (isisd,bgpd)*| +| PE3 | ifstate | FRR (isisd,bgpd) | +| CE1 | systemd-network | FRR (bgpd) | +| CE2 | legacy networking options | BIRD | +| CE3 | legacy networking options | FRR (bgpd) | +| CE4 | ifstate | FRR (bgpd) | + +\* GoBGP planned + +## Resources +This test was only possible because of these blog posts: +- https://onvox.net/2022/06/27/srv6-frr/ +- https://onvox.net/2024/02/01/srv6-vyos/ +- https://onvox.net/2024/12/16/srv6-frr/ +- https://onvox.net/2024/12/26/srv6-vyos-revisit/ diff --git a/tests/bgp-frr-srv6/ce1.nix b/tests/bgp-frr-srv6/ce1.nix new file mode 100644 index 0000000..1dc4380 --- /dev/null +++ b/tests/bgp-frr-srv6/ce1.nix @@ -0,0 +1,66 @@ +{ + virtualisation.interfaces.eth1 = { + vlan = 10; + assignIP = false; + }; + systemd.network = { + enable = true; + networks = { + "10-lo" = { + matchConfig.Name = "lo"; + address = [ + "10.10.1.100/32" + "3fff:aaaa:1::100/128" + ]; + }; + "20-eth1" = { + matchConfig.Name = "eth1"; + address = [ + "192.0.2.129/30" + "2001:db8:10:128::1/64" + ]; + }; + }; + }; + services.frr = { + bgpd.enable = true; + config = '' + route-map set-src permit 10 + set src 10.10.1.100 + exit + + route-map set-src-6 permit 10 + set src 3fff:aaaa:1::100 + exit + + ip protocol bgp route-map set-src + ipv6 protocol bgp route-map set-src-6 + + ip route 10.10.1.0/24 reject + ipv6 route 3fff:aaaa:1::/48 reject + + router bgp 65001 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor 192.0.2.130 remote-as 65000 + no neighbor 192.0.2.130 enforce-first-as + neighbor 2001:db8:10:128::2 remote-as 65000 + no neighbor 2001:db8:10:128::2 enforce-first-as + + address-family ipv4 unicast + network 10.10.1.0/24 + neighbor 192.0.2.130 activate + neighbor 192.0.2.130 soft-reconfiguration inbound + exit-address-family + + address-family ipv6 unicast + network 3fff:aaaa:1::/48 + neighbor 2001:db8:10:128::2 activate + neighbor 2001:db8:10:128::2 soft-reconfiguration inbound + exit-address-family + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/ce2.nix b/tests/bgp-frr-srv6/ce2.nix new file mode 100644 index 0000000..e3e9490 --- /dev/null +++ b/tests/bgp-frr-srv6/ce2.nix @@ -0,0 +1,97 @@ +{ + virtualisation.interfaces.eth1 = { + vlan = 11; + assignIP = false; + }; + networking.interfaces = { + lo = { + ipv4.addresses = [ + { + address = "10.10.2.100"; + prefixLength = 32; + } + ]; + ipv6.addresses = [ + { + address = "3fff:aaaa:2::100"; + prefixLength = 128; + } + ]; + }; + eth1 = { + ipv4.addresses = [ + { + address = "192.0.2.133"; + prefixLength = 30; + } + ]; + ipv6.addresses = [ + { + address = "2001:db8:10:132::1"; + prefixLength = 64; + } + ]; + }; + }; + services.bird = { + enable = true; + config = '' + log syslog all; + router id 10.10.2.100; + + protocol device { + scan time 10; + } + + protocol kernel kernel4 { + ipv4 { + import none; + export filter { + krt_prefsrc = 10.10.2.100; + accept; + }; + }; + } + protocol kernel kernel6 { + ipv6 { + import none; + export filter { + krt_prefsrc = 3fff:aaaa:2::100; + accept; + }; + }; + } + + protocol static static4 { + ipv4; + + route 10.10.2.0/24 unreachable; + } + protocol static static6 { + ipv6; + + route 3fff:aaaa:2::/48 unreachable; + } + + protocol bgp pe2_v4 { + local as 65002; + neighbor 192.0.2.134 as 65000; + + ipv4 { + import all; + export all; + }; + } + + protocol bgp pe2_v6 { + local as 65002; + neighbor 2001:db8:10:132::2 as 65000; + + ipv6 { + import all; + export all; + }; + } + ''; + }; +} diff --git a/tests/bgp-frr-srv6/ce3.nix b/tests/bgp-frr-srv6/ce3.nix new file mode 100644 index 0000000..9226236 --- /dev/null +++ b/tests/bgp-frr-srv6/ce3.nix @@ -0,0 +1,54 @@ +{ + virtualisation.interfaces.eth1 = { + vlan = 20; + assignIP = false; + }; + networking = { + interfaces = { + lo = { + ipv4.addresses = [ + { + address = "10.20.1.100"; + prefixLength = 32; + } + ]; + ipv6.addresses = [ + { + address = "3fff:bbbb:1::100"; + prefixLength = 128; + } + ]; + }; + eth1 = { }; # set interface up + }; + }; + services.frr = { + bgpd.enable = true; + config = '' + ip route 10.20.1.0/24 reject + ipv6 route 3fff:bbbb:1::/48 reject + + router bgp 65003 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor eth1 interface remote-as 65000 + no neighbor eth1 enforce-first-as + no neighbor eth1 capability link-local + + address-family ipv4 unicast + network 10.20.1.0/24 + neighbor eth1 activate + neighbor eth1 soft-reconfiguration inbound + exit-address-family + + address-family ipv6 unicast + network 3fff:bbbb:1::/48 + neighbor eth1 activate + neighbor eth1 soft-reconfiguration inbound + exit-address-family + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/ce4.nix b/tests/bgp-frr-srv6/ce4.nix new file mode 100644 index 0000000..19707ff --- /dev/null +++ b/tests/bgp-frr-srv6/ce4.nix @@ -0,0 +1,65 @@ +{ + virtualisation.interfaces.eth1 = { + vlan = 21; + assignIP = false; + }; + networking = { + ifstate = { + enable = true; + settings = { + parameters.ignore.ifname = [ + "eth0" + ]; + interfaces = { + eth1.link = { + state = "up"; + kind = "physical"; + }; + loopback = { + addresses = [ + "10.20.2.100/32" + "3fff:bbbb:2::100/128" + ]; + link = { + state = "up"; + kind = "dummy"; + }; + }; + }; + sysctl.all = { + ipv4.forwarding = 1; + ipv6.forwarding = 1; + }; + }; + }; + }; + services.frr = { + bgpd.enable = true; + config = '' + ip route 10.20.2.0/24 reject + ipv6 route 3fff:bbbb:2::/48 reject + + router bgp 65004 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor eth1 interface remote-as 65000 + no neighbor eth1 enforce-first-as + no neighbor eth1 capability link-local + + address-family ipv4 unicast + network 10.20.2.0/24 + neighbor eth1 activate + neighbor eth1 soft-reconfiguration inbound + exit-address-family + + address-family ipv6 unicast + network 3fff:bbbb:2::/48 + neighbor eth1 activate + neighbor eth1 soft-reconfiguration inbound + exit-address-family + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/default.nix b/tests/bgp-frr-srv6/default.nix new file mode 100644 index 0000000..6842e7b --- /dev/null +++ b/tests/bgp-frr-srv6/default.nix @@ -0,0 +1,196 @@ +{ lib, pkgs, ... }: +{ + name = "bgp-frr-srv6"; + + defaults = { + networking = { + useDHCP = false; + firewall = { + allowedTCPPorts = [ 179 ]; + extraCommands = '' + ip6tables -I INPUT -m pkttype --pkt-type unicast -j ACCEPT + ip6tables -I INPUT -m pkttype --pkt-type multicast -j ACCEPT + ''; + }; + }; + }; + + nodes = { + p1 = import ./p1.nix; + pe1 = import ./pe1.nix; + pe2 = import ./pe2.nix; + pe3 = import ./pe3.nix; + ce1 = import ./ce1.nix; + ce2 = import ./ce2.nix; + ce3 = import ./ce3.nix; + ce4 = import ./ce4.nix; + }; + + interactive.nodes = lib.listToAttrs ( + map + (name: { + inherit name; + value.environment.systemPackages = with pkgs; [ + tcpdump + pwru + ]; + }) + [ + "pe1" + "pe2" + "pe3" + ] + ); + + testScript = + let + jq = lib.getExe pkgs.jq; + in + '' + start_all() + + for m in [p1, pe1, pe2, pe3, ce1, ce2, ce3, ce4]: + m.wait_for_unit("network.target") + + pe1.wait_for_unit("network-local-commands.service") + + for m in [p1, pe1, pe2, pe3, ce1, ce3, ce4]: + m.wait_for_unit("frr.service") + ce2.wait_for_unit("bird.service") + + + with subtest("Ensure ip rule reconfiguration on PE worked"): + for m in [pe1, pe2, pe3]: + m.fail("ip -4 --json rule | ${jq} -e 'any(.[]; .priority == 0)'") + m.fail("ip -6 --json rule | ${jq} -e 'any(.[]; .priority == 0)'") + m.succeed("ip -6 --json rule | ${jq} -e 'map(select(.priority == 500)) | length == 2'") + + + with subtest("Ensure IS-IS found neighbors"): + for m, interface in [ + (p1, "eth1"), (pe1, "eth1"), + (p1, "eth2"), (pe2, "eth1"), + (p1, "eth3"), (pe3, "eth1"), + (pe1, "eth4"), (pe2, "eth3"), + ]: + m.wait_until_succeeds(f""" + vtysh -c 'show isis neighbor json' | ${jq} -e -r '.areas[].circuits[] | select(.interface == "{interface}") | .state == "Up"' + """) + + + with subtest("Ensure IS-IS has ipv6 route"): + for route in [f"2001:db8:{i}::/48" for i in range(1, 4)]: + p1.wait_until_succeeds(f"vtysh -c 'show ipv6 route isis' | grep 'I>\\* '{route}") + + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:2::/48'") + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:3::/48'") + + pe2.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:1::/48'") + pe2.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:3::/48'") + + pe3.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:1::/48'") + pe3.wait_until_succeeds("vtysh -c 'show ipv6 route isis' | grep 'I>\\* 2001:db8:2::/48'") + + + with subtest("Ensure PE can ping each other"): + pe1.wait_until_succeeds("ping -c 1 2001:db8:2:ffff::1") + pe1.wait_until_succeeds("ping -c 1 2001:db8:3:ffff::1") + + pe2.wait_until_succeeds("ping -c 1 2001:db8:1:ffff::1") + pe2.wait_until_succeeds("ping -c 1 2001:db8:3:ffff::1") + + pe3.wait_until_succeeds("ping -c 1 2001:db8:1:ffff::1") + pe3.wait_until_succeeds("ping -c 1 2001:db8:2:ffff::1") + + + with subtest("Ensure seg6 is enabled on interfaces towards provider network"): + assert "= 1" in pe1.succeed("sysctl net.ipv6.conf.eth1.seg6_enabled") + assert "= 1" in pe1.succeed("sysctl net.ipv6.conf.eth4.seg6_enabled") + + assert "= 1" in pe2.succeed("sysctl net.ipv6.conf.eth1.seg6_enabled") + assert "= 1" in pe2.succeed("sysctl net.ipv6.conf.eth3.seg6_enabled") + + assert "= 1" in pe3.succeed("sysctl net.ipv6.conf.eth1.seg6_enabled") + + + with subtest("Validate SRv6 SID exist"): + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route bgp' | grep 'B>\\* 2001:db8:1:aaa:65::/128.*seg6local uDT46 table 101'") + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route bgp' | grep 'B>\\* 2001:db8:1:aaa:66::/128.*seg6local uDT46 table 102'") + pe2.wait_until_succeeds("vtysh -c 'show ipv6 route bgp' | grep 'B>\\* 2001:db8:2:aaa:65::/128.*seg6local uDT46 table 101'") + pe3.wait_until_succeeds("vtysh -c 'show ipv6 route bgp' | grep 'B>\\* 2001:db8:3:aaa:66::/128.*seg6local uDT46 table 102'") + + + with subtest("Validate routes are in the global IPv4 VPN table"): + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv4 vpn' | grep '\\*>\\s*10.10.1.0/24\\s*192.0.2.129@7<'") + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv4 vpn' | grep '\\*>\\s*10.20.1.0/24\\s*fe80::5054:ff:fe12:1403@8<'") + pe2.wait_until_succeeds("vtysh -c 'show bgp ipv4 vpn' | grep '\\*>\\s*10.10.2.0/24\\s*192.0.2.133@6<'") + pe3.wait_until_succeeds("vtysh -c 'show bgp ipv4 vpn' | grep '\\*>\\s*10.20.2.0/24\\s*fe80::5054:ff:fe12:1504@5<'") + + + with subtest("Validate routes are in the global IPv6 VPN table"): + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv6 vpn' | grep '\\*>\\s*3fff:aaaa:1::/48\\s*2001:db8:10:128::1@7<'") + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv6 vpn' | grep '\\*>\\s*3fff:bbbb:1::/48\\s*fe80::5054:ff:fe12:1403@8<'") + pe2.wait_until_succeeds("vtysh -c 'show bgp ipv6 vpn' | grep '\\*>\\s*3fff:aaaa:2::/48\\s*2001:db8:10:132::1@6<'") + pe3.wait_until_succeeds("vtysh -c 'show bgp ipv6 vpn' | grep '\\*>\\s*3fff:bbbb:2::/48\\s*fe80::5054:ff:fe12:1504@5<'") + + + with subtest("Validate IPv4 routes are received from the CE and are imported into the VRF from other PEs"): + pe1.wait_until_succeeds("vtysh -c 'show bgp vrf A ipv4' | grep '\\*>\\s*10.10.1.0/24\\s*192.0.2.129'") + pe1.wait_until_succeeds("vtysh -c 'show bgp vrf B ipv4' | grep '\\*>\\s*10.20.1.0/24\\s*eth3'") + pe2.wait_until_succeeds("vtysh -c 'show bgp vrf A ipv4' | grep '\\*>\\s*10.10.2.0/24\\s*192.0.2.133'") + pe3.wait_until_succeeds("vtysh -c 'show bgp vrf B ipv4' | grep '\\*>\\s*10.20.2.0/24\\s*eth2'") + + + with subtest("Validate IPv6 routes are received from the CE and are imported into the VRF from other PEs"): + pe1.wait_until_succeeds("vtysh -c 'show bgp vrf A ipv6' | grep '\\*>\\s*3fff:aaaa:1::/48\\s*fe80::5054:ff:fe12:a01'") + pe1.wait_until_succeeds("vtysh -c 'show bgp vrf B ipv6' | grep '\\*>\\s*3fff:bbbb:1::/48\\s*eth3'") + pe2.wait_until_succeeds("vtysh -c 'show bgp vrf A ipv6' | grep '\\*>\\s*3fff:aaaa:2::/48\\s*fe80::5054:ff:fe12:b02'") + pe3.wait_until_succeeds("vtysh -c 'show bgp vrf B ipv6' | grep '\\*>\\s*3fff:bbbb:2::/48\\s*eth2'") + + + with subtest("Verify IPv4 routes are installed into the Linux kernel"): + pe1.wait_until_succeeds("vtysh -c 'show ip route vrf A' | grep 'B>\\* 10.10.1.0/24.*via 192.0.2.129, eth2'") + pe1.wait_until_succeeds("vtysh -c 'show ip route vrf B' | grep 'B>\\* 10.20.1.0/24.*via fe80::5054:ff:fe12:1403, eth3'") + pe2.wait_until_succeeds("vtysh -c 'show ip route vrf A' | grep 'B>\\* 10.10.2.0/24.*via 192.0.2.133, eth2'") + pe3.wait_until_succeeds("vtysh -c 'show ip route vrf B' | grep 'B>\\* 10.20.2.0/24.*via fe80::5054:ff:fe12:1504, eth2'") + + + with subtest("Verify IPv6 routes are installed into the Linux kernel"): + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route vrf A' | grep 'B>\\* 3fff:aaaa:1::/48.*via fe80::5054:ff:fe12:a01, eth2'") + pe1.wait_until_succeeds("vtysh -c 'show ipv6 route vrf B' | grep 'B>\\* 3fff:bbbb:1::/48.*via fe80::5054:ff:fe12:1403, eth3'") + pe2.wait_until_succeeds("vtysh -c 'show ipv6 route vrf A' | grep 'B>\\* 3fff:aaaa:2::/48.*via fe80::5054:ff:fe12:b02, eth2'") + pe3.wait_until_succeeds("vtysh -c 'show ipv6 route vrf B' | grep 'B>\\* 3fff:bbbb:2::/48.*via fe80::5054:ff:fe12:1504, eth2'") + + + with subtest("Verify iBGP sessions are established"): + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:2:ffff::1.*1\\s*2\\s*PE2'") + pe1.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:3:ffff::1.*1\\s*2\\s*PE3'") + + pe2.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:1:ffff::1.*2\\s*1\\s*PE1'") + pe2.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:3:ffff::1.*1\\s*1\\s*PE3'") + + pe3.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:1:ffff::1.*2\\s*1\\s*PE1'") + pe3.wait_until_succeeds("vtysh -c 'show bgp ipv6 summary' | grep '2001:db8:2:ffff::1.*1\\s*1\\s*PE2'") + + + with subtest("Customer A"): + # ce1.succeed("ping -c 1 10.10.2.100") + # ce2.succeed("ping -c 1 10.10.1.100") + ce1.succeed("ping -c 1 3fff:aaaa:2::100") + ce2.succeed("ping -c 1 3fff:aaaa:1::100") + + + with subtest("Customer B"): + # ce3.succeed("ping -c 1 10.20.2.100") + # ce4.succeed("ping -c 1 10.20.1.100") + ce3.succeed("ping -c 1 3fff:bbbb:2::100") + ce4.succeed("ping -c 1 3fff:bbbb:1::100") + + + with subtest("Customers can not reach each other"): + # ce3.fail("ping -c 1 10.10.1.100") + ce3.fail("ping -c 1 3fff:aaaa:1::100") + # ce1.fail("ping -c 1 10.20.1.100") + ce1.fail("ping -c 1 3fff:bbbb:1::100") + ''; +} diff --git a/tests/bgp-frr-srv6/p1.nix b/tests/bgp-frr-srv6/p1.nix new file mode 100644 index 0000000..02be74f --- /dev/null +++ b/tests/bgp-frr-srv6/p1.nix @@ -0,0 +1,44 @@ +{ + virtualisation.interfaces = { + eth1 = { + vlan = 3; + assignIP = false; + }; + eth2 = { + vlan = 4; + assignIP = false; + }; + eth3 = { + vlan = 5; + assignIP = false; + }; + }; + # set interfaces up + networking.interfaces = { + eth1 = { }; + eth2 = { }; + eth3 = { }; + }; + boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; + services.frr = { + isisd.enable = true; + config = '' + interface eth1 + ipv6 router isis provider + exit + + interface eth2 + ipv6 router isis provider + exit + + interface eth3 + ipv6 router isis provider + exit + + router isis provider + is-type level-2-only + net 49.0000.1920.0000.2000.00 + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/pe1.nix b/tests/bgp-frr-srv6/pe1.nix new file mode 100644 index 0000000..3b68734 --- /dev/null +++ b/tests/bgp-frr-srv6/pe1.nix @@ -0,0 +1,219 @@ +{ lib, pkgs, ... }: +{ + virtualisation = { + interfaces = { + eth1 = { + vlan = 3; + assignIP = false; + }; + eth2 = { + vlan = 10; + assignIP = false; + }; + eth3 = { + vlan = 20; + assignIP = false; + }; + eth4 = { + vlan = 6; + assignIP = false; + }; + }; + }; + networking = { + interfaces = { + lo.ipv6.addresses = [ + { + address = "2001:db8:1:ffff::1"; + prefixLength = 128; + } + ]; + eth1 = { }; # set interface up + eth2 = { + ipv4.addresses = [ + { + address = "192.0.2.130"; + prefixLength = 30; + } + ]; + ipv6.addresses = [ + { + address = "2001:db8:10:128::2"; # TODO not working + prefixLength = 64; + } + ]; + }; + eth3 = { }; # set interface up + eth4 = { }; # set interface up + }; + localCommands = '' + ip -4 rule del pref 0 + ip -4 rule add from all lookup local pref 32765 + + ip -6 rule del pref 0 + ip -6 rule add from all lookup local pref 32765 + + ip -6 rule add from 2001:db8:3:ffff::1 to 2001:db8:2::/48 lookup main pref 500 + ip -6 rule add from 2001:db8:3:ffff::1 to 2001:db8:3::/48 lookup main pref 500 + + ip link add A type vrf table 101 + ip link add B type vrf table 102 + + ip link set eth2 master A + ip link set eth3 master B + + ip link set A up + ip link set B up + + ip addr add 2001:db8:10:128::2/64 dev eth2 + ''; + }; + boot.kernel.sysctl = { + "net.ipv4.conf.all.forwarding" = 1; + "net.ipv6.conf.all.forwarding" = 1; + + "net.ipv6.conf.eth1.seg6_enabled" = 1; + "net.ipv6.conf.eth4.seg6_enabled" = 1; + + "net.vrf.strict_mode" = 1; # not working + }; + systemd.services.frr.preStart = '' + ${lib.getExe' pkgs.busybox "sysctl"} -w net.vrf.strict_mode=1 + ''; + services.frr = { + bgpd.enable = true; + isisd.enable = true; + config = '' + ipv6 route 2001:db8:1::/48 blackhole + + vrf A + exit-vrf + + vrf B + exit-vrf + + interface eth1 + ipv6 router isis provider + exit + + interface eth4 + ipv6 router isis provider + exit + + interface lo + ipv6 router isis provider + exit + + router bgp 65000 + bgp router-id 10.0.0.1 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor PE peer-group + neighbor PE remote-as internal + no neighbor PE enforce-first-as + neighbor PE update-source lo + neighbor PE capability extended-nexthop + neighbor 2001:db8:2:ffff::1 peer-group PE + neighbor 2001:db8:2:ffff::1 description PE2 + no neighbor 2001:db8:2:ffff::1 enforce-first-as + neighbor 2001:db8:3:ffff::1 peer-group PE + neighbor 2001:db8:3:ffff::1 description PE3 + no neighbor 2001:db8:3:ffff::1 enforce-first-as + + segment-routing srv6 + locator L3VPN + exit + + address-family ipv4 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + + address-family ipv6 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + exit + + router bgp 65000 vrf A + bgp router-id 10.0.0.1 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor 192.0.2.129 remote-as 65001 + no neighbor 192.0.2.129 enforce-first-as + neighbor 2001:db8:10:128::1 remote-as 65001 + no neighbor 2001:db8:10:128::1 enforce-first-as + sid vpn per-vrf export 101 + + address-family ipv4 unicast + neighbor 192.0.2.129 activate + neighbor 192.0.2.129 soft-reconfiguration inbound + rd vpn export 10.0.0.1:101 + rt vpn both 65000:101 + export vpn + import vpn + exit-address-family + + address-family ipv6 unicast + neighbor 2001:db8:10:128::1 activate + neighbor 2001:db8:10:128::1 soft-reconfiguration inbound + rd vpn export 10.0.0.1:101 + rt vpn both 65000:101 + export vpn + import vpn + exit-address-family + exit + + router bgp 65000 vrf B + bgp router-id 10.0.0.1 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor eth3 interface remote-as 65003 + no neighbor eth3 enforce-first-as + no neighbor eth3 capability link-local + sid vpn per-vrf export 102 + + address-family ipv4 unicast + neighbor eth3 activate + neighbor eth3 soft-reconfiguration inbound + rd vpn export 10.0.0.1:102 + rt vpn both 65000:102 + export vpn + import vpn + exit-address-family + + address-family ipv6 unicast + neighbor eth3 activate + neighbor eth3 soft-reconfiguration inbound + rd vpn export 10.0.0.1:102 + rt vpn both 65000:102 + export vpn + import vpn + exit-address-family + exit + + router isis provider + is-type level-2-only + net 49.0000.1920.0000.2001.00 + redistribute ipv6 static level-2 + exit + + segment-routing + srv6 + locators + locator L3VPN + prefix 2001:db8:1:aaa::/64 + behavior usid + exit + exit + exit + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/pe2.nix b/tests/bgp-frr-srv6/pe2.nix new file mode 100644 index 0000000..9194680 --- /dev/null +++ b/tests/bgp-frr-srv6/pe2.nix @@ -0,0 +1,203 @@ +{ lib, pkgs, ... }: +{ + virtualisation = { + interfaces = { + eth1 = { + vlan = 4; + assignIP = false; + }; + eth2 = { + vlan = 11; + assignIP = false; + }; + eth3 = { + vlan = 6; + assignIP = false; + }; + }; + }; + systemd.network = { + enable = true; + config = { + addRouteTablesToIPRoute2 = true; + routeTables = { + A = 101; + }; + }; + networks = { + "10-A" = { + matchConfig.Name = "A"; + linkConfig = { + ActivationPolicy = "up"; + RequiredForOnline = "no"; + }; + networkConfig = { + IPv4Forwarding = true; + IPv6Forwarding = true; + }; + routingPolicyRules = [ + { + Priority = 500; + From = "2001:db8:2:ffff::1"; + To = "2001:db8:1::/48"; + } + { + Priority = 500; + From = "2001:db8:2:ffff::1"; + To = "2001:db8:3::/48"; + } + { + Priority = 32765; + Table = "local"; + Family = "ipv4"; + } + { + Priority = 32765; + Table = "local"; + Family = "ipv6"; + } + ]; + }; + "20-lo" = { + matchConfig.Name = "lo"; + address = [ + "2001:db8:2:ffff::1/128" + ]; + }; + "30-eth1".matchConfig.Name = "eth1"; + "40-eth2" = { + matchConfig.Name = "eth2"; + address = [ + "192.0.2.134/30" + "2001:db8:10:132::2/64" + ]; + networkConfig.VRF = "A"; + }; + "50-eth3".matchConfig.Name = "eth3"; + }; + netdevs."A" = { + enable = true; + netdevConfig = { + Kind = "vrf"; + Name = "A"; + }; + vrfConfig.Table = 101; + }; + }; + networking.localCommands = '' + ip -4 rule del pref 0 + ip -6 rule del pref 0 + ''; + boot.kernel.sysctl = { + "net.ipv6.conf.eth1.seg6_enabled" = 1; + "net.ipv6.conf.eth3.seg6_enabled" = 1; + + "net.vrf.strict_mode" = 1; # not working + }; + systemd.services.frr.preStart = '' + ${lib.getExe' pkgs.busybox "sysctl"} -w net.vrf.strict_mode=1 + ''; + services.frr = { + bgpd.enable = true; + isisd.enable = true; + config = '' + ipv6 route 2001:db8:2::/48 blackhole + + vrf A + exit-vrf + + interface eth1 + ipv6 router isis provider + exit + + interface eth3 + ipv6 router isis provider + exit + + interface lo + ipv6 router isis provider + exit + + router bgp 65000 + bgp router-id 10.0.0.2 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor PE peer-group + neighbor PE remote-as internal + no neighbor PE enforce-first-as + neighbor PE update-source lo + neighbor PE capability extended-nexthop + neighbor 2001:db8:1:ffff::1 peer-group PE + neighbor 2001:db8:1:ffff::1 description PE1 + no neighbor 2001:db8:1:ffff::1 enforce-first-as + neighbor 2001:db8:3:ffff::1 peer-group PE + neighbor 2001:db8:3:ffff::1 description PE3 + no neighbor 2001:db8:3:ffff::1 enforce-first-as + + segment-routing srv6 + locator L3VPN + exit + + address-family ipv4 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + + address-family ipv6 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + exit + + router bgp 65000 vrf A + bgp router-id 10.0.0.2 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor 192.0.2.133 remote-as 65002 + no neighbor 192.0.2.133 enforce-first-as + neighbor 2001:db8:10:132::1 remote-as 65002 + no neighbor 2001:db8:10:132::1 enforce-first-as + sid vpn per-vrf export 101 + + address-family ipv4 unicast + neighbor 192.0.2.133 activate + neighbor 192.0.2.133 soft-reconfiguration inbound + rd vpn export 10.0.0.2:101 + rt vpn both 65000:101 + export vpn + import vpn + exit-address-family + + address-family ipv6 unicast + neighbor 2001:db8:10:132::1 activate + neighbor 2001:db8:10:132::1 soft-reconfiguration inbound + rd vpn export 10.0.0.2:101 + rt vpn both 65000:101 + export vpn + import vpn + exit-address-family + exit + + router isis provider + is-type level-2-only + net 49.0000.1920.0000.2002.00 + redistribute ipv6 static level-2 + exit + + segment-routing + srv6 + locators + locator L3VPN + prefix 2001:db8:2:aaa::/64 + behavior usid + exit + exit + exit + exit + ''; + }; +} diff --git a/tests/bgp-frr-srv6/pe3.nix b/tests/bgp-frr-srv6/pe3.nix new file mode 100644 index 0000000..dbce186 --- /dev/null +++ b/tests/bgp-frr-srv6/pe3.nix @@ -0,0 +1,193 @@ +{ lib, pkgs, ... }: +{ + virtualisation = { + interfaces = { + eth1 = { + vlan = 5; + assignIP = false; + }; + eth2 = { + vlan = 21; + assignIP = false; + }; + }; + }; + networking = { + iproute2 = { + enable = true; + rttablesExtraConfig = '' + 102 B + ''; + }; + localCommands = '' + # https://github.com/FRRouting/frr/issues/15909 + ip -4 rule del pref 0 + ip -6 rule del pref 0 + ''; + ifstate = { + enable = true; + settings = { + parameters.ignore.ifname = [ + "eth0" + ]; + interfaces = { + B.link = { + state = "up"; + kind = "vrf"; + vrf_table = 102; + }; + eth1 = { + link = { + state = "up"; + kind = "physical"; + }; + sysctl.ipv6.seg6_enabled = 1; + }; + eth2.link = { + state = "up"; + kind = "physical"; + master = "B"; + }; + loopback = { + addresses = [ + "2001:db8:3:ffff::1/128" + ]; + link = { + state = "up"; + kind = "dummy"; + }; + }; + }; + sysctl.all = { + ipv4.forwarding = 1; + ipv6.forwarding = 1; + }; + routing.rules = [ + { + priority = 500; + table = "main"; + from = "2001:db8:3:ffff::1"; + to = "2001:db8:1::/48"; + } + { + priority = 500; + table = "main"; + from = "2001:db8:3:ffff::1"; + to = "2001:db8:2::/48"; + } + { + priority = 32765; + table = "local"; + } + { + priority = 32765; + table = "local"; + family = "inet6"; + } + ]; + }; + }; + }; + boot.kernel.sysctl."net.vrf.strict_mode" = 1; # not working + systemd.services.frr.preStart = '' + ${lib.getExe' pkgs.busybox "sysctl"} -w net.vrf.strict_mode=1 + ''; + services.frr = { + bgpd.enable = true; + isisd.enable = true; + config = '' + ipv6 route 2001:db8:3::/48 blackhole + + vrf B + exit-vrf + + interface eth1 + ipv6 router isis provider + exit + + interface loopback + ipv6 router isis provider + exit + + router bgp 65000 + bgp router-id 10.0.0.3 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor PE peer-group + neighbor PE remote-as internal + no neighbor PE enforce-first-as + neighbor PE update-source lo + neighbor PE capability extended-nexthop + neighbor 2001:db8:1:ffff::1 peer-group PE + neighbor 2001:db8:1:ffff::1 description PE1 + no neighbor 2001:db8:1:ffff::1 enforce-first-as + neighbor 2001:db8:2:ffff::1 peer-group PE + neighbor 2001:db8:2:ffff::1 description PE2 + no neighbor 2001:db8:2:ffff::1 enforce-first-as + + segment-routing srv6 + locator L3VPN + exit + + address-family ipv4 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + + address-family ipv6 vpn + neighbor PE activate + neighbor PE next-hop-self + exit-address-family + exit + + router bgp 65000 vrf B + bgp router-id 10.0.0.3 + no bgp ebgp-requires-policy + no bgp reject-as-sets + no bgp default ipv4-unicast + no bgp network import-check + neighbor eth2 interface remote-as 65004 + no neighbor eth2 enforce-first-as + no neighbor eth2 capability link-local + sid vpn per-vrf export 102 + + address-family ipv4 unicast + neighbor eth2 activate + neighbor eth2 soft-reconfiguration inbound + rd vpn export 10.0.0.3:102 + rt vpn both 65000:102 + export vpn + import vpn + exit-address-family + + address-family ipv6 unicast + neighbor eth2 activate + neighbor eth2 soft-reconfiguration inbound + rd vpn export 10.0.0.3:102 + rt vpn both 65000:102 + export vpn + import vpn + exit-address-family + exit + + router isis provider + is-type level-2-only + net 49.0000.1920.0000.2003.00 + redistribute ipv6 static level-2 + exit + + segment-routing + srv6 + locators + locator L3VPN + prefix 2001:db8:3:aaa::/64 + behavior usid + exit + exit + exit + exit + ''; + }; +}