test: add new tests for RIP

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2025-12-05 11:12:03 +01:00
parent 024b51cc6a
commit 0a491ffff5
21 changed files with 1620 additions and 1 deletions
+21 -1
View File
@@ -7,9 +7,13 @@ Tests verifying standard routing protocols and configuration:
- OSPF basic neighbor discovery and LSA exchange
- OSPF unnumbered interface configuration
- OSPF multi-area configuration and inter-area routing
- OSPF with BFD (Bidirectional Forwarding Detection)
- OSPF with BFD (Bidirectional Forwarding Detection)
- OSPF default route advertisement and propagation
- OSPF debug logging configuration and verification
- RIP basic neighbor discovery and route exchange
- RIP passive interface configuration
- RIP route redistribution (connected, static, and OSPF)
- RIP multi-hop routing with multiple neighbors
- Route preference handling for OSPF routes
- Route preference handling for DHCP-learned routes
- Administrative distance configuration (route preference 255)
@@ -42,6 +46,22 @@ include::ospf_debug/Readme.adoc[]
<<<
include::rip_basic/Readme.adoc[]
<<<
include::rip_passive_interface/Readme.adoc[]
<<<
include::rip_redistribute/Readme.adoc[]
<<<
include::rip_multihop/Readme.adoc[]
<<<
include::route_pref_ospf/Readme.adoc[]
<<<
+12
View File
@@ -28,3 +28,15 @@
- name: OSPF Debug Logging
case: ospf_debug/test.py
- name: RIP Basic
case: rip_basic/test.py
- name: RIP Passive Interface
case: rip_passive_interface/test.py
- name: RIP Redistribution
case: rip_redistribute/test.py
- name: RIP Multi-hop
case: rip_multihop/test.py
+1
View File
@@ -0,0 +1 @@
test.adoc
+28
View File
@@ -0,0 +1,28 @@
=== RIP Basic
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/rip_basic]
==== Description
Verifies basic RIP functionality by configuring two routers (R1 and R2)
with RIP on their interconnecting link. The test ensures RIP routes are
exchanged between the routers and end-to-end connectivity is achieved.
The test PC uses data1 interface to connect to R1's data port, and data2
interface to connect to R2's data port (which does not have RIP enabled).
This verifies that RIP status information remains accessible when a router
has non-RIP interfaces.
==== Topology
image::topology.svg[RIP Basic topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUTs
. Configure targets
. Wait for RIP routes to be exchanged
. Test connectivity from PC:data1 to R2 loopback via RIP
. Test connectivity from PC:data2 to R1 loopback via RIP
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""RIP Basic
Verifies basic RIP functionality by configuring two routers (R1 and R2)
with RIP on their interconnecting link. The test ensures RIP routes are
exchanged between the routers and end-to-end connectivity is achieved.
The test PC uses data1 interface to connect to R1's data port, and data2
interface to connect to R2's data port (which does not have RIP enabled).
This verifies that RIP status information remains accessible when a router
has non-RIP interfaces.
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_target1(target, data, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.10.1",
"prefix-length": 24
}]}
}, {
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.100.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"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"
}
}]
}
}
}, {
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "static"
}, {
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
def config_target2(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"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
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
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("Configure targets"):
_, R1data = env.ltop.xlate("R1", "data")
_, R2link = env.ltop.xlate("R2", "link")
_, R1link = env.ltop.xlate("R1", "link")
_, R2data = env.ltop.xlate("R2", "data")
parallel(config_target1(R1, R1data, R1link),
config_target2(R2, R2link, R2data))
with test.step("Wait for RIP routes to be exchanged"):
print("Waiting for RIP routes to propagate...")
# R1 should learn R2's loopback
until(lambda: route.ipv4_route_exist(R1, "192.168.200.1/32", proto="ietf-rip:rip"), attempts=40)
# R2 should learn R1's loopback
until(lambda: route.ipv4_route_exist(R2, "192.168.100.1/32", proto="ietf-rip:rip"), attempts=40)
# R2 should learn R1's static route (redistributed)
until(lambda: route.ipv4_route_exist(R2, "192.168.33.1/32", proto="ietf-rip:rip"), attempts=40)
with test.step("Test connectivity from PC:data1 to R2 loopback via RIP"):
_, hport0 = env.ltop.xlate("PC", "data1")
with infamy.IsolatedMacVlan(hport0) as ns0:
ns0.addip("192.168.10.2")
ns0.addroute("192.168.200.1/32", "192.168.10.1")
ns0.must_reach("192.168.200.1")
with test.step("Test connectivity from PC:data2 to R1 loopback via RIP"):
_, hport1 = env.ltop.xlate("PC", "data2")
with infamy.IsolatedMacVlan(hport1) as ns1:
ns1.addip("192.168.60.2")
ns1.addroute("192.168.100.1/32", "192.168.60.1")
ns1.must_reach("192.168.100.1")
test.succeed()
+34
View File
@@ -0,0 +1,34 @@
graph "2x2" {
layout="neato";
overlap="false";
esep="+40";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data1> data1 | \n\n\n\n\n\n\n\n | <mgmt2> mgmt2 | <data2> data2 }",
pos="20,50!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link} | R1 \n 192.168.100.1/32 \n(lo)",
pos="190,85!",
requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R2 \n 192.168.200.1/32 \n(lo)",
pos="190,15!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:data1 -- R1:data [color="black", label="192.168.10.0/24", headlabel=".1", taillabel=".2", labeldistance=2, fontcolor="black"]
R1:link -- R2:link [label="192.168.50.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
PC:data2 -- R2:data [label="192.168.60.0/24", headlabel=".1", taillabel=".2", labeldistance=2, fontcolor="black", color="black"]
}
+89
View File
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: 2x2 Pages: 1 -->
<svg width="574pt" height="249pt"
viewBox="0.00 0.00 573.90 248.51" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 244.51)">
<title>2x2</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-244.51 569.9,-244.51 569.9,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-6.5 0,-234.5 91,-234.5 91,-6.5 0,-6.5"/>
<text text-anchor="middle" x="16.5" y="-116.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-6.5 33,-234.5 "/>
<text text-anchor="middle" x="62" y="-219.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-211.5 91,-211.5 "/>
<text text-anchor="middle" x="62" y="-196.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
<polyline fill="none" stroke="black" points="33,-188.5 91,-188.5 "/>
<polyline fill="none" stroke="black" points="33,-52.5 91,-52.5 "/>
<text text-anchor="middle" x="62" y="-37.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
<polyline fill="none" stroke="black" points="33,-29.5 91,-29.5 "/>
<text text-anchor="middle" x="62" y="-14.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="350.9,-171.01 350.9,-240.01 565.9,-240.01 565.9,-171.01 350.9,-171.01"/>
<text text-anchor="middle" x="375.9" y="-224.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="350.9,-217.01 400.9,-217.01 "/>
<text text-anchor="middle" x="375.9" y="-201.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="350.9,-194.01 400.9,-194.01 "/>
<text text-anchor="middle" x="375.9" y="-178.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="400.9,-171.01 400.9,-240.01 "/>
<text text-anchor="middle" x="483.4" y="-216.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="483.4" y="-201.81" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.100.1/32 </text>
<text text-anchor="middle" x="483.4" y="-186.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-223.5C91.5,-223.5 350.4,-228.51 350.4,-228.51"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge3" class="edge">
<title>PC:data1&#45;&#45;R1:data</title>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-200.5C91.5,-200.5 350.4,-205.51 350.4,-205.51"/>
<text text-anchor="middle" x="161.95" y="-206.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.0/24</text>
<text text-anchor="middle" x="332.11" y="-209.91" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
<text text-anchor="middle" x="109.79" y="-188.7" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="350.9,-1 350.9,-70 565.9,-70 565.9,-1 350.9,-1"/>
<text text-anchor="middle" x="375.9" y="-54.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="350.9,-47 400.9,-47 "/>
<text text-anchor="middle" x="375.9" y="-31.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="350.9,-24 400.9,-24 "/>
<text text-anchor="middle" x="375.9" y="-8.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="400.9,-1 400.9,-70 "/>
<text text-anchor="middle" x="483.4" y="-46.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="483.4" y="-31.8" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.200.1/32 </text>
<text text-anchor="middle" x="483.4" y="-16.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-40.5C91.5,-40.5 350.4,-35.5 350.4,-35.5"/>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge5" class="edge">
<title>PC:data2&#45;&#45;R2:data</title>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-17.5C91.5,-17.5 350.4,-12.5 350.4,-12.5"/>
<text text-anchor="middle" x="250.45" y="-3.8" font-family="DejaVu Serif, Book" font-size="14.00">192.168.60.0/24</text>
<text text-anchor="middle" x="332.44" y="-17.6" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
<text text-anchor="middle" x="109.46" y="-5" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge4" class="edge">
<title>R1:link&#45;&#45;R2:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M375.4,-170.51C375.4,-170.51 375.4,-70.5 375.4,-70.5"/>
<text text-anchor="middle" x="316.4" y="-124.3" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.0/24</text>
<text text-anchor="middle" x="383.85" y="-84.92" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="366.95" y="-148.69" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

+1
View File
@@ -0,0 +1 @@
test.adoc
+314
View File
@@ -0,0 +1,314 @@
#!/usr/bin/env python3
"""RIP Multi-hop
Verifies RIP functionality across multiple hops with three routers in a line
topology (R1 -- R2 -- R3). This test ensures:
- RIP routes propagate through multiple hops
- R2 (middle router) has two RIP neighbors
- End-to-end connectivity works across the RIP network
Topology:
PC:data1 -- R1 -- R2 -- R3 -- PC:data2
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_r1(target, data, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.10.1",
"prefix-length": 24
}]
}
}, {
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.11.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
def config_r2(target, west, east):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": west,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}, {
"name": east,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.22.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": west
}, {
"interface": east
}]
}
}
}]
}
}
}
})
def config_r3(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.2",
"prefix-length": 24
}]
}
}, {
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.70.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.33.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R3"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
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")
R3 = env.attach("R3", "mgmt")
with test.step("Configure routers"):
_, R1data = env.ltop.xlate("R1", "data")
_, R1link = env.ltop.xlate("R1", "link")
_, R2west = env.ltop.xlate("R2", "west")
_, R2east = env.ltop.xlate("R2", "east")
_, R3link = env.ltop.xlate("R3", "link")
_, R3data = env.ltop.xlate("R3", "data")
parallel(config_r1(R1, R1data, R1link),
config_r2(R2, R2west, R2east),
config_r3(R3, R3link, R3data))
with test.step("Wait for RIP routes to be exchanged"):
print("Waiting for RIP routes to propagate...")
# R1 should learn R2's loopback
until(lambda: route.ipv4_route_exist(R1, "192.168.22.1/32", proto="ietf-rip:rip"), attempts=40)
# R1 should learn R3's loopback (via R2)
until(lambda: route.ipv4_route_exist(R1, "192.168.33.1/32", proto="ietf-rip:rip"), attempts=40)
# R2 should learn R1's loopback
until(lambda: route.ipv4_route_exist(R2, "192.168.11.1/32", proto="ietf-rip:rip"), attempts=40)
# R2 should learn R3's loopback
until(lambda: route.ipv4_route_exist(R2, "192.168.33.1/32", proto="ietf-rip:rip"), attempts=40)
# R3 should learn R2's loopback
until(lambda: route.ipv4_route_exist(R3, "192.168.22.1/32", proto="ietf-rip:rip"), attempts=40)
# R3 should learn R1's loopback (via R2)
until(lambda: route.ipv4_route_exist(R3, "192.168.11.1/32", proto="ietf-rip:rip"), attempts=40)
with test.step("Verify R2 has two RIP neighbors"):
print("Checking R2 has two RIP neighbors...")
# R2 should have neighbors: 192.168.50.1 (R1) and 192.168.60.2 (R3)
# Query without predicates to avoid RESTCONF encoding issues
routing_data = R2.get_data("/ietf-routing:routing/control-plane-protocols")
# Navigate to RIP protocol
protocols = routing_data.get("routing", {}).get("control-plane-protocols", {}).get("control-plane-protocol", [])
if not protocols:
raise Exception("No protocols found")
# Find RIP protocol
rip = None
for protocol in protocols:
if protocol.get("type") == "infix-routing:ripv2" and protocol.get("name") == "default":
rip = protocol.get("rip", {})
break
if not rip:
raise Exception("RIP protocol not found in control-plane-protocols")
ipv4_data = rip.get("ipv4", {})
neighbors_data = ipv4_data.get("neighbors", {})
neighbor_list = neighbors_data.get("neighbor", [])
assert len(neighbor_list) == 2, f"Expected 2 neighbors, found {len(neighbor_list)}"
neighbor_ips = [n.get("ipv4-address") for n in neighbor_list]
assert "192.168.50.1" in neighbor_ips, "R1 not in neighbor list"
assert "192.168.60.2" in neighbor_ips, "R3 not in neighbor list"
print(f"R2 has correct neighbors: {neighbor_ips}")
with test.step("Test end-to-end connectivity PC:data1 to R3 loopback"):
_, hport1 = env.ltop.xlate("PC", "data1")
with infamy.IsolatedMacVlan(hport1) as ns1:
ns1.addip("192.168.10.2")
ns1.addroute("192.168.33.1/32", "192.168.10.1")
ns1.must_reach("192.168.33.1")
with test.step("Test end-to-end connectivity PC:data2 to R1 loopback"):
_, hport2 = env.ltop.xlate("PC", "data2")
with infamy.IsolatedMacVlan(hport2) as ns2:
ns2.addip("192.168.70.2")
ns2.addroute("192.168.11.1/32", "192.168.70.1")
ns2.must_reach("192.168.11.1")
test.succeed()
@@ -0,0 +1,41 @@
graph "rip-multihop" {
layout="neato";
overlap="false";
esep="+40";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data1> data1 | \n\n\n\n | <mgmt2> mgmt2 | <mgmt3> mgmt3 | <data2> data2 }",
pos="20,54!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link} | R1 \n 192.168.11.1/32 \n(lo)",
pos="100,70!",
requires="infix",
];
R2 [
label="{ <west> west | <mgmt> mgmt | <east> east } | R2 \n 192.168.22.1/32 \n(lo)",
pos="100,50!",
requires="infix",
];
R3 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R3 \n 192.168.33.1/32 \n(lo)",
pos="100,30!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt3 -- R3:mgmt [requires="mgmt", color="lightgray"]
PC:data1 -- R1:data [label="192.168.10.0/24", headlabel=".1", taillabel=".2", labeldistance=2, fontcolor="black", color="black"]
R1:link -- R2:west [label="192.168.50.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
R2:east -- R3:link [label="192.168.60.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
R3:data -- PC:data2 [label="192.168.70.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
}
+118
View File
@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: rip&#45;multihop Pages: 1 -->
<svg width="720pt" height="360pt"
viewBox="0.00 0.00 720.00 359.57" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(0.86 0.86) rotate(0) translate(4 414.03)">
<title>rip&#45;multihop</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-414.03 833.07,-414.03 833.07,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-145.52 0,-332.52 91,-332.52 91,-145.52 0,-145.52"/>
<text text-anchor="middle" x="16.5" y="-235.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-145.52 33,-332.52 "/>
<text text-anchor="middle" x="62" y="-317.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-309.52 91,-309.52 "/>
<text text-anchor="middle" x="62" y="-294.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
<polyline fill="none" stroke="black" points="33,-286.52 91,-286.52 "/>
<polyline fill="none" stroke="black" points="33,-214.52 91,-214.52 "/>
<text text-anchor="middle" x="62" y="-199.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
<polyline fill="none" stroke="black" points="33,-191.52 91,-191.52 "/>
<text text-anchor="middle" x="62" y="-176.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
<polyline fill="none" stroke="black" points="33,-168.52 91,-168.52 "/>
<text text-anchor="middle" x="62" y="-153.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="622.07,-340.53 622.07,-409.53 829.07,-409.53 829.07,-340.53 622.07,-340.53"/>
<text text-anchor="middle" x="647.07" y="-394.33" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="622.07,-386.53 672.07,-386.53 "/>
<text text-anchor="middle" x="647.07" y="-371.33" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="622.07,-363.53 672.07,-363.53 "/>
<text text-anchor="middle" x="647.07" y="-348.33" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="672.07,-340.53 672.07,-409.53 "/>
<text text-anchor="middle" x="750.57" y="-386.33" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="750.57" y="-371.33" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.11.1/32 </text>
<text text-anchor="middle" x="750.57" y="-356.33" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-321.02C91.5,-321.02 621.57,-398.03 621.57,-398.03"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge4" class="edge">
<title>PC:data1&#45;&#45;R1:data</title>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-298.02C91.5,-298.02 621.57,-375.03 621.57,-375.03"/>
<text text-anchor="middle" x="297.53" y="-340.33" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.0/24</text>
<text text-anchor="middle" x="602.41" y="-377.09" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
<text text-anchor="middle" x="110.65" y="-288.56" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="622.07,-170.52 622.07,-239.52 829.07,-239.52 829.07,-170.52 622.07,-170.52"/>
<text text-anchor="middle" x="647.07" y="-224.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">west</text>
<polyline fill="none" stroke="black" points="622.07,-216.52 672.07,-216.52 "/>
<text text-anchor="middle" x="647.07" y="-201.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="622.07,-193.52 672.07,-193.52 "/>
<text text-anchor="middle" x="647.07" y="-178.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">east</text>
<polyline fill="none" stroke="black" points="672.07,-170.52 672.07,-239.52 "/>
<text text-anchor="middle" x="750.57" y="-216.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="750.57" y="-201.32" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.22.1/32 </text>
<text text-anchor="middle" x="750.57" y="-186.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-203.02C91.5,-203.02 621.57,-205.02 621.57,-205.02"/>
</g>
<!-- R3 -->
<g id="node4" class="node">
<title>R3</title>
<polygon fill="none" stroke="black" points="622.07,-0.5 622.07,-69.5 829.07,-69.5 829.07,-0.5 622.07,-0.5"/>
<text text-anchor="middle" x="647.07" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="622.07,-46.5 672.07,-46.5 "/>
<text text-anchor="middle" x="647.07" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="622.07,-23.5 672.07,-23.5 "/>
<text text-anchor="middle" x="647.07" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="672.07,-0.5 672.07,-69.5 "/>
<text text-anchor="middle" x="750.57" y="-46.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R3 </text>
<text text-anchor="middle" x="750.57" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.33.1/32 </text>
<text text-anchor="middle" x="750.57" y="-16.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R3 -->
<g id="edge3" class="edge">
<title>PC:mgmt3&#45;&#45;R3:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-180.02C91.5,-180.02 621.57,-35 621.57,-35"/>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge5" class="edge">
<title>R1:link&#45;&#45;R2:west</title>
<path fill="none" stroke="black" stroke-width="2" d="M646.57,-340.03C646.57,-340.03 646.57,-240.02 646.57,-240.02"/>
<text text-anchor="middle" x="587.57" y="-293.83" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.0/24</text>
<text text-anchor="middle" x="655.02" y="-254.44" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="638.12" y="-318.21" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
<!-- R2&#45;&#45;R3 -->
<g id="edge6" class="edge">
<title>R2:east&#45;&#45;R3:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M646.57,-170.02C646.57,-170.02 646.57,-70 646.57,-70"/>
<text text-anchor="middle" x="587.57" y="-123.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.60.0/24</text>
<text text-anchor="middle" x="655.02" y="-84.43" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="638.12" y="-148.19" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
<!-- R3&#45;&#45;PC -->
<g id="edge7" class="edge">
<title>R3:data&#45;&#45;PC:data2</title>
<path fill="none" stroke="black" stroke-width="2" d="M621.57,-12C621.57,-12 91.5,-157.02 91.5,-157.02"/>
<text text-anchor="middle" x="297.53" y="-88.31" font-family="DejaVu Serif, Book" font-size="14.00">192.168.70.0/24</text>
<text text-anchor="middle" x="106.75" y="-140.38" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="606.31" y="-21.24" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

+1
View File
@@ -0,0 +1 @@
test.adoc
@@ -0,0 +1,29 @@
=== RIP Passive Interface
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/rip_passive_interface]
==== Description
Verifies RIP passive interface functionality. A passive interface means that
RIP will include the interface's network in routing updates but will not send
or receive RIP updates on that interface.
R1 has two RIP-enabled interfaces:
- data: Passive interface (192.168.10.0/24 advertised but no updates sent/received)
- link: Active interface (RIP updates exchanged with R2)
R2 should learn about 192.168.10.0/24 from R1 via the link interface, even
though the data interface is passive.
==== Topology
image::topology.svg[RIP Passive Interface topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUTs
. Configure targets
. Wait for RIP to exchange routes
. Verify connectivity to passive interface network
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env python3
"""RIP Passive Interface
Verifies RIP passive interface functionality. A passive interface means that
RIP will include the interface's network in routing updates but will not send
or receive RIP updates on that interface.
R1 has two RIP-enabled interfaces:
- data: Passive interface (192.168.10.0/24 advertised but no updates sent/received)
- link: Active interface (RIP updates exchanged with R2)
R2 should learn about 192.168.10.0/24 from R1 via the link interface, even
though the data interface is passive.
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_target1(target, data, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.10.1",
"prefix-length": 24
}]}
}, {
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"interfaces": {
"interface": [{
"interface": data,
"passive": None
}, {
"interface": link
}]
}
}
}]
}
}
}
})
def config_target2(target, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
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("Configure targets"):
_, R1data = env.ltop.xlate("R1", "data")
_, R2link = env.ltop.xlate("R2", "link")
_, R1link = env.ltop.xlate("R1", "link")
parallel(config_target1(R1, R1data, R1link),
config_target2(R2, R2link))
with test.step("Wait for RIP to exchange routes"):
print("Waiting for RIP routes to propagate...")
# R2 should learn about R1's passive interface network (192.168.10.0/24)
# even though it's passive, R1 should still advertise it
until(lambda: route.ipv4_route_exist(R2, "192.168.10.0/24", proto="ietf-rip:rip"), attempts=40)
with test.step("Verify connectivity to passive interface network"):
# Test that we can reach the passive interface from PC
_, hport0 = env.ltop.xlate("PC", "data")
with infamy.IsolatedMacVlan(hport0) as ns0:
ns0.addip("192.168.10.2")
# No need for route since we're on the same network
ns0.must_reach("192.168.10.1")
test.succeed()
@@ -0,0 +1,33 @@
graph "rip-passive" {
layout="neato";
overlap="false";
esep="+30";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 }",
pos="20,50!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link} | R1",
pos="160,60!",
requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt } | R2",
pos="160,30!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:data -- R1:data [color="black", label="192.168.10.0/24", headlabel=".1", taillabel=".2", labeldistance=2, fontcolor="black"]
R1:link -- R2:link [taillabel="192.168.50.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
}
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: rip&#45;passive Pages: 1 -->
<svg width="718pt" height="200pt"
viewBox="0.00 0.00 718.06 200.01" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 196.01)">
<title>rip&#45;passive</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-196.01 714.06,-196.01 714.06,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-78.01 0,-147.01 91,-147.01 91,-78.01 0,-78.01"/>
<text text-anchor="middle" x="16.5" y="-108.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-78.01 33,-147.01 "/>
<text text-anchor="middle" x="62" y="-131.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-124.01 91,-124.01 "/>
<text text-anchor="middle" x="62" y="-108.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="33,-101.01 91,-101.01 "/>
<text text-anchor="middle" x="62" y="-85.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="627.06,-122.51 627.06,-191.51 710.06,-191.51 710.06,-122.51 627.06,-122.51"/>
<text text-anchor="middle" x="652.06" y="-176.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="627.06,-168.51 677.06,-168.51 "/>
<text text-anchor="middle" x="652.06" y="-153.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="627.06,-145.51 677.06,-145.51 "/>
<text text-anchor="middle" x="652.06" y="-130.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="677.06,-122.51 677.06,-191.51 "/>
<text text-anchor="middle" x="693.56" y="-153.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-135.51C91.5,-135.51 626.56,-180.01 626.56,-180.01"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge3" class="edge">
<title>PC:data&#45;&#45;R1:data</title>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-112.51C91.5,-112.51 626.56,-157.01 626.56,-157.01"/>
<text text-anchor="middle" x="300.03" y="-138.56" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.0/24</text>
<text text-anchor="middle" x="607.8" y="-160.23" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
<text text-anchor="middle" x="110.26" y="-101.89" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="627.06,-0.5 627.06,-46.5 710.06,-46.5 710.06,-0.5 627.06,-0.5"/>
<text text-anchor="middle" x="652.06" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="627.06,-23.5 677.06,-23.5 "/>
<text text-anchor="middle" x="652.06" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="677.06,-0.5 677.06,-46.5 "/>
<text text-anchor="middle" x="693.56" y="-19.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-89.51C91.5,-89.51 626.56,-11.5 626.56,-11.5"/>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge4" class="edge">
<title>R1:link&#45;&#45;R2:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M651.56,-122.01C651.56,-122.01 651.56,-46.5 651.56,-46.5"/>
<text text-anchor="middle" x="660.01" y="-60.93" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="643.11" y="-100.19" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

+1
View File
@@ -0,0 +1 @@
test.adoc
@@ -0,0 +1,37 @@
=== RIP Redistribution
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/rip_redistribute]
==== Description
Verifies that RIP can redistribute routes from other protocols.
Topology:
- R1: Gateway router running both RIP and OSPF
- RIP interface to R2
- OSPF interface to R3
- Redistributes OSPF routes into RIP
- Redistributes RIP routes into OSPF
- R2: RIP-only router with loopback 192.168.200.1/32
- R3: OSPF-only router with loopback 192.168.100.1/32
Expected behavior:
- R2 (RIP) should learn R3's OSPF loopback (192.168.100.1/32) via RIP redistribution
- R3 (OSPF) should learn R2's RIP loopback (192.168.200.1/32) via OSPF redistribution
==== Topology
image::topology.svg[RIP Redistribution topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUTs
. Configure routers
. Wait for OSPF to converge on R1-R3 link
. Wait for RIP to converge on R1-R2 link
. Verify R2 (RIP) learns R3's OSPF routes via redistribution
. Verify R3 (OSPF) learns R2's RIP routes via redistribution
+286
View File
@@ -0,0 +1,286 @@
#!/usr/bin/env python3
"""RIP Redistribution
Verifies that RIP can redistribute routes from other protocols.
Topology:
- R1: Gateway router running both RIP and OSPF
- RIP interface to R2
- OSPF interface to R3
- Redistributes OSPF routes into RIP
- Redistributes RIP routes into OSPF
- R2: RIP-only router with loopback 192.168.200.1/32
- R3: OSPF-only router with loopback 192.168.100.1/32
Expected behavior:
- R2 (RIP) should learn R3's OSPF loopback (192.168.100.1/32) via RIP redistribution
- R3 (OSPF) should learn R2's RIP loopback (192.168.200.1/32) via OSPF redistribution
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_r1_gateway(target, rip_link, ospf_link):
"""Configure R1 as gateway running both RIP and OSPF"""
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": rip_link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
}, {
"name": ospf_link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.1",
"prefix-length": 24
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "ospf"
}, {
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": rip_link
}]
}
}
}, {
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "rip"
}, {
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"enabled": True,
"name": ospf_link,
"hello-interval": 1,
"dead-interval": 3
}]
}
}]
}
}
}]
}
}
}
})
def config_r2_rip(target, link):
"""Configure R2 with RIP only"""
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ripv2",
"name": "default",
"rip": {
"timers": {
"update-interval": 5,
"invalid-interval": 15,
"flush-interval": 20
},
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"interfaces": {
"interface": [{
"interface": link
}]
}
}
}]
}
}
}
})
def config_r3_ospf(target, link):
"""Configure R3 with OSPF only"""
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.2",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.100.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R3"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
"hello-interval": 1,
"dead-interval": 3
}]
}
}]
}
}
}]
}
}
}
})
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")
R3 = env.attach("R3", "mgmt")
with test.step("Configure routers"):
_, R1rip = env.ltop.xlate("R1", "rip")
_, R1ospf = env.ltop.xlate("R1", "ospf")
_, R2link = env.ltop.xlate("R2", "link")
_, R3link = env.ltop.xlate("R3", "link")
parallel(config_r1_gateway(R1, R1rip, R1ospf),
config_r2_rip(R2, R2link),
config_r3_ospf(R3, R3link))
with test.step("Wait for OSPF to converge on R1-R3 link"):
print("Waiting for OSPF convergence...")
# R1 should learn R3's loopback via OSPF
until(lambda: route.ipv4_route_exist(R1, "192.168.100.1/32", proto="ietf-ospf:ospfv2"), attempts=40)
# R3 should learn R1's OSPF link via OSPF
until(lambda: route.ipv4_route_exist(R3, "192.168.60.0/24", proto="ietf-ospf:ospfv2"), attempts=40)
with test.step("Wait for RIP to converge on R1-R2 link"):
print("Waiting for RIP convergence...")
# R1 should learn R2's loopback via RIP
until(lambda: route.ipv4_route_exist(R1, "192.168.200.1/32", proto="ietf-rip:rip"), attempts=40)
# R2 should learn R1's OSPF link (192.168.60.0/24) via RIP (redistributed from connected)
until(lambda: route.ipv4_route_exist(R2, "192.168.60.0/24", proto="ietf-rip:rip"), attempts=40)
with test.step("Verify R2 (RIP) learns R3's OSPF routes via redistribution"):
print("Checking OSPF->RIP redistribution...")
# R2 should learn R3's loopback (OSPF route) via RIP redistribution on R1
until(lambda: route.ipv4_route_exist(R2, "192.168.100.1/32", proto="ietf-rip:rip"), attempts=40)
with test.step("Verify R3 (OSPF) learns R2's RIP routes via redistribution"):
print("Checking RIP->OSPF redistribution...")
# R3 should learn R2's loopback (RIP route) via OSPF redistribution on R1
until(lambda: route.ipv4_route_exist(R3, "192.168.200.1/32", proto="ietf-ospf:ospfv2"), attempts=40)
test.succeed()
@@ -0,0 +1,39 @@
graph "rip-redistribute" {
layout="neato";
overlap="false";
esep="+40";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt3> mgmt3 | \n\n | <mgmt1> mgmt1 | \n\n | <mgmt2> mgmt2 }",
pos="20,50!",
requires="controller",
];
R3 [
label="{ <mgmt> mgmt | <link> link } | R3 (OSPF) \n 192.168.100.1/32 \n(lo)",
pos="100,100!",
requires="infix",
];
R1 [
label="{ <ospf> ospf | <mgmt> mgmt | <rip> rip } | R1 (ASBR)",
pos="91,50!",
requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt } | R2 (RIP) \n 192.168.200.1/32 \n(lo)",
pos="100,10!",
requires="infix",
];
PC:mgmt3 -- R3:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
R3:link -- R1:ospf [label="192.168.60.0/24", headlabel=".1", taillabel=".2", labeldistance=2, fontcolor="black", color="blue"]
R1:rip -- R2:link [label="192.168.50.0/24", headlabel=".2", taillabel=".1", labeldistance=2, fontcolor="black", color="black"]
}
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: rip&#45;redistribute Pages: 1 -->
<svg width="485pt" height="427pt"
viewBox="0.00 0.00 485.03 426.54" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 422.54)">
<title>rip&#45;redistribute</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-422.54 481.03,-422.54 481.03,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-114.52 0,-263.52 91,-263.52 91,-114.52 0,-114.52"/>
<text text-anchor="middle" x="16.5" y="-185.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-114.52 33,-263.52 "/>
<text text-anchor="middle" x="62" y="-248.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
<polyline fill="none" stroke="black" points="33,-240.52 91,-240.52 "/>
<polyline fill="none" stroke="black" points="33,-200.52 91,-200.52 "/>
<text text-anchor="middle" x="62" y="-185.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-177.52 91,-177.52 "/>
<polyline fill="none" stroke="black" points="33,-137.52 91,-137.52 "/>
<text text-anchor="middle" x="62" y="-122.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
</g>
<!-- R3 -->
<g id="node2" class="node">
<title>R3</title>
<polygon fill="none" stroke="black" points="262.03,-365.04 262.03,-418.04 477.03,-418.04 477.03,-365.04 262.03,-365.04"/>
<text text-anchor="middle" x="287.03" y="-401.34" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="262.03,-392.04 312.03,-392.04 "/>
<text text-anchor="middle" x="287.03" y="-374.84" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="312.03,-365.04 312.03,-418.04 "/>
<text text-anchor="middle" x="394.53" y="-402.84" font-family="DejaVu Sans Mono, Book" font-size="14.00">R3 (OSPF) </text>
<text text-anchor="middle" x="394.53" y="-387.84" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.100.1/32 </text>
<text text-anchor="middle" x="394.53" y="-372.84" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R3 -->
<g id="edge1" class="edge">
<title>PC:mgmt3&#45;&#45;R3:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-252.02C91.5,-252.02 261.53,-405.54 261.53,-405.54"/>
</g>
<!-- R1 -->
<g id="node3" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="262.58,-154.52 262.58,-223.52 403.58,-223.52 403.58,-154.52 262.58,-154.52"/>
<text text-anchor="middle" x="287.58" y="-208.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">ospf</text>
<polyline fill="none" stroke="black" points="262.58,-200.52 312.58,-200.52 "/>
<text text-anchor="middle" x="287.58" y="-185.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="262.58,-177.52 312.58,-177.52 "/>
<text text-anchor="middle" x="287.58" y="-162.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">rip</text>
<polyline fill="none" stroke="black" points="312.58,-154.52 312.58,-223.52 "/>
<text text-anchor="middle" x="358.08" y="-185.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 (ASBR)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge2" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-189.02C91.5,-189.02 262.08,-189.02 262.08,-189.02"/>
</g>
<!-- R2 -->
<g id="node4" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="262.03,-0.5 262.03,-53.5 477.03,-53.5 477.03,-0.5 262.03,-0.5"/>
<text text-anchor="middle" x="287.03" y="-36.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="262.03,-27.5 312.03,-27.5 "/>
<text text-anchor="middle" x="287.03" y="-10.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="312.03,-0.5 312.03,-53.5 "/>
<text text-anchor="middle" x="394.53" y="-38.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 (RIP) </text>
<text text-anchor="middle" x="394.53" y="-23.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.200.1/32 </text>
<text text-anchor="middle" x="394.53" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge3" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-126.02C91.5,-126.02 261.53,-14 261.53,-14"/>
</g>
<!-- R3&#45;&#45;R1 -->
<g id="edge4" class="edge">
<title>R3:link&#45;&#45;R1:ospf</title>
<path fill="none" stroke="blue" stroke-width="2" d="M286.53,-364.54C286.53,-364.54 287.08,-224.02 287.08,-224.02"/>
<text text-anchor="middle" x="227.81" y="-298.08" font-family="DejaVu Serif, Book" font-size="14.00">192.168.60.0/24</text>
<text text-anchor="middle" x="295.46" y="-238.48" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
<text text-anchor="middle" x="278.15" y="-342.68" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge5" class="edge">
<title>R1:rip&#45;&#45;R2:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M287.08,-154.02C287.08,-154.02 286.53,-54 286.53,-54"/>
<text text-anchor="middle" x="227.81" y="-107.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.0/24</text>
<text text-anchor="middle" x="295.08" y="-68.38" font-family="DejaVu Serif, Book" font-size="14.00">.2</text>
<text text-anchor="middle" x="278.53" y="-132.24" font-family="DejaVu Serif, Book" font-size="14.00">.1</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB