mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-30 12:33:02 +02:00
Let's drop the leading IETF or Infix prefixes from tests. Initially the idea was to mimnic the YANG models, but it's difficult to navigate and does not provide any real benefit to developers or end-users. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
198 lines
7.9 KiB
Python
Executable File
198 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Route preference: OSPF vs Static
|
|
|
|
This test configures a device with both an OSPF-acquired route on a
|
|
dedicated interface and a static route to the same destination on
|
|
another interface. The static route has a higher preference value than
|
|
OSPF.
|
|
|
|
Initially, the device should prefer the OSPF route; if the OSPF route
|
|
becomes unavailable, the static route should take over.
|
|
"""
|
|
|
|
import infamy
|
|
import infamy.route as route
|
|
from infamy.util import until, parallel
|
|
from infamy.netns import TPMR
|
|
|
|
|
|
def configure_interface(name, ip, prefix_length, forwarding=True):
|
|
return {
|
|
"name": name,
|
|
"enabled": True,
|
|
"ipv4": {
|
|
"forwarding": forwarding,
|
|
"address": [{"ip": ip, "prefix-length": prefix_length}]
|
|
}
|
|
}
|
|
|
|
def config_target1(target, data, link, ospf):
|
|
target.put_config_dicts({
|
|
"ietf-interfaces": {
|
|
"interfaces": {
|
|
"interface": [
|
|
configure_interface(data, "192.168.10.1", 24),
|
|
configure_interface(link, "192.168.50.1", 24),
|
|
configure_interface(ospf, "192.168.60.1", 24)
|
|
]
|
|
}
|
|
},
|
|
"ietf-routing": {
|
|
"routing": {
|
|
"control-plane-protocols": {
|
|
"control-plane-protocol": [
|
|
{
|
|
"type": "infix-routing:ospfv2",
|
|
"name": "ospf-default",
|
|
"ospf": {
|
|
"redistribute": {
|
|
"redistribute": [{"protocol": "connected"}]
|
|
},
|
|
"areas": {
|
|
"area": [{
|
|
"area-id": "0.0.0.0",
|
|
"interfaces": {
|
|
"interface": [{
|
|
"name": ospf,
|
|
"hello-interval": 1,
|
|
"dead-interval": 3
|
|
}]
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "infix-routing:static",
|
|
"name": "dot20",
|
|
"static-routes": {
|
|
"ipv4": {
|
|
"route": [{
|
|
"destination-prefix": "192.168.20.0/24",
|
|
"next-hop": {"next-hop-address": "192.168.50.2"},
|
|
"route-preference": 120
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
def config_target2(target, data, link, ospf):
|
|
target.put_config_dicts({
|
|
"ietf-interfaces": {
|
|
"interfaces": {
|
|
"interface": [
|
|
configure_interface(data, "192.168.20.2", 24),
|
|
configure_interface(link, "192.168.50.2", 24),
|
|
configure_interface(ospf, "192.168.60.2", 24)
|
|
]
|
|
}
|
|
},
|
|
"ietf-routing": {
|
|
"routing": {
|
|
"control-plane-protocols": {
|
|
"control-plane-protocol": [
|
|
{
|
|
"type": "infix-routing:ospfv2",
|
|
"name": "ospf-default",
|
|
"ospf": {
|
|
"redistribute": {
|
|
"redistribute": [{"protocol": "connected"}]
|
|
},
|
|
"areas": {
|
|
"area": [{
|
|
"area-id": "0.0.0.0",
|
|
"interfaces": {
|
|
"interface": [{
|
|
"name": ospf,
|
|
"hello-interval": 1,
|
|
"dead-interval": 3
|
|
}]
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "infix-routing:static",
|
|
"name": "default",
|
|
"static-routes": {
|
|
"ipv4": {
|
|
"route": [{
|
|
"destination-prefix": "0.0.0.0/0",
|
|
"next-hop": {"next-hop-address": "192.168.50.1"}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
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")
|
|
|
|
with test.step("Set up TPMR between R1ospf and R2ospf"):
|
|
ospf_breaker = TPMR(env.ltop.xlate("PC", "R1_ospf")[1], env.ltop.xlate("PC", "R2_ospf")[1]).start()
|
|
|
|
with test.step("Configure targets"):
|
|
_, R1data = env.ltop.xlate("R1", "data")
|
|
_, R1link = env.ltop.xlate("R1", "link")
|
|
_, R1ospf = env.ltop.xlate("R1", "ospf")
|
|
_, R2data = env.ltop.xlate("R2", "data")
|
|
_, R2link = env.ltop.xlate("R2", "link")
|
|
_, R2ospf = env.ltop.xlate("R2", "ospf")
|
|
|
|
parallel(config_target1(R1, R1data, R1link, R1ospf), config_target2(R2, R2data, R2link, R2ospf))
|
|
|
|
with test.step("Set up persistent MacVlan namespaces"):
|
|
_, hport_data1 = env.ltop.xlate("PC", "data1")
|
|
_, hport_data2 = env.ltop.xlate("PC", "data2")
|
|
|
|
ns1 = infamy.IsolatedMacVlan(hport_data1).start()
|
|
ns1.addip("192.168.10.11", prefix_length=24)
|
|
ns1.addroute("default", "192.168.10.1")
|
|
|
|
ns2 = infamy.IsolatedMacVlan(hport_data2).start()
|
|
ns2.addip("192.168.20.22", prefix_length=24)
|
|
ns2.addroute("default", "192.168.20.2")
|
|
|
|
with test.step("Wait for OSPF and static routes"):
|
|
print("Waiting for OSPF and static routes...")
|
|
until(lambda: route.ipv4_route_exist(R1, "192.168.20.0/24", proto="ietf-ospf:ospfv2"), attempts=200)
|
|
until(lambda: route.ipv4_route_exist(R1, "192.168.20.0/24", proto="ietf-routing:static"), attempts=200)
|
|
|
|
with test.step("Verify connectivity from PC:data1 to PC:data2 via OSPF"):
|
|
ns1.must_reach("192.168.20.22")
|
|
|
|
ospf_route_active = route.ipv4_route_exist(R1, "192.168.20.0/24", proto="ietf-ospf:ospfv2", active_check=True)
|
|
assert ospf_route_active, "OSPF route should be preferred when available."
|
|
|
|
hops = [row[1] for row in ns1.traceroute("192.168.20.22")]
|
|
assert "192.168.60.2" in hops, f"Path does not use expected OSPF route: {hops}"
|
|
|
|
with test.step("Simulate OSPF route loss by blocking OSPF interface"):
|
|
ospf_breaker.block()
|
|
until(lambda: not route.ipv4_route_exist(R1, "192.168.20.0/24", proto="ietf-ospf:ospfv2"), attempts=200)
|
|
|
|
with test.step("Verify connectivity via static route after OSPF failover"):
|
|
ns1.must_reach("192.168.20.22")
|
|
|
|
static_route_active = route.ipv4_route_exist(R1, "192.168.20.0/24", proto="ietf-routing:static", active_check=True)
|
|
assert static_route_active, "Static route should be preferred when OSPF route is unavailable."
|
|
|
|
hops = [row[1] for row in ns1.traceroute("192.168.20.22")]
|
|
assert "192.168.50.2" in hops, f"Path does not use expected static route: {hops}"
|
|
|
|
test.succeed()
|