test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP

OSPF(v2) ECMP + unnumbered combination test.

Test that ECMP doesn't break in weird ways if nexthops don't have unique IPs. https://blog.ipspace.net/2023/08/unnumbered-ospf-arp.html#1903

::startup
::test_init_session:#79:r1/bgpd/vtysh[show ip bgp neighbor json]
::test_init_session:#79:r2/bgpd/vtysh[show ip bgp neighbor json]
::test_kernel_ecmp:#93:r1/routes-v4
::test_kernel_ecmp:#93:r2/routes-v4
::shutdown

::startup

passed after 1.29s
('test_bgp_ecmp_enhe.py', -inf, 'startup')

::test_init_session

Wait for BGP session.

::test_init_session:#79:r1/bgpd/vtysh[show ip bgp neighbor json]

passed after 0.30s, CLI command: show ip bgp neighbor json
Expected output:
{'fe80::fc02:ff:febc:300': {'bgpState': 'Established'}, 'fe80::fc02:ff:febc:400': {'bgpState': 'Established'}}
('test_bgp_ecmp_enhe.py', 79, '#79:r1/bgpd/vtysh[show ip bgp neighbor json]')

::test_init_session:#79:r2/bgpd/vtysh[show ip bgp neighbor json]

passed after 0.00s, CLI command: show ip bgp neighbor json
Expected output:
{'fe80::fc01:ff:febc:300': {'bgpState': 'Established'}, 'fe80::fc01:ff:febc:400': {'bgpState': 'Established'}}
('test_bgp_ecmp_enhe.py', 79, '#79:r2/bgpd/vtysh[show ip bgp neighbor json]')

::test_kernel_ecmp

Check that OSPF passed off the route as ECMP to zebra and it was installed in the kernel.

::test_kernel_ecmp:#93:r1/routes-v4

passed after 1.21s
('test_bgp_ecmp_enhe.py', 93, '#93:r1/routes-v4')

::test_kernel_ecmp:#93:r2/routes-v4

failed after 8.81s
('test_bgp_ecmp_enhe.py', 93, '#93:r2/routes-v4')
self = <test_bgp_ecmp_enhe.BGP_Unnumbered_ECMP object at 0x7f8a4e927b50>, topo = <topotato.toponom.Network object at 0x7f8a4ff6c0d0>
r1 = <Router 1 "r1">, r2 = <Router 2 "r2">

    @topotatofunc
    def test_kernel_ecmp(self, topo, r1, r2):
        """
        Check that OSPF passed off the route as ECMP to zebra and it was installed in the kernel.
        """
        for rtr, other_lan in (r1, "lan2"), (r2, "lan1"):
>           yield from AssertKernelRoutesV4.make(
                rtr.name,
                {
                    str(topo.lans[other_lan].ip4[0]): [
                        {
                            "nexthops": [
                                JSONCompareListKeyedDict("dev"),
                                {
                                    "dev": rtr.iface_to("u1").ifname,
                                },
                                {
                                    "dev": rtr.iface_to("u2").ifname,
                                },
                            ],
                        },
                    ],
                },
                maxwait=10.0,
            )
E           topotato.exceptions.TopotatoRouteCompareFail: expected key(s) ['10.101.0.0/16'] in json (have ['10.102.0.0/16']):
E           --- Expected value
E           +++ Current value
E           @@ -2 +2 @@
E           -    "10.101.0.0/16": [
E           +    "10.102.0.0/16": [
E           @@ -4,9 +4,6 @@
E           -            "nexthops": [
E           -                {},
E           -                {
E           -                    "dev": "r2-u1"
E           -                },
E           -                {
E           -                    "dev": "r2-u2"
E           -                }
E           -            ]
E           +            "dev": "r2-lan2",
E           +            "dst": "10.102.0.0/16",
E           +            "flags": [],
E           +            "prefsrc": "10.102.0.2",
E           +            "protocol": "kernel",
E           +            "scope": "link"

/home/equinox/python/topotato/test_bgp_ecmp_enhe.py:93: TopotatoRouteCompareFail

::shutdown

passed after 1.12s
('test_bgp_ecmp_enhe.py', inf, 'shutdown')
net router-r1 r1 10.255.0.1/32 fd00::1/128 r1-u1 fe:01:00:bc:03:00 fdbc:3::fc01:ff:febc:300/64 r1-lan1 fe:01:00:bc:01:00 10.101.0.1/16 fdbc:1::fc01:ff:febc:100/64 r1-u2 fe:01:00:bc:04:00 fdbc:4::fc01:ff:febc:400/64 lan-u1 u1 fdbc:3::/64 router-r1:r1-u1--lan-u1 lan-lan1 lan1 10.101.0.0/16 fdbc:1::/64 router-r1:r1-lan1--lan-lan1 lan-u2 u2 fdbc:4::/64 router-r1:r1-u2--lan-u2 router-r2 r2 10.255.0.2/32 fd00::2/128 r2-u1 fe:02:00:bc:03:00 fdbc:3::fc02:ff:febc:300/64 r2-lan2 fe:02:00:bc:02:00 10.102.0.2/16 fdbc:2::fc02:ff:febc:200/64 r2-u2 fe:02:00:bc:04:00 fdbc:4::fc02:ff:febc:400/64 router-r2:r2-u1--lan-u1 lan-lan2 lan2 10.102.0.0/16 fdbc:2::/64 router-r2:r2-lan2--lan-lan2 router-r2:r2-u2--lan-u2