as we discussed off-list:
We should have a section in this test-case for every supported line by
the old conf.local parser. One that extends an existing section (if we
generate one in the SDN stack) and one that adds a new section of the
respective type. E.g. VRFs and ipv6 prefix-lists are completely missing.

On 3/5/26 11:04 AM, Gabriel Goller wrote:
> Add a test that tests the frr.conf.local merging. This should ensure we
> do not run into further regressions.
> 
> Signed-off-by: Gabriel Goller <[email protected]>
> ---
>  src/test/run_test_zones.pl                    |  16 +-
>  .../expected_controller_config                | 148 ++++++++++++++++++
>  .../frr_local_merge/expected_sdn_interfaces   |  53 +++++++
>  .../zones/evpn/frr_local_merge/frr.conf.local |  75 +++++++++
>  .../zones/evpn/frr_local_merge/interfaces     |   7 +
>  .../zones/evpn/frr_local_merge/sdn_config     |  81 ++++++++++
>  6 files changed, 377 insertions(+), 3 deletions(-)
>  create mode 100644 
> src/test/zones/evpn/frr_local_merge/expected_controller_config
>  create mode 100644 
> src/test/zones/evpn/frr_local_merge/expected_sdn_interfaces
>  create mode 100644 src/test/zones/evpn/frr_local_merge/frr.conf.local
>  create mode 100644 src/test/zones/evpn/frr_local_merge/interfaces
>  create mode 100644 src/test/zones/evpn/frr_local_merge/sdn_config
> 
> diff --git a/src/test/run_test_zones.pl b/src/test/run_test_zones.pl
> index 905b2f42e1dc..806225735e6b 100755
> --- a/src/test/run_test_zones.pl
> +++ b/src/test/run_test_zones.pl
> @@ -126,12 +126,22 @@ foreach my $test (@tests) {
>              reload_controller => sub {
>                  return;
>              },
> -            read_local_frr_config => sub {
> -                return;
> -            },
>          );
>      }
>  
> +    # Mock read_local_frr_config in PVE::Network::SDN::Frr to support 
> testing frr.conf.local merging
> +    my $frr_local_config;
> +    my $frr_local_path = "./$test/frr.conf.local";
> +    if (-e $frr_local_path) {
> +        $frr_local_config = read_file($frr_local_path);
> +    }
> +    my $mocked_frr = Test::MockModule->new('PVE::Network::SDN::Frr');
> +    $mocked_frr->mock(
> +        read_local_frr_config => sub {
> +            return $frr_local_config;
> +        },
> +    );
> +
>      my $name = $test;
>      my $expected = read_file("./$test/expected_sdn_interfaces");
>  
> diff --git a/src/test/zones/evpn/frr_local_merge/expected_controller_config 
> b/src/test/zones/evpn/frr_local_merge/expected_controller_config
> new file mode 100644
> index 000000000000..82f36c9e37ec
> --- /dev/null
> +++ b/src/test/zones/evpn/frr_local_merge/expected_controller_config
> @@ -0,0 +1,148 @@
> +frr version 10.4.1
> +frr defaults datacenter
> +hostname localhost
> +log syslog informational
> +service integrated-vtysh-config
> +!
> +!
> +vrf vrf_myzone
> + vni 1000
> +exit-vrf
> +!
> +interface ens19
> + no ip ospf passive
> +!
> +interface eth0
> + ip router isis isis1
> +!
> +interface eth1
> + ip router isis isis1
> + isis circuit-type level-2-only
> +!
> +interface iface2
> + ip ospf area 0
> +!
> +router bgp 65000
> + bgp router-id 192.168.0.1
> + no bgp default ipv4-unicast
> + coalesce-time 1000
> + bgp disable-ebgp-connected-route-check
> + neighbor BGP peer-group
> + neighbor BGP remote-as external
> + neighbor BGP bfd
> + neighbor 172.16.0.254 peer-group BGP
> + neighbor 172.17.0.254 peer-group BGP
> + neighbor VTEP peer-group
> + neighbor VTEP remote-as 65000
> + neighbor VTEP bfd
> + neighbor VTEP update-source dummy1
> + neighbor 192.168.0.2 peer-group VTEP
> + neighbor 192.168.0.3 peer-group VTEP
> + neighbor 192.168.1.1 remote-as 65001
> + neighbor 192.168.1.1 description "External Peer"
> + neighbor VTEP prefix-list MY_PREFIX_LIST out
> + neighbor VTEP allowas-in 1
> + neighbor VTEP remote-as 64600
> + no neighbor VTEP peer-group
> + !
> + address-family ipv4 unicast
> +  network 192.168.0.1/32
> +  neighbor BGP activate
> +  neighbor BGP soft-reconfiguration inbound
> +  neighbor VTEP activate
> + exit-address-family
> + !
> + address-family l2vpn evpn
> +  neighbor VTEP activate
> +  neighbor VTEP route-map MAP_VTEP_IN in
> +  neighbor VTEP route-map MAP_VTEP_OUT out
> +  advertise-all-vni
> +  advertise-svi-ip
> +  no neighbor VTEP route-map MAP_VTEP_IN in
> +  neighbor VTEP route-map MAP_VTEP_IN_CUSTOM in
> + exit-address-family
> +exit
> +!
> +router bgp 65000 vrf vrf_myzone
> + bgp router-id 192.168.0.1
> + no bgp hard-administrative-reset
> + no bgp graceful-restart notification
> +exit
> +!
> +router eigrp 1
> + network 10.0.0.0/8
> +exit
> +!
> +router isis isis1
> + net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
> + redistribute ipv4 connected level-1
> + redistribute ipv6 connected level-1
> + log-adjacency-changes
> +exit
> +!
> +router ospf
> + passive-interface default
> +exit
> +!
> +ip prefix-list PL_ALLOW seq 10 permit 10.0.0.0/8 le 24
> +ip prefix-list loopbacks_ips seq 10 permit 0.0.0.0/0 le 32
> +!
> +bgp community-list standard CL_LOCAL permit 65000:200
> +!
> +route-map CUSTOM_MAP permit 1
> + match ip address prefix-list PL_ALLOW
> +exit
> +!
> +route-map MAP_VTEP_IN permit 1
> +exit
> +!
> +route-map MAP_VTEP_IN permit 2
> + set community 65000:200
> +exit
> +!
> +route-map MAP_VTEP_OUT permit 1
> +exit
> +!
> +route-map MAP_VTEP_OUT permit 2
> + set community 65000:100
> +exit
> +!
> +route-map MAP_VTEP_OUT permit 3
> + match ip next-hop LOCAL
> +exit
> +!
> +route-map correct_src permit 1
> + match ip address prefix-list loopbacks_ips
> + set src 192.168.0.1
> +exit
> +!
> +route-map correct_src deny 2
> + match ip next-hop NOT_LOCAL
> +exit
> +!
> +ip protocol bgp route-map correct_src
> +router ospf
> + ospf router-id 172.20.30.1
> +exit
> +!
> +interface dummy_test
> + ip ospf area 0
> + ip ospf passive
> +exit
> +!
> +interface ens19
> + ip ospf area 0
> +exit
> +!
> +access-list pve_ospf_test_ips permit 172.20.30.0/24
> +!
> +route-map pve_ospf permit 100
> + match ip address pve_ospf_test_ips
> + set src 172.20.30.1
> +exit
> +!
> +ip protocol ospf route-map pve_ospf
> +!
> +!
> +line vty
> +!
> diff --git a/src/test/zones/evpn/frr_local_merge/expected_sdn_interfaces 
> b/src/test/zones/evpn/frr_local_merge/expected_sdn_interfaces
> new file mode 100644
> index 000000000000..c7ddf44ef6d3
> --- /dev/null
> +++ b/src/test/zones/evpn/frr_local_merge/expected_sdn_interfaces
> @@ -0,0 +1,53 @@
> +#version:1
> +
> +auto myvnet
> +iface myvnet
> +     address 10.0.0.1/24
> +     hwaddress A2:1D:CB:1A:C0:8B
> +     bridge_ports vxlan_myvnet
> +     bridge_stp off
> +     bridge_fd 0
> +     mtu 1450
> +     ip-forward on
> +     arp-accept on
> +     vrf vrf_myzone
> +
> +auto vrf_myzone
> +iface vrf_myzone
> +     vrf-table auto
> +     post-up ip route add vrf vrf_myzone unreachable default metric 
> 4278198272
> +
> +auto vrfbr_myzone
> +iface vrfbr_myzone
> +     bridge-ports vrfvx_myzone
> +     bridge_stp off
> +     bridge_fd 0
> +     mtu 1450
> +     vrf vrf_myzone
> +
> +auto vrfvx_myzone
> +iface vrfvx_myzone
> +     vxlan-id 1000
> +     vxlan-local-tunnelip 192.168.0.1
> +     bridge-learning off
> +     bridge-arp-nd-suppress on
> +     mtu 1450
> +
> +auto vxlan_myvnet
> +iface vxlan_myvnet
> +     vxlan-id 100
> +     vxlan-local-tunnelip 192.168.0.1
> +     bridge-learning off
> +     bridge-arp-nd-suppress on
> +     mtu 1450
> +
> +auto dummy_test
> +iface dummy_test inet static
> +     address 172.20.30.1/32
> +     link-type dummy
> +     ip-forward 1
> +
> +auto ens19
> +iface ens19 inet static
> +     address 172.16.3.10/31
> +     ip-forward 1
> diff --git a/src/test/zones/evpn/frr_local_merge/frr.conf.local 
> b/src/test/zones/evpn/frr_local_merge/frr.conf.local
> new file mode 100644
> index 000000000000..9003dd47c83b
> --- /dev/null
> +++ b/src/test/zones/evpn/frr_local_merge/frr.conf.local
> @@ -0,0 +1,75 @@
> +!
> +! Custom FRR configuration to be merged
> +!
> +ip nht resolve-via-default
> +!
> +ip route 192.0.2.0/24 198.51.100.1
> +!
> +ip protocol bgp route-map correct_src
> +!
> +router bgp 65000
> + neighbor 192.168.1.1 remote-as 65001
> + neighbor 192.168.1.1 description "External Peer"
> + address-family l2vpn evpn
> +  advertise-svi-ip
> + exit-address-family
> + address-family ipv4 unicast
> +  neighbor VTEP activate
> + exit-address-family
> +exit
> +!
> +route-map MAP_VTEP_OUT permit 1
> + set community 65000:100
> +exit
> +!
> +route-map MAP_VTEP_OUT permit 2
> + match ip next-hop LOCAL
> +exit
> +!
> +route-map correct_src deny 1
> + match ip next-hop NOT_LOCAL
> +exit
> +!
> +route-map MAP_VTEP_IN permit 2
> + set community 65000:200
> +exit
> +!
> +ip prefix-list PL_ALLOW seq 10 permit 10.0.0.0/8 le 24
> +!
> +route-map CUSTOM_MAP permit 10
> + match ip address prefix-list PL_ALLOW
> +exit
> +!
> +bgp community-list standard CL_LOCAL permit 65000:200
> +!
> +interface eth1
> + isis circuit-type level-2-only
> +exit
> +!
> +interface iface2
> + ip ospf area 0
> +exit
> +!
> +interface ens19
> + no ip ospf passive
> +exit
> +!
> +router ospf
> + passive-interface default
> +exit
> +!
> +router bgp 65000
> + neighbor VTEP prefix-list MY_PREFIX_LIST out
> + neighbor VTEP allowas-in 1
> + neighbor VTEP remote-as 64600
> + no neighbor VTEP peer-group
> + address-family l2vpn evpn
> +  no neighbor VTEP route-map MAP_VTEP_IN in
> +  neighbor VTEP route-map MAP_VTEP_IN_CUSTOM in
> + exit-address-family
> +exit
> +!
> +router eigrp 1
> + network 10.0.0.0/8
> +exit
> +!
> diff --git a/src/test/zones/evpn/frr_local_merge/interfaces 
> b/src/test/zones/evpn/frr_local_merge/interfaces
> new file mode 100644
> index 000000000000..66bb826a44b3
> --- /dev/null
> +++ b/src/test/zones/evpn/frr_local_merge/interfaces
> @@ -0,0 +1,7 @@
> +auto vmbr0
> +iface vmbr0 inet static
> +     address 192.168.0.1/24
> +     gateway 192.168.0.254
> +        bridge-ports eth0
> +        bridge-stp off
> +        bridge-fd 0
> diff --git a/src/test/zones/evpn/frr_local_merge/sdn_config 
> b/src/test/zones/evpn/frr_local_merge/sdn_config
> new file mode 100644
> index 000000000000..4f90ab416495
> --- /dev/null
> +++ b/src/test/zones/evpn/frr_local_merge/sdn_config
> @@ -0,0 +1,81 @@
> +{
> +    version => 1,
> +    vnets => {
> +        ids => {
> +            myvnet => { tag => "100", type => "vnet", zone => "myzone" },
> +        },
> +    },
> +
> +    zones => {
> +        ids => { myzone => { ipam => "pve", type => "evpn", controller => 
> "evpnctl", 'vrf-vxlan' => 1000, 'mac' => 'A2:1D:CB:1A:C0:8B' } },
> +    },
> +    controllers => {
> +        ids => {
> +            evpnctl => {
> +                type => "evpn",
> +                'peers' => '192.168.0.1,192.168.0.2,192.168.0.3',
> +                asn => "65000"
> +            },
> +            bgplocalhost => {
> +                type => "bgp",
> +                'peers' => '172.16.0.254,172.17.0.254',
> +                ebgp => "1",
> +                asn => "65000",
> +                loopback => 'dummy1',
> +                node => "localhost"
> +            },
> +            localhost => {
> +                type => "isis",
> +                'isis-domain' => 'isis1',
> +                'isis-ifaces' => 'eth1,eth0',
> +                'isis-net' => 
> "47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00",
> +                loopback => 'dummy1',
> +                node => "localhost",
> +            },
> +        },
> +    },
> +
> +    subnets => {
> +        ids => {
> +            'myzone-10.0.0.0-24' => {
> +                'type' => 'subnet',
> +                'vnet' => 'myvnet',
> +                'gateway' => '10.0.0.1',
> +            }
> +        }
> +    },
> +    fabrics => {
> +        ids => {
> +            test_pathfinder => {
> +                id => 'test_pathfinder',
> +                interfaces => [
> +                    'name=ens19,ip=172.16.3.20/31'
> +                ],
> +                ip => '172.20.30.2',
> +                type => 'ospf_node'
> +            },
> +            test => {
> +                ip_prefix => '172.20.30.0/24',
> +                area => '0',
> +                type => 'ospf_fabric',
> +                id => 'test',
> +            },
> +            test_localhost => {
> +                id => 'test_localhost',
> +                interfaces => [
> +                    'name=ens19,ip=172.16.3.10/31'
> +                ],
> +                ip => '172.20.30.1',
> +                type => 'ospf_node'
> +            },
> +            test_raider => {
> +                type => 'ospf_node',
> +                ip => '172.20.30.3',
> +                id => 'test_raider',
> +                interfaces => [
> +                    'name=ens19,ip=172.16.3.30/31'
> +                ]
> +            }
> +        }
> +    }
> +}




Reply via email to