Skip to content

Commit 9bc5f06

Browse files
authored
Merge pull request #1183 from kernelkit/ospf-neigh-regression-test
Verify OSPF neighbors in setup with non-OSPF interface
2 parents 4cfd0eb + 5f51ef0 commit 9bc5f06

File tree

5 files changed

+200
-108
lines changed

5 files changed

+200
-108
lines changed

test/case/ietf_routing/ospf_basic/test.adoc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ietf_routing/ospf_basic]
44

55
==== Description
66

7-
Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
8-
and that they exchange routes, ending with a simple connectivity check.
7+
Verifies basic OSPF functionality by configuring two routers (R1 and R2)
8+
with OSPF on their interconnecting link. The test ensures OSPF
9+
neighbors are established, routes are exchanged between the routers, and
10+
end-to-end connectivity is achieved.
11+
12+
An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
13+
This verifies that OSPF status information remains accessible when a router
14+
has non-OSPF interfaces.
915

1016
==== Topology
1117

@@ -16,6 +22,7 @@ image::topology.svg[OSPF Basic topology, align=center, scaledwidth=75%]
1622
. Set up topology and attach to target DUTs
1723
. Configure targets
1824
. Wait for OSPF routes
25+
. Verify R2 OSPF neighbors with non-OSPF interface
1926
. Test connectivity from PC:data to 192.168.200.1
2027

2128

test/case/ietf_routing/ospf_basic/test.py

Lines changed: 105 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
#!/usr/bin/env python3
2-
"""
3-
OSPF Basic
2+
"""OSPF Basic
3+
4+
Verifies basic OSPF functionality by configuring two routers (R1 and R2)
5+
with OSPF on their interconnecting link. The test ensures OSPF
6+
neighbors are established, routes are exchanged between the routers, and
7+
end-to-end connectivity is achieved.
8+
9+
An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
10+
This verifies that OSPF status information remains accessible when a router
11+
has non-OSPF interfaces.
412
5-
Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
6-
and that they exchange routes, ending with a simple connectivity check.
713
"""
814

15+
# TODO: Remove HOST node once Infamy supports unconnected ports in topologies
16+
917
import infamy
1018
import infamy.route as route
1119
from infamy.util import until, parallel
1220

21+
1322
def config_target1(target, data, link):
1423
target.put_config_dict("ietf-interfaces", {
1524
"interfaces": {
@@ -30,8 +39,8 @@ def config_target1(target, data, link):
3039
"ipv4": {
3140
"forwarding": True,
3241
"address": [{
33-
"ip": "192.168.50.1",
34-
"prefix-length": 24
42+
"ip": "192.168.50.1",
43+
"prefix-length": 24
3544
}]
3645
}
3746
},
@@ -40,8 +49,8 @@ def config_target1(target, data, link):
4049
"enabled": True,
4150
"ipv4": {
4251
"address": [{
43-
"ip": "192.168.100.1",
44-
"prefix-length": 32
52+
"ip": "192.168.100.1",
53+
"prefix-length": 32
4554
}]
4655
}
4756
}
@@ -56,38 +65,34 @@ def config_target1(target, data, link):
5665
target.put_config_dict("ietf-routing", {
5766
"routing": {
5867
"control-plane-protocols": {
59-
"control-plane-protocol": [
60-
{
61-
"type": "infix-routing:static",
62-
"name": "default",
63-
"static-routes": {
64-
"ipv4": {
65-
"route": [{
66-
"destination-prefix": "192.168.33.1/32",
67-
"next-hop": {
68-
"special-next-hop": "blackhole"
69-
}
70-
}]
71-
}
68+
"control-plane-protocol": [{
69+
"type": "infix-routing:static",
70+
"name": "default",
71+
"static-routes": {
72+
"ipv4": {
73+
"route": [{
74+
"destination-prefix": "192.168.33.1/32",
75+
"next-hop": {
76+
"special-next-hop": "blackhole"
77+
}
78+
}]
7279
}
73-
},
74-
{
80+
}
81+
}, {
7582
"type": "infix-routing:ospfv2",
7683
"name": "default",
7784
"ospf": {
7885
"redistribute": {
7986
"redistribute": [{
8087
"protocol": "static"
81-
},
82-
{
88+
}, {
8389
"protocol": "connected"
8490
}]
8591
},
8692
"areas": {
8793
"area": [{
8894
"area-id": "0.0.0.0",
89-
"interfaces":
90-
{
95+
"interfaces": {
9196
"interface": [{
9297
"enabled": True,
9398
"name": link,
@@ -103,35 +108,43 @@ def config_target1(target, data, link):
103108
}
104109
})
105110

106-
def config_target2(target, link):
111+
112+
def config_target2(target, link, data):
107113
target.put_config_dict("ietf-interfaces", {
108-
"interfaces": {
109-
"interface": [
110-
{
111-
"name": link,
112-
"enabled": True,
113-
"ipv4": {
114-
"forwarding": True,
115-
"address": [{
116-
"ip": "192.168.50.2",
117-
"prefix-length": 24
118-
}]
119-
}
120-
},
121-
{
122-
"name": "lo",
123-
"enabled": True,
124-
"forwarding": True,
125-
"ipv4": {
126-
"address": [{
127-
"ip": "192.168.200.1",
128-
"prefix-length": 32
129-
}]
130-
}
131-
}
132-
]
133-
}
134-
})
114+
"interfaces": {
115+
"interface": [{
116+
"name": link,
117+
"enabled": True,
118+
"ipv4": {
119+
"forwarding": True,
120+
"address": [{
121+
"ip": "192.168.50.2",
122+
"prefix-length": 24
123+
}]
124+
}
125+
}, {
126+
"name": data,
127+
"enabled": True,
128+
"ipv4": {
129+
"forwarding": True,
130+
"address": [{
131+
"ip": "192.168.60.1",
132+
"prefix-length": 24
133+
}]
134+
}
135+
}, {
136+
"name": "lo",
137+
"enabled": True,
138+
"forwarding": True,
139+
"ipv4": {
140+
"address": [{
141+
"ip": "192.168.200.1",
142+
"prefix-length": 32
143+
}]
144+
}
145+
}]
146+
}
147+
})
135148

136149
target.put_config_dict("ietf-system", {
137150
"system": {
@@ -141,8 +154,7 @@ def config_target2(target, link):
141154
target.put_config_dict("ietf-routing", {
142155
"routing": {
143156
"control-plane-protocols": {
144-
"control-plane-protocol": [
145-
{
157+
"control-plane-protocol": [{
146158
"type": "infix-routing:ospfv2",
147159
"name": "default",
148160
"ospf": {
@@ -154,7 +166,7 @@ def config_target2(target, link):
154166
"areas": {
155167
"area": [{
156168
"area-id": "0.0.0.0",
157-
"interfaces":{
169+
"interfaces": {
158170
"interface": [{
159171
"enabled": True,
160172
"name": link,
@@ -165,31 +177,61 @@ def config_target2(target, link):
165177
}]
166178
}
167179
}
168-
}
169-
]
180+
}]
170181
}
171182
}
172183
})
173184

185+
186+
def config_host(target, link):
187+
target.put_config_dict("ietf-interfaces", {
188+
"interfaces": {
189+
"interface": [{
190+
"name": link,
191+
"enabled": True,
192+
"ipv4": {
193+
"address": [{
194+
"ip": "192.168.60.2",
195+
"prefix-length": 24
196+
}]
197+
}
198+
}]
199+
}
200+
})
201+
202+
target.put_config_dict("ietf-system", {
203+
"system": {
204+
"hostname": "HOST"
205+
}
206+
})
207+
208+
174209
with infamy.Test() as test:
175210
with test.step("Set up topology and attach to target DUTs"):
176211
env = infamy.Env()
177212
R1 = env.attach("R1", "mgmt")
178213
R2 = env.attach("R2", "mgmt")
214+
HOST = env.attach("HOST", "mgmt")
179215

180216
with test.step("Configure targets"):
181217
_, R1data = env.ltop.xlate("R1", "data")
182218
_, R2link = env.ltop.xlate("R2", "link")
183-
_, R1link= env.ltop.xlate("R1", "link")
219+
_, R1link = env.ltop.xlate("R1", "link")
220+
_, R2data = env.ltop.xlate("R2", "data")
221+
_, HOSTlink = env.ltop.xlate("HOST", "link")
184222

185223
parallel(config_target1(R1, R1data, R1link),
186-
config_target2(R2, R2link))
224+
config_target2(R2, R2link, R2data),
225+
config_host(HOST, HOSTlink))
187226
with test.step("Wait for OSPF routes"):
188-
print("Waiting for OSPF routes..")
189227
until(lambda: route.ipv4_route_exist(R1, "192.168.200.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
190228
until(lambda: route.ipv4_route_exist(R2, "192.168.100.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
191229
until(lambda: route.ipv4_route_exist(R2, "192.168.33.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
192230

231+
with test.step("Verify R2 OSPF neighbors with non-OSPF interface"):
232+
# Regression test for #1169
233+
assert route.ospf_has_neighbors(R2)
234+
193235
with test.step("Test connectivity from PC:data to 192.168.200.1"):
194236
_, hport0 = env.ltop.xlate("PC", "data")
195237
with infamy.IsolatedMacVlan(hport0) as ns0:

test/case/ietf_routing/ospf_basic/topology.dot

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,34 @@ graph "2x2" {
88
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
99

1010
PC [
11-
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 }",
12-
pos="20,80!",
11+
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 | <mgmt3> mgmt3 }",
12+
pos="20,30!",
1313
requires="controller",
1414
];
1515

1616
R1 [
1717
label="{ <mgmt> mgmt | <data> data | <link> link} | R1 \n 192.168.100.1/32 \n(lo)",
18-
pos="250,80!",
18+
pos="160,60!",
1919

2020
requires="infix",
2121
];
2222
R2 [
2323
label="{ <link> link | <mgmt> mgmt | <data> data } | R2 \n 192.168.200.1/32 \n(lo)",
24-
pos="250,30!",
24+
pos="160,30!",
2525

2626
requires="infix",
2727
];
28-
28+
HOST [
29+
label="{ <link> link | <mgmt> mgmt } | HOST \n end-device",
30+
pos="153,0!",
31+
32+
requires="infix",
33+
];
34+
2935
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
3036
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
31-
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", fontcolor="black"]
37+
PC:mgmt3 -- HOST:mgmt [requires="mgmt", color="lightgray"]
38+
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", labeldistance=6, fontcolor="black"]
3239
R1:link -- R2:link [headlabel="192.168.50.2/24", taillabel="192.168.50.1/24", labeldistance=1, fontcolor="black", color="black"]
40+
R2:data -- HOST:link [headlabel="192.168.60.2/24", taillabel="192.168.60.1/24", labeldistance=1, fontcolor="black", color="black"]
3341
}

0 commit comments

Comments
 (0)