Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions test/case/ietf_routing/ospf_basic/test.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ietf_routing/ospf_basic]

==== Description

Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
and that they exchange routes, ending with a simple connectivity check.
Verifies basic OSPF functionality by configuring two routers (R1 and R2)
with OSPF on their interconnecting link. The test ensures OSPF
neighbors are established, routes are exchanged between the routers, and
end-to-end connectivity is achieved.

An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
This verifies that OSPF status information remains accessible when a router
has non-OSPF interfaces.

==== Topology

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


168 changes: 105 additions & 63 deletions test/case/ietf_routing/ospf_basic/test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
#!/usr/bin/env python3
"""
OSPF Basic
"""OSPF Basic

Verifies basic OSPF functionality by configuring two routers (R1 and R2)
with OSPF on their interconnecting link. The test ensures OSPF
neighbors are established, routes are exchanged between the routers, and
end-to-end connectivity is achieved.

An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
This verifies that OSPF status information remains accessible when a router
has non-OSPF interfaces.

Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
and that they exchange routes, ending with a simple connectivity check.
"""

# TODO: Remove HOST node once Infamy supports unconnected ports in topologies

import infamy
import infamy.route as route
from infamy.util import until, parallel


def config_target1(target, data, link):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
Expand All @@ -30,8 +39,8 @@ def config_target1(target, data, link):
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
},
Expand All @@ -40,8 +49,8 @@ def config_target1(target, data, link):
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.100.1",
"prefix-length": 32
"ip": "192.168.100.1",
"prefix-length": 32
}]
}
}
Expand All @@ -56,38 +65,34 @@ def config_target1(target, data, link):
target.put_config_dict("ietf-routing", {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"type": "infix-routing:static",
"name": "default",
"static-routes": {
"ipv4": {
"route": [{
"destination-prefix": "192.168.33.1/32",
"next-hop": {
"special-next-hop": "blackhole"
}
}]
}
"control-plane-protocol": [{
"type": "infix-routing:static",
"name": "default",
"static-routes": {
"ipv4": {
"route": [{
"destination-prefix": "192.168.33.1/32",
"next-hop": {
"special-next-hop": "blackhole"
}
}]
}
},
{
}
}, {
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "static"
},
{
}, {
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces":
{
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
Expand All @@ -103,35 +108,43 @@ def config_target1(target, data, link):
}
})

def config_target2(target, link):

def config_target2(target, link, data):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"forwarding": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}
]
}
})
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}, {
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"forwarding": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}]
}
})

target.put_config_dict("ietf-system", {
"system": {
Expand All @@ -141,8 +154,7 @@ def config_target2(target, link):
target.put_config_dict("ietf-routing", {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
Expand All @@ -154,7 +166,7 @@ def config_target2(target, link):
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces":{
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
Expand All @@ -165,31 +177,61 @@ def config_target2(target, link):
}]
}
}
}
]
}]
}
}
})


def config_host(target, link):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.60.2",
"prefix-length": 24
}]
}
}]
}
})

target.put_config_dict("ietf-system", {
"system": {
"hostname": "HOST"
}
})


with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
R1 = env.attach("R1", "mgmt")
R2 = env.attach("R2", "mgmt")
HOST = env.attach("HOST", "mgmt")

with test.step("Configure targets"):
_, R1data = env.ltop.xlate("R1", "data")
_, R2link = env.ltop.xlate("R2", "link")
_, R1link= env.ltop.xlate("R1", "link")
_, R1link = env.ltop.xlate("R1", "link")
_, R2data = env.ltop.xlate("R2", "data")
_, HOSTlink = env.ltop.xlate("HOST", "link")

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

with test.step("Verify R2 OSPF neighbors with non-OSPF interface"):
# Regression test for #1169
assert route.ospf_has_neighbors(R2)

with test.step("Test connectivity from PC:data to 192.168.200.1"):
_, hport0 = env.ltop.xlate("PC", "data")
with infamy.IsolatedMacVlan(hport0) as ns0:
Expand Down
20 changes: 14 additions & 6 deletions test/case/ietf_routing/ospf_basic/topology.dot
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,34 @@ graph "2x2" {
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];

PC [
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 }",
pos="20,80!",
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 | <mgmt3> mgmt3 }",
pos="20,30!",
requires="controller",
];

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

requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R2 \n 192.168.200.1/32 \n(lo)",
pos="250,30!",
pos="160,30!",

requires="infix",
];

HOST [
label="{ <link> link | <mgmt> mgmt } | HOST \n end-device",
pos="153,0!",

requires="infix",
];

PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", fontcolor="black"]
PC:mgmt3 -- HOST:mgmt [requires="mgmt", color="lightgray"]
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", labeldistance=6, fontcolor="black"]
R1:link -- R2:link [headlabel="192.168.50.2/24", taillabel="192.168.50.1/24", labeldistance=1, fontcolor="black", color="black"]
R2:data -- HOST:link [headlabel="192.168.60.2/24", taillabel="192.168.60.1/24", labeldistance=1, fontcolor="black", color="black"]
}
Loading
Loading