-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtest_ospf_ecmp_unnumbered.py
139 lines (127 loc) Β· 4.32 KB
/
test_ospf_ecmp_unnumbered.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2023 David Lamparter for NetDEF, Inc.
"""
OSPF(v2) ECMP + unnumbered combination test.
"""
from topotato.v1 import *
@topology_fixture()
def topology(topo):
"""
[ ]--{ u1 }--[ ]
{ lan1 }--[ r1 ] [ r2 ]--{ lan2 }
[ ]--{ u2 }--[ ]
"""
topo.lans["u1"].ip4.noauto = True
topo.lans["u2"].ip4.noauto = True
class Configs(FRRConfigs):
zebra = """
#% extends "boilerplate.conf"
#% block main
#% for iface in router.ifaces
#% if not iface.other.endpoint.name.startswith("lan")
interface {{ iface.ifname }}
! unnumbered configured as IPv4 PtP addressing ("LO_ADDR peer PEER_LO_ADDR/32")
ip address {{ router.lo_ip4[0].ip }} peer {{ router.flip("r1", "r2").lo_ip4[0] }}
#% endif
#% endfor
#% endblock
"""
ospfd = """
#% extends "boilerplate.conf"
#% block main
debug ospf lsa install
!
#% for iface in router.ifaces
interface {{ iface.ifname }}
ip ospf network point-to-point
ip ospf hello-interval 1
ip ospf dead-interval 2
ip ospf retransmit-interval 3
ip ospf area 0.0.0.0
#% endfor
!
router ospf
ospf router-id {{ router.lo_ip4[0].ip }}
timers throttle lsa all 500
timers throttle spf 0 50 500
redistribute connected
#% endblock
"""
class OSPF_Unnumbered_ECMP(TestBase, AutoFixture, topo=topology, configs=Configs):
"""
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
"""
@topotatofunc
def test_init_neigh(self, topo, r1, r2):
"""
Wait for OSPF adjacency to reach Full on both links.
"""
for r_self in r1, r2:
r_other = r_self.flip("r1", "r2")
expect = {
"neighbors": {
str(r_other.lo_ip4[0].ip): [
JSONCompareListKeyedDict("ifaceName"),
{
"nbrState": "Full/-",
"ifaceName": f"{ r_self.iface_to('u1').ifname }:{ r_self.lo_ip4[0].ip }",
},
{
"nbrState": "Full/-",
"ifaceName": f"{ r_self.iface_to('u2').ifname }:{ r_self.lo_ip4[0].ip }",
},
],
},
}
yield from AssertVtysh.make(
r_self, "ospfd", "show ip ospf neighbor json", expect, maxwait=10.0
)
@topotatofunc
def test_ecmp(self, topo, r1, r2):
"""
Check OSPF actually produced an ECMP route using both links.
"""
for rtr, other_lan in (r1, "lan2"), (r2, "lan1"):
expect = {
str(topo.lans[other_lan].ip4[0]): {
"nexthops": [
{
"via": rtr.iface_to("u1").ifname,
},
{
"via": rtr.iface_to("u2").ifname,
},
],
},
}
yield from AssertVtysh.make(
rtr, "ospfd", "show ip ospf route json", expect, maxwait=10.0
)
@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=1.0,
)