test: Verify route preference (DHCP vs Static)

This commit is contained in:
Ahmed Karic
2024-11-25 18:05:51 +01:00
parent 03a2cf7b3b
commit e9fc62b365
6 changed files with 371 additions and 0 deletions
+2
View File
@@ -13,3 +13,5 @@ include::ospf_unnumbered_interface/Readme.adoc[]
include::ospf_multiarea/Readme.adoc[]
include::ospf_bfd/Readme.adoc[]
include::route_pref_dhcp/Readme.adoc[]
+3
View File
@@ -13,3 +13,6 @@
- name: ospf_bfd
case: ospf_bfd/test.py
- name: route_pref_dhcp
case: route_pref_dhcp/test.py
@@ -0,0 +1,33 @@
=== Route preference: DHCP vs Static
==== Description
This test configures a device with both a DHCP-acquired route on a
dedicated interface and a static route to the same destination on
another interface.
Initially, DHCP is preferred over Static. Afterwards, the static
route takes precedence by adjusting the routing preference value
to the one lower than DHCP.
==== Topology
ifdef::topdoc[]
image::../../test/case/ietf_routing/route_pref_dhcp/topology.svg[Route preference: DHCP vs Static topology]
endif::topdoc[]
ifndef::topdoc[]
ifdef::testgroup[]
image::route_pref_dhcp/topology.svg[Route preference: DHCP vs Static topology]
endif::testgroup[]
ifndef::testgroup[]
image::topology.svg[Route preference: DHCP vs Static topology]
endif::testgroup[]
endif::topdoc[]
==== Test sequence
. Set up topology and attach to target DUTs
. Configure targets. Assign higher priority to the dhcp route
. Wait for DHCP and static routes
. Verify connectivity from PC:data12 to R2:lo via DHCP
. Assign higher priority to the static route
. Verify connectivity from PC:data12 to R2:lo via static route
<<<
+196
View File
@@ -0,0 +1,196 @@
#!/usr/bin/env python3
"""
Route preference: DHCP vs Static
This test configures a device with both a DHCP-acquired route on a
dedicated interface and a static route to the same destination on
another interface.
Initially, DHCP is preferred over Static. Afterwards, the static
route takes precedence by adjusting the routing preference value
to the one lower than DHCP.
"""
import infamy
import infamy.route as route
import infamy.dhcp
from infamy.util import until, parallel
from infamy.netns import IsolatedMacVlans
def configure_interface(name, ip=None, prefix_length=None, forwarding=True):
interface_config = {
"name": name,
"enabled": True,
"ipv4": {
"forwarding": forwarding,
"address": []
}
}
if ip and prefix_length:
interface_config["ipv4"]["address"].append({"ip": ip, "prefix-length": prefix_length})
return interface_config
def config_target1(target, data1, data2, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
configure_interface(data1),
configure_interface(data2, "192.168.30.1", 24),
configure_interface(link, "192.168.50.1", 24)
]
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"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.2"},
"route-preference": 120
}]
}
}
}
]
}
}
},
"infix-dhcp-client": {
"dhcp-client": {
"enabled": True,
"client-if": [
{
"if-name": data1,
"enabled": True,
"option": [
{"name": "broadcast"},
{"name": "dns"},
{"name": "domain"},
{"name": "hostname"},
{"name": "ntpsrv"},
{"name": "router"},
{"name": "subnet"}
],
"route-preference": 5
}
]
}
}
})
def config_target2(target, data, link):
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("lo", "192.168.200.1", 32)
]
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"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("Configure targets. Assign higher priority to the dhcp route"):
_, R1data1 = env.ltop.xlate("R1", "data1")
_, R1data2 = env.ltop.xlate("R1", "data2")
_, R1link = env.ltop.xlate("R1", "link")
_, R2data = env.ltop.xlate("R2", "data")
_, R2link = env.ltop.xlate("R2", "link")
parallel(config_target1(R1, R1data1, R1data2, R1link),
config_target2(R2, R2data, R2link))
_, hport_data12 = env.ltop.xlate("PC", "data12")
ns0 = infamy.IsolatedMacVlan(hport_data12).start()
ns0.addip("192.168.30.3", prefix_length=24)
ns0.addroute("default", "192.168.30.1")
_, hport_data11 = env.ltop.xlate("PC", "data11")
_, hport_data2 = env.ltop.xlate("PC", "data2")
ifmap={ hport_data11: "a", hport_data2: "b" }
ns1 = IsolatedMacVlans(ifmap, False).start()
ns1.addip(ifname="b", addr="192.168.20.3", prefix_length=24)
ns1.addroute("192.168.200.1/32", "192.168.20.2")
ns1.addip(ifname="a", addr="192.168.10.3", prefix_length=24)
ns1.runsh("ip route add default dev a")
with infamy.dhcp.Server(netns=ns1, ip="192.168.10.1", netmask="255.255.255.0", router="192.168.10.3", iface="a"):
with test.step("Wait for DHCP and static routes"):
print("Waiting for DHCP and static routes...")
until(lambda: route.ipv4_route_exist(R1, "0.0.0.0/0", proto="ietf-routing:static", pref=5), attempts=200)
until(lambda: route.ipv4_route_exist(R1, "0.0.0.0/0", proto="ietf-routing:static", pref=120), attempts=200)
with test.step("Verify connectivity from PC:data12 to R2:lo via DHCP"):
dhcp_route_active = route.ipv4_route_exist(R1, "0.0.0.0/0", pref=5, active_check=True)
assert dhcp_route_active, "Failed to activate DHCP route: Expected DHCP-acquired route not found."
ns0.must_reach("192.168.200.1")
with test.step("Assign higher priority to the static route"):
R1.put_config_dicts({
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"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.2"},
"route-preference": 1
}]
}
}
}
]
}
}
}
})
with test.step("Verify connectivity from PC:data12 to R2:lo via static route"):
ns0.must_reach("192.168.200.1")
static_route_active = route.ipv4_route_exist(R1, "0.0.0.0/0", pref=1, active_check=True)
assert static_route_active, "Static route activation failed: Verify route-preference adjustment on R1."
test.succeed()
@@ -0,0 +1,40 @@
graph "route-preference" {
layout="neato";
overlap="false";
esep="+20";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC
[
label="PC | { <mgmt1> mgmt1 | <data11> data11 | <data12> data12 | <> \n |<data2> data2 | <mgmt2> mgmt2 }",
pos="20,50!",
kind="controller",
];
R1
[
label="{ <mgmt> mgmt | <data1> data1 | <data2> data2 | <link> link } | R1 \n 192.168.100.1/32 \n(lo)",
pos="60,51.8!",
kind="infix",
];
R2
[
label="{ <link> link | <data> data | <mgmt> mgmt } | R2 \n 192.168.200.1/32 \n(lo)",
pos="60,42!",
kind="infix",
];
PC:mgmt1 -- R1:mgmt [kind=mgmt, color="lightgray"]
PC:mgmt2 -- R2:mgmt [kind=mgmt, color="lightgray"]
PC:data11 -- R1:data1 [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.3/24", fontcolor="black"]
PC:data12 -- R1:data2 [color="black", headlabel="192.168.30.1/24", taillabel="192.168.30.3/24", fontcolor="black"]
PC:data2 -- R2:data [color="black", headlabel="192.168.20.2/24", taillabel="192.168.20.3/24", fontcolor="black"]
R1:link -- R2:link [headlabel="192.168.50.2/24", taillabel="192.168.50.1/24", labeldistance=1, fontcolor="black", color="black"]
}
@@ -0,0 +1,97 @@
<?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: route&#45;preference Pages: 1 -->
<svg width="706pt" height="221pt"
viewBox="0.00 0.00 705.79 221.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 217.01)">
<title>route&#45;preference</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-217.01 701.79,-217.01 701.79,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-72.86 0,-211.86 99,-211.86 99,-72.86 0,-72.86"/>
<text text-anchor="middle" x="16.5" y="-138.66" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-72.86 33,-211.86 "/>
<text text-anchor="middle" x="66" y="-196.66" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-188.86 99,-188.86 "/>
<text text-anchor="middle" x="66" y="-173.66" font-family="DejaVu Sans Mono, Book" font-size="14.00">data11</text>
<polyline fill="none" stroke="black" points="33,-165.86 99,-165.86 "/>
<text text-anchor="middle" x="66" y="-150.66" font-family="DejaVu Sans Mono, Book" font-size="14.00">data12</text>
<polyline fill="none" stroke="black" points="33,-142.86 99,-142.86 "/>
<polyline fill="none" stroke="black" points="33,-118.86 99,-118.86 "/>
<text text-anchor="middle" x="66" y="-103.66" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
<polyline fill="none" stroke="black" points="33,-95.86 99,-95.86 "/>
<text text-anchor="middle" x="66" y="-80.66" 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="474.79,-120.51 474.79,-212.51 697.79,-212.51 697.79,-120.51 474.79,-120.51"/>
<text text-anchor="middle" x="503.79" y="-197.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="474.79,-189.51 532.79,-189.51 "/>
<text text-anchor="middle" x="503.79" y="-174.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
<polyline fill="none" stroke="black" points="474.79,-166.51 532.79,-166.51 "/>
<text text-anchor="middle" x="503.79" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
<polyline fill="none" stroke="black" points="474.79,-143.51 532.79,-143.51 "/>
<text text-anchor="middle" x="503.79" y="-128.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="532.79,-120.51 532.79,-212.51 "/>
<text text-anchor="middle" x="615.29" y="-177.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="615.29" y="-162.81" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.100.1/32 </text>
<text text-anchor="middle" x="615.29" y="-147.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="M99.5,-200.36C99.5,-200.36 474.29,-201.51 474.29,-201.51"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge3" class="edge">
<title>PC:data11&#45;&#45;R1:data1</title>
<path fill="none" stroke="black" stroke-width="2" d="M99.5,-177.36C99.5,-177.36 474.29,-178.51 474.29,-178.51"/>
<text text-anchor="middle" x="415.29" y="-182.31" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.1/24</text>
<text text-anchor="middle" x="158.5" y="-181.16" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.3/24</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge4" class="edge">
<title>PC:data12&#45;&#45;R1:data2</title>
<path fill="none" stroke="black" stroke-width="2" d="M99.5,-154.36C99.5,-154.36 474.29,-154.51 474.29,-154.51"/>
<text text-anchor="middle" x="415.29" y="-158.31" font-family="DejaVu Serif, Book" font-size="14.00">192.168.30.1/24</text>
<text text-anchor="middle" x="158.5" y="-158.16" font-family="DejaVu Serif, Book" font-size="14.00">192.168.30.3/24</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="478.79,-0.5 478.79,-69.5 693.79,-69.5 693.79,-0.5 478.79,-0.5"/>
<text text-anchor="middle" x="503.79" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="478.79,-46.5 528.79,-46.5 "/>
<text text-anchor="middle" x="503.79" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="478.79,-23.5 528.79,-23.5 "/>
<text text-anchor="middle" x="503.79" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="528.79,-0.5 528.79,-69.5 "/>
<text text-anchor="middle" x="611.29" y="-46.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="611.29" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.200.1/32 </text>
<text text-anchor="middle" x="611.29" y="-16.3" 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="M99.5,-84.36C99.5,-84.36 478.29,-12 478.29,-12"/>
</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="M99.5,-107.36C99.5,-107.36 478.29,-35 478.29,-35"/>
<text text-anchor="middle" x="419.29" y="-38.8" font-family="DejaVu Serif, Book" font-size="14.00">192.168.20.2/24</text>
<text text-anchor="middle" x="158.5" y="-111.16" font-family="DejaVu Serif, Book" font-size="14.00">192.168.20.3/24</text>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge6" class="edge">
<title>R1:link&#45;&#45;R2:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M503.29,-120.51C503.29,-120.51 503.29,-70 503.29,-70"/>
<text text-anchor="middle" x="507.51" y="-75.36" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.2/24</text>
<text text-anchor="middle" x="499.06" y="-107.75" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.1/24</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB